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: releng/10.3/sys/dev/an/if_an.c 265614 2014-05-07 21:38:33Z gavin $");
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>
11455992Swpaul#include <net/if_arp.h>
115152315Sru#include <net/if_dl.h>
11655992Swpaul#include <net/ethernet.h>
11755992Swpaul#include <net/if_types.h>
11877217Sphk#include <net/if_media.h>
11955992Swpaul
120116951Ssam#include <net80211/ieee80211_var.h>
121116951Ssam#include <net80211/ieee80211_ioctl.h>
122116951Ssam
12355992Swpaul#ifdef INET
12455992Swpaul#include <netinet/in.h>
12555992Swpaul#include <netinet/in_systm.h>
12655992Swpaul#include <netinet/in_var.h>
12755992Swpaul#include <netinet/ip.h>
12855992Swpaul#endif
12955992Swpaul
13055992Swpaul#include <net/bpf.h>
13155992Swpaul
13255992Swpaul#include <machine/md_var.h>
13355992Swpaul
13455992Swpaul#include <dev/an/if_aironet_ieee.h>
13555992Swpaul#include <dev/an/if_anreg.h>
13655992Swpaul
13755992Swpaul/* These are global because we need them in sys/pci/if_an_p.c. */
138150446Simpstatic void an_reset(struct an_softc *);
139150446Simpstatic int an_init_mpi350_desc(struct an_softc *);
140150446Simpstatic int an_ioctl(struct ifnet *, u_long, caddr_t);
141150446Simpstatic void an_init(void *);
142199154Sjhbstatic void an_init_locked(struct an_softc *);
143150446Simpstatic int an_init_tx_ring(struct an_softc *);
144150446Simpstatic void an_start(struct ifnet *);
145199154Sjhbstatic void an_start_locked(struct ifnet *);
146199154Sjhbstatic void an_watchdog(struct an_softc *);
147150446Simpstatic void an_rxeof(struct an_softc *);
148150446Simpstatic void an_txeof(struct an_softc *, int);
14955992Swpaul
150150446Simpstatic void an_promisc(struct an_softc *, int);
151150446Simpstatic int an_cmd(struct an_softc *, int, int);
152150446Simpstatic int an_cmd_struct(struct an_softc *, struct an_command *,
153150446Simp    struct an_reply *);
154150446Simpstatic int an_read_record(struct an_softc *, struct an_ltv_gen *);
155150446Simpstatic int an_write_record(struct an_softc *, struct an_ltv_gen *);
156150446Simpstatic int an_read_data(struct an_softc *, int, int, caddr_t, int);
157150446Simpstatic int an_write_data(struct an_softc *, int, int, caddr_t, int);
158150446Simpstatic int an_seek(struct an_softc *, int, int, int);
159150446Simpstatic int an_alloc_nicmem(struct an_softc *, int, int *);
160150446Simpstatic int an_dma_malloc(struct an_softc *, bus_size_t, struct an_dma_alloc *,
161150446Simp    int);
162150446Simpstatic void an_dma_free(struct an_softc *, struct an_dma_alloc *);
163150446Simpstatic void an_dma_malloc_cb(void *, bus_dma_segment_t *, int, int);
164150446Simpstatic void an_stats_update(void *);
165150446Simpstatic void an_setdef(struct an_softc *, struct an_req *);
16655992Swpaul#ifdef ANCACHE
167150446Simpstatic void an_cache_store(struct an_softc *, struct ether_header *,
168150446Simp    struct mbuf *, u_int8_t, u_int8_t);
16955992Swpaul#endif
17055992Swpaul
17188748Sambrisko/* function definitions for use with the Cisco's Linux configuration
17288748Sambrisko   utilities
17388748Sambrisko*/
17488748Sambrisko
17592739Salfredstatic int readrids(struct ifnet*, struct aironet_ioctl*);
17692739Salfredstatic int writerids(struct ifnet*, struct aironet_ioctl*);
17792739Salfredstatic int flashcard(struct ifnet*, struct aironet_ioctl*);
17888748Sambrisko
17992739Salfredstatic int cmdreset(struct ifnet *);
18092739Salfredstatic int setflashmode(struct ifnet *);
18192739Salfredstatic int flashgchar(struct ifnet *,int,int);
18292739Salfredstatic int flashpchar(struct ifnet *,int,int);
18392739Salfredstatic int flashputbuf(struct ifnet *);
18492739Salfredstatic int flashrestart(struct ifnet *);
18592739Salfredstatic int WaitBusy(struct ifnet *, int);
18692739Salfredstatic int unstickbusy(struct ifnet *);
18788748Sambrisko
18892739Salfredstatic void an_dump_record	(struct an_softc *,struct an_ltv_gen *,
18992739Salfred				    char *);
19078639Sbrooks
19192739Salfredstatic int an_media_change	(struct ifnet *);
19292739Salfredstatic void an_media_status	(struct ifnet *, struct ifmediareq *);
19377217Sphk
19478639Sbrooksstatic int	an_dump = 0;
195108401Sambriskostatic int	an_cache_mode = 0;
19688748Sambrisko
197108401Sambrisko#define DBM 0
198108401Sambrisko#define PERCENT 1
199108401Sambrisko#define RAW 2
200108401Sambrisko
20183269Sbrooksstatic char an_conf[256];
202108401Sambriskostatic char an_conf_cache[256];
20383269Sbrooks
20483269Sbrooks/* sysctl vars */
205108401Sambrisko
206227309Sedstatic SYSCTL_NODE(_hw, OID_AUTO, an, CTLFLAG_RD, 0,
207227309Sed    "Wireless driver parameters");
20883269Sbrooks
209106937Ssam/* XXX violate ethernet/netgraph callback hooks */
210106937Ssamextern	void	(*ng_ether_attach_p)(struct ifnet *ifp);
211106937Ssamextern	void	(*ng_ether_detach_p)(struct ifnet *ifp);
212106937Ssam
21383269Sbrooksstatic int
21483269Sbrookssysctl_an_dump(SYSCTL_HANDLER_ARGS)
21583269Sbrooks{
21683269Sbrooks	int	error, r, last;
21783269Sbrooks	char 	*s = an_conf;
21883270Sbrooks
21983269Sbrooks	last = an_dump;
22083269Sbrooks
22183270Sbrooks	switch (an_dump) {
22283269Sbrooks	case 0:
223108401Sambrisko		strcpy(an_conf, "off");
22483269Sbrooks		break;
22583269Sbrooks	case 1:
226108401Sambrisko		strcpy(an_conf, "type");
22783269Sbrooks		break;
22883269Sbrooks	case 2:
229108401Sambrisko		strcpy(an_conf, "dump");
23083269Sbrooks		break;
23183269Sbrooks	default:
23283269Sbrooks		snprintf(an_conf, 5, "%x", an_dump);
23383269Sbrooks		break;
23483269Sbrooks	}
23583269Sbrooks
23683269Sbrooks	error = sysctl_handle_string(oidp, an_conf, sizeof(an_conf), req);
23783269Sbrooks
238108401Sambrisko	if (strncmp(an_conf,"off", 3) == 0) {
23983269Sbrooks		an_dump = 0;
24083269Sbrooks 	}
24183270Sbrooks	if (strncmp(an_conf,"dump", 4) == 0) {
24283269Sbrooks		an_dump = 1;
24383269Sbrooks	}
24483270Sbrooks	if (strncmp(an_conf,"type", 4) == 0) {
24583269Sbrooks		an_dump = 2;
24683269Sbrooks	}
24783270Sbrooks	if (*s == 'f') {
24883269Sbrooks		r = 0;
24983270Sbrooks		for (;;s++) {
25083270Sbrooks			if ((*s >= '0') && (*s <= '9')) {
25183269Sbrooks				r = r * 16 + (*s - '0');
25283270Sbrooks			} else if ((*s >= 'a') && (*s <= 'f')) {
25383269Sbrooks				r = r * 16 + (*s - 'a' + 10);
25483270Sbrooks			} else {
25583270Sbrooks				break;
25683269Sbrooks			}
25783269Sbrooks		}
25883269Sbrooks		an_dump = r;
25983269Sbrooks	}
26083269Sbrooks	if (an_dump != last)
26183269Sbrooks		printf("Sysctl changed for Aironet driver\n");
26283269Sbrooks
26383269Sbrooks	return error;
26483269Sbrooks}
26583269Sbrooks
266110531SambriskoSYSCTL_PROC(_hw_an, OID_AUTO, an_dump, CTLTYPE_STRING | CTLFLAG_RW,
267175446Sambrisko	    0, sizeof(an_conf), sysctl_an_dump, "A", "");
26883269Sbrooks
269108401Sambriskostatic int
270108401Sambriskosysctl_an_cache_mode(SYSCTL_HANDLER_ARGS)
271108401Sambrisko{
272108401Sambrisko	int	error, last;
273108401Sambrisko
274108401Sambrisko	last = an_cache_mode;
275108401Sambrisko
276108401Sambrisko	switch (an_cache_mode) {
277108401Sambrisko	case 1:
278108401Sambrisko		strcpy(an_conf_cache, "per");
279108401Sambrisko		break;
280108401Sambrisko	case 2:
281108401Sambrisko		strcpy(an_conf_cache, "raw");
282108401Sambrisko		break;
283108401Sambrisko	default:
284108401Sambrisko		strcpy(an_conf_cache, "dbm");
285108401Sambrisko		break;
286108401Sambrisko	}
287108401Sambrisko
288175445Sambrisko	error = sysctl_handle_string(oidp, an_conf_cache,
289108401Sambrisko			sizeof(an_conf_cache), req);
290108401Sambrisko
291108401Sambrisko	if (strncmp(an_conf_cache,"dbm", 3) == 0) {
292108401Sambrisko		an_cache_mode = 0;
293108401Sambrisko	}
294108401Sambrisko	if (strncmp(an_conf_cache,"per", 3) == 0) {
295108401Sambrisko		an_cache_mode = 1;
296108401Sambrisko 	}
297108401Sambrisko	if (strncmp(an_conf_cache,"raw", 3) == 0) {
298108401Sambrisko		an_cache_mode = 2;
299108401Sambrisko	}
300108401Sambrisko
301108401Sambrisko	return error;
302108401Sambrisko}
303108401Sambrisko
304110531SambriskoSYSCTL_PROC(_hw_an, OID_AUTO, an_cache_mode, CTLTYPE_STRING | CTLFLAG_RW,
305175446Sambrisko	    0, sizeof(an_conf_cache), sysctl_an_cache_mode, "A", "");
306108401Sambrisko
30783270Sbrooks/*
308175445Sambrisko * Setup the lock for PCI attachment since it skips the an_probe
309175445Sambrisko * function.  We need to setup the lock in an_probe since some
310175445Sambrisko * operations need the lock.  So we might as well create the
311175445Sambrisko * lock in the probe.
312175445Sambrisko */
313175445Sambriskoint
314175445Sambriskoan_pci_probe(device_t dev)
315175445Sambrisko{
316175446Sambrisko	struct an_softc *sc = device_get_softc(dev);
317175445Sambrisko
318175445Sambrisko	mtx_init(&sc->an_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
319199154Sjhb	    MTX_DEF);
320175445Sambrisko
321175445Sambrisko	return(0);
322175445Sambrisko}
323175445Sambrisko
324175445Sambrisko/*
32555992Swpaul * We probe for an Aironet 4500/4800 card by attempting to
32655992Swpaul * read the default SSID list. On reset, the first entry in
32755992Swpaul * the SSID list will contain the name "tsunami." If we don't
32855992Swpaul * find this, then there's no card present.
32955992Swpaul */
33083270Sbrooksint
331150446Simpan_probe(device_t dev)
33255992Swpaul{
333175446Sambrisko	struct an_softc *sc = device_get_softc(dev);
334119156Sambrisko	struct an_ltv_ssidlist_new	ssid;
33555992Swpaul	int	error;
33655992Swpaul
33755992Swpaul	bzero((char *)&ssid, sizeof(ssid));
33855992Swpaul
33955992Swpaul	error = an_alloc_port(dev, 0, AN_IOSIZ);
34078639Sbrooks	if (error != 0)
34155992Swpaul		return (0);
34255992Swpaul
34355992Swpaul	/* can't do autoprobing */
34455992Swpaul	if (rman_get_start(sc->port_res) == -1)
34555992Swpaul		return(0);
34655992Swpaul
34755992Swpaul	/*
34855992Swpaul	 * We need to fake up a softc structure long enough
34955992Swpaul	 * to be able to issue commands and call some of the
35055992Swpaul	 * other routines.
35155992Swpaul	 */
35255992Swpaul	ssid.an_len = sizeof(ssid);
35355992Swpaul	ssid.an_type = AN_RID_SSIDLIST;
35455992Swpaul
355175446Sambrisko	/* Make sure interrupts are disabled. */
356119156Sambrisko	sc->mpi350 = 0;
357175446Sambrisko	CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), 0);
358175446Sambrisko	CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), 0xFFFF);
35955992Swpaul
360265614Sgavin	sc->an_dev = dev;
361175445Sambrisko	mtx_init(&sc->an_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
362199154Sjhb	    MTX_DEF);
363175445Sambrisko	AN_LOCK(sc);
36455992Swpaul	an_reset(sc);
36555992Swpaul
366175445Sambrisko	if (an_cmd(sc, AN_CMD_READCFG, 0)) {
367175445Sambrisko		AN_UNLOCK(sc);
368175445Sambrisko		goto fail;
369175445Sambrisko	}
37055992Swpaul
371175445Sambrisko	if (an_read_record(sc, (struct an_ltv_gen *)&ssid)) {
372175445Sambrisko		AN_UNLOCK(sc);
373175445Sambrisko		goto fail;
374175445Sambrisko	}
37555992Swpaul
37668692Swpaul	/* See if the ssid matches what we expect ... but doesn't have to */
377175445Sambrisko	if (strcmp(ssid.an_entry[0].an_ssid, AN_DEF_SSID)) {
378175445Sambrisko		AN_UNLOCK(sc);
379175445Sambrisko		goto fail;
380175445Sambrisko	}
38183270Sbrooks
382175445Sambrisko	AN_UNLOCK(sc);
38355992Swpaul	return(AN_IOSIZ);
384175445Sambriskofail:
385175445Sambrisko	mtx_destroy(&sc->an_mtx);
386175445Sambrisko	return(0);
38755992Swpaul}
38855992Swpaul
38955992Swpaul/*
39055992Swpaul * Allocate a port resource with the given resource id.
39155992Swpaul */
39255992Swpaulint
393150446Simpan_alloc_port(device_t dev, int rid, int size)
39455992Swpaul{
39555992Swpaul	struct an_softc *sc = device_get_softc(dev);
39655992Swpaul	struct resource *res;
39755992Swpaul
39855992Swpaul	res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
39955992Swpaul				 0ul, ~0ul, size, RF_ACTIVE);
40055992Swpaul	if (res) {
40155992Swpaul		sc->port_rid = rid;
40255992Swpaul		sc->port_res = res;
40355992Swpaul		return (0);
40455992Swpaul	} else {
40555992Swpaul		return (ENOENT);
40655992Swpaul	}
40755992Swpaul}
40855992Swpaul
40955992Swpaul/*
410108401Sambrisko * Allocate a memory resource with the given resource id.
411108401Sambrisko */
412108401Sambriskoint an_alloc_memory(device_t dev, int rid, int size)
413108401Sambrisko{
414108401Sambrisko	struct an_softc *sc = device_get_softc(dev);
415108401Sambrisko	struct resource *res;
416108401Sambrisko
417108401Sambrisko	res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
418108401Sambrisko				 0ul, ~0ul, size, RF_ACTIVE);
419108401Sambrisko	if (res) {
420108401Sambrisko		sc->mem_rid = rid;
421108401Sambrisko		sc->mem_res = res;
422108401Sambrisko		sc->mem_used = size;
423108401Sambrisko		return (0);
424108401Sambrisko	} else {
425108401Sambrisko		return (ENOENT);
426108401Sambrisko	}
427108401Sambrisko}
428108401Sambrisko
429108401Sambrisko/*
430108401Sambrisko * Allocate a auxilary memory resource with the given resource id.
431108401Sambrisko */
432108401Sambriskoint an_alloc_aux_memory(device_t dev, int rid, int size)
433108401Sambrisko{
434108401Sambrisko	struct an_softc *sc = device_get_softc(dev);
435108401Sambrisko	struct resource *res;
436108401Sambrisko
437108401Sambrisko	res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
438108401Sambrisko				 0ul, ~0ul, size, RF_ACTIVE);
439108401Sambrisko	if (res) {
440108401Sambrisko		sc->mem_aux_rid = rid;
441108401Sambrisko		sc->mem_aux_res = res;
442108401Sambrisko		sc->mem_aux_used = size;
443108401Sambrisko		return (0);
444108401Sambrisko	} else {
445108401Sambrisko		return (ENOENT);
446108401Sambrisko	}
447108401Sambrisko}
448108401Sambrisko
449108401Sambrisko/*
45055992Swpaul * Allocate an irq resource with the given resource id.
45155992Swpaul */
45255992Swpaulint
453150446Simpan_alloc_irq(device_t dev, int rid, int flags)
45455992Swpaul{
45555992Swpaul	struct an_softc *sc = device_get_softc(dev);
45655992Swpaul	struct resource *res;
45755992Swpaul
458127135Snjl	res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
459127135Snjl				     (RF_ACTIVE | flags));
46055992Swpaul	if (res) {
46155992Swpaul		sc->irq_rid = rid;
46255992Swpaul		sc->irq_res = res;
46355992Swpaul		return (0);
46455992Swpaul	} else {
46555992Swpaul		return (ENOENT);
46655992Swpaul	}
46755992Swpaul}
46855992Swpaul
469108401Sambriskostatic void
470150446Simpan_dma_malloc_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
471108401Sambrisko{
472108401Sambrisko	bus_addr_t *paddr = (bus_addr_t*) arg;
473108401Sambrisko	*paddr = segs->ds_addr;
474108401Sambrisko}
475108401Sambrisko
47655992Swpaul/*
477108401Sambrisko * Alloc DMA memory and set the pointer to it
478108401Sambrisko */
479108401Sambriskostatic int
480150446Simpan_dma_malloc(struct an_softc *sc, bus_size_t size, struct an_dma_alloc *dma,
481150446Simp    int mapflags)
482108401Sambrisko{
483108401Sambrisko	int r;
484108401Sambrisko
485108401Sambrisko	r = bus_dmamap_create(sc->an_dtag, BUS_DMA_NOWAIT, &dma->an_dma_map);
486108401Sambrisko	if (r != 0)
487108401Sambrisko		goto fail_0;
488108401Sambrisko
489108401Sambrisko	r = bus_dmamem_alloc(sc->an_dtag, (void**) &dma->an_dma_vaddr,
490108401Sambrisko			     BUS_DMA_NOWAIT, &dma->an_dma_map);
491108401Sambrisko	if (r != 0)
492108401Sambrisko		goto fail_1;
493108401Sambrisko
494108401Sambrisko	r = bus_dmamap_load(sc->an_dtag, dma->an_dma_map, dma->an_dma_vaddr,
495175446Sambrisko			    size,
496108401Sambrisko			    an_dma_malloc_cb,
497108401Sambrisko			    &dma->an_dma_paddr,
498108401Sambrisko			    mapflags | BUS_DMA_NOWAIT);
499108401Sambrisko	if (r != 0)
500108401Sambrisko		goto fail_2;
501108401Sambrisko
502108401Sambrisko	dma->an_dma_size = size;
503108401Sambrisko	return (0);
504108401Sambrisko
505108401Sambriskofail_2:
506108401Sambrisko	bus_dmamap_unload(sc->an_dtag, dma->an_dma_map);
507108401Sambriskofail_1:
508108401Sambrisko	bus_dmamem_free(sc->an_dtag, dma->an_dma_vaddr, dma->an_dma_map);
509108401Sambriskofail_0:
510108401Sambrisko	bus_dmamap_destroy(sc->an_dtag, dma->an_dma_map);
511108401Sambrisko	dma->an_dma_map = NULL;
512108401Sambrisko	return (r);
513108401Sambrisko}
514108401Sambrisko
515108401Sambriskostatic void
516150446Simpan_dma_free(struct an_softc *sc, struct an_dma_alloc *dma)
517108401Sambrisko{
518108401Sambrisko	bus_dmamap_unload(sc->an_dtag, dma->an_dma_map);
519108401Sambrisko	bus_dmamem_free(sc->an_dtag, dma->an_dma_vaddr, dma->an_dma_map);
520123978Sambrisko	dma->an_dma_vaddr = 0;
521108401Sambrisko	bus_dmamap_destroy(sc->an_dtag, dma->an_dma_map);
522108401Sambrisko}
523108401Sambrisko
524108401Sambrisko/*
52555992Swpaul * Release all resources
52655992Swpaul */
52755992Swpaulvoid
528150446Simpan_release_resources(device_t dev)
52955992Swpaul{
53055992Swpaul	struct an_softc *sc = device_get_softc(dev);
531108401Sambrisko	int i;
53255992Swpaul
53355992Swpaul	if (sc->port_res) {
53455992Swpaul		bus_release_resource(dev, SYS_RES_IOPORT,
53555992Swpaul				     sc->port_rid, sc->port_res);
53655992Swpaul		sc->port_res = 0;
53755992Swpaul	}
538108401Sambrisko	if (sc->mem_res) {
539108401Sambrisko		bus_release_resource(dev, SYS_RES_MEMORY,
540108401Sambrisko				     sc->mem_rid, sc->mem_res);
541108401Sambrisko		sc->mem_res = 0;
542108401Sambrisko	}
543108401Sambrisko	if (sc->mem_aux_res) {
544108401Sambrisko		bus_release_resource(dev, SYS_RES_MEMORY,
545108401Sambrisko				     sc->mem_aux_rid, sc->mem_aux_res);
546108401Sambrisko		sc->mem_aux_res = 0;
547108401Sambrisko	}
54855992Swpaul	if (sc->irq_res) {
54955992Swpaul		bus_release_resource(dev, SYS_RES_IRQ,
55055992Swpaul				     sc->irq_rid, sc->irq_res);
55155992Swpaul		sc->irq_res = 0;
55255992Swpaul	}
553108401Sambrisko	if (sc->an_rid_buffer.an_dma_paddr) {
554108401Sambrisko		an_dma_free(sc, &sc->an_rid_buffer);
555108401Sambrisko	}
556108401Sambrisko	for (i = 0; i < AN_MAX_RX_DESC; i++)
557108401Sambrisko		if (sc->an_rx_buffer[i].an_dma_paddr) {
558108401Sambrisko			an_dma_free(sc, &sc->an_rx_buffer[i]);
559108401Sambrisko		}
560108401Sambrisko	for (i = 0; i < AN_MAX_TX_DESC; i++)
561108401Sambrisko		if (sc->an_tx_buffer[i].an_dma_paddr) {
562108401Sambrisko			an_dma_free(sc, &sc->an_tx_buffer[i]);
563108401Sambrisko		}
564108401Sambrisko	if (sc->an_dtag) {
565108401Sambrisko		bus_dma_tag_destroy(sc->an_dtag);
566108401Sambrisko	}
567108401Sambrisko
56855992Swpaul}
56955992Swpaul
57083270Sbrooksint
571150446Simpan_init_mpi350_desc(struct an_softc *sc)
572108401Sambrisko{
573108401Sambrisko	struct an_command	cmd_struct;
574108401Sambrisko	struct an_reply		reply;
575108401Sambrisko	struct an_card_rid_desc an_rid_desc;
576108401Sambrisko	struct an_card_rx_desc	an_rx_desc;
577108401Sambrisko	struct an_card_tx_desc	an_tx_desc;
578108401Sambrisko	int			i, desc;
579108401Sambrisko
580175445Sambrisko	AN_LOCK_ASSERT(sc);
581108401Sambrisko	if(!sc->an_rid_buffer.an_dma_paddr)
582108401Sambrisko		an_dma_malloc(sc, AN_RID_BUFFER_SIZE,
583108401Sambrisko				 &sc->an_rid_buffer, 0);
584108401Sambrisko	for (i = 0; i < AN_MAX_RX_DESC; i++)
585108401Sambrisko		if(!sc->an_rx_buffer[i].an_dma_paddr)
586108401Sambrisko			an_dma_malloc(sc, AN_RX_BUFFER_SIZE,
587108401Sambrisko				      &sc->an_rx_buffer[i], 0);
588108401Sambrisko	for (i = 0; i < AN_MAX_TX_DESC; i++)
589108401Sambrisko		if(!sc->an_tx_buffer[i].an_dma_paddr)
590108401Sambrisko			an_dma_malloc(sc, AN_TX_BUFFER_SIZE,
591108401Sambrisko				      &sc->an_tx_buffer[i], 0);
592108401Sambrisko
593108401Sambrisko	/*
594108401Sambrisko	 * Allocate RX descriptor
595108401Sambrisko	 */
596108401Sambrisko	bzero(&reply,sizeof(reply));
597108401Sambrisko	cmd_struct.an_cmd   = AN_CMD_ALLOC_DESC;
598108401Sambrisko	cmd_struct.an_parm0 = AN_DESCRIPTOR_RX;
599108401Sambrisko	cmd_struct.an_parm1 = AN_RX_DESC_OFFSET;
600108401Sambrisko	cmd_struct.an_parm2 = AN_MAX_RX_DESC;
601108401Sambrisko	if (an_cmd_struct(sc, &cmd_struct, &reply)) {
602198987Sjhb		if_printf(sc->an_ifp, "failed to allocate RX descriptor\n");
603108401Sambrisko		return(EIO);
604108401Sambrisko	}
605108401Sambrisko
606108401Sambrisko	for (desc = 0; desc < AN_MAX_RX_DESC; desc++) {
607108401Sambrisko		bzero(&an_rx_desc, sizeof(an_rx_desc));
608108401Sambrisko		an_rx_desc.an_valid = 1;
609108401Sambrisko		an_rx_desc.an_len = AN_RX_BUFFER_SIZE;
610108401Sambrisko		an_rx_desc.an_done = 0;
611108401Sambrisko		an_rx_desc.an_phys = sc->an_rx_buffer[desc].an_dma_paddr;
612108401Sambrisko
613108401Sambrisko		for (i = 0; i < sizeof(an_rx_desc) / 4; i++)
614155321Simp			CSR_MEM_AUX_WRITE_4(sc, AN_RX_DESC_OFFSET
615155321Simp			    + (desc * sizeof(an_rx_desc))
616155321Simp			    + (i * 4),
617155321Simp			    ((u_int32_t *)(void *)&an_rx_desc)[i]);
618108401Sambrisko	}
619108401Sambrisko
620108401Sambrisko	/*
621108401Sambrisko	 * Allocate TX descriptor
622108401Sambrisko	 */
623108401Sambrisko
624108401Sambrisko	bzero(&reply,sizeof(reply));
625108401Sambrisko	cmd_struct.an_cmd   = AN_CMD_ALLOC_DESC;
626108401Sambrisko	cmd_struct.an_parm0 = AN_DESCRIPTOR_TX;
627108401Sambrisko	cmd_struct.an_parm1 = AN_TX_DESC_OFFSET;
628108401Sambrisko	cmd_struct.an_parm2 = AN_MAX_TX_DESC;
629108401Sambrisko	if (an_cmd_struct(sc, &cmd_struct, &reply)) {
630198987Sjhb		if_printf(sc->an_ifp, "failed to allocate TX descriptor\n");
631108401Sambrisko		return(EIO);
632108401Sambrisko	}
633108401Sambrisko
634108401Sambrisko	for (desc = 0; desc < AN_MAX_TX_DESC; desc++) {
635108401Sambrisko		bzero(&an_tx_desc, sizeof(an_tx_desc));
636108401Sambrisko		an_tx_desc.an_offset = 0;
637108401Sambrisko		an_tx_desc.an_eoc = 0;
638108401Sambrisko		an_tx_desc.an_valid = 0;
639108401Sambrisko		an_tx_desc.an_len = 0;
640108401Sambrisko		an_tx_desc.an_phys = sc->an_tx_buffer[desc].an_dma_paddr;
641108401Sambrisko
642108401Sambrisko		for (i = 0; i < sizeof(an_tx_desc) / 4; i++)
643108401Sambrisko			CSR_MEM_AUX_WRITE_4(sc, AN_TX_DESC_OFFSET
644155321Simp			    + (desc * sizeof(an_tx_desc))
645155321Simp			    + (i * 4),
646155321Simp			    ((u_int32_t *)(void *)&an_tx_desc)[i]);
647108401Sambrisko	}
648108401Sambrisko
649108401Sambrisko	/*
650108401Sambrisko	 * Allocate RID descriptor
651108401Sambrisko	 */
652108401Sambrisko
653108401Sambrisko	bzero(&reply,sizeof(reply));
654108401Sambrisko	cmd_struct.an_cmd   = AN_CMD_ALLOC_DESC;
655108401Sambrisko	cmd_struct.an_parm0 = AN_DESCRIPTOR_HOSTRW;
656108401Sambrisko	cmd_struct.an_parm1 = AN_HOST_DESC_OFFSET;
657108401Sambrisko	cmd_struct.an_parm2 = 1;
658108401Sambrisko	if (an_cmd_struct(sc, &cmd_struct, &reply)) {
659198987Sjhb		if_printf(sc->an_ifp, "failed to allocate host descriptor\n");
660108401Sambrisko		return(EIO);
661108401Sambrisko	}
662108401Sambrisko
663108401Sambrisko	bzero(&an_rid_desc, sizeof(an_rid_desc));
664108401Sambrisko	an_rid_desc.an_valid = 1;
665108401Sambrisko	an_rid_desc.an_len = AN_RID_BUFFER_SIZE;
666108401Sambrisko	an_rid_desc.an_rid = 0;
667108401Sambrisko	an_rid_desc.an_phys = sc->an_rid_buffer.an_dma_paddr;
668108401Sambrisko
669108401Sambrisko	for (i = 0; i < sizeof(an_rid_desc) / 4; i++)
670175445Sambrisko		CSR_MEM_AUX_WRITE_4(sc, AN_HOST_DESC_OFFSET + i * 4,
671155321Simp				    ((u_int32_t *)(void *)&an_rid_desc)[i]);
672108401Sambrisko
673108401Sambrisko	return(0);
674108401Sambrisko}
675108401Sambrisko
676108401Sambriskoint
677198995Sjhban_attach(struct an_softc *sc, int flags)
67855992Swpaul{
679147256Sbrooks	struct ifnet		*ifp;
680113316Simp	int			error = EIO;
681110253Sambrisko	int			i, nrate, mword;
682110253Sambrisko	u_int8_t		r;
68355992Swpaul
684147380Sdelphij	ifp = sc->an_ifp = if_alloc(IFT_ETHER);
685147256Sbrooks	if (ifp == NULL) {
686198987Sjhb		device_printf(sc->an_dev, "can not if_alloc()\n");
687147256Sbrooks		goto fail;
688147256Sbrooks	}
689265614Sgavin	ifp->if_softc = sc;
690265614Sgavin	if_initname(ifp, device_get_name(sc->an_dev),
691265614Sgavin	    device_get_unit(sc->an_dev));
692175445Sambrisko
69355992Swpaul	sc->an_gone = 0;
69455992Swpaul	sc->an_associated = 0;
69583269Sbrooks	sc->an_monitor = 0;
69683269Sbrooks	sc->an_was_monitor = 0;
697108401Sambrisko	sc->an_flash_buffer = NULL;
69855992Swpaul
69955992Swpaul	/* Reset the NIC. */
700175445Sambrisko	AN_LOCK(sc);
70155992Swpaul	an_reset(sc);
702110104Sambrisko	if (sc->mpi350) {
703108401Sambrisko		error = an_init_mpi350_desc(sc);
704108401Sambrisko		if (error)
705113316Simp			goto fail;
706108401Sambrisko	}
70755992Swpaul
70855992Swpaul	/* Load factory config */
70955992Swpaul	if (an_cmd(sc, AN_CMD_READCFG, 0)) {
710198987Sjhb		device_printf(sc->an_dev, "failed to load config data\n");
711113316Simp		goto fail;
71255992Swpaul	}
71355992Swpaul
71455992Swpaul	/* Read the current configuration */
71555992Swpaul	sc->an_config.an_type = AN_RID_GENCONFIG;
71655992Swpaul	sc->an_config.an_len = sizeof(struct an_ltv_genconfig);
71755992Swpaul	if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_config)) {
718198987Sjhb		device_printf(sc->an_dev, "read record failed\n");
719113316Simp		goto fail;
72055992Swpaul	}
72155992Swpaul
72255992Swpaul	/* Read the card capabilities */
72355992Swpaul	sc->an_caps.an_type = AN_RID_CAPABILITIES;
72455992Swpaul	sc->an_caps.an_len = sizeof(struct an_ltv_caps);
72555992Swpaul	if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_caps)) {
726198987Sjhb		device_printf(sc->an_dev, "read record failed\n");
727113316Simp		goto fail;
72855992Swpaul	}
72955992Swpaul
73055992Swpaul	/* Read ssid list */
73155992Swpaul	sc->an_ssidlist.an_type = AN_RID_SSIDLIST;
732119156Sambrisko	sc->an_ssidlist.an_len = sizeof(struct an_ltv_ssidlist_new);
73355992Swpaul	if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_ssidlist)) {
734198987Sjhb		device_printf(sc->an_dev, "read record failed\n");
735113316Simp		goto fail;
73655992Swpaul	}
73755992Swpaul
73855992Swpaul	/* Read AP list */
73955992Swpaul	sc->an_aplist.an_type = AN_RID_APLIST;
74055992Swpaul	sc->an_aplist.an_len = sizeof(struct an_ltv_aplist);
74155992Swpaul	if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_aplist)) {
742198987Sjhb		device_printf(sc->an_dev, "read record failed\n");
743113316Simp		goto fail;
74455992Swpaul	}
74555992Swpaul
746108401Sambrisko#ifdef ANCACHE
747108401Sambrisko	/* Read the RSSI <-> dBm map */
748108401Sambrisko	sc->an_have_rssimap = 0;
749108401Sambrisko	if (sc->an_caps.an_softcaps & 8) {
750108401Sambrisko		sc->an_rssimap.an_type = AN_RID_RSSI_MAP;
751108401Sambrisko		sc->an_rssimap.an_len = sizeof(struct an_ltv_rssi_map);
752108401Sambrisko		if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_rssimap)) {
753198987Sjhb			device_printf(sc->an_dev,
754198987Sjhb			    "unable to get RSSI <-> dBM map\n");
755108401Sambrisko		} else {
756198987Sjhb			device_printf(sc->an_dev, "got RSSI <-> dBM map\n");
757108401Sambrisko			sc->an_have_rssimap = 1;
758108401Sambrisko		}
759108401Sambrisko	} else {
760198987Sjhb		device_printf(sc->an_dev, "no RSSI <-> dBM map\n");
761108401Sambrisko	}
762108401Sambrisko#endif
763175445Sambrisko	AN_UNLOCK(sc);
764108401Sambrisko
76555992Swpaul	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
76655992Swpaul	ifp->if_ioctl = an_ioctl;
76755992Swpaul	ifp->if_start = an_start;
76855992Swpaul	ifp->if_init = an_init;
76955992Swpaul	ifp->if_baudrate = 10000000;
770207554Ssobomax	IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
771207554Ssobomax	ifp->if_snd.ifq_drv_maxlen = ifqmaxlen;
772132986Smlaier	IFQ_SET_READY(&ifp->if_snd);
77355992Swpaul
77455992Swpaul	bzero(sc->an_config.an_nodename, sizeof(sc->an_config.an_nodename));
77555992Swpaul	bcopy(AN_DEFAULT_NODENAME, sc->an_config.an_nodename,
77655992Swpaul	    sizeof(AN_DEFAULT_NODENAME) - 1);
77755992Swpaul
778119156Sambrisko	bzero(sc->an_ssidlist.an_entry[0].an_ssid,
779119156Sambrisko	      sizeof(sc->an_ssidlist.an_entry[0].an_ssid));
780119156Sambrisko	bcopy(AN_DEFAULT_NETNAME, sc->an_ssidlist.an_entry[0].an_ssid,
78155992Swpaul	    sizeof(AN_DEFAULT_NETNAME) - 1);
782119156Sambrisko	sc->an_ssidlist.an_entry[0].an_len = strlen(AN_DEFAULT_NETNAME);
78355992Swpaul
78455992Swpaul	sc->an_config.an_opmode =
78574144Sassar	    AN_OPMODE_INFRASTRUCTURE_STATION;
78655992Swpaul
78755992Swpaul	sc->an_tx_rate = 0;
78855992Swpaul	bzero((char *)&sc->an_stats, sizeof(sc->an_stats));
78955992Swpaul
790110253Sambrisko	nrate = 8;
791110253Sambrisko
79277217Sphk	ifmedia_init(&sc->an_ifmedia, 0, an_media_change, an_media_status);
793110253Sambrisko	if_printf(ifp, "supported rates: ");
794110253Sambrisko#define	ADD(s, o)	ifmedia_add(&sc->an_ifmedia, \
795110253Sambrisko	IFM_MAKEWORD(IFM_IEEE80211, (s), (o), 0), 0, NULL)
796110253Sambrisko	ADD(IFM_AUTO, 0);
797110253Sambrisko	ADD(IFM_AUTO, IFM_IEEE80211_ADHOC);
798110253Sambrisko	for (i = 0; i < nrate; i++) {
799110253Sambrisko		r = sc->an_caps.an_rates[i];
800228621Sbschmidt		mword = ieee80211_rate2media(NULL, r, IEEE80211_MODE_AUTO);
801110253Sambrisko		if (mword == 0)
802110253Sambrisko			continue;
803110253Sambrisko		printf("%s%d%sMbps", (i != 0 ? " " : ""),
804110253Sambrisko		    (r & IEEE80211_RATE_VAL) / 2, ((r & 0x1) != 0 ? ".5" : ""));
805110253Sambrisko		ADD(mword, 0);
806110253Sambrisko		ADD(mword, IFM_IEEE80211_ADHOC);
80777217Sphk	}
808110253Sambrisko	printf("\n");
809175445Sambrisko	ifmedia_set(&sc->an_ifmedia, IFM_MAKEWORD(IFM_IEEE80211,
810110253Sambrisko	    IFM_AUTO, 0, 0));
811110253Sambrisko#undef ADD
81277217Sphk
81355992Swpaul	/*
81463090Sarchie	 * Call MI attach routine.
81555992Swpaul	 */
816147256Sbrooks
817147256Sbrooks	ether_ifattach(ifp, sc->an_caps.an_oemaddr);
818173668Savatar	callout_init_mtx(&sc->an_stat_ch, &sc->an_mtx, 0);
81955992Swpaul
82055992Swpaul	return(0);
821175445Sambriskofail:
822175445Sambrisko	AN_UNLOCK(sc);
823113316Simp	mtx_destroy(&sc->an_mtx);
824147256Sbrooks	if (ifp != NULL)
825147256Sbrooks		if_free(ifp);
826113316Simp	return(error);
82755992Swpaul}
82855992Swpaul
829123978Sambriskoint
830123978Sambriskoan_detach(device_t dev)
831123978Sambrisko{
832123978Sambrisko	struct an_softc		*sc = device_get_softc(dev);
833147256Sbrooks	struct ifnet		*ifp = sc->an_ifp;
834123978Sambrisko
835123978Sambrisko	if (sc->an_gone) {
836123978Sambrisko		device_printf(dev,"already unloaded\n");
837123978Sambrisko		return(0);
838123978Sambrisko	}
839148639Semax	AN_LOCK(sc);
840123978Sambrisko	an_stop(sc);
841148454Semax	sc->an_gone = 1;
842123978Sambrisko	ifmedia_removeall(&sc->an_ifmedia);
843148887Srwatson	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
844148454Semax	AN_UNLOCK(sc);
845123978Sambrisko	ether_ifdetach(ifp);
846150306Simp	bus_teardown_intr(dev, sc->irq_res, sc->irq_handle);
847173668Savatar	callout_drain(&sc->an_stat_ch);
848147256Sbrooks	if_free(ifp);
849123978Sambrisko	an_release_resources(dev);
850123978Sambrisko	mtx_destroy(&sc->an_mtx);
851123978Sambrisko	return (0);
852123978Sambrisko}
853123978Sambrisko
85483270Sbrooksstatic void
855150446Simpan_rxeof(struct an_softc *sc)
85655992Swpaul{
85783269Sbrooks	struct ifnet   *ifp;
85883269Sbrooks	struct ether_header *eh;
85983269Sbrooks	struct ieee80211_frame *ih;
86083269Sbrooks	struct an_rxframe rx_frame;
86183269Sbrooks	struct an_rxframe_802_3 rx_frame_802_3;
86283269Sbrooks	struct mbuf    *m;
863108401Sambrisko	int		len, id, error = 0, i, count = 0;
864108401Sambrisko	int		ieee80211_header_len;
865108401Sambrisko	u_char		*bpf_buf;
866108401Sambrisko	u_short		fc1;
867108401Sambrisko	struct an_card_rx_desc an_rx_desc;
868108401Sambrisko	u_int8_t	*buf;
86955992Swpaul
870122689Ssam	AN_LOCK_ASSERT(sc);
871122689Ssam
872147256Sbrooks	ifp = sc->an_ifp;
87355992Swpaul
874108401Sambrisko	if (!sc->mpi350) {
875108401Sambrisko		id = CSR_READ_2(sc, AN_RX_FID);
87655992Swpaul
877108401Sambrisko		if (sc->an_monitor && (ifp->if_flags & IFF_PROMISC)) {
878108401Sambrisko			/* read raw 802.11 packet */
879108401Sambrisko			bpf_buf = sc->buf_802_11;
88055992Swpaul
881108401Sambrisko			/* read header */
882108401Sambrisko			if (an_read_data(sc, id, 0x0, (caddr_t)&rx_frame,
883108401Sambrisko					 sizeof(rx_frame))) {
884108401Sambrisko				ifp->if_ierrors++;
885108401Sambrisko				return;
886108401Sambrisko			}
88755992Swpaul
888108401Sambrisko			/*
889108401Sambrisko			 * skip beacon by default since this increases the
890108401Sambrisko			 * system load a lot
891108401Sambrisko			 */
89283270Sbrooks
893108401Sambrisko			if (!(sc->an_monitor & AN_MONITOR_INCLUDE_BEACON) &&
894108401Sambrisko			    (rx_frame.an_frame_ctl &
895108401Sambrisko			     IEEE80211_FC0_SUBTYPE_BEACON)) {
89683269Sbrooks				return;
89783269Sbrooks			}
89855992Swpaul
899108401Sambrisko			if (sc->an_monitor & AN_MONITOR_AIRONET_HEADER) {
900108401Sambrisko				len = rx_frame.an_rx_payload_len
901108401Sambrisko					+ sizeof(rx_frame);
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);
907108401Sambrisko					ifp->if_ierrors++;
908108401Sambrisko					return;
909108401Sambrisko				}
91055992Swpaul
911108401Sambrisko				bcopy((char *)&rx_frame,
912108401Sambrisko				      bpf_buf, sizeof(rx_frame));
913108401Sambrisko
914108401Sambrisko				error = an_read_data(sc, id, sizeof(rx_frame),
915108401Sambrisko					    (caddr_t)bpf_buf+sizeof(rx_frame),
916108401Sambrisko					    rx_frame.an_rx_payload_len);
917108401Sambrisko			} else {
918108401Sambrisko				fc1=rx_frame.an_frame_ctl >> 8;
919175445Sambrisko				ieee80211_header_len =
920108401Sambrisko					sizeof(struct ieee80211_frame);
921108401Sambrisko				if ((fc1 & IEEE80211_FC1_DIR_TODS) &&
922108401Sambrisko				    (fc1 & IEEE80211_FC1_DIR_FROMDS)) {
923108401Sambrisko					ieee80211_header_len += ETHER_ADDR_LEN;
924108401Sambrisko				}
925108401Sambrisko
926108401Sambrisko				len = rx_frame.an_rx_payload_len
927108401Sambrisko					+ ieee80211_header_len;
928108401Sambrisko				/* Check for insane frame length */
929108401Sambrisko				if (len > sizeof(sc->buf_802_11)) {
930198987Sjhb					if_printf(ifp, "oversized packet "
931108401Sambrisko					       "received (%d, %d)\n",
932198987Sjhb					       len, MCLBYTES);
933108401Sambrisko					ifp->if_ierrors++;
934108401Sambrisko					return;
935108401Sambrisko				}
936108401Sambrisko
937108401Sambrisko				ih = (struct ieee80211_frame *)bpf_buf;
938108401Sambrisko
939108401Sambrisko				bcopy((char *)&rx_frame.an_frame_ctl,
940108401Sambrisko				      (char *)ih, ieee80211_header_len);
941108401Sambrisko
942108401Sambrisko				error = an_read_data(sc, id, sizeof(rx_frame) +
943108401Sambrisko					    rx_frame.an_gaplen,
944108401Sambrisko					    (caddr_t)ih +ieee80211_header_len,
945108401Sambrisko					    rx_frame.an_rx_payload_len);
946108401Sambrisko			}
947108401Sambrisko			/* dump raw 802.11 packet to bpf and skip ip stack */
948108401Sambrisko			BPF_TAP(ifp, bpf_buf, len);
94983270Sbrooks		} else {
950243857Sglebius			MGETHDR(m, M_NOWAIT, MT_DATA);
951108401Sambrisko			if (m == NULL) {
952108401Sambrisko				ifp->if_ierrors++;
953108401Sambrisko				return;
95483269Sbrooks			}
955243857Sglebius			MCLGET(m, M_NOWAIT);
956108401Sambrisko			if (!(m->m_flags & M_EXT)) {
957108401Sambrisko				m_freem(m);
958108401Sambrisko				ifp->if_ierrors++;
959108401Sambrisko				return;
960108401Sambrisko			}
961108401Sambrisko			m->m_pkthdr.rcvif = ifp;
962108401Sambrisko			/* Read Ethernet encapsulated packet */
96355992Swpaul
964108401Sambrisko#ifdef ANCACHE
965108401Sambrisko			/* Read NIC frame header */
966175445Sambrisko			if (an_read_data(sc, id, 0, (caddr_t)&rx_frame,
967108401Sambrisko					 sizeof(rx_frame))) {
968154394Srwatson				m_freem(m);
969108401Sambrisko				ifp->if_ierrors++;
970108401Sambrisko				return;
971108401Sambrisko			}
972108401Sambrisko#endif
973108401Sambrisko			/* Read in the 802_3 frame header */
974175445Sambrisko			if (an_read_data(sc, id, 0x34,
975108401Sambrisko					 (caddr_t)&rx_frame_802_3,
976108401Sambrisko					 sizeof(rx_frame_802_3))) {
977154394Srwatson				m_freem(m);
978108401Sambrisko				ifp->if_ierrors++;
979108401Sambrisko				return;
980108401Sambrisko			}
981108401Sambrisko			if (rx_frame_802_3.an_rx_802_3_status != 0) {
982154394Srwatson				m_freem(m);
983108401Sambrisko				ifp->if_ierrors++;
984108401Sambrisko				return;
985108401Sambrisko			}
98683269Sbrooks			/* Check for insane frame length */
987108401Sambrisko			len = rx_frame_802_3.an_rx_802_3_payload_len;
98883269Sbrooks			if (len > sizeof(sc->buf_802_11)) {
989154394Srwatson				m_freem(m);
990198987Sjhb				if_printf(ifp, "oversized packet "
991108401Sambrisko				       "received (%d, %d)\n",
992198987Sjhb				       len, MCLBYTES);
99383269Sbrooks				ifp->if_ierrors++;
99483269Sbrooks				return;
99583269Sbrooks			}
996108401Sambrisko			m->m_pkthdr.len = m->m_len =
997108401Sambrisko				rx_frame_802_3.an_rx_802_3_payload_len + 12;
99855992Swpaul
999108401Sambrisko			eh = mtod(m, struct ether_header *);
100055992Swpaul
1001108401Sambrisko			bcopy((char *)&rx_frame_802_3.an_rx_dst_addr,
1002108401Sambrisko			      (char *)&eh->ether_dhost, ETHER_ADDR_LEN);
1003108401Sambrisko			bcopy((char *)&rx_frame_802_3.an_rx_src_addr,
1004108401Sambrisko			      (char *)&eh->ether_shost, ETHER_ADDR_LEN);
100555992Swpaul
1006108401Sambrisko			/* in mbuf header type is just before payload */
1007175445Sambrisko			error = an_read_data(sc, id, 0x44,
1008108401Sambrisko				    (caddr_t)&(eh->ether_type),
1009108401Sambrisko				    rx_frame_802_3.an_rx_802_3_payload_len);
101055992Swpaul
1011108401Sambrisko			if (error) {
1012108401Sambrisko				m_freem(m);
1013108401Sambrisko				ifp->if_ierrors++;
1014108401Sambrisko				return;
1015108401Sambrisko			}
1016108401Sambrisko			ifp->if_ipackets++;
1017108401Sambrisko
1018108401Sambrisko			/* Receive packet. */
101983269Sbrooks#ifdef ANCACHE
1020175445Sambrisko			an_cache_store(sc, eh, m,
1021110253Sambrisko				rx_frame.an_rx_signal_strength,
1022110253Sambrisko				rx_frame.an_rsvd0);
102383269Sbrooks#endif
1024122689Ssam			AN_UNLOCK(sc);
1025108401Sambrisko			(*ifp->if_input)(ifp, m);
1026122689Ssam			AN_LOCK(sc);
102783269Sbrooks		}
102855992Swpaul
1029108401Sambrisko	} else { /* MPI-350 */
1030108401Sambrisko		for (count = 0; count < AN_MAX_RX_DESC; count++){
1031108401Sambrisko			for (i = 0; i < sizeof(an_rx_desc) / 4; i++)
1032175445Sambrisko				((u_int32_t *)(void *)&an_rx_desc)[i]
1033175445Sambrisko					= CSR_MEM_AUX_READ_4(sc,
1034175445Sambrisko						AN_RX_DESC_OFFSET
1035108401Sambrisko						+ (count * sizeof(an_rx_desc))
1036108401Sambrisko						+ (i * 4));
103783269Sbrooks
1038108401Sambrisko			if (an_rx_desc.an_done && !an_rx_desc.an_valid) {
1039108401Sambrisko				buf = sc->an_rx_buffer[count].an_dma_vaddr;
104083269Sbrooks
1041243857Sglebius				MGETHDR(m, M_NOWAIT, MT_DATA);
1042108401Sambrisko				if (m == NULL) {
1043108401Sambrisko					ifp->if_ierrors++;
1044108401Sambrisko					return;
1045108401Sambrisko				}
1046243857Sglebius				MCLGET(m, M_NOWAIT);
1047108401Sambrisko				if (!(m->m_flags & M_EXT)) {
1048108401Sambrisko					m_freem(m);
1049108401Sambrisko					ifp->if_ierrors++;
1050108401Sambrisko					return;
1051108401Sambrisko				}
1052108401Sambrisko				m->m_pkthdr.rcvif = ifp;
1053108401Sambrisko				/* Read Ethernet encapsulated packet */
105483269Sbrooks
1055175445Sambrisko				/*
1056108401Sambrisko				 * No ANCACHE support since we just get back
1057108401Sambrisko				 * an Ethernet packet no 802.11 info
1058108401Sambrisko				 */
1059108401Sambrisko#if 0
1060108401Sambrisko#ifdef ANCACHE
1061108401Sambrisko				/* Read NIC frame header */
1062175445Sambrisko				bcopy(buf, (caddr_t)&rx_frame,
1063108401Sambrisko				      sizeof(rx_frame));
1064108401Sambrisko#endif
1065108401Sambrisko#endif
1066108401Sambrisko				/* Check for insane frame length */
1067108401Sambrisko				len = an_rx_desc.an_len + 12;
1068108401Sambrisko				if (len > MCLBYTES) {
1069154393Srwatson					m_freem(m);
1070198987Sjhb					if_printf(ifp, "oversized packet "
1071108401Sambrisko					       "received (%d, %d)\n",
1072198987Sjhb					       len, MCLBYTES);
1073108401Sambrisko					ifp->if_ierrors++;
1074108401Sambrisko					return;
1075108401Sambrisko				}
107683269Sbrooks
1077108401Sambrisko				m->m_pkthdr.len = m->m_len =
1078108401Sambrisko					an_rx_desc.an_len + 12;
1079175445Sambrisko
1080108401Sambrisko				eh = mtod(m, struct ether_header *);
1081175445Sambrisko
1082108401Sambrisko				bcopy(buf, (char *)eh,
1083108401Sambrisko				      m->m_pkthdr.len);
1084175445Sambrisko
1085108401Sambrisko				ifp->if_ipackets++;
1086175445Sambrisko
1087108401Sambrisko				/* Receive packet. */
1088108401Sambrisko#if 0
108955992Swpaul#ifdef ANCACHE
1090175445Sambrisko				an_cache_store(sc, eh, m,
1091110253Sambrisko					rx_frame.an_rx_signal_strength,
1092110253Sambrisko					rx_frame.an_rsvd0);
109355992Swpaul#endif
1094108401Sambrisko#endif
1095171775Savatar				AN_UNLOCK(sc);
1096108401Sambrisko				(*ifp->if_input)(ifp, m);
1097171775Savatar				AN_LOCK(sc);
1098171775Savatar
1099108401Sambrisko				an_rx_desc.an_valid = 1;
1100108401Sambrisko				an_rx_desc.an_len = AN_RX_BUFFER_SIZE;
1101108401Sambrisko				an_rx_desc.an_done = 0;
1102175445Sambrisko				an_rx_desc.an_phys =
1103108401Sambrisko					sc->an_rx_buffer[count].an_dma_paddr;
1104175445Sambrisko
1105108401Sambrisko				for (i = 0; i < sizeof(an_rx_desc) / 4; i++)
1106175445Sambrisko					CSR_MEM_AUX_WRITE_4(sc,
1107175445Sambrisko					    AN_RX_DESC_OFFSET
1108155321Simp					    + (count * sizeof(an_rx_desc))
1109155321Simp					    + (i * 4),
1110155321Simp					    ((u_int32_t *)(void *)&an_rx_desc)[i]);
1111175445Sambrisko
1112108401Sambrisko			} else {
1113198987Sjhb				if_printf(ifp, "Didn't get valid RX packet "
1114108401Sambrisko				       "%x %x %d\n",
1115108401Sambrisko				       an_rx_desc.an_done,
1116108401Sambrisko				       an_rx_desc.an_valid, an_rx_desc.an_len);
1117108401Sambrisko			}
1118108401Sambrisko		}
111983269Sbrooks	}
112055992Swpaul}
112155992Swpaul
112283270Sbrooksstatic void
1123150446Simpan_txeof(struct an_softc *sc, int status)
112455992Swpaul{
112555992Swpaul	struct ifnet		*ifp;
112678639Sbrooks	int			id, i;
112755992Swpaul
1128175445Sambrisko	AN_LOCK_ASSERT(sc);
1129147256Sbrooks	ifp = sc->an_ifp;
113055992Swpaul
1131199154Sjhb	sc->an_timer = 0;
1132148887Srwatson	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
113355992Swpaul
1134108401Sambrisko	if (!sc->mpi350) {
1135119156Sambrisko		id = CSR_READ_2(sc, AN_TX_CMP_FID(sc->mpi350));
113655992Swpaul
1137108401Sambrisko		if (status & AN_EV_TX_EXC) {
1138108401Sambrisko			ifp->if_oerrors++;
1139108401Sambrisko		} else
1140108401Sambrisko			ifp->if_opackets++;
114155992Swpaul
1142108401Sambrisko		for (i = 0; i < AN_TX_RING_CNT; i++) {
1143108401Sambrisko			if (id == sc->an_rdata.an_tx_ring[i]) {
1144108401Sambrisko				sc->an_rdata.an_tx_ring[i] = 0;
1145108401Sambrisko				break;
1146108401Sambrisko			}
114778639Sbrooks		}
1148108401Sambrisko
1149108401Sambrisko		AN_INC(sc->an_rdata.an_tx_cons, AN_TX_RING_CNT);
1150108401Sambrisko	} else { /* MPI 350 */
1151119156Sambrisko		id = CSR_READ_2(sc, AN_TX_CMP_FID(sc->mpi350));
1152119156Sambrisko		if (!sc->an_rdata.an_tx_empty){
1153119156Sambrisko			if (status & AN_EV_TX_EXC) {
1154119156Sambrisko				ifp->if_oerrors++;
1155119156Sambrisko			} else
1156119156Sambrisko				ifp->if_opackets++;
1157119156Sambrisko			AN_INC(sc->an_rdata.an_tx_cons, AN_MAX_TX_DESC);
1158119156Sambrisko			if (sc->an_rdata.an_tx_prod ==
1159119156Sambrisko			    sc->an_rdata.an_tx_cons)
1160119156Sambrisko				sc->an_rdata.an_tx_empty = 1;
1161119156Sambrisko		}
116278639Sbrooks	}
116355992Swpaul
116455992Swpaul	return;
116555992Swpaul}
116655992Swpaul
116755992Swpaul/*
116855992Swpaul * We abuse the stats updater to check the current NIC status. This
116955992Swpaul * is important because we don't want to allow transmissions until
117055992Swpaul * the NIC has synchronized to the current cell (either as the master
117155992Swpaul * in an ad-hoc group, or as a station connected to an access point).
1172173668Savatar *
1173173668Savatar * Note that this function will be called via callout(9) with a lock held.
117455992Swpaul */
1175104094Sphkstatic void
1176150446Simpan_stats_update(void *xsc)
117755992Swpaul{
117855992Swpaul	struct an_softc		*sc;
117955992Swpaul	struct ifnet		*ifp;
118055992Swpaul
118155992Swpaul	sc = xsc;
1182173668Savatar	AN_LOCK_ASSERT(sc);
1183147256Sbrooks	ifp = sc->an_ifp;
1184199154Sjhb	if (sc->an_timer > 0 && --sc->an_timer == 0)
1185199154Sjhb		an_watchdog(sc);
118655992Swpaul
118755992Swpaul	sc->an_status.an_type = AN_RID_STATUS;
118855992Swpaul	sc->an_status.an_len = sizeof(struct an_ltv_status);
1189173668Savatar	if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_status))
1190173668Savatar		return;
119155992Swpaul
119255992Swpaul	if (sc->an_status.an_opmode & AN_STATUS_OPMODE_IN_SYNC)
119355992Swpaul		sc->an_associated = 1;
119455992Swpaul	else
119555992Swpaul		sc->an_associated = 0;
119655992Swpaul
119755992Swpaul	/* Don't do this while we're transmitting */
1198148887Srwatson	if (ifp->if_drv_flags & IFF_DRV_OACTIVE) {
1199173668Savatar		callout_reset(&sc->an_stat_ch, hz, an_stats_update, sc);
120055992Swpaul		return;
120155992Swpaul	}
120255992Swpaul
120355992Swpaul	sc->an_stats.an_len = sizeof(struct an_ltv_stats);
120455992Swpaul	sc->an_stats.an_type = AN_RID_32BITS_CUM;
1205173668Savatar	if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_stats.an_len))
1206173668Savatar		return;
120755992Swpaul
1208173668Savatar	callout_reset(&sc->an_stat_ch, hz, an_stats_update, sc);
120955992Swpaul
121055992Swpaul	return;
121155992Swpaul}
121255992Swpaul
121383270Sbrooksvoid
1214150446Simpan_intr(void *xsc)
121555992Swpaul{
121655992Swpaul	struct an_softc		*sc;
121755992Swpaul	struct ifnet		*ifp;
121855992Swpaul	u_int16_t		status;
121955992Swpaul
122055992Swpaul	sc = (struct an_softc*)xsc;
122155992Swpaul
122267094Swpaul	AN_LOCK(sc);
122367094Swpaul
122467094Swpaul	if (sc->an_gone) {
122567094Swpaul		AN_UNLOCK(sc);
122655992Swpaul		return;
122767094Swpaul	}
122855992Swpaul
1229147256Sbrooks	ifp = sc->an_ifp;
123055992Swpaul
123155992Swpaul	/* Disable interrupts. */
1232108401Sambrisko	CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), 0);
123355992Swpaul
1234108401Sambrisko	status = CSR_READ_2(sc, AN_EVENT_STAT(sc->mpi350));
1235119156Sambrisko	CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), ~AN_INTRS(sc->mpi350));
123655992Swpaul
1237119156Sambrisko	if (status & AN_EV_MIC) {
1238119156Sambrisko		CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_MIC);
123955992Swpaul	}
124055992Swpaul
124155992Swpaul	if (status & AN_EV_LINKSTAT) {
1242175445Sambrisko		if (CSR_READ_2(sc, AN_LINKSTAT(sc->mpi350))
1243108401Sambrisko		    == AN_LINKSTAT_ASSOCIATED)
124455992Swpaul			sc->an_associated = 1;
124555992Swpaul		else
124655992Swpaul			sc->an_associated = 0;
1247108401Sambrisko		CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_LINKSTAT);
124855992Swpaul	}
124955992Swpaul
125055992Swpaul	if (status & AN_EV_RX) {
125155992Swpaul		an_rxeof(sc);
1252108401Sambrisko		CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_RX);
125355992Swpaul	}
125455992Swpaul
1255119156Sambrisko	if (sc->mpi350 && status & AN_EV_TX_CPY) {
1256119156Sambrisko		an_txeof(sc, status);
1257150446Simp		CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_TX_CPY);
1258119156Sambrisko	}
1259119156Sambrisko
126055992Swpaul	if (status & AN_EV_TX) {
126155992Swpaul		an_txeof(sc, status);
1262150446Simp		CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_TX);
126355992Swpaul	}
126455992Swpaul
126555992Swpaul	if (status & AN_EV_TX_EXC) {
126655992Swpaul		an_txeof(sc, status);
1267108401Sambrisko		CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_TX_EXC);
126855992Swpaul	}
126955992Swpaul
127055992Swpaul	if (status & AN_EV_ALLOC)
1271108401Sambrisko		CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_ALLOC);
127255992Swpaul
127355992Swpaul	/* Re-enable interrupts. */
1274119156Sambrisko	CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), AN_INTRS(sc->mpi350));
127555992Swpaul
1276132986Smlaier	if ((ifp->if_flags & IFF_UP) && !IFQ_DRV_IS_EMPTY(&ifp->if_snd))
1277199154Sjhb		an_start_locked(ifp);
127855992Swpaul
127967094Swpaul	AN_UNLOCK(sc);
128067094Swpaul
128155992Swpaul	return;
128255992Swpaul}
128355992Swpaul
1284108401Sambrisko
128583270Sbrooksstatic int
1286150446Simpan_cmd_struct(struct an_softc *sc, struct an_command *cmd,
1287150446Simp    struct an_reply *reply)
1288108401Sambrisko{
1289108401Sambrisko	int			i;
1290108401Sambrisko
1291175445Sambrisko	AN_LOCK_ASSERT(sc);
1292108401Sambrisko	for (i = 0; i != AN_TIMEOUT; i++) {
1293108401Sambrisko		if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350)) & AN_CMD_BUSY) {
1294110531Sambrisko			DELAY(1000);
1295110104Sambrisko		} else
1296108401Sambrisko			break;
1297108401Sambrisko	}
1298119156Sambrisko
1299108401Sambrisko	if( i == AN_TIMEOUT) {
1300108401Sambrisko		printf("BUSY\n");
1301108401Sambrisko		return(ETIMEDOUT);
1302108401Sambrisko	}
1303108401Sambrisko
1304108401Sambrisko	CSR_WRITE_2(sc, AN_PARAM0(sc->mpi350), cmd->an_parm0);
1305108401Sambrisko	CSR_WRITE_2(sc, AN_PARAM1(sc->mpi350), cmd->an_parm1);
1306108401Sambrisko	CSR_WRITE_2(sc, AN_PARAM2(sc->mpi350), cmd->an_parm2);
1307108401Sambrisko	CSR_WRITE_2(sc, AN_COMMAND(sc->mpi350), cmd->an_cmd);
1308108401Sambrisko
1309108401Sambrisko	for (i = 0; i < AN_TIMEOUT; i++) {
1310108401Sambrisko		if (CSR_READ_2(sc, AN_EVENT_STAT(sc->mpi350)) & AN_EV_CMD)
1311108401Sambrisko			break;
1312110531Sambrisko		DELAY(1000);
1313108401Sambrisko	}
1314108401Sambrisko
1315108401Sambrisko	reply->an_resp0 = CSR_READ_2(sc, AN_RESP0(sc->mpi350));
1316108401Sambrisko	reply->an_resp1 = CSR_READ_2(sc, AN_RESP1(sc->mpi350));
1317108401Sambrisko	reply->an_resp2 = CSR_READ_2(sc, AN_RESP2(sc->mpi350));
1318108401Sambrisko	reply->an_status = CSR_READ_2(sc, AN_STATUS(sc->mpi350));
1319108401Sambrisko
1320108401Sambrisko	if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350)) & AN_CMD_BUSY)
1321175445Sambrisko		CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350),
1322119156Sambrisko		    AN_EV_CLR_STUCK_BUSY);
1323108401Sambrisko
1324108401Sambrisko	/* Ack the command */
1325108401Sambrisko	CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_CMD);
1326108401Sambrisko
1327108401Sambrisko	if (i == AN_TIMEOUT)
1328108401Sambrisko		return(ETIMEDOUT);
1329108401Sambrisko
1330108401Sambrisko	return(0);
1331108401Sambrisko}
1332108401Sambrisko
1333108401Sambriskostatic int
1334150446Simpan_cmd(struct an_softc *sc, int cmd, int val)
133555992Swpaul{
133655992Swpaul	int			i, s = 0;
133755992Swpaul
1338175445Sambrisko	AN_LOCK_ASSERT(sc);
1339108401Sambrisko	CSR_WRITE_2(sc, AN_PARAM0(sc->mpi350), val);
1340108401Sambrisko	CSR_WRITE_2(sc, AN_PARAM1(sc->mpi350), 0);
1341108401Sambrisko	CSR_WRITE_2(sc, AN_PARAM2(sc->mpi350), 0);
1342108401Sambrisko	CSR_WRITE_2(sc, AN_COMMAND(sc->mpi350), cmd);
134355992Swpaul
134455992Swpaul	for (i = 0; i < AN_TIMEOUT; i++) {
1345108401Sambrisko		if (CSR_READ_2(sc, AN_EVENT_STAT(sc->mpi350)) & AN_EV_CMD)
134655992Swpaul			break;
134755992Swpaul		else {
1348108401Sambrisko			if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350)) == cmd)
1349108401Sambrisko				CSR_WRITE_2(sc, AN_COMMAND(sc->mpi350), cmd);
135055992Swpaul		}
135155992Swpaul	}
135255992Swpaul
135355992Swpaul	for (i = 0; i < AN_TIMEOUT; i++) {
1354108401Sambrisko		CSR_READ_2(sc, AN_RESP0(sc->mpi350));
1355108401Sambrisko		CSR_READ_2(sc, AN_RESP1(sc->mpi350));
1356108401Sambrisko		CSR_READ_2(sc, AN_RESP2(sc->mpi350));
1357108401Sambrisko		s = CSR_READ_2(sc, AN_STATUS(sc->mpi350));
135855992Swpaul		if ((s & AN_STAT_CMD_CODE) == (cmd & AN_STAT_CMD_CODE))
135955992Swpaul			break;
136055992Swpaul	}
136155992Swpaul
136255992Swpaul	/* Ack the command */
1363108401Sambrisko	CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_CMD);
136455992Swpaul
1365108401Sambrisko	if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350)) & AN_CMD_BUSY)
1366108401Sambrisko		CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_CLR_STUCK_BUSY);
136755992Swpaul
136855992Swpaul	if (i == AN_TIMEOUT)
136955992Swpaul		return(ETIMEDOUT);
137055992Swpaul
137155992Swpaul	return(0);
137255992Swpaul}
137355992Swpaul
137455992Swpaul/*
137555992Swpaul * This reset sequence may look a little strange, but this is the
137655992Swpaul * most reliable method I've found to really kick the NIC in the
137755992Swpaul * head and force it to reboot correctly.
137855992Swpaul */
137983270Sbrooksstatic void
1380150446Simpan_reset(struct an_softc *sc)
138155992Swpaul{
138255992Swpaul	if (sc->an_gone)
138355992Swpaul		return;
138483270Sbrooks
1385175445Sambrisko	AN_LOCK_ASSERT(sc);
138655992Swpaul	an_cmd(sc, AN_CMD_ENABLE, 0);
138755992Swpaul	an_cmd(sc, AN_CMD_FW_RESTART, 0);
138855992Swpaul	an_cmd(sc, AN_CMD_NOOP2, 0);
138955992Swpaul
139055992Swpaul	if (an_cmd(sc, AN_CMD_FORCE_SYNCLOSS, 0) == ETIMEDOUT)
1391265614Sgavin		device_printf(sc->an_dev, "reset failed\n");
139255992Swpaul
139355992Swpaul	an_cmd(sc, AN_CMD_DISABLE, 0);
139455992Swpaul
139555992Swpaul	return;
139655992Swpaul}
139755992Swpaul
139855992Swpaul/*
139955992Swpaul * Read an LTV record from the NIC.
140055992Swpaul */
140183270Sbrooksstatic int
1402150446Simpan_read_record(struct an_softc *sc, struct an_ltv_gen *ltv)
140355992Swpaul{
1404108401Sambrisko	struct an_ltv_gen	*an_ltv;
1405108401Sambrisko	struct an_card_rid_desc an_rid_desc;
1406108401Sambrisko	struct an_command	cmd;
1407108401Sambrisko	struct an_reply		reply;
1408198987Sjhb	struct ifnet		*ifp;
140955992Swpaul	u_int16_t		*ptr;
141078639Sbrooks	u_int8_t		*ptr2;
141155992Swpaul	int			i, len;
141255992Swpaul
1413175445Sambrisko	AN_LOCK_ASSERT(sc);
141478639Sbrooks	if (ltv->an_len < 4 || ltv->an_type == 0)
141555992Swpaul		return(EINVAL);
141655992Swpaul
1417198987Sjhb	ifp = sc->an_ifp;
1418108401Sambrisko	if (!sc->mpi350){
1419108401Sambrisko		/* Tell the NIC to enter record read mode. */
1420108401Sambrisko		if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_READ, ltv->an_type)) {
1421198987Sjhb			if_printf(ifp, "RID access failed\n");
1422108401Sambrisko			return(EIO);
1423108401Sambrisko		}
142455992Swpaul
1425108401Sambrisko		/* Seek to the record. */
1426108401Sambrisko		if (an_seek(sc, ltv->an_type, 0, AN_BAP1)) {
1427198987Sjhb			if_printf(ifp, "seek to record failed\n");
1428108401Sambrisko			return(EIO);
1429108401Sambrisko		}
143055992Swpaul
1431108401Sambrisko		/*
1432108401Sambrisko		 * Read the length and record type and make sure they
1433108401Sambrisko		 * match what we expect (this verifies that we have enough
1434108401Sambrisko		 * room to hold all of the returned data).
1435108401Sambrisko		 * Length includes type but not length.
1436108401Sambrisko		 */
1437108401Sambrisko		len = CSR_READ_2(sc, AN_DATA1);
1438108401Sambrisko		if (len > (ltv->an_len - 2)) {
1439198987Sjhb			if_printf(ifp, "record length mismatch -- expected %d, "
1440198987Sjhb			       "got %d for Rid %x\n",
1441108401Sambrisko			       ltv->an_len - 2, len, ltv->an_type);
1442108401Sambrisko			len = ltv->an_len - 2;
1443108401Sambrisko		} else {
1444108401Sambrisko			ltv->an_len = len + 2;
1445108401Sambrisko		}
1446108401Sambrisko
1447108401Sambrisko		/* Now read the data. */
1448108401Sambrisko		len -= 2;	/* skip the type */
1449108401Sambrisko		ptr = &ltv->an_val;
1450108401Sambrisko		for (i = len; i > 1; i -= 2)
1451108401Sambrisko			*ptr++ = CSR_READ_2(sc, AN_DATA1);
1452108401Sambrisko		if (i) {
1453108401Sambrisko			ptr2 = (u_int8_t *)ptr;
1454108401Sambrisko			*ptr2 = CSR_READ_1(sc, AN_DATA1);
1455108401Sambrisko		}
1456108401Sambrisko	} else { /* MPI-350 */
1457123978Sambrisko		if (!sc->an_rid_buffer.an_dma_vaddr)
1458123978Sambrisko			return(EIO);
1459108401Sambrisko		an_rid_desc.an_valid = 1;
1460108401Sambrisko		an_rid_desc.an_len = AN_RID_BUFFER_SIZE;
1461108401Sambrisko		an_rid_desc.an_rid = 0;
1462108401Sambrisko		an_rid_desc.an_phys = sc->an_rid_buffer.an_dma_paddr;
1463108401Sambrisko		bzero(sc->an_rid_buffer.an_dma_vaddr, AN_RID_BUFFER_SIZE);
1464108401Sambrisko
1465108401Sambrisko		bzero(&cmd, sizeof(cmd));
1466108401Sambrisko		bzero(&reply, sizeof(reply));
1467108401Sambrisko		cmd.an_cmd = AN_CMD_ACCESS|AN_ACCESS_READ;
1468108401Sambrisko		cmd.an_parm0 = ltv->an_type;
1469108401Sambrisko
1470108401Sambrisko		for (i = 0; i < sizeof(an_rid_desc) / 4; i++)
1471175445Sambrisko			CSR_MEM_AUX_WRITE_4(sc, AN_HOST_DESC_OFFSET + i * 4,
1472155321Simp			    ((u_int32_t *)(void *)&an_rid_desc)[i]);
1473108401Sambrisko
1474108401Sambrisko		if (an_cmd_struct(sc, &cmd, &reply)
1475108401Sambrisko		    || reply.an_status & AN_CMD_QUAL_MASK) {
1476198987Sjhb			if_printf(ifp, "failed to read RID %x %x %x %x %x, %d\n",
1477198987Sjhb			       ltv->an_type,
1478108401Sambrisko			       reply.an_status,
1479108401Sambrisko			       reply.an_resp0,
1480108401Sambrisko			       reply.an_resp1,
1481108401Sambrisko			       reply.an_resp2,
1482108401Sambrisko			       i);
1483108401Sambrisko			return(EIO);
1484108401Sambrisko		}
1485108401Sambrisko
1486108401Sambrisko		an_ltv = (struct an_ltv_gen *)sc->an_rid_buffer.an_dma_vaddr;
1487108401Sambrisko		if (an_ltv->an_len + 2 < an_rid_desc.an_len) {
1488108401Sambrisko			an_rid_desc.an_len = an_ltv->an_len;
1489108401Sambrisko		}
1490108401Sambrisko
1491123978Sambrisko		len = an_rid_desc.an_len;
1492123978Sambrisko		if (len > (ltv->an_len - 2)) {
1493198987Sjhb			if_printf(ifp, "record length mismatch -- expected %d, "
1494198987Sjhb			       "got %d for Rid %x\n",
1495123978Sambrisko			       ltv->an_len - 2, len, ltv->an_type);
1496123978Sambrisko			len = ltv->an_len - 2;
1497123978Sambrisko		} else {
1498123978Sambrisko			ltv->an_len = len + 2;
1499123978Sambrisko		}
1500123978Sambrisko		bcopy(&an_ltv->an_type,
1501175445Sambrisko		    &ltv->an_val,
1502123978Sambrisko		    len);
150355992Swpaul	}
150455992Swpaul
150578639Sbrooks	if (an_dump)
150678639Sbrooks		an_dump_record(sc, ltv, "Read");
150755992Swpaul
150855992Swpaul	return(0);
150955992Swpaul}
151055992Swpaul
151155992Swpaul/*
151255992Swpaul * Same as read, except we inject data instead of reading it.
151355992Swpaul */
151483270Sbrooksstatic int
1515150446Simpan_write_record(struct an_softc *sc, struct an_ltv_gen *ltv)
151655992Swpaul{
1517108401Sambrisko	struct an_card_rid_desc an_rid_desc;
1518108401Sambrisko	struct an_command	cmd;
1519108401Sambrisko	struct an_reply		reply;
152055992Swpaul	u_int16_t		*ptr;
152178639Sbrooks	u_int8_t		*ptr2;
152278639Sbrooks	int			i, len;
152355992Swpaul
1524175445Sambrisko	AN_LOCK_ASSERT(sc);
152578639Sbrooks	if (an_dump)
152678639Sbrooks		an_dump_record(sc, ltv, "Write");
152778639Sbrooks
1528108401Sambrisko	if (!sc->mpi350){
1529108401Sambrisko		if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_READ, ltv->an_type))
1530108401Sambrisko			return(EIO);
153183270Sbrooks
1532108401Sambrisko		if (an_seek(sc, ltv->an_type, 0, AN_BAP1))
1533108401Sambrisko			return(EIO);
1534108401Sambrisko
1535108401Sambrisko		/*
1536108401Sambrisko		 * Length includes type but not length.
1537108401Sambrisko		 */
1538108401Sambrisko		len = ltv->an_len - 2;
1539108401Sambrisko		CSR_WRITE_2(sc, AN_DATA1, len);
1540108401Sambrisko
1541108401Sambrisko		len -= 2;	/* skip the type */
1542108401Sambrisko		ptr = &ltv->an_val;
1543108401Sambrisko		for (i = len; i > 1; i -= 2)
1544108401Sambrisko			CSR_WRITE_2(sc, AN_DATA1, *ptr++);
1545108401Sambrisko		if (i) {
1546108401Sambrisko			ptr2 = (u_int8_t *)ptr;
1547108401Sambrisko			CSR_WRITE_1(sc, AN_DATA0, *ptr2);
1548108401Sambrisko		}
1549108401Sambrisko
1550108401Sambrisko		if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_WRITE, ltv->an_type))
1551108401Sambrisko			return(EIO);
1552175445Sambrisko	} else {
1553110104Sambrisko		/* MPI-350 */
1554108401Sambrisko
1555108401Sambrisko		for (i = 0; i != AN_TIMEOUT; i++) {
1556175445Sambrisko			if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350))
1557110104Sambrisko			    & AN_CMD_BUSY) {
1558108401Sambrisko				DELAY(10);
1559110104Sambrisko			} else
1560108401Sambrisko				break;
1561108401Sambrisko		}
1562108401Sambrisko		if (i == AN_TIMEOUT) {
1563108401Sambrisko			printf("BUSY\n");
1564108401Sambrisko		}
1565108401Sambrisko
1566108401Sambrisko		an_rid_desc.an_valid = 1;
1567108401Sambrisko		an_rid_desc.an_len = ltv->an_len - 2;
1568108401Sambrisko		an_rid_desc.an_rid = ltv->an_type;
1569108401Sambrisko		an_rid_desc.an_phys = sc->an_rid_buffer.an_dma_paddr;
1570108401Sambrisko
1571108401Sambrisko		bcopy(&ltv->an_type, sc->an_rid_buffer.an_dma_vaddr,
1572108401Sambrisko		      an_rid_desc.an_len);
1573108401Sambrisko
1574108401Sambrisko		bzero(&cmd,sizeof(cmd));
1575108401Sambrisko		bzero(&reply,sizeof(reply));
1576108401Sambrisko		cmd.an_cmd = AN_CMD_ACCESS|AN_ACCESS_WRITE;
1577108401Sambrisko		cmd.an_parm0 = ltv->an_type;
1578108401Sambrisko
1579108401Sambrisko		for (i = 0; i < sizeof(an_rid_desc) / 4; i++)
1580175445Sambrisko			CSR_MEM_AUX_WRITE_4(sc, AN_HOST_DESC_OFFSET + i * 4,
1581155321Simp			    ((u_int32_t *)(void *)&an_rid_desc)[i]);
1582108401Sambrisko
1583110531Sambrisko		DELAY(100000);
1584110531Sambrisko
1585108401Sambrisko		if ((i = an_cmd_struct(sc, &cmd, &reply))) {
1586198987Sjhb			if_printf(sc->an_ifp,
1587198987Sjhb			    "failed to write RID 1 %x %x %x %x %x, %d\n",
1588198987Sjhb			    ltv->an_type,
1589110104Sambrisko			    reply.an_status,
1590110104Sambrisko			    reply.an_resp0,
1591110104Sambrisko			    reply.an_resp1,
1592110104Sambrisko			    reply.an_resp2,
1593110104Sambrisko			    i);
1594110104Sambrisko			return(EIO);
1595108401Sambrisko		}
159655992Swpaul
159783270Sbrooks
1598108401Sambrisko		if (reply.an_status & AN_CMD_QUAL_MASK) {
1599198987Sjhb			if_printf(sc->an_ifp,
1600198987Sjhb			    "failed to write RID 2 %x %x %x %x %x, %d\n",
1601198987Sjhb			    ltv->an_type,
1602110104Sambrisko			    reply.an_status,
1603110104Sambrisko			    reply.an_resp0,
1604110104Sambrisko			    reply.an_resp1,
1605110104Sambrisko			    reply.an_resp2,
1606110104Sambrisko			    i);
1607108401Sambrisko			return(EIO);
1608108401Sambrisko		}
1609110531Sambrisko		DELAY(100000);
161078639Sbrooks	}
161155992Swpaul
161255992Swpaul	return(0);
161355992Swpaul}
161455992Swpaul
161583270Sbrooksstatic void
1616150446Simpan_dump_record(struct an_softc *sc, struct an_ltv_gen *ltv, char *string)
161778639Sbrooks{
161878639Sbrooks	u_int8_t		*ptr2;
161978639Sbrooks	int			len;
162078639Sbrooks	int			i;
162178639Sbrooks	int			count = 0;
162278639Sbrooks	char			buf[17], temp;
162378639Sbrooks
162478639Sbrooks	len = ltv->an_len - 4;
1625198987Sjhb	if_printf(sc->an_ifp, "RID %4x, Length %4d, Mode %s\n",
1626198987Sjhb		ltv->an_type, ltv->an_len - 4, string);
162778639Sbrooks
162878639Sbrooks	if (an_dump == 1 || (an_dump == ltv->an_type)) {
1629198987Sjhb		if_printf(sc->an_ifp, "\t");
163078639Sbrooks		bzero(buf,sizeof(buf));
163178639Sbrooks
163278639Sbrooks		ptr2 = (u_int8_t *)&ltv->an_val;
163378639Sbrooks		for (i = len; i > 0; i--) {
163478639Sbrooks			printf("%02x ", *ptr2);
163578639Sbrooks
163678639Sbrooks			temp = *ptr2++;
1637154866Snjl			if (isprint(temp))
163878639Sbrooks				buf[count] = temp;
163978639Sbrooks			else
164078639Sbrooks				buf[count] = '.';
164178639Sbrooks			if (++count == 16) {
164278639Sbrooks				count = 0;
164378639Sbrooks				printf("%s\n",buf);
1644198987Sjhb				if_printf(sc->an_ifp, "\t");
164578639Sbrooks				bzero(buf,sizeof(buf));
164678639Sbrooks			}
164778639Sbrooks		}
164878639Sbrooks		for (; count != 16; count++) {
164978639Sbrooks			printf("   ");
165078639Sbrooks		}
165178639Sbrooks		printf(" %s\n",buf);
165278639Sbrooks	}
165378639Sbrooks}
165478639Sbrooks
165583270Sbrooksstatic int
1656150446Simpan_seek(struct an_softc *sc, int id, int off, int chan)
165755992Swpaul{
165855992Swpaul	int			i;
165955992Swpaul	int			selreg, offreg;
166055992Swpaul
166155992Swpaul	switch (chan) {
166255992Swpaul	case AN_BAP0:
166355992Swpaul		selreg = AN_SEL0;
166455992Swpaul		offreg = AN_OFF0;
166555992Swpaul		break;
166655992Swpaul	case AN_BAP1:
166755992Swpaul		selreg = AN_SEL1;
166855992Swpaul		offreg = AN_OFF1;
166955992Swpaul		break;
167055992Swpaul	default:
1671198987Sjhb		if_printf(sc->an_ifp, "invalid data path: %x\n", chan);
167255992Swpaul		return(EIO);
167355992Swpaul	}
167455992Swpaul
167555992Swpaul	CSR_WRITE_2(sc, selreg, id);
167655992Swpaul	CSR_WRITE_2(sc, offreg, off);
167755992Swpaul
167855992Swpaul	for (i = 0; i < AN_TIMEOUT; i++) {
167955992Swpaul		if (!(CSR_READ_2(sc, offreg) & (AN_OFF_BUSY|AN_OFF_ERR)))
168055992Swpaul			break;
168155992Swpaul	}
168255992Swpaul
168355992Swpaul	if (i == AN_TIMEOUT)
168455992Swpaul		return(ETIMEDOUT);
168555992Swpaul
168655992Swpaul	return(0);
168755992Swpaul}
168855992Swpaul
168983270Sbrooksstatic int
1690150446Simpan_read_data(struct an_softc *sc, int id, int off, caddr_t buf, int len)
169155992Swpaul{
169255992Swpaul	int			i;
169355992Swpaul	u_int16_t		*ptr;
169455992Swpaul	u_int8_t		*ptr2;
169555992Swpaul
169655992Swpaul	if (off != -1) {
169755992Swpaul		if (an_seek(sc, id, off, AN_BAP1))
169855992Swpaul			return(EIO);
169955992Swpaul	}
170055992Swpaul
170155992Swpaul	ptr = (u_int16_t *)buf;
170278639Sbrooks	for (i = len; i > 1; i -= 2)
170378639Sbrooks		*ptr++ = CSR_READ_2(sc, AN_DATA1);
170478639Sbrooks	if (i) {
170578639Sbrooks		ptr2 = (u_int8_t *)ptr;
170678639Sbrooks		*ptr2 = CSR_READ_1(sc, AN_DATA1);
170755992Swpaul	}
170855992Swpaul
170955992Swpaul	return(0);
171055992Swpaul}
171155992Swpaul
171283270Sbrooksstatic int
1713150446Simpan_write_data(struct an_softc *sc, int id, int off, caddr_t buf, int len)
171455992Swpaul{
171555992Swpaul	int			i;
171655992Swpaul	u_int16_t		*ptr;
171755992Swpaul	u_int8_t		*ptr2;
171855992Swpaul
171955992Swpaul	if (off != -1) {
172055992Swpaul		if (an_seek(sc, id, off, AN_BAP0))
172155992Swpaul			return(EIO);
172255992Swpaul	}
172355992Swpaul
172455992Swpaul	ptr = (u_int16_t *)buf;
172578639Sbrooks	for (i = len; i > 1; i -= 2)
172678639Sbrooks		CSR_WRITE_2(sc, AN_DATA0, *ptr++);
172778639Sbrooks	if (i) {
1728175446Sambrisko		ptr2 = (u_int8_t *)ptr;
1729175446Sambrisko		CSR_WRITE_1(sc, AN_DATA0, *ptr2);
173055992Swpaul	}
173155992Swpaul
173255992Swpaul	return(0);
173355992Swpaul}
173455992Swpaul
173555992Swpaul/*
173655992Swpaul * Allocate a region of memory inside the NIC and zero
173755992Swpaul * it out.
173855992Swpaul */
173983270Sbrooksstatic int
1740150446Simpan_alloc_nicmem(struct an_softc *sc, int len, int *id)
174155992Swpaul{
174255992Swpaul	int			i;
174355992Swpaul
174455992Swpaul	if (an_cmd(sc, AN_CMD_ALLOC_MEM, len)) {
1745198987Sjhb		if_printf(sc->an_ifp, "failed to allocate %d bytes on NIC\n",
1746198987Sjhb		    len);
174755992Swpaul		return(ENOMEM);
174855992Swpaul	}
174955992Swpaul
175055992Swpaul	for (i = 0; i < AN_TIMEOUT; i++) {
1751108401Sambrisko		if (CSR_READ_2(sc, AN_EVENT_STAT(sc->mpi350)) & AN_EV_ALLOC)
175255992Swpaul			break;
175355992Swpaul	}
175455992Swpaul
175555992Swpaul	if (i == AN_TIMEOUT)
175655992Swpaul		return(ETIMEDOUT);
175755992Swpaul
1758108401Sambrisko	CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_ALLOC);
175955992Swpaul	*id = CSR_READ_2(sc, AN_ALLOC_FID);
176055992Swpaul
176155992Swpaul	if (an_seek(sc, *id, 0, AN_BAP0))
176255992Swpaul		return(EIO);
176355992Swpaul
176455992Swpaul	for (i = 0; i < len / 2; i++)
176555992Swpaul		CSR_WRITE_2(sc, AN_DATA0, 0);
176655992Swpaul
176755992Swpaul	return(0);
176855992Swpaul}
176955992Swpaul
177083270Sbrooksstatic void
1771150446Simpan_setdef(struct an_softc *sc, struct an_req *areq)
177255992Swpaul{
177355992Swpaul	struct ifnet		*ifp;
177455992Swpaul	struct an_ltv_genconfig	*cfg;
1775119156Sambrisko	struct an_ltv_ssidlist_new	*ssid;
177655992Swpaul	struct an_ltv_aplist	*ap;
177755992Swpaul	struct an_ltv_gen	*sp;
177855992Swpaul
1779147256Sbrooks	ifp = sc->an_ifp;
178055992Swpaul
1781175445Sambrisko	AN_LOCK_ASSERT(sc);
178255992Swpaul	switch (areq->an_type) {
178355992Swpaul	case AN_RID_GENCONFIG:
178455992Swpaul		cfg = (struct an_ltv_genconfig *)areq;
178555992Swpaul
1786152315Sru		bcopy((char *)&cfg->an_macaddr, IF_LLADDR(sc->an_ifp),
178755992Swpaul		    ETHER_ADDR_LEN);
178855992Swpaul
178955992Swpaul		bcopy((char *)cfg, (char *)&sc->an_config,
179055992Swpaul			sizeof(struct an_ltv_genconfig));
179155992Swpaul		break;
179255992Swpaul	case AN_RID_SSIDLIST:
1793119156Sambrisko		ssid = (struct an_ltv_ssidlist_new *)areq;
179455992Swpaul		bcopy((char *)ssid, (char *)&sc->an_ssidlist,
1795119156Sambrisko			sizeof(struct an_ltv_ssidlist_new));
179655992Swpaul		break;
179755992Swpaul	case AN_RID_APLIST:
179855992Swpaul		ap = (struct an_ltv_aplist *)areq;
179955992Swpaul		bcopy((char *)ap, (char *)&sc->an_aplist,
180055992Swpaul			sizeof(struct an_ltv_aplist));
180155992Swpaul		break;
180255992Swpaul	case AN_RID_TX_SPEED:
180355992Swpaul		sp = (struct an_ltv_gen *)areq;
180455992Swpaul		sc->an_tx_rate = sp->an_val;
1805110253Sambrisko
1806110253Sambrisko		/* Read the current configuration */
1807110253Sambrisko		sc->an_config.an_type = AN_RID_GENCONFIG;
1808110253Sambrisko		sc->an_config.an_len = sizeof(struct an_ltv_genconfig);
1809110253Sambrisko		an_read_record(sc, (struct an_ltv_gen *)&sc->an_config);
1810110253Sambrisko		cfg = &sc->an_config;
1811110253Sambrisko
1812110253Sambrisko		/* clear other rates and set the only one we want */
1813110253Sambrisko		bzero(cfg->an_rates, sizeof(cfg->an_rates));
1814110253Sambrisko		cfg->an_rates[0] = sc->an_tx_rate;
1815110253Sambrisko
1816110253Sambrisko		/* Save the new rate */
1817110253Sambrisko		sc->an_config.an_type = AN_RID_GENCONFIG;
1818110253Sambrisko		sc->an_config.an_len = sizeof(struct an_ltv_genconfig);
181955992Swpaul		break;
182068692Swpaul	case AN_RID_WEP_TEMP:
1821110531Sambrisko		/* Cache the temp keys */
1822175445Sambrisko		bcopy(areq,
1823175445Sambrisko		    &sc->an_temp_keys[((struct an_ltv_key *)areq)->kindex],
1824110531Sambrisko		    sizeof(struct an_ltv_key));
182568692Swpaul	case AN_RID_WEP_PERM:
182688748Sambrisko	case AN_RID_LEAPUSERNAME:
182788748Sambrisko	case AN_RID_LEAPPASSWORD:
1828199154Sjhb		an_init_locked(sc);
1829119156Sambrisko
183068692Swpaul		/* Disable the MAC. */
183168692Swpaul		an_cmd(sc, AN_CMD_DISABLE, 0);
183283270Sbrooks
183383269Sbrooks		/* Write the key */
183468692Swpaul		an_write_record(sc, (struct an_ltv_gen *)areq);
183583270Sbrooks
183683270Sbrooks		/* Turn the MAC back on. */
183768692Swpaul		an_cmd(sc, AN_CMD_ENABLE, 0);
183883270Sbrooks
183968692Swpaul		break;
184083269Sbrooks	case AN_RID_MONITOR_MODE:
184183269Sbrooks		cfg = (struct an_ltv_genconfig *)areq;
184283269Sbrooks		bpfdetach(ifp);
184383269Sbrooks		if (ng_ether_detach_p != NULL)
184483269Sbrooks			(*ng_ether_detach_p) (ifp);
184583269Sbrooks		sc->an_monitor = cfg->an_len;
184683269Sbrooks
184783270Sbrooks		if (sc->an_monitor & AN_MONITOR) {
184883270Sbrooks			if (sc->an_monitor & AN_MONITOR_AIRONET_HEADER) {
184983270Sbrooks				bpfattach(ifp, DLT_AIRONET_HEADER,
185083269Sbrooks					sizeof(struct ether_header));
185183269Sbrooks			} else {
185283270Sbrooks				bpfattach(ifp, DLT_IEEE802_11,
185383269Sbrooks					sizeof(struct ether_header));
185483269Sbrooks			}
185583269Sbrooks		} else {
185683270Sbrooks			bpfattach(ifp, DLT_EN10MB,
185783269Sbrooks				  sizeof(struct ether_header));
185883269Sbrooks			if (ng_ether_attach_p != NULL)
185983269Sbrooks				(*ng_ether_attach_p) (ifp);
186083269Sbrooks		}
186183269Sbrooks		break;
186255992Swpaul	default:
1863198987Sjhb		if_printf(ifp, "unknown RID: %x\n", areq->an_type);
186455992Swpaul		return;
186555992Swpaul	}
186655992Swpaul
186755992Swpaul
186855992Swpaul	/* Reinitialize the card. */
1869199154Sjhb	if (ifp->if_flags)
1870199154Sjhb		an_init_locked(sc);
187155992Swpaul
187255992Swpaul	return;
187355992Swpaul}
187455992Swpaul
187555992Swpaul/*
187683269Sbrooks * Derived from Linux driver to enable promiscious mode.
187755992Swpaul */
187883269Sbrooks
187983270Sbrooksstatic void
1880150446Simpan_promisc(struct an_softc *sc, int promisc)
188155992Swpaul{
1882175445Sambrisko	AN_LOCK_ASSERT(sc);
1883150446Simp	if (sc->an_was_monitor) {
188483269Sbrooks		an_reset(sc);
1885108401Sambrisko		if (sc->mpi350)
1886175445Sambrisko			an_init_mpi350_desc(sc);
1887150446Simp	}
1888199154Sjhb	if (sc->an_monitor || sc->an_was_monitor)
1889199154Sjhb		an_init_locked(sc);
189083269Sbrooks
189183269Sbrooks	sc->an_was_monitor = sc->an_monitor;
189274698Sarchie	an_cmd(sc, AN_CMD_SET_MODE, promisc ? 0xffff : 0);
189383270Sbrooks
189455992Swpaul	return;
189555992Swpaul}
189655992Swpaul
189783270Sbrooksstatic int
1898150446Simpan_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
189955992Swpaul{
190067094Swpaul	int			error = 0;
190177217Sphk	int			len;
1902119156Sambrisko	int			i, max;
190355992Swpaul	struct an_softc		*sc;
190455992Swpaul	struct ifreq		*ifr;
190593593Sjhb	struct thread		*td = curthread;
190677217Sphk	struct ieee80211req	*ireq;
1907172112Savatar	struct ieee80211_channel	ch;
190877217Sphk	u_int8_t		tmpstr[IEEE80211_NWID_LEN*2];
190977217Sphk	u_int8_t		*tmpptr;
191077217Sphk	struct an_ltv_genconfig	*config;
191177217Sphk	struct an_ltv_key	*key;
191277217Sphk	struct an_ltv_status	*status;
1913119156Sambrisko	struct an_ltv_ssidlist_new	*ssids;
191488748Sambrisko	int			mode;
191588748Sambrisko	struct aironet_ioctl	l_ioctl;
191655992Swpaul
191755992Swpaul	sc = ifp->if_softc;
191855992Swpaul	ifr = (struct ifreq *)data;
191977217Sphk	ireq = (struct ieee80211req *)data;
192055992Swpaul
192188749Sambrisko	config = (struct an_ltv_genconfig *)&sc->areq;
192288749Sambrisko	key = (struct an_ltv_key *)&sc->areq;
192388749Sambrisko	status = (struct an_ltv_status *)&sc->areq;
1924119156Sambrisko	ssids = (struct an_ltv_ssidlist_new *)&sc->areq;
192577217Sphk
192664429Speter	if (sc->an_gone) {
192761816Sroberto		error = ENODEV;
192861816Sroberto		goto out;
192961816Sroberto	}
193055992Swpaul
193183270Sbrooks	switch (command) {
193255992Swpaul	case SIOCSIFFLAGS:
1933175445Sambrisko		AN_LOCK(sc);
193455992Swpaul		if (ifp->if_flags & IFF_UP) {
1935148887Srwatson			if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
193655992Swpaul			    ifp->if_flags & IFF_PROMISC &&
193755992Swpaul			    !(sc->an_if_flags & IFF_PROMISC)) {
193855992Swpaul				an_promisc(sc, 1);
1939148887Srwatson			} else if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
194055992Swpaul			    !(ifp->if_flags & IFF_PROMISC) &&
194155992Swpaul			    sc->an_if_flags & IFF_PROMISC) {
194255992Swpaul				an_promisc(sc, 0);
1943199154Sjhb			} else
1944199154Sjhb				an_init_locked(sc);
194555992Swpaul		} else {
1946199154Sjhb			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
194755992Swpaul				an_stop(sc);
194855992Swpaul		}
1949199154Sjhb		sc->an_if_flags = ifp->if_flags;
1950175445Sambrisko		AN_UNLOCK(sc);
195155992Swpaul		error = 0;
195255992Swpaul		break;
195377217Sphk	case SIOCSIFMEDIA:
195477217Sphk	case SIOCGIFMEDIA:
195577217Sphk		error = ifmedia_ioctl(ifp, ifr, &sc->an_ifmedia, command);
195677217Sphk		break;
195755992Swpaul	case SIOCADDMULTI:
195855992Swpaul	case SIOCDELMULTI:
195955992Swpaul		/* The Aironet has no multicast filter. */
196055992Swpaul		error = 0;
196155992Swpaul		break;
196255992Swpaul	case SIOCGAIRONET:
196388749Sambrisko		error = copyin(ifr->ifr_data, &sc->areq, sizeof(sc->areq));
196478639Sbrooks		if (error != 0)
196555992Swpaul			break;
1966175445Sambrisko		AN_LOCK(sc);
196755992Swpaul#ifdef ANCACHE
196888749Sambrisko		if (sc->areq.an_type == AN_RID_ZERO_CACHE) {
1969164033Srwatson			error = priv_check(td, PRIV_DRIVER);
1970108259Srwatson			if (error)
1971108259Srwatson				break;
197255992Swpaul			sc->an_sigitems = sc->an_nextitem = 0;
197355992Swpaul			break;
197488749Sambrisko		} else if (sc->areq.an_type == AN_RID_READ_CACHE) {
197588749Sambrisko			char *pt = (char *)&sc->areq.an_val;
197655992Swpaul			bcopy((char *)&sc->an_sigitems, (char *)pt,
197755992Swpaul			    sizeof(int));
197855992Swpaul			pt += sizeof(int);
197988749Sambrisko			sc->areq.an_len = sizeof(int) / 2;
198055992Swpaul			bcopy((char *)&sc->an_sigcache, (char *)pt,
198155992Swpaul			    sizeof(struct an_sigcache) * sc->an_sigitems);
198288749Sambrisko			sc->areq.an_len += ((sizeof(struct an_sigcache) *
198355992Swpaul			    sc->an_sigitems) / 2) + 1;
198455992Swpaul		} else
198555992Swpaul#endif
198688749Sambrisko		if (an_read_record(sc, (struct an_ltv_gen *)&sc->areq)) {
1987175445Sambrisko			AN_UNLOCK(sc);
198855992Swpaul			error = EINVAL;
198955992Swpaul			break;
199055992Swpaul		}
1991171692Savatar		AN_UNLOCK(sc);
199288749Sambrisko		error = copyout(&sc->areq, ifr->ifr_data, sizeof(sc->areq));
199355992Swpaul		break;
199455992Swpaul	case SIOCSAIRONET:
1995164033Srwatson		if ((error = priv_check(td, PRIV_DRIVER)))
199664429Speter			goto out;
1997175445Sambrisko		AN_LOCK(sc);
199888749Sambrisko		error = copyin(ifr->ifr_data, &sc->areq, sizeof(sc->areq));
199978639Sbrooks		if (error != 0)
200055992Swpaul			break;
200188749Sambrisko		an_setdef(sc, &sc->areq);
2002175445Sambrisko		AN_UNLOCK(sc);
200355992Swpaul		break;
2004175446Sambrisko	case SIOCGPRIVATE_0:		/* used by Cisco client utility */
2005164033Srwatson		if ((error = priv_check(td, PRIV_DRIVER)))
200692292Sambrisko			goto out;
2007144242Ssam		error = copyin(ifr->ifr_data, &l_ioctl, sizeof(l_ioctl));
2008144242Ssam		if (error)
2009144242Ssam			goto out;
201088748Sambrisko		mode = l_ioctl.command;
201188748Sambrisko
2012175445Sambrisko		AN_LOCK(sc);
201388748Sambrisko		if (mode >= AIROGCAP && mode <= AIROGSTATSD32) {
201488748Sambrisko			error = readrids(ifp, &l_ioctl);
2015110104Sambrisko		} else if (mode >= AIROPCAP && mode <= AIROPLEAPUSR) {
201688748Sambrisko			error = writerids(ifp, &l_ioctl);
2017110104Sambrisko		} else if (mode >= AIROFLSHRST && mode <= AIRORESTART) {
201888748Sambrisko			error = flashcard(ifp, &l_ioctl);
2019110104Sambrisko		} else {
202088748Sambrisko			error =-1;
202188748Sambrisko		}
2022175445Sambrisko		AN_UNLOCK(sc);
2023144242Ssam		if (!error) {
2024144242Ssam			/* copy out the updated command info */
2025144242Ssam			error = copyout(&l_ioctl, ifr->ifr_data, sizeof(l_ioctl));
2026144242Ssam		}
202788748Sambrisko		break;
2028175446Sambrisko	case SIOCGPRIVATE_1:		/* used by Cisco client utility */
2029164033Srwatson		if ((error = priv_check(td, PRIV_DRIVER)))
203092292Sambrisko			goto out;
2031144242Ssam		error = copyin(ifr->ifr_data, &l_ioctl, sizeof(l_ioctl));
2032144242Ssam		if (error)
2033144242Ssam			goto out;
203488748Sambrisko		l_ioctl.command = 0;
203588748Sambrisko		error = AIROMAGIC;
2036144242Ssam		(void) copyout(&error, l_ioctl.data, sizeof(error));
2037175446Sambrisko		error = 0;
203888748Sambrisko		break;
203977217Sphk	case SIOCG80211:
204088749Sambrisko		sc->areq.an_len = sizeof(sc->areq);
204188748Sambrisko		/* was that a good idea DJA we are doing a short-cut */
204283270Sbrooks		switch (ireq->i_type) {
204377217Sphk		case IEEE80211_IOC_SSID:
2044175445Sambrisko			AN_LOCK(sc);
204578639Sbrooks			if (ireq->i_val == -1) {
204688749Sambrisko				sc->areq.an_type = AN_RID_STATUS;
204777217Sphk				if (an_read_record(sc,
204888749Sambrisko				    (struct an_ltv_gen *)&sc->areq)) {
204977217Sphk					error = EINVAL;
2050175445Sambrisko					AN_UNLOCK(sc);
205177217Sphk					break;
205277217Sphk				}
205377217Sphk				len = status->an_ssidlen;
205477217Sphk				tmpptr = status->an_ssid;
205578639Sbrooks			} else if (ireq->i_val >= 0) {
205688749Sambrisko				sc->areq.an_type = AN_RID_SSIDLIST;
205777217Sphk				if (an_read_record(sc,
205888749Sambrisko				    (struct an_ltv_gen *)&sc->areq)) {
205977217Sphk					error = EINVAL;
2060175445Sambrisko					AN_UNLOCK(sc);
206177217Sphk					break;
206277217Sphk				}
2063119156Sambrisko				max = (sc->areq.an_len - 4)
2064119156Sambrisko				    / sizeof(struct an_ltv_ssid_entry);
2065119156Sambrisko				if ( max > MAX_SSIDS ) {
2066119156Sambrisko					printf("To many SSIDs only using "
2067119156Sambrisko					    "%d of %d\n",
2068119156Sambrisko					    MAX_SSIDS, max);
2069119156Sambrisko					max = MAX_SSIDS;
2070119156Sambrisko				}
2071119156Sambrisko				if (ireq->i_val > max) {
207277217Sphk					error = EINVAL;
2073175445Sambrisko					AN_UNLOCK(sc);
207477217Sphk					break;
2075119156Sambrisko				} else {
2076119156Sambrisko					len = ssids->an_entry[ireq->i_val].an_len;
2077119156Sambrisko					tmpptr = ssids->an_entry[ireq->i_val].an_ssid;
207877217Sphk				}
207977217Sphk			} else {
208077217Sphk				error = EINVAL;
2081175445Sambrisko				AN_UNLOCK(sc);
208277217Sphk				break;
208377217Sphk			}
208478639Sbrooks			if (len > IEEE80211_NWID_LEN) {
208577217Sphk				error = EINVAL;
2086175445Sambrisko				AN_UNLOCK(sc);
208777217Sphk				break;
208877217Sphk			}
2089175445Sambrisko			AN_UNLOCK(sc);
209077217Sphk			ireq->i_len = len;
209177217Sphk			bzero(tmpstr, IEEE80211_NWID_LEN);
209277217Sphk			bcopy(tmpptr, tmpstr, len);
209377217Sphk			error = copyout(tmpstr, ireq->i_data,
209477217Sphk			    IEEE80211_NWID_LEN);
209577217Sphk			break;
209677217Sphk		case IEEE80211_IOC_NUMSSIDS:
2097175445Sambrisko			AN_LOCK(sc);
2098119156Sambrisko			sc->areq.an_len = sizeof(sc->areq);
2099119156Sambrisko			sc->areq.an_type = AN_RID_SSIDLIST;
2100119156Sambrisko			if (an_read_record(sc,
2101119156Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
2102175445Sambrisko				AN_UNLOCK(sc);
2103119156Sambrisko				error = EINVAL;
2104119156Sambrisko				break;
2105119156Sambrisko			}
2106119156Sambrisko			max = (sc->areq.an_len - 4)
2107119156Sambrisko			    / sizeof(struct an_ltv_ssid_entry);
2108175445Sambrisko			AN_UNLOCK(sc);
2109119156Sambrisko			if ( max > MAX_SSIDS ) {
2110119156Sambrisko				printf("To many SSIDs only using "
2111119156Sambrisko				    "%d of %d\n",
2112119156Sambrisko				    MAX_SSIDS, max);
2113119156Sambrisko				max = MAX_SSIDS;
2114119156Sambrisko			}
2115119156Sambrisko			ireq->i_val = max;
211677217Sphk			break;
211777217Sphk		case IEEE80211_IOC_WEP:
2118175445Sambrisko			AN_LOCK(sc);
211988749Sambrisko			sc->areq.an_type = AN_RID_ACTUALCFG;
212077217Sphk			if (an_read_record(sc,
212188749Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
212277217Sphk				error = EINVAL;
2123175445Sambrisko				AN_UNLOCK(sc);
212477217Sphk				break;
212577217Sphk			}
2126175445Sambrisko			AN_UNLOCK(sc);
212778639Sbrooks			if (config->an_authtype & AN_AUTHTYPE_PRIVACY_IN_USE) {
212878639Sbrooks				if (config->an_authtype &
212977217Sphk				    AN_AUTHTYPE_ALLOW_UNENCRYPTED)
213077217Sphk					ireq->i_val = IEEE80211_WEP_MIXED;
213177217Sphk				else
213277217Sphk					ireq->i_val = IEEE80211_WEP_ON;
213377217Sphk			} else {
213477217Sphk				ireq->i_val = IEEE80211_WEP_OFF;
213577217Sphk			}
213677217Sphk			break;
213777217Sphk		case IEEE80211_IOC_WEPKEY:
213877217Sphk			/*
213977217Sphk			 * XXX: I'm not entierly convinced this is
214077217Sphk			 * correct, but it's what is implemented in
214177217Sphk			 * ancontrol so it will have to do until we get
214277217Sphk			 * access to actual Cisco code.
214377217Sphk			 */
214488748Sambrisko			if (ireq->i_val < 0 || ireq->i_val > 8) {
214577217Sphk				error = EINVAL;
214677217Sphk				break;
214777217Sphk			}
214877217Sphk			len = 0;
214988748Sambrisko			if (ireq->i_val < 5) {
2150175445Sambrisko				AN_LOCK(sc);
215188749Sambrisko				sc->areq.an_type = AN_RID_WEP_TEMP;
215278639Sbrooks				for (i = 0; i < 5; i++) {
215377217Sphk					if (an_read_record(sc,
215488749Sambrisko					    (struct an_ltv_gen *)&sc->areq)) {
215577217Sphk						error = EINVAL;
215677217Sphk						break;
215777217Sphk					}
215878639Sbrooks					if (key->kindex == 0xffff)
215977217Sphk						break;
216078639Sbrooks					if (key->kindex == ireq->i_val)
216178639Sbrooks						len = key->klen;
216277217Sphk					/* Required to get next entry */
216388749Sambrisko					sc->areq.an_type = AN_RID_WEP_PERM;
216477217Sphk				}
2165175445Sambrisko				AN_UNLOCK(sc);
2166175445Sambrisko				if (error != 0) {
216777217Sphk					break;
2168175445Sambrisko				}
216977217Sphk			}
217077217Sphk			/* We aren't allowed to read the value of the
217177217Sphk			 * key from the card so we just output zeros
217277217Sphk			 * like we would if we could read the card, but
217377217Sphk			 * denied the user access.
217477217Sphk			 */
217577217Sphk			bzero(tmpstr, len);
217677217Sphk			ireq->i_len = len;
217777217Sphk			error = copyout(tmpstr, ireq->i_data, len);
217877217Sphk			break;
217977217Sphk		case IEEE80211_IOC_NUMWEPKEYS:
218088748Sambrisko			ireq->i_val = 9; /* include home key */
218177217Sphk			break;
218277217Sphk		case IEEE80211_IOC_WEPTXKEY:
218378639Sbrooks			/*
218478639Sbrooks			 * For some strange reason, you have to read all
218578639Sbrooks			 * keys before you can read the txkey.
218678639Sbrooks			 */
2187175445Sambrisko			AN_LOCK(sc);
218888749Sambrisko			sc->areq.an_type = AN_RID_WEP_TEMP;
218978639Sbrooks			for (i = 0; i < 5; i++) {
219078639Sbrooks				if (an_read_record(sc,
219188749Sambrisko				    (struct an_ltv_gen *) &sc->areq)) {
219278639Sbrooks					error = EINVAL;
219378639Sbrooks					break;
219478639Sbrooks				}
2195175445Sambrisko				if (key->kindex == 0xffff) {
219678639Sbrooks					break;
2197175445Sambrisko				}
219878639Sbrooks				/* Required to get next entry */
219988749Sambrisko				sc->areq.an_type = AN_RID_WEP_PERM;
220078639Sbrooks			}
2201175445Sambrisko			if (error != 0) {
2202175445Sambrisko				AN_UNLOCK(sc);
220378639Sbrooks				break;
2204175445Sambrisko			}
220578639Sbrooks
220688749Sambrisko			sc->areq.an_type = AN_RID_WEP_PERM;
220777217Sphk			key->kindex = 0xffff;
220877217Sphk			if (an_read_record(sc,
220988749Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
221077217Sphk				error = EINVAL;
2211175445Sambrisko				AN_UNLOCK(sc);
221277217Sphk				break;
221377217Sphk			}
221477217Sphk			ireq->i_val = key->mac[0];
221588748Sambrisko			/*
221688748Sambrisko			 * Check for home mode.  Map home mode into
221788748Sambrisko			 * 5th key since that is how it is stored on
221888748Sambrisko			 * the card
221988748Sambrisko			 */
222088749Sambrisko			sc->areq.an_len  = sizeof(struct an_ltv_genconfig);
222188749Sambrisko			sc->areq.an_type = AN_RID_GENCONFIG;
222288748Sambrisko			if (an_read_record(sc,
222388749Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
222488748Sambrisko				error = EINVAL;
2225175445Sambrisko				AN_UNLOCK(sc);
222688748Sambrisko				break;
222788748Sambrisko			}
222888748Sambrisko			if (config->an_home_product & AN_HOME_NETWORK)
222988748Sambrisko				ireq->i_val = 4;
2230175445Sambrisko			AN_UNLOCK(sc);
223177217Sphk			break;
223277217Sphk		case IEEE80211_IOC_AUTHMODE:
2233175445Sambrisko			AN_LOCK(sc);
223488749Sambrisko			sc->areq.an_type = AN_RID_ACTUALCFG;
223577217Sphk			if (an_read_record(sc,
223688749Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
223777217Sphk				error = EINVAL;
2238175445Sambrisko				AN_UNLOCK(sc);
223977217Sphk				break;
224077217Sphk			}
2241175445Sambrisko			AN_UNLOCK(sc);
224277217Sphk			if ((config->an_authtype & AN_AUTHTYPE_MASK) ==
224377217Sphk			    AN_AUTHTYPE_NONE) {
224477217Sphk			    ireq->i_val = IEEE80211_AUTH_NONE;
224577217Sphk			} else if ((config->an_authtype & AN_AUTHTYPE_MASK) ==
224677217Sphk			    AN_AUTHTYPE_OPEN) {
224777217Sphk			    ireq->i_val = IEEE80211_AUTH_OPEN;
224877217Sphk			} else if ((config->an_authtype & AN_AUTHTYPE_MASK) ==
224977217Sphk			    AN_AUTHTYPE_SHAREDKEY) {
225077217Sphk			    ireq->i_val = IEEE80211_AUTH_SHARED;
225177217Sphk			} else
225277217Sphk				error = EINVAL;
225377217Sphk			break;
225477217Sphk		case IEEE80211_IOC_STATIONNAME:
2255175445Sambrisko			AN_LOCK(sc);
225688749Sambrisko			sc->areq.an_type = AN_RID_ACTUALCFG;
225777217Sphk			if (an_read_record(sc,
225888749Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
225977217Sphk				error = EINVAL;
2260175445Sambrisko				AN_UNLOCK(sc);
226177217Sphk				break;
226277217Sphk			}
2263175445Sambrisko			AN_UNLOCK(sc);
226477217Sphk			ireq->i_len = sizeof(config->an_nodename);
226577217Sphk			tmpptr = config->an_nodename;
226677217Sphk			bzero(tmpstr, IEEE80211_NWID_LEN);
226777217Sphk			bcopy(tmpptr, tmpstr, ireq->i_len);
226877217Sphk			error = copyout(tmpstr, ireq->i_data,
226977217Sphk			    IEEE80211_NWID_LEN);
227077217Sphk			break;
227177217Sphk		case IEEE80211_IOC_CHANNEL:
2272175445Sambrisko			AN_LOCK(sc);
227388749Sambrisko			sc->areq.an_type = AN_RID_STATUS;
227477217Sphk			if (an_read_record(sc,
227588749Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
227677217Sphk				error = EINVAL;
2277175445Sambrisko				AN_UNLOCK(sc);
227877217Sphk				break;
227977217Sphk			}
2280175445Sambrisko			AN_UNLOCK(sc);
228177217Sphk			ireq->i_val = status->an_cur_channel;
228277217Sphk			break;
2283175445Sambrisko		case IEEE80211_IOC_CURCHAN:
2284175445Sambrisko			AN_LOCK(sc);
2285175445Sambrisko			sc->areq.an_type = AN_RID_STATUS;
2286175445Sambrisko			if (an_read_record(sc,
2287175445Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
2288172112Savatar				error = EINVAL;
2289175445Sambrisko				AN_UNLOCK(sc);
2290172112Savatar				break;
2291172112Savatar			}
2292175445Sambrisko			AN_UNLOCK(sc);
2293172112Savatar			bzero(&ch, sizeof(ch));
2294172112Savatar			ch.ic_freq = ieee80211_ieee2mhz(status->an_cur_channel,
2295172112Savatar			    IEEE80211_CHAN_B);
2296172112Savatar			ch.ic_flags = IEEE80211_CHAN_B;
2297172112Savatar			ch.ic_ieee = status->an_cur_channel;
2298172112Savatar			error = copyout(&ch, ireq->i_data, sizeof(ch));
2299172112Savatar			break;
230077217Sphk		case IEEE80211_IOC_POWERSAVE:
2301175445Sambrisko			AN_LOCK(sc);
230288749Sambrisko			sc->areq.an_type = AN_RID_ACTUALCFG;
230377217Sphk			if (an_read_record(sc,
230488749Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
230577217Sphk				error = EINVAL;
2306175445Sambrisko				AN_UNLOCK(sc);
230777217Sphk				break;
230877217Sphk			}
2309175445Sambrisko			AN_UNLOCK(sc);
231078639Sbrooks			if (config->an_psave_mode == AN_PSAVE_NONE) {
231177217Sphk				ireq->i_val = IEEE80211_POWERSAVE_OFF;
231278639Sbrooks			} else if (config->an_psave_mode == AN_PSAVE_CAM) {
231377217Sphk				ireq->i_val = IEEE80211_POWERSAVE_CAM;
231478639Sbrooks			} else if (config->an_psave_mode == AN_PSAVE_PSP) {
231577217Sphk				ireq->i_val = IEEE80211_POWERSAVE_PSP;
231678639Sbrooks			} else if (config->an_psave_mode == AN_PSAVE_PSP_CAM) {
231777217Sphk				ireq->i_val = IEEE80211_POWERSAVE_PSP_CAM;
231877217Sphk			} else
231977217Sphk				error = EINVAL;
232077217Sphk			break;
232177217Sphk		case IEEE80211_IOC_POWERSAVESLEEP:
2322175445Sambrisko			AN_LOCK(sc);
232388749Sambrisko			sc->areq.an_type = AN_RID_ACTUALCFG;
232477217Sphk			if (an_read_record(sc,
232588749Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
232677217Sphk				error = EINVAL;
2327175445Sambrisko				AN_UNLOCK(sc);
232877217Sphk				break;
232977217Sphk			}
2330175445Sambrisko			AN_UNLOCK(sc);
233177217Sphk			ireq->i_val = config->an_listen_interval;
233277217Sphk			break;
233383270Sbrooks		}
233477217Sphk		break;
233577217Sphk	case SIOCS80211:
2336164033Srwatson		if ((error = priv_check(td, PRIV_NET80211_MANAGE)))
233777217Sphk			goto out;
2338175445Sambrisko		AN_LOCK(sc);
233988749Sambrisko		sc->areq.an_len = sizeof(sc->areq);
234077217Sphk		/*
234177217Sphk		 * We need a config structure for everything but the WEP
234277217Sphk		 * key management and SSIDs so we get it now so avoid
234377217Sphk		 * duplicating this code every time.
234477217Sphk		 */
234577217Sphk		if (ireq->i_type != IEEE80211_IOC_SSID &&
234677217Sphk		    ireq->i_type != IEEE80211_IOC_WEPKEY &&
234777217Sphk		    ireq->i_type != IEEE80211_IOC_WEPTXKEY) {
234888749Sambrisko			sc->areq.an_type = AN_RID_GENCONFIG;
234977217Sphk			if (an_read_record(sc,
235088749Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
235177217Sphk				error = EINVAL;
2352175445Sambrisko				AN_UNLOCK(sc);
235377217Sphk				break;
235477217Sphk			}
235577217Sphk		}
235683270Sbrooks		switch (ireq->i_type) {
235777217Sphk		case IEEE80211_IOC_SSID:
2358119156Sambrisko			sc->areq.an_len = sizeof(sc->areq);
235988749Sambrisko			sc->areq.an_type = AN_RID_SSIDLIST;
236077217Sphk			if (an_read_record(sc,
236188749Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
236277217Sphk				error = EINVAL;
2363175445Sambrisko				AN_UNLOCK(sc);
236477217Sphk				break;
236577217Sphk			}
236678639Sbrooks			if (ireq->i_len > IEEE80211_NWID_LEN) {
236777217Sphk				error = EINVAL;
2368175445Sambrisko				AN_UNLOCK(sc);
236977217Sphk				break;
237077217Sphk			}
2371119156Sambrisko			max = (sc->areq.an_len - 4)
2372119156Sambrisko			    / sizeof(struct an_ltv_ssid_entry);
2373119156Sambrisko			if ( max > MAX_SSIDS ) {
2374119156Sambrisko				printf("To many SSIDs only using "
2375119156Sambrisko				    "%d of %d\n",
2376119156Sambrisko				    MAX_SSIDS, max);
2377119156Sambrisko				max = MAX_SSIDS;
2378119156Sambrisko			}
2379119156Sambrisko			if (ireq->i_val > max) {
2380119156Sambrisko				error = EINVAL;
2381175445Sambrisko				AN_UNLOCK(sc);
238277217Sphk				break;
2383119156Sambrisko			} else {
238477217Sphk				error = copyin(ireq->i_data,
2385175445Sambrisko				    ssids->an_entry[ireq->i_val].an_ssid,
2386119156Sambrisko				    ireq->i_len);
2387175445Sambrisko				ssids->an_entry[ireq->i_val].an_len
2388119156Sambrisko				    = ireq->i_len;
2389175445Sambrisko				sc->areq.an_len = sizeof(sc->areq);
2390175445Sambrisko				sc->areq.an_type = AN_RID_SSIDLIST;
2391175445Sambrisko				an_setdef(sc, &sc->areq);
2392175445Sambrisko				AN_UNLOCK(sc);
239377217Sphk				break;
239477217Sphk			}
239577217Sphk			break;
239677217Sphk		case IEEE80211_IOC_WEP:
239777217Sphk			switch (ireq->i_val) {
239877217Sphk			case IEEE80211_WEP_OFF:
239977217Sphk				config->an_authtype &=
240077217Sphk				    ~(AN_AUTHTYPE_PRIVACY_IN_USE |
240177217Sphk				    AN_AUTHTYPE_ALLOW_UNENCRYPTED);
240277217Sphk				break;
240377217Sphk			case IEEE80211_WEP_ON:
240477217Sphk				config->an_authtype |=
240577217Sphk				    AN_AUTHTYPE_PRIVACY_IN_USE;
240677217Sphk				config->an_authtype &=
240777217Sphk				    ~AN_AUTHTYPE_ALLOW_UNENCRYPTED;
240877217Sphk				break;
240977217Sphk			case IEEE80211_WEP_MIXED:
241077217Sphk				config->an_authtype |=
241177217Sphk				    AN_AUTHTYPE_PRIVACY_IN_USE |
241277217Sphk				    AN_AUTHTYPE_ALLOW_UNENCRYPTED;
241377217Sphk				break;
241477217Sphk			default:
241577217Sphk				error = EINVAL;
241677217Sphk				break;
241777217Sphk			}
2418175445Sambrisko			if (error != EINVAL)
2419175445Sambrisko				an_setdef(sc, &sc->areq);
2420175445Sambrisko			AN_UNLOCK(sc);
242177217Sphk			break;
242277217Sphk		case IEEE80211_IOC_WEPKEY:
2423110531Sambrisko			if (ireq->i_val < 0 || ireq->i_val > 8 ||
242477217Sphk			    ireq->i_len > 13) {
242577217Sphk				error = EINVAL;
2426175445Sambrisko				AN_UNLOCK(sc);
242777217Sphk				break;
242877217Sphk			}
242977217Sphk			error = copyin(ireq->i_data, tmpstr, 13);
2430175445Sambrisko			if (error != 0) {
2431175445Sambrisko				AN_UNLOCK(sc);
243277217Sphk				break;
2433175445Sambrisko			}
2434110531Sambrisko			/*
2435110531Sambrisko			 * Map the 9th key into the home mode
2436110531Sambrisko			 * since that is how it is stored on
2437110531Sambrisko			 * the card
2438110531Sambrisko			 */
243988749Sambrisko			bzero(&sc->areq, sizeof(struct an_ltv_key));
244088749Sambrisko			sc->areq.an_len = sizeof(struct an_ltv_key);
244177217Sphk			key->mac[0] = 1;	/* The others are 0. */
2442110531Sambrisko			if (ireq->i_val < 4) {
244388749Sambrisko				sc->areq.an_type = AN_RID_WEP_TEMP;
2444110531Sambrisko				key->kindex = ireq->i_val;
2445110531Sambrisko			} else {
244688749Sambrisko				sc->areq.an_type = AN_RID_WEP_PERM;
2447110531Sambrisko				key->kindex = ireq->i_val - 4;
2448110531Sambrisko			}
244977217Sphk			key->klen = ireq->i_len;
245077217Sphk			bcopy(tmpstr, key->key, key->klen);
2451175445Sambrisko			an_setdef(sc, &sc->areq);
2452175445Sambrisko			AN_UNLOCK(sc);
245377217Sphk			break;
245477217Sphk		case IEEE80211_IOC_WEPTXKEY:
2455110531Sambrisko			if (ireq->i_val < 0 || ireq->i_val > 4) {
2456110531Sambrisko				error = EINVAL;
2457175445Sambrisko				AN_UNLOCK(sc);
2458110531Sambrisko				break;
2459110531Sambrisko			}
2460110531Sambrisko
246188748Sambrisko			/*
246288748Sambrisko			 * Map the 5th key into the home mode
246388748Sambrisko			 * since that is how it is stored on
246488748Sambrisko			 * the card
246588748Sambrisko			 */
246688749Sambrisko			sc->areq.an_len  = sizeof(struct an_ltv_genconfig);
246788749Sambrisko			sc->areq.an_type = AN_RID_ACTUALCFG;
246888748Sambrisko			if (an_read_record(sc,
2469175445Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
2470175445Sambrisko				error = EINVAL;
2471175445Sambrisko				AN_UNLOCK(sc);
247288748Sambrisko				break;
247388748Sambrisko			}
247488748Sambrisko			if (ireq->i_val ==  4) {
247588748Sambrisko				config->an_home_product |= AN_HOME_NETWORK;
247688748Sambrisko				ireq->i_val = 0;
247788748Sambrisko			} else {
247888748Sambrisko				config->an_home_product &= ~AN_HOME_NETWORK;
247988748Sambrisko			}
248088748Sambrisko
248188748Sambrisko			sc->an_config.an_home_product
248288748Sambrisko				= config->an_home_product;
248388748Sambrisko
2484110531Sambrisko			/* update configuration */
2485199154Sjhb			an_init_locked(sc);
2486110531Sambrisko
248788749Sambrisko			bzero(&sc->areq, sizeof(struct an_ltv_key));
248888749Sambrisko			sc->areq.an_len = sizeof(struct an_ltv_key);
248988749Sambrisko			sc->areq.an_type = AN_RID_WEP_PERM;
249077217Sphk			key->kindex = 0xffff;
249177217Sphk			key->mac[0] = ireq->i_val;
2492175445Sambrisko			an_setdef(sc, &sc->areq);
2493175445Sambrisko			AN_UNLOCK(sc);
249477217Sphk			break;
249577217Sphk		case IEEE80211_IOC_AUTHMODE:
249677217Sphk			switch (ireq->i_val) {
249777217Sphk			case IEEE80211_AUTH_NONE:
249877217Sphk				config->an_authtype = AN_AUTHTYPE_NONE |
249977217Sphk				    (config->an_authtype & ~AN_AUTHTYPE_MASK);
250077217Sphk				break;
250177217Sphk			case IEEE80211_AUTH_OPEN:
250277217Sphk				config->an_authtype = AN_AUTHTYPE_OPEN |
250377217Sphk				    (config->an_authtype & ~AN_AUTHTYPE_MASK);
250477217Sphk				break;
250577217Sphk			case IEEE80211_AUTH_SHARED:
250677217Sphk				config->an_authtype = AN_AUTHTYPE_SHAREDKEY |
250777217Sphk				    (config->an_authtype & ~AN_AUTHTYPE_MASK);
250877217Sphk				break;
250977217Sphk			default:
251077217Sphk				error = EINVAL;
251177217Sphk			}
2512175445Sambrisko			if (error != EINVAL) {
2513175445Sambrisko				an_setdef(sc, &sc->areq);
2514175445Sambrisko			}
2515175445Sambrisko			AN_UNLOCK(sc);
251677217Sphk			break;
251777217Sphk		case IEEE80211_IOC_STATIONNAME:
251878639Sbrooks			if (ireq->i_len > 16) {
251977217Sphk				error = EINVAL;
2520175445Sambrisko				AN_UNLOCK(sc);
252177217Sphk				break;
252277217Sphk			}
252377217Sphk			bzero(config->an_nodename, 16);
252477217Sphk			error = copyin(ireq->i_data,
252577217Sphk			    config->an_nodename, ireq->i_len);
2526175445Sambrisko			an_setdef(sc, &sc->areq);
2527175445Sambrisko			AN_UNLOCK(sc);
252877217Sphk			break;
252977217Sphk		case IEEE80211_IOC_CHANNEL:
253077217Sphk			/*
253177217Sphk			 * The actual range is 1-14, but if you set it
253277217Sphk			 * to 0 you get the default so we let that work
253377217Sphk			 * too.
253477217Sphk			 */
253577217Sphk			if (ireq->i_val < 0 || ireq->i_val >14) {
253677217Sphk				error = EINVAL;
2537175445Sambrisko				AN_UNLOCK(sc);
253877217Sphk				break;
253977217Sphk			}
254077217Sphk			config->an_ds_channel = ireq->i_val;
2541175445Sambrisko			an_setdef(sc, &sc->areq);
2542175445Sambrisko			AN_UNLOCK(sc);
254377217Sphk			break;
254477217Sphk		case IEEE80211_IOC_POWERSAVE:
254577217Sphk			switch (ireq->i_val) {
254677217Sphk			case IEEE80211_POWERSAVE_OFF:
254777217Sphk				config->an_psave_mode = AN_PSAVE_NONE;
254877217Sphk				break;
254977217Sphk			case IEEE80211_POWERSAVE_CAM:
255077217Sphk				config->an_psave_mode = AN_PSAVE_CAM;
255177217Sphk				break;
255277217Sphk			case IEEE80211_POWERSAVE_PSP:
255377217Sphk				config->an_psave_mode = AN_PSAVE_PSP;
255477217Sphk				break;
255577217Sphk			case IEEE80211_POWERSAVE_PSP_CAM:
255677217Sphk				config->an_psave_mode = AN_PSAVE_PSP_CAM;
255777217Sphk				break;
255877217Sphk			default:
255977217Sphk				error = EINVAL;
256077217Sphk				break;
256177217Sphk			}
2562175445Sambrisko			an_setdef(sc, &sc->areq);
2563175445Sambrisko			AN_UNLOCK(sc);
256477217Sphk			break;
256577217Sphk		case IEEE80211_IOC_POWERSAVESLEEP:
256677217Sphk			config->an_listen_interval = ireq->i_val;
2567175445Sambrisko			an_setdef(sc, &sc->areq);
2568175445Sambrisko			AN_UNLOCK(sc);
256977217Sphk			break;
2570199154Sjhb		default:
2571199154Sjhb			AN_UNLOCK(sc);
2572199154Sjhb			break;
257377217Sphk		}
257477217Sphk
2575175445Sambrisko		/*
2576175445Sambrisko		if (!error) {
2577175445Sambrisko			AN_LOCK(sc);
257888749Sambrisko			an_setdef(sc, &sc->areq);
2579175445Sambrisko			AN_UNLOCK(sc);
2580175445Sambrisko		}
2581175445Sambrisko		*/
258277217Sphk		break;
258355992Swpaul	default:
2584106937Ssam		error = ether_ioctl(ifp, command, data);
258555992Swpaul		break;
258655992Swpaul	}
258761816Srobertoout:
258855992Swpaul
258978639Sbrooks	return(error != 0);
259055992Swpaul}
259155992Swpaul
259283270Sbrooksstatic int
2593150446Simpan_init_tx_ring(struct an_softc *sc)
259455992Swpaul{
259555992Swpaul	int			i;
259655992Swpaul	int			id;
259755992Swpaul
259855992Swpaul	if (sc->an_gone)
259955992Swpaul		return (0);
260055992Swpaul
2601108401Sambrisko	if (!sc->mpi350) {
2602108401Sambrisko		for (i = 0; i < AN_TX_RING_CNT; i++) {
2603108401Sambrisko			if (an_alloc_nicmem(sc, 1518 +
2604108401Sambrisko			    0x44, &id))
2605108401Sambrisko				return(ENOMEM);
2606108401Sambrisko			sc->an_rdata.an_tx_fids[i] = id;
2607108401Sambrisko			sc->an_rdata.an_tx_ring[i] = 0;
2608108401Sambrisko		}
260955992Swpaul	}
261055992Swpaul
261155992Swpaul	sc->an_rdata.an_tx_prod = 0;
261255992Swpaul	sc->an_rdata.an_tx_cons = 0;
2613108401Sambrisko	sc->an_rdata.an_tx_empty = 1;
261455992Swpaul
261555992Swpaul	return(0);
261655992Swpaul}
261755992Swpaul
261883270Sbrooksstatic void
2619150446Simpan_init(void *xsc)
262055992Swpaul{
262155992Swpaul	struct an_softc		*sc = xsc;
262255992Swpaul
262367094Swpaul	AN_LOCK(sc);
2624199154Sjhb	an_init_locked(sc);
2625199154Sjhb	AN_UNLOCK(sc);
2626199154Sjhb}
262767094Swpaul
2628199154Sjhbstatic void
2629199154Sjhban_init_locked(struct an_softc *sc)
2630199154Sjhb{
2631199154Sjhb	struct ifnet *ifp;
2632199154Sjhb
2633199154Sjhb	AN_LOCK_ASSERT(sc);
2634199154Sjhb	ifp = sc->an_ifp;
2635199154Sjhb	if (sc->an_gone)
263655992Swpaul		return;
263755992Swpaul
2638148887Srwatson	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
263955992Swpaul		an_stop(sc);
264055992Swpaul
264155992Swpaul	sc->an_associated = 0;
264255992Swpaul
264355992Swpaul	/* Allocate the TX buffers */
264455992Swpaul	if (an_init_tx_ring(sc)) {
264555992Swpaul		an_reset(sc);
2646108401Sambrisko		if (sc->mpi350)
2647175445Sambrisko			an_init_mpi350_desc(sc);
264855992Swpaul		if (an_init_tx_ring(sc)) {
2649198987Sjhb			if_printf(ifp, "tx buffer allocation failed\n");
265055992Swpaul			return;
265155992Swpaul		}
265255992Swpaul	}
265355992Swpaul
265455992Swpaul	/* Set our MAC address. */
2655152315Sru	bcopy((char *)IF_LLADDR(sc->an_ifp),
265655992Swpaul	    (char *)&sc->an_config.an_macaddr, ETHER_ADDR_LEN);
265755992Swpaul
265855992Swpaul	if (ifp->if_flags & IFF_BROADCAST)
265955992Swpaul		sc->an_config.an_rxmode = AN_RXMODE_BC_ADDR;
266055992Swpaul	else
266155992Swpaul		sc->an_config.an_rxmode = AN_RXMODE_ADDR;
266255992Swpaul
266355992Swpaul	if (ifp->if_flags & IFF_MULTICAST)
266455992Swpaul		sc->an_config.an_rxmode = AN_RXMODE_BC_MC_ADDR;
266555992Swpaul
266683269Sbrooks	if (ifp->if_flags & IFF_PROMISC) {
266783269Sbrooks		if (sc->an_monitor & AN_MONITOR) {
266883269Sbrooks			if (sc->an_monitor & AN_MONITOR_ANY_BSS) {
266983269Sbrooks				sc->an_config.an_rxmode |=
267083269Sbrooks				    AN_RXMODE_80211_MONITOR_ANYBSS |
267183269Sbrooks				    AN_RXMODE_NO_8023_HEADER;
267283269Sbrooks			} else {
267383269Sbrooks				sc->an_config.an_rxmode |=
267483269Sbrooks				    AN_RXMODE_80211_MONITOR_CURBSS |
267583269Sbrooks				    AN_RXMODE_NO_8023_HEADER;
267683269Sbrooks			}
267783269Sbrooks		}
267883269Sbrooks	}
267955992Swpaul
2680184708Sbz#ifdef ANCACHE
2681108401Sambrisko	if (sc->an_have_rssimap)
2682108401Sambrisko		sc->an_config.an_rxmode |= AN_RXMODE_NORMALIZED_RSSI;
2683184708Sbz#endif
2684108401Sambrisko
268555992Swpaul	/* Set the ssid list */
268655992Swpaul	sc->an_ssidlist.an_type = AN_RID_SSIDLIST;
2687119156Sambrisko	sc->an_ssidlist.an_len = sizeof(struct an_ltv_ssidlist_new);
268855992Swpaul	if (an_write_record(sc, (struct an_ltv_gen *)&sc->an_ssidlist)) {
2689198987Sjhb		if_printf(ifp, "failed to set ssid list\n");
269055992Swpaul		return;
269155992Swpaul	}
269255992Swpaul
269355992Swpaul	/* Set the AP list */
269455992Swpaul	sc->an_aplist.an_type = AN_RID_APLIST;
269555992Swpaul	sc->an_aplist.an_len = sizeof(struct an_ltv_aplist);
269655992Swpaul	if (an_write_record(sc, (struct an_ltv_gen *)&sc->an_aplist)) {
2697198987Sjhb		if_printf(ifp, "failed to set AP list\n");
269855992Swpaul		return;
269955992Swpaul	}
270055992Swpaul
270155992Swpaul	/* Set the configuration in the NIC */
270255992Swpaul	sc->an_config.an_len = sizeof(struct an_ltv_genconfig);
270355992Swpaul	sc->an_config.an_type = AN_RID_GENCONFIG;
270455992Swpaul	if (an_write_record(sc, (struct an_ltv_gen *)&sc->an_config)) {
2705198987Sjhb		if_printf(ifp, "failed to set configuration\n");
270655992Swpaul		return;
270755992Swpaul	}
270855992Swpaul
270955992Swpaul	/* Enable the MAC */
271055992Swpaul	if (an_cmd(sc, AN_CMD_ENABLE, 0)) {
2711198987Sjhb		if_printf(ifp, "failed to enable MAC\n");
271255992Swpaul		return;
271355992Swpaul	}
271455992Swpaul
271574698Sarchie	if (ifp->if_flags & IFF_PROMISC)
271674698Sarchie		an_cmd(sc, AN_CMD_SET_MODE, 0xffff);
271774698Sarchie
271855992Swpaul	/* enable interrupts */
2719119156Sambrisko	CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), AN_INTRS(sc->mpi350));
272055992Swpaul
2721148887Srwatson	ifp->if_drv_flags |= IFF_DRV_RUNNING;
2722148887Srwatson	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
272355992Swpaul
2724173668Savatar	callout_reset(&sc->an_stat_ch, hz, an_stats_update, sc);
272555992Swpaul
272655992Swpaul	return;
272755992Swpaul}
272855992Swpaul
272983270Sbrooksstatic void
2730150446Simpan_start(struct ifnet *ifp)
273155992Swpaul{
273255992Swpaul	struct an_softc		*sc;
2733199154Sjhb
2734199154Sjhb	sc = ifp->if_softc;
2735199154Sjhb	AN_LOCK(sc);
2736199154Sjhb	an_start_locked(ifp);
2737199154Sjhb	AN_UNLOCK(sc);
2738199154Sjhb}
2739199154Sjhb
2740199154Sjhbstatic void
2741199154Sjhban_start_locked(struct ifnet *ifp)
2742199154Sjhb{
2743199154Sjhb	struct an_softc		*sc;
274455992Swpaul	struct mbuf		*m0 = NULL;
274555992Swpaul	struct an_txframe_802_3	tx_frame_802_3;
274655992Swpaul	struct ether_header	*eh;
2747108401Sambrisko	int			id, idx, i;
2748175446Sambrisko	unsigned char		txcontrol;
2749108401Sambrisko	struct an_card_tx_desc an_tx_desc;
2750108401Sambrisko	u_int8_t		*buf;
275155992Swpaul
275255992Swpaul	sc = ifp->if_softc;
275355992Swpaul
2754199154Sjhb	AN_LOCK_ASSERT(sc);
275555992Swpaul	if (sc->an_gone)
275655992Swpaul		return;
275755992Swpaul
2758148887Srwatson	if (ifp->if_drv_flags & IFF_DRV_OACTIVE)
275955992Swpaul		return;
276055992Swpaul
276155992Swpaul	if (!sc->an_associated)
276255992Swpaul		return;
276355992Swpaul
276490990Sbrooks	/* We can't send in monitor mode so toss any attempts. */
276583269Sbrooks	if (sc->an_monitor && (ifp->if_flags & IFF_PROMISC)) {
276683270Sbrooks		for (;;) {
2767132986Smlaier			IFQ_DRV_DEQUEUE(&ifp->if_snd, m0);
276883269Sbrooks			if (m0 == NULL)
276983269Sbrooks				break;
277090990Sbrooks			m_freem(m0);
277183269Sbrooks		}
277283269Sbrooks		return;
277383269Sbrooks	}
277483269Sbrooks
277555992Swpaul	idx = sc->an_rdata.an_tx_prod;
277655992Swpaul
2777108401Sambrisko	if (!sc->mpi350) {
2778108401Sambrisko		bzero((char *)&tx_frame_802_3, sizeof(tx_frame_802_3));
277955992Swpaul
2780108401Sambrisko		while (sc->an_rdata.an_tx_ring[idx] == 0) {
2781132986Smlaier			IFQ_DRV_DEQUEUE(&ifp->if_snd, m0);
2782108401Sambrisko			if (m0 == NULL)
2783108401Sambrisko				break;
278455992Swpaul
2785108401Sambrisko			id = sc->an_rdata.an_tx_fids[idx];
2786108401Sambrisko			eh = mtod(m0, struct ether_header *);
278783270Sbrooks
2788108401Sambrisko			bcopy((char *)&eh->ether_dhost,
2789175445Sambrisko			      (char *)&tx_frame_802_3.an_tx_dst_addr,
2790108401Sambrisko			      ETHER_ADDR_LEN);
2791108401Sambrisko			bcopy((char *)&eh->ether_shost,
2792175445Sambrisko			      (char *)&tx_frame_802_3.an_tx_src_addr,
2793108401Sambrisko			      ETHER_ADDR_LEN);
279455992Swpaul
2795108401Sambrisko			/* minus src/dest mac & type */
2796108401Sambrisko			tx_frame_802_3.an_tx_802_3_payload_len =
2797175445Sambrisko				m0->m_pkthdr.len - 12;
279855992Swpaul
2799108401Sambrisko			m_copydata(m0, sizeof(struct ether_header) - 2 ,
2800108401Sambrisko				   tx_frame_802_3.an_tx_802_3_payload_len,
2801108401Sambrisko				   (caddr_t)&sc->an_txbuf);
2802108401Sambrisko
2803199757Sjhb			txcontrol = AN_TXCTL_8023 | AN_TXCTL_HW(sc->mpi350);
2804108401Sambrisko			/* write the txcontrol only */
2805108401Sambrisko			an_write_data(sc, id, 0x08, (caddr_t)&txcontrol,
2806108401Sambrisko				      sizeof(txcontrol));
2807108401Sambrisko
2808108401Sambrisko			/* 802_3 header */
2809108401Sambrisko			an_write_data(sc, id, 0x34, (caddr_t)&tx_frame_802_3,
2810108401Sambrisko				      sizeof(struct an_txframe_802_3));
2811108401Sambrisko
2812108401Sambrisko			/* in mbuf header type is just before payload */
2813108401Sambrisko			an_write_data(sc, id, 0x44, (caddr_t)&sc->an_txbuf,
2814108401Sambrisko				      tx_frame_802_3.an_tx_802_3_payload_len);
2815108401Sambrisko
2816108401Sambrisko			/*
2817108401Sambrisko			 * If there's a BPF listner, bounce a copy of
2818108401Sambrisko			 * this frame to him.
2819108401Sambrisko			 */
2820108401Sambrisko			BPF_MTAP(ifp, m0);
2821108401Sambrisko
2822108401Sambrisko			m_freem(m0);
2823108401Sambrisko			m0 = NULL;
2824108401Sambrisko
2825108401Sambrisko			sc->an_rdata.an_tx_ring[idx] = id;
2826108401Sambrisko			if (an_cmd(sc, AN_CMD_TX, id))
2827198987Sjhb				if_printf(ifp, "xmit failed\n");
2828108401Sambrisko
2829108401Sambrisko			AN_INC(idx, AN_TX_RING_CNT);
2830119156Sambrisko
2831119156Sambrisko			/*
2832119156Sambrisko			 * Set a timeout in case the chip goes out to lunch.
2833119156Sambrisko			 */
2834199154Sjhb			sc->an_timer = 5;
2835108401Sambrisko		}
2836108401Sambrisko	} else { /* MPI-350 */
2837130620Sambrisko		/* Disable interrupts. */
2838130620Sambrisko		CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), 0);
2839130620Sambrisko
2840108401Sambrisko		while (sc->an_rdata.an_tx_empty ||
2841108401Sambrisko		    idx != sc->an_rdata.an_tx_cons) {
2842132986Smlaier			IFQ_DRV_DEQUEUE(&ifp->if_snd, m0);
2843108401Sambrisko			if (m0 == NULL) {
2844108401Sambrisko				break;
2845108401Sambrisko			}
2846108401Sambrisko			buf = sc->an_tx_buffer[idx].an_dma_vaddr;
2847108401Sambrisko
2848108401Sambrisko			eh = mtod(m0, struct ether_header *);
2849108401Sambrisko
2850108401Sambrisko			/* DJA optimize this to limit bcopy */
2851108401Sambrisko			bcopy((char *)&eh->ether_dhost,
2852175445Sambrisko			      (char *)&tx_frame_802_3.an_tx_dst_addr,
2853108401Sambrisko			      ETHER_ADDR_LEN);
2854108401Sambrisko			bcopy((char *)&eh->ether_shost,
2855175445Sambrisko			      (char *)&tx_frame_802_3.an_tx_src_addr,
2856108401Sambrisko			      ETHER_ADDR_LEN);
2857108401Sambrisko
2858108401Sambrisko			/* minus src/dest mac & type */
2859108401Sambrisko			tx_frame_802_3.an_tx_802_3_payload_len =
2860175445Sambrisko				m0->m_pkthdr.len - 12;
2861108401Sambrisko
2862108401Sambrisko			m_copydata(m0, sizeof(struct ether_header) - 2 ,
2863108401Sambrisko				   tx_frame_802_3.an_tx_802_3_payload_len,
2864108401Sambrisko				   (caddr_t)&sc->an_txbuf);
2865108401Sambrisko
2866199757Sjhb			txcontrol = AN_TXCTL_8023 | AN_TXCTL_HW(sc->mpi350);
2867108401Sambrisko			/* write the txcontrol only */
2868108401Sambrisko			bcopy((caddr_t)&txcontrol, &buf[0x08],
286955992Swpaul			      sizeof(txcontrol));
287083270Sbrooks
2871108401Sambrisko			/* 802_3 header */
2872108401Sambrisko			bcopy((caddr_t)&tx_frame_802_3, &buf[0x34],
287355992Swpaul			      sizeof(struct an_txframe_802_3));
287483270Sbrooks
2875108401Sambrisko			/* in mbuf header type is just before payload */
2876108401Sambrisko			bcopy((caddr_t)&sc->an_txbuf, &buf[0x44],
2877108401Sambrisko			      tx_frame_802_3.an_tx_802_3_payload_len);
287883270Sbrooks
287955992Swpaul
2880108401Sambrisko			bzero(&an_tx_desc, sizeof(an_tx_desc));
2881108401Sambrisko			an_tx_desc.an_offset = 0;
2882108401Sambrisko			an_tx_desc.an_eoc = 1;
2883108401Sambrisko			an_tx_desc.an_valid = 1;
2884108401Sambrisko			an_tx_desc.an_len =  0x44 +
2885119156Sambrisko			    tx_frame_802_3.an_tx_802_3_payload_len;
2886175445Sambrisko			an_tx_desc.an_phys
2887119156Sambrisko			    = sc->an_tx_buffer[idx].an_dma_paddr;
2888199757Sjhb			for (i = sizeof(an_tx_desc) / 4 - 1; i >= 0; i--) {
2889119156Sambrisko				CSR_MEM_AUX_WRITE_4(sc, AN_TX_DESC_OFFSET
2890175445Sambrisko				    /* zero for now */
2891119156Sambrisko				    + (0 * sizeof(an_tx_desc))
2892119156Sambrisko				    + (i * 4),
2893155321Simp				    ((u_int32_t *)(void *)&an_tx_desc)[i]);
2894108401Sambrisko			}
289555992Swpaul
2896108401Sambrisko			/*
2897108401Sambrisko			 * If there's a BPF listner, bounce a copy of
2898108401Sambrisko			 * this frame to him.
2899108401Sambrisko			 */
2900108401Sambrisko			BPF_MTAP(ifp, m0);
290155992Swpaul
2902108401Sambrisko			m_freem(m0);
2903108401Sambrisko			m0 = NULL;
2904119156Sambrisko			AN_INC(idx, AN_MAX_TX_DESC);
2905119156Sambrisko			sc->an_rdata.an_tx_empty = 0;
2906108401Sambrisko			CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_ALLOC);
2907108401Sambrisko
2908119156Sambrisko			/*
2909119156Sambrisko			 * Set a timeout in case the chip goes out to lunch.
2910119156Sambrisko			 */
2911199154Sjhb			sc->an_timer = 5;
2912108401Sambrisko		}
2913130620Sambrisko
2914130620Sambrisko		/* Re-enable interrupts. */
2915130620Sambrisko		CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), AN_INTRS(sc->mpi350));
291655992Swpaul	}
291755992Swpaul
291855992Swpaul	if (m0 != NULL)
2919148887Srwatson		ifp->if_drv_flags |= IFF_DRV_OACTIVE;
292055992Swpaul
292155992Swpaul	sc->an_rdata.an_tx_prod = idx;
292255992Swpaul
292355992Swpaul	return;
292455992Swpaul}
292555992Swpaul
292683270Sbrooksvoid
2927150446Simpan_stop(struct an_softc *sc)
292855992Swpaul{
292955992Swpaul	struct ifnet		*ifp;
293055992Swpaul	int			i;
293155992Swpaul
2932199154Sjhb	AN_LOCK_ASSERT(sc);
293367094Swpaul
2934199154Sjhb	if (sc->an_gone)
293555992Swpaul		return;
293655992Swpaul
2937147256Sbrooks	ifp = sc->an_ifp;
293855992Swpaul
293955992Swpaul	an_cmd(sc, AN_CMD_FORCE_SYNCLOSS, 0);
2940108401Sambrisko	CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), 0);
294155992Swpaul	an_cmd(sc, AN_CMD_DISABLE, 0);
294255992Swpaul
294355992Swpaul	for (i = 0; i < AN_TX_RING_CNT; i++)
294455992Swpaul		an_cmd(sc, AN_CMD_DEALLOC_MEM, sc->an_rdata.an_tx_fids[i]);
294555992Swpaul
2946173668Savatar	callout_stop(&sc->an_stat_ch);
294755992Swpaul
2948148887Srwatson	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING|IFF_DRV_OACTIVE);
294955992Swpaul
2950108401Sambrisko	if (sc->an_flash_buffer) {
2951108401Sambrisko		free(sc->an_flash_buffer, M_DEVBUF);
2952108401Sambrisko		sc->an_flash_buffer = NULL;
2953108401Sambrisko	}
295455992Swpaul}
295555992Swpaul
295683270Sbrooksstatic void
2957199154Sjhban_watchdog(struct an_softc *sc)
295855992Swpaul{
2959199154Sjhb	struct ifnet *ifp;
296055992Swpaul
2961199154Sjhb	AN_LOCK_ASSERT(sc);
296255992Swpaul
2963199154Sjhb	if (sc->an_gone)
296455992Swpaul		return;
296555992Swpaul
2966199154Sjhb	ifp = sc->an_ifp;
2967198987Sjhb	if_printf(ifp, "device timeout\n");
296855992Swpaul
296955992Swpaul	an_reset(sc);
2970108401Sambrisko	if (sc->mpi350)
2971175445Sambrisko		an_init_mpi350_desc(sc);
2972199154Sjhb	an_init_locked(sc);
297355992Swpaul
297455992Swpaul	ifp->if_oerrors++;
297555992Swpaul}
297655992Swpaul
2977188128Simpint
2978150446Simpan_shutdown(device_t dev)
297955992Swpaul{
298055992Swpaul	struct an_softc		*sc;
298155992Swpaul
298255992Swpaul	sc = device_get_softc(dev);
2983199154Sjhb	AN_LOCK(sc);
298455992Swpaul	an_stop(sc);
2985110531Sambrisko	sc->an_gone = 1;
2986199154Sjhb	AN_UNLOCK(sc);
298755992Swpaul
2988199154Sjhb	return (0);
298955992Swpaul}
299055992Swpaul
2991110362Sambriskovoid
2992150446Simpan_resume(device_t dev)
2993110362Sambrisko{
2994110362Sambrisko	struct an_softc		*sc;
2995110362Sambrisko	struct ifnet		*ifp;
2996110531Sambrisko	int			i;
2997110531Sambrisko
2998110362Sambrisko	sc = device_get_softc(dev);
2999110531Sambrisko	AN_LOCK(sc);
3000147256Sbrooks	ifp = sc->an_ifp;
3001110362Sambrisko
3002110531Sambrisko	sc->an_gone = 0;
3003110362Sambrisko	an_reset(sc);
3004110362Sambrisko	if (sc->mpi350)
3005175445Sambrisko		an_init_mpi350_desc(sc);
3006199154Sjhb	an_init_locked(sc);
3007110362Sambrisko
3008110531Sambrisko	/* Recovery temporary keys */
3009110531Sambrisko	for (i = 0; i < 4; i++) {
3010110531Sambrisko		sc->areq.an_type = AN_RID_WEP_TEMP;
3011175445Sambrisko		sc->areq.an_len = sizeof(struct an_ltv_key);
3012110531Sambrisko		bcopy(&sc->an_temp_keys[i],
3013110531Sambrisko		    &sc->areq, sizeof(struct an_ltv_key));
3014110531Sambrisko		an_setdef(sc, &sc->areq);
3015110531Sambrisko	}
3016110531Sambrisko
3017110362Sambrisko	if (ifp->if_flags & IFF_UP)
3018199154Sjhb		an_start_locked(ifp);
3019110531Sambrisko	AN_UNLOCK(sc);
3020110362Sambrisko
3021110362Sambrisko	return;
3022110362Sambrisko}
3023110362Sambrisko
302455992Swpaul#ifdef ANCACHE
302555992Swpaul/* Aironet signal strength cache code.
302655992Swpaul * store signal/noise/quality on per MAC src basis in
302755992Swpaul * a small fixed cache.  The cache wraps if > MAX slots
302855992Swpaul * used.  The cache may be zeroed out to start over.
302955992Swpaul * Two simple filters exist to reduce computation:
303088748Sambrisko * 1. ip only (literally 0x800, ETHERTYPE_IP) which may be used
303155992Swpaul * to ignore some packets.  It defaults to ip only.
303255992Swpaul * it could be used to focus on broadcast, non-IP 802.11 beacons.
303355992Swpaul * 2. multicast/broadcast only.  This may be used to
303455992Swpaul * ignore unicast packets and only cache signal strength
303555992Swpaul * for multicast/broadcast packets (beacons); e.g., Mobile-IP
303655992Swpaul * beacons and not unicast traffic.
303755992Swpaul *
303855992Swpaul * The cache stores (MAC src(index), IP src (major clue), signal,
303955992Swpaul *	quality, noise)
304055992Swpaul *
304155992Swpaul * No apologies for storing IP src here.  It's easy and saves much
304283270Sbrooks * trouble elsewhere.  The cache is assumed to be INET dependent,
304355992Swpaul * although it need not be.
304455992Swpaul *
304555992Swpaul * Note: the Aironet only has a single byte of signal strength value
304655992Swpaul * in the rx frame header, and it's not scaled to anything sensible.
304755992Swpaul * This is kind of lame, but it's all we've got.
304855992Swpaul */
304955992Swpaul
305055992Swpaul#ifdef documentation
305155992Swpaul
3052175446Sambriskoint an_sigitems;				/* number of cached entries */
3053175446Sambriskostruct an_sigcache an_sigcache[MAXANCACHE];	/* array of cache entries */
3054175446Sambriskoint an_nextitem;				/* index/# of entries */
305555992Swpaul
305655992Swpaul
305755992Swpaul#endif
305855992Swpaul
305955992Swpaul/* control variables for cache filtering.  Basic idea is
306055992Swpaul * to reduce cost (e.g., to only Mobile-IP agent beacons
306155992Swpaul * which are broadcast or multicast).  Still you might
306255992Swpaul * want to measure signal strength anth unicast ping packets
306355992Swpaul * on a pt. to pt. ant. setup.
306455992Swpaul */
306583270Sbrooks/* set true if you want to limit cache items to broadcast/mcast
306655992Swpaul * only packets (not unicast).  Useful for mobile-ip beacons which
306755992Swpaul * are broadcast/multicast at network layer.  Default is all packets
306855992Swpaul * so ping/unicast anll work say anth pt. to pt. antennae setup.
306955992Swpaul */
307055992Swpaulstatic int an_cache_mcastonly = 0;
3071110531SambriskoSYSCTL_INT(_hw_an, OID_AUTO, an_cache_mcastonly, CTLFLAG_RW,
307255992Swpaul	&an_cache_mcastonly, 0, "");
307355992Swpaul
307455992Swpaul/* set true if you want to limit cache items to IP packets only
307555992Swpaul*/
307655992Swpaulstatic int an_cache_iponly = 1;
3077110531SambriskoSYSCTL_INT(_hw_an, OID_AUTO, an_cache_iponly, CTLFLAG_RW,
307855992Swpaul	&an_cache_iponly, 0, "");
307955992Swpaul
308055992Swpaul/*
308155992Swpaul * an_cache_store, per rx packet store signal
308255992Swpaul * strength in MAC (src) indexed cache.
308355992Swpaul */
308483270Sbrooksstatic void
3085150446Simpan_cache_store(struct an_softc *sc, struct ether_header *eh, struct mbuf *m,
3086150446Simp    u_int8_t rx_rssi, u_int8_t rx_quality)
308755992Swpaul{
308883270Sbrooks	struct ip *ip = 0;
308955992Swpaul	int i;
309055992Swpaul	static int cache_slot = 0; 	/* use this cache entry */
3091175446Sambrisko	static int wrapindex = 0;	/* next "free" cache entry */
309288748Sambrisko	int type_ipv4 = 0;
309355992Swpaul
309455992Swpaul	/* filters:
309555992Swpaul	 * 1. ip only
309655992Swpaul	 * 2. configurable filter to throw out unicast packets,
309755992Swpaul	 * keep multicast only.
309855992Swpaul	 */
309983270Sbrooks
310088748Sambrisko	if ((ntohs(eh->ether_type) == ETHERTYPE_IP)) {
310188748Sambrisko		type_ipv4 = 1;
310255992Swpaul	}
310355992Swpaul
310483270Sbrooks	/* filter for ip packets only
310555992Swpaul	*/
310688748Sambrisko	if ( an_cache_iponly && !type_ipv4) {
310755992Swpaul		return;
310855992Swpaul	}
310955992Swpaul
311055992Swpaul	/* filter for broadcast/multicast only
311155992Swpaul	 */
311255992Swpaul	if (an_cache_mcastonly && ((eh->ether_dhost[0] & 1) == 0)) {
311355992Swpaul		return;
311455992Swpaul	}
311555992Swpaul
311655992Swpaul#ifdef SIGDEBUG
3117198987Sjhb	if_printf(sc->an_ifp, "q value %x (MSB=0x%x, LSB=0x%x) \n",
3118108401Sambrisko		rx_rssi & 0xffff, rx_rssi >> 8, rx_rssi & 0xff);
311955992Swpaul#endif
312055992Swpaul
312155992Swpaul	/* find the ip header.  we want to store the ip_src
312283270Sbrooks	 * address.
312355992Swpaul	 */
312488748Sambrisko	if (type_ipv4) {
312555992Swpaul		ip = mtod(m, struct ip *);
312655992Swpaul	}
312783270Sbrooks
312883270Sbrooks	/* do a linear search for a matching MAC address
312955992Swpaul	 * in the cache table
313055992Swpaul	 * . MAC address is 6 bytes,
313155992Swpaul	 * . var w_nextitem holds total number of entries already cached
313255992Swpaul	 */
313378639Sbrooks	for (i = 0; i < sc->an_nextitem; i++) {
313455992Swpaul		if (! bcmp(eh->ether_shost , sc->an_sigcache[i].macsrc,  6 )) {
313555992Swpaul			/* Match!,
313655992Swpaul			 * so we already have this entry,
313755992Swpaul			 * update the data
313855992Swpaul			 */
313983270Sbrooks			break;
314055992Swpaul		}
314155992Swpaul	}
314255992Swpaul
314355992Swpaul	/* did we find a matching mac address?
314455992Swpaul	 * if yes, then overwrite a previously existing cache entry
314555992Swpaul	 */
314655992Swpaul	if (i < sc->an_nextitem )   {
314783270Sbrooks		cache_slot = i;
314855992Swpaul	}
314955992Swpaul	/* else, have a new address entry,so
315055992Swpaul	 * add this new entry,
315155992Swpaul	 * if table full, then we need to replace LRU entry
315255992Swpaul	 */
315383270Sbrooks	else    {
315455992Swpaul
315583270Sbrooks		/* check for space in cache table
315655992Swpaul		 * note: an_nextitem also holds number of entries
315783270Sbrooks		 * added in the cache table
315855992Swpaul		 */
315955992Swpaul		if ( sc->an_nextitem < MAXANCACHE ) {
316055992Swpaul			cache_slot = sc->an_nextitem;
316183270Sbrooks			sc->an_nextitem++;
316255992Swpaul			sc->an_sigitems = sc->an_nextitem;
316355992Swpaul		}
3164175446Sambrisko		/* no space found, so simply wrap anth wrap index
316555992Swpaul		 * and "zap" the next entry
316655992Swpaul		 */
316755992Swpaul		else {
316855992Swpaul			if (wrapindex == MAXANCACHE) {
316955992Swpaul				wrapindex = 0;
317055992Swpaul			}
317155992Swpaul			cache_slot = wrapindex++;
317255992Swpaul		}
317355992Swpaul	}
317455992Swpaul
317555992Swpaul	/* invariant: cache_slot now points at some slot
317655992Swpaul	 * in cache.
317755992Swpaul	 */
317855992Swpaul	if (cache_slot < 0 || cache_slot >= MAXANCACHE) {
317955992Swpaul		log(LOG_ERR, "an_cache_store, bad index: %d of "
318055992Swpaul		    "[0..%d], gross cache error\n",
318155992Swpaul		    cache_slot, MAXANCACHE);
318255992Swpaul		return;
318355992Swpaul	}
318455992Swpaul
318555992Swpaul	/*  store items in cache
318655992Swpaul	 *  .ip source address
318755992Swpaul	 *  .mac src
318855992Swpaul	 *  .signal, etc.
318955992Swpaul	 */
319088748Sambrisko	if (type_ipv4) {
319155992Swpaul		sc->an_sigcache[cache_slot].ipsrc = ip->ip_src.s_addr;
319255992Swpaul	}
319355992Swpaul	bcopy( eh->ether_shost, sc->an_sigcache[cache_slot].macsrc,  6);
319455992Swpaul
319555992Swpaul
3196108401Sambrisko	switch (an_cache_mode) {
3197108401Sambrisko	case DBM:
3198108401Sambrisko		if (sc->an_have_rssimap) {
3199175445Sambrisko			sc->an_sigcache[cache_slot].signal =
3200108401Sambrisko				- sc->an_rssimap.an_entries[rx_rssi].an_rss_dbm;
3201175445Sambrisko			sc->an_sigcache[cache_slot].quality =
3202108401Sambrisko				- sc->an_rssimap.an_entries[rx_quality].an_rss_dbm;
3203108401Sambrisko		} else {
3204108401Sambrisko			sc->an_sigcache[cache_slot].signal = rx_rssi - 100;
3205108401Sambrisko			sc->an_sigcache[cache_slot].quality = rx_quality - 100;
3206108401Sambrisko		}
3207108401Sambrisko		break;
3208108401Sambrisko	case PERCENT:
3209108401Sambrisko		if (sc->an_have_rssimap) {
3210175445Sambrisko			sc->an_sigcache[cache_slot].signal =
3211108401Sambrisko				sc->an_rssimap.an_entries[rx_rssi].an_rss_pct;
3212175445Sambrisko			sc->an_sigcache[cache_slot].quality =
3213108401Sambrisko				sc->an_rssimap.an_entries[rx_quality].an_rss_pct;
3214108401Sambrisko		} else {
3215108401Sambrisko			if (rx_rssi > 100)
3216108401Sambrisko				rx_rssi = 100;
3217108401Sambrisko			if (rx_quality > 100)
3218108401Sambrisko				rx_quality = 100;
3219108401Sambrisko			sc->an_sigcache[cache_slot].signal = rx_rssi;
3220108401Sambrisko			sc->an_sigcache[cache_slot].quality = rx_quality;
3221108401Sambrisko		}
3222108401Sambrisko		break;
3223108401Sambrisko	case RAW:
3224108401Sambrisko		sc->an_sigcache[cache_slot].signal = rx_rssi;
3225108401Sambrisko		sc->an_sigcache[cache_slot].quality = rx_quality;
3226108401Sambrisko		break;
3227108401Sambrisko	}
3228108401Sambrisko
3229108401Sambrisko	sc->an_sigcache[cache_slot].noise = 0;
3230108401Sambrisko
323155992Swpaul	return;
323255992Swpaul}
323355992Swpaul#endif
323477217Sphk
323583270Sbrooksstatic int
3236150446Simpan_media_change(struct ifnet *ifp)
323777217Sphk{
323877217Sphk	struct an_softc *sc = ifp->if_softc;
3239110253Sambrisko	struct an_ltv_genconfig	*cfg;
324077217Sphk	int otype = sc->an_config.an_opmode;
324177217Sphk	int orate = sc->an_tx_rate;
324277217Sphk
3243199154Sjhb	AN_LOCK(sc);
3244116951Ssam	sc->an_tx_rate = ieee80211_media2rate(
3245116951Ssam		IFM_SUBTYPE(sc->an_ifmedia.ifm_cur->ifm_media));
3246119156Sambrisko	if (sc->an_tx_rate < 0)
3247119156Sambrisko		sc->an_tx_rate = 0;
3248110253Sambrisko
3249110253Sambrisko	if (orate != sc->an_tx_rate) {
3250110253Sambrisko		/* Read the current configuration */
3251110253Sambrisko		sc->an_config.an_type = AN_RID_GENCONFIG;
3252110253Sambrisko		sc->an_config.an_len = sizeof(struct an_ltv_genconfig);
3253110253Sambrisko		an_read_record(sc, (struct an_ltv_gen *)&sc->an_config);
3254110253Sambrisko		cfg = &sc->an_config;
3255110253Sambrisko
3256110253Sambrisko		/* clear other rates and set the only one we want */
3257110253Sambrisko		bzero(cfg->an_rates, sizeof(cfg->an_rates));
3258110253Sambrisko		cfg->an_rates[0] = sc->an_tx_rate;
3259110253Sambrisko
3260110253Sambrisko		/* Save the new rate */
3261110253Sambrisko		sc->an_config.an_type = AN_RID_GENCONFIG;
3262110253Sambrisko		sc->an_config.an_len = sizeof(struct an_ltv_genconfig);
326377217Sphk	}
326477217Sphk
3265119156Sambrisko	if ((sc->an_ifmedia.ifm_cur->ifm_media & IFM_IEEE80211_ADHOC) != 0)
3266119156Sambrisko		sc->an_config.an_opmode &= ~AN_OPMODE_INFRASTRUCTURE_STATION;
3267119156Sambrisko	else
3268119156Sambrisko		sc->an_config.an_opmode |= AN_OPMODE_INFRASTRUCTURE_STATION;
3269119156Sambrisko
3270175445Sambrisko	if (otype != sc->an_config.an_opmode ||
3271110531Sambrisko	    orate != sc->an_tx_rate)
3272199154Sjhb		an_init_locked(sc);
3273199154Sjhb	AN_UNLOCK(sc);
327477217Sphk
327577217Sphk	return(0);
327677217Sphk}
327777217Sphk
327883270Sbrooksstatic void
3279150446Simpan_media_status(struct ifnet *ifp, struct ifmediareq *imr)
328077217Sphk{
328177217Sphk	struct an_ltv_status	status;
328277217Sphk	struct an_softc		*sc = ifp->if_softc;
328377217Sphk
3284110253Sambrisko	imr->ifm_active = IFM_IEEE80211;
3285110253Sambrisko
3286175445Sambrisko	AN_LOCK(sc);
328777217Sphk	status.an_len = sizeof(status);
328877217Sphk	status.an_type = AN_RID_STATUS;
328977217Sphk	if (an_read_record(sc, (struct an_ltv_gen *)&status)) {
329077217Sphk		/* If the status read fails, just lie. */
329177217Sphk		imr->ifm_active = sc->an_ifmedia.ifm_cur->ifm_media;
329277217Sphk		imr->ifm_status = IFM_AVALID|IFM_ACTIVE;
329377217Sphk	}
329477217Sphk
329578639Sbrooks	if (sc->an_tx_rate == 0) {
329677217Sphk		imr->ifm_active = IFM_IEEE80211|IFM_AUTO;
329777217Sphk	}
329877217Sphk
3299110253Sambrisko	if (sc->an_config.an_opmode == AN_OPMODE_IBSS_ADHOC)
3300110253Sambrisko		imr->ifm_active |= IFM_IEEE80211_ADHOC;
3301116951Ssam	imr->ifm_active |= ieee80211_rate2media(NULL,
3302228621Sbschmidt		status.an_current_tx_rate, IEEE80211_MODE_AUTO);
330377217Sphk	imr->ifm_status = IFM_AVALID;
330491283Sambrisko	if (status.an_opmode & AN_STATUS_OPMODE_ASSOCIATED)
330577217Sphk		imr->ifm_status |= IFM_ACTIVE;
3306199154Sjhb	AN_UNLOCK(sc);
330777217Sphk}
330888748Sambrisko
330988748Sambrisko/********************** Cisco utility support routines *************/
331088748Sambrisko
331188748Sambrisko/*
331288748Sambrisko * ReadRids & WriteRids derived from Cisco driver additions to Ben Reed's
331388748Sambrisko * Linux driver
331488748Sambrisko */
331588748Sambrisko
331688748Sambriskostatic int
3317150446Simpreadrids(struct ifnet *ifp, struct aironet_ioctl *l_ioctl)
331888748Sambrisko{
331988749Sambrisko	unsigned short  rid;
332088748Sambrisko	struct an_softc *sc;
3321171692Savatar	int error;
332288748Sambrisko
332388748Sambrisko	switch (l_ioctl->command) {
332488748Sambrisko	case AIROGCAP:
332588748Sambrisko		rid = AN_RID_CAPABILITIES;
332688748Sambrisko		break;
332788748Sambrisko	case AIROGCFG:
332888748Sambrisko		rid = AN_RID_GENCONFIG;
332988748Sambrisko		break;
333088748Sambrisko	case AIROGSLIST:
333188748Sambrisko		rid = AN_RID_SSIDLIST;
333288748Sambrisko		break;
333388748Sambrisko	case AIROGVLIST:
333488748Sambrisko		rid = AN_RID_APLIST;
333588748Sambrisko		break;
333688748Sambrisko	case AIROGDRVNAM:
333788748Sambrisko		rid = AN_RID_DRVNAME;
333888748Sambrisko		break;
333988748Sambrisko	case AIROGEHTENC:
334088748Sambrisko		rid = AN_RID_ENCAPPROTO;
334188748Sambrisko		break;
334288748Sambrisko	case AIROGWEPKTMP:
334388748Sambrisko		rid = AN_RID_WEP_TEMP;
334488748Sambrisko		break;
334588748Sambrisko	case AIROGWEPKNV:
334688748Sambrisko		rid = AN_RID_WEP_PERM;
334788748Sambrisko		break;
334888748Sambrisko	case AIROGSTAT:
334988748Sambrisko		rid = AN_RID_STATUS;
335088748Sambrisko		break;
335188748Sambrisko	case AIROGSTATSD32:
335288748Sambrisko		rid = AN_RID_32BITS_DELTA;
335388748Sambrisko		break;
335488748Sambrisko	case AIROGSTATSC32:
335588748Sambrisko		rid = AN_RID_32BITS_CUM;
335688748Sambrisko		break;
335788748Sambrisko	default:
335888748Sambrisko		rid = 999;
335988748Sambrisko		break;
336088748Sambrisko	}
336188748Sambrisko
336288748Sambrisko	if (rid == 999)	/* Is bad command */
336388748Sambrisko		return -EINVAL;
336488748Sambrisko
336588748Sambrisko	sc = ifp->if_softc;
336688749Sambrisko	sc->areq.an_len  = AN_MAX_DATALEN;
336788749Sambrisko	sc->areq.an_type = rid;
336888748Sambrisko
336988749Sambrisko	an_read_record(sc, (struct an_ltv_gen *)&sc->areq);
337088748Sambrisko
337188749Sambrisko	l_ioctl->len = sc->areq.an_len - 4;	/* just data */
337288748Sambrisko
3373171692Savatar	AN_UNLOCK(sc);
337488748Sambrisko	/* the data contains the length at first */
337588749Sambrisko	if (copyout(&(sc->areq.an_len), l_ioctl->data,
337688749Sambrisko		    sizeof(sc->areq.an_len))) {
3377171692Savatar		error = -EFAULT;
3378171692Savatar		goto lock_exit;
337988748Sambrisko	}
338088748Sambrisko	/* Just copy the data back */
338188749Sambrisko	if (copyout(&(sc->areq.an_val), l_ioctl->data + 2,
338288748Sambrisko		    l_ioctl->len)) {
3383171692Savatar		error = -EFAULT;
3384171692Savatar		goto lock_exit;
338588748Sambrisko	}
3386171692Savatar	error = 0;
3387171692Savatarlock_exit:
3388171692Savatar	AN_LOCK(sc);
3389171692Savatar	return (error);
339088748Sambrisko}
339188748Sambrisko
339288748Sambriskostatic int
3393150446Simpwriterids(struct ifnet *ifp, struct aironet_ioctl *l_ioctl)
339488748Sambrisko{
339588748Sambrisko	struct an_softc *sc;
3396175446Sambrisko	int		rid, command, error;
339788748Sambrisko
339888748Sambrisko	sc = ifp->if_softc;
3399175445Sambrisko	AN_LOCK_ASSERT(sc);
340088748Sambrisko	rid = 0;
340188748Sambrisko	command = l_ioctl->command;
340288748Sambrisko
340388748Sambrisko	switch (command) {
340488748Sambrisko	case AIROPSIDS:
340588748Sambrisko		rid = AN_RID_SSIDLIST;
340688748Sambrisko		break;
340788748Sambrisko	case AIROPCAP:
340888748Sambrisko		rid = AN_RID_CAPABILITIES;
340988748Sambrisko		break;
341088748Sambrisko	case AIROPAPLIST:
341188748Sambrisko		rid = AN_RID_APLIST;
341288748Sambrisko		break;
341388748Sambrisko	case AIROPCFG:
341488748Sambrisko		rid = AN_RID_GENCONFIG;
341588748Sambrisko		break;
341688748Sambrisko	case AIROPMACON:
341788748Sambrisko		an_cmd(sc, AN_CMD_ENABLE, 0);
341888748Sambrisko		return 0;
341988748Sambrisko		break;
342088748Sambrisko	case AIROPMACOFF:
342188748Sambrisko		an_cmd(sc, AN_CMD_DISABLE, 0);
342288748Sambrisko		return 0;
342388748Sambrisko		break;
342488748Sambrisko	case AIROPSTCLR:
342588748Sambrisko		/*
342688748Sambrisko		 * This command merely clears the counts does not actually
342788748Sambrisko		 * store any data only reads rid. But as it changes the cards
342888748Sambrisko		 * state, I put it in the writerid routines.
342988748Sambrisko		 */
343088748Sambrisko
343188748Sambrisko		rid = AN_RID_32BITS_DELTACLR;
343288748Sambrisko		sc = ifp->if_softc;
343388749Sambrisko		sc->areq.an_len = AN_MAX_DATALEN;
343488749Sambrisko		sc->areq.an_type = rid;
343588748Sambrisko
343688749Sambrisko		an_read_record(sc, (struct an_ltv_gen *)&sc->areq);
343788749Sambrisko		l_ioctl->len = sc->areq.an_len - 4;	/* just data */
343888748Sambrisko
3439171692Savatar		AN_UNLOCK(sc);
344088748Sambrisko		/* the data contains the length at first */
3441171692Savatar		error = copyout(&(sc->areq.an_len), l_ioctl->data,
3442171692Savatar			    sizeof(sc->areq.an_len));
3443171692Savatar		if (error) {
3444171692Savatar			AN_LOCK(sc);
344588748Sambrisko			return -EFAULT;
344688748Sambrisko		}
344788748Sambrisko		/* Just copy the data */
3448171692Savatar		error = copyout(&(sc->areq.an_val), l_ioctl->data + 2,
3449171692Savatar			    l_ioctl->len);
3450171692Savatar		AN_LOCK(sc);
3451171692Savatar		if (error)
345288748Sambrisko			return -EFAULT;
345388748Sambrisko		return 0;
345488748Sambrisko		break;
345588748Sambrisko	case AIROPWEPKEY:
345688748Sambrisko		rid = AN_RID_WEP_TEMP;
345788748Sambrisko		break;
345888748Sambrisko	case AIROPWEPKEYNV:
345988748Sambrisko		rid = AN_RID_WEP_PERM;
346088748Sambrisko		break;
346188748Sambrisko	case AIROPLEAPUSR:
346288748Sambrisko		rid = AN_RID_LEAPUSERNAME;
346388748Sambrisko		break;
346488748Sambrisko	case AIROPLEAPPWD:
346588748Sambrisko		rid = AN_RID_LEAPPASSWORD;
346688748Sambrisko		break;
346788748Sambrisko	default:
346888748Sambrisko		return -EOPNOTSUPP;
346988748Sambrisko	}
347088748Sambrisko
347188748Sambrisko	if (rid) {
347288749Sambrisko		if (l_ioctl->len > sizeof(sc->areq.an_val) + 4)
347388748Sambrisko			return -EINVAL;
347488749Sambrisko		sc->areq.an_len = l_ioctl->len + 4;	/* add type & length */
347588749Sambrisko		sc->areq.an_type = rid;
347688748Sambrisko
347788748Sambrisko		/* Just copy the data back */
3478171692Savatar		AN_UNLOCK(sc);
3479171692Savatar		error = copyin((l_ioctl->data) + 2, &sc->areq.an_val,
3480171692Savatar		       l_ioctl->len);
3481171692Savatar		AN_LOCK(sc);
3482171692Savatar		if (error)
3483144242Ssam			return -EFAULT;
3484171692Savatar
348588748Sambrisko		an_cmd(sc, AN_CMD_DISABLE, 0);
348688749Sambrisko		an_write_record(sc, (struct an_ltv_gen *)&sc->areq);
348788748Sambrisko		an_cmd(sc, AN_CMD_ENABLE, 0);
348888748Sambrisko		return 0;
348988748Sambrisko	}
349088748Sambrisko	return -EOPNOTSUPP;
349188748Sambrisko}
349288748Sambrisko
349388748Sambrisko/*
349488748Sambrisko * General Flash utilities derived from Cisco driver additions to Ben Reed's
349588748Sambrisko * Linux driver
349688748Sambrisko */
349788748Sambrisko
3498123978Sambrisko#define FLASH_DELAY(_sc, x)	msleep(ifp, &(_sc)->an_mtx, PZERO, \
3499123978Sambrisko	"flash", ((x) / hz) + 1);
3500108401Sambrisko#define FLASH_COMMAND	0x7e7e
3501108401Sambrisko#define FLASH_SIZE	32 * 1024
350288748Sambrisko
350388748Sambriskostatic int
3504150446Simpunstickbusy(struct ifnet *ifp)
350588748Sambrisko{
350688748Sambrisko	struct an_softc *sc = ifp->if_softc;
350788748Sambrisko
3508108401Sambrisko	if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350)) & AN_CMD_BUSY) {
3509175445Sambrisko		CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350),
3510108401Sambrisko			    AN_EV_CLR_STUCK_BUSY);
351188748Sambrisko		return 1;
351288748Sambrisko	}
351388748Sambrisko	return 0;
351488748Sambrisko}
351588748Sambrisko
351688748Sambrisko/*
351788748Sambrisko * Wait for busy completion from card wait for delay uSec's Return true for
351888748Sambrisko * success meaning command reg is clear
351988748Sambrisko */
352088748Sambrisko
352188748Sambriskostatic int
3522150446SimpWaitBusy(struct ifnet *ifp, int uSec)
352388748Sambrisko{
3524175446Sambrisko	int		statword = 0xffff;
3525175446Sambrisko	int		delay = 0;
3526175446Sambrisko	struct an_softc	*sc = ifp->if_softc;
352788748Sambrisko
352888748Sambrisko	while ((statword & AN_CMD_BUSY) && delay <= (1000 * 100)) {
3529119163Sambrisko		FLASH_DELAY(sc, 10);
353088748Sambrisko		delay += 10;
3531108401Sambrisko		statword = CSR_READ_2(sc, AN_COMMAND(sc->mpi350));
353288748Sambrisko
353388748Sambrisko		if ((AN_CMD_BUSY & statword) && (delay % 200)) {
353488748Sambrisko			unstickbusy(ifp);
353588748Sambrisko		}
353688748Sambrisko	}
353788748Sambrisko
353888748Sambrisko	return 0 == (AN_CMD_BUSY & statword);
353988748Sambrisko}
354088748Sambrisko
354188748Sambrisko/*
354288748Sambrisko * STEP 1) Disable MAC and do soft reset on card.
354388748Sambrisko */
354488748Sambrisko
354588748Sambriskostatic int
3546150446Simpcmdreset(struct ifnet *ifp)
354788748Sambrisko{
3548175446Sambrisko	int		status;
3549175446Sambrisko	struct an_softc	*sc = ifp->if_softc;
355088748Sambrisko
3551199154Sjhb	AN_LOCK(sc);
355288748Sambrisko	an_stop(sc);
355388748Sambrisko
355488748Sambrisko	an_cmd(sc, AN_CMD_DISABLE, 0);
355588748Sambrisko
3556108401Sambrisko	if (!(status = WaitBusy(ifp, AN_TIMEOUT))) {
3557198987Sjhb		if_printf(ifp, "Waitbusy hang b4 RESET =%d\n", status);
3558175445Sambrisko		AN_UNLOCK(sc);
355988748Sambrisko		return -EBUSY;
356088748Sambrisko	}
3561108401Sambrisko	CSR_WRITE_2(sc, AN_COMMAND(sc->mpi350), AN_CMD_FW_RESTART);
356288748Sambrisko
3563119163Sambrisko	FLASH_DELAY(sc, 1000);	/* WAS 600 12/7/00 */
356488748Sambrisko
356588748Sambrisko
356688748Sambrisko	if (!(status = WaitBusy(ifp, 100))) {
3567198987Sjhb		if_printf(ifp, "Waitbusy hang AFTER RESET =%d\n", status);
3568175445Sambrisko		AN_UNLOCK(sc);
356988748Sambrisko		return -EBUSY;
357088748Sambrisko	}
3571175445Sambrisko	AN_UNLOCK(sc);
357288748Sambrisko	return 0;
357388748Sambrisko}
357488748Sambrisko
357588748Sambrisko/*
357688748Sambrisko * STEP 2) Put the card in legendary flash mode
357788748Sambrisko */
357888748Sambrisko
357988748Sambriskostatic int
3580150446Simpsetflashmode(struct ifnet *ifp)
358188748Sambrisko{
3582175446Sambrisko	int		status;
3583175446Sambrisko	struct an_softc	*sc = ifp->if_softc;
358488748Sambrisko
3585108401Sambrisko	CSR_WRITE_2(sc, AN_SW0(sc->mpi350), FLASH_COMMAND);
3586108401Sambrisko	CSR_WRITE_2(sc, AN_SW1(sc->mpi350), FLASH_COMMAND);
3587108401Sambrisko	CSR_WRITE_2(sc, AN_SW0(sc->mpi350), FLASH_COMMAND);
3588108401Sambrisko	CSR_WRITE_2(sc, AN_COMMAND(sc->mpi350), FLASH_COMMAND);
358988748Sambrisko
359088748Sambrisko	/*
359188748Sambrisko	 * mdelay(500); // 500ms delay
359288748Sambrisko	 */
359388748Sambrisko
3594119163Sambrisko	FLASH_DELAY(sc, 500);
359588748Sambrisko
3596108401Sambrisko	if (!(status = WaitBusy(ifp, AN_TIMEOUT))) {
359788748Sambrisko		printf("Waitbusy hang after setflash mode\n");
359888748Sambrisko		return -EIO;
359988748Sambrisko	}
360088748Sambrisko	return 0;
360188748Sambrisko}
360288748Sambrisko
360388748Sambrisko/*
360488748Sambrisko * Get a character from the card matching matchbyte Step 3)
360588748Sambrisko */
360688748Sambrisko
360788748Sambriskostatic int
3608150446Simpflashgchar(struct ifnet *ifp, int matchbyte, int dwelltime)
360988748Sambrisko{
3610175446Sambrisko	int		rchar;
3611175446Sambrisko	unsigned char	rbyte = 0;
3612175446Sambrisko	int		success = -1;
3613175446Sambrisko	struct an_softc	*sc = ifp->if_softc;
361488748Sambrisko
361588748Sambrisko
361688748Sambrisko	do {
3617108401Sambrisko		rchar = CSR_READ_2(sc, AN_SW1(sc->mpi350));
361888748Sambrisko
361988748Sambrisko		if (dwelltime && !(0x8000 & rchar)) {
362088748Sambrisko			dwelltime -= 10;
3621119163Sambrisko			FLASH_DELAY(sc, 10);
362288748Sambrisko			continue;
362388748Sambrisko		}
362488748Sambrisko		rbyte = 0xff & rchar;
362588748Sambrisko
362688748Sambrisko		if ((rbyte == matchbyte) && (0x8000 & rchar)) {
3627108401Sambrisko			CSR_WRITE_2(sc, AN_SW1(sc->mpi350), 0);
362888748Sambrisko			success = 1;
362988748Sambrisko			break;
363088748Sambrisko		}
363188748Sambrisko		if (rbyte == 0x81 || rbyte == 0x82 || rbyte == 0x83 || rbyte == 0x1a || 0xffff == rchar)
363288748Sambrisko			break;
3633108401Sambrisko		CSR_WRITE_2(sc, AN_SW1(sc->mpi350), 0);
363488748Sambrisko
363588748Sambrisko	} while (dwelltime > 0);
363688748Sambrisko	return success;
363788748Sambrisko}
363888748Sambrisko
363988748Sambrisko/*
364088748Sambrisko * Put character to SWS0 wait for dwelltime x 50us for  echo .
364188748Sambrisko */
364288748Sambrisko
364388748Sambriskostatic int
3644150446Simpflashpchar(struct ifnet *ifp, int byte, int dwelltime)
364588748Sambrisko{
3646175446Sambrisko	int		echo;
3647175446Sambrisko	int		pollbusy, waittime;
3648175446Sambrisko	struct an_softc	*sc = ifp->if_softc;
364988748Sambrisko
365088748Sambrisko	byte |= 0x8000;
365188748Sambrisko
365288748Sambrisko	if (dwelltime == 0)
365388748Sambrisko		dwelltime = 200;
365488748Sambrisko
365588748Sambrisko	waittime = dwelltime;
365688748Sambrisko
365788748Sambrisko	/*
365888748Sambrisko	 * Wait for busy bit d15 to go false indicating buffer empty
365988748Sambrisko	 */
366088748Sambrisko	do {
3661108401Sambrisko		pollbusy = CSR_READ_2(sc, AN_SW0(sc->mpi350));
366288748Sambrisko
366388748Sambrisko		if (pollbusy & 0x8000) {
3664119163Sambrisko			FLASH_DELAY(sc, 50);
366588748Sambrisko			waittime -= 50;
366688748Sambrisko			continue;
366788748Sambrisko		} else
366888748Sambrisko			break;
366988748Sambrisko	}
367088748Sambrisko	while (waittime >= 0);
367188748Sambrisko
367288748Sambrisko	/* timeout for busy clear wait */
367388748Sambrisko
367488748Sambrisko	if (waittime <= 0) {
3675198987Sjhb		if_printf(ifp, "flash putchar busywait timeout!\n");
367688748Sambrisko		return -1;
367788748Sambrisko	}
367888748Sambrisko	/*
367988748Sambrisko	 * Port is clear now write byte and wait for it to echo back
368088748Sambrisko	 */
368188748Sambrisko	do {
3682108401Sambrisko		CSR_WRITE_2(sc, AN_SW0(sc->mpi350), byte);
3683119163Sambrisko		FLASH_DELAY(sc, 50);
368488748Sambrisko		dwelltime -= 50;
3685108401Sambrisko		echo = CSR_READ_2(sc, AN_SW1(sc->mpi350));
368688748Sambrisko	} while (dwelltime >= 0 && echo != byte);
368788748Sambrisko
368888748Sambrisko
3689108401Sambrisko	CSR_WRITE_2(sc, AN_SW1(sc->mpi350), 0);
369088748Sambrisko
369188748Sambrisko	return echo == byte;
369288748Sambrisko}
369388748Sambrisko
369488748Sambrisko/*
369588748Sambrisko * Transfer 32k of firmware data from user buffer to our buffer and send to
369688748Sambrisko * the card
369788748Sambrisko */
369888748Sambrisko
369988748Sambriskostatic int
3700150446Simpflashputbuf(struct ifnet *ifp)
370188748Sambrisko{
370288748Sambrisko	unsigned short *bufp;
3703175446Sambrisko	int		nwords;
3704175446Sambrisko	struct an_softc	*sc = ifp->if_softc;
370588748Sambrisko
370688748Sambrisko	/* Write stuff */
370788748Sambrisko
3708108401Sambrisko	bufp = sc->an_flash_buffer;
370988748Sambrisko
3710108401Sambrisko	if (!sc->mpi350) {
3711108401Sambrisko		CSR_WRITE_2(sc, AN_AUX_PAGE, 0x100);
3712108401Sambrisko		CSR_WRITE_2(sc, AN_AUX_OFFSET, 0);
371388748Sambrisko
3714108401Sambrisko		for (nwords = 0; nwords != FLASH_SIZE / 2; nwords++) {
3715108401Sambrisko			CSR_WRITE_2(sc, AN_AUX_DATA, bufp[nwords] & 0xffff);
3716108401Sambrisko		}
3717108401Sambrisko	} else {
3718108401Sambrisko		for (nwords = 0; nwords != FLASH_SIZE / 4; nwords++) {
3719175445Sambrisko			CSR_MEM_AUX_WRITE_4(sc, 0x8000,
3720108401Sambrisko				((u_int32_t *)bufp)[nwords] & 0xffff);
3721108401Sambrisko		}
372288748Sambrisko	}
372388748Sambrisko
3724108401Sambrisko	CSR_WRITE_2(sc, AN_SW0(sc->mpi350), 0x8000);
372588748Sambrisko
372688748Sambrisko	return 0;
372788748Sambrisko}
372888748Sambrisko
372988748Sambrisko/*
373088748Sambrisko * After flashing restart the card.
373188748Sambrisko */
373288748Sambrisko
373388748Sambriskostatic int
3734150446Simpflashrestart(struct ifnet *ifp)
373588748Sambrisko{
3736175446Sambrisko	int		status = 0;
3737175446Sambrisko	struct an_softc	*sc = ifp->if_softc;
373888748Sambrisko
3739119163Sambrisko	FLASH_DELAY(sc, 1024);		/* Added 12/7/00 */
374088748Sambrisko
3741199154Sjhb	an_init_locked(sc);
374288748Sambrisko
3743119163Sambrisko	FLASH_DELAY(sc, 1024);		/* Added 12/7/00 */
374488748Sambrisko	return status;
374588748Sambrisko}
374688748Sambrisko
374788748Sambrisko/*
374888748Sambrisko * Entry point for flash ioclt.
374988748Sambrisko */
375088748Sambrisko
375188748Sambriskostatic int
3752150446Simpflashcard(struct ifnet *ifp, struct aironet_ioctl *l_ioctl)
375388748Sambrisko{
3754175446Sambrisko	int		z = 0, status;
375588748Sambrisko	struct an_softc	*sc;
375688748Sambrisko
375788748Sambrisko	sc = ifp->if_softc;
3758108401Sambrisko	if (sc->mpi350) {
3759198987Sjhb		if_printf(ifp, "flashing not supported on MPI 350 yet\n");
3760108401Sambrisko		return(-1);
3761108401Sambrisko	}
376288748Sambrisko	status = l_ioctl->command;
376388748Sambrisko
376488748Sambrisko	switch (l_ioctl->command) {
376588748Sambrisko	case AIROFLSHRST:
376688748Sambrisko		return cmdreset(ifp);
376788748Sambrisko		break;
376888748Sambrisko	case AIROFLSHSTFL:
3769108401Sambrisko		if (sc->an_flash_buffer) {
3770108401Sambrisko			free(sc->an_flash_buffer, M_DEVBUF);
3771108401Sambrisko			sc->an_flash_buffer = NULL;
3772108401Sambrisko		}
3773111119Simp		sc->an_flash_buffer = malloc(FLASH_SIZE, M_DEVBUF, M_WAITOK);
3774108401Sambrisko		if (sc->an_flash_buffer)
3775108401Sambrisko			return setflashmode(ifp);
3776108401Sambrisko		else
3777108401Sambrisko			return ENOBUFS;
377888748Sambrisko		break;
377988748Sambrisko	case AIROFLSHGCHR:	/* Get char from aux */
3780171692Savatar		AN_UNLOCK(sc);
3781144242Ssam		status = copyin(l_ioctl->data, &sc->areq, l_ioctl->len);
3782171692Savatar		AN_LOCK(sc);
3783144242Ssam		if (status)
3784144242Ssam			return status;
378588749Sambrisko		z = *(int *)&sc->areq;
378688748Sambrisko		if ((status = flashgchar(ifp, z, 8000)) == 1)
378788748Sambrisko			return 0;
378888748Sambrisko		else
378988748Sambrisko			return -1;
379088748Sambrisko	case AIROFLSHPCHR:	/* Send char to card. */
3791171692Savatar		AN_UNLOCK(sc);
3792144242Ssam		status = copyin(l_ioctl->data, &sc->areq, l_ioctl->len);
3793171692Savatar		AN_LOCK(sc);
3794144242Ssam		if (status)
3795144242Ssam			return status;
379688749Sambrisko		z = *(int *)&sc->areq;
379788748Sambrisko		if ((status = flashpchar(ifp, z, 8000)) == -1)
379888748Sambrisko			return -EIO;
379988748Sambrisko		else
380088748Sambrisko			return 0;
380188748Sambrisko		break;
380288748Sambrisko	case AIROFLPUTBUF:	/* Send 32k to card */
3803108401Sambrisko		if (l_ioctl->len > FLASH_SIZE) {
3804198987Sjhb			if_printf(ifp, "Buffer to big, %x %x\n",
3805108401Sambrisko			       l_ioctl->len, FLASH_SIZE);
380688748Sambrisko			return -EINVAL;
380788748Sambrisko		}
3808171692Savatar		AN_UNLOCK(sc);
3809144242Ssam		status = copyin(l_ioctl->data, sc->an_flash_buffer, l_ioctl->len);
3810171692Savatar		AN_LOCK(sc);
3811144242Ssam		if (status)
3812144242Ssam			return status;
381388748Sambrisko
381488748Sambrisko		if ((status = flashputbuf(ifp)) != 0)
381588748Sambrisko			return -EIO;
381688748Sambrisko		else
381788748Sambrisko			return 0;
381888748Sambrisko		break;
381988748Sambrisko	case AIRORESTART:
382088748Sambrisko		if ((status = flashrestart(ifp)) != 0) {
3821198987Sjhb			if_printf(ifp, "FLASHRESTART returned %d\n", status);
382288748Sambrisko			return -EIO;
382388748Sambrisko		} else
382488748Sambrisko			return 0;
382588748Sambrisko
382688748Sambrisko		break;
382788748Sambrisko	default:
382888748Sambrisko		return -EINVAL;
382988748Sambrisko	}
383088748Sambrisko
383188748Sambrisko	return -EINVAL;
383288748Sambrisko}
3833