mba.c revision 1.5 1 /* $NetBSD: mba.c,v 1.5 1996/03/17 22:56:39 ragge Exp $ */
2 /*
3 * Copyright (c) 1994, 1996 Ludd, University of Lule}, Sweden.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed at Ludd, University of
17 * Lule}, Sweden and its contributors.
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 /*
34 * Simple massbus drive routine.
35 * TODO:
36 * Autoconfig new devices 'on the fly'.
37 * More intelligent way to handle different interrupts.
38 */
39
40 #include <sys/param.h>
41 #include <sys/device.h>
42 #include <sys/queue.h>
43 #include <sys/buf.h>
44 #include <sys/proc.h>
45
46 #include <vm/vm.h>
47 #include <vm/vm_kern.h>
48
49 #include <machine/trap.h>
50 #include <machine/scb.h>
51 #include <machine/nexus.h>
52 #include <machine/pte.h>
53 #include <machine/pcb.h>
54 #include <machine/sid.h>
55
56 #include <vax/mba/mbareg.h>
57 #include <vax/mba/mbavar.h>
58
59 struct mbaunit mbaunit[] = {
60 MBADT_RP04, "rp04", MB_RP,
61 MBADT_RP05, "rp05", MB_RP,
62 MBADT_RP06, "rp06", MB_RP,
63 MBADT_RP07, "rp07", MB_RP,
64 MBADT_RM02, "rm02", MB_RP,
65 MBADT_RM03, "rm03", MB_RP,
66 MBADT_RM05, "rm05", MB_RP,
67 MBADT_RM80, "rm80", MB_RP,
68 0, 0, 0
69 };
70
71 int mbamatch __P((struct device *, void *, void *));
72 void mbaattach __P((struct device *, struct device *, void *));
73 void mbaintr __P((int));
74 int mbaprint __P((void *, char *));
75 void mbaqueue __P((struct mba_device *));
76 void mbastart __P((struct mba_softc *));
77 void mbamapregs __P((struct mba_softc *));
78
79 struct cfdriver mba_cd = {
80 NULL, "mba", DV_DULL
81 };
82
83 struct cfattach mba_ca = {
84 sizeof(struct mba_softc), mbamatch, mbaattach
85 };
86
87 /*
88 * Look if this is a massbuss adapter.
89 */
90 int
91 mbamatch(parent, match, aux)
92 struct device *parent;
93 void *match, *aux;
94 {
95 struct sbi_attach_args *sa = (struct sbi_attach_args *)aux;
96 struct cfdata *cf = match;
97
98 if ((cf->cf_loc[0] != sa->nexnum) && (cf->cf_loc[0] > -1 ))
99 return 0;
100
101 if (sa->type == NEX_MBA)
102 return 1;
103
104 return 0;
105 }
106
107 /*
108 * Attach the found massbuss adapter. Setup its interrupt vectors,
109 * reset it and go searching for drives on it.
110 */
111 void
112 mbaattach(parent, self, aux)
113 struct device *parent, *self;
114 void *aux;
115 {
116 struct mba_softc *sc = (void *)self;
117 struct sbi_attach_args *sa = (struct sbi_attach_args *)aux;
118 volatile struct mba_regs *mbar = (struct mba_regs *)sa->nexaddr;
119 struct mba_attach_args ma;
120 extern struct ivec_dsp idsptch;
121 int i, j;
122
123 printf("\n");
124 /*
125 * Set up interrupt vectors for this MBA.
126 */
127 bcopy(&idsptch, &sc->sc_dsp, sizeof(struct ivec_dsp));
128 scb->scb_nexvec[0][sa->nexnum] = scb->scb_nexvec[1][sa->nexnum] =
129 scb->scb_nexvec[2][sa->nexnum] = scb->scb_nexvec[3][sa->nexnum] =
130 &sc->sc_dsp;
131 sc->sc_dsp.pushlarg = sc->sc_dev.dv_unit;
132 sc->sc_dsp.hoppaddr = mbaintr;
133
134 sc->sc_physnr = sa->nexnum - 8; /* MBA's have TR between 8 - 11... */
135 #ifdef VAX750
136 if (cpunumber == VAX_750)
137 sc->sc_physnr += 4; /* ...but not on 11/750 */
138 #endif
139 sc->sc_first = 0;
140 sc->sc_last = (void *)&sc->sc_first;
141 sc->sc_mbareg = (struct mba_regs *)mbar;
142 mbar->mba_cr = MBACR_INIT; /* Reset adapter */
143 mbar->mba_cr = MBACR_IE; /* Enable interrupts */
144
145 for (i = 0; i < MAXMBADEV; i++) {
146 sc->sc_state = SC_AUTOCONF;
147 if ((mbar->mba_md[i].md_ds & MBADS_DPR) == 0)
148 continue;
149 /* We have a drive, ok. */
150 ma.unit = i;
151 ma.type = mbar->mba_md[i].md_dt & 0777;
152 j = 0;
153 while (mbaunit[j++].nr)
154 if (mbaunit[j].nr == ma.type)
155 break;
156 ma.devtyp = mbaunit[j].devtyp;
157 ma.name = mbaunit[j].name;
158 config_found(&sc->sc_dev, (void *)&ma, mbaprint);
159 }
160 }
161
162 /*
163 * We got an interrupt. Check type of interrupt and call the specific
164 * device interrupt handling routine.
165 */
166 void
167 mbaintr(mba)
168 int mba;
169 {
170 struct mba_softc *sc = mba_cd.cd_devs[mba];
171 volatile struct mba_regs *mr = sc->sc_mbareg;
172 struct mba_device *md;
173 struct buf *bp;
174 int itype, attn, anr, serv = 0;
175
176 itype = mr->mba_sr;
177 mr->mba_sr = itype; /* Write back to clear bits */
178
179 attn = mr->mba_md[0].md_as & 0xff;
180 mr->mba_md[0].md_as = attn;
181
182 if (sc->sc_state == SC_AUTOCONF)
183 return; /* During autoconfig */
184
185 md = sc->sc_first;
186 bp = md->md_q.b_actf;
187 /*
188 * A data-transfer interrupt. Current operation is finished,
189 * call that device's finish routine to see what to do next.
190 */
191 if (sc->sc_state == SC_ACTIVE) {
192
193 sc->sc_state = SC_IDLE;
194 switch ((*md->md_finish)(md, itype, &attn)) {
195
196 case XFER_FINISH:
197 /*
198 * Transfer is finished. Take buffer of drive
199 * queue, and take drive of adapter queue.
200 * If more to transfer, start the adapter again
201 * by calling mbastart().
202 */
203 md->md_q.b_actf = bp->b_actf;
204 sc->sc_first = md->md_back;
205 md->md_back = 0;
206 if (sc->sc_first == 0)
207 sc->sc_last = (void *)&sc->sc_first;
208
209 if (md->md_q.b_actf) {
210 sc->sc_last->md_back = md;
211 sc->sc_last = md;
212 }
213
214 bp->b_resid = 0;
215 biodone(bp);
216 if (sc->sc_first)
217 mbastart(sc);
218 break;
219
220 case XFER_RESTART:
221 /*
222 * Something went wrong with the transfer. Try again.
223 */
224 mbastart(sc);
225 break;
226 }
227 }
228
229 while (attn) {
230 anr = ffs(attn) - 1;
231 attn &= ~(1 << anr);
232 if (sc->sc_md[anr]->md_attn == 0)
233 panic("Should check for new MBA device %d", anr);
234 (*sc->sc_md[anr]->md_attn)(sc->sc_md[anr]);
235 }
236 }
237
238 int
239 mbaprint(aux, mbaname)
240 void *aux;
241 char *mbaname;
242 {
243 struct mba_attach_args *ma = aux;
244
245 if (mbaname) {
246 if (ma->name)
247 printf("%s", ma->name);
248 else
249 printf("device type %o", ma->type);
250 printf(" at %s", mbaname);
251 }
252 printf(" drive %d", ma->unit);
253 return (ma->name ? UNCONF : UNSUPP);
254 }
255
256 /*
257 * A device calls mbaqueue() when it wants to get on the adapter queue.
258 * Called at splbio(). If the adapter is inactive, start it.
259 */
260 void
261 mbaqueue(md)
262 struct mba_device *md;
263 {
264 struct mba_softc *sc = md->md_mba;
265 int i = (int)sc->sc_first;
266
267 sc->sc_last->md_back = md;
268 sc->sc_last = md;
269
270 if (i == 0)
271 mbastart(sc);
272 }
273
274 /*
275 * Start activity on (idling) adapter. Calls mbamapregs() to setup
276 * for dma transfer, then the unit-specific start routine.
277 */
278 void
279 mbastart(sc)
280 struct mba_softc *sc;
281 {
282 struct mba_device *md = sc->sc_first;
283 volatile struct mba_regs *mr = sc->sc_mbareg;
284 struct buf *bp = md->md_q.b_actf;
285
286 mbamapregs(sc);
287
288 sc->sc_state = SC_ACTIVE;
289 mr->mba_var = ((u_int)bp->b_un.b_addr & PGOFSET);
290 mr->mba_bc = (~bp->b_bcount) + 1;
291 (*md->md_start)(md); /* machine-dependent start */
292 }
293
294 /*
295 * Setup map registers for a dma transfer.
296 * This routine could be synced with the other adapter map routines!
297 */
298 void
299 mbamapregs(sc)
300 struct mba_softc *sc;
301 {
302 struct mba_device *md = sc->sc_first;
303 volatile struct mba_regs *mr = sc->sc_mbareg;
304 struct buf *bp = md->md_q.b_actf;
305 struct pcb *pcb;
306 pt_entry_t *pte;
307 volatile pt_entry_t *io;
308 int pfnum, npf, o, i;
309 caddr_t addr;
310
311 o = (int)bp->b_un.b_addr & PGOFSET;
312 npf = btoc(bp->b_bcount + o) + 1;
313 addr = bp->b_un.b_addr;
314
315 /*
316 * Get a pointer to the pte pointing out the first virtual address.
317 * Use different ways in kernel and user space.
318 */
319 if ((bp->b_flags & B_PHYS) == 0) {
320 pte = kvtopte(addr);
321 } else {
322 pcb = bp->b_proc->p_vmspace->vm_pmap.pm_pcb;
323 pte = uvtopte(addr, pcb);
324 }
325
326 /*
327 * When we are doing DMA to user space, be sure that all pages
328 * we want to transfer to is mapped. WHY DO WE NEED THIS???
329 * SHOULDN'T THEY ALWAYS BE MAPPED WHEN DOING THIS???
330 */
331 for (i = 0; i < (npf - 1); i++) {
332 if ((pte + i)->pg_pfn == 0) {
333 int rv;
334 rv = vm_fault(&bp->b_proc->p_vmspace->vm_map,
335 (unsigned)addr + i * NBPG,
336 VM_PROT_READ|VM_PROT_WRITE, FALSE);
337 if (rv)
338 panic("MBA DMA to nonexistent page, %d", rv);
339 }
340 }
341
342 io = &mr->mba_map[0];
343 while (--npf > 0) {
344 pfnum = pte->pg_pfn;
345 if (pfnum == 0)
346 panic("mba zero entry");
347 pte++;
348 *(int *)io++ = pfnum | PG_V;
349 }
350 *(int *)io = 0;
351 }
352
353
354