xref: /onnv-gate/usr/src/uts/common/io/pcan/pcan.c (revision 7656:2621e50fdf4a)
1 /*
2  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /*
7  * Copyright (c) 1997, 1998, 1999
8  *      Bill Paul <wpaul@ctr.columbia.edu>.  All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *      This product includes software developed by Bill Paul.
21  * 4. Neither the name of the author nor the names of any co-contributors
22  *    may be used to endorse or promote products derived from this software
23  *    without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
29  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
35  * THE POSSIBILITY OF SUCH DAMAGE.
36  */
37 
38 #include <sys/conf.h>
39 #include <sys/ddi.h>
40 #include <sys/sunddi.h>
41 #include <sys/dlpi.h>
42 #include <sys/ethernet.h>
43 #include <sys/strsun.h>
44 #include <sys/stat.h>
45 #include <sys/byteorder.h>
46 #include <sys/pccard.h>
47 #include <sys/pci.h>
48 #include <sys/policy.h>
49 #include <sys/mac.h>
50 #include <sys/stream.h>
51 #include <inet/common.h>
52 #include <inet/nd.h>
53 #include <inet/mi.h>
54 
55 #include "pcan.h"
56 #include <sys/mac_wifi.h>
57 #include <inet/wifi_ioctl.h>
58 
59 #ifdef	DEBUG
60 #define	PCAN_DBG_BASIC		0x1
61 #define	PCAN_DBG_INFO		0x2
62 #define	PCAN_DBG_SEND		0x4
63 #define	PCAN_DBG_RCV		0x8
64 #define	PCAN_DBG_LINKINFO	0x10
65 #define	PCAN_DBG_FW_VERSION	0x20
66 #define	PCAN_DBG_CMD		0x40
67 uint32_t pcan_debug = 0;
68 #define	PCANDBG(x) \
69 	if (pcan_debug & PCAN_DBG_BASIC) cmn_err x
70 #else
71 #define	PCANDBG(x)
72 #endif
73 
74 static ddi_device_acc_attr_t accattr = {
75 		DDI_DEVICE_ATTR_V0,
76 		DDI_STRUCTURE_LE_ACC,
77 		DDI_STRICTORDER_ACC,
78 };
79 
80 static ddi_dma_attr_t control_cmd_dma_attr = {
81 	DMA_ATTR_V0,		/* version of this structure */
82 	0,			/* lowest usable address */
83 	0xffffffffffffffffull,	/* highest usable address */
84 	0xffffffffull,		/* maximum DMAable byte count */
85 	4,			/* alignment in bytes */
86 	0xfff,			/* burst sizes (any) */
87 	1,			/* minimum transfer */
88 	0xffffull,		/* maximum transfer */
89 	0xffffffffffffffffull,	/* maximum segment length */
90 	1,			/* maximum number of segments */
91 	1,			/* granularity */
92 	0,			/* flags (reserved) */
93 };
94 
95 void *pcan_soft_state_p = NULL;
96 static int pcan_device_type;
97 
98 mac_callbacks_t pcan_m_callbacks = {
99 	MC_IOCTL,
100 	pcan_gstat,
101 	pcan_start,
102 	pcan_stop,
103 	pcan_prom,
104 	pcan_sdmulti,
105 	pcan_saddr,
106 	pcan_tx,
107 	NULL,
108 	pcan_ioctl
109 };
110 
111 static char *pcan_name_str = "pcan";
112 
113 DDI_DEFINE_STREAM_OPS(pcan_dev_ops, nulldev, pcan_probe, pcan_attach,
114     pcan_detach, nodev, NULL, D_MP, NULL, ddi_quiesce_not_supported);
115 
116 extern struct mod_ops mod_driverops;
117 static struct modldrv modldrv = {
118 	&mod_driverops,
119 	"Cisco-Aironet 802.11b driver",
120 	&pcan_dev_ops
121 };
122 
123 static struct modlinkage modlinkage = {
124 	MODREV_1, (void *)&modldrv, NULL
125 	};
126 
127 int
128 _init(void)
129 {
130 	int stat;
131 
132 	/* Allocate soft state */
133 	if ((stat = ddi_soft_state_init(&pcan_soft_state_p,
134 	    sizeof (pcan_maci_t), 2)) != DDI_SUCCESS)
135 		return (stat);
136 
137 	mac_init_ops(&pcan_dev_ops, "pcan");
138 	stat = mod_install(&modlinkage);
139 	if (stat != 0) {
140 		mac_fini_ops(&pcan_dev_ops);
141 		ddi_soft_state_fini(&pcan_soft_state_p);
142 	}
143 
144 	return (stat);
145 }
146 
147 int
148 _fini(void)
149 {
150 	int stat;
151 
152 	stat = mod_remove(&modlinkage);
153 	if (stat != DDI_SUCCESS)
154 		return (stat);
155 	mac_fini_ops(&pcan_dev_ops);
156 	ddi_soft_state_fini(&pcan_soft_state_p);
157 	return (stat);
158 }
159 
160 int
161 _info(struct modinfo *modinfop)
162 {
163 	return (mod_info(&modlinkage, modinfop));
164 }
165 
166 static int
167 pcan_probe(dev_info_t *dip)
168 {
169 	int len, ret;
170 	char *buf;
171 	dev_info_t *pdip = ddi_get_parent(dip);
172 
173 	PCANDBG((CE_NOTE, "pcan probe: parent dip=0x%p-%s(%d)\n", (void *)pdip,
174 	    ddi_driver_name(pdip), ddi_get_instance(pdip)));
175 
176 	ret = ddi_getlongprop(DDI_DEV_T_ANY, pdip, 0, "device_type",
177 	    (caddr_t)&buf, &len);
178 	if (ret != DDI_SUCCESS)
179 		return (DDI_PROBE_FAILURE);
180 
181 	PCANDBG((CE_NOTE, "pcan probe: device_type %s\n", buf));
182 	if ((strcmp(buf, "pccard") == 0) || (strcmp(buf, "pcmcia") == 0)) {
183 		pcan_device_type = PCAN_DEVICE_PCCARD;
184 #ifdef DEBUG
185 		if (pcan_debug & PCAN_DBG_FW_VERSION) {
186 			cmn_err(CE_NOTE, "Cisco 802.11 pccard\n");
187 		}
188 #endif
189 		ret = DDI_PROBE_SUCCESS;
190 	} else if (strcmp(buf, "pci") == 0) {
191 		pcan_device_type = PCAN_DEVICE_PCI;
192 #ifdef DEBUG
193 		if (pcan_debug & PCAN_DBG_FW_VERSION) {
194 			cmn_err(CE_NOTE, "Cisco 802.11 minipci card\n");
195 		}
196 #endif
197 		ret = DDI_PROBE_SUCCESS;
198 	} else {
199 		cmn_err(CE_NOTE, "pcan probe: unsupported card\n");
200 		ret = DDI_PROBE_FAILURE;
201 	}
202 
203 	kmem_free(buf, len);
204 	return (ret);
205 }
206 
207 static int
208 pcan_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
209 {
210 	int ret;
211 	int instance;
212 	uint16_t stat;
213 	uint32_t err;
214 	pcan_maci_t *pcan_p;
215 	wifi_data_t	wd = { 0 };
216 	mac_register_t	*macp;
217 	modify_config_t cfgmod;
218 	char strbuf[256];
219 
220 	PCANDBG((CE_NOTE, "dip=0x%p cmd=%x\n", (void *)dip, cmd));
221 	if (cmd != DDI_ATTACH)
222 		goto attach_fail1;
223 
224 	/*
225 	 * Since this driver is porting from freebsd, so just like
226 	 * the original driver, the minipci card doesn't work on amd64
227 	 * machine.
228 	 * For sparc, since no pci card is available for the test, so this
229 	 * version doesn't support sparc. If there is card available and
230 	 * requirement, future version will try to support sparc.
231 	 * This driver works well for minipci card on 32bit x86
232 	 * machine, so keep the code to just support minipci card on 32bit
233 	 * mode.
234 	 */
235 #if defined(sparc) || defined(__sparc)
236 	if (pcan_device_type == PCAN_DEVICE_PCI) {
237 		cmn_err(CE_NOTE, "pcan attach: this driver does not support "
238 		    "PCI/MiniPCI card on Sparc\n");
239 		goto attach_fail1;
240 	}
241 #endif /* sparc */
242 #if defined(__amd64)
243 	if (pcan_device_type == PCAN_DEVICE_PCI) {
244 		cmn_err(CE_NOTE, "pcan attach: this driver does not support "
245 		    "PCI/MiniPCI card on amd64\n");
246 		goto attach_fail1;
247 	}
248 #endif /* amd64 */
249 
250 	/* Allocate soft state associated with this instance. */
251 	if (ddi_soft_state_zalloc(pcan_soft_state_p,
252 	    ddi_get_instance(dip)) != DDI_SUCCESS) {
253 		cmn_err(CE_CONT, "pcan attach: alloc softstate failed\n");
254 		goto attach_fail1;
255 	}
256 	pcan_p = (pcan_maci_t *)ddi_get_soft_state(pcan_soft_state_p,
257 	    ddi_get_instance(dip));
258 
259 	pcan_p->pcan_device_type = pcan_device_type;
260 	if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
261 		if (ddi_regs_map_setup(dip, 0,
262 		    (caddr_t *)&pcan_p->pcan_cfg_base, 0, 0,
263 		    &accattr, &pcan_p->pcan_cfg_handle) != DDI_SUCCESS)
264 			goto attach_fail2;
265 
266 		stat = ddi_get16(pcan_p->pcan_cfg_handle,
267 		    (uint16_t *)(pcan_p->pcan_cfg_base + PCI_CONF_COMM));
268 		stat |= (PCI_COMM_IO | PCI_COMM_MAE);
269 		ddi_put16(pcan_p->pcan_cfg_handle,
270 		    (uint16_t *)(pcan_p->pcan_cfg_base + PCI_CONF_COMM), stat);
271 
272 		ddi_regs_map_free(&pcan_p->pcan_cfg_handle);
273 		if (ddi_regs_map_setup(dip, 1, (caddr_t *)&pcan_p->pcan_bar0,
274 		    0, 0, &accattr, &pcan_p->pcan_handle0) != DDI_SUCCESS)
275 			goto attach_fail3;
276 		if (ddi_regs_map_setup(dip, 2, (caddr_t *)&pcan_p->pcan_bar1,
277 		    0, 0, &accattr, &pcan_p->pcan_handle1) != DDI_SUCCESS)
278 			goto attach_fail3;
279 		if (ddi_regs_map_setup(dip, 3, (caddr_t *)&pcan_p->pcan_bar2,
280 		    0, 0, &accattr, &pcan_p->pcan_handle2) != DDI_SUCCESS)
281 			goto attach_fail3;
282 	}
283 
284 	pcan_p->pcan_dip		= dip;
285 	pcan_p->pcan_flag		= 0;
286 	pcan_p->glds_nocarrier		= 0;
287 	pcan_p->glds_noxmtbuf		= 0;
288 	pcan_p->glds_norcvbuf		= 0;
289 	pcan_p->pcan_socket		= ddi_getprop(DDI_DEV_T_NONE, dip,
290 	    DDI_PROP_DONTPASS, "socket", -1);
291 
292 	pcan_p->pcan_reschedule_need = B_FALSE;
293 	pcan_p->pcan_info_softint_pending = 0;
294 	pcan_p->pcan_reset_delay = ddi_getprop(DDI_DEV_T_ANY, dip,
295 	    DDI_PROP_DONTPASS, "reset-delay", 5000);
296 
297 	if (ddi_get_iblock_cookie(dip,
298 	    0, &pcan_p->pcan_ib_cookie) != DDI_SUCCESS) {
299 		cmn_err(CE_WARN, "pcan attach: get_iblk_cookie failed\n");
300 		goto attach_fail3;
301 	}
302 
303 	mutex_init(&pcan_p->pcan_glock, NULL,
304 	    MUTEX_DRIVER, pcan_p->pcan_ib_cookie);
305 	mutex_init(&pcan_p->pcan_scanlist_lock, NULL,
306 	    MUTEX_DRIVER, pcan_p->pcan_ib_cookie);
307 	mutex_init(&pcan_p->pcan_txring.an_tx_lock, NULL,
308 	    MUTEX_DRIVER, pcan_p->pcan_ib_cookie);
309 
310 	if (ret = ddi_add_softintr(dip, DDI_SOFTINT_LOW,
311 	    &pcan_p->pcan_info_softint_id, &pcan_p->pcan_ib_cookie, NULL,
312 	    pcan_info_softint, (caddr_t)pcan_p)) {
313 		cmn_err(CE_WARN, "pcan attach: add info_softintr failed\n");
314 		goto attach_fail3a;
315 	}
316 
317 	if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
318 		if (ret = ddi_add_intr(dip, 0, NULL, NULL,
319 		    pcan_intr, (caddr_t)pcan_p)) {
320 			cmn_err(CE_WARN, "pcan attach: add intr failed\n");
321 			goto attach_fail4;
322 		}
323 	} else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) {
324 		if (ret = pcan_register_cs(dip, pcan_p)) {
325 			PCANDBG((CE_NOTE, "pcan attach: register_cs failed"
326 			    " %x\n", ret));
327 			goto attach_fail4;
328 		}
329 	} else {
330 		cmn_err(CE_WARN, "pcan attach: unsupported device type\n");
331 		goto attach_fail4;
332 	}
333 
334 	mutex_enter(&pcan_p->pcan_glock);
335 	pcan_reset_backend(pcan_p, pcan_p->pcan_reset_delay);
336 	/* leaves IF down, intr disabled */
337 
338 	if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
339 		if (ret = pcan_init_dma(dip, pcan_p)) {
340 			cmn_err(CE_WARN, "pcan init_dma: failed\n");
341 			mutex_exit(&pcan_p->pcan_glock);
342 			goto attach_fail5;
343 		}
344 	}
345 	if (ret = pcan_get_cap(pcan_p)) { /* sets macaddr for gld_register */
346 		cmn_err(CE_WARN, "pcan attach: get_cap failed %x\n", ret);
347 		mutex_exit(&pcan_p->pcan_glock);
348 		goto attach_fail6;
349 	}
350 
351 	mutex_exit(&pcan_p->pcan_glock);
352 	/*
353 	 * Provide initial settings for the WiFi plugin; whenever this
354 	 * information changes, we need to call mac_pdata_update()
355 	 */
356 	wd.wd_secalloc = WIFI_SEC_NONE;
357 	wd.wd_opmode = IEEE80211_M_STA;
358 
359 	macp = mac_alloc(MAC_VERSION);
360 	if (macp == NULL) {
361 		PCANDBG((CE_NOTE, "pcan attach: "
362 		    "MAC version mismatch\n"));
363 		goto attach_fail6;
364 	}
365 
366 	macp->m_type_ident	= MAC_PLUGIN_IDENT_WIFI;
367 	macp->m_driver		= pcan_p;
368 	macp->m_dip		= dip;
369 	macp->m_src_addr	= pcan_p->pcan_mac_addr;
370 	macp->m_callbacks	= &pcan_m_callbacks;
371 	macp->m_min_sdu		= 0;
372 	macp->m_max_sdu		= IEEE80211_MTU;
373 	macp->m_pdata		= &wd;
374 	macp->m_pdata_size	= sizeof (wd);
375 
376 	err = mac_register(macp, &pcan_p->pcan_mh);
377 	mac_free(macp);
378 	if (err != 0) {
379 		PCANDBG((CE_NOTE, "pcan attach: "
380 		    "mac_register err\n"));
381 		goto attach_fail6;
382 	}
383 
384 	if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) {
385 		/* turn on CS interrupt */
386 		cfgmod.Attributes = CONF_ENABLE_IRQ_STEERING |
387 		    CONF_IRQ_CHANGE_VALID;
388 		cfgmod.Vpp1 = 50;
389 		cfgmod.Vpp2 = 50;
390 		(void) csx_ModifyConfiguration(pcan_p->pcan_chdl, &cfgmod);
391 
392 		mutex_enter(&pcan_p->pcan_glock);
393 		if (ret = pcan_init_nicmem(pcan_p)) {
394 			cmn_err(CE_WARN, "pcan attach: init_nicmem failed %x\n",
395 			    ret);
396 			mutex_exit(&pcan_p->pcan_glock);
397 			goto attach_fail7;
398 		}
399 		mutex_exit(&pcan_p->pcan_glock);
400 	}
401 	(void) ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
402 	    "bad-rids", (caddr_t)&pcan_p->pcan_badrids,
403 	    &pcan_p->pcan_badrids_len);
404 
405 	pcan_p->an_config.an_rxmode = AN_NORMAL_RXMODE;
406 	ether_copy(pcan_p->pcan_mac_addr, pcan_p->an_config.an_macaddr);
407 	mutex_enter(&pcan_p->pcan_glock);
408 	list_create(&pcan_p->an_scan_list, sizeof (an_scan_list_t),
409 	    offsetof(an_scan_list_t, an_scan_node));
410 	pcan_p->an_scan_num = 0;
411 	mutex_exit(&pcan_p->pcan_glock);
412 	pcan_p->an_scanlist_timeout_id = timeout(pcan_scanlist_timeout,
413 	    pcan_p, drv_usectohz(1000000));
414 
415 	instance = ddi_get_instance(dip);
416 	(void) snprintf(strbuf, sizeof (strbuf), "pcan%d", instance);
417 	if (ddi_create_minor_node(dip, strbuf, S_IFCHR,
418 	    instance + 1, DDI_NT_NET_WIFI, 0) != DDI_SUCCESS) {
419 		goto attach_fail8;
420 	}
421 	mutex_enter(&pcan_p->pcan_glock);
422 	PCAN_DISABLE_INTR_CLEAR(pcan_p);
423 	(void) pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0);
424 	pcan_p->pcan_flag |= PCAN_ATTACHED;
425 	if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
426 		pcan_p->pcan_flag |= PCAN_CARD_READY;
427 	}
428 	mutex_exit(&pcan_p->pcan_glock);
429 	return (DDI_SUCCESS);
430 attach_fail8:
431 	if (pcan_p->an_scanlist_timeout_id != 0) {
432 		(void) untimeout(pcan_p->an_scanlist_timeout_id);
433 		pcan_p->an_scanlist_timeout_id = 0;
434 	}
435 	list_destroy(&pcan_p->an_scan_list);
436 attach_fail7:
437 	(void) mac_unregister(pcan_p->pcan_mh);
438 attach_fail6:
439 	if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI)
440 		pcan_free_dma(pcan_p);
441 attach_fail5:
442 	if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
443 		ddi_remove_intr(dip, 0, pcan_p->pcan_ib_cookie);
444 	} else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) {
445 		pcan_unregister_cs(pcan_p);
446 	}
447 attach_fail4:
448 	if (pcan_p->pcan_info_softint_id)
449 		ddi_remove_softintr(pcan_p->pcan_info_softint_id);
450 attach_fail3a:
451 	pcan_destroy_locks(pcan_p);
452 attach_fail3:
453 	if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
454 		if (pcan_p->pcan_handle0)
455 			ddi_regs_map_free(&pcan_p->pcan_handle0);
456 		if (pcan_p->pcan_handle1)
457 			ddi_regs_map_free(&pcan_p->pcan_handle1);
458 		if (pcan_p->pcan_handle2)
459 			ddi_regs_map_free(&pcan_p->pcan_handle2);
460 	}
461 attach_fail2:
462 	ddi_soft_state_free(pcan_soft_state_p, ddi_get_instance(dip));
463 attach_fail1:
464 	return (DDI_FAILURE);
465 }
466 
467 static int
468 pcan_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
469 {
470 	pcan_maci_t *pcan_p;
471 	an_scan_list_t *scan_item0;
472 	int ret;
473 	pcan_p = ddi_get_soft_state(pcan_soft_state_p, ddi_get_instance(dip));
474 
475 	if (cmd != DDI_DETACH)
476 		return (DDI_FAILURE);
477 	if (!(pcan_p->pcan_flag & PCAN_ATTACHED))
478 		return (DDI_FAILURE);
479 
480 	ret = mac_disable(pcan_p->pcan_mh);
481 	if (ret != 0)
482 		return (DDI_FAILURE);
483 
484 	if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
485 		mutex_enter(&pcan_p->pcan_glock);
486 		pcan_stop_locked(pcan_p);
487 		PCAN_DISABLE_INTR(pcan_p);
488 		mutex_exit(&pcan_p->pcan_glock);
489 	}
490 	if (pcan_p->an_scanlist_timeout_id != 0) {
491 		(void) untimeout(pcan_p->an_scanlist_timeout_id);
492 		pcan_p->an_scanlist_timeout_id = 0;
493 	}
494 	if (pcan_p->pcan_connect_timeout_id != 0) {
495 		(void) untimeout(pcan_p->pcan_connect_timeout_id);
496 		pcan_p->pcan_connect_timeout_id = 0;
497 	}
498 	mutex_enter(&pcan_p->pcan_scanlist_lock);
499 	scan_item0 = list_head(&pcan_p->an_scan_list);
500 	while (scan_item0) {
501 		pcan_delete_scan_item(pcan_p, scan_item0);
502 		scan_item0 = list_head(&pcan_p->an_scan_list);
503 	}
504 	list_destroy(&pcan_p->an_scan_list);
505 	mutex_exit(&pcan_p->pcan_scanlist_lock);
506 
507 	(void) mac_unregister(pcan_p->pcan_mh);
508 
509 	mutex_enter(&pcan_p->pcan_glock);
510 	if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
511 		ddi_remove_intr(dip, 0, pcan_p->pcan_ib_cookie);
512 		pcan_free_dma(pcan_p);
513 		if (pcan_p->pcan_handle0)
514 			ddi_regs_map_free(&pcan_p->pcan_handle0);
515 		if (pcan_p->pcan_handle1)
516 			ddi_regs_map_free(&pcan_p->pcan_handle1);
517 		if (pcan_p->pcan_handle2)
518 			ddi_regs_map_free(&pcan_p->pcan_handle2);
519 	} else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) {
520 		pcan_unregister_cs(pcan_p);
521 	} else {
522 		cmn_err(CE_WARN, "pcan detach: unsupported device type\n");
523 	}
524 	mutex_exit(&pcan_p->pcan_glock);
525 	pcan_destroy_locks(pcan_p);
526 	if (pcan_p->pcan_info_softint_id)
527 		ddi_remove_softintr(pcan_p->pcan_info_softint_id);
528 
529 	if (pcan_p->pcan_badrids_len)
530 		kmem_free(pcan_p->pcan_badrids, pcan_p->pcan_badrids_len);
531 
532 	ddi_soft_state_free(pcan_soft_state_p, ddi_get_instance(dip));
533 	ddi_remove_minor_node(dip, NULL);
534 
535 	return (DDI_SUCCESS);
536 }
537 
538 /*
539  * card services and event handlers
540  */
541 
542 static int
543 pcan_register_cs(dev_info_t *dip, pcan_maci_t *pcan_p)
544 {
545 	int ret;
546 	client_reg_t cr;
547 	client_handle_t chdl; /* uint encoding of socket, function, client */
548 	get_status_t card_status;
549 	request_socket_mask_t sock_req;
550 
551 	bzero(&cr, sizeof (cr));
552 	cr.Attributes	= INFO_IO_CLIENT|INFO_CARD_EXCL|INFO_CARD_SHARE;
553 	cr.EventMask	= CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
554 	    CS_EVENT_REGISTRATION_COMPLETE | CS_EVENT_CARD_REMOVAL_LOWP |
555 	    CS_EVENT_CARD_READY | CS_EVENT_PM_RESUME | CS_EVENT_PM_SUSPEND |
556 	    CS_EVENT_CLIENT_INFO;
557 	cr.event_callback_args.client_data = pcan_p;
558 	cr.Version = CS_VERSION;
559 	cr.event_handler = (csfunction_t *)pcan_ev_hdlr;
560 	cr.dip = dip;
561 	(void) strcpy(cr.driver_name, pcan_name_str);
562 	if (ret = csx_RegisterClient(&chdl, &cr)) {
563 		cmn_err(CE_WARN, "pcan: RegisterClient failed %x", ret);
564 		goto regcs_ret;
565 	}
566 
567 	pcan_p->pcan_chdl = chdl;
568 
569 	bzero(&card_status, sizeof (card_status));
570 	(void) csx_GetStatus(chdl, &card_status);
571 	PCANDBG((CE_NOTE, "pcan: getstat Sock=%x CState=%x SState=%x rState=%x",
572 	    card_status.Socket, card_status.CardState,
573 	    card_status.SocketState, card_status.raw_CardState));
574 	if (!(card_status.CardState & CS_STATUS_CARD_INSERTED)) {
575 		/* card is not present, why are we attaching ? */
576 		ret = CS_NO_CARD;
577 		goto unreg;
578 	}
579 	cv_init(&pcan_p->pcan_cscv, NULL, CV_DRIVER, NULL);
580 	mutex_init(&pcan_p->pcan_cslock, NULL, MUTEX_DRIVER, *cr.iblk_cookie);
581 	mutex_enter(&pcan_p->pcan_cslock);
582 	if (ret = csx_MapLogSocket(chdl, &pcan_p->pcan_log_sock)) {
583 		cmn_err(CE_WARN, "pcan: MapLogSocket failed %x", ret);
584 		goto fail;
585 	}
586 	PCANDBG((CE_NOTE, "pcan: logsock: LogSock=%x PhyAdapter=%x PhySock=%x",
587 	    pcan_p->pcan_log_sock.LogSocket,
588 	    pcan_p->pcan_log_sock.PhyAdapter,
589 	    pcan_p->pcan_log_sock.PhySocket));
590 
591 	/* turn on initialization events */
592 	sock_req.Socket = 0;
593 	sock_req.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
594 	    CS_EVENT_REGISTRATION_COMPLETE;
595 	if (ret = csx_RequestSocketMask(chdl, &sock_req)) {
596 		cmn_err(CE_WARN, "pcan: RequestSocketMask failed %x\n", ret);
597 		goto fail;
598 	}
599 
600 	/* wait for and process card insertion events */
601 	while (!(pcan_p->pcan_flag & PCAN_CARD_READY))
602 		cv_wait(&pcan_p->pcan_cscv, &pcan_p->pcan_cslock);
603 	mutex_exit(&pcan_p->pcan_cslock);
604 
605 	pcan_p->pcan_flag |= PCAN_CS_REGISTERED;
606 	return (CS_SUCCESS);
607 fail:
608 	mutex_destroy(&pcan_p->pcan_cslock);
609 	cv_destroy(&pcan_p->pcan_cscv);
610 unreg:
611 	(void) csx_DeregisterClient(chdl);
612 regcs_ret:
613 	pcan_p->pcan_flag &= ~PCAN_CS_REGISTERED;
614 	return (ret);
615 }
616 
617 static void
618 pcan_unregister_cs(pcan_maci_t *pcan_p)
619 {
620 	int ret;
621 	release_socket_mask_t mask;
622 	mask.Socket = pcan_p->pcan_socket;
623 
624 	/*
625 	 * The card service not registered means register_cs function
626 	 * doesnot return TRUE. Then all the lelated resource has been
627 	 * released in register_cs.
628 	 */
629 	if (!(pcan_p->pcan_flag | PCAN_CS_REGISTERED))
630 		return;
631 	(void) csx_ReleaseSocketMask(pcan_p->pcan_chdl, &mask);
632 
633 	if (pcan_p->pcan_flag & PCAN_CARD_READY) {
634 		pcan_card_remove(pcan_p);
635 		pcan_p->pcan_flag &= ~PCAN_CARD_READY;
636 	}
637 	mutex_destroy(&pcan_p->pcan_cslock);
638 	cv_destroy(&pcan_p->pcan_cscv);
639 	if (ret = csx_DeregisterClient(pcan_p->pcan_chdl))
640 		cmn_err(CE_WARN, "pcan: deregister failed %x\n", ret);
641 }
642 static void
643 pcan_destroy_locks(pcan_maci_t *pcan_p)
644 {
645 	mutex_destroy(&pcan_p->pcan_txring.an_tx_lock);
646 	mutex_destroy(&pcan_p->pcan_scanlist_lock);
647 	mutex_destroy(&pcan_p->pcan_glock);
648 }
649 
650 static int
651 pcan_ev_hdlr(event_t event, int priority, event_callback_args_t *arg)
652 {
653 	int ret = CS_SUCCESS;
654 	pcan_maci_t *pcan_p = (pcan_maci_t *)arg->client_data;
655 	client_info_t *ci_p = (client_info_t *)&arg->client_info;
656 
657 	mutex_enter(&pcan_p->pcan_cslock);
658 	switch (event) {
659 	case CS_EVENT_CARD_INSERTION:
660 		ret = pcan_card_insert(pcan_p);
661 		cv_broadcast(&pcan_p->pcan_cscv);
662 		break;
663 	case CS_EVENT_REGISTRATION_COMPLETE:
664 		cv_broadcast(&pcan_p->pcan_cscv);
665 		break;
666 	case CS_EVENT_CARD_REMOVAL:
667 		if (priority & CS_EVENT_PRI_HIGH)
668 			break;
669 		pcan_card_remove(pcan_p);
670 		cv_broadcast(&pcan_p->pcan_cscv);
671 		break;
672 	case CS_EVENT_CLIENT_INFO:
673 		if (GET_CLIENT_INFO_SUBSVC(ci_p->Attributes) !=
674 		    CS_CLIENT_INFO_SUBSVC_CS)
675 			break;
676 
677 		ci_p->Revision = 0x0101;
678 		ci_p->CSLevel = CS_VERSION;
679 		ci_p->RevDate = CS_CLIENT_INFO_MAKE_DATE(9, 12, 14);
680 		(void) strcpy(ci_p->ClientName, PCAN_IDENT_STRING);
681 		(void) strcpy(ci_p->VendorName, CS_SUN_VENDOR_DESCRIPTION);
682 		ci_p->Attributes |= CS_CLIENT_INFO_VALID;
683 		break;
684 	default:
685 		ret = CS_UNSUPPORTED_EVENT;
686 		break;
687 	}
688 	mutex_exit(&pcan_p->pcan_cslock);
689 	return (ret);
690 }
691 
692 static int
693 pcan_card_insert(pcan_maci_t *pcan_p)
694 {
695 	int ret, hi, lo;
696 	tuple_t tuple;
697 	cisparse_t cisparse;
698 	io_req_t	io;
699 	irq_req_t	irq;
700 	config_req_t	cfg;
701 	cistpl_config_t config;
702 	cistpl_cftable_entry_t *tbl_p;
703 	register client_handle_t chdl = pcan_p->pcan_chdl;
704 
705 	bzero(&tuple, sizeof (tuple));
706 	tuple.DesiredTuple = CISTPL_MANFID;
707 	if (ret = csx_GetFirstTuple(chdl, &tuple)) {
708 		cmn_err(CE_WARN, "pcan: get manufacture id failed %x\n", ret);
709 		goto insert_ret;
710 	}
711 	bzero(&cisparse, sizeof (cisparse));
712 	if (ret = csx_Parse_CISTPL_MANFID(chdl, &tuple, &cisparse.manfid)) {
713 		cmn_err(CE_WARN, "pcan: parse manufacture id failed %x\n", ret);
714 		goto insert_ret;
715 	}
716 	/* verify manufacture ID */
717 	PCANDBG((CE_NOTE, "pcan: manufacturer_id=%x card=%x\n",
718 	    cisparse.manfid.manf, cisparse.manfid.card));
719 
720 	bzero(&tuple, sizeof (tuple));
721 	tuple.DesiredTuple = CISTPL_FUNCID;
722 	if (ret = csx_GetFirstTuple(chdl, &tuple)) {
723 		cmn_err(CE_WARN, "pcan: get function id failed %x\n", ret);
724 		goto insert_ret;
725 	}
726 	bzero(&cisparse, sizeof (cisparse));
727 	if (ret = csx_Parse_CISTPL_FUNCID(chdl, &tuple, &cisparse.funcid)) {
728 		cmn_err(CE_WARN, "pcan: parse function id failed %x\n", ret);
729 		goto insert_ret;
730 	}
731 	/* verify function ID */
732 	PCANDBG((CE_NOTE, "funcid=%x\n", cisparse.funcid.function));
733 
734 	bzero(&tuple, sizeof (tuple));
735 	tuple.DesiredTuple = CISTPL_CONFIG;
736 	if (ret = csx_GetFirstTuple(chdl, &tuple)) {
737 		cmn_err(CE_WARN, "pcan: get config failed %x\n", ret);
738 		goto insert_ret;
739 	}
740 	bzero(&config, sizeof (config));
741 	if (ret = csx_Parse_CISTPL_CONFIG(chdl, &tuple, &config)) {
742 		cmn_err(CE_WARN, "pcan: parse config failed %x\n", ret);
743 		goto insert_ret;
744 	}
745 	PCANDBG((CE_NOTE,
746 	    "pcan: config present=%x nr=%x hr=%x regs[0]=%x base=%x last=%x\n",
747 	    config.present, config.nr, config.hr, config.regs[0],
748 	    config.base, config.last));
749 
750 	hi = 0;
751 	lo = (int)-1;		/* really big number */
752 	tbl_p = &cisparse.cftable;
753 	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
754 	for (tbl_p->index = 0; tbl_p->index <= config.hr; ) {
755 		PCANDBG((CE_NOTE, "pcan: tuple idx=%x:\n", tbl_p->index));
756 		if (ret = csx_GetNextTuple(chdl, &tuple)) {
757 			cmn_err(CE_WARN, "pcan: get cftable failed %x\n", ret);
758 			break;
759 		}
760 		bzero((caddr_t)&cisparse, sizeof (cisparse));
761 		if (ret = csx_Parse_CISTPL_CFTABLE_ENTRY(chdl, &tuple, tbl_p)) {
762 			cmn_err(CE_WARN, "pcan: parse cftable failed%x\n", ret);
763 			break;
764 		}
765 		if (tbl_p->flags & CISTPL_CFTABLE_TPCE_FS_PWR &&
766 		    tbl_p->pd.flags & CISTPL_CFTABLE_TPCE_FS_PWR_VCC) {
767 			if (tbl_p->pd.pd_vcc.avgI > hi) {
768 				hi = tbl_p->pd.pd_vcc.avgI;
769 				pcan_p->pcan_config_hi = tbl_p->index;
770 			}
771 			if (tbl_p->pd.pd_vcc.avgI < lo) {
772 				lo = tbl_p->pd.pd_vcc.avgI;
773 				pcan_p->pcan_config = tbl_p->index;
774 			}
775 		}
776 		if (tbl_p->flags & CISTPL_CFTABLE_TPCE_DEFAULT) {
777 			if (tbl_p->pd.flags & CISTPL_CFTABLE_TPCE_FS_PWR_VCC)
778 				pcan_p->pcan_vcc = tbl_p->pd.pd_vcc.nomV;
779 			if (tbl_p->flags & CISTPL_CFTABLE_TPCE_FS_IO)
780 				pcan_p->pcan_iodecode = tbl_p->io.addr_lines;
781 		}
782 	}
783 	PCANDBG((CE_NOTE, "pcan: cfg_hi=%x cfg=%x vcc=%x iodecode=%x\n",
784 	    pcan_p->pcan_config_hi, pcan_p->pcan_config,
785 	    pcan_p->pcan_vcc, pcan_p->pcan_iodecode));
786 
787 	bzero(&io, sizeof (io));
788 	io.BasePort1.base = 0;
789 	io.NumPorts1 = 1 << pcan_p->pcan_iodecode;
790 	io.Attributes1 = IO_DATA_PATH_WIDTH_16;
791 	io.IOAddrLines = pcan_p->pcan_iodecode;
792 	if (ret = csx_RequestIO(chdl, &io)) {
793 		cmn_err(CE_WARN, "pcan: RequestIO failed %x\n", ret);
794 		goto insert_ret;
795 	}
796 	pcan_p->pcan_port = io.BasePort1.handle;
797 
798 	if (ret = ddi_add_softintr(DIP(pcan_p), DDI_SOFTINT_HIGH,
799 	    &pcan_p->pcan_softint_id, &pcan_p->pcan_ib_cookie, NULL,
800 	    pcan_intr, (caddr_t)pcan_p)) {
801 		cmn_err(CE_NOTE, "pcan: Add softintr failed\n");
802 		goto insert_ret;
803 	}
804 	irq.Attributes = IRQ_TYPE_EXCLUSIVE;
805 	irq.irq_handler = ddi_intr_hilevel(DIP(pcan_p), 0) ?
806 	    (csfunction_t *)pcan_intr_hi : (csfunction_t *)pcan_intr;
807 	irq.irq_handler_arg = pcan_p;
808 	if (ret = csx_RequestIRQ(chdl, &irq)) {
809 		cmn_err(CE_WARN, "pcan: RequestIRQ failed %x\n", ret);
810 		goto un_io;
811 	}
812 
813 	bzero(&cfg, sizeof (cfg));
814 	cfg.Attributes = 0; /* not ready for CONF_ENABLE_IRQ_STEERING yet */
815 	cfg.Vcc = 50; /* pcan_vcc == 0 */
816 	cfg.Vpp1 = 50;
817 	cfg.Vpp2 = 50;
818 	cfg.IntType = SOCKET_INTERFACE_MEMORY_AND_IO;
819 	cfg.ConfigBase = config.base;
820 	cfg.ConfigIndex = pcan_p->pcan_config;
821 	cfg.Status = CCSR_IO_IS_8; /* no use */
822 	cfg.Present = config.present;
823 	pcan_p->pcan_flag |= PCAN_CARD_READY;
824 	if (ret = csx_RequestConfiguration(chdl, &cfg)) {
825 		cmn_err(CE_WARN, "pcan: RequestConfiguration failed %x\n", ret);
826 		goto un_irq;
827 	}
828 	return (CS_SUCCESS);
829 un_irq:
830 	(void) csx_ReleaseIRQ(chdl, &irq);
831 un_io:
832 	ddi_remove_softintr(pcan_p->pcan_softint_id);
833 
834 	(void) csx_ReleaseIO(chdl, &io);
835 	pcan_p->pcan_port = 0;
836 insert_ret:
837 	pcan_p->pcan_flag &= ~PCAN_CARD_READY;
838 	return (ret);
839 }
840 
841 /*
842  * assume card is already removed, don't touch the hardware
843  */
844 static void
845 pcan_card_remove(pcan_maci_t *pcan_p)
846 {
847 	int ret;
848 	io_req_t io;
849 	irq_req_t irq;
850 
851 	if (!(pcan_p->pcan_flag & PCAN_CARD_READY))
852 		return;
853 	if (ret = csx_ReleaseConfiguration(pcan_p->pcan_chdl, NULL))
854 		cmn_err(CE_WARN, "pcan: ReleaseConfiguration failed %x\n", ret);
855 
856 	bzero(&irq, sizeof (irq));
857 	if (ret = csx_ReleaseIRQ(pcan_p->pcan_chdl, &irq))
858 		cmn_err(CE_WARN, "pcan: ReleaseIRQ failed %x\n", ret);
859 
860 	ddi_remove_softintr(pcan_p->pcan_softint_id);
861 
862 	bzero(&io, sizeof (io));
863 	io.BasePort1.handle = pcan_p->pcan_port;
864 	io.NumPorts1 = 16;
865 	if (ret = csx_ReleaseIO(pcan_p->pcan_chdl, &io))
866 		cmn_err(CE_WARN, "pcan: Release IO failed %x\n", ret);
867 
868 	pcan_p->pcan_port = 0;
869 	pcan_p->pcan_flag &= ~PCAN_CARD_READY;
870 }
871 
872 /*
873  * gld operation interface routines
874  */
875 static int
876 pcan_start(void *arg)
877 {
878 	pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
879 
880 	mutex_enter(&pcan_p->pcan_glock);
881 	if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
882 		mutex_exit(&pcan_p->pcan_glock);
883 		return (PCAN_FAIL);
884 	}
885 	(void) pcan_loaddef(pcan_p);
886 	pcan_start_locked(pcan_p);
887 	mutex_exit(&pcan_p->pcan_glock);
888 	return (PCAN_SUCCESS);
889 }
890 
891 static void
892 pcan_stop(void *arg)
893 {
894 	pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
895 
896 	mutex_enter(&pcan_p->pcan_glock);
897 	if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
898 		mutex_exit(&pcan_p->pcan_glock);
899 		return;
900 	}
901 	pcan_stop_locked(pcan_p);
902 	mutex_exit(&pcan_p->pcan_glock);
903 	if (pcan_p->pcan_connect_timeout_id != 0) {
904 		(void) untimeout(pcan_p->pcan_connect_timeout_id);
905 		pcan_p->pcan_connect_timeout_id = 0;
906 	}
907 }
908 
909 /*
910  * mac address can only be set in 'disable' state and
911  * be effective after 'enable' state.
912  */
913 static int
914 pcan_saddr(void *arg, const uint8_t *macaddr)
915 {
916 	pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
917 	int ret = PCAN_SUCCESS;
918 	ether_copy(macaddr, pcan_p->pcan_mac_addr);
919 
920 	mutex_enter(&pcan_p->pcan_glock);
921 	if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
922 		ret = PCAN_FAIL;
923 		goto done;
924 	}
925 	ether_copy(pcan_p->pcan_mac_addr, pcan_p->an_config.an_macaddr);
926 	if (pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0)) {
927 		cmn_err(CE_WARN, "pcan set mac addr: failed\n");
928 		ret = PCAN_FAIL;
929 		goto done;
930 	}
931 	if (pcan_config_mac(pcan_p)) {
932 		cmn_err(CE_WARN, "pcan set mac addr: config_mac failed\n");
933 		ret = PCAN_FAIL;
934 		goto done;
935 	}
936 	if (pcan_set_cmd(pcan_p, AN_CMD_ENABLE, 0)) {
937 		cmn_err(CE_WARN, "pcan set mac addr: failed\n");
938 		ret = PCAN_FAIL;
939 	}
940 done:
941 	mutex_exit(&pcan_p->pcan_glock);
942 	return (ret);
943 }
944 
945 /*
946  * send a packet out for pccard
947  */
948 static int
949 pcan_send(pcan_maci_t *pcan_p, mblk_t *mblk_p)
950 {
951 	char *buf, *buf_p;
952 	an_txfrm_t *frm_p;
953 #ifdef PCAN_SEND_DEBUG
954 	struct an_ltv_status radio_status;
955 #endif /* PCAN_SEND_DEBUG */
956 	uint16_t pkt_len, xmt_id, ring_idx;
957 	struct ieee80211_frame *wh;
958 	int i = 0;
959 
960 	mutex_enter(&pcan_p->pcan_glock);
961 	if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
962 		mutex_exit(&pcan_p->pcan_glock);
963 		freemsg(mblk_p);
964 		return (PCAN_SUCCESS);		/* drop packet */
965 	}
966 	if (!(pcan_p->pcan_flag & PCAN_CARD_LINKUP)) {	/* link down */
967 		PCANDBG((CE_NOTE, "pcan: link down, dropped\n"));
968 		pcan_p->glds_nocarrier++;
969 		mutex_exit(&pcan_p->pcan_glock);
970 		freemsg(mblk_p);
971 		return (PCAN_SUCCESS);		/* drop packet */
972 	}
973 	mutex_exit(&pcan_p->pcan_glock);
974 	if (pullupmsg(mblk_p, -1) == 0) {
975 		cmn_err(CE_NOTE, "pcan send: pullupmsg failed\n");
976 		freemsg(mblk_p);
977 		return (PCAN_SUCCESS);		/* drop packet */
978 	}
979 	wh = (struct ieee80211_frame *)mblk_p->b_rptr;
980 
981 	mutex_enter(&pcan_p->pcan_txring.an_tx_lock);
982 	ring_idx = pcan_p->pcan_txring.an_tx_prod;
983 	pcan_p->pcan_txring.an_tx_prod = (ring_idx + 1) & AN_TX_RING_MASK;
984 
985 	/* check whether there is a xmt buffer available */
986 	while ((i < AN_TX_RING_CNT) &&
987 	    (pcan_p->pcan_txring.an_tx_ring[ring_idx])) {
988 		ring_idx = pcan_p->pcan_txring.an_tx_prod;
989 		pcan_p->pcan_txring.an_tx_prod =
990 		    (ring_idx + 1) & AN_TX_RING_MASK;
991 		i++;
992 	}
993 
994 	if (i == AN_TX_RING_CNT) {
995 		mutex_exit(&pcan_p->pcan_txring.an_tx_lock);
996 		PCANDBG((CE_NOTE, "pcan: ring full, retrying\n"));
997 		mutex_enter(&pcan_p->pcan_glock);
998 		pcan_p->pcan_reschedule_need = B_TRUE;
999 		mutex_exit(&pcan_p->pcan_glock);
1000 		pcan_p->glds_noxmtbuf++;
1001 		return (PCAN_FAIL);
1002 	}
1003 	xmt_id = pcan_p->pcan_txring.an_tx_fids[ring_idx];
1004 	pcan_p->pcan_txring.an_tx_ring[ring_idx] = xmt_id;
1005 	mutex_exit(&pcan_p->pcan_txring.an_tx_lock);
1006 
1007 	buf = kmem_zalloc(PCAN_NICMEM_SZ, KM_SLEEP); /* too big for stack */
1008 	buf_p = (ulong_t)buf & 1 ? buf + 1 : buf;	/* 16-bit round up */
1009 	frm_p = (an_txfrm_t *)buf_p;
1010 
1011 #ifdef DEBUG
1012 	if (pcan_debug & PCAN_DBG_SEND) {
1013 		cmn_err(CE_NOTE, "pcan send: packet from plugin");
1014 		for (i = 0; i < MBLKL(mblk_p); i++)
1015 			cmn_err(CE_NOTE, "%x: %x\n", i,
1016 			    *((unsigned char *)mblk_p->b_rptr + i));
1017 	}
1018 #endif
1019 	pkt_len = msgdsize(mblk_p);
1020 	if (pkt_len > PCAN_NICMEM_SZ - sizeof (an_txfrm_t)) {
1021 		cmn_err(CE_WARN, "pcan send: mblk is too long");
1022 		kmem_free(buf, PCAN_NICMEM_SZ);
1023 		freemsg(mblk_p);
1024 		return (PCAN_SUCCESS);		/* drop packet */
1025 	}
1026 	if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) !=
1027 	    IEEE80211_FC1_DIR_TODS) {
1028 		kmem_free(buf, PCAN_NICMEM_SZ);
1029 		freemsg(mblk_p);
1030 		return (PCAN_SUCCESS);		/* drop packet */
1031 	}
1032 
1033 	/* initialize xmt frame header, payload_len must be stored in LE */
1034 	bzero(frm_p, sizeof (an_txfrm_t) + 2);
1035 	frm_p->an_tx_ctl = AN_TXCTL_8023;
1036 
1037 	/*
1038 	 * mblk sent down from plugin includes station mode 802.11 frame and
1039 	 * llc, so we here need to remove them and add an ethernet header.
1040 	 */
1041 	pkt_len = pkt_len - (sizeof (*wh) + sizeof (struct ieee80211_llc))
1042 	    + 2;
1043 	bcopy(wh->i_addr3, buf_p + 0x38, ETHERADDRL); /* dst macaddr */
1044 	bcopy(wh->i_addr2, buf_p + 0x3e, ETHERADDRL); /* src macaddr */
1045 	*((uint16_t *)(buf_p + 0x36)) = pkt_len;
1046 	bcopy(mblk_p->b_rptr + sizeof (*wh) + sizeof (struct ieee80211_llc)
1047 	    - 2, buf_p + 0x44, pkt_len);
1048 
1049 	if (pkt_len & 1) {	/* round up to 16-bit boundary and pad 0 */
1050 		buf_p[pkt_len + 0x44] = 0;
1051 		pkt_len++;
1052 	}
1053 	ASSERT(pkt_len <= PCAN_NICMEM_SZ);
1054 #ifdef DEBUG
1055 	if (pcan_debug & PCAN_DBG_SEND) {
1056 		cmn_err(CE_NOTE, "pcan send: packet to hardware--pkt_len=%x",
1057 		    pkt_len);
1058 		for (i = 0; i < pkt_len + 4; i++)
1059 			cmn_err(CE_NOTE, "%x: %x\n", i,
1060 			    *((unsigned char *)buf_p + 0x36 + i));
1061 	}
1062 #endif
1063 	mutex_enter(&pcan_p->pcan_glock);
1064 	(void) WRCH1(pcan_p, xmt_id, 0, (uint16_t *)buf_p, 0x38); /* frm */
1065 	(void) WRPKT(pcan_p, xmt_id, 0x38, (uint16_t *)(buf_p + 0x38),
1066 	    pkt_len + 12);
1067 	ring_idx = pcan_set_cmd(pcan_p, AN_CMD_TX, xmt_id);
1068 	mutex_exit(&pcan_p->pcan_glock);
1069 
1070 	PCANDBG((CE_NOTE, "pcan: pkt_len=0x44+%x=%x xmt=%x ret=%x\n",
1071 	    pkt_len, 0x44 + pkt_len, xmt_id, ring_idx));
1072 	kmem_free(buf, PCAN_NICMEM_SZ);
1073 #ifdef PCAN_SEND_DEBUG
1074 	if (pkt_len = pcan_status_ltv(PCAN_READ_LTV, pcan_p, &radio_status)) {
1075 		PCANDBG((CE_NOTE, "pcan: bad radio status %x\n", pkt_len));
1076 	} else {
1077 		PCANDBG((CE_NOTE, "pcan: radio status:\n"));
1078 	}
1079 #endif /* PCAN_SEND_DEBUG */
1080 	if (ring_idx)
1081 		return (PCAN_FAIL);
1082 	else {
1083 		freemsg(mblk_p);
1084 		return (PCAN_SUCCESS);
1085 	}
1086 }
1087 
1088 /*
1089  * send a packet out for PCI/MiniPCI card
1090  */
1091 static int
1092 pcian_send(pcan_maci_t *pcan_p, mblk_t *mblk_p)
1093 {
1094 	char *buf;
1095 	uint16_t pkt_len = msgdsize(mblk_p), ring_idx;
1096 	uint32_t i;
1097 	struct ieee80211_frame *wh;
1098 	struct an_card_tx_desc an_tx_desc;
1099 
1100 	ring_idx = pcan_p->pcan_txring.an_tx_prod;
1101 
1102 	mutex_enter(&pcan_p->pcan_glock);
1103 	if (!(pcan_p->pcan_flag & PCAN_CARD_LINKUP)) {	/* link down */
1104 		mutex_exit(&pcan_p->pcan_glock);
1105 		pcan_p->glds_nocarrier++;
1106 		freemsg(mblk_p);
1107 		return (PCAN_SUCCESS);		/* drop packet */
1108 	}
1109 	mutex_exit(&pcan_p->pcan_glock);
1110 	if (pullupmsg(mblk_p, -1) == 0) {
1111 		cmn_err(CE_NOTE, "pcan(pci) send: pullupmsg failed\n");
1112 		freemsg(mblk_p);
1113 		return (PCAN_SUCCESS);		/* drop packet */
1114 	}
1115 	wh = (struct ieee80211_frame *)mblk_p->b_rptr;
1116 
1117 	mutex_enter(&pcan_p->pcan_txring.an_tx_lock);
1118 	if ((pcan_p->pcan_flag & PCAN_CARD_SEND) &&
1119 	    (ring_idx == pcan_p->pcan_txring.an_tx_cons)) {
1120 		pcan_p->glds_noxmtbuf++;
1121 		pcan_p->pcan_reschedule_need = B_TRUE;
1122 		mutex_exit(&pcan_p->pcan_txring.an_tx_lock);
1123 		return (PCAN_FAIL);
1124 	}
1125 	mutex_exit(&pcan_p->pcan_txring.an_tx_lock);
1126 
1127 #ifdef DEBUG
1128 	if (pcan_debug & PCAN_DBG_SEND) {
1129 		cmn_err(CE_NOTE, "pcan(pci) send: packet from plugin");
1130 		for (i = 0; i < MBLKL(mblk_p); i++)
1131 			cmn_err(CE_NOTE, "%x: %x\n", i,
1132 			    *((unsigned char *)mblk_p->b_rptr + i));
1133 	}
1134 #endif
1135 	mutex_enter(&pcan_p->pcan_glock);
1136 
1137 	buf = pcan_p->pcan_tx[ring_idx].dma_virtaddr;
1138 	bzero(buf, AN_TX_BUFFER_SIZE);
1139 
1140 	/*
1141 	 * mblk sent down from plugin includes station mode 802.11 frame and
1142 	 * llc, so we here need to remove them and add an ethernet header.
1143 	 */
1144 	*((uint16_t *)(buf + 8)) = htons(AN_TXCTL_8023);
1145 	pkt_len = pkt_len - (sizeof (*wh) + sizeof (struct ieee80211_llc))
1146 	    + 2;
1147 	bcopy(wh->i_addr3, buf + 0x38, ETHERADDRL); /* dst macaddr */
1148 	bcopy(wh->i_addr2, buf + 0x3e, ETHERADDRL); /* src macaddr */
1149 	*((uint16_t *)(buf + 0x36)) = pkt_len;
1150 	bcopy(mblk_p->b_rptr + sizeof (*wh) + sizeof (struct ieee80211_llc)
1151 	    - 2, buf + 0x44, pkt_len);
1152 
1153 #ifdef DEBUG
1154 	if (pcan_debug & PCAN_DBG_SEND) {
1155 		cmn_err(CE_NOTE, "pcan(pci) send: packet to hardware "
1156 		    "pkt_len=%x", pkt_len);
1157 		for (i = 0; i < pkt_len + 14; i++)
1158 			cmn_err(CE_NOTE, "%x: %x\n", i,
1159 			    *((unsigned char *)buf + 0x36 + i));
1160 	}
1161 #endif
1162 	bzero(&an_tx_desc, sizeof (an_tx_desc));
1163 	an_tx_desc.an_offset = 0;
1164 	an_tx_desc.an_eoc = (ring_idx == (AN_MAX_TX_DESC-1) ? 1 : 0);
1165 	an_tx_desc.an_valid = 1;
1166 	an_tx_desc.an_len =  0x44 + pkt_len;
1167 	an_tx_desc.an_phys  = pcan_p->pcan_tx[ring_idx].dma_physaddr;
1168 	for (i = 0; i < sizeof (an_tx_desc) / 4; i++) {
1169 		PCAN_AUX_PUT32(pcan_p, AN_TX_DESC_OFFSET +
1170 		    (ring_idx * sizeof (an_tx_desc)) + (i * 4),
1171 		    ((uint32_t *)&an_tx_desc)[i]);
1172 	}
1173 
1174 	mutex_enter(&pcan_p->pcan_txring.an_tx_lock);
1175 	pcan_p->pcan_txring.an_tx_prod = (ring_idx + 1) % AN_MAX_TX_DESC;
1176 	pcan_p->pcan_flag |= PCAN_CARD_SEND;
1177 	PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_ALLOC);
1178 	mutex_exit(&pcan_p->pcan_txring.an_tx_lock);
1179 
1180 	freemsg(mblk_p);
1181 	mutex_exit(&pcan_p->pcan_glock);
1182 	return (PCAN_SUCCESS);
1183 }
1184 
1185 static mblk_t *
1186 pcan_tx(void *arg, mblk_t *mp)
1187 {
1188 	pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
1189 	mblk_t *next;
1190 	int ret = 0;
1191 
1192 	ASSERT(mp != NULL);
1193 	mutex_enter(&pcan_p->pcan_glock);
1194 	if ((pcan_p->pcan_flag & (PCAN_CARD_LINKUP | PCAN_CARD_READY)) !=
1195 	    (PCAN_CARD_LINKUP | PCAN_CARD_READY)) {
1196 		mutex_exit(&pcan_p->pcan_glock);
1197 		return (mp);
1198 	}
1199 	mutex_exit(&pcan_p->pcan_glock);
1200 	while (mp != NULL) {
1201 		next =  mp->b_next;
1202 		mp->b_next = NULL;
1203 
1204 		if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
1205 			ret = pcian_send(pcan_p, mp);
1206 		} else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) {
1207 			ret = pcan_send(pcan_p, mp);
1208 		}
1209 		if (ret) {
1210 			mp->b_next = next;
1211 			break;
1212 		}
1213 		mp = next;
1214 	}
1215 	return (mp);
1216 }
1217 
1218 /*
1219  * this driver is porting from freebsd, the code in freebsd
1220  * doesn't show how to set promiscous mode.
1221  */
1222 /*ARGSUSED*/
1223 static int
1224 pcan_prom(void *arg, boolean_t on)
1225 {
1226 	pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
1227 	int ret = PCAN_SUCCESS;
1228 
1229 	mutex_enter(&pcan_p->pcan_glock);
1230 	if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
1231 		ret = PCAN_FAIL;
1232 	}
1233 	mutex_exit(&pcan_p->pcan_glock);
1234 	return (ret);
1235 }
1236 
1237 /*ARGSUSED*/
1238 static int
1239 pcan_gstat(void *arg, uint_t statitem, uint64_t *val)
1240 {
1241 	uint16_t i;
1242 	int ret = PCAN_SUCCESS;
1243 	pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
1244 	uint64_t *cntr_p = pcan_p->pcan_cntrs_s;
1245 
1246 	PCANDBG((CE_NOTE, "pcan: gstat called\n"));
1247 
1248 	mutex_enter(&pcan_p->pcan_glock);
1249 	if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
1250 		ret = PCAN_FAIL;
1251 		goto done;
1252 	}
1253 	if (pcan_get_ltv(pcan_p, sizeof (pcan_p->an_stats),
1254 	    AN_RID_16BITS_DELTACLR, (uint16_t *)&pcan_p->an_stats)) {
1255 		cmn_err(CE_WARN, "pcan kstat: get ltv(32 delta statistics)"
1256 		    " failed \n");
1257 		ret = PCAN_FAIL;
1258 		goto done;
1259 	}
1260 	for (i = 0; i < ANC_STAT_CNT; i++) {
1261 		cntr_p[i] += *((uint16_t *)&pcan_p->an_stats + 1 + i);
1262 	}
1263 	if (pcan_status_ltv(PCAN_READ_LTV, pcan_p, &pcan_p->an_status)) {
1264 		cmn_err(CE_WARN, "pcan kstat: read status failed \n");
1265 		ret = PCAN_FAIL;
1266 		goto done;
1267 	}
1268 
1269 	switch (statitem) {
1270 	case MAC_STAT_IFSPEED:
1271 		*val = 500000 * pcan_p->an_status.an_cur_tx_rate;
1272 		break;
1273 	case MAC_STAT_NOXMTBUF:
1274 		*val = pcan_p->glds_noxmtbuf;
1275 		break;
1276 	case MAC_STAT_NORCVBUF:
1277 		*val = pcan_p->glds_norcvbuf;
1278 		break;
1279 	case MAC_STAT_IERRORS:
1280 		*val = cntr_p[ANC_RX_OVERRUNS] +
1281 		    cntr_p[ANC_RX_PLCP_CSUM_ERRS] +
1282 		    cntr_p[ANC_RX_PLCP_FORMAT_ERRS] +
1283 		    cntr_p[ANC_RX_PLCP_LEN_ERRS] +
1284 		    cntr_p[ANC_RX_MAC_CRC_ERRS] +
1285 		    cntr_p[ANC_RX_WEP_ERRS];
1286 		break;
1287 	case MAC_STAT_OERRORS:
1288 		*val = cntr_p[ANC_TX_HOST_FAILED];
1289 		break;
1290 	case MAC_STAT_RBYTES:
1291 		*val = cntr_p[ANC_HOST_RX_BYTES];
1292 		break;
1293 	case MAC_STAT_IPACKETS:
1294 		*val = cntr_p[ANC_RX_HOST_UCASTS];
1295 		break;
1296 	case MAC_STAT_OBYTES:
1297 		*val = cntr_p[ANC_HOST_TX_BYTES];
1298 		break;
1299 	case MAC_STAT_OPACKETS:
1300 		*val = cntr_p[ANC_TX_HOST_UCASTS];
1301 		break;
1302 	case WIFI_STAT_TX_FAILED:
1303 		*val = cntr_p[ANC_TX_HOST_FAILED];
1304 		break;
1305 	case WIFI_STAT_TX_RETRANS:
1306 		*val = cntr_p[ANC_HOST_RETRIES];
1307 		break;
1308 	case WIFI_STAT_FCS_ERRORS:
1309 		*val = cntr_p[ANC_RX_MAC_CRC_ERRS];
1310 		break;
1311 	case WIFI_STAT_WEP_ERRORS:
1312 		*val = cntr_p[ANC_RX_WEP_ERRS];
1313 		break;
1314 	case WIFI_STAT_MCAST_TX:
1315 		*val = cntr_p[ANC_TX_HOST_MCASTS];
1316 		break;
1317 	case WIFI_STAT_MCAST_RX:
1318 		*val = cntr_p[ANC_RX_HOST_MCASTS];
1319 		break;
1320 	case WIFI_STAT_TX_FRAGS:
1321 	case WIFI_STAT_RX_FRAGS:
1322 		*val = 0;
1323 		break;
1324 	case WIFI_STAT_RTS_SUCCESS:
1325 		*val = cntr_p[ANC_TX_RTS_OK];
1326 		break;
1327 	case WIFI_STAT_RTS_FAILURE:
1328 		*val = cntr_p[ANC_NO_CTS];
1329 		break;
1330 	case WIFI_STAT_ACK_FAILURE:
1331 		*val = cntr_p[ANC_NO_ACK];
1332 		break;
1333 	case WIFI_STAT_RX_DUPS:
1334 		*val = cntr_p[ANC_RX_DUPS];
1335 		break;
1336 	default:
1337 		ret = ENOTSUP;
1338 	}
1339 
1340 
1341 done:
1342 	mutex_exit(&pcan_p->pcan_glock);
1343 	return (ret);
1344 }
1345 
1346 /*
1347  * this driver is porting from freebsd, the code in freebsd
1348  * doesn't show how to set multi address.
1349  */
1350 /*ARGSUSED*/
1351 static int
1352 pcan_sdmulti(void *arg, boolean_t add, const uint8_t *eth_p)
1353 {
1354 	pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
1355 
1356 	mutex_enter(&pcan_p->pcan_glock);
1357 	if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
1358 		mutex_exit(&pcan_p->pcan_glock);
1359 		return (PCAN_FAIL);
1360 	}
1361 	mutex_exit(&pcan_p->pcan_glock);
1362 	return (PCAN_SUCCESS);
1363 }
1364 
1365 static uint_t
1366 pcan_info_softint(caddr_t arg)
1367 {
1368 	pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
1369 	wifi_data_t wd = { 0 };
1370 	uint16_t link;
1371 	uint32_t link_up;
1372 
1373 	mutex_enter(&pcan_p->pcan_glock);
1374 	if (pcan_p->pcan_info_softint_pending != 1) {
1375 		mutex_exit(&pcan_p->pcan_glock);
1376 		return (DDI_INTR_UNCLAIMED);
1377 	}
1378 
1379 	PCAN_READ(pcan_p, AN_LINKSTAT(pcan_p), link);
1380 	link_up = pcan_p->pcan_flag & PCAN_CARD_LINKUP;
1381 	if ((link == AN_LINKSTAT_ASSOCIATED) && !link_up) {
1382 		pcan_p->pcan_flag |= PCAN_CARD_LINKUP;
1383 		mutex_exit(&pcan_p->pcan_glock);
1384 		if (pcan_p->pcan_connect_timeout_id != 0) {
1385 			(void) untimeout(pcan_p->pcan_connect_timeout_id);
1386 			pcan_p->pcan_connect_timeout_id = 0;
1387 		}
1388 		mac_link_update(GLD3(pcan_p), LINK_STATE_UP);
1389 		mutex_enter(&pcan_p->pcan_glock);
1390 		(void) pcan_status_ltv(PCAN_READ_LTV, pcan_p,
1391 		    &pcan_p->an_status);
1392 		bcopy(pcan_p->an_status.an_cur_bssid, wd.wd_bssid, 6);
1393 		wd.wd_secalloc = WIFI_SEC_NONE;
1394 		wd.wd_opmode = IEEE80211_M_STA;
1395 		(void) mac_pdata_update(pcan_p->pcan_mh, &wd,
1396 		    sizeof (wd));
1397 #ifdef DEBUG
1398 		if (pcan_debug & PCAN_DBG_LINKINFO) {
1399 			cmn_err(CE_NOTE, "pcan: link Up, chan=%d, "
1400 			    "ssid=\"%s\""
1401 			    " (%02x:%02x:%02x:%02x:%02x:%02x)\n",
1402 			    pcan_p->an_status.an_channel_set,
1403 			    pcan_p->an_status.an_ssid,
1404 			    pcan_p->an_status.an_cur_bssid[0],
1405 			    pcan_p->an_status.an_cur_bssid[1],
1406 			    pcan_p->an_status.an_cur_bssid[2],
1407 			    pcan_p->an_status.an_cur_bssid[3],
1408 			    pcan_p->an_status.an_cur_bssid[4],
1409 			    pcan_p->an_status.an_cur_bssid[5]);
1410 		}
1411 #endif
1412 	}
1413 	if ((link != AN_LINKSTAT_ASSOCIATED) && link_up) {
1414 		pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP;
1415 #ifdef DEBUG
1416 		if (pcan_debug & PCAN_DBG_LINKINFO) {
1417 			cmn_err(CE_NOTE, "pcan: link Down 0x%x\n", link);
1418 		}
1419 #endif
1420 		if (link != AN_LINKSTAT_SYNCLOST_HOSTREQ) {
1421 			pcan_p->pcan_connect_timeout_id =
1422 			    timeout(pcan_connect_timeout,
1423 			    pcan_p, drv_usectohz(1000));
1424 		}
1425 		mutex_exit(&pcan_p->pcan_glock);
1426 		mac_link_update(GLD3(pcan_p), LINK_STATE_DOWN);
1427 		mutex_enter(&pcan_p->pcan_glock);
1428 	}
1429 
1430 	pcan_p->pcan_info_softint_pending = 0;
1431 	mutex_exit(&pcan_p->pcan_glock);
1432 	return (DDI_INTR_CLAIMED);
1433 }
1434 
1435 static uint_t
1436 pcan_intr(caddr_t arg)
1437 {
1438 	uint16_t stat;
1439 	pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
1440 
1441 	mutex_enter(&pcan_p->pcan_glock);
1442 	if ((pcan_p->pcan_flag & (PCAN_CARD_READY | PCAN_CARD_INTREN)) !=
1443 	    (PCAN_CARD_READY | PCAN_CARD_INTREN)) {
1444 		mutex_exit(&pcan_p->pcan_glock);
1445 		return (DDI_INTR_UNCLAIMED);
1446 	}
1447 	PCAN_READ(pcan_p, AN_EVENT_STAT(pcan_p), stat);
1448 
1449 	if (!(stat & AN_INTRS(pcan_p)) || stat == AN_EV_ALL) {
1450 		mutex_exit(&pcan_p->pcan_glock);
1451 		return (DDI_INTR_UNCLAIMED);
1452 	}
1453 
1454 	PCAN_DISABLE_INTR(pcan_p);
1455 	PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), ~AN_INTRS(pcan_p));
1456 
1457 	PCANDBG((CE_NOTE, "pcan intr: stat=%x pcan_flags=%x\n", stat,
1458 	    pcan_p->pcan_flag));
1459 
1460 	if (stat & AN_EV_AWAKE) {
1461 		PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_AWAKE);
1462 		PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_AWAKE);
1463 	}
1464 	if (stat & AN_EV_LINKSTAT) {
1465 		pcan_p->pcan_info_softint_pending = 1;
1466 		ddi_trigger_softintr(pcan_p->pcan_info_softint_id);
1467 		PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_LINKSTAT);
1468 	}
1469 	if (stat & AN_EV_RX) {
1470 		if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
1471 			pcian_rcv(pcan_p);
1472 		} else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) {
1473 			pcan_rcv(pcan_p);
1474 		}
1475 		PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_RX);
1476 	}
1477 	if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
1478 		if (stat & AN_EV_TX_CPY) {
1479 			(void) pcan_txdone(pcan_p, stat & AN_EV_TX_CPY);
1480 			if (pcan_p->pcan_reschedule_need == B_TRUE) {
1481 				mac_tx_update(GLD3(pcan_p));
1482 				pcan_p->pcan_reschedule_need = B_FALSE;
1483 			}
1484 			PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_TX_CPY);
1485 	}
1486 	}
1487 	if (stat & AN_EV_TX) {
1488 		if (pcan_txdone(pcan_p, stat & AN_EV_TX) == 0) {
1489 			if (pcan_p->pcan_reschedule_need == B_TRUE) {
1490 				mac_tx_update(GLD3(pcan_p));
1491 				pcan_p->pcan_reschedule_need = B_FALSE;
1492 			}
1493 		}
1494 		PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_TX);
1495 	}
1496 	if (stat & AN_EV_TX_EXC) {
1497 		if (pcan_txdone(pcan_p, stat & AN_EV_TX_EXC) == 0) {
1498 			if (pcan_p->pcan_reschedule_need == B_TRUE) {
1499 				mutex_exit(&pcan_p->pcan_glock);
1500 				mac_tx_update(GLD3(pcan_p));
1501 				mutex_enter(&pcan_p->pcan_glock);
1502 				pcan_p->pcan_reschedule_need = B_FALSE;
1503 			}
1504 		}
1505 		PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_TX_EXC);
1506 	}
1507 	if (stat & AN_EV_ALLOC) {
1508 		PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_ALLOC);
1509 		PCANDBG((CE_NOTE, "pcan intr: nicmem alloc done\n"));
1510 	}
1511 	if (stat & AN_EV_MIC) {
1512 		PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_MIC);
1513 	}
1514 	PCAN_ENABLE_INTR(pcan_p);
1515 	mutex_exit(&pcan_p->pcan_glock);
1516 	return (DDI_INTR_CLAIMED);
1517 }
1518 
1519 static uint_t
1520 pcan_intr_hi(caddr_t arg)
1521 {
1522 	uint16_t stat;
1523 	pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
1524 
1525 	mutex_enter(&pcan_p->pcan_glock);
1526 	if ((pcan_p->pcan_flag & (PCAN_CARD_READY | PCAN_CARD_INTREN)) !=
1527 	    (PCAN_CARD_READY | PCAN_CARD_INTREN)) {
1528 		mutex_exit(&pcan_p->pcan_glock);
1529 		return (DDI_INTR_UNCLAIMED);
1530 	}
1531 	PCAN_READ(pcan_p, AN_EVENT_STAT(pcan_p), stat);
1532 	PCANDBG((CE_NOTE, "pcan intr(hi): stat=%x pcan_flags=%x\n", stat,
1533 	    pcan_p->pcan_flag));
1534 
1535 	if (!(stat & AN_INTRS(pcan_p)) || stat == AN_EV_ALL) {
1536 		mutex_exit(&pcan_p->pcan_glock);
1537 		return (DDI_INTR_UNCLAIMED);
1538 	}
1539 	/* disable interrupt without ack */
1540 	PCAN_WRITE(pcan_p, AN_INT_EN(pcan_p), 0);
1541 	mutex_exit(&pcan_p->pcan_glock);
1542 	ddi_trigger_softintr(pcan_p->pcan_softint_id);
1543 	return (DDI_INTR_CLAIMED);
1544 }
1545 
1546 /*
1547  * retrieve data from pccard
1548  */
1549 static void
1550 pcan_rcv(pcan_maci_t *pcan_p)
1551 {
1552 	uint16_t id, off, ret, data_len, pkt_stat, frm_ctl;
1553 	an_rxfrm_t frm;
1554 	struct ieee80211_llc *llc;
1555 
1556 	mblk_t *mp = allocb(PCAN_NICMEM_SZ, BPRI_MED);
1557 	if (!mp) {
1558 		cmn_err(CE_WARN, "pcan: failed to alloc rcv buf");
1559 		pcan_p->glds_norcvbuf++;
1560 		return;
1561 	}
1562 	ASSERT(mp->b_rptr == mp->b_wptr);
1563 
1564 	PCAN_READ(pcan_p, AN_RX_FID, id);
1565 	if (id == AN_INVALID_FID) {
1566 		PCANDBG((CE_NOTE, "pcan rcv: can't get rx_fid\n"));
1567 		pcan_p->glds_norcvbuf++;
1568 		ret = PCAN_FAIL;
1569 		goto done;
1570 	}
1571 	if (ret = RDCH0(pcan_p, id, 0, (uint16_t *)&frm, sizeof (frm))) {
1572 		PCANDBG((CE_NOTE, "pcan rcv: read frm err %x\n", ret));
1573 		goto done;
1574 	}
1575 	off = sizeof (frm);
1576 	if (frm.an_rx_status) {
1577 		PCANDBG((CE_NOTE, "pcan rcv: err stat %x\n", frm.an_rx_status));
1578 		ret = frm.an_rx_status;
1579 		goto done;
1580 	}
1581 	PCANDBG((CE_NOTE, "pcan rcv: payload_len=%x gap_len=%x\n",
1582 	    frm.an_rx_payload_len, frm.an_gaplen));
1583 	if (frm.an_rx_payload_len > PCAN_NICMEM_SZ ||
1584 	    frm.an_gaplen > AN_RXGAP_MAX) {
1585 		PCANDBG((CE_NOTE, "pcan rcv: bad len\n"));
1586 		ret = PCAN_FAIL;
1587 		goto done;
1588 	}
1589 	if (ret = RDCH0(pcan_p, id, off, &pkt_stat, sizeof (pkt_stat))) {
1590 		PCANDBG((CE_NOTE, "pcan rcv: pkt status err %x\n", ret));
1591 		ret = PCAN_FAIL;
1592 		goto done;
1593 	}
1594 	off += sizeof (pkt_stat);
1595 	if (ret = RDCH0(pcan_p, id, off, &data_len, sizeof (data_len))) {
1596 		PCANDBG((CE_NOTE, "pcan rcv: payload len err %x\n", ret));
1597 		ret = PCAN_FAIL;
1598 		goto done;
1599 	}
1600 	off += sizeof (data_len);
1601 	off += ETHERADDRL << 1;
1602 	PCANDBG((CE_NOTE, "pcan rcv: pkt_stat=%x payload_len=%x+c off=%x\n",
1603 	    pkt_stat, data_len, off));
1604 
1605 #ifdef DEBUG
1606 	if (pcan_debug & PCAN_DBG_RCV) {
1607 		int i;
1608 		cmn_err(CE_NOTE, "pcan rcv: frm header\n");
1609 		for (i = 0; i < sizeof (frm); i++)
1610 			cmn_err(CE_NOTE, "%x: %x\n", i,
1611 			    *((uint8_t *)&frm + i));
1612 	}
1613 #endif
1614 	/*
1615 	 * this driver deal with WEP by itself. so plugin always thinks no wep.
1616 	 */
1617 	frm.an_frame_ctl &= ~(IEEE80211_FC1_WEP << 8);
1618 	frm_ctl = frm.an_frame_ctl;
1619 	PCAN_SWAP16((uint16_t *)&frm.an_frame_ctl,
1620 	    sizeof (struct ieee80211_frame));
1621 	/*
1622 	 * discard those frames which are not from the AP we connect or
1623 	 * without 'ap->sta' direction
1624 	 */
1625 	if (((pcan_p->an_config.an_opmode == AN_OPMODE_INFR_STATION)) &&
1626 	    ((((frm_ctl >> 8) & IEEE80211_FC1_DIR_MASK) !=
1627 	    IEEE80211_FC1_DIR_FROMDS) ||
1628 	    bcmp(pcan_p->an_status.an_cur_bssid, frm.an_addr2, 6) != 0)) {
1629 		ret = PCAN_FAIL;
1630 		goto done;
1631 	}
1632 	bcopy(&frm.an_frame_ctl, mp->b_wptr,
1633 	    sizeof (struct ieee80211_frame));
1634 	mp->b_wptr += sizeof (struct ieee80211_frame);
1635 
1636 	/* the plugin need a llc here */
1637 	llc = (struct ieee80211_llc *)mp->b_wptr;
1638 	llc->illc_dsap = llc->illc_ssap = AN_SNAP_K1;
1639 	llc->illc_control = AN_SNAP_CONTROL;
1640 	bzero(llc->illc_oc, sizeof (llc->illc_oc));
1641 	mp->b_wptr += AN_SNAPHDR_LEN;
1642 
1643 	/* read in the rest of data */
1644 	data_len += data_len & 1;	/* adjust to word boundary */
1645 	if (data_len > MBLKSIZE(mp)) {
1646 		cmn_err(CE_NOTE, "pcan rcv: data over length%x\n", data_len);
1647 		ret = PCAN_FAIL;
1648 		goto done;
1649 	}
1650 
1651 	if (ret = RDPKT(pcan_p, id, off, (uint16_t *)mp->b_wptr, data_len)) {
1652 		PCANDBG((CE_NOTE, "pcan rcv: err read data %x\n", ret));
1653 	}
1654 done:
1655 	if (ret) {
1656 		PCANDBG((CE_NOTE, "pcan rcv: rd data %x\n", ret));
1657 		freemsg(mp);
1658 		return;
1659 	}
1660 	mp->b_wptr += data_len;
1661 #ifdef DEBUG
1662 	if (pcan_debug & PCAN_DBG_RCV) {
1663 		int i;
1664 		cmn_err(CE_NOTE, "pcan rcv: len=0x%x\n", data_len);
1665 		for (i = 0; i < data_len + sizeof (frm); i++)
1666 			cmn_err(CE_NOTE, "%x: %x\n", i,
1667 			    *((uint8_t *)mp->b_rptr + i));
1668 	}
1669 #endif
1670 	mutex_exit(&pcan_p->pcan_glock);
1671 	mac_rx(GLD3(pcan_p), NULL, mp);
1672 	mutex_enter(&pcan_p->pcan_glock);
1673 }
1674 
1675 /*
1676  * retrieve data from mini-pci card
1677  */
1678 static void
1679 pcian_rcv(pcan_maci_t *pcan_p)
1680 {
1681 	struct an_card_rx_desc an_rx_desc;
1682 	char *buf;
1683 	uint16_t ret = 0, data_len;
1684 	int i, j;
1685 	struct ieee80211_frame *frm;
1686 	struct ieee80211_llc *llc;
1687 
1688 	mblk_t *mp = allocb(AN_RX_BUFFER_SIZE, BPRI_MED);
1689 	if (!mp) {
1690 		cmn_err(CE_WARN, "pcan(pci): failed to alloc rcv buf");
1691 		pcan_p->glds_norcvbuf++;
1692 		return;
1693 	}
1694 	ASSERT(mp->b_rptr == mp->b_wptr);
1695 
1696 	for (i = 0; i < sizeof (an_rx_desc) / 4; i++)
1697 		PCAN_AUX_GET32(pcan_p, AN_RX_DESC_OFFSET + (i * 4),
1698 		    ((uint32_t *)&an_rx_desc)[i]);
1699 	if (an_rx_desc.an_done && !an_rx_desc.an_valid) {
1700 		buf = pcan_p->pcan_rx[0].dma_virtaddr;
1701 		data_len = an_rx_desc.an_len;
1702 #ifdef DEBUG
1703 		if (pcan_debug & PCAN_DBG_RCV) {
1704 			cmn_err(CE_NOTE, "pcan(pci) rcv: data_len=%x",
1705 			    data_len);
1706 			for (j = 0; j < data_len + 14; j++)
1707 				cmn_err(CE_NOTE, "pcan_rcv %d: %x", j,
1708 				    *((uint8_t *)buf + j));
1709 		}
1710 #endif
1711 		if (data_len > MBLKSIZE(mp)) {
1712 			cmn_err(CE_NOTE, "pcan(pci) rcv: data over length%x\n",
1713 			    data_len);
1714 			ret = PCAN_FAIL;
1715 			goto done;
1716 		}
1717 		/*
1718 		 * minipci card receive an ethernet frame, so assembly a 802.11
1719 		 * frame here manually.
1720 		 */
1721 		frm = (struct ieee80211_frame *)mp->b_wptr;
1722 		bzero(frm, sizeof (*frm));
1723 		frm->i_fc[0] |= IEEE80211_FC0_TYPE_DATA;
1724 		frm->i_fc[1] |= IEEE80211_FC1_DIR_FROMDS;
1725 		bcopy(pcan_p->an_status.an_cur_bssid, frm->i_addr2, 6);
1726 		bcopy(buf, frm->i_addr1, 6);
1727 		bcopy(buf + 6, frm->i_addr3, 6);
1728 		mp->b_wptr += sizeof (struct ieee80211_frame);
1729 
1730 		llc = (struct ieee80211_llc *)mp->b_wptr;
1731 		llc->illc_dsap = llc->illc_ssap = AN_SNAP_K1;
1732 		llc->illc_control = AN_SNAP_CONTROL;
1733 		bzero(llc->illc_oc, sizeof (llc->illc_oc));
1734 		mp->b_wptr += AN_SNAPHDR_LEN;
1735 
1736 		bcopy(buf + 12, mp->b_wptr, data_len);
1737 		mp->b_wptr += data_len;
1738 #ifdef DEBUG
1739 		if (pcan_debug & PCAN_DBG_RCV) {
1740 			int i;
1741 			cmn_err(CE_NOTE, "pcan(pci) rcv: len=0x%x\n", data_len);
1742 			for (i = 0; i < data_len + sizeof (*frm)
1743 			    + sizeof (*llc); i++)
1744 				cmn_err(CE_NOTE, "%x: %x\n", i,
1745 				    *((uint8_t *)mp->b_rptr + i));
1746 		}
1747 #endif
1748 		mutex_exit(&pcan_p->pcan_glock);
1749 		mac_rx(GLD3(pcan_p), NULL, mp);
1750 		mutex_enter(&pcan_p->pcan_glock);
1751 	}
1752 done:
1753 	bzero(&an_rx_desc, sizeof (an_rx_desc));
1754 	an_rx_desc.an_valid = 1;
1755 	an_rx_desc.an_len = AN_RX_BUFFER_SIZE;
1756 	an_rx_desc.an_done = 0;
1757 	an_rx_desc.an_phys = pcan_p->pcan_rx[0].dma_physaddr;
1758 
1759 	for (i = 0; i < sizeof (an_rx_desc) / 4; i++)
1760 		PCAN_AUX_PUT32(pcan_p, AN_RX_DESC_OFFSET + (i * 4),
1761 		    ((uint32_t *)&an_rx_desc)[i]);
1762 	if (ret) {
1763 		freemsg(mp);
1764 	}
1765 }
1766 
1767 /*ARGSUSED*/
1768 static uint32_t
1769 pcan_txdone(pcan_maci_t *pcan_p, uint16_t err)
1770 {
1771 	uint16_t fid, i, ring_idx;
1772 	uint32_t ret = 0;
1773 
1774 	PCAN_READ(pcan_p, AN_TX_CMP_FID(pcan_p), fid);
1775 	mutex_enter(&pcan_p->pcan_txring.an_tx_lock);
1776 	if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
1777 		if (pcan_p->pcan_flag & PCAN_CARD_SEND) {
1778 			ring_idx = pcan_p->pcan_txring.an_tx_cons;
1779 			pcan_p->pcan_txring.an_tx_cons =
1780 			    (ring_idx + 1) % AN_MAX_TX_DESC;
1781 			if (pcan_p->pcan_txring.an_tx_prod ==
1782 			    pcan_p->pcan_txring.an_tx_cons) {
1783 				pcan_p->pcan_flag &= ~PCAN_CARD_SEND;
1784 			}
1785 		}
1786 		ret = 0;
1787 	} else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) {
1788 		for (i = 0; i < AN_TX_RING_CNT; i++) {
1789 			if (fid == pcan_p->pcan_txring.an_tx_ring[i]) {
1790 				pcan_p->pcan_txring.an_tx_ring[i] = 0;
1791 				break;
1792 			}
1793 		}
1794 		pcan_p->pcan_txring.an_tx_cons =
1795 		    (pcan_p->pcan_txring.an_tx_cons + 1) & AN_TX_RING_MASK;
1796 		ret = (i == AN_TX_RING_CNT ? 1 : 0);
1797 	}
1798 	mutex_exit(&pcan_p->pcan_txring.an_tx_lock);
1799 	return (ret);
1800 }
1801 
1802 /*
1803  * delay in which the mutex is not hold.
1804  * assuming the mutex has already been hold.
1805  */
1806 static void
1807 pcan_delay(pcan_maci_t *pcan_p, clock_t microsecs)
1808 {
1809 	ASSERT(mutex_owned(&pcan_p->pcan_glock));
1810 
1811 	mutex_exit(&pcan_p->pcan_glock);
1812 	delay(drv_usectohz(microsecs));
1813 	mutex_enter(&pcan_p->pcan_glock);
1814 }
1815 
1816 static void
1817 pcan_reset_backend(pcan_maci_t *pcan_p, int timeout)
1818 {
1819 	if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
1820 		(void) pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0);
1821 		PCAN_DISABLE_INTR_CLEAR(pcan_p);
1822 		(void) pcan_set_cmd(pcan_p, AN_CMD_FW_RESTART, 0);
1823 		(void) pcan_set_cmd(pcan_p, AN_CMD_NOOP2, 0);
1824 		(void) pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0);
1825 	} else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) {
1826 		(void) pcan_set_cmd0(pcan_p, AN_CMD_DISABLE, 0, 0, 0);
1827 		(void) pcan_set_cmd0(pcan_p, AN_CMD_NOOP2, 0, 0, 0);
1828 		PCAN_WRITE(pcan_p, AN_COMMAND(pcan_p), AN_CMD_FW_RESTART);
1829 		pcan_delay(pcan_p, timeout); /* wait for firmware restart */
1830 
1831 		(void) pcan_set_cmd(pcan_p, AN_CMD_NOOP, 0);
1832 		(void) pcan_set_cmd0(pcan_p, AN_CMD_DISABLE, 0, 0, 0);
1833 
1834 		PCAN_DISABLE_INTR_CLEAR(pcan_p);
1835 	}
1836 }
1837 
1838 /*
1839  * set command without the need of ACK.
1840  */
1841 static uint16_t
1842 pcan_set_cmd0(pcan_maci_t *pcan_p, uint16_t cmd, uint16_t p0,
1843     uint16_t p1, uint16_t p2)
1844 {
1845 	int i;
1846 	uint16_t stat, r0, r1, r2;
1847 
1848 	if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
1849 		for (i = 0; i < AN_TIMEOUT; i++) {
1850 			PCAN_READ(pcan_p, AN_COMMAND(pcan_p), stat);
1851 			if (!(stat & AN_CMD_BUSY))
1852 				break;
1853 		}
1854 		if (i == AN_TIMEOUT) {
1855 			PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p),
1856 			    AN_EV_CLR_STUCK_BUSY);
1857 			PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CMD);
1858 			drv_usecwait(10);
1859 		}
1860 		PCAN_WRITE(pcan_p, AN_PARAM0(pcan_p), p0);
1861 		PCAN_WRITE(pcan_p, AN_PARAM1(pcan_p), p1);
1862 		PCAN_WRITE(pcan_p, AN_PARAM2(pcan_p), p2);
1863 	}
1864 	PCAN_WRITE(pcan_p, AN_COMMAND(pcan_p), cmd);
1865 	for (i = 0; i < AN_TIMEOUT; i++) {
1866 		PCAN_READ(pcan_p, AN_EVENT_STAT(pcan_p), stat);
1867 		if (stat & AN_EV_CMD)
1868 			break;
1869 	}
1870 	if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
1871 		PCAN_READ(pcan_p, AN_RESP0(pcan_p), r0);
1872 		PCAN_READ(pcan_p, AN_RESP1(pcan_p), r1);
1873 		PCAN_READ(pcan_p, AN_RESP2(pcan_p), r2);
1874 		PCAN_READ(pcan_p, AN_COMMAND(pcan_p), stat);
1875 		if (stat & AN_CMD_BUSY)
1876 			PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p),
1877 			    AN_EV_CLR_STUCK_BUSY);
1878 		PCANDBG((CE_NOTE, "pcan set_cmd0: "
1879 		    "stat=%x, r0=%x, r1=%x, r2=%x\n",
1880 		    stat, r0, r1, r2));
1881 	}
1882 	PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CMD);
1883 	return (i == AN_TIMEOUT ? PCAN_TIMEDOUT_ACCESS : PCAN_SUCCESS);
1884 }
1885 
1886 static uint16_t
1887 pcan_set_cmd(pcan_maci_t *pcan_p, uint16_t cmd, uint16_t param)
1888 {
1889 	int i;
1890 	uint16_t stat, r0, r1, r2;
1891 	uint16_t ret;
1892 
1893 	if (((cmd == AN_CMD_ENABLE) &&
1894 	    ((pcan_p->pcan_flag & PCAN_ENABLED) != 0)) ||
1895 	    ((cmd == AN_CMD_DISABLE) &&
1896 	    ((pcan_p->pcan_flag & PCAN_ENABLED) == 0)))
1897 		return (PCAN_SUCCESS);
1898 	for (i = 0; i < AN_TIMEOUT; i++) {
1899 		PCAN_READ(pcan_p, AN_COMMAND(pcan_p), stat);
1900 		if (!(stat & AN_CMD_BUSY)) {
1901 			break;
1902 		}
1903 	}
1904 	if (i == AN_TIMEOUT) {
1905 		PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CLR_STUCK_BUSY);
1906 		PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CMD);
1907 		drv_usecwait(10);
1908 	}
1909 
1910 	PCAN_WRITE(pcan_p, AN_PARAM0(pcan_p), param);
1911 	PCAN_WRITE(pcan_p, AN_PARAM1(pcan_p), 0);
1912 	PCAN_WRITE(pcan_p, AN_PARAM2(pcan_p), 0);
1913 	PCAN_WRITE(pcan_p, AN_COMMAND(pcan_p), cmd);
1914 
1915 	for (i = 0; i < AN_TIMEOUT; i++) {
1916 		PCAN_READ(pcan_p, AN_EVENT_STAT(pcan_p), stat);
1917 		if (stat & AN_EV_CMD) {
1918 			break;
1919 		}
1920 		PCAN_READ(pcan_p, AN_COMMAND(pcan_p), stat);
1921 		if (stat == cmd)
1922 			PCAN_WRITE(pcan_p, AN_COMMAND(pcan_p), cmd);
1923 	}
1924 	if (i == AN_TIMEOUT) {
1925 		if (cmd == AN_CMD_FW_RESTART) {
1926 			PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CMD);
1927 			return (PCAN_SUCCESS);
1928 		}
1929 #ifdef DEBUG
1930 		if (pcan_debug & PCAN_DBG_CMD) {
1931 			cmn_err(CE_WARN, "pcan set_cmd: %x timeout stat=%x\n",
1932 			    cmd, stat);
1933 		}
1934 #endif
1935 		PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CMD);
1936 		return (PCAN_TIMEDOUT_CMD);
1937 	}
1938 
1939 	for (i = 0; i < AN_TIMEOUT; i++) {
1940 		PCAN_READ(pcan_p, AN_STATUS(pcan_p), stat);
1941 		PCAN_READ(pcan_p, AN_RESP0(pcan_p), r0);
1942 		PCAN_READ(pcan_p, AN_RESP1(pcan_p), r1);
1943 		PCAN_READ(pcan_p, AN_RESP2(pcan_p), r2);
1944 		if ((stat & AN_STAT_CMD_CODE) == (cmd & AN_STAT_CMD_CODE))
1945 			break;
1946 	}
1947 	if (cmd == AN_CMD_FW_RESTART) {
1948 		PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CMD);
1949 		return (PCAN_SUCCESS);
1950 	}
1951 	if (i == AN_TIMEOUT) {
1952 #ifdef DEBUG
1953 		if (pcan_debug & PCAN_DBG_CMD) {
1954 			cmn_err(CE_WARN, "pcan set_cmd<%x,%x>: timeout "
1955 			    "%x,%x,%x,%x\n", cmd, param, stat, r0, r1, r2);
1956 		}
1957 #endif
1958 		ret = PCAN_TIMEDOUT_ACCESS;
1959 	} else {
1960 		if (stat & AN_STAT_CMD_RESULT) {
1961 #ifdef DEBUG
1962 			if (pcan_debug & PCAN_DBG_CMD) {
1963 				cmn_err(CE_WARN, "pcan set_cmd<%x,%x>: failed "
1964 				    "%x,%x,%x,%x\n",
1965 				    cmd, param, stat, r0, r1, r2);
1966 			}
1967 #endif
1968 			ret = PCAN_TIMEDOUT_ACCESS;
1969 		} else {
1970 			ret = PCAN_SUCCESS;
1971 		}
1972 	}
1973 	PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CMD);
1974 	PCAN_READ(pcan_p, AN_COMMAND(pcan_p), stat);
1975 	if (stat & AN_CMD_BUSY)
1976 		PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CLR_STUCK_BUSY);
1977 	if (ret == PCAN_SUCCESS) {
1978 		if (cmd == AN_CMD_ENABLE)
1979 			pcan_p->pcan_flag |= PCAN_ENABLED;
1980 		if (cmd == AN_CMD_DISABLE)
1981 			pcan_p->pcan_flag &= (~PCAN_ENABLED);
1982 	}
1983 	return (ret);
1984 }
1985 
1986 static uint16_t
1987 pcan_set_ch(pcan_maci_t *pcan_p, uint16_t type, uint16_t off, uint16_t channel)
1988 {
1989 	int i;
1990 	uint16_t stat, select, offset;
1991 
1992 	if (channel) {
1993 		select = AN_SEL1;
1994 		offset = AN_OFF1;
1995 	} else {
1996 		select = AN_SEL0;
1997 		offset = AN_OFF0;
1998 	}
1999 	PCAN_WRITE(pcan_p, select, type);
2000 	PCAN_WRITE(pcan_p, offset, off);
2001 	for (i = 0; i < AN_TIMEOUT; i++) {
2002 		PCAN_READ(pcan_p, offset, stat);
2003 		if (!(stat & (AN_OFF_BUSY|AN_OFF_ERR)))
2004 			break;
2005 	}
2006 	if (stat & (AN_OFF_BUSY|AN_OFF_ERR)) { /* time out */
2007 		PCANDBG((CE_WARN, "pcan: set_ch%d %x %x TO %x\n",
2008 		    channel, type, off, stat));
2009 		return (PCAN_TIMEDOUT_TARGET);
2010 	}
2011 	return (PCAN_SUCCESS);
2012 }
2013 
2014 static uint16_t
2015 pcan_get_ltv(pcan_maci_t *pcan_p, uint16_t len, uint16_t type, uint16_t *val_p)
2016 {
2017 	uint16_t stat;
2018 
2019 	PCANDBG((CE_NOTE, "pcan: get_ltv(%p,%x,%x,%p)\n",
2020 	    (void *)pcan_p, len, type, (void *)val_p));
2021 	ASSERT(!(len & 1));
2022 
2023 	if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
2024 		uint32_t i;
2025 		struct an_card_rid_desc an_rid_desc;
2026 		struct an_ltv_gen *an_ltv;
2027 		if (!pcan_p->pcan_cmd.dma_virtaddr)
2028 			return (EIO);
2029 		an_rid_desc.an_valid = 1;
2030 		an_rid_desc.an_len = AN_RID_BUFFER_SIZE;
2031 		an_rid_desc.an_rid = 0;
2032 		an_rid_desc.an_phys = pcan_p->pcan_cmd.dma_physaddr;
2033 		bzero(pcan_p->pcan_cmd.dma_virtaddr, AN_RID_BUFFER_SIZE);
2034 
2035 		for (i = 0; i < sizeof (an_rid_desc) / 4; i++)
2036 			PCAN_AUX_PUT32(pcan_p, AN_HOST_DESC_OFFSET + i * 4,
2037 			    ((uint32_t *)&an_rid_desc)[i]);
2038 
2039 		if (pcan_set_cmd0(pcan_p, AN_CMD_ACCESS |
2040 		    AN_ACCESS_READ, type, 0, 0)) {
2041 			cmn_err(CE_WARN, "pcan get_ltv: set cmd error");
2042 			return (EIO);
2043 		}
2044 
2045 		an_ltv = (struct an_ltv_gen *)pcan_p->pcan_cmd.dma_virtaddr;
2046 #ifdef DEBUG
2047 		if (pcan_debug & PCAN_DBG_INFO) {
2048 			cmn_err(CE_NOTE, "pcan get_ltv: type=%x,"
2049 			    "expected len=%d," "actual len=%d",
2050 			    type, len, an_ltv->an_len);
2051 			for (i = 0; i < an_ltv->an_len; i++)
2052 				cmn_err(CE_NOTE, "%d: %x", i,
2053 				    *(((uint8_t *)an_ltv) + i));
2054 		}
2055 #endif
2056 		if (an_ltv->an_len != len) {
2057 			PCANDBG((CE_WARN, "pcan get_ltv: rid=%x expected len=%d"
2058 			    "actual: len=%d", type,
2059 			    len, an_ltv->an_len));
2060 			/* return (EIO); */
2061 		}
2062 		bcopy(an_ltv, val_p, len);
2063 	} else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) {
2064 		len >>= 1;	/* convert bytes to 16-bit words */
2065 
2066 		/* 1. select read mode */
2067 		if (stat = pcan_set_cmd(pcan_p, AN_CMD_ACCESS |
2068 		    AN_ACCESS_READ, type))
2069 			return (stat);
2070 
2071 		/* 2. select Buffer Access Path (channel) 1 for PIO */
2072 		if (stat = pcan_set_ch(pcan_p, type, 0, 1))
2073 			return (stat);
2074 
2075 		/* 3. read length */
2076 		PCAN_READ(pcan_p, AN_DATA1, stat);
2077 		*val_p++ = stat;
2078 		if (stat != (len << 1)) {
2079 			PCANDBG((CE_NOTE, "pcan get_ltv[%x]:expect %x,"
2080 			    "got %x\n", type, (len + 1) << 1, stat));
2081 			stat = (stat >> 1) - 1;
2082 			len = MIN(stat, len);
2083 		}
2084 		/* 4. read value */
2085 		for (stat = 0; stat < len - 1; stat++, val_p++) {
2086 			PCAN_READ_P(pcan_p, AN_DATA1, val_p, 1);
2087 		}
2088 	}
2089 	return (PCAN_SUCCESS);
2090 }
2091 
2092 static uint16_t
2093 pcan_put_ltv(pcan_maci_t *pcan_p, uint16_t len, uint16_t type, uint16_t *val_p)
2094 {
2095 	uint16_t stat;
2096 	int i;
2097 
2098 	ASSERT(!(len & 1));
2099 
2100 	if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
2101 		struct an_card_rid_desc an_rid_desc;
2102 
2103 		for (i = 0; i < AN_TIMEOUT; i++) {
2104 			PCAN_READ(pcan_p, AN_COMMAND(pcan_p), stat);
2105 			if (!(stat & AN_CMD_BUSY)) {
2106 				break;
2107 			}
2108 		}
2109 		if (i == AN_TIMEOUT) {
2110 			cmn_err(CE_WARN, "pcan put_ltv: busy");
2111 		}
2112 
2113 		an_rid_desc.an_valid = 1;
2114 		an_rid_desc.an_len = len;
2115 		an_rid_desc.an_rid = type;
2116 		an_rid_desc.an_phys = pcan_p->pcan_cmd.dma_physaddr;
2117 
2118 		bcopy(val_p, pcan_p->pcan_cmd.dma_virtaddr,
2119 		    an_rid_desc.an_len);
2120 
2121 		for (i = 0; i < sizeof (an_rid_desc) / 4; i++)
2122 			PCAN_AUX_PUT32(pcan_p, AN_HOST_DESC_OFFSET + i * 4,
2123 			    ((uint32_t *)&an_rid_desc)[i]);
2124 		pcan_delay(pcan_p, 100000);
2125 		stat = pcan_set_cmd0(pcan_p, AN_CMD_ACCESS |
2126 		    AN_ACCESS_WRITE, type, 0, 0);
2127 		pcan_delay(pcan_p, 100000);
2128 		return (stat);
2129 	} else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) {
2130 		/* 0. select read mode first */
2131 		if (stat = pcan_set_cmd(pcan_p, AN_CMD_ACCESS |
2132 		    AN_ACCESS_READ, type))
2133 			return (stat);
2134 
2135 		/* 1. select Buffer Access Path (channel) 1 for PIO */
2136 		if (stat = pcan_set_ch(pcan_p, type, 0, 1))
2137 			return (stat);
2138 
2139 		/* 2. write length */
2140 		len >>= 1;		/* convert bytes to 16-bit words */
2141 		stat = len;
2142 		PCAN_WRITE(pcan_p, AN_DATA1, stat);
2143 
2144 		/* 3. write value */
2145 		val_p++;
2146 		for (stat = 0; stat < len-1; stat++, val_p++) {
2147 			PCAN_WRITE_P(pcan_p, AN_DATA1, val_p, 1);
2148 		}
2149 
2150 		/* 4. select write mode */
2151 		return (pcan_set_cmd(pcan_p, AN_CMD_ACCESS |
2152 		    AN_ACCESS_WRITE, type));
2153 	}
2154 	return (PCAN_FAIL);
2155 }
2156 
2157 /*ARGSUSED*/
2158 static uint16_t
2159 pcan_rdch0(pcan_maci_t *pcan_p, uint16_t type, uint16_t off, uint16_t *buf_p,
2160 	int len, int order)
2161 {
2162 	ASSERT(!(len & 1));
2163 
2164 	if (pcan_set_ch(pcan_p, type, off, 0) != PCAN_SUCCESS)
2165 		return (PCAN_FAIL);
2166 	len >>= 1;
2167 	for (off = 0; off < len; off++, buf_p++) {
2168 		PCAN_READ_P(pcan_p, AN_DATA0, buf_p, order);
2169 	}
2170 	return (PCAN_SUCCESS);
2171 }
2172 
2173 /*ARGSUSED*/
2174 static uint16_t
2175 pcan_wrch1(pcan_maci_t *pcan_p, uint16_t type, uint16_t off, uint16_t *buf_p,
2176 	int len, int order)
2177 {
2178 	ASSERT(!(len & 1));
2179 
2180 	if (pcan_set_ch(pcan_p, type, off, 1) != PCAN_SUCCESS)
2181 		return (PCAN_FAIL);
2182 	len >>= 1;
2183 	for (off = 0; off < len; off++, buf_p++) {
2184 		PCAN_WRITE_P(pcan_p, AN_DATA1, buf_p, order);
2185 	}
2186 	return (PCAN_SUCCESS);
2187 }
2188 
2189 static uint16_t
2190 pcan_status_ltv(int rw, pcan_maci_t *pcan_p, struct an_ltv_status *status_p)
2191 {
2192 	uint16_t ret, len;
2193 
2194 	if (rw != PCAN_READ_LTV) {
2195 		cmn_err(CE_WARN, "pcan status_ltv: unsupported op %x", rw);
2196 		return (PCAN_FAIL);
2197 	}
2198 	if (ret = pcan_get_ltv(pcan_p, sizeof (*status_p), AN_RID_STATUS,
2199 	    (uint16_t *)status_p))
2200 		return (ret);
2201 
2202 	PCAN_SWAP16_BUF(status_p->an_macaddr);
2203 	PCAN_SWAP16_BUF(status_p->an_ssid);
2204 	len = min(status_p->an_ssidlen, 31);
2205 	status_p->an_ssid[len] = '\0';
2206 	PCAN_SWAP16_BUF(status_p->an_ap_name);
2207 	PCAN_SWAP16_BUF(status_p->an_cur_bssid);
2208 	PCAN_SWAP16_BUF(status_p->an_prev_bssid1);
2209 	PCAN_SWAP16_BUF(status_p->an_prev_bssid2);
2210 	PCAN_SWAP16_BUF(status_p->an_prev_bssid3);
2211 	PCAN_SWAP16_BUF(status_p->an_ap_ip_address);
2212 	PCAN_SWAP16_BUF(status_p->an_carrier);
2213 	return (PCAN_SUCCESS);
2214 }
2215 
2216 static uint16_t
2217 pcan_cfg_ltv(int rw, pcan_maci_t *pcan_p, struct an_ltv_genconfig *cfg_p)
2218 {
2219 	uint16_t ret;
2220 	uint16_t rid = cfg_p == &pcan_p->an_config ?
2221 	    AN_RID_GENCONFIG : AN_RID_ACTUALCFG;
2222 
2223 	if (rw == PCAN_READ_LTV) {
2224 		if (ret = pcan_get_ltv(pcan_p, sizeof (*cfg_p), rid,
2225 		    (uint16_t *)cfg_p))
2226 			return (ret);
2227 		goto done;
2228 	}
2229 	PCAN_SWAP16_BUF(cfg_p->an_macaddr);
2230 	PCAN_SWAP16_BUF(cfg_p->an_rates);
2231 	if (ret = pcan_put_ltv(pcan_p, sizeof (*cfg_p),
2232 	    rid, (uint16_t *)cfg_p))
2233 		return (ret);
2234 done:
2235 	PCAN_SWAP16_BUF(cfg_p->an_macaddr);
2236 	PCAN_SWAP16_BUF(cfg_p->an_rates);
2237 	return (ret);
2238 }
2239 
2240 static uint16_t
2241 pcan_cap_ltv(int rw, pcan_maci_t *pcan_p)
2242 {
2243 	uint16_t ret;
2244 
2245 	if (rw != PCAN_READ_LTV) {
2246 		cmn_err(CE_WARN, "pcan cap_ltv: unsupported op %x", rw);
2247 		return (PCAN_FAIL);
2248 	}
2249 	if (ret = pcan_get_ltv(pcan_p, sizeof (struct an_ltv_caps),
2250 	    AN_RID_CAPABILITIES, (uint16_t *)&pcan_p->an_caps))
2251 		return (ret);
2252 
2253 	PCAN_SWAP16_BUF(pcan_p->an_caps.an_oui);
2254 	PCAN_SWAP16_BUF(pcan_p->an_caps.an_manufname);
2255 	PCAN_SWAP16_BUF(pcan_p->an_caps.an_prodname);
2256 	PCAN_SWAP16_BUF(pcan_p->an_caps.an_prodvers);
2257 	PCAN_SWAP16_BUF(pcan_p->an_caps.an_oemaddr);
2258 	PCAN_SWAP16_BUF(pcan_p->an_caps.an_aironetaddr);
2259 	PCAN_SWAP16_BUF(pcan_p->an_caps.an_callid);
2260 	PCAN_SWAP16_BUF(pcan_p->an_caps.an_supported_rates);
2261 	return (PCAN_SUCCESS);
2262 }
2263 
2264 static uint16_t
2265 pcan_ssid_ltv(int rw, pcan_maci_t *pcan_p)
2266 {
2267 	uint16_t ret;
2268 
2269 	if (rw == PCAN_READ_LTV) {
2270 		if (ret = pcan_get_ltv(pcan_p, sizeof (struct an_ltv_ssidlist),
2271 		    AN_RID_SSIDLIST, (uint16_t *)&pcan_p->an_ssidlist))
2272 			return (ret);
2273 		goto done;
2274 	}
2275 	PCAN_SWAP16_BUF(pcan_p->an_ssidlist.an_ssid1);
2276 	PCAN_SWAP16_BUF(pcan_p->an_ssidlist.an_ssid2);
2277 	PCAN_SWAP16_BUF(pcan_p->an_ssidlist.an_ssid3);
2278 	if (ret = pcan_put_ltv(pcan_p, sizeof (struct an_ltv_ssidlist),
2279 	    AN_RID_SSIDLIST, (uint16_t *)&pcan_p->an_ssidlist))
2280 		return (ret);
2281 done:
2282 	PCAN_SWAP16_BUF(pcan_p->an_ssidlist.an_ssid1);
2283 	PCAN_SWAP16_BUF(pcan_p->an_ssidlist.an_ssid2);
2284 	PCAN_SWAP16_BUF(pcan_p->an_ssidlist.an_ssid3);
2285 	return (ret);
2286 }
2287 
2288 static uint16_t
2289 pcan_aplist_ltv(int rw, pcan_maci_t *pcan_p)
2290 {
2291 	uint16_t ret;
2292 
2293 	if (rw == PCAN_READ_LTV) {
2294 		if (ret = pcan_get_ltv(pcan_p, sizeof (struct an_ltv_aplist),
2295 		    AN_RID_APLIST, (uint16_t *)&pcan_p->an_aplist))
2296 			return (ret);
2297 		goto done;
2298 	}
2299 	PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap1);
2300 	PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap2);
2301 	PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap3);
2302 	PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap4);
2303 	if (ret = pcan_put_ltv(pcan_p, sizeof (struct an_ltv_aplist),
2304 	    AN_RID_APLIST, (uint16_t *)&pcan_p->an_aplist))
2305 		return (ret);
2306 done:
2307 	PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap1);
2308 	PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap2);
2309 	PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap3);
2310 	PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap4);
2311 	return (ret);
2312 }
2313 
2314 static uint16_t
2315 pcan_scanresult_ltv(int rw, pcan_maci_t *pcan_p, uint16_t type,
2316     struct an_ltv_scanresult *scanresult_p)
2317 {
2318 	uint16_t ret, len;
2319 
2320 	if (rw != PCAN_READ_LTV) {
2321 		cmn_err(CE_WARN, "pcan scan_ltv: readonly rid %x\n", type);
2322 		return (PCAN_FAIL);
2323 	}
2324 	if (ret = pcan_get_ltv(pcan_p, sizeof (struct an_ltv_scanresult),
2325 	    type, (uint16_t *)scanresult_p))
2326 		return (ret);
2327 	PCAN_SWAP16_BUF(scanresult_p->an_bssid);
2328 	PCAN_SWAP16_BUF(scanresult_p->an_ssid);
2329 	len = min(scanresult_p->an_ssidlen, 31);
2330 	scanresult_p->an_ssid[len] = '\0';
2331 	PCAN_SWAP16_BUF(scanresult_p->an_rates);
2332 	return (PCAN_SUCCESS);
2333 }
2334 
2335 static uint16_t
2336 pcan_one_wepkey(int rw, pcan_maci_t *pcan_p, struct an_ltv_wepkey *wkp,
2337     uint16_t rid)
2338 {
2339 	uint16_t ret;
2340 
2341 	if (rw == PCAN_READ_LTV) {
2342 		if (ret = pcan_get_ltv(pcan_p, sizeof (struct an_ltv_wepkey),
2343 		    rid, (uint16_t *)wkp)) {
2344 			return (ret);
2345 		}
2346 		goto done;
2347 	}
2348 	PCAN_SWAP16_BUF(wkp->an_macaddr);
2349 	PCAN_SWAP16_BUF(wkp->an_key);
2350 	if (ret = pcan_put_ltv(pcan_p, sizeof (struct an_ltv_wepkey),
2351 	    rid, (uint16_t *)wkp))
2352 		return (ret);
2353 done:
2354 	PCAN_SWAP16_BUF(wkp->an_macaddr);
2355 	PCAN_SWAP16_BUF(wkp->an_key);
2356 	return (ret);
2357 }
2358 
2359 static uint16_t
2360 pcan_wepkey_ltv(int rw, pcan_maci_t *pcan_p)
2361 {
2362 	uint16_t ret, i;
2363 	struct an_ltv_wepkey wk;
2364 
2365 	if (rw == PCAN_READ_LTV) {
2366 		uint16_t rid = AN_RID_WEPKEY2;
2367 
2368 		if (ret = pcan_one_wepkey(rw, pcan_p, &wk, rid))
2369 			return (ret);
2370 		for (i = 0; i < 5; i++) {
2371 			if (wk.an_index < 4)
2372 				pcan_p->an_wepkey[wk.an_index] = wk;
2373 			else if (wk.an_index == 0xffff)
2374 				pcan_p->an_cur_wepkey = wk.an_macaddr[0];
2375 			rid = AN_RID_WEPKEY;
2376 		}
2377 		return (PCAN_SUCCESS);
2378 	}
2379 	for (i = 0; i < MAX_NWEPKEYS; i++) {
2380 		if (pcan_p->an_wepkey[i].an_index == i) {
2381 			if (ret = pcan_one_wepkey(rw, pcan_p,
2382 			    &pcan_p->an_wepkey[i], AN_RID_WEPKEY2))
2383 				return (ret);
2384 		}
2385 	}
2386 	/* Now set the default key */
2387 	(void) memset(&wk, 0, sizeof (wk));
2388 	wk.an_index = 0xffff;
2389 	wk.an_macaddr[0] = pcan_p->an_cur_wepkey;
2390 	ret = pcan_one_wepkey(rw, pcan_p, &wk, AN_RID_WEPKEY2);
2391 	return (ret);
2392 }
2393 
2394 static uint16_t
2395 pcan_alloc_nicmem(pcan_maci_t *pcan_p, uint16_t len, uint16_t *id_p)
2396 {
2397 	int i;
2398 	uint16_t stat;
2399 
2400 	len = ((len + 1) >> 1) << 1;	/* round up to 16-bit boundary */
2401 
2402 	if (stat = pcan_set_cmd(pcan_p, AN_CMD_ALLOC_MEM, len))
2403 		return (stat);
2404 	for (i = 0; !(stat & AN_EV_ALLOC) && (i < AN_TIMEOUT); i++) {
2405 		PCAN_READ(pcan_p, AN_EVENT_STAT(pcan_p), stat);
2406 	}
2407 	if (!(stat & AN_EV_ALLOC))
2408 		return (PCAN_TIMEDOUT_ALLOC);
2409 	PCAN_READ(pcan_p, AN_ALLOC_FID, stat);
2410 	PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_ALLOC);
2411 	*id_p = stat;
2412 
2413 	/* zero fill the allocated NIC mem - sort of pcan_fill_ch0 */
2414 	(void) pcan_set_ch(pcan_p, stat, 0, 0);
2415 	for (len >>= 1, stat = 0; stat < len; stat++) {
2416 		PCAN_WRITE(pcan_p, AN_DATA0, 0);
2417 	}
2418 	return (PCAN_SUCCESS);
2419 }
2420 
2421 static void
2422 pcan_stop_rx_dma(pcan_maci_t *pcan_p)
2423 {
2424 	int i, j;
2425 	struct an_card_rx_desc  an_rx_desc;
2426 
2427 	for (i = 0; i < AN_MAX_RX_DESC; i++) {
2428 		bzero(&an_rx_desc, sizeof (an_rx_desc));
2429 		an_rx_desc.an_valid = 0;
2430 		an_rx_desc.an_len = AN_RX_BUFFER_SIZE;
2431 		an_rx_desc.an_done = 1;
2432 		an_rx_desc.an_phys = pcan_p->pcan_rx[i].dma_physaddr;
2433 		for (j = 0; j < sizeof (an_rx_desc) / 4; j++)
2434 			PCAN_AUX_PUT32(pcan_p, AN_RX_DESC_OFFSET
2435 			    + (i * sizeof (an_rx_desc))
2436 			    + (j * 4), ((uint32_t *)&an_rx_desc)[j]);
2437 	}
2438 }
2439 
2440 static int
2441 pcan_init_dma_desc(pcan_maci_t *pcan_p)
2442 {
2443 	int i, j;
2444 	struct an_card_rid_desc an_rid_desc;
2445 	struct an_card_rx_desc  an_rx_desc;
2446 	struct an_card_tx_desc  an_tx_desc;
2447 
2448 	/* Allocate DMA for rx */
2449 	if (pcan_set_cmd0(pcan_p, AN_CMD_ALLOC_DESC,
2450 	    AN_DESCRIPTOR_RX, AN_RX_DESC_OFFSET,
2451 	    AN_MAX_RX_DESC) != PCAN_SUCCESS) {
2452 		cmn_err(CE_WARN, "pcan init_dma: fail to alloc rx descriptor");
2453 		goto error;
2454 	}
2455 	for (i = 0; i < AN_MAX_RX_DESC; i++) {
2456 		bzero(&an_rx_desc, sizeof (an_rx_desc));
2457 		an_rx_desc.an_valid = 1;
2458 		an_rx_desc.an_len = AN_RX_BUFFER_SIZE;
2459 		an_rx_desc.an_done = 0;
2460 		an_rx_desc.an_phys = pcan_p->pcan_rx[i].dma_physaddr;
2461 		for (j = 0; j < sizeof (an_rx_desc) / 4; j++)
2462 			PCAN_AUX_PUT32(pcan_p, AN_RX_DESC_OFFSET
2463 			    + (i * sizeof (an_rx_desc))
2464 			    + (j * 4), ((uint32_t *)&an_rx_desc)[j]);
2465 	}
2466 
2467 
2468 	/* Allocate DMA for tx */
2469 	if (pcan_set_cmd0(pcan_p, AN_CMD_ALLOC_DESC,
2470 	    AN_DESCRIPTOR_TX, AN_TX_DESC_OFFSET,
2471 	    AN_MAX_TX_DESC) != PCAN_SUCCESS) {
2472 		cmn_err(CE_WARN, "pcan init_dma: fail to alloc tx descriptor");
2473 		goto error;
2474 	}
2475 
2476 	for (i = 0; i < AN_MAX_TX_DESC; i++) {
2477 		an_tx_desc.an_offset = 0;
2478 		an_tx_desc.an_eoc = 0;
2479 		an_tx_desc.an_valid = 0;
2480 		an_tx_desc.an_len = 0;
2481 		an_tx_desc.an_phys = pcan_p->pcan_tx[i].dma_physaddr;
2482 
2483 		for (j = 0; j < sizeof (an_tx_desc) / 4; j++)
2484 			PCAN_AUX_PUT32(pcan_p, AN_TX_DESC_OFFSET
2485 			    + (i * sizeof (an_tx_desc))
2486 			    + (j * 4), ((uint32_t *)&an_tx_desc)[j]);
2487 	}
2488 
2489 	/* Allocate DMA for rid */
2490 	if (pcan_set_cmd0(pcan_p, AN_CMD_ALLOC_DESC,
2491 	    AN_DESCRIPTOR_HOSTRW, AN_HOST_DESC_OFFSET, 1) != PCAN_SUCCESS) {
2492 		cmn_err(CE_WARN, "pcan init_dma: fail to alloc rid descriptor");
2493 		goto error;
2494 	}
2495 	bzero(&an_rid_desc, sizeof (an_rid_desc));
2496 	an_rid_desc.an_valid = 1;
2497 	an_rid_desc.an_len = AN_RID_BUFFER_SIZE;
2498 	an_rid_desc.an_rid = 0;
2499 	an_rid_desc.an_phys = pcan_p->pcan_cmd.dma_physaddr;
2500 
2501 	for (i = 0; i < sizeof (an_rid_desc) / 4; i++)
2502 		PCAN_AUX_PUT32(pcan_p, AN_HOST_DESC_OFFSET + i * 4,
2503 		    ((uint32_t *)&an_rid_desc)[i]);
2504 
2505 	pcan_p->pcan_txring.an_tx_prod = 0;
2506 	pcan_p->pcan_txring.an_tx_cons = 0;
2507 	pcan_p->pcan_flag &= ~PCAN_CARD_SEND;
2508 	return (PCAN_SUCCESS);
2509 error:
2510 	return (PCAN_FAIL);
2511 }
2512 
2513 static int
2514 pcan_init_dma(dev_info_t *dip, pcan_maci_t *pcan_p)
2515 {
2516 	int i, ret = PCAN_FAIL;
2517 	ddi_dma_cookie_t dma_cookie;
2518 	size_t len;
2519 
2520 	/* Allocate DMA for rx */
2521 	for (i = 0; i < AN_MAX_RX_DESC; i++) {
2522 		if (ddi_dma_alloc_handle(dip, &control_cmd_dma_attr,
2523 		    DDI_DMA_SLEEP, 0,
2524 		    &pcan_p->pcan_rx[i].dma_handle) != DDI_SUCCESS)
2525 			goto error;
2526 
2527 		if (ddi_dma_mem_alloc(pcan_p->pcan_rx[i].dma_handle,
2528 		    AN_RX_BUFFER_SIZE, &accattr,
2529 		    DDI_DMA_STREAMING, DDI_DMA_SLEEP, 0,
2530 		    (caddr_t *)&pcan_p->pcan_rx[i].dma_virtaddr, &len,
2531 		    &pcan_p->pcan_rx[i].dma_acc_handle) != DDI_SUCCESS) {
2532 			goto error;
2533 		}
2534 		if (ddi_dma_addr_bind_handle(
2535 		    pcan_p->pcan_rx[i].dma_handle,
2536 		    NULL, (caddr_t)pcan_p->pcan_rx[i].dma_virtaddr,
2537 		    len, DDI_DMA_READ |
2538 		    DDI_DMA_STREAMING, DDI_DMA_SLEEP, 0, &dma_cookie,
2539 		    &pcan_p->pcan_rx[i].ncookies) != DDI_DMA_MAPPED) {
2540 			goto error;
2541 		}
2542 		ASSERT(pcan_p->pcan_rx[i].ncookies == 1);
2543 		pcan_p->pcan_rx[i].dma_physaddr = dma_cookie.dmac_address;
2544 	}
2545 
2546 	/* Allocate DMA for tx */
2547 	for (i = 0; i < AN_MAX_TX_DESC; i++) {
2548 		if (ddi_dma_alloc_handle(dip, &control_cmd_dma_attr,
2549 		    DDI_DMA_SLEEP, 0,
2550 		    &pcan_p->pcan_tx[i].dma_handle) != DDI_SUCCESS)
2551 			goto error;
2552 
2553 		if (ddi_dma_mem_alloc(pcan_p->pcan_tx[i].dma_handle,
2554 		    AN_TX_BUFFER_SIZE, &accattr,
2555 		    DDI_DMA_STREAMING, DDI_DMA_SLEEP, 0,
2556 		    (caddr_t *)&pcan_p->pcan_tx[i].dma_virtaddr, &len,
2557 		    &pcan_p->pcan_tx[i].dma_acc_handle) != DDI_SUCCESS) {
2558 			goto error;
2559 		}
2560 		if (ddi_dma_addr_bind_handle(
2561 		    pcan_p->pcan_tx[i].dma_handle,
2562 		    NULL, (caddr_t)pcan_p->pcan_tx[i].dma_virtaddr,
2563 		    len, DDI_DMA_WRITE |
2564 		    DDI_DMA_STREAMING, DDI_DMA_SLEEP, 0, &dma_cookie,
2565 		    &pcan_p->pcan_tx[i].ncookies) != DDI_DMA_MAPPED) {
2566 			goto error;
2567 		}
2568 		ASSERT(pcan_p->pcan_tx[i].ncookies == 1);
2569 		pcan_p->pcan_tx[i].dma_physaddr = dma_cookie.dmac_address;
2570 	}
2571 
2572 	/* Allocate DMA for rid */
2573 	if (ddi_dma_alloc_handle(dip, &control_cmd_dma_attr,
2574 	    DDI_DMA_SLEEP, 0,
2575 	    &pcan_p->pcan_cmd.dma_handle) != DDI_SUCCESS)
2576 		goto error;
2577 
2578 	if (ddi_dma_mem_alloc(pcan_p->pcan_cmd.dma_handle,
2579 	    AN_RID_BUFFER_SIZE, &accattr,
2580 	    DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, 0,
2581 	    (caddr_t *)&pcan_p->pcan_cmd.dma_virtaddr, &len,
2582 	    &pcan_p->pcan_cmd.dma_acc_handle) != DDI_SUCCESS) {
2583 		goto error;
2584 	}
2585 	if (ddi_dma_addr_bind_handle(
2586 	    pcan_p->pcan_cmd.dma_handle,
2587 	    NULL, (caddr_t)pcan_p->pcan_cmd.dma_virtaddr,
2588 	    len, DDI_DMA_RDWR |
2589 	    DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, 0, &dma_cookie,
2590 	    &pcan_p->pcan_cmd.ncookies) != DDI_DMA_MAPPED) {
2591 		goto error;
2592 	}
2593 	ASSERT(pcan_p->pcan_cmd.ncookies == 1);
2594 	pcan_p->pcan_cmd.dma_physaddr = dma_cookie.dmac_address;
2595 
2596 	if (ret = pcan_init_dma_desc(pcan_p)) {
2597 		cmn_err(CE_WARN, "pcan init_dma_desc: failed\n");
2598 		goto error;
2599 	}
2600 
2601 	return (PCAN_SUCCESS);
2602 error:
2603 	pcan_free_dma(pcan_p);
2604 	return (ret);
2605 }
2606 
2607 static void
2608 pcan_free_dma(pcan_maci_t *pcan_p)
2609 {
2610 	int i;
2611 
2612 	/* free RX dma */
2613 	pcan_stop_rx_dma(pcan_p);
2614 	for (i = 0; i < AN_MAX_RX_DESC; i++) {
2615 		if (pcan_p->pcan_rx[i].dma_handle != NULL) {
2616 			if (pcan_p->pcan_rx[i].ncookies) {
2617 				(void) ddi_dma_unbind_handle(
2618 				    pcan_p->pcan_rx[i].dma_handle);
2619 				pcan_p->pcan_rx[i].ncookies = 0;
2620 			}
2621 			ddi_dma_free_handle(
2622 			    &pcan_p->pcan_rx[i].dma_handle);
2623 			pcan_p->pcan_rx[i].dma_handle = NULL;
2624 		}
2625 		if (pcan_p->pcan_rx[i].dma_acc_handle != NULL) {
2626 			ddi_dma_mem_free(
2627 			    &pcan_p->pcan_rx[i].dma_acc_handle);
2628 			pcan_p->pcan_rx[i].dma_acc_handle = NULL;
2629 		}
2630 	}
2631 
2632 	/* free TX dma */
2633 	for (i = 0; i < AN_MAX_TX_DESC; i++) {
2634 		if (pcan_p->pcan_tx[i].dma_handle != NULL) {
2635 			if (pcan_p->pcan_tx[i].ncookies) {
2636 				(void) ddi_dma_unbind_handle(
2637 				    pcan_p->pcan_tx[i].dma_handle);
2638 				pcan_p->pcan_tx[i].ncookies = 0;
2639 			}
2640 			ddi_dma_free_handle(
2641 			    &pcan_p->pcan_tx[i].dma_handle);
2642 			pcan_p->pcan_tx[i].dma_handle = NULL;
2643 		}
2644 		if (pcan_p->pcan_tx[i].dma_acc_handle != NULL) {
2645 			ddi_dma_mem_free(
2646 			    &pcan_p->pcan_tx[i].dma_acc_handle);
2647 			pcan_p->pcan_tx[i].dma_acc_handle = NULL;
2648 		}
2649 	}
2650 
2651 	/* free cmd dma */
2652 	if (pcan_p->pcan_cmd.dma_handle != NULL) {
2653 		if (pcan_p->pcan_cmd.ncookies) {
2654 			(void) ddi_dma_unbind_handle(
2655 			    pcan_p->pcan_cmd.dma_handle);
2656 			pcan_p->pcan_cmd.ncookies = 0;
2657 		}
2658 		ddi_dma_free_handle(
2659 		    &pcan_p->pcan_cmd.dma_handle);
2660 		pcan_p->pcan_cmd.dma_handle = NULL;
2661 	}
2662 	if (pcan_p->pcan_cmd.dma_acc_handle != NULL) {
2663 		ddi_dma_mem_free(
2664 		    &pcan_p->pcan_cmd.dma_acc_handle);
2665 		pcan_p->pcan_cmd.dma_acc_handle = NULL;
2666 	}
2667 }
2668 
2669 /*
2670  * get card capability (WEP, default channel), setup broadcast, mac addresses
2671  */
2672 static uint32_t
2673 pcan_get_cap(pcan_maci_t *pcan_p)
2674 {
2675 	uint16_t stat;
2676 
2677 	if (stat = pcan_cfg_ltv(PCAN_READ_LTV, pcan_p, &pcan_p->an_config)) {
2678 		PCANDBG((CE_NOTE, "pcan get_cap: read cfg fail %x", stat));
2679 		return ((uint32_t)AN_RID_GENCONFIG << 16 | stat);
2680 	}
2681 
2682 	if (stat = pcan_cap_ltv(PCAN_READ_LTV, pcan_p)) {
2683 		PCANDBG((CE_NOTE, "pcan get_cap: read cap fail %x", stat));
2684 		return ((uint32_t)AN_RID_CAPABILITIES << 16 | stat);
2685 	}
2686 #ifdef DEBUG
2687 	if (pcan_debug & PCAN_DBG_FW_VERSION) {
2688 		cmn_err(CE_NOTE, "the version of the firmware in the wifi card "
2689 		    "'%s %s %s' is %s\n",
2690 		    pcan_p->an_caps.an_manufname,
2691 		    pcan_p->an_caps.an_prodname,
2692 		    pcan_p->pcan_device_type == PCAN_DEVICE_PCI ?
2693 		    "minipci" : "pccard",
2694 		    pcan_p->an_caps.an_prodvers);
2695 	}
2696 #endif
2697 
2698 	if (stat = pcan_ssid_ltv(PCAN_READ_LTV, pcan_p)) {
2699 		PCANDBG((CE_NOTE, "pcan get_cap: read ssid fail %x", stat));
2700 		return ((uint32_t)AN_RID_SSIDLIST << 16 | stat);
2701 	}
2702 
2703 	if (stat = pcan_aplist_ltv(PCAN_READ_LTV, pcan_p)) {
2704 		PCANDBG((CE_NOTE, "pcan get_cap: read aplist fail %x", stat));
2705 		return ((uint32_t)AN_RID_APLIST << 16 | stat);
2706 	}
2707 	if (stat = pcan_wepkey_ltv(PCAN_READ_LTV, pcan_p)) {
2708 		PCANDBG((CE_NOTE, "pcan get_cap: read wepkey fail %x", stat));
2709 		return ((uint32_t)AN_RID_WEPKEY2 << 16 | stat);
2710 	}
2711 	ether_copy(pcan_p->an_caps.an_oemaddr, pcan_p->pcan_mac_addr);
2712 	return (PCAN_SUCCESS);
2713 }
2714 
2715 static int
2716 pcan_config_mac(pcan_maci_t *pcan_p)
2717 {
2718 	uint16_t stat;
2719 
2720 	if (stat = pcan_ssid_ltv(PCAN_WRITE_LTV, pcan_p)) {
2721 		PCANDBG((CE_NOTE, "pcan config_mac: write SSID failed%x\n",
2722 		    stat));
2723 		return ((int)stat);
2724 	}
2725 
2726 	if (stat = pcan_aplist_ltv(PCAN_WRITE_LTV, pcan_p)) {
2727 		PCANDBG((CE_NOTE, "pcan config_mac: write APlist failed%x\n",
2728 		    stat));
2729 		return ((int)stat);
2730 	}
2731 	if (stat = pcan_wepkey_ltv(PCAN_WRITE_LTV, pcan_p)) {
2732 		PCANDBG((CE_NOTE, "pcan config_mac: write wepkey failed%x\n",
2733 		    stat));
2734 		return ((int)stat);
2735 	}
2736 	if (pcan_p->pcan_usewep)
2737 		pcan_p->an_config.an_authtype |=
2738 		    AN_AUTHTYPE_ENABLEWEP | AN_AUTHTYPE_ALLOW_UNENCRYPTED;
2739 	PCANDBG((CE_NOTE, "pcan config_mac: usewep=%x authtype=%x opmode=%x\n",
2740 	    pcan_p->pcan_usewep, pcan_p->an_config.an_authtype,
2741 	    pcan_p->an_config.an_opmode));
2742 
2743 	pcan_p->an_config.an_assoc_timeout = 5000; /* stop assoc seq in 5 sec */
2744 	if (stat = pcan_cfg_ltv(PCAN_WRITE_LTV, pcan_p, &pcan_p->an_config)) {
2745 		PCANDBG((CE_NOTE, "pcan config_mac: write cfg failed %x\n",
2746 		    stat));
2747 		return ((int)stat);
2748 	}
2749 
2750 	if (stat = pcan_cfg_ltv(PCAN_READ_LTV, pcan_p,
2751 	    &pcan_p->an_actual_config)) {
2752 		PCANDBG((CE_NOTE, "pcan config_mac: read cfg failed%x\n",
2753 		    stat));
2754 		return ((int)stat);
2755 	}
2756 	PCANDBG((CE_NOTE, "pcan config_mac: optionmask=%x authtype=%x\n", 0,
2757 	    pcan_p->an_actual_config.an_authtype));
2758 
2759 	if (stat = pcan_status_ltv(PCAN_READ_LTV, pcan_p, &pcan_p->an_status)) {
2760 		PCANDBG((CE_NOTE, "pcan config_mac: read status failed %x\n",
2761 		    stat));
2762 		return ((int)stat);
2763 	}
2764 	return (PCAN_SUCCESS);
2765 }
2766 
2767 static int
2768 pcan_loaddef(pcan_maci_t *pcan_p)
2769 {
2770 	int i;
2771 
2772 	pcan_p->an_ssidlist.an_ssid1_len = 0;
2773 	bzero(pcan_p->an_ssidlist.an_ssid1,
2774 	    sizeof (pcan_p->an_ssidlist.an_ssid1));
2775 	for (i = 0; i < MAX_NWEPKEYS; i++) {
2776 		pcan_p->an_wepkey[i].an_index = 0xffff;
2777 		bzero(pcan_p->an_wepkey[i].an_key,
2778 		    sizeof (pcan_p->an_wepkey[i].an_key));
2779 		pcan_p->an_wepkey[i].an_keylen = 0;
2780 		bzero(pcan_p->an_wepkey[i].an_macaddr,
2781 		    sizeof (pcan_p->an_wepkey[i].an_macaddr));
2782 		pcan_p->an_wepkey[i].an_macaddr[0] = 1;
2783 	}
2784 	pcan_p->an_cur_wepkey = 0;
2785 
2786 	pcan_p->pcan_usewep = 0;
2787 	pcan_p->an_config.an_opmode = AN_OPMODE_INFR_STATION;
2788 	pcan_p->an_config.an_authtype = AN_AUTHTYPE_OPEN;
2789 	pcan_p->an_config.an_stationary = 1;
2790 	pcan_p->an_config.an_max_beacon_lost_time = 0xffff;
2791 	i = pcan_config_mac(pcan_p);
2792 
2793 	return (i);
2794 }
2795 
2796 static int
2797 pcan_init_nicmem(pcan_maci_t *pcan_p)
2798 {
2799 	int i;
2800 	uint16_t ret;
2801 	pcan_txring_t *ring_p = &pcan_p->pcan_txring;
2802 
2803 	for (i = 0; i < AN_TX_RING_CNT; i++) {
2804 		uint16_t rc;
2805 		ret = pcan_alloc_nicmem(pcan_p, PCAN_NICMEM_SZ, &rc);
2806 		if (ret) {
2807 			cmn_err(CE_WARN, "pcan alloc NIC Tx buf[%x]: failed "
2808 			    "%x\n", i, ret);
2809 			return (DDI_FAILURE);
2810 		}
2811 		ring_p->an_tx_fids[i] = rc;
2812 		ring_p->an_tx_ring[i] = 0;
2813 		PCANDBG((CE_NOTE, "pcan: NIC tx_id[%x]=%x\n", i, rc));
2814 	}
2815 	ring_p->an_tx_prod = ring_p->an_tx_cons = 0;
2816 	return (PCAN_SUCCESS);
2817 }
2818 
2819 
2820 
2821 static void
2822 pcan_start_locked(pcan_maci_t *pcan_p)
2823 {
2824 	pcan_p->pcan_flag |= PCAN_CARD_INTREN;
2825 	PCAN_ENABLE_INTR(pcan_p);
2826 }
2827 
2828 static void
2829 pcan_stop_locked(pcan_maci_t *pcan_p)
2830 {
2831 	PCAN_DISABLE_INTR_CLEAR(pcan_p);
2832 	pcan_p->pcan_flag &= ~PCAN_CARD_INTREN;
2833 }
2834 
2835 /*
2836  * for scan result
2837  */
2838 static int
2839 pcan_add_scan_item(pcan_maci_t *pcan_p, struct an_ltv_scanresult s)
2840 {
2841 	an_scan_list_t *scan_item;
2842 
2843 	scan_item = kmem_zalloc(sizeof (an_scan_list_t), KM_SLEEP);
2844 	if (scan_item == NULL) {
2845 		cmn_err(CE_WARN, "pcan add_scan_item: zalloc failed\n");
2846 		return (PCAN_FAIL);
2847 	}
2848 	scan_item->an_val = s;
2849 	scan_item->an_timeout = AN_SCAN_TIMEOUT_MAX;
2850 	list_insert_tail(&pcan_p->an_scan_list, scan_item);
2851 	pcan_p->an_scan_num++;
2852 	return (PCAN_SUCCESS);
2853 }
2854 
2855 static void
2856 pcan_delete_scan_item(pcan_maci_t *pcan_p, an_scan_list_t *s)
2857 {
2858 	list_remove(&pcan_p->an_scan_list, s);
2859 	kmem_free(s, sizeof (*s));
2860 	pcan_p->an_scan_num--;
2861 }
2862 
2863 static void
2864 pcan_scanlist_timeout(void *arg)
2865 {
2866 	pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
2867 	an_scan_list_t *scan_item0, *scan_item1;
2868 
2869 	mutex_enter(&pcan_p->pcan_scanlist_lock);
2870 	scan_item0 = list_head(&pcan_p->an_scan_list);
2871 	for (; scan_item0; ) {
2872 		PCANDBG((CE_NOTE, "pcan scanlist: ssid = %s\n",
2873 		    scan_item0->an_val.an_ssid));
2874 		PCANDBG((CE_NOTE, "pcan scanlist: timeout left: %ds",
2875 		    scan_item0->an_timeout));
2876 		scan_item1 = list_next(&pcan_p->an_scan_list, scan_item0);
2877 		if (scan_item0->an_timeout == 0) {
2878 			pcan_delete_scan_item(pcan_p, scan_item0);
2879 		} else {
2880 			scan_item0->an_timeout--;
2881 		}
2882 		scan_item0 = scan_item1;
2883 	}
2884 	mutex_exit(&pcan_p->pcan_scanlist_lock);
2885 	pcan_p->an_scanlist_timeout_id = timeout(pcan_scanlist_timeout,
2886 	    pcan_p, drv_usectohz(1000000));
2887 }
2888 
2889 
2890 /*
2891  * for wificonfig and dlamd ioctl
2892  */
2893 static int
2894 pcan_cfg_essid(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
2895 {
2896 	uint16_t i;
2897 	char *value;
2898 	wldp_t	*infp;
2899 	wldp_t *outfp;
2900 	char *buf;
2901 	int iret;
2902 	struct an_ltv_status *status_p;
2903 	struct an_ltv_ssidlist *ssidlist_p;
2904 
2905 	status_p = &pcan_p->an_status;
2906 	ssidlist_p = &pcan_p->an_ssidlist;
2907 
2908 	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
2909 	if (buf == NULL) {
2910 		PCANDBG((CE_NOTE, "pcan cfg_essid: failed to alloc "
2911 		    "memory(%d)\n", MAX_BUF_LEN));
2912 		return (ENOMEM);
2913 	}
2914 	outfp = (wldp_t *)buf;
2915 	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
2916 	infp = (wldp_t *)mp->b_rptr;
2917 
2918 	if (cmd == WLAN_GET_PARAM) {
2919 		if (pcan_status_ltv(PCAN_READ_LTV, pcan_p, status_p)) {
2920 			outfp->wldp_length = WIFI_BUF_OFFSET;
2921 			outfp->wldp_result = WL_HW_ERROR;
2922 			goto done;
2923 		}
2924 
2925 		outfp->wldp_length = WIFI_BUF_OFFSET +
2926 		    offsetof(wl_essid_t, wl_essid_essid) +
2927 		    status_p->an_ssidlen;
2928 		((wl_essid_t *)(outfp->wldp_buf))->wl_essid_length =
2929 		    status_p->an_ssidlen;
2930 		bcopy(status_p->an_ssid, buf + WIFI_BUF_OFFSET +
2931 		    offsetof(wl_essid_t, wl_essid_essid),
2932 		    status_p->an_ssidlen);
2933 		outfp->wldp_result = WL_SUCCESS;
2934 	} else if (cmd == WLAN_SET_PARAM) {
2935 		bzero(ssidlist_p, sizeof (*ssidlist_p));
2936 		value = ((wl_essid_t *)(infp->wldp_buf))->wl_essid_essid;
2937 		(void) strncpy(ssidlist_p->an_ssid1, value,
2938 		    MIN(32, strlen(value)));
2939 		ssidlist_p->an_ssid1_len = strlen(value);
2940 		outfp->wldp_length = WIFI_BUF_OFFSET;
2941 		outfp->wldp_result = WL_SUCCESS;
2942 	} else {
2943 		kmem_free(buf, MAX_BUF_LEN);
2944 		return (EINVAL);
2945 	}
2946 done:
2947 	for (i = 0; i < (outfp->wldp_length); i++) {
2948 		(void) mi_mpprintf_putc((char *)mp, buf[i]);
2949 	}
2950 	iret = (int)(outfp->wldp_result);
2951 	kmem_free(buf, MAX_BUF_LEN);
2952 	return (iret);
2953 }
2954 
2955 static int
2956 pcan_cfg_bssid(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
2957 {
2958 	uint16_t i;
2959 	wldp_t *infp;
2960 	wldp_t *outfp;
2961 	char *buf;
2962 	wl_bssid_t *value;
2963 	int iret;
2964 	struct an_ltv_status *status_p;
2965 	struct an_ltv_aplist *aplist_p;
2966 
2967 	status_p = &pcan_p->an_status;
2968 	aplist_p = &pcan_p->an_aplist;
2969 
2970 	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
2971 	if (buf == NULL) {
2972 		PCANDBG((CE_NOTE, "pcan cfg_bssid: failed to alloc "
2973 		    "memory(%d)\n", MAX_BUF_LEN));
2974 		return (ENOMEM);
2975 	}
2976 	outfp = (wldp_t *)buf;
2977 	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
2978 	infp = (wldp_t *)mp->b_rptr;
2979 
2980 	outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_bssid_t);
2981 
2982 	if (cmd == WLAN_GET_PARAM) {
2983 		if (pcan_status_ltv(PCAN_READ_LTV, pcan_p, status_p)) {
2984 			outfp->wldp_length = WIFI_BUF_OFFSET;
2985 			outfp->wldp_result = WL_HW_ERROR;
2986 			goto done;
2987 		}
2988 
2989 		bcopy(status_p->an_cur_bssid, buf + WIFI_BUF_OFFSET,
2990 		    sizeof (wl_bssid_t));
2991 		outfp->wldp_result = WL_SUCCESS;
2992 		PCANDBG((CE_CONT,
2993 		    "pcan: cfg_bssid: bssid=%x %x %x %x %x %x\n",
2994 		    status_p->an_cur_bssid[0],
2995 		    status_p->an_cur_bssid[1],
2996 		    status_p->an_cur_bssid[2],
2997 		    status_p->an_cur_bssid[3],
2998 		    status_p->an_cur_bssid[4],
2999 		    status_p->an_cur_bssid[5]));
3000 	} else if (cmd == WLAN_SET_PARAM) {
3001 		value = (wl_bssid_t *)(infp->wldp_buf);
3002 		(void) strncpy((char *)aplist_p->an_ap1, (char *)value, 6);
3003 		outfp->wldp_length = WIFI_BUF_OFFSET;
3004 		outfp->wldp_result = WL_SUCCESS;
3005 	} else {
3006 		kmem_free(buf, MAX_BUF_LEN);
3007 		return (EINVAL);
3008 	}
3009 done:
3010 	for (i = 0; i < (outfp->wldp_length); i++) {
3011 		(void) mi_mpprintf_putc((char *)mp, buf[i]);
3012 	}
3013 	iret = (int)(outfp->wldp_result);
3014 	kmem_free(buf, MAX_BUF_LEN);
3015 	return (iret);
3016 }
3017 
3018 /*ARGSUSED*/
3019 static int
3020 pcan_cmd_scan(pcan_maci_t *pcan_p)
3021 {
3022 	uint16_t i = 0, j, ret = WL_SUCCESS;
3023 	uint8_t	bssid_t[6];
3024 	uint32_t check_num, enable;
3025 	an_scan_list_t *scan_item0;
3026 
3027 	enable = pcan_p->pcan_flag & PCAN_ENABLED;
3028 	if ((!enable) &&
3029 	    (ret = pcan_set_cmd(pcan_p, AN_CMD_ENABLE, 0))) {
3030 		ret = (int)WL_HW_ERROR;
3031 		goto exit;
3032 	}
3033 	if (ret = pcan_set_cmd(pcan_p, AN_CMD_SCAN, 0)) {
3034 		ret = (int)WL_HW_ERROR;
3035 		goto exit;
3036 	}
3037 
3038 	pcan_delay(pcan_p, 500000);
3039 	ret =  pcan_scanresult_ltv(PCAN_READ_LTV,
3040 	    pcan_p, AN_RID_ESSIDLIST_FIRST, &pcan_p->an_scanresult[i]);
3041 	if ((ret) || pcan_p->an_scanresult[i].an_index == 0xffff) {
3042 		goto done;
3043 	}
3044 	do
3045 	{
3046 		i++;
3047 		ret =  pcan_scanresult_ltv(PCAN_READ_LTV,
3048 		    pcan_p, AN_RID_ESSIDLIST_NEXT, &pcan_p->an_scanresult[i]);
3049 	} while ((!ret) && (i < 32) &&
3050 	    (pcan_p->an_scanresult[i].an_index != 0xffff));
3051 done:
3052 	if ((!enable) &&
3053 	    (ret = pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0))) {
3054 		ret = (int)WL_HW_ERROR;
3055 		goto exit;
3056 	}
3057 	/* record the scan result for future use */
3058 	bzero(bssid_t, sizeof (bssid_t));
3059 	for (j = 0; j < i; j++) {
3060 		/*
3061 		 * sometimes, those empty items are recorded by hardware,
3062 		 * this is wrong, just ignore those items here.
3063 		 */
3064 		if (bcmp(pcan_p->an_scanresult[j].an_bssid,
3065 		    bssid_t, 6) == 0) {
3066 			continue;
3067 		}
3068 		/*
3069 		 * save/update the scan item in scanlist
3070 		 */
3071 		mutex_enter(&pcan_p->pcan_scanlist_lock);
3072 		check_num = 0;
3073 		scan_item0 = list_head(&pcan_p->an_scan_list);
3074 		if (scan_item0 == NULL) {
3075 			if (pcan_add_scan_item(pcan_p,
3076 			    pcan_p->an_scanresult[j]) != 0) {
3077 				mutex_exit(&pcan_p->pcan_scanlist_lock);
3078 				return (WL_SUCCESS);
3079 			}
3080 		}
3081 		for (; scan_item0; ) {
3082 			if (bcmp(pcan_p->an_scanresult[j].an_bssid,
3083 			    scan_item0->an_val.an_bssid, 6) == 0) {
3084 				scan_item0->an_val = pcan_p->an_scanresult[j];
3085 				scan_item0->an_timeout = AN_SCAN_TIMEOUT_MAX;
3086 				break;
3087 			} else {
3088 				check_num++;
3089 			}
3090 			scan_item0 = list_next(&pcan_p->an_scan_list,
3091 			    scan_item0);
3092 		}
3093 		if (check_num == pcan_p->an_scan_num) {
3094 			if (pcan_add_scan_item(pcan_p,
3095 			    pcan_p->an_scanresult[j]) != 0) {
3096 				mutex_exit(&pcan_p->pcan_scanlist_lock);
3097 				return (WL_SUCCESS);
3098 			}
3099 		}
3100 		mutex_exit(&pcan_p->pcan_scanlist_lock);
3101 	}
3102 exit:
3103 	if (ret)
3104 		cmn_err(CE_WARN, "pcan: scan failed due to hardware error");
3105 	return (ret);
3106 }
3107 
3108 /*ARGSUSED*/
3109 static int
3110 pcan_cfg_scan(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
3111 {
3112 	wl_ess_conf_t *p_ess_conf;
3113 	wldp_t *outfp;
3114 	char *buf;
3115 	uint16_t i;
3116 	an_scan_list_t *scan_item;
3117 
3118 	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3119 	if (buf == NULL) {
3120 		PCANDBG((CE_NOTE, "pcan cfg_scanlist: failed to alloc "
3121 		    "memory(%d)\n", MAX_BUF_LEN));
3122 		return (ENOMEM);
3123 	}
3124 	outfp = (wldp_t *)buf;
3125 	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3126 
3127 	mutex_enter(&pcan_p->pcan_scanlist_lock);
3128 	((wl_ess_list_t *)(outfp->wldp_buf))->wl_ess_list_num =
3129 	    pcan_p->an_scan_num;
3130 	outfp->wldp_length = WIFI_BUF_OFFSET +
3131 	    offsetof(wl_ess_list_t, wl_ess_list_ess) +
3132 	    pcan_p->an_scan_num * sizeof (wl_ess_conf_t);
3133 
3134 	scan_item = list_head(&pcan_p->an_scan_list);
3135 	for (i = 0; i < pcan_p->an_scan_num; i++) {
3136 		if (!scan_item)
3137 			goto done;
3138 
3139 		p_ess_conf = (wl_ess_conf_t *)(buf + WIFI_BUF_OFFSET +
3140 		    offsetof(wl_ess_list_t, wl_ess_list_ess) +
3141 		    i * sizeof (wl_ess_conf_t));
3142 		bcopy(scan_item->an_val.an_ssid,
3143 		    p_ess_conf->wl_ess_conf_essid.wl_essid_essid,
3144 		    mi_strlen(scan_item->an_val.an_ssid));
3145 		bcopy(scan_item->an_val.an_bssid,
3146 		    p_ess_conf->wl_ess_conf_bssid, 6);
3147 		(p_ess_conf->wl_phy_conf).wl_phy_dsss_conf.wl_dsss_subtype
3148 		    = WL_DSSS;
3149 		p_ess_conf->wl_ess_conf_wepenabled =
3150 		    (scan_item->an_val.an_cap & 0x10 ?
3151 		    WL_ENC_WEP : WL_NOENCRYPTION);
3152 		p_ess_conf->wl_ess_conf_bsstype =
3153 		    (scan_item->an_val.an_cap & 0x1 ?
3154 		    WL_BSS_BSS : WL_BSS_IBSS);
3155 		p_ess_conf->wl_phy_conf.wl_phy_dsss_conf.wl_dsss_channel =
3156 		    scan_item->an_val.an_dschannel;
3157 		p_ess_conf->wl_ess_conf_sl = 15 -
3158 		    ((scan_item->an_val.an_rssi & 0xff) * 15 / 128);
3159 		p_ess_conf->wl_supported_rates[0] = WL_RATE_1M;
3160 		p_ess_conf->wl_supported_rates[1] = WL_RATE_2M;
3161 		p_ess_conf->wl_supported_rates[2] = WL_RATE_5_5M;
3162 		p_ess_conf->wl_supported_rates[3] = WL_RATE_11M;
3163 		scan_item = list_next(&pcan_p->an_scan_list, scan_item);
3164 	}
3165 done:
3166 	mutex_exit(&pcan_p->pcan_scanlist_lock);
3167 	outfp->wldp_result = WL_SUCCESS;
3168 	for (i = 0; i < (outfp->wldp_length); i++)
3169 		(void) mi_mpprintf_putc((char *)mp, buf[i]);
3170 	kmem_free(buf, MAX_BUF_LEN);
3171 	return (WL_SUCCESS);
3172 }
3173 
3174 /*ARGSUSED*/
3175 static int
3176 pcan_cfg_linkstatus(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
3177 {
3178 	wldp_t *outfp;
3179 	char *buf;
3180 	uint16_t i;
3181 
3182 	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3183 	if (buf == NULL) {
3184 		PCANDBG((CE_NOTE, "pcan cfg_linkstatus: failed to alloc "
3185 		    "memory(%d)\n", MAX_BUF_LEN));
3186 		return (ENOMEM);
3187 	}
3188 	outfp = (wldp_t *)buf;
3189 	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3190 
3191 	if (pcan_p->pcan_flag & PCAN_CARD_LINKUP)
3192 		*(wl_linkstatus_t *)(outfp->wldp_buf) = WL_CONNECTED;
3193 	else
3194 		*(wl_linkstatus_t *)(outfp->wldp_buf) = WL_NOTCONNECTED;
3195 	outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_encryption_t);
3196 	outfp->wldp_result = WL_SUCCESS;
3197 	for (i = 0; i < (outfp->wldp_length); i++)
3198 		(void) mi_mpprintf_putc((char *)mp, buf[i]);
3199 	kmem_free(buf, MAX_BUF_LEN);
3200 	return (WL_SUCCESS);
3201 }
3202 
3203 static int
3204 pcan_cfg_bsstype(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
3205 {
3206 	uint16_t i;
3207 	wldp_t	*infp;
3208 	wldp_t *outfp;
3209 	char *buf;
3210 	int iret;
3211 	struct an_ltv_genconfig *cfg_p;
3212 
3213 	cfg_p = &pcan_p->an_config;
3214 
3215 	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3216 	if (buf == NULL) {
3217 		PCANDBG((CE_NOTE, "pcan cfg_bsstype: failed to alloc "
3218 		    "memory(%d)\n", MAX_BUF_LEN));
3219 		return (ENOMEM);
3220 	}
3221 	outfp = (wldp_t *)buf;
3222 	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3223 	infp = (wldp_t *)mp->b_rptr;
3224 
3225 	outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_bss_type_t);
3226 
3227 	if (cmd == WLAN_GET_PARAM) {
3228 		if (cfg_p->an_opmode == AN_OPMODE_INFR_STATION) {
3229 			*(wl_bss_type_t *)(outfp->wldp_buf) = WL_BSS_BSS;
3230 		} else if (cfg_p->an_opmode == AN_OPMODE_IBSS_ADHOC) {
3231 			*(wl_bss_type_t *)(outfp->wldp_buf) = WL_BSS_IBSS;
3232 		}
3233 		outfp->wldp_result = WL_SUCCESS;
3234 	} else if (cmd == WLAN_SET_PARAM) {
3235 		if (*(wl_bss_type_t *)(infp->wldp_buf) == WL_BSS_BSS)
3236 			cfg_p->an_opmode = AN_OPMODE_INFR_STATION;
3237 		if (*(wl_bss_type_t *)(infp->wldp_buf) == WL_BSS_IBSS)
3238 			cfg_p->an_opmode = AN_OPMODE_IBSS_ADHOC;
3239 		if (*(wl_bss_type_t *)(infp->wldp_buf) == WL_BSS_ANY)
3240 			cfg_p->an_opmode = AN_OPMODE_INFR_STATION;
3241 		cfg_p->an_assoc_timeout = 5000;
3242 		outfp->wldp_result = WL_SUCCESS;
3243 	} else {
3244 		kmem_free(buf, MAX_BUF_LEN);
3245 		return (EINVAL);
3246 	}
3247 
3248 	for (i = 0; i < (outfp->wldp_length); i++)
3249 		(void) mi_mpprintf_putc((char *)mp, buf[i]);
3250 	iret = (int)(outfp->wldp_result);
3251 	kmem_free(buf, MAX_BUF_LEN);
3252 	return (iret);
3253 }
3254 
3255 static int
3256 pcan_cfg_phy(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
3257 {
3258 	uint16_t ret, i;
3259 	wldp_t	*infp;
3260 	wldp_t *outfp;
3261 	char *buf;
3262 	int iret;
3263 	struct an_ltv_genconfig *cfg_p;
3264 	struct an_ltv_status *status_p;
3265 
3266 	cfg_p = &pcan_p->an_config;
3267 	status_p = &pcan_p->an_status;
3268 
3269 	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3270 	if (buf == NULL) {
3271 		PCANDBG((CE_NOTE, "pcan cfg_phy: failed to alloc "
3272 		    "memory(%d)\n", MAX_BUF_LEN));
3273 		return (ENOMEM);
3274 	}
3275 	outfp = (wldp_t *)buf;
3276 	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3277 	infp = (wldp_t *)mp->b_rptr;
3278 
3279 	outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_dsss_t);
3280 	if (cmd == WLAN_GET_PARAM) {
3281 		if (ret = pcan_status_ltv(PCAN_READ_LTV, pcan_p, status_p)) {
3282 			outfp->wldp_length = WIFI_BUF_OFFSET;
3283 			outfp->wldp_result = WL_HW_ERROR;
3284 			goto done;
3285 		}
3286 		((wl_dsss_t *)(outfp->wldp_buf))->wl_dsss_channel =
3287 		    status_p->an_channel_set;
3288 		((wl_dsss_t *)(outfp->wldp_buf))->wl_dsss_subtype = WL_DSSS;
3289 		outfp->wldp_result = WL_SUCCESS;
3290 	} else if (cmd == WLAN_SET_PARAM) {
3291 		ret = (uint16_t)
3292 		    (((wl_phy_conf_t *)(infp->wldp_buf))
3293 		    ->wl_phy_dsss_conf.wl_dsss_channel);
3294 		if (ret < 1 || ret > 14) {
3295 			outfp->wldp_result = WL_NOTSUPPORTED;
3296 			goto done;
3297 		}
3298 		cfg_p->an_ds_channel = ret;
3299 		cfg_p->an_assoc_timeout = 5000;
3300 		outfp->wldp_result = WL_SUCCESS;
3301 	} else {
3302 		kmem_free(buf, MAX_BUF_LEN);
3303 		return (EINVAL);
3304 	}
3305 done:
3306 	for (i = 0; i < (outfp->wldp_length); i++)
3307 		(void) mi_mpprintf_putc((char *)mp, buf[i]);
3308 	iret = (int)(outfp->wldp_result);
3309 	kmem_free(buf, MAX_BUF_LEN);
3310 	return (iret);
3311 
3312 }
3313 
3314 /*ARGSUSED*/
3315 static int
3316 pcan_cfg_desiredrates(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
3317 {
3318 	uint16_t i;
3319 	uint8_t rates = 0;
3320 	wldp_t	*infp;
3321 	wldp_t *outfp;
3322 	char *buf;
3323 	int iret;
3324 	struct an_ltv_genconfig *cfg_p;
3325 	struct an_ltv_genconfig *actcfg_p;
3326 
3327 	cfg_p = &pcan_p->an_config;
3328 	actcfg_p = &pcan_p->an_actual_config;
3329 	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3330 	if (buf == NULL) {
3331 		PCANDBG((CE_NOTE, "pcan cfg_rates: failed to alloc "
3332 		    "memory(%d)\n", MAX_BUF_LEN));
3333 		return (ENOMEM);
3334 	}
3335 	outfp = (wldp_t *)buf;
3336 	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3337 	infp = (wldp_t *)mp->b_rptr;
3338 
3339 	if (cmd == WLAN_GET_PARAM) {
3340 		if (pcan_cfg_ltv(PCAN_READ_LTV, pcan_p, actcfg_p)) {
3341 			outfp->wldp_length = WIFI_BUF_OFFSET;
3342 			outfp->wldp_result = WL_HW_ERROR;
3343 			goto done;
3344 		}
3345 		for (i = 0; i < sizeof (actcfg_p->an_rates); i++) {
3346 			if (actcfg_p->an_rates[i] == 0)
3347 				break;
3348 			rates = MAX(rates, actcfg_p->an_rates[i]);
3349 		}
3350 		(((wl_rates_t *)(outfp->wldp_buf))->wl_rates_rates)[0]
3351 		    = rates;
3352 		((wl_rates_t *)(outfp->wldp_buf))->wl_rates_num = 1;
3353 		outfp->wldp_length = WIFI_BUF_OFFSET +
3354 		    offsetof(wl_rates_t, wl_rates_rates) + sizeof (char);
3355 		outfp->wldp_result = WL_SUCCESS;
3356 	} else if (cmd == WLAN_SET_PARAM) {
3357 		bzero(cfg_p->an_rates, sizeof (cfg_p->an_rates));
3358 		for (i = 0; i < ((wl_rates_t *)(infp->wldp_buf))->wl_rates_num;
3359 		    i++) {
3360 			cfg_p->an_rates[i] = (((wl_rates_t *)
3361 			    (infp->wldp_buf))->wl_rates_rates)[i];
3362 		}
3363 		cfg_p->an_assoc_timeout = 5000;
3364 		outfp->wldp_length = WIFI_BUF_OFFSET;
3365 		outfp->wldp_result = WL_SUCCESS;
3366 	} else {
3367 		kmem_free(buf, MAX_BUF_LEN);
3368 		return (EINVAL);
3369 	}
3370 done:
3371 	for (i = 0; i < (outfp->wldp_length); i++)
3372 		(void) mi_mpprintf_putc((char *)mp, buf[i]);
3373 	iret = (int)(outfp->wldp_result);
3374 	kmem_free(buf, MAX_BUF_LEN);
3375 	return (iret);
3376 }
3377 
3378 /*ARGSUSED*/
3379 static int
3380 pcan_cfg_supportrates(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
3381 {
3382 	uint16_t i;
3383 	int iret;
3384 	wldp_t *outfp;
3385 	char *buf;
3386 
3387 	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3388 	if (buf == NULL) {
3389 		PCANDBG((CE_NOTE, "pcan cfg_supportedrates: failed to alloc "
3390 		    "memory(%d)\n", MAX_BUF_LEN));
3391 		return (ENOMEM);
3392 	}
3393 	outfp = (wldp_t *)buf;
3394 	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3395 
3396 	if (cmd == WLAN_GET_PARAM) {
3397 		((wl_rates_t *)(outfp->wldp_buf))->wl_rates_num = 4;
3398 		(((wl_rates_t *)(outfp->wldp_buf))->wl_rates_rates)[0]
3399 		    = WL_RATE_1M;
3400 		(((wl_rates_t *)(outfp->wldp_buf))->wl_rates_rates)[1]
3401 		    = WL_RATE_2M;
3402 		(((wl_rates_t *)(outfp->wldp_buf))->wl_rates_rates)[2]
3403 		    = WL_RATE_5_5M;
3404 		(((wl_rates_t *)(outfp->wldp_buf))->wl_rates_rates)[3]
3405 		    = WL_RATE_11M;
3406 		outfp->wldp_length = WIFI_BUF_OFFSET +
3407 		    offsetof(wl_rates_t, wl_rates_rates) +
3408 		    4 * sizeof (char);
3409 		outfp->wldp_result = WL_SUCCESS;
3410 	} else {
3411 		kmem_free(buf, MAX_BUF_LEN);
3412 		return (EINVAL);
3413 	}
3414 done:
3415 	for (i = 0; i < (outfp->wldp_length); i++)
3416 		(void) mi_mpprintf_putc((char *)mp, buf[i]);
3417 	iret = (int)(outfp->wldp_result);
3418 	kmem_free(buf, MAX_BUF_LEN);
3419 	return (iret);
3420 }
3421 
3422 /*ARGSUSED*/
3423 static int
3424 pcan_cfg_powermode(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
3425 {
3426 	uint16_t i;
3427 	wldp_t *outfp;
3428 	char *buf;
3429 	int iret;
3430 	struct an_ltv_genconfig *actcfg_p;
3431 
3432 	actcfg_p = &pcan_p->an_actual_config;
3433 
3434 	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3435 	if (buf == NULL) {
3436 		PCANDBG((CE_NOTE, "pcan cfg_powermode: failed to alloc "
3437 		    "memory(%d)\n", MAX_BUF_LEN));
3438 		return (ENOMEM);
3439 	}
3440 	outfp = (wldp_t *)buf;
3441 	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3442 
3443 	if (cmd == WLAN_GET_PARAM) {
3444 		if (pcan_cfg_ltv(PCAN_READ_LTV, pcan_p, actcfg_p)) {
3445 			outfp->wldp_length = WIFI_BUF_OFFSET;
3446 			outfp->wldp_result = WL_HW_ERROR;
3447 			goto done;
3448 		}
3449 		((wl_ps_mode_t *)(outfp->wldp_buf))->wl_ps_mode =
3450 		    actcfg_p->an_psave_mode;
3451 		outfp->wldp_length = WIFI_BUF_OFFSET +
3452 		    sizeof (wl_ps_mode_t);
3453 		outfp->wldp_result = WL_SUCCESS;
3454 	} else if (cmd == WLAN_SET_PARAM) {
3455 		outfp->wldp_length = WIFI_BUF_OFFSET;
3456 		outfp->wldp_result = WL_LACK_FEATURE;
3457 	} else {
3458 		kmem_free(buf, MAX_BUF_LEN);
3459 		return (EINVAL);
3460 	}
3461 done:
3462 	for (i = 0; i < (outfp->wldp_length); i++)
3463 		(void) mi_mpprintf_putc((char *)mp, buf[i]);
3464 	iret = (int)(outfp->wldp_result);
3465 	kmem_free(buf, MAX_BUF_LEN);
3466 	return (iret);
3467 
3468 }
3469 
3470 static int
3471 pcan_cfg_authmode(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
3472 {
3473 	uint16_t i;
3474 	wldp_t *outfp;
3475 	char *buf;
3476 	int iret;
3477 	struct an_ltv_genconfig *cfg_p;
3478 	struct an_ltv_genconfig *actcfg_p;
3479 
3480 	cfg_p = &pcan_p->an_config;
3481 	actcfg_p = &pcan_p->an_actual_config;
3482 
3483 	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3484 	if (buf == NULL) {
3485 		PCANDBG((CE_NOTE, "pcan cfg_autymode: failed to alloc "
3486 		    "memory(%d)\n", MAX_BUF_LEN));
3487 		return (ENOMEM);
3488 	}
3489 	outfp = (wldp_t *)buf;
3490 	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3491 
3492 	if (cmd == WLAN_GET_PARAM) {
3493 		outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_authmode_t);
3494 		if (cfg_p->an_authtype & AN_AUTHTYPE_SHAREDKEY) {
3495 			*(wl_bss_type_t *)(outfp->wldp_buf) = WL_SHAREDKEY;
3496 		} else {
3497 			*(wl_bss_type_t *)(outfp->wldp_buf) = WL_OPENSYSTEM;
3498 		}
3499 		outfp->wldp_result = WL_SUCCESS;
3500 	} else if (cmd == WLAN_SET_PARAM) {
3501 		if (*(wl_authmode_t *)(outfp->wldp_buf) == WL_OPENSYSTEM) {
3502 			cfg_p->an_authtype |= AN_AUTHTYPE_OPEN;
3503 			cfg_p->an_assoc_timeout = 5000;
3504 			outfp->wldp_length = WIFI_BUF_OFFSET;
3505 			outfp->wldp_result = WL_SUCCESS;
3506 		} else {
3507 			outfp->wldp_length = WIFI_BUF_OFFSET;
3508 			outfp->wldp_result = WL_LACK_FEATURE;
3509 		}
3510 	} else {
3511 		kmem_free(buf, MAX_BUF_LEN);
3512 		return (EINVAL);
3513 	}
3514 	PCANDBG((CE_NOTE, "pcan cfg_authmode: actual.authmode=%x",
3515 	    actcfg_p->an_authtype));
3516 	PCANDBG((CE_NOTE, "pcan cfg_authmode: actual.home_product=%x",
3517 	    actcfg_p->an_rsvd6[2]));
3518 	for (i = 0; i < (outfp->wldp_length); i++)
3519 		(void) mi_mpprintf_putc((char *)mp, buf[i]);
3520 	iret = (int)(outfp->wldp_result);
3521 	kmem_free(buf, MAX_BUF_LEN);
3522 	return (iret);
3523 }
3524 
3525 static int
3526 pcan_cfg_encryption(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
3527 {
3528 	uint16_t i;
3529 	wldp_t *outfp;
3530 	char *buf;
3531 	int iret;
3532 	struct an_ltv_genconfig *cfg_p;
3533 
3534 	cfg_p = &pcan_p->an_config;
3535 
3536 	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3537 	if (buf == NULL) {
3538 		PCANDBG((CE_NOTE, "pcan cfg_encryption: failed to alloc "
3539 		    "memory(%d)\n", MAX_BUF_LEN));
3540 		return (ENOMEM);
3541 	}
3542 	outfp = (wldp_t *)buf;
3543 	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3544 
3545 	if (cmd == WLAN_GET_PARAM) {
3546 		outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_encryption_t);
3547 		if (cfg_p->an_authtype & AN_AUTHTYPE_ENABLEWEP) {
3548 			*(wl_bss_type_t *)(outfp->wldp_buf) = WL_ENC_WEP;
3549 		} else {
3550 			*(wl_bss_type_t *)(outfp->wldp_buf) = WL_NOENCRYPTION;
3551 		}
3552 		outfp->wldp_result = WL_SUCCESS;
3553 	} else if (cmd == WLAN_SET_PARAM) {
3554 		if (*(wl_encryption_t *)(outfp->wldp_buf) == WL_ENC_WEP) {
3555 			cfg_p->an_authtype |= (AN_AUTHTYPE_ENABLEWEP |
3556 			    AN_AUTHTYPE_ALLOW_UNENCRYPTED);
3557 			pcan_p->pcan_usewep = 1;
3558 		}
3559 		if (*(wl_authmode_t *)(outfp->wldp_buf) == WL_NOENCRYPTION) {
3560 			cfg_p->an_authtype &= (~(AN_AUTHTYPE_ENABLEWEP |
3561 			    AN_AUTHTYPE_ALLOW_UNENCRYPTED));
3562 			pcan_p->pcan_usewep = 0;
3563 		}
3564 		cfg_p->an_assoc_timeout = 5000;
3565 		outfp->wldp_length = WIFI_BUF_OFFSET;
3566 		outfp->wldp_result = WL_SUCCESS;
3567 	} else {
3568 		kmem_free(buf, MAX_BUF_LEN);
3569 		return (EINVAL);
3570 	}
3571 	for (i = 0; i < (outfp->wldp_length); i++)
3572 		(void) mi_mpprintf_putc((char *)mp, buf[i]);
3573 	iret = (int)(outfp->wldp_result);
3574 	kmem_free(buf, MAX_BUF_LEN);
3575 	return (iret);
3576 }
3577 
3578 static int
3579 pcan_cfg_wepkeyid(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
3580 {
3581 	uint16_t i, ret;
3582 	wldp_t	*infp;
3583 	wldp_t *outfp;
3584 	char *buf;
3585 	int iret;
3586 	struct an_ltv_wepkey wepkey;
3587 
3588 	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3589 	if (buf == NULL) {
3590 		PCANDBG((CE_NOTE, "pcan cfg_wepkeyid: failed to alloc "
3591 		    "memory(%d)\n", MAX_BUF_LEN));
3592 		return (ENOMEM);
3593 	}
3594 	outfp = (wldp_t *)buf;
3595 	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3596 	infp = (wldp_t *)mp->b_rptr;
3597 
3598 	if (cmd == WLAN_GET_PARAM) {
3599 		outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_wep_key_id_t);
3600 		outfp->wldp_result = WL_SUCCESS;
3601 		*(wl_wep_key_id_t *)(outfp->wldp_buf) = pcan_p->an_cur_wepkey;
3602 	} else if (cmd == WLAN_SET_PARAM) {
3603 		ret = (uint16_t)(*(wl_wep_key_id_t *)(infp->wldp_buf));
3604 		if (ret > 3) {
3605 			kmem_free(buf, MAX_BUF_LEN);
3606 			return (EINVAL);
3607 		}
3608 		wepkey.an_index = 0xffff;
3609 		wepkey.an_macaddr[0] = ret & 0xff;
3610 		pcan_p->an_cur_wepkey = ret;
3611 		outfp->wldp_length = WIFI_BUF_OFFSET;
3612 		outfp->wldp_result = WL_SUCCESS;
3613 	} else {
3614 		kmem_free(buf, MAX_BUF_LEN);
3615 		return (EINVAL);
3616 	}
3617 	for (i = 0; i < (outfp->wldp_length); i++)
3618 		(void) mi_mpprintf_putc((char *)mp, buf[i]);
3619 	iret = (int)(outfp->wldp_result);
3620 	kmem_free(buf, MAX_BUF_LEN);
3621 	return (iret);
3622 }
3623 
3624 /*ARGSUSED*/
3625 static int
3626 pcan_cfg_createibss(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
3627 {
3628 	uint16_t i;
3629 	wldp_t *outfp;
3630 	char *buf;
3631 	int iret;
3632 
3633 	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3634 	if (buf == NULL) {
3635 		PCANDBG((CE_NOTE, "pcan cfg_createibss: failed to alloc "
3636 		    "memory(%d)\n", MAX_BUF_LEN));
3637 		return (ENOMEM);
3638 	}
3639 	outfp = (wldp_t *)buf;
3640 	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3641 
3642 	outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_create_ibss_t);
3643 	outfp->wldp_result = WL_LACK_FEATURE;
3644 	for (i = 0; i < (outfp->wldp_length); i++)
3645 		(void) mi_mpprintf_putc((char *)mp, buf[i]);
3646 	iret = (int)(outfp->wldp_result);
3647 	kmem_free(buf, MAX_BUF_LEN);
3648 	return (iret);
3649 }
3650 
3651 static int
3652 pcan_cfg_rssi(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
3653 {
3654 	uint16_t i, val;
3655 	int iret;
3656 	wldp_t *outfp;
3657 	char *buf;
3658 	struct an_ltv_status *status_p;
3659 	status_p = &pcan_p->an_status;
3660 
3661 	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3662 	if (buf == NULL) {
3663 		PCANDBG((CE_NOTE, "pcan cfg_rssi: failed to alloc "
3664 		    "memory(%d)\n", MAX_BUF_LEN));
3665 		return (ENOMEM);
3666 	}
3667 	outfp = (wldp_t *)buf;
3668 	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3669 
3670 	outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_rssi_t);
3671 
3672 	if (cmd == WLAN_GET_PARAM) {
3673 		if (val = pcan_status_ltv(PCAN_READ_LTV, pcan_p, status_p)) {
3674 			outfp->wldp_length = WIFI_BUF_OFFSET;
3675 			outfp->wldp_result = WL_HW_ERROR;
3676 			goto done;
3677 		}
3678 		val = status_p->an_cur_signal_quality;
3679 		PCANDBG((CE_NOTE, "pcan cfg_rssi: sl=%x", val));
3680 		/*
3681 		 * we reflect the value to 1-15 as rssi
3682 		 */
3683 		*(wl_rssi_t *)(outfp->wldp_buf) = 15 -
3684 		    ((val & 0xff) * 15 / 128 + 1);
3685 		outfp->wldp_result = WL_SUCCESS;
3686 	} else if (cmd == WLAN_SET_PARAM) {
3687 		outfp->wldp_result = WL_READONLY;
3688 	} else {
3689 		kmem_free(buf, MAX_BUF_LEN);
3690 		return (EINVAL);
3691 	}
3692 done:
3693 	for (i = 0; i < (outfp->wldp_length); i++)
3694 		(void) mi_mpprintf_putc((char *)mp, buf[i]);
3695 	iret = (int)(outfp->wldp_result);
3696 	kmem_free(buf, MAX_BUF_LEN);
3697 	return (iret);
3698 }
3699 
3700 /*ARGSUSED*/
3701 static int
3702 pcan_cfg_radio(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
3703 {
3704 	uint16_t i;
3705 	int iret;
3706 	wldp_t *outfp;
3707 	char *buf;
3708 
3709 	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3710 	if (buf == NULL) {
3711 		PCANDBG((CE_NOTE, "pcan cfg_radio: failed to alloc "
3712 		    "memory(%d)\n", MAX_BUF_LEN));
3713 		return (ENOMEM);
3714 	}
3715 	outfp = (wldp_t *)buf;
3716 	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3717 
3718 	if (cmd == WLAN_GET_PARAM) {
3719 		*(wl_radio_t *)(outfp->wldp_buf) = B_TRUE;
3720 		outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_radio_t);
3721 		outfp->wldp_result = WL_SUCCESS;
3722 	} else if (cmd == WLAN_SET_PARAM) {
3723 		outfp->wldp_length = WIFI_BUF_OFFSET;
3724 		outfp->wldp_result = WL_LACK_FEATURE;
3725 	} else {
3726 		kmem_free(buf, MAX_BUF_LEN);
3727 		return (EINVAL);
3728 	}
3729 
3730 	for (i = 0; i < (outfp->wldp_length); i++)
3731 		(void) mi_mpprintf_putc((char *)mp, buf[i]);
3732 	iret = (int)(outfp->wldp_result);
3733 	kmem_free(buf, MAX_BUF_LEN);
3734 	return (iret);
3735 }
3736 
3737 static int
3738 pcan_cfg_wepkey(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
3739 {
3740 	uint16_t i;
3741 	wl_wep_key_t *p_wepkey_tab;
3742 	wldp_t *outfp;
3743 	char *buf;
3744 	int iret;
3745 	wldp_t	*infp;
3746 	struct an_ltv_wepkey *wepkey_p;
3747 
3748 	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3749 	if (buf == NULL) {
3750 		PCANDBG((CE_NOTE, "pcan cfg_wep: failed to alloc "
3751 		    "memory(%d)\n", MAX_BUF_LEN));
3752 		return (ENOMEM);
3753 	}
3754 	outfp = (wldp_t *)buf;
3755 	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3756 	infp = (wldp_t *)mp->b_rptr;
3757 
3758 	if (cmd == WLAN_GET_PARAM) {
3759 		outfp->wldp_length = WIFI_BUF_OFFSET +
3760 		    sizeof (wl_wep_key_tab_t);
3761 		outfp->wldp_result = WL_WRITEONLY;
3762 	} else if (cmd == WLAN_SET_PARAM) {
3763 		p_wepkey_tab = (wl_wep_key_t *)(infp->wldp_buf);
3764 		for (i = 0; i < MAX_NWEPKEYS; i++) {
3765 			if (p_wepkey_tab[i].wl_wep_operation == WL_ADD) {
3766 				wepkey_p = &pcan_p->an_wepkey[i];
3767 				bzero(wepkey_p, sizeof (*wepkey_p));
3768 				wepkey_p->an_keylen =
3769 				    p_wepkey_tab[i].wl_wep_length;
3770 				bcopy(p_wepkey_tab[i].wl_wep_key,
3771 				    wepkey_p->an_key,
3772 				    p_wepkey_tab[i].wl_wep_length);
3773 				wepkey_p->an_index = i;
3774 				wepkey_p->an_macaddr[0] = 1;
3775 			}
3776 		}
3777 		outfp->wldp_length = WIFI_BUF_OFFSET;
3778 		outfp->wldp_result = WL_SUCCESS;
3779 	} else {
3780 		kmem_free(buf, MAX_BUF_LEN);
3781 		return (EINVAL);
3782 	}
3783 
3784 	for (i = 0; i < (outfp->wldp_length); i++)
3785 		(void) mi_mpprintf_putc((char *)mp, buf[i]);
3786 	iret = (int)(outfp->wldp_result);
3787 	kmem_free(buf, MAX_BUF_LEN);
3788 	return (iret);
3789 }
3790 
3791 static void
3792 pcan_connect_timeout(void *arg)
3793 {
3794 	pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
3795 	uint16_t ret;
3796 
3797 	mutex_enter(&pcan_p->pcan_glock);
3798 	if (ret = pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0))
3799 		goto done;
3800 	pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP;
3801 	if (ret = pcan_config_mac(pcan_p))
3802 		goto done;
3803 	ret = pcan_set_cmd(pcan_p, AN_CMD_ENABLE, 0);
3804 done:
3805 	if (ret)
3806 		cmn_err(CE_WARN, "pcan: connect failed due to hardware error");
3807 	mutex_exit(&pcan_p->pcan_glock);
3808 	pcan_p->pcan_connect_timeout_id = 0;
3809 }
3810 
3811 static int
3812 pcan_getset(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
3813 {
3814 	int ret = WL_SUCCESS;
3815 	int connect = 0;
3816 
3817 	mutex_enter(&pcan_p->pcan_glock);
3818 	if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
3819 		mutex_exit(&pcan_p->pcan_glock);
3820 		return (PCAN_FAIL);
3821 	}
3822 
3823 	switch (((wldp_t *)mp->b_rptr)->wldp_id) {
3824 	case WL_ESSID:
3825 		ret = pcan_cfg_essid(mp, pcan_p, cmd);
3826 		connect = 1;
3827 		PCANDBG((CE_NOTE, "cfg_essid\n"));
3828 		break;
3829 	case WL_BSSID:
3830 		ret = pcan_cfg_bssid(mp, pcan_p, cmd);
3831 		connect = 1;
3832 		PCANDBG((CE_NOTE, "cfg_bssid\n"));
3833 		break;
3834 	case WL_ESS_LIST:
3835 		ret = pcan_cfg_scan(mp, pcan_p, cmd);
3836 		PCANDBG((CE_NOTE, "cfg_scan\n"));
3837 		break;
3838 	case WL_LINKSTATUS:
3839 		ret = pcan_cfg_linkstatus(mp, pcan_p, cmd);
3840 		PCANDBG((CE_NOTE, "cfg_linkstatus\n"));
3841 		break;
3842 	case WL_BSS_TYPE:
3843 		ret = pcan_cfg_bsstype(mp, pcan_p, cmd);
3844 		connect = 1;
3845 		PCANDBG((CE_NOTE, "cfg_bsstype\n"));
3846 		break;
3847 	case WL_PHY_CONFIG:
3848 		ret = pcan_cfg_phy(mp, pcan_p, cmd);
3849 		connect = 1;
3850 		PCANDBG((CE_NOTE, "cfg_phy\n"));
3851 		break;
3852 	case WL_DESIRED_RATES:
3853 		ret = pcan_cfg_desiredrates(mp, pcan_p, cmd);
3854 		connect = 1;
3855 		PCANDBG((CE_NOTE, "cfg_disred-rates\n"));
3856 		break;
3857 	case WL_SUPPORTED_RATES:
3858 		ret = pcan_cfg_supportrates(mp, pcan_p, cmd);
3859 		PCANDBG((CE_NOTE, "cfg_supported-rates\n"));
3860 		break;
3861 	case WL_POWER_MODE:
3862 		ret = pcan_cfg_powermode(mp, pcan_p, cmd);
3863 		PCANDBG((CE_NOTE, "cfg_powermode\n"));
3864 		break;
3865 	case WL_AUTH_MODE:
3866 		ret = pcan_cfg_authmode(mp, pcan_p, cmd);
3867 		connect = 1;
3868 		PCANDBG((CE_NOTE, "cfg_authmode\n"));
3869 		break;
3870 	case WL_ENCRYPTION:
3871 		ret = pcan_cfg_encryption(mp, pcan_p, cmd);
3872 		connect = 1;
3873 		PCANDBG((CE_NOTE, "cfg_encryption\n"));
3874 		break;
3875 	case WL_WEP_KEY_ID:
3876 		ret = pcan_cfg_wepkeyid(mp, pcan_p, cmd);
3877 		connect = 1;
3878 		PCANDBG((CE_NOTE, "cfg_wepkeyid\n"));
3879 		break;
3880 	case WL_CREATE_IBSS:
3881 		ret = pcan_cfg_createibss(mp, pcan_p, cmd);
3882 		connect = 1;
3883 		PCANDBG((CE_NOTE, "cfg_create-ibss\n"));
3884 		break;
3885 	case WL_RSSI:
3886 		ret = pcan_cfg_rssi(mp, pcan_p, cmd);
3887 		PCANDBG((CE_NOTE, "cfg_rssi\n"));
3888 		break;
3889 	case WL_RADIO:
3890 		ret = pcan_cfg_radio(mp, pcan_p, cmd);
3891 		PCANDBG((CE_NOTE, "cfg_radio\n"));
3892 		break;
3893 	case WL_WEP_KEY_TAB:
3894 		ret = pcan_cfg_wepkey(mp, pcan_p, cmd);
3895 		connect = 1;
3896 		PCANDBG((CE_NOTE, "cfg_wepkey\n"));
3897 		break;
3898 	case WL_SCAN:
3899 		mutex_exit(&pcan_p->pcan_glock);
3900 		if (pcan_p->pcan_connect_timeout_id != 0) {
3901 			(void) untimeout(pcan_p->pcan_connect_timeout_id);
3902 			pcan_p->pcan_connect_timeout_id = 0;
3903 		}
3904 		mutex_enter(&pcan_p->pcan_glock);
3905 		ret = pcan_cmd_scan(pcan_p);
3906 		/*
3907 		 * a trick here.
3908 		 * since the scan doesn't return too many items due to hardware
3909 		 * reason, so the current scan result is an accumulation of
3910 		 * several scans. For the first time or after many of the items
3911 		 * aged, we scan again if too few items now in the scan table.
3912 		 */
3913 		if (pcan_p->an_scan_num < AN_SCAN_AGAIN_THRESHOLD)
3914 			ret = pcan_cmd_scan(pcan_p);
3915 		break;
3916 	case WL_LOAD_DEFAULTS:
3917 		if (ret = pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0)) {
3918 			ret = (int)WL_HW_ERROR;
3919 			break;
3920 		}
3921 		if (ret = pcan_loaddef(pcan_p)) {
3922 			ret = (int)WL_HW_ERROR;
3923 			break;
3924 		}
3925 		if (ret = pcan_set_cmd(pcan_p, AN_CMD_ENABLE, 0)) {
3926 			ret = (int)WL_HW_ERROR;
3927 			break;
3928 		}
3929 		PCANDBG((CE_NOTE, "loaddef\n"));
3930 		break;
3931 	case WL_DISASSOCIATE:
3932 		mutex_exit(&pcan_p->pcan_glock);
3933 		if (pcan_p->pcan_connect_timeout_id != 0) {
3934 			(void) untimeout(pcan_p->pcan_connect_timeout_id);
3935 			pcan_p->pcan_connect_timeout_id = 0;
3936 		}
3937 		mutex_enter(&pcan_p->pcan_glock);
3938 		pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP;
3939 		if (ret = pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0)) {
3940 			ret = (int)WL_HW_ERROR;
3941 			break;
3942 		}
3943 		if (ret = pcan_loaddef(pcan_p)) {
3944 			ret = (int)WL_HW_ERROR;
3945 			break;
3946 		}
3947 		PCANDBG((CE_NOTE, "disassociate\n"));
3948 		break;
3949 	case WL_REASSOCIATE:
3950 	case WL_ASSOCIAT:
3951 		mutex_exit(&pcan_p->pcan_glock);
3952 		if (pcan_p->pcan_connect_timeout_id != 0) {
3953 			(void) untimeout(pcan_p->pcan_connect_timeout_id);
3954 			pcan_p->pcan_connect_timeout_id = 0;
3955 		}
3956 		mutex_enter(&pcan_p->pcan_glock);
3957 		if (ret = pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0)) {
3958 			ret = (int)WL_HW_ERROR;
3959 			break;
3960 		}
3961 		pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP;
3962 		if (ret = pcan_config_mac(pcan_p)) {
3963 			ret = (int)WL_HW_ERROR;
3964 			break;
3965 		}
3966 		if (ret = pcan_set_cmd(pcan_p, AN_CMD_ENABLE, 0)) {
3967 			ret = (int)WL_HW_ERROR;
3968 			break;
3969 		}
3970 		PCANDBG((CE_NOTE, "associate"));
3971 		break;
3972 
3973 	default:
3974 		break;
3975 	}
3976 	mutex_exit(&pcan_p->pcan_glock);
3977 	if ((cmd == WLAN_SET_PARAM) && (ret == WL_SUCCESS) && (connect)) {
3978 		pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP;
3979 		(void) pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0);
3980 		if (pcan_p->pcan_connect_timeout_id != 0) {
3981 			(void) untimeout(pcan_p->pcan_connect_timeout_id);
3982 			pcan_p->pcan_connect_timeout_id = 0;
3983 		}
3984 		pcan_p->pcan_connect_timeout_id = timeout(pcan_connect_timeout,
3985 		    pcan_p, drv_usectohz(1000000));
3986 	}
3987 	return (ret);
3988 }
3989 
3990 static void
3991 pcan_wlan_ioctl(pcan_maci_t *pcan_p, queue_t *wq, mblk_t *mp, uint32_t cmd)
3992 {
3993 
3994 	struct	iocblk	*iocp = (struct iocblk *)mp->b_rptr;
3995 	uint32_t len, ret;
3996 	mblk_t	*mp1;
3997 
3998 	/* sanity check */
3999 	if (iocp->ioc_count == 0 || !(mp1 = mp->b_cont)) {
4000 		miocnak(wq, mp, 0, EINVAL);
4001 		return;
4002 	}
4003 
4004 	/* assuming single data block */
4005 	if (mp1->b_cont) {
4006 		freemsg(mp1->b_cont);
4007 		mp1->b_cont = NULL;
4008 	}
4009 
4010 	/* we will overwrite everything */
4011 	mp1->b_wptr = mp1->b_rptr;
4012 
4013 	ret = pcan_getset(mp1, pcan_p, cmd);
4014 	len = msgdsize(mp1);
4015 	miocack(wq, mp, len, ret);
4016 }
4017 
4018 static void
4019 pcan_ioctl(void *arg, queue_t *wq, mblk_t *mp)
4020 {
4021 	struct iocblk *iocp;
4022 	uint32_t cmd, ret;
4023 	pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
4024 	boolean_t need_privilege = B_TRUE;
4025 
4026 	iocp = (struct iocblk *)mp->b_rptr;
4027 	iocp->ioc_error = 0;
4028 	cmd = iocp->ioc_cmd;
4029 	switch (cmd) {
4030 	default:
4031 		miocnak(wq, mp, 0, EINVAL);
4032 		return;
4033 	case WLAN_GET_PARAM:
4034 		need_privilege = B_FALSE;
4035 		break;
4036 	case WLAN_SET_PARAM:
4037 	case WLAN_COMMAND:
4038 		break;
4039 	}
4040 
4041 	if (need_privilege && (ret = secpolicy_dl_config(iocp->ioc_cr)) != 0)
4042 		miocnak(wq, mp, 0, ret);
4043 	else
4044 		pcan_wlan_ioctl(pcan_p, wq, mp, cmd);
4045 }
4046