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