xref: /titanic_41/usr/src/uts/common/io/iwh/iwh.c (revision edafac1f8203a7de1490688213c118b03215c89d)
1 /*
2  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /*
7  * Copyright (c) 2009, Intel Corporation
8  * All rights reserved.
9  */
10 
11 /*
12  * Copyright (c) 2006
13  * Copyright (c) 2007
14  *	Damien Bergamini <damien.bergamini@free.fr>
15  *
16  * Permission to use, copy, modify, and distribute this software for any
17  * purpose with or without fee is hereby granted, provided that the above
18  * copyright notice and this permission notice appear in all copies.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
21  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
22  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
23  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
24  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
25  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
26  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
27  */
28 
29 /*
30  * Intel(R) WiFi Link 5100/5300 Driver
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/net80211.h>
54 #include <sys/net80211_proto.h>
55 #include <sys/net80211_ht.h>
56 #include <sys/varargs.h>
57 #include <sys/policy.h>
58 #include <sys/pci.h>
59 
60 #include "iwh_calibration.h"
61 #include "iwh_hw.h"
62 #include "iwh_eeprom.h"
63 #include "iwh_var.h"
64 #include <inet/wifi_ioctl.h>
65 
66 #ifdef DEBUG
67 #define	IWH_DEBUG_80211		(1 << 0)
68 #define	IWH_DEBUG_CMD		(1 << 1)
69 #define	IWH_DEBUG_DMA		(1 << 2)
70 #define	IWH_DEBUG_EEPROM	(1 << 3)
71 #define	IWH_DEBUG_FW		(1 << 4)
72 #define	IWH_DEBUG_HW		(1 << 5)
73 #define	IWH_DEBUG_INTR		(1 << 6)
74 #define	IWH_DEBUG_MRR		(1 << 7)
75 #define	IWH_DEBUG_PIO		(1 << 8)
76 #define	IWH_DEBUG_RX		(1 << 9)
77 #define	IWH_DEBUG_SCAN		(1 << 10)
78 #define	IWH_DEBUG_TX		(1 << 11)
79 #define	IWH_DEBUG_RATECTL	(1 << 12)
80 #define	IWH_DEBUG_RADIO		(1 << 13)
81 #define	IWH_DEBUG_RESUME	(1 << 14)
82 #define	IWH_DEBUG_CALIBRATION	(1 << 15)
83 #define	IWH_DEBUG_BA		(1 << 16)
84 #define	IWH_DEBUG_RXON		(1 << 17)
85 #define	IWH_DEBUG_HWRATE	(1 << 18)
86 #define	IWH_DEBUG_HTRATE	(1 << 19)
87 #define	IWH_DEBUG_QOS		(1 << 20)
88 /*
89  * if want to see debug message of a given section,
90  * please set this flag to one of above values
91  */
92 uint32_t iwh_dbg_flags = 0;
93 #define	IWH_DBG(x) \
94 	iwh_dbg x
95 #else
96 #define	IWH_DBG(x)
97 #endif
98 
99 #define	MS(v, f)    (((v) & f) >> f##_S)
100 
101 static void	*iwh_soft_state_p = NULL;
102 
103 /*
104  * ucode will be compiled into driver image
105  */
106 static uint8_t iwh_fw_5000_bin[] = {
107 #include "fw-iw/fw_5000/iwh_5000.ucode"
108 };
109 
110 static uint8_t iwh_fw_5150_bin[] = {
111 #include "fw-iw/fw_5150/iwh_5150.ucode"
112 };
113 
114 /*
115  * DMA attributes for a shared page
116  */
117 static ddi_dma_attr_t sh_dma_attr = {
118 	DMA_ATTR_V0,	/* version of this structure */
119 	0,		/* lowest usable address */
120 	0xffffffffU,	/* highest usable address */
121 	0xffffffffU,	/* maximum DMAable byte count */
122 	0x1000,		/* alignment in bytes */
123 	0x1000,		/* burst sizes (any?) */
124 	1,		/* minimum transfer */
125 	0xffffffffU,	/* maximum transfer */
126 	0xffffffffU,	/* maximum segment length */
127 	1,		/* maximum number of segments */
128 	1,		/* granularity */
129 	0,		/* flags (reserved) */
130 };
131 
132 /*
133  * DMA attributes for a keep warm DRAM descriptor
134  */
135 static ddi_dma_attr_t kw_dma_attr = {
136 	DMA_ATTR_V0,	/* version of this structure */
137 	0,		/* lowest usable address */
138 	0xffffffffU,	/* highest usable address */
139 	0xffffffffU,	/* maximum DMAable byte count */
140 	0x1000,		/* alignment in bytes */
141 	0x1000,		/* burst sizes (any?) */
142 	1,		/* minimum transfer */
143 	0xffffffffU,	/* maximum transfer */
144 	0xffffffffU,	/* maximum segment length */
145 	1,		/* maximum number of segments */
146 	1,		/* granularity */
147 	0,		/* flags (reserved) */
148 };
149 
150 /*
151  * DMA attributes for a ring descriptor
152  */
153 static ddi_dma_attr_t ring_desc_dma_attr = {
154 	DMA_ATTR_V0,	/* version of this structure */
155 	0,		/* lowest usable address */
156 	0xffffffffU,	/* highest usable address */
157 	0xffffffffU,	/* maximum DMAable byte count */
158 	0x100,		/* alignment in bytes */
159 	0x100,		/* burst sizes (any?) */
160 	1,		/* minimum transfer */
161 	0xffffffffU,	/* maximum transfer */
162 	0xffffffffU,	/* maximum segment length */
163 	1,		/* maximum number of segments */
164 	1,		/* granularity */
165 	0,		/* flags (reserved) */
166 };
167 
168 /*
169  * DMA attributes for a cmd
170  */
171 static ddi_dma_attr_t cmd_dma_attr = {
172 	DMA_ATTR_V0,	/* version of this structure */
173 	0,		/* lowest usable address */
174 	0xffffffffU,	/* highest usable address */
175 	0xffffffffU,	/* maximum DMAable byte count */
176 	4,		/* alignment in bytes */
177 	0x100,		/* burst sizes (any?) */
178 	1,		/* minimum transfer */
179 	0xffffffffU,	/* maximum transfer */
180 	0xffffffffU,	/* maximum segment length */
181 	1,		/* maximum number of segments */
182 	1,		/* granularity */
183 	0,		/* flags (reserved) */
184 };
185 
186 /*
187  * DMA attributes for a rx buffer
188  */
189 static ddi_dma_attr_t rx_buffer_dma_attr = {
190 	DMA_ATTR_V0,	/* version of this structure */
191 	0,		/* lowest usable address */
192 	0xffffffffU,	/* highest usable address */
193 	0xffffffffU,	/* maximum DMAable byte count */
194 	0x100,		/* alignment in bytes */
195 	0x100,		/* burst sizes (any?) */
196 	1,		/* minimum transfer */
197 	0xffffffffU,	/* maximum transfer */
198 	0xffffffffU,	/* maximum segment length */
199 	1,		/* maximum number of segments */
200 	1,		/* granularity */
201 	0,		/* flags (reserved) */
202 };
203 
204 /*
205  * DMA attributes for a tx buffer.
206  * the maximum number of segments is 4 for the hardware.
207  * now all the wifi drivers put the whole frame in a single
208  * descriptor, so we define the maximum  number of segments 1,
209  * just the same as the rx_buffer. we consider leverage the HW
210  * ability in the future, that is why we don't define rx and tx
211  * buffer_dma_attr as the same.
212  */
213 static ddi_dma_attr_t tx_buffer_dma_attr = {
214 	DMA_ATTR_V0,	/* version of this structure */
215 	0,		/* lowest usable address */
216 	0xffffffffU,	/* highest usable address */
217 	0xffffffffU,	/* maximum DMAable byte count */
218 	4,		/* alignment in bytes */
219 	0x100,		/* burst sizes (any?) */
220 	1,		/* minimum transfer */
221 	0xffffffffU,	/* maximum transfer */
222 	0xffffffffU,	/* maximum segment length */
223 	1,		/* maximum number of segments */
224 	1,		/* granularity */
225 	0,		/* flags (reserved) */
226 };
227 
228 /*
229  * DMA attributes for text and data part in the firmware
230  */
231 static ddi_dma_attr_t fw_dma_attr = {
232 	DMA_ATTR_V0,	/* version of this structure */
233 	0,		/* lowest usable address */
234 	0xffffffffU,	/* highest usable address */
235 	0x7fffffff,	/* maximum DMAable byte count */
236 	0x10,		/* alignment in bytes */
237 	0x100,		/* burst sizes (any?) */
238 	1,		/* minimum transfer */
239 	0xffffffffU,	/* maximum transfer */
240 	0xffffffffU,	/* maximum segment length */
241 	1,		/* maximum number of segments */
242 	1,		/* granularity */
243 	0,		/* flags (reserved) */
244 };
245 
246 /*
247  * regs access attributes
248  */
249 static ddi_device_acc_attr_t iwh_reg_accattr = {
250 	DDI_DEVICE_ATTR_V0,
251 	DDI_STRUCTURE_LE_ACC,
252 	DDI_STRICTORDER_ACC,
253 	DDI_DEFAULT_ACC
254 };
255 
256 /*
257  * DMA access attributes for descriptor
258  */
259 static ddi_device_acc_attr_t iwh_dma_descattr = {
260 	DDI_DEVICE_ATTR_V0,
261 	DDI_STRUCTURE_LE_ACC,
262 	DDI_STRICTORDER_ACC,
263 	DDI_DEFAULT_ACC
264 };
265 
266 /*
267  * DMA access attributes
268  */
269 static ddi_device_acc_attr_t iwh_dma_accattr = {
270 	DDI_DEVICE_ATTR_V0,
271 	DDI_NEVERSWAP_ACC,
272 	DDI_STRICTORDER_ACC,
273 	DDI_DEFAULT_ACC
274 };
275 
276 static int	iwh_ring_init(iwh_sc_t *);
277 static void	iwh_ring_free(iwh_sc_t *);
278 static int	iwh_alloc_shared(iwh_sc_t *);
279 static void	iwh_free_shared(iwh_sc_t *);
280 static int	iwh_alloc_kw(iwh_sc_t *);
281 static void	iwh_free_kw(iwh_sc_t *);
282 static int	iwh_alloc_fw_dma(iwh_sc_t *);
283 static void	iwh_free_fw_dma(iwh_sc_t *);
284 static int	iwh_alloc_rx_ring(iwh_sc_t *);
285 static void	iwh_reset_rx_ring(iwh_sc_t *);
286 static void	iwh_free_rx_ring(iwh_sc_t *);
287 static int	iwh_alloc_tx_ring(iwh_sc_t *, iwh_tx_ring_t *,
288     int, int);
289 static void	iwh_reset_tx_ring(iwh_sc_t *, iwh_tx_ring_t *);
290 static void	iwh_free_tx_ring(iwh_tx_ring_t *);
291 static ieee80211_node_t *iwh_node_alloc(ieee80211com_t *);
292 static void	iwh_node_free(ieee80211_node_t *);
293 static int	iwh_newstate(ieee80211com_t *, enum ieee80211_state, int);
294 static void	iwh_mac_access_enter(iwh_sc_t *);
295 static void	iwh_mac_access_exit(iwh_sc_t *);
296 static uint32_t	iwh_reg_read(iwh_sc_t *, uint32_t);
297 static void	iwh_reg_write(iwh_sc_t *, uint32_t, uint32_t);
298 static int	iwh_load_init_firmware(iwh_sc_t *);
299 static int	iwh_load_run_firmware(iwh_sc_t *);
300 static void	iwh_tx_intr(iwh_sc_t *, iwh_rx_desc_t *);
301 static void	iwh_cmd_intr(iwh_sc_t *, iwh_rx_desc_t *);
302 static uint_t   iwh_intr(caddr_t, caddr_t);
303 static int	iwh_eep_load(iwh_sc_t *);
304 static void	iwh_get_mac_from_eep(iwh_sc_t *);
305 static int	iwh_eep_sem_down(iwh_sc_t *);
306 static void	iwh_eep_sem_up(iwh_sc_t *);
307 static uint_t   iwh_rx_softintr(caddr_t, caddr_t);
308 static uint8_t	iwh_rate_to_plcp(int);
309 static int	iwh_cmd(iwh_sc_t *, int, const void *, int, int);
310 static void	iwh_set_led(iwh_sc_t *, uint8_t, uint8_t, uint8_t);
311 static int	iwh_hw_set_before_auth(iwh_sc_t *);
312 static int	iwh_scan(iwh_sc_t *);
313 static int	iwh_config(iwh_sc_t *);
314 static void	iwh_stop_master(iwh_sc_t *);
315 static int	iwh_power_up(iwh_sc_t *);
316 static int	iwh_preinit(iwh_sc_t *);
317 static int	iwh_init(iwh_sc_t *);
318 static void	iwh_stop(iwh_sc_t *);
319 static int	iwh_quiesce(dev_info_t *t);
320 static void	iwh_amrr_init(iwh_amrr_t *);
321 static void	iwh_amrr_timeout(iwh_sc_t *);
322 static void	iwh_amrr_ratectl(void *, ieee80211_node_t *);
323 static void	iwh_ucode_alive(iwh_sc_t *, iwh_rx_desc_t *);
324 static void	iwh_rx_phy_intr(iwh_sc_t *, iwh_rx_desc_t *);
325 static void	iwh_rx_mpdu_intr(iwh_sc_t *, iwh_rx_desc_t *);
326 static void	iwh_release_calib_buffer(iwh_sc_t *);
327 static int	iwh_init_common(iwh_sc_t *);
328 static uint8_t	*iwh_eep_addr_trans(iwh_sc_t *, uint32_t);
329 static int	iwh_put_seg_fw(iwh_sc_t *, uint32_t, uint32_t, uint32_t);
330 static	int	iwh_alive_common(iwh_sc_t *);
331 static void	iwh_save_calib_result(iwh_sc_t *, iwh_rx_desc_t *);
332 static int	iwh_tx_power_table(iwh_sc_t *, int);
333 static int	iwh_attach(dev_info_t *, ddi_attach_cmd_t);
334 static int	iwh_detach(dev_info_t *, ddi_detach_cmd_t);
335 static void	iwh_destroy_locks(iwh_sc_t *);
336 static int	iwh_send(ieee80211com_t *, mblk_t *, uint8_t);
337 static void	iwh_thread(iwh_sc_t *);
338 static int	iwh_run_state_config(iwh_sc_t *);
339 static int	iwh_fast_recover(iwh_sc_t *);
340 static int	iwh_wme_update(ieee80211com_t *);
341 static int	iwh_qosparam_to_hw(iwh_sc_t *, int);
342 static int	iwh_wme_to_qos_ac(int);
343 static uint16_t	iwh_cw_e_to_cw(uint8_t);
344 static int	iwh_wmeparam_check(struct wmeParams *);
345 static inline int	iwh_wme_tid_qos_ac(int);
346 static inline int	iwh_qos_ac_to_txq(int);
347 static int	iwh_wme_tid_to_txq(int);
348 static void	iwh_init_ht_conf(iwh_sc_t *);
349 static void	iwh_overwrite_11n_rateset(iwh_sc_t *);
350 static void	iwh_overwrite_ic_default(iwh_sc_t *);
351 static void	iwh_config_rxon_chain(iwh_sc_t *);
352 static int	iwh_add_ap_sta(iwh_sc_t *);
353 static int	iwh_ap_lq(iwh_sc_t *);
354 static void	iwh_recv_action(struct ieee80211_node *,
355     const uint8_t *, const uint8_t *);
356 static int	iwh_send_action(struct ieee80211_node *,
357     int, int, uint16_t[4]);
358 static int	iwh_is_max_rate(ieee80211_node_t *);
359 static int	iwh_is_min_rate(ieee80211_node_t *);
360 static void	iwh_increase_rate(ieee80211_node_t *);
361 static void	iwh_decrease_rate(ieee80211_node_t *);
362 static int	iwh_alloc_dma_mem(iwh_sc_t *, size_t,
363     ddi_dma_attr_t *, ddi_device_acc_attr_t *,
364     uint_t, iwh_dma_t *);
365 static void	iwh_free_dma_mem(iwh_dma_t *);
366 static int	iwh_reset_hw(iwh_sc_t *);
367 
368 /*
369  * GLD specific operations
370  */
371 static int	iwh_m_stat(void *, uint_t, uint64_t *);
372 static int	iwh_m_start(void *);
373 static void	iwh_m_stop(void *);
374 static int	iwh_m_unicst(void *, const uint8_t *);
375 static int	iwh_m_multicst(void *, boolean_t, const uint8_t *);
376 static int	iwh_m_promisc(void *, boolean_t);
377 static mblk_t	*iwh_m_tx(void *, mblk_t *);
378 static void	iwh_m_ioctl(void *, queue_t *, mblk_t *);
379 static int	iwh_m_setprop(void *arg, const char *pr_name,
380     mac_prop_id_t wldp_pr_num, uint_t wldp_length, const void *wldp_buf);
381 static int	iwh_m_getprop(void *arg, const char *pr_name,
382     mac_prop_id_t wldp_pr_num, uint_t pr_flags, uint_t wldp_length,
383     void *wldp_buf, uint_t *perm);
384 
385 /*
386  * Supported rates for 802.11b/g modes (in 500Kbps unit).
387  */
388 static const struct ieee80211_rateset iwh_rateset_11b =
389 	{ 4, { 2, 4, 11, 22 } };
390 
391 static const struct ieee80211_rateset iwh_rateset_11g =
392 	{ 12, { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 } };
393 
394 /*
395  * Default 11n reates supported by this station.
396  */
397 extern struct ieee80211_htrateset ieee80211_rateset_11n;
398 
399 /*
400  * For mfthread only
401  */
402 extern pri_t minclsyspri;
403 
404 #define	DRV_NAME_SP	"iwh"
405 
406 /*
407  * Module Loading Data & Entry Points
408  */
409 DDI_DEFINE_STREAM_OPS(iwh_devops, nulldev, nulldev, iwh_attach,
410     iwh_detach, nodev, NULL, D_MP, NULL, iwh_quiesce);
411 
412 static struct modldrv iwh_modldrv = {
413 	&mod_driverops,
414 	"Intel(R) ShirleyPeak/EchoPeak driver(N)",
415 	&iwh_devops
416 };
417 
418 static struct modlinkage iwh_modlinkage = {
419 	MODREV_1,
420 	&iwh_modldrv,
421 	NULL
422 };
423 
424 int
425 _init(void)
426 {
427 	int status;
428 
429 	status = ddi_soft_state_init(&iwh_soft_state_p,
430 	    sizeof (iwh_sc_t), 1);
431 	if (status != DDI_SUCCESS) {
432 		return (status);
433 	}
434 
435 	mac_init_ops(&iwh_devops, DRV_NAME_SP);
436 	status = mod_install(&iwh_modlinkage);
437 	if (status != DDI_SUCCESS) {
438 		mac_fini_ops(&iwh_devops);
439 		ddi_soft_state_fini(&iwh_soft_state_p);
440 	}
441 
442 	return (status);
443 }
444 
445 int
446 _fini(void)
447 {
448 	int status;
449 
450 	status = mod_remove(&iwh_modlinkage);
451 	if (DDI_SUCCESS == status) {
452 		mac_fini_ops(&iwh_devops);
453 		ddi_soft_state_fini(&iwh_soft_state_p);
454 	}
455 
456 	return (status);
457 }
458 
459 int
460 _info(struct modinfo *mip)
461 {
462 	return (mod_info(&iwh_modlinkage, mip));
463 }
464 
465 /*
466  * Mac Call Back entries
467  */
468 mac_callbacks_t	iwh_m_callbacks = {
469 	MC_IOCTL | MC_SETPROP | MC_GETPROP,
470 	iwh_m_stat,
471 	iwh_m_start,
472 	iwh_m_stop,
473 	iwh_m_promisc,
474 	iwh_m_multicst,
475 	iwh_m_unicst,
476 	iwh_m_tx,
477 	iwh_m_ioctl,
478 	NULL,
479 	NULL,
480 	NULL,
481 	iwh_m_setprop,
482 	iwh_m_getprop
483 };
484 
485 #ifdef DEBUG
486 void
487 iwh_dbg(uint32_t flags, const char *fmt, ...)
488 {
489 	va_list	ap;
490 
491 	if (flags & iwh_dbg_flags) {
492 		va_start(ap, fmt);
493 		vcmn_err(CE_NOTE, fmt, ap);
494 		va_end(ap);
495 	}
496 }
497 #endif	/* DEBUG */
498 
499 /*
500  * device operations
501  */
502 int
503 iwh_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
504 {
505 	iwh_sc_t *sc;
506 	ieee80211com_t *ic;
507 	int instance, i;
508 	char strbuf[32];
509 	wifi_data_t wd = { 0 };
510 	mac_register_t *macp;
511 	int intr_type;
512 	int intr_count;
513 	int intr_actual;
514 	int err = DDI_FAILURE;
515 
516 	switch (cmd) {
517 	case DDI_ATTACH:
518 		break;
519 
520 	case DDI_RESUME:
521 		instance = ddi_get_instance(dip);
522 		sc = ddi_get_soft_state(iwh_soft_state_p,
523 		    instance);
524 		ASSERT(sc != NULL);
525 
526 		if (sc->sc_flags & IWH_F_RUNNING) {
527 			(void) iwh_init(sc);
528 		}
529 
530 		atomic_and_32(&sc->sc_flags, ~IWH_F_SUSPEND);
531 
532 		IWH_DBG((IWH_DEBUG_RESUME, "iwh_attach(): "
533 		    "resume\n"));
534 		return (DDI_SUCCESS);
535 
536 	default:
537 		goto attach_fail1;
538 	}
539 
540 	instance = ddi_get_instance(dip);
541 	err = ddi_soft_state_zalloc(iwh_soft_state_p, instance);
542 	if (err != DDI_SUCCESS) {
543 		cmn_err(CE_WARN, "iwh_attach(): "
544 		    "failed to allocate soft state\n");
545 		goto attach_fail1;
546 	}
547 
548 	sc = ddi_get_soft_state(iwh_soft_state_p, instance);
549 	ASSERT(sc != NULL);
550 
551 	sc->sc_dip = dip;
552 
553 	/*
554 	 * map configure space
555 	 */
556 	err = ddi_regs_map_setup(dip, 0, &sc->sc_cfg_base, 0, 0,
557 	    &iwh_reg_accattr, &sc->sc_cfg_handle);
558 	if (err != DDI_SUCCESS) {
559 		cmn_err(CE_WARN, "iwh_attach(): "
560 		    "failed to map config spaces regs\n");
561 		goto attach_fail2;
562 	}
563 
564 	sc->sc_dev_id = ddi_get16(sc->sc_cfg_handle,
565 	    (uint16_t *)(sc->sc_cfg_base + PCI_CONF_DEVID));
566 	if ((sc->sc_dev_id != 0x4232) &&
567 	    (sc->sc_dev_id != 0x4235) &&
568 	    (sc->sc_dev_id != 0x4236) &&
569 	    (sc->sc_dev_id != 0x4237) &&
570 	    (sc->sc_dev_id != 0x423a) &&
571 	    (sc->sc_dev_id != 0x423b) &&
572 	    (sc->sc_dev_id != 0x423c) &&
573 	    (sc->sc_dev_id != 0x423d)) {
574 		cmn_err(CE_WARN, "iwh_attach(): "
575 		    "Do not support this device\n");
576 		goto attach_fail3;
577 	}
578 
579 	iwh_init_ht_conf(sc);
580 	iwh_overwrite_11n_rateset(sc);
581 
582 	sc->sc_rev = ddi_get8(sc->sc_cfg_handle,
583 	    (uint8_t *)(sc->sc_cfg_base + PCI_CONF_REVID));
584 
585 	/*
586 	 * keep from disturbing C3 state of CPU
587 	 */
588 	ddi_put8(sc->sc_cfg_handle, (uint8_t *)(sc->sc_cfg_base +
589 	    PCI_CFG_RETRY_TIMEOUT), 0);
590 
591 	/*
592 	 * determine the size of buffer for frame and command to ucode
593 	 */
594 	sc->sc_clsz = ddi_get16(sc->sc_cfg_handle,
595 	    (uint16_t *)(sc->sc_cfg_base + PCI_CONF_CACHE_LINESZ));
596 	if (!sc->sc_clsz) {
597 		sc->sc_clsz = 16;
598 	}
599 	sc->sc_clsz = (sc->sc_clsz << 2);
600 
601 	sc->sc_dmabuf_sz = roundup(0x2000 + sizeof (struct ieee80211_frame) +
602 	    IEEE80211_MTU + IEEE80211_CRC_LEN +
603 	    (IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN +
604 	    IEEE80211_WEP_CRCLEN), sc->sc_clsz);
605 
606 	/*
607 	 * Map operating registers
608 	 */
609 	err = ddi_regs_map_setup(dip, 1, &sc->sc_base,
610 	    0, 0, &iwh_reg_accattr, &sc->sc_handle);
611 	if (err != DDI_SUCCESS) {
612 		cmn_err(CE_WARN, "iwh_attach(): "
613 		    "failed to map device regs\n");
614 		goto attach_fail3;
615 	}
616 
617 	/*
618 	 * this is used to differentiate type of hardware
619 	 */
620 	sc->sc_hw_rev = IWH_READ(sc, CSR_HW_REV);
621 
622 	err = ddi_intr_get_supported_types(dip, &intr_type);
623 	if ((err != DDI_SUCCESS) || (!(intr_type & DDI_INTR_TYPE_FIXED))) {
624 		cmn_err(CE_WARN, "iwh_attach(): "
625 		    "fixed type interrupt is not supported\n");
626 		goto attach_fail4;
627 	}
628 
629 	err = ddi_intr_get_nintrs(dip, DDI_INTR_TYPE_FIXED, &intr_count);
630 	if ((err != DDI_SUCCESS) || (intr_count != 1)) {
631 		cmn_err(CE_WARN, "iwh_attach(): "
632 		    "no fixed interrupts\n");
633 		goto attach_fail4;
634 	}
635 
636 	sc->sc_intr_htable = kmem_zalloc(sizeof (ddi_intr_handle_t), KM_SLEEP);
637 
638 	err = ddi_intr_alloc(dip, sc->sc_intr_htable, DDI_INTR_TYPE_FIXED, 0,
639 	    intr_count, &intr_actual, 0);
640 	if ((err != DDI_SUCCESS) || (intr_actual != 1)) {
641 		cmn_err(CE_WARN, "iwh_attach(): "
642 		    "ddi_intr_alloc() failed 0x%x\n", err);
643 		goto attach_fail5;
644 	}
645 
646 	err = ddi_intr_get_pri(sc->sc_intr_htable[0], &sc->sc_intr_pri);
647 	if (err != DDI_SUCCESS) {
648 		cmn_err(CE_WARN, "iwh_attach(): "
649 		    "ddi_intr_get_pri() failed 0x%x\n", err);
650 		goto attach_fail6;
651 	}
652 
653 	mutex_init(&sc->sc_glock, NULL, MUTEX_DRIVER,
654 	    DDI_INTR_PRI(sc->sc_intr_pri));
655 	mutex_init(&sc->sc_tx_lock, NULL, MUTEX_DRIVER,
656 	    DDI_INTR_PRI(sc->sc_intr_pri));
657 	mutex_init(&sc->sc_mt_lock, NULL, MUTEX_DRIVER,
658 	    DDI_INTR_PRI(sc->sc_intr_pri));
659 
660 	cv_init(&sc->sc_cmd_cv, NULL, CV_DRIVER, NULL);
661 	cv_init(&sc->sc_put_seg_cv, NULL, CV_DRIVER, NULL);
662 	cv_init(&sc->sc_ucode_cv, NULL, CV_DRIVER, NULL);
663 
664 	/*
665 	 * initialize the mfthread
666 	 */
667 	cv_init(&sc->sc_mt_cv, NULL, CV_DRIVER, NULL);
668 	sc->sc_mf_thread = NULL;
669 	sc->sc_mf_thread_switch = 0;
670 
671 	/*
672 	 * Allocate shared buffer for communication between driver and ucode.
673 	 */
674 	err = iwh_alloc_shared(sc);
675 	if (err != DDI_SUCCESS) {
676 		cmn_err(CE_WARN, "iwh_attach(): "
677 		    "failed to allocate shared page\n");
678 		goto attach_fail7;
679 	}
680 
681 	(void) memset(sc->sc_shared, 0, sizeof (iwh_shared_t));
682 
683 	/*
684 	 * Allocate keep warm page.
685 	 */
686 	err = iwh_alloc_kw(sc);
687 	if (err != DDI_SUCCESS) {
688 		cmn_err(CE_WARN, "iwh_attach(): "
689 		    "failed to allocate keep warm page\n");
690 		goto attach_fail8;
691 	}
692 
693 	err = iwh_reset_hw(sc);
694 	if (err != IWH_SUCCESS) {
695 		cmn_err(CE_WARN, "iwh_attach(): "
696 		    "failed to reset hardware\n");
697 		goto attach_fail9;
698 	}
699 
700 	/*
701 	 * Do some necessary hardware initializations.
702 	 */
703 	err = iwh_preinit(sc);
704 	if (err != IWH_SUCCESS) {
705 		cmn_err(CE_WARN, "iwh_attach(): "
706 		    "failed to initialize hardware\n");
707 		goto attach_fail9;
708 	}
709 
710 	/*
711 	 * get hardware configurations from eeprom
712 	 */
713 	err = iwh_eep_load(sc);
714 	if (err != IWH_SUCCESS) {
715 		cmn_err(CE_WARN, "iwh_attach(): "
716 		    "failed to load eeprom\n");
717 		goto attach_fail9;
718 	}
719 
720 	if (IWH_READ_EEP_SHORT(sc, EEP_VERSION) < 0x011a) {
721 		IWH_DBG((IWH_DEBUG_EEPROM, "iwh_attach(): "
722 		    "unsupported eeprom detected\n"));
723 		goto attach_fail9;
724 	}
725 
726 	/*
727 	 * get MAC address of this chipset
728 	 */
729 	iwh_get_mac_from_eep(sc);
730 
731 	/*
732 	 * calibration information from EEPROM
733 	 */
734 	sc->sc_eep_calib = (struct iwh_eep_calibration *)
735 	    iwh_eep_addr_trans(sc, EEP_CALIBRATION);
736 
737 	/*
738 	 * initialize TX and RX ring buffers
739 	 */
740 	err = iwh_ring_init(sc);
741 	if (err != DDI_SUCCESS) {
742 		cmn_err(CE_WARN, "iwh_attach(): "
743 		    "failed to allocate and initialize ring\n");
744 		goto attach_fail9;
745 	}
746 
747 	if ((0x423c == sc->sc_dev_id) || (0x423d == sc->sc_dev_id)) {
748 		sc->sc_hdr = (iwh_firmware_hdr_t *)iwh_fw_5150_bin;
749 	} else {
750 		sc->sc_hdr = (iwh_firmware_hdr_t *)iwh_fw_5000_bin;
751 	}
752 
753 	/*
754 	 * copy ucode to dma buffer
755 	 */
756 	err = iwh_alloc_fw_dma(sc);
757 	if (err != DDI_SUCCESS) {
758 		cmn_err(CE_WARN, "iwh_attach(): "
759 		    "failed to allocate firmware dma\n");
760 		goto attach_fail10;
761 	}
762 
763 	/*
764 	 * Initialize the wifi part, which will be used by
765 	 * 802.11 module
766 	 */
767 	ic = &sc->sc_ic;
768 	ic->ic_phytype  = IEEE80211_T_HT;
769 	ic->ic_opmode   = IEEE80211_M_STA; /* default to BSS mode */
770 	ic->ic_state    = IEEE80211_S_INIT;
771 	ic->ic_maxrssi  = 100; /* experimental number */
772 	ic->ic_caps = IEEE80211_C_SHPREAMBLE | IEEE80211_C_TXPMGT |
773 	    IEEE80211_C_PMGT | IEEE80211_C_SHSLOT;
774 
775 	/*
776 	 * Support WPA/WPA2
777 	 */
778 	ic->ic_caps |= IEEE80211_C_WPA;
779 
780 	/*
781 	 * Support QoS/WME
782 	 */
783 	ic->ic_caps |= IEEE80211_C_WME;
784 	ic->ic_wme.wme_update = iwh_wme_update;
785 
786 	/*
787 	 * Support 802.11n/HT
788 	 */
789 	if (sc->sc_ht_conf.ht_support) {
790 		ic->ic_htcaps = IEEE80211_HTC_HT |
791 		    IEEE80211_HTC_AMSDU;
792 		ic->ic_htcaps |= IEEE80211_HTCAP_MAXAMSDU_7935;
793 	}
794 
795 	/*
796 	 * set supported .11b and .11g rates
797 	 */
798 	ic->ic_sup_rates[IEEE80211_MODE_11B] = iwh_rateset_11b;
799 	ic->ic_sup_rates[IEEE80211_MODE_11G] = iwh_rateset_11g;
800 
801 	/*
802 	 * set supported .11b and .11g channels (1 through 11)
803 	 */
804 	for (i = 1; i <= 11; i++) {
805 		ic->ic_sup_channels[i].ich_freq =
806 		    ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ);
807 		ic->ic_sup_channels[i].ich_flags =
808 		    IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM |
809 		    IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ |
810 		    IEEE80211_CHAN_PASSIVE;
811 
812 		if (sc->sc_ht_conf.cap & HT_CAP_SUP_WIDTH) {
813 			ic->ic_sup_channels[i].ich_flags |=
814 			    IEEE80211_CHAN_HT40;
815 		} else {
816 			ic->ic_sup_channels[i].ich_flags |=
817 			    IEEE80211_CHAN_HT20;
818 		}
819 	}
820 
821 	ic->ic_ibss_chan = &ic->ic_sup_channels[0];
822 	ic->ic_xmit = iwh_send;
823 
824 	/*
825 	 * attach to 802.11 module
826 	 */
827 	ieee80211_attach(ic);
828 
829 	/*
830 	 * different instance has different WPA door
831 	 */
832 	(void) snprintf(ic->ic_wpadoor, MAX_IEEE80211STR, "%s_%s%d", WPA_DOOR,
833 	    ddi_driver_name(dip),
834 	    ddi_get_instance(dip));
835 
836 	/*
837 	 * Overwrite 80211 default configurations.
838 	 */
839 	iwh_overwrite_ic_default(sc);
840 
841 	/*
842 	 * initialize 802.11 module
843 	 */
844 	ieee80211_media_init(ic);
845 
846 	/*
847 	 * initialize default tx key
848 	 */
849 	ic->ic_def_txkey = 0;
850 
851 	err = ddi_intr_add_softint(dip, &sc->sc_soft_hdl, DDI_INTR_SOFTPRI_MAX,
852 	    iwh_rx_softintr, (caddr_t)sc);
853 	if (err != DDI_SUCCESS) {
854 		cmn_err(CE_WARN, "iwh_attach(): "
855 		    "add soft interrupt failed\n");
856 		goto attach_fail12;
857 	}
858 
859 	err = ddi_intr_add_handler(sc->sc_intr_htable[0], iwh_intr,
860 	    (caddr_t)sc, NULL);
861 	if (err != DDI_SUCCESS) {
862 		cmn_err(CE_WARN, "iwh_attach(): "
863 		    "ddi_intr_add_handle() failed\n");
864 		goto attach_fail13;
865 	}
866 
867 	err = ddi_intr_enable(sc->sc_intr_htable[0]);
868 	if (err != DDI_SUCCESS) {
869 		cmn_err(CE_WARN, "iwh_attach(): "
870 		    "ddi_intr_enable() failed\n");
871 		goto attach_fail14;
872 	}
873 
874 	/*
875 	 * Initialize pointer to device specific functions
876 	 */
877 	wd.wd_secalloc = WIFI_SEC_NONE;
878 	wd.wd_opmode = ic->ic_opmode;
879 	IEEE80211_ADDR_COPY(wd.wd_bssid, ic->ic_macaddr);
880 
881 	/*
882 	 * create relation to GLD
883 	 */
884 	macp = mac_alloc(MAC_VERSION);
885 	if (NULL == macp) {
886 		cmn_err(CE_WARN, "iwh_attach(): "
887 		    "failed to do mac_alloc()\n");
888 		goto attach_fail15;
889 	}
890 
891 	macp->m_type_ident	= MAC_PLUGIN_IDENT_WIFI;
892 	macp->m_driver		= sc;
893 	macp->m_dip		= dip;
894 	macp->m_src_addr	= ic->ic_macaddr;
895 	macp->m_callbacks	= &iwh_m_callbacks;
896 	macp->m_min_sdu		= 0;
897 	macp->m_max_sdu		= IEEE80211_MTU;
898 	macp->m_pdata		= &wd;
899 	macp->m_pdata_size	= sizeof (wd);
900 
901 	/*
902 	 * Register the macp to mac
903 	 */
904 	err = mac_register(macp, &ic->ic_mach);
905 	mac_free(macp);
906 	if (err != DDI_SUCCESS) {
907 		cmn_err(CE_WARN, "iwh_attach(): "
908 		    "failed to do mac_register()\n");
909 		goto attach_fail15;
910 	}
911 
912 	/*
913 	 * Create minor node of type DDI_NT_NET_WIFI
914 	 */
915 	(void) snprintf(strbuf, sizeof (strbuf), DRV_NAME_SP"%d", instance);
916 	err = ddi_create_minor_node(dip, strbuf, S_IFCHR,
917 	    instance + 1, DDI_NT_NET_WIFI, 0);
918 	if (err != DDI_SUCCESS) {
919 		cmn_err(CE_WARN, "iwh_attach(): "
920 		    "failed to do ddi_create_minor_node()\n");
921 	}
922 
923 	/*
924 	 * Notify link is down now
925 	 */
926 	mac_link_update(ic->ic_mach, LINK_STATE_DOWN);
927 
928 	/*
929 	 * create the mf thread to handle the link status,
930 	 * recovery fatal error, etc.
931 	 */
932 	sc->sc_mf_thread_switch = 1;
933 	if (NULL == sc->sc_mf_thread) {
934 		sc->sc_mf_thread = thread_create((caddr_t)NULL, 0,
935 		    iwh_thread, sc, 0, &p0, TS_RUN, minclsyspri);
936 	}
937 
938 	atomic_or_32(&sc->sc_flags, IWH_F_ATTACHED);
939 
940 	return (DDI_SUCCESS);
941 
942 attach_fail15:
943 	(void) ddi_intr_disable(sc->sc_intr_htable[0]);
944 
945 attach_fail14:
946 	(void) ddi_intr_remove_handler(sc->sc_intr_htable[0]);
947 
948 attach_fail13:
949 	(void) ddi_intr_remove_softint(sc->sc_soft_hdl);
950 	sc->sc_soft_hdl = NULL;
951 
952 attach_fail12:
953 	ieee80211_detach(ic);
954 
955 attach_fail11:
956 	iwh_free_fw_dma(sc);
957 
958 attach_fail10:
959 	iwh_ring_free(sc);
960 
961 attach_fail9:
962 	iwh_free_kw(sc);
963 
964 attach_fail8:
965 	iwh_free_shared(sc);
966 
967 attach_fail7:
968 	iwh_destroy_locks(sc);
969 
970 attach_fail6:
971 	(void) ddi_intr_free(sc->sc_intr_htable[0]);
972 
973 attach_fail5:
974 	kmem_free(sc->sc_intr_htable, sizeof (ddi_intr_handle_t));
975 
976 attach_fail4:
977 	ddi_regs_map_free(&sc->sc_handle);
978 
979 attach_fail3:
980 	ddi_regs_map_free(&sc->sc_cfg_handle);
981 
982 attach_fail2:
983 	ddi_soft_state_free(iwh_soft_state_p, instance);
984 
985 attach_fail1:
986 	return (DDI_FAILURE);
987 }
988 
989 int
990 iwh_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
991 {
992 	iwh_sc_t *sc;
993 	ieee80211com_t *ic;
994 	int err;
995 
996 	sc = ddi_get_soft_state(iwh_soft_state_p, ddi_get_instance(dip));
997 	ASSERT(sc != NULL);
998 	ic = &sc->sc_ic;
999 
1000 	switch (cmd) {
1001 	case DDI_DETACH:
1002 		break;
1003 
1004 	case DDI_SUSPEND:
1005 		atomic_and_32(&sc->sc_flags, ~IWH_F_HW_ERR_RECOVER);
1006 		atomic_and_32(&sc->sc_flags, ~IWH_F_RATE_AUTO_CTL);
1007 
1008 		atomic_or_32(&sc->sc_flags, IWH_F_SUSPEND);
1009 
1010 		if (sc->sc_flags & IWH_F_RUNNING) {
1011 			ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
1012 			iwh_stop(sc);
1013 		}
1014 
1015 		IWH_DBG((IWH_DEBUG_RESUME, "iwh_detach(): "
1016 		    "suspend\n"));
1017 		return (DDI_SUCCESS);
1018 
1019 	default:
1020 		return (DDI_FAILURE);
1021 	}
1022 
1023 	if (!(sc->sc_flags & IWH_F_ATTACHED)) {
1024 		return (DDI_FAILURE);
1025 	}
1026 
1027 	/*
1028 	 * Destroy the mf_thread
1029 	 */
1030 	sc->sc_mf_thread_switch = 0;
1031 
1032 	mutex_enter(&sc->sc_mt_lock);
1033 	while (sc->sc_mf_thread != NULL) {
1034 		if (cv_wait_sig(&sc->sc_mt_cv, &sc->sc_mt_lock) == 0) {
1035 			break;
1036 		}
1037 	}
1038 	mutex_exit(&sc->sc_mt_lock);
1039 
1040 	err = mac_disable(sc->sc_ic.ic_mach);
1041 	if (err != DDI_SUCCESS) {
1042 		return (err);
1043 	}
1044 
1045 	/*
1046 	 * stop chipset
1047 	 */
1048 	iwh_stop(sc);
1049 
1050 	DELAY(500000);
1051 
1052 	/*
1053 	 * release buffer for calibration
1054 	 */
1055 	iwh_release_calib_buffer(sc);
1056 
1057 	/*
1058 	 * Unregiste from GLD
1059 	 */
1060 	(void) mac_unregister(sc->sc_ic.ic_mach);
1061 
1062 	mutex_enter(&sc->sc_glock);
1063 	iwh_free_fw_dma(sc);
1064 	iwh_ring_free(sc);
1065 	iwh_free_kw(sc);
1066 	iwh_free_shared(sc);
1067 	mutex_exit(&sc->sc_glock);
1068 
1069 	(void) ddi_intr_disable(sc->sc_intr_htable[0]);
1070 	(void) ddi_intr_remove_handler(sc->sc_intr_htable[0]);
1071 	(void) ddi_intr_free(sc->sc_intr_htable[0]);
1072 	kmem_free(sc->sc_intr_htable, sizeof (ddi_intr_handle_t));
1073 
1074 	(void) ddi_intr_remove_softint(sc->sc_soft_hdl);
1075 	sc->sc_soft_hdl = NULL;
1076 
1077 	/*
1078 	 * detach from 80211 module
1079 	 */
1080 	ieee80211_detach(&sc->sc_ic);
1081 
1082 	iwh_destroy_locks(sc);
1083 
1084 	ddi_regs_map_free(&sc->sc_handle);
1085 	ddi_regs_map_free(&sc->sc_cfg_handle);
1086 	ddi_remove_minor_node(dip, NULL);
1087 	ddi_soft_state_free(iwh_soft_state_p, ddi_get_instance(dip));
1088 
1089 	return (DDI_SUCCESS);
1090 }
1091 
1092 /*
1093  * destroy all locks
1094  */
1095 static void
1096 iwh_destroy_locks(iwh_sc_t *sc)
1097 {
1098 	cv_destroy(&sc->sc_mt_cv);
1099 	cv_destroy(&sc->sc_cmd_cv);
1100 	cv_destroy(&sc->sc_put_seg_cv);
1101 	cv_destroy(&sc->sc_ucode_cv);
1102 	mutex_destroy(&sc->sc_mt_lock);
1103 	mutex_destroy(&sc->sc_tx_lock);
1104 	mutex_destroy(&sc->sc_glock);
1105 }
1106 
1107 /*
1108  * Allocate an area of memory and a DMA handle for accessing it
1109  */
1110 static int
1111 iwh_alloc_dma_mem(iwh_sc_t *sc, size_t memsize,
1112     ddi_dma_attr_t *dma_attr_p, ddi_device_acc_attr_t *acc_attr_p,
1113     uint_t dma_flags, iwh_dma_t *dma_p)
1114 {
1115 	caddr_t vaddr;
1116 	int err = DDI_FAILURE;
1117 
1118 	/*
1119 	 * Allocate handle
1120 	 */
1121 	err = ddi_dma_alloc_handle(sc->sc_dip, dma_attr_p,
1122 	    DDI_DMA_SLEEP, NULL, &dma_p->dma_hdl);
1123 	if (err != DDI_SUCCESS) {
1124 		dma_p->dma_hdl = NULL;
1125 		return (DDI_FAILURE);
1126 	}
1127 
1128 	/*
1129 	 * Allocate memory
1130 	 */
1131 	err = ddi_dma_mem_alloc(dma_p->dma_hdl, memsize, acc_attr_p,
1132 	    dma_flags & (DDI_DMA_CONSISTENT | DDI_DMA_STREAMING),
1133 	    DDI_DMA_SLEEP, NULL, &vaddr, &dma_p->alength, &dma_p->acc_hdl);
1134 	if (err != DDI_SUCCESS) {
1135 		ddi_dma_free_handle(&dma_p->dma_hdl);
1136 		dma_p->dma_hdl = NULL;
1137 		dma_p->acc_hdl = NULL;
1138 		return (DDI_FAILURE);
1139 	}
1140 
1141 	/*
1142 	 * Bind the two together
1143 	 */
1144 	dma_p->mem_va = vaddr;
1145 	err = ddi_dma_addr_bind_handle(dma_p->dma_hdl, NULL,
1146 	    vaddr, dma_p->alength, dma_flags, DDI_DMA_SLEEP, NULL,
1147 	    &dma_p->cookie, &dma_p->ncookies);
1148 	if (err != DDI_DMA_MAPPED) {
1149 		ddi_dma_mem_free(&dma_p->acc_hdl);
1150 		ddi_dma_free_handle(&dma_p->dma_hdl);
1151 		dma_p->acc_hdl = NULL;
1152 		dma_p->dma_hdl = NULL;
1153 		return (DDI_FAILURE);
1154 	}
1155 
1156 	dma_p->nslots = ~0U;
1157 	dma_p->size = ~0U;
1158 	dma_p->token = ~0U;
1159 	dma_p->offset = 0;
1160 	return (DDI_SUCCESS);
1161 }
1162 
1163 /*
1164  * Free one allocated area of DMAable memory
1165  */
1166 static void
1167 iwh_free_dma_mem(iwh_dma_t *dma_p)
1168 {
1169 	if (dma_p->dma_hdl != NULL) {
1170 		if (dma_p->ncookies) {
1171 			(void) ddi_dma_unbind_handle(dma_p->dma_hdl);
1172 			dma_p->ncookies = 0;
1173 		}
1174 		ddi_dma_free_handle(&dma_p->dma_hdl);
1175 		dma_p->dma_hdl = NULL;
1176 	}
1177 
1178 	if (dma_p->acc_hdl != NULL) {
1179 		ddi_dma_mem_free(&dma_p->acc_hdl);
1180 		dma_p->acc_hdl = NULL;
1181 	}
1182 }
1183 
1184 /*
1185  * copy ucode into dma buffers
1186  */
1187 static int
1188 iwh_alloc_fw_dma(iwh_sc_t *sc)
1189 {
1190 	int err = DDI_FAILURE;
1191 	iwh_dma_t *dma_p;
1192 	char *t;
1193 
1194 	/*
1195 	 * firmware image layout:
1196 	 * |HDR|<-TEXT->|<-DATA->|<-INIT_TEXT->|<-INIT_DATA->|<-BOOT->|
1197 	 */
1198 
1199 	/*
1200 	 * copy text of runtime ucode
1201 	 */
1202 	t = (char *)(sc->sc_hdr + 1);
1203 	err = iwh_alloc_dma_mem(sc, LE_32(sc->sc_hdr->textsz),
1204 	    &fw_dma_attr, &iwh_dma_accattr,
1205 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1206 	    &sc->sc_dma_fw_text);
1207 	if (err != DDI_SUCCESS) {
1208 		cmn_err(CE_WARN, "iwh_alloc_fw_dma(): "
1209 		    "failed to allocate text dma memory.\n");
1210 		goto fail;
1211 	}
1212 
1213 	dma_p = &sc->sc_dma_fw_text;
1214 
1215 	IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_fw_dma(): "
1216 	    "text[ncookies:%d addr:%lx size:%lx]\n",
1217 	    dma_p->ncookies, dma_p->cookie.dmac_address,
1218 	    dma_p->cookie.dmac_size));
1219 
1220 	bcopy(t, dma_p->mem_va, LE_32(sc->sc_hdr->textsz));
1221 
1222 	/*
1223 	 * copy data and bak-data of runtime ucode
1224 	 */
1225 	t += LE_32(sc->sc_hdr->textsz);
1226 	err = iwh_alloc_dma_mem(sc, LE_32(sc->sc_hdr->datasz),
1227 	    &fw_dma_attr, &iwh_dma_accattr,
1228 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1229 	    &sc->sc_dma_fw_data);
1230 	if (err != DDI_SUCCESS) {
1231 		cmn_err(CE_WARN, "iwh_alloc_fw_dma(): "
1232 		    "failed to allocate data dma memory\n");
1233 		goto fail;
1234 	}
1235 
1236 	dma_p = &sc->sc_dma_fw_data;
1237 
1238 	IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_fw_dma(): "
1239 	    "data[ncookies:%d addr:%lx size:%lx]\n",
1240 	    dma_p->ncookies, dma_p->cookie.dmac_address,
1241 	    dma_p->cookie.dmac_size));
1242 
1243 	bcopy(t, dma_p->mem_va, LE_32(sc->sc_hdr->datasz));
1244 
1245 	err = iwh_alloc_dma_mem(sc, LE_32(sc->sc_hdr->datasz),
1246 	    &fw_dma_attr, &iwh_dma_accattr,
1247 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1248 	    &sc->sc_dma_fw_data_bak);
1249 	if (err != DDI_SUCCESS) {
1250 		cmn_err(CE_WARN, "iwh_alloc_fw_dma(): "
1251 		    "failed to allocate data bakup dma memory\n");
1252 		goto fail;
1253 	}
1254 
1255 	dma_p = &sc->sc_dma_fw_data_bak;
1256 
1257 	IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_fw_dma(): "
1258 	    "data_bak[ncookies:%d addr:%lx "
1259 	    "size:%lx]\n",
1260 	    dma_p->ncookies, dma_p->cookie.dmac_address,
1261 	    dma_p->cookie.dmac_size));
1262 
1263 	bcopy(t, dma_p->mem_va, LE_32(sc->sc_hdr->datasz));
1264 
1265 	/*
1266 	 * copy text of init ucode
1267 	 */
1268 	t += LE_32(sc->sc_hdr->datasz);
1269 	err = iwh_alloc_dma_mem(sc, LE_32(sc->sc_hdr->init_textsz),
1270 	    &fw_dma_attr, &iwh_dma_accattr,
1271 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1272 	    &sc->sc_dma_fw_init_text);
1273 	if (err != DDI_SUCCESS) {
1274 		cmn_err(CE_WARN, "iwh_alloc_fw_dma(): "
1275 		    "failed to allocate init text dma memory\n");
1276 		goto fail;
1277 	}
1278 
1279 	dma_p = &sc->sc_dma_fw_init_text;
1280 
1281 	IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_fw_dma(): "
1282 	    "init_text[ncookies:%d addr:%lx "
1283 	    "size:%lx]\n",
1284 	    dma_p->ncookies, dma_p->cookie.dmac_address,
1285 	    dma_p->cookie.dmac_size));
1286 
1287 	bcopy(t, dma_p->mem_va, LE_32(sc->sc_hdr->init_textsz));
1288 
1289 	/*
1290 	 * copy data of init ucode
1291 	 */
1292 	t += LE_32(sc->sc_hdr->init_textsz);
1293 	err = iwh_alloc_dma_mem(sc, LE_32(sc->sc_hdr->init_datasz),
1294 	    &fw_dma_attr, &iwh_dma_accattr,
1295 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1296 	    &sc->sc_dma_fw_init_data);
1297 	if (err != DDI_SUCCESS) {
1298 		cmn_err(CE_WARN, "iwh_alloc_fw_dma(): "
1299 		    "failed to allocate init data dma memory\n");
1300 		goto fail;
1301 	}
1302 
1303 	dma_p = &sc->sc_dma_fw_init_data;
1304 
1305 	IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_fw_dma(): "
1306 	    "init_data[ncookies:%d addr:%lx "
1307 	    "size:%lx]\n",
1308 	    dma_p->ncookies, dma_p->cookie.dmac_address,
1309 	    dma_p->cookie.dmac_size));
1310 
1311 	bcopy(t, dma_p->mem_va, LE_32(sc->sc_hdr->init_datasz));
1312 
1313 	sc->sc_boot = t + LE_32(sc->sc_hdr->init_datasz);
1314 
1315 fail:
1316 	return (err);
1317 }
1318 
1319 static void
1320 iwh_free_fw_dma(iwh_sc_t *sc)
1321 {
1322 	iwh_free_dma_mem(&sc->sc_dma_fw_text);
1323 	iwh_free_dma_mem(&sc->sc_dma_fw_data);
1324 	iwh_free_dma_mem(&sc->sc_dma_fw_data_bak);
1325 	iwh_free_dma_mem(&sc->sc_dma_fw_init_text);
1326 	iwh_free_dma_mem(&sc->sc_dma_fw_init_data);
1327 }
1328 
1329 /*
1330  * Allocate a shared buffer between host and NIC.
1331  */
1332 static int
1333 iwh_alloc_shared(iwh_sc_t *sc)
1334 {
1335 #ifdef	DEBUG
1336 	iwh_dma_t *dma_p;
1337 #endif
1338 	int err = DDI_FAILURE;
1339 
1340 	/*
1341 	 * must be aligned on a 4K-page boundary
1342 	 */
1343 	err = iwh_alloc_dma_mem(sc, sizeof (iwh_shared_t),
1344 	    &sh_dma_attr, &iwh_dma_descattr,
1345 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1346 	    &sc->sc_dma_sh);
1347 	if (err != DDI_SUCCESS) {
1348 		goto fail;
1349 	}
1350 
1351 	sc->sc_shared = (iwh_shared_t *)sc->sc_dma_sh.mem_va;
1352 
1353 #ifdef	DEBUG
1354 	dma_p = &sc->sc_dma_sh;
1355 #endif
1356 	IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_shared(): "
1357 	    "sh[ncookies:%d addr:%lx size:%lx]\n",
1358 	    dma_p->ncookies, dma_p->cookie.dmac_address,
1359 	    dma_p->cookie.dmac_size));
1360 
1361 	return (err);
1362 
1363 fail:
1364 	iwh_free_shared(sc);
1365 	return (err);
1366 }
1367 
1368 static void
1369 iwh_free_shared(iwh_sc_t *sc)
1370 {
1371 	iwh_free_dma_mem(&sc->sc_dma_sh);
1372 }
1373 
1374 /*
1375  * Allocate a keep warm page.
1376  */
1377 static int
1378 iwh_alloc_kw(iwh_sc_t *sc)
1379 {
1380 #ifdef	DEBUG
1381 	iwh_dma_t *dma_p;
1382 #endif
1383 	int err = DDI_FAILURE;
1384 
1385 	/*
1386 	 * must be aligned on a 4K-page boundary
1387 	 */
1388 	err = iwh_alloc_dma_mem(sc, IWH_KW_SIZE,
1389 	    &kw_dma_attr, &iwh_dma_descattr,
1390 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1391 	    &sc->sc_dma_kw);
1392 	if (err != DDI_SUCCESS) {
1393 		goto fail;
1394 	}
1395 
1396 #ifdef	DEBUG
1397 	dma_p = &sc->sc_dma_kw;
1398 #endif
1399 	IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_kw(): "
1400 	    "kw[ncookies:%d addr:%lx size:%lx]\n",
1401 	    dma_p->ncookies, dma_p->cookie.dmac_address,
1402 	    dma_p->cookie.dmac_size));
1403 
1404 	return (err);
1405 
1406 fail:
1407 	iwh_free_kw(sc);
1408 	return (err);
1409 }
1410 
1411 static void
1412 iwh_free_kw(iwh_sc_t *sc)
1413 {
1414 	iwh_free_dma_mem(&sc->sc_dma_kw);
1415 }
1416 
1417 /*
1418  * initialize RX ring buffers
1419  */
1420 static int
1421 iwh_alloc_rx_ring(iwh_sc_t *sc)
1422 {
1423 	iwh_rx_ring_t *ring;
1424 	iwh_rx_data_t *data;
1425 #ifdef	DEBUG
1426 	iwh_dma_t *dma_p;
1427 #endif
1428 	int i, err = DDI_FAILURE;
1429 
1430 	ring = &sc->sc_rxq;
1431 	ring->cur = 0;
1432 
1433 	/*
1434 	 * allocate RX description ring buffer
1435 	 */
1436 	err = iwh_alloc_dma_mem(sc, RX_QUEUE_SIZE * sizeof (uint32_t),
1437 	    &ring_desc_dma_attr, &iwh_dma_descattr,
1438 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1439 	    &ring->dma_desc);
1440 	if (err != DDI_SUCCESS) {
1441 		IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_rx_ring(): "
1442 		    "dma alloc rx ring desc "
1443 		    "failed\n"));
1444 		goto fail;
1445 	}
1446 
1447 	ring->desc = (uint32_t *)ring->dma_desc.mem_va;
1448 #ifdef	DEBUG
1449 	dma_p = &ring->dma_desc;
1450 #endif
1451 	IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_rx_ring(): "
1452 	    "rx bd[ncookies:%d addr:%lx size:%lx]\n",
1453 	    dma_p->ncookies, dma_p->cookie.dmac_address,
1454 	    dma_p->cookie.dmac_size));
1455 
1456 	/*
1457 	 * Allocate Rx frame buffers.
1458 	 */
1459 	for (i = 0; i < RX_QUEUE_SIZE; i++) {
1460 		data = &ring->data[i];
1461 		err = iwh_alloc_dma_mem(sc, sc->sc_dmabuf_sz,
1462 		    &rx_buffer_dma_attr, &iwh_dma_accattr,
1463 		    DDI_DMA_READ | DDI_DMA_STREAMING,
1464 		    &data->dma_data);
1465 		if (err != DDI_SUCCESS) {
1466 			IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_rx_ring(): "
1467 			    "dma alloc rx ring "
1468 			    "buf[%d] failed\n", i));
1469 			goto fail;
1470 		}
1471 		/*
1472 		 * the physical address bit [8-36] are used,
1473 		 * instead of bit [0-31] in 3945.
1474 		 */
1475 		ring->desc[i] = (uint32_t)
1476 		    (data->dma_data.cookie.dmac_address >> 8);
1477 	}
1478 
1479 #ifdef	DEBUG
1480 	dma_p = &ring->data[0].dma_data;
1481 #endif
1482 	IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_rx_ring(): "
1483 	    "rx buffer[0][ncookies:%d addr:%lx "
1484 	    "size:%lx]\n",
1485 	    dma_p->ncookies, dma_p->cookie.dmac_address,
1486 	    dma_p->cookie.dmac_size));
1487 
1488 	IWH_DMA_SYNC(ring->dma_desc, DDI_DMA_SYNC_FORDEV);
1489 
1490 	return (err);
1491 
1492 fail:
1493 	iwh_free_rx_ring(sc);
1494 	return (err);
1495 }
1496 
1497 /*
1498  * disable RX ring
1499  */
1500 static void
1501 iwh_reset_rx_ring(iwh_sc_t *sc)
1502 {
1503 	int n;
1504 
1505 	iwh_mac_access_enter(sc);
1506 	IWH_WRITE(sc, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
1507 	for (n = 0; n < 2000; n++) {
1508 		if (IWH_READ(sc, FH_MEM_RSSR_RX_STATUS_REG) & (1 << 24)) {
1509 			break;
1510 		}
1511 		DELAY(1000);
1512 	}
1513 #ifdef DEBUG
1514 	if (2000 == n) {
1515 		IWH_DBG((IWH_DEBUG_DMA, "iwh_reset_rx_ring(): "
1516 		    "timeout resetting Rx ring\n"));
1517 	}
1518 #endif
1519 	iwh_mac_access_exit(sc);
1520 
1521 	sc->sc_rxq.cur = 0;
1522 }
1523 
1524 static void
1525 iwh_free_rx_ring(iwh_sc_t *sc)
1526 {
1527 	int i;
1528 
1529 	for (i = 0; i < RX_QUEUE_SIZE; i++) {
1530 		if (sc->sc_rxq.data[i].dma_data.dma_hdl) {
1531 			IWH_DMA_SYNC(sc->sc_rxq.data[i].dma_data,
1532 			    DDI_DMA_SYNC_FORCPU);
1533 		}
1534 
1535 		iwh_free_dma_mem(&sc->sc_rxq.data[i].dma_data);
1536 	}
1537 
1538 	if (sc->sc_rxq.dma_desc.dma_hdl) {
1539 		IWH_DMA_SYNC(sc->sc_rxq.dma_desc, DDI_DMA_SYNC_FORDEV);
1540 	}
1541 
1542 	iwh_free_dma_mem(&sc->sc_rxq.dma_desc);
1543 }
1544 
1545 /*
1546  * initialize TX ring buffers
1547  */
1548 static int
1549 iwh_alloc_tx_ring(iwh_sc_t *sc, iwh_tx_ring_t *ring,
1550     int slots, int qid)
1551 {
1552 	iwh_tx_data_t *data;
1553 	iwh_tx_desc_t *desc_h;
1554 	uint32_t paddr_desc_h;
1555 	iwh_cmd_t *cmd_h;
1556 	uint32_t paddr_cmd_h;
1557 #ifdef	DEBUG
1558 	iwh_dma_t *dma_p;
1559 #endif
1560 	int i, err = DDI_FAILURE;
1561 
1562 	ring->qid = qid;
1563 	ring->count = TFD_QUEUE_SIZE_MAX;
1564 	ring->window = slots;
1565 	ring->queued = 0;
1566 	ring->cur = 0;
1567 	ring->desc_cur = 0;
1568 
1569 	/*
1570 	 * allocate buffer for TX descriptor ring
1571 	 */
1572 	err = iwh_alloc_dma_mem(sc,
1573 	    TFD_QUEUE_SIZE_MAX * sizeof (iwh_tx_desc_t),
1574 	    &ring_desc_dma_attr, &iwh_dma_descattr,
1575 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1576 	    &ring->dma_desc);
1577 	if (err != DDI_SUCCESS) {
1578 		IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_tx_ring(): "
1579 		    "dma alloc tx ring desc[%d] "
1580 		    "failed\n", qid));
1581 		goto fail;
1582 	}
1583 
1584 #ifdef	DEBUG
1585 	dma_p = &ring->dma_desc;
1586 #endif
1587 	IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_tx_ring(): "
1588 	    "tx bd[ncookies:%d addr:%lx size:%lx]\n",
1589 	    dma_p->ncookies, dma_p->cookie.dmac_address,
1590 	    dma_p->cookie.dmac_size));
1591 
1592 	desc_h = (iwh_tx_desc_t *)ring->dma_desc.mem_va;
1593 	paddr_desc_h = ring->dma_desc.cookie.dmac_address;
1594 
1595 	/*
1596 	 * allocate buffer for ucode command
1597 	 */
1598 	err = iwh_alloc_dma_mem(sc,
1599 	    TFD_QUEUE_SIZE_MAX * sizeof (iwh_cmd_t),
1600 	    &cmd_dma_attr, &iwh_dma_accattr,
1601 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1602 	    &ring->dma_cmd);
1603 	if (err != DDI_SUCCESS) {
1604 		IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_tx_ring(): "
1605 		    "dma alloc tx ring cmd[%d]"
1606 		    " failed\n", qid));
1607 		goto fail;
1608 	}
1609 
1610 #ifdef	DEBUG
1611 	dma_p = &ring->dma_cmd;
1612 #endif
1613 	IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_tx_ring(): "
1614 	    "tx cmd[ncookies:%d addr:%lx size:%lx]\n",
1615 	    dma_p->ncookies, dma_p->cookie.dmac_address,
1616 	    dma_p->cookie.dmac_size));
1617 
1618 	cmd_h = (iwh_cmd_t *)ring->dma_cmd.mem_va;
1619 	paddr_cmd_h = ring->dma_cmd.cookie.dmac_address;
1620 
1621 	/*
1622 	 * Allocate Tx frame buffers.
1623 	 */
1624 	ring->data = kmem_zalloc(sizeof (iwh_tx_data_t) * TFD_QUEUE_SIZE_MAX,
1625 	    KM_NOSLEEP);
1626 	if (NULL == ring->data) {
1627 		IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_tx_ring(): "
1628 		    "could not allocate "
1629 		    "tx data slots\n"));
1630 		goto fail;
1631 	}
1632 
1633 	for (i = 0; i < TFD_QUEUE_SIZE_MAX; i++) {
1634 		data = &ring->data[i];
1635 		err = iwh_alloc_dma_mem(sc, sc->sc_dmabuf_sz,
1636 		    &tx_buffer_dma_attr, &iwh_dma_accattr,
1637 		    DDI_DMA_WRITE | DDI_DMA_STREAMING,
1638 		    &data->dma_data);
1639 		if (err != DDI_SUCCESS) {
1640 			IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_tx_ring(): "
1641 			    "dma alloc tx "
1642 			    "ring buf[%d] failed\n", i));
1643 			goto fail;
1644 		}
1645 
1646 		data->desc = desc_h + i;
1647 		data->paddr_desc = paddr_desc_h +
1648 		    _PTRDIFF(data->desc, desc_h);
1649 		data->cmd = cmd_h +  i;
1650 		data->paddr_cmd = paddr_cmd_h +
1651 		    _PTRDIFF(data->cmd, cmd_h);
1652 	}
1653 #ifdef	DEBUG
1654 	dma_p = &ring->data[0].dma_data;
1655 #endif
1656 	IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_tx_ring(): "
1657 	    "tx buffer[0][ncookies:%d addr:%lx "
1658 	    "size:%lx]\n",
1659 	    dma_p->ncookies, dma_p->cookie.dmac_address,
1660 	    dma_p->cookie.dmac_size));
1661 
1662 	return (err);
1663 
1664 fail:
1665 	iwh_free_tx_ring(ring);
1666 
1667 	return (err);
1668 }
1669 
1670 /*
1671  * disable TX ring
1672  */
1673 static void
1674 iwh_reset_tx_ring(iwh_sc_t *sc, iwh_tx_ring_t *ring)
1675 {
1676 	iwh_tx_data_t *data;
1677 	int i, n;
1678 
1679 	iwh_mac_access_enter(sc);
1680 
1681 	IWH_WRITE(sc, IWH_FH_TCSR_CHNL_TX_CONFIG_REG(ring->qid), 0);
1682 	for (n = 0; n < 200; n++) {
1683 		if (IWH_READ(sc, IWH_FH_TSSR_TX_STATUS_REG) &
1684 		    IWH_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ring->qid)) {
1685 			break;
1686 		}
1687 		DELAY(10);
1688 	}
1689 
1690 #ifdef	DEBUG
1691 	if (200 == n) {
1692 		IWH_DBG((IWH_DEBUG_DMA, "iwh_reset_tx_ring(): "
1693 		    "timeout reset tx ring %d\n",
1694 		    ring->qid));
1695 	}
1696 #endif
1697 
1698 	iwh_mac_access_exit(sc);
1699 
1700 	/*
1701 	 * by pass, if it's quiesce
1702 	 */
1703 	if (!(sc->sc_flags & IWH_F_QUIESCED)) {
1704 		for (i = 0; i < ring->count; i++) {
1705 			data = &ring->data[i];
1706 			IWH_DMA_SYNC(data->dma_data, DDI_DMA_SYNC_FORDEV);
1707 		}
1708 	}
1709 
1710 	ring->queued = 0;
1711 	ring->cur = 0;
1712 	ring->desc_cur = 0;
1713 }
1714 
1715 static void
1716 iwh_free_tx_ring(iwh_tx_ring_t *ring)
1717 {
1718 	int i;
1719 
1720 	if (ring->dma_desc.dma_hdl != NULL) {
1721 		IWH_DMA_SYNC(ring->dma_desc, DDI_DMA_SYNC_FORDEV);
1722 	}
1723 	iwh_free_dma_mem(&ring->dma_desc);
1724 
1725 	if (ring->dma_cmd.dma_hdl != NULL) {
1726 		IWH_DMA_SYNC(ring->dma_cmd, DDI_DMA_SYNC_FORDEV);
1727 	}
1728 	iwh_free_dma_mem(&ring->dma_cmd);
1729 
1730 	if (ring->data != NULL) {
1731 		for (i = 0; i < ring->count; i++) {
1732 			if (ring->data[i].dma_data.dma_hdl) {
1733 				IWH_DMA_SYNC(ring->data[i].dma_data,
1734 				    DDI_DMA_SYNC_FORDEV);
1735 			}
1736 			iwh_free_dma_mem(&ring->data[i].dma_data);
1737 		}
1738 		kmem_free(ring->data, ring->count * sizeof (iwh_tx_data_t));
1739 	}
1740 }
1741 
1742 /*
1743  * initialize TX and RX ring
1744  */
1745 static int
1746 iwh_ring_init(iwh_sc_t *sc)
1747 {
1748 	int i, err = DDI_FAILURE;
1749 
1750 	for (i = 0; i < IWH_NUM_QUEUES; i++) {
1751 		if (IWH_CMD_QUEUE_NUM == i) {
1752 			continue;
1753 		}
1754 
1755 		err = iwh_alloc_tx_ring(sc, &sc->sc_txq[i], TFD_TX_CMD_SLOTS,
1756 		    i);
1757 		if (err != DDI_SUCCESS) {
1758 			goto fail;
1759 		}
1760 	}
1761 
1762 	/*
1763 	 * initialize command queue
1764 	 */
1765 	err = iwh_alloc_tx_ring(sc, &sc->sc_txq[IWH_CMD_QUEUE_NUM],
1766 	    TFD_CMD_SLOTS, IWH_CMD_QUEUE_NUM);
1767 	if (err != DDI_SUCCESS) {
1768 		goto fail;
1769 	}
1770 
1771 	err = iwh_alloc_rx_ring(sc);
1772 	if (err != DDI_SUCCESS) {
1773 		goto fail;
1774 	}
1775 
1776 fail:
1777 	return (err);
1778 }
1779 
1780 static void
1781 iwh_ring_free(iwh_sc_t *sc)
1782 {
1783 	int i = IWH_NUM_QUEUES;
1784 
1785 	iwh_free_rx_ring(sc);
1786 	while (--i >= 0) {
1787 		iwh_free_tx_ring(&sc->sc_txq[i]);
1788 	}
1789 }
1790 
1791 /* ARGSUSED */
1792 static ieee80211_node_t *
1793 iwh_node_alloc(ieee80211com_t *ic)
1794 {
1795 	iwh_amrr_t *amrr;
1796 
1797 	amrr = kmem_zalloc(sizeof (iwh_amrr_t), KM_SLEEP);
1798 	if (NULL == amrr) {
1799 		cmn_err(CE_WARN, "iwh_node_alloc(): "
1800 		    "failed to allocate memory for amrr structure\n");
1801 		return (NULL);
1802 	}
1803 
1804 	iwh_amrr_init(amrr);
1805 
1806 	return (&amrr->in);
1807 }
1808 
1809 static void
1810 iwh_node_free(ieee80211_node_t *in)
1811 {
1812 	ieee80211com_t *ic;
1813 
1814 	if ((NULL == in) ||
1815 	    (NULL == in->in_ic)) {
1816 		cmn_err(CE_WARN, "iwh_node_free() "
1817 		    "Got a NULL point from Net80211 module\n");
1818 		return;
1819 	}
1820 	ic = in->in_ic;
1821 
1822 	if (ic->ic_node_cleanup != NULL) {
1823 		ic->ic_node_cleanup(in);
1824 	}
1825 
1826 	if (in->in_wpa_ie != NULL) {
1827 		ieee80211_free(in->in_wpa_ie);
1828 	}
1829 
1830 	if (in->in_wme_ie != NULL) {
1831 		ieee80211_free(in->in_wme_ie);
1832 	}
1833 
1834 	if (in->in_htcap_ie != NULL) {
1835 		ieee80211_free(in->in_htcap_ie);
1836 	}
1837 
1838 	kmem_free(in, sizeof (iwh_amrr_t));
1839 }
1840 
1841 /*
1842  * change station's state. this function will be invoked by 80211 module
1843  * when need to change staton's state.
1844  */
1845 static int
1846 iwh_newstate(ieee80211com_t *ic, enum ieee80211_state nstate, int arg)
1847 {
1848 	iwh_sc_t *sc;
1849 	ieee80211_node_t *in;
1850 	enum ieee80211_state ostate;
1851 	iwh_add_sta_t node;
1852 	iwh_amrr_t *amrr;
1853 	uint8_t r;
1854 	int i, err = IWH_FAIL;
1855 
1856 	if (NULL == ic) {
1857 		return (err);
1858 	}
1859 	sc = (iwh_sc_t *)ic;
1860 	in = ic->ic_bss;
1861 	ostate = ic->ic_state;
1862 
1863 	mutex_enter(&sc->sc_glock);
1864 
1865 	switch (nstate) {
1866 	case IEEE80211_S_SCAN:
1867 		switch (ostate) {
1868 		case IEEE80211_S_INIT:
1869 			atomic_or_32(&sc->sc_flags, IWH_F_SCANNING);
1870 			iwh_set_led(sc, 2, 10, 2);
1871 
1872 			/*
1873 			 * clear association to receive beacons from
1874 			 * all BSS'es
1875 			 */
1876 			sc->sc_config.assoc_id = 0;
1877 			sc->sc_config.filter_flags &=
1878 			    ~LE_32(RXON_FILTER_ASSOC_MSK);
1879 
1880 			IWH_DBG((IWH_DEBUG_80211, "iwh_newstate(): "
1881 			    "config chan %d "
1882 			    "flags %x filter_flags %x\n",
1883 			    LE_16(sc->sc_config.chan),
1884 			    LE_32(sc->sc_config.flags),
1885 			    LE_32(sc->sc_config.filter_flags)));
1886 
1887 			err = iwh_cmd(sc, REPLY_RXON, &sc->sc_config,
1888 			    sizeof (iwh_rxon_cmd_t), 1);
1889 			if (err != IWH_SUCCESS) {
1890 				cmn_err(CE_WARN, "iwh_newstate(): "
1891 				    "could not clear association\n");
1892 				atomic_and_32(&sc->sc_flags, ~IWH_F_SCANNING);
1893 				mutex_exit(&sc->sc_glock);
1894 				return (err);
1895 			}
1896 
1897 			/*
1898 			 * add broadcast node to send probe request
1899 			 */
1900 			(void) memset(&node, 0, sizeof (node));
1901 			(void) memset(&node.sta.addr, 0xff, IEEE80211_ADDR_LEN);
1902 			node.sta.sta_id = IWH_BROADCAST_ID;
1903 			err = iwh_cmd(sc, REPLY_ADD_STA, &node,
1904 			    sizeof (node), 1);
1905 			if (err != IWH_SUCCESS) {
1906 				cmn_err(CE_WARN, "iwh_newstate(): "
1907 				    "could not add broadcast node\n");
1908 				atomic_and_32(&sc->sc_flags, ~IWH_F_SCANNING);
1909 				mutex_exit(&sc->sc_glock);
1910 				return (err);
1911 			}
1912 			break;
1913 		case IEEE80211_S_SCAN:
1914 			mutex_exit(&sc->sc_glock);
1915 			/* step to next channel before actual FW scan */
1916 			err = sc->sc_newstate(ic, nstate, arg);
1917 			mutex_enter(&sc->sc_glock);
1918 			if ((err != 0) || ((err = iwh_scan(sc)) != 0)) {
1919 				cmn_err(CE_WARN, "iwh_newstate(): "
1920 				    "could not initiate scan\n");
1921 				atomic_and_32(&sc->sc_flags, ~IWH_F_SCANNING);
1922 				ieee80211_cancel_scan(ic);
1923 			}
1924 			mutex_exit(&sc->sc_glock);
1925 			return (err);
1926 		default:
1927 			break;
1928 		}
1929 		sc->sc_clk = 0;
1930 		break;
1931 
1932 	case IEEE80211_S_AUTH:
1933 		if (ostate == IEEE80211_S_SCAN) {
1934 			atomic_and_32(&sc->sc_flags, ~IWH_F_SCANNING);
1935 		}
1936 
1937 		/*
1938 		 * reset state to handle reassociations correctly
1939 		 */
1940 		sc->sc_config.assoc_id = 0;
1941 		sc->sc_config.filter_flags &= ~LE_32(RXON_FILTER_ASSOC_MSK);
1942 
1943 		/*
1944 		 * before sending authentication and association request frame,
1945 		 * we need do something in the hardware, such as setting the
1946 		 * channel same to the target AP...
1947 		 */
1948 		if ((err = iwh_hw_set_before_auth(sc)) != 0) {
1949 			IWH_DBG((IWH_DEBUG_80211, "iwh_newstate(): "
1950 			    "could not send authentication request\n"));
1951 			mutex_exit(&sc->sc_glock);
1952 			return (err);
1953 		}
1954 		break;
1955 
1956 	case IEEE80211_S_RUN:
1957 		if (ostate == IEEE80211_S_SCAN) {
1958 			atomic_and_32(&sc->sc_flags, ~IWH_F_SCANNING);
1959 		}
1960 
1961 		if (IEEE80211_M_MONITOR == ic->ic_opmode) {
1962 			/*
1963 			 * let LED blink when monitoring
1964 			 */
1965 			iwh_set_led(sc, 2, 10, 10);
1966 			break;
1967 		}
1968 
1969 		IWH_DBG((IWH_DEBUG_80211, "iwh_newstate(): "
1970 		    "associated.\n"));
1971 
1972 		err = iwh_run_state_config(sc);
1973 		if (err != IWH_SUCCESS) {
1974 			cmn_err(CE_WARN, "iwh_newstate(): "
1975 			    "failed to set up association\n");
1976 			mutex_exit(&sc->sc_glock);
1977 			return (err);
1978 		}
1979 
1980 		/*
1981 		 * start automatic rate control
1982 		 */
1983 		if ((in->in_flags & IEEE80211_NODE_HT) &&
1984 		    (sc->sc_ht_conf.ht_support) &&
1985 		    (in->in_htrates.rs_nrates > 0) &&
1986 		    (in->in_htrates.rs_nrates <= IEEE80211_HTRATE_MAXSIZE)) {
1987 			amrr = (iwh_amrr_t *)in;
1988 
1989 			for (i = in->in_htrates.rs_nrates - 1; i > 0; i--) {
1990 
1991 				r = in->in_htrates.rs_rates[i] &
1992 				    IEEE80211_RATE_VAL;
1993 				if ((r != 0) && (r <= 0xd) &&
1994 				    (sc->sc_ht_conf.tx_support_mcs[r/8] &
1995 				    (1 << (r%8)))) {
1996 					amrr->ht_mcs_idx = r;
1997 					atomic_or_32(&sc->sc_flags,
1998 					    IWH_F_RATE_AUTO_CTL);
1999 					break;
2000 				}
2001 			}
2002 		} else {
2003 			if (IEEE80211_FIXED_RATE_NONE == ic->ic_fixed_rate) {
2004 				atomic_or_32(&sc->sc_flags,
2005 				    IWH_F_RATE_AUTO_CTL);
2006 
2007 				/*
2008 				 * set rate to some reasonable initial value
2009 				 */
2010 				i = in->in_rates.ir_nrates - 1;
2011 				while (i > 0 && IEEE80211_RATE(i) > 72) {
2012 					i--;
2013 				}
2014 				in->in_txrate = i;
2015 
2016 			} else {
2017 				atomic_and_32(&sc->sc_flags,
2018 				    ~IWH_F_RATE_AUTO_CTL);
2019 			}
2020 		}
2021 
2022 		/*
2023 		 * set LED on after associated
2024 		 */
2025 		iwh_set_led(sc, 2, 0, 1);
2026 		break;
2027 
2028 	case IEEE80211_S_INIT:
2029 		if (ostate == IEEE80211_S_SCAN) {
2030 			atomic_and_32(&sc->sc_flags, ~IWH_F_SCANNING);
2031 		}
2032 		/*
2033 		 * set LED off after init
2034 		 */
2035 		iwh_set_led(sc, 2, 1, 0);
2036 		break;
2037 
2038 	case IEEE80211_S_ASSOC:
2039 		if (ostate == IEEE80211_S_SCAN) {
2040 			atomic_and_32(&sc->sc_flags, ~IWH_F_SCANNING);
2041 		}
2042 		break;
2043 	}
2044 
2045 	mutex_exit(&sc->sc_glock);
2046 
2047 	return (sc->sc_newstate(ic, nstate, arg));
2048 }
2049 
2050 /*
2051  * exclusive access to mac begin.
2052  */
2053 static void
2054 iwh_mac_access_enter(iwh_sc_t *sc)
2055 {
2056 	uint32_t tmp;
2057 	int n;
2058 
2059 	tmp = IWH_READ(sc, CSR_GP_CNTRL);
2060 	IWH_WRITE(sc, CSR_GP_CNTRL,
2061 	    tmp | CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
2062 
2063 	/*
2064 	 * wait until we succeed
2065 	 */
2066 	for (n = 0; n < 1000; n++) {
2067 		if ((IWH_READ(sc, CSR_GP_CNTRL) &
2068 		    (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY |
2069 		    CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP)) ==
2070 		    CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN) {
2071 			break;
2072 		}
2073 		DELAY(10);
2074 	}
2075 
2076 #ifdef	DEBUG
2077 	if (1000 == n) {
2078 		IWH_DBG((IWH_DEBUG_PIO, "iwh_mac_access_enter(): "
2079 		    "could not lock memory\n"));
2080 	}
2081 #endif
2082 }
2083 
2084 /*
2085  * exclusive access to mac end.
2086  */
2087 static void
2088 iwh_mac_access_exit(iwh_sc_t *sc)
2089 {
2090 	uint32_t tmp = IWH_READ(sc, CSR_GP_CNTRL);
2091 	IWH_WRITE(sc, CSR_GP_CNTRL,
2092 	    tmp & ~CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
2093 }
2094 
2095 /*
2096  * this function defined here for future use.
2097  * static uint32_t
2098  * iwh_mem_read(iwh_sc_t *sc, uint32_t addr)
2099  * {
2100  * 	IWH_WRITE(sc, HBUS_TARG_MEM_RADDR, addr);
2101  * 	return (IWH_READ(sc, HBUS_TARG_MEM_RDAT));
2102  * }
2103  */
2104 
2105 /*
2106  * write mac memory
2107  */
2108 static void
2109 iwh_mem_write(iwh_sc_t *sc, uint32_t addr, uint32_t data)
2110 {
2111 	IWH_WRITE(sc, HBUS_TARG_MEM_WADDR, addr);
2112 	IWH_WRITE(sc, HBUS_TARG_MEM_WDAT, data);
2113 }
2114 
2115 /*
2116  * read mac register
2117  */
2118 static uint32_t
2119 iwh_reg_read(iwh_sc_t *sc, uint32_t addr)
2120 {
2121 	IWH_WRITE(sc, HBUS_TARG_PRPH_RADDR, addr | (3 << 24));
2122 	return (IWH_READ(sc, HBUS_TARG_PRPH_RDAT));
2123 }
2124 
2125 /*
2126  * write mac register
2127  */
2128 static void
2129 iwh_reg_write(iwh_sc_t *sc, uint32_t addr, uint32_t data)
2130 {
2131 	IWH_WRITE(sc, HBUS_TARG_PRPH_WADDR, addr | (3 << 24));
2132 	IWH_WRITE(sc, HBUS_TARG_PRPH_WDAT, data);
2133 }
2134 
2135 
2136 /*
2137  * steps of loading ucode:
2138  * load init ucode=>init alive=>calibrate=>
2139  * receive calibration result=>reinitialize NIC=>
2140  * load runtime ucode=>runtime alive=>
2141  * send calibration result=>running.
2142  */
2143 static int
2144 iwh_load_init_firmware(iwh_sc_t *sc)
2145 {
2146 	int err = IWH_FAIL;
2147 	clock_t	clk;
2148 
2149 	atomic_and_32(&sc->sc_flags, ~IWH_F_PUT_SEG);
2150 
2151 	/*
2152 	 * load init_text section of uCode to hardware
2153 	 */
2154 	err = iwh_put_seg_fw(sc, sc->sc_dma_fw_init_text.cookie.dmac_address,
2155 	    RTC_INST_LOWER_BOUND, sc->sc_dma_fw_init_text.cookie.dmac_size);
2156 	if (err != IWH_SUCCESS) {
2157 		cmn_err(CE_WARN, "iwh_load_init_firmware(): "
2158 		    "failed to write init uCode.\n");
2159 		return (err);
2160 	}
2161 
2162 	clk = ddi_get_lbolt() + drv_usectohz(1000000);
2163 
2164 	/*
2165 	 * wait loading init_text until completed or timeout
2166 	 */
2167 	while (!(sc->sc_flags & IWH_F_PUT_SEG)) {
2168 		if (cv_timedwait(&sc->sc_put_seg_cv, &sc->sc_glock, clk) < 0) {
2169 			break;
2170 		}
2171 	}
2172 
2173 	if (!(sc->sc_flags & IWH_F_PUT_SEG)) {
2174 		cmn_err(CE_WARN, "iwh_load_init_firmware(): "
2175 		    "timeout waiting for init uCode load.\n");
2176 		return (IWH_FAIL);
2177 	}
2178 
2179 	atomic_and_32(&sc->sc_flags, ~IWH_F_PUT_SEG);
2180 
2181 	/*
2182 	 * load init_data section of uCode to hardware
2183 	 */
2184 	err = iwh_put_seg_fw(sc, sc->sc_dma_fw_init_data.cookie.dmac_address,
2185 	    RTC_DATA_LOWER_BOUND, sc->sc_dma_fw_init_data.cookie.dmac_size);
2186 	if (err != IWH_SUCCESS) {
2187 		cmn_err(CE_WARN, "iwh_load_init_firmware(): "
2188 		    "failed to write init_data uCode.\n");
2189 		return (err);
2190 	}
2191 
2192 	clk = ddi_get_lbolt() + drv_usectohz(1000000);
2193 
2194 	/*
2195 	 * wait loading init_data until completed or timeout
2196 	 */
2197 	while (!(sc->sc_flags & IWH_F_PUT_SEG)) {
2198 		if (cv_timedwait(&sc->sc_put_seg_cv, &sc->sc_glock, clk) < 0) {
2199 			break;
2200 		}
2201 	}
2202 
2203 	if (!(sc->sc_flags & IWH_F_PUT_SEG)) {
2204 		cmn_err(CE_WARN, "iwh_load_init_firmware(): "
2205 		    "timeout waiting for init_data uCode load.\n");
2206 		return (IWH_FAIL);
2207 	}
2208 
2209 	atomic_and_32(&sc->sc_flags, ~IWH_F_PUT_SEG);
2210 
2211 	return (err);
2212 }
2213 
2214 static int
2215 iwh_load_run_firmware(iwh_sc_t *sc)
2216 {
2217 	int err = IWH_FAIL;
2218 	clock_t	clk;
2219 
2220 	atomic_and_32(&sc->sc_flags, ~IWH_F_PUT_SEG);
2221 
2222 	/*
2223 	 * load init_text section of uCode to hardware
2224 	 */
2225 	err = iwh_put_seg_fw(sc, sc->sc_dma_fw_text.cookie.dmac_address,
2226 	    RTC_INST_LOWER_BOUND, sc->sc_dma_fw_text.cookie.dmac_size);
2227 	if (err != IWH_SUCCESS) {
2228 		cmn_err(CE_WARN, "iwh_load_run_firmware(): "
2229 		    "failed to write run uCode.\n");
2230 		return (err);
2231 	}
2232 
2233 	clk = ddi_get_lbolt() + drv_usectohz(1000000);
2234 
2235 	/*
2236 	 * wait loading run_text until completed or timeout
2237 	 */
2238 	while (!(sc->sc_flags & IWH_F_PUT_SEG)) {
2239 		if (cv_timedwait(&sc->sc_put_seg_cv, &sc->sc_glock, clk) < 0) {
2240 			break;
2241 		}
2242 	}
2243 
2244 	if (!(sc->sc_flags & IWH_F_PUT_SEG)) {
2245 		cmn_err(CE_WARN, "iwh_load_run_firmware(): "
2246 		    "timeout waiting for run uCode load.\n");
2247 		return (IWH_FAIL);
2248 	}
2249 
2250 	atomic_and_32(&sc->sc_flags, ~IWH_F_PUT_SEG);
2251 
2252 	/*
2253 	 * load run_data section of uCode to hardware
2254 	 */
2255 	err = iwh_put_seg_fw(sc, sc->sc_dma_fw_data_bak.cookie.dmac_address,
2256 	    RTC_DATA_LOWER_BOUND, sc->sc_dma_fw_data.cookie.dmac_size);
2257 	if (err != IWH_SUCCESS) {
2258 		cmn_err(CE_WARN, "iwh_load_run_firmware(): "
2259 		    "failed to write run_data uCode.\n");
2260 		return (err);
2261 	}
2262 
2263 	clk = ddi_get_lbolt() + drv_usectohz(1000000);
2264 
2265 	/*
2266 	 * wait loading run_data until completed or timeout
2267 	 */
2268 	while (!(sc->sc_flags & IWH_F_PUT_SEG)) {
2269 		if (cv_timedwait(&sc->sc_put_seg_cv, &sc->sc_glock, clk) < 0) {
2270 			break;
2271 		}
2272 	}
2273 
2274 	if (!(sc->sc_flags & IWH_F_PUT_SEG)) {
2275 		cmn_err(CE_WARN, "iwh_load_run_firmware(): "
2276 		    "timeout waiting for run_data uCode load.\n");
2277 		return (IWH_FAIL);
2278 	}
2279 
2280 	atomic_and_32(&sc->sc_flags, ~IWH_F_PUT_SEG);
2281 
2282 	return (err);
2283 }
2284 
2285 /*
2286  * this function will be invoked to receive phy information
2287  * when a frame is received.
2288  */
2289 static void
2290 iwh_rx_phy_intr(iwh_sc_t *sc, iwh_rx_desc_t *desc)
2291 {
2292 
2293 	sc->sc_rx_phy_res.flag = 1;
2294 
2295 	bcopy((uint8_t *)(desc + 1), sc->sc_rx_phy_res.buf,
2296 	    sizeof (iwh_rx_phy_res_t));
2297 }
2298 
2299 /*
2300  * this function will be invoked to receive body of frame when
2301  * a frame is received.
2302  */
2303 static void
2304 iwh_rx_mpdu_intr(iwh_sc_t *sc, iwh_rx_desc_t *desc)
2305 {
2306 	ieee80211com_t *ic = &sc->sc_ic;
2307 #ifdef	DEBUG
2308 	iwh_rx_ring_t *ring = &sc->sc_rxq;
2309 #endif
2310 	struct ieee80211_frame *wh;
2311 	struct iwh_rx_non_cfg_phy *phyinfo;
2312 	struct iwh_rx_mpdu_body_size *mpdu_size;
2313 	mblk_t *mp;
2314 	int16_t t;
2315 	uint16_t len, rssi, agc;
2316 	uint32_t temp, crc, *tail;
2317 	uint32_t arssi, brssi, crssi, mrssi;
2318 	iwh_rx_phy_res_t *stat;
2319 	ieee80211_node_t *in;
2320 
2321 	/*
2322 	 * assuming not 11n here. cope with 11n in phase-II
2323 	 */
2324 	mpdu_size = (struct iwh_rx_mpdu_body_size *)(desc + 1);
2325 	stat = (iwh_rx_phy_res_t *)sc->sc_rx_phy_res.buf;
2326 	if (stat->cfg_phy_cnt > 20) {
2327 		return;
2328 	}
2329 
2330 	phyinfo = (struct iwh_rx_non_cfg_phy *)stat->non_cfg_phy;
2331 	temp = LE_32(phyinfo->non_cfg_phy[IWH_RX_RES_AGC_IDX]);
2332 	agc = (temp & IWH_OFDM_AGC_MSK) >> IWH_OFDM_AGC_BIT_POS;
2333 
2334 	temp = LE_32(phyinfo->non_cfg_phy[IWH_RX_RES_RSSI_AB_IDX]);
2335 	arssi = (temp & IWH_OFDM_RSSI_A_MSK) >> IWH_OFDM_RSSI_A_BIT_POS;
2336 	brssi = (temp & IWH_OFDM_RSSI_B_MSK) >> IWH_OFDM_RSSI_B_BIT_POS;
2337 
2338 	temp = LE_32(phyinfo->non_cfg_phy[IWH_RX_RES_RSSI_C_IDX]);
2339 	crssi = (temp & IWH_OFDM_RSSI_C_MSK) >> IWH_OFDM_RSSI_C_BIT_POS;
2340 
2341 	mrssi = MAX(arssi, brssi);
2342 	mrssi = MAX(mrssi, crssi);
2343 
2344 	t = mrssi - agc - IWH_RSSI_OFFSET;
2345 	/*
2346 	 * convert dBm to percentage
2347 	 */
2348 	rssi = (100 * 75 * 75 - (-20 - t) * (15 * 75 + 62 * (-20 - t)))
2349 	    / (75 * 75);
2350 	if (rssi > 100) {
2351 		rssi = 100;
2352 	}
2353 	if (rssi < 1) {
2354 		rssi = 1;
2355 	}
2356 
2357 	/*
2358 	 * size of frame, not include FCS
2359 	 */
2360 	len = LE_16(mpdu_size->byte_count);
2361 	tail = (uint32_t *)((uint8_t *)(desc + 1) +
2362 	    sizeof (struct iwh_rx_mpdu_body_size) + len);
2363 	bcopy(tail, &crc, 4);
2364 
2365 	IWH_DBG((IWH_DEBUG_RX, "iwh_rx_mpdu_intr(): "
2366 	    "rx intr: idx=%d phy_len=%x len=%d "
2367 	    "rate=%x chan=%d tstamp=%x non_cfg_phy_count=%x "
2368 	    "cfg_phy_count=%x tail=%x", ring->cur, sizeof (*stat),
2369 	    len, stat->rate.r.s.rate, stat->channel,
2370 	    LE_32(stat->timestampl), stat->non_cfg_phy_cnt,
2371 	    stat->cfg_phy_cnt, LE_32(crc)));
2372 
2373 	if ((len < 16) || (len > sc->sc_dmabuf_sz)) {
2374 		IWH_DBG((IWH_DEBUG_RX, "iwh_rx_mpdu_intr(): "
2375 		    "rx frame oversize\n"));
2376 		return;
2377 	}
2378 
2379 	/*
2380 	 * discard Rx frames with bad CRC
2381 	 */
2382 	if ((LE_32(crc) &
2383 	    (RX_RES_STATUS_NO_CRC32_ERROR | RX_RES_STATUS_NO_RXE_OVERFLOW)) !=
2384 	    (RX_RES_STATUS_NO_CRC32_ERROR | RX_RES_STATUS_NO_RXE_OVERFLOW)) {
2385 		IWH_DBG((IWH_DEBUG_RX, "iwh_rx_mpdu_intr(): "
2386 		    "rx crc error tail: %x\n",
2387 		    LE_32(crc)));
2388 		sc->sc_rx_err++;
2389 		return;
2390 	}
2391 
2392 	wh = (struct ieee80211_frame *)
2393 	    ((uint8_t *)(desc + 1)+ sizeof (struct iwh_rx_mpdu_body_size));
2394 
2395 	if (IEEE80211_FC0_SUBTYPE_ASSOC_RESP == *(uint8_t *)wh) {
2396 		sc->sc_assoc_id = *((uint16_t *)(wh + 1) + 2);
2397 		IWH_DBG((IWH_DEBUG_RX, "iwh_rx_mpdu_intr(): "
2398 		    "rx : association id = %x\n",
2399 		    sc->sc_assoc_id));
2400 	}
2401 
2402 #ifdef DEBUG
2403 	if (iwh_dbg_flags & IWH_DEBUG_RX) {
2404 		ieee80211_dump_pkt((uint8_t *)wh, len, 0, 0);
2405 	}
2406 #endif
2407 
2408 	in = ieee80211_find_rxnode(ic, wh);
2409 	mp = allocb(len, BPRI_MED);
2410 	if (mp) {
2411 		bcopy(wh, mp->b_wptr, len);
2412 		mp->b_wptr += len;
2413 
2414 		/*
2415 		 * send the frame to the 802.11 layer
2416 		 */
2417 		(void) ieee80211_input(ic, mp, in, rssi, 0);
2418 	} else {
2419 		sc->sc_rx_nobuf++;
2420 		IWH_DBG((IWH_DEBUG_RX, "iwh_rx_mpdu_intr(): "
2421 		    "alloc rx buf failed\n"));
2422 	}
2423 
2424 	/*
2425 	 * release node reference
2426 	 */
2427 	ieee80211_free_node(in);
2428 }
2429 
2430 /*
2431  * process correlative affairs after a frame is sent.
2432  */
2433 static void
2434 iwh_tx_intr(iwh_sc_t *sc, iwh_rx_desc_t *desc)
2435 {
2436 	ieee80211com_t *ic = &sc->sc_ic;
2437 	iwh_tx_ring_t *ring = &sc->sc_txq[desc->hdr.qid & 0x3];
2438 	iwh_tx_stat_t *stat = (iwh_tx_stat_t *)(desc + 1);
2439 	iwh_amrr_t *amrr;
2440 
2441 	if (NULL == ic->ic_bss) {
2442 		return;
2443 	}
2444 
2445 	amrr = (iwh_amrr_t *)ic->ic_bss;
2446 
2447 	amrr->txcnt++;
2448 	IWH_DBG((IWH_DEBUG_RATECTL, "iwh_tx_intr(): "
2449 	    "tx: %d cnt\n", amrr->txcnt));
2450 
2451 	if (stat->ntries > 0) {
2452 		amrr->retrycnt++;
2453 		sc->sc_tx_retries++;
2454 		IWH_DBG((IWH_DEBUG_TX, "iwh_tx_intr(): "
2455 		    "tx: %d retries\n",
2456 		    sc->sc_tx_retries));
2457 	}
2458 
2459 	mutex_enter(&sc->sc_mt_lock);
2460 	sc->sc_tx_timer = 0;
2461 	mutex_exit(&sc->sc_mt_lock);
2462 
2463 	mutex_enter(&sc->sc_tx_lock);
2464 
2465 	ring->queued--;
2466 	if (ring->queued < 0) {
2467 		ring->queued = 0;
2468 	}
2469 
2470 	if ((sc->sc_need_reschedule) && (ring->queued <= (ring->count >> 3))) {
2471 		sc->sc_need_reschedule = 0;
2472 		mutex_exit(&sc->sc_tx_lock);
2473 		mac_tx_update(ic->ic_mach);
2474 		mutex_enter(&sc->sc_tx_lock);
2475 	}
2476 
2477 	mutex_exit(&sc->sc_tx_lock);
2478 }
2479 
2480 /*
2481  * inform a given command has been executed
2482  */
2483 static void
2484 iwh_cmd_intr(iwh_sc_t *sc, iwh_rx_desc_t *desc)
2485 {
2486 	if ((desc->hdr.qid & 7) != 4) {
2487 		return;
2488 	}
2489 
2490 	if (sc->sc_cmd_accum > 0) {
2491 		sc->sc_cmd_accum--;
2492 		return;
2493 	}
2494 
2495 	mutex_enter(&sc->sc_glock);
2496 
2497 	sc->sc_cmd_flag = SC_CMD_FLG_DONE;
2498 
2499 	cv_signal(&sc->sc_cmd_cv);
2500 
2501 	mutex_exit(&sc->sc_glock);
2502 
2503 	IWH_DBG((IWH_DEBUG_CMD, "iwh_cmd_intr(): "
2504 	    "qid=%x idx=%d flags=%x type=0x%x\n",
2505 	    desc->hdr.qid, desc->hdr.idx, desc->hdr.flags,
2506 	    desc->hdr.type));
2507 }
2508 
2509 /*
2510  * this function will be invoked when alive notification occur.
2511  */
2512 static void
2513 iwh_ucode_alive(iwh_sc_t *sc, iwh_rx_desc_t *desc)
2514 {
2515 	uint32_t rv;
2516 	struct iwh_calib_cfg_cmd cmd;
2517 	struct iwh_alive_resp *ar =
2518 	    (struct iwh_alive_resp *)(desc + 1);
2519 	struct iwh_calib_results *res_p = &sc->sc_calib_results;
2520 
2521 	/*
2522 	 * the microcontroller is ready
2523 	 */
2524 	IWH_DBG((IWH_DEBUG_FW, "iwh_ucode_alive(): "
2525 	    "microcode alive notification minor: %x major: %x type: "
2526 	    "%x subtype: %x\n",
2527 	    ar->ucode_minor, ar->ucode_minor, ar->ver_type, ar->ver_subtype));
2528 
2529 #ifdef	DEBUG
2530 	if (LE_32(ar->is_valid) != UCODE_VALID_OK) {
2531 		IWH_DBG((IWH_DEBUG_FW, "iwh_ucode_alive(): "
2532 		    "microcontroller initialization failed\n"));
2533 	}
2534 #endif
2535 
2536 	/*
2537 	 * determine if init alive or runtime alive.
2538 	 */
2539 	if (INITIALIZE_SUBTYPE == ar->ver_subtype) {
2540 		IWH_DBG((IWH_DEBUG_FW, "iwh_ucode_alive(): "
2541 		    "initialization alive received.\n"));
2542 
2543 		bcopy(ar, &sc->sc_card_alive_init,
2544 		    sizeof (struct iwh_init_alive_resp));
2545 
2546 		/*
2547 		 * necessary configuration to NIC
2548 		 */
2549 		mutex_enter(&sc->sc_glock);
2550 
2551 		rv = iwh_alive_common(sc);
2552 		if (rv != IWH_SUCCESS) {
2553 			cmn_err(CE_WARN, "iwh_ucode_alive(): "
2554 			    "common alive process failed in init alive.\n");
2555 			mutex_exit(&sc->sc_glock);
2556 			return;
2557 		}
2558 
2559 		(void) memset(&cmd, 0, sizeof (cmd));
2560 
2561 		cmd.ucd_calib_cfg.once.is_enable = IWH_CALIB_INIT_CFG_ALL;
2562 		cmd.ucd_calib_cfg.once.start = IWH_CALIB_INIT_CFG_ALL;
2563 		cmd.ucd_calib_cfg.once.send_res = IWH_CALIB_INIT_CFG_ALL;
2564 		cmd.ucd_calib_cfg.flags = IWH_CALIB_INIT_CFG_ALL;
2565 
2566 		/*
2567 		 * require ucode execute calibration
2568 		 */
2569 		rv = iwh_cmd(sc, CALIBRATION_CFG_CMD, &cmd, sizeof (cmd), 1);
2570 		if (rv != IWH_SUCCESS) {
2571 			cmn_err(CE_WARN, "iwh_ucode_alive(): "
2572 			    "failed to send calibration configure command.\n");
2573 			mutex_exit(&sc->sc_glock);
2574 			return;
2575 		}
2576 
2577 		mutex_exit(&sc->sc_glock);
2578 
2579 	} else {	/* runtime alive */
2580 
2581 		IWH_DBG((IWH_DEBUG_FW, "iwh_ucode_alive(): "
2582 		    "runtime alive received.\n"));
2583 
2584 		bcopy(ar, &sc->sc_card_alive_run,
2585 		    sizeof (struct iwh_alive_resp));
2586 
2587 		mutex_enter(&sc->sc_glock);
2588 
2589 		/*
2590 		 * necessary configuration to NIC
2591 		 */
2592 		rv = iwh_alive_common(sc);
2593 		if (rv != IWH_SUCCESS) {
2594 			cmn_err(CE_WARN, "iwh_ucode_alive(): "
2595 			    "common alive process failed in run alive.\n");
2596 			mutex_exit(&sc->sc_glock);
2597 			return;
2598 		}
2599 
2600 		/*
2601 		 * send the result of local oscilator calibration to uCode.
2602 		 */
2603 		if (res_p->lo_res != NULL) {
2604 			rv = iwh_cmd(sc, REPLY_PHY_CALIBRATION_CMD,
2605 			    res_p->lo_res, res_p->lo_res_len, 1);
2606 			if (rv != IWH_SUCCESS) {
2607 				cmn_err(CE_WARN, "iwh_ucode_alive(): "
2608 				    "failed to send local"
2609 				    "oscilator calibration command.\n");
2610 				mutex_exit(&sc->sc_glock);
2611 				return;
2612 			}
2613 
2614 			DELAY(1000);
2615 		}
2616 
2617 		/*
2618 		 * send the result of TX IQ calibration to uCode.
2619 		 */
2620 		if (res_p->tx_iq_res != NULL) {
2621 			rv = iwh_cmd(sc, REPLY_PHY_CALIBRATION_CMD,
2622 			    res_p->tx_iq_res, res_p->tx_iq_res_len, 1);
2623 			if (rv != IWH_SUCCESS) {
2624 				cmn_err(CE_WARN, "iwh_ucode_alive(): "
2625 				    "failed to send TX IQ"
2626 				    "calibration command.\n");
2627 				mutex_exit(&sc->sc_glock);
2628 				return;
2629 			}
2630 
2631 			DELAY(1000);
2632 		}
2633 
2634 		/*
2635 		 * sned the result of TX IQ perd calibration to uCode.
2636 		 */
2637 		if (res_p->tx_iq_perd_res != NULL) {
2638 			rv = iwh_cmd(sc, REPLY_PHY_CALIBRATION_CMD,
2639 			    res_p->tx_iq_perd_res,
2640 			    res_p->tx_iq_perd_res_len, 1);
2641 			if (rv != IWH_SUCCESS) {
2642 				cmn_err(CE_WARN, "iwh_ucode_alive(): "
2643 				    "failed to send TX IQ perd"
2644 				    "calibration command.\n");
2645 				mutex_exit(&sc->sc_glock);
2646 				return;
2647 			}
2648 
2649 			DELAY(1000);
2650 		}
2651 
2652 		/*
2653 		 * send the result of DC calibration to uCode.
2654 		 */
2655 		if (res_p->dc_res != NULL) {
2656 			rv = iwh_cmd(sc, REPLY_PHY_CALIBRATION_CMD,
2657 			    res_p->dc_res,
2658 			    res_p->dc_res_len, 1);
2659 			if (rv != IWH_SUCCESS) {
2660 				cmn_err(CE_WARN, "iwh_ucode_alive(): "
2661 				    "failed to send DC"
2662 				    "calibration command.\n");
2663 				mutex_exit(&sc->sc_glock);
2664 				return;
2665 			}
2666 
2667 			DELAY(1000);
2668 		}
2669 
2670 		/*
2671 		 * send the result of BASE BAND calibration to uCode.
2672 		 */
2673 		if (res_p->base_band_res != NULL) {
2674 			rv = iwh_cmd(sc, REPLY_PHY_CALIBRATION_CMD,
2675 			    res_p->base_band_res,
2676 			    res_p->base_band_res_len, 1);
2677 			if (rv != IWH_SUCCESS) {
2678 				cmn_err(CE_WARN, "iwh_ucode_alive(): "
2679 				    "failed to send BASE BAND"
2680 				    "calibration command.\n");
2681 				mutex_exit(&sc->sc_glock);
2682 				return;
2683 			}
2684 
2685 			DELAY(1000);
2686 		}
2687 
2688 		atomic_or_32(&sc->sc_flags, IWH_F_FW_INIT);
2689 		cv_signal(&sc->sc_ucode_cv);
2690 
2691 		mutex_exit(&sc->sc_glock);
2692 	}
2693 
2694 }
2695 
2696 /*
2697  * deal with receiving frames, command response
2698  * and all notifications from ucode.
2699  */
2700 /* ARGSUSED */
2701 static uint_t
2702 iwh_rx_softintr(caddr_t arg, caddr_t unused)
2703 {
2704 	iwh_sc_t *sc;
2705 	ieee80211com_t *ic;
2706 	iwh_rx_desc_t *desc;
2707 	iwh_rx_data_t *data;
2708 	uint32_t index;
2709 
2710 	if (NULL == arg) {
2711 		return (DDI_INTR_UNCLAIMED);
2712 	}
2713 	sc = (iwh_sc_t *)arg;
2714 	ic = &sc->sc_ic;
2715 
2716 	/*
2717 	 * firmware has moved the index of the rx queue, driver get it,
2718 	 * and deal with it.
2719 	 */
2720 	index = (sc->sc_shared->val0) & 0xfff;
2721 
2722 	while (sc->sc_rxq.cur != index) {
2723 		data = &sc->sc_rxq.data[sc->sc_rxq.cur];
2724 		desc = (iwh_rx_desc_t *)data->dma_data.mem_va;
2725 
2726 		IWH_DBG((IWH_DEBUG_INTR, "iwh_rx_softintr(): "
2727 		    "rx notification index = %d"
2728 		    " cur = %d qid=%x idx=%d flags=%x type=%x len=%d\n",
2729 		    index, sc->sc_rxq.cur, desc->hdr.qid, desc->hdr.idx,
2730 		    desc->hdr.flags, desc->hdr.type, LE_32(desc->len)));
2731 
2732 		/*
2733 		 * a command other than a tx need to be replied
2734 		 */
2735 		if (!(desc->hdr.qid & 0x80) &&
2736 		    (desc->hdr.type != REPLY_SCAN_CMD) &&
2737 		    (desc->hdr.type != REPLY_TX)) {
2738 			iwh_cmd_intr(sc, desc);
2739 		}
2740 
2741 		switch (desc->hdr.type) {
2742 		case REPLY_RX_PHY_CMD:
2743 			iwh_rx_phy_intr(sc, desc);
2744 			break;
2745 
2746 		case REPLY_RX_MPDU_CMD:
2747 			iwh_rx_mpdu_intr(sc, desc);
2748 			break;
2749 
2750 		case REPLY_TX:
2751 			iwh_tx_intr(sc, desc);
2752 			break;
2753 
2754 		case REPLY_ALIVE:
2755 			iwh_ucode_alive(sc, desc);
2756 			break;
2757 
2758 		case CARD_STATE_NOTIFICATION:
2759 		{
2760 			uint32_t *status = (uint32_t *)(desc + 1);
2761 
2762 			IWH_DBG((IWH_DEBUG_RADIO, "iwh_rx_softintr(): "
2763 			    "state changed to %x\n",
2764 			    LE_32(*status)));
2765 
2766 			if (LE_32(*status) & 1) {
2767 				/*
2768 				 * the radio button has to be pushed(OFF). It
2769 				 * is considered as a hw error, the
2770 				 * iwh_thread() tries to recover it after the
2771 				 * button is pushed again(ON)
2772 				 */
2773 				cmn_err(CE_NOTE, "iwh_rx_softintr(): "
2774 				    "radio transmitter is off\n");
2775 				sc->sc_ostate = sc->sc_ic.ic_state;
2776 				ieee80211_new_state(&sc->sc_ic,
2777 				    IEEE80211_S_INIT, -1);
2778 				atomic_or_32(&sc->sc_flags,
2779 				    (IWH_F_HW_ERR_RECOVER | IWH_F_RADIO_OFF));
2780 			}
2781 
2782 			break;
2783 		}
2784 
2785 		case SCAN_START_NOTIFICATION:
2786 		{
2787 			iwh_start_scan_t *scan =
2788 			    (iwh_start_scan_t *)(desc + 1);
2789 
2790 			IWH_DBG((IWH_DEBUG_SCAN, "iwh_rx_softintr(): "
2791 			    "scanning channel %d status %x\n",
2792 			    scan->chan, LE_32(scan->status)));
2793 
2794 			ic->ic_curchan = &ic->ic_sup_channels[scan->chan];
2795 			break;
2796 		}
2797 
2798 		case SCAN_COMPLETE_NOTIFICATION:
2799 		{
2800 #ifdef	DEBUG
2801 			iwh_stop_scan_t *scan =
2802 			    (iwh_stop_scan_t *)(desc + 1);
2803 
2804 			IWH_DBG((IWH_DEBUG_SCAN, "iwh_rx_softintr(): "
2805 			    "completed channel %d (burst of %d) status %02x\n",
2806 			    scan->chan, scan->nchan, scan->status));
2807 #endif
2808 
2809 			sc->sc_scan_pending++;
2810 			break;
2811 		}
2812 
2813 		case STATISTICS_NOTIFICATION:
2814 		{
2815 			/*
2816 			 * handle statistics notification
2817 			 */
2818 			break;
2819 		}
2820 
2821 		case CALIBRATION_RES_NOTIFICATION:
2822 			iwh_save_calib_result(sc, desc);
2823 			break;
2824 
2825 		case CALIBRATION_COMPLETE_NOTIFICATION:
2826 			mutex_enter(&sc->sc_glock);
2827 			atomic_or_32(&sc->sc_flags, IWH_F_FW_INIT);
2828 			cv_signal(&sc->sc_ucode_cv);
2829 			mutex_exit(&sc->sc_glock);
2830 			break;
2831 
2832 		case MISSED_BEACONS_NOTIFICATION:
2833 			/* handle beacon miss by software mechanism */
2834 			break;
2835 		}
2836 
2837 		sc->sc_rxq.cur = (sc->sc_rxq.cur + 1) % RX_QUEUE_SIZE;
2838 	}
2839 
2840 	/*
2841 	 * driver dealt with what received in rx queue and tell the information
2842 	 * to the firmware.
2843 	 */
2844 	index = (0 == index) ? RX_QUEUE_SIZE - 1 : index - 1;
2845 	IWH_WRITE(sc, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, index & (~7));
2846 
2847 	/*
2848 	 * re-enable interrupts
2849 	 */
2850 	IWH_WRITE(sc, CSR_INT_MASK, CSR_INI_SET_MASK);
2851 
2852 	return (DDI_INTR_CLAIMED);
2853 }
2854 
2855 /*
2856  * the handle of interrupt
2857  */
2858 /* ARGSUSED */
2859 static uint_t
2860 iwh_intr(caddr_t arg, caddr_t unused)
2861 {
2862 	iwh_sc_t *sc;
2863 	uint32_t r, rfh;
2864 
2865 	if (NULL == arg) {
2866 		return (DDI_INTR_UNCLAIMED);
2867 	}
2868 	sc = (iwh_sc_t *)arg;
2869 
2870 	r = IWH_READ(sc, CSR_INT);
2871 	if (0 == r || 0xffffffff == r) {
2872 		return (DDI_INTR_UNCLAIMED);
2873 	}
2874 
2875 	IWH_DBG((IWH_DEBUG_INTR, "iwh_intr(): "
2876 	    "interrupt reg %x\n", r));
2877 
2878 	rfh = IWH_READ(sc, CSR_FH_INT_STATUS);
2879 
2880 	IWH_DBG((IWH_DEBUG_INTR, "iwh_intr(): "
2881 	    "FH interrupt reg %x\n", rfh));
2882 
2883 	/*
2884 	 * disable interrupts
2885 	 */
2886 	IWH_WRITE(sc, CSR_INT_MASK, 0);
2887 
2888 	/*
2889 	 * ack interrupts
2890 	 */
2891 	IWH_WRITE(sc, CSR_INT, r);
2892 	IWH_WRITE(sc, CSR_FH_INT_STATUS, rfh);
2893 
2894 	if (r & (BIT_INT_SWERROR | BIT_INT_ERR)) {
2895 		IWH_DBG((IWH_DEBUG_FW, "iwh_intr(): "
2896 		    "fatal firmware error\n"));
2897 		iwh_stop(sc);
2898 		sc->sc_ostate = sc->sc_ic.ic_state;
2899 
2900 		/*
2901 		 * notify upper layer
2902 		 */
2903 		if (!IWH_CHK_FAST_RECOVER(sc)) {
2904 			ieee80211_new_state(&sc->sc_ic, IEEE80211_S_INIT, -1);
2905 		}
2906 
2907 		atomic_or_32(&sc->sc_flags, IWH_F_HW_ERR_RECOVER);
2908 		return (DDI_INTR_CLAIMED);
2909 	}
2910 
2911 	if (r & BIT_INT_RF_KILL) {
2912 		uint32_t tmp = IWH_READ(sc, CSR_GP_CNTRL);
2913 		if (tmp & (1 << 27)) {
2914 			cmn_err(CE_NOTE, "RF switch: radio on\n");
2915 		}
2916 	}
2917 
2918 	if ((r & (BIT_INT_FH_RX | BIT_INT_SW_RX)) ||
2919 	    (rfh & FH_INT_RX_MASK)) {
2920 		(void) ddi_intr_trigger_softint(sc->sc_soft_hdl, NULL);
2921 		return (DDI_INTR_CLAIMED);
2922 	}
2923 
2924 	if (r & BIT_INT_FH_TX) {
2925 		mutex_enter(&sc->sc_glock);
2926 		atomic_or_32(&sc->sc_flags, IWH_F_PUT_SEG);
2927 		cv_signal(&sc->sc_put_seg_cv);
2928 		mutex_exit(&sc->sc_glock);
2929 	}
2930 
2931 #ifdef	DEBUG
2932 	if (r & BIT_INT_ALIVE)	{
2933 		IWH_DBG((IWH_DEBUG_FW, "iwh_intr(): "
2934 		    "firmware initialized.\n"));
2935 	}
2936 #endif
2937 
2938 	/*
2939 	 * re-enable interrupts
2940 	 */
2941 	IWH_WRITE(sc, CSR_INT_MASK, CSR_INI_SET_MASK);
2942 
2943 	return (DDI_INTR_CLAIMED);
2944 }
2945 
2946 static uint8_t
2947 iwh_rate_to_plcp(int rate)
2948 {
2949 	uint8_t ret;
2950 
2951 	switch (rate) {
2952 	/*
2953 	 * CCK rates
2954 	 */
2955 	case 2:
2956 		ret = 0xa;
2957 		break;
2958 
2959 	case 4:
2960 		ret = 0x14;
2961 		break;
2962 
2963 	case 11:
2964 		ret = 0x37;
2965 		break;
2966 
2967 	case 22:
2968 		ret = 0x6e;
2969 		break;
2970 
2971 	/*
2972 	 * OFDM rates
2973 	 */
2974 	case 12:
2975 		ret = 0xd;
2976 		break;
2977 
2978 	case 18:
2979 		ret = 0xf;
2980 		break;
2981 
2982 	case 24:
2983 		ret = 0x5;
2984 		break;
2985 
2986 	case 36:
2987 		ret = 0x7;
2988 		break;
2989 
2990 	case 48:
2991 		ret = 0x9;
2992 		break;
2993 
2994 	case 72:
2995 		ret = 0xb;
2996 		break;
2997 
2998 	case 96:
2999 		ret = 0x1;
3000 		break;
3001 
3002 	case 108:
3003 		ret = 0x3;
3004 		break;
3005 
3006 	default:
3007 		ret = 0;
3008 		break;
3009 	}
3010 
3011 	return (ret);
3012 }
3013 
3014 /*
3015  * invoked by GLD send frames
3016  */
3017 static mblk_t *
3018 iwh_m_tx(void *arg, mblk_t *mp)
3019 {
3020 	iwh_sc_t *sc;
3021 	ieee80211com_t *ic;
3022 	mblk_t *next;
3023 
3024 	if (NULL == arg) {
3025 		return (NULL);
3026 	}
3027 	sc = (iwh_sc_t *)arg;
3028 	ic = &sc->sc_ic;
3029 
3030 	if (sc->sc_flags & IWH_F_SUSPEND) {
3031 		freemsgchain(mp);
3032 		return (NULL);
3033 	}
3034 
3035 	if (ic->ic_state != IEEE80211_S_RUN) {
3036 		freemsgchain(mp);
3037 		return (NULL);
3038 	}
3039 
3040 	if ((sc->sc_flags & IWH_F_HW_ERR_RECOVER) &&
3041 	    IWH_CHK_FAST_RECOVER(sc)) {
3042 		IWH_DBG((IWH_DEBUG_FW, "iwh_m_tx(): "
3043 		    "hold queue\n"));
3044 		return (mp);
3045 	}
3046 
3047 	while (mp != NULL) {
3048 		next = mp->b_next;
3049 		mp->b_next = NULL;
3050 		if (iwh_send(ic, mp, IEEE80211_FC0_TYPE_DATA) != 0) {
3051 			mp->b_next = next;
3052 			break;
3053 		}
3054 		mp = next;
3055 	}
3056 
3057 	return (mp);
3058 }
3059 
3060 /*
3061  * send frames
3062  */
3063 static int
3064 iwh_send(ieee80211com_t *ic, mblk_t *mp, uint8_t type)
3065 {
3066 	iwh_sc_t *sc;
3067 	iwh_tx_ring_t *ring;
3068 	iwh_tx_desc_t *desc;
3069 	iwh_tx_data_t *data;
3070 	iwh_tx_data_t *desc_data;
3071 	iwh_cmd_t *cmd;
3072 	iwh_tx_cmd_t *tx;
3073 	ieee80211_node_t *in;
3074 	struct ieee80211_frame *wh, *mp_wh;
3075 	struct ieee80211_key *k = NULL;
3076 	mblk_t *m, *m0;
3077 	int hdrlen, len, len0, mblen, off, err = IWH_SUCCESS;
3078 	uint16_t masks = 0;
3079 	uint32_t rate, s_id = 0;
3080 	int txq_id = NON_QOS_TXQ;
3081 	struct ieee80211_qosframe *qwh = NULL;
3082 	int tid = WME_TID_INVALID;
3083 
3084 	if (NULL == ic) {
3085 		return (IWH_FAIL);
3086 	}
3087 	sc = (iwh_sc_t *)ic;
3088 
3089 	if (sc->sc_flags & IWH_F_SUSPEND) {
3090 		if ((type & IEEE80211_FC0_TYPE_MASK) !=
3091 		    IEEE80211_FC0_TYPE_DATA) {
3092 			freemsg(mp);
3093 		}
3094 		err = IWH_FAIL;
3095 		goto exit;
3096 	}
3097 
3098 	if ((NULL == mp) || (MBLKL(mp) <= 0)) {
3099 		return (IWH_FAIL);
3100 	}
3101 
3102 	mp_wh = (struct ieee80211_frame *)mp->b_rptr;
3103 
3104 	/*
3105 	 * Determine send which AP or station in IBSS
3106 	 */
3107 	in = ieee80211_find_txnode(ic, mp_wh->i_addr1);
3108 	if (NULL == in) {
3109 		cmn_err(CE_WARN, "iwh_send(): "
3110 		    "failed to find tx node\n");
3111 		freemsg(mp);
3112 		sc->sc_tx_err++;
3113 		err = IWH_SUCCESS;
3114 		goto exit;
3115 	}
3116 
3117 	/*
3118 	 * Determine TX queue according to traffic ID in frame
3119 	 * if working in QoS mode.
3120 	 */
3121 	if (in->in_flags & IEEE80211_NODE_QOS) {
3122 
3123 		if ((type & IEEE80211_FC0_TYPE_MASK) ==
3124 		    IEEE80211_FC0_TYPE_DATA) {
3125 
3126 			if (mp_wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_QOS) {
3127 				qwh = (struct ieee80211_qosframe *)mp_wh;
3128 
3129 				tid = qwh->i_qos[0] & IEEE80211_QOS_TID;
3130 				txq_id = iwh_wme_tid_to_txq(tid);
3131 
3132 				if (txq_id < TXQ_FOR_AC_MIN ||
3133 				    (txq_id > TXQ_FOR_AC_MAX)) {
3134 					freemsg(mp);
3135 					sc->sc_tx_err++;
3136 					err = IWH_SUCCESS;
3137 					goto exit;
3138 				}
3139 
3140 			} else {
3141 				txq_id = NON_QOS_TXQ;
3142 			}
3143 
3144 		} else if ((type & IEEE80211_FC0_TYPE_MASK) ==
3145 		    IEEE80211_FC0_TYPE_MGT) {
3146 			txq_id = QOS_TXQ_FOR_MGT;
3147 		} else {
3148 			txq_id = NON_QOS_TXQ;
3149 		}
3150 
3151 	} else {
3152 		txq_id = NON_QOS_TXQ;
3153 	}
3154 
3155 	mutex_enter(&sc->sc_tx_lock);
3156 	ring = &sc->sc_txq[txq_id];
3157 	data = &ring->data[ring->cur];
3158 	cmd = data->cmd;
3159 	bzero(cmd, sizeof (*cmd));
3160 
3161 	ring->cur = (ring->cur + 1) % ring->count;
3162 
3163 	/*
3164 	 * Need reschedule TX if TX buffer is full.
3165 	 */
3166 	if (ring->queued > ring->count - IWH_MAX_WIN_SIZE) {
3167 		IWH_DBG((IWH_DEBUG_TX, "iwh_send(): "
3168 		"no txbuf\n"));
3169 
3170 		sc->sc_need_reschedule = 1;
3171 		mutex_exit(&sc->sc_tx_lock);
3172 
3173 		if ((type & IEEE80211_FC0_TYPE_MASK) !=
3174 		    IEEE80211_FC0_TYPE_DATA) {
3175 			freemsg(mp);
3176 		}
3177 		sc->sc_tx_nobuf++;
3178 		err = IWH_FAIL;
3179 		goto exit;
3180 	}
3181 
3182 	ring->queued++;
3183 
3184 	mutex_exit(&sc->sc_tx_lock);
3185 
3186 	hdrlen = ieee80211_hdrspace(ic, mp->b_rptr);
3187 
3188 	m = allocb(msgdsize(mp) + 32, BPRI_MED);
3189 	if (NULL == m) { /* can not alloc buf, drop this package */
3190 		cmn_err(CE_WARN, "iwh_send(): "
3191 		    "failed to allocate msgbuf\n");
3192 		freemsg(mp);
3193 
3194 		mutex_enter(&sc->sc_tx_lock);
3195 		ring->queued--;
3196 		if ((sc->sc_need_reschedule) && (ring->queued <= 0)) {
3197 			sc->sc_need_reschedule = 0;
3198 			mutex_exit(&sc->sc_tx_lock);
3199 			mac_tx_update(ic->ic_mach);
3200 			mutex_enter(&sc->sc_tx_lock);
3201 		}
3202 		mutex_exit(&sc->sc_tx_lock);
3203 
3204 		err = IWH_SUCCESS;
3205 		goto exit;
3206 	}
3207 
3208 	for (off = 0, m0 = mp; m0 != NULL; m0 = m0->b_cont) {
3209 		mblen = MBLKL(m0);
3210 		bcopy(m0->b_rptr, m->b_rptr + off, mblen);
3211 		off += mblen;
3212 	}
3213 
3214 	m->b_wptr += off;
3215 
3216 	wh = (struct ieee80211_frame *)m->b_rptr;
3217 
3218 	/*
3219 	 * Net80211 module encapsulate outbound data frames.
3220 	 * Add some feilds of 80211 frame.
3221 	 */
3222 	if ((type & IEEE80211_FC0_TYPE_MASK) ==
3223 	    IEEE80211_FC0_TYPE_DATA) {
3224 		(void) ieee80211_encap(ic, m, in);
3225 	}
3226 
3227 	freemsg(mp);
3228 
3229 	cmd->hdr.type = REPLY_TX;
3230 	cmd->hdr.flags = 0;
3231 	cmd->hdr.qid = ring->qid;
3232 
3233 	tx = (iwh_tx_cmd_t *)cmd->data;
3234 	tx->tx_flags = 0;
3235 
3236 	if (IEEE80211_IS_MULTICAST(wh->i_addr1)) {
3237 		tx->tx_flags &= ~(LE_32(TX_CMD_FLG_ACK_MSK));
3238 	} else {
3239 		tx->tx_flags |= LE_32(TX_CMD_FLG_ACK_MSK);
3240 	}
3241 
3242 	if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
3243 		k = ieee80211_crypto_encap(ic, m);
3244 		if (NULL == k) {
3245 			freemsg(m);
3246 			sc->sc_tx_err++;
3247 
3248 			mutex_enter(&sc->sc_tx_lock);
3249 			ring->queued--;
3250 			if ((sc->sc_need_reschedule) && (ring->queued <= 0)) {
3251 				sc->sc_need_reschedule = 0;
3252 				mutex_exit(&sc->sc_tx_lock);
3253 				mac_tx_update(ic->ic_mach);
3254 				mutex_enter(&sc->sc_tx_lock);
3255 			}
3256 			mutex_exit(&sc->sc_tx_lock);
3257 
3258 			err = IWH_SUCCESS;
3259 			goto exit;
3260 		}
3261 
3262 		/*
3263 		 * packet header may have moved, reset our local pointer
3264 		 */
3265 		wh = (struct ieee80211_frame *)m->b_rptr;
3266 	}
3267 
3268 	len = msgdsize(m);
3269 
3270 #ifdef DEBUG
3271 	if (iwh_dbg_flags & IWH_DEBUG_TX) {
3272 		ieee80211_dump_pkt((uint8_t *)wh, hdrlen, 0, 0);
3273 	}
3274 #endif
3275 
3276 	tx->rts_retry_limit = IWH_TX_RTS_RETRY_LIMIT;
3277 	tx->data_retry_limit = IWH_TX_DATA_RETRY_LIMIT;
3278 
3279 	/*
3280 	 * specific TX parameters for management frames
3281 	 */
3282 	if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
3283 	    IEEE80211_FC0_TYPE_MGT) {
3284 		/*
3285 		 * mgmt frames are sent at 1M
3286 		 */
3287 		if ((in->in_rates.ir_rates[0] &
3288 		    IEEE80211_RATE_VAL) != 0) {
3289 			rate = in->in_rates.ir_rates[0] & IEEE80211_RATE_VAL;
3290 		} else {
3291 			rate = 2;
3292 		}
3293 
3294 		tx->tx_flags |= LE_32(TX_CMD_FLG_SEQ_CTL_MSK);
3295 
3296 		/*
3297 		 * tell h/w to set timestamp in probe responses
3298 		 */
3299 		if ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
3300 		    IEEE80211_FC0_SUBTYPE_PROBE_RESP) {
3301 			tx->tx_flags |= LE_32(TX_CMD_FLG_TSF_MSK);
3302 
3303 			tx->data_retry_limit = 3;
3304 			if (tx->data_retry_limit < tx->rts_retry_limit) {
3305 				tx->rts_retry_limit = tx->data_retry_limit;
3306 			}
3307 		}
3308 
3309 		if (((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
3310 		    IEEE80211_FC0_SUBTYPE_ASSOC_REQ) ||
3311 		    ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
3312 		    IEEE80211_FC0_SUBTYPE_REASSOC_REQ)) {
3313 			tx->timeout.pm_frame_timeout = LE_16(3);
3314 		} else {
3315 			tx->timeout.pm_frame_timeout = LE_16(2);
3316 		}
3317 
3318 	} else {
3319 		/*
3320 		 * do it here for the software way rate scaling.
3321 		 * later for rate scaling in hardware.
3322 		 *
3323 		 * now the txrate is determined in tx cmd flags, set to the
3324 		 * max value 54M for 11g and 11M for 11b and 96M for 11n
3325 		 * originally.
3326 		 */
3327 		if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE) {
3328 			rate = ic->ic_fixed_rate;
3329 		} else {
3330 			if ((in->in_flags & IEEE80211_NODE_HT) &&
3331 			    (sc->sc_ht_conf.ht_support)) {
3332 				iwh_amrr_t *amrr = (iwh_amrr_t *)in;
3333 				rate = amrr->ht_mcs_idx;
3334 			} else {
3335 				if ((in->in_rates.ir_rates[in->in_txrate] &
3336 				    IEEE80211_RATE_VAL) != 0) {
3337 					rate = in->in_rates.
3338 					    ir_rates[in->in_txrate] &
3339 					    IEEE80211_RATE_VAL;
3340 				}
3341 			}
3342 		}
3343 
3344 		if (tid != WME_TID_INVALID) {
3345 			tx->tid_tspec = (uint8_t)tid;
3346 			tx->tx_flags &= LE_32(~TX_CMD_FLG_SEQ_CTL_MSK);
3347 		} else {
3348 			tx->tx_flags |= LE_32(TX_CMD_FLG_SEQ_CTL_MSK);
3349 		}
3350 
3351 		tx->timeout.pm_frame_timeout = 0;
3352 	}
3353 
3354 	IWH_DBG((IWH_DEBUG_TX, "iwh_send(): "
3355 	    "tx rate[%d of %d] = %x",
3356 	    in->in_txrate, in->in_rates.ir_nrates, rate));
3357 
3358 	len0 = roundup(4 + sizeof (iwh_tx_cmd_t) + hdrlen, 4);
3359 	if (len0 != (4 + sizeof (iwh_tx_cmd_t) + hdrlen)) {
3360 		tx->tx_flags |= LE_32(TX_CMD_FLG_MH_PAD_MSK);
3361 	}
3362 
3363 	/*
3364 	 * retrieve destination node's id
3365 	 */
3366 	if (IEEE80211_IS_MULTICAST(wh->i_addr1)) {
3367 		tx->sta_id = IWH_BROADCAST_ID;
3368 	} else {
3369 		tx->sta_id = IWH_AP_ID;
3370 	}
3371 
3372 	if ((in->in_flags & IEEE80211_NODE_HT) &&
3373 	    (sc->sc_ht_conf.ht_support) &&
3374 	    ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
3375 	    IEEE80211_FC0_TYPE_DATA)) {
3376 		if (rate >= HT_2CHAIN_RATE_MIN_IDX) {
3377 			rate |= LE_32(RATE_MCS_ANT_AB_MSK);
3378 		} else {
3379 			rate |= LE_32(RATE_MCS_ANT_B_MSK);
3380 		}
3381 
3382 		rate |= LE_32((1 << RATE_MCS_HT_POS));
3383 
3384 		tx->rate.r.rate_n_flags = rate;
3385 
3386 	} else {
3387 		if (2 == rate || 4 == rate || 11 == rate || 22 == rate) {
3388 			masks |= RATE_MCS_CCK_MSK;
3389 		}
3390 
3391 		masks |= RATE_MCS_ANT_B_MSK;
3392 		tx->rate.r.rate_n_flags = LE_32(iwh_rate_to_plcp(rate) | masks);
3393 	}
3394 
3395 	IWH_DBG((IWH_DEBUG_TX, "iwh_send(): "
3396 	    "tx flag = %x",
3397 	    tx->tx_flags));
3398 
3399 	tx->stop_time.life_time  = LE_32(0xffffffff);
3400 
3401 	tx->len = LE_16(len);
3402 
3403 	tx->dram_lsb_ptr =
3404 	    LE_32(data->paddr_cmd + 4 + offsetof(iwh_tx_cmd_t, scratch));
3405 	tx->dram_msb_ptr = 0;
3406 	tx->driver_txop = 0;
3407 	tx->next_frame_len = 0;
3408 
3409 	bcopy(m->b_rptr, tx + 1, hdrlen);
3410 	m->b_rptr += hdrlen;
3411 	bcopy(m->b_rptr, data->dma_data.mem_va, (len - hdrlen));
3412 
3413 	IWH_DBG((IWH_DEBUG_TX, "iwh_send(): "
3414 	    "sending data: qid=%d idx=%d len=%d",
3415 	    ring->qid, ring->cur, len));
3416 
3417 	/*
3418 	 * first segment includes the tx cmd plus the 802.11 header,
3419 	 * the second includes the remaining of the 802.11 frame.
3420 	 */
3421 
3422 	mutex_enter(&sc->sc_tx_lock);
3423 	cmd->hdr.idx = ring->desc_cur;
3424 	desc_data = &ring->data[ring->desc_cur];
3425 	desc = desc_data->desc;
3426 	bzero(desc, sizeof (*desc));
3427 	desc->val0 = 2 << 24;
3428 	desc->pa[0].tb1_addr = data->paddr_cmd;
3429 	desc->pa[0].val1 = ((len0 << 4) & 0xfff0) |
3430 	    ((data->dma_data.cookie.dmac_address & 0xffff) << 16);
3431 	desc->pa[0].val2 =
3432 	    ((data->dma_data.cookie.dmac_address & 0xffff0000) >> 16) |
3433 	    ((len - hdrlen) << 20);
3434 	IWH_DBG((IWH_DEBUG_TX, "iwh_send(): "
3435 	    "phy addr1 = 0x%x phy addr2 = 0x%x "
3436 	    "len1 = 0x%x, len2 = 0x%x val1 = 0x%x val2 = 0x%x",
3437 	    data->paddr_cmd, data->dma_data.cookie.dmac_address,
3438 	    len0, len - hdrlen, desc->pa[0].val1, desc->pa[0].val2));
3439 
3440 	/*
3441 	 * kick ring
3442 	 */
3443 	s_id = tx->sta_id;
3444 
3445 	sc->sc_shared->queues_byte_cnt_tbls[ring->qid].
3446 	    tfd_offset[ring->desc_cur].val =
3447 	    (8 + len) | (s_id << 12);
3448 	if (ring->desc_cur < IWH_MAX_WIN_SIZE) {
3449 		sc->sc_shared->queues_byte_cnt_tbls[ring->qid].
3450 		    tfd_offset[IWH_QUEUE_SIZE + ring->desc_cur].val =
3451 		    (8 + len) | (s_id << 12);
3452 	}
3453 
3454 	IWH_DMA_SYNC(data->dma_data, DDI_DMA_SYNC_FORDEV);
3455 	IWH_DMA_SYNC(ring->dma_desc, DDI_DMA_SYNC_FORDEV);
3456 
3457 	ring->desc_cur = (ring->desc_cur + 1) % ring->count;
3458 	IWH_WRITE(sc, HBUS_TARG_WRPTR, ring->qid << 8 | ring->desc_cur);
3459 
3460 	mutex_exit(&sc->sc_tx_lock);
3461 	freemsg(m);
3462 
3463 	/*
3464 	 * release node reference
3465 	 */
3466 	ieee80211_free_node(in);
3467 
3468 	ic->ic_stats.is_tx_bytes += len;
3469 	ic->ic_stats.is_tx_frags++;
3470 
3471 	mutex_enter(&sc->sc_mt_lock);
3472 	if (0 == sc->sc_tx_timer) {
3473 		sc->sc_tx_timer = 4;
3474 	}
3475 	mutex_exit(&sc->sc_mt_lock);
3476 
3477 exit:
3478 	return (err);
3479 }
3480 
3481 /*
3482  * invoked by GLD to deal with IOCTL affaires
3483  */
3484 static void
3485 iwh_m_ioctl(void* arg, queue_t *wq, mblk_t *mp)
3486 {
3487 	iwh_sc_t *sc;
3488 	ieee80211com_t *ic;
3489 	int err = EINVAL;
3490 
3491 	if (NULL == arg) {
3492 		return;
3493 	}
3494 	sc = (iwh_sc_t *)arg;
3495 	ic = &sc->sc_ic;
3496 
3497 	err = ieee80211_ioctl(ic, wq, mp);
3498 	if (ENETRESET == err) {
3499 		/*
3500 		 * This is special for the hidden AP connection.
3501 		 * In any case, we should make sure only one 'scan'
3502 		 * in the driver for a 'connect' CLI command. So
3503 		 * when connecting to a hidden AP, the scan is just
3504 		 * sent out to the air when we know the desired
3505 		 * essid of the AP we want to connect.
3506 		 */
3507 		if (ic->ic_des_esslen) {
3508 			if (sc->sc_flags & IWH_F_RUNNING) {
3509 				iwh_m_stop(sc);
3510 				(void) iwh_m_start(sc);
3511 				(void) ieee80211_new_state(ic,
3512 				    IEEE80211_S_SCAN, -1);
3513 			}
3514 		}
3515 	}
3516 }
3517 
3518 /*
3519  * Call back functions for get/set proporty
3520  */
3521 static int
3522 iwh_m_getprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
3523     uint_t pr_flags, uint_t wldp_length, void *wldp_buf, uint_t *perm)
3524 {
3525 	iwh_sc_t *sc;
3526 	int err = EINVAL;
3527 
3528 	if (NULL == arg) {
3529 		return (EINVAL);
3530 	}
3531 	sc = (iwh_sc_t *)arg;
3532 
3533 	err = ieee80211_getprop(&sc->sc_ic, pr_name, wldp_pr_num,
3534 	    pr_flags, wldp_length, wldp_buf, perm);
3535 
3536 	return (err);
3537 }
3538 
3539 static int
3540 iwh_m_setprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
3541     uint_t wldp_length, const void *wldp_buf)
3542 {
3543 	iwh_sc_t *sc;
3544 	ieee80211com_t *ic;
3545 	int err = EINVAL;
3546 
3547 	if (NULL == arg) {
3548 		return (EINVAL);
3549 	}
3550 	sc = (iwh_sc_t *)arg;
3551 	ic = &sc->sc_ic;
3552 
3553 	err = ieee80211_setprop(ic, pr_name, wldp_pr_num, wldp_length,
3554 	    wldp_buf);
3555 
3556 	if (err == ENETRESET) {
3557 		if (ic->ic_des_esslen) {
3558 			if (sc->sc_flags & IWH_F_RUNNING) {
3559 				iwh_m_stop(sc);
3560 				(void) iwh_m_start(sc);
3561 				(void) ieee80211_new_state(ic,
3562 				    IEEE80211_S_SCAN, -1);
3563 			}
3564 		}
3565 		err = 0;
3566 	}
3567 	return (err);
3568 }
3569 
3570 /*
3571  * invoked by GLD supply statistics NIC and driver
3572  */
3573 static int
3574 iwh_m_stat(void *arg, uint_t stat, uint64_t *val)
3575 {
3576 	iwh_sc_t *sc;
3577 	ieee80211com_t *ic;
3578 	ieee80211_node_t *in;
3579 
3580 	if (NULL == arg) {
3581 		return (EINVAL);
3582 	}
3583 	sc = (iwh_sc_t *)arg;
3584 	ic = &sc->sc_ic;
3585 
3586 	mutex_enter(&sc->sc_glock);
3587 
3588 	switch (stat) {
3589 	case MAC_STAT_IFSPEED:
3590 		in = ic->ic_bss;
3591 		*val = ((IEEE80211_FIXED_RATE_NONE == ic->ic_fixed_rate) ?
3592 		    IEEE80211_RATE(in->in_txrate) :
3593 		    ic->ic_fixed_rate) / 2 * 1000000;
3594 		break;
3595 
3596 	case MAC_STAT_NOXMTBUF:
3597 		*val = sc->sc_tx_nobuf;
3598 		break;
3599 
3600 	case MAC_STAT_NORCVBUF:
3601 		*val = sc->sc_rx_nobuf;
3602 		break;
3603 
3604 	case MAC_STAT_IERRORS:
3605 		*val = sc->sc_rx_err;
3606 		break;
3607 
3608 	case MAC_STAT_RBYTES:
3609 		*val = ic->ic_stats.is_rx_bytes;
3610 		break;
3611 
3612 	case MAC_STAT_IPACKETS:
3613 		*val = ic->ic_stats.is_rx_frags;
3614 		break;
3615 
3616 	case MAC_STAT_OBYTES:
3617 		*val = ic->ic_stats.is_tx_bytes;
3618 		break;
3619 
3620 	case MAC_STAT_OPACKETS:
3621 		*val = ic->ic_stats.is_tx_frags;
3622 		break;
3623 
3624 	case MAC_STAT_OERRORS:
3625 	case WIFI_STAT_TX_FAILED:
3626 		*val = sc->sc_tx_err;
3627 		break;
3628 
3629 	case WIFI_STAT_TX_RETRANS:
3630 		*val = sc->sc_tx_retries;
3631 		break;
3632 
3633 	case WIFI_STAT_FCS_ERRORS:
3634 	case WIFI_STAT_WEP_ERRORS:
3635 	case WIFI_STAT_TX_FRAGS:
3636 	case WIFI_STAT_MCAST_TX:
3637 	case WIFI_STAT_RTS_SUCCESS:
3638 	case WIFI_STAT_RTS_FAILURE:
3639 	case WIFI_STAT_ACK_FAILURE:
3640 	case WIFI_STAT_RX_FRAGS:
3641 	case WIFI_STAT_MCAST_RX:
3642 	case WIFI_STAT_RX_DUPS:
3643 		mutex_exit(&sc->sc_glock);
3644 		return (ieee80211_stat(ic, stat, val));
3645 
3646 	default:
3647 		mutex_exit(&sc->sc_glock);
3648 		return (ENOTSUP);
3649 	}
3650 
3651 	mutex_exit(&sc->sc_glock);
3652 
3653 	return (IWH_SUCCESS);
3654 }
3655 
3656 /*
3657  * invoked by GLD to start or open NIC
3658  */
3659 static int
3660 iwh_m_start(void *arg)
3661 {
3662 	iwh_sc_t *sc;
3663 	ieee80211com_t *ic;
3664 	int err = IWH_FAIL;
3665 
3666 	if (NULL == arg) {
3667 		return (EINVAL);
3668 	}
3669 	sc = (iwh_sc_t *)arg;
3670 	ic = &sc->sc_ic;
3671 
3672 	err = iwh_init(sc);
3673 	if (err != IWH_SUCCESS) {
3674 		/*
3675 		 * The hw init err(eg. RF is OFF). Return Success to make
3676 		 * the 'plumb' succeed. The iwh_thread() tries to re-init
3677 		 * background.
3678 		 */
3679 		atomic_or_32(&sc->sc_flags, IWH_F_HW_ERR_RECOVER);
3680 		return (IWH_SUCCESS);
3681 	}
3682 
3683 	ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
3684 
3685 	atomic_or_32(&sc->sc_flags, IWH_F_RUNNING);
3686 
3687 	return (IWH_SUCCESS);
3688 }
3689 
3690 /*
3691  * invoked by GLD to stop or down NIC
3692  */
3693 static void
3694 iwh_m_stop(void *arg)
3695 {
3696 	iwh_sc_t *sc;
3697 	ieee80211com_t *ic;
3698 
3699 	if (NULL == arg) {
3700 		return;
3701 	}
3702 	sc = (iwh_sc_t *)arg;
3703 	ic = &sc->sc_ic;
3704 
3705 	iwh_stop(sc);
3706 
3707 	/*
3708 	 * release buffer for calibration
3709 	 */
3710 	iwh_release_calib_buffer(sc);
3711 
3712 	ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
3713 
3714 	atomic_and_32(&sc->sc_flags, ~IWH_F_HW_ERR_RECOVER);
3715 	atomic_and_32(&sc->sc_flags, ~IWH_F_RATE_AUTO_CTL);
3716 
3717 	atomic_and_32(&sc->sc_flags, ~IWH_F_RUNNING);
3718 	atomic_and_32(&sc->sc_flags, ~IWH_F_SCANNING);
3719 }
3720 
3721 /*
3722  * invoked by GLD to configure NIC
3723  */
3724 static int
3725 iwh_m_unicst(void *arg, const uint8_t *macaddr)
3726 {
3727 	iwh_sc_t *sc;
3728 	ieee80211com_t *ic;
3729 	int err = IWH_SUCCESS;
3730 
3731 	if (NULL == arg) {
3732 		return (EINVAL);
3733 	}
3734 	sc = (iwh_sc_t *)arg;
3735 	ic = &sc->sc_ic;
3736 
3737 	if (!IEEE80211_ADDR_EQ(ic->ic_macaddr, macaddr)) {
3738 		IEEE80211_ADDR_COPY(ic->ic_macaddr, macaddr);
3739 		mutex_enter(&sc->sc_glock);
3740 		err = iwh_config(sc);
3741 		mutex_exit(&sc->sc_glock);
3742 		if (err != IWH_SUCCESS) {
3743 			cmn_err(CE_WARN, "iwh_m_unicst(): "
3744 			    "failed to configure device\n");
3745 			goto fail;
3746 		}
3747 	}
3748 
3749 fail:
3750 	return (err);
3751 }
3752 
3753 /* ARGSUSED */
3754 static int
3755 iwh_m_multicst(void *arg, boolean_t add, const uint8_t *m)
3756 {
3757 	return (IWH_SUCCESS);
3758 }
3759 
3760 /* ARGSUSED */
3761 static int
3762 iwh_m_promisc(void *arg, boolean_t on)
3763 {
3764 	return (IWH_SUCCESS);
3765 }
3766 
3767 /*
3768  * kernel thread to deal with exceptional situation
3769  */
3770 static void
3771 iwh_thread(iwh_sc_t *sc)
3772 {
3773 	ieee80211com_t *ic = &sc->sc_ic;
3774 	clock_t clk;
3775 	int err, n = 0, timeout = 0;
3776 	uint32_t tmp;
3777 #ifdef	DEBUG
3778 	int times = 0;
3779 #endif
3780 
3781 	while (sc->sc_mf_thread_switch) {
3782 		tmp = IWH_READ(sc, CSR_GP_CNTRL);
3783 		if (tmp & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) {
3784 			atomic_and_32(&sc->sc_flags, ~IWH_F_RADIO_OFF);
3785 		} else {
3786 			atomic_or_32(&sc->sc_flags, IWH_F_RADIO_OFF);
3787 		}
3788 
3789 		/*
3790 		 * If  in SUSPEND or the RF is OFF, do nothing.
3791 		 */
3792 		if (sc->sc_flags & IWH_F_RADIO_OFF) {
3793 			delay(drv_usectohz(100000));
3794 			continue;
3795 		}
3796 
3797 		/*
3798 		 * recovery fatal error
3799 		 */
3800 		if (ic->ic_mach &&
3801 		    (sc->sc_flags & IWH_F_HW_ERR_RECOVER)) {
3802 
3803 			IWH_DBG((IWH_DEBUG_FW, "iwh_thread(): "
3804 			    "try to recover fatal hw error: %d\n", times++));
3805 
3806 			iwh_stop(sc);
3807 
3808 			if (IWH_CHK_FAST_RECOVER(sc)) {
3809 				/*
3810 				 * save runtime configuration
3811 				 */
3812 				bcopy(&sc->sc_config, &sc->sc_config_save,
3813 				    sizeof (sc->sc_config));
3814 			} else {
3815 				ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
3816 				delay(drv_usectohz(2000000 + n*500000));
3817 			}
3818 
3819 			err = iwh_init(sc);
3820 			if (err != IWH_SUCCESS) {
3821 				n++;
3822 				if (n < 20) {
3823 					continue;
3824 				}
3825 			}
3826 
3827 			n = 0;
3828 			if (!err) {
3829 				atomic_or_32(&sc->sc_flags, IWH_F_RUNNING);
3830 			}
3831 
3832 
3833 			if (!IWH_CHK_FAST_RECOVER(sc) ||
3834 			    iwh_fast_recover(sc) != IWH_SUCCESS) {
3835 				atomic_and_32(&sc->sc_flags,
3836 				    ~IWH_F_HW_ERR_RECOVER);
3837 
3838 				delay(drv_usectohz(2000000));
3839 				if (sc->sc_ostate != IEEE80211_S_INIT) {
3840 					ieee80211_new_state(ic,
3841 					    IEEE80211_S_SCAN, 0);
3842 				}
3843 			}
3844 		}
3845 
3846 		if (ic->ic_mach &&
3847 		    (sc->sc_flags & IWH_F_SCANNING) && sc->sc_scan_pending) {
3848 			IWH_DBG((IWH_DEBUG_SCAN, "iwh_thread(): "
3849 			    "wait for probe response\n"));
3850 
3851 			sc->sc_scan_pending--;
3852 			delay(drv_usectohz(200000));
3853 			ieee80211_next_scan(ic);
3854 		}
3855 
3856 		/*
3857 		 * rate ctl
3858 		 */
3859 		if (ic->ic_mach &&
3860 		    (sc->sc_flags & IWH_F_RATE_AUTO_CTL)) {
3861 			clk = ddi_get_lbolt();
3862 			if (clk > sc->sc_clk + drv_usectohz(1000000)) {
3863 				iwh_amrr_timeout(sc);
3864 			}
3865 		}
3866 
3867 		if ((ic->ic_state == IEEE80211_S_RUN) &&
3868 		    (ic->ic_beaconmiss++ > 100)) {	/* 10 seconds */
3869 			cmn_err(CE_WARN, "iwh: beacon missed for 10 seconds\n");
3870 			(void) ieee80211_new_state(ic,
3871 			    IEEE80211_S_INIT, -1);
3872 		}
3873 
3874 		delay(drv_usectohz(100000));
3875 
3876 		mutex_enter(&sc->sc_mt_lock);
3877 		if (sc->sc_tx_timer) {
3878 			timeout++;
3879 			if (10 == timeout) {
3880 				sc->sc_tx_timer--;
3881 				if (0 == sc->sc_tx_timer) {
3882 					atomic_or_32(&sc->sc_flags,
3883 					    IWH_F_HW_ERR_RECOVER);
3884 					sc->sc_ostate = IEEE80211_S_RUN;
3885 					IWH_DBG((IWH_DEBUG_FW, "iwh_thread(): "
3886 					    "try to recover from "
3887 					    "send fail\n"));
3888 				}
3889 				timeout = 0;
3890 			}
3891 		}
3892 		mutex_exit(&sc->sc_mt_lock);
3893 	}
3894 
3895 	mutex_enter(&sc->sc_mt_lock);
3896 	sc->sc_mf_thread = NULL;
3897 	cv_signal(&sc->sc_mt_cv);
3898 	mutex_exit(&sc->sc_mt_lock);
3899 }
3900 
3901 /*
3902  * Send a command to the ucode.
3903  */
3904 static int
3905 iwh_cmd(iwh_sc_t *sc, int code, const void *buf, int size, int async)
3906 {
3907 	iwh_tx_ring_t *ring = &sc->sc_txq[IWH_CMD_QUEUE_NUM];
3908 	iwh_tx_desc_t *desc;
3909 	iwh_cmd_t *cmd;
3910 
3911 	ASSERT(size <= sizeof (cmd->data));
3912 	ASSERT(mutex_owned(&sc->sc_glock));
3913 
3914 	IWH_DBG((IWH_DEBUG_CMD, "iwh_cmd() "
3915 	    "code[%d]", code));
3916 	desc = ring->data[ring->cur].desc;
3917 	cmd = ring->data[ring->cur].cmd;
3918 
3919 	cmd->hdr.type = (uint8_t)code;
3920 	cmd->hdr.flags = 0;
3921 	cmd->hdr.qid = ring->qid;
3922 	cmd->hdr.idx = ring->cur;
3923 	bcopy(buf, cmd->data, size);
3924 	(void) memset(desc, 0, sizeof (*desc));
3925 
3926 	desc->val0 = 1 << 24;
3927 	desc->pa[0].tb1_addr =
3928 	    (uint32_t)(ring->data[ring->cur].paddr_cmd & 0xffffffff);
3929 	desc->pa[0].val1 = ((4 + size) << 4) & 0xfff0;
3930 
3931 	if (async) {
3932 		sc->sc_cmd_accum++;
3933 	}
3934 
3935 	/*
3936 	 * kick cmd ring XXX
3937 	 */
3938 	sc->sc_shared->queues_byte_cnt_tbls[ring->qid].
3939 	    tfd_offset[ring->cur].val = 8;
3940 	if (ring->cur < IWH_MAX_WIN_SIZE) {
3941 		sc->sc_shared->queues_byte_cnt_tbls[ring->qid].
3942 		    tfd_offset[IWH_QUEUE_SIZE + ring->cur].val = 8;
3943 	}
3944 	ring->cur = (ring->cur + 1) % ring->count;
3945 	IWH_WRITE(sc, HBUS_TARG_WRPTR, ring->qid << 8 | ring->cur);
3946 
3947 	if (async) {
3948 		return (IWH_SUCCESS);
3949 	} else {
3950 		clock_t clk;
3951 
3952 		clk = ddi_get_lbolt() + drv_usectohz(2000000);
3953 		while (sc->sc_cmd_flag != SC_CMD_FLG_DONE) {
3954 			if (cv_timedwait(&sc->sc_cmd_cv,
3955 			    &sc->sc_glock, clk) < 0) {
3956 				break;
3957 			}
3958 		}
3959 
3960 		if (SC_CMD_FLG_DONE == sc->sc_cmd_flag) {
3961 			sc->sc_cmd_flag = SC_CMD_FLG_NONE;
3962 			return (IWH_SUCCESS);
3963 		} else {
3964 			sc->sc_cmd_flag = SC_CMD_FLG_NONE;
3965 			return (IWH_FAIL);
3966 		}
3967 	}
3968 }
3969 
3970 /*
3971  * require ucode seting led of NIC
3972  */
3973 static void
3974 iwh_set_led(iwh_sc_t *sc, uint8_t id, uint8_t off, uint8_t on)
3975 {
3976 	iwh_led_cmd_t led;
3977 
3978 	led.interval = LE_32(100000);	/* unit: 100ms */
3979 	led.id = id;
3980 	led.off = off;
3981 	led.on = on;
3982 
3983 	(void) iwh_cmd(sc, REPLY_LEDS_CMD, &led, sizeof (led), 1);
3984 }
3985 
3986 /*
3987  * necessary setting to NIC before authentication
3988  */
3989 static int
3990 iwh_hw_set_before_auth(iwh_sc_t *sc)
3991 {
3992 	ieee80211com_t *ic = &sc->sc_ic;
3993 	ieee80211_node_t *in = ic->ic_bss;
3994 	int err = IWH_FAIL;
3995 
3996 	/*
3997 	 * update adapter's configuration according
3998 	 * the info of target AP
3999 	 */
4000 	IEEE80211_ADDR_COPY(sc->sc_config.bssid, in->in_bssid);
4001 	sc->sc_config.chan = LE_16(ieee80211_chan2ieee(ic, in->in_chan));
4002 
4003 	if (ic->ic_curmode != IEEE80211_MODE_11NG) {
4004 
4005 		sc->sc_config.ofdm_ht_triple_stream_basic_rates = 0;
4006 		sc->sc_config.ofdm_ht_dual_stream_basic_rates = 0;
4007 		sc->sc_config.ofdm_ht_single_stream_basic_rates = 0;
4008 
4009 		if (IEEE80211_MODE_11B == ic->ic_curmode) {
4010 			sc->sc_config.cck_basic_rates  = 0x03;
4011 			sc->sc_config.ofdm_basic_rates = 0;
4012 		} else if ((in->in_chan != IEEE80211_CHAN_ANYC) &&
4013 		    (IEEE80211_IS_CHAN_5GHZ(in->in_chan))) {
4014 			sc->sc_config.cck_basic_rates  = 0;
4015 			sc->sc_config.ofdm_basic_rates = 0x15;
4016 		} else { /* assume 802.11b/g */
4017 			sc->sc_config.cck_basic_rates  = 0x0f;
4018 			sc->sc_config.ofdm_basic_rates = 0xff;
4019 		}
4020 	}
4021 
4022 	sc->sc_config.flags &= ~LE_32(RXON_FLG_SHORT_PREAMBLE_MSK |
4023 	    RXON_FLG_SHORT_SLOT_MSK);
4024 
4025 	if (ic->ic_flags & IEEE80211_F_SHSLOT) {
4026 		sc->sc_config.flags |= LE_32(RXON_FLG_SHORT_SLOT_MSK);
4027 	} else {
4028 		sc->sc_config.flags &= LE_32(~RXON_FLG_SHORT_SLOT_MSK);
4029 	}
4030 
4031 	if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) {
4032 		sc->sc_config.flags |= LE_32(RXON_FLG_SHORT_PREAMBLE_MSK);
4033 	} else {
4034 		sc->sc_config.flags &= LE_32(~RXON_FLG_SHORT_PREAMBLE_MSK);
4035 	}
4036 
4037 	IWH_DBG((IWH_DEBUG_80211, "iwh_hw_set_before_auth(): "
4038 	    "config chan %d flags %x "
4039 	    "filter_flags %x  cck %x ofdm %x"
4040 	    " bssid:%02x:%02x:%02x:%02x:%02x:%2x\n",
4041 	    LE_16(sc->sc_config.chan), LE_32(sc->sc_config.flags),
4042 	    LE_32(sc->sc_config.filter_flags),
4043 	    sc->sc_config.cck_basic_rates, sc->sc_config.ofdm_basic_rates,
4044 	    sc->sc_config.bssid[0], sc->sc_config.bssid[1],
4045 	    sc->sc_config.bssid[2], sc->sc_config.bssid[3],
4046 	    sc->sc_config.bssid[4], sc->sc_config.bssid[5]));
4047 
4048 	err = iwh_cmd(sc, REPLY_RXON, &sc->sc_config,
4049 	    sizeof (iwh_rxon_cmd_t), 1);
4050 	if (err != IWH_SUCCESS) {
4051 		cmn_err(CE_WARN, "iwh_hw_set_before_auth(): "
4052 		    "failed to config chan%d\n", sc->sc_config.chan);
4053 		return (err);
4054 	}
4055 
4056 	if ((sc->sc_dev_id != 0x423c) &&
4057 	    (sc->sc_dev_id != 0x423d)) {
4058 		err = iwh_tx_power_table(sc, 1);
4059 		if (err != IWH_SUCCESS) {
4060 			return (err);
4061 		}
4062 	}
4063 
4064 	/*
4065 	 * add default AP node
4066 	 */
4067 	err = iwh_add_ap_sta(sc);
4068 	if (err != IWH_SUCCESS) {
4069 		return (err);
4070 	}
4071 
4072 	if ((sc->sc_dev_id != 0x423c) &&
4073 	    (sc->sc_dev_id != 0x423d)) {
4074 		/*
4075 		 * set up retry rate table for AP node
4076 		 */
4077 		err = iwh_ap_lq(sc);
4078 		if (err != IWH_SUCCESS) {
4079 			return (err);
4080 		}
4081 	}
4082 
4083 	return (err);
4084 }
4085 
4086 /*
4087  * Send a scan request(assembly scan cmd) to the firmware.
4088  */
4089 static int
4090 iwh_scan(iwh_sc_t *sc)
4091 {
4092 	ieee80211com_t *ic = &sc->sc_ic;
4093 	iwh_tx_ring_t *ring = &sc->sc_txq[IWH_CMD_QUEUE_NUM];
4094 	iwh_tx_desc_t *desc;
4095 	iwh_tx_data_t *data;
4096 	iwh_cmd_t *cmd;
4097 	iwh_scan_hdr_t *hdr;
4098 	iwh_scan_chan_t chan;
4099 	struct ieee80211_frame *wh;
4100 	ieee80211_node_t *in = ic->ic_bss;
4101 	uint8_t essid[IEEE80211_NWID_LEN+1];
4102 	struct ieee80211_rateset *rs;
4103 	enum ieee80211_phymode mode;
4104 	uint8_t *frm;
4105 	int i, pktlen, nrates;
4106 
4107 	data = &ring->data[ring->cur];
4108 	desc = data->desc;
4109 	cmd = (iwh_cmd_t *)data->dma_data.mem_va;
4110 
4111 	cmd->hdr.type = REPLY_SCAN_CMD;
4112 	cmd->hdr.flags = 0;
4113 	cmd->hdr.qid = ring->qid;
4114 	cmd->hdr.idx = ring->cur | 0x40;
4115 
4116 	hdr = (iwh_scan_hdr_t *)cmd->data;
4117 	(void) memset(hdr, 0, sizeof (iwh_scan_hdr_t));
4118 	hdr->nchan = 1;
4119 	hdr->quiet_time = LE_16(50);
4120 	hdr->quiet_plcp_th = LE_16(1);
4121 
4122 	hdr->flags = LE_32(RXON_FLG_BAND_24G_MSK);
4123 	hdr->rx_chain = LE_16(RXON_RX_CHAIN_DRIVER_FORCE_MSK |
4124 	    (0x7 << RXON_RX_CHAIN_VALID_POS) |
4125 	    (0x2 << RXON_RX_CHAIN_FORCE_SEL_POS) |
4126 	    (0x2 << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS));
4127 
4128 	hdr->tx_cmd.tx_flags = LE_32(TX_CMD_FLG_SEQ_CTL_MSK);
4129 	hdr->tx_cmd.sta_id = IWH_BROADCAST_ID;
4130 	hdr->tx_cmd.stop_time.life_time = LE_32(0xffffffff);
4131 	hdr->tx_cmd.rate.r.rate_n_flags = LE_32(iwh_rate_to_plcp(2));
4132 	hdr->tx_cmd.rate.r.rate_n_flags |=
4133 	    LE_32(RATE_MCS_ANT_B_MSK |RATE_MCS_CCK_MSK);
4134 	hdr->direct_scan[0].len = ic->ic_des_esslen;
4135 	hdr->direct_scan[0].id  = IEEE80211_ELEMID_SSID;
4136 
4137 	hdr->filter_flags = LE_32(RXON_FILTER_ACCEPT_GRP_MSK |
4138 	    RXON_FILTER_BCON_AWARE_MSK);
4139 
4140 	if (ic->ic_des_esslen) {
4141 		bcopy(ic->ic_des_essid, essid, ic->ic_des_esslen);
4142 		essid[ic->ic_des_esslen] = '\0';
4143 		IWH_DBG((IWH_DEBUG_SCAN, "iwh_scan(): "
4144 		    "directed scan %s\n", essid));
4145 
4146 		bcopy(ic->ic_des_essid, hdr->direct_scan[0].ssid,
4147 		    ic->ic_des_esslen);
4148 	} else {
4149 		bzero(hdr->direct_scan[0].ssid,
4150 		    sizeof (hdr->direct_scan[0].ssid));
4151 	}
4152 
4153 	/*
4154 	 * a probe request frame is required after the REPLY_SCAN_CMD
4155 	 */
4156 	wh = (struct ieee80211_frame *)(hdr + 1);
4157 	wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT |
4158 	    IEEE80211_FC0_SUBTYPE_PROBE_REQ;
4159 	wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
4160 	(void) memset(wh->i_addr1, 0xff, 6);
4161 	IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_macaddr);
4162 	(void) memset(wh->i_addr3, 0xff, 6);
4163 	*(uint16_t *)&wh->i_dur[0] = 0;
4164 	*(uint16_t *)&wh->i_seq[0] = 0;
4165 
4166 	frm = (uint8_t *)(wh + 1);
4167 
4168 	/*
4169 	 * essid IE
4170 	 */
4171 	if (in->in_esslen) {
4172 		bcopy(in->in_essid, essid, in->in_esslen);
4173 		essid[in->in_esslen] = '\0';
4174 		IWH_DBG((IWH_DEBUG_SCAN, "iwh_scan(): "
4175 		    "probe with ESSID %s\n",
4176 		    essid));
4177 	}
4178 	*frm++ = IEEE80211_ELEMID_SSID;
4179 	*frm++ = in->in_esslen;
4180 	bcopy(in->in_essid, frm, in->in_esslen);
4181 	frm += in->in_esslen;
4182 
4183 	mode = ieee80211_chan2mode(ic, ic->ic_curchan);
4184 	rs = &ic->ic_sup_rates[mode];
4185 
4186 	/*
4187 	 * supported rates IE
4188 	 */
4189 	*frm++ = IEEE80211_ELEMID_RATES;
4190 	nrates = rs->ir_nrates;
4191 	if (nrates > IEEE80211_RATE_SIZE) {
4192 		nrates = IEEE80211_RATE_SIZE;
4193 	}
4194 
4195 	*frm++ = (uint8_t)nrates;
4196 	bcopy(rs->ir_rates, frm, nrates);
4197 	frm += nrates;
4198 
4199 	/*
4200 	 * supported xrates IE
4201 	 */
4202 	if (rs->ir_nrates > IEEE80211_RATE_SIZE) {
4203 		nrates = rs->ir_nrates - IEEE80211_RATE_SIZE;
4204 		*frm++ = IEEE80211_ELEMID_XRATES;
4205 		*frm++ = (uint8_t)nrates;
4206 		bcopy(rs->ir_rates + IEEE80211_RATE_SIZE, frm, nrates);
4207 		frm += nrates;
4208 	}
4209 
4210 	/*
4211 	 * optionnal IE (usually for wpa)
4212 	 */
4213 	if (ic->ic_opt_ie != NULL) {
4214 		bcopy(ic->ic_opt_ie, frm, ic->ic_opt_ie_len);
4215 		frm += ic->ic_opt_ie_len;
4216 	}
4217 
4218 	/* setup length of probe request */
4219 	hdr->tx_cmd.len = LE_16(_PTRDIFF(frm, wh));
4220 	hdr->len = LE_16(hdr->nchan * sizeof (iwh_scan_chan_t) +
4221 	    LE_16(hdr->tx_cmd.len) + sizeof (iwh_scan_hdr_t));
4222 
4223 	/*
4224 	 * the attribute of the scan channels are required after the probe
4225 	 * request frame.
4226 	 */
4227 	for (i = 1; i <= hdr->nchan; i++) {
4228 		if (ic->ic_des_esslen) {
4229 			chan.type = LE_32(3);
4230 		} else {
4231 			chan.type = LE_32(1);
4232 		}
4233 
4234 		chan.chan = LE_16(ieee80211_chan2ieee(ic, ic->ic_curchan));
4235 		chan.tpc.tx_gain = 0x28;
4236 		chan.tpc.dsp_atten = 110;
4237 		chan.active_dwell = LE_16(50);
4238 		chan.passive_dwell = LE_16(120);
4239 
4240 		bcopy(&chan, frm, sizeof (iwh_scan_chan_t));
4241 		frm += sizeof (iwh_scan_chan_t);
4242 	}
4243 
4244 	pktlen = _PTRDIFF(frm, cmd);
4245 
4246 	(void) memset(desc, 0, sizeof (*desc));
4247 	desc->val0 = 1 << 24;
4248 	desc->pa[0].tb1_addr =
4249 	    (uint32_t)(data->dma_data.cookie.dmac_address & 0xffffffff);
4250 	desc->pa[0].val1 = (pktlen << 4) & 0xfff0;
4251 
4252 	/*
4253 	 * maybe for cmd, filling the byte cnt table is not necessary.
4254 	 * anyway, we fill it here.
4255 	 */
4256 	sc->sc_shared->queues_byte_cnt_tbls[ring->qid]
4257 	    .tfd_offset[ring->cur].val = 8;
4258 	if (ring->cur < IWH_MAX_WIN_SIZE) {
4259 		sc->sc_shared->queues_byte_cnt_tbls[ring->qid].
4260 		    tfd_offset[IWH_QUEUE_SIZE + ring->cur].val = 8;
4261 	}
4262 
4263 	/*
4264 	 * kick cmd ring
4265 	 */
4266 	ring->cur = (ring->cur + 1) % ring->count;
4267 	IWH_WRITE(sc, HBUS_TARG_WRPTR, ring->qid << 8 | ring->cur);
4268 
4269 	return (IWH_SUCCESS);
4270 }
4271 
4272 /*
4273  * configure NIC by using ucode commands after loading ucode.
4274  */
4275 static int
4276 iwh_config(iwh_sc_t *sc)
4277 {
4278 	ieee80211com_t *ic = &sc->sc_ic;
4279 	iwh_powertable_cmd_t powertable;
4280 	iwh_bt_cmd_t bt;
4281 	iwh_add_sta_t node;
4282 	iwh_rem_sta_t rm_sta;
4283 	const uint8_t bcast[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
4284 	iwh_link_quality_cmd_t link_quality;
4285 	int i, err = IWH_FAIL;
4286 	uint16_t masks = 0;
4287 
4288 	/*
4289 	 * set power mode. Disable power management at present, do it later
4290 	 */
4291 	(void) memset(&powertable, 0, sizeof (powertable));
4292 	powertable.flags = LE_16(0x8);
4293 	err = iwh_cmd(sc, POWER_TABLE_CMD, &powertable,
4294 	    sizeof (powertable), 0);
4295 	if (err != IWH_SUCCESS) {
4296 		cmn_err(CE_WARN, "iwh_config(): "
4297 		    "failed to set power mode\n");
4298 		return (err);
4299 	}
4300 
4301 	/*
4302 	 * configure bt coexistence
4303 	 */
4304 	(void) memset(&bt, 0, sizeof (bt));
4305 	bt.flags = 3;
4306 	bt.lead_time = 0xaa;
4307 	bt.max_kill = 1;
4308 	err = iwh_cmd(sc, REPLY_BT_CONFIG, &bt,
4309 	    sizeof (bt), 0);
4310 	if (err != IWH_SUCCESS) {
4311 		cmn_err(CE_WARN, "iwh_config(): "
4312 		    "failed to configurate bt coexistence\n");
4313 		return (err);
4314 	}
4315 
4316 	/*
4317 	 * configure rxon
4318 	 */
4319 	(void) memset(&sc->sc_config, 0, sizeof (iwh_rxon_cmd_t));
4320 	IEEE80211_ADDR_COPY(sc->sc_config.node_addr, ic->ic_macaddr);
4321 	IEEE80211_ADDR_COPY(sc->sc_config.wlap_bssid, ic->ic_macaddr);
4322 	sc->sc_config.chan = LE_16(ieee80211_chan2ieee(ic, ic->ic_curchan));
4323 	sc->sc_config.flags = LE_32(RXON_FLG_BAND_24G_MSK);
4324 	sc->sc_config.flags &= LE_32(~(RXON_FLG_CHANNEL_MODE_MIXED_MSK |
4325 	    RXON_FLG_CHANNEL_MODE_PURE_40_MSK));
4326 
4327 	switch (ic->ic_opmode) {
4328 	case IEEE80211_M_STA:
4329 		sc->sc_config.dev_type = RXON_DEV_TYPE_ESS;
4330 		sc->sc_config.filter_flags |= LE_32(RXON_FILTER_ACCEPT_GRP_MSK |
4331 		    RXON_FILTER_DIS_DECRYPT_MSK |
4332 		    RXON_FILTER_DIS_GRP_DECRYPT_MSK);
4333 		break;
4334 
4335 	case IEEE80211_M_IBSS:
4336 	case IEEE80211_M_AHDEMO:
4337 		sc->sc_config.dev_type = RXON_DEV_TYPE_IBSS;
4338 
4339 		sc->sc_config.flags |= LE_32(RXON_FLG_SHORT_PREAMBLE_MSK);
4340 		sc->sc_config.filter_flags = LE_32(RXON_FILTER_ACCEPT_GRP_MSK |
4341 		    RXON_FILTER_DIS_DECRYPT_MSK |
4342 		    RXON_FILTER_DIS_GRP_DECRYPT_MSK);
4343 		break;
4344 
4345 	case IEEE80211_M_HOSTAP:
4346 		sc->sc_config.dev_type = RXON_DEV_TYPE_AP;
4347 		break;
4348 
4349 	case IEEE80211_M_MONITOR:
4350 		sc->sc_config.dev_type = RXON_DEV_TYPE_SNIFFER;
4351 		sc->sc_config.filter_flags |= LE_32(RXON_FILTER_ACCEPT_GRP_MSK |
4352 		    RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_PROMISC_MSK);
4353 		break;
4354 	}
4355 
4356 	/*
4357 	 * Support all CCK rates.
4358 	 */
4359 	sc->sc_config.cck_basic_rates  = 0x0f;
4360 
4361 	/*
4362 	 * Support all OFDM rates.
4363 	 */
4364 	sc->sc_config.ofdm_basic_rates = 0xff;
4365 
4366 	/*
4367 	 * Determine HT supported rates.
4368 	 */
4369 	switch (sc->sc_ht_conf.rx_stream_count) {
4370 	case 3:
4371 		sc->sc_config.ofdm_ht_triple_stream_basic_rates = 0xff;
4372 		sc->sc_config.ofdm_ht_dual_stream_basic_rates = 0xff;
4373 		sc->sc_config.ofdm_ht_single_stream_basic_rates = 0xff;
4374 		break;
4375 	case 2:
4376 		sc->sc_config.ofdm_ht_dual_stream_basic_rates = 0xff;
4377 		sc->sc_config.ofdm_ht_single_stream_basic_rates = 0xff;
4378 		break;
4379 	case 1:
4380 		sc->sc_config.ofdm_ht_single_stream_basic_rates = 0xff;
4381 		break;
4382 	default:
4383 		cmn_err(CE_WARN, "iwh_config(): "
4384 		    "RX stream count %d is not in suitable range\n",
4385 		    sc->sc_ht_conf.rx_stream_count);
4386 		return (IWH_FAIL);
4387 	}
4388 
4389 	/*
4390 	 * set RX chains/antennas.
4391 	 */
4392 	iwh_config_rxon_chain(sc);
4393 
4394 	err = iwh_cmd(sc, REPLY_RXON, &sc->sc_config,
4395 	    sizeof (iwh_rxon_cmd_t), 0);
4396 	if (err != IWH_SUCCESS) {
4397 		cmn_err(CE_WARN, "iwh_config(): "
4398 		    "failed to set configure command\n");
4399 		return (err);
4400 	}
4401 
4402 	/*
4403 	 * remove all nodes in NIC
4404 	 */
4405 	(void) memset(&rm_sta, 0, sizeof (rm_sta));
4406 	rm_sta.num_sta = 1;
4407 	bcopy(bcast, rm_sta.addr, 6);
4408 
4409 	err = iwh_cmd(sc, REPLY_REMOVE_STA, &rm_sta, sizeof (iwh_rem_sta_t), 0);
4410 	if (err != IWH_SUCCESS) {
4411 		cmn_err(CE_WARN, "iwh_config(): "
4412 		    "failed to remove broadcast node in hardware.\n");
4413 		return (err);
4414 	}
4415 
4416 	if ((sc->sc_dev_id != 0x423c) &&
4417 	    (sc->sc_dev_id != 0x423d)) {
4418 		/*
4419 		 * configure TX power table
4420 		 */
4421 		err = iwh_tx_power_table(sc, 0);
4422 		if (err != IWH_SUCCESS) {
4423 			return (err);
4424 		}
4425 	}
4426 
4427 	/*
4428 	 * add broadcast node so that we can send broadcast frame
4429 	 */
4430 	(void) memset(&node, 0, sizeof (node));
4431 	(void) memset(node.sta.addr, 0xff, 6);
4432 	node.mode = 0;
4433 	node.sta.sta_id = IWH_BROADCAST_ID;
4434 	node.station_flags = 0;
4435 
4436 	err = iwh_cmd(sc, REPLY_ADD_STA, &node, sizeof (node), 0);
4437 	if (err != IWH_SUCCESS) {
4438 		cmn_err(CE_WARN, "iwh_config(): "
4439 		    "failed to add broadcast node\n");
4440 		return (err);
4441 	}
4442 
4443 	if ((sc->sc_dev_id != 0x423c) &&
4444 	    (sc->sc_dev_id != 0x423d)) {
4445 		/*
4446 		 * TX_LINK_QUALITY cmd
4447 		 */
4448 		(void) memset(&link_quality, 0, sizeof (link_quality));
4449 		for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
4450 			masks |= RATE_MCS_CCK_MSK;
4451 			masks |= RATE_MCS_ANT_B_MSK;
4452 			masks &= ~RATE_MCS_ANT_A_MSK;
4453 			link_quality.rate_n_flags[i] =
4454 			    LE_32(iwh_rate_to_plcp(2) | masks);
4455 		}
4456 
4457 		link_quality.general_params.single_stream_ant_msk = 2;
4458 		link_quality.general_params.dual_stream_ant_msk = 3;
4459 		link_quality.agg_params.agg_dis_start_th = 3;
4460 		link_quality.agg_params.agg_time_limit = LE_16(4000);
4461 		link_quality.sta_id = IWH_BROADCAST_ID;
4462 		err = iwh_cmd(sc, REPLY_TX_LINK_QUALITY_CMD, &link_quality,
4463 		    sizeof (link_quality), 0);
4464 		if (err != IWH_SUCCESS) {
4465 			cmn_err(CE_WARN, "iwh_config(): "
4466 			    "failed to config link quality table\n");
4467 			return (err);
4468 		}
4469 	}
4470 
4471 	return (err);
4472 }
4473 
4474 /*
4475  * quiesce(9E) entry point.
4476  * This function is called when the system is single-threaded at high
4477  * PIL with preemption disabled. Therefore, this function must not be
4478  * blocked.
4479  * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
4480  * DDI_FAILURE indicates an error condition and should almost never happen.
4481  */
4482 static int
4483 iwh_quiesce(dev_info_t *dip)
4484 {
4485 	iwh_sc_t *sc;
4486 
4487 	sc = ddi_get_soft_state(iwh_soft_state_p, ddi_get_instance(dip));
4488 	if (sc == NULL) {
4489 		return (DDI_FAILURE);
4490 	}
4491 
4492 #ifdef DEBUG
4493 	/*
4494 	 * by pass any messages, if it's quiesce
4495 	 */
4496 	iwh_dbg_flags = 0;
4497 #endif
4498 
4499 	/*
4500 	 * No more blocking is allowed while we are in the
4501 	 * quiesce(9E) entry point.
4502 	 */
4503 	atomic_or_32(&sc->sc_flags, IWH_F_QUIESCED);
4504 
4505 	/*
4506 	 * Disable and mask all interrupts.
4507 	 */
4508 	iwh_stop(sc);
4509 
4510 	return (DDI_SUCCESS);
4511 }
4512 
4513 static void
4514 iwh_stop_master(iwh_sc_t *sc)
4515 {
4516 	uint32_t tmp;
4517 	int n;
4518 
4519 	tmp = IWH_READ(sc, CSR_RESET);
4520 	IWH_WRITE(sc, CSR_RESET, tmp | CSR_RESET_REG_FLAG_STOP_MASTER);
4521 
4522 	tmp = IWH_READ(sc, CSR_GP_CNTRL);
4523 	if ((tmp & CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE) ==
4524 	    CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE) {
4525 		return;
4526 	}
4527 
4528 	for (n = 0; n < 2000; n++) {
4529 		if (IWH_READ(sc, CSR_RESET) &
4530 		    CSR_RESET_REG_FLAG_MASTER_DISABLED) {
4531 			break;
4532 		}
4533 		DELAY(1000);
4534 	}
4535 
4536 #ifdef	DEBUG
4537 	if (2000 == n) {
4538 		IWH_DBG((IWH_DEBUG_HW, "iwh_stop_master(): "
4539 		    "timeout waiting for master stop\n"));
4540 	}
4541 #endif
4542 }
4543 
4544 static int
4545 iwh_power_up(iwh_sc_t *sc)
4546 {
4547 	uint32_t tmp;
4548 
4549 	iwh_mac_access_enter(sc);
4550 	tmp = iwh_reg_read(sc, ALM_APMG_PS_CTL);
4551 	tmp &= ~APMG_PS_CTRL_REG_MSK_POWER_SRC;
4552 	tmp |= APMG_PS_CTRL_REG_VAL_POWER_SRC_VMAIN;
4553 	iwh_reg_write(sc, ALM_APMG_PS_CTL, tmp);
4554 	iwh_mac_access_exit(sc);
4555 
4556 	DELAY(5000);
4557 	return (IWH_SUCCESS);
4558 }
4559 
4560 /*
4561  * hardware initialization
4562  */
4563 static int
4564 iwh_preinit(iwh_sc_t *sc)
4565 {
4566 	int n;
4567 	uint8_t vlink;
4568 	uint16_t radio_cfg;
4569 	uint32_t tmp;
4570 
4571 	/*
4572 	 * clear any pending interrupts
4573 	 */
4574 	IWH_WRITE(sc, CSR_INT, 0xffffffff);
4575 
4576 	tmp = IWH_READ(sc, CSR_GIO_CHICKEN_BITS);
4577 	IWH_WRITE(sc, CSR_GIO_CHICKEN_BITS,
4578 	    tmp | CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
4579 
4580 	tmp = IWH_READ(sc, CSR_ANA_PLL_CFG);
4581 	IWH_WRITE(sc, CSR_ANA_PLL_CFG, tmp | IWH_CSR_ANA_PLL_CFG);
4582 
4583 	tmp = IWH_READ(sc, CSR_GP_CNTRL);
4584 	IWH_WRITE(sc, CSR_GP_CNTRL, tmp | CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
4585 
4586 	/*
4587 	 * wait for clock ready
4588 	 */
4589 	for (n = 0; n < 1000; n++) {
4590 		if (IWH_READ(sc, CSR_GP_CNTRL) &
4591 		    CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY) {
4592 			break;
4593 		}
4594 		DELAY(10);
4595 	}
4596 
4597 	if (1000 == n) {
4598 		return (ETIMEDOUT);
4599 	}
4600 
4601 	iwh_mac_access_enter(sc);
4602 
4603 	iwh_reg_write(sc, ALM_APMG_CLK_EN, APMG_CLK_REG_VAL_DMA_CLK_RQT);
4604 
4605 	DELAY(20);
4606 	tmp = iwh_reg_read(sc, ALM_APMG_PCIDEV_STT);
4607 	iwh_reg_write(sc, ALM_APMG_PCIDEV_STT, tmp |
4608 	    APMG_DEV_STATE_REG_VAL_L1_ACTIVE_DISABLE);
4609 	iwh_mac_access_exit(sc);
4610 
4611 	radio_cfg = IWH_READ_EEP_SHORT(sc, EEP_SP_RADIO_CONFIGURATION);
4612 	if (SP_RADIO_TYPE_MSK(radio_cfg) < SP_RADIO_TYPE_MAX) {
4613 		tmp = IWH_READ(sc, CSR_HW_IF_CONFIG_REG);
4614 		IWH_WRITE(sc, CSR_HW_IF_CONFIG_REG,
4615 		    tmp | SP_RADIO_TYPE_MSK(radio_cfg) |
4616 		    SP_RADIO_STEP_MSK(radio_cfg) |
4617 		    SP_RADIO_DASH_MSK(radio_cfg));
4618 	} else {
4619 		cmn_err(CE_WARN, "iwh_preinit(): "
4620 		    "radio configuration information in eeprom is wrong\n");
4621 		return (IWH_FAIL);
4622 	}
4623 
4624 
4625 	IWH_WRITE(sc, CSR_INT_COALESCING, 512 / 32);
4626 
4627 	(void) iwh_power_up(sc);
4628 
4629 	if ((sc->sc_rev & 0x80) == 0x80 && (sc->sc_rev & 0x7f) < 8) {
4630 		tmp = ddi_get32(sc->sc_cfg_handle,
4631 		    (uint32_t *)(sc->sc_cfg_base + 0xe8));
4632 		ddi_put32(sc->sc_cfg_handle,
4633 		    (uint32_t *)(sc->sc_cfg_base + 0xe8),
4634 		    tmp & ~(1 << 11));
4635 	}
4636 
4637 	vlink = ddi_get8(sc->sc_cfg_handle,
4638 	    (uint8_t *)(sc->sc_cfg_base + 0xf0));
4639 	ddi_put8(sc->sc_cfg_handle, (uint8_t *)(sc->sc_cfg_base + 0xf0),
4640 	    vlink & ~2);
4641 
4642 	tmp = IWH_READ(sc, CSR_HW_IF_CONFIG_REG);
4643 	tmp |= CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI |
4644 	    CSR_HW_IF_CONFIG_REG_BIT_MAC_SI;
4645 	IWH_WRITE(sc, CSR_SW_VER, tmp);
4646 
4647 	/*
4648 	 * make sure power supply on each part of the hardware
4649 	 */
4650 	iwh_mac_access_enter(sc);
4651 	tmp = iwh_reg_read(sc, ALM_APMG_PS_CTL);
4652 	tmp |= APMG_PS_CTRL_REG_VAL_ALM_R_RESET_REQ;
4653 	iwh_reg_write(sc, ALM_APMG_PS_CTL, tmp);
4654 	DELAY(5);
4655 
4656 	tmp = iwh_reg_read(sc, ALM_APMG_PS_CTL);
4657 	tmp &= ~APMG_PS_CTRL_REG_VAL_ALM_R_RESET_REQ;
4658 	iwh_reg_write(sc, ALM_APMG_PS_CTL, tmp);
4659 	iwh_mac_access_exit(sc);
4660 
4661 	return (IWH_SUCCESS);
4662 }
4663 
4664 /*
4665  * set up semphore flag to own EEPROM
4666  */
4667 static int
4668 iwh_eep_sem_down(iwh_sc_t *sc)
4669 {
4670 	int count1, count2;
4671 	uint32_t tmp;
4672 
4673 	for (count1 = 0; count1 < 1000; count1++) {
4674 		tmp = IWH_READ(sc, CSR_HW_IF_CONFIG_REG);
4675 		IWH_WRITE(sc, CSR_HW_IF_CONFIG_REG,
4676 		    tmp | CSR_HW_IF_CONFIG_REG_EEP_SEM);
4677 
4678 		for (count2 = 0; count2 < 2; count2++) {
4679 			if (IWH_READ(sc, CSR_HW_IF_CONFIG_REG) &
4680 			    CSR_HW_IF_CONFIG_REG_EEP_SEM) {
4681 				return (IWH_SUCCESS);
4682 			}
4683 			DELAY(10000);
4684 		}
4685 	}
4686 
4687 	return (IWH_FAIL);
4688 }
4689 
4690 /*
4691  * reset semphore flag to release EEPROM
4692  */
4693 static void
4694 iwh_eep_sem_up(iwh_sc_t *sc)
4695 {
4696 	uint32_t tmp;
4697 
4698 	tmp = IWH_READ(sc, CSR_HW_IF_CONFIG_REG);
4699 	IWH_WRITE(sc, CSR_HW_IF_CONFIG_REG,
4700 	    tmp & (~CSR_HW_IF_CONFIG_REG_EEP_SEM));
4701 }
4702 
4703 /*
4704  * This function read all infomation from eeprom
4705  */
4706 static int
4707 iwh_eep_load(iwh_sc_t *sc)
4708 {
4709 	int i, rr;
4710 	uint32_t rv, tmp, eep_gp;
4711 	uint16_t addr, eep_sz = sizeof (sc->sc_eep_map);
4712 	uint16_t *eep_p = (uint16_t *)&sc->sc_eep_map;
4713 
4714 	/*
4715 	 * read eeprom gp register in CSR
4716 	 */
4717 	eep_gp = IWH_READ(sc, CSR_EEPROM_GP);
4718 	if ((eep_gp & CSR_EEPROM_GP_VALID_MSK) ==
4719 	    CSR_EEPROM_GP_BAD_SIGNATURE) {
4720 		IWH_DBG((IWH_DEBUG_EEPROM, "iwh_eep_load(): "
4721 		    "not find eeprom\n"));
4722 		return (IWH_FAIL);
4723 	}
4724 
4725 	rr = iwh_eep_sem_down(sc);
4726 	if (rr != 0) {
4727 		IWH_DBG((IWH_DEBUG_EEPROM, "iwh_eep_load(): "
4728 		    "driver failed to own EEPROM\n"));
4729 		return (IWH_FAIL);
4730 	}
4731 
4732 	for (addr = 0; addr < eep_sz; addr += 2) {
4733 		IWH_WRITE(sc, CSR_EEPROM_REG, addr<<1);
4734 		tmp = IWH_READ(sc, CSR_EEPROM_REG);
4735 		IWH_WRITE(sc, CSR_EEPROM_REG, tmp & ~(0x2));
4736 
4737 		for (i = 0; i < 10; i++) {
4738 			rv = IWH_READ(sc, CSR_EEPROM_REG);
4739 			if (rv & 1) {
4740 				break;
4741 			}
4742 			DELAY(10);
4743 		}
4744 
4745 		if (!(rv & 1)) {
4746 			IWH_DBG((IWH_DEBUG_EEPROM, "iwh_eep_load(): "
4747 			    "time out when read eeprome\n"));
4748 			iwh_eep_sem_up(sc);
4749 			return (IWH_FAIL);
4750 		}
4751 
4752 		eep_p[addr/2] = LE_16(rv >> 16);
4753 	}
4754 
4755 	iwh_eep_sem_up(sc);
4756 	return (IWH_SUCCESS);
4757 }
4758 
4759 /*
4760  * initialize mac address in ieee80211com_t struct
4761  */
4762 static void
4763 iwh_get_mac_from_eep(iwh_sc_t *sc)
4764 {
4765 	ieee80211com_t *ic = &sc->sc_ic;
4766 
4767 	IEEE80211_ADDR_COPY(ic->ic_macaddr, &sc->sc_eep_map[EEP_MAC_ADDRESS]);
4768 
4769 	IWH_DBG((IWH_DEBUG_EEPROM, "iwh_get_mac_from_eep(): "
4770 	    "mac:%2x:%2x:%2x:%2x:%2x:%2x\n",
4771 	    ic->ic_macaddr[0], ic->ic_macaddr[1], ic->ic_macaddr[2],
4772 	    ic->ic_macaddr[3], ic->ic_macaddr[4], ic->ic_macaddr[5]));
4773 }
4774 
4775 /*
4776  * main initialization function
4777  */
4778 static int
4779 iwh_init(iwh_sc_t *sc)
4780 {
4781 	int err = IWH_FAIL;
4782 	clock_t clk;
4783 
4784 	/*
4785 	 * release buffer for calibration
4786 	 */
4787 	iwh_release_calib_buffer(sc);
4788 
4789 	mutex_enter(&sc->sc_glock);
4790 	atomic_and_32(&sc->sc_flags, ~IWH_F_FW_INIT);
4791 
4792 	err = iwh_init_common(sc);
4793 	if (err != IWH_SUCCESS) {
4794 		mutex_exit(&sc->sc_glock);
4795 		return (IWH_FAIL);
4796 	}
4797 
4798 	/*
4799 	 * backup ucode data part for future use.
4800 	 */
4801 	bcopy(sc->sc_dma_fw_data.mem_va,
4802 	    sc->sc_dma_fw_data_bak.mem_va,
4803 	    sc->sc_dma_fw_data.alength);
4804 
4805 	/* load firmware init segment into NIC */
4806 	err = iwh_load_init_firmware(sc);
4807 	if (err != IWH_SUCCESS) {
4808 		cmn_err(CE_WARN, "iwh_init(): "
4809 		    "failed to setup init firmware\n");
4810 		mutex_exit(&sc->sc_glock);
4811 		return (IWH_FAIL);
4812 	}
4813 
4814 	/*
4815 	 * now press "execute" start running
4816 	 */
4817 	IWH_WRITE(sc, CSR_RESET, 0);
4818 
4819 	clk = ddi_get_lbolt() + drv_usectohz(1000000);
4820 	while (!(sc->sc_flags & IWH_F_FW_INIT)) {
4821 		if (cv_timedwait(&sc->sc_ucode_cv,
4822 		    &sc->sc_glock, clk) < 0) {
4823 			break;
4824 		}
4825 	}
4826 
4827 	if (!(sc->sc_flags & IWH_F_FW_INIT)) {
4828 		cmn_err(CE_WARN, "iwh_init(): "
4829 		    "failed to process init alive.\n");
4830 		mutex_exit(&sc->sc_glock);
4831 		return (IWH_FAIL);
4832 	}
4833 
4834 	mutex_exit(&sc->sc_glock);
4835 
4836 	/*
4837 	 * stop chipset for initializing chipset again
4838 	 */
4839 	iwh_stop(sc);
4840 
4841 	mutex_enter(&sc->sc_glock);
4842 	atomic_and_32(&sc->sc_flags, ~IWH_F_FW_INIT);
4843 
4844 	err = iwh_init_common(sc);
4845 	if (err != IWH_SUCCESS) {
4846 		mutex_exit(&sc->sc_glock);
4847 		return (IWH_FAIL);
4848 	}
4849 
4850 	/*
4851 	 * load firmware run segment into NIC
4852 	 */
4853 	err = iwh_load_run_firmware(sc);
4854 	if (err != IWH_SUCCESS) {
4855 		cmn_err(CE_WARN, "iwh_init(): "
4856 		    "failed to setup run firmware\n");
4857 		mutex_exit(&sc->sc_glock);
4858 		return (IWH_FAIL);
4859 	}
4860 
4861 	/*
4862 	 * now press "execute" start running
4863 	 */
4864 	IWH_WRITE(sc, CSR_RESET, 0);
4865 
4866 	clk = ddi_get_lbolt() + drv_usectohz(1000000);
4867 	while (!(sc->sc_flags & IWH_F_FW_INIT)) {
4868 		if (cv_timedwait(&sc->sc_ucode_cv,
4869 		    &sc->sc_glock, clk) < 0) {
4870 			break;
4871 		}
4872 	}
4873 
4874 	if (!(sc->sc_flags & IWH_F_FW_INIT)) {
4875 		cmn_err(CE_WARN, "iwh_init(): "
4876 		    "failed to process runtime alive.\n");
4877 		mutex_exit(&sc->sc_glock);
4878 		return (IWH_FAIL);
4879 	}
4880 
4881 	mutex_exit(&sc->sc_glock);
4882 
4883 	DELAY(1000);
4884 
4885 	mutex_enter(&sc->sc_glock);
4886 	atomic_and_32(&sc->sc_flags, ~IWH_F_FW_INIT);
4887 
4888 	/*
4889 	 * at this point, the firmware is loaded OK, then config the hardware
4890 	 * with the ucode API, including rxon, txpower, etc.
4891 	 */
4892 	err = iwh_config(sc);
4893 	if (err) {
4894 		cmn_err(CE_WARN, "iwh_init(): "
4895 		    "failed to configure device\n");
4896 		mutex_exit(&sc->sc_glock);
4897 		return (IWH_FAIL);
4898 	}
4899 
4900 	/*
4901 	 * at this point, hardware may receive beacons :)
4902 	 */
4903 	mutex_exit(&sc->sc_glock);
4904 	return (IWH_SUCCESS);
4905 }
4906 
4907 /*
4908  * stop or disable NIC
4909  */
4910 static void
4911 iwh_stop(iwh_sc_t *sc)
4912 {
4913 	uint32_t tmp;
4914 	int i;
4915 
4916 	/*
4917 	 * by pass if it's quiesced
4918 	 */
4919 	if (!(sc->sc_flags & IWH_F_QUIESCED)) {
4920 		mutex_enter(&sc->sc_glock);
4921 	}
4922 
4923 	IWH_WRITE(sc, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
4924 	/*
4925 	 * disable interrupts
4926 	 */
4927 	IWH_WRITE(sc, CSR_INT_MASK, 0);
4928 	IWH_WRITE(sc, CSR_INT, CSR_INI_SET_MASK);
4929 	IWH_WRITE(sc, CSR_FH_INT_STATUS, 0xffffffff);
4930 
4931 	/*
4932 	 * reset all Tx rings
4933 	 */
4934 	for (i = 0; i < IWH_NUM_QUEUES; i++) {
4935 		iwh_reset_tx_ring(sc, &sc->sc_txq[i]);
4936 	}
4937 
4938 	/*
4939 	 * reset Rx ring
4940 	 */
4941 	iwh_reset_rx_ring(sc);
4942 
4943 	iwh_mac_access_enter(sc);
4944 	iwh_reg_write(sc, ALM_APMG_CLK_DIS, APMG_CLK_REG_VAL_DMA_CLK_RQT);
4945 	iwh_mac_access_exit(sc);
4946 
4947 	DELAY(5);
4948 
4949 	iwh_stop_master(sc);
4950 
4951 	mutex_enter(&sc->sc_mt_lock);
4952 	sc->sc_tx_timer = 0;
4953 	mutex_exit(&sc->sc_mt_lock);
4954 
4955 	tmp = IWH_READ(sc, CSR_RESET);
4956 	IWH_WRITE(sc, CSR_RESET, tmp | CSR_RESET_REG_FLAG_SW_RESET);
4957 
4958 	/*
4959 	 * by pass if it's quiesced
4960 	 */
4961 	if (!(sc->sc_flags & IWH_F_QUIESCED)) {
4962 		mutex_exit(&sc->sc_glock);
4963 	}
4964 }
4965 
4966 /*
4967  * Naive implementation of the Adaptive Multi Rate Retry algorithm:
4968  * "IEEE 802.11 Rate Adaptation: A Practical Approach"
4969  * Mathieu Lacage, Hossein Manshaei, Thierry Turletti
4970  * INRIA Sophia - Projet Planete
4971  * http://www-sop.inria.fr/rapports/sophia/RR-5208.html
4972  */
4973 #define	is_success(amrr)	\
4974 	((amrr)->retrycnt < (amrr)->txcnt / 10)
4975 #define	is_failure(amrr)	\
4976 	((amrr)->retrycnt > (amrr)->txcnt / 3)
4977 #define	is_enough(amrr)		\
4978 	((amrr)->txcnt > 200)
4979 #define	not_very_few(amrr)	\
4980 	((amrr)->txcnt > 40)
4981 #define	is_min_rate(in)		\
4982 	(0 == (in)->in_txrate)
4983 #define	is_max_rate(in)		\
4984 	((in)->in_rates.ir_nrates - 1 == (in)->in_txrate)
4985 #define	increase_rate(in)	\
4986 	((in)->in_txrate++)
4987 #define	decrease_rate(in)	\
4988 	((in)->in_txrate--)
4989 #define	reset_cnt(amrr)		\
4990 	{ (amrr)->txcnt = (amrr)->retrycnt = 0; }
4991 
4992 #define	IWH_AMRR_MIN_SUCCESS_THRESHOLD	 1
4993 #define	IWH_AMRR_MAX_SUCCESS_THRESHOLD	15
4994 
4995 static void
4996 iwh_amrr_init(iwh_amrr_t *amrr)
4997 {
4998 	amrr->success = 0;
4999 	amrr->recovery = 0;
5000 	amrr->txcnt = amrr->retrycnt = 0;
5001 	amrr->success_threshold = IWH_AMRR_MIN_SUCCESS_THRESHOLD;
5002 	amrr->ht_mcs_idx = 0;	/* 6Mbps */
5003 }
5004 
5005 static void
5006 iwh_amrr_timeout(iwh_sc_t *sc)
5007 {
5008 	ieee80211com_t *ic = &sc->sc_ic;
5009 
5010 	IWH_DBG((IWH_DEBUG_RATECTL, "iwh_amrr_timeout(): "
5011 	    "enter\n"));
5012 
5013 	if (IEEE80211_M_STA == ic->ic_opmode) {
5014 		iwh_amrr_ratectl(NULL, ic->ic_bss);
5015 	} else {
5016 		ieee80211_iterate_nodes(&ic->ic_sta, iwh_amrr_ratectl, NULL);
5017 	}
5018 
5019 	sc->sc_clk = ddi_get_lbolt();
5020 }
5021 
5022 static int
5023 iwh_is_max_rate(ieee80211_node_t *in)
5024 {
5025 	int i;
5026 	iwh_amrr_t *amrr = (iwh_amrr_t *)in;
5027 	uint8_t r = (uint8_t)amrr->ht_mcs_idx;
5028 	ieee80211com_t *ic = in->in_ic;
5029 	iwh_sc_t *sc = (iwh_sc_t *)ic;
5030 
5031 	if (in->in_flags & IEEE80211_NODE_HT) {
5032 		for (i = in->in_htrates.rs_nrates - 1; i >= 0; i--) {
5033 			r = in->in_htrates.rs_rates[i] &
5034 			    IEEE80211_RATE_VAL;
5035 			if (sc->sc_ht_conf.tx_support_mcs[r/8] &
5036 			    (1 << (r%8))) {
5037 				break;
5038 			}
5039 		}
5040 
5041 		return (r == (uint8_t)amrr->ht_mcs_idx);
5042 	} else {
5043 		return (is_max_rate(in));
5044 	}
5045 }
5046 
5047 static int
5048 iwh_is_min_rate(ieee80211_node_t *in)
5049 {
5050 	int i;
5051 	uint8_t r = 0;
5052 	iwh_amrr_t *amrr = (iwh_amrr_t *)in;
5053 	ieee80211com_t *ic = in->in_ic;
5054 	iwh_sc_t *sc = (iwh_sc_t *)ic;
5055 
5056 	if (in->in_flags & IEEE80211_NODE_HT) {
5057 		for (i = 0; i < in->in_htrates.rs_nrates; i++) {
5058 			r = in->in_htrates.rs_rates[i] &
5059 			    IEEE80211_RATE_VAL;
5060 			if (sc->sc_ht_conf.tx_support_mcs[r/8] &
5061 			    (1 << (r%8))) {
5062 				break;
5063 			}
5064 		}
5065 
5066 		return (r == (uint8_t)amrr->ht_mcs_idx);
5067 	} else {
5068 		return (is_min_rate(in));
5069 	}
5070 }
5071 
5072 static void
5073 iwh_increase_rate(ieee80211_node_t *in)
5074 {
5075 	int i;
5076 	uint8_t r;
5077 	iwh_amrr_t *amrr = (iwh_amrr_t *)in;
5078 	ieee80211com_t *ic = in->in_ic;
5079 	iwh_sc_t *sc = (iwh_sc_t *)ic;
5080 
5081 	if (in->in_flags & IEEE80211_NODE_HT) {
5082 again:
5083 		amrr->ht_mcs_idx++;
5084 
5085 		for (i = 0; i < in->in_htrates.rs_nrates; i++) {
5086 			r = in->in_htrates.rs_rates[i] &
5087 			    IEEE80211_RATE_VAL;
5088 			if ((r == (uint8_t)amrr->ht_mcs_idx) &&
5089 			    (sc->sc_ht_conf.tx_support_mcs[r/8] &
5090 			    (1 << (r%8)))) {
5091 				break;
5092 			}
5093 		}
5094 
5095 		if (i >= in->in_htrates.rs_nrates) {
5096 			goto again;
5097 		}
5098 	} else {
5099 		increase_rate(in);
5100 	}
5101 }
5102 
5103 static void
5104 iwh_decrease_rate(ieee80211_node_t *in)
5105 {
5106 	int i;
5107 	uint8_t r;
5108 	iwh_amrr_t *amrr = (iwh_amrr_t *)in;
5109 	ieee80211com_t *ic = in->in_ic;
5110 	iwh_sc_t *sc = (iwh_sc_t *)ic;
5111 
5112 	if (in->in_flags & IEEE80211_NODE_HT) {
5113 again:
5114 		amrr->ht_mcs_idx--;
5115 
5116 		for (i = 0; i < in->in_htrates.rs_nrates; i++) {
5117 			r = in->in_htrates.rs_rates[i] &
5118 			    IEEE80211_RATE_VAL;
5119 			if ((r == (uint8_t)amrr->ht_mcs_idx) &&
5120 			    (sc->sc_ht_conf.tx_support_mcs[r/8] &
5121 			    (1 << (r%8)))) {
5122 				break;
5123 			}
5124 		}
5125 
5126 		if (i >= in->in_htrates.rs_nrates) {
5127 			goto again;
5128 		}
5129 	} else {
5130 		decrease_rate(in);
5131 	}
5132 }
5133 
5134 /* ARGSUSED */
5135 static void
5136 iwh_amrr_ratectl(void *arg, ieee80211_node_t *in)
5137 {
5138 	iwh_amrr_t *amrr = (iwh_amrr_t *)in;
5139 	int need_change = 0;
5140 
5141 	if (is_success(amrr) && is_enough(amrr)) {
5142 		amrr->success++;
5143 		if (amrr->success >= amrr->success_threshold &&
5144 		    !iwh_is_max_rate(in)) {
5145 			amrr->recovery = 1;
5146 			amrr->success = 0;
5147 			iwh_increase_rate(in);
5148 			IWH_DBG((IWH_DEBUG_RATECTL, "iwh_amrr_ratectl(): "
5149 			    "AMRR increasing rate %d "
5150 			    "(txcnt=%d retrycnt=%d), mcs_idx=%d\n",
5151 			    in->in_txrate, amrr->txcnt,
5152 			    amrr->retrycnt, amrr->ht_mcs_idx));
5153 			need_change = 1;
5154 		} else {
5155 			amrr->recovery = 0;
5156 		}
5157 	} else if (not_very_few(amrr) && is_failure(amrr)) {
5158 		amrr->success = 0;
5159 		if (!iwh_is_min_rate(in)) {
5160 			if (amrr->recovery) {
5161 				amrr->success_threshold++;
5162 				if (amrr->success_threshold >
5163 				    IWH_AMRR_MAX_SUCCESS_THRESHOLD) {
5164 					amrr->success_threshold =
5165 					    IWH_AMRR_MAX_SUCCESS_THRESHOLD;
5166 				}
5167 			} else {
5168 				amrr->success_threshold =
5169 				    IWH_AMRR_MIN_SUCCESS_THRESHOLD;
5170 			}
5171 			iwh_decrease_rate(in);
5172 			IWH_DBG((IWH_DEBUG_RATECTL, "iwh_amrr_ratectl(): "
5173 			    "AMRR decreasing rate %d "
5174 			    "(txcnt=%d retrycnt=%d), mcs_idx=%d\n",
5175 			    in->in_txrate, amrr->txcnt,
5176 			    amrr->retrycnt, amrr->ht_mcs_idx));
5177 			need_change = 1;
5178 		}
5179 		amrr->recovery = 0;	/* paper is incorrect */
5180 	}
5181 
5182 	if (is_enough(amrr) || need_change) {
5183 		reset_cnt(amrr);
5184 	}
5185 }
5186 
5187 /*
5188  * translate indirect address in eeprom to direct address
5189  * in eeprom and return address of entry whos indirect address
5190  * is indi_addr
5191  */
5192 static uint8_t *
5193 iwh_eep_addr_trans(iwh_sc_t *sc, uint32_t indi_addr)
5194 {
5195 	uint32_t di_addr;
5196 	uint16_t temp;
5197 
5198 	if (!(indi_addr & INDIRECT_ADDRESS)) {
5199 		di_addr = indi_addr;
5200 		return (&sc->sc_eep_map[di_addr]);
5201 	}
5202 
5203 	switch (indi_addr & INDIRECT_TYPE_MSK) {
5204 	case INDIRECT_GENERAL:
5205 		temp = IWH_READ_EEP_SHORT(sc, EEP_LINK_GENERAL);
5206 		break;
5207 
5208 	case	INDIRECT_HOST:
5209 		temp = IWH_READ_EEP_SHORT(sc, EEP_LINK_HOST);
5210 		break;
5211 
5212 	case	INDIRECT_REGULATORY:
5213 		temp = IWH_READ_EEP_SHORT(sc, EEP_LINK_REGULATORY);
5214 		break;
5215 
5216 	case	INDIRECT_CALIBRATION:
5217 		temp = IWH_READ_EEP_SHORT(sc, EEP_LINK_CALIBRATION);
5218 		break;
5219 
5220 	case	INDIRECT_PROCESS_ADJST:
5221 		temp = IWH_READ_EEP_SHORT(sc, EEP_LINK_PROCESS_ADJST);
5222 		break;
5223 
5224 	case	INDIRECT_OTHERS:
5225 		temp = IWH_READ_EEP_SHORT(sc, EEP_LINK_OTHERS);
5226 		break;
5227 
5228 	default:
5229 		temp = 0;
5230 		cmn_err(CE_WARN, "iwh_eep_addr_trans(): "
5231 		    "incorrect indirect eeprom address.\n");
5232 		break;
5233 	}
5234 
5235 	di_addr = (indi_addr & ADDRESS_MSK) + (temp << 1);
5236 
5237 	return (&sc->sc_eep_map[di_addr]);
5238 }
5239 
5240 /*
5241  * loade a section of ucode into NIC
5242  */
5243 static int
5244 iwh_put_seg_fw(iwh_sc_t *sc, uint32_t addr_s, uint32_t addr_d, uint32_t len)
5245 {
5246 
5247 	iwh_mac_access_enter(sc);
5248 
5249 	IWH_WRITE(sc, IWH_FH_TCSR_CHNL_TX_CONFIG_REG(IWH_FH_SRVC_CHNL),
5250 	    IWH_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE);
5251 
5252 	IWH_WRITE(sc, IWH_FH_SRVC_CHNL_SRAM_ADDR_REG(IWH_FH_SRVC_CHNL), addr_d);
5253 
5254 	IWH_WRITE(sc, IWH_FH_TFDIB_CTRL0_REG(IWH_FH_SRVC_CHNL),
5255 	    (addr_s & FH_MEM_TFDIB_DRAM_ADDR_LSB_MASK));
5256 
5257 	IWH_WRITE(sc, IWH_FH_TFDIB_CTRL1_REG(IWH_FH_SRVC_CHNL), len);
5258 
5259 	IWH_WRITE(sc, IWH_FH_TCSR_CHNL_TX_BUF_STS_REG(IWH_FH_SRVC_CHNL),
5260 	    (1 << IWH_FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM) |
5261 	    (1 << IWH_FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX) |
5262 	    IWH_FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID);
5263 
5264 	IWH_WRITE(sc, IWH_FH_TCSR_CHNL_TX_CONFIG_REG(IWH_FH_SRVC_CHNL),
5265 	    IWH_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
5266 	    IWH_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE_VAL |
5267 	    IWH_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD);
5268 
5269 	iwh_mac_access_exit(sc);
5270 
5271 	return (IWH_SUCCESS);
5272 }
5273 
5274 /*
5275  * necessary setting during alive notification
5276  */
5277 static int
5278 iwh_alive_common(iwh_sc_t *sc)
5279 {
5280 	uint32_t base;
5281 	uint32_t i;
5282 	iwh_wimax_coex_cmd_t w_cmd;
5283 	iwh_calibration_crystal_cmd_t c_cmd;
5284 	uint32_t rv = IWH_FAIL;
5285 
5286 	/*
5287 	 * initialize SCD related registers to make TX work.
5288 	 */
5289 	iwh_mac_access_enter(sc);
5290 
5291 	/*
5292 	 * read sram address of data base.
5293 	 */
5294 	sc->sc_scd_base = iwh_reg_read(sc, IWH_SCD_SRAM_BASE_ADDR);
5295 
5296 	for (base = sc->sc_scd_base + IWH_SCD_CONTEXT_DATA_OFFSET;
5297 	    base < sc->sc_scd_base + IWH_SCD_TX_STTS_BITMAP_OFFSET;
5298 	    base += 4) {
5299 		iwh_mem_write(sc, base, 0);
5300 	}
5301 
5302 	for (; base < sc->sc_scd_base + IWH_SCD_TRANSLATE_TBL_OFFSET;
5303 	    base += 4) {
5304 		iwh_mem_write(sc, base, 0);
5305 	}
5306 
5307 	for (i = 0; i < sizeof (uint16_t) * IWH_NUM_QUEUES; i += 4) {
5308 		iwh_mem_write(sc, base + i, 0);
5309 	}
5310 
5311 	iwh_reg_write(sc, IWH_SCD_DRAM_BASE_ADDR,
5312 	    sc->sc_dma_sh.cookie.dmac_address >> 10);
5313 
5314 	iwh_reg_write(sc, IWH_SCD_QUEUECHAIN_SEL,
5315 	    IWH_SCD_QUEUECHAIN_SEL_ALL(IWH_NUM_QUEUES));
5316 
5317 	iwh_reg_write(sc, IWH_SCD_AGGR_SEL, 0);
5318 
5319 	for (i = 0; i < IWH_NUM_QUEUES; i++) {
5320 		iwh_reg_write(sc, IWH_SCD_QUEUE_RDPTR(i), 0);
5321 		IWH_WRITE(sc, HBUS_TARG_WRPTR, 0 | (i << 8));
5322 		iwh_mem_write(sc, sc->sc_scd_base +
5323 		    IWH_SCD_CONTEXT_QUEUE_OFFSET(i), 0);
5324 		iwh_mem_write(sc, sc->sc_scd_base +
5325 		    IWH_SCD_CONTEXT_QUEUE_OFFSET(i) +
5326 		    sizeof (uint32_t),
5327 		    ((SCD_WIN_SIZE << IWH_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
5328 		    IWH_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
5329 		    ((SCD_FRAME_LIMIT <<
5330 		    IWH_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
5331 		    IWH_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
5332 	}
5333 
5334 	iwh_reg_write(sc, IWH_SCD_INTERRUPT_MASK, (1 << IWH_NUM_QUEUES) - 1);
5335 
5336 	iwh_reg_write(sc, (IWH_SCD_BASE + 0x10),
5337 	    SCD_TXFACT_REG_TXFIFO_MASK(0, 7));
5338 
5339 	IWH_WRITE(sc, HBUS_TARG_WRPTR, (IWH_CMD_QUEUE_NUM << 8));
5340 	iwh_reg_write(sc, IWH_SCD_QUEUE_RDPTR(IWH_CMD_QUEUE_NUM), 0);
5341 
5342 	/*
5343 	 * queue 0-7 map to FIFO 0-7 and
5344 	 * all queues work under FIFO mode(none-scheduler_ack)
5345 	 */
5346 	for (i = 0; i < 4; i++) {
5347 		iwh_reg_write(sc, IWH_SCD_QUEUE_STATUS_BITS(i),
5348 		    (1 << IWH_SCD_QUEUE_STTS_REG_POS_ACTIVE) |
5349 		    ((3-i) << IWH_SCD_QUEUE_STTS_REG_POS_TXF) |
5350 		    (1 << IWH_SCD_QUEUE_STTS_REG_POS_WSL) |
5351 		    IWH_SCD_QUEUE_STTS_REG_MSK);
5352 	}
5353 
5354 	iwh_reg_write(sc, IWH_SCD_QUEUE_STATUS_BITS(IWH_CMD_QUEUE_NUM),
5355 	    (1 << IWH_SCD_QUEUE_STTS_REG_POS_ACTIVE) |
5356 	    (IWH_CMD_FIFO_NUM << IWH_SCD_QUEUE_STTS_REG_POS_TXF) |
5357 	    (1 << IWH_SCD_QUEUE_STTS_REG_POS_WSL) |
5358 	    IWH_SCD_QUEUE_STTS_REG_MSK);
5359 
5360 	for (i = 5; i < 7; i++) {
5361 		iwh_reg_write(sc, IWH_SCD_QUEUE_STATUS_BITS(i),
5362 		    (1 << IWH_SCD_QUEUE_STTS_REG_POS_ACTIVE) |
5363 		    (i << IWH_SCD_QUEUE_STTS_REG_POS_TXF) |
5364 		    (1 << IWH_SCD_QUEUE_STTS_REG_POS_WSL) |
5365 		    IWH_SCD_QUEUE_STTS_REG_MSK);
5366 	}
5367 
5368 	iwh_mac_access_exit(sc);
5369 
5370 	(void) memset(&w_cmd, 0, sizeof (w_cmd));
5371 
5372 	rv = iwh_cmd(sc, COEX_PRIORITY_TABLE_CMD, &w_cmd, sizeof (w_cmd), 1);
5373 	if (rv != IWH_SUCCESS) {
5374 		cmn_err(CE_WARN, "iwh_alive_common(): "
5375 		    "failed to send wimax coexist command.\n");
5376 		return (rv);
5377 	}
5378 
5379 	if ((sc->sc_dev_id != 0x423c) &&
5380 	    (sc->sc_dev_id != 0x423d)) {
5381 		(void) memset(&c_cmd, 0, sizeof (c_cmd));
5382 
5383 		c_cmd.opCode = PHY_CALIBRATE_CRYSTAL_FRQ_CMD;
5384 		c_cmd.data.cap_pin1 = LE_16(sc->sc_eep_calib->xtal_calib[0]);
5385 		c_cmd.data.cap_pin2 = LE_16(sc->sc_eep_calib->xtal_calib[1]);
5386 
5387 		rv = iwh_cmd(sc, REPLY_PHY_CALIBRATION_CMD,
5388 		    &c_cmd, sizeof (c_cmd), 1);
5389 		if (rv != IWH_SUCCESS) {
5390 			cmn_err(CE_WARN, "iwh_alive_common(): "
5391 			    "failed to send crystal"
5392 			    "frq calibration command.\n");
5393 			return (rv);
5394 		}
5395 
5396 		/*
5397 		 * make sure crystal frequency calibration ready
5398 		 * before next operations.
5399 		 */
5400 		DELAY(1000);
5401 	}
5402 
5403 	return (IWH_SUCCESS);
5404 }
5405 
5406 /*
5407  * save results of calibration from ucode
5408  */
5409 static void
5410 iwh_save_calib_result(iwh_sc_t *sc, iwh_rx_desc_t *desc)
5411 {
5412 	struct iwh_calib_results *res_p = &sc->sc_calib_results;
5413 	struct iwh_calib_hdr *calib_hdr = (struct iwh_calib_hdr *)(desc + 1);
5414 	int len = LE_32(desc->len);
5415 
5416 	/*
5417 	 * ensure the size of buffer is not too big
5418 	 */
5419 	len = (len & FH_RSCSR_FRAME_SIZE_MASK) - 4;
5420 
5421 	switch (calib_hdr->op_code) {
5422 	case PHY_CALIBRATE_LO_CMD:
5423 		if (NULL == res_p->lo_res) {
5424 			res_p->lo_res = kmem_alloc(len, KM_NOSLEEP);
5425 		}
5426 
5427 		if (NULL == res_p->lo_res) {
5428 			cmn_err(CE_WARN, "iwh_save_calib_result(): "
5429 			    "failed to allocate memory.\n");
5430 			return;
5431 		}
5432 
5433 		res_p->lo_res_len = len;
5434 		bcopy(calib_hdr, res_p->lo_res, len);
5435 		break;
5436 
5437 	case PHY_CALIBRATE_TX_IQ_CMD:
5438 		if (NULL == res_p->tx_iq_res) {
5439 			res_p->tx_iq_res = kmem_alloc(len, KM_NOSLEEP);
5440 		}
5441 
5442 		if (NULL == res_p->tx_iq_res) {
5443 			cmn_err(CE_WARN, "iwh_save_calib_result(): "
5444 			    "failed to allocate memory.\n");
5445 			return;
5446 		}
5447 
5448 		res_p->tx_iq_res_len = len;
5449 		bcopy(calib_hdr, res_p->tx_iq_res, len);
5450 		break;
5451 
5452 	case PHY_CALIBRATE_TX_IQ_PERD_CMD:
5453 		if (NULL == res_p->tx_iq_perd_res) {
5454 			res_p->tx_iq_perd_res = kmem_alloc(len, KM_NOSLEEP);
5455 		}
5456 
5457 		if (NULL == res_p->tx_iq_perd_res) {
5458 			cmn_err(CE_WARN, "iwh_save_calib_result(): "
5459 			    "failed to allocate memory.\n");
5460 			return;
5461 		}
5462 
5463 		res_p->tx_iq_perd_res_len = len;
5464 		bcopy(calib_hdr, res_p->tx_iq_perd_res, len);
5465 		break;
5466 
5467 	case PHY_CALIBRATE_DC_CMD:
5468 		if (NULL == res_p->dc_res) {
5469 			res_p->dc_res = kmem_alloc(len, KM_NOSLEEP);
5470 		}
5471 
5472 		if (NULL == res_p->dc_res) {
5473 			cmn_err(CE_WARN, "iwh_save_calib_result(): "
5474 			    "failed to allocate memory.\n");
5475 			return;
5476 		}
5477 
5478 		res_p->dc_res_len = len;
5479 		bcopy(calib_hdr, res_p->dc_res, len);
5480 		break;
5481 
5482 	case PHY_CALIBRATE_BASE_BAND_CMD:
5483 		if (NULL == res_p->base_band_res) {
5484 			res_p->base_band_res = kmem_alloc(len, KM_NOSLEEP);
5485 		}
5486 
5487 		if (NULL == res_p->base_band_res) {
5488 			cmn_err(CE_WARN, "iwh_save_calib_result(): "
5489 			    "failed to allocate memory.\n");
5490 			return;
5491 		}
5492 
5493 		res_p->base_band_res_len = len;
5494 		bcopy(calib_hdr, res_p->base_band_res, len);
5495 		break;
5496 
5497 	default:
5498 		cmn_err(CE_WARN, "iwh_save_calib_result(): "
5499 		    "incorrect calibration type(%d).\n", calib_hdr->op_code);
5500 		break;
5501 	}
5502 
5503 }
5504 
5505 /*
5506  * configure TX pwoer table
5507  */
5508 static int
5509 iwh_tx_power_table(iwh_sc_t *sc, int async)
5510 {
5511 	iwh_tx_power_table_cmd_t txpower;
5512 	int i, err = IWH_FAIL;
5513 
5514 	(void) memset(&txpower, 0, sizeof (txpower));
5515 
5516 	txpower.band = 1; /* for 2.4G */
5517 	txpower.channel = (uint8_t)LE_16(sc->sc_config.chan);
5518 	txpower.pa_measurements = 1;
5519 	txpower.max_mcs = 23;
5520 
5521 	for (i = 0; i < 24; i++) {
5522 		txpower.db.ht_ofdm_power[i].s.radio_tx_gain[0] = 0x16;
5523 		txpower.db.ht_ofdm_power[i].s.radio_tx_gain[1] = 0x16;
5524 		txpower.db.ht_ofdm_power[i].s.radio_tx_gain[2] = 0x16;
5525 		txpower.db.ht_ofdm_power[i].s.dsp_predis_atten[0] = 0x6E;
5526 		txpower.db.ht_ofdm_power[i].s.dsp_predis_atten[1] = 0x6E;
5527 		txpower.db.ht_ofdm_power[i].s.dsp_predis_atten[2] = 0x6E;
5528 	}
5529 
5530 	for (i = 0; i < 2; i++) {
5531 		txpower.db.cck_power[i].s.radio_tx_gain[0] = 0x16;
5532 		txpower.db.cck_power[i].s.radio_tx_gain[1] = 0x16;
5533 		txpower.db.cck_power[i].s.radio_tx_gain[2] = 0x16;
5534 		txpower.db.cck_power[i].s.dsp_predis_atten[0] = 0x6E;
5535 		txpower.db.cck_power[i].s.dsp_predis_atten[1] = 0x6E;
5536 		txpower.db.cck_power[i].s.dsp_predis_atten[2] = 0x6E;
5537 	}
5538 
5539 	err = iwh_cmd(sc, REPLY_TX_PWR_TABLE_CMD, &txpower,
5540 	    sizeof (txpower), async);
5541 	if (err != IWH_SUCCESS) {
5542 		cmn_err(CE_WARN, "iwh_tx_power_table(): "
5543 		    "failed to set tx power table.\n");
5544 		return (err);
5545 	}
5546 
5547 	return (err);
5548 }
5549 
5550 static void
5551 iwh_release_calib_buffer(iwh_sc_t *sc)
5552 {
5553 	if (sc->sc_calib_results.lo_res != NULL) {
5554 		kmem_free(sc->sc_calib_results.lo_res,
5555 		    sc->sc_calib_results.lo_res_len);
5556 		sc->sc_calib_results.lo_res = NULL;
5557 	}
5558 
5559 	if (sc->sc_calib_results.tx_iq_res != NULL) {
5560 		kmem_free(sc->sc_calib_results.tx_iq_res,
5561 		    sc->sc_calib_results.tx_iq_res_len);
5562 		sc->sc_calib_results.tx_iq_res = NULL;
5563 	}
5564 
5565 	if (sc->sc_calib_results.tx_iq_perd_res != NULL) {
5566 		kmem_free(sc->sc_calib_results.tx_iq_perd_res,
5567 		    sc->sc_calib_results.tx_iq_perd_res_len);
5568 		sc->sc_calib_results.tx_iq_perd_res = NULL;
5569 	}
5570 
5571 	if (sc->sc_calib_results.dc_res != NULL) {
5572 		kmem_free(sc->sc_calib_results.dc_res,
5573 		    sc->sc_calib_results.dc_res_len);
5574 		sc->sc_calib_results.dc_res = NULL;
5575 	}
5576 
5577 	if (sc->sc_calib_results.base_band_res != NULL) {
5578 		kmem_free(sc->sc_calib_results.base_band_res,
5579 		    sc->sc_calib_results.base_band_res_len);
5580 		sc->sc_calib_results.base_band_res = NULL;
5581 	}
5582 }
5583 
5584 /*
5585  * common section of intialization
5586  */
5587 static int
5588 iwh_init_common(iwh_sc_t *sc)
5589 {
5590 	int32_t	qid;
5591 	uint32_t tmp;
5592 
5593 	if (iwh_reset_hw(sc) != IWH_SUCCESS) {
5594 		cmn_err(CE_WARN, "iwh_init_common(): "
5595 		    "failed to reset hardware\n");
5596 		return (IWH_FAIL);
5597 	}
5598 
5599 	(void) iwh_preinit(sc);
5600 
5601 	tmp = IWH_READ(sc, CSR_GP_CNTRL);
5602 	if (!(tmp & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) {
5603 		cmn_err(CE_NOTE, "iwh_init_common(): "
5604 		    "radio transmitter is off\n");
5605 		return (IWH_FAIL);
5606 	}
5607 
5608 	/*
5609 	 * init Rx ring
5610 	 */
5611 	iwh_mac_access_enter(sc);
5612 	IWH_WRITE(sc, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
5613 
5614 	IWH_WRITE(sc, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0);
5615 	IWH_WRITE(sc, FH_RSCSR_CHNL0_RBDCB_BASE_REG,
5616 	    sc->sc_rxq.dma_desc.cookie.dmac_address >> 8);
5617 
5618 	IWH_WRITE(sc, FH_RSCSR_CHNL0_STTS_WPTR_REG,
5619 	    ((uint32_t)(sc->sc_dma_sh.cookie.dmac_address +
5620 	    offsetof(struct iwh_shared, val0)) >> 4));
5621 
5622 	IWH_WRITE(sc, FH_MEM_RCSR_CHNL0_CONFIG_REG,
5623 	    FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL |
5624 	    FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL |
5625 	    IWH_FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K |
5626 	    (RX_QUEUE_SIZE_LOG <<
5627 	    FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT));
5628 	iwh_mac_access_exit(sc);
5629 	IWH_WRITE(sc, FH_RSCSR_CHNL0_RBDCB_WPTR_REG,
5630 	    (RX_QUEUE_SIZE - 1) & ~0x7);
5631 
5632 	/*
5633 	 * init Tx rings
5634 	 */
5635 	iwh_mac_access_enter(sc);
5636 	iwh_reg_write(sc, IWH_SCD_TXFACT, 0);
5637 
5638 	/*
5639 	 * keep warm page
5640 	 */
5641 	IWH_WRITE(sc, IWH_FH_KW_MEM_ADDR_REG,
5642 	    sc->sc_dma_kw.cookie.dmac_address >> 4);
5643 
5644 	for (qid = 0; qid < IWH_NUM_QUEUES; qid++) {
5645 		IWH_WRITE(sc, FH_MEM_CBBC_QUEUE(qid),
5646 		    sc->sc_txq[qid].dma_desc.cookie.dmac_address >> 8);
5647 		IWH_WRITE(sc, IWH_FH_TCSR_CHNL_TX_CONFIG_REG(qid),
5648 		    IWH_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
5649 		    IWH_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL);
5650 	}
5651 
5652 	iwh_mac_access_exit(sc);
5653 
5654 	/*
5655 	 * clear "radio off" and "disable command" bits
5656 	 */
5657 	IWH_WRITE(sc, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
5658 	IWH_WRITE(sc, CSR_UCODE_DRV_GP1_CLR,
5659 	    CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
5660 
5661 	/*
5662 	 * clear any pending interrupts
5663 	 */
5664 	IWH_WRITE(sc, CSR_INT, 0xffffffff);
5665 
5666 	/*
5667 	 * enable interrupts
5668 	 */
5669 	IWH_WRITE(sc, CSR_INT_MASK, CSR_INI_SET_MASK);
5670 
5671 	IWH_WRITE(sc, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
5672 	IWH_WRITE(sc, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
5673 
5674 	return (IWH_SUCCESS);
5675 }
5676 
5677 static int
5678 iwh_fast_recover(iwh_sc_t *sc)
5679 {
5680 	ieee80211com_t *ic = &sc->sc_ic;
5681 	int err = IWH_FAIL;
5682 
5683 	mutex_enter(&sc->sc_glock);
5684 
5685 	/*
5686 	 * restore runtime configuration
5687 	 */
5688 	bcopy(&sc->sc_config_save, &sc->sc_config,
5689 	    sizeof (sc->sc_config));
5690 
5691 	sc->sc_config.assoc_id = 0;
5692 	sc->sc_config.filter_flags &= ~LE_32(RXON_FILTER_ASSOC_MSK);
5693 
5694 	if ((err = iwh_hw_set_before_auth(sc)) != IWH_SUCCESS) {
5695 		cmn_err(CE_WARN, "iwh_fast_recover(): "
5696 		    "could not setup authentication\n");
5697 		mutex_exit(&sc->sc_glock);
5698 		return (err);
5699 	}
5700 
5701 	bcopy(&sc->sc_config_save, &sc->sc_config,
5702 	    sizeof (sc->sc_config));
5703 
5704 	/*
5705 	 * update adapter's configuration
5706 	 */
5707 	err = iwh_run_state_config(sc);
5708 	if (err != IWH_SUCCESS) {
5709 		cmn_err(CE_WARN, "iwh_fast_recover(): "
5710 		    "failed to setup association\n");
5711 		mutex_exit(&sc->sc_glock);
5712 		return (err);
5713 	}
5714 
5715 	/*
5716 	 * set LED on
5717 	 */
5718 	iwh_set_led(sc, 2, 0, 1);
5719 
5720 	mutex_exit(&sc->sc_glock);
5721 
5722 	atomic_and_32(&sc->sc_flags, ~IWH_F_HW_ERR_RECOVER);
5723 
5724 	/*
5725 	 * start queue
5726 	 */
5727 	IWH_DBG((IWH_DEBUG_FW, "iwh_fast_recover(): "
5728 	    "resume xmit\n"));
5729 	mac_tx_update(ic->ic_mach);
5730 
5731 	return (IWH_SUCCESS);
5732 }
5733 
5734 static int
5735 iwh_run_state_config(iwh_sc_t *sc)
5736 {
5737 	struct ieee80211com *ic = &sc->sc_ic;
5738 	ieee80211_node_t *in = ic->ic_bss;
5739 	uint32_t ht_protec = (uint32_t)(-1);
5740 	int err = IWH_FAIL;
5741 
5742 	/*
5743 	 * update adapter's configuration
5744 	 */
5745 	sc->sc_config.assoc_id = in->in_associd & 0x3fff;
5746 
5747 	/*
5748 	 * short preamble/slot time are
5749 	 * negotiated when associating
5750 	 */
5751 	sc->sc_config.flags &=
5752 	    ~LE_32(RXON_FLG_SHORT_PREAMBLE_MSK |
5753 	    RXON_FLG_SHORT_SLOT_MSK);
5754 
5755 	if (ic->ic_flags & IEEE80211_F_SHSLOT) {
5756 		sc->sc_config.flags |=
5757 		    LE_32(RXON_FLG_SHORT_SLOT_MSK);
5758 	}
5759 
5760 	if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) {
5761 		sc->sc_config.flags |=
5762 		    LE_32(RXON_FLG_SHORT_PREAMBLE_MSK);
5763 	}
5764 
5765 	if (in->in_flags & IEEE80211_NODE_HT) {
5766 		ht_protec = in->in_htopmode;
5767 		if (ht_protec > 3) {
5768 			cmn_err(CE_WARN, "iwh_run_state_config(): "
5769 			    "HT protection mode is not correct.\n");
5770 			return (IWH_FAIL);
5771 		} else if (NO_HT_PROT == ht_protec) {
5772 			ht_protec = sc->sc_ht_conf.ht_protection;
5773 		}
5774 
5775 		sc->sc_config.flags |=
5776 		    LE_32(ht_protec << RXON_FLG_HT_OPERATING_MODE_POS);
5777 	}
5778 
5779 	/*
5780 	 * set RX chains/antennas.
5781 	 */
5782 	iwh_config_rxon_chain(sc);
5783 
5784 	sc->sc_config.filter_flags |=
5785 	    LE_32(RXON_FILTER_ASSOC_MSK);
5786 
5787 	if (ic->ic_opmode != IEEE80211_M_STA) {
5788 		sc->sc_config.filter_flags |=
5789 		    LE_32(RXON_FILTER_BCON_AWARE_MSK);
5790 	}
5791 
5792 	IWH_DBG((IWH_DEBUG_80211, "iwh_run_state_config(): "
5793 	    "config chan %d flags %x"
5794 	    " filter_flags %x\n",
5795 	    sc->sc_config.chan, sc->sc_config.flags,
5796 	    sc->sc_config.filter_flags));
5797 
5798 	err = iwh_cmd(sc, REPLY_RXON, &sc->sc_config,
5799 	    sizeof (iwh_rxon_cmd_t), 1);
5800 	if (err != IWH_SUCCESS) {
5801 		cmn_err(CE_WARN, "iwh_run_state_config(): "
5802 		    "could not update configuration\n");
5803 		return (err);
5804 	}
5805 
5806 	if ((sc->sc_dev_id != 0x423c) &&
5807 	    (sc->sc_dev_id != 0x423d)) {
5808 		/*
5809 		 * send tx power table command
5810 		 */
5811 		err = iwh_tx_power_table(sc, 1);
5812 		if (err != IWH_SUCCESS) {
5813 			return (err);
5814 		}
5815 	}
5816 
5817 	/*
5818 	 * Not need to update retry rate table for AP node
5819 	 */
5820 	err = iwh_qosparam_to_hw(sc, 1);
5821 	if (err != IWH_SUCCESS) {
5822 		return (err);
5823 	}
5824 
5825 	return (err);
5826 }
5827 
5828 /*
5829  * This function is only for compatibility with Net80211 module.
5830  * iwh_qosparam_to_hw() is the actual function updating EDCA
5831  * parameters to hardware.
5832  */
5833 /* ARGSUSED */
5834 static int
5835 iwh_wme_update(ieee80211com_t *ic)
5836 {
5837 	return (0);
5838 }
5839 
5840 static int
5841 iwh_wme_to_qos_ac(int wme_ac)
5842 {
5843 	int qos_ac = QOS_AC_INVALID;
5844 
5845 	if (wme_ac < WME_AC_BE || wme_ac > WME_AC_VO) {
5846 		cmn_err(CE_WARN, "iwh_wme_to_qos_ac(): "
5847 		    "WME AC index is not in suitable range.\n");
5848 		return (qos_ac);
5849 	}
5850 
5851 	switch (wme_ac) {
5852 	case WME_AC_BE:
5853 		qos_ac = QOS_AC_BK;
5854 		break;
5855 	case WME_AC_BK:
5856 		qos_ac = QOS_AC_BE;
5857 		break;
5858 	case WME_AC_VI:
5859 		qos_ac = QOS_AC_VI;
5860 		break;
5861 	case WME_AC_VO:
5862 		qos_ac = QOS_AC_VO;
5863 		break;
5864 	}
5865 
5866 	return (qos_ac);
5867 }
5868 
5869 static uint16_t
5870 iwh_cw_e_to_cw(uint8_t cw_e)
5871 {
5872 	uint16_t cw = 1;
5873 
5874 	while (cw_e > 0) {
5875 		cw <<= 1;
5876 		cw_e--;
5877 	}
5878 
5879 	cw -= 1;
5880 	return (cw);
5881 }
5882 
5883 static int
5884 iwh_wmeparam_check(struct wmeParams *wmeparam)
5885 {
5886 	int i;
5887 
5888 	for (i = 0; i < WME_NUM_AC; i++) {
5889 
5890 		if ((wmeparam[i].wmep_logcwmax > QOS_CW_RANGE_MAX) ||
5891 		    (wmeparam[i].wmep_logcwmin >= wmeparam[i].wmep_logcwmax)) {
5892 			cmn_err(CE_WARN, "iwh_wmeparam_check(): "
5893 			    "Contention window is not in suitable range.\n");
5894 			return (IWH_FAIL);
5895 		}
5896 
5897 		if ((wmeparam[i].wmep_aifsn < QOS_AIFSN_MIN) ||
5898 		    (wmeparam[i].wmep_aifsn > QOS_AIFSN_MAX)) {
5899 			cmn_err(CE_WARN, "iwh_wmeparam_check(): "
5900 			    "Arbitration interframe space number"
5901 			    "is not in suitable range.\n");
5902 			return (IWH_FAIL);
5903 		}
5904 	}
5905 
5906 	return (IWH_SUCCESS);
5907 }
5908 
5909 /*
5910  * This function updates EDCA parameters into hardware.
5911  * FIFO0-background, FIFO1-best effort, FIFO2-viedo, FIFO3-voice.
5912  */
5913 static int
5914 iwh_qosparam_to_hw(iwh_sc_t *sc, int async)
5915 {
5916 	ieee80211com_t *ic = &sc->sc_ic;
5917 	ieee80211_node_t *in = ic->ic_bss;
5918 	struct wmeParams *wmeparam;
5919 	iwh_qos_param_cmd_t qosparam_cmd;
5920 	int i, j;
5921 	int err = IWH_FAIL;
5922 
5923 	if ((in->in_flags & IEEE80211_NODE_QOS) &&
5924 	    (IEEE80211_M_STA == ic->ic_opmode)) {
5925 		wmeparam = ic->ic_wme.wme_chanParams.cap_wmeParams;
5926 	} else {
5927 		return (IWH_SUCCESS);
5928 	}
5929 
5930 	(void) memset(&qosparam_cmd, 0, sizeof (qosparam_cmd));
5931 
5932 	err = iwh_wmeparam_check(wmeparam);
5933 	if (err != IWH_SUCCESS) {
5934 		return (err);
5935 	}
5936 
5937 	if (in->in_flags & IEEE80211_NODE_QOS) {
5938 		qosparam_cmd.flags |= QOS_PARAM_FLG_UPDATE_EDCA;
5939 	}
5940 
5941 	if (in->in_flags & (IEEE80211_NODE_QOS | IEEE80211_NODE_HT)) {
5942 		qosparam_cmd.flags |= QOS_PARAM_FLG_TGN;
5943 	}
5944 
5945 	for (i = 0; i < WME_NUM_AC; i++) {
5946 
5947 		j = iwh_wme_to_qos_ac(i);
5948 		if (j < QOS_AC_BK || j > QOS_AC_VO) {
5949 			return (IWH_FAIL);
5950 		}
5951 
5952 		qosparam_cmd.ac[j].cw_min =
5953 		    iwh_cw_e_to_cw(wmeparam[i].wmep_logcwmin);
5954 		qosparam_cmd.ac[j].cw_max =
5955 		    iwh_cw_e_to_cw(wmeparam[i].wmep_logcwmax);
5956 		qosparam_cmd.ac[j].aifsn =
5957 		    wmeparam[i].wmep_aifsn;
5958 		qosparam_cmd.ac[j].txop =
5959 		    (uint16_t)(wmeparam[i].wmep_txopLimit * 32);
5960 	}
5961 
5962 	err = iwh_cmd(sc, REPLY_QOS_PARAM, &qosparam_cmd,
5963 	    sizeof (qosparam_cmd), async);
5964 	if (err != IWH_SUCCESS) {
5965 		cmn_err(CE_WARN, "iwh_qosparam_to_hw(): "
5966 		    "failed to update QoS parameters into hardware.\n");
5967 		return (err);
5968 	}
5969 
5970 #ifdef	DEBUG
5971 	IWH_DBG((IWH_DEBUG_QOS, "iwh_qosparam_to_hw(): "
5972 	    "EDCA parameters are as follows:\n"));
5973 
5974 	IWH_DBG((IWH_DEBUG_QOS, "BK parameters are: "
5975 	    "cw_min = %d, cw_max = %d, aifsn = %d, txop = %d\n",
5976 	    qosparam_cmd.ac[0].cw_min, qosparam_cmd.ac[0].cw_max,
5977 	    qosparam_cmd.ac[0].aifsn, qosparam_cmd.ac[0].txop));
5978 
5979 	IWH_DBG((IWH_DEBUG_QOS, "BE parameters are: "
5980 	    "cw_min = %d, cw_max = %d, aifsn = %d, txop = %d\n",
5981 	    qosparam_cmd.ac[1].cw_min, qosparam_cmd.ac[1].cw_max,
5982 	    qosparam_cmd.ac[1].aifsn, qosparam_cmd.ac[1].txop));
5983 
5984 	IWH_DBG((IWH_DEBUG_QOS, "VI parameters are: "
5985 	    "cw_min = %d, cw_max = %d, aifsn = %d, txop = %d\n",
5986 	    qosparam_cmd.ac[2].cw_min, qosparam_cmd.ac[2].cw_max,
5987 	    qosparam_cmd.ac[2].aifsn, qosparam_cmd.ac[2].txop));
5988 
5989 	IWH_DBG((IWH_DEBUG_QOS, "VO parameters are: "
5990 	    "cw_min = %d, cw_max = %d, aifsn = %d, txop = %d\n",
5991 	    qosparam_cmd.ac[3].cw_min, qosparam_cmd.ac[3].cw_max,
5992 	    qosparam_cmd.ac[3].aifsn, qosparam_cmd.ac[3].txop));
5993 #endif
5994 	return (err);
5995 }
5996 
5997 static inline int
5998 iwh_wme_tid_qos_ac(int tid)
5999 {
6000 	switch (tid) {
6001 	case 1:
6002 	case 2:
6003 		return (QOS_AC_BK);
6004 	case 0:
6005 	case 3:
6006 		return (QOS_AC_BE);
6007 	case 4:
6008 	case 5:
6009 		return (QOS_AC_VI);
6010 	case 6:
6011 	case 7:
6012 		return (QOS_AC_VO);
6013 	}
6014 
6015 	return (QOS_AC_BE);
6016 }
6017 
6018 static inline int
6019 iwh_qos_ac_to_txq(int qos_ac)
6020 {
6021 	switch (qos_ac) {
6022 	case QOS_AC_BK:
6023 		return (QOS_AC_BK_TO_TXQ);
6024 	case QOS_AC_BE:
6025 		return (QOS_AC_BE_TO_TXQ);
6026 	case QOS_AC_VI:
6027 		return (QOS_AC_VI_TO_TXQ);
6028 	case QOS_AC_VO:
6029 		return (QOS_AC_VO_TO_TXQ);
6030 	}
6031 
6032 	return (QOS_AC_BE_TO_TXQ);
6033 }
6034 
6035 static int
6036 iwh_wme_tid_to_txq(int tid)
6037 {
6038 	int queue_n = TXQ_FOR_AC_INVALID;
6039 	int qos_ac;
6040 
6041 	if (tid < WME_TID_MIN ||
6042 	    tid > WME_TID_MAX) {
6043 		cmn_err(CE_WARN, "wme_tid_to_txq(): "
6044 		    "TID is not in suitable range.\n");
6045 		return (queue_n);
6046 	}
6047 
6048 	qos_ac = iwh_wme_tid_qos_ac(tid);
6049 	queue_n = iwh_qos_ac_to_txq(qos_ac);
6050 
6051 	return (queue_n);
6052 }
6053 
6054 /*
6055  * This function is used for intializing HT relevant configurations.
6056  */
6057 static void
6058 iwh_init_ht_conf(iwh_sc_t *sc)
6059 {
6060 	(void) memset(&sc->sc_ht_conf, 0, sizeof (iwh_ht_conf_t));
6061 
6062 	if ((0x4235 == sc->sc_dev_id) ||
6063 	    (0x4236 == sc->sc_dev_id) ||
6064 	    (0x423a == sc->sc_dev_id)) {
6065 		sc->sc_ht_conf.ht_support = 1;
6066 
6067 		sc->sc_ht_conf.valid_chains = 3;
6068 		sc->sc_ht_conf.tx_stream_count = 2;
6069 		sc->sc_ht_conf.rx_stream_count = 2;
6070 
6071 		sc->sc_ht_conf.tx_support_mcs[0] = 0xff;
6072 		sc->sc_ht_conf.tx_support_mcs[1] = 0xff;
6073 		sc->sc_ht_conf.rx_support_mcs[0] = 0xff;
6074 		sc->sc_ht_conf.rx_support_mcs[1] = 0xff;
6075 	} else {
6076 		sc->sc_ht_conf.ht_support = 1;
6077 
6078 		sc->sc_ht_conf.valid_chains = 2;
6079 		sc->sc_ht_conf.tx_stream_count = 1;
6080 		sc->sc_ht_conf.rx_stream_count = 2;
6081 
6082 		sc->sc_ht_conf.tx_support_mcs[0] = 0xff;
6083 		sc->sc_ht_conf.rx_support_mcs[0] = 0xff;
6084 		sc->sc_ht_conf.rx_support_mcs[1] = 0xff;
6085 	}
6086 
6087 	if (sc->sc_ht_conf.ht_support) {
6088 		sc->sc_ht_conf.cap |= HT_CAP_GRN_FLD;
6089 		sc->sc_ht_conf.cap |= HT_CAP_SGI_20;
6090 		sc->sc_ht_conf.cap |= HT_CAP_MAX_AMSDU;
6091 		/* should disable MIMO */
6092 		sc->sc_ht_conf.cap |= HT_CAP_MIMO_PS;
6093 
6094 		sc->sc_ht_conf.ampdu_p.factor = HT_RX_AMPDU_FACTOR;
6095 		sc->sc_ht_conf.ampdu_p.density = HT_MPDU_DENSITY;
6096 
6097 		sc->sc_ht_conf.ht_protection = HT_PROT_CHAN_NON_HT;
6098 	}
6099 }
6100 
6101 /*
6102  * This function overwrites default ieee80211_rateset_11n struc.
6103  */
6104 static void
6105 iwh_overwrite_11n_rateset(iwh_sc_t *sc)
6106 {
6107 	uint8_t *ht_rs = sc->sc_ht_conf.rx_support_mcs;
6108 	int mcs_idx, mcs_count = 0;
6109 	int i, j;
6110 
6111 	for (i = 0; i < HT_RATESET_NUM; i++) {
6112 		for (j = 0; j < 8; j++) {
6113 			if (ht_rs[i] & (1 << j)) {
6114 				mcs_idx = i * 8 + j;
6115 				if (mcs_idx >= IEEE80211_HTRATE_MAXSIZE) {
6116 					break;
6117 				}
6118 
6119 				ieee80211_rateset_11n.rs_rates[mcs_idx] =
6120 				    (uint8_t)mcs_idx;
6121 				mcs_count++;
6122 			}
6123 		}
6124 	}
6125 
6126 	ieee80211_rateset_11n.rs_nrates = (uint8_t)mcs_count;
6127 
6128 #ifdef	DEBUG
6129 	IWH_DBG((IWH_DEBUG_HTRATE, "iwh_overwrite_11n_rateset(): "
6130 	    "HT rates supported by this station is as follows:\n"));
6131 
6132 	for (i = 0; i < ieee80211_rateset_11n.rs_nrates; i++) {
6133 		IWH_DBG((IWH_DEBUG_HTRATE, "Rate %d is %d\n",
6134 		    i, ieee80211_rateset_11n.rs_rates[i]));
6135 	}
6136 #endif
6137 }
6138 
6139 /*
6140  * This function overwrites default configurations of
6141  * ieee80211com structure in Net80211 module.
6142  */
6143 static void
6144 iwh_overwrite_ic_default(iwh_sc_t *sc)
6145 {
6146 	ieee80211com_t *ic = &sc->sc_ic;
6147 
6148 	sc->sc_newstate = ic->ic_newstate;
6149 	ic->ic_newstate = iwh_newstate;
6150 	ic->ic_node_alloc = iwh_node_alloc;
6151 	ic->ic_node_free = iwh_node_free;
6152 
6153 	if (sc->sc_ht_conf.ht_support) {
6154 		sc->sc_recv_action = ic->ic_recv_action;
6155 		ic->ic_recv_action = iwh_recv_action;
6156 		sc->sc_send_action = ic->ic_send_action;
6157 		ic->ic_send_action = iwh_send_action;
6158 
6159 		ic->ic_ampdu_rxmax = sc->sc_ht_conf.ampdu_p.factor;
6160 		ic->ic_ampdu_density = sc->sc_ht_conf.ampdu_p.density;
6161 		ic->ic_ampdu_limit = ic->ic_ampdu_rxmax;
6162 	}
6163 }
6164 
6165 /*
6166  * This function sets "RX chain selection" feild
6167  * in RXON command during plumb driver.
6168  */
6169 static void
6170 iwh_config_rxon_chain(iwh_sc_t *sc)
6171 {
6172 	ieee80211com_t *ic = &sc->sc_ic;
6173 	ieee80211_node_t *in = ic->ic_bss;
6174 
6175 	if (3 == sc->sc_ht_conf.valid_chains) {
6176 		sc->sc_config.rx_chain = LE_16((RXON_RX_CHAIN_A_MSK |
6177 		    RXON_RX_CHAIN_B_MSK | RXON_RX_CHAIN_C_MSK) <<
6178 		    RXON_RX_CHAIN_VALID_POS);
6179 
6180 		sc->sc_config.rx_chain |= LE_16((RXON_RX_CHAIN_A_MSK |
6181 		    RXON_RX_CHAIN_B_MSK | RXON_RX_CHAIN_C_MSK) <<
6182 		    RXON_RX_CHAIN_FORCE_SEL_POS);
6183 
6184 		sc->sc_config.rx_chain |= LE_16((RXON_RX_CHAIN_A_MSK |
6185 		    RXON_RX_CHAIN_B_MSK | RXON_RX_CHAIN_C_MSK) <<
6186 		    RXON_RX_CHAIN_FORCE_MIMO_SEL_POS);
6187 	} else {
6188 		sc->sc_config.rx_chain = LE_16((RXON_RX_CHAIN_A_MSK |
6189 		    RXON_RX_CHAIN_B_MSK) << RXON_RX_CHAIN_VALID_POS);
6190 
6191 		sc->sc_config.rx_chain |= LE_16((RXON_RX_CHAIN_A_MSK |
6192 		    RXON_RX_CHAIN_B_MSK) << RXON_RX_CHAIN_FORCE_SEL_POS);
6193 
6194 		sc->sc_config.rx_chain |= LE_16((RXON_RX_CHAIN_A_MSK |
6195 		    RXON_RX_CHAIN_B_MSK) <<
6196 		    RXON_RX_CHAIN_FORCE_MIMO_SEL_POS);
6197 	}
6198 
6199 	sc->sc_config.rx_chain |= LE_16(RXON_RX_CHAIN_DRIVER_FORCE_MSK);
6200 
6201 	if ((in != NULL) &&
6202 	    (in->in_flags & IEEE80211_NODE_HT) &&
6203 	    sc->sc_ht_conf.ht_support) {
6204 		if (3 == sc->sc_ht_conf.valid_chains) {
6205 			sc->sc_config.rx_chain |= LE_16(3 <<
6206 			    RXON_RX_CHAIN_CNT_POS);
6207 			sc->sc_config.rx_chain |= LE_16(3 <<
6208 			    RXON_RX_CHAIN_MIMO_CNT_POS);
6209 		} else {
6210 			sc->sc_config.rx_chain |= LE_16(2 <<
6211 			    RXON_RX_CHAIN_CNT_POS);
6212 			sc->sc_config.rx_chain |= LE_16(2 <<
6213 			    RXON_RX_CHAIN_MIMO_CNT_POS);
6214 		}
6215 
6216 		sc->sc_config.rx_chain |= LE_16(1 <<
6217 		    RXON_RX_CHAIN_MIMO_FORCE_POS);
6218 	}
6219 
6220 	IWH_DBG((IWH_DEBUG_RXON, "iwh_config_rxon_chain(): "
6221 	    "rxon->rx_chain = %x\n", sc->sc_config.rx_chain));
6222 }
6223 
6224 /*
6225  * This function adds AP station into hardware.
6226  */
6227 static int
6228 iwh_add_ap_sta(iwh_sc_t *sc)
6229 {
6230 	ieee80211com_t *ic = &sc->sc_ic;
6231 	ieee80211_node_t *in = ic->ic_bss;
6232 	iwh_add_sta_t node;
6233 	uint32_t ampdu_factor, ampdu_density;
6234 	int err = IWH_FAIL;
6235 
6236 	/*
6237 	 * Add AP node into hardware.
6238 	 */
6239 	(void) memset(&node, 0, sizeof (node));
6240 	IEEE80211_ADDR_COPY(node.sta.addr, in->in_bssid);
6241 	node.mode = STA_MODE_ADD_MSK;
6242 	node.sta.sta_id = IWH_AP_ID;
6243 
6244 	if (sc->sc_ht_conf.ht_support &&
6245 	    (in->in_htcap_ie != NULL) &&
6246 	    (in->in_htcap != 0) &&
6247 	    (in->in_htparam != 0)) {
6248 
6249 		if (((in->in_htcap & HT_CAP_MIMO_PS) >> 2)
6250 		    == HT_CAP_MIMO_PS_DYNAMIC) {
6251 			node.station_flags |= LE_32(STA_FLG_RTS_MIMO_PROT);
6252 		}
6253 
6254 		ampdu_factor = in->in_htparam & HT_RX_AMPDU_FACTOR_MSK;
6255 		node.station_flags |=
6256 		    LE_32(ampdu_factor << STA_FLG_MAX_AMPDU_POS);
6257 
6258 		ampdu_density = (in->in_htparam & HT_MPDU_DENSITY_MSK) >>
6259 		    HT_MPDU_DENSITY_POS;
6260 		node.station_flags |=
6261 		    LE_32(ampdu_density << STA_FLG_AMPDU_DENSITY_POS);
6262 
6263 		if (in->in_htcap & LE_16(HT_CAP_SUP_WIDTH)) {
6264 			node.station_flags |=
6265 			    LE_32(STA_FLG_FAT_EN);
6266 		}
6267 	}
6268 
6269 	err = iwh_cmd(sc, REPLY_ADD_STA, &node, sizeof (node), 1);
6270 	if (err != IWH_SUCCESS) {
6271 		cmn_err(CE_WARN, "iwh_add_ap_lq(): "
6272 		    "failed to add AP node\n");
6273 		return (err);
6274 	}
6275 
6276 	return (err);
6277 }
6278 
6279 /*
6280  * Each station in the Shirley Peak's internal station table has
6281  * its own table of 16 TX rates and modulation modes for retrying
6282  * TX when an ACK is not received. This function replaces the entire
6283  * table for one station.Station must already be in Shirley Peak's
6284  * station talbe.
6285  */
6286 static int
6287 iwh_ap_lq(iwh_sc_t *sc)
6288 {
6289 	ieee80211com_t *ic = &sc->sc_ic;
6290 	ieee80211_node_t *in = ic->ic_bss;
6291 	iwh_link_quality_cmd_t link_quality;
6292 	const struct ieee80211_rateset *rs_sup = NULL;
6293 	uint32_t masks = 0, rate;
6294 	int i, err = IWH_FAIL;
6295 
6296 	/*
6297 	 * TX_LINK_QUALITY cmd
6298 	 */
6299 	(void) memset(&link_quality, 0, sizeof (link_quality));
6300 	if (in->in_chan == IEEE80211_CHAN_ANYC)	/* skip null node */
6301 		return (err);
6302 	rs_sup = ieee80211_get_suprates(ic, in->in_chan);
6303 
6304 	for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
6305 		if (i < rs_sup->ir_nrates) {
6306 			rate = rs_sup->ir_rates[rs_sup->ir_nrates - i] &
6307 			    IEEE80211_RATE_VAL;
6308 		} else {
6309 			rate = 2;
6310 		}
6311 
6312 		if (2 == rate || 4 == rate ||
6313 		    11 == rate || 22 == rate) {
6314 			masks |= LE_32(RATE_MCS_CCK_MSK);
6315 		}
6316 
6317 		masks |= LE_32(RATE_MCS_ANT_B_MSK);
6318 
6319 		link_quality.rate_n_flags[i] =
6320 		    LE_32(iwh_rate_to_plcp(rate) | masks);
6321 	}
6322 
6323 	link_quality.general_params.single_stream_ant_msk = LINK_QUAL_ANT_B_MSK;
6324 	link_quality.general_params.dual_stream_ant_msk = LINK_QUAL_ANT_MSK;
6325 	link_quality.agg_params.agg_dis_start_th = 3;
6326 	link_quality.agg_params.agg_time_limit = LE_16(4000);
6327 	link_quality.sta_id = IWH_AP_ID;
6328 	err = iwh_cmd(sc, REPLY_TX_LINK_QUALITY_CMD, &link_quality,
6329 	    sizeof (link_quality), 1);
6330 	if (err != IWH_SUCCESS) {
6331 		cmn_err(CE_WARN, "iwh_ap_lq(): "
6332 		    "failed to config link quality table\n");
6333 		return (err);
6334 	}
6335 
6336 #ifdef	DEBUG
6337 	IWH_DBG((IWH_DEBUG_HWRATE, "iwh_ap_lq(): "
6338 	    "Rates in HW are as follows:\n"));
6339 
6340 	for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
6341 		IWH_DBG((IWH_DEBUG_HWRATE,
6342 		    "Rate %d in HW is %x\n", i, link_quality.rate_n_flags[i]));
6343 	}
6344 #endif
6345 
6346 	return (err);
6347 }
6348 
6349 /*
6350  * When block ACK agreement has been set up between station and AP,
6351  * Net80211 module will call this function to inform hardware about
6352  * informations of this BA agreement.
6353  * When AP wants to delete BA agreement that was originated by it,
6354  * Net80211 modele will call this function to clean up relevant
6355  * information in hardware.
6356  */
6357 static void
6358 iwh_recv_action(struct ieee80211_node *in,
6359     const uint8_t *frm, const uint8_t *efrm)
6360 {
6361 	struct ieee80211com *ic;
6362 	iwh_sc_t *sc;
6363 	const struct ieee80211_action *ia;
6364 	uint16_t baparamset, baseqctl;
6365 	uint32_t tid, ssn;
6366 	iwh_add_sta_t node;
6367 	int err = IWH_FAIL;
6368 
6369 	if ((NULL == in) || (NULL == frm)) {
6370 		return;
6371 	}
6372 
6373 	ic = in->in_ic;
6374 	if (NULL == ic) {
6375 		return;
6376 	}
6377 
6378 	sc = (iwh_sc_t *)ic;
6379 
6380 	sc->sc_recv_action(in, frm, efrm);
6381 
6382 	ia = (const struct ieee80211_action *)frm;
6383 	if (ia->ia_category != IEEE80211_ACTION_CAT_BA) {
6384 		return;
6385 	}
6386 
6387 	switch (ia->ia_action) {
6388 	case IEEE80211_ACTION_BA_ADDBA_REQUEST:
6389 		baparamset = *(uint16_t *)(frm + 3);
6390 		baseqctl = *(uint16_t *)(frm + 7);
6391 
6392 		tid = MS(baparamset, IEEE80211_BAPS_TID);
6393 		ssn = MS(baseqctl, IEEE80211_BASEQ_START);
6394 
6395 		(void) memset(&node, 0, sizeof (node));
6396 		IEEE80211_ADDR_COPY(node.sta.addr, in->in_bssid);
6397 		node.mode = STA_MODE_MODIFY_MSK;
6398 		node.sta.sta_id = IWH_AP_ID;
6399 
6400 		node.station_flags_msk = 0;
6401 		node.sta.modify_mask = STA_MODIFY_ADDBA_TID_MSK;
6402 		node.add_immediate_ba_tid = (uint8_t)tid;
6403 		node.add_immediate_ba_ssn = LE_16(ssn);
6404 
6405 		mutex_enter(&sc->sc_glock);
6406 		err = iwh_cmd(sc, REPLY_ADD_STA, &node, sizeof (node), 1);
6407 		if (err != IWH_SUCCESS) {
6408 			cmn_err(CE_WARN, "iwh_recv_action(): "
6409 			    "failed to setup RX block ACK\n");
6410 			mutex_exit(&sc->sc_glock);
6411 			return;
6412 		}
6413 		mutex_exit(&sc->sc_glock);
6414 
6415 		IWH_DBG((IWH_DEBUG_BA, "iwh_recv_action(): "
6416 		    "RX block ACK "
6417 		    "was setup on TID %d and SSN is %d.\n", tid, ssn));
6418 
6419 		return;
6420 
6421 	case IEEE80211_ACTION_BA_DELBA:
6422 		baparamset = *(uint16_t *)(frm + 2);
6423 
6424 		if ((baparamset & IEEE80211_DELBAPS_INIT) == 0) {
6425 			return;
6426 		}
6427 
6428 		tid = MS(baparamset, IEEE80211_DELBAPS_TID);
6429 
6430 		(void) memset(&node, 0, sizeof (node));
6431 		IEEE80211_ADDR_COPY(node.sta.addr, in->in_bssid);
6432 		node.mode = STA_MODE_MODIFY_MSK;
6433 		node.sta.sta_id = IWH_AP_ID;
6434 
6435 		node.station_flags_msk = 0;
6436 		node.sta.modify_mask = STA_MODIFY_DELBA_TID_MSK;
6437 		node.add_immediate_ba_tid = (uint8_t)tid;
6438 
6439 		mutex_enter(&sc->sc_glock);
6440 		err = iwh_cmd(sc, REPLY_ADD_STA, &node, sizeof (node), 1);
6441 		if (err != IWH_SUCCESS) {
6442 			cmn_err(CE_WARN, "iwh_recv_action(): "
6443 			    "failed to delete RX block ACK\n");
6444 			mutex_exit(&sc->sc_glock);
6445 			return;
6446 		}
6447 		mutex_exit(&sc->sc_glock);
6448 
6449 		IWH_DBG((IWH_DEBUG_BA, "iwh_recv_action(): "
6450 		    "RX block ACK "
6451 		    "was deleted on TID %d.\n", tid));
6452 
6453 		return;
6454 	}
6455 }
6456 
6457 /*
6458  * When local station wants to delete BA agreement that was originated by AP,
6459  * Net80211 module will call this function to clean up relevant information
6460  * in hardware.
6461  */
6462 static int
6463 iwh_send_action(struct ieee80211_node *in,
6464     int category, int action, uint16_t args[4])
6465 {
6466 	struct ieee80211com *ic;
6467 	iwh_sc_t *sc;
6468 	uint32_t tid;
6469 	iwh_add_sta_t node;
6470 	int ret = EIO;
6471 	int err = IWH_FAIL;
6472 
6473 
6474 	if (NULL == in) {
6475 		return (ret);
6476 	}
6477 
6478 	ic = in->in_ic;
6479 	if (NULL == ic) {
6480 		return (ret);
6481 	}
6482 
6483 	sc = (iwh_sc_t *)ic;
6484 
6485 	ret = sc->sc_send_action(in, category, action, args);
6486 
6487 	if (category != IEEE80211_ACTION_CAT_BA) {
6488 		return (ret);
6489 	}
6490 
6491 	switch (action) {
6492 	case IEEE80211_ACTION_BA_DELBA:
6493 		if (IEEE80211_DELBAPS_INIT == args[1]) {
6494 			return (ret);
6495 		}
6496 
6497 		tid = args[0];
6498 
6499 		(void) memset(&node, 0, sizeof (node));
6500 		IEEE80211_ADDR_COPY(node.sta.addr, in->in_bssid);
6501 		node.mode = STA_MODE_MODIFY_MSK;
6502 		node.sta.sta_id = IWH_AP_ID;
6503 
6504 		node.station_flags_msk = 0;
6505 		node.sta.modify_mask = STA_MODIFY_DELBA_TID_MSK;
6506 		node.add_immediate_ba_tid = (uint8_t)tid;
6507 
6508 		mutex_enter(&sc->sc_glock);
6509 		err = iwh_cmd(sc, REPLY_ADD_STA, &node, sizeof (node), 1);
6510 		if (err != IWH_SUCCESS) {
6511 			cmn_err(CE_WARN, "iwh_send_action(): "
6512 			    "failed to delete RX balock ACK\n");
6513 			mutex_exit(&sc->sc_glock);
6514 			return (EIO);
6515 		}
6516 		mutex_exit(&sc->sc_glock);
6517 
6518 		IWH_DBG((IWH_DEBUG_BA, "iwh_send_action(): "
6519 		    "RX block ACK "
6520 		    "was deleted on TID %d.\n", tid));
6521 
6522 		break;
6523 	}
6524 
6525 	return (ret);
6526 }
6527 
6528 static int
6529 iwh_reset_hw(iwh_sc_t *sc)
6530 {
6531 	uint32_t tmp;
6532 	int n;
6533 
6534 	tmp = IWH_READ(sc, CSR_HW_IF_CONFIG_REG);
6535 	IWH_WRITE(sc, CSR_HW_IF_CONFIG_REG,
6536 	    tmp | CSR_HW_IF_CONFIG_REG_BITS_NIC_READY);
6537 
6538 	/*
6539 	 * wait for HW ready
6540 	 */
6541 	for (n = 0; n < 5; n++) {
6542 		if (IWH_READ(sc, CSR_HW_IF_CONFIG_REG) &
6543 		    CSR_HW_IF_CONFIG_REG_BITS_NIC_READY) {
6544 			break;
6545 		}
6546 		DELAY(10);
6547 	}
6548 
6549 	if (n != 5) {
6550 		return (IWH_SUCCESS);
6551 	}
6552 
6553 	tmp = IWH_READ(sc, CSR_HW_IF_CONFIG_REG);
6554 	IWH_WRITE(sc, CSR_HW_IF_CONFIG_REG,
6555 	    tmp | CSR_HW_IF_CONFIG_REG_BITS_PREPARE);
6556 
6557 	for (n = 0; n < 15000; n++) {
6558 		if (0 == (IWH_READ(sc, CSR_HW_IF_CONFIG_REG) &
6559 		    CSR_HW_IF_CONFIG_REG_BITS_NIC_PREPARE_DONE)) {
6560 			break;
6561 		}
6562 		DELAY(10);
6563 	}
6564 
6565 	if (15000 == n) {
6566 		return (ETIMEDOUT);
6567 	}
6568 
6569 	tmp = IWH_READ(sc, CSR_HW_IF_CONFIG_REG);
6570 	IWH_WRITE(sc, CSR_HW_IF_CONFIG_REG,
6571 	    tmp | CSR_HW_IF_CONFIG_REG_BITS_NIC_READY);
6572 
6573 	/*
6574 	 * wait for HW ready
6575 	 */
6576 	for (n = 0; n < 5; n++) {
6577 		if (IWH_READ(sc, CSR_HW_IF_CONFIG_REG) &
6578 		    CSR_HW_IF_CONFIG_REG_BITS_NIC_READY) {
6579 			break;
6580 		}
6581 		DELAY(10);
6582 	}
6583 
6584 	if (n != 5) {
6585 		return (IWH_SUCCESS);
6586 	} else {
6587 		return (ETIMEDOUT);
6588 	}
6589 }
6590