1139749Simp/*-
255992Swpaul * Copyright (c) 1997, 1998, 1999
355992Swpaul *	Bill Paul <wpaul@ctr.columbia.edu>.  All rights reserved.
455992Swpaul *
555992Swpaul * Redistribution and use in source and binary forms, with or without
655992Swpaul * modification, are permitted provided that the following conditions
755992Swpaul * are met:
855992Swpaul * 1. Redistributions of source code must retain the above copyright
955992Swpaul *    notice, this list of conditions and the following disclaimer.
1055992Swpaul * 2. Redistributions in binary form must reproduce the above copyright
1155992Swpaul *    notice, this list of conditions and the following disclaimer in the
1255992Swpaul *    documentation and/or other materials provided with the distribution.
1355992Swpaul * 3. All advertising materials mentioning features or use of this software
1455992Swpaul *    must display the following acknowledgement:
1555992Swpaul *	This product includes software developed by Bill Paul.
1655992Swpaul * 4. Neither the name of the author nor the names of any co-contributors
1755992Swpaul *    may be used to endorse or promote products derived from this software
1855992Swpaul *    without specific prior written permission.
1955992Swpaul *
2055992Swpaul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
2155992Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2255992Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2355992Swpaul * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
2455992Swpaul * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2555992Swpaul * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2655992Swpaul * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2755992Swpaul * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2855992Swpaul * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2955992Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
3055992Swpaul * THE POSSIBILITY OF SUCH DAMAGE.
3155992Swpaul */
3255992Swpaul/*
3355992Swpaul * Aironet 4500/4800 802.11 PCMCIA/ISA/PCI driver for FreeBSD.
3455992Swpaul *
3555992Swpaul * Written by Bill Paul <wpaul@ctr.columbia.edu>
3655992Swpaul * Electrical Engineering Department
3755992Swpaul * Columbia University, New York City
3855992Swpaul */
3955992Swpaul
40119418Sobrien#include <sys/cdefs.h>
41119418Sobrien__FBSDID("$FreeBSD: stable/11/sys/dev/an/if_an.c 355934 2019-12-20 16:05:29Z markj $");
42119418Sobrien
4355992Swpaul/*
4486259Sphk * The Aironet 4500/4800 series cards come in PCMCIA, ISA and PCI form.
4555992Swpaul * This driver supports all three device types (PCI devices are supported
46100770Sfenner * through an extra PCI shim: /sys/dev/an/if_an_pci.c). ISA devices can be
4755992Swpaul * supported either using hard-coded IO port/IRQ settings or via Plug
4855992Swpaul * and Play. The 4500 series devices support 1Mbps and 2Mbps data rates.
4955992Swpaul * The 4800 devices support 1, 2, 5.5 and 11Mbps rates.
5055992Swpaul *
5155992Swpaul * Like the WaveLAN/IEEE cards, the Aironet NICs are all essentially
5255992Swpaul * PCMCIA devices. The ISA and PCI cards are a combination of a PCMCIA
5355992Swpaul * device and a PCMCIA to ISA or PCMCIA to PCI adapter card. There are
5455992Swpaul * a couple of important differences though:
5555992Swpaul *
5655992Swpaul * - Lucent ISA card looks to the host like a PCMCIA controller with
5755992Swpaul *   a PCMCIA WaveLAN card inserted. This means that even desktop
5855992Swpaul *   machines need to be configured with PCMCIA support in order to
5955992Swpaul *   use WaveLAN/IEEE ISA cards. The Aironet cards on the other hand
6055992Swpaul *   actually look like normal ISA and PCI devices to the host, so
6155992Swpaul *   no PCMCIA controller support is needed
6255992Swpaul *
6355992Swpaul * The latter point results in a small gotcha. The Aironet PCMCIA
6455992Swpaul * cards can be configured for one of two operating modes depending
6555992Swpaul * on how the Vpp1 and Vpp2 programming voltages are set when the
6655992Swpaul * card is activated. In order to put the card in proper PCMCIA
6755992Swpaul * operation (where the CIS table is visible and the interface is
6855992Swpaul * programmed for PCMCIA operation), both Vpp1 and Vpp2 have to be
6955992Swpaul * set to 5 volts. FreeBSD by default doesn't set the Vpp voltages,
7055992Swpaul * which leaves the card in ISA/PCI mode, which prevents it from
7186381Simp * being activated as an PCMCIA device.
7255992Swpaul *
7355992Swpaul * Note that some PCMCIA controller software packages for Windows NT
7455992Swpaul * fail to set the voltages as well.
7583270Sbrooks *
7655992Swpaul * The Aironet devices can operate in both station mode and access point
7755992Swpaul * mode. Typically, when programmed for station mode, the card can be set
7855992Swpaul * to automatically perform encapsulation/decapsulation of Ethernet II
7955992Swpaul * and 802.3 frames within 802.11 frames so that the host doesn't have
8055992Swpaul * to do it itself. This driver doesn't program the card that way: the
8155992Swpaul * driver handles all of the encapsulation/decapsulation itself.
8255992Swpaul */
8355992Swpaul
8455992Swpaul#include "opt_inet.h"
8555992Swpaul
8655992Swpaul#ifdef INET
8755992Swpaul#define ANCACHE			/* enable signal strength cache */
8855992Swpaul#endif
8955992Swpaul
9055992Swpaul#include <sys/param.h>
91154866Snjl#include <sys/ctype.h>
9255992Swpaul#include <sys/systm.h>
9355992Swpaul#include <sys/sockio.h>
9455992Swpaul#include <sys/mbuf.h>
95164033Srwatson#include <sys/priv.h>
9683366Sjulian#include <sys/proc.h>
9755992Swpaul#include <sys/kernel.h>
9855992Swpaul#include <sys/socket.h>
9955992Swpaul#ifdef ANCACHE
10055992Swpaul#include <sys/syslog.h>
101108401Sambrisko#endif
10255992Swpaul#include <sys/sysctl.h>
10355992Swpaul
10455992Swpaul#include <sys/module.h>
10555992Swpaul#include <sys/bus.h>
10655992Swpaul#include <machine/bus.h>
10755992Swpaul#include <sys/rman.h>
10884811Sjhb#include <sys/lock.h>
10967365Sjhb#include <sys/mutex.h>
11055992Swpaul#include <machine/resource.h>
111108401Sambrisko#include <sys/malloc.h>
11255992Swpaul
11355992Swpaul#include <net/if.h>
114257176Sglebius#include <net/if_var.h>
11555992Swpaul#include <net/if_arp.h>
116152315Sru#include <net/if_dl.h>
11755992Swpaul#include <net/ethernet.h>
11855992Swpaul#include <net/if_types.h>
11977217Sphk#include <net/if_media.h>
12055992Swpaul
121116951Ssam#include <net80211/ieee80211_var.h>
122116951Ssam#include <net80211/ieee80211_ioctl.h>
123116951Ssam
12455992Swpaul#ifdef INET
12555992Swpaul#include <netinet/in.h>
12655992Swpaul#include <netinet/in_systm.h>
12755992Swpaul#include <netinet/in_var.h>
12855992Swpaul#include <netinet/ip.h>
12955992Swpaul#endif
13055992Swpaul
13155992Swpaul#include <net/bpf.h>
13255992Swpaul
13355992Swpaul#include <machine/md_var.h>
13455992Swpaul
13555992Swpaul#include <dev/an/if_aironet_ieee.h>
13655992Swpaul#include <dev/an/if_anreg.h>
13755992Swpaul
13855992Swpaul/* These are global because we need them in sys/pci/if_an_p.c. */
139150446Simpstatic void an_reset(struct an_softc *);
140150446Simpstatic int an_init_mpi350_desc(struct an_softc *);
141150446Simpstatic int an_ioctl(struct ifnet *, u_long, caddr_t);
142150446Simpstatic void an_init(void *);
143199154Sjhbstatic void an_init_locked(struct an_softc *);
144150446Simpstatic int an_init_tx_ring(struct an_softc *);
145150446Simpstatic void an_start(struct ifnet *);
146199154Sjhbstatic void an_start_locked(struct ifnet *);
147199154Sjhbstatic void an_watchdog(struct an_softc *);
148150446Simpstatic void an_rxeof(struct an_softc *);
149150446Simpstatic void an_txeof(struct an_softc *, int);
15055992Swpaul
151150446Simpstatic void an_promisc(struct an_softc *, int);
152150446Simpstatic int an_cmd(struct an_softc *, int, int);
153150446Simpstatic int an_cmd_struct(struct an_softc *, struct an_command *,
154150446Simp    struct an_reply *);
155150446Simpstatic int an_read_record(struct an_softc *, struct an_ltv_gen *);
156150446Simpstatic int an_write_record(struct an_softc *, struct an_ltv_gen *);
157150446Simpstatic int an_read_data(struct an_softc *, int, int, caddr_t, int);
158150446Simpstatic int an_write_data(struct an_softc *, int, int, caddr_t, int);
159150446Simpstatic int an_seek(struct an_softc *, int, int, int);
160150446Simpstatic int an_alloc_nicmem(struct an_softc *, int, int *);
161150446Simpstatic int an_dma_malloc(struct an_softc *, bus_size_t, struct an_dma_alloc *,
162150446Simp    int);
163150446Simpstatic void an_dma_free(struct an_softc *, struct an_dma_alloc *);
164150446Simpstatic void an_dma_malloc_cb(void *, bus_dma_segment_t *, int, int);
165150446Simpstatic void an_stats_update(void *);
166150446Simpstatic void an_setdef(struct an_softc *, struct an_req *);
16755992Swpaul#ifdef ANCACHE
168150446Simpstatic void an_cache_store(struct an_softc *, struct ether_header *,
169150446Simp    struct mbuf *, u_int8_t, u_int8_t);
17055992Swpaul#endif
17155992Swpaul
17288748Sambrisko/* function definitions for use with the Cisco's Linux configuration
17388748Sambrisko   utilities
17488748Sambrisko*/
17588748Sambrisko
17692739Salfredstatic int readrids(struct ifnet*, struct aironet_ioctl*);
17792739Salfredstatic int writerids(struct ifnet*, struct aironet_ioctl*);
17892739Salfredstatic int flashcard(struct ifnet*, struct aironet_ioctl*);
17988748Sambrisko
18092739Salfredstatic int cmdreset(struct ifnet *);
18192739Salfredstatic int setflashmode(struct ifnet *);
18292739Salfredstatic int flashgchar(struct ifnet *,int,int);
18392739Salfredstatic int flashpchar(struct ifnet *,int,int);
18492739Salfredstatic int flashputbuf(struct ifnet *);
18592739Salfredstatic int flashrestart(struct ifnet *);
18692739Salfredstatic int WaitBusy(struct ifnet *, int);
18792739Salfredstatic int unstickbusy(struct ifnet *);
18888748Sambrisko
18992739Salfredstatic void an_dump_record	(struct an_softc *,struct an_ltv_gen *,
19092739Salfred				    char *);
19178639Sbrooks
19292739Salfredstatic int an_media_change	(struct ifnet *);
19392739Salfredstatic void an_media_status	(struct ifnet *, struct ifmediareq *);
19477217Sphk
19578639Sbrooksstatic int	an_dump = 0;
196108401Sambriskostatic int	an_cache_mode = 0;
19788748Sambrisko
198108401Sambrisko#define DBM 0
199108401Sambrisko#define PERCENT 1
200108401Sambrisko#define RAW 2
201108401Sambrisko
20283269Sbrooksstatic char an_conf[256];
203108401Sambriskostatic char an_conf_cache[256];
20483269Sbrooks
20583269Sbrooks/* sysctl vars */
206108401Sambrisko
207227309Sedstatic SYSCTL_NODE(_hw, OID_AUTO, an, CTLFLAG_RD, 0,
208227309Sed    "Wireless driver parameters");
20983269Sbrooks
210106937Ssam/* XXX violate ethernet/netgraph callback hooks */
211106937Ssamextern	void	(*ng_ether_attach_p)(struct ifnet *ifp);
212106937Ssamextern	void	(*ng_ether_detach_p)(struct ifnet *ifp);
213106937Ssam
21483269Sbrooksstatic int
21583269Sbrookssysctl_an_dump(SYSCTL_HANDLER_ARGS)
21683269Sbrooks{
21783269Sbrooks	int	error, r, last;
21883269Sbrooks	char 	*s = an_conf;
21983270Sbrooks
22083269Sbrooks	last = an_dump;
22183269Sbrooks
22283270Sbrooks	switch (an_dump) {
22383269Sbrooks	case 0:
224108401Sambrisko		strcpy(an_conf, "off");
22583269Sbrooks		break;
22683269Sbrooks	case 1:
227108401Sambrisko		strcpy(an_conf, "type");
22883269Sbrooks		break;
22983269Sbrooks	case 2:
230108401Sambrisko		strcpy(an_conf, "dump");
23183269Sbrooks		break;
23283269Sbrooks	default:
23383269Sbrooks		snprintf(an_conf, 5, "%x", an_dump);
23483269Sbrooks		break;
23583269Sbrooks	}
23683269Sbrooks
23783269Sbrooks	error = sysctl_handle_string(oidp, an_conf, sizeof(an_conf), req);
23883269Sbrooks
239108401Sambrisko	if (strncmp(an_conf,"off", 3) == 0) {
24083269Sbrooks		an_dump = 0;
24183269Sbrooks 	}
24283270Sbrooks	if (strncmp(an_conf,"dump", 4) == 0) {
24383269Sbrooks		an_dump = 1;
24483269Sbrooks	}
24583270Sbrooks	if (strncmp(an_conf,"type", 4) == 0) {
24683269Sbrooks		an_dump = 2;
24783269Sbrooks	}
24883270Sbrooks	if (*s == 'f') {
24983269Sbrooks		r = 0;
25083270Sbrooks		for (;;s++) {
25183270Sbrooks			if ((*s >= '0') && (*s <= '9')) {
25283269Sbrooks				r = r * 16 + (*s - '0');
25383270Sbrooks			} else if ((*s >= 'a') && (*s <= 'f')) {
25483269Sbrooks				r = r * 16 + (*s - 'a' + 10);
25583270Sbrooks			} else {
25683270Sbrooks				break;
25783269Sbrooks			}
25883269Sbrooks		}
25983269Sbrooks		an_dump = r;
26083269Sbrooks	}
26183269Sbrooks	if (an_dump != last)
26283269Sbrooks		printf("Sysctl changed for Aironet driver\n");
26383269Sbrooks
26483269Sbrooks	return error;
26583269Sbrooks}
26683269Sbrooks
267110531SambriskoSYSCTL_PROC(_hw_an, OID_AUTO, an_dump, CTLTYPE_STRING | CTLFLAG_RW,
268175446Sambrisko	    0, sizeof(an_conf), sysctl_an_dump, "A", "");
26983269Sbrooks
270108401Sambriskostatic int
271108401Sambriskosysctl_an_cache_mode(SYSCTL_HANDLER_ARGS)
272108401Sambrisko{
273269712Simp	int	error;
274108401Sambrisko
275108401Sambrisko	switch (an_cache_mode) {
276108401Sambrisko	case 1:
277108401Sambrisko		strcpy(an_conf_cache, "per");
278108401Sambrisko		break;
279108401Sambrisko	case 2:
280108401Sambrisko		strcpy(an_conf_cache, "raw");
281108401Sambrisko		break;
282108401Sambrisko	default:
283108401Sambrisko		strcpy(an_conf_cache, "dbm");
284108401Sambrisko		break;
285108401Sambrisko	}
286108401Sambrisko
287175445Sambrisko	error = sysctl_handle_string(oidp, an_conf_cache,
288108401Sambrisko			sizeof(an_conf_cache), req);
289108401Sambrisko
290108401Sambrisko	if (strncmp(an_conf_cache,"dbm", 3) == 0) {
291108401Sambrisko		an_cache_mode = 0;
292108401Sambrisko	}
293108401Sambrisko	if (strncmp(an_conf_cache,"per", 3) == 0) {
294108401Sambrisko		an_cache_mode = 1;
295108401Sambrisko 	}
296108401Sambrisko	if (strncmp(an_conf_cache,"raw", 3) == 0) {
297108401Sambrisko		an_cache_mode = 2;
298108401Sambrisko	}
299108401Sambrisko
300108401Sambrisko	return error;
301108401Sambrisko}
302108401Sambrisko
303110531SambriskoSYSCTL_PROC(_hw_an, OID_AUTO, an_cache_mode, CTLTYPE_STRING | CTLFLAG_RW,
304175446Sambrisko	    0, sizeof(an_conf_cache), sysctl_an_cache_mode, "A", "");
305108401Sambrisko
30683270Sbrooks/*
30755992Swpaul * We probe for an Aironet 4500/4800 card by attempting to
30855992Swpaul * read the default SSID list. On reset, the first entry in
30955992Swpaul * the SSID list will contain the name "tsunami." If we don't
31055992Swpaul * find this, then there's no card present.
31155992Swpaul */
31283270Sbrooksint
313150446Simpan_probe(device_t dev)
31455992Swpaul{
315175446Sambrisko	struct an_softc *sc = device_get_softc(dev);
316119156Sambrisko	struct an_ltv_ssidlist_new	ssid;
31755992Swpaul	int	error;
31855992Swpaul
31955992Swpaul	bzero((char *)&ssid, sizeof(ssid));
32055992Swpaul
32155992Swpaul	error = an_alloc_port(dev, 0, AN_IOSIZ);
32278639Sbrooks	if (error != 0)
32355992Swpaul		return (0);
32455992Swpaul
32555992Swpaul	/* can't do autoprobing */
32655992Swpaul	if (rman_get_start(sc->port_res) == -1)
32755992Swpaul		return(0);
32855992Swpaul
32955992Swpaul	/*
33055992Swpaul	 * We need to fake up a softc structure long enough
33155992Swpaul	 * to be able to issue commands and call some of the
33255992Swpaul	 * other routines.
33355992Swpaul	 */
33455992Swpaul	ssid.an_len = sizeof(ssid);
33555992Swpaul	ssid.an_type = AN_RID_SSIDLIST;
33655992Swpaul
337175446Sambrisko	/* Make sure interrupts are disabled. */
338119156Sambrisko	sc->mpi350 = 0;
339175446Sambrisko	CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), 0);
340175446Sambrisko	CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), 0xFFFF);
34155992Swpaul
342259393Sgavin	sc->an_dev = dev;
343175445Sambrisko	mtx_init(&sc->an_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
344199154Sjhb	    MTX_DEF);
345175445Sambrisko	AN_LOCK(sc);
34655992Swpaul	an_reset(sc);
34755992Swpaul
348175445Sambrisko	if (an_cmd(sc, AN_CMD_READCFG, 0)) {
349175445Sambrisko		AN_UNLOCK(sc);
350175445Sambrisko		goto fail;
351175445Sambrisko	}
35255992Swpaul
353175445Sambrisko	if (an_read_record(sc, (struct an_ltv_gen *)&ssid)) {
354175445Sambrisko		AN_UNLOCK(sc);
355175445Sambrisko		goto fail;
356175445Sambrisko	}
35755992Swpaul
35868692Swpaul	/* See if the ssid matches what we expect ... but doesn't have to */
359175445Sambrisko	if (strcmp(ssid.an_entry[0].an_ssid, AN_DEF_SSID)) {
360175445Sambrisko		AN_UNLOCK(sc);
361175445Sambrisko		goto fail;
362175445Sambrisko	}
36383270Sbrooks
364175445Sambrisko	AN_UNLOCK(sc);
36555992Swpaul	return(AN_IOSIZ);
366175445Sambriskofail:
367175445Sambrisko	mtx_destroy(&sc->an_mtx);
368175445Sambrisko	return(0);
36955992Swpaul}
37055992Swpaul
37155992Swpaul/*
37255992Swpaul * Allocate a port resource with the given resource id.
37355992Swpaul */
37455992Swpaulint
375150446Simpan_alloc_port(device_t dev, int rid, int size)
37655992Swpaul{
37755992Swpaul	struct an_softc *sc = device_get_softc(dev);
37855992Swpaul	struct resource *res;
37955992Swpaul
380296137Sjhibbits	res = bus_alloc_resource_anywhere(dev, SYS_RES_IOPORT, &rid,
381296137Sjhibbits					  size, RF_ACTIVE);
38255992Swpaul	if (res) {
38355992Swpaul		sc->port_rid = rid;
38455992Swpaul		sc->port_res = res;
38555992Swpaul		return (0);
38655992Swpaul	} else {
38755992Swpaul		return (ENOENT);
38855992Swpaul	}
38955992Swpaul}
39055992Swpaul
39155992Swpaul/*
392108401Sambrisko * Allocate a memory resource with the given resource id.
393108401Sambrisko */
394108401Sambriskoint an_alloc_memory(device_t dev, int rid, int size)
395108401Sambrisko{
396108401Sambrisko	struct an_softc *sc = device_get_softc(dev);
397108401Sambrisko	struct resource *res;
398108401Sambrisko
399296137Sjhibbits	res = bus_alloc_resource_anywhere(dev, SYS_RES_MEMORY, &rid,
400296137Sjhibbits					  size, RF_ACTIVE);
401108401Sambrisko	if (res) {
402108401Sambrisko		sc->mem_rid = rid;
403108401Sambrisko		sc->mem_res = res;
404108401Sambrisko		sc->mem_used = size;
405108401Sambrisko		return (0);
406108401Sambrisko	} else {
407108401Sambrisko		return (ENOENT);
408108401Sambrisko	}
409108401Sambrisko}
410108401Sambrisko
411108401Sambrisko/*
412298955Spfg * Allocate a auxiliary memory resource with the given resource id.
413108401Sambrisko */
414108401Sambriskoint an_alloc_aux_memory(device_t dev, int rid, int size)
415108401Sambrisko{
416108401Sambrisko	struct an_softc *sc = device_get_softc(dev);
417108401Sambrisko	struct resource *res;
418108401Sambrisko
419296137Sjhibbits	res = bus_alloc_resource_anywhere(dev, SYS_RES_MEMORY, &rid,
420296137Sjhibbits					  size, RF_ACTIVE);
421108401Sambrisko	if (res) {
422108401Sambrisko		sc->mem_aux_rid = rid;
423108401Sambrisko		sc->mem_aux_res = res;
424108401Sambrisko		sc->mem_aux_used = size;
425108401Sambrisko		return (0);
426108401Sambrisko	} else {
427108401Sambrisko		return (ENOENT);
428108401Sambrisko	}
429108401Sambrisko}
430108401Sambrisko
431108401Sambrisko/*
43255992Swpaul * Allocate an irq resource with the given resource id.
43355992Swpaul */
43455992Swpaulint
435150446Simpan_alloc_irq(device_t dev, int rid, int flags)
43655992Swpaul{
43755992Swpaul	struct an_softc *sc = device_get_softc(dev);
43855992Swpaul	struct resource *res;
43955992Swpaul
440127135Snjl	res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
441127135Snjl				     (RF_ACTIVE | flags));
44255992Swpaul	if (res) {
44355992Swpaul		sc->irq_rid = rid;
44455992Swpaul		sc->irq_res = res;
44555992Swpaul		return (0);
44655992Swpaul	} else {
44755992Swpaul		return (ENOENT);
44855992Swpaul	}
44955992Swpaul}
45055992Swpaul
451108401Sambriskostatic void
452150446Simpan_dma_malloc_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
453108401Sambrisko{
454108401Sambrisko	bus_addr_t *paddr = (bus_addr_t*) arg;
455108401Sambrisko	*paddr = segs->ds_addr;
456108401Sambrisko}
457108401Sambrisko
45855992Swpaul/*
459108401Sambrisko * Alloc DMA memory and set the pointer to it
460108401Sambrisko */
461108401Sambriskostatic int
462150446Simpan_dma_malloc(struct an_softc *sc, bus_size_t size, struct an_dma_alloc *dma,
463150446Simp    int mapflags)
464108401Sambrisko{
465108401Sambrisko	int r;
466108401Sambrisko
467108401Sambrisko	r = bus_dmamem_alloc(sc->an_dtag, (void**) &dma->an_dma_vaddr,
468108401Sambrisko			     BUS_DMA_NOWAIT, &dma->an_dma_map);
469108401Sambrisko	if (r != 0)
470108401Sambrisko		goto fail_1;
471108401Sambrisko
472108401Sambrisko	r = bus_dmamap_load(sc->an_dtag, dma->an_dma_map, dma->an_dma_vaddr,
473175446Sambrisko			    size,
474108401Sambrisko			    an_dma_malloc_cb,
475108401Sambrisko			    &dma->an_dma_paddr,
476108401Sambrisko			    mapflags | BUS_DMA_NOWAIT);
477108401Sambrisko	if (r != 0)
478108401Sambrisko		goto fail_2;
479108401Sambrisko
480108401Sambrisko	dma->an_dma_size = size;
481108401Sambrisko	return (0);
482108401Sambrisko
483108401Sambriskofail_2:
484108401Sambrisko	bus_dmamap_unload(sc->an_dtag, dma->an_dma_map);
485108401Sambriskofail_1:
486108401Sambrisko	bus_dmamem_free(sc->an_dtag, dma->an_dma_vaddr, dma->an_dma_map);
487108401Sambrisko	return (r);
488108401Sambrisko}
489108401Sambrisko
490108401Sambriskostatic void
491150446Simpan_dma_free(struct an_softc *sc, struct an_dma_alloc *dma)
492108401Sambrisko{
493108401Sambrisko	bus_dmamap_unload(sc->an_dtag, dma->an_dma_map);
494108401Sambrisko	bus_dmamem_free(sc->an_dtag, dma->an_dma_vaddr, dma->an_dma_map);
495123978Sambrisko	dma->an_dma_vaddr = 0;
496108401Sambrisko}
497108401Sambrisko
498108401Sambrisko/*
49955992Swpaul * Release all resources
50055992Swpaul */
50155992Swpaulvoid
502150446Simpan_release_resources(device_t dev)
50355992Swpaul{
50455992Swpaul	struct an_softc *sc = device_get_softc(dev);
505108401Sambrisko	int i;
50655992Swpaul
50755992Swpaul	if (sc->port_res) {
50855992Swpaul		bus_release_resource(dev, SYS_RES_IOPORT,
50955992Swpaul				     sc->port_rid, sc->port_res);
51055992Swpaul		sc->port_res = 0;
51155992Swpaul	}
512108401Sambrisko	if (sc->mem_res) {
513108401Sambrisko		bus_release_resource(dev, SYS_RES_MEMORY,
514108401Sambrisko				     sc->mem_rid, sc->mem_res);
515108401Sambrisko		sc->mem_res = 0;
516108401Sambrisko	}
517108401Sambrisko	if (sc->mem_aux_res) {
518108401Sambrisko		bus_release_resource(dev, SYS_RES_MEMORY,
519108401Sambrisko				     sc->mem_aux_rid, sc->mem_aux_res);
520108401Sambrisko		sc->mem_aux_res = 0;
521108401Sambrisko	}
52255992Swpaul	if (sc->irq_res) {
52355992Swpaul		bus_release_resource(dev, SYS_RES_IRQ,
52455992Swpaul				     sc->irq_rid, sc->irq_res);
52555992Swpaul		sc->irq_res = 0;
52655992Swpaul	}
527108401Sambrisko	if (sc->an_rid_buffer.an_dma_paddr) {
528108401Sambrisko		an_dma_free(sc, &sc->an_rid_buffer);
529108401Sambrisko	}
530108401Sambrisko	for (i = 0; i < AN_MAX_RX_DESC; i++)
531108401Sambrisko		if (sc->an_rx_buffer[i].an_dma_paddr) {
532108401Sambrisko			an_dma_free(sc, &sc->an_rx_buffer[i]);
533108401Sambrisko		}
534108401Sambrisko	for (i = 0; i < AN_MAX_TX_DESC; i++)
535108401Sambrisko		if (sc->an_tx_buffer[i].an_dma_paddr) {
536108401Sambrisko			an_dma_free(sc, &sc->an_tx_buffer[i]);
537108401Sambrisko		}
538108401Sambrisko	if (sc->an_dtag) {
539108401Sambrisko		bus_dma_tag_destroy(sc->an_dtag);
540108401Sambrisko	}
541108401Sambrisko
54255992Swpaul}
54355992Swpaul
54483270Sbrooksint
545150446Simpan_init_mpi350_desc(struct an_softc *sc)
546108401Sambrisko{
547108401Sambrisko	struct an_command	cmd_struct;
548108401Sambrisko	struct an_reply		reply;
549108401Sambrisko	struct an_card_rid_desc an_rid_desc;
550108401Sambrisko	struct an_card_rx_desc	an_rx_desc;
551108401Sambrisko	struct an_card_tx_desc	an_tx_desc;
552108401Sambrisko	int			i, desc;
553108401Sambrisko
554175445Sambrisko	AN_LOCK_ASSERT(sc);
555108401Sambrisko	if(!sc->an_rid_buffer.an_dma_paddr)
556108401Sambrisko		an_dma_malloc(sc, AN_RID_BUFFER_SIZE,
557108401Sambrisko				 &sc->an_rid_buffer, 0);
558108401Sambrisko	for (i = 0; i < AN_MAX_RX_DESC; i++)
559108401Sambrisko		if(!sc->an_rx_buffer[i].an_dma_paddr)
560108401Sambrisko			an_dma_malloc(sc, AN_RX_BUFFER_SIZE,
561108401Sambrisko				      &sc->an_rx_buffer[i], 0);
562108401Sambrisko	for (i = 0; i < AN_MAX_TX_DESC; i++)
563108401Sambrisko		if(!sc->an_tx_buffer[i].an_dma_paddr)
564108401Sambrisko			an_dma_malloc(sc, AN_TX_BUFFER_SIZE,
565108401Sambrisko				      &sc->an_tx_buffer[i], 0);
566108401Sambrisko
567108401Sambrisko	/*
568108401Sambrisko	 * Allocate RX descriptor
569108401Sambrisko	 */
570108401Sambrisko	bzero(&reply,sizeof(reply));
571108401Sambrisko	cmd_struct.an_cmd   = AN_CMD_ALLOC_DESC;
572108401Sambrisko	cmd_struct.an_parm0 = AN_DESCRIPTOR_RX;
573108401Sambrisko	cmd_struct.an_parm1 = AN_RX_DESC_OFFSET;
574108401Sambrisko	cmd_struct.an_parm2 = AN_MAX_RX_DESC;
575108401Sambrisko	if (an_cmd_struct(sc, &cmd_struct, &reply)) {
576198987Sjhb		if_printf(sc->an_ifp, "failed to allocate RX descriptor\n");
577108401Sambrisko		return(EIO);
578108401Sambrisko	}
579108401Sambrisko
580108401Sambrisko	for (desc = 0; desc < AN_MAX_RX_DESC; desc++) {
581108401Sambrisko		bzero(&an_rx_desc, sizeof(an_rx_desc));
582108401Sambrisko		an_rx_desc.an_valid = 1;
583108401Sambrisko		an_rx_desc.an_len = AN_RX_BUFFER_SIZE;
584108401Sambrisko		an_rx_desc.an_done = 0;
585108401Sambrisko		an_rx_desc.an_phys = sc->an_rx_buffer[desc].an_dma_paddr;
586108401Sambrisko
587108401Sambrisko		for (i = 0; i < sizeof(an_rx_desc) / 4; i++)
588155321Simp			CSR_MEM_AUX_WRITE_4(sc, AN_RX_DESC_OFFSET
589155321Simp			    + (desc * sizeof(an_rx_desc))
590155321Simp			    + (i * 4),
591155321Simp			    ((u_int32_t *)(void *)&an_rx_desc)[i]);
592108401Sambrisko	}
593108401Sambrisko
594108401Sambrisko	/*
595108401Sambrisko	 * Allocate TX descriptor
596108401Sambrisko	 */
597108401Sambrisko
598108401Sambrisko	bzero(&reply,sizeof(reply));
599108401Sambrisko	cmd_struct.an_cmd   = AN_CMD_ALLOC_DESC;
600108401Sambrisko	cmd_struct.an_parm0 = AN_DESCRIPTOR_TX;
601108401Sambrisko	cmd_struct.an_parm1 = AN_TX_DESC_OFFSET;
602108401Sambrisko	cmd_struct.an_parm2 = AN_MAX_TX_DESC;
603108401Sambrisko	if (an_cmd_struct(sc, &cmd_struct, &reply)) {
604198987Sjhb		if_printf(sc->an_ifp, "failed to allocate TX descriptor\n");
605108401Sambrisko		return(EIO);
606108401Sambrisko	}
607108401Sambrisko
608108401Sambrisko	for (desc = 0; desc < AN_MAX_TX_DESC; desc++) {
609108401Sambrisko		bzero(&an_tx_desc, sizeof(an_tx_desc));
610108401Sambrisko		an_tx_desc.an_offset = 0;
611108401Sambrisko		an_tx_desc.an_eoc = 0;
612108401Sambrisko		an_tx_desc.an_valid = 0;
613108401Sambrisko		an_tx_desc.an_len = 0;
614108401Sambrisko		an_tx_desc.an_phys = sc->an_tx_buffer[desc].an_dma_paddr;
615108401Sambrisko
616108401Sambrisko		for (i = 0; i < sizeof(an_tx_desc) / 4; i++)
617108401Sambrisko			CSR_MEM_AUX_WRITE_4(sc, AN_TX_DESC_OFFSET
618155321Simp			    + (desc * sizeof(an_tx_desc))
619155321Simp			    + (i * 4),
620155321Simp			    ((u_int32_t *)(void *)&an_tx_desc)[i]);
621108401Sambrisko	}
622108401Sambrisko
623108401Sambrisko	/*
624108401Sambrisko	 * Allocate RID descriptor
625108401Sambrisko	 */
626108401Sambrisko
627108401Sambrisko	bzero(&reply,sizeof(reply));
628108401Sambrisko	cmd_struct.an_cmd   = AN_CMD_ALLOC_DESC;
629108401Sambrisko	cmd_struct.an_parm0 = AN_DESCRIPTOR_HOSTRW;
630108401Sambrisko	cmd_struct.an_parm1 = AN_HOST_DESC_OFFSET;
631108401Sambrisko	cmd_struct.an_parm2 = 1;
632108401Sambrisko	if (an_cmd_struct(sc, &cmd_struct, &reply)) {
633198987Sjhb		if_printf(sc->an_ifp, "failed to allocate host descriptor\n");
634108401Sambrisko		return(EIO);
635108401Sambrisko	}
636108401Sambrisko
637108401Sambrisko	bzero(&an_rid_desc, sizeof(an_rid_desc));
638108401Sambrisko	an_rid_desc.an_valid = 1;
639108401Sambrisko	an_rid_desc.an_len = AN_RID_BUFFER_SIZE;
640108401Sambrisko	an_rid_desc.an_rid = 0;
641108401Sambrisko	an_rid_desc.an_phys = sc->an_rid_buffer.an_dma_paddr;
642108401Sambrisko
643108401Sambrisko	for (i = 0; i < sizeof(an_rid_desc) / 4; i++)
644175445Sambrisko		CSR_MEM_AUX_WRITE_4(sc, AN_HOST_DESC_OFFSET + i * 4,
645155321Simp				    ((u_int32_t *)(void *)&an_rid_desc)[i]);
646108401Sambrisko
647108401Sambrisko	return(0);
648108401Sambrisko}
649108401Sambrisko
650108401Sambriskoint
651198995Sjhban_attach(struct an_softc *sc, int flags)
65255992Swpaul{
653147256Sbrooks	struct ifnet		*ifp;
654113316Simp	int			error = EIO;
655110253Sambrisko	int			i, nrate, mword;
656110253Sambrisko	u_int8_t		r;
65755992Swpaul
658147380Sdelphij	ifp = sc->an_ifp = if_alloc(IFT_ETHER);
659147256Sbrooks	if (ifp == NULL) {
660198987Sjhb		device_printf(sc->an_dev, "can not if_alloc()\n");
661147256Sbrooks		goto fail;
662147256Sbrooks	}
663259393Sgavin	ifp->if_softc = sc;
664259393Sgavin	if_initname(ifp, device_get_name(sc->an_dev),
665259393Sgavin	    device_get_unit(sc->an_dev));
666175445Sambrisko
66755992Swpaul	sc->an_gone = 0;
66855992Swpaul	sc->an_associated = 0;
66983269Sbrooks	sc->an_monitor = 0;
67083269Sbrooks	sc->an_was_monitor = 0;
671108401Sambrisko	sc->an_flash_buffer = NULL;
67255992Swpaul
67355992Swpaul	/* Reset the NIC. */
674175445Sambrisko	AN_LOCK(sc);
67555992Swpaul	an_reset(sc);
676110104Sambrisko	if (sc->mpi350) {
677108401Sambrisko		error = an_init_mpi350_desc(sc);
678108401Sambrisko		if (error)
679113316Simp			goto fail;
680108401Sambrisko	}
68155992Swpaul
68255992Swpaul	/* Load factory config */
68355992Swpaul	if (an_cmd(sc, AN_CMD_READCFG, 0)) {
684198987Sjhb		device_printf(sc->an_dev, "failed to load config data\n");
685113316Simp		goto fail;
68655992Swpaul	}
68755992Swpaul
68855992Swpaul	/* Read the current configuration */
68955992Swpaul	sc->an_config.an_type = AN_RID_GENCONFIG;
69055992Swpaul	sc->an_config.an_len = sizeof(struct an_ltv_genconfig);
69155992Swpaul	if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_config)) {
692198987Sjhb		device_printf(sc->an_dev, "read record failed\n");
693113316Simp		goto fail;
69455992Swpaul	}
69555992Swpaul
69655992Swpaul	/* Read the card capabilities */
69755992Swpaul	sc->an_caps.an_type = AN_RID_CAPABILITIES;
69855992Swpaul	sc->an_caps.an_len = sizeof(struct an_ltv_caps);
69955992Swpaul	if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_caps)) {
700198987Sjhb		device_printf(sc->an_dev, "read record failed\n");
701113316Simp		goto fail;
70255992Swpaul	}
70355992Swpaul
70455992Swpaul	/* Read ssid list */
70555992Swpaul	sc->an_ssidlist.an_type = AN_RID_SSIDLIST;
706119156Sambrisko	sc->an_ssidlist.an_len = sizeof(struct an_ltv_ssidlist_new);
70755992Swpaul	if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_ssidlist)) {
708198987Sjhb		device_printf(sc->an_dev, "read record failed\n");
709113316Simp		goto fail;
71055992Swpaul	}
71155992Swpaul
71255992Swpaul	/* Read AP list */
71355992Swpaul	sc->an_aplist.an_type = AN_RID_APLIST;
71455992Swpaul	sc->an_aplist.an_len = sizeof(struct an_ltv_aplist);
71555992Swpaul	if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_aplist)) {
716198987Sjhb		device_printf(sc->an_dev, "read record failed\n");
717113316Simp		goto fail;
71855992Swpaul	}
71955992Swpaul
720108401Sambrisko#ifdef ANCACHE
721108401Sambrisko	/* Read the RSSI <-> dBm map */
722108401Sambrisko	sc->an_have_rssimap = 0;
723108401Sambrisko	if (sc->an_caps.an_softcaps & 8) {
724108401Sambrisko		sc->an_rssimap.an_type = AN_RID_RSSI_MAP;
725108401Sambrisko		sc->an_rssimap.an_len = sizeof(struct an_ltv_rssi_map);
726108401Sambrisko		if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_rssimap)) {
727198987Sjhb			device_printf(sc->an_dev,
728198987Sjhb			    "unable to get RSSI <-> dBM map\n");
729108401Sambrisko		} else {
730198987Sjhb			device_printf(sc->an_dev, "got RSSI <-> dBM map\n");
731108401Sambrisko			sc->an_have_rssimap = 1;
732108401Sambrisko		}
733108401Sambrisko	} else {
734198987Sjhb		device_printf(sc->an_dev, "no RSSI <-> dBM map\n");
735108401Sambrisko	}
736108401Sambrisko#endif
737175445Sambrisko	AN_UNLOCK(sc);
738108401Sambrisko
73955992Swpaul	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
74055992Swpaul	ifp->if_ioctl = an_ioctl;
74155992Swpaul	ifp->if_start = an_start;
74255992Swpaul	ifp->if_init = an_init;
74355992Swpaul	ifp->if_baudrate = 10000000;
744207554Ssobomax	IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
745207554Ssobomax	ifp->if_snd.ifq_drv_maxlen = ifqmaxlen;
746132986Smlaier	IFQ_SET_READY(&ifp->if_snd);
74755992Swpaul
74855992Swpaul	bzero(sc->an_config.an_nodename, sizeof(sc->an_config.an_nodename));
74955992Swpaul	bcopy(AN_DEFAULT_NODENAME, sc->an_config.an_nodename,
75055992Swpaul	    sizeof(AN_DEFAULT_NODENAME) - 1);
75155992Swpaul
752119156Sambrisko	bzero(sc->an_ssidlist.an_entry[0].an_ssid,
753119156Sambrisko	      sizeof(sc->an_ssidlist.an_entry[0].an_ssid));
754119156Sambrisko	bcopy(AN_DEFAULT_NETNAME, sc->an_ssidlist.an_entry[0].an_ssid,
75555992Swpaul	    sizeof(AN_DEFAULT_NETNAME) - 1);
756119156Sambrisko	sc->an_ssidlist.an_entry[0].an_len = strlen(AN_DEFAULT_NETNAME);
75755992Swpaul
75855992Swpaul	sc->an_config.an_opmode =
75974144Sassar	    AN_OPMODE_INFRASTRUCTURE_STATION;
76055992Swpaul
76155992Swpaul	sc->an_tx_rate = 0;
76255992Swpaul	bzero((char *)&sc->an_stats, sizeof(sc->an_stats));
76355992Swpaul
764110253Sambrisko	nrate = 8;
765110253Sambrisko
76677217Sphk	ifmedia_init(&sc->an_ifmedia, 0, an_media_change, an_media_status);
767110253Sambrisko	if_printf(ifp, "supported rates: ");
768110253Sambrisko#define	ADD(s, o)	ifmedia_add(&sc->an_ifmedia, \
769110253Sambrisko	IFM_MAKEWORD(IFM_IEEE80211, (s), (o), 0), 0, NULL)
770110253Sambrisko	ADD(IFM_AUTO, 0);
771110253Sambrisko	ADD(IFM_AUTO, IFM_IEEE80211_ADHOC);
772110253Sambrisko	for (i = 0; i < nrate; i++) {
773110253Sambrisko		r = sc->an_caps.an_rates[i];
774228621Sbschmidt		mword = ieee80211_rate2media(NULL, r, IEEE80211_MODE_AUTO);
775110253Sambrisko		if (mword == 0)
776110253Sambrisko			continue;
777110253Sambrisko		printf("%s%d%sMbps", (i != 0 ? " " : ""),
778110253Sambrisko		    (r & IEEE80211_RATE_VAL) / 2, ((r & 0x1) != 0 ? ".5" : ""));
779110253Sambrisko		ADD(mword, 0);
780110253Sambrisko		ADD(mword, IFM_IEEE80211_ADHOC);
78177217Sphk	}
782110253Sambrisko	printf("\n");
783175445Sambrisko	ifmedia_set(&sc->an_ifmedia, IFM_MAKEWORD(IFM_IEEE80211,
784110253Sambrisko	    IFM_AUTO, 0, 0));
785110253Sambrisko#undef ADD
78677217Sphk
78755992Swpaul	/*
78863090Sarchie	 * Call MI attach routine.
78955992Swpaul	 */
790147256Sbrooks
791147256Sbrooks	ether_ifattach(ifp, sc->an_caps.an_oemaddr);
792173668Savatar	callout_init_mtx(&sc->an_stat_ch, &sc->an_mtx, 0);
79355992Swpaul
79455992Swpaul	return(0);
795175445Sambriskofail:
796175445Sambrisko	AN_UNLOCK(sc);
797113316Simp	mtx_destroy(&sc->an_mtx);
798147256Sbrooks	if (ifp != NULL)
799147256Sbrooks		if_free(ifp);
800113316Simp	return(error);
80155992Swpaul}
80255992Swpaul
803123978Sambriskoint
804123978Sambriskoan_detach(device_t dev)
805123978Sambrisko{
806123978Sambrisko	struct an_softc		*sc = device_get_softc(dev);
807147256Sbrooks	struct ifnet		*ifp = sc->an_ifp;
808123978Sambrisko
809123978Sambrisko	if (sc->an_gone) {
810123978Sambrisko		device_printf(dev,"already unloaded\n");
811123978Sambrisko		return(0);
812123978Sambrisko	}
813148639Semax	AN_LOCK(sc);
814123978Sambrisko	an_stop(sc);
815148454Semax	sc->an_gone = 1;
816123978Sambrisko	ifmedia_removeall(&sc->an_ifmedia);
817148887Srwatson	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
818148454Semax	AN_UNLOCK(sc);
819123978Sambrisko	ether_ifdetach(ifp);
820150306Simp	bus_teardown_intr(dev, sc->irq_res, sc->irq_handle);
821173668Savatar	callout_drain(&sc->an_stat_ch);
822147256Sbrooks	if_free(ifp);
823123978Sambrisko	an_release_resources(dev);
824123978Sambrisko	mtx_destroy(&sc->an_mtx);
825123978Sambrisko	return (0);
826123978Sambrisko}
827123978Sambrisko
82883270Sbrooksstatic void
829150446Simpan_rxeof(struct an_softc *sc)
83055992Swpaul{
83183269Sbrooks	struct ifnet   *ifp;
83283269Sbrooks	struct ether_header *eh;
83383269Sbrooks	struct ieee80211_frame *ih;
83483269Sbrooks	struct an_rxframe rx_frame;
83583269Sbrooks	struct an_rxframe_802_3 rx_frame_802_3;
83683269Sbrooks	struct mbuf    *m;
837108401Sambrisko	int		len, id, error = 0, i, count = 0;
838108401Sambrisko	int		ieee80211_header_len;
839108401Sambrisko	u_char		*bpf_buf;
840108401Sambrisko	u_short		fc1;
841108401Sambrisko	struct an_card_rx_desc an_rx_desc;
842108401Sambrisko	u_int8_t	*buf;
84355992Swpaul
844122689Ssam	AN_LOCK_ASSERT(sc);
845122689Ssam
846147256Sbrooks	ifp = sc->an_ifp;
84755992Swpaul
848108401Sambrisko	if (!sc->mpi350) {
849108401Sambrisko		id = CSR_READ_2(sc, AN_RX_FID);
85055992Swpaul
851108401Sambrisko		if (sc->an_monitor && (ifp->if_flags & IFF_PROMISC)) {
852108401Sambrisko			/* read raw 802.11 packet */
853108401Sambrisko			bpf_buf = sc->buf_802_11;
85455992Swpaul
855108401Sambrisko			/* read header */
856108401Sambrisko			if (an_read_data(sc, id, 0x0, (caddr_t)&rx_frame,
857108401Sambrisko					 sizeof(rx_frame))) {
858271849Sglebius				if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
859108401Sambrisko				return;
860108401Sambrisko			}
86155992Swpaul
862108401Sambrisko			/*
863108401Sambrisko			 * skip beacon by default since this increases the
864108401Sambrisko			 * system load a lot
865108401Sambrisko			 */
86683270Sbrooks
867108401Sambrisko			if (!(sc->an_monitor & AN_MONITOR_INCLUDE_BEACON) &&
868108401Sambrisko			    (rx_frame.an_frame_ctl &
869108401Sambrisko			     IEEE80211_FC0_SUBTYPE_BEACON)) {
87083269Sbrooks				return;
87183269Sbrooks			}
87255992Swpaul
873108401Sambrisko			if (sc->an_monitor & AN_MONITOR_AIRONET_HEADER) {
874108401Sambrisko				len = rx_frame.an_rx_payload_len
875108401Sambrisko					+ sizeof(rx_frame);
876108401Sambrisko				/* Check for insane frame length */
877108401Sambrisko				if (len > sizeof(sc->buf_802_11)) {
878198987Sjhb					if_printf(ifp, "oversized packet "
879108401Sambrisko					       "received (%d, %d)\n",
880198987Sjhb					       len, MCLBYTES);
881271849Sglebius					if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
882108401Sambrisko					return;
883108401Sambrisko				}
88455992Swpaul
885108401Sambrisko				bcopy((char *)&rx_frame,
886108401Sambrisko				      bpf_buf, sizeof(rx_frame));
887108401Sambrisko
888108401Sambrisko				error = an_read_data(sc, id, sizeof(rx_frame),
889108401Sambrisko					    (caddr_t)bpf_buf+sizeof(rx_frame),
890108401Sambrisko					    rx_frame.an_rx_payload_len);
891108401Sambrisko			} else {
892108401Sambrisko				fc1=rx_frame.an_frame_ctl >> 8;
893175445Sambrisko				ieee80211_header_len =
894108401Sambrisko					sizeof(struct ieee80211_frame);
895108401Sambrisko				if ((fc1 & IEEE80211_FC1_DIR_TODS) &&
896108401Sambrisko				    (fc1 & IEEE80211_FC1_DIR_FROMDS)) {
897108401Sambrisko					ieee80211_header_len += ETHER_ADDR_LEN;
898108401Sambrisko				}
899108401Sambrisko
900108401Sambrisko				len = rx_frame.an_rx_payload_len
901108401Sambrisko					+ ieee80211_header_len;
902108401Sambrisko				/* Check for insane frame length */
903108401Sambrisko				if (len > sizeof(sc->buf_802_11)) {
904198987Sjhb					if_printf(ifp, "oversized packet "
905108401Sambrisko					       "received (%d, %d)\n",
906198987Sjhb					       len, MCLBYTES);
907271849Sglebius					if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
908108401Sambrisko					return;
909108401Sambrisko				}
910108401Sambrisko
911108401Sambrisko				ih = (struct ieee80211_frame *)bpf_buf;
912108401Sambrisko
913108401Sambrisko				bcopy((char *)&rx_frame.an_frame_ctl,
914108401Sambrisko				      (char *)ih, ieee80211_header_len);
915108401Sambrisko
916108401Sambrisko				error = an_read_data(sc, id, sizeof(rx_frame) +
917108401Sambrisko					    rx_frame.an_gaplen,
918108401Sambrisko					    (caddr_t)ih +ieee80211_header_len,
919108401Sambrisko					    rx_frame.an_rx_payload_len);
920108401Sambrisko			}
921108401Sambrisko			/* dump raw 802.11 packet to bpf and skip ip stack */
922108401Sambrisko			BPF_TAP(ifp, bpf_buf, len);
92383270Sbrooks		} else {
924243857Sglebius			MGETHDR(m, M_NOWAIT, MT_DATA);
925108401Sambrisko			if (m == NULL) {
926271849Sglebius				if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
927108401Sambrisko				return;
92883269Sbrooks			}
929276750Srwatson			if (!(MCLGET(m, M_NOWAIT))) {
930108401Sambrisko				m_freem(m);
931271849Sglebius				if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
932108401Sambrisko				return;
933108401Sambrisko			}
934108401Sambrisko			m->m_pkthdr.rcvif = ifp;
935108401Sambrisko			/* Read Ethernet encapsulated packet */
93655992Swpaul
937108401Sambrisko#ifdef ANCACHE
938108401Sambrisko			/* Read NIC frame header */
939175445Sambrisko			if (an_read_data(sc, id, 0, (caddr_t)&rx_frame,
940108401Sambrisko					 sizeof(rx_frame))) {
941154394Srwatson				m_freem(m);
942271849Sglebius				if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
943108401Sambrisko				return;
944108401Sambrisko			}
945108401Sambrisko#endif
946108401Sambrisko			/* Read in the 802_3 frame header */
947175445Sambrisko			if (an_read_data(sc, id, 0x34,
948108401Sambrisko					 (caddr_t)&rx_frame_802_3,
949108401Sambrisko					 sizeof(rx_frame_802_3))) {
950154394Srwatson				m_freem(m);
951271849Sglebius				if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
952108401Sambrisko				return;
953108401Sambrisko			}
954108401Sambrisko			if (rx_frame_802_3.an_rx_802_3_status != 0) {
955154394Srwatson				m_freem(m);
956271849Sglebius				if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
957108401Sambrisko				return;
958108401Sambrisko			}
95983269Sbrooks			/* Check for insane frame length */
960108401Sambrisko			len = rx_frame_802_3.an_rx_802_3_payload_len;
96183269Sbrooks			if (len > sizeof(sc->buf_802_11)) {
962154394Srwatson				m_freem(m);
963198987Sjhb				if_printf(ifp, "oversized packet "
964108401Sambrisko				       "received (%d, %d)\n",
965198987Sjhb				       len, MCLBYTES);
966271849Sglebius				if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
96783269Sbrooks				return;
96883269Sbrooks			}
969108401Sambrisko			m->m_pkthdr.len = m->m_len =
970108401Sambrisko				rx_frame_802_3.an_rx_802_3_payload_len + 12;
97155992Swpaul
972108401Sambrisko			eh = mtod(m, struct ether_header *);
97355992Swpaul
974108401Sambrisko			bcopy((char *)&rx_frame_802_3.an_rx_dst_addr,
975108401Sambrisko			      (char *)&eh->ether_dhost, ETHER_ADDR_LEN);
976108401Sambrisko			bcopy((char *)&rx_frame_802_3.an_rx_src_addr,
977108401Sambrisko			      (char *)&eh->ether_shost, ETHER_ADDR_LEN);
97855992Swpaul
979108401Sambrisko			/* in mbuf header type is just before payload */
980175445Sambrisko			error = an_read_data(sc, id, 0x44,
981108401Sambrisko				    (caddr_t)&(eh->ether_type),
982108401Sambrisko				    rx_frame_802_3.an_rx_802_3_payload_len);
98355992Swpaul
984108401Sambrisko			if (error) {
985108401Sambrisko				m_freem(m);
986271849Sglebius				if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
987108401Sambrisko				return;
988108401Sambrisko			}
989271849Sglebius			if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
990108401Sambrisko
991108401Sambrisko			/* Receive packet. */
99283269Sbrooks#ifdef ANCACHE
993175445Sambrisko			an_cache_store(sc, eh, m,
994110253Sambrisko				rx_frame.an_rx_signal_strength,
995110253Sambrisko				rx_frame.an_rsvd0);
99683269Sbrooks#endif
997122689Ssam			AN_UNLOCK(sc);
998108401Sambrisko			(*ifp->if_input)(ifp, m);
999122689Ssam			AN_LOCK(sc);
100083269Sbrooks		}
100155992Swpaul
1002108401Sambrisko	} else { /* MPI-350 */
1003108401Sambrisko		for (count = 0; count < AN_MAX_RX_DESC; count++){
1004108401Sambrisko			for (i = 0; i < sizeof(an_rx_desc) / 4; i++)
1005175445Sambrisko				((u_int32_t *)(void *)&an_rx_desc)[i]
1006175445Sambrisko					= CSR_MEM_AUX_READ_4(sc,
1007175445Sambrisko						AN_RX_DESC_OFFSET
1008108401Sambrisko						+ (count * sizeof(an_rx_desc))
1009108401Sambrisko						+ (i * 4));
101083269Sbrooks
1011108401Sambrisko			if (an_rx_desc.an_done && !an_rx_desc.an_valid) {
1012108401Sambrisko				buf = sc->an_rx_buffer[count].an_dma_vaddr;
101383269Sbrooks
1014243857Sglebius				MGETHDR(m, M_NOWAIT, MT_DATA);
1015108401Sambrisko				if (m == NULL) {
1016271849Sglebius					if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
1017108401Sambrisko					return;
1018108401Sambrisko				}
1019276750Srwatson				if (!(MCLGET(m, M_NOWAIT))) {
1020108401Sambrisko					m_freem(m);
1021271849Sglebius					if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
1022108401Sambrisko					return;
1023108401Sambrisko				}
1024108401Sambrisko				m->m_pkthdr.rcvif = ifp;
1025108401Sambrisko				/* Read Ethernet encapsulated packet */
102683269Sbrooks
1027175445Sambrisko				/*
1028108401Sambrisko				 * No ANCACHE support since we just get back
1029108401Sambrisko				 * an Ethernet packet no 802.11 info
1030108401Sambrisko				 */
1031108401Sambrisko#if 0
1032108401Sambrisko#ifdef ANCACHE
1033108401Sambrisko				/* Read NIC frame header */
1034175445Sambrisko				bcopy(buf, (caddr_t)&rx_frame,
1035108401Sambrisko				      sizeof(rx_frame));
1036108401Sambrisko#endif
1037108401Sambrisko#endif
1038108401Sambrisko				/* Check for insane frame length */
1039108401Sambrisko				len = an_rx_desc.an_len + 12;
1040108401Sambrisko				if (len > MCLBYTES) {
1041154393Srwatson					m_freem(m);
1042198987Sjhb					if_printf(ifp, "oversized packet "
1043108401Sambrisko					       "received (%d, %d)\n",
1044198987Sjhb					       len, MCLBYTES);
1045271849Sglebius					if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
1046108401Sambrisko					return;
1047108401Sambrisko				}
104883269Sbrooks
1049108401Sambrisko				m->m_pkthdr.len = m->m_len =
1050108401Sambrisko					an_rx_desc.an_len + 12;
1051175445Sambrisko
1052108401Sambrisko				eh = mtod(m, struct ether_header *);
1053175445Sambrisko
1054108401Sambrisko				bcopy(buf, (char *)eh,
1055108401Sambrisko				      m->m_pkthdr.len);
1056175445Sambrisko
1057271849Sglebius				if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
1058175445Sambrisko
1059108401Sambrisko				/* Receive packet. */
1060108401Sambrisko#if 0
106155992Swpaul#ifdef ANCACHE
1062175445Sambrisko				an_cache_store(sc, eh, m,
1063110253Sambrisko					rx_frame.an_rx_signal_strength,
1064110253Sambrisko					rx_frame.an_rsvd0);
106555992Swpaul#endif
1066108401Sambrisko#endif
1067171775Savatar				AN_UNLOCK(sc);
1068108401Sambrisko				(*ifp->if_input)(ifp, m);
1069171775Savatar				AN_LOCK(sc);
1070171775Savatar
1071108401Sambrisko				an_rx_desc.an_valid = 1;
1072108401Sambrisko				an_rx_desc.an_len = AN_RX_BUFFER_SIZE;
1073108401Sambrisko				an_rx_desc.an_done = 0;
1074175445Sambrisko				an_rx_desc.an_phys =
1075108401Sambrisko					sc->an_rx_buffer[count].an_dma_paddr;
1076175445Sambrisko
1077108401Sambrisko				for (i = 0; i < sizeof(an_rx_desc) / 4; i++)
1078175445Sambrisko					CSR_MEM_AUX_WRITE_4(sc,
1079175445Sambrisko					    AN_RX_DESC_OFFSET
1080155321Simp					    + (count * sizeof(an_rx_desc))
1081155321Simp					    + (i * 4),
1082155321Simp					    ((u_int32_t *)(void *)&an_rx_desc)[i]);
1083175445Sambrisko
1084108401Sambrisko			} else {
1085198987Sjhb				if_printf(ifp, "Didn't get valid RX packet "
1086108401Sambrisko				       "%x %x %d\n",
1087108401Sambrisko				       an_rx_desc.an_done,
1088108401Sambrisko				       an_rx_desc.an_valid, an_rx_desc.an_len);
1089108401Sambrisko			}
1090108401Sambrisko		}
109183269Sbrooks	}
109255992Swpaul}
109355992Swpaul
109483270Sbrooksstatic void
1095150446Simpan_txeof(struct an_softc *sc, int status)
109655992Swpaul{
109755992Swpaul	struct ifnet		*ifp;
109878639Sbrooks	int			id, i;
109955992Swpaul
1100175445Sambrisko	AN_LOCK_ASSERT(sc);
1101147256Sbrooks	ifp = sc->an_ifp;
110255992Swpaul
1103199154Sjhb	sc->an_timer = 0;
1104148887Srwatson	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
110555992Swpaul
1106108401Sambrisko	if (!sc->mpi350) {
1107119156Sambrisko		id = CSR_READ_2(sc, AN_TX_CMP_FID(sc->mpi350));
110855992Swpaul
1109108401Sambrisko		if (status & AN_EV_TX_EXC) {
1110271849Sglebius			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
1111108401Sambrisko		} else
1112271849Sglebius			if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
111355992Swpaul
1114108401Sambrisko		for (i = 0; i < AN_TX_RING_CNT; i++) {
1115108401Sambrisko			if (id == sc->an_rdata.an_tx_ring[i]) {
1116108401Sambrisko				sc->an_rdata.an_tx_ring[i] = 0;
1117108401Sambrisko				break;
1118108401Sambrisko			}
111978639Sbrooks		}
1120108401Sambrisko
1121108401Sambrisko		AN_INC(sc->an_rdata.an_tx_cons, AN_TX_RING_CNT);
1122108401Sambrisko	} else { /* MPI 350 */
1123119156Sambrisko		id = CSR_READ_2(sc, AN_TX_CMP_FID(sc->mpi350));
1124119156Sambrisko		if (!sc->an_rdata.an_tx_empty){
1125119156Sambrisko			if (status & AN_EV_TX_EXC) {
1126271849Sglebius				if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
1127119156Sambrisko			} else
1128271849Sglebius				if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
1129119156Sambrisko			AN_INC(sc->an_rdata.an_tx_cons, AN_MAX_TX_DESC);
1130119156Sambrisko			if (sc->an_rdata.an_tx_prod ==
1131119156Sambrisko			    sc->an_rdata.an_tx_cons)
1132119156Sambrisko				sc->an_rdata.an_tx_empty = 1;
1133119156Sambrisko		}
113478639Sbrooks	}
113555992Swpaul
113655992Swpaul	return;
113755992Swpaul}
113855992Swpaul
113955992Swpaul/*
114055992Swpaul * We abuse the stats updater to check the current NIC status. This
114155992Swpaul * is important because we don't want to allow transmissions until
114255992Swpaul * the NIC has synchronized to the current cell (either as the master
114355992Swpaul * in an ad-hoc group, or as a station connected to an access point).
1144173668Savatar *
1145173668Savatar * Note that this function will be called via callout(9) with a lock held.
114655992Swpaul */
1147104094Sphkstatic void
1148150446Simpan_stats_update(void *xsc)
114955992Swpaul{
115055992Swpaul	struct an_softc		*sc;
115155992Swpaul	struct ifnet		*ifp;
115255992Swpaul
115355992Swpaul	sc = xsc;
1154173668Savatar	AN_LOCK_ASSERT(sc);
1155147256Sbrooks	ifp = sc->an_ifp;
1156199154Sjhb	if (sc->an_timer > 0 && --sc->an_timer == 0)
1157199154Sjhb		an_watchdog(sc);
115855992Swpaul
115955992Swpaul	sc->an_status.an_type = AN_RID_STATUS;
116055992Swpaul	sc->an_status.an_len = sizeof(struct an_ltv_status);
1161173668Savatar	if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_status))
1162173668Savatar		return;
116355992Swpaul
116455992Swpaul	if (sc->an_status.an_opmode & AN_STATUS_OPMODE_IN_SYNC)
116555992Swpaul		sc->an_associated = 1;
116655992Swpaul	else
116755992Swpaul		sc->an_associated = 0;
116855992Swpaul
116955992Swpaul	/* Don't do this while we're transmitting */
1170148887Srwatson	if (ifp->if_drv_flags & IFF_DRV_OACTIVE) {
1171173668Savatar		callout_reset(&sc->an_stat_ch, hz, an_stats_update, sc);
117255992Swpaul		return;
117355992Swpaul	}
117455992Swpaul
117555992Swpaul	sc->an_stats.an_len = sizeof(struct an_ltv_stats);
117655992Swpaul	sc->an_stats.an_type = AN_RID_32BITS_CUM;
1177173668Savatar	if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_stats.an_len))
1178173668Savatar		return;
117955992Swpaul
1180173668Savatar	callout_reset(&sc->an_stat_ch, hz, an_stats_update, sc);
118155992Swpaul
118255992Swpaul	return;
118355992Swpaul}
118455992Swpaul
118583270Sbrooksvoid
1186150446Simpan_intr(void *xsc)
118755992Swpaul{
118855992Swpaul	struct an_softc		*sc;
118955992Swpaul	struct ifnet		*ifp;
119055992Swpaul	u_int16_t		status;
119155992Swpaul
119255992Swpaul	sc = (struct an_softc*)xsc;
119355992Swpaul
119467094Swpaul	AN_LOCK(sc);
119567094Swpaul
119667094Swpaul	if (sc->an_gone) {
119767094Swpaul		AN_UNLOCK(sc);
119855992Swpaul		return;
119967094Swpaul	}
120055992Swpaul
1201147256Sbrooks	ifp = sc->an_ifp;
120255992Swpaul
120355992Swpaul	/* Disable interrupts. */
1204108401Sambrisko	CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), 0);
120555992Swpaul
1206108401Sambrisko	status = CSR_READ_2(sc, AN_EVENT_STAT(sc->mpi350));
1207119156Sambrisko	CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), ~AN_INTRS(sc->mpi350));
120855992Swpaul
1209119156Sambrisko	if (status & AN_EV_MIC) {
1210119156Sambrisko		CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_MIC);
121155992Swpaul	}
121255992Swpaul
121355992Swpaul	if (status & AN_EV_LINKSTAT) {
1214175445Sambrisko		if (CSR_READ_2(sc, AN_LINKSTAT(sc->mpi350))
1215108401Sambrisko		    == AN_LINKSTAT_ASSOCIATED)
121655992Swpaul			sc->an_associated = 1;
121755992Swpaul		else
121855992Swpaul			sc->an_associated = 0;
1219108401Sambrisko		CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_LINKSTAT);
122055992Swpaul	}
122155992Swpaul
122255992Swpaul	if (status & AN_EV_RX) {
122355992Swpaul		an_rxeof(sc);
1224108401Sambrisko		CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_RX);
122555992Swpaul	}
122655992Swpaul
1227119156Sambrisko	if (sc->mpi350 && status & AN_EV_TX_CPY) {
1228119156Sambrisko		an_txeof(sc, status);
1229150446Simp		CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_TX_CPY);
1230119156Sambrisko	}
1231119156Sambrisko
123255992Swpaul	if (status & AN_EV_TX) {
123355992Swpaul		an_txeof(sc, status);
1234150446Simp		CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_TX);
123555992Swpaul	}
123655992Swpaul
123755992Swpaul	if (status & AN_EV_TX_EXC) {
123855992Swpaul		an_txeof(sc, status);
1239108401Sambrisko		CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_TX_EXC);
124055992Swpaul	}
124155992Swpaul
124255992Swpaul	if (status & AN_EV_ALLOC)
1243108401Sambrisko		CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_ALLOC);
124455992Swpaul
124555992Swpaul	/* Re-enable interrupts. */
1246119156Sambrisko	CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), AN_INTRS(sc->mpi350));
124755992Swpaul
1248132986Smlaier	if ((ifp->if_flags & IFF_UP) && !IFQ_DRV_IS_EMPTY(&ifp->if_snd))
1249199154Sjhb		an_start_locked(ifp);
125055992Swpaul
125167094Swpaul	AN_UNLOCK(sc);
125267094Swpaul
125355992Swpaul	return;
125455992Swpaul}
125555992Swpaul
1256108401Sambrisko
125783270Sbrooksstatic int
1258150446Simpan_cmd_struct(struct an_softc *sc, struct an_command *cmd,
1259150446Simp    struct an_reply *reply)
1260108401Sambrisko{
1261108401Sambrisko	int			i;
1262108401Sambrisko
1263175445Sambrisko	AN_LOCK_ASSERT(sc);
1264108401Sambrisko	for (i = 0; i != AN_TIMEOUT; i++) {
1265108401Sambrisko		if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350)) & AN_CMD_BUSY) {
1266110531Sambrisko			DELAY(1000);
1267110104Sambrisko		} else
1268108401Sambrisko			break;
1269108401Sambrisko	}
1270119156Sambrisko
1271108401Sambrisko	if( i == AN_TIMEOUT) {
1272108401Sambrisko		printf("BUSY\n");
1273108401Sambrisko		return(ETIMEDOUT);
1274108401Sambrisko	}
1275108401Sambrisko
1276108401Sambrisko	CSR_WRITE_2(sc, AN_PARAM0(sc->mpi350), cmd->an_parm0);
1277108401Sambrisko	CSR_WRITE_2(sc, AN_PARAM1(sc->mpi350), cmd->an_parm1);
1278108401Sambrisko	CSR_WRITE_2(sc, AN_PARAM2(sc->mpi350), cmd->an_parm2);
1279108401Sambrisko	CSR_WRITE_2(sc, AN_COMMAND(sc->mpi350), cmd->an_cmd);
1280108401Sambrisko
1281108401Sambrisko	for (i = 0; i < AN_TIMEOUT; i++) {
1282108401Sambrisko		if (CSR_READ_2(sc, AN_EVENT_STAT(sc->mpi350)) & AN_EV_CMD)
1283108401Sambrisko			break;
1284110531Sambrisko		DELAY(1000);
1285108401Sambrisko	}
1286108401Sambrisko
1287108401Sambrisko	reply->an_resp0 = CSR_READ_2(sc, AN_RESP0(sc->mpi350));
1288108401Sambrisko	reply->an_resp1 = CSR_READ_2(sc, AN_RESP1(sc->mpi350));
1289108401Sambrisko	reply->an_resp2 = CSR_READ_2(sc, AN_RESP2(sc->mpi350));
1290108401Sambrisko	reply->an_status = CSR_READ_2(sc, AN_STATUS(sc->mpi350));
1291108401Sambrisko
1292108401Sambrisko	if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350)) & AN_CMD_BUSY)
1293175445Sambrisko		CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350),
1294119156Sambrisko		    AN_EV_CLR_STUCK_BUSY);
1295108401Sambrisko
1296108401Sambrisko	/* Ack the command */
1297108401Sambrisko	CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_CMD);
1298108401Sambrisko
1299108401Sambrisko	if (i == AN_TIMEOUT)
1300108401Sambrisko		return(ETIMEDOUT);
1301108401Sambrisko
1302108401Sambrisko	return(0);
1303108401Sambrisko}
1304108401Sambrisko
1305108401Sambriskostatic int
1306150446Simpan_cmd(struct an_softc *sc, int cmd, int val)
130755992Swpaul{
130855992Swpaul	int			i, s = 0;
130955992Swpaul
1310175445Sambrisko	AN_LOCK_ASSERT(sc);
1311108401Sambrisko	CSR_WRITE_2(sc, AN_PARAM0(sc->mpi350), val);
1312108401Sambrisko	CSR_WRITE_2(sc, AN_PARAM1(sc->mpi350), 0);
1313108401Sambrisko	CSR_WRITE_2(sc, AN_PARAM2(sc->mpi350), 0);
1314108401Sambrisko	CSR_WRITE_2(sc, AN_COMMAND(sc->mpi350), cmd);
131555992Swpaul
131655992Swpaul	for (i = 0; i < AN_TIMEOUT; i++) {
1317108401Sambrisko		if (CSR_READ_2(sc, AN_EVENT_STAT(sc->mpi350)) & AN_EV_CMD)
131855992Swpaul			break;
131955992Swpaul		else {
1320108401Sambrisko			if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350)) == cmd)
1321108401Sambrisko				CSR_WRITE_2(sc, AN_COMMAND(sc->mpi350), cmd);
132255992Swpaul		}
132355992Swpaul	}
132455992Swpaul
132555992Swpaul	for (i = 0; i < AN_TIMEOUT; i++) {
1326108401Sambrisko		CSR_READ_2(sc, AN_RESP0(sc->mpi350));
1327108401Sambrisko		CSR_READ_2(sc, AN_RESP1(sc->mpi350));
1328108401Sambrisko		CSR_READ_2(sc, AN_RESP2(sc->mpi350));
1329108401Sambrisko		s = CSR_READ_2(sc, AN_STATUS(sc->mpi350));
133055992Swpaul		if ((s & AN_STAT_CMD_CODE) == (cmd & AN_STAT_CMD_CODE))
133155992Swpaul			break;
133255992Swpaul	}
133355992Swpaul
133455992Swpaul	/* Ack the command */
1335108401Sambrisko	CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_CMD);
133655992Swpaul
1337108401Sambrisko	if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350)) & AN_CMD_BUSY)
1338108401Sambrisko		CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_CLR_STUCK_BUSY);
133955992Swpaul
134055992Swpaul	if (i == AN_TIMEOUT)
134155992Swpaul		return(ETIMEDOUT);
134255992Swpaul
134355992Swpaul	return(0);
134455992Swpaul}
134555992Swpaul
134655992Swpaul/*
134755992Swpaul * This reset sequence may look a little strange, but this is the
134855992Swpaul * most reliable method I've found to really kick the NIC in the
134955992Swpaul * head and force it to reboot correctly.
135055992Swpaul */
135183270Sbrooksstatic void
1352150446Simpan_reset(struct an_softc *sc)
135355992Swpaul{
135455992Swpaul	if (sc->an_gone)
135555992Swpaul		return;
135683270Sbrooks
1357175445Sambrisko	AN_LOCK_ASSERT(sc);
135855992Swpaul	an_cmd(sc, AN_CMD_ENABLE, 0);
135955992Swpaul	an_cmd(sc, AN_CMD_FW_RESTART, 0);
136055992Swpaul	an_cmd(sc, AN_CMD_NOOP2, 0);
136155992Swpaul
136255992Swpaul	if (an_cmd(sc, AN_CMD_FORCE_SYNCLOSS, 0) == ETIMEDOUT)
1363259393Sgavin		device_printf(sc->an_dev, "reset failed\n");
136455992Swpaul
136555992Swpaul	an_cmd(sc, AN_CMD_DISABLE, 0);
136655992Swpaul
136755992Swpaul	return;
136855992Swpaul}
136955992Swpaul
137055992Swpaul/*
137155992Swpaul * Read an LTV record from the NIC.
137255992Swpaul */
137383270Sbrooksstatic int
1374150446Simpan_read_record(struct an_softc *sc, struct an_ltv_gen *ltv)
137555992Swpaul{
1376108401Sambrisko	struct an_ltv_gen	*an_ltv;
1377108401Sambrisko	struct an_card_rid_desc an_rid_desc;
1378108401Sambrisko	struct an_command	cmd;
1379108401Sambrisko	struct an_reply		reply;
1380198987Sjhb	struct ifnet		*ifp;
138155992Swpaul	u_int16_t		*ptr;
138278639Sbrooks	u_int8_t		*ptr2;
138355992Swpaul	int			i, len;
138455992Swpaul
1385175445Sambrisko	AN_LOCK_ASSERT(sc);
138678639Sbrooks	if (ltv->an_len < 4 || ltv->an_type == 0)
138755992Swpaul		return(EINVAL);
138855992Swpaul
1389198987Sjhb	ifp = sc->an_ifp;
1390108401Sambrisko	if (!sc->mpi350){
1391108401Sambrisko		/* Tell the NIC to enter record read mode. */
1392108401Sambrisko		if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_READ, ltv->an_type)) {
1393198987Sjhb			if_printf(ifp, "RID access failed\n");
1394108401Sambrisko			return(EIO);
1395108401Sambrisko		}
139655992Swpaul
1397108401Sambrisko		/* Seek to the record. */
1398108401Sambrisko		if (an_seek(sc, ltv->an_type, 0, AN_BAP1)) {
1399198987Sjhb			if_printf(ifp, "seek to record failed\n");
1400108401Sambrisko			return(EIO);
1401108401Sambrisko		}
140255992Swpaul
1403108401Sambrisko		/*
1404108401Sambrisko		 * Read the length and record type and make sure they
1405108401Sambrisko		 * match what we expect (this verifies that we have enough
1406108401Sambrisko		 * room to hold all of the returned data).
1407108401Sambrisko		 * Length includes type but not length.
1408108401Sambrisko		 */
1409108401Sambrisko		len = CSR_READ_2(sc, AN_DATA1);
1410108401Sambrisko		if (len > (ltv->an_len - 2)) {
1411198987Sjhb			if_printf(ifp, "record length mismatch -- expected %d, "
1412198987Sjhb			       "got %d for Rid %x\n",
1413108401Sambrisko			       ltv->an_len - 2, len, ltv->an_type);
1414108401Sambrisko			len = ltv->an_len - 2;
1415108401Sambrisko		} else {
1416108401Sambrisko			ltv->an_len = len + 2;
1417108401Sambrisko		}
1418108401Sambrisko
1419108401Sambrisko		/* Now read the data. */
1420108401Sambrisko		len -= 2;	/* skip the type */
1421108401Sambrisko		ptr = &ltv->an_val;
1422108401Sambrisko		for (i = len; i > 1; i -= 2)
1423108401Sambrisko			*ptr++ = CSR_READ_2(sc, AN_DATA1);
1424108401Sambrisko		if (i) {
1425108401Sambrisko			ptr2 = (u_int8_t *)ptr;
1426108401Sambrisko			*ptr2 = CSR_READ_1(sc, AN_DATA1);
1427108401Sambrisko		}
1428108401Sambrisko	} else { /* MPI-350 */
1429123978Sambrisko		if (!sc->an_rid_buffer.an_dma_vaddr)
1430123978Sambrisko			return(EIO);
1431108401Sambrisko		an_rid_desc.an_valid = 1;
1432108401Sambrisko		an_rid_desc.an_len = AN_RID_BUFFER_SIZE;
1433108401Sambrisko		an_rid_desc.an_rid = 0;
1434108401Sambrisko		an_rid_desc.an_phys = sc->an_rid_buffer.an_dma_paddr;
1435108401Sambrisko		bzero(sc->an_rid_buffer.an_dma_vaddr, AN_RID_BUFFER_SIZE);
1436108401Sambrisko
1437108401Sambrisko		bzero(&cmd, sizeof(cmd));
1438108401Sambrisko		bzero(&reply, sizeof(reply));
1439108401Sambrisko		cmd.an_cmd = AN_CMD_ACCESS|AN_ACCESS_READ;
1440108401Sambrisko		cmd.an_parm0 = ltv->an_type;
1441108401Sambrisko
1442108401Sambrisko		for (i = 0; i < sizeof(an_rid_desc) / 4; i++)
1443175445Sambrisko			CSR_MEM_AUX_WRITE_4(sc, AN_HOST_DESC_OFFSET + i * 4,
1444155321Simp			    ((u_int32_t *)(void *)&an_rid_desc)[i]);
1445108401Sambrisko
1446108401Sambrisko		if (an_cmd_struct(sc, &cmd, &reply)
1447108401Sambrisko		    || reply.an_status & AN_CMD_QUAL_MASK) {
1448198987Sjhb			if_printf(ifp, "failed to read RID %x %x %x %x %x, %d\n",
1449198987Sjhb			       ltv->an_type,
1450108401Sambrisko			       reply.an_status,
1451108401Sambrisko			       reply.an_resp0,
1452108401Sambrisko			       reply.an_resp1,
1453108401Sambrisko			       reply.an_resp2,
1454108401Sambrisko			       i);
1455108401Sambrisko			return(EIO);
1456108401Sambrisko		}
1457108401Sambrisko
1458108401Sambrisko		an_ltv = (struct an_ltv_gen *)sc->an_rid_buffer.an_dma_vaddr;
1459108401Sambrisko		if (an_ltv->an_len + 2 < an_rid_desc.an_len) {
1460108401Sambrisko			an_rid_desc.an_len = an_ltv->an_len;
1461108401Sambrisko		}
1462108401Sambrisko
1463123978Sambrisko		len = an_rid_desc.an_len;
1464123978Sambrisko		if (len > (ltv->an_len - 2)) {
1465198987Sjhb			if_printf(ifp, "record length mismatch -- expected %d, "
1466198987Sjhb			       "got %d for Rid %x\n",
1467123978Sambrisko			       ltv->an_len - 2, len, ltv->an_type);
1468123978Sambrisko			len = ltv->an_len - 2;
1469123978Sambrisko		} else {
1470123978Sambrisko			ltv->an_len = len + 2;
1471123978Sambrisko		}
1472123978Sambrisko		bcopy(&an_ltv->an_type,
1473175445Sambrisko		    &ltv->an_val,
1474123978Sambrisko		    len);
147555992Swpaul	}
147655992Swpaul
147778639Sbrooks	if (an_dump)
147878639Sbrooks		an_dump_record(sc, ltv, "Read");
147955992Swpaul
148055992Swpaul	return(0);
148155992Swpaul}
148255992Swpaul
148355992Swpaul/*
148455992Swpaul * Same as read, except we inject data instead of reading it.
148555992Swpaul */
148683270Sbrooksstatic int
1487150446Simpan_write_record(struct an_softc *sc, struct an_ltv_gen *ltv)
148855992Swpaul{
1489108401Sambrisko	struct an_card_rid_desc an_rid_desc;
1490108401Sambrisko	struct an_command	cmd;
1491108401Sambrisko	struct an_reply		reply;
149255992Swpaul	u_int16_t		*ptr;
149378639Sbrooks	u_int8_t		*ptr2;
149478639Sbrooks	int			i, len;
149555992Swpaul
1496175445Sambrisko	AN_LOCK_ASSERT(sc);
149778639Sbrooks	if (an_dump)
149878639Sbrooks		an_dump_record(sc, ltv, "Write");
149978639Sbrooks
1500108401Sambrisko	if (!sc->mpi350){
1501108401Sambrisko		if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_READ, ltv->an_type))
1502108401Sambrisko			return(EIO);
150383270Sbrooks
1504108401Sambrisko		if (an_seek(sc, ltv->an_type, 0, AN_BAP1))
1505108401Sambrisko			return(EIO);
1506108401Sambrisko
1507108401Sambrisko		/*
1508108401Sambrisko		 * Length includes type but not length.
1509108401Sambrisko		 */
1510108401Sambrisko		len = ltv->an_len - 2;
1511108401Sambrisko		CSR_WRITE_2(sc, AN_DATA1, len);
1512108401Sambrisko
1513108401Sambrisko		len -= 2;	/* skip the type */
1514108401Sambrisko		ptr = &ltv->an_val;
1515108401Sambrisko		for (i = len; i > 1; i -= 2)
1516108401Sambrisko			CSR_WRITE_2(sc, AN_DATA1, *ptr++);
1517108401Sambrisko		if (i) {
1518108401Sambrisko			ptr2 = (u_int8_t *)ptr;
1519108401Sambrisko			CSR_WRITE_1(sc, AN_DATA0, *ptr2);
1520108401Sambrisko		}
1521108401Sambrisko
1522108401Sambrisko		if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_WRITE, ltv->an_type))
1523108401Sambrisko			return(EIO);
1524175445Sambrisko	} else {
1525110104Sambrisko		/* MPI-350 */
1526108401Sambrisko
1527108401Sambrisko		for (i = 0; i != AN_TIMEOUT; i++) {
1528175445Sambrisko			if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350))
1529110104Sambrisko			    & AN_CMD_BUSY) {
1530108401Sambrisko				DELAY(10);
1531110104Sambrisko			} else
1532108401Sambrisko				break;
1533108401Sambrisko		}
1534108401Sambrisko		if (i == AN_TIMEOUT) {
1535108401Sambrisko			printf("BUSY\n");
1536108401Sambrisko		}
1537108401Sambrisko
1538108401Sambrisko		an_rid_desc.an_valid = 1;
1539108401Sambrisko		an_rid_desc.an_len = ltv->an_len - 2;
1540108401Sambrisko		an_rid_desc.an_rid = ltv->an_type;
1541108401Sambrisko		an_rid_desc.an_phys = sc->an_rid_buffer.an_dma_paddr;
1542108401Sambrisko
1543108401Sambrisko		bcopy(&ltv->an_type, sc->an_rid_buffer.an_dma_vaddr,
1544108401Sambrisko		      an_rid_desc.an_len);
1545108401Sambrisko
1546108401Sambrisko		bzero(&cmd,sizeof(cmd));
1547108401Sambrisko		bzero(&reply,sizeof(reply));
1548108401Sambrisko		cmd.an_cmd = AN_CMD_ACCESS|AN_ACCESS_WRITE;
1549108401Sambrisko		cmd.an_parm0 = ltv->an_type;
1550108401Sambrisko
1551108401Sambrisko		for (i = 0; i < sizeof(an_rid_desc) / 4; i++)
1552175445Sambrisko			CSR_MEM_AUX_WRITE_4(sc, AN_HOST_DESC_OFFSET + i * 4,
1553155321Simp			    ((u_int32_t *)(void *)&an_rid_desc)[i]);
1554108401Sambrisko
1555110531Sambrisko		DELAY(100000);
1556110531Sambrisko
1557108401Sambrisko		if ((i = an_cmd_struct(sc, &cmd, &reply))) {
1558198987Sjhb			if_printf(sc->an_ifp,
1559198987Sjhb			    "failed to write RID 1 %x %x %x %x %x, %d\n",
1560198987Sjhb			    ltv->an_type,
1561110104Sambrisko			    reply.an_status,
1562110104Sambrisko			    reply.an_resp0,
1563110104Sambrisko			    reply.an_resp1,
1564110104Sambrisko			    reply.an_resp2,
1565110104Sambrisko			    i);
1566110104Sambrisko			return(EIO);
1567108401Sambrisko		}
156855992Swpaul
156983270Sbrooks
1570108401Sambrisko		if (reply.an_status & AN_CMD_QUAL_MASK) {
1571198987Sjhb			if_printf(sc->an_ifp,
1572198987Sjhb			    "failed to write RID 2 %x %x %x %x %x, %d\n",
1573198987Sjhb			    ltv->an_type,
1574110104Sambrisko			    reply.an_status,
1575110104Sambrisko			    reply.an_resp0,
1576110104Sambrisko			    reply.an_resp1,
1577110104Sambrisko			    reply.an_resp2,
1578110104Sambrisko			    i);
1579108401Sambrisko			return(EIO);
1580108401Sambrisko		}
1581110531Sambrisko		DELAY(100000);
158278639Sbrooks	}
158355992Swpaul
158455992Swpaul	return(0);
158555992Swpaul}
158655992Swpaul
158783270Sbrooksstatic void
1588150446Simpan_dump_record(struct an_softc *sc, struct an_ltv_gen *ltv, char *string)
158978639Sbrooks{
159078639Sbrooks	u_int8_t		*ptr2;
159178639Sbrooks	int			len;
159278639Sbrooks	int			i;
159378639Sbrooks	int			count = 0;
159478639Sbrooks	char			buf[17], temp;
159578639Sbrooks
159678639Sbrooks	len = ltv->an_len - 4;
1597198987Sjhb	if_printf(sc->an_ifp, "RID %4x, Length %4d, Mode %s\n",
1598198987Sjhb		ltv->an_type, ltv->an_len - 4, string);
159978639Sbrooks
160078639Sbrooks	if (an_dump == 1 || (an_dump == ltv->an_type)) {
1601198987Sjhb		if_printf(sc->an_ifp, "\t");
160278639Sbrooks		bzero(buf,sizeof(buf));
160378639Sbrooks
160478639Sbrooks		ptr2 = (u_int8_t *)&ltv->an_val;
160578639Sbrooks		for (i = len; i > 0; i--) {
160678639Sbrooks			printf("%02x ", *ptr2);
160778639Sbrooks
160878639Sbrooks			temp = *ptr2++;
1609154866Snjl			if (isprint(temp))
161078639Sbrooks				buf[count] = temp;
161178639Sbrooks			else
161278639Sbrooks				buf[count] = '.';
161378639Sbrooks			if (++count == 16) {
161478639Sbrooks				count = 0;
161578639Sbrooks				printf("%s\n",buf);
1616198987Sjhb				if_printf(sc->an_ifp, "\t");
161778639Sbrooks				bzero(buf,sizeof(buf));
161878639Sbrooks			}
161978639Sbrooks		}
162078639Sbrooks		for (; count != 16; count++) {
162178639Sbrooks			printf("   ");
162278639Sbrooks		}
162378639Sbrooks		printf(" %s\n",buf);
162478639Sbrooks	}
162578639Sbrooks}
162678639Sbrooks
162783270Sbrooksstatic int
1628150446Simpan_seek(struct an_softc *sc, int id, int off, int chan)
162955992Swpaul{
163055992Swpaul	int			i;
163155992Swpaul	int			selreg, offreg;
163255992Swpaul
163355992Swpaul	switch (chan) {
163455992Swpaul	case AN_BAP0:
163555992Swpaul		selreg = AN_SEL0;
163655992Swpaul		offreg = AN_OFF0;
163755992Swpaul		break;
163855992Swpaul	case AN_BAP1:
163955992Swpaul		selreg = AN_SEL1;
164055992Swpaul		offreg = AN_OFF1;
164155992Swpaul		break;
164255992Swpaul	default:
1643198987Sjhb		if_printf(sc->an_ifp, "invalid data path: %x\n", chan);
164455992Swpaul		return(EIO);
164555992Swpaul	}
164655992Swpaul
164755992Swpaul	CSR_WRITE_2(sc, selreg, id);
164855992Swpaul	CSR_WRITE_2(sc, offreg, off);
164955992Swpaul
165055992Swpaul	for (i = 0; i < AN_TIMEOUT; i++) {
165155992Swpaul		if (!(CSR_READ_2(sc, offreg) & (AN_OFF_BUSY|AN_OFF_ERR)))
165255992Swpaul			break;
165355992Swpaul	}
165455992Swpaul
165555992Swpaul	if (i == AN_TIMEOUT)
165655992Swpaul		return(ETIMEDOUT);
165755992Swpaul
165855992Swpaul	return(0);
165955992Swpaul}
166055992Swpaul
166183270Sbrooksstatic int
1662150446Simpan_read_data(struct an_softc *sc, int id, int off, caddr_t buf, int len)
166355992Swpaul{
166455992Swpaul	int			i;
166555992Swpaul	u_int16_t		*ptr;
166655992Swpaul	u_int8_t		*ptr2;
166755992Swpaul
166855992Swpaul	if (off != -1) {
166955992Swpaul		if (an_seek(sc, id, off, AN_BAP1))
167055992Swpaul			return(EIO);
167155992Swpaul	}
167255992Swpaul
167355992Swpaul	ptr = (u_int16_t *)buf;
167478639Sbrooks	for (i = len; i > 1; i -= 2)
167578639Sbrooks		*ptr++ = CSR_READ_2(sc, AN_DATA1);
167678639Sbrooks	if (i) {
167778639Sbrooks		ptr2 = (u_int8_t *)ptr;
167878639Sbrooks		*ptr2 = CSR_READ_1(sc, AN_DATA1);
167955992Swpaul	}
168055992Swpaul
168155992Swpaul	return(0);
168255992Swpaul}
168355992Swpaul
168483270Sbrooksstatic int
1685150446Simpan_write_data(struct an_softc *sc, int id, int off, caddr_t buf, int len)
168655992Swpaul{
168755992Swpaul	int			i;
168855992Swpaul	u_int16_t		*ptr;
168955992Swpaul	u_int8_t		*ptr2;
169055992Swpaul
169155992Swpaul	if (off != -1) {
169255992Swpaul		if (an_seek(sc, id, off, AN_BAP0))
169355992Swpaul			return(EIO);
169455992Swpaul	}
169555992Swpaul
169655992Swpaul	ptr = (u_int16_t *)buf;
169778639Sbrooks	for (i = len; i > 1; i -= 2)
169878639Sbrooks		CSR_WRITE_2(sc, AN_DATA0, *ptr++);
169978639Sbrooks	if (i) {
1700175446Sambrisko		ptr2 = (u_int8_t *)ptr;
1701175446Sambrisko		CSR_WRITE_1(sc, AN_DATA0, *ptr2);
170255992Swpaul	}
170355992Swpaul
170455992Swpaul	return(0);
170555992Swpaul}
170655992Swpaul
170755992Swpaul/*
170855992Swpaul * Allocate a region of memory inside the NIC and zero
170955992Swpaul * it out.
171055992Swpaul */
171183270Sbrooksstatic int
1712150446Simpan_alloc_nicmem(struct an_softc *sc, int len, int *id)
171355992Swpaul{
171455992Swpaul	int			i;
171555992Swpaul
171655992Swpaul	if (an_cmd(sc, AN_CMD_ALLOC_MEM, len)) {
1717198987Sjhb		if_printf(sc->an_ifp, "failed to allocate %d bytes on NIC\n",
1718198987Sjhb		    len);
171955992Swpaul		return(ENOMEM);
172055992Swpaul	}
172155992Swpaul
172255992Swpaul	for (i = 0; i < AN_TIMEOUT; i++) {
1723108401Sambrisko		if (CSR_READ_2(sc, AN_EVENT_STAT(sc->mpi350)) & AN_EV_ALLOC)
172455992Swpaul			break;
172555992Swpaul	}
172655992Swpaul
172755992Swpaul	if (i == AN_TIMEOUT)
172855992Swpaul		return(ETIMEDOUT);
172955992Swpaul
1730108401Sambrisko	CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_ALLOC);
173155992Swpaul	*id = CSR_READ_2(sc, AN_ALLOC_FID);
173255992Swpaul
173355992Swpaul	if (an_seek(sc, *id, 0, AN_BAP0))
173455992Swpaul		return(EIO);
173555992Swpaul
173655992Swpaul	for (i = 0; i < len / 2; i++)
173755992Swpaul		CSR_WRITE_2(sc, AN_DATA0, 0);
173855992Swpaul
173955992Swpaul	return(0);
174055992Swpaul}
174155992Swpaul
174283270Sbrooksstatic void
1743150446Simpan_setdef(struct an_softc *sc, struct an_req *areq)
174455992Swpaul{
174555992Swpaul	struct ifnet		*ifp;
174655992Swpaul	struct an_ltv_genconfig	*cfg;
1747119156Sambrisko	struct an_ltv_ssidlist_new	*ssid;
174855992Swpaul	struct an_ltv_aplist	*ap;
174955992Swpaul	struct an_ltv_gen	*sp;
175055992Swpaul
1751147256Sbrooks	ifp = sc->an_ifp;
175255992Swpaul
1753175445Sambrisko	AN_LOCK_ASSERT(sc);
175455992Swpaul	switch (areq->an_type) {
175555992Swpaul	case AN_RID_GENCONFIG:
175655992Swpaul		cfg = (struct an_ltv_genconfig *)areq;
175755992Swpaul
1758152315Sru		bcopy((char *)&cfg->an_macaddr, IF_LLADDR(sc->an_ifp),
175955992Swpaul		    ETHER_ADDR_LEN);
176055992Swpaul
176155992Swpaul		bcopy((char *)cfg, (char *)&sc->an_config,
176255992Swpaul			sizeof(struct an_ltv_genconfig));
176355992Swpaul		break;
176455992Swpaul	case AN_RID_SSIDLIST:
1765119156Sambrisko		ssid = (struct an_ltv_ssidlist_new *)areq;
176655992Swpaul		bcopy((char *)ssid, (char *)&sc->an_ssidlist,
1767119156Sambrisko			sizeof(struct an_ltv_ssidlist_new));
176855992Swpaul		break;
176955992Swpaul	case AN_RID_APLIST:
177055992Swpaul		ap = (struct an_ltv_aplist *)areq;
177155992Swpaul		bcopy((char *)ap, (char *)&sc->an_aplist,
177255992Swpaul			sizeof(struct an_ltv_aplist));
177355992Swpaul		break;
177455992Swpaul	case AN_RID_TX_SPEED:
177555992Swpaul		sp = (struct an_ltv_gen *)areq;
177655992Swpaul		sc->an_tx_rate = sp->an_val;
1777110253Sambrisko
1778110253Sambrisko		/* Read the current configuration */
1779110253Sambrisko		sc->an_config.an_type = AN_RID_GENCONFIG;
1780110253Sambrisko		sc->an_config.an_len = sizeof(struct an_ltv_genconfig);
1781110253Sambrisko		an_read_record(sc, (struct an_ltv_gen *)&sc->an_config);
1782110253Sambrisko		cfg = &sc->an_config;
1783110253Sambrisko
1784110253Sambrisko		/* clear other rates and set the only one we want */
1785110253Sambrisko		bzero(cfg->an_rates, sizeof(cfg->an_rates));
1786110253Sambrisko		cfg->an_rates[0] = sc->an_tx_rate;
1787110253Sambrisko
1788110253Sambrisko		/* Save the new rate */
1789110253Sambrisko		sc->an_config.an_type = AN_RID_GENCONFIG;
1790110253Sambrisko		sc->an_config.an_len = sizeof(struct an_ltv_genconfig);
179155992Swpaul		break;
179268692Swpaul	case AN_RID_WEP_TEMP:
1793110531Sambrisko		/* Cache the temp keys */
1794175445Sambrisko		bcopy(areq,
1795175445Sambrisko		    &sc->an_temp_keys[((struct an_ltv_key *)areq)->kindex],
1796110531Sambrisko		    sizeof(struct an_ltv_key));
179768692Swpaul	case AN_RID_WEP_PERM:
179888748Sambrisko	case AN_RID_LEAPUSERNAME:
179988748Sambrisko	case AN_RID_LEAPPASSWORD:
1800199154Sjhb		an_init_locked(sc);
1801119156Sambrisko
180268692Swpaul		/* Disable the MAC. */
180368692Swpaul		an_cmd(sc, AN_CMD_DISABLE, 0);
180483270Sbrooks
180583269Sbrooks		/* Write the key */
180668692Swpaul		an_write_record(sc, (struct an_ltv_gen *)areq);
180783270Sbrooks
180883270Sbrooks		/* Turn the MAC back on. */
180968692Swpaul		an_cmd(sc, AN_CMD_ENABLE, 0);
181083270Sbrooks
181168692Swpaul		break;
181283269Sbrooks	case AN_RID_MONITOR_MODE:
181383269Sbrooks		cfg = (struct an_ltv_genconfig *)areq;
181483269Sbrooks		bpfdetach(ifp);
181583269Sbrooks		if (ng_ether_detach_p != NULL)
181683269Sbrooks			(*ng_ether_detach_p) (ifp);
181783269Sbrooks		sc->an_monitor = cfg->an_len;
181883269Sbrooks
181983270Sbrooks		if (sc->an_monitor & AN_MONITOR) {
182083270Sbrooks			if (sc->an_monitor & AN_MONITOR_AIRONET_HEADER) {
182183270Sbrooks				bpfattach(ifp, DLT_AIRONET_HEADER,
182283269Sbrooks					sizeof(struct ether_header));
182383269Sbrooks			} else {
182483270Sbrooks				bpfattach(ifp, DLT_IEEE802_11,
182583269Sbrooks					sizeof(struct ether_header));
182683269Sbrooks			}
182783269Sbrooks		} else {
182883270Sbrooks			bpfattach(ifp, DLT_EN10MB,
182983269Sbrooks				  sizeof(struct ether_header));
183083269Sbrooks			if (ng_ether_attach_p != NULL)
183183269Sbrooks				(*ng_ether_attach_p) (ifp);
183283269Sbrooks		}
183383269Sbrooks		break;
183455992Swpaul	default:
1835198987Sjhb		if_printf(ifp, "unknown RID: %x\n", areq->an_type);
183655992Swpaul		return;
183755992Swpaul	}
183855992Swpaul
183955992Swpaul
184055992Swpaul	/* Reinitialize the card. */
1841199154Sjhb	if (ifp->if_flags)
1842199154Sjhb		an_init_locked(sc);
184355992Swpaul
184455992Swpaul	return;
184555992Swpaul}
184655992Swpaul
184755992Swpaul/*
184883269Sbrooks * Derived from Linux driver to enable promiscious mode.
184955992Swpaul */
185083269Sbrooks
185183270Sbrooksstatic void
1852150446Simpan_promisc(struct an_softc *sc, int promisc)
185355992Swpaul{
1854175445Sambrisko	AN_LOCK_ASSERT(sc);
1855150446Simp	if (sc->an_was_monitor) {
185683269Sbrooks		an_reset(sc);
1857108401Sambrisko		if (sc->mpi350)
1858175445Sambrisko			an_init_mpi350_desc(sc);
1859150446Simp	}
1860199154Sjhb	if (sc->an_monitor || sc->an_was_monitor)
1861199154Sjhb		an_init_locked(sc);
186283269Sbrooks
186383269Sbrooks	sc->an_was_monitor = sc->an_monitor;
186474698Sarchie	an_cmd(sc, AN_CMD_SET_MODE, promisc ? 0xffff : 0);
186583270Sbrooks
186655992Swpaul	return;
186755992Swpaul}
186855992Swpaul
186983270Sbrooksstatic int
1870150446Simpan_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
187155992Swpaul{
187267094Swpaul	int			error = 0;
187377217Sphk	int			len;
1874119156Sambrisko	int			i, max;
187555992Swpaul	struct an_softc		*sc;
1876355934Smarkj	struct an_req		*areq;
187755992Swpaul	struct ifreq		*ifr;
187893593Sjhb	struct thread		*td = curthread;
187977217Sphk	struct ieee80211req	*ireq;
1880172112Savatar	struct ieee80211_channel	ch;
188177217Sphk	u_int8_t		tmpstr[IEEE80211_NWID_LEN*2];
188277217Sphk	u_int8_t		*tmpptr;
188377217Sphk	struct an_ltv_genconfig	*config;
188477217Sphk	struct an_ltv_key	*key;
188577217Sphk	struct an_ltv_status	*status;
1886119156Sambrisko	struct an_ltv_ssidlist_new	*ssids;
188788748Sambrisko	int			mode;
188888748Sambrisko	struct aironet_ioctl	l_ioctl;
188955992Swpaul
189055992Swpaul	sc = ifp->if_softc;
189155992Swpaul	ifr = (struct ifreq *)data;
189277217Sphk	ireq = (struct ieee80211req *)data;
189355992Swpaul
189488749Sambrisko	config = (struct an_ltv_genconfig *)&sc->areq;
189588749Sambrisko	key = (struct an_ltv_key *)&sc->areq;
189688749Sambrisko	status = (struct an_ltv_status *)&sc->areq;
1897119156Sambrisko	ssids = (struct an_ltv_ssidlist_new *)&sc->areq;
189877217Sphk
189964429Speter	if (sc->an_gone) {
190061816Sroberto		error = ENODEV;
190161816Sroberto		goto out;
190261816Sroberto	}
190355992Swpaul
190483270Sbrooks	switch (command) {
190555992Swpaul	case SIOCSIFFLAGS:
1906175445Sambrisko		AN_LOCK(sc);
190755992Swpaul		if (ifp->if_flags & IFF_UP) {
1908148887Srwatson			if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
190955992Swpaul			    ifp->if_flags & IFF_PROMISC &&
191055992Swpaul			    !(sc->an_if_flags & IFF_PROMISC)) {
191155992Swpaul				an_promisc(sc, 1);
1912148887Srwatson			} else if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
191355992Swpaul			    !(ifp->if_flags & IFF_PROMISC) &&
191455992Swpaul			    sc->an_if_flags & IFF_PROMISC) {
191555992Swpaul				an_promisc(sc, 0);
1916199154Sjhb			} else
1917199154Sjhb				an_init_locked(sc);
191855992Swpaul		} else {
1919199154Sjhb			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
192055992Swpaul				an_stop(sc);
192155992Swpaul		}
1922199154Sjhb		sc->an_if_flags = ifp->if_flags;
1923175445Sambrisko		AN_UNLOCK(sc);
192455992Swpaul		error = 0;
192555992Swpaul		break;
192677217Sphk	case SIOCSIFMEDIA:
192777217Sphk	case SIOCGIFMEDIA:
192877217Sphk		error = ifmedia_ioctl(ifp, ifr, &sc->an_ifmedia, command);
192977217Sphk		break;
193055992Swpaul	case SIOCADDMULTI:
193155992Swpaul	case SIOCDELMULTI:
193255992Swpaul		/* The Aironet has no multicast filter. */
193355992Swpaul		error = 0;
193455992Swpaul		break;
193555992Swpaul	case SIOCGAIRONET:
1936355934Smarkj		error = priv_check(td, PRIV_DRIVER);
1937355934Smarkj		if (error)
193855992Swpaul			break;
1939355934Smarkj		areq = malloc(sizeof(*areq), M_TEMP, M_WAITOK);
1940355934Smarkj		error = copyin(ifr_data_get_ptr(ifr), areq, sizeof(*areq));
1941355934Smarkj		if (error != 0) {
1942355934Smarkj			free(areq, M_TEMP);
1943355934Smarkj			break;
1944355934Smarkj		}
1945175445Sambrisko		AN_LOCK(sc);
1946355934Smarkj		memcpy(&sc->areq, areq, sizeof(sc->areq));
194755992Swpaul#ifdef ANCACHE
194888749Sambrisko		if (sc->areq.an_type == AN_RID_ZERO_CACHE) {
194955992Swpaul			sc->an_sigitems = sc->an_nextitem = 0;
1950355934Smarkj			free(areq, M_TEMP);
195155992Swpaul			break;
195288749Sambrisko		} else if (sc->areq.an_type == AN_RID_READ_CACHE) {
195388749Sambrisko			char *pt = (char *)&sc->areq.an_val;
195455992Swpaul			bcopy((char *)&sc->an_sigitems, (char *)pt,
195555992Swpaul			    sizeof(int));
195655992Swpaul			pt += sizeof(int);
195788749Sambrisko			sc->areq.an_len = sizeof(int) / 2;
195855992Swpaul			bcopy((char *)&sc->an_sigcache, (char *)pt,
195955992Swpaul			    sizeof(struct an_sigcache) * sc->an_sigitems);
196088749Sambrisko			sc->areq.an_len += ((sizeof(struct an_sigcache) *
196155992Swpaul			    sc->an_sigitems) / 2) + 1;
196255992Swpaul		} else
196355992Swpaul#endif
196488749Sambrisko		if (an_read_record(sc, (struct an_ltv_gen *)&sc->areq)) {
1965175445Sambrisko			AN_UNLOCK(sc);
1966355934Smarkj			free(areq, M_TEMP);
196755992Swpaul			error = EINVAL;
196855992Swpaul			break;
196955992Swpaul		}
1970355934Smarkj		memcpy(areq, &sc->areq, sizeof(*areq));
1971171692Savatar		AN_UNLOCK(sc);
1972355934Smarkj		error = copyout(areq, ifr_data_get_ptr(ifr), sizeof(*areq));
1973355934Smarkj		free(areq, M_TEMP);
197455992Swpaul		break;
197555992Swpaul	case SIOCSAIRONET:
1976164033Srwatson		if ((error = priv_check(td, PRIV_DRIVER)))
197764429Speter			goto out;
1978175445Sambrisko		AN_LOCK(sc);
1979332288Sbrooks		error = copyin(ifr_data_get_ptr(ifr), &sc->areq,
1980332288Sbrooks		    sizeof(sc->areq));
198178639Sbrooks		if (error != 0)
198255992Swpaul			break;
198388749Sambrisko		an_setdef(sc, &sc->areq);
1984175445Sambrisko		AN_UNLOCK(sc);
198555992Swpaul		break;
1986175446Sambrisko	case SIOCGPRIVATE_0:		/* used by Cisco client utility */
1987164033Srwatson		if ((error = priv_check(td, PRIV_DRIVER)))
198892292Sambrisko			goto out;
1989332288Sbrooks		error = copyin(ifr_data_get_ptr(ifr), &l_ioctl,
1990332288Sbrooks		    sizeof(l_ioctl));
1991144242Ssam		if (error)
1992144242Ssam			goto out;
199388748Sambrisko		mode = l_ioctl.command;
199488748Sambrisko
1995175445Sambrisko		AN_LOCK(sc);
199688748Sambrisko		if (mode >= AIROGCAP && mode <= AIROGSTATSD32) {
199788748Sambrisko			error = readrids(ifp, &l_ioctl);
1998110104Sambrisko		} else if (mode >= AIROPCAP && mode <= AIROPLEAPUSR) {
199988748Sambrisko			error = writerids(ifp, &l_ioctl);
2000110104Sambrisko		} else if (mode >= AIROFLSHRST && mode <= AIRORESTART) {
200188748Sambrisko			error = flashcard(ifp, &l_ioctl);
2002110104Sambrisko		} else {
200388748Sambrisko			error =-1;
200488748Sambrisko		}
2005175445Sambrisko		AN_UNLOCK(sc);
2006144242Ssam		if (!error) {
2007144242Ssam			/* copy out the updated command info */
2008332288Sbrooks			error = copyout(&l_ioctl, ifr_data_get_ptr(ifr),
2009332288Sbrooks			    sizeof(l_ioctl));
2010144242Ssam		}
201188748Sambrisko		break;
2012175446Sambrisko	case SIOCGPRIVATE_1:		/* used by Cisco client utility */
2013164033Srwatson		if ((error = priv_check(td, PRIV_DRIVER)))
201492292Sambrisko			goto out;
2015332288Sbrooks		error = copyin(ifr_data_get_ptr(ifr), &l_ioctl,
2016332288Sbrooks		    sizeof(l_ioctl));
2017144242Ssam		if (error)
2018144242Ssam			goto out;
201988748Sambrisko		l_ioctl.command = 0;
202088748Sambrisko		error = AIROMAGIC;
2021144242Ssam		(void) copyout(&error, l_ioctl.data, sizeof(error));
2022175446Sambrisko		error = 0;
202388748Sambrisko		break;
202477217Sphk	case SIOCG80211:
202588749Sambrisko		sc->areq.an_len = sizeof(sc->areq);
202688748Sambrisko		/* was that a good idea DJA we are doing a short-cut */
202783270Sbrooks		switch (ireq->i_type) {
202877217Sphk		case IEEE80211_IOC_SSID:
2029175445Sambrisko			AN_LOCK(sc);
203078639Sbrooks			if (ireq->i_val == -1) {
203188749Sambrisko				sc->areq.an_type = AN_RID_STATUS;
203277217Sphk				if (an_read_record(sc,
203388749Sambrisko				    (struct an_ltv_gen *)&sc->areq)) {
203477217Sphk					error = EINVAL;
2035175445Sambrisko					AN_UNLOCK(sc);
203677217Sphk					break;
203777217Sphk				}
203877217Sphk				len = status->an_ssidlen;
203977217Sphk				tmpptr = status->an_ssid;
204078639Sbrooks			} else if (ireq->i_val >= 0) {
204188749Sambrisko				sc->areq.an_type = AN_RID_SSIDLIST;
204277217Sphk				if (an_read_record(sc,
204388749Sambrisko				    (struct an_ltv_gen *)&sc->areq)) {
204477217Sphk					error = EINVAL;
2045175445Sambrisko					AN_UNLOCK(sc);
204677217Sphk					break;
204777217Sphk				}
2048119156Sambrisko				max = (sc->areq.an_len - 4)
2049119156Sambrisko				    / sizeof(struct an_ltv_ssid_entry);
2050119156Sambrisko				if ( max > MAX_SSIDS ) {
2051119156Sambrisko					printf("To many SSIDs only using "
2052119156Sambrisko					    "%d of %d\n",
2053119156Sambrisko					    MAX_SSIDS, max);
2054119156Sambrisko					max = MAX_SSIDS;
2055119156Sambrisko				}
2056119156Sambrisko				if (ireq->i_val > max) {
205777217Sphk					error = EINVAL;
2058175445Sambrisko					AN_UNLOCK(sc);
205977217Sphk					break;
2060119156Sambrisko				} else {
2061119156Sambrisko					len = ssids->an_entry[ireq->i_val].an_len;
2062119156Sambrisko					tmpptr = ssids->an_entry[ireq->i_val].an_ssid;
206377217Sphk				}
206477217Sphk			} else {
206577217Sphk				error = EINVAL;
2066175445Sambrisko				AN_UNLOCK(sc);
206777217Sphk				break;
206877217Sphk			}
206978639Sbrooks			if (len > IEEE80211_NWID_LEN) {
207077217Sphk				error = EINVAL;
2071175445Sambrisko				AN_UNLOCK(sc);
207277217Sphk				break;
207377217Sphk			}
2074175445Sambrisko			AN_UNLOCK(sc);
207577217Sphk			ireq->i_len = len;
207677217Sphk			bzero(tmpstr, IEEE80211_NWID_LEN);
207777217Sphk			bcopy(tmpptr, tmpstr, len);
207877217Sphk			error = copyout(tmpstr, ireq->i_data,
207977217Sphk			    IEEE80211_NWID_LEN);
208077217Sphk			break;
208177217Sphk		case IEEE80211_IOC_NUMSSIDS:
2082175445Sambrisko			AN_LOCK(sc);
2083119156Sambrisko			sc->areq.an_len = sizeof(sc->areq);
2084119156Sambrisko			sc->areq.an_type = AN_RID_SSIDLIST;
2085119156Sambrisko			if (an_read_record(sc,
2086119156Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
2087175445Sambrisko				AN_UNLOCK(sc);
2088119156Sambrisko				error = EINVAL;
2089119156Sambrisko				break;
2090119156Sambrisko			}
2091119156Sambrisko			max = (sc->areq.an_len - 4)
2092119156Sambrisko			    / sizeof(struct an_ltv_ssid_entry);
2093175445Sambrisko			AN_UNLOCK(sc);
2094119156Sambrisko			if ( max > MAX_SSIDS ) {
2095119156Sambrisko				printf("To many SSIDs only using "
2096119156Sambrisko				    "%d of %d\n",
2097119156Sambrisko				    MAX_SSIDS, max);
2098119156Sambrisko				max = MAX_SSIDS;
2099119156Sambrisko			}
2100119156Sambrisko			ireq->i_val = max;
210177217Sphk			break;
210277217Sphk		case IEEE80211_IOC_WEP:
2103175445Sambrisko			AN_LOCK(sc);
210488749Sambrisko			sc->areq.an_type = AN_RID_ACTUALCFG;
210577217Sphk			if (an_read_record(sc,
210688749Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
210777217Sphk				error = EINVAL;
2108175445Sambrisko				AN_UNLOCK(sc);
210977217Sphk				break;
211077217Sphk			}
2111175445Sambrisko			AN_UNLOCK(sc);
211278639Sbrooks			if (config->an_authtype & AN_AUTHTYPE_PRIVACY_IN_USE) {
211378639Sbrooks				if (config->an_authtype &
211477217Sphk				    AN_AUTHTYPE_ALLOW_UNENCRYPTED)
211577217Sphk					ireq->i_val = IEEE80211_WEP_MIXED;
211677217Sphk				else
211777217Sphk					ireq->i_val = IEEE80211_WEP_ON;
211877217Sphk			} else {
211977217Sphk				ireq->i_val = IEEE80211_WEP_OFF;
212077217Sphk			}
212177217Sphk			break;
212277217Sphk		case IEEE80211_IOC_WEPKEY:
212377217Sphk			/*
212477217Sphk			 * XXX: I'm not entierly convinced this is
212577217Sphk			 * correct, but it's what is implemented in
212677217Sphk			 * ancontrol so it will have to do until we get
212777217Sphk			 * access to actual Cisco code.
212877217Sphk			 */
212988748Sambrisko			if (ireq->i_val < 0 || ireq->i_val > 8) {
213077217Sphk				error = EINVAL;
213177217Sphk				break;
213277217Sphk			}
213377217Sphk			len = 0;
213488748Sambrisko			if (ireq->i_val < 5) {
2135175445Sambrisko				AN_LOCK(sc);
213688749Sambrisko				sc->areq.an_type = AN_RID_WEP_TEMP;
213778639Sbrooks				for (i = 0; i < 5; i++) {
213877217Sphk					if (an_read_record(sc,
213988749Sambrisko					    (struct an_ltv_gen *)&sc->areq)) {
214077217Sphk						error = EINVAL;
214177217Sphk						break;
214277217Sphk					}
214378639Sbrooks					if (key->kindex == 0xffff)
214477217Sphk						break;
214578639Sbrooks					if (key->kindex == ireq->i_val)
214678639Sbrooks						len = key->klen;
214777217Sphk					/* Required to get next entry */
214888749Sambrisko					sc->areq.an_type = AN_RID_WEP_PERM;
214977217Sphk				}
2150175445Sambrisko				AN_UNLOCK(sc);
2151175445Sambrisko				if (error != 0) {
215277217Sphk					break;
2153175445Sambrisko				}
215477217Sphk			}
215577217Sphk			/* We aren't allowed to read the value of the
215677217Sphk			 * key from the card so we just output zeros
215777217Sphk			 * like we would if we could read the card, but
215877217Sphk			 * denied the user access.
215977217Sphk			 */
216077217Sphk			bzero(tmpstr, len);
216177217Sphk			ireq->i_len = len;
216277217Sphk			error = copyout(tmpstr, ireq->i_data, len);
216377217Sphk			break;
216477217Sphk		case IEEE80211_IOC_NUMWEPKEYS:
216588748Sambrisko			ireq->i_val = 9; /* include home key */
216677217Sphk			break;
216777217Sphk		case IEEE80211_IOC_WEPTXKEY:
216878639Sbrooks			/*
216978639Sbrooks			 * For some strange reason, you have to read all
217078639Sbrooks			 * keys before you can read the txkey.
217178639Sbrooks			 */
2172175445Sambrisko			AN_LOCK(sc);
217388749Sambrisko			sc->areq.an_type = AN_RID_WEP_TEMP;
217478639Sbrooks			for (i = 0; i < 5; i++) {
217578639Sbrooks				if (an_read_record(sc,
217688749Sambrisko				    (struct an_ltv_gen *) &sc->areq)) {
217778639Sbrooks					error = EINVAL;
217878639Sbrooks					break;
217978639Sbrooks				}
2180175445Sambrisko				if (key->kindex == 0xffff) {
218178639Sbrooks					break;
2182175445Sambrisko				}
218378639Sbrooks				/* Required to get next entry */
218488749Sambrisko				sc->areq.an_type = AN_RID_WEP_PERM;
218578639Sbrooks			}
2186175445Sambrisko			if (error != 0) {
2187175445Sambrisko				AN_UNLOCK(sc);
218878639Sbrooks				break;
2189175445Sambrisko			}
219078639Sbrooks
219188749Sambrisko			sc->areq.an_type = AN_RID_WEP_PERM;
219277217Sphk			key->kindex = 0xffff;
219377217Sphk			if (an_read_record(sc,
219488749Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
219577217Sphk				error = EINVAL;
2196175445Sambrisko				AN_UNLOCK(sc);
219777217Sphk				break;
219877217Sphk			}
219977217Sphk			ireq->i_val = key->mac[0];
220088748Sambrisko			/*
220188748Sambrisko			 * Check for home mode.  Map home mode into
220288748Sambrisko			 * 5th key since that is how it is stored on
220388748Sambrisko			 * the card
220488748Sambrisko			 */
220588749Sambrisko			sc->areq.an_len  = sizeof(struct an_ltv_genconfig);
220688749Sambrisko			sc->areq.an_type = AN_RID_GENCONFIG;
220788748Sambrisko			if (an_read_record(sc,
220888749Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
220988748Sambrisko				error = EINVAL;
2210175445Sambrisko				AN_UNLOCK(sc);
221188748Sambrisko				break;
221288748Sambrisko			}
221388748Sambrisko			if (config->an_home_product & AN_HOME_NETWORK)
221488748Sambrisko				ireq->i_val = 4;
2215175445Sambrisko			AN_UNLOCK(sc);
221677217Sphk			break;
221777217Sphk		case IEEE80211_IOC_AUTHMODE:
2218175445Sambrisko			AN_LOCK(sc);
221988749Sambrisko			sc->areq.an_type = AN_RID_ACTUALCFG;
222077217Sphk			if (an_read_record(sc,
222188749Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
222277217Sphk				error = EINVAL;
2223175445Sambrisko				AN_UNLOCK(sc);
222477217Sphk				break;
222577217Sphk			}
2226175445Sambrisko			AN_UNLOCK(sc);
222777217Sphk			if ((config->an_authtype & AN_AUTHTYPE_MASK) ==
222877217Sphk			    AN_AUTHTYPE_NONE) {
222977217Sphk			    ireq->i_val = IEEE80211_AUTH_NONE;
223077217Sphk			} else if ((config->an_authtype & AN_AUTHTYPE_MASK) ==
223177217Sphk			    AN_AUTHTYPE_OPEN) {
223277217Sphk			    ireq->i_val = IEEE80211_AUTH_OPEN;
223377217Sphk			} else if ((config->an_authtype & AN_AUTHTYPE_MASK) ==
223477217Sphk			    AN_AUTHTYPE_SHAREDKEY) {
223577217Sphk			    ireq->i_val = IEEE80211_AUTH_SHARED;
223677217Sphk			} else
223777217Sphk				error = EINVAL;
223877217Sphk			break;
223977217Sphk		case IEEE80211_IOC_STATIONNAME:
2240175445Sambrisko			AN_LOCK(sc);
224188749Sambrisko			sc->areq.an_type = AN_RID_ACTUALCFG;
224277217Sphk			if (an_read_record(sc,
224388749Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
224477217Sphk				error = EINVAL;
2245175445Sambrisko				AN_UNLOCK(sc);
224677217Sphk				break;
224777217Sphk			}
2248175445Sambrisko			AN_UNLOCK(sc);
224977217Sphk			ireq->i_len = sizeof(config->an_nodename);
225077217Sphk			tmpptr = config->an_nodename;
225177217Sphk			bzero(tmpstr, IEEE80211_NWID_LEN);
225277217Sphk			bcopy(tmpptr, tmpstr, ireq->i_len);
225377217Sphk			error = copyout(tmpstr, ireq->i_data,
225477217Sphk			    IEEE80211_NWID_LEN);
225577217Sphk			break;
225677217Sphk		case IEEE80211_IOC_CHANNEL:
2257175445Sambrisko			AN_LOCK(sc);
225888749Sambrisko			sc->areq.an_type = AN_RID_STATUS;
225977217Sphk			if (an_read_record(sc,
226088749Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
226177217Sphk				error = EINVAL;
2262175445Sambrisko				AN_UNLOCK(sc);
226377217Sphk				break;
226477217Sphk			}
2265175445Sambrisko			AN_UNLOCK(sc);
226677217Sphk			ireq->i_val = status->an_cur_channel;
226777217Sphk			break;
2268175445Sambrisko		case IEEE80211_IOC_CURCHAN:
2269175445Sambrisko			AN_LOCK(sc);
2270175445Sambrisko			sc->areq.an_type = AN_RID_STATUS;
2271175445Sambrisko			if (an_read_record(sc,
2272175445Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
2273172112Savatar				error = EINVAL;
2274175445Sambrisko				AN_UNLOCK(sc);
2275172112Savatar				break;
2276172112Savatar			}
2277175445Sambrisko			AN_UNLOCK(sc);
2278172112Savatar			bzero(&ch, sizeof(ch));
2279172112Savatar			ch.ic_freq = ieee80211_ieee2mhz(status->an_cur_channel,
2280172112Savatar			    IEEE80211_CHAN_B);
2281172112Savatar			ch.ic_flags = IEEE80211_CHAN_B;
2282172112Savatar			ch.ic_ieee = status->an_cur_channel;
2283172112Savatar			error = copyout(&ch, ireq->i_data, sizeof(ch));
2284172112Savatar			break;
228577217Sphk		case IEEE80211_IOC_POWERSAVE:
2286175445Sambrisko			AN_LOCK(sc);
228788749Sambrisko			sc->areq.an_type = AN_RID_ACTUALCFG;
228877217Sphk			if (an_read_record(sc,
228988749Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
229077217Sphk				error = EINVAL;
2291175445Sambrisko				AN_UNLOCK(sc);
229277217Sphk				break;
229377217Sphk			}
2294175445Sambrisko			AN_UNLOCK(sc);
229578639Sbrooks			if (config->an_psave_mode == AN_PSAVE_NONE) {
229677217Sphk				ireq->i_val = IEEE80211_POWERSAVE_OFF;
229778639Sbrooks			} else if (config->an_psave_mode == AN_PSAVE_CAM) {
229877217Sphk				ireq->i_val = IEEE80211_POWERSAVE_CAM;
229978639Sbrooks			} else if (config->an_psave_mode == AN_PSAVE_PSP) {
230077217Sphk				ireq->i_val = IEEE80211_POWERSAVE_PSP;
230178639Sbrooks			} else if (config->an_psave_mode == AN_PSAVE_PSP_CAM) {
230277217Sphk				ireq->i_val = IEEE80211_POWERSAVE_PSP_CAM;
230377217Sphk			} else
230477217Sphk				error = EINVAL;
230577217Sphk			break;
230677217Sphk		case IEEE80211_IOC_POWERSAVESLEEP:
2307175445Sambrisko			AN_LOCK(sc);
230888749Sambrisko			sc->areq.an_type = AN_RID_ACTUALCFG;
230977217Sphk			if (an_read_record(sc,
231088749Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
231177217Sphk				error = EINVAL;
2312175445Sambrisko				AN_UNLOCK(sc);
231377217Sphk				break;
231477217Sphk			}
2315175445Sambrisko			AN_UNLOCK(sc);
231677217Sphk			ireq->i_val = config->an_listen_interval;
231777217Sphk			break;
231883270Sbrooks		}
231977217Sphk		break;
232077217Sphk	case SIOCS80211:
2321164033Srwatson		if ((error = priv_check(td, PRIV_NET80211_MANAGE)))
232277217Sphk			goto out;
2323175445Sambrisko		AN_LOCK(sc);
232488749Sambrisko		sc->areq.an_len = sizeof(sc->areq);
232577217Sphk		/*
232677217Sphk		 * We need a config structure for everything but the WEP
232777217Sphk		 * key management and SSIDs so we get it now so avoid
232877217Sphk		 * duplicating this code every time.
232977217Sphk		 */
233077217Sphk		if (ireq->i_type != IEEE80211_IOC_SSID &&
233177217Sphk		    ireq->i_type != IEEE80211_IOC_WEPKEY &&
233277217Sphk		    ireq->i_type != IEEE80211_IOC_WEPTXKEY) {
233388749Sambrisko			sc->areq.an_type = AN_RID_GENCONFIG;
233477217Sphk			if (an_read_record(sc,
233588749Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
233677217Sphk				error = EINVAL;
2337175445Sambrisko				AN_UNLOCK(sc);
233877217Sphk				break;
233977217Sphk			}
234077217Sphk		}
234183270Sbrooks		switch (ireq->i_type) {
234277217Sphk		case IEEE80211_IOC_SSID:
2343119156Sambrisko			sc->areq.an_len = sizeof(sc->areq);
234488749Sambrisko			sc->areq.an_type = AN_RID_SSIDLIST;
234577217Sphk			if (an_read_record(sc,
234688749Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
234777217Sphk				error = EINVAL;
2348175445Sambrisko				AN_UNLOCK(sc);
234977217Sphk				break;
235077217Sphk			}
235178639Sbrooks			if (ireq->i_len > IEEE80211_NWID_LEN) {
235277217Sphk				error = EINVAL;
2353175445Sambrisko				AN_UNLOCK(sc);
235477217Sphk				break;
235577217Sphk			}
2356119156Sambrisko			max = (sc->areq.an_len - 4)
2357119156Sambrisko			    / sizeof(struct an_ltv_ssid_entry);
2358119156Sambrisko			if ( max > MAX_SSIDS ) {
2359119156Sambrisko				printf("To many SSIDs only using "
2360119156Sambrisko				    "%d of %d\n",
2361119156Sambrisko				    MAX_SSIDS, max);
2362119156Sambrisko				max = MAX_SSIDS;
2363119156Sambrisko			}
2364119156Sambrisko			if (ireq->i_val > max) {
2365119156Sambrisko				error = EINVAL;
2366175445Sambrisko				AN_UNLOCK(sc);
236777217Sphk				break;
2368119156Sambrisko			} else {
236977217Sphk				error = copyin(ireq->i_data,
2370175445Sambrisko				    ssids->an_entry[ireq->i_val].an_ssid,
2371119156Sambrisko				    ireq->i_len);
2372175445Sambrisko				ssids->an_entry[ireq->i_val].an_len
2373119156Sambrisko				    = ireq->i_len;
2374175445Sambrisko				sc->areq.an_len = sizeof(sc->areq);
2375175445Sambrisko				sc->areq.an_type = AN_RID_SSIDLIST;
2376175445Sambrisko				an_setdef(sc, &sc->areq);
2377175445Sambrisko				AN_UNLOCK(sc);
237877217Sphk				break;
237977217Sphk			}
238077217Sphk			break;
238177217Sphk		case IEEE80211_IOC_WEP:
238277217Sphk			switch (ireq->i_val) {
238377217Sphk			case IEEE80211_WEP_OFF:
238477217Sphk				config->an_authtype &=
238577217Sphk				    ~(AN_AUTHTYPE_PRIVACY_IN_USE |
238677217Sphk				    AN_AUTHTYPE_ALLOW_UNENCRYPTED);
238777217Sphk				break;
238877217Sphk			case IEEE80211_WEP_ON:
238977217Sphk				config->an_authtype |=
239077217Sphk				    AN_AUTHTYPE_PRIVACY_IN_USE;
239177217Sphk				config->an_authtype &=
239277217Sphk				    ~AN_AUTHTYPE_ALLOW_UNENCRYPTED;
239377217Sphk				break;
239477217Sphk			case IEEE80211_WEP_MIXED:
239577217Sphk				config->an_authtype |=
239677217Sphk				    AN_AUTHTYPE_PRIVACY_IN_USE |
239777217Sphk				    AN_AUTHTYPE_ALLOW_UNENCRYPTED;
239877217Sphk				break;
239977217Sphk			default:
240077217Sphk				error = EINVAL;
240177217Sphk				break;
240277217Sphk			}
2403175445Sambrisko			if (error != EINVAL)
2404175445Sambrisko				an_setdef(sc, &sc->areq);
2405175445Sambrisko			AN_UNLOCK(sc);
240677217Sphk			break;
240777217Sphk		case IEEE80211_IOC_WEPKEY:
2408110531Sambrisko			if (ireq->i_val < 0 || ireq->i_val > 8 ||
240977217Sphk			    ireq->i_len > 13) {
241077217Sphk				error = EINVAL;
2411175445Sambrisko				AN_UNLOCK(sc);
241277217Sphk				break;
241377217Sphk			}
241477217Sphk			error = copyin(ireq->i_data, tmpstr, 13);
2415175445Sambrisko			if (error != 0) {
2416175445Sambrisko				AN_UNLOCK(sc);
241777217Sphk				break;
2418175445Sambrisko			}
2419110531Sambrisko			/*
2420110531Sambrisko			 * Map the 9th key into the home mode
2421110531Sambrisko			 * since that is how it is stored on
2422110531Sambrisko			 * the card
2423110531Sambrisko			 */
242488749Sambrisko			bzero(&sc->areq, sizeof(struct an_ltv_key));
242588749Sambrisko			sc->areq.an_len = sizeof(struct an_ltv_key);
242677217Sphk			key->mac[0] = 1;	/* The others are 0. */
2427110531Sambrisko			if (ireq->i_val < 4) {
242888749Sambrisko				sc->areq.an_type = AN_RID_WEP_TEMP;
2429110531Sambrisko				key->kindex = ireq->i_val;
2430110531Sambrisko			} else {
243188749Sambrisko				sc->areq.an_type = AN_RID_WEP_PERM;
2432110531Sambrisko				key->kindex = ireq->i_val - 4;
2433110531Sambrisko			}
243477217Sphk			key->klen = ireq->i_len;
243577217Sphk			bcopy(tmpstr, key->key, key->klen);
2436175445Sambrisko			an_setdef(sc, &sc->areq);
2437175445Sambrisko			AN_UNLOCK(sc);
243877217Sphk			break;
243977217Sphk		case IEEE80211_IOC_WEPTXKEY:
2440110531Sambrisko			if (ireq->i_val < 0 || ireq->i_val > 4) {
2441110531Sambrisko				error = EINVAL;
2442175445Sambrisko				AN_UNLOCK(sc);
2443110531Sambrisko				break;
2444110531Sambrisko			}
2445110531Sambrisko
244688748Sambrisko			/*
244788748Sambrisko			 * Map the 5th key into the home mode
244888748Sambrisko			 * since that is how it is stored on
244988748Sambrisko			 * the card
245088748Sambrisko			 */
245188749Sambrisko			sc->areq.an_len  = sizeof(struct an_ltv_genconfig);
245288749Sambrisko			sc->areq.an_type = AN_RID_ACTUALCFG;
245388748Sambrisko			if (an_read_record(sc,
2454175445Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
2455175445Sambrisko				error = EINVAL;
2456175445Sambrisko				AN_UNLOCK(sc);
245788748Sambrisko				break;
245888748Sambrisko			}
245988748Sambrisko			if (ireq->i_val ==  4) {
246088748Sambrisko				config->an_home_product |= AN_HOME_NETWORK;
246188748Sambrisko				ireq->i_val = 0;
246288748Sambrisko			} else {
246388748Sambrisko				config->an_home_product &= ~AN_HOME_NETWORK;
246488748Sambrisko			}
246588748Sambrisko
246688748Sambrisko			sc->an_config.an_home_product
246788748Sambrisko				= config->an_home_product;
246888748Sambrisko
2469110531Sambrisko			/* update configuration */
2470199154Sjhb			an_init_locked(sc);
2471110531Sambrisko
247288749Sambrisko			bzero(&sc->areq, sizeof(struct an_ltv_key));
247388749Sambrisko			sc->areq.an_len = sizeof(struct an_ltv_key);
247488749Sambrisko			sc->areq.an_type = AN_RID_WEP_PERM;
247577217Sphk			key->kindex = 0xffff;
247677217Sphk			key->mac[0] = ireq->i_val;
2477175445Sambrisko			an_setdef(sc, &sc->areq);
2478175445Sambrisko			AN_UNLOCK(sc);
247977217Sphk			break;
248077217Sphk		case IEEE80211_IOC_AUTHMODE:
248177217Sphk			switch (ireq->i_val) {
248277217Sphk			case IEEE80211_AUTH_NONE:
248377217Sphk				config->an_authtype = AN_AUTHTYPE_NONE |
248477217Sphk				    (config->an_authtype & ~AN_AUTHTYPE_MASK);
248577217Sphk				break;
248677217Sphk			case IEEE80211_AUTH_OPEN:
248777217Sphk				config->an_authtype = AN_AUTHTYPE_OPEN |
248877217Sphk				    (config->an_authtype & ~AN_AUTHTYPE_MASK);
248977217Sphk				break;
249077217Sphk			case IEEE80211_AUTH_SHARED:
249177217Sphk				config->an_authtype = AN_AUTHTYPE_SHAREDKEY |
249277217Sphk				    (config->an_authtype & ~AN_AUTHTYPE_MASK);
249377217Sphk				break;
249477217Sphk			default:
249577217Sphk				error = EINVAL;
249677217Sphk			}
2497175445Sambrisko			if (error != EINVAL) {
2498175445Sambrisko				an_setdef(sc, &sc->areq);
2499175445Sambrisko			}
2500175445Sambrisko			AN_UNLOCK(sc);
250177217Sphk			break;
250277217Sphk		case IEEE80211_IOC_STATIONNAME:
250378639Sbrooks			if (ireq->i_len > 16) {
250477217Sphk				error = EINVAL;
2505175445Sambrisko				AN_UNLOCK(sc);
250677217Sphk				break;
250777217Sphk			}
250877217Sphk			bzero(config->an_nodename, 16);
250977217Sphk			error = copyin(ireq->i_data,
251077217Sphk			    config->an_nodename, ireq->i_len);
2511175445Sambrisko			an_setdef(sc, &sc->areq);
2512175445Sambrisko			AN_UNLOCK(sc);
251377217Sphk			break;
251477217Sphk		case IEEE80211_IOC_CHANNEL:
251577217Sphk			/*
251677217Sphk			 * The actual range is 1-14, but if you set it
251777217Sphk			 * to 0 you get the default so we let that work
251877217Sphk			 * too.
251977217Sphk			 */
252077217Sphk			if (ireq->i_val < 0 || ireq->i_val >14) {
252177217Sphk				error = EINVAL;
2522175445Sambrisko				AN_UNLOCK(sc);
252377217Sphk				break;
252477217Sphk			}
252577217Sphk			config->an_ds_channel = ireq->i_val;
2526175445Sambrisko			an_setdef(sc, &sc->areq);
2527175445Sambrisko			AN_UNLOCK(sc);
252877217Sphk			break;
252977217Sphk		case IEEE80211_IOC_POWERSAVE:
253077217Sphk			switch (ireq->i_val) {
253177217Sphk			case IEEE80211_POWERSAVE_OFF:
253277217Sphk				config->an_psave_mode = AN_PSAVE_NONE;
253377217Sphk				break;
253477217Sphk			case IEEE80211_POWERSAVE_CAM:
253577217Sphk				config->an_psave_mode = AN_PSAVE_CAM;
253677217Sphk				break;
253777217Sphk			case IEEE80211_POWERSAVE_PSP:
253877217Sphk				config->an_psave_mode = AN_PSAVE_PSP;
253977217Sphk				break;
254077217Sphk			case IEEE80211_POWERSAVE_PSP_CAM:
254177217Sphk				config->an_psave_mode = AN_PSAVE_PSP_CAM;
254277217Sphk				break;
254377217Sphk			default:
254477217Sphk				error = EINVAL;
254577217Sphk				break;
254677217Sphk			}
2547175445Sambrisko			an_setdef(sc, &sc->areq);
2548175445Sambrisko			AN_UNLOCK(sc);
254977217Sphk			break;
255077217Sphk		case IEEE80211_IOC_POWERSAVESLEEP:
255177217Sphk			config->an_listen_interval = ireq->i_val;
2552175445Sambrisko			an_setdef(sc, &sc->areq);
2553175445Sambrisko			AN_UNLOCK(sc);
255477217Sphk			break;
2555199154Sjhb		default:
2556199154Sjhb			AN_UNLOCK(sc);
2557199154Sjhb			break;
255877217Sphk		}
255977217Sphk
2560175445Sambrisko		/*
2561175445Sambrisko		if (!error) {
2562175445Sambrisko			AN_LOCK(sc);
256388749Sambrisko			an_setdef(sc, &sc->areq);
2564175445Sambrisko			AN_UNLOCK(sc);
2565175445Sambrisko		}
2566175445Sambrisko		*/
256777217Sphk		break;
256855992Swpaul	default:
2569106937Ssam		error = ether_ioctl(ifp, command, data);
257055992Swpaul		break;
257155992Swpaul	}
257261816Srobertoout:
257355992Swpaul
257478639Sbrooks	return(error != 0);
257555992Swpaul}
257655992Swpaul
257783270Sbrooksstatic int
2578150446Simpan_init_tx_ring(struct an_softc *sc)
257955992Swpaul{
258055992Swpaul	int			i;
258155992Swpaul	int			id;
258255992Swpaul
258355992Swpaul	if (sc->an_gone)
258455992Swpaul		return (0);
258555992Swpaul
2586108401Sambrisko	if (!sc->mpi350) {
2587108401Sambrisko		for (i = 0; i < AN_TX_RING_CNT; i++) {
2588108401Sambrisko			if (an_alloc_nicmem(sc, 1518 +
2589108401Sambrisko			    0x44, &id))
2590108401Sambrisko				return(ENOMEM);
2591108401Sambrisko			sc->an_rdata.an_tx_fids[i] = id;
2592108401Sambrisko			sc->an_rdata.an_tx_ring[i] = 0;
2593108401Sambrisko		}
259455992Swpaul	}
259555992Swpaul
259655992Swpaul	sc->an_rdata.an_tx_prod = 0;
259755992Swpaul	sc->an_rdata.an_tx_cons = 0;
2598108401Sambrisko	sc->an_rdata.an_tx_empty = 1;
259955992Swpaul
260055992Swpaul	return(0);
260155992Swpaul}
260255992Swpaul
260383270Sbrooksstatic void
2604150446Simpan_init(void *xsc)
260555992Swpaul{
260655992Swpaul	struct an_softc		*sc = xsc;
260755992Swpaul
260867094Swpaul	AN_LOCK(sc);
2609199154Sjhb	an_init_locked(sc);
2610199154Sjhb	AN_UNLOCK(sc);
2611199154Sjhb}
261267094Swpaul
2613199154Sjhbstatic void
2614199154Sjhban_init_locked(struct an_softc *sc)
2615199154Sjhb{
2616199154Sjhb	struct ifnet *ifp;
2617199154Sjhb
2618199154Sjhb	AN_LOCK_ASSERT(sc);
2619199154Sjhb	ifp = sc->an_ifp;
2620199154Sjhb	if (sc->an_gone)
262155992Swpaul		return;
262255992Swpaul
2623148887Srwatson	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
262455992Swpaul		an_stop(sc);
262555992Swpaul
262655992Swpaul	sc->an_associated = 0;
262755992Swpaul
262855992Swpaul	/* Allocate the TX buffers */
262955992Swpaul	if (an_init_tx_ring(sc)) {
263055992Swpaul		an_reset(sc);
2631108401Sambrisko		if (sc->mpi350)
2632175445Sambrisko			an_init_mpi350_desc(sc);
263355992Swpaul		if (an_init_tx_ring(sc)) {
2634198987Sjhb			if_printf(ifp, "tx buffer allocation failed\n");
263555992Swpaul			return;
263655992Swpaul		}
263755992Swpaul	}
263855992Swpaul
263955992Swpaul	/* Set our MAC address. */
2640152315Sru	bcopy((char *)IF_LLADDR(sc->an_ifp),
264155992Swpaul	    (char *)&sc->an_config.an_macaddr, ETHER_ADDR_LEN);
264255992Swpaul
264355992Swpaul	if (ifp->if_flags & IFF_BROADCAST)
264455992Swpaul		sc->an_config.an_rxmode = AN_RXMODE_BC_ADDR;
264555992Swpaul	else
264655992Swpaul		sc->an_config.an_rxmode = AN_RXMODE_ADDR;
264755992Swpaul
264855992Swpaul	if (ifp->if_flags & IFF_MULTICAST)
264955992Swpaul		sc->an_config.an_rxmode = AN_RXMODE_BC_MC_ADDR;
265055992Swpaul
265183269Sbrooks	if (ifp->if_flags & IFF_PROMISC) {
265283269Sbrooks		if (sc->an_monitor & AN_MONITOR) {
265383269Sbrooks			if (sc->an_monitor & AN_MONITOR_ANY_BSS) {
265483269Sbrooks				sc->an_config.an_rxmode |=
265583269Sbrooks				    AN_RXMODE_80211_MONITOR_ANYBSS |
265683269Sbrooks				    AN_RXMODE_NO_8023_HEADER;
265783269Sbrooks			} else {
265883269Sbrooks				sc->an_config.an_rxmode |=
265983269Sbrooks				    AN_RXMODE_80211_MONITOR_CURBSS |
266083269Sbrooks				    AN_RXMODE_NO_8023_HEADER;
266183269Sbrooks			}
266283269Sbrooks		}
266383269Sbrooks	}
266455992Swpaul
2665184708Sbz#ifdef ANCACHE
2666108401Sambrisko	if (sc->an_have_rssimap)
2667108401Sambrisko		sc->an_config.an_rxmode |= AN_RXMODE_NORMALIZED_RSSI;
2668184708Sbz#endif
2669108401Sambrisko
267055992Swpaul	/* Set the ssid list */
267155992Swpaul	sc->an_ssidlist.an_type = AN_RID_SSIDLIST;
2672119156Sambrisko	sc->an_ssidlist.an_len = sizeof(struct an_ltv_ssidlist_new);
267355992Swpaul	if (an_write_record(sc, (struct an_ltv_gen *)&sc->an_ssidlist)) {
2674198987Sjhb		if_printf(ifp, "failed to set ssid list\n");
267555992Swpaul		return;
267655992Swpaul	}
267755992Swpaul
267855992Swpaul	/* Set the AP list */
267955992Swpaul	sc->an_aplist.an_type = AN_RID_APLIST;
268055992Swpaul	sc->an_aplist.an_len = sizeof(struct an_ltv_aplist);
268155992Swpaul	if (an_write_record(sc, (struct an_ltv_gen *)&sc->an_aplist)) {
2682198987Sjhb		if_printf(ifp, "failed to set AP list\n");
268355992Swpaul		return;
268455992Swpaul	}
268555992Swpaul
268655992Swpaul	/* Set the configuration in the NIC */
268755992Swpaul	sc->an_config.an_len = sizeof(struct an_ltv_genconfig);
268855992Swpaul	sc->an_config.an_type = AN_RID_GENCONFIG;
268955992Swpaul	if (an_write_record(sc, (struct an_ltv_gen *)&sc->an_config)) {
2690198987Sjhb		if_printf(ifp, "failed to set configuration\n");
269155992Swpaul		return;
269255992Swpaul	}
269355992Swpaul
269455992Swpaul	/* Enable the MAC */
269555992Swpaul	if (an_cmd(sc, AN_CMD_ENABLE, 0)) {
2696198987Sjhb		if_printf(ifp, "failed to enable MAC\n");
269755992Swpaul		return;
269855992Swpaul	}
269955992Swpaul
270074698Sarchie	if (ifp->if_flags & IFF_PROMISC)
270174698Sarchie		an_cmd(sc, AN_CMD_SET_MODE, 0xffff);
270274698Sarchie
270355992Swpaul	/* enable interrupts */
2704119156Sambrisko	CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), AN_INTRS(sc->mpi350));
270555992Swpaul
2706148887Srwatson	ifp->if_drv_flags |= IFF_DRV_RUNNING;
2707148887Srwatson	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
270855992Swpaul
2709173668Savatar	callout_reset(&sc->an_stat_ch, hz, an_stats_update, sc);
271055992Swpaul
271155992Swpaul	return;
271255992Swpaul}
271355992Swpaul
271483270Sbrooksstatic void
2715150446Simpan_start(struct ifnet *ifp)
271655992Swpaul{
271755992Swpaul	struct an_softc		*sc;
2718199154Sjhb
2719199154Sjhb	sc = ifp->if_softc;
2720199154Sjhb	AN_LOCK(sc);
2721199154Sjhb	an_start_locked(ifp);
2722199154Sjhb	AN_UNLOCK(sc);
2723199154Sjhb}
2724199154Sjhb
2725199154Sjhbstatic void
2726199154Sjhban_start_locked(struct ifnet *ifp)
2727199154Sjhb{
2728199154Sjhb	struct an_softc		*sc;
272955992Swpaul	struct mbuf		*m0 = NULL;
273055992Swpaul	struct an_txframe_802_3	tx_frame_802_3;
273155992Swpaul	struct ether_header	*eh;
2732108401Sambrisko	int			id, idx, i;
2733175446Sambrisko	unsigned char		txcontrol;
2734108401Sambrisko	struct an_card_tx_desc an_tx_desc;
2735108401Sambrisko	u_int8_t		*buf;
273655992Swpaul
273755992Swpaul	sc = ifp->if_softc;
273855992Swpaul
2739199154Sjhb	AN_LOCK_ASSERT(sc);
274055992Swpaul	if (sc->an_gone)
274155992Swpaul		return;
274255992Swpaul
2743148887Srwatson	if (ifp->if_drv_flags & IFF_DRV_OACTIVE)
274455992Swpaul		return;
274555992Swpaul
274655992Swpaul	if (!sc->an_associated)
274755992Swpaul		return;
274855992Swpaul
274990990Sbrooks	/* We can't send in monitor mode so toss any attempts. */
275083269Sbrooks	if (sc->an_monitor && (ifp->if_flags & IFF_PROMISC)) {
275183270Sbrooks		for (;;) {
2752132986Smlaier			IFQ_DRV_DEQUEUE(&ifp->if_snd, m0);
275383269Sbrooks			if (m0 == NULL)
275483269Sbrooks				break;
275590990Sbrooks			m_freem(m0);
275683269Sbrooks		}
275783269Sbrooks		return;
275883269Sbrooks	}
275983269Sbrooks
276055992Swpaul	idx = sc->an_rdata.an_tx_prod;
276155992Swpaul
2762108401Sambrisko	if (!sc->mpi350) {
2763108401Sambrisko		bzero((char *)&tx_frame_802_3, sizeof(tx_frame_802_3));
276455992Swpaul
2765108401Sambrisko		while (sc->an_rdata.an_tx_ring[idx] == 0) {
2766132986Smlaier			IFQ_DRV_DEQUEUE(&ifp->if_snd, m0);
2767108401Sambrisko			if (m0 == NULL)
2768108401Sambrisko				break;
276955992Swpaul
2770108401Sambrisko			id = sc->an_rdata.an_tx_fids[idx];
2771108401Sambrisko			eh = mtod(m0, struct ether_header *);
277283270Sbrooks
2773108401Sambrisko			bcopy((char *)&eh->ether_dhost,
2774175445Sambrisko			      (char *)&tx_frame_802_3.an_tx_dst_addr,
2775108401Sambrisko			      ETHER_ADDR_LEN);
2776108401Sambrisko			bcopy((char *)&eh->ether_shost,
2777175445Sambrisko			      (char *)&tx_frame_802_3.an_tx_src_addr,
2778108401Sambrisko			      ETHER_ADDR_LEN);
277955992Swpaul
2780108401Sambrisko			/* minus src/dest mac & type */
2781108401Sambrisko			tx_frame_802_3.an_tx_802_3_payload_len =
2782175445Sambrisko				m0->m_pkthdr.len - 12;
278355992Swpaul
2784108401Sambrisko			m_copydata(m0, sizeof(struct ether_header) - 2 ,
2785108401Sambrisko				   tx_frame_802_3.an_tx_802_3_payload_len,
2786108401Sambrisko				   (caddr_t)&sc->an_txbuf);
2787108401Sambrisko
2788199757Sjhb			txcontrol = AN_TXCTL_8023 | AN_TXCTL_HW(sc->mpi350);
2789108401Sambrisko			/* write the txcontrol only */
2790108401Sambrisko			an_write_data(sc, id, 0x08, (caddr_t)&txcontrol,
2791108401Sambrisko				      sizeof(txcontrol));
2792108401Sambrisko
2793108401Sambrisko			/* 802_3 header */
2794108401Sambrisko			an_write_data(sc, id, 0x34, (caddr_t)&tx_frame_802_3,
2795108401Sambrisko				      sizeof(struct an_txframe_802_3));
2796108401Sambrisko
2797108401Sambrisko			/* in mbuf header type is just before payload */
2798108401Sambrisko			an_write_data(sc, id, 0x44, (caddr_t)&sc->an_txbuf,
2799108401Sambrisko				      tx_frame_802_3.an_tx_802_3_payload_len);
2800108401Sambrisko
2801108401Sambrisko			/*
2802108401Sambrisko			 * If there's a BPF listner, bounce a copy of
2803108401Sambrisko			 * this frame to him.
2804108401Sambrisko			 */
2805108401Sambrisko			BPF_MTAP(ifp, m0);
2806108401Sambrisko
2807108401Sambrisko			m_freem(m0);
2808108401Sambrisko			m0 = NULL;
2809108401Sambrisko
2810108401Sambrisko			sc->an_rdata.an_tx_ring[idx] = id;
2811108401Sambrisko			if (an_cmd(sc, AN_CMD_TX, id))
2812198987Sjhb				if_printf(ifp, "xmit failed\n");
2813108401Sambrisko
2814108401Sambrisko			AN_INC(idx, AN_TX_RING_CNT);
2815119156Sambrisko
2816119156Sambrisko			/*
2817119156Sambrisko			 * Set a timeout in case the chip goes out to lunch.
2818119156Sambrisko			 */
2819199154Sjhb			sc->an_timer = 5;
2820108401Sambrisko		}
2821108401Sambrisko	} else { /* MPI-350 */
2822130620Sambrisko		/* Disable interrupts. */
2823130620Sambrisko		CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), 0);
2824130620Sambrisko
2825108401Sambrisko		while (sc->an_rdata.an_tx_empty ||
2826108401Sambrisko		    idx != sc->an_rdata.an_tx_cons) {
2827132986Smlaier			IFQ_DRV_DEQUEUE(&ifp->if_snd, m0);
2828108401Sambrisko			if (m0 == NULL) {
2829108401Sambrisko				break;
2830108401Sambrisko			}
2831108401Sambrisko			buf = sc->an_tx_buffer[idx].an_dma_vaddr;
2832108401Sambrisko
2833108401Sambrisko			eh = mtod(m0, struct ether_header *);
2834108401Sambrisko
2835108401Sambrisko			/* DJA optimize this to limit bcopy */
2836108401Sambrisko			bcopy((char *)&eh->ether_dhost,
2837175445Sambrisko			      (char *)&tx_frame_802_3.an_tx_dst_addr,
2838108401Sambrisko			      ETHER_ADDR_LEN);
2839108401Sambrisko			bcopy((char *)&eh->ether_shost,
2840175445Sambrisko			      (char *)&tx_frame_802_3.an_tx_src_addr,
2841108401Sambrisko			      ETHER_ADDR_LEN);
2842108401Sambrisko
2843108401Sambrisko			/* minus src/dest mac & type */
2844108401Sambrisko			tx_frame_802_3.an_tx_802_3_payload_len =
2845175445Sambrisko				m0->m_pkthdr.len - 12;
2846108401Sambrisko
2847108401Sambrisko			m_copydata(m0, sizeof(struct ether_header) - 2 ,
2848108401Sambrisko				   tx_frame_802_3.an_tx_802_3_payload_len,
2849108401Sambrisko				   (caddr_t)&sc->an_txbuf);
2850108401Sambrisko
2851199757Sjhb			txcontrol = AN_TXCTL_8023 | AN_TXCTL_HW(sc->mpi350);
2852108401Sambrisko			/* write the txcontrol only */
2853108401Sambrisko			bcopy((caddr_t)&txcontrol, &buf[0x08],
285455992Swpaul			      sizeof(txcontrol));
285583270Sbrooks
2856108401Sambrisko			/* 802_3 header */
2857108401Sambrisko			bcopy((caddr_t)&tx_frame_802_3, &buf[0x34],
285855992Swpaul			      sizeof(struct an_txframe_802_3));
285983270Sbrooks
2860108401Sambrisko			/* in mbuf header type is just before payload */
2861108401Sambrisko			bcopy((caddr_t)&sc->an_txbuf, &buf[0x44],
2862108401Sambrisko			      tx_frame_802_3.an_tx_802_3_payload_len);
286383270Sbrooks
286455992Swpaul
2865108401Sambrisko			bzero(&an_tx_desc, sizeof(an_tx_desc));
2866108401Sambrisko			an_tx_desc.an_offset = 0;
2867108401Sambrisko			an_tx_desc.an_eoc = 1;
2868108401Sambrisko			an_tx_desc.an_valid = 1;
2869108401Sambrisko			an_tx_desc.an_len =  0x44 +
2870119156Sambrisko			    tx_frame_802_3.an_tx_802_3_payload_len;
2871175445Sambrisko			an_tx_desc.an_phys
2872119156Sambrisko			    = sc->an_tx_buffer[idx].an_dma_paddr;
2873199757Sjhb			for (i = sizeof(an_tx_desc) / 4 - 1; i >= 0; i--) {
2874119156Sambrisko				CSR_MEM_AUX_WRITE_4(sc, AN_TX_DESC_OFFSET
2875175445Sambrisko				    /* zero for now */
2876119156Sambrisko				    + (0 * sizeof(an_tx_desc))
2877119156Sambrisko				    + (i * 4),
2878155321Simp				    ((u_int32_t *)(void *)&an_tx_desc)[i]);
2879108401Sambrisko			}
288055992Swpaul
2881108401Sambrisko			/*
2882108401Sambrisko			 * If there's a BPF listner, bounce a copy of
2883108401Sambrisko			 * this frame to him.
2884108401Sambrisko			 */
2885108401Sambrisko			BPF_MTAP(ifp, m0);
288655992Swpaul
2887108401Sambrisko			m_freem(m0);
2888108401Sambrisko			m0 = NULL;
2889119156Sambrisko			AN_INC(idx, AN_MAX_TX_DESC);
2890119156Sambrisko			sc->an_rdata.an_tx_empty = 0;
2891108401Sambrisko			CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_ALLOC);
2892108401Sambrisko
2893119156Sambrisko			/*
2894119156Sambrisko			 * Set a timeout in case the chip goes out to lunch.
2895119156Sambrisko			 */
2896199154Sjhb			sc->an_timer = 5;
2897108401Sambrisko		}
2898130620Sambrisko
2899130620Sambrisko		/* Re-enable interrupts. */
2900130620Sambrisko		CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), AN_INTRS(sc->mpi350));
290155992Swpaul	}
290255992Swpaul
290355992Swpaul	if (m0 != NULL)
2904148887Srwatson		ifp->if_drv_flags |= IFF_DRV_OACTIVE;
290555992Swpaul
290655992Swpaul	sc->an_rdata.an_tx_prod = idx;
290755992Swpaul
290855992Swpaul	return;
290955992Swpaul}
291055992Swpaul
291183270Sbrooksvoid
2912150446Simpan_stop(struct an_softc *sc)
291355992Swpaul{
291455992Swpaul	struct ifnet		*ifp;
291555992Swpaul	int			i;
291655992Swpaul
2917199154Sjhb	AN_LOCK_ASSERT(sc);
291867094Swpaul
2919199154Sjhb	if (sc->an_gone)
292055992Swpaul		return;
292155992Swpaul
2922147256Sbrooks	ifp = sc->an_ifp;
292355992Swpaul
292455992Swpaul	an_cmd(sc, AN_CMD_FORCE_SYNCLOSS, 0);
2925108401Sambrisko	CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), 0);
292655992Swpaul	an_cmd(sc, AN_CMD_DISABLE, 0);
292755992Swpaul
292855992Swpaul	for (i = 0; i < AN_TX_RING_CNT; i++)
292955992Swpaul		an_cmd(sc, AN_CMD_DEALLOC_MEM, sc->an_rdata.an_tx_fids[i]);
293055992Swpaul
2931173668Savatar	callout_stop(&sc->an_stat_ch);
293255992Swpaul
2933148887Srwatson	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING|IFF_DRV_OACTIVE);
293455992Swpaul
2935108401Sambrisko	if (sc->an_flash_buffer) {
2936108401Sambrisko		free(sc->an_flash_buffer, M_DEVBUF);
2937108401Sambrisko		sc->an_flash_buffer = NULL;
2938108401Sambrisko	}
293955992Swpaul}
294055992Swpaul
294183270Sbrooksstatic void
2942199154Sjhban_watchdog(struct an_softc *sc)
294355992Swpaul{
2944199154Sjhb	struct ifnet *ifp;
294555992Swpaul
2946199154Sjhb	AN_LOCK_ASSERT(sc);
294755992Swpaul
2948199154Sjhb	if (sc->an_gone)
294955992Swpaul		return;
295055992Swpaul
2951199154Sjhb	ifp = sc->an_ifp;
2952198987Sjhb	if_printf(ifp, "device timeout\n");
295355992Swpaul
295455992Swpaul	an_reset(sc);
2955108401Sambrisko	if (sc->mpi350)
2956175445Sambrisko		an_init_mpi350_desc(sc);
2957199154Sjhb	an_init_locked(sc);
295855992Swpaul
2959271849Sglebius	if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
296055992Swpaul}
296155992Swpaul
2962188128Simpint
2963150446Simpan_shutdown(device_t dev)
296455992Swpaul{
296555992Swpaul	struct an_softc		*sc;
296655992Swpaul
296755992Swpaul	sc = device_get_softc(dev);
2968199154Sjhb	AN_LOCK(sc);
296955992Swpaul	an_stop(sc);
2970110531Sambrisko	sc->an_gone = 1;
2971199154Sjhb	AN_UNLOCK(sc);
297255992Swpaul
2973199154Sjhb	return (0);
297455992Swpaul}
297555992Swpaul
2976110362Sambriskovoid
2977150446Simpan_resume(device_t dev)
2978110362Sambrisko{
2979110362Sambrisko	struct an_softc		*sc;
2980110362Sambrisko	struct ifnet		*ifp;
2981110531Sambrisko	int			i;
2982110531Sambrisko
2983110362Sambrisko	sc = device_get_softc(dev);
2984110531Sambrisko	AN_LOCK(sc);
2985147256Sbrooks	ifp = sc->an_ifp;
2986110362Sambrisko
2987110531Sambrisko	sc->an_gone = 0;
2988110362Sambrisko	an_reset(sc);
2989110362Sambrisko	if (sc->mpi350)
2990175445Sambrisko		an_init_mpi350_desc(sc);
2991199154Sjhb	an_init_locked(sc);
2992110362Sambrisko
2993110531Sambrisko	/* Recovery temporary keys */
2994110531Sambrisko	for (i = 0; i < 4; i++) {
2995110531Sambrisko		sc->areq.an_type = AN_RID_WEP_TEMP;
2996175445Sambrisko		sc->areq.an_len = sizeof(struct an_ltv_key);
2997110531Sambrisko		bcopy(&sc->an_temp_keys[i],
2998110531Sambrisko		    &sc->areq, sizeof(struct an_ltv_key));
2999110531Sambrisko		an_setdef(sc, &sc->areq);
3000110531Sambrisko	}
3001110531Sambrisko
3002110362Sambrisko	if (ifp->if_flags & IFF_UP)
3003199154Sjhb		an_start_locked(ifp);
3004110531Sambrisko	AN_UNLOCK(sc);
3005110362Sambrisko
3006110362Sambrisko	return;
3007110362Sambrisko}
3008110362Sambrisko
300955992Swpaul#ifdef ANCACHE
301055992Swpaul/* Aironet signal strength cache code.
301155992Swpaul * store signal/noise/quality on per MAC src basis in
301255992Swpaul * a small fixed cache.  The cache wraps if > MAX slots
301355992Swpaul * used.  The cache may be zeroed out to start over.
301455992Swpaul * Two simple filters exist to reduce computation:
301588748Sambrisko * 1. ip only (literally 0x800, ETHERTYPE_IP) which may be used
301655992Swpaul * to ignore some packets.  It defaults to ip only.
301755992Swpaul * it could be used to focus on broadcast, non-IP 802.11 beacons.
301855992Swpaul * 2. multicast/broadcast only.  This may be used to
301955992Swpaul * ignore unicast packets and only cache signal strength
302055992Swpaul * for multicast/broadcast packets (beacons); e.g., Mobile-IP
302155992Swpaul * beacons and not unicast traffic.
302255992Swpaul *
302355992Swpaul * The cache stores (MAC src(index), IP src (major clue), signal,
302455992Swpaul *	quality, noise)
302555992Swpaul *
302655992Swpaul * No apologies for storing IP src here.  It's easy and saves much
302783270Sbrooks * trouble elsewhere.  The cache is assumed to be INET dependent,
302855992Swpaul * although it need not be.
302955992Swpaul *
303055992Swpaul * Note: the Aironet only has a single byte of signal strength value
303155992Swpaul * in the rx frame header, and it's not scaled to anything sensible.
303255992Swpaul * This is kind of lame, but it's all we've got.
303355992Swpaul */
303455992Swpaul
303555992Swpaul#ifdef documentation
303655992Swpaul
3037175446Sambriskoint an_sigitems;				/* number of cached entries */
3038175446Sambriskostruct an_sigcache an_sigcache[MAXANCACHE];	/* array of cache entries */
3039175446Sambriskoint an_nextitem;				/* index/# of entries */
304055992Swpaul
304155992Swpaul
304255992Swpaul#endif
304355992Swpaul
304455992Swpaul/* control variables for cache filtering.  Basic idea is
304555992Swpaul * to reduce cost (e.g., to only Mobile-IP agent beacons
304655992Swpaul * which are broadcast or multicast).  Still you might
304755992Swpaul * want to measure signal strength anth unicast ping packets
304855992Swpaul * on a pt. to pt. ant. setup.
304955992Swpaul */
305083270Sbrooks/* set true if you want to limit cache items to broadcast/mcast
305155992Swpaul * only packets (not unicast).  Useful for mobile-ip beacons which
305255992Swpaul * are broadcast/multicast at network layer.  Default is all packets
305355992Swpaul * so ping/unicast anll work say anth pt. to pt. antennae setup.
305455992Swpaul */
305555992Swpaulstatic int an_cache_mcastonly = 0;
3056110531SambriskoSYSCTL_INT(_hw_an, OID_AUTO, an_cache_mcastonly, CTLFLAG_RW,
305755992Swpaul	&an_cache_mcastonly, 0, "");
305855992Swpaul
305955992Swpaul/* set true if you want to limit cache items to IP packets only
306055992Swpaul*/
306155992Swpaulstatic int an_cache_iponly = 1;
3062110531SambriskoSYSCTL_INT(_hw_an, OID_AUTO, an_cache_iponly, CTLFLAG_RW,
306355992Swpaul	&an_cache_iponly, 0, "");
306455992Swpaul
306555992Swpaul/*
306655992Swpaul * an_cache_store, per rx packet store signal
306755992Swpaul * strength in MAC (src) indexed cache.
306855992Swpaul */
306983270Sbrooksstatic void
3070150446Simpan_cache_store(struct an_softc *sc, struct ether_header *eh, struct mbuf *m,
3071150446Simp    u_int8_t rx_rssi, u_int8_t rx_quality)
307255992Swpaul{
3073315221Spfg	struct ip *ip = NULL;
307455992Swpaul	int i;
307555992Swpaul	static int cache_slot = 0; 	/* use this cache entry */
3076175446Sambrisko	static int wrapindex = 0;	/* next "free" cache entry */
307788748Sambrisko	int type_ipv4 = 0;
307855992Swpaul
307955992Swpaul	/* filters:
308055992Swpaul	 * 1. ip only
308155992Swpaul	 * 2. configurable filter to throw out unicast packets,
308255992Swpaul	 * keep multicast only.
308355992Swpaul	 */
308483270Sbrooks
308588748Sambrisko	if ((ntohs(eh->ether_type) == ETHERTYPE_IP)) {
308688748Sambrisko		type_ipv4 = 1;
308755992Swpaul	}
308855992Swpaul
308983270Sbrooks	/* filter for ip packets only
309055992Swpaul	*/
309188748Sambrisko	if ( an_cache_iponly && !type_ipv4) {
309255992Swpaul		return;
309355992Swpaul	}
309455992Swpaul
309555992Swpaul	/* filter for broadcast/multicast only
309655992Swpaul	 */
309755992Swpaul	if (an_cache_mcastonly && ((eh->ether_dhost[0] & 1) == 0)) {
309855992Swpaul		return;
309955992Swpaul	}
310055992Swpaul
310155992Swpaul#ifdef SIGDEBUG
3102198987Sjhb	if_printf(sc->an_ifp, "q value %x (MSB=0x%x, LSB=0x%x) \n",
3103108401Sambrisko		rx_rssi & 0xffff, rx_rssi >> 8, rx_rssi & 0xff);
310455992Swpaul#endif
310555992Swpaul
310655992Swpaul	/* find the ip header.  we want to store the ip_src
310783270Sbrooks	 * address.
310855992Swpaul	 */
310988748Sambrisko	if (type_ipv4) {
311055992Swpaul		ip = mtod(m, struct ip *);
311155992Swpaul	}
311283270Sbrooks
311383270Sbrooks	/* do a linear search for a matching MAC address
311455992Swpaul	 * in the cache table
311555992Swpaul	 * . MAC address is 6 bytes,
311655992Swpaul	 * . var w_nextitem holds total number of entries already cached
311755992Swpaul	 */
311878639Sbrooks	for (i = 0; i < sc->an_nextitem; i++) {
311955992Swpaul		if (! bcmp(eh->ether_shost , sc->an_sigcache[i].macsrc,  6 )) {
312055992Swpaul			/* Match!,
312155992Swpaul			 * so we already have this entry,
312255992Swpaul			 * update the data
312355992Swpaul			 */
312483270Sbrooks			break;
312555992Swpaul		}
312655992Swpaul	}
312755992Swpaul
312855992Swpaul	/* did we find a matching mac address?
312955992Swpaul	 * if yes, then overwrite a previously existing cache entry
313055992Swpaul	 */
313155992Swpaul	if (i < sc->an_nextitem )   {
313283270Sbrooks		cache_slot = i;
313355992Swpaul	}
313455992Swpaul	/* else, have a new address entry,so
313555992Swpaul	 * add this new entry,
313655992Swpaul	 * if table full, then we need to replace LRU entry
313755992Swpaul	 */
313883270Sbrooks	else    {
313955992Swpaul
314083270Sbrooks		/* check for space in cache table
314155992Swpaul		 * note: an_nextitem also holds number of entries
314283270Sbrooks		 * added in the cache table
314355992Swpaul		 */
314455992Swpaul		if ( sc->an_nextitem < MAXANCACHE ) {
314555992Swpaul			cache_slot = sc->an_nextitem;
314683270Sbrooks			sc->an_nextitem++;
314755992Swpaul			sc->an_sigitems = sc->an_nextitem;
314855992Swpaul		}
3149175446Sambrisko		/* no space found, so simply wrap anth wrap index
315055992Swpaul		 * and "zap" the next entry
315155992Swpaul		 */
315255992Swpaul		else {
315355992Swpaul			if (wrapindex == MAXANCACHE) {
315455992Swpaul				wrapindex = 0;
315555992Swpaul			}
315655992Swpaul			cache_slot = wrapindex++;
315755992Swpaul		}
315855992Swpaul	}
315955992Swpaul
316055992Swpaul	/* invariant: cache_slot now points at some slot
316155992Swpaul	 * in cache.
316255992Swpaul	 */
316355992Swpaul	if (cache_slot < 0 || cache_slot >= MAXANCACHE) {
316455992Swpaul		log(LOG_ERR, "an_cache_store, bad index: %d of "
316555992Swpaul		    "[0..%d], gross cache error\n",
316655992Swpaul		    cache_slot, MAXANCACHE);
316755992Swpaul		return;
316855992Swpaul	}
316955992Swpaul
317055992Swpaul	/*  store items in cache
317155992Swpaul	 *  .ip source address
317255992Swpaul	 *  .mac src
317355992Swpaul	 *  .signal, etc.
317455992Swpaul	 */
317588748Sambrisko	if (type_ipv4) {
317655992Swpaul		sc->an_sigcache[cache_slot].ipsrc = ip->ip_src.s_addr;
317755992Swpaul	}
317855992Swpaul	bcopy( eh->ether_shost, sc->an_sigcache[cache_slot].macsrc,  6);
317955992Swpaul
318055992Swpaul
3181108401Sambrisko	switch (an_cache_mode) {
3182108401Sambrisko	case DBM:
3183108401Sambrisko		if (sc->an_have_rssimap) {
3184175445Sambrisko			sc->an_sigcache[cache_slot].signal =
3185108401Sambrisko				- sc->an_rssimap.an_entries[rx_rssi].an_rss_dbm;
3186175445Sambrisko			sc->an_sigcache[cache_slot].quality =
3187108401Sambrisko				- sc->an_rssimap.an_entries[rx_quality].an_rss_dbm;
3188108401Sambrisko		} else {
3189108401Sambrisko			sc->an_sigcache[cache_slot].signal = rx_rssi - 100;
3190108401Sambrisko			sc->an_sigcache[cache_slot].quality = rx_quality - 100;
3191108401Sambrisko		}
3192108401Sambrisko		break;
3193108401Sambrisko	case PERCENT:
3194108401Sambrisko		if (sc->an_have_rssimap) {
3195175445Sambrisko			sc->an_sigcache[cache_slot].signal =
3196108401Sambrisko				sc->an_rssimap.an_entries[rx_rssi].an_rss_pct;
3197175445Sambrisko			sc->an_sigcache[cache_slot].quality =
3198108401Sambrisko				sc->an_rssimap.an_entries[rx_quality].an_rss_pct;
3199108401Sambrisko		} else {
3200108401Sambrisko			if (rx_rssi > 100)
3201108401Sambrisko				rx_rssi = 100;
3202108401Sambrisko			if (rx_quality > 100)
3203108401Sambrisko				rx_quality = 100;
3204108401Sambrisko			sc->an_sigcache[cache_slot].signal = rx_rssi;
3205108401Sambrisko			sc->an_sigcache[cache_slot].quality = rx_quality;
3206108401Sambrisko		}
3207108401Sambrisko		break;
3208108401Sambrisko	case RAW:
3209108401Sambrisko		sc->an_sigcache[cache_slot].signal = rx_rssi;
3210108401Sambrisko		sc->an_sigcache[cache_slot].quality = rx_quality;
3211108401Sambrisko		break;
3212108401Sambrisko	}
3213108401Sambrisko
3214108401Sambrisko	sc->an_sigcache[cache_slot].noise = 0;
3215108401Sambrisko
321655992Swpaul	return;
321755992Swpaul}
321855992Swpaul#endif
321977217Sphk
322083270Sbrooksstatic int
3221150446Simpan_media_change(struct ifnet *ifp)
322277217Sphk{
322377217Sphk	struct an_softc *sc = ifp->if_softc;
3224110253Sambrisko	struct an_ltv_genconfig	*cfg;
322577217Sphk	int otype = sc->an_config.an_opmode;
322677217Sphk	int orate = sc->an_tx_rate;
322777217Sphk
3228199154Sjhb	AN_LOCK(sc);
3229116951Ssam	sc->an_tx_rate = ieee80211_media2rate(
3230116951Ssam		IFM_SUBTYPE(sc->an_ifmedia.ifm_cur->ifm_media));
3231119156Sambrisko	if (sc->an_tx_rate < 0)
3232119156Sambrisko		sc->an_tx_rate = 0;
3233110253Sambrisko
3234110253Sambrisko	if (orate != sc->an_tx_rate) {
3235110253Sambrisko		/* Read the current configuration */
3236110253Sambrisko		sc->an_config.an_type = AN_RID_GENCONFIG;
3237110253Sambrisko		sc->an_config.an_len = sizeof(struct an_ltv_genconfig);
3238110253Sambrisko		an_read_record(sc, (struct an_ltv_gen *)&sc->an_config);
3239110253Sambrisko		cfg = &sc->an_config;
3240110253Sambrisko
3241110253Sambrisko		/* clear other rates and set the only one we want */
3242110253Sambrisko		bzero(cfg->an_rates, sizeof(cfg->an_rates));
3243110253Sambrisko		cfg->an_rates[0] = sc->an_tx_rate;
3244110253Sambrisko
3245110253Sambrisko		/* Save the new rate */
3246110253Sambrisko		sc->an_config.an_type = AN_RID_GENCONFIG;
3247110253Sambrisko		sc->an_config.an_len = sizeof(struct an_ltv_genconfig);
324877217Sphk	}
324977217Sphk
3250119156Sambrisko	if ((sc->an_ifmedia.ifm_cur->ifm_media & IFM_IEEE80211_ADHOC) != 0)
3251119156Sambrisko		sc->an_config.an_opmode &= ~AN_OPMODE_INFRASTRUCTURE_STATION;
3252119156Sambrisko	else
3253119156Sambrisko		sc->an_config.an_opmode |= AN_OPMODE_INFRASTRUCTURE_STATION;
3254119156Sambrisko
3255175445Sambrisko	if (otype != sc->an_config.an_opmode ||
3256110531Sambrisko	    orate != sc->an_tx_rate)
3257199154Sjhb		an_init_locked(sc);
3258199154Sjhb	AN_UNLOCK(sc);
325977217Sphk
326077217Sphk	return(0);
326177217Sphk}
326277217Sphk
326383270Sbrooksstatic void
3264150446Simpan_media_status(struct ifnet *ifp, struct ifmediareq *imr)
326577217Sphk{
326677217Sphk	struct an_ltv_status	status;
326777217Sphk	struct an_softc		*sc = ifp->if_softc;
326877217Sphk
3269110253Sambrisko	imr->ifm_active = IFM_IEEE80211;
3270110253Sambrisko
3271175445Sambrisko	AN_LOCK(sc);
327277217Sphk	status.an_len = sizeof(status);
327377217Sphk	status.an_type = AN_RID_STATUS;
327477217Sphk	if (an_read_record(sc, (struct an_ltv_gen *)&status)) {
327577217Sphk		/* If the status read fails, just lie. */
327677217Sphk		imr->ifm_active = sc->an_ifmedia.ifm_cur->ifm_media;
327777217Sphk		imr->ifm_status = IFM_AVALID|IFM_ACTIVE;
327877217Sphk	}
327977217Sphk
328078639Sbrooks	if (sc->an_tx_rate == 0) {
328177217Sphk		imr->ifm_active = IFM_IEEE80211|IFM_AUTO;
328277217Sphk	}
328377217Sphk
3284110253Sambrisko	if (sc->an_config.an_opmode == AN_OPMODE_IBSS_ADHOC)
3285110253Sambrisko		imr->ifm_active |= IFM_IEEE80211_ADHOC;
3286116951Ssam	imr->ifm_active |= ieee80211_rate2media(NULL,
3287228621Sbschmidt		status.an_current_tx_rate, IEEE80211_MODE_AUTO);
328877217Sphk	imr->ifm_status = IFM_AVALID;
328991283Sambrisko	if (status.an_opmode & AN_STATUS_OPMODE_ASSOCIATED)
329077217Sphk		imr->ifm_status |= IFM_ACTIVE;
3291199154Sjhb	AN_UNLOCK(sc);
329277217Sphk}
329388748Sambrisko
329488748Sambrisko/********************** Cisco utility support routines *************/
329588748Sambrisko
329688748Sambrisko/*
329788748Sambrisko * ReadRids & WriteRids derived from Cisco driver additions to Ben Reed's
329888748Sambrisko * Linux driver
329988748Sambrisko */
330088748Sambrisko
330188748Sambriskostatic int
3302150446Simpreadrids(struct ifnet *ifp, struct aironet_ioctl *l_ioctl)
330388748Sambrisko{
330488749Sambrisko	unsigned short  rid;
330588748Sambrisko	struct an_softc *sc;
3306171692Savatar	int error;
330788748Sambrisko
330888748Sambrisko	switch (l_ioctl->command) {
330988748Sambrisko	case AIROGCAP:
331088748Sambrisko		rid = AN_RID_CAPABILITIES;
331188748Sambrisko		break;
331288748Sambrisko	case AIROGCFG:
331388748Sambrisko		rid = AN_RID_GENCONFIG;
331488748Sambrisko		break;
331588748Sambrisko	case AIROGSLIST:
331688748Sambrisko		rid = AN_RID_SSIDLIST;
331788748Sambrisko		break;
331888748Sambrisko	case AIROGVLIST:
331988748Sambrisko		rid = AN_RID_APLIST;
332088748Sambrisko		break;
332188748Sambrisko	case AIROGDRVNAM:
332288748Sambrisko		rid = AN_RID_DRVNAME;
332388748Sambrisko		break;
332488748Sambrisko	case AIROGEHTENC:
332588748Sambrisko		rid = AN_RID_ENCAPPROTO;
332688748Sambrisko		break;
332788748Sambrisko	case AIROGWEPKTMP:
332888748Sambrisko		rid = AN_RID_WEP_TEMP;
332988748Sambrisko		break;
333088748Sambrisko	case AIROGWEPKNV:
333188748Sambrisko		rid = AN_RID_WEP_PERM;
333288748Sambrisko		break;
333388748Sambrisko	case AIROGSTAT:
333488748Sambrisko		rid = AN_RID_STATUS;
333588748Sambrisko		break;
333688748Sambrisko	case AIROGSTATSD32:
333788748Sambrisko		rid = AN_RID_32BITS_DELTA;
333888748Sambrisko		break;
333988748Sambrisko	case AIROGSTATSC32:
334088748Sambrisko		rid = AN_RID_32BITS_CUM;
334188748Sambrisko		break;
334288748Sambrisko	default:
334388748Sambrisko		rid = 999;
334488748Sambrisko		break;
334588748Sambrisko	}
334688748Sambrisko
334788748Sambrisko	if (rid == 999)	/* Is bad command */
334888748Sambrisko		return -EINVAL;
334988748Sambrisko
335088748Sambrisko	sc = ifp->if_softc;
335188749Sambrisko	sc->areq.an_len  = AN_MAX_DATALEN;
335288749Sambrisko	sc->areq.an_type = rid;
335388748Sambrisko
335488749Sambrisko	an_read_record(sc, (struct an_ltv_gen *)&sc->areq);
335588748Sambrisko
335688749Sambrisko	l_ioctl->len = sc->areq.an_len - 4;	/* just data */
335788748Sambrisko
3358171692Savatar	AN_UNLOCK(sc);
335988748Sambrisko	/* the data contains the length at first */
336088749Sambrisko	if (copyout(&(sc->areq.an_len), l_ioctl->data,
336188749Sambrisko		    sizeof(sc->areq.an_len))) {
3362171692Savatar		error = -EFAULT;
3363171692Savatar		goto lock_exit;
336488748Sambrisko	}
336588748Sambrisko	/* Just copy the data back */
336688749Sambrisko	if (copyout(&(sc->areq.an_val), l_ioctl->data + 2,
336788748Sambrisko		    l_ioctl->len)) {
3368171692Savatar		error = -EFAULT;
3369171692Savatar		goto lock_exit;
337088748Sambrisko	}
3371171692Savatar	error = 0;
3372171692Savatarlock_exit:
3373171692Savatar	AN_LOCK(sc);
3374171692Savatar	return (error);
337588748Sambrisko}
337688748Sambrisko
337788748Sambriskostatic int
3378150446Simpwriterids(struct ifnet *ifp, struct aironet_ioctl *l_ioctl)
337988748Sambrisko{
338088748Sambrisko	struct an_softc *sc;
3381175446Sambrisko	int		rid, command, error;
338288748Sambrisko
338388748Sambrisko	sc = ifp->if_softc;
3384175445Sambrisko	AN_LOCK_ASSERT(sc);
338588748Sambrisko	rid = 0;
338688748Sambrisko	command = l_ioctl->command;
338788748Sambrisko
338888748Sambrisko	switch (command) {
338988748Sambrisko	case AIROPSIDS:
339088748Sambrisko		rid = AN_RID_SSIDLIST;
339188748Sambrisko		break;
339288748Sambrisko	case AIROPCAP:
339388748Sambrisko		rid = AN_RID_CAPABILITIES;
339488748Sambrisko		break;
339588748Sambrisko	case AIROPAPLIST:
339688748Sambrisko		rid = AN_RID_APLIST;
339788748Sambrisko		break;
339888748Sambrisko	case AIROPCFG:
339988748Sambrisko		rid = AN_RID_GENCONFIG;
340088748Sambrisko		break;
340188748Sambrisko	case AIROPMACON:
340288748Sambrisko		an_cmd(sc, AN_CMD_ENABLE, 0);
340388748Sambrisko		return 0;
340488748Sambrisko		break;
340588748Sambrisko	case AIROPMACOFF:
340688748Sambrisko		an_cmd(sc, AN_CMD_DISABLE, 0);
340788748Sambrisko		return 0;
340888748Sambrisko		break;
340988748Sambrisko	case AIROPSTCLR:
341088748Sambrisko		/*
341188748Sambrisko		 * This command merely clears the counts does not actually
341288748Sambrisko		 * store any data only reads rid. But as it changes the cards
341388748Sambrisko		 * state, I put it in the writerid routines.
341488748Sambrisko		 */
341588748Sambrisko
341688748Sambrisko		rid = AN_RID_32BITS_DELTACLR;
341788748Sambrisko		sc = ifp->if_softc;
341888749Sambrisko		sc->areq.an_len = AN_MAX_DATALEN;
341988749Sambrisko		sc->areq.an_type = rid;
342088748Sambrisko
342188749Sambrisko		an_read_record(sc, (struct an_ltv_gen *)&sc->areq);
342288749Sambrisko		l_ioctl->len = sc->areq.an_len - 4;	/* just data */
342388748Sambrisko
3424171692Savatar		AN_UNLOCK(sc);
342588748Sambrisko		/* the data contains the length at first */
3426171692Savatar		error = copyout(&(sc->areq.an_len), l_ioctl->data,
3427171692Savatar			    sizeof(sc->areq.an_len));
3428171692Savatar		if (error) {
3429171692Savatar			AN_LOCK(sc);
343088748Sambrisko			return -EFAULT;
343188748Sambrisko		}
343288748Sambrisko		/* Just copy the data */
3433171692Savatar		error = copyout(&(sc->areq.an_val), l_ioctl->data + 2,
3434171692Savatar			    l_ioctl->len);
3435171692Savatar		AN_LOCK(sc);
3436171692Savatar		if (error)
343788748Sambrisko			return -EFAULT;
343888748Sambrisko		return 0;
343988748Sambrisko		break;
344088748Sambrisko	case AIROPWEPKEY:
344188748Sambrisko		rid = AN_RID_WEP_TEMP;
344288748Sambrisko		break;
344388748Sambrisko	case AIROPWEPKEYNV:
344488748Sambrisko		rid = AN_RID_WEP_PERM;
344588748Sambrisko		break;
344688748Sambrisko	case AIROPLEAPUSR:
344788748Sambrisko		rid = AN_RID_LEAPUSERNAME;
344888748Sambrisko		break;
344988748Sambrisko	case AIROPLEAPPWD:
345088748Sambrisko		rid = AN_RID_LEAPPASSWORD;
345188748Sambrisko		break;
345288748Sambrisko	default:
345388748Sambrisko		return -EOPNOTSUPP;
345488748Sambrisko	}
345588748Sambrisko
345688748Sambrisko	if (rid) {
345788749Sambrisko		if (l_ioctl->len > sizeof(sc->areq.an_val) + 4)
345888748Sambrisko			return -EINVAL;
345988749Sambrisko		sc->areq.an_len = l_ioctl->len + 4;	/* add type & length */
346088749Sambrisko		sc->areq.an_type = rid;
346188748Sambrisko
346288748Sambrisko		/* Just copy the data back */
3463171692Savatar		AN_UNLOCK(sc);
3464171692Savatar		error = copyin((l_ioctl->data) + 2, &sc->areq.an_val,
3465171692Savatar		       l_ioctl->len);
3466171692Savatar		AN_LOCK(sc);
3467171692Savatar		if (error)
3468144242Ssam			return -EFAULT;
3469171692Savatar
347088748Sambrisko		an_cmd(sc, AN_CMD_DISABLE, 0);
347188749Sambrisko		an_write_record(sc, (struct an_ltv_gen *)&sc->areq);
347288748Sambrisko		an_cmd(sc, AN_CMD_ENABLE, 0);
347388748Sambrisko		return 0;
347488748Sambrisko	}
347588748Sambrisko	return -EOPNOTSUPP;
347688748Sambrisko}
347788748Sambrisko
347888748Sambrisko/*
347988748Sambrisko * General Flash utilities derived from Cisco driver additions to Ben Reed's
348088748Sambrisko * Linux driver
348188748Sambrisko */
348288748Sambrisko
3483123978Sambrisko#define FLASH_DELAY(_sc, x)	msleep(ifp, &(_sc)->an_mtx, PZERO, \
3484123978Sambrisko	"flash", ((x) / hz) + 1);
3485108401Sambrisko#define FLASH_COMMAND	0x7e7e
3486108401Sambrisko#define FLASH_SIZE	32 * 1024
348788748Sambrisko
348888748Sambriskostatic int
3489150446Simpunstickbusy(struct ifnet *ifp)
349088748Sambrisko{
349188748Sambrisko	struct an_softc *sc = ifp->if_softc;
349288748Sambrisko
3493108401Sambrisko	if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350)) & AN_CMD_BUSY) {
3494175445Sambrisko		CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350),
3495108401Sambrisko			    AN_EV_CLR_STUCK_BUSY);
349688748Sambrisko		return 1;
349788748Sambrisko	}
349888748Sambrisko	return 0;
349988748Sambrisko}
350088748Sambrisko
350188748Sambrisko/*
350288748Sambrisko * Wait for busy completion from card wait for delay uSec's Return true for
350388748Sambrisko * success meaning command reg is clear
350488748Sambrisko */
350588748Sambrisko
350688748Sambriskostatic int
3507150446SimpWaitBusy(struct ifnet *ifp, int uSec)
350888748Sambrisko{
3509175446Sambrisko	int		statword = 0xffff;
3510175446Sambrisko	int		delay = 0;
3511175446Sambrisko	struct an_softc	*sc = ifp->if_softc;
351288748Sambrisko
351388748Sambrisko	while ((statword & AN_CMD_BUSY) && delay <= (1000 * 100)) {
3514119163Sambrisko		FLASH_DELAY(sc, 10);
351588748Sambrisko		delay += 10;
3516108401Sambrisko		statword = CSR_READ_2(sc, AN_COMMAND(sc->mpi350));
351788748Sambrisko
351888748Sambrisko		if ((AN_CMD_BUSY & statword) && (delay % 200)) {
351988748Sambrisko			unstickbusy(ifp);
352088748Sambrisko		}
352188748Sambrisko	}
352288748Sambrisko
352388748Sambrisko	return 0 == (AN_CMD_BUSY & statword);
352488748Sambrisko}
352588748Sambrisko
352688748Sambrisko/*
352788748Sambrisko * STEP 1) Disable MAC and do soft reset on card.
352888748Sambrisko */
352988748Sambrisko
353088748Sambriskostatic int
3531150446Simpcmdreset(struct ifnet *ifp)
353288748Sambrisko{
3533175446Sambrisko	int		status;
3534175446Sambrisko	struct an_softc	*sc = ifp->if_softc;
353588748Sambrisko
3536199154Sjhb	AN_LOCK(sc);
353788748Sambrisko	an_stop(sc);
353888748Sambrisko
353988748Sambrisko	an_cmd(sc, AN_CMD_DISABLE, 0);
354088748Sambrisko
3541108401Sambrisko	if (!(status = WaitBusy(ifp, AN_TIMEOUT))) {
3542198987Sjhb		if_printf(ifp, "Waitbusy hang b4 RESET =%d\n", status);
3543175445Sambrisko		AN_UNLOCK(sc);
354488748Sambrisko		return -EBUSY;
354588748Sambrisko	}
3546108401Sambrisko	CSR_WRITE_2(sc, AN_COMMAND(sc->mpi350), AN_CMD_FW_RESTART);
354788748Sambrisko
3548119163Sambrisko	FLASH_DELAY(sc, 1000);	/* WAS 600 12/7/00 */
354988748Sambrisko
355088748Sambrisko
355188748Sambrisko	if (!(status = WaitBusy(ifp, 100))) {
3552198987Sjhb		if_printf(ifp, "Waitbusy hang AFTER RESET =%d\n", status);
3553175445Sambrisko		AN_UNLOCK(sc);
355488748Sambrisko		return -EBUSY;
355588748Sambrisko	}
3556175445Sambrisko	AN_UNLOCK(sc);
355788748Sambrisko	return 0;
355888748Sambrisko}
355988748Sambrisko
356088748Sambrisko/*
356188748Sambrisko * STEP 2) Put the card in legendary flash mode
356288748Sambrisko */
356388748Sambrisko
356488748Sambriskostatic int
3565150446Simpsetflashmode(struct ifnet *ifp)
356688748Sambrisko{
3567175446Sambrisko	int		status;
3568175446Sambrisko	struct an_softc	*sc = ifp->if_softc;
356988748Sambrisko
3570108401Sambrisko	CSR_WRITE_2(sc, AN_SW0(sc->mpi350), FLASH_COMMAND);
3571108401Sambrisko	CSR_WRITE_2(sc, AN_SW1(sc->mpi350), FLASH_COMMAND);
3572108401Sambrisko	CSR_WRITE_2(sc, AN_SW0(sc->mpi350), FLASH_COMMAND);
3573108401Sambrisko	CSR_WRITE_2(sc, AN_COMMAND(sc->mpi350), FLASH_COMMAND);
357488748Sambrisko
357588748Sambrisko	/*
357688748Sambrisko	 * mdelay(500); // 500ms delay
357788748Sambrisko	 */
357888748Sambrisko
3579119163Sambrisko	FLASH_DELAY(sc, 500);
358088748Sambrisko
3581108401Sambrisko	if (!(status = WaitBusy(ifp, AN_TIMEOUT))) {
358288748Sambrisko		printf("Waitbusy hang after setflash mode\n");
358388748Sambrisko		return -EIO;
358488748Sambrisko	}
358588748Sambrisko	return 0;
358688748Sambrisko}
358788748Sambrisko
358888748Sambrisko/*
358988748Sambrisko * Get a character from the card matching matchbyte Step 3)
359088748Sambrisko */
359188748Sambrisko
359288748Sambriskostatic int
3593150446Simpflashgchar(struct ifnet *ifp, int matchbyte, int dwelltime)
359488748Sambrisko{
3595175446Sambrisko	int		rchar;
3596175446Sambrisko	unsigned char	rbyte = 0;
3597175446Sambrisko	int		success = -1;
3598175446Sambrisko	struct an_softc	*sc = ifp->if_softc;
359988748Sambrisko
360088748Sambrisko
360188748Sambrisko	do {
3602108401Sambrisko		rchar = CSR_READ_2(sc, AN_SW1(sc->mpi350));
360388748Sambrisko
360488748Sambrisko		if (dwelltime && !(0x8000 & rchar)) {
360588748Sambrisko			dwelltime -= 10;
3606119163Sambrisko			FLASH_DELAY(sc, 10);
360788748Sambrisko			continue;
360888748Sambrisko		}
360988748Sambrisko		rbyte = 0xff & rchar;
361088748Sambrisko
361188748Sambrisko		if ((rbyte == matchbyte) && (0x8000 & rchar)) {
3612108401Sambrisko			CSR_WRITE_2(sc, AN_SW1(sc->mpi350), 0);
361388748Sambrisko			success = 1;
361488748Sambrisko			break;
361588748Sambrisko		}
361688748Sambrisko		if (rbyte == 0x81 || rbyte == 0x82 || rbyte == 0x83 || rbyte == 0x1a || 0xffff == rchar)
361788748Sambrisko			break;
3618108401Sambrisko		CSR_WRITE_2(sc, AN_SW1(sc->mpi350), 0);
361988748Sambrisko
362088748Sambrisko	} while (dwelltime > 0);
362188748Sambrisko	return success;
362288748Sambrisko}
362388748Sambrisko
362488748Sambrisko/*
362588748Sambrisko * Put character to SWS0 wait for dwelltime x 50us for  echo .
362688748Sambrisko */
362788748Sambrisko
362888748Sambriskostatic int
3629150446Simpflashpchar(struct ifnet *ifp, int byte, int dwelltime)
363088748Sambrisko{
3631175446Sambrisko	int		echo;
3632175446Sambrisko	int		pollbusy, waittime;
3633175446Sambrisko	struct an_softc	*sc = ifp->if_softc;
363488748Sambrisko
363588748Sambrisko	byte |= 0x8000;
363688748Sambrisko
363788748Sambrisko	if (dwelltime == 0)
363888748Sambrisko		dwelltime = 200;
363988748Sambrisko
364088748Sambrisko	waittime = dwelltime;
364188748Sambrisko
364288748Sambrisko	/*
364388748Sambrisko	 * Wait for busy bit d15 to go false indicating buffer empty
364488748Sambrisko	 */
364588748Sambrisko	do {
3646108401Sambrisko		pollbusy = CSR_READ_2(sc, AN_SW0(sc->mpi350));
364788748Sambrisko
364888748Sambrisko		if (pollbusy & 0x8000) {
3649119163Sambrisko			FLASH_DELAY(sc, 50);
365088748Sambrisko			waittime -= 50;
365188748Sambrisko			continue;
365288748Sambrisko		} else
365388748Sambrisko			break;
365488748Sambrisko	}
365588748Sambrisko	while (waittime >= 0);
365688748Sambrisko
365788748Sambrisko	/* timeout for busy clear wait */
365888748Sambrisko
365988748Sambrisko	if (waittime <= 0) {
3660198987Sjhb		if_printf(ifp, "flash putchar busywait timeout!\n");
366188748Sambrisko		return -1;
366288748Sambrisko	}
366388748Sambrisko	/*
366488748Sambrisko	 * Port is clear now write byte and wait for it to echo back
366588748Sambrisko	 */
366688748Sambrisko	do {
3667108401Sambrisko		CSR_WRITE_2(sc, AN_SW0(sc->mpi350), byte);
3668119163Sambrisko		FLASH_DELAY(sc, 50);
366988748Sambrisko		dwelltime -= 50;
3670108401Sambrisko		echo = CSR_READ_2(sc, AN_SW1(sc->mpi350));
367188748Sambrisko	} while (dwelltime >= 0 && echo != byte);
367288748Sambrisko
367388748Sambrisko
3674108401Sambrisko	CSR_WRITE_2(sc, AN_SW1(sc->mpi350), 0);
367588748Sambrisko
367688748Sambrisko	return echo == byte;
367788748Sambrisko}
367888748Sambrisko
367988748Sambrisko/*
368088748Sambrisko * Transfer 32k of firmware data from user buffer to our buffer and send to
368188748Sambrisko * the card
368288748Sambrisko */
368388748Sambrisko
368488748Sambriskostatic int
3685150446Simpflashputbuf(struct ifnet *ifp)
368688748Sambrisko{
368788748Sambrisko	unsigned short *bufp;
3688175446Sambrisko	int		nwords;
3689175446Sambrisko	struct an_softc	*sc = ifp->if_softc;
369088748Sambrisko
369188748Sambrisko	/* Write stuff */
369288748Sambrisko
3693108401Sambrisko	bufp = sc->an_flash_buffer;
369488748Sambrisko
3695108401Sambrisko	if (!sc->mpi350) {
3696108401Sambrisko		CSR_WRITE_2(sc, AN_AUX_PAGE, 0x100);
3697108401Sambrisko		CSR_WRITE_2(sc, AN_AUX_OFFSET, 0);
369888748Sambrisko
3699108401Sambrisko		for (nwords = 0; nwords != FLASH_SIZE / 2; nwords++) {
3700108401Sambrisko			CSR_WRITE_2(sc, AN_AUX_DATA, bufp[nwords] & 0xffff);
3701108401Sambrisko		}
3702108401Sambrisko	} else {
3703108401Sambrisko		for (nwords = 0; nwords != FLASH_SIZE / 4; nwords++) {
3704175445Sambrisko			CSR_MEM_AUX_WRITE_4(sc, 0x8000,
3705108401Sambrisko				((u_int32_t *)bufp)[nwords] & 0xffff);
3706108401Sambrisko		}
370788748Sambrisko	}
370888748Sambrisko
3709108401Sambrisko	CSR_WRITE_2(sc, AN_SW0(sc->mpi350), 0x8000);
371088748Sambrisko
371188748Sambrisko	return 0;
371288748Sambrisko}
371388748Sambrisko
371488748Sambrisko/*
371588748Sambrisko * After flashing restart the card.
371688748Sambrisko */
371788748Sambrisko
371888748Sambriskostatic int
3719150446Simpflashrestart(struct ifnet *ifp)
372088748Sambrisko{
3721175446Sambrisko	int		status = 0;
3722175446Sambrisko	struct an_softc	*sc = ifp->if_softc;
372388748Sambrisko
3724119163Sambrisko	FLASH_DELAY(sc, 1024);		/* Added 12/7/00 */
372588748Sambrisko
3726199154Sjhb	an_init_locked(sc);
372788748Sambrisko
3728119163Sambrisko	FLASH_DELAY(sc, 1024);		/* Added 12/7/00 */
372988748Sambrisko	return status;
373088748Sambrisko}
373188748Sambrisko
373288748Sambrisko/*
373388748Sambrisko * Entry point for flash ioclt.
373488748Sambrisko */
373588748Sambrisko
373688748Sambriskostatic int
3737150446Simpflashcard(struct ifnet *ifp, struct aironet_ioctl *l_ioctl)
373888748Sambrisko{
3739175446Sambrisko	int		z = 0, status;
374088748Sambrisko	struct an_softc	*sc;
374188748Sambrisko
374288748Sambrisko	sc = ifp->if_softc;
3743108401Sambrisko	if (sc->mpi350) {
3744198987Sjhb		if_printf(ifp, "flashing not supported on MPI 350 yet\n");
3745108401Sambrisko		return(-1);
3746108401Sambrisko	}
374788748Sambrisko	status = l_ioctl->command;
374888748Sambrisko
374988748Sambrisko	switch (l_ioctl->command) {
375088748Sambrisko	case AIROFLSHRST:
375188748Sambrisko		return cmdreset(ifp);
375288748Sambrisko		break;
375388748Sambrisko	case AIROFLSHSTFL:
3754108401Sambrisko		if (sc->an_flash_buffer) {
3755108401Sambrisko			free(sc->an_flash_buffer, M_DEVBUF);
3756108401Sambrisko			sc->an_flash_buffer = NULL;
3757108401Sambrisko		}
3758111119Simp		sc->an_flash_buffer = malloc(FLASH_SIZE, M_DEVBUF, M_WAITOK);
3759108401Sambrisko		if (sc->an_flash_buffer)
3760108401Sambrisko			return setflashmode(ifp);
3761108401Sambrisko		else
3762108401Sambrisko			return ENOBUFS;
376388748Sambrisko		break;
376488748Sambrisko	case AIROFLSHGCHR:	/* Get char from aux */
3765300612Ssbruno		if (l_ioctl->len > sizeof(sc->areq)) {
3766300612Ssbruno			return -EINVAL;
3767300612Ssbruno		}
3768171692Savatar		AN_UNLOCK(sc);
3769144242Ssam		status = copyin(l_ioctl->data, &sc->areq, l_ioctl->len);
3770171692Savatar		AN_LOCK(sc);
3771144242Ssam		if (status)
3772144242Ssam			return status;
377388749Sambrisko		z = *(int *)&sc->areq;
377488748Sambrisko		if ((status = flashgchar(ifp, z, 8000)) == 1)
377588748Sambrisko			return 0;
377688748Sambrisko		else
377788748Sambrisko			return -1;
377888748Sambrisko	case AIROFLSHPCHR:	/* Send char to card. */
3779300612Ssbruno		if (l_ioctl->len > sizeof(sc->areq)) {
3780300612Ssbruno			return -EINVAL;
3781300612Ssbruno		}
3782171692Savatar		AN_UNLOCK(sc);
3783144242Ssam		status = copyin(l_ioctl->data, &sc->areq, l_ioctl->len);
3784171692Savatar		AN_LOCK(sc);
3785144242Ssam		if (status)
3786144242Ssam			return status;
378788749Sambrisko		z = *(int *)&sc->areq;
378888748Sambrisko		if ((status = flashpchar(ifp, z, 8000)) == -1)
378988748Sambrisko			return -EIO;
379088748Sambrisko		else
379188748Sambrisko			return 0;
379288748Sambrisko		break;
379388748Sambrisko	case AIROFLPUTBUF:	/* Send 32k to card */
3794108401Sambrisko		if (l_ioctl->len > FLASH_SIZE) {
3795198987Sjhb			if_printf(ifp, "Buffer to big, %x %x\n",
3796108401Sambrisko			       l_ioctl->len, FLASH_SIZE);
379788748Sambrisko			return -EINVAL;
379888748Sambrisko		}
3799171692Savatar		AN_UNLOCK(sc);
3800144242Ssam		status = copyin(l_ioctl->data, sc->an_flash_buffer, l_ioctl->len);
3801171692Savatar		AN_LOCK(sc);
3802144242Ssam		if (status)
3803144242Ssam			return status;
380488748Sambrisko
380588748Sambrisko		if ((status = flashputbuf(ifp)) != 0)
380688748Sambrisko			return -EIO;
380788748Sambrisko		else
380888748Sambrisko			return 0;
380988748Sambrisko		break;
381088748Sambrisko	case AIRORESTART:
381188748Sambrisko		if ((status = flashrestart(ifp)) != 0) {
3812198987Sjhb			if_printf(ifp, "FLASHRESTART returned %d\n", status);
381388748Sambrisko			return -EIO;
381488748Sambrisko		} else
381588748Sambrisko			return 0;
381688748Sambrisko
381788748Sambrisko		break;
381888748Sambrisko	default:
381988748Sambrisko		return -EINVAL;
382088748Sambrisko	}
382188748Sambrisko
382288748Sambrisko	return -EINVAL;
382388748Sambrisko}
3824