Commit | Line | Data |
---|---|---|
896962b1 | 1 | /* uda.c 4.10 82/10/10 */ |
db738443 BJ |
2 | |
3 | #include "ra.h" | |
4 | #if NUDA > 0 | |
5 | /* | |
6 | * UDA50/RAxx disk device driver | |
7 | * | |
8 | * Restrictions: | |
9 | * Unit numbers must be less than 8. | |
10 | * | |
11 | * TO DO: | |
12 | * write dump code | |
13 | * test on 750 | |
14 | */ | |
15 | ||
16 | #include "../h/param.h" | |
17 | #include "../h/systm.h" | |
18 | #include "../h/buf.h" | |
19 | #include "../h/conf.h" | |
20 | #include "../h/dir.h" | |
21 | #include "../h/user.h" | |
22 | #include "../h/pte.h" | |
23 | #include "../h/map.h" | |
24 | #include "../h/vm.h" | |
db738443 | 25 | #include "../h/dk.h" |
db738443 | 26 | #include "../h/cmap.h" |
740e4029 | 27 | #include "../h/uio.h" |
db738443 | 28 | |
896962b1 BJ |
29 | #include "../vax/cpu.h" |
30 | #include "../vaxuba/ubareg.h" | |
31 | #include "../vaxuba/ubavar.h" | |
32 | #include "../vaxuba/udareg.h" | |
33 | ||
db738443 BJ |
34 | int udadebug; |
35 | #define printd if(udadebug&1)printf | |
36 | ||
5fd46eab SL |
37 | int udaerror = 0; /* set to cause hex dump of error log packets */ |
38 | ||
db738443 BJ |
39 | /* |
40 | * Parameters for the communications area | |
41 | */ | |
42 | ||
5fd46eab SL |
43 | #define NRSPL2 3 /* log2 number of response packets */ |
44 | #define NCMDL2 3 /* log2 number of command packets */ | |
db738443 BJ |
45 | #define NRSP (1<<NRSPL2) |
46 | #define NCMD (1<<NCMDL2) | |
47 | ||
896962b1 | 48 | #include "../vax/mscp.h" |
db738443 BJ |
49 | |
50 | struct uda_softc { | |
51 | short sc_state; /* state of controller */ | |
52 | short sc_mapped; /* Unibus map allocated for uda struct? */ | |
53 | int sc_ubainfo; /* Unibus mapping info */ | |
54 | struct uda *sc_uda; /* Unibus address of uda struct */ | |
55 | int sc_ivec; /* interrupt vector address */ | |
56 | short sc_credits; /* transfer credits */ | |
57 | short sc_lastcmd; /* pointer into command ring */ | |
58 | short sc_lastrsp; /* pointer into response ring */ | |
59 | } uda_softc[NUDA]; | |
60 | ||
61 | /* | |
62 | * Controller states | |
63 | */ | |
64 | #define S_IDLE 0 /* hasn't been initialized */ | |
65 | #define S_STEP1 1 /* doing step 1 init */ | |
66 | #define S_STEP2 2 /* doing step 2 init */ | |
67 | #define S_STEP3 3 /* doing step 3 init */ | |
68 | #define S_SCHAR 4 /* doing "set controller characteristics" */ | |
69 | #define S_RUN 5 /* running */ | |
70 | ||
71 | struct uda { | |
72 | struct udaca uda_ca; /* communications area */ | |
73 | struct mscp uda_rsp[NRSP]; /* response packets */ | |
74 | struct mscp uda_cmd[NCMD]; /* command packets */ | |
75 | } uda[NUDA]; | |
76 | ||
77 | /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */ | |
78 | struct size { | |
79 | daddr_t nblocks; | |
80 | daddr_t blkoff; | |
81 | } ra_sizes[8] ={ | |
82 | 15884, 0, /* A=blk 0 thru 15883 */ | |
83 | 33440, 15884, /* B=blk 15884 thru 49323 */ | |
84 | -1, 0, /* C=blk 0 thru end */ | |
5fd46eab SL |
85 | 15884, 340670, /* D=blk 340670 thru 356553 */ |
86 | 55936, 356554, /* E=blk 356554 thru 412489 */ | |
87 | -1, 412490, /* F=blk 412490 thru end */ | |
db738443 BJ |
88 | 82080, 49324, /* G=blk 49324 thru 131403 */ |
89 | -1, 131404, /* H=blk 131404 thru end */ | |
90 | }; | |
91 | /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */ | |
92 | ||
93 | daddr_t radsize[NRA]; /* disk size, from ONLINE end packet */ | |
94 | ||
95 | int udprobe(), udslave(), udattach(), udintr(); | |
96 | struct mscp *udgetcp(); | |
97 | struct uba_ctlr *udminfo[NUDA]; | |
98 | struct uba_device *uddinfo[NRA]; | |
99 | struct uba_device *udip[NUDA][8]; /* 8 == max number of drives */ | |
100 | ||
5fd46eab | 101 | u_short udstd[] = { 0772150, 0 }; |
db738443 BJ |
102 | struct uba_driver udadriver = |
103 | { udprobe, udslave, udattach, 0, udstd, "ra", uddinfo, "uda", udminfo, 0 }; | |
104 | struct buf rudbuf[NRA]; | |
105 | struct buf udutab[NRA]; | |
106 | struct buf udwtab[NUDA]; /* I/O wait queue, per controller */ | |
107 | ||
108 | #define b_qsize b_resid /* queue size per drive, in udutab */ | |
109 | #define b_ubinfo b_resid /* Unibus mapping info, per buffer */ | |
110 | ||
111 | udprobe(reg, ctlr) | |
112 | caddr_t reg; | |
113 | int ctlr; | |
114 | { | |
115 | register int br, cvec; | |
116 | register struct uda_softc *sc = &uda_softc[ctlr]; | |
117 | ||
118 | #ifdef lint | |
155d9ff0 | 119 | br = 0; cvec = br; br = cvec; reg = reg; |
002227dd | 120 | udread(0, 0); udwrite(0, 0); udreset(0); udintr(0); |
db738443 BJ |
121 | #endif |
122 | /* SHOULD CHECK THAT IT REALLY IS A UDA */ | |
123 | br = 0x15; | |
124 | cvec = sc->sc_ivec = (uba_hd[numuba].uh_lastiv -= 4); | |
9c0adba0 | 125 | return(sizeof (struct udadevice)); |
db738443 BJ |
126 | } |
127 | ||
128 | udslave(ui, reg) | |
129 | struct uba_device *ui; | |
130 | caddr_t reg; | |
131 | { | |
132 | /* | |
133 | * TOO HARD TO FIND OUT IF DISK IS THERE UNTIL | |
134 | * INITIALIZED. WE'LL FIND OUT WHEN WE FIRST | |
135 | * TRY TO ACCESS IT. | |
136 | */ | |
155d9ff0 SL |
137 | #ifdef lint |
138 | ui = ui; reg = reg; | |
139 | #endif | |
db738443 BJ |
140 | return(1); |
141 | } | |
142 | ||
143 | udattach(ui) | |
144 | register struct uba_device *ui; | |
145 | { | |
146 | ||
147 | if (ui->ui_dk > 0) | |
148 | dk_mspw[ui->ui_dk] = 1.0 / (60 * 31 * 256); /* approx */ | |
149 | ui->ui_flags = 0; | |
150 | udip[ui->ui_ctlr][ui->ui_slave] = ui; | |
151 | radsize[ui->ui_unit] = (daddr_t)0xffffff; /* max possible size */ | |
152 | } | |
153 | ||
154 | /* | |
155 | * Open a UDA. Initialize the device and | |
156 | * set the unit online. | |
157 | */ | |
158 | udopen(dev, flag) | |
159 | dev_t dev; | |
160 | int flag; | |
161 | { | |
162 | register int unit; | |
163 | register struct uba_device *ui; | |
164 | register struct uda_softc *sc; | |
530d0032 | 165 | int s; |
db738443 | 166 | |
155d9ff0 SL |
167 | #ifdef lint |
168 | flag = flag; | |
169 | #endif | |
db738443 BJ |
170 | unit = minor(dev) >> 3; |
171 | if (unit >= NRA || (ui = uddinfo[unit]) == 0 || ui->ui_alive == 0) { | |
172 | u.u_error = ENXIO; | |
173 | return; | |
174 | } | |
175 | sc = &uda_softc[ui->ui_ctlr]; | |
530d0032 | 176 | s = spl5(); |
db738443 BJ |
177 | if (sc->sc_state != S_RUN) { |
178 | if (sc->sc_state == S_IDLE) | |
179 | udinit(ui->ui_ctlr); | |
155d9ff0 SL |
180 | /* wait for initialization to complete */ |
181 | sleep((caddr_t)ui->ui_mi, 0); | |
db738443 BJ |
182 | if (sc->sc_state != S_RUN) { |
183 | u.u_error = EIO; | |
184 | return; | |
185 | } | |
186 | } | |
530d0032 | 187 | splx(s); |
db738443 BJ |
188 | /* SHOULD PROBABLY FORCE AN ONLINE ATTEMPT |
189 | TO SEE IF DISK IS REALLY THERE */ | |
190 | } | |
191 | ||
192 | /* | |
193 | * Initialize a UDA. Set up UBA mapping registers, | |
194 | * initialize data structures, and start hardware | |
195 | * initialization sequence. | |
196 | */ | |
197 | udinit(d) | |
198 | int d; | |
199 | { | |
200 | register struct uda_softc *sc; | |
201 | register struct uda *ud; | |
202 | struct udadevice *udaddr; | |
203 | struct uba_ctlr *um; | |
204 | ||
205 | sc = &uda_softc[d]; | |
206 | um = udminfo[d]; | |
207 | um->um_tab.b_active++; | |
208 | ud = &uda[d]; | |
209 | udaddr = (struct udadevice *)um->um_addr; | |
210 | if (sc->sc_mapped == 0) { | |
211 | /* | |
212 | * Map the communications area and command | |
213 | * and response packets into Unibus address | |
214 | * space. | |
215 | */ | |
216 | sc->sc_ubainfo = uballoc(um->um_ubanum, (caddr_t)ud, | |
217 | sizeof (struct uda), 0); | |
218 | sc->sc_uda = (struct uda *)(sc->sc_ubainfo & 0x3ffff); | |
219 | sc->sc_mapped = 1; | |
220 | } | |
221 | ||
222 | /* | |
223 | * Start the hardware initialization sequence. | |
224 | */ | |
225 | udaddr->udaip = 0; /* start initialization */ | |
226 | while ((udaddr->udasa & UDA_STEP1) == 0) | |
227 | ; | |
228 | udaddr->udasa = UDA_ERR|(NCMDL2<<11)|(NRSPL2<<8)|UDA_IE|(sc->sc_ivec/4); | |
229 | /* | |
230 | * Initialization continues in interrupt routine. | |
231 | */ | |
232 | sc->sc_state = S_STEP1; | |
233 | sc->sc_credits = 0; | |
234 | } | |
235 | ||
236 | udstrategy(bp) | |
237 | register struct buf *bp; | |
238 | { | |
239 | register struct uba_device *ui; | |
240 | register struct uba_ctlr *um; | |
241 | register struct buf *dp; | |
242 | register int unit; | |
243 | int xunit = minor(bp->b_dev) & 07; | |
244 | daddr_t sz, maxsz; | |
530d0032 | 245 | int s; |
db738443 BJ |
246 | |
247 | sz = (bp->b_bcount+511) >> 9; | |
248 | unit = dkunit(bp); | |
249 | if (unit >= NRA) | |
250 | goto bad; | |
251 | ui = uddinfo[unit]; | |
252 | um = ui->ui_mi; | |
253 | if (ui == 0 || ui->ui_alive == 0) | |
254 | goto bad; | |
255 | if ((maxsz = ra_sizes[xunit].nblocks) < 0) | |
256 | maxsz = radsize[unit] - ra_sizes[xunit].blkoff; | |
257 | if (bp->b_blkno < 0 || bp->b_blkno+sz > maxsz || | |
258 | ra_sizes[xunit].blkoff >= radsize[unit]) | |
259 | goto bad; | |
530d0032 | 260 | s = spl5(); |
db738443 BJ |
261 | /* |
262 | * Link the buffer onto the drive queue | |
263 | */ | |
264 | dp = &udutab[ui->ui_unit]; | |
265 | if (dp->b_actf == 0) | |
266 | dp->b_actf = bp; | |
267 | else | |
268 | dp->b_actl->av_forw = bp; | |
269 | dp->b_actl = bp; | |
270 | bp->av_forw = 0; | |
271 | /* | |
272 | * Link the drive onto the controller queue | |
273 | */ | |
274 | if (dp->b_active == 0) { | |
275 | dp->b_forw = NULL; | |
276 | if (um->um_tab.b_actf == NULL) | |
277 | um->um_tab.b_actf = dp; | |
278 | else | |
279 | um->um_tab.b_actl->b_forw = dp; | |
280 | um->um_tab.b_actl = dp; | |
281 | dp->b_active = 1; | |
282 | } | |
283 | if (um->um_tab.b_active == 0) { | |
284 | #if defined(VAX750) | |
285 | if (cpu == VAX_750) { | |
286 | if (um->um_ubinfo != 0) | |
287 | printf("uda: ubinfo %x\n",um->um_ubinfo); | |
288 | else | |
289 | um->um_ubinfo = | |
155d9ff0 SL |
290 | uballoc(um->um_ubanum, (caddr_t)0, 0, |
291 | UBA_NEEDBDP); | |
db738443 BJ |
292 | } |
293 | #endif | |
294 | (void) udstart(um); | |
295 | } | |
530d0032 | 296 | splx(s); |
db738443 BJ |
297 | return; |
298 | ||
299 | bad: | |
300 | bp->b_flags |= B_ERROR; | |
301 | iodone(bp); | |
302 | return; | |
303 | } | |
304 | ||
305 | udstart(um) | |
306 | register struct uba_ctlr *um; | |
307 | { | |
308 | register struct buf *bp, *dp; | |
309 | register struct mscp *mp; | |
310 | register struct uda_softc *sc; | |
311 | register struct uba_device *ui; | |
312 | struct udadevice *udaddr; | |
313 | int i; | |
314 | ||
315 | sc = &uda_softc[um->um_ctlr]; | |
316 | ||
317 | loop: | |
318 | if ((dp = um->um_tab.b_actf) == NULL) { | |
319 | /* | |
320 | * Release uneeded UBA resources and return | |
321 | */ | |
322 | um->um_tab.b_active = 0; | |
323 | #if defined(VAX750) | |
324 | if (cpu == VAX_750) { | |
325 | if (um->um_ubinfo == 0) | |
326 | printf("uda: um_ubinfo == 0\n"); | |
327 | else | |
328 | ubarelse(um->um_ubanum, &um->um_ubinfo); | |
329 | } | |
330 | #endif | |
155d9ff0 | 331 | return (0); |
db738443 BJ |
332 | } |
333 | if ((bp = dp->b_actf) == NULL) { | |
334 | /* | |
335 | * No more requests for this drive, remove | |
336 | * from controller queue and look at next drive. | |
337 | * We know we're at the head of the controller queue. | |
338 | */ | |
339 | dp->b_active = 0; | |
340 | um->um_tab.b_actf = dp->b_forw; | |
341 | goto loop; | |
342 | } | |
343 | um->um_tab.b_active++; | |
344 | udaddr = (struct udadevice *)um->um_addr; | |
345 | if ((udaddr->udasa&UDA_ERR) || sc->sc_state != S_RUN) { | |
346 | harderr(bp, "ra"); | |
347 | printf("udasa %o, state %d\n", udaddr->udasa&0xffff, sc->sc_state); | |
348 | udinit(um->um_ctlr); | |
349 | /* SHOULD REQUEUE OUTSTANDING REQUESTS, LIKE UDRESET */ | |
155d9ff0 | 350 | return (0); |
db738443 BJ |
351 | } |
352 | ui = uddinfo[dkunit(bp)]; | |
353 | /* | |
354 | * If no credits, can't issue any commands | |
355 | * until some outstanding commands complete. | |
356 | */ | |
357 | if (sc->sc_credits < 2) | |
155d9ff0 | 358 | return (0); |
db738443 | 359 | if ((mp = udgetcp(um)) == NULL) |
155d9ff0 | 360 | return (0); |
db738443 BJ |
361 | sc->sc_credits--; /* committed to issuing a command */ |
362 | if (ui->ui_flags == 0) { /* not online */ | |
363 | mp->mscp_opcode = M_OP_ONLIN; | |
364 | mp->mscp_unit = ui->ui_slave; | |
365 | dp->b_active = 2; | |
366 | um->um_tab.b_actf = dp->b_forw; /* remove from controller q */ | |
367 | printd("uda: bring unit %d online\n", ui->ui_slave); | |
368 | *((long *)mp->mscp_dscptr) |= UDA_OWN|UDA_INT; | |
369 | i = udaddr->udaip; | |
370 | goto loop; | |
371 | } | |
372 | switch (cpu) { | |
373 | case VAX_780: | |
374 | i = UBA_NEEDBDP|UBA_CANTWAIT; | |
375 | break; | |
376 | ||
377 | case VAX_750: | |
378 | i = um->um_ubinfo|UBA_HAVEBDP|UBA_CANTWAIT; | |
379 | break; | |
380 | ||
10f66600 | 381 | case VAX_730: |
db738443 BJ |
382 | i = UBA_CANTWAIT; |
383 | break; | |
384 | } | |
385 | if ((i = ubasetup(um->um_ubanum, bp, i)) == 0) { | |
386 | mp->mscp_opcode = M_OP_GTUNT; | |
387 | mp->mscp_unit = ui->ui_slave; | |
388 | *((long *)mp->mscp_dscptr) |= UDA_OWN|UDA_INT; | |
389 | i = udaddr->udaip; /* initiate polling */ | |
390 | return(1); /* wait for interrupt */ | |
391 | } | |
392 | mp->mscp_cmdref = (long)bp; /* pointer to get back */ | |
393 | mp->mscp_opcode = bp->b_flags&B_READ ? M_OP_READ : M_OP_WRITE; | |
394 | mp->mscp_unit = ui->ui_slave; | |
395 | mp->mscp_lbn = bp->b_blkno + ra_sizes[minor(bp->b_dev)&7].blkoff; | |
396 | mp->mscp_bytecnt = bp->b_bcount; | |
397 | mp->mscp_buffer = (i & 0x3ffff) | (((i>>28)&0xf)<<24); | |
398 | #if defined(VAX750) | |
399 | if (cpu == VAX_750) | |
400 | i &= 0xfffffff; /* mask off bdp */ | |
401 | #endif | |
402 | bp->b_ubinfo = i; /* save mapping info */ | |
403 | *((long *)mp->mscp_dscptr) |= UDA_OWN|UDA_INT; | |
404 | i = udaddr->udaip; /* initiate polling */ | |
405 | if (ui->ui_dk >= 0) { | |
406 | dk_busy |= 1<<ui->ui_dk; | |
407 | dp->b_qsize++; | |
408 | dk_xfer[ui->ui_dk]++; | |
409 | dk_wds[ui->ui_dk] += bp->b_bcount>>6; | |
410 | } | |
411 | ||
412 | /* | |
413 | * Move drive to the end of the controller queue | |
414 | */ | |
415 | if (dp->b_forw != NULL) { | |
416 | um->um_tab.b_actf = dp->b_forw; | |
417 | um->um_tab.b_actl->b_forw = dp; | |
418 | um->um_tab.b_actl = dp; | |
419 | dp->b_forw = NULL; | |
420 | } | |
421 | /* | |
422 | * Move buffer to I/O wait queue | |
423 | */ | |
424 | dp->b_actf = bp->av_forw; | |
425 | dp = &udwtab[um->um_ctlr]; | |
426 | bp->av_forw = dp; | |
427 | bp->av_back = dp->av_back; | |
428 | dp->av_back->av_forw = bp; | |
429 | dp->av_back = bp; | |
430 | goto loop; | |
431 | } | |
432 | ||
433 | /* | |
434 | * UDA interrupt routine. | |
435 | */ | |
436 | udintr(d) | |
437 | int d; | |
438 | { | |
439 | register struct uba_ctlr *um = udminfo[d]; | |
440 | register struct udadevice *udaddr = (struct udadevice *)um->um_addr; | |
441 | struct buf *bp; | |
442 | register int i; | |
443 | register struct uda_softc *sc = &uda_softc[d]; | |
444 | register struct uda *ud = &uda[d]; | |
445 | struct uda *uud; | |
446 | struct mscp *mp; | |
447 | ||
448 | printd("udintr: state %d, udasa %o\n", sc->sc_state, udaddr->udasa); | |
449 | switch (sc->sc_state) { | |
450 | case S_IDLE: | |
451 | printf("uda%d: random interrupt ignored\n", d); | |
452 | return; | |
453 | ||
454 | case S_STEP1: | |
5fd46eab | 455 | #define STEP1MASK 0174377 |
db738443 | 456 | #define STEP1GOOD (UDA_STEP2|UDA_IE|(NCMDL2<<3)|NRSPL2) |
5fd46eab | 457 | if ((udaddr->udasa&STEP1MASK) != STEP1GOOD) { |
db738443 | 458 | sc->sc_state = S_IDLE; |
155d9ff0 | 459 | wakeup((caddr_t)um); |
db738443 BJ |
460 | return; |
461 | } | |
462 | udaddr->udasa = ((int)&sc->sc_uda->uda_ca.ca_ringbase)| | |
463 | (cpu == VAX_780 ? UDA_PI : 0); | |
464 | sc->sc_state = S_STEP2; | |
465 | return; | |
466 | ||
467 | case S_STEP2: | |
5fd46eab | 468 | #define STEP2MASK 0174377 |
db738443 | 469 | #define STEP2GOOD (UDA_STEP3|UDA_IE|(sc->sc_ivec/4)) |
5fd46eab | 470 | if ((udaddr->udasa&STEP2MASK) != STEP2GOOD) { |
db738443 | 471 | sc->sc_state = S_IDLE; |
155d9ff0 | 472 | wakeup((caddr_t)um); |
db738443 BJ |
473 | return; |
474 | } | |
475 | udaddr->udasa = ((int)&sc->sc_uda->uda_ca.ca_ringbase)>>16; | |
476 | sc->sc_state = S_STEP3; | |
477 | return; | |
478 | ||
479 | case S_STEP3: | |
5fd46eab | 480 | #define STEP3MASK 0174000 |
db738443 | 481 | #define STEP3GOOD UDA_STEP4 |
5fd46eab | 482 | if ((udaddr->udasa&STEP3MASK) != STEP3GOOD) { |
db738443 | 483 | sc->sc_state = S_IDLE; |
155d9ff0 | 484 | wakeup((caddr_t)um); |
db738443 BJ |
485 | return; |
486 | } | |
487 | udaddr->udasa = UDA_GO; | |
488 | sc->sc_state = S_SCHAR; | |
489 | ||
490 | /* | |
491 | * Initialize the data structures. | |
492 | */ | |
493 | uud = sc->sc_uda; | |
494 | for (i = 0; i < NRSP; i++) { | |
495 | ud->uda_ca.ca_rspdsc[i] = UDA_OWN|UDA_INT| | |
496 | (long)&uud->uda_rsp[i].mscp_cmdref; | |
497 | ud->uda_rsp[i].mscp_dscptr = &ud->uda_ca.ca_rspdsc[i]; | |
498 | ud->uda_rsp[i].mscp_header.uda_msglen = sizeof (struct mscp); | |
499 | } | |
500 | for (i = 0; i < NCMD; i++) { | |
501 | ud->uda_ca.ca_cmddsc[i] = UDA_INT| | |
502 | (long)&uud->uda_cmd[i].mscp_cmdref; | |
503 | ud->uda_cmd[i].mscp_dscptr = &ud->uda_ca.ca_cmddsc[i]; | |
504 | ud->uda_cmd[i].mscp_header.uda_msglen = sizeof (struct mscp); | |
505 | } | |
506 | bp = &udwtab[d]; | |
507 | bp->av_forw = bp->av_back = bp; | |
508 | sc->sc_lastcmd = 0; | |
509 | sc->sc_lastrsp = 0; | |
510 | if ((mp = udgetcp(um)) == NULL) { | |
511 | sc->sc_state = S_IDLE; | |
155d9ff0 | 512 | wakeup((caddr_t)um); |
db738443 BJ |
513 | return; |
514 | } | |
515 | mp->mscp_opcode = M_OP_STCON; | |
516 | mp->mscp_cntflgs = M_CF_ATTN|M_CF_MISC|M_CF_THIS; | |
517 | *((long *)mp->mscp_dscptr) |= UDA_OWN|UDA_INT; | |
518 | i = udaddr->udaip; /* initiate polling */ | |
519 | return; | |
520 | ||
521 | case S_SCHAR: | |
522 | case S_RUN: | |
523 | break; | |
524 | ||
525 | default: | |
526 | printf("uda%d: interrupt in unknown state %d ignored\n", | |
527 | d, sc->sc_state); | |
528 | return; | |
529 | } | |
530 | ||
531 | if (udaddr->udasa&UDA_ERR) { | |
532 | printf("uda%d: fatal error (%o)\n", d, udaddr->udasa&0xffff); | |
533 | udaddr->udaip = 0; | |
155d9ff0 | 534 | wakeup((caddr_t)um); |
db738443 BJ |
535 | } |
536 | ||
537 | /* | |
538 | * Check for a buffer purge request. | |
539 | */ | |
540 | if (ud->uda_ca.ca_bdp) { | |
541 | /* | |
542 | * THIS IS A KLUDGE. | |
543 | * Maybe we should change the entire | |
544 | * UBA interface structure. | |
545 | */ | |
546 | int s = spl7(); | |
547 | ||
548 | i = um->um_ubinfo; | |
549 | printd("uda: purge bdp %d\n", ud->uda_ca.ca_bdp); | |
550 | um->um_ubinfo = ud->uda_ca.ca_bdp<<28; | |
551 | ubapurge(um); | |
552 | um->um_ubinfo = i; | |
553 | (void) splx(s); | |
554 | ud->uda_ca.ca_bdp = 0; | |
555 | udaddr->udasa = 0; /* signal purge complete */ | |
556 | } | |
557 | ||
558 | /* | |
559 | * Check for response ring transition. | |
560 | */ | |
561 | if (ud->uda_ca.ca_rspint) { | |
562 | ud->uda_ca.ca_rspint = 0; | |
563 | for (i = sc->sc_lastrsp;; i++) { | |
564 | i %= NRSP; | |
565 | if (ud->uda_ca.ca_rspdsc[i]&UDA_OWN) | |
566 | break; | |
567 | udrsp(um, ud, sc, i); | |
568 | ud->uda_ca.ca_rspdsc[i] |= UDA_OWN; | |
569 | } | |
570 | sc->sc_lastrsp = i; | |
571 | } | |
572 | ||
573 | /* | |
574 | * Check for command ring transition. | |
575 | */ | |
576 | if (ud->uda_ca.ca_cmdint) { | |
577 | printd("uda: command ring transition\n"); | |
578 | ud->uda_ca.ca_cmdint = 0; | |
579 | } | |
155d9ff0 | 580 | (void) udstart(um); |
db738443 BJ |
581 | } |
582 | ||
583 | /* | |
584 | * Process a response packet | |
585 | */ | |
586 | udrsp(um, ud, sc, i) | |
587 | register struct uba_ctlr *um; | |
588 | register struct uda *ud; | |
589 | register struct uda_softc *sc; | |
590 | int i; | |
591 | { | |
592 | register struct mscp *mp; | |
593 | struct uba_device *ui; | |
594 | struct buf *dp, *bp; | |
595 | int st; | |
596 | ||
597 | mp = &ud->uda_rsp[i]; | |
598 | mp->mscp_header.uda_msglen = sizeof (struct mscp); | |
599 | sc->sc_credits += mp->mscp_header.uda_credits & 0xf; | |
600 | if ((mp->mscp_header.uda_credits & 0xf0) > 0x10) | |
601 | return; | |
602 | /* | |
603 | * If it's an error log message (datagram), | |
604 | * pass it on for more extensive processing. | |
605 | */ | |
606 | if ((mp->mscp_header.uda_credits & 0xf0) == 0x10) { | |
607 | uderror(um, (struct mslg *)mp); | |
608 | return; | |
609 | } | |
610 | if (mp->mscp_unit >= 8) | |
611 | return; | |
612 | if ((ui = udip[um->um_ctlr][mp->mscp_unit]) == 0) | |
613 | return; | |
614 | st = mp->mscp_status&M_ST_MASK; | |
615 | switch (mp->mscp_opcode) { | |
616 | case M_OP_STCON|M_OP_END: | |
617 | if (st == M_ST_SUCC) | |
618 | sc->sc_state = S_RUN; | |
619 | else | |
620 | sc->sc_state = S_IDLE; | |
621 | um->um_tab.b_active = 0; | |
155d9ff0 | 622 | wakeup((caddr_t)um); |
db738443 BJ |
623 | break; |
624 | ||
625 | case M_OP_ONLIN|M_OP_END: | |
626 | /* | |
627 | * Link the drive onto the controller queue | |
628 | */ | |
629 | dp = &udutab[ui->ui_unit]; | |
630 | dp->b_forw = NULL; | |
631 | if (um->um_tab.b_actf == NULL) | |
632 | um->um_tab.b_actf = dp; | |
633 | else | |
634 | um->um_tab.b_actl->b_forw = dp; | |
635 | um->um_tab.b_actl = dp; | |
636 | if (st == M_ST_SUCC) { | |
637 | ui->ui_flags = 1; /* mark it online */ | |
638 | radsize[ui->ui_unit] = (daddr_t)mp->mscp_untsize; | |
639 | printd("uda: unit %d online\n", mp->mscp_unit); | |
640 | } else { | |
641 | harderr(dp->b_actf, "ra"); | |
642 | printf("OFFLINE\n"); | |
643 | while (bp = dp->b_actf) { | |
644 | dp->b_actf = bp->av_forw; | |
645 | bp->b_flags |= B_ERROR; | |
646 | iodone(bp); | |
647 | } | |
648 | } | |
649 | dp->b_active = 1; | |
650 | break; | |
651 | ||
652 | case M_OP_AVATN: | |
653 | printd("uda: unit %d attention\n", mp->mscp_unit); | |
654 | ui->ui_flags = 0; /* it went offline and we didn't notice */ | |
655 | break; | |
656 | ||
657 | case M_OP_READ|M_OP_END: | |
658 | case M_OP_WRITE|M_OP_END: | |
659 | bp = (struct buf *)mp->mscp_cmdref; | |
5fd46eab | 660 | ubarelse(um->um_ubanum, (int *)&bp->b_ubinfo); |
db738443 BJ |
661 | /* |
662 | * Unlink buffer from I/O wait queue. | |
663 | */ | |
664 | bp->av_back->av_forw = bp->av_forw; | |
665 | bp->av_forw->av_back = bp->av_back; | |
666 | dp = &udutab[ui->ui_unit]; | |
667 | if (ui->ui_dk >= 0) | |
668 | if (--dp->b_qsize == 0) | |
669 | dk_busy &= ~(1<<ui->ui_dk); | |
670 | if (st == M_ST_OFFLN || st == M_ST_AVLBL) { | |
671 | ui->ui_flags = 0; /* mark unit offline */ | |
672 | /* | |
673 | * Link the buffer onto the front of the drive queue | |
674 | */ | |
675 | if ((bp->av_forw = dp->b_actf) == 0) | |
676 | dp->b_actl = bp; | |
677 | dp->b_actf = bp; | |
678 | /* | |
679 | * Link the drive onto the controller queue | |
680 | */ | |
681 | if (dp->b_active == 0) { | |
682 | dp->b_forw = NULL; | |
683 | if (um->um_tab.b_actf == NULL) | |
684 | um->um_tab.b_actf = dp; | |
685 | else | |
686 | um->um_tab.b_actl->b_forw = dp; | |
687 | um->um_tab.b_actl = dp; | |
688 | dp->b_active = 1; | |
689 | } | |
690 | return; | |
691 | } | |
692 | if (st != M_ST_SUCC) { | |
693 | harderr(bp, "ra"); | |
694 | printf("status %o\n", mp->mscp_status); | |
695 | bp->b_flags |= B_ERROR; | |
696 | } | |
697 | bp->b_resid = bp->b_bcount - mp->mscp_bytecnt; | |
698 | iodone(bp); | |
699 | break; | |
700 | ||
701 | case M_OP_GTUNT|M_OP_END: | |
702 | break; | |
703 | ||
704 | default: | |
705 | printf("uda: unknown packet\n"); | |
706 | } | |
707 | } | |
708 | ||
709 | ||
710 | /* | |
711 | * Process an error log message | |
712 | * | |
713 | * For now, just log the error on the console. | |
714 | * Only minimal decoding is done, only "useful" | |
715 | * information is printed. Eventually should | |
716 | * send message to an error logger. | |
717 | */ | |
718 | uderror(um, mp) | |
719 | register struct uba_ctlr *um; | |
720 | register struct mslg *mp; | |
721 | { | |
5fd46eab | 722 | printf("uda%d: %s error, ", um->um_ctlr, |
db738443 BJ |
723 | mp->mslg_flags&M_LF_SUCC ? "soft" : "hard"); |
724 | switch (mp->mslg_format) { | |
725 | case M_FM_CNTERR: | |
726 | printf("controller error, event 0%o\n", mp->mslg_event); | |
727 | break; | |
728 | ||
729 | case M_FM_BUSADDR: | |
730 | printf("host memory access error, event 0%o, addr 0%o\n", | |
731 | mp->mslg_event, *((long *)&mp->mslg_busaddr[0])); | |
732 | break; | |
733 | ||
734 | case M_FM_DISKTRN: | |
5fd46eab | 735 | printf("disk transfer error, unit %d\n", mp->mslg_unit); |
db738443 BJ |
736 | break; |
737 | ||
738 | case M_FM_SDI: | |
5fd46eab SL |
739 | printf("SDI error, unit %d, event 0%o\n", mp->mslg_unit, |
740 | mp->mslg_event); | |
db738443 BJ |
741 | break; |
742 | ||
743 | case M_FM_SMLDSK: | |
744 | printf("small disk error, unit %d, event 0%o, cyl %d\n", | |
745 | mp->mslg_unit, mp->mslg_event, mp->mslg_sdecyl); | |
746 | break; | |
747 | ||
748 | default: | |
749 | printf("unknown error, unit %d, format 0%o, event 0%o\n", | |
750 | mp->mslg_unit, mp->mslg_format, mp->mslg_event); | |
751 | } | |
5fd46eab SL |
752 | |
753 | if (udaerror) { | |
754 | register long *p = (long *)mp; | |
755 | register int i; | |
756 | ||
757 | for (i = 0; i < mp->mslg_header.uda_msglen; i += sizeof(*p)) | |
758 | printf("%x ", *p++); | |
759 | printf("\n"); | |
760 | } | |
db738443 BJ |
761 | } |
762 | ||
763 | ||
764 | /* | |
765 | * Find an unused command packet | |
766 | */ | |
767 | struct mscp * | |
768 | udgetcp(um) | |
769 | struct uba_ctlr *um; | |
770 | { | |
771 | register struct mscp *mp; | |
772 | register struct udaca *cp; | |
773 | register struct uda_softc *sc; | |
774 | register int i; | |
775 | ||
776 | cp = &uda[um->um_ctlr].uda_ca; | |
777 | sc = &uda_softc[um->um_ctlr]; | |
778 | i = sc->sc_lastcmd; | |
779 | if ((cp->ca_cmddsc[i] & (UDA_OWN|UDA_INT)) == UDA_INT) { | |
780 | cp->ca_cmddsc[i] &= ~UDA_INT; | |
781 | mp = &uda[um->um_ctlr].uda_cmd[i]; | |
782 | mp->mscp_unit = mp->mscp_modifier = 0; | |
783 | mp->mscp_opcode = mp->mscp_flags = 0; | |
784 | mp->mscp_bytecnt = mp->mscp_buffer = 0; | |
785 | mp->mscp_errlgfl = mp->mscp_copyspd = 0; | |
786 | sc->sc_lastcmd = (i + 1) % NCMD; | |
787 | return(mp); | |
788 | } | |
789 | return(NULL); | |
790 | } | |
791 | ||
740e4029 | 792 | udread(dev, uio) |
db738443 | 793 | dev_t dev; |
740e4029 | 794 | struct uio *uio; |
db738443 BJ |
795 | { |
796 | register int unit = minor(dev) >> 3; | |
797 | ||
798 | if (unit >= NRA) | |
0cd5eac7 BJ |
799 | return (ENXIO); |
800 | return (physio(udstrategy, &rudbuf[unit], dev, B_READ, minphys, uio)); | |
db738443 BJ |
801 | } |
802 | ||
002227dd | 803 | udwrite(dev, uio) |
db738443 | 804 | dev_t dev; |
002227dd | 805 | struct uio *uio; |
db738443 BJ |
806 | { |
807 | register int unit = minor(dev) >> 3; | |
808 | ||
809 | if (unit >= NRA) | |
0cd5eac7 BJ |
810 | return (ENXIO); |
811 | return (physio(udstrategy, &rudbuf[unit], dev, B_WRITE, minphys, uio)); | |
db738443 BJ |
812 | } |
813 | ||
814 | udreset(uban) | |
815 | int uban; | |
816 | { | |
817 | register struct uba_ctlr *um; | |
818 | register struct uba_device *ui; | |
819 | register struct buf *bp, *dp; | |
820 | register int unit; | |
821 | struct buf *nbp; | |
822 | int d; | |
823 | ||
824 | for (d = 0; d < NUDA; d++) { | |
825 | if ((um = udminfo[d]) == 0 || um->um_ubanum != uban || | |
826 | um->um_alive == 0) | |
827 | continue; | |
828 | printf(" uda%d", d); | |
829 | um->um_tab.b_active = 0; | |
830 | um->um_tab.b_actf = um->um_tab.b_actl = 0; | |
831 | uda_softc[d].sc_state = S_IDLE; | |
832 | for (unit = 0; unit < NRA; unit++) { | |
833 | if ((ui = uddinfo[unit]) == 0) | |
834 | continue; | |
835 | if (ui->ui_alive == 0 || ui->ui_mi != um) | |
836 | continue; | |
837 | udutab[unit].b_active = 0; | |
838 | udutab[unit].b_qsize = 0; | |
839 | } | |
840 | for (bp = udwtab[d].av_forw; bp != &udwtab[d]; bp = nbp) { | |
841 | nbp = bp->av_forw; | |
155d9ff0 | 842 | ubarelse(uban, (int *)&bp->b_ubinfo); |
db738443 BJ |
843 | /* |
844 | * Link the buffer onto the drive queue | |
845 | */ | |
846 | dp = &udutab[dkunit(bp)]; | |
847 | if (dp->b_actf == 0) | |
848 | dp->b_actf = bp; | |
849 | else | |
850 | dp->b_actl->av_forw = bp; | |
851 | dp->b_actl = bp; | |
852 | bp->av_forw = 0; | |
853 | /* | |
854 | * Link the drive onto the controller queue | |
855 | */ | |
856 | if (dp->b_active == 0) { | |
857 | dp->b_forw = NULL; | |
858 | if (um->um_tab.b_actf == NULL) | |
859 | um->um_tab.b_actf = dp; | |
860 | else | |
861 | um->um_tab.b_actl->b_forw = dp; | |
862 | um->um_tab.b_actl = dp; | |
863 | dp->b_active = 1; | |
864 | } | |
865 | } | |
866 | udinit(d); | |
867 | } | |
868 | } | |
869 | ||
870 | uddump() | |
871 | { | |
872 | return(ENXIO); | |
873 | } |