xref: /netbsd-src/sys/arch/pmax/stand/common/if_prom.c (revision e3b6673e18064f1bd82f8b1736012d1a58e7cae8)
1*e3b6673eStsutsui /*      $NetBSD: if_prom.c,v 1.11 2011/01/12 15:32:43 tsutsui Exp $ */
2feb0773eSgmcgarry 
3feb0773eSgmcgarry /* Copyright (c) 1999 The NetBSD Foundation, Inc.
4feb0773eSgmcgarry  * All rights reserved.
5feb0773eSgmcgarry  *
6feb0773eSgmcgarry  * This code is derived from software contributed to The NetBSD Foundation
7feb0773eSgmcgarry  * by Gregory McGarry.
8feb0773eSgmcgarry  *
9feb0773eSgmcgarry  * Redistribution and use in source and binary forms, with or without
10feb0773eSgmcgarry  * modification, are permitted provided that the following conditions
11feb0773eSgmcgarry  * are met:
12feb0773eSgmcgarry  * 1. Redistributions of source code must retain the above copyright
13feb0773eSgmcgarry  *    notice, this list of conditions and the following disclaimer.
14feb0773eSgmcgarry  * 2. Redistributions in binary form must reproduce the above copyright
15feb0773eSgmcgarry  *    notice, this list of conditions and the following disclaimer in the
16feb0773eSgmcgarry  *    documentation and/or other materials provided with the distribution.
17feb0773eSgmcgarry  *
18feb0773eSgmcgarry  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19feb0773eSgmcgarry  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20feb0773eSgmcgarry  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21feb0773eSgmcgarry  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22feb0773eSgmcgarry  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23feb0773eSgmcgarry  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24feb0773eSgmcgarry  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25feb0773eSgmcgarry  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26feb0773eSgmcgarry  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27feb0773eSgmcgarry  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28feb0773eSgmcgarry  * POSSIBILITY OF SUCH DAMAGE.
29feb0773eSgmcgarry  */
30feb0773eSgmcgarry 
31feb0773eSgmcgarry #include <sys/param.h>
32feb0773eSgmcgarry #include <sys/types.h>
33feb0773eSgmcgarry 
34feb0773eSgmcgarry #include <net/if_ether.h>
35feb0773eSgmcgarry #include <netinet/in.h>
36feb0773eSgmcgarry #include <netinet/in_systm.h>
37feb0773eSgmcgarry #include <netinet/ip.h>
38feb0773eSgmcgarry 
39feb0773eSgmcgarry #include <lib/libsa/stand.h>
40feb0773eSgmcgarry #include <lib/libsa/net.h>
41feb0773eSgmcgarry #include <lib/libsa/netif.h>
42d1b230abStsutsui #include <lib/libsa/dev_net.h>
43feb0773eSgmcgarry #include <lib/libkern/libkern.h>
44feb0773eSgmcgarry 
45feb0773eSgmcgarry #include <machine/dec_prom.h>
46feb0773eSgmcgarry #include <stand/common/common.h>
47feb0773eSgmcgarry 
48feb0773eSgmcgarry #ifdef NET_DEBUG
49dd6122d4Stsutsui #define DPRINTF(x)	printf(x)
50dd6122d4Stsutsui #else
51dd6122d4Stsutsui #define DPRINTF(x)
52dd6122d4Stsutsui #endif
53dd6122d4Stsutsui 
54dd6122d4Stsutsui #ifdef NET_DEBUG
5502cdf4d2Sdsl void dump_packet_info(void *, int);
56feb0773eSgmcgarry #endif
57feb0773eSgmcgarry 
58feb0773eSgmcgarry /*
59feb0773eSgmcgarry  *  For some reason the proms won't pass arp responses back to us.  I
60feb0773eSgmcgarry  *  have checked if the first parameter to bootread/bootwrite do anything
61feb0773eSgmcgarry  *  but it doesn't appear so.  Therefore, we stop the upper layers from
62feb0773eSgmcgarry  *  sending arp requests in the first place, by monitoring packets which
63feb0773eSgmcgarry  *  come in and filling the arp cache ourselves.  - gmcgarry
64feb0773eSgmcgarry  */
65feb0773eSgmcgarry #ifdef FILL_ARPCACHE
66feb0773eSgmcgarry struct arp_list {
67feb0773eSgmcgarry 	struct in_addr	addr;
68feb0773eSgmcgarry 	u_char		ea[6];
69feb0773eSgmcgarry };
70feb0773eSgmcgarry extern struct arp_list arp_list[8];
71feb0773eSgmcgarry extern int arp_num;
7202cdf4d2Sdsl void fill_arpcache(void *, int);
73feb0773eSgmcgarry #endif
74feb0773eSgmcgarry 
75feb0773eSgmcgarry /* forward declarations */
7602cdf4d2Sdsl int prom_probe(struct netif *, void *);
7702cdf4d2Sdsl int prom_match(struct netif *, void *);
7802cdf4d2Sdsl void prom_init(struct iodesc *, void *);
7902cdf4d2Sdsl int prom_get(struct iodesc *, void *, size_t, saseconds_t);
8002cdf4d2Sdsl int prom_put(struct iodesc *, void *, size_t);
8102cdf4d2Sdsl void prom_end(struct netif *);
82feb0773eSgmcgarry 
83feb0773eSgmcgarry extern struct netif_stats       prom_stats[];
84feb0773eSgmcgarry struct netif_dif prom_ifs[] = {
85feb0773eSgmcgarry /*	dif_unit	dif_nsel	dif_stats	dif_private	*/
86feb0773eSgmcgarry {	0,		1,		&prom_stats[0],	0,		},
87feb0773eSgmcgarry };
88e537123cSdrochner #define NPROM_IFS (sizeof(prom_ifs) / sizeof(prom_ifs[0]))
89e537123cSdrochner struct netif_stats prom_stats[NPROM_IFS];
90feb0773eSgmcgarry 
91feb0773eSgmcgarry struct netif_driver prom_netif_driver = {
92feb0773eSgmcgarry 	"prom",				/* netif_bname */
93feb0773eSgmcgarry 	prom_match,			/* netif_match */
94feb0773eSgmcgarry 	prom_probe,			/* netif_probe */
95feb0773eSgmcgarry 	prom_init,			/* netif_init */
96feb0773eSgmcgarry 	prom_get,			/* netif_get */
97feb0773eSgmcgarry 	prom_put,			/* netif_put */
98feb0773eSgmcgarry 	prom_end,			/* netif_end */
99feb0773eSgmcgarry 	prom_ifs,			/* netif_ifs */
100e537123cSdrochner 	NPROM_IFS			/* netif_nifs */
101feb0773eSgmcgarry };
102feb0773eSgmcgarry 
103feb0773eSgmcgarry static int sc_fd;				/* PROM file id */
104feb0773eSgmcgarry 
105feb0773eSgmcgarry int
prom_match(struct netif * nif,void * machdep_hint)106454af1c0Sdsl prom_match(struct netif *nif, void *machdep_hint)
107feb0773eSgmcgarry {
108feb0773eSgmcgarry 
109dd6122d4Stsutsui 	DPRINTF(("prom_match: called\n"));
110dd6122d4Stsutsui 	return 1;
111feb0773eSgmcgarry }
112feb0773eSgmcgarry 
113feb0773eSgmcgarry 
114feb0773eSgmcgarry int
prom_probe(struct netif * nif,void * machdep_hint)115454af1c0Sdsl prom_probe(struct netif *nif, void *machdep_hint)
116feb0773eSgmcgarry {
117feb0773eSgmcgarry 
118dd6122d4Stsutsui 	DPRINTF(("prom_probe: called\n"));
119feb0773eSgmcgarry 	return 0;
120feb0773eSgmcgarry }
121feb0773eSgmcgarry 
122feb0773eSgmcgarry 
123feb0773eSgmcgarry void
prom_init(struct iodesc * desc,void * machdep_hint)124454af1c0Sdsl prom_init(struct iodesc *desc, void *machdep_hint)
125feb0773eSgmcgarry {
126dd6122d4Stsutsui 	struct netif *nif;
127dd6122d4Stsutsui 	char *device, *enet;
128eae5c43dStsutsui 	uint8_t *cp, *dest;
129eae5c43dStsutsui 	int i;
130feb0773eSgmcgarry 
131dd6122d4Stsutsui 	DPRINTF(("prom_init: called\n"));
132feb0773eSgmcgarry 
133feb0773eSgmcgarry 	try_bootp = 1;
134feb0773eSgmcgarry 
135feb0773eSgmcgarry 	/*
136feb0773eSgmcgarry 	 * Get our hardware address (this prom call is one of the rare ones
137feb0773eSgmcgarry 	 * which is the same for new and old proms)
138feb0773eSgmcgarry 	 */
139feb0773eSgmcgarry 	enet = (*callv->_getenv)("enet");
140feb0773eSgmcgarry 
141eae5c43dStsutsui 	if (enet == NULL) {
142eae5c43dStsutsui 		printf("No `enet' environment variable found.\n"
143eae5c43dStsutsui 		    "Set MAC address to `enet' manually by setenv command.\n");
14483460859Stsutsui 		prom_restart();
145eae5c43dStsutsui 		/* NOTREACHED */
146eae5c43dStsutsui 	}
147eae5c43dStsutsui 
148feb0773eSgmcgarry #ifdef NET_DEBUG
149feb0773eSgmcgarry 	if (debug)
150feb0773eSgmcgarry 		printf("enet=%s\n", enet);
151feb0773eSgmcgarry #endif
152feb0773eSgmcgarry 
153*e3b6673eStsutsui #define atox(c)	(((c) <= '9') ? ((c) - '0') : ((toupper(c) - 'A') + 10))
154eae5c43dStsutsui 
155eae5c43dStsutsui 	cp = (uint8_t *)enet;
156eae5c43dStsutsui 	dest = desc->myea;
157feb0773eSgmcgarry 	for (i = 0; i < 6; i++) {
158eae5c43dStsutsui 		if (isxdigit(*cp)) {
159eae5c43dStsutsui 			*dest = atox(*cp);
160eae5c43dStsutsui 			cp++;
161eae5c43dStsutsui 			if (isxdigit(*cp)) {
162eae5c43dStsutsui 				*dest = (*dest << 4) | atox(*cp);
163eae5c43dStsutsui 				cp++;
164eae5c43dStsutsui 			}
165eae5c43dStsutsui 		}
166eae5c43dStsutsui 		dest++;
167eae5c43dStsutsui 		cp++;	/* skip '-' or ':' etc. */
168feb0773eSgmcgarry 	}
169feb0773eSgmcgarry 
170feb0773eSgmcgarry 	desc->xid = 0x66d30000;
171feb0773eSgmcgarry 
172dd6122d4Stsutsui 	nif = desc->io_netif;
173dd6122d4Stsutsui 	device = nif->nif_driver->netif_bname;
174feb0773eSgmcgarry 	if (callv == &callvec)
175feb0773eSgmcgarry 		sc_fd = prom_open(device, 0);
176feb0773eSgmcgarry 	else
177feb0773eSgmcgarry 		sc_fd = (*callv->_bootinit)(device);
178feb0773eSgmcgarry 
179feb0773eSgmcgarry 	if (sc_fd < 0)
180feb0773eSgmcgarry 		printf("problem initialising device\n");
181feb0773eSgmcgarry }
182feb0773eSgmcgarry 
183feb0773eSgmcgarry 
184feb0773eSgmcgarry int
prom_put(struct iodesc * desc,void * pkt,size_t len)185454af1c0Sdsl prom_put(struct iodesc *desc, void *pkt, size_t len)
186feb0773eSgmcgarry {
187feb0773eSgmcgarry 	int s;
188feb0773eSgmcgarry 
189dd6122d4Stsutsui 	DPRINTF(("prom_put: called\n"));
190feb0773eSgmcgarry 
191feb0773eSgmcgarry #ifdef NET_DEBUG
192feb0773eSgmcgarry 	if (debug)
193feb0773eSgmcgarry 		dump_packet_info(pkt,len);
194feb0773eSgmcgarry #endif
195feb0773eSgmcgarry 
196feb0773eSgmcgarry 	if (callv == &callvec)
197feb0773eSgmcgarry 		s = prom_write(sc_fd, pkt, len);
198feb0773eSgmcgarry 	else {
199feb0773eSgmcgarry 		s = (*callv->_bootwrite)(0, pkt, len);
200feb0773eSgmcgarry 		(*callv->_wbflush)(); /* didn't really make a difference */
201feb0773eSgmcgarry 	}
202feb0773eSgmcgarry 	if (s < 0)
203dd6122d4Stsutsui 		return EIO;
204feb0773eSgmcgarry 	return s;
205feb0773eSgmcgarry }
206feb0773eSgmcgarry 
207feb0773eSgmcgarry 
208feb0773eSgmcgarry int
prom_get(struct iodesc * desc,void * pkt,size_t len,saseconds_t timeout)209454af1c0Sdsl prom_get(struct iodesc *desc, void *pkt, size_t len, saseconds_t timeout)
210feb0773eSgmcgarry {
211feb0773eSgmcgarry 	int s;
21269cf32a7Stsutsui 	satime_t t;
213feb0773eSgmcgarry 
214dd6122d4Stsutsui 	DPRINTF(("prom_get: called\n"));
215feb0773eSgmcgarry 
216feb0773eSgmcgarry 	t = getsecs();
217feb0773eSgmcgarry 	s = 0;
218feb0773eSgmcgarry 	while (((getsecs() - t) < timeout) && !s) {
219feb0773eSgmcgarry 		if (callv == &callvec)
220feb0773eSgmcgarry 			s = prom_read(sc_fd, pkt, len);
221feb0773eSgmcgarry 		else
222feb0773eSgmcgarry 			s = (*callv->_bootread)(0, pkt, len);
223feb0773eSgmcgarry 	}
224feb0773eSgmcgarry 
225feb0773eSgmcgarry #ifdef FILL_ARPCACHE
226feb0773eSgmcgarry 	if (s > 0)
227feb0773eSgmcgarry 		fill_arpcache(pkt,s);
228feb0773eSgmcgarry #endif
229feb0773eSgmcgarry 
230feb0773eSgmcgarry 	return s;
231feb0773eSgmcgarry }
232feb0773eSgmcgarry 
233feb0773eSgmcgarry 
234feb0773eSgmcgarry void
prom_end(struct netif * nif)235454af1c0Sdsl prom_end(struct netif *nif)
236feb0773eSgmcgarry {
237feb0773eSgmcgarry 
238dd6122d4Stsutsui 	DPRINTF(("prom_end: called\n"));
239feb0773eSgmcgarry 
240feb0773eSgmcgarry 	if (callv == &callvec)
241feb0773eSgmcgarry 		prom_close(sc_fd);
242feb0773eSgmcgarry }
243feb0773eSgmcgarry 
244feb0773eSgmcgarry 
245feb0773eSgmcgarry #ifdef FILL_ARPCACHE
246dd6122d4Stsutsui void
fill_arpcache(void * pkt,int len)247dd6122d4Stsutsui fill_arpcache(void *pkt, int len)
248feb0773eSgmcgarry {
249feb0773eSgmcgarry 	int i;
250feb0773eSgmcgarry 	struct arp_list *al;
251feb0773eSgmcgarry 	struct ether_header *eh = (struct ether_header *)pkt;
252feb0773eSgmcgarry 	struct ip *ih = (struct ip *)(eh + 1);
253feb0773eSgmcgarry 
254feb0773eSgmcgarry #ifdef NET_DEBUG
255feb0773eSgmcgarry 	if (debug)
256feb0773eSgmcgarry 		dump_packet_info(pkt, len);
257feb0773eSgmcgarry #endif
258feb0773eSgmcgarry 
259feb0773eSgmcgarry 	if (ntohs(eh->ether_type) == 0x0800) {
260feb0773eSgmcgarry 
261feb0773eSgmcgarry 		/* check arp cache */
262feb0773eSgmcgarry 		for (i=0, al=arp_list; i<arp_num; ++i, ++al) {
263feb0773eSgmcgarry 			if (al->addr.s_addr == ih->ip_src.s_addr) {
264feb0773eSgmcgarry 				/* already in cache */
265feb0773eSgmcgarry 				return;
266feb0773eSgmcgarry 			}
267feb0773eSgmcgarry 		}
268feb0773eSgmcgarry 		if (arp_num > 7)
269feb0773eSgmcgarry 			arp_num = 1;	/* recycle */
270feb0773eSgmcgarry 		al->addr.s_addr = ih->ip_src.s_addr;
271feb0773eSgmcgarry 		for (i = 0; i < 6; i++)
272feb0773eSgmcgarry 			al->ea[i] = eh->ether_shost[i];
273feb0773eSgmcgarry 		++arp_num;
274feb0773eSgmcgarry 	}
275feb0773eSgmcgarry }
276feb0773eSgmcgarry #endif
277feb0773eSgmcgarry 
278feb0773eSgmcgarry #ifdef NET_DEBUG
279dd6122d4Stsutsui void
dump_packet_info(void * pkt,int len)280dd6122d4Stsutsui dump_packet_info(void *pkt, int len)
281feb0773eSgmcgarry {
282feb0773eSgmcgarry 	struct ether_header *eh = (struct ether_header *)pkt;
283feb0773eSgmcgarry 	struct ip *ih = (struct ip *)(eh + 1);
284feb0773eSgmcgarry 
285feb0773eSgmcgarry 	printf("ether_dhost = %s\n", ether_sprintf(eh->ether_dhost));
286feb0773eSgmcgarry 	printf("ether_shost = %s\n", ether_sprintf(eh->ether_shost));
287feb0773eSgmcgarry 	printf("ether_type = 0x%x\n", ntohs(eh->ether_type));
288feb0773eSgmcgarry 
289feb0773eSgmcgarry 	if (ntohs(eh->ether_type) == 0x0800) {
290feb0773eSgmcgarry 		printf("ip packet version %d\n", ih->ip_v);
291feb0773eSgmcgarry 		printf("source ip: 0x%x\n", ih->ip_src.s_addr);
292feb0773eSgmcgarry 		printf("dest ip: 0x%x\n", ih->ip_dst.s_addr);
293feb0773eSgmcgarry 	}
294feb0773eSgmcgarry }
295feb0773eSgmcgarry #endif
296