if_an.c revision 199154
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: head/sys/dev/an/if_an.c 199154 2009-11-10 22:04:19Z jhb $");
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>
10583269Sbrooks#include <sys/sysctl.h>
10655992Swpaul#include <sys/bus.h>
10755992Swpaul#include <machine/bus.h>
10855992Swpaul#include <sys/rman.h>
10984811Sjhb#include <sys/lock.h>
11067365Sjhb#include <sys/mutex.h>
11155992Swpaul#include <machine/resource.h>
112108401Sambrisko#include <sys/malloc.h>
11355992Swpaul
11455992Swpaul#include <net/if.h>
11555992Swpaul#include <net/if_arp.h>
116152315Sru#include <net/if_dl.h>
11755992Swpaul#include <net/ethernet.h>
11855992Swpaul#include <net/if_types.h>
11977217Sphk#include <net/if_media.h>
12055992Swpaul
121116951Ssam#include <net80211/ieee80211_var.h>
122116951Ssam#include <net80211/ieee80211_ioctl.h>
123116951Ssam
12455992Swpaul#ifdef INET
12555992Swpaul#include <netinet/in.h>
12655992Swpaul#include <netinet/in_systm.h>
12755992Swpaul#include <netinet/in_var.h>
12855992Swpaul#include <netinet/ip.h>
12955992Swpaul#endif
13055992Swpaul
13155992Swpaul#include <net/bpf.h>
13255992Swpaul
13355992Swpaul#include <machine/md_var.h>
13455992Swpaul
13555992Swpaul#include <dev/an/if_aironet_ieee.h>
13655992Swpaul#include <dev/an/if_anreg.h>
13755992Swpaul
13855992Swpaul/* These are global because we need them in sys/pci/if_an_p.c. */
139150446Simpstatic void an_reset(struct an_softc *);
140150446Simpstatic int an_init_mpi350_desc(struct an_softc *);
141150446Simpstatic int an_ioctl(struct ifnet *, u_long, caddr_t);
142150446Simpstatic void an_init(void *);
143199154Sjhbstatic void an_init_locked(struct an_softc *);
144150446Simpstatic int an_init_tx_ring(struct an_softc *);
145150446Simpstatic void an_start(struct ifnet *);
146199154Sjhbstatic void an_start_locked(struct ifnet *);
147199154Sjhbstatic void an_watchdog(struct an_softc *);
148150446Simpstatic void an_rxeof(struct an_softc *);
149150446Simpstatic void an_txeof(struct an_softc *, int);
15055992Swpaul
151150446Simpstatic void an_promisc(struct an_softc *, int);
152150446Simpstatic int an_cmd(struct an_softc *, int, int);
153150446Simpstatic int an_cmd_struct(struct an_softc *, struct an_command *,
154150446Simp    struct an_reply *);
155150446Simpstatic int an_read_record(struct an_softc *, struct an_ltv_gen *);
156150446Simpstatic int an_write_record(struct an_softc *, struct an_ltv_gen *);
157150446Simpstatic int an_read_data(struct an_softc *, int, int, caddr_t, int);
158150446Simpstatic int an_write_data(struct an_softc *, int, int, caddr_t, int);
159150446Simpstatic int an_seek(struct an_softc *, int, int, int);
160150446Simpstatic int an_alloc_nicmem(struct an_softc *, int, int *);
161150446Simpstatic int an_dma_malloc(struct an_softc *, bus_size_t, struct an_dma_alloc *,
162150446Simp    int);
163150446Simpstatic void an_dma_free(struct an_softc *, struct an_dma_alloc *);
164150446Simpstatic void an_dma_malloc_cb(void *, bus_dma_segment_t *, int, int);
165150446Simpstatic void an_stats_update(void *);
166150446Simpstatic void an_setdef(struct an_softc *, struct an_req *);
16755992Swpaul#ifdef ANCACHE
168150446Simpstatic void an_cache_store(struct an_softc *, struct ether_header *,
169150446Simp    struct mbuf *, u_int8_t, u_int8_t);
17055992Swpaul#endif
17155992Swpaul
17288748Sambrisko/* function definitions for use with the Cisco's Linux configuration
17388748Sambrisko   utilities
17488748Sambrisko*/
17588748Sambrisko
17692739Salfredstatic int readrids(struct ifnet*, struct aironet_ioctl*);
17792739Salfredstatic int writerids(struct ifnet*, struct aironet_ioctl*);
17892739Salfredstatic int flashcard(struct ifnet*, struct aironet_ioctl*);
17988748Sambrisko
18092739Salfredstatic int cmdreset(struct ifnet *);
18192739Salfredstatic int setflashmode(struct ifnet *);
18292739Salfredstatic int flashgchar(struct ifnet *,int,int);
18392739Salfredstatic int flashpchar(struct ifnet *,int,int);
18492739Salfredstatic int flashputbuf(struct ifnet *);
18592739Salfredstatic int flashrestart(struct ifnet *);
18692739Salfredstatic int WaitBusy(struct ifnet *, int);
18792739Salfredstatic int unstickbusy(struct ifnet *);
18888748Sambrisko
18992739Salfredstatic void an_dump_record	(struct an_softc *,struct an_ltv_gen *,
19092739Salfred				    char *);
19178639Sbrooks
19292739Salfredstatic int an_media_change	(struct ifnet *);
19392739Salfredstatic void an_media_status	(struct ifnet *, struct ifmediareq *);
19477217Sphk
19578639Sbrooksstatic int	an_dump = 0;
196108401Sambriskostatic int	an_cache_mode = 0;
19788748Sambrisko
198108401Sambrisko#define DBM 0
199108401Sambrisko#define PERCENT 1
200108401Sambrisko#define RAW 2
201108401Sambrisko
20283269Sbrooksstatic char an_conf[256];
203108401Sambriskostatic char an_conf_cache[256];
20483269Sbrooks
20583269Sbrooks/* sysctl vars */
206108401Sambrisko
207110531SambriskoSYSCTL_NODE(_hw, OID_AUTO, an, CTLFLAG_RD, 0, "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	 */
35256094Swpaul	sc->an_bhandle = rman_get_bushandle(sc->port_res);
35355992Swpaul	sc->an_btag = rman_get_bustag(sc->port_res);
35455992Swpaul
35555992Swpaul	ssid.an_len = sizeof(ssid);
35655992Swpaul	ssid.an_type = AN_RID_SSIDLIST;
35755992Swpaul
358175446Sambrisko	/* Make sure interrupts are disabled. */
359119156Sambrisko	sc->mpi350 = 0;
360175446Sambrisko	CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), 0);
361175446Sambrisko	CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), 0xFFFF);
36255992Swpaul
363175445Sambrisko	mtx_init(&sc->an_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
364199154Sjhb	    MTX_DEF);
365175445Sambrisko	AN_LOCK(sc);
36655992Swpaul	an_reset(sc);
36755992Swpaul
368175445Sambrisko	if (an_cmd(sc, AN_CMD_READCFG, 0)) {
369175445Sambrisko		AN_UNLOCK(sc);
370175445Sambrisko		goto fail;
371175445Sambrisko	}
37255992Swpaul
373175445Sambrisko	if (an_read_record(sc, (struct an_ltv_gen *)&ssid)) {
374175445Sambrisko		AN_UNLOCK(sc);
375175445Sambrisko		goto fail;
376175445Sambrisko	}
37755992Swpaul
37868692Swpaul	/* See if the ssid matches what we expect ... but doesn't have to */
379175445Sambrisko	if (strcmp(ssid.an_entry[0].an_ssid, AN_DEF_SSID)) {
380175445Sambrisko		AN_UNLOCK(sc);
381175445Sambrisko		goto fail;
382175445Sambrisko	}
38383270Sbrooks
384175445Sambrisko	AN_UNLOCK(sc);
38555992Swpaul	return(AN_IOSIZ);
386175445Sambriskofail:
387175445Sambrisko	mtx_destroy(&sc->an_mtx);
388175445Sambrisko	return(0);
38955992Swpaul}
39055992Swpaul
39155992Swpaul/*
39255992Swpaul * Allocate a port resource with the given resource id.
39355992Swpaul */
39455992Swpaulint
395150446Simpan_alloc_port(device_t dev, int rid, int size)
39655992Swpaul{
39755992Swpaul	struct an_softc *sc = device_get_softc(dev);
39855992Swpaul	struct resource *res;
39955992Swpaul
40055992Swpaul	res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
40155992Swpaul				 0ul, ~0ul, size, RF_ACTIVE);
40255992Swpaul	if (res) {
40355992Swpaul		sc->port_rid = rid;
40455992Swpaul		sc->port_res = res;
40555992Swpaul		return (0);
40655992Swpaul	} else {
40755992Swpaul		return (ENOENT);
40855992Swpaul	}
40955992Swpaul}
41055992Swpaul
41155992Swpaul/*
412108401Sambrisko * Allocate a memory resource with the given resource id.
413108401Sambrisko */
414108401Sambriskoint an_alloc_memory(device_t dev, int rid, int size)
415108401Sambrisko{
416108401Sambrisko	struct an_softc *sc = device_get_softc(dev);
417108401Sambrisko	struct resource *res;
418108401Sambrisko
419108401Sambrisko	res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
420108401Sambrisko				 0ul, ~0ul, size, RF_ACTIVE);
421108401Sambrisko	if (res) {
422108401Sambrisko		sc->mem_rid = rid;
423108401Sambrisko		sc->mem_res = res;
424108401Sambrisko		sc->mem_used = size;
425108401Sambrisko		return (0);
426108401Sambrisko	} else {
427108401Sambrisko		return (ENOENT);
428108401Sambrisko	}
429108401Sambrisko}
430108401Sambrisko
431108401Sambrisko/*
432108401Sambrisko * Allocate a auxilary memory resource with the given resource id.
433108401Sambrisko */
434108401Sambriskoint an_alloc_aux_memory(device_t dev, int rid, int size)
435108401Sambrisko{
436108401Sambrisko	struct an_softc *sc = device_get_softc(dev);
437108401Sambrisko	struct resource *res;
438108401Sambrisko
439108401Sambrisko	res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
440108401Sambrisko				 0ul, ~0ul, size, RF_ACTIVE);
441108401Sambrisko	if (res) {
442108401Sambrisko		sc->mem_aux_rid = rid;
443108401Sambrisko		sc->mem_aux_res = res;
444108401Sambrisko		sc->mem_aux_used = size;
445108401Sambrisko		return (0);
446108401Sambrisko	} else {
447108401Sambrisko		return (ENOENT);
448108401Sambrisko	}
449108401Sambrisko}
450108401Sambrisko
451108401Sambrisko/*
45255992Swpaul * Allocate an irq resource with the given resource id.
45355992Swpaul */
45455992Swpaulint
455150446Simpan_alloc_irq(device_t dev, int rid, int flags)
45655992Swpaul{
45755992Swpaul	struct an_softc *sc = device_get_softc(dev);
45855992Swpaul	struct resource *res;
45955992Swpaul
460127135Snjl	res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
461127135Snjl				     (RF_ACTIVE | flags));
46255992Swpaul	if (res) {
46355992Swpaul		sc->irq_rid = rid;
46455992Swpaul		sc->irq_res = res;
46555992Swpaul		return (0);
46655992Swpaul	} else {
46755992Swpaul		return (ENOENT);
46855992Swpaul	}
46955992Swpaul}
47055992Swpaul
471108401Sambriskostatic void
472150446Simpan_dma_malloc_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
473108401Sambrisko{
474108401Sambrisko	bus_addr_t *paddr = (bus_addr_t*) arg;
475108401Sambrisko	*paddr = segs->ds_addr;
476108401Sambrisko}
477108401Sambrisko
47855992Swpaul/*
479108401Sambrisko * Alloc DMA memory and set the pointer to it
480108401Sambrisko */
481108401Sambriskostatic int
482150446Simpan_dma_malloc(struct an_softc *sc, bus_size_t size, struct an_dma_alloc *dma,
483150446Simp    int mapflags)
484108401Sambrisko{
485108401Sambrisko	int r;
486108401Sambrisko
487108401Sambrisko	r = bus_dmamap_create(sc->an_dtag, BUS_DMA_NOWAIT, &dma->an_dma_map);
488108401Sambrisko	if (r != 0)
489108401Sambrisko		goto fail_0;
490108401Sambrisko
491108401Sambrisko	r = bus_dmamem_alloc(sc->an_dtag, (void**) &dma->an_dma_vaddr,
492108401Sambrisko			     BUS_DMA_NOWAIT, &dma->an_dma_map);
493108401Sambrisko	if (r != 0)
494108401Sambrisko		goto fail_1;
495108401Sambrisko
496108401Sambrisko	r = bus_dmamap_load(sc->an_dtag, dma->an_dma_map, dma->an_dma_vaddr,
497175446Sambrisko			    size,
498108401Sambrisko			    an_dma_malloc_cb,
499108401Sambrisko			    &dma->an_dma_paddr,
500108401Sambrisko			    mapflags | BUS_DMA_NOWAIT);
501108401Sambrisko	if (r != 0)
502108401Sambrisko		goto fail_2;
503108401Sambrisko
504108401Sambrisko	dma->an_dma_size = size;
505108401Sambrisko	return (0);
506108401Sambrisko
507108401Sambriskofail_2:
508108401Sambrisko	bus_dmamap_unload(sc->an_dtag, dma->an_dma_map);
509108401Sambriskofail_1:
510108401Sambrisko	bus_dmamem_free(sc->an_dtag, dma->an_dma_vaddr, dma->an_dma_map);
511108401Sambriskofail_0:
512108401Sambrisko	bus_dmamap_destroy(sc->an_dtag, dma->an_dma_map);
513108401Sambrisko	dma->an_dma_map = NULL;
514108401Sambrisko	return (r);
515108401Sambrisko}
516108401Sambrisko
517108401Sambriskostatic void
518150446Simpan_dma_free(struct an_softc *sc, struct an_dma_alloc *dma)
519108401Sambrisko{
520108401Sambrisko	bus_dmamap_unload(sc->an_dtag, dma->an_dma_map);
521108401Sambrisko	bus_dmamem_free(sc->an_dtag, dma->an_dma_vaddr, dma->an_dma_map);
522123978Sambrisko	dma->an_dma_vaddr = 0;
523108401Sambrisko	bus_dmamap_destroy(sc->an_dtag, dma->an_dma_map);
524108401Sambrisko}
525108401Sambrisko
526108401Sambrisko/*
52755992Swpaul * Release all resources
52855992Swpaul */
52955992Swpaulvoid
530150446Simpan_release_resources(device_t dev)
53155992Swpaul{
53255992Swpaul	struct an_softc *sc = device_get_softc(dev);
533108401Sambrisko	int i;
53455992Swpaul
53555992Swpaul	if (sc->port_res) {
53655992Swpaul		bus_release_resource(dev, SYS_RES_IOPORT,
53755992Swpaul				     sc->port_rid, sc->port_res);
53855992Swpaul		sc->port_res = 0;
53955992Swpaul	}
540108401Sambrisko	if (sc->mem_res) {
541108401Sambrisko		bus_release_resource(dev, SYS_RES_MEMORY,
542108401Sambrisko				     sc->mem_rid, sc->mem_res);
543108401Sambrisko		sc->mem_res = 0;
544108401Sambrisko	}
545108401Sambrisko	if (sc->mem_aux_res) {
546108401Sambrisko		bus_release_resource(dev, SYS_RES_MEMORY,
547108401Sambrisko				     sc->mem_aux_rid, sc->mem_aux_res);
548108401Sambrisko		sc->mem_aux_res = 0;
549108401Sambrisko	}
55055992Swpaul	if (sc->irq_res) {
55155992Swpaul		bus_release_resource(dev, SYS_RES_IRQ,
55255992Swpaul				     sc->irq_rid, sc->irq_res);
55355992Swpaul		sc->irq_res = 0;
55455992Swpaul	}
555108401Sambrisko	if (sc->an_rid_buffer.an_dma_paddr) {
556108401Sambrisko		an_dma_free(sc, &sc->an_rid_buffer);
557108401Sambrisko	}
558108401Sambrisko	for (i = 0; i < AN_MAX_RX_DESC; i++)
559108401Sambrisko		if (sc->an_rx_buffer[i].an_dma_paddr) {
560108401Sambrisko			an_dma_free(sc, &sc->an_rx_buffer[i]);
561108401Sambrisko		}
562108401Sambrisko	for (i = 0; i < AN_MAX_TX_DESC; i++)
563108401Sambrisko		if (sc->an_tx_buffer[i].an_dma_paddr) {
564108401Sambrisko			an_dma_free(sc, &sc->an_tx_buffer[i]);
565108401Sambrisko		}
566108401Sambrisko	if (sc->an_dtag) {
567108401Sambrisko		bus_dma_tag_destroy(sc->an_dtag);
568108401Sambrisko	}
569108401Sambrisko
57055992Swpaul}
57155992Swpaul
57283270Sbrooksint
573150446Simpan_init_mpi350_desc(struct an_softc *sc)
574108401Sambrisko{
575108401Sambrisko	struct an_command	cmd_struct;
576108401Sambrisko	struct an_reply		reply;
577108401Sambrisko	struct an_card_rid_desc an_rid_desc;
578108401Sambrisko	struct an_card_rx_desc	an_rx_desc;
579108401Sambrisko	struct an_card_tx_desc	an_tx_desc;
580108401Sambrisko	int			i, desc;
581108401Sambrisko
582175445Sambrisko	AN_LOCK_ASSERT(sc);
583108401Sambrisko	if(!sc->an_rid_buffer.an_dma_paddr)
584108401Sambrisko		an_dma_malloc(sc, AN_RID_BUFFER_SIZE,
585108401Sambrisko				 &sc->an_rid_buffer, 0);
586108401Sambrisko	for (i = 0; i < AN_MAX_RX_DESC; i++)
587108401Sambrisko		if(!sc->an_rx_buffer[i].an_dma_paddr)
588108401Sambrisko			an_dma_malloc(sc, AN_RX_BUFFER_SIZE,
589108401Sambrisko				      &sc->an_rx_buffer[i], 0);
590108401Sambrisko	for (i = 0; i < AN_MAX_TX_DESC; i++)
591108401Sambrisko		if(!sc->an_tx_buffer[i].an_dma_paddr)
592108401Sambrisko			an_dma_malloc(sc, AN_TX_BUFFER_SIZE,
593108401Sambrisko				      &sc->an_tx_buffer[i], 0);
594108401Sambrisko
595108401Sambrisko	/*
596108401Sambrisko	 * Allocate RX descriptor
597108401Sambrisko	 */
598108401Sambrisko	bzero(&reply,sizeof(reply));
599108401Sambrisko	cmd_struct.an_cmd   = AN_CMD_ALLOC_DESC;
600108401Sambrisko	cmd_struct.an_parm0 = AN_DESCRIPTOR_RX;
601108401Sambrisko	cmd_struct.an_parm1 = AN_RX_DESC_OFFSET;
602108401Sambrisko	cmd_struct.an_parm2 = AN_MAX_RX_DESC;
603108401Sambrisko	if (an_cmd_struct(sc, &cmd_struct, &reply)) {
604198987Sjhb		if_printf(sc->an_ifp, "failed to allocate RX descriptor\n");
605108401Sambrisko		return(EIO);
606108401Sambrisko	}
607108401Sambrisko
608108401Sambrisko	for (desc = 0; desc < AN_MAX_RX_DESC; desc++) {
609108401Sambrisko		bzero(&an_rx_desc, sizeof(an_rx_desc));
610108401Sambrisko		an_rx_desc.an_valid = 1;
611108401Sambrisko		an_rx_desc.an_len = AN_RX_BUFFER_SIZE;
612108401Sambrisko		an_rx_desc.an_done = 0;
613108401Sambrisko		an_rx_desc.an_phys = sc->an_rx_buffer[desc].an_dma_paddr;
614108401Sambrisko
615108401Sambrisko		for (i = 0; i < sizeof(an_rx_desc) / 4; i++)
616155321Simp			CSR_MEM_AUX_WRITE_4(sc, AN_RX_DESC_OFFSET
617155321Simp			    + (desc * sizeof(an_rx_desc))
618155321Simp			    + (i * 4),
619155321Simp			    ((u_int32_t *)(void *)&an_rx_desc)[i]);
620108401Sambrisko	}
621108401Sambrisko
622108401Sambrisko	/*
623108401Sambrisko	 * Allocate TX descriptor
624108401Sambrisko	 */
625108401Sambrisko
626108401Sambrisko	bzero(&reply,sizeof(reply));
627108401Sambrisko	cmd_struct.an_cmd   = AN_CMD_ALLOC_DESC;
628108401Sambrisko	cmd_struct.an_parm0 = AN_DESCRIPTOR_TX;
629108401Sambrisko	cmd_struct.an_parm1 = AN_TX_DESC_OFFSET;
630108401Sambrisko	cmd_struct.an_parm2 = AN_MAX_TX_DESC;
631108401Sambrisko	if (an_cmd_struct(sc, &cmd_struct, &reply)) {
632198987Sjhb		if_printf(sc->an_ifp, "failed to allocate TX descriptor\n");
633108401Sambrisko		return(EIO);
634108401Sambrisko	}
635108401Sambrisko
636108401Sambrisko	for (desc = 0; desc < AN_MAX_TX_DESC; desc++) {
637108401Sambrisko		bzero(&an_tx_desc, sizeof(an_tx_desc));
638108401Sambrisko		an_tx_desc.an_offset = 0;
639108401Sambrisko		an_tx_desc.an_eoc = 0;
640108401Sambrisko		an_tx_desc.an_valid = 0;
641108401Sambrisko		an_tx_desc.an_len = 0;
642108401Sambrisko		an_tx_desc.an_phys = sc->an_tx_buffer[desc].an_dma_paddr;
643108401Sambrisko
644108401Sambrisko		for (i = 0; i < sizeof(an_tx_desc) / 4; i++)
645108401Sambrisko			CSR_MEM_AUX_WRITE_4(sc, AN_TX_DESC_OFFSET
646155321Simp			    + (desc * sizeof(an_tx_desc))
647155321Simp			    + (i * 4),
648155321Simp			    ((u_int32_t *)(void *)&an_tx_desc)[i]);
649108401Sambrisko	}
650108401Sambrisko
651108401Sambrisko	/*
652108401Sambrisko	 * Allocate RID descriptor
653108401Sambrisko	 */
654108401Sambrisko
655108401Sambrisko	bzero(&reply,sizeof(reply));
656108401Sambrisko	cmd_struct.an_cmd   = AN_CMD_ALLOC_DESC;
657108401Sambrisko	cmd_struct.an_parm0 = AN_DESCRIPTOR_HOSTRW;
658108401Sambrisko	cmd_struct.an_parm1 = AN_HOST_DESC_OFFSET;
659108401Sambrisko	cmd_struct.an_parm2 = 1;
660108401Sambrisko	if (an_cmd_struct(sc, &cmd_struct, &reply)) {
661198987Sjhb		if_printf(sc->an_ifp, "failed to allocate host descriptor\n");
662108401Sambrisko		return(EIO);
663108401Sambrisko	}
664108401Sambrisko
665108401Sambrisko	bzero(&an_rid_desc, sizeof(an_rid_desc));
666108401Sambrisko	an_rid_desc.an_valid = 1;
667108401Sambrisko	an_rid_desc.an_len = AN_RID_BUFFER_SIZE;
668108401Sambrisko	an_rid_desc.an_rid = 0;
669108401Sambrisko	an_rid_desc.an_phys = sc->an_rid_buffer.an_dma_paddr;
670108401Sambrisko
671108401Sambrisko	for (i = 0; i < sizeof(an_rid_desc) / 4; i++)
672175445Sambrisko		CSR_MEM_AUX_WRITE_4(sc, AN_HOST_DESC_OFFSET + i * 4,
673155321Simp				    ((u_int32_t *)(void *)&an_rid_desc)[i]);
674108401Sambrisko
675108401Sambrisko	return(0);
676108401Sambrisko}
677108401Sambrisko
678108401Sambriskoint
679198995Sjhban_attach(struct an_softc *sc, int flags)
68055992Swpaul{
681147256Sbrooks	struct ifnet		*ifp;
682113316Simp	int			error = EIO;
683110253Sambrisko	int			i, nrate, mword;
684110253Sambrisko	u_int8_t		r;
68555992Swpaul
686147380Sdelphij	ifp = sc->an_ifp = if_alloc(IFT_ETHER);
687147256Sbrooks	if (ifp == NULL) {
688198987Sjhb		device_printf(sc->an_dev, "can not if_alloc()\n");
689147256Sbrooks		goto fail;
690147256Sbrooks	}
691175445Sambrisko
69255992Swpaul	sc->an_gone = 0;
69355992Swpaul	sc->an_associated = 0;
69483269Sbrooks	sc->an_monitor = 0;
69583269Sbrooks	sc->an_was_monitor = 0;
696108401Sambrisko	sc->an_flash_buffer = NULL;
69755992Swpaul
69855992Swpaul	/* Reset the NIC. */
699175445Sambrisko	AN_LOCK(sc);
70055992Swpaul	an_reset(sc);
701110104Sambrisko	if (sc->mpi350) {
702108401Sambrisko		error = an_init_mpi350_desc(sc);
703108401Sambrisko		if (error)
704113316Simp			goto fail;
705108401Sambrisko	}
70655992Swpaul
70755992Swpaul	/* Load factory config */
70855992Swpaul	if (an_cmd(sc, AN_CMD_READCFG, 0)) {
709198987Sjhb		device_printf(sc->an_dev, "failed to load config data\n");
710113316Simp		goto fail;
71155992Swpaul	}
71255992Swpaul
71355992Swpaul	/* Read the current configuration */
71455992Swpaul	sc->an_config.an_type = AN_RID_GENCONFIG;
71555992Swpaul	sc->an_config.an_len = sizeof(struct an_ltv_genconfig);
71655992Swpaul	if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_config)) {
717198987Sjhb		device_printf(sc->an_dev, "read record failed\n");
718113316Simp		goto fail;
71955992Swpaul	}
72055992Swpaul
72155992Swpaul	/* Read the card capabilities */
72255992Swpaul	sc->an_caps.an_type = AN_RID_CAPABILITIES;
72355992Swpaul	sc->an_caps.an_len = sizeof(struct an_ltv_caps);
72455992Swpaul	if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_caps)) {
725198987Sjhb		device_printf(sc->an_dev, "read record failed\n");
726113316Simp		goto fail;
72755992Swpaul	}
72855992Swpaul
72955992Swpaul	/* Read ssid list */
73055992Swpaul	sc->an_ssidlist.an_type = AN_RID_SSIDLIST;
731119156Sambrisko	sc->an_ssidlist.an_len = sizeof(struct an_ltv_ssidlist_new);
73255992Swpaul	if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_ssidlist)) {
733198987Sjhb		device_printf(sc->an_dev, "read record failed\n");
734113316Simp		goto fail;
73555992Swpaul	}
73655992Swpaul
73755992Swpaul	/* Read AP list */
73855992Swpaul	sc->an_aplist.an_type = AN_RID_APLIST;
73955992Swpaul	sc->an_aplist.an_len = sizeof(struct an_ltv_aplist);
74055992Swpaul	if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_aplist)) {
741198987Sjhb		device_printf(sc->an_dev, "read record failed\n");
742113316Simp		goto fail;
74355992Swpaul	}
74455992Swpaul
745108401Sambrisko#ifdef ANCACHE
746108401Sambrisko	/* Read the RSSI <-> dBm map */
747108401Sambrisko	sc->an_have_rssimap = 0;
748108401Sambrisko	if (sc->an_caps.an_softcaps & 8) {
749108401Sambrisko		sc->an_rssimap.an_type = AN_RID_RSSI_MAP;
750108401Sambrisko		sc->an_rssimap.an_len = sizeof(struct an_ltv_rssi_map);
751108401Sambrisko		if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_rssimap)) {
752198987Sjhb			device_printf(sc->an_dev,
753198987Sjhb			    "unable to get RSSI <-> dBM map\n");
754108401Sambrisko		} else {
755198987Sjhb			device_printf(sc->an_dev, "got RSSI <-> dBM map\n");
756108401Sambrisko			sc->an_have_rssimap = 1;
757108401Sambrisko		}
758108401Sambrisko	} else {
759198987Sjhb		device_printf(sc->an_dev, "no RSSI <-> dBM map\n");
760108401Sambrisko	}
761108401Sambrisko#endif
762175445Sambrisko	AN_UNLOCK(sc);
763108401Sambrisko
76455992Swpaul	ifp->if_softc = sc;
765121816Sbrooks	if_initname(ifp, device_get_name(sc->an_dev),
766121816Sbrooks	    device_get_unit(sc->an_dev));
76755992Swpaul	ifp->if_mtu = ETHERMTU;
76855992Swpaul	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
76955992Swpaul	ifp->if_ioctl = an_ioctl;
77055992Swpaul	ifp->if_start = an_start;
77155992Swpaul	ifp->if_init = an_init;
77255992Swpaul	ifp->if_baudrate = 10000000;
773132986Smlaier	IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
774132986Smlaier	ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN;
775132986Smlaier	IFQ_SET_READY(&ifp->if_snd);
77655992Swpaul
77755992Swpaul	bzero(sc->an_config.an_nodename, sizeof(sc->an_config.an_nodename));
77855992Swpaul	bcopy(AN_DEFAULT_NODENAME, sc->an_config.an_nodename,
77955992Swpaul	    sizeof(AN_DEFAULT_NODENAME) - 1);
78055992Swpaul
781119156Sambrisko	bzero(sc->an_ssidlist.an_entry[0].an_ssid,
782119156Sambrisko	      sizeof(sc->an_ssidlist.an_entry[0].an_ssid));
783119156Sambrisko	bcopy(AN_DEFAULT_NETNAME, sc->an_ssidlist.an_entry[0].an_ssid,
78455992Swpaul	    sizeof(AN_DEFAULT_NETNAME) - 1);
785119156Sambrisko	sc->an_ssidlist.an_entry[0].an_len = strlen(AN_DEFAULT_NETNAME);
78655992Swpaul
78755992Swpaul	sc->an_config.an_opmode =
78874144Sassar	    AN_OPMODE_INFRASTRUCTURE_STATION;
78955992Swpaul
79055992Swpaul	sc->an_tx_rate = 0;
79155992Swpaul	bzero((char *)&sc->an_stats, sizeof(sc->an_stats));
79255992Swpaul
793110253Sambrisko	nrate = 8;
794110253Sambrisko
79577217Sphk	ifmedia_init(&sc->an_ifmedia, 0, an_media_change, an_media_status);
796110253Sambrisko	if_printf(ifp, "supported rates: ");
797110253Sambrisko#define	ADD(s, o)	ifmedia_add(&sc->an_ifmedia, \
798110253Sambrisko	IFM_MAKEWORD(IFM_IEEE80211, (s), (o), 0), 0, NULL)
799110253Sambrisko	ADD(IFM_AUTO, 0);
800110253Sambrisko	ADD(IFM_AUTO, IFM_IEEE80211_ADHOC);
801110253Sambrisko	for (i = 0; i < nrate; i++) {
802110253Sambrisko		r = sc->an_caps.an_rates[i];
803116951Ssam		mword = ieee80211_rate2media(NULL, r, IEEE80211_T_DS);
804110253Sambrisko		if (mword == 0)
805110253Sambrisko			continue;
806110253Sambrisko		printf("%s%d%sMbps", (i != 0 ? " " : ""),
807110253Sambrisko		    (r & IEEE80211_RATE_VAL) / 2, ((r & 0x1) != 0 ? ".5" : ""));
808110253Sambrisko		ADD(mword, 0);
809110253Sambrisko		ADD(mword, IFM_IEEE80211_ADHOC);
81077217Sphk	}
811110253Sambrisko	printf("\n");
812175445Sambrisko	ifmedia_set(&sc->an_ifmedia, IFM_MAKEWORD(IFM_IEEE80211,
813110253Sambrisko	    IFM_AUTO, 0, 0));
814110253Sambrisko#undef ADD
81577217Sphk
81655992Swpaul	/*
81763090Sarchie	 * Call MI attach routine.
81855992Swpaul	 */
819147256Sbrooks
820147256Sbrooks	ether_ifattach(ifp, sc->an_caps.an_oemaddr);
821173668Savatar	callout_init_mtx(&sc->an_stat_ch, &sc->an_mtx, 0);
82255992Swpaul
82355992Swpaul	return(0);
824175445Sambriskofail:
825175445Sambrisko	AN_UNLOCK(sc);
826113316Simp	mtx_destroy(&sc->an_mtx);
827147256Sbrooks	if (ifp != NULL)
828147256Sbrooks		if_free(ifp);
829113316Simp	return(error);
83055992Swpaul}
83155992Swpaul
832123978Sambriskoint
833123978Sambriskoan_detach(device_t dev)
834123978Sambrisko{
835123978Sambrisko	struct an_softc		*sc = device_get_softc(dev);
836147256Sbrooks	struct ifnet		*ifp = sc->an_ifp;
837123978Sambrisko
838123978Sambrisko	if (sc->an_gone) {
839123978Sambrisko		device_printf(dev,"already unloaded\n");
840123978Sambrisko		return(0);
841123978Sambrisko	}
842148639Semax	AN_LOCK(sc);
843123978Sambrisko	an_stop(sc);
844148454Semax	sc->an_gone = 1;
845123978Sambrisko	ifmedia_removeall(&sc->an_ifmedia);
846148887Srwatson	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
847148454Semax	AN_UNLOCK(sc);
848123978Sambrisko	ether_ifdetach(ifp);
849150306Simp	bus_teardown_intr(dev, sc->irq_res, sc->irq_handle);
850173668Savatar	callout_drain(&sc->an_stat_ch);
851147256Sbrooks	if_free(ifp);
852123978Sambrisko	an_release_resources(dev);
853123978Sambrisko	mtx_destroy(&sc->an_mtx);
854123978Sambrisko	return (0);
855123978Sambrisko}
856123978Sambrisko
85783270Sbrooksstatic void
858150446Simpan_rxeof(struct an_softc *sc)
85955992Swpaul{
86083269Sbrooks	struct ifnet   *ifp;
86183269Sbrooks	struct ether_header *eh;
86283269Sbrooks	struct ieee80211_frame *ih;
86383269Sbrooks	struct an_rxframe rx_frame;
86483269Sbrooks	struct an_rxframe_802_3 rx_frame_802_3;
86583269Sbrooks	struct mbuf    *m;
866108401Sambrisko	int		len, id, error = 0, i, count = 0;
867108401Sambrisko	int		ieee80211_header_len;
868108401Sambrisko	u_char		*bpf_buf;
869108401Sambrisko	u_short		fc1;
870108401Sambrisko	struct an_card_rx_desc an_rx_desc;
871108401Sambrisko	u_int8_t	*buf;
87255992Swpaul
873122689Ssam	AN_LOCK_ASSERT(sc);
874122689Ssam
875147256Sbrooks	ifp = sc->an_ifp;
87655992Swpaul
877108401Sambrisko	if (!sc->mpi350) {
878108401Sambrisko		id = CSR_READ_2(sc, AN_RX_FID);
87955992Swpaul
880108401Sambrisko		if (sc->an_monitor && (ifp->if_flags & IFF_PROMISC)) {
881108401Sambrisko			/* read raw 802.11 packet */
882108401Sambrisko			bpf_buf = sc->buf_802_11;
88355992Swpaul
884108401Sambrisko			/* read header */
885108401Sambrisko			if (an_read_data(sc, id, 0x0, (caddr_t)&rx_frame,
886108401Sambrisko					 sizeof(rx_frame))) {
887108401Sambrisko				ifp->if_ierrors++;
888108401Sambrisko				return;
889108401Sambrisko			}
89055992Swpaul
891108401Sambrisko			/*
892108401Sambrisko			 * skip beacon by default since this increases the
893108401Sambrisko			 * system load a lot
894108401Sambrisko			 */
89583270Sbrooks
896108401Sambrisko			if (!(sc->an_monitor & AN_MONITOR_INCLUDE_BEACON) &&
897108401Sambrisko			    (rx_frame.an_frame_ctl &
898108401Sambrisko			     IEEE80211_FC0_SUBTYPE_BEACON)) {
89983269Sbrooks				return;
90083269Sbrooks			}
90155992Swpaul
902108401Sambrisko			if (sc->an_monitor & AN_MONITOR_AIRONET_HEADER) {
903108401Sambrisko				len = rx_frame.an_rx_payload_len
904108401Sambrisko					+ sizeof(rx_frame);
905108401Sambrisko				/* Check for insane frame length */
906108401Sambrisko				if (len > sizeof(sc->buf_802_11)) {
907198987Sjhb					if_printf(ifp, "oversized packet "
908108401Sambrisko					       "received (%d, %d)\n",
909198987Sjhb					       len, MCLBYTES);
910108401Sambrisko					ifp->if_ierrors++;
911108401Sambrisko					return;
912108401Sambrisko				}
91355992Swpaul
914108401Sambrisko				bcopy((char *)&rx_frame,
915108401Sambrisko				      bpf_buf, sizeof(rx_frame));
916108401Sambrisko
917108401Sambrisko				error = an_read_data(sc, id, sizeof(rx_frame),
918108401Sambrisko					    (caddr_t)bpf_buf+sizeof(rx_frame),
919108401Sambrisko					    rx_frame.an_rx_payload_len);
920108401Sambrisko			} else {
921108401Sambrisko				fc1=rx_frame.an_frame_ctl >> 8;
922175445Sambrisko				ieee80211_header_len =
923108401Sambrisko					sizeof(struct ieee80211_frame);
924108401Sambrisko				if ((fc1 & IEEE80211_FC1_DIR_TODS) &&
925108401Sambrisko				    (fc1 & IEEE80211_FC1_DIR_FROMDS)) {
926108401Sambrisko					ieee80211_header_len += ETHER_ADDR_LEN;
927108401Sambrisko				}
928108401Sambrisko
929108401Sambrisko				len = rx_frame.an_rx_payload_len
930108401Sambrisko					+ ieee80211_header_len;
931108401Sambrisko				/* Check for insane frame length */
932108401Sambrisko				if (len > sizeof(sc->buf_802_11)) {
933198987Sjhb					if_printf(ifp, "oversized packet "
934108401Sambrisko					       "received (%d, %d)\n",
935198987Sjhb					       len, MCLBYTES);
936108401Sambrisko					ifp->if_ierrors++;
937108401Sambrisko					return;
938108401Sambrisko				}
939108401Sambrisko
940108401Sambrisko				ih = (struct ieee80211_frame *)bpf_buf;
941108401Sambrisko
942108401Sambrisko				bcopy((char *)&rx_frame.an_frame_ctl,
943108401Sambrisko				      (char *)ih, ieee80211_header_len);
944108401Sambrisko
945108401Sambrisko				error = an_read_data(sc, id, sizeof(rx_frame) +
946108401Sambrisko					    rx_frame.an_gaplen,
947108401Sambrisko					    (caddr_t)ih +ieee80211_header_len,
948108401Sambrisko					    rx_frame.an_rx_payload_len);
949108401Sambrisko			}
950108401Sambrisko			/* dump raw 802.11 packet to bpf and skip ip stack */
951108401Sambrisko			BPF_TAP(ifp, bpf_buf, len);
95283270Sbrooks		} else {
953111119Simp			MGETHDR(m, M_DONTWAIT, MT_DATA);
954108401Sambrisko			if (m == NULL) {
955108401Sambrisko				ifp->if_ierrors++;
956108401Sambrisko				return;
95783269Sbrooks			}
958111119Simp			MCLGET(m, M_DONTWAIT);
959108401Sambrisko			if (!(m->m_flags & M_EXT)) {
960108401Sambrisko				m_freem(m);
961108401Sambrisko				ifp->if_ierrors++;
962108401Sambrisko				return;
963108401Sambrisko			}
964108401Sambrisko			m->m_pkthdr.rcvif = ifp;
965108401Sambrisko			/* Read Ethernet encapsulated packet */
96655992Swpaul
967108401Sambrisko#ifdef ANCACHE
968108401Sambrisko			/* Read NIC frame header */
969175445Sambrisko			if (an_read_data(sc, id, 0, (caddr_t)&rx_frame,
970108401Sambrisko					 sizeof(rx_frame))) {
971154394Srwatson				m_freem(m);
972108401Sambrisko				ifp->if_ierrors++;
973108401Sambrisko				return;
974108401Sambrisko			}
975108401Sambrisko#endif
976108401Sambrisko			/* Read in the 802_3 frame header */
977175445Sambrisko			if (an_read_data(sc, id, 0x34,
978108401Sambrisko					 (caddr_t)&rx_frame_802_3,
979108401Sambrisko					 sizeof(rx_frame_802_3))) {
980154394Srwatson				m_freem(m);
981108401Sambrisko				ifp->if_ierrors++;
982108401Sambrisko				return;
983108401Sambrisko			}
984108401Sambrisko			if (rx_frame_802_3.an_rx_802_3_status != 0) {
985154394Srwatson				m_freem(m);
986108401Sambrisko				ifp->if_ierrors++;
987108401Sambrisko				return;
988108401Sambrisko			}
98983269Sbrooks			/* Check for insane frame length */
990108401Sambrisko			len = rx_frame_802_3.an_rx_802_3_payload_len;
99183269Sbrooks			if (len > sizeof(sc->buf_802_11)) {
992154394Srwatson				m_freem(m);
993198987Sjhb				if_printf(ifp, "oversized packet "
994108401Sambrisko				       "received (%d, %d)\n",
995198987Sjhb				       len, MCLBYTES);
99683269Sbrooks				ifp->if_ierrors++;
99783269Sbrooks				return;
99883269Sbrooks			}
999108401Sambrisko			m->m_pkthdr.len = m->m_len =
1000108401Sambrisko				rx_frame_802_3.an_rx_802_3_payload_len + 12;
100155992Swpaul
1002108401Sambrisko			eh = mtod(m, struct ether_header *);
100355992Swpaul
1004108401Sambrisko			bcopy((char *)&rx_frame_802_3.an_rx_dst_addr,
1005108401Sambrisko			      (char *)&eh->ether_dhost, ETHER_ADDR_LEN);
1006108401Sambrisko			bcopy((char *)&rx_frame_802_3.an_rx_src_addr,
1007108401Sambrisko			      (char *)&eh->ether_shost, ETHER_ADDR_LEN);
100855992Swpaul
1009108401Sambrisko			/* in mbuf header type is just before payload */
1010175445Sambrisko			error = an_read_data(sc, id, 0x44,
1011108401Sambrisko				    (caddr_t)&(eh->ether_type),
1012108401Sambrisko				    rx_frame_802_3.an_rx_802_3_payload_len);
101355992Swpaul
1014108401Sambrisko			if (error) {
1015108401Sambrisko				m_freem(m);
1016108401Sambrisko				ifp->if_ierrors++;
1017108401Sambrisko				return;
1018108401Sambrisko			}
1019108401Sambrisko			ifp->if_ipackets++;
1020108401Sambrisko
1021108401Sambrisko			/* Receive packet. */
102283269Sbrooks#ifdef ANCACHE
1023175445Sambrisko			an_cache_store(sc, eh, m,
1024110253Sambrisko				rx_frame.an_rx_signal_strength,
1025110253Sambrisko				rx_frame.an_rsvd0);
102683269Sbrooks#endif
1027122689Ssam			AN_UNLOCK(sc);
1028108401Sambrisko			(*ifp->if_input)(ifp, m);
1029122689Ssam			AN_LOCK(sc);
103083269Sbrooks		}
103155992Swpaul
1032108401Sambrisko	} else { /* MPI-350 */
1033108401Sambrisko		for (count = 0; count < AN_MAX_RX_DESC; count++){
1034108401Sambrisko			for (i = 0; i < sizeof(an_rx_desc) / 4; i++)
1035175445Sambrisko				((u_int32_t *)(void *)&an_rx_desc)[i]
1036175445Sambrisko					= CSR_MEM_AUX_READ_4(sc,
1037175445Sambrisko						AN_RX_DESC_OFFSET
1038108401Sambrisko						+ (count * sizeof(an_rx_desc))
1039108401Sambrisko						+ (i * 4));
104083269Sbrooks
1041108401Sambrisko			if (an_rx_desc.an_done && !an_rx_desc.an_valid) {
1042108401Sambrisko				buf = sc->an_rx_buffer[count].an_dma_vaddr;
104383269Sbrooks
1044111119Simp				MGETHDR(m, M_DONTWAIT, MT_DATA);
1045108401Sambrisko				if (m == NULL) {
1046108401Sambrisko					ifp->if_ierrors++;
1047108401Sambrisko					return;
1048108401Sambrisko				}
1049111119Simp				MCLGET(m, M_DONTWAIT);
1050108401Sambrisko				if (!(m->m_flags & M_EXT)) {
1051108401Sambrisko					m_freem(m);
1052108401Sambrisko					ifp->if_ierrors++;
1053108401Sambrisko					return;
1054108401Sambrisko				}
1055108401Sambrisko				m->m_pkthdr.rcvif = ifp;
1056108401Sambrisko				/* Read Ethernet encapsulated packet */
105783269Sbrooks
1058175445Sambrisko				/*
1059108401Sambrisko				 * No ANCACHE support since we just get back
1060108401Sambrisko				 * an Ethernet packet no 802.11 info
1061108401Sambrisko				 */
1062108401Sambrisko#if 0
1063108401Sambrisko#ifdef ANCACHE
1064108401Sambrisko				/* Read NIC frame header */
1065175445Sambrisko				bcopy(buf, (caddr_t)&rx_frame,
1066108401Sambrisko				      sizeof(rx_frame));
1067108401Sambrisko#endif
1068108401Sambrisko#endif
1069108401Sambrisko				/* Check for insane frame length */
1070108401Sambrisko				len = an_rx_desc.an_len + 12;
1071108401Sambrisko				if (len > MCLBYTES) {
1072154393Srwatson					m_freem(m);
1073198987Sjhb					if_printf(ifp, "oversized packet "
1074108401Sambrisko					       "received (%d, %d)\n",
1075198987Sjhb					       len, MCLBYTES);
1076108401Sambrisko					ifp->if_ierrors++;
1077108401Sambrisko					return;
1078108401Sambrisko				}
107983269Sbrooks
1080108401Sambrisko				m->m_pkthdr.len = m->m_len =
1081108401Sambrisko					an_rx_desc.an_len + 12;
1082175445Sambrisko
1083108401Sambrisko				eh = mtod(m, struct ether_header *);
1084175445Sambrisko
1085108401Sambrisko				bcopy(buf, (char *)eh,
1086108401Sambrisko				      m->m_pkthdr.len);
1087175445Sambrisko
1088108401Sambrisko				ifp->if_ipackets++;
1089175445Sambrisko
1090108401Sambrisko				/* Receive packet. */
1091108401Sambrisko#if 0
109255992Swpaul#ifdef ANCACHE
1093175445Sambrisko				an_cache_store(sc, eh, m,
1094110253Sambrisko					rx_frame.an_rx_signal_strength,
1095110253Sambrisko					rx_frame.an_rsvd0);
109655992Swpaul#endif
1097108401Sambrisko#endif
1098171775Savatar				AN_UNLOCK(sc);
1099108401Sambrisko				(*ifp->if_input)(ifp, m);
1100171775Savatar				AN_LOCK(sc);
1101171775Savatar
1102108401Sambrisko				an_rx_desc.an_valid = 1;
1103108401Sambrisko				an_rx_desc.an_len = AN_RX_BUFFER_SIZE;
1104108401Sambrisko				an_rx_desc.an_done = 0;
1105175445Sambrisko				an_rx_desc.an_phys =
1106108401Sambrisko					sc->an_rx_buffer[count].an_dma_paddr;
1107175445Sambrisko
1108108401Sambrisko				for (i = 0; i < sizeof(an_rx_desc) / 4; i++)
1109175445Sambrisko					CSR_MEM_AUX_WRITE_4(sc,
1110175445Sambrisko					    AN_RX_DESC_OFFSET
1111155321Simp					    + (count * sizeof(an_rx_desc))
1112155321Simp					    + (i * 4),
1113155321Simp					    ((u_int32_t *)(void *)&an_rx_desc)[i]);
1114175445Sambrisko
1115108401Sambrisko			} else {
1116198987Sjhb				if_printf(ifp, "Didn't get valid RX packet "
1117108401Sambrisko				       "%x %x %d\n",
1118108401Sambrisko				       an_rx_desc.an_done,
1119108401Sambrisko				       an_rx_desc.an_valid, an_rx_desc.an_len);
1120108401Sambrisko			}
1121108401Sambrisko		}
112283269Sbrooks	}
112355992Swpaul}
112455992Swpaul
112583270Sbrooksstatic void
1126150446Simpan_txeof(struct an_softc *sc, int status)
112755992Swpaul{
112855992Swpaul	struct ifnet		*ifp;
112978639Sbrooks	int			id, i;
113055992Swpaul
1131175445Sambrisko	AN_LOCK_ASSERT(sc);
1132147256Sbrooks	ifp = sc->an_ifp;
113355992Swpaul
1134199154Sjhb	sc->an_timer = 0;
1135148887Srwatson	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
113655992Swpaul
1137108401Sambrisko	if (!sc->mpi350) {
1138119156Sambrisko		id = CSR_READ_2(sc, AN_TX_CMP_FID(sc->mpi350));
113955992Swpaul
1140108401Sambrisko		if (status & AN_EV_TX_EXC) {
1141108401Sambrisko			ifp->if_oerrors++;
1142108401Sambrisko		} else
1143108401Sambrisko			ifp->if_opackets++;
114455992Swpaul
1145108401Sambrisko		for (i = 0; i < AN_TX_RING_CNT; i++) {
1146108401Sambrisko			if (id == sc->an_rdata.an_tx_ring[i]) {
1147108401Sambrisko				sc->an_rdata.an_tx_ring[i] = 0;
1148108401Sambrisko				break;
1149108401Sambrisko			}
115078639Sbrooks		}
1151108401Sambrisko
1152108401Sambrisko		AN_INC(sc->an_rdata.an_tx_cons, AN_TX_RING_CNT);
1153108401Sambrisko	} else { /* MPI 350 */
1154119156Sambrisko		id = CSR_READ_2(sc, AN_TX_CMP_FID(sc->mpi350));
1155119156Sambrisko		if (!sc->an_rdata.an_tx_empty){
1156119156Sambrisko			if (status & AN_EV_TX_EXC) {
1157119156Sambrisko				ifp->if_oerrors++;
1158119156Sambrisko			} else
1159119156Sambrisko				ifp->if_opackets++;
1160119156Sambrisko			AN_INC(sc->an_rdata.an_tx_cons, AN_MAX_TX_DESC);
1161119156Sambrisko			if (sc->an_rdata.an_tx_prod ==
1162119156Sambrisko			    sc->an_rdata.an_tx_cons)
1163119156Sambrisko				sc->an_rdata.an_tx_empty = 1;
1164119156Sambrisko		}
116578639Sbrooks	}
116655992Swpaul
116755992Swpaul	return;
116855992Swpaul}
116955992Swpaul
117055992Swpaul/*
117155992Swpaul * We abuse the stats updater to check the current NIC status. This
117255992Swpaul * is important because we don't want to allow transmissions until
117355992Swpaul * the NIC has synchronized to the current cell (either as the master
117455992Swpaul * in an ad-hoc group, or as a station connected to an access point).
1175173668Savatar *
1176173668Savatar * Note that this function will be called via callout(9) with a lock held.
117755992Swpaul */
1178104094Sphkstatic void
1179150446Simpan_stats_update(void *xsc)
118055992Swpaul{
118155992Swpaul	struct an_softc		*sc;
118255992Swpaul	struct ifnet		*ifp;
118355992Swpaul
118455992Swpaul	sc = xsc;
1185173668Savatar	AN_LOCK_ASSERT(sc);
1186147256Sbrooks	ifp = sc->an_ifp;
1187199154Sjhb	if (sc->an_timer > 0 && --sc->an_timer == 0)
1188199154Sjhb		an_watchdog(sc);
118955992Swpaul
119055992Swpaul	sc->an_status.an_type = AN_RID_STATUS;
119155992Swpaul	sc->an_status.an_len = sizeof(struct an_ltv_status);
1192173668Savatar	if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_status))
1193173668Savatar		return;
119455992Swpaul
119555992Swpaul	if (sc->an_status.an_opmode & AN_STATUS_OPMODE_IN_SYNC)
119655992Swpaul		sc->an_associated = 1;
119755992Swpaul	else
119855992Swpaul		sc->an_associated = 0;
119955992Swpaul
120055992Swpaul	/* Don't do this while we're transmitting */
1201148887Srwatson	if (ifp->if_drv_flags & IFF_DRV_OACTIVE) {
1202173668Savatar		callout_reset(&sc->an_stat_ch, hz, an_stats_update, sc);
120355992Swpaul		return;
120455992Swpaul	}
120555992Swpaul
120655992Swpaul	sc->an_stats.an_len = sizeof(struct an_ltv_stats);
120755992Swpaul	sc->an_stats.an_type = AN_RID_32BITS_CUM;
1208173668Savatar	if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_stats.an_len))
1209173668Savatar		return;
121055992Swpaul
1211173668Savatar	callout_reset(&sc->an_stat_ch, hz, an_stats_update, sc);
121255992Swpaul
121355992Swpaul	return;
121455992Swpaul}
121555992Swpaul
121683270Sbrooksvoid
1217150446Simpan_intr(void *xsc)
121855992Swpaul{
121955992Swpaul	struct an_softc		*sc;
122055992Swpaul	struct ifnet		*ifp;
122155992Swpaul	u_int16_t		status;
122255992Swpaul
122355992Swpaul	sc = (struct an_softc*)xsc;
122455992Swpaul
122567094Swpaul	AN_LOCK(sc);
122667094Swpaul
122767094Swpaul	if (sc->an_gone) {
122867094Swpaul		AN_UNLOCK(sc);
122955992Swpaul		return;
123067094Swpaul	}
123155992Swpaul
1232147256Sbrooks	ifp = sc->an_ifp;
123355992Swpaul
123455992Swpaul	/* Disable interrupts. */
1235108401Sambrisko	CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), 0);
123655992Swpaul
1237108401Sambrisko	status = CSR_READ_2(sc, AN_EVENT_STAT(sc->mpi350));
1238119156Sambrisko	CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), ~AN_INTRS(sc->mpi350));
123955992Swpaul
1240119156Sambrisko	if (status & AN_EV_MIC) {
1241119156Sambrisko		CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_MIC);
124255992Swpaul	}
124355992Swpaul
124455992Swpaul	if (status & AN_EV_LINKSTAT) {
1245175445Sambrisko		if (CSR_READ_2(sc, AN_LINKSTAT(sc->mpi350))
1246108401Sambrisko		    == AN_LINKSTAT_ASSOCIATED)
124755992Swpaul			sc->an_associated = 1;
124855992Swpaul		else
124955992Swpaul			sc->an_associated = 0;
1250108401Sambrisko		CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_LINKSTAT);
125155992Swpaul	}
125255992Swpaul
125355992Swpaul	if (status & AN_EV_RX) {
125455992Swpaul		an_rxeof(sc);
1255108401Sambrisko		CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_RX);
125655992Swpaul	}
125755992Swpaul
1258119156Sambrisko	if (sc->mpi350 && status & AN_EV_TX_CPY) {
1259119156Sambrisko		an_txeof(sc, status);
1260150446Simp		CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_TX_CPY);
1261119156Sambrisko	}
1262119156Sambrisko
126355992Swpaul	if (status & AN_EV_TX) {
126455992Swpaul		an_txeof(sc, status);
1265150446Simp		CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_TX);
126655992Swpaul	}
126755992Swpaul
126855992Swpaul	if (status & AN_EV_TX_EXC) {
126955992Swpaul		an_txeof(sc, status);
1270108401Sambrisko		CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_TX_EXC);
127155992Swpaul	}
127255992Swpaul
127355992Swpaul	if (status & AN_EV_ALLOC)
1274108401Sambrisko		CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_ALLOC);
127555992Swpaul
127655992Swpaul	/* Re-enable interrupts. */
1277119156Sambrisko	CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), AN_INTRS(sc->mpi350));
127855992Swpaul
1279132986Smlaier	if ((ifp->if_flags & IFF_UP) && !IFQ_DRV_IS_EMPTY(&ifp->if_snd))
1280199154Sjhb		an_start_locked(ifp);
128155992Swpaul
128267094Swpaul	AN_UNLOCK(sc);
128367094Swpaul
128455992Swpaul	return;
128555992Swpaul}
128655992Swpaul
1287108401Sambrisko
128883270Sbrooksstatic int
1289150446Simpan_cmd_struct(struct an_softc *sc, struct an_command *cmd,
1290150446Simp    struct an_reply *reply)
1291108401Sambrisko{
1292108401Sambrisko	int			i;
1293108401Sambrisko
1294175445Sambrisko	AN_LOCK_ASSERT(sc);
1295108401Sambrisko	for (i = 0; i != AN_TIMEOUT; i++) {
1296108401Sambrisko		if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350)) & AN_CMD_BUSY) {
1297110531Sambrisko			DELAY(1000);
1298110104Sambrisko		} else
1299108401Sambrisko			break;
1300108401Sambrisko	}
1301119156Sambrisko
1302108401Sambrisko	if( i == AN_TIMEOUT) {
1303108401Sambrisko		printf("BUSY\n");
1304108401Sambrisko		return(ETIMEDOUT);
1305108401Sambrisko	}
1306108401Sambrisko
1307108401Sambrisko	CSR_WRITE_2(sc, AN_PARAM0(sc->mpi350), cmd->an_parm0);
1308108401Sambrisko	CSR_WRITE_2(sc, AN_PARAM1(sc->mpi350), cmd->an_parm1);
1309108401Sambrisko	CSR_WRITE_2(sc, AN_PARAM2(sc->mpi350), cmd->an_parm2);
1310108401Sambrisko	CSR_WRITE_2(sc, AN_COMMAND(sc->mpi350), cmd->an_cmd);
1311108401Sambrisko
1312108401Sambrisko	for (i = 0; i < AN_TIMEOUT; i++) {
1313108401Sambrisko		if (CSR_READ_2(sc, AN_EVENT_STAT(sc->mpi350)) & AN_EV_CMD)
1314108401Sambrisko			break;
1315110531Sambrisko		DELAY(1000);
1316108401Sambrisko	}
1317108401Sambrisko
1318108401Sambrisko	reply->an_resp0 = CSR_READ_2(sc, AN_RESP0(sc->mpi350));
1319108401Sambrisko	reply->an_resp1 = CSR_READ_2(sc, AN_RESP1(sc->mpi350));
1320108401Sambrisko	reply->an_resp2 = CSR_READ_2(sc, AN_RESP2(sc->mpi350));
1321108401Sambrisko	reply->an_status = CSR_READ_2(sc, AN_STATUS(sc->mpi350));
1322108401Sambrisko
1323108401Sambrisko	if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350)) & AN_CMD_BUSY)
1324175445Sambrisko		CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350),
1325119156Sambrisko		    AN_EV_CLR_STUCK_BUSY);
1326108401Sambrisko
1327108401Sambrisko	/* Ack the command */
1328108401Sambrisko	CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_CMD);
1329108401Sambrisko
1330108401Sambrisko	if (i == AN_TIMEOUT)
1331108401Sambrisko		return(ETIMEDOUT);
1332108401Sambrisko
1333108401Sambrisko	return(0);
1334108401Sambrisko}
1335108401Sambrisko
1336108401Sambriskostatic int
1337150446Simpan_cmd(struct an_softc *sc, int cmd, int val)
133855992Swpaul{
133955992Swpaul	int			i, s = 0;
134055992Swpaul
1341175445Sambrisko	AN_LOCK_ASSERT(sc);
1342108401Sambrisko	CSR_WRITE_2(sc, AN_PARAM0(sc->mpi350), val);
1343108401Sambrisko	CSR_WRITE_2(sc, AN_PARAM1(sc->mpi350), 0);
1344108401Sambrisko	CSR_WRITE_2(sc, AN_PARAM2(sc->mpi350), 0);
1345108401Sambrisko	CSR_WRITE_2(sc, AN_COMMAND(sc->mpi350), cmd);
134655992Swpaul
134755992Swpaul	for (i = 0; i < AN_TIMEOUT; i++) {
1348108401Sambrisko		if (CSR_READ_2(sc, AN_EVENT_STAT(sc->mpi350)) & AN_EV_CMD)
134955992Swpaul			break;
135055992Swpaul		else {
1351108401Sambrisko			if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350)) == cmd)
1352108401Sambrisko				CSR_WRITE_2(sc, AN_COMMAND(sc->mpi350), cmd);
135355992Swpaul		}
135455992Swpaul	}
135555992Swpaul
135655992Swpaul	for (i = 0; i < AN_TIMEOUT; i++) {
1357108401Sambrisko		CSR_READ_2(sc, AN_RESP0(sc->mpi350));
1358108401Sambrisko		CSR_READ_2(sc, AN_RESP1(sc->mpi350));
1359108401Sambrisko		CSR_READ_2(sc, AN_RESP2(sc->mpi350));
1360108401Sambrisko		s = CSR_READ_2(sc, AN_STATUS(sc->mpi350));
136155992Swpaul		if ((s & AN_STAT_CMD_CODE) == (cmd & AN_STAT_CMD_CODE))
136255992Swpaul			break;
136355992Swpaul	}
136455992Swpaul
136555992Swpaul	/* Ack the command */
1366108401Sambrisko	CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_CMD);
136755992Swpaul
1368108401Sambrisko	if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350)) & AN_CMD_BUSY)
1369108401Sambrisko		CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_CLR_STUCK_BUSY);
137055992Swpaul
137155992Swpaul	if (i == AN_TIMEOUT)
137255992Swpaul		return(ETIMEDOUT);
137355992Swpaul
137455992Swpaul	return(0);
137555992Swpaul}
137655992Swpaul
137755992Swpaul/*
137855992Swpaul * This reset sequence may look a little strange, but this is the
137955992Swpaul * most reliable method I've found to really kick the NIC in the
138055992Swpaul * head and force it to reboot correctly.
138155992Swpaul */
138283270Sbrooksstatic void
1383150446Simpan_reset(struct an_softc *sc)
138455992Swpaul{
138555992Swpaul	if (sc->an_gone)
138655992Swpaul		return;
138783270Sbrooks
1388175445Sambrisko	AN_LOCK_ASSERT(sc);
138955992Swpaul	an_cmd(sc, AN_CMD_ENABLE, 0);
139055992Swpaul	an_cmd(sc, AN_CMD_FW_RESTART, 0);
139155992Swpaul	an_cmd(sc, AN_CMD_NOOP2, 0);
139255992Swpaul
139355992Swpaul	if (an_cmd(sc, AN_CMD_FORCE_SYNCLOSS, 0) == ETIMEDOUT)
1394198987Sjhb		if_printf(sc->an_ifp, "reset failed\n");
139555992Swpaul
139655992Swpaul	an_cmd(sc, AN_CMD_DISABLE, 0);
139755992Swpaul
139855992Swpaul	return;
139955992Swpaul}
140055992Swpaul
140155992Swpaul/*
140255992Swpaul * Read an LTV record from the NIC.
140355992Swpaul */
140483270Sbrooksstatic int
1405150446Simpan_read_record(struct an_softc *sc, struct an_ltv_gen *ltv)
140655992Swpaul{
1407108401Sambrisko	struct an_ltv_gen	*an_ltv;
1408108401Sambrisko	struct an_card_rid_desc an_rid_desc;
1409108401Sambrisko	struct an_command	cmd;
1410108401Sambrisko	struct an_reply		reply;
1411198987Sjhb	struct ifnet		*ifp;
141255992Swpaul	u_int16_t		*ptr;
141378639Sbrooks	u_int8_t		*ptr2;
141455992Swpaul	int			i, len;
141555992Swpaul
1416175445Sambrisko	AN_LOCK_ASSERT(sc);
141778639Sbrooks	if (ltv->an_len < 4 || ltv->an_type == 0)
141855992Swpaul		return(EINVAL);
141955992Swpaul
1420198987Sjhb	ifp = sc->an_ifp;
1421108401Sambrisko	if (!sc->mpi350){
1422108401Sambrisko		/* Tell the NIC to enter record read mode. */
1423108401Sambrisko		if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_READ, ltv->an_type)) {
1424198987Sjhb			if_printf(ifp, "RID access failed\n");
1425108401Sambrisko			return(EIO);
1426108401Sambrisko		}
142755992Swpaul
1428108401Sambrisko		/* Seek to the record. */
1429108401Sambrisko		if (an_seek(sc, ltv->an_type, 0, AN_BAP1)) {
1430198987Sjhb			if_printf(ifp, "seek to record failed\n");
1431108401Sambrisko			return(EIO);
1432108401Sambrisko		}
143355992Swpaul
1434108401Sambrisko		/*
1435108401Sambrisko		 * Read the length and record type and make sure they
1436108401Sambrisko		 * match what we expect (this verifies that we have enough
1437108401Sambrisko		 * room to hold all of the returned data).
1438108401Sambrisko		 * Length includes type but not length.
1439108401Sambrisko		 */
1440108401Sambrisko		len = CSR_READ_2(sc, AN_DATA1);
1441108401Sambrisko		if (len > (ltv->an_len - 2)) {
1442198987Sjhb			if_printf(ifp, "record length mismatch -- expected %d, "
1443198987Sjhb			       "got %d for Rid %x\n",
1444108401Sambrisko			       ltv->an_len - 2, len, ltv->an_type);
1445108401Sambrisko			len = ltv->an_len - 2;
1446108401Sambrisko		} else {
1447108401Sambrisko			ltv->an_len = len + 2;
1448108401Sambrisko		}
1449108401Sambrisko
1450108401Sambrisko		/* Now read the data. */
1451108401Sambrisko		len -= 2;	/* skip the type */
1452108401Sambrisko		ptr = &ltv->an_val;
1453108401Sambrisko		for (i = len; i > 1; i -= 2)
1454108401Sambrisko			*ptr++ = CSR_READ_2(sc, AN_DATA1);
1455108401Sambrisko		if (i) {
1456108401Sambrisko			ptr2 = (u_int8_t *)ptr;
1457108401Sambrisko			*ptr2 = CSR_READ_1(sc, AN_DATA1);
1458108401Sambrisko		}
1459108401Sambrisko	} else { /* MPI-350 */
1460123978Sambrisko		if (!sc->an_rid_buffer.an_dma_vaddr)
1461123978Sambrisko			return(EIO);
1462108401Sambrisko		an_rid_desc.an_valid = 1;
1463108401Sambrisko		an_rid_desc.an_len = AN_RID_BUFFER_SIZE;
1464108401Sambrisko		an_rid_desc.an_rid = 0;
1465108401Sambrisko		an_rid_desc.an_phys = sc->an_rid_buffer.an_dma_paddr;
1466108401Sambrisko		bzero(sc->an_rid_buffer.an_dma_vaddr, AN_RID_BUFFER_SIZE);
1467108401Sambrisko
1468108401Sambrisko		bzero(&cmd, sizeof(cmd));
1469108401Sambrisko		bzero(&reply, sizeof(reply));
1470108401Sambrisko		cmd.an_cmd = AN_CMD_ACCESS|AN_ACCESS_READ;
1471108401Sambrisko		cmd.an_parm0 = ltv->an_type;
1472108401Sambrisko
1473108401Sambrisko		for (i = 0; i < sizeof(an_rid_desc) / 4; i++)
1474175445Sambrisko			CSR_MEM_AUX_WRITE_4(sc, AN_HOST_DESC_OFFSET + i * 4,
1475155321Simp			    ((u_int32_t *)(void *)&an_rid_desc)[i]);
1476108401Sambrisko
1477108401Sambrisko		if (an_cmd_struct(sc, &cmd, &reply)
1478108401Sambrisko		    || reply.an_status & AN_CMD_QUAL_MASK) {
1479198987Sjhb			if_printf(ifp, "failed to read RID %x %x %x %x %x, %d\n",
1480198987Sjhb			       ltv->an_type,
1481108401Sambrisko			       reply.an_status,
1482108401Sambrisko			       reply.an_resp0,
1483108401Sambrisko			       reply.an_resp1,
1484108401Sambrisko			       reply.an_resp2,
1485108401Sambrisko			       i);
1486108401Sambrisko			return(EIO);
1487108401Sambrisko		}
1488108401Sambrisko
1489108401Sambrisko		an_ltv = (struct an_ltv_gen *)sc->an_rid_buffer.an_dma_vaddr;
1490108401Sambrisko		if (an_ltv->an_len + 2 < an_rid_desc.an_len) {
1491108401Sambrisko			an_rid_desc.an_len = an_ltv->an_len;
1492108401Sambrisko		}
1493108401Sambrisko
1494123978Sambrisko		len = an_rid_desc.an_len;
1495123978Sambrisko		if (len > (ltv->an_len - 2)) {
1496198987Sjhb			if_printf(ifp, "record length mismatch -- expected %d, "
1497198987Sjhb			       "got %d for Rid %x\n",
1498123978Sambrisko			       ltv->an_len - 2, len, ltv->an_type);
1499123978Sambrisko			len = ltv->an_len - 2;
1500123978Sambrisko		} else {
1501123978Sambrisko			ltv->an_len = len + 2;
1502123978Sambrisko		}
1503123978Sambrisko		bcopy(&an_ltv->an_type,
1504175445Sambrisko		    &ltv->an_val,
1505123978Sambrisko		    len);
150655992Swpaul	}
150755992Swpaul
150878639Sbrooks	if (an_dump)
150978639Sbrooks		an_dump_record(sc, ltv, "Read");
151055992Swpaul
151155992Swpaul	return(0);
151255992Swpaul}
151355992Swpaul
151455992Swpaul/*
151555992Swpaul * Same as read, except we inject data instead of reading it.
151655992Swpaul */
151783270Sbrooksstatic int
1518150446Simpan_write_record(struct an_softc *sc, struct an_ltv_gen *ltv)
151955992Swpaul{
1520108401Sambrisko	struct an_card_rid_desc an_rid_desc;
1521108401Sambrisko	struct an_command	cmd;
1522108401Sambrisko	struct an_reply		reply;
152355992Swpaul	u_int16_t		*ptr;
152478639Sbrooks	u_int8_t		*ptr2;
152578639Sbrooks	int			i, len;
152655992Swpaul
1527175445Sambrisko	AN_LOCK_ASSERT(sc);
152878639Sbrooks	if (an_dump)
152978639Sbrooks		an_dump_record(sc, ltv, "Write");
153078639Sbrooks
1531108401Sambrisko	if (!sc->mpi350){
1532108401Sambrisko		if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_READ, ltv->an_type))
1533108401Sambrisko			return(EIO);
153483270Sbrooks
1535108401Sambrisko		if (an_seek(sc, ltv->an_type, 0, AN_BAP1))
1536108401Sambrisko			return(EIO);
1537108401Sambrisko
1538108401Sambrisko		/*
1539108401Sambrisko		 * Length includes type but not length.
1540108401Sambrisko		 */
1541108401Sambrisko		len = ltv->an_len - 2;
1542108401Sambrisko		CSR_WRITE_2(sc, AN_DATA1, len);
1543108401Sambrisko
1544108401Sambrisko		len -= 2;	/* skip the type */
1545108401Sambrisko		ptr = &ltv->an_val;
1546108401Sambrisko		for (i = len; i > 1; i -= 2)
1547108401Sambrisko			CSR_WRITE_2(sc, AN_DATA1, *ptr++);
1548108401Sambrisko		if (i) {
1549108401Sambrisko			ptr2 = (u_int8_t *)ptr;
1550108401Sambrisko			CSR_WRITE_1(sc, AN_DATA0, *ptr2);
1551108401Sambrisko		}
1552108401Sambrisko
1553108401Sambrisko		if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_WRITE, ltv->an_type))
1554108401Sambrisko			return(EIO);
1555175445Sambrisko	} else {
1556110104Sambrisko		/* MPI-350 */
1557108401Sambrisko
1558108401Sambrisko		for (i = 0; i != AN_TIMEOUT; i++) {
1559175445Sambrisko			if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350))
1560110104Sambrisko			    & AN_CMD_BUSY) {
1561108401Sambrisko				DELAY(10);
1562110104Sambrisko			} else
1563108401Sambrisko				break;
1564108401Sambrisko		}
1565108401Sambrisko		if (i == AN_TIMEOUT) {
1566108401Sambrisko			printf("BUSY\n");
1567108401Sambrisko		}
1568108401Sambrisko
1569108401Sambrisko		an_rid_desc.an_valid = 1;
1570108401Sambrisko		an_rid_desc.an_len = ltv->an_len - 2;
1571108401Sambrisko		an_rid_desc.an_rid = ltv->an_type;
1572108401Sambrisko		an_rid_desc.an_phys = sc->an_rid_buffer.an_dma_paddr;
1573108401Sambrisko
1574108401Sambrisko		bcopy(&ltv->an_type, sc->an_rid_buffer.an_dma_vaddr,
1575108401Sambrisko		      an_rid_desc.an_len);
1576108401Sambrisko
1577108401Sambrisko		bzero(&cmd,sizeof(cmd));
1578108401Sambrisko		bzero(&reply,sizeof(reply));
1579108401Sambrisko		cmd.an_cmd = AN_CMD_ACCESS|AN_ACCESS_WRITE;
1580108401Sambrisko		cmd.an_parm0 = ltv->an_type;
1581108401Sambrisko
1582108401Sambrisko		for (i = 0; i < sizeof(an_rid_desc) / 4; i++)
1583175445Sambrisko			CSR_MEM_AUX_WRITE_4(sc, AN_HOST_DESC_OFFSET + i * 4,
1584155321Simp			    ((u_int32_t *)(void *)&an_rid_desc)[i]);
1585108401Sambrisko
1586110531Sambrisko		DELAY(100000);
1587110531Sambrisko
1588108401Sambrisko		if ((i = an_cmd_struct(sc, &cmd, &reply))) {
1589198987Sjhb			if_printf(sc->an_ifp,
1590198987Sjhb			    "failed to write RID 1 %x %x %x %x %x, %d\n",
1591198987Sjhb			    ltv->an_type,
1592110104Sambrisko			    reply.an_status,
1593110104Sambrisko			    reply.an_resp0,
1594110104Sambrisko			    reply.an_resp1,
1595110104Sambrisko			    reply.an_resp2,
1596110104Sambrisko			    i);
1597110104Sambrisko			return(EIO);
1598108401Sambrisko		}
159955992Swpaul
160083270Sbrooks
1601108401Sambrisko		if (reply.an_status & AN_CMD_QUAL_MASK) {
1602198987Sjhb			if_printf(sc->an_ifp,
1603198987Sjhb			    "failed to write RID 2 %x %x %x %x %x, %d\n",
1604198987Sjhb			    ltv->an_type,
1605110104Sambrisko			    reply.an_status,
1606110104Sambrisko			    reply.an_resp0,
1607110104Sambrisko			    reply.an_resp1,
1608110104Sambrisko			    reply.an_resp2,
1609110104Sambrisko			    i);
1610108401Sambrisko			return(EIO);
1611108401Sambrisko		}
1612110531Sambrisko		DELAY(100000);
161378639Sbrooks	}
161455992Swpaul
161555992Swpaul	return(0);
161655992Swpaul}
161755992Swpaul
161883270Sbrooksstatic void
1619150446Simpan_dump_record(struct an_softc *sc, struct an_ltv_gen *ltv, char *string)
162078639Sbrooks{
162178639Sbrooks	u_int8_t		*ptr2;
162278639Sbrooks	int			len;
162378639Sbrooks	int			i;
162478639Sbrooks	int			count = 0;
162578639Sbrooks	char			buf[17], temp;
162678639Sbrooks
162778639Sbrooks	len = ltv->an_len - 4;
1628198987Sjhb	if_printf(sc->an_ifp, "RID %4x, Length %4d, Mode %s\n",
1629198987Sjhb		ltv->an_type, ltv->an_len - 4, string);
163078639Sbrooks
163178639Sbrooks	if (an_dump == 1 || (an_dump == ltv->an_type)) {
1632198987Sjhb		if_printf(sc->an_ifp, "\t");
163378639Sbrooks		bzero(buf,sizeof(buf));
163478639Sbrooks
163578639Sbrooks		ptr2 = (u_int8_t *)&ltv->an_val;
163678639Sbrooks		for (i = len; i > 0; i--) {
163778639Sbrooks			printf("%02x ", *ptr2);
163878639Sbrooks
163978639Sbrooks			temp = *ptr2++;
1640154866Snjl			if (isprint(temp))
164178639Sbrooks				buf[count] = temp;
164278639Sbrooks			else
164378639Sbrooks				buf[count] = '.';
164478639Sbrooks			if (++count == 16) {
164578639Sbrooks				count = 0;
164678639Sbrooks				printf("%s\n",buf);
1647198987Sjhb				if_printf(sc->an_ifp, "\t");
164878639Sbrooks				bzero(buf,sizeof(buf));
164978639Sbrooks			}
165078639Sbrooks		}
165178639Sbrooks		for (; count != 16; count++) {
165278639Sbrooks			printf("   ");
165378639Sbrooks		}
165478639Sbrooks		printf(" %s\n",buf);
165578639Sbrooks	}
165678639Sbrooks}
165778639Sbrooks
165883270Sbrooksstatic int
1659150446Simpan_seek(struct an_softc *sc, int id, int off, int chan)
166055992Swpaul{
166155992Swpaul	int			i;
166255992Swpaul	int			selreg, offreg;
166355992Swpaul
166455992Swpaul	switch (chan) {
166555992Swpaul	case AN_BAP0:
166655992Swpaul		selreg = AN_SEL0;
166755992Swpaul		offreg = AN_OFF0;
166855992Swpaul		break;
166955992Swpaul	case AN_BAP1:
167055992Swpaul		selreg = AN_SEL1;
167155992Swpaul		offreg = AN_OFF1;
167255992Swpaul		break;
167355992Swpaul	default:
1674198987Sjhb		if_printf(sc->an_ifp, "invalid data path: %x\n", chan);
167555992Swpaul		return(EIO);
167655992Swpaul	}
167755992Swpaul
167855992Swpaul	CSR_WRITE_2(sc, selreg, id);
167955992Swpaul	CSR_WRITE_2(sc, offreg, off);
168055992Swpaul
168155992Swpaul	for (i = 0; i < AN_TIMEOUT; i++) {
168255992Swpaul		if (!(CSR_READ_2(sc, offreg) & (AN_OFF_BUSY|AN_OFF_ERR)))
168355992Swpaul			break;
168455992Swpaul	}
168555992Swpaul
168655992Swpaul	if (i == AN_TIMEOUT)
168755992Swpaul		return(ETIMEDOUT);
168855992Swpaul
168955992Swpaul	return(0);
169055992Swpaul}
169155992Swpaul
169283270Sbrooksstatic int
1693150446Simpan_read_data(struct an_softc *sc, int id, int off, caddr_t buf, int len)
169455992Swpaul{
169555992Swpaul	int			i;
169655992Swpaul	u_int16_t		*ptr;
169755992Swpaul	u_int8_t		*ptr2;
169855992Swpaul
169955992Swpaul	if (off != -1) {
170055992Swpaul		if (an_seek(sc, id, off, AN_BAP1))
170155992Swpaul			return(EIO);
170255992Swpaul	}
170355992Swpaul
170455992Swpaul	ptr = (u_int16_t *)buf;
170578639Sbrooks	for (i = len; i > 1; i -= 2)
170678639Sbrooks		*ptr++ = CSR_READ_2(sc, AN_DATA1);
170778639Sbrooks	if (i) {
170878639Sbrooks		ptr2 = (u_int8_t *)ptr;
170978639Sbrooks		*ptr2 = CSR_READ_1(sc, AN_DATA1);
171055992Swpaul	}
171155992Swpaul
171255992Swpaul	return(0);
171355992Swpaul}
171455992Swpaul
171583270Sbrooksstatic int
1716150446Simpan_write_data(struct an_softc *sc, int id, int off, caddr_t buf, int len)
171755992Swpaul{
171855992Swpaul	int			i;
171955992Swpaul	u_int16_t		*ptr;
172055992Swpaul	u_int8_t		*ptr2;
172155992Swpaul
172255992Swpaul	if (off != -1) {
172355992Swpaul		if (an_seek(sc, id, off, AN_BAP0))
172455992Swpaul			return(EIO);
172555992Swpaul	}
172655992Swpaul
172755992Swpaul	ptr = (u_int16_t *)buf;
172878639Sbrooks	for (i = len; i > 1; i -= 2)
172978639Sbrooks		CSR_WRITE_2(sc, AN_DATA0, *ptr++);
173078639Sbrooks	if (i) {
1731175446Sambrisko		ptr2 = (u_int8_t *)ptr;
1732175446Sambrisko		CSR_WRITE_1(sc, AN_DATA0, *ptr2);
173355992Swpaul	}
173455992Swpaul
173555992Swpaul	return(0);
173655992Swpaul}
173755992Swpaul
173855992Swpaul/*
173955992Swpaul * Allocate a region of memory inside the NIC and zero
174055992Swpaul * it out.
174155992Swpaul */
174283270Sbrooksstatic int
1743150446Simpan_alloc_nicmem(struct an_softc *sc, int len, int *id)
174455992Swpaul{
174555992Swpaul	int			i;
174655992Swpaul
174755992Swpaul	if (an_cmd(sc, AN_CMD_ALLOC_MEM, len)) {
1748198987Sjhb		if_printf(sc->an_ifp, "failed to allocate %d bytes on NIC\n",
1749198987Sjhb		    len);
175055992Swpaul		return(ENOMEM);
175155992Swpaul	}
175255992Swpaul
175355992Swpaul	for (i = 0; i < AN_TIMEOUT; i++) {
1754108401Sambrisko		if (CSR_READ_2(sc, AN_EVENT_STAT(sc->mpi350)) & AN_EV_ALLOC)
175555992Swpaul			break;
175655992Swpaul	}
175755992Swpaul
175855992Swpaul	if (i == AN_TIMEOUT)
175955992Swpaul		return(ETIMEDOUT);
176055992Swpaul
1761108401Sambrisko	CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_ALLOC);
176255992Swpaul	*id = CSR_READ_2(sc, AN_ALLOC_FID);
176355992Swpaul
176455992Swpaul	if (an_seek(sc, *id, 0, AN_BAP0))
176555992Swpaul		return(EIO);
176655992Swpaul
176755992Swpaul	for (i = 0; i < len / 2; i++)
176855992Swpaul		CSR_WRITE_2(sc, AN_DATA0, 0);
176955992Swpaul
177055992Swpaul	return(0);
177155992Swpaul}
177255992Swpaul
177383270Sbrooksstatic void
1774150446Simpan_setdef(struct an_softc *sc, struct an_req *areq)
177555992Swpaul{
177655992Swpaul	struct ifnet		*ifp;
177755992Swpaul	struct an_ltv_genconfig	*cfg;
1778119156Sambrisko	struct an_ltv_ssidlist_new	*ssid;
177955992Swpaul	struct an_ltv_aplist	*ap;
178055992Swpaul	struct an_ltv_gen	*sp;
178155992Swpaul
1782147256Sbrooks	ifp = sc->an_ifp;
178355992Swpaul
1784175445Sambrisko	AN_LOCK_ASSERT(sc);
178555992Swpaul	switch (areq->an_type) {
178655992Swpaul	case AN_RID_GENCONFIG:
178755992Swpaul		cfg = (struct an_ltv_genconfig *)areq;
178855992Swpaul
1789152315Sru		bcopy((char *)&cfg->an_macaddr, IF_LLADDR(sc->an_ifp),
179055992Swpaul		    ETHER_ADDR_LEN);
179155992Swpaul
179255992Swpaul		bcopy((char *)cfg, (char *)&sc->an_config,
179355992Swpaul			sizeof(struct an_ltv_genconfig));
179455992Swpaul		break;
179555992Swpaul	case AN_RID_SSIDLIST:
1796119156Sambrisko		ssid = (struct an_ltv_ssidlist_new *)areq;
179755992Swpaul		bcopy((char *)ssid, (char *)&sc->an_ssidlist,
1798119156Sambrisko			sizeof(struct an_ltv_ssidlist_new));
179955992Swpaul		break;
180055992Swpaul	case AN_RID_APLIST:
180155992Swpaul		ap = (struct an_ltv_aplist *)areq;
180255992Swpaul		bcopy((char *)ap, (char *)&sc->an_aplist,
180355992Swpaul			sizeof(struct an_ltv_aplist));
180455992Swpaul		break;
180555992Swpaul	case AN_RID_TX_SPEED:
180655992Swpaul		sp = (struct an_ltv_gen *)areq;
180755992Swpaul		sc->an_tx_rate = sp->an_val;
1808110253Sambrisko
1809110253Sambrisko		/* Read the current configuration */
1810110253Sambrisko		sc->an_config.an_type = AN_RID_GENCONFIG;
1811110253Sambrisko		sc->an_config.an_len = sizeof(struct an_ltv_genconfig);
1812110253Sambrisko		an_read_record(sc, (struct an_ltv_gen *)&sc->an_config);
1813110253Sambrisko		cfg = &sc->an_config;
1814110253Sambrisko
1815110253Sambrisko		/* clear other rates and set the only one we want */
1816110253Sambrisko		bzero(cfg->an_rates, sizeof(cfg->an_rates));
1817110253Sambrisko		cfg->an_rates[0] = sc->an_tx_rate;
1818110253Sambrisko
1819110253Sambrisko		/* Save the new rate */
1820110253Sambrisko		sc->an_config.an_type = AN_RID_GENCONFIG;
1821110253Sambrisko		sc->an_config.an_len = sizeof(struct an_ltv_genconfig);
182255992Swpaul		break;
182368692Swpaul	case AN_RID_WEP_TEMP:
1824110531Sambrisko		/* Cache the temp keys */
1825175445Sambrisko		bcopy(areq,
1826175445Sambrisko		    &sc->an_temp_keys[((struct an_ltv_key *)areq)->kindex],
1827110531Sambrisko		    sizeof(struct an_ltv_key));
182868692Swpaul	case AN_RID_WEP_PERM:
182988748Sambrisko	case AN_RID_LEAPUSERNAME:
183088748Sambrisko	case AN_RID_LEAPPASSWORD:
1831199154Sjhb		an_init_locked(sc);
1832119156Sambrisko
183368692Swpaul		/* Disable the MAC. */
183468692Swpaul		an_cmd(sc, AN_CMD_DISABLE, 0);
183583270Sbrooks
183683269Sbrooks		/* Write the key */
183768692Swpaul		an_write_record(sc, (struct an_ltv_gen *)areq);
183883270Sbrooks
183983270Sbrooks		/* Turn the MAC back on. */
184068692Swpaul		an_cmd(sc, AN_CMD_ENABLE, 0);
184183270Sbrooks
184268692Swpaul		break;
184383269Sbrooks	case AN_RID_MONITOR_MODE:
184483269Sbrooks		cfg = (struct an_ltv_genconfig *)areq;
184583269Sbrooks		bpfdetach(ifp);
184683269Sbrooks		if (ng_ether_detach_p != NULL)
184783269Sbrooks			(*ng_ether_detach_p) (ifp);
184883269Sbrooks		sc->an_monitor = cfg->an_len;
184983269Sbrooks
185083270Sbrooks		if (sc->an_monitor & AN_MONITOR) {
185183270Sbrooks			if (sc->an_monitor & AN_MONITOR_AIRONET_HEADER) {
185283270Sbrooks				bpfattach(ifp, DLT_AIRONET_HEADER,
185383269Sbrooks					sizeof(struct ether_header));
185483269Sbrooks			} else {
185583270Sbrooks				bpfattach(ifp, DLT_IEEE802_11,
185683269Sbrooks					sizeof(struct ether_header));
185783269Sbrooks			}
185883269Sbrooks		} else {
185983270Sbrooks			bpfattach(ifp, DLT_EN10MB,
186083269Sbrooks				  sizeof(struct ether_header));
186183269Sbrooks			if (ng_ether_attach_p != NULL)
186283269Sbrooks				(*ng_ether_attach_p) (ifp);
186383269Sbrooks		}
186483269Sbrooks		break;
186555992Swpaul	default:
1866198987Sjhb		if_printf(ifp, "unknown RID: %x\n", areq->an_type);
186755992Swpaul		return;
186855992Swpaul	}
186955992Swpaul
187055992Swpaul
187155992Swpaul	/* Reinitialize the card. */
1872199154Sjhb	if (ifp->if_flags)
1873199154Sjhb		an_init_locked(sc);
187455992Swpaul
187555992Swpaul	return;
187655992Swpaul}
187755992Swpaul
187855992Swpaul/*
187983269Sbrooks * Derived from Linux driver to enable promiscious mode.
188055992Swpaul */
188183269Sbrooks
188283270Sbrooksstatic void
1883150446Simpan_promisc(struct an_softc *sc, int promisc)
188455992Swpaul{
1885175445Sambrisko	AN_LOCK_ASSERT(sc);
1886150446Simp	if (sc->an_was_monitor) {
188783269Sbrooks		an_reset(sc);
1888108401Sambrisko		if (sc->mpi350)
1889175445Sambrisko			an_init_mpi350_desc(sc);
1890150446Simp	}
1891199154Sjhb	if (sc->an_monitor || sc->an_was_monitor)
1892199154Sjhb		an_init_locked(sc);
189383269Sbrooks
189483269Sbrooks	sc->an_was_monitor = sc->an_monitor;
189574698Sarchie	an_cmd(sc, AN_CMD_SET_MODE, promisc ? 0xffff : 0);
189683270Sbrooks
189755992Swpaul	return;
189855992Swpaul}
189955992Swpaul
190083270Sbrooksstatic int
1901150446Simpan_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
190255992Swpaul{
190367094Swpaul	int			error = 0;
190477217Sphk	int			len;
1905119156Sambrisko	int			i, max;
190655992Swpaul	struct an_softc		*sc;
190755992Swpaul	struct ifreq		*ifr;
190893593Sjhb	struct thread		*td = curthread;
190977217Sphk	struct ieee80211req	*ireq;
1910172112Savatar	struct ieee80211_channel	ch;
191177217Sphk	u_int8_t		tmpstr[IEEE80211_NWID_LEN*2];
191277217Sphk	u_int8_t		*tmpptr;
191377217Sphk	struct an_ltv_genconfig	*config;
191477217Sphk	struct an_ltv_key	*key;
191577217Sphk	struct an_ltv_status	*status;
1916119156Sambrisko	struct an_ltv_ssidlist_new	*ssids;
191788748Sambrisko	int			mode;
191888748Sambrisko	struct aironet_ioctl	l_ioctl;
191955992Swpaul
192055992Swpaul	sc = ifp->if_softc;
192155992Swpaul	ifr = (struct ifreq *)data;
192277217Sphk	ireq = (struct ieee80211req *)data;
192355992Swpaul
192488749Sambrisko	config = (struct an_ltv_genconfig *)&sc->areq;
192588749Sambrisko	key = (struct an_ltv_key *)&sc->areq;
192688749Sambrisko	status = (struct an_ltv_status *)&sc->areq;
1927119156Sambrisko	ssids = (struct an_ltv_ssidlist_new *)&sc->areq;
192877217Sphk
192964429Speter	if (sc->an_gone) {
193061816Sroberto		error = ENODEV;
193161816Sroberto		goto out;
193261816Sroberto	}
193355992Swpaul
193483270Sbrooks	switch (command) {
193555992Swpaul	case SIOCSIFFLAGS:
1936175445Sambrisko		AN_LOCK(sc);
193755992Swpaul		if (ifp->if_flags & IFF_UP) {
1938148887Srwatson			if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
193955992Swpaul			    ifp->if_flags & IFF_PROMISC &&
194055992Swpaul			    !(sc->an_if_flags & IFF_PROMISC)) {
194155992Swpaul				an_promisc(sc, 1);
1942148887Srwatson			} else if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
194355992Swpaul			    !(ifp->if_flags & IFF_PROMISC) &&
194455992Swpaul			    sc->an_if_flags & IFF_PROMISC) {
194555992Swpaul				an_promisc(sc, 0);
1946199154Sjhb			} else
1947199154Sjhb				an_init_locked(sc);
194855992Swpaul		} else {
1949199154Sjhb			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
195055992Swpaul				an_stop(sc);
195155992Swpaul		}
1952199154Sjhb		sc->an_if_flags = ifp->if_flags;
1953175445Sambrisko		AN_UNLOCK(sc);
195455992Swpaul		error = 0;
195555992Swpaul		break;
195677217Sphk	case SIOCSIFMEDIA:
195777217Sphk	case SIOCGIFMEDIA:
195877217Sphk		error = ifmedia_ioctl(ifp, ifr, &sc->an_ifmedia, command);
195977217Sphk		break;
196055992Swpaul	case SIOCADDMULTI:
196155992Swpaul	case SIOCDELMULTI:
196255992Swpaul		/* The Aironet has no multicast filter. */
196355992Swpaul		error = 0;
196455992Swpaul		break;
196555992Swpaul	case SIOCGAIRONET:
196688749Sambrisko		error = copyin(ifr->ifr_data, &sc->areq, sizeof(sc->areq));
196778639Sbrooks		if (error != 0)
196855992Swpaul			break;
1969175445Sambrisko		AN_LOCK(sc);
197055992Swpaul#ifdef ANCACHE
197188749Sambrisko		if (sc->areq.an_type == AN_RID_ZERO_CACHE) {
1972164033Srwatson			error = priv_check(td, PRIV_DRIVER);
1973108259Srwatson			if (error)
1974108259Srwatson				break;
197555992Swpaul			sc->an_sigitems = sc->an_nextitem = 0;
197655992Swpaul			break;
197788749Sambrisko		} else if (sc->areq.an_type == AN_RID_READ_CACHE) {
197888749Sambrisko			char *pt = (char *)&sc->areq.an_val;
197955992Swpaul			bcopy((char *)&sc->an_sigitems, (char *)pt,
198055992Swpaul			    sizeof(int));
198155992Swpaul			pt += sizeof(int);
198288749Sambrisko			sc->areq.an_len = sizeof(int) / 2;
198355992Swpaul			bcopy((char *)&sc->an_sigcache, (char *)pt,
198455992Swpaul			    sizeof(struct an_sigcache) * sc->an_sigitems);
198588749Sambrisko			sc->areq.an_len += ((sizeof(struct an_sigcache) *
198655992Swpaul			    sc->an_sigitems) / 2) + 1;
198755992Swpaul		} else
198855992Swpaul#endif
198988749Sambrisko		if (an_read_record(sc, (struct an_ltv_gen *)&sc->areq)) {
1990175445Sambrisko			AN_UNLOCK(sc);
199155992Swpaul			error = EINVAL;
199255992Swpaul			break;
199355992Swpaul		}
1994171692Savatar		AN_UNLOCK(sc);
199588749Sambrisko		error = copyout(&sc->areq, ifr->ifr_data, sizeof(sc->areq));
199655992Swpaul		break;
199755992Swpaul	case SIOCSAIRONET:
1998164033Srwatson		if ((error = priv_check(td, PRIV_DRIVER)))
199964429Speter			goto out;
2000175445Sambrisko		AN_LOCK(sc);
200188749Sambrisko		error = copyin(ifr->ifr_data, &sc->areq, sizeof(sc->areq));
200278639Sbrooks		if (error != 0)
200355992Swpaul			break;
200488749Sambrisko		an_setdef(sc, &sc->areq);
2005175445Sambrisko		AN_UNLOCK(sc);
200655992Swpaul		break;
2007175446Sambrisko	case SIOCGPRIVATE_0:		/* used by Cisco client utility */
2008164033Srwatson		if ((error = priv_check(td, PRIV_DRIVER)))
200992292Sambrisko			goto out;
2010144242Ssam		error = copyin(ifr->ifr_data, &l_ioctl, sizeof(l_ioctl));
2011144242Ssam		if (error)
2012144242Ssam			goto out;
201388748Sambrisko		mode = l_ioctl.command;
201488748Sambrisko
2015175445Sambrisko		AN_LOCK(sc);
201688748Sambrisko		if (mode >= AIROGCAP && mode <= AIROGSTATSD32) {
201788748Sambrisko			error = readrids(ifp, &l_ioctl);
2018110104Sambrisko		} else if (mode >= AIROPCAP && mode <= AIROPLEAPUSR) {
201988748Sambrisko			error = writerids(ifp, &l_ioctl);
2020110104Sambrisko		} else if (mode >= AIROFLSHRST && mode <= AIRORESTART) {
202188748Sambrisko			error = flashcard(ifp, &l_ioctl);
2022110104Sambrisko		} else {
202388748Sambrisko			error =-1;
202488748Sambrisko		}
2025175445Sambrisko		AN_UNLOCK(sc);
2026144242Ssam		if (!error) {
2027144242Ssam			/* copy out the updated command info */
2028144242Ssam			error = copyout(&l_ioctl, ifr->ifr_data, sizeof(l_ioctl));
2029144242Ssam		}
203088748Sambrisko		break;
2031175446Sambrisko	case SIOCGPRIVATE_1:		/* used by Cisco client utility */
2032164033Srwatson		if ((error = priv_check(td, PRIV_DRIVER)))
203392292Sambrisko			goto out;
2034144242Ssam		error = copyin(ifr->ifr_data, &l_ioctl, sizeof(l_ioctl));
2035144242Ssam		if (error)
2036144242Ssam			goto out;
203788748Sambrisko		l_ioctl.command = 0;
203888748Sambrisko		error = AIROMAGIC;
2039144242Ssam		(void) copyout(&error, l_ioctl.data, sizeof(error));
2040175446Sambrisko		error = 0;
204188748Sambrisko		break;
204277217Sphk	case SIOCG80211:
204388749Sambrisko		sc->areq.an_len = sizeof(sc->areq);
204488748Sambrisko		/* was that a good idea DJA we are doing a short-cut */
204583270Sbrooks		switch (ireq->i_type) {
204677217Sphk		case IEEE80211_IOC_SSID:
2047175445Sambrisko			AN_LOCK(sc);
204878639Sbrooks			if (ireq->i_val == -1) {
204988749Sambrisko				sc->areq.an_type = AN_RID_STATUS;
205077217Sphk				if (an_read_record(sc,
205188749Sambrisko				    (struct an_ltv_gen *)&sc->areq)) {
205277217Sphk					error = EINVAL;
2053175445Sambrisko					AN_UNLOCK(sc);
205477217Sphk					break;
205577217Sphk				}
205677217Sphk				len = status->an_ssidlen;
205777217Sphk				tmpptr = status->an_ssid;
205878639Sbrooks			} else if (ireq->i_val >= 0) {
205988749Sambrisko				sc->areq.an_type = AN_RID_SSIDLIST;
206077217Sphk				if (an_read_record(sc,
206188749Sambrisko				    (struct an_ltv_gen *)&sc->areq)) {
206277217Sphk					error = EINVAL;
2063175445Sambrisko					AN_UNLOCK(sc);
206477217Sphk					break;
206577217Sphk				}
2066119156Sambrisko				max = (sc->areq.an_len - 4)
2067119156Sambrisko				    / sizeof(struct an_ltv_ssid_entry);
2068119156Sambrisko				if ( max > MAX_SSIDS ) {
2069119156Sambrisko					printf("To many SSIDs only using "
2070119156Sambrisko					    "%d of %d\n",
2071119156Sambrisko					    MAX_SSIDS, max);
2072119156Sambrisko					max = MAX_SSIDS;
2073119156Sambrisko				}
2074119156Sambrisko				if (ireq->i_val > max) {
207577217Sphk					error = EINVAL;
2076175445Sambrisko					AN_UNLOCK(sc);
207777217Sphk					break;
2078119156Sambrisko				} else {
2079119156Sambrisko					len = ssids->an_entry[ireq->i_val].an_len;
2080119156Sambrisko					tmpptr = ssids->an_entry[ireq->i_val].an_ssid;
208177217Sphk				}
208277217Sphk			} else {
208377217Sphk				error = EINVAL;
2084175445Sambrisko				AN_UNLOCK(sc);
208577217Sphk				break;
208677217Sphk			}
208778639Sbrooks			if (len > IEEE80211_NWID_LEN) {
208877217Sphk				error = EINVAL;
2089175445Sambrisko				AN_UNLOCK(sc);
209077217Sphk				break;
209177217Sphk			}
2092175445Sambrisko			AN_UNLOCK(sc);
209377217Sphk			ireq->i_len = len;
209477217Sphk			bzero(tmpstr, IEEE80211_NWID_LEN);
209577217Sphk			bcopy(tmpptr, tmpstr, len);
209677217Sphk			error = copyout(tmpstr, ireq->i_data,
209777217Sphk			    IEEE80211_NWID_LEN);
209877217Sphk			break;
209977217Sphk		case IEEE80211_IOC_NUMSSIDS:
2100175445Sambrisko			AN_LOCK(sc);
2101119156Sambrisko			sc->areq.an_len = sizeof(sc->areq);
2102119156Sambrisko			sc->areq.an_type = AN_RID_SSIDLIST;
2103119156Sambrisko			if (an_read_record(sc,
2104119156Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
2105175445Sambrisko				AN_UNLOCK(sc);
2106119156Sambrisko				error = EINVAL;
2107119156Sambrisko				break;
2108119156Sambrisko			}
2109119156Sambrisko			max = (sc->areq.an_len - 4)
2110119156Sambrisko			    / sizeof(struct an_ltv_ssid_entry);
2111175445Sambrisko			AN_UNLOCK(sc);
2112119156Sambrisko			if ( max > MAX_SSIDS ) {
2113119156Sambrisko				printf("To many SSIDs only using "
2114119156Sambrisko				    "%d of %d\n",
2115119156Sambrisko				    MAX_SSIDS, max);
2116119156Sambrisko				max = MAX_SSIDS;
2117119156Sambrisko			}
2118119156Sambrisko			ireq->i_val = max;
211977217Sphk			break;
212077217Sphk		case IEEE80211_IOC_WEP:
2121175445Sambrisko			AN_LOCK(sc);
212288749Sambrisko			sc->areq.an_type = AN_RID_ACTUALCFG;
212377217Sphk			if (an_read_record(sc,
212488749Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
212577217Sphk				error = EINVAL;
2126175445Sambrisko				AN_UNLOCK(sc);
212777217Sphk				break;
212877217Sphk			}
2129175445Sambrisko			AN_UNLOCK(sc);
213078639Sbrooks			if (config->an_authtype & AN_AUTHTYPE_PRIVACY_IN_USE) {
213178639Sbrooks				if (config->an_authtype &
213277217Sphk				    AN_AUTHTYPE_ALLOW_UNENCRYPTED)
213377217Sphk					ireq->i_val = IEEE80211_WEP_MIXED;
213477217Sphk				else
213577217Sphk					ireq->i_val = IEEE80211_WEP_ON;
213677217Sphk			} else {
213777217Sphk				ireq->i_val = IEEE80211_WEP_OFF;
213877217Sphk			}
213977217Sphk			break;
214077217Sphk		case IEEE80211_IOC_WEPKEY:
214177217Sphk			/*
214277217Sphk			 * XXX: I'm not entierly convinced this is
214377217Sphk			 * correct, but it's what is implemented in
214477217Sphk			 * ancontrol so it will have to do until we get
214577217Sphk			 * access to actual Cisco code.
214677217Sphk			 */
214788748Sambrisko			if (ireq->i_val < 0 || ireq->i_val > 8) {
214877217Sphk				error = EINVAL;
214977217Sphk				break;
215077217Sphk			}
215177217Sphk			len = 0;
215288748Sambrisko			if (ireq->i_val < 5) {
2153175445Sambrisko				AN_LOCK(sc);
215488749Sambrisko				sc->areq.an_type = AN_RID_WEP_TEMP;
215578639Sbrooks				for (i = 0; i < 5; i++) {
215677217Sphk					if (an_read_record(sc,
215788749Sambrisko					    (struct an_ltv_gen *)&sc->areq)) {
215877217Sphk						error = EINVAL;
215977217Sphk						break;
216077217Sphk					}
216178639Sbrooks					if (key->kindex == 0xffff)
216277217Sphk						break;
216378639Sbrooks					if (key->kindex == ireq->i_val)
216478639Sbrooks						len = key->klen;
216577217Sphk					/* Required to get next entry */
216688749Sambrisko					sc->areq.an_type = AN_RID_WEP_PERM;
216777217Sphk				}
2168175445Sambrisko				AN_UNLOCK(sc);
2169175445Sambrisko				if (error != 0) {
217077217Sphk					break;
2171175445Sambrisko				}
217277217Sphk			}
217377217Sphk			/* We aren't allowed to read the value of the
217477217Sphk			 * key from the card so we just output zeros
217577217Sphk			 * like we would if we could read the card, but
217677217Sphk			 * denied the user access.
217777217Sphk			 */
217877217Sphk			bzero(tmpstr, len);
217977217Sphk			ireq->i_len = len;
218077217Sphk			error = copyout(tmpstr, ireq->i_data, len);
218177217Sphk			break;
218277217Sphk		case IEEE80211_IOC_NUMWEPKEYS:
218388748Sambrisko			ireq->i_val = 9; /* include home key */
218477217Sphk			break;
218577217Sphk		case IEEE80211_IOC_WEPTXKEY:
218678639Sbrooks			/*
218778639Sbrooks			 * For some strange reason, you have to read all
218878639Sbrooks			 * keys before you can read the txkey.
218978639Sbrooks			 */
2190175445Sambrisko			AN_LOCK(sc);
219188749Sambrisko			sc->areq.an_type = AN_RID_WEP_TEMP;
219278639Sbrooks			for (i = 0; i < 5; i++) {
219378639Sbrooks				if (an_read_record(sc,
219488749Sambrisko				    (struct an_ltv_gen *) &sc->areq)) {
219578639Sbrooks					error = EINVAL;
219678639Sbrooks					break;
219778639Sbrooks				}
2198175445Sambrisko				if (key->kindex == 0xffff) {
219978639Sbrooks					break;
2200175445Sambrisko				}
220178639Sbrooks				/* Required to get next entry */
220288749Sambrisko				sc->areq.an_type = AN_RID_WEP_PERM;
220378639Sbrooks			}
2204175445Sambrisko			if (error != 0) {
2205175445Sambrisko				AN_UNLOCK(sc);
220678639Sbrooks				break;
2207175445Sambrisko			}
220878639Sbrooks
220988749Sambrisko			sc->areq.an_type = AN_RID_WEP_PERM;
221077217Sphk			key->kindex = 0xffff;
221177217Sphk			if (an_read_record(sc,
221288749Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
221377217Sphk				error = EINVAL;
2214175445Sambrisko				AN_UNLOCK(sc);
221577217Sphk				break;
221677217Sphk			}
221777217Sphk			ireq->i_val = key->mac[0];
221888748Sambrisko			/*
221988748Sambrisko			 * Check for home mode.  Map home mode into
222088748Sambrisko			 * 5th key since that is how it is stored on
222188748Sambrisko			 * the card
222288748Sambrisko			 */
222388749Sambrisko			sc->areq.an_len  = sizeof(struct an_ltv_genconfig);
222488749Sambrisko			sc->areq.an_type = AN_RID_GENCONFIG;
222588748Sambrisko			if (an_read_record(sc,
222688749Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
222788748Sambrisko				error = EINVAL;
2228175445Sambrisko				AN_UNLOCK(sc);
222988748Sambrisko				break;
223088748Sambrisko			}
223188748Sambrisko			if (config->an_home_product & AN_HOME_NETWORK)
223288748Sambrisko				ireq->i_val = 4;
2233175445Sambrisko			AN_UNLOCK(sc);
223477217Sphk			break;
223577217Sphk		case IEEE80211_IOC_AUTHMODE:
2236175445Sambrisko			AN_LOCK(sc);
223788749Sambrisko			sc->areq.an_type = AN_RID_ACTUALCFG;
223877217Sphk			if (an_read_record(sc,
223988749Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
224077217Sphk				error = EINVAL;
2241175445Sambrisko				AN_UNLOCK(sc);
224277217Sphk				break;
224377217Sphk			}
2244175445Sambrisko			AN_UNLOCK(sc);
224577217Sphk			if ((config->an_authtype & AN_AUTHTYPE_MASK) ==
224677217Sphk			    AN_AUTHTYPE_NONE) {
224777217Sphk			    ireq->i_val = IEEE80211_AUTH_NONE;
224877217Sphk			} else if ((config->an_authtype & AN_AUTHTYPE_MASK) ==
224977217Sphk			    AN_AUTHTYPE_OPEN) {
225077217Sphk			    ireq->i_val = IEEE80211_AUTH_OPEN;
225177217Sphk			} else if ((config->an_authtype & AN_AUTHTYPE_MASK) ==
225277217Sphk			    AN_AUTHTYPE_SHAREDKEY) {
225377217Sphk			    ireq->i_val = IEEE80211_AUTH_SHARED;
225477217Sphk			} else
225577217Sphk				error = EINVAL;
225677217Sphk			break;
225777217Sphk		case IEEE80211_IOC_STATIONNAME:
2258175445Sambrisko			AN_LOCK(sc);
225988749Sambrisko			sc->areq.an_type = AN_RID_ACTUALCFG;
226077217Sphk			if (an_read_record(sc,
226188749Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
226277217Sphk				error = EINVAL;
2263175445Sambrisko				AN_UNLOCK(sc);
226477217Sphk				break;
226577217Sphk			}
2266175445Sambrisko			AN_UNLOCK(sc);
226777217Sphk			ireq->i_len = sizeof(config->an_nodename);
226877217Sphk			tmpptr = config->an_nodename;
226977217Sphk			bzero(tmpstr, IEEE80211_NWID_LEN);
227077217Sphk			bcopy(tmpptr, tmpstr, ireq->i_len);
227177217Sphk			error = copyout(tmpstr, ireq->i_data,
227277217Sphk			    IEEE80211_NWID_LEN);
227377217Sphk			break;
227477217Sphk		case IEEE80211_IOC_CHANNEL:
2275175445Sambrisko			AN_LOCK(sc);
227688749Sambrisko			sc->areq.an_type = AN_RID_STATUS;
227777217Sphk			if (an_read_record(sc,
227888749Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
227977217Sphk				error = EINVAL;
2280175445Sambrisko				AN_UNLOCK(sc);
228177217Sphk				break;
228277217Sphk			}
2283175445Sambrisko			AN_UNLOCK(sc);
228477217Sphk			ireq->i_val = status->an_cur_channel;
228577217Sphk			break;
2286175445Sambrisko		case IEEE80211_IOC_CURCHAN:
2287175445Sambrisko			AN_LOCK(sc);
2288175445Sambrisko			sc->areq.an_type = AN_RID_STATUS;
2289175445Sambrisko			if (an_read_record(sc,
2290175445Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
2291172112Savatar				error = EINVAL;
2292175445Sambrisko				AN_UNLOCK(sc);
2293172112Savatar				break;
2294172112Savatar			}
2295175445Sambrisko			AN_UNLOCK(sc);
2296172112Savatar			bzero(&ch, sizeof(ch));
2297172112Savatar			ch.ic_freq = ieee80211_ieee2mhz(status->an_cur_channel,
2298172112Savatar			    IEEE80211_CHAN_B);
2299172112Savatar			ch.ic_flags = IEEE80211_CHAN_B;
2300172112Savatar			ch.ic_ieee = status->an_cur_channel;
2301172112Savatar			error = copyout(&ch, ireq->i_data, sizeof(ch));
2302172112Savatar			break;
230377217Sphk		case IEEE80211_IOC_POWERSAVE:
2304175445Sambrisko			AN_LOCK(sc);
230588749Sambrisko			sc->areq.an_type = AN_RID_ACTUALCFG;
230677217Sphk			if (an_read_record(sc,
230788749Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
230877217Sphk				error = EINVAL;
2309175445Sambrisko				AN_UNLOCK(sc);
231077217Sphk				break;
231177217Sphk			}
2312175445Sambrisko			AN_UNLOCK(sc);
231378639Sbrooks			if (config->an_psave_mode == AN_PSAVE_NONE) {
231477217Sphk				ireq->i_val = IEEE80211_POWERSAVE_OFF;
231578639Sbrooks			} else if (config->an_psave_mode == AN_PSAVE_CAM) {
231677217Sphk				ireq->i_val = IEEE80211_POWERSAVE_CAM;
231778639Sbrooks			} else if (config->an_psave_mode == AN_PSAVE_PSP) {
231877217Sphk				ireq->i_val = IEEE80211_POWERSAVE_PSP;
231978639Sbrooks			} else if (config->an_psave_mode == AN_PSAVE_PSP_CAM) {
232077217Sphk				ireq->i_val = IEEE80211_POWERSAVE_PSP_CAM;
232177217Sphk			} else
232277217Sphk				error = EINVAL;
232377217Sphk			break;
232477217Sphk		case IEEE80211_IOC_POWERSAVESLEEP:
2325175445Sambrisko			AN_LOCK(sc);
232688749Sambrisko			sc->areq.an_type = AN_RID_ACTUALCFG;
232777217Sphk			if (an_read_record(sc,
232888749Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
232977217Sphk				error = EINVAL;
2330175445Sambrisko				AN_UNLOCK(sc);
233177217Sphk				break;
233277217Sphk			}
2333175445Sambrisko			AN_UNLOCK(sc);
233477217Sphk			ireq->i_val = config->an_listen_interval;
233577217Sphk			break;
233683270Sbrooks		}
233777217Sphk		break;
233877217Sphk	case SIOCS80211:
2339164033Srwatson		if ((error = priv_check(td, PRIV_NET80211_MANAGE)))
234077217Sphk			goto out;
2341175445Sambrisko		AN_LOCK(sc);
234288749Sambrisko		sc->areq.an_len = sizeof(sc->areq);
234377217Sphk		/*
234477217Sphk		 * We need a config structure for everything but the WEP
234577217Sphk		 * key management and SSIDs so we get it now so avoid
234677217Sphk		 * duplicating this code every time.
234777217Sphk		 */
234877217Sphk		if (ireq->i_type != IEEE80211_IOC_SSID &&
234977217Sphk		    ireq->i_type != IEEE80211_IOC_WEPKEY &&
235077217Sphk		    ireq->i_type != IEEE80211_IOC_WEPTXKEY) {
235188749Sambrisko			sc->areq.an_type = AN_RID_GENCONFIG;
235277217Sphk			if (an_read_record(sc,
235388749Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
235477217Sphk				error = EINVAL;
2355175445Sambrisko				AN_UNLOCK(sc);
235677217Sphk				break;
235777217Sphk			}
235877217Sphk		}
235983270Sbrooks		switch (ireq->i_type) {
236077217Sphk		case IEEE80211_IOC_SSID:
2361119156Sambrisko			sc->areq.an_len = sizeof(sc->areq);
236288749Sambrisko			sc->areq.an_type = AN_RID_SSIDLIST;
236377217Sphk			if (an_read_record(sc,
236488749Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
236577217Sphk				error = EINVAL;
2366175445Sambrisko				AN_UNLOCK(sc);
236777217Sphk				break;
236877217Sphk			}
236978639Sbrooks			if (ireq->i_len > IEEE80211_NWID_LEN) {
237077217Sphk				error = EINVAL;
2371175445Sambrisko				AN_UNLOCK(sc);
237277217Sphk				break;
237377217Sphk			}
2374119156Sambrisko			max = (sc->areq.an_len - 4)
2375119156Sambrisko			    / sizeof(struct an_ltv_ssid_entry);
2376119156Sambrisko			if ( max > MAX_SSIDS ) {
2377119156Sambrisko				printf("To many SSIDs only using "
2378119156Sambrisko				    "%d of %d\n",
2379119156Sambrisko				    MAX_SSIDS, max);
2380119156Sambrisko				max = MAX_SSIDS;
2381119156Sambrisko			}
2382119156Sambrisko			if (ireq->i_val > max) {
2383119156Sambrisko				error = EINVAL;
2384175445Sambrisko				AN_UNLOCK(sc);
238577217Sphk				break;
2386119156Sambrisko			} else {
238777217Sphk				error = copyin(ireq->i_data,
2388175445Sambrisko				    ssids->an_entry[ireq->i_val].an_ssid,
2389119156Sambrisko				    ireq->i_len);
2390175445Sambrisko				ssids->an_entry[ireq->i_val].an_len
2391119156Sambrisko				    = ireq->i_len;
2392175445Sambrisko				sc->areq.an_len = sizeof(sc->areq);
2393175445Sambrisko				sc->areq.an_type = AN_RID_SSIDLIST;
2394175445Sambrisko				an_setdef(sc, &sc->areq);
2395175445Sambrisko				AN_UNLOCK(sc);
239677217Sphk				break;
239777217Sphk			}
239877217Sphk			break;
239977217Sphk		case IEEE80211_IOC_WEP:
240077217Sphk			switch (ireq->i_val) {
240177217Sphk			case IEEE80211_WEP_OFF:
240277217Sphk				config->an_authtype &=
240377217Sphk				    ~(AN_AUTHTYPE_PRIVACY_IN_USE |
240477217Sphk				    AN_AUTHTYPE_ALLOW_UNENCRYPTED);
240577217Sphk				break;
240677217Sphk			case IEEE80211_WEP_ON:
240777217Sphk				config->an_authtype |=
240877217Sphk				    AN_AUTHTYPE_PRIVACY_IN_USE;
240977217Sphk				config->an_authtype &=
241077217Sphk				    ~AN_AUTHTYPE_ALLOW_UNENCRYPTED;
241177217Sphk				break;
241277217Sphk			case IEEE80211_WEP_MIXED:
241377217Sphk				config->an_authtype |=
241477217Sphk				    AN_AUTHTYPE_PRIVACY_IN_USE |
241577217Sphk				    AN_AUTHTYPE_ALLOW_UNENCRYPTED;
241677217Sphk				break;
241777217Sphk			default:
241877217Sphk				error = EINVAL;
241977217Sphk				break;
242077217Sphk			}
2421175445Sambrisko			if (error != EINVAL)
2422175445Sambrisko				an_setdef(sc, &sc->areq);
2423175445Sambrisko			AN_UNLOCK(sc);
242477217Sphk			break;
242577217Sphk		case IEEE80211_IOC_WEPKEY:
2426110531Sambrisko			if (ireq->i_val < 0 || ireq->i_val > 8 ||
242777217Sphk			    ireq->i_len > 13) {
242877217Sphk				error = EINVAL;
2429175445Sambrisko				AN_UNLOCK(sc);
243077217Sphk				break;
243177217Sphk			}
243277217Sphk			error = copyin(ireq->i_data, tmpstr, 13);
2433175445Sambrisko			if (error != 0) {
2434175445Sambrisko				AN_UNLOCK(sc);
243577217Sphk				break;
2436175445Sambrisko			}
2437110531Sambrisko			/*
2438110531Sambrisko			 * Map the 9th key into the home mode
2439110531Sambrisko			 * since that is how it is stored on
2440110531Sambrisko			 * the card
2441110531Sambrisko			 */
244288749Sambrisko			bzero(&sc->areq, sizeof(struct an_ltv_key));
244388749Sambrisko			sc->areq.an_len = sizeof(struct an_ltv_key);
244477217Sphk			key->mac[0] = 1;	/* The others are 0. */
2445110531Sambrisko			if (ireq->i_val < 4) {
244688749Sambrisko				sc->areq.an_type = AN_RID_WEP_TEMP;
2447110531Sambrisko				key->kindex = ireq->i_val;
2448110531Sambrisko			} else {
244988749Sambrisko				sc->areq.an_type = AN_RID_WEP_PERM;
2450110531Sambrisko				key->kindex = ireq->i_val - 4;
2451110531Sambrisko			}
245277217Sphk			key->klen = ireq->i_len;
245377217Sphk			bcopy(tmpstr, key->key, key->klen);
2454175445Sambrisko			an_setdef(sc, &sc->areq);
2455175445Sambrisko			AN_UNLOCK(sc);
245677217Sphk			break;
245777217Sphk		case IEEE80211_IOC_WEPTXKEY:
2458110531Sambrisko			if (ireq->i_val < 0 || ireq->i_val > 4) {
2459110531Sambrisko				error = EINVAL;
2460175445Sambrisko				AN_UNLOCK(sc);
2461110531Sambrisko				break;
2462110531Sambrisko			}
2463110531Sambrisko
246488748Sambrisko			/*
246588748Sambrisko			 * Map the 5th key into the home mode
246688748Sambrisko			 * since that is how it is stored on
246788748Sambrisko			 * the card
246888748Sambrisko			 */
246988749Sambrisko			sc->areq.an_len  = sizeof(struct an_ltv_genconfig);
247088749Sambrisko			sc->areq.an_type = AN_RID_ACTUALCFG;
247188748Sambrisko			if (an_read_record(sc,
2472175445Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
2473175445Sambrisko				error = EINVAL;
2474175445Sambrisko				AN_UNLOCK(sc);
247588748Sambrisko				break;
247688748Sambrisko			}
247788748Sambrisko			if (ireq->i_val ==  4) {
247888748Sambrisko				config->an_home_product |= AN_HOME_NETWORK;
247988748Sambrisko				ireq->i_val = 0;
248088748Sambrisko			} else {
248188748Sambrisko				config->an_home_product &= ~AN_HOME_NETWORK;
248288748Sambrisko			}
248388748Sambrisko
248488748Sambrisko			sc->an_config.an_home_product
248588748Sambrisko				= config->an_home_product;
248688748Sambrisko
2487110531Sambrisko			/* update configuration */
2488199154Sjhb			an_init_locked(sc);
2489110531Sambrisko
249088749Sambrisko			bzero(&sc->areq, sizeof(struct an_ltv_key));
249188749Sambrisko			sc->areq.an_len = sizeof(struct an_ltv_key);
249288749Sambrisko			sc->areq.an_type = AN_RID_WEP_PERM;
249377217Sphk			key->kindex = 0xffff;
249477217Sphk			key->mac[0] = ireq->i_val;
2495175445Sambrisko			an_setdef(sc, &sc->areq);
2496175445Sambrisko			AN_UNLOCK(sc);
249777217Sphk			break;
249877217Sphk		case IEEE80211_IOC_AUTHMODE:
249977217Sphk			switch (ireq->i_val) {
250077217Sphk			case IEEE80211_AUTH_NONE:
250177217Sphk				config->an_authtype = AN_AUTHTYPE_NONE |
250277217Sphk				    (config->an_authtype & ~AN_AUTHTYPE_MASK);
250377217Sphk				break;
250477217Sphk			case IEEE80211_AUTH_OPEN:
250577217Sphk				config->an_authtype = AN_AUTHTYPE_OPEN |
250677217Sphk				    (config->an_authtype & ~AN_AUTHTYPE_MASK);
250777217Sphk				break;
250877217Sphk			case IEEE80211_AUTH_SHARED:
250977217Sphk				config->an_authtype = AN_AUTHTYPE_SHAREDKEY |
251077217Sphk				    (config->an_authtype & ~AN_AUTHTYPE_MASK);
251177217Sphk				break;
251277217Sphk			default:
251377217Sphk				error = EINVAL;
251477217Sphk			}
2515175445Sambrisko			if (error != EINVAL) {
2516175445Sambrisko				an_setdef(sc, &sc->areq);
2517175445Sambrisko			}
2518175445Sambrisko			AN_UNLOCK(sc);
251977217Sphk			break;
252077217Sphk		case IEEE80211_IOC_STATIONNAME:
252178639Sbrooks			if (ireq->i_len > 16) {
252277217Sphk				error = EINVAL;
2523175445Sambrisko				AN_UNLOCK(sc);
252477217Sphk				break;
252577217Sphk			}
252677217Sphk			bzero(config->an_nodename, 16);
252777217Sphk			error = copyin(ireq->i_data,
252877217Sphk			    config->an_nodename, ireq->i_len);
2529175445Sambrisko			an_setdef(sc, &sc->areq);
2530175445Sambrisko			AN_UNLOCK(sc);
253177217Sphk			break;
253277217Sphk		case IEEE80211_IOC_CHANNEL:
253377217Sphk			/*
253477217Sphk			 * The actual range is 1-14, but if you set it
253577217Sphk			 * to 0 you get the default so we let that work
253677217Sphk			 * too.
253777217Sphk			 */
253877217Sphk			if (ireq->i_val < 0 || ireq->i_val >14) {
253977217Sphk				error = EINVAL;
2540175445Sambrisko				AN_UNLOCK(sc);
254177217Sphk				break;
254277217Sphk			}
254377217Sphk			config->an_ds_channel = ireq->i_val;
2544175445Sambrisko			an_setdef(sc, &sc->areq);
2545175445Sambrisko			AN_UNLOCK(sc);
254677217Sphk			break;
254777217Sphk		case IEEE80211_IOC_POWERSAVE:
254877217Sphk			switch (ireq->i_val) {
254977217Sphk			case IEEE80211_POWERSAVE_OFF:
255077217Sphk				config->an_psave_mode = AN_PSAVE_NONE;
255177217Sphk				break;
255277217Sphk			case IEEE80211_POWERSAVE_CAM:
255377217Sphk				config->an_psave_mode = AN_PSAVE_CAM;
255477217Sphk				break;
255577217Sphk			case IEEE80211_POWERSAVE_PSP:
255677217Sphk				config->an_psave_mode = AN_PSAVE_PSP;
255777217Sphk				break;
255877217Sphk			case IEEE80211_POWERSAVE_PSP_CAM:
255977217Sphk				config->an_psave_mode = AN_PSAVE_PSP_CAM;
256077217Sphk				break;
256177217Sphk			default:
256277217Sphk				error = EINVAL;
256377217Sphk				break;
256477217Sphk			}
2565175445Sambrisko			an_setdef(sc, &sc->areq);
2566175445Sambrisko			AN_UNLOCK(sc);
256777217Sphk			break;
256877217Sphk		case IEEE80211_IOC_POWERSAVESLEEP:
256977217Sphk			config->an_listen_interval = ireq->i_val;
2570175445Sambrisko			an_setdef(sc, &sc->areq);
2571175445Sambrisko			AN_UNLOCK(sc);
257277217Sphk			break;
2573199154Sjhb		default:
2574199154Sjhb			AN_UNLOCK(sc);
2575199154Sjhb			break;
257677217Sphk		}
257777217Sphk
2578175445Sambrisko		/*
2579175445Sambrisko		if (!error) {
2580175445Sambrisko			AN_LOCK(sc);
258188749Sambrisko			an_setdef(sc, &sc->areq);
2582175445Sambrisko			AN_UNLOCK(sc);
2583175445Sambrisko		}
2584175445Sambrisko		*/
258577217Sphk		break;
258655992Swpaul	default:
2587106937Ssam		error = ether_ioctl(ifp, command, data);
258855992Swpaul		break;
258955992Swpaul	}
259061816Srobertoout:
259155992Swpaul
259278639Sbrooks	return(error != 0);
259355992Swpaul}
259455992Swpaul
259583270Sbrooksstatic int
2596150446Simpan_init_tx_ring(struct an_softc *sc)
259755992Swpaul{
259855992Swpaul	int			i;
259955992Swpaul	int			id;
260055992Swpaul
260155992Swpaul	if (sc->an_gone)
260255992Swpaul		return (0);
260355992Swpaul
2604108401Sambrisko	if (!sc->mpi350) {
2605108401Sambrisko		for (i = 0; i < AN_TX_RING_CNT; i++) {
2606108401Sambrisko			if (an_alloc_nicmem(sc, 1518 +
2607108401Sambrisko			    0x44, &id))
2608108401Sambrisko				return(ENOMEM);
2609108401Sambrisko			sc->an_rdata.an_tx_fids[i] = id;
2610108401Sambrisko			sc->an_rdata.an_tx_ring[i] = 0;
2611108401Sambrisko		}
261255992Swpaul	}
261355992Swpaul
261455992Swpaul	sc->an_rdata.an_tx_prod = 0;
261555992Swpaul	sc->an_rdata.an_tx_cons = 0;
2616108401Sambrisko	sc->an_rdata.an_tx_empty = 1;
261755992Swpaul
261855992Swpaul	return(0);
261955992Swpaul}
262055992Swpaul
262183270Sbrooksstatic void
2622150446Simpan_init(void *xsc)
262355992Swpaul{
262455992Swpaul	struct an_softc		*sc = xsc;
262555992Swpaul
262667094Swpaul	AN_LOCK(sc);
2627199154Sjhb	an_init_locked(sc);
2628199154Sjhb	AN_UNLOCK(sc);
2629199154Sjhb}
263067094Swpaul
2631199154Sjhbstatic void
2632199154Sjhban_init_locked(struct an_softc *sc)
2633199154Sjhb{
2634199154Sjhb	struct ifnet *ifp;
2635199154Sjhb
2636199154Sjhb	AN_LOCK_ASSERT(sc);
2637199154Sjhb	ifp = sc->an_ifp;
2638199154Sjhb	if (sc->an_gone)
263955992Swpaul		return;
264055992Swpaul
2641148887Srwatson	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
264255992Swpaul		an_stop(sc);
264355992Swpaul
264455992Swpaul	sc->an_associated = 0;
264555992Swpaul
264655992Swpaul	/* Allocate the TX buffers */
264755992Swpaul	if (an_init_tx_ring(sc)) {
264855992Swpaul		an_reset(sc);
2649108401Sambrisko		if (sc->mpi350)
2650175445Sambrisko			an_init_mpi350_desc(sc);
265155992Swpaul		if (an_init_tx_ring(sc)) {
2652198987Sjhb			if_printf(ifp, "tx buffer allocation failed\n");
265355992Swpaul			return;
265455992Swpaul		}
265555992Swpaul	}
265655992Swpaul
265755992Swpaul	/* Set our MAC address. */
2658152315Sru	bcopy((char *)IF_LLADDR(sc->an_ifp),
265955992Swpaul	    (char *)&sc->an_config.an_macaddr, ETHER_ADDR_LEN);
266055992Swpaul
266155992Swpaul	if (ifp->if_flags & IFF_BROADCAST)
266255992Swpaul		sc->an_config.an_rxmode = AN_RXMODE_BC_ADDR;
266355992Swpaul	else
266455992Swpaul		sc->an_config.an_rxmode = AN_RXMODE_ADDR;
266555992Swpaul
266655992Swpaul	if (ifp->if_flags & IFF_MULTICAST)
266755992Swpaul		sc->an_config.an_rxmode = AN_RXMODE_BC_MC_ADDR;
266855992Swpaul
266983269Sbrooks	if (ifp->if_flags & IFF_PROMISC) {
267083269Sbrooks		if (sc->an_monitor & AN_MONITOR) {
267183269Sbrooks			if (sc->an_monitor & AN_MONITOR_ANY_BSS) {
267283269Sbrooks				sc->an_config.an_rxmode |=
267383269Sbrooks				    AN_RXMODE_80211_MONITOR_ANYBSS |
267483269Sbrooks				    AN_RXMODE_NO_8023_HEADER;
267583269Sbrooks			} else {
267683269Sbrooks				sc->an_config.an_rxmode |=
267783269Sbrooks				    AN_RXMODE_80211_MONITOR_CURBSS |
267883269Sbrooks				    AN_RXMODE_NO_8023_HEADER;
267983269Sbrooks			}
268083269Sbrooks		}
268183269Sbrooks	}
268255992Swpaul
2683184708Sbz#ifdef ANCACHE
2684108401Sambrisko	if (sc->an_have_rssimap)
2685108401Sambrisko		sc->an_config.an_rxmode |= AN_RXMODE_NORMALIZED_RSSI;
2686184708Sbz#endif
2687108401Sambrisko
268855992Swpaul	/* Set the ssid list */
268955992Swpaul	sc->an_ssidlist.an_type = AN_RID_SSIDLIST;
2690119156Sambrisko	sc->an_ssidlist.an_len = sizeof(struct an_ltv_ssidlist_new);
269155992Swpaul	if (an_write_record(sc, (struct an_ltv_gen *)&sc->an_ssidlist)) {
2692198987Sjhb		if_printf(ifp, "failed to set ssid list\n");
269355992Swpaul		return;
269455992Swpaul	}
269555992Swpaul
269655992Swpaul	/* Set the AP list */
269755992Swpaul	sc->an_aplist.an_type = AN_RID_APLIST;
269855992Swpaul	sc->an_aplist.an_len = sizeof(struct an_ltv_aplist);
269955992Swpaul	if (an_write_record(sc, (struct an_ltv_gen *)&sc->an_aplist)) {
2700198987Sjhb		if_printf(ifp, "failed to set AP list\n");
270155992Swpaul		return;
270255992Swpaul	}
270355992Swpaul
270455992Swpaul	/* Set the configuration in the NIC */
270555992Swpaul	sc->an_config.an_len = sizeof(struct an_ltv_genconfig);
270655992Swpaul	sc->an_config.an_type = AN_RID_GENCONFIG;
270755992Swpaul	if (an_write_record(sc, (struct an_ltv_gen *)&sc->an_config)) {
2708198987Sjhb		if_printf(ifp, "failed to set configuration\n");
270955992Swpaul		return;
271055992Swpaul	}
271155992Swpaul
271255992Swpaul	/* Enable the MAC */
271355992Swpaul	if (an_cmd(sc, AN_CMD_ENABLE, 0)) {
2714198987Sjhb		if_printf(ifp, "failed to enable MAC\n");
271555992Swpaul		return;
271655992Swpaul	}
271755992Swpaul
271874698Sarchie	if (ifp->if_flags & IFF_PROMISC)
271974698Sarchie		an_cmd(sc, AN_CMD_SET_MODE, 0xffff);
272074698Sarchie
272155992Swpaul	/* enable interrupts */
2722119156Sambrisko	CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), AN_INTRS(sc->mpi350));
272355992Swpaul
2724148887Srwatson	ifp->if_drv_flags |= IFF_DRV_RUNNING;
2725148887Srwatson	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
272655992Swpaul
2727173668Savatar	callout_reset(&sc->an_stat_ch, hz, an_stats_update, sc);
272855992Swpaul
272955992Swpaul	return;
273055992Swpaul}
273155992Swpaul
273283270Sbrooksstatic void
2733150446Simpan_start(struct ifnet *ifp)
273455992Swpaul{
273555992Swpaul	struct an_softc		*sc;
2736199154Sjhb
2737199154Sjhb	sc = ifp->if_softc;
2738199154Sjhb	AN_LOCK(sc);
2739199154Sjhb	an_start_locked(ifp);
2740199154Sjhb	AN_UNLOCK(sc);
2741199154Sjhb}
2742199154Sjhb
2743199154Sjhbstatic void
2744199154Sjhban_start_locked(struct ifnet *ifp)
2745199154Sjhb{
2746199154Sjhb	struct an_softc		*sc;
274755992Swpaul	struct mbuf		*m0 = NULL;
274855992Swpaul	struct an_txframe_802_3	tx_frame_802_3;
274955992Swpaul	struct ether_header	*eh;
2750108401Sambrisko	int			id, idx, i;
2751175446Sambrisko	unsigned char		txcontrol;
2752108401Sambrisko	struct an_card_tx_desc an_tx_desc;
2753108401Sambrisko	u_int8_t		*buf;
275455992Swpaul
275555992Swpaul	sc = ifp->if_softc;
275655992Swpaul
2757199154Sjhb	AN_LOCK_ASSERT(sc);
275855992Swpaul	if (sc->an_gone)
275955992Swpaul		return;
276055992Swpaul
2761148887Srwatson	if (ifp->if_drv_flags & IFF_DRV_OACTIVE)
276255992Swpaul		return;
276355992Swpaul
276455992Swpaul	if (!sc->an_associated)
276555992Swpaul		return;
276655992Swpaul
276790990Sbrooks	/* We can't send in monitor mode so toss any attempts. */
276883269Sbrooks	if (sc->an_monitor && (ifp->if_flags & IFF_PROMISC)) {
276983270Sbrooks		for (;;) {
2770132986Smlaier			IFQ_DRV_DEQUEUE(&ifp->if_snd, m0);
277183269Sbrooks			if (m0 == NULL)
277283269Sbrooks				break;
277390990Sbrooks			m_freem(m0);
277483269Sbrooks		}
277583269Sbrooks		return;
277683269Sbrooks	}
277783269Sbrooks
277855992Swpaul	idx = sc->an_rdata.an_tx_prod;
277955992Swpaul
2780108401Sambrisko	if (!sc->mpi350) {
2781108401Sambrisko		bzero((char *)&tx_frame_802_3, sizeof(tx_frame_802_3));
278255992Swpaul
2783108401Sambrisko		while (sc->an_rdata.an_tx_ring[idx] == 0) {
2784132986Smlaier			IFQ_DRV_DEQUEUE(&ifp->if_snd, m0);
2785108401Sambrisko			if (m0 == NULL)
2786108401Sambrisko				break;
278755992Swpaul
2788108401Sambrisko			id = sc->an_rdata.an_tx_fids[idx];
2789108401Sambrisko			eh = mtod(m0, struct ether_header *);
279083270Sbrooks
2791108401Sambrisko			bcopy((char *)&eh->ether_dhost,
2792175445Sambrisko			      (char *)&tx_frame_802_3.an_tx_dst_addr,
2793108401Sambrisko			      ETHER_ADDR_LEN);
2794108401Sambrisko			bcopy((char *)&eh->ether_shost,
2795175445Sambrisko			      (char *)&tx_frame_802_3.an_tx_src_addr,
2796108401Sambrisko			      ETHER_ADDR_LEN);
279755992Swpaul
2798108401Sambrisko			/* minus src/dest mac & type */
2799108401Sambrisko			tx_frame_802_3.an_tx_802_3_payload_len =
2800175445Sambrisko				m0->m_pkthdr.len - 12;
280155992Swpaul
2802108401Sambrisko			m_copydata(m0, sizeof(struct ether_header) - 2 ,
2803108401Sambrisko				   tx_frame_802_3.an_tx_802_3_payload_len,
2804108401Sambrisko				   (caddr_t)&sc->an_txbuf);
2805108401Sambrisko
2806108401Sambrisko			txcontrol = AN_TXCTL_8023;
2807108401Sambrisko			/* write the txcontrol only */
2808108401Sambrisko			an_write_data(sc, id, 0x08, (caddr_t)&txcontrol,
2809108401Sambrisko				      sizeof(txcontrol));
2810108401Sambrisko
2811108401Sambrisko			/* 802_3 header */
2812108401Sambrisko			an_write_data(sc, id, 0x34, (caddr_t)&tx_frame_802_3,
2813108401Sambrisko				      sizeof(struct an_txframe_802_3));
2814108401Sambrisko
2815108401Sambrisko			/* in mbuf header type is just before payload */
2816108401Sambrisko			an_write_data(sc, id, 0x44, (caddr_t)&sc->an_txbuf,
2817108401Sambrisko				      tx_frame_802_3.an_tx_802_3_payload_len);
2818108401Sambrisko
2819108401Sambrisko			/*
2820108401Sambrisko			 * If there's a BPF listner, bounce a copy of
2821108401Sambrisko			 * this frame to him.
2822108401Sambrisko			 */
2823108401Sambrisko			BPF_MTAP(ifp, m0);
2824108401Sambrisko
2825108401Sambrisko			m_freem(m0);
2826108401Sambrisko			m0 = NULL;
2827108401Sambrisko
2828108401Sambrisko			sc->an_rdata.an_tx_ring[idx] = id;
2829108401Sambrisko			if (an_cmd(sc, AN_CMD_TX, id))
2830198987Sjhb				if_printf(ifp, "xmit failed\n");
2831108401Sambrisko
2832108401Sambrisko			AN_INC(idx, AN_TX_RING_CNT);
2833119156Sambrisko
2834119156Sambrisko			/*
2835119156Sambrisko			 * Set a timeout in case the chip goes out to lunch.
2836119156Sambrisko			 */
2837199154Sjhb			sc->an_timer = 5;
2838108401Sambrisko		}
2839108401Sambrisko	} else { /* MPI-350 */
2840130620Sambrisko		/* Disable interrupts. */
2841130620Sambrisko		CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), 0);
2842130620Sambrisko
2843108401Sambrisko		while (sc->an_rdata.an_tx_empty ||
2844108401Sambrisko		    idx != sc->an_rdata.an_tx_cons) {
2845132986Smlaier			IFQ_DRV_DEQUEUE(&ifp->if_snd, m0);
2846108401Sambrisko			if (m0 == NULL) {
2847108401Sambrisko				break;
2848108401Sambrisko			}
2849108401Sambrisko			buf = sc->an_tx_buffer[idx].an_dma_vaddr;
2850108401Sambrisko
2851108401Sambrisko			eh = mtod(m0, struct ether_header *);
2852108401Sambrisko
2853108401Sambrisko			/* DJA optimize this to limit bcopy */
2854108401Sambrisko			bcopy((char *)&eh->ether_dhost,
2855175445Sambrisko			      (char *)&tx_frame_802_3.an_tx_dst_addr,
2856108401Sambrisko			      ETHER_ADDR_LEN);
2857108401Sambrisko			bcopy((char *)&eh->ether_shost,
2858175445Sambrisko			      (char *)&tx_frame_802_3.an_tx_src_addr,
2859108401Sambrisko			      ETHER_ADDR_LEN);
2860108401Sambrisko
2861108401Sambrisko			/* minus src/dest mac & type */
2862108401Sambrisko			tx_frame_802_3.an_tx_802_3_payload_len =
2863175445Sambrisko				m0->m_pkthdr.len - 12;
2864108401Sambrisko
2865108401Sambrisko			m_copydata(m0, sizeof(struct ether_header) - 2 ,
2866108401Sambrisko				   tx_frame_802_3.an_tx_802_3_payload_len,
2867108401Sambrisko				   (caddr_t)&sc->an_txbuf);
2868108401Sambrisko
2869108401Sambrisko			txcontrol = AN_TXCTL_8023;
2870108401Sambrisko			/* write the txcontrol only */
2871108401Sambrisko			bcopy((caddr_t)&txcontrol, &buf[0x08],
287255992Swpaul			      sizeof(txcontrol));
287383270Sbrooks
2874108401Sambrisko			/* 802_3 header */
2875108401Sambrisko			bcopy((caddr_t)&tx_frame_802_3, &buf[0x34],
287655992Swpaul			      sizeof(struct an_txframe_802_3));
287783270Sbrooks
2878108401Sambrisko			/* in mbuf header type is just before payload */
2879108401Sambrisko			bcopy((caddr_t)&sc->an_txbuf, &buf[0x44],
2880108401Sambrisko			      tx_frame_802_3.an_tx_802_3_payload_len);
288183270Sbrooks
288255992Swpaul
2883108401Sambrisko			bzero(&an_tx_desc, sizeof(an_tx_desc));
2884108401Sambrisko			an_tx_desc.an_offset = 0;
2885108401Sambrisko			an_tx_desc.an_eoc = 1;
2886108401Sambrisko			an_tx_desc.an_valid = 1;
2887108401Sambrisko			an_tx_desc.an_len =  0x44 +
2888119156Sambrisko			    tx_frame_802_3.an_tx_802_3_payload_len;
2889175445Sambrisko			an_tx_desc.an_phys
2890119156Sambrisko			    = sc->an_tx_buffer[idx].an_dma_paddr;
2891119156Sambrisko			for (i = 0; i < sizeof(an_tx_desc) / 4 ; i++) {
2892119156Sambrisko				CSR_MEM_AUX_WRITE_4(sc, AN_TX_DESC_OFFSET
2893175445Sambrisko				    /* zero for now */
2894119156Sambrisko				    + (0 * sizeof(an_tx_desc))
2895119156Sambrisko				    + (i * 4),
2896155321Simp				    ((u_int32_t *)(void *)&an_tx_desc)[i]);
2897108401Sambrisko			}
289855992Swpaul
2899108401Sambrisko			/*
2900108401Sambrisko			 * If there's a BPF listner, bounce a copy of
2901108401Sambrisko			 * this frame to him.
2902108401Sambrisko			 */
2903108401Sambrisko			BPF_MTAP(ifp, m0);
290455992Swpaul
2905108401Sambrisko			m_freem(m0);
2906108401Sambrisko			m0 = NULL;
2907119156Sambrisko			AN_INC(idx, AN_MAX_TX_DESC);
2908119156Sambrisko			sc->an_rdata.an_tx_empty = 0;
2909108401Sambrisko			CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_ALLOC);
2910108401Sambrisko
2911119156Sambrisko			/*
2912119156Sambrisko			 * Set a timeout in case the chip goes out to lunch.
2913119156Sambrisko			 */
2914199154Sjhb			sc->an_timer = 5;
2915108401Sambrisko		}
2916130620Sambrisko
2917130620Sambrisko		/* Re-enable interrupts. */
2918130620Sambrisko		CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), AN_INTRS(sc->mpi350));
291955992Swpaul	}
292055992Swpaul
292155992Swpaul	if (m0 != NULL)
2922148887Srwatson		ifp->if_drv_flags |= IFF_DRV_OACTIVE;
292355992Swpaul
292455992Swpaul	sc->an_rdata.an_tx_prod = idx;
292555992Swpaul
292655992Swpaul	return;
292755992Swpaul}
292855992Swpaul
292983270Sbrooksvoid
2930150446Simpan_stop(struct an_softc *sc)
293155992Swpaul{
293255992Swpaul	struct ifnet		*ifp;
293355992Swpaul	int			i;
293455992Swpaul
2935199154Sjhb	AN_LOCK_ASSERT(sc);
293667094Swpaul
2937199154Sjhb	if (sc->an_gone)
293855992Swpaul		return;
293955992Swpaul
2940147256Sbrooks	ifp = sc->an_ifp;
294155992Swpaul
294255992Swpaul	an_cmd(sc, AN_CMD_FORCE_SYNCLOSS, 0);
2943108401Sambrisko	CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), 0);
294455992Swpaul	an_cmd(sc, AN_CMD_DISABLE, 0);
294555992Swpaul
294655992Swpaul	for (i = 0; i < AN_TX_RING_CNT; i++)
294755992Swpaul		an_cmd(sc, AN_CMD_DEALLOC_MEM, sc->an_rdata.an_tx_fids[i]);
294855992Swpaul
2949173668Savatar	callout_stop(&sc->an_stat_ch);
295055992Swpaul
2951148887Srwatson	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING|IFF_DRV_OACTIVE);
295255992Swpaul
2953108401Sambrisko	if (sc->an_flash_buffer) {
2954108401Sambrisko		free(sc->an_flash_buffer, M_DEVBUF);
2955108401Sambrisko		sc->an_flash_buffer = NULL;
2956108401Sambrisko	}
295755992Swpaul}
295855992Swpaul
295983270Sbrooksstatic void
2960199154Sjhban_watchdog(struct an_softc *sc)
296155992Swpaul{
2962199154Sjhb	struct ifnet *ifp;
296355992Swpaul
2964199154Sjhb	AN_LOCK_ASSERT(sc);
296555992Swpaul
2966199154Sjhb	if (sc->an_gone)
296755992Swpaul		return;
296855992Swpaul
2969199154Sjhb	ifp = sc->an_ifp;
2970198987Sjhb	if_printf(ifp, "device timeout\n");
297155992Swpaul
297255992Swpaul	an_reset(sc);
2973108401Sambrisko	if (sc->mpi350)
2974175445Sambrisko		an_init_mpi350_desc(sc);
2975199154Sjhb	an_init_locked(sc);
297655992Swpaul
297755992Swpaul	ifp->if_oerrors++;
297855992Swpaul}
297955992Swpaul
2980188128Simpint
2981150446Simpan_shutdown(device_t dev)
298255992Swpaul{
298355992Swpaul	struct an_softc		*sc;
298455992Swpaul
298555992Swpaul	sc = device_get_softc(dev);
2986199154Sjhb	AN_LOCK(sc);
298755992Swpaul	an_stop(sc);
2988110531Sambrisko	sc->an_gone = 1;
2989199154Sjhb	AN_UNLOCK(sc);
299055992Swpaul
2991199154Sjhb	return (0);
299255992Swpaul}
299355992Swpaul
2994110362Sambriskovoid
2995150446Simpan_resume(device_t dev)
2996110362Sambrisko{
2997110362Sambrisko	struct an_softc		*sc;
2998110362Sambrisko	struct ifnet		*ifp;
2999110531Sambrisko	int			i;
3000110531Sambrisko
3001110362Sambrisko	sc = device_get_softc(dev);
3002110531Sambrisko	AN_LOCK(sc);
3003147256Sbrooks	ifp = sc->an_ifp;
3004110362Sambrisko
3005110531Sambrisko	sc->an_gone = 0;
3006110362Sambrisko	an_reset(sc);
3007110362Sambrisko	if (sc->mpi350)
3008175445Sambrisko		an_init_mpi350_desc(sc);
3009199154Sjhb	an_init_locked(sc);
3010110362Sambrisko
3011110531Sambrisko	/* Recovery temporary keys */
3012110531Sambrisko	for (i = 0; i < 4; i++) {
3013110531Sambrisko		sc->areq.an_type = AN_RID_WEP_TEMP;
3014175445Sambrisko		sc->areq.an_len = sizeof(struct an_ltv_key);
3015110531Sambrisko		bcopy(&sc->an_temp_keys[i],
3016110531Sambrisko		    &sc->areq, sizeof(struct an_ltv_key));
3017110531Sambrisko		an_setdef(sc, &sc->areq);
3018110531Sambrisko	}
3019110531Sambrisko
3020110362Sambrisko	if (ifp->if_flags & IFF_UP)
3021199154Sjhb		an_start_locked(ifp);
3022110531Sambrisko	AN_UNLOCK(sc);
3023110362Sambrisko
3024110362Sambrisko	return;
3025110362Sambrisko}
3026110362Sambrisko
302755992Swpaul#ifdef ANCACHE
302855992Swpaul/* Aironet signal strength cache code.
302955992Swpaul * store signal/noise/quality on per MAC src basis in
303055992Swpaul * a small fixed cache.  The cache wraps if > MAX slots
303155992Swpaul * used.  The cache may be zeroed out to start over.
303255992Swpaul * Two simple filters exist to reduce computation:
303388748Sambrisko * 1. ip only (literally 0x800, ETHERTYPE_IP) which may be used
303455992Swpaul * to ignore some packets.  It defaults to ip only.
303555992Swpaul * it could be used to focus on broadcast, non-IP 802.11 beacons.
303655992Swpaul * 2. multicast/broadcast only.  This may be used to
303755992Swpaul * ignore unicast packets and only cache signal strength
303855992Swpaul * for multicast/broadcast packets (beacons); e.g., Mobile-IP
303955992Swpaul * beacons and not unicast traffic.
304055992Swpaul *
304155992Swpaul * The cache stores (MAC src(index), IP src (major clue), signal,
304255992Swpaul *	quality, noise)
304355992Swpaul *
304455992Swpaul * No apologies for storing IP src here.  It's easy and saves much
304583270Sbrooks * trouble elsewhere.  The cache is assumed to be INET dependent,
304655992Swpaul * although it need not be.
304755992Swpaul *
304855992Swpaul * Note: the Aironet only has a single byte of signal strength value
304955992Swpaul * in the rx frame header, and it's not scaled to anything sensible.
305055992Swpaul * This is kind of lame, but it's all we've got.
305155992Swpaul */
305255992Swpaul
305355992Swpaul#ifdef documentation
305455992Swpaul
3055175446Sambriskoint an_sigitems;				/* number of cached entries */
3056175446Sambriskostruct an_sigcache an_sigcache[MAXANCACHE];	/* array of cache entries */
3057175446Sambriskoint an_nextitem;				/* index/# of entries */
305855992Swpaul
305955992Swpaul
306055992Swpaul#endif
306155992Swpaul
306255992Swpaul/* control variables for cache filtering.  Basic idea is
306355992Swpaul * to reduce cost (e.g., to only Mobile-IP agent beacons
306455992Swpaul * which are broadcast or multicast).  Still you might
306555992Swpaul * want to measure signal strength anth unicast ping packets
306655992Swpaul * on a pt. to pt. ant. setup.
306755992Swpaul */
306883270Sbrooks/* set true if you want to limit cache items to broadcast/mcast
306955992Swpaul * only packets (not unicast).  Useful for mobile-ip beacons which
307055992Swpaul * are broadcast/multicast at network layer.  Default is all packets
307155992Swpaul * so ping/unicast anll work say anth pt. to pt. antennae setup.
307255992Swpaul */
307355992Swpaulstatic int an_cache_mcastonly = 0;
3074110531SambriskoSYSCTL_INT(_hw_an, OID_AUTO, an_cache_mcastonly, CTLFLAG_RW,
307555992Swpaul	&an_cache_mcastonly, 0, "");
307655992Swpaul
307755992Swpaul/* set true if you want to limit cache items to IP packets only
307855992Swpaul*/
307955992Swpaulstatic int an_cache_iponly = 1;
3080110531SambriskoSYSCTL_INT(_hw_an, OID_AUTO, an_cache_iponly, CTLFLAG_RW,
308155992Swpaul	&an_cache_iponly, 0, "");
308255992Swpaul
308355992Swpaul/*
308455992Swpaul * an_cache_store, per rx packet store signal
308555992Swpaul * strength in MAC (src) indexed cache.
308655992Swpaul */
308783270Sbrooksstatic void
3088150446Simpan_cache_store(struct an_softc *sc, struct ether_header *eh, struct mbuf *m,
3089150446Simp    u_int8_t rx_rssi, u_int8_t rx_quality)
309055992Swpaul{
309183270Sbrooks	struct ip *ip = 0;
309255992Swpaul	int i;
309355992Swpaul	static int cache_slot = 0; 	/* use this cache entry */
3094175446Sambrisko	static int wrapindex = 0;	/* next "free" cache entry */
309588748Sambrisko	int type_ipv4 = 0;
309655992Swpaul
309755992Swpaul	/* filters:
309855992Swpaul	 * 1. ip only
309955992Swpaul	 * 2. configurable filter to throw out unicast packets,
310055992Swpaul	 * keep multicast only.
310155992Swpaul	 */
310283270Sbrooks
310388748Sambrisko	if ((ntohs(eh->ether_type) == ETHERTYPE_IP)) {
310488748Sambrisko		type_ipv4 = 1;
310555992Swpaul	}
310655992Swpaul
310783270Sbrooks	/* filter for ip packets only
310855992Swpaul	*/
310988748Sambrisko	if ( an_cache_iponly && !type_ipv4) {
311055992Swpaul		return;
311155992Swpaul	}
311255992Swpaul
311355992Swpaul	/* filter for broadcast/multicast only
311455992Swpaul	 */
311555992Swpaul	if (an_cache_mcastonly && ((eh->ether_dhost[0] & 1) == 0)) {
311655992Swpaul		return;
311755992Swpaul	}
311855992Swpaul
311955992Swpaul#ifdef SIGDEBUG
3120198987Sjhb	if_printf(sc->an_ifp, "q value %x (MSB=0x%x, LSB=0x%x) \n",
3121108401Sambrisko		rx_rssi & 0xffff, rx_rssi >> 8, rx_rssi & 0xff);
312255992Swpaul#endif
312355992Swpaul
312455992Swpaul	/* find the ip header.  we want to store the ip_src
312583270Sbrooks	 * address.
312655992Swpaul	 */
312788748Sambrisko	if (type_ipv4) {
312855992Swpaul		ip = mtod(m, struct ip *);
312955992Swpaul	}
313083270Sbrooks
313183270Sbrooks	/* do a linear search for a matching MAC address
313255992Swpaul	 * in the cache table
313355992Swpaul	 * . MAC address is 6 bytes,
313455992Swpaul	 * . var w_nextitem holds total number of entries already cached
313555992Swpaul	 */
313678639Sbrooks	for (i = 0; i < sc->an_nextitem; i++) {
313755992Swpaul		if (! bcmp(eh->ether_shost , sc->an_sigcache[i].macsrc,  6 )) {
313855992Swpaul			/* Match!,
313955992Swpaul			 * so we already have this entry,
314055992Swpaul			 * update the data
314155992Swpaul			 */
314283270Sbrooks			break;
314355992Swpaul		}
314455992Swpaul	}
314555992Swpaul
314655992Swpaul	/* did we find a matching mac address?
314755992Swpaul	 * if yes, then overwrite a previously existing cache entry
314855992Swpaul	 */
314955992Swpaul	if (i < sc->an_nextitem )   {
315083270Sbrooks		cache_slot = i;
315155992Swpaul	}
315255992Swpaul	/* else, have a new address entry,so
315355992Swpaul	 * add this new entry,
315455992Swpaul	 * if table full, then we need to replace LRU entry
315555992Swpaul	 */
315683270Sbrooks	else    {
315755992Swpaul
315883270Sbrooks		/* check for space in cache table
315955992Swpaul		 * note: an_nextitem also holds number of entries
316083270Sbrooks		 * added in the cache table
316155992Swpaul		 */
316255992Swpaul		if ( sc->an_nextitem < MAXANCACHE ) {
316355992Swpaul			cache_slot = sc->an_nextitem;
316483270Sbrooks			sc->an_nextitem++;
316555992Swpaul			sc->an_sigitems = sc->an_nextitem;
316655992Swpaul		}
3167175446Sambrisko		/* no space found, so simply wrap anth wrap index
316855992Swpaul		 * and "zap" the next entry
316955992Swpaul		 */
317055992Swpaul		else {
317155992Swpaul			if (wrapindex == MAXANCACHE) {
317255992Swpaul				wrapindex = 0;
317355992Swpaul			}
317455992Swpaul			cache_slot = wrapindex++;
317555992Swpaul		}
317655992Swpaul	}
317755992Swpaul
317855992Swpaul	/* invariant: cache_slot now points at some slot
317955992Swpaul	 * in cache.
318055992Swpaul	 */
318155992Swpaul	if (cache_slot < 0 || cache_slot >= MAXANCACHE) {
318255992Swpaul		log(LOG_ERR, "an_cache_store, bad index: %d of "
318355992Swpaul		    "[0..%d], gross cache error\n",
318455992Swpaul		    cache_slot, MAXANCACHE);
318555992Swpaul		return;
318655992Swpaul	}
318755992Swpaul
318855992Swpaul	/*  store items in cache
318955992Swpaul	 *  .ip source address
319055992Swpaul	 *  .mac src
319155992Swpaul	 *  .signal, etc.
319255992Swpaul	 */
319388748Sambrisko	if (type_ipv4) {
319455992Swpaul		sc->an_sigcache[cache_slot].ipsrc = ip->ip_src.s_addr;
319555992Swpaul	}
319655992Swpaul	bcopy( eh->ether_shost, sc->an_sigcache[cache_slot].macsrc,  6);
319755992Swpaul
319855992Swpaul
3199108401Sambrisko	switch (an_cache_mode) {
3200108401Sambrisko	case DBM:
3201108401Sambrisko		if (sc->an_have_rssimap) {
3202175445Sambrisko			sc->an_sigcache[cache_slot].signal =
3203108401Sambrisko				- sc->an_rssimap.an_entries[rx_rssi].an_rss_dbm;
3204175445Sambrisko			sc->an_sigcache[cache_slot].quality =
3205108401Sambrisko				- sc->an_rssimap.an_entries[rx_quality].an_rss_dbm;
3206108401Sambrisko		} else {
3207108401Sambrisko			sc->an_sigcache[cache_slot].signal = rx_rssi - 100;
3208108401Sambrisko			sc->an_sigcache[cache_slot].quality = rx_quality - 100;
3209108401Sambrisko		}
3210108401Sambrisko		break;
3211108401Sambrisko	case PERCENT:
3212108401Sambrisko		if (sc->an_have_rssimap) {
3213175445Sambrisko			sc->an_sigcache[cache_slot].signal =
3214108401Sambrisko				sc->an_rssimap.an_entries[rx_rssi].an_rss_pct;
3215175445Sambrisko			sc->an_sigcache[cache_slot].quality =
3216108401Sambrisko				sc->an_rssimap.an_entries[rx_quality].an_rss_pct;
3217108401Sambrisko		} else {
3218108401Sambrisko			if (rx_rssi > 100)
3219108401Sambrisko				rx_rssi = 100;
3220108401Sambrisko			if (rx_quality > 100)
3221108401Sambrisko				rx_quality = 100;
3222108401Sambrisko			sc->an_sigcache[cache_slot].signal = rx_rssi;
3223108401Sambrisko			sc->an_sigcache[cache_slot].quality = rx_quality;
3224108401Sambrisko		}
3225108401Sambrisko		break;
3226108401Sambrisko	case RAW:
3227108401Sambrisko		sc->an_sigcache[cache_slot].signal = rx_rssi;
3228108401Sambrisko		sc->an_sigcache[cache_slot].quality = rx_quality;
3229108401Sambrisko		break;
3230108401Sambrisko	}
3231108401Sambrisko
3232108401Sambrisko	sc->an_sigcache[cache_slot].noise = 0;
3233108401Sambrisko
323455992Swpaul	return;
323555992Swpaul}
323655992Swpaul#endif
323777217Sphk
323883270Sbrooksstatic int
3239150446Simpan_media_change(struct ifnet *ifp)
324077217Sphk{
324177217Sphk	struct an_softc *sc = ifp->if_softc;
3242110253Sambrisko	struct an_ltv_genconfig	*cfg;
324377217Sphk	int otype = sc->an_config.an_opmode;
324477217Sphk	int orate = sc->an_tx_rate;
324577217Sphk
3246199154Sjhb	AN_LOCK(sc);
3247116951Ssam	sc->an_tx_rate = ieee80211_media2rate(
3248116951Ssam		IFM_SUBTYPE(sc->an_ifmedia.ifm_cur->ifm_media));
3249119156Sambrisko	if (sc->an_tx_rate < 0)
3250119156Sambrisko		sc->an_tx_rate = 0;
3251110253Sambrisko
3252110253Sambrisko	if (orate != sc->an_tx_rate) {
3253110253Sambrisko		/* Read the current configuration */
3254110253Sambrisko		sc->an_config.an_type = AN_RID_GENCONFIG;
3255110253Sambrisko		sc->an_config.an_len = sizeof(struct an_ltv_genconfig);
3256110253Sambrisko		an_read_record(sc, (struct an_ltv_gen *)&sc->an_config);
3257110253Sambrisko		cfg = &sc->an_config;
3258110253Sambrisko
3259110253Sambrisko		/* clear other rates and set the only one we want */
3260110253Sambrisko		bzero(cfg->an_rates, sizeof(cfg->an_rates));
3261110253Sambrisko		cfg->an_rates[0] = sc->an_tx_rate;
3262110253Sambrisko
3263110253Sambrisko		/* Save the new rate */
3264110253Sambrisko		sc->an_config.an_type = AN_RID_GENCONFIG;
3265110253Sambrisko		sc->an_config.an_len = sizeof(struct an_ltv_genconfig);
326677217Sphk	}
326777217Sphk
3268119156Sambrisko	if ((sc->an_ifmedia.ifm_cur->ifm_media & IFM_IEEE80211_ADHOC) != 0)
3269119156Sambrisko		sc->an_config.an_opmode &= ~AN_OPMODE_INFRASTRUCTURE_STATION;
3270119156Sambrisko	else
3271119156Sambrisko		sc->an_config.an_opmode |= AN_OPMODE_INFRASTRUCTURE_STATION;
3272119156Sambrisko
3273175445Sambrisko	if (otype != sc->an_config.an_opmode ||
3274110531Sambrisko	    orate != sc->an_tx_rate)
3275199154Sjhb		an_init_locked(sc);
3276199154Sjhb	AN_UNLOCK(sc);
327777217Sphk
327877217Sphk	return(0);
327977217Sphk}
328077217Sphk
328183270Sbrooksstatic void
3282150446Simpan_media_status(struct ifnet *ifp, struct ifmediareq *imr)
328377217Sphk{
328477217Sphk	struct an_ltv_status	status;
328577217Sphk	struct an_softc		*sc = ifp->if_softc;
328677217Sphk
3287110253Sambrisko	imr->ifm_active = IFM_IEEE80211;
3288110253Sambrisko
3289175445Sambrisko	AN_LOCK(sc);
329077217Sphk	status.an_len = sizeof(status);
329177217Sphk	status.an_type = AN_RID_STATUS;
329277217Sphk	if (an_read_record(sc, (struct an_ltv_gen *)&status)) {
329377217Sphk		/* If the status read fails, just lie. */
329477217Sphk		imr->ifm_active = sc->an_ifmedia.ifm_cur->ifm_media;
329577217Sphk		imr->ifm_status = IFM_AVALID|IFM_ACTIVE;
329677217Sphk	}
329777217Sphk
329878639Sbrooks	if (sc->an_tx_rate == 0) {
329977217Sphk		imr->ifm_active = IFM_IEEE80211|IFM_AUTO;
330077217Sphk	}
330177217Sphk
3302110253Sambrisko	if (sc->an_config.an_opmode == AN_OPMODE_IBSS_ADHOC)
3303110253Sambrisko		imr->ifm_active |= IFM_IEEE80211_ADHOC;
3304116951Ssam	imr->ifm_active |= ieee80211_rate2media(NULL,
3305116951Ssam		status.an_current_tx_rate, IEEE80211_T_DS);
330677217Sphk	imr->ifm_status = IFM_AVALID;
330791283Sambrisko	if (status.an_opmode & AN_STATUS_OPMODE_ASSOCIATED)
330877217Sphk		imr->ifm_status |= IFM_ACTIVE;
3309199154Sjhb	AN_UNLOCK(sc);
331077217Sphk}
331188748Sambrisko
331288748Sambrisko/********************** Cisco utility support routines *************/
331388748Sambrisko
331488748Sambrisko/*
331588748Sambrisko * ReadRids & WriteRids derived from Cisco driver additions to Ben Reed's
331688748Sambrisko * Linux driver
331788748Sambrisko */
331888748Sambrisko
331988748Sambriskostatic int
3320150446Simpreadrids(struct ifnet *ifp, struct aironet_ioctl *l_ioctl)
332188748Sambrisko{
332288749Sambrisko	unsigned short  rid;
332388748Sambrisko	struct an_softc *sc;
3324171692Savatar	int error;
332588748Sambrisko
332688748Sambrisko	switch (l_ioctl->command) {
332788748Sambrisko	case AIROGCAP:
332888748Sambrisko		rid = AN_RID_CAPABILITIES;
332988748Sambrisko		break;
333088748Sambrisko	case AIROGCFG:
333188748Sambrisko		rid = AN_RID_GENCONFIG;
333288748Sambrisko		break;
333388748Sambrisko	case AIROGSLIST:
333488748Sambrisko		rid = AN_RID_SSIDLIST;
333588748Sambrisko		break;
333688748Sambrisko	case AIROGVLIST:
333788748Sambrisko		rid = AN_RID_APLIST;
333888748Sambrisko		break;
333988748Sambrisko	case AIROGDRVNAM:
334088748Sambrisko		rid = AN_RID_DRVNAME;
334188748Sambrisko		break;
334288748Sambrisko	case AIROGEHTENC:
334388748Sambrisko		rid = AN_RID_ENCAPPROTO;
334488748Sambrisko		break;
334588748Sambrisko	case AIROGWEPKTMP:
334688748Sambrisko		rid = AN_RID_WEP_TEMP;
334788748Sambrisko		break;
334888748Sambrisko	case AIROGWEPKNV:
334988748Sambrisko		rid = AN_RID_WEP_PERM;
335088748Sambrisko		break;
335188748Sambrisko	case AIROGSTAT:
335288748Sambrisko		rid = AN_RID_STATUS;
335388748Sambrisko		break;
335488748Sambrisko	case AIROGSTATSD32:
335588748Sambrisko		rid = AN_RID_32BITS_DELTA;
335688748Sambrisko		break;
335788748Sambrisko	case AIROGSTATSC32:
335888748Sambrisko		rid = AN_RID_32BITS_CUM;
335988748Sambrisko		break;
336088748Sambrisko	default:
336188748Sambrisko		rid = 999;
336288748Sambrisko		break;
336388748Sambrisko	}
336488748Sambrisko
336588748Sambrisko	if (rid == 999)	/* Is bad command */
336688748Sambrisko		return -EINVAL;
336788748Sambrisko
336888748Sambrisko	sc = ifp->if_softc;
336988749Sambrisko	sc->areq.an_len  = AN_MAX_DATALEN;
337088749Sambrisko	sc->areq.an_type = rid;
337188748Sambrisko
337288749Sambrisko	an_read_record(sc, (struct an_ltv_gen *)&sc->areq);
337388748Sambrisko
337488749Sambrisko	l_ioctl->len = sc->areq.an_len - 4;	/* just data */
337588748Sambrisko
3376171692Savatar	AN_UNLOCK(sc);
337788748Sambrisko	/* the data contains the length at first */
337888749Sambrisko	if (copyout(&(sc->areq.an_len), l_ioctl->data,
337988749Sambrisko		    sizeof(sc->areq.an_len))) {
3380171692Savatar		error = -EFAULT;
3381171692Savatar		goto lock_exit;
338288748Sambrisko	}
338388748Sambrisko	/* Just copy the data back */
338488749Sambrisko	if (copyout(&(sc->areq.an_val), l_ioctl->data + 2,
338588748Sambrisko		    l_ioctl->len)) {
3386171692Savatar		error = -EFAULT;
3387171692Savatar		goto lock_exit;
338888748Sambrisko	}
3389171692Savatar	error = 0;
3390171692Savatarlock_exit:
3391171692Savatar	AN_LOCK(sc);
3392171692Savatar	return (error);
339388748Sambrisko}
339488748Sambrisko
339588748Sambriskostatic int
3396150446Simpwriterids(struct ifnet *ifp, struct aironet_ioctl *l_ioctl)
339788748Sambrisko{
339888748Sambrisko	struct an_softc *sc;
3399175446Sambrisko	int		rid, command, error;
340088748Sambrisko
340188748Sambrisko	sc = ifp->if_softc;
3402175445Sambrisko	AN_LOCK_ASSERT(sc);
340388748Sambrisko	rid = 0;
340488748Sambrisko	command = l_ioctl->command;
340588748Sambrisko
340688748Sambrisko	switch (command) {
340788748Sambrisko	case AIROPSIDS:
340888748Sambrisko		rid = AN_RID_SSIDLIST;
340988748Sambrisko		break;
341088748Sambrisko	case AIROPCAP:
341188748Sambrisko		rid = AN_RID_CAPABILITIES;
341288748Sambrisko		break;
341388748Sambrisko	case AIROPAPLIST:
341488748Sambrisko		rid = AN_RID_APLIST;
341588748Sambrisko		break;
341688748Sambrisko	case AIROPCFG:
341788748Sambrisko		rid = AN_RID_GENCONFIG;
341888748Sambrisko		break;
341988748Sambrisko	case AIROPMACON:
342088748Sambrisko		an_cmd(sc, AN_CMD_ENABLE, 0);
342188748Sambrisko		return 0;
342288748Sambrisko		break;
342388748Sambrisko	case AIROPMACOFF:
342488748Sambrisko		an_cmd(sc, AN_CMD_DISABLE, 0);
342588748Sambrisko		return 0;
342688748Sambrisko		break;
342788748Sambrisko	case AIROPSTCLR:
342888748Sambrisko		/*
342988748Sambrisko		 * This command merely clears the counts does not actually
343088748Sambrisko		 * store any data only reads rid. But as it changes the cards
343188748Sambrisko		 * state, I put it in the writerid routines.
343288748Sambrisko		 */
343388748Sambrisko
343488748Sambrisko		rid = AN_RID_32BITS_DELTACLR;
343588748Sambrisko		sc = ifp->if_softc;
343688749Sambrisko		sc->areq.an_len = AN_MAX_DATALEN;
343788749Sambrisko		sc->areq.an_type = rid;
343888748Sambrisko
343988749Sambrisko		an_read_record(sc, (struct an_ltv_gen *)&sc->areq);
344088749Sambrisko		l_ioctl->len = sc->areq.an_len - 4;	/* just data */
344188748Sambrisko
3442171692Savatar		AN_UNLOCK(sc);
344388748Sambrisko		/* the data contains the length at first */
3444171692Savatar		error = copyout(&(sc->areq.an_len), l_ioctl->data,
3445171692Savatar			    sizeof(sc->areq.an_len));
3446171692Savatar		if (error) {
3447171692Savatar			AN_LOCK(sc);
344888748Sambrisko			return -EFAULT;
344988748Sambrisko		}
345088748Sambrisko		/* Just copy the data */
3451171692Savatar		error = copyout(&(sc->areq.an_val), l_ioctl->data + 2,
3452171692Savatar			    l_ioctl->len);
3453171692Savatar		AN_LOCK(sc);
3454171692Savatar		if (error)
345588748Sambrisko			return -EFAULT;
345688748Sambrisko		return 0;
345788748Sambrisko		break;
345888748Sambrisko	case AIROPWEPKEY:
345988748Sambrisko		rid = AN_RID_WEP_TEMP;
346088748Sambrisko		break;
346188748Sambrisko	case AIROPWEPKEYNV:
346288748Sambrisko		rid = AN_RID_WEP_PERM;
346388748Sambrisko		break;
346488748Sambrisko	case AIROPLEAPUSR:
346588748Sambrisko		rid = AN_RID_LEAPUSERNAME;
346688748Sambrisko		break;
346788748Sambrisko	case AIROPLEAPPWD:
346888748Sambrisko		rid = AN_RID_LEAPPASSWORD;
346988748Sambrisko		break;
347088748Sambrisko	default:
347188748Sambrisko		return -EOPNOTSUPP;
347288748Sambrisko	}
347388748Sambrisko
347488748Sambrisko	if (rid) {
347588749Sambrisko		if (l_ioctl->len > sizeof(sc->areq.an_val) + 4)
347688748Sambrisko			return -EINVAL;
347788749Sambrisko		sc->areq.an_len = l_ioctl->len + 4;	/* add type & length */
347888749Sambrisko		sc->areq.an_type = rid;
347988748Sambrisko
348088748Sambrisko		/* Just copy the data back */
3481171692Savatar		AN_UNLOCK(sc);
3482171692Savatar		error = copyin((l_ioctl->data) + 2, &sc->areq.an_val,
3483171692Savatar		       l_ioctl->len);
3484171692Savatar		AN_LOCK(sc);
3485171692Savatar		if (error)
3486144242Ssam			return -EFAULT;
3487171692Savatar
348888748Sambrisko		an_cmd(sc, AN_CMD_DISABLE, 0);
348988749Sambrisko		an_write_record(sc, (struct an_ltv_gen *)&sc->areq);
349088748Sambrisko		an_cmd(sc, AN_CMD_ENABLE, 0);
349188748Sambrisko		return 0;
349288748Sambrisko	}
349388748Sambrisko	return -EOPNOTSUPP;
349488748Sambrisko}
349588748Sambrisko
349688748Sambrisko/*
349788748Sambrisko * General Flash utilities derived from Cisco driver additions to Ben Reed's
349888748Sambrisko * Linux driver
349988748Sambrisko */
350088748Sambrisko
3501123978Sambrisko#define FLASH_DELAY(_sc, x)	msleep(ifp, &(_sc)->an_mtx, PZERO, \
3502123978Sambrisko	"flash", ((x) / hz) + 1);
3503108401Sambrisko#define FLASH_COMMAND	0x7e7e
3504108401Sambrisko#define FLASH_SIZE	32 * 1024
350588748Sambrisko
350688748Sambriskostatic int
3507150446Simpunstickbusy(struct ifnet *ifp)
350888748Sambrisko{
350988748Sambrisko	struct an_softc *sc = ifp->if_softc;
351088748Sambrisko
3511108401Sambrisko	if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350)) & AN_CMD_BUSY) {
3512175445Sambrisko		CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350),
3513108401Sambrisko			    AN_EV_CLR_STUCK_BUSY);
351488748Sambrisko		return 1;
351588748Sambrisko	}
351688748Sambrisko	return 0;
351788748Sambrisko}
351888748Sambrisko
351988748Sambrisko/*
352088748Sambrisko * Wait for busy completion from card wait for delay uSec's Return true for
352188748Sambrisko * success meaning command reg is clear
352288748Sambrisko */
352388748Sambrisko
352488748Sambriskostatic int
3525150446SimpWaitBusy(struct ifnet *ifp, int uSec)
352688748Sambrisko{
3527175446Sambrisko	int		statword = 0xffff;
3528175446Sambrisko	int		delay = 0;
3529175446Sambrisko	struct an_softc	*sc = ifp->if_softc;
353088748Sambrisko
353188748Sambrisko	while ((statword & AN_CMD_BUSY) && delay <= (1000 * 100)) {
3532119163Sambrisko		FLASH_DELAY(sc, 10);
353388748Sambrisko		delay += 10;
3534108401Sambrisko		statword = CSR_READ_2(sc, AN_COMMAND(sc->mpi350));
353588748Sambrisko
353688748Sambrisko		if ((AN_CMD_BUSY & statword) && (delay % 200)) {
353788748Sambrisko			unstickbusy(ifp);
353888748Sambrisko		}
353988748Sambrisko	}
354088748Sambrisko
354188748Sambrisko	return 0 == (AN_CMD_BUSY & statword);
354288748Sambrisko}
354388748Sambrisko
354488748Sambrisko/*
354588748Sambrisko * STEP 1) Disable MAC and do soft reset on card.
354688748Sambrisko */
354788748Sambrisko
354888748Sambriskostatic int
3549150446Simpcmdreset(struct ifnet *ifp)
355088748Sambrisko{
3551175446Sambrisko	int		status;
3552175446Sambrisko	struct an_softc	*sc = ifp->if_softc;
355388748Sambrisko
3554199154Sjhb	AN_LOCK(sc);
355588748Sambrisko	an_stop(sc);
355688748Sambrisko
355788748Sambrisko	an_cmd(sc, AN_CMD_DISABLE, 0);
355888748Sambrisko
3559108401Sambrisko	if (!(status = WaitBusy(ifp, AN_TIMEOUT))) {
3560198987Sjhb		if_printf(ifp, "Waitbusy hang b4 RESET =%d\n", status);
3561175445Sambrisko		AN_UNLOCK(sc);
356288748Sambrisko		return -EBUSY;
356388748Sambrisko	}
3564108401Sambrisko	CSR_WRITE_2(sc, AN_COMMAND(sc->mpi350), AN_CMD_FW_RESTART);
356588748Sambrisko
3566119163Sambrisko	FLASH_DELAY(sc, 1000);	/* WAS 600 12/7/00 */
356788748Sambrisko
356888748Sambrisko
356988748Sambrisko	if (!(status = WaitBusy(ifp, 100))) {
3570198987Sjhb		if_printf(ifp, "Waitbusy hang AFTER RESET =%d\n", status);
3571175445Sambrisko		AN_UNLOCK(sc);
357288748Sambrisko		return -EBUSY;
357388748Sambrisko	}
3574175445Sambrisko	AN_UNLOCK(sc);
357588748Sambrisko	return 0;
357688748Sambrisko}
357788748Sambrisko
357888748Sambrisko/*
357988748Sambrisko * STEP 2) Put the card in legendary flash mode
358088748Sambrisko */
358188748Sambrisko
358288748Sambriskostatic int
3583150446Simpsetflashmode(struct ifnet *ifp)
358488748Sambrisko{
3585175446Sambrisko	int		status;
3586175446Sambrisko	struct an_softc	*sc = ifp->if_softc;
358788748Sambrisko
3588108401Sambrisko	CSR_WRITE_2(sc, AN_SW0(sc->mpi350), FLASH_COMMAND);
3589108401Sambrisko	CSR_WRITE_2(sc, AN_SW1(sc->mpi350), FLASH_COMMAND);
3590108401Sambrisko	CSR_WRITE_2(sc, AN_SW0(sc->mpi350), FLASH_COMMAND);
3591108401Sambrisko	CSR_WRITE_2(sc, AN_COMMAND(sc->mpi350), FLASH_COMMAND);
359288748Sambrisko
359388748Sambrisko	/*
359488748Sambrisko	 * mdelay(500); // 500ms delay
359588748Sambrisko	 */
359688748Sambrisko
3597119163Sambrisko	FLASH_DELAY(sc, 500);
359888748Sambrisko
3599108401Sambrisko	if (!(status = WaitBusy(ifp, AN_TIMEOUT))) {
360088748Sambrisko		printf("Waitbusy hang after setflash mode\n");
360188748Sambrisko		return -EIO;
360288748Sambrisko	}
360388748Sambrisko	return 0;
360488748Sambrisko}
360588748Sambrisko
360688748Sambrisko/*
360788748Sambrisko * Get a character from the card matching matchbyte Step 3)
360888748Sambrisko */
360988748Sambrisko
361088748Sambriskostatic int
3611150446Simpflashgchar(struct ifnet *ifp, int matchbyte, int dwelltime)
361288748Sambrisko{
3613175446Sambrisko	int		rchar;
3614175446Sambrisko	unsigned char	rbyte = 0;
3615175446Sambrisko	int		success = -1;
3616175446Sambrisko	struct an_softc	*sc = ifp->if_softc;
361788748Sambrisko
361888748Sambrisko
361988748Sambrisko	do {
3620108401Sambrisko		rchar = CSR_READ_2(sc, AN_SW1(sc->mpi350));
362188748Sambrisko
362288748Sambrisko		if (dwelltime && !(0x8000 & rchar)) {
362388748Sambrisko			dwelltime -= 10;
3624119163Sambrisko			FLASH_DELAY(sc, 10);
362588748Sambrisko			continue;
362688748Sambrisko		}
362788748Sambrisko		rbyte = 0xff & rchar;
362888748Sambrisko
362988748Sambrisko		if ((rbyte == matchbyte) && (0x8000 & rchar)) {
3630108401Sambrisko			CSR_WRITE_2(sc, AN_SW1(sc->mpi350), 0);
363188748Sambrisko			success = 1;
363288748Sambrisko			break;
363388748Sambrisko		}
363488748Sambrisko		if (rbyte == 0x81 || rbyte == 0x82 || rbyte == 0x83 || rbyte == 0x1a || 0xffff == rchar)
363588748Sambrisko			break;
3636108401Sambrisko		CSR_WRITE_2(sc, AN_SW1(sc->mpi350), 0);
363788748Sambrisko
363888748Sambrisko	} while (dwelltime > 0);
363988748Sambrisko	return success;
364088748Sambrisko}
364188748Sambrisko
364288748Sambrisko/*
364388748Sambrisko * Put character to SWS0 wait for dwelltime x 50us for  echo .
364488748Sambrisko */
364588748Sambrisko
364688748Sambriskostatic int
3647150446Simpflashpchar(struct ifnet *ifp, int byte, int dwelltime)
364888748Sambrisko{
3649175446Sambrisko	int		echo;
3650175446Sambrisko	int		pollbusy, waittime;
3651175446Sambrisko	struct an_softc	*sc = ifp->if_softc;
365288748Sambrisko
365388748Sambrisko	byte |= 0x8000;
365488748Sambrisko
365588748Sambrisko	if (dwelltime == 0)
365688748Sambrisko		dwelltime = 200;
365788748Sambrisko
365888748Sambrisko	waittime = dwelltime;
365988748Sambrisko
366088748Sambrisko	/*
366188748Sambrisko	 * Wait for busy bit d15 to go false indicating buffer empty
366288748Sambrisko	 */
366388748Sambrisko	do {
3664108401Sambrisko		pollbusy = CSR_READ_2(sc, AN_SW0(sc->mpi350));
366588748Sambrisko
366688748Sambrisko		if (pollbusy & 0x8000) {
3667119163Sambrisko			FLASH_DELAY(sc, 50);
366888748Sambrisko			waittime -= 50;
366988748Sambrisko			continue;
367088748Sambrisko		} else
367188748Sambrisko			break;
367288748Sambrisko	}
367388748Sambrisko	while (waittime >= 0);
367488748Sambrisko
367588748Sambrisko	/* timeout for busy clear wait */
367688748Sambrisko
367788748Sambrisko	if (waittime <= 0) {
3678198987Sjhb		if_printf(ifp, "flash putchar busywait timeout!\n");
367988748Sambrisko		return -1;
368088748Sambrisko	}
368188748Sambrisko	/*
368288748Sambrisko	 * Port is clear now write byte and wait for it to echo back
368388748Sambrisko	 */
368488748Sambrisko	do {
3685108401Sambrisko		CSR_WRITE_2(sc, AN_SW0(sc->mpi350), byte);
3686119163Sambrisko		FLASH_DELAY(sc, 50);
368788748Sambrisko		dwelltime -= 50;
3688108401Sambrisko		echo = CSR_READ_2(sc, AN_SW1(sc->mpi350));
368988748Sambrisko	} while (dwelltime >= 0 && echo != byte);
369088748Sambrisko
369188748Sambrisko
3692108401Sambrisko	CSR_WRITE_2(sc, AN_SW1(sc->mpi350), 0);
369388748Sambrisko
369488748Sambrisko	return echo == byte;
369588748Sambrisko}
369688748Sambrisko
369788748Sambrisko/*
369888748Sambrisko * Transfer 32k of firmware data from user buffer to our buffer and send to
369988748Sambrisko * the card
370088748Sambrisko */
370188748Sambrisko
370288748Sambriskostatic int
3703150446Simpflashputbuf(struct ifnet *ifp)
370488748Sambrisko{
370588748Sambrisko	unsigned short *bufp;
3706175446Sambrisko	int		nwords;
3707175446Sambrisko	struct an_softc	*sc = ifp->if_softc;
370888748Sambrisko
370988748Sambrisko	/* Write stuff */
371088748Sambrisko
3711108401Sambrisko	bufp = sc->an_flash_buffer;
371288748Sambrisko
3713108401Sambrisko	if (!sc->mpi350) {
3714108401Sambrisko		CSR_WRITE_2(sc, AN_AUX_PAGE, 0x100);
3715108401Sambrisko		CSR_WRITE_2(sc, AN_AUX_OFFSET, 0);
371688748Sambrisko
3717108401Sambrisko		for (nwords = 0; nwords != FLASH_SIZE / 2; nwords++) {
3718108401Sambrisko			CSR_WRITE_2(sc, AN_AUX_DATA, bufp[nwords] & 0xffff);
3719108401Sambrisko		}
3720108401Sambrisko	} else {
3721108401Sambrisko		for (nwords = 0; nwords != FLASH_SIZE / 4; nwords++) {
3722175445Sambrisko			CSR_MEM_AUX_WRITE_4(sc, 0x8000,
3723108401Sambrisko				((u_int32_t *)bufp)[nwords] & 0xffff);
3724108401Sambrisko		}
372588748Sambrisko	}
372688748Sambrisko
3727108401Sambrisko	CSR_WRITE_2(sc, AN_SW0(sc->mpi350), 0x8000);
372888748Sambrisko
372988748Sambrisko	return 0;
373088748Sambrisko}
373188748Sambrisko
373288748Sambrisko/*
373388748Sambrisko * After flashing restart the card.
373488748Sambrisko */
373588748Sambrisko
373688748Sambriskostatic int
3737150446Simpflashrestart(struct ifnet *ifp)
373888748Sambrisko{
3739175446Sambrisko	int		status = 0;
3740175446Sambrisko	struct an_softc	*sc = ifp->if_softc;
374188748Sambrisko
3742119163Sambrisko	FLASH_DELAY(sc, 1024);		/* Added 12/7/00 */
374388748Sambrisko
3744199154Sjhb	an_init_locked(sc);
374588748Sambrisko
3746119163Sambrisko	FLASH_DELAY(sc, 1024);		/* Added 12/7/00 */
374788748Sambrisko	return status;
374888748Sambrisko}
374988748Sambrisko
375088748Sambrisko/*
375188748Sambrisko * Entry point for flash ioclt.
375288748Sambrisko */
375388748Sambrisko
375488748Sambriskostatic int
3755150446Simpflashcard(struct ifnet *ifp, struct aironet_ioctl *l_ioctl)
375688748Sambrisko{
3757175446Sambrisko	int		z = 0, status;
375888748Sambrisko	struct an_softc	*sc;
375988748Sambrisko
376088748Sambrisko	sc = ifp->if_softc;
3761108401Sambrisko	if (sc->mpi350) {
3762198987Sjhb		if_printf(ifp, "flashing not supported on MPI 350 yet\n");
3763108401Sambrisko		return(-1);
3764108401Sambrisko	}
376588748Sambrisko	status = l_ioctl->command;
376688748Sambrisko
376788748Sambrisko	switch (l_ioctl->command) {
376888748Sambrisko	case AIROFLSHRST:
376988748Sambrisko		return cmdreset(ifp);
377088748Sambrisko		break;
377188748Sambrisko	case AIROFLSHSTFL:
3772108401Sambrisko		if (sc->an_flash_buffer) {
3773108401Sambrisko			free(sc->an_flash_buffer, M_DEVBUF);
3774108401Sambrisko			sc->an_flash_buffer = NULL;
3775108401Sambrisko		}
3776111119Simp		sc->an_flash_buffer = malloc(FLASH_SIZE, M_DEVBUF, M_WAITOK);
3777108401Sambrisko		if (sc->an_flash_buffer)
3778108401Sambrisko			return setflashmode(ifp);
3779108401Sambrisko		else
3780108401Sambrisko			return ENOBUFS;
378188748Sambrisko		break;
378288748Sambrisko	case AIROFLSHGCHR:	/* Get char from aux */
3783171692Savatar		AN_UNLOCK(sc);
3784144242Ssam		status = copyin(l_ioctl->data, &sc->areq, l_ioctl->len);
3785171692Savatar		AN_LOCK(sc);
3786144242Ssam		if (status)
3787144242Ssam			return status;
378888749Sambrisko		z = *(int *)&sc->areq;
378988748Sambrisko		if ((status = flashgchar(ifp, z, 8000)) == 1)
379088748Sambrisko			return 0;
379188748Sambrisko		else
379288748Sambrisko			return -1;
379388748Sambrisko	case AIROFLSHPCHR:	/* Send char to card. */
3794171692Savatar		AN_UNLOCK(sc);
3795144242Ssam		status = copyin(l_ioctl->data, &sc->areq, l_ioctl->len);
3796171692Savatar		AN_LOCK(sc);
3797144242Ssam		if (status)
3798144242Ssam			return status;
379988749Sambrisko		z = *(int *)&sc->areq;
380088748Sambrisko		if ((status = flashpchar(ifp, z, 8000)) == -1)
380188748Sambrisko			return -EIO;
380288748Sambrisko		else
380388748Sambrisko			return 0;
380488748Sambrisko		break;
380588748Sambrisko	case AIROFLPUTBUF:	/* Send 32k to card */
3806108401Sambrisko		if (l_ioctl->len > FLASH_SIZE) {
3807198987Sjhb			if_printf(ifp, "Buffer to big, %x %x\n",
3808108401Sambrisko			       l_ioctl->len, FLASH_SIZE);
380988748Sambrisko			return -EINVAL;
381088748Sambrisko		}
3811171692Savatar		AN_UNLOCK(sc);
3812144242Ssam		status = copyin(l_ioctl->data, sc->an_flash_buffer, l_ioctl->len);
3813171692Savatar		AN_LOCK(sc);
3814144242Ssam		if (status)
3815144242Ssam			return status;
381688748Sambrisko
381788748Sambrisko		if ((status = flashputbuf(ifp)) != 0)
381888748Sambrisko			return -EIO;
381988748Sambrisko		else
382088748Sambrisko			return 0;
382188748Sambrisko		break;
382288748Sambrisko	case AIRORESTART:
382388748Sambrisko		if ((status = flashrestart(ifp)) != 0) {
3824198987Sjhb			if_printf(ifp, "FLASHRESTART returned %d\n", status);
382588748Sambrisko			return -EIO;
382688748Sambrisko		} else
382788748Sambrisko			return 0;
382888748Sambrisko
382988748Sambrisko		break;
383088748Sambrisko	default:
383188748Sambrisko		return -EINVAL;
383288748Sambrisko	}
383388748Sambrisko
383488748Sambrisko	return -EINVAL;
383588748Sambrisko}
3836