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