Commit | Line | Data |
---|---|---|
963989ee | 1 | /* rx.c 4.10 83/04/04 */ |
63e51da2 SL |
2 | |
3 | #include "rx.h" | |
4 | #if NFX > 0 | |
5 | /* | |
6 | * RX02 floppy disk device driver | |
7 | * | |
63e51da2 | 8 | */ |
91c2156c HS |
9 | |
10 | /* | |
91c2156c HS |
11 | * Note: If the drive subsystem is |
12 | * powered off at boot time, the controller won't interrupt! | |
13 | */ | |
14 | ||
9246378c SL |
15 | #include "../machine/pte.h" |
16 | ||
63e51da2 | 17 | #include "../h/param.h" |
63e51da2 | 18 | #include "../h/buf.h" |
9246378c | 19 | #include "../h/systm.h" |
63e51da2 | 20 | #include "../h/conf.h" |
95c06320 HS |
21 | #include "../h/errno.h" |
22 | #include "../h/time.h" | |
9246378c SL |
23 | #include "../h/kernel.h" |
24 | #include "../h/uio.h" | |
95c06320 | 25 | #include "../h/file.h" |
63e51da2 | 26 | |
9246378c | 27 | #include "../vax/cpu.h" |
63e51da2 SL |
28 | #include "../vax/nexus.h" |
29 | #include "../vaxuba/ubavar.h" | |
30 | #include "../vaxuba/ubareg.h" | |
31 | #include "../vaxuba/rxreg.h" | |
32 | ||
33 | /* per-controller data */ | |
34 | struct rx_ctlr { | |
35 | int rxc_state; /* controller state */ | |
36 | #define RXS_READ 1 /* read started */ | |
37 | #define RXS_EMPTY 2 /* empty started */ | |
38 | #define RXS_FILL 3 /* fill started */ | |
39 | #define RXS_WRITE 4 /* write started */ | |
40 | #define RXS_FORMAT 5 /* format started */ | |
41 | #define RXS_RDSTAT 6 /* status read started */ | |
42 | #define RXS_RDERR 7 /* error read started */ | |
963989ee | 43 | #define RXS_IDLE 8 /* device is idle */ |
63e51da2 SL |
44 | u_short rxc_rxcs; /* extended error status */ |
45 | u_short rxc_rxdb; | |
46 | u_short rxc_rxxt[4]; | |
91c2156c | 47 | int rxc_tocnt; /* for watchdog routine */ |
9246378c | 48 | #define RX_MAXTIMEOUT 30 /* # seconds to wait before giving up */ |
63e51da2 | 49 | } rx_ctlr[NFX]; |
8606ef36 HS |
50 | |
51 | /* per-drive buffers */ | |
0e653e06 | 52 | struct buf rrxbuf[NRX]; /* buffers for raw I/O */ |
8606ef36 | 53 | struct buf erxbuf[NRX]; /* buffers for reading error status */ |
0e653e06 | 54 | struct buf rxutab[NRX]; /* per drive buffer queue heads */ |
63e51da2 SL |
55 | |
56 | /* per-drive data */ | |
57 | struct rx_softc { | |
9246378c | 58 | int sc_flags; /* drive status flags */ |
63e51da2 SL |
59 | #define RXF_DBLDEN 0x01 /* use double density */ |
60 | #define RXF_DIRECT 0x02 /* use direct sector mapping */ | |
61 | #define RXF_TRKZERO 0x04 /* start mapping on track 0 */ | |
62 | #define RXF_DEVTYPE 0x07 /* density and mapping flags */ | |
63 | #define RXF_OPEN 0x10 /* open */ | |
64 | #define RXF_DDMK 0x20 /* deleted-data mark detected */ | |
65 | #define RXF_USEWDDS 0x40 /* write deleted-data sector */ | |
9246378c | 66 | int sc_csbits; /* constant bits for CS register */ |
0e653e06 HS |
67 | caddr_t sc_uaddr; /* save orig. unibus address while */ |
68 | /* doing multisector transfers */ | |
69 | long sc_bcnt; /* save total transfer count for */ | |
70 | /* multisector transfers */ | |
963989ee HS |
71 | int sc_offset; /* raw mode kludge: gives the offset into */ |
72 | /* a block of DEV_BSIZE for the current */ | |
73 | /* request */ | |
63e51da2 SL |
74 | } rx_softc[NRX]; |
75 | ||
9246378c SL |
76 | struct rxerr { |
77 | short rxcs; | |
78 | short rxdb; | |
79 | short rxxt[4]; /* error code dump from controller */ | |
735f89eb HS |
80 | } rxerr[NRX]; |
81 | /* End of per-drive data */ | |
9246378c | 82 | |
63e51da2 SL |
83 | struct uba_device *rxdinfo[NRX]; |
84 | struct uba_ctlr *rxminfo[NFX]; | |
735f89eb | 85 | int rxprobe(), rxslave(), rxattach(), rxdgo(), rxintr(), rxwatch(), rxphys(); |
63e51da2 SL |
86 | u_short rxstd[] = { 0177170, 0177150, 0 }; |
87 | struct uba_driver fxdriver = | |
88 | { rxprobe, rxslave, rxattach, rxdgo, rxstd, "rx", rxdinfo, "fx", rxminfo }; | |
89 | ||
90 | int rxwstart; | |
735f89eb | 91 | #define RXUNIT(dev) (minor(dev)>>3) |
963989ee HS |
92 | #define MASKREG(reg) (reg&0xffff) |
93 | #define NDPC 2 /* # drives per controller */ | |
63e51da2 | 94 | |
63e51da2 SL |
95 | /* constants related to floppy data capacity */ |
96 | #define RXSECS 2002 /* # sectors on a floppy */ | |
9246378c | 97 | #define DDSTATE (sc->sc_flags&RXF_DBLDEN) |
63e51da2 SL |
98 | #define NBPS (DDSTATE ? 256 : 128) /* # bytes per sector */ |
99 | #define NWPS (DDSTATE ? 128 : 64) /* # words per sector */ | |
100 | #define RXSIZE (DDSTATE ? 512512 : 256256) /* # bytes per disk */ | |
101 | #define SECSHFT (DDSTATE ? 8 : 7) /* # bits to shift for sctr # */ | |
102 | #define SECMASK (DDSTATE ? 0xff : 0x7f) /* shifted-out bits of offset */ | |
103 | ||
9246378c | 104 | #define B_CTRL 0x80000000 /* control (format) request */ |
63e51da2 SL |
105 | |
106 | /*ARGSUSED*/ | |
107 | rxprobe (reg) | |
108 | caddr_t reg; | |
109 | { | |
9246378c | 110 | register int br, cvec; /* value-result */ |
63e51da2 SL |
111 | struct rxdevice *rxaddr = (struct rxdevice *)reg; |
112 | ||
113 | #ifdef lint | |
114 | br = 0; cvec = br; br = cvec; | |
9246378c | 115 | rxintr(0); |
63e51da2 SL |
116 | #endif lint |
117 | rxaddr->rxcs = RX_INTR; | |
118 | DELAY(10); | |
119 | rxaddr->rxcs = 0; | |
120 | return (sizeof (*rxaddr)); | |
121 | } | |
122 | ||
963989ee | 123 | rxslave(ui, reg) |
63e51da2 SL |
124 | struct uba_device *ui; |
125 | caddr_t reg; | |
126 | { | |
127 | ||
128 | ui->ui_dk = 1; | |
129 | return (ui->ui_slave == 0 || ui->ui_slave == 1); | |
130 | } | |
131 | ||
132 | /*ARGSUSED*/ | |
133 | rxattach(ui) | |
134 | struct uba_device *ui; | |
135 | { | |
136 | ||
137 | } | |
138 | ||
139 | /*ARGSUSED1*/ | |
140 | rxopen(dev, flag) | |
141 | dev_t dev; | |
142 | int flag; | |
143 | { | |
144 | register int unit = RXUNIT(dev); | |
145 | register struct rx_softc *sc; | |
146 | register struct uba_device *ui; | |
91c2156c HS |
147 | struct rx_ctlr *rxc; |
148 | int ctlr; | |
63e51da2 | 149 | |
735f89eb | 150 | if (unit >= NRX || (ui = rxdinfo[unit]) == 0 || ui->ui_alive == 0) |
9246378c | 151 | return (ENXIO); |
63e51da2 | 152 | sc = &rx_softc[unit]; |
9246378c SL |
153 | if (sc->sc_flags & RXF_OPEN) |
154 | return (EBUSY); | |
91c2156c HS |
155 | ctlr = ui->ui_mi->um_ctlr; |
156 | rxc = &rx_ctlr[ctlr]; | |
9246378c SL |
157 | sc->sc_flags = RXF_OPEN | (minor(dev) & RXF_DEVTYPE); |
158 | sc->sc_csbits = RX_INTR; | |
159 | sc->sc_csbits |= ui->ui_slave == 0 ? RX_DRV0 : RX_DRV1; | |
160 | sc->sc_csbits |= minor(dev) & RXF_DBLDEN ? RX_DDEN : RX_SDEN; | |
91c2156c HS |
161 | rxc->rxc_tocnt = 0; |
162 | if (rxwstart == 0) { | |
91c2156c | 163 | rxwstart++; |
963989ee | 164 | rxtimo(); /* start watchdog */ |
0e653e06 | 165 | } |
9246378c | 166 | return (0); |
63e51da2 SL |
167 | } |
168 | ||
169 | /*ARGSUSED1*/ | |
170 | rxclose(dev, flag) | |
171 | dev_t dev; | |
172 | int flag; | |
173 | { | |
174 | register struct rx_softc *sc = &rx_softc[RXUNIT(dev)]; | |
963989ee | 175 | int i; |
63e51da2 SL |
176 | |
177 | sc->sc_flags &= ~RXF_OPEN; | |
178 | sc->sc_csbits = 0; | |
963989ee HS |
179 | for (i=0; i<NFX*NDPC; i++) { |
180 | if (rx_softc[i].sc_flags&RXF_OPEN) | |
181 | break; | |
182 | } | |
183 | if (i == NFX*NDPC) | |
184 | rxwstart = 0; /* Turn off watchdog if all */ | |
185 | /* devices are closed */ | |
63e51da2 SL |
186 | } |
187 | ||
188 | rxstrategy(bp) | |
189 | register struct buf *bp; | |
190 | { | |
191 | struct uba_device *ui; | |
0e653e06 HS |
192 | register struct buf *dp; |
193 | struct rx_softc *sc; | |
194 | int s, unit = RXUNIT(bp->b_dev); | |
63e51da2 | 195 | |
963989ee HS |
196 | if (unit >= NRX) |
197 | goto bad; | |
0e653e06 HS |
198 | ui = rxdinfo[unit]; |
199 | sc = &rx_softc[unit]; | |
200 | if (ui == 0 || ui->ui_alive == 0) | |
201 | goto bad; | |
0e653e06 HS |
202 | if (bp->b_blkno < 0 || (bp->b_blkno * DEV_BSIZE) > RXSIZE ) |
203 | goto bad; | |
9246378c | 204 | s = spl5(); |
963989ee | 205 | dp = &rxutab[unit]; |
0e653e06 | 206 | bp->b_resid = bp->b_bcount; |
963989ee HS |
207 | disksort(dp, bp); |
208 | if (dp->b_active == 0) { | |
209 | rxustart(ui); | |
210 | bp = &ui->ui_mi->um_tab; | |
211 | if (bp->b_actf && bp->b_active == 0) | |
212 | rxstart(ui->ui_mi); | |
213 | } | |
63e51da2 | 214 | splx(s); |
0e653e06 HS |
215 | return; |
216 | ||
217 | bad: bp->b_flags |= B_ERROR; | |
218 | iodone(bp); | |
219 | return; | |
63e51da2 SL |
220 | } |
221 | ||
0e653e06 HS |
222 | /* |
223 | * Unit start routine. | |
963989ee | 224 | * Put this unit on the ready queue for the controller |
0e653e06 HS |
225 | */ |
226 | rxustart(ui) | |
227 | register struct uba_device *ui; | |
228 | { | |
963989ee HS |
229 | struct buf *dp = &rxutab[ui->ui_unit]; |
230 | struct uba_ctlr *um = ui->ui_mi; | |
231 | ||
232 | dp->b_forw = NULL; | |
233 | if (um->um_tab.b_actf == NULL) | |
234 | um->um_tab.b_actf = dp; | |
235 | else | |
236 | um->um_tab.b_actl->b_forw = dp; | |
237 | um->um_tab.b_actl = dp; | |
238 | dp->b_active++; | |
0e653e06 | 239 | } |
63e51da2 SL |
240 | /* |
241 | * Sector mapping routine. | |
242 | * Two independent sets of choices are available: | |
243 | * | |
244 | * (a) The first logical sector may either be on track 1 or track 0. | |
245 | * (b) The sectors on a track may either be taken in 2-for-1 interleaved | |
246 | * fashion or directly. | |
247 | * This gives a total of four possible mapping schemes. | |
248 | * | |
249 | * Physical tracks on the RX02 are numbered 0-76. Physical sectors on | |
250 | * each track are numbered 1-26. | |
251 | * | |
252 | * When interleaving is used, sectors on the first logical track are | |
253 | * taken in the order 1, 3, 5, ..., 25, 2, 4, 6, ..., 26. A skew of | |
254 | * six sectors per track is also used (to allow time for the heads to | |
255 | * move); hence, the sectors on the second logical track are taken in | |
256 | * the order 7, 9, 11, ..., 25, 1, 3, 5, 8, 10, 12, ..., 26, 2, 4, 6; | |
257 | * the third logical track starts with sector 13; and so on. | |
258 | * | |
259 | * When the mapping starts with track 1, track 0 is the last logical | |
260 | * track, and this track is always handled directly (without inter- | |
261 | * leaving), even when the rest of the disk is interleaved. (This is | |
262 | * still compatible with DEC RT-11, which does not use track 0 at all.) | |
263 | */ | |
9246378c SL |
264 | rxmap(bp, psector, ptrack) |
265 | struct buf *bp; | |
266 | int *psector, *ptrack; | |
63e51da2 SL |
267 | { |
268 | register int lt, ls, ptoff; | |
9246378c | 269 | struct rx_softc *sc = &rx_softc[RXUNIT(bp->b_dev)]; |
63e51da2 | 270 | |
963989ee | 271 | ls = ( bp->b_blkno * DEV_BSIZE + ( sc->sc_offset - bp->b_resid ))/NBPS; |
9246378c SL |
272 | lt = ls / 26; |
273 | ls %= 26; | |
63e51da2 SL |
274 | /* |
275 | * The "physical track offset" (ptoff) takes the | |
276 | * starting physical track (0 or 1) and the desired | |
277 | * interleaving into account. If lt+ptoff >= 77, | |
278 | * then interleaving is not performed. | |
279 | */ | |
280 | ptoff = 0; | |
9246378c SL |
281 | if (sc->sc_flags&RXF_DIRECT) |
282 | ptoff = 77; | |
91c2156c | 283 | if (!(sc->sc_flags&RXF_TRKZERO)) |
63e51da2 SL |
284 | ptoff++; |
285 | if (lt + ptoff < 77) | |
286 | ls = ((ls << 1) + (ls >= 13) + (6*lt)) % 26; | |
9246378c SL |
287 | *ptrack = (lt + ptoff) % 77; |
288 | *psector = ls + 1; | |
63e51da2 SL |
289 | } |
290 | ||
0e653e06 | 291 | /* |
963989ee HS |
292 | * Controller start routine. |
293 | * Start a new transfer or continue a multisector | |
294 | * transfer. If this is a new transfer (dp->b_active == 1) | |
295 | * save the start address of the data buffer and the total | |
296 | * byte count in the soft control structure. These are | |
297 | * restored into the buffer structure when the transfer has | |
298 | * been completed, before calling 'iodone'. | |
0e653e06 | 299 | */ |
63e51da2 SL |
300 | rxstart(um) |
301 | register struct uba_ctlr *um; | |
302 | { | |
303 | register struct rxdevice *rxaddr; | |
304 | register struct rx_ctlr *rxc; | |
305 | register struct rx_softc *sc; | |
0e653e06 | 306 | struct buf *dp, *bp; |
9246378c | 307 | int unit, sector, track; |
63e51da2 | 308 | |
0e653e06 HS |
309 | if (um->um_tab.b_active) |
310 | return; | |
311 | loop: | |
312 | if ((dp = um->um_tab.b_actf) == NULL) | |
63e51da2 | 313 | return; |
0e653e06 HS |
314 | if ((bp = dp->b_actf) == NULL) { |
315 | um->um_tab.b_actf = dp->b_forw; | |
316 | goto loop; | |
317 | } | |
63e51da2 SL |
318 | unit = RXUNIT(bp->b_dev); |
319 | sc = &rx_softc[unit]; | |
963989ee HS |
320 | if (dp->b_active == 1) { |
321 | sc->sc_uaddr = bp->b_un.b_addr; | |
322 | sc->sc_bcnt = bp->b_bcount; | |
323 | sc->sc_offset += sc->sc_bcnt; | |
324 | dp->b_active++; | |
325 | } | |
326 | um->um_tab.b_active++; | |
63e51da2 SL |
327 | rxaddr = (struct rxdevice *)um->um_addr; |
328 | rxc = &rx_ctlr[um->um_ctlr]; | |
0e653e06 HS |
329 | bp->b_bcount = bp->b_resid; |
330 | if (bp->b_bcount > NBPS) | |
331 | bp->b_bcount = NBPS; | |
91c2156c | 332 | rxc->rxc_tocnt = 0; |
4deb63fb HS |
333 | if (rxaddr->rxcs == 0x800) { |
334 | /* | |
963989ee | 335 | * 'Volume valid'?, check |
4deb63fb HS |
336 | * if the drive unit has been powered down |
337 | */ | |
338 | rxaddr->rxcs = RX_INIT; | |
339 | while((rxaddr->rxcs&RX_DONE) == 0) | |
340 | ; | |
341 | } | |
342 | if (bp->b_flags&B_CTRL) { /* format */ | |
63e51da2 SL |
343 | rxc->rxc_state = RXS_FORMAT; |
344 | rxaddr->rxcs = RX_FORMAT | sc->sc_csbits; | |
9246378c | 345 | while ((rxaddr->rxcs&RX_TREQ) == 0) |
63e51da2 SL |
346 | ; |
347 | rxaddr->rxdb = 'I'; | |
348 | return; | |
349 | } | |
91c2156c | 350 | |
4deb63fb | 351 | if (bp->b_flags&B_READ) { |
91c2156c | 352 | rxmap(bp, §or, &track); /* read */ |
63e51da2 SL |
353 | rxc->rxc_state = RXS_READ; |
354 | rxaddr->rxcs = RX_READ | sc->sc_csbits; | |
9246378c | 355 | while ((rxaddr->rxcs&RX_TREQ) == 0) |
63e51da2 | 356 | ; |
9246378c SL |
357 | rxaddr->rxdb = (u_short)sector; |
358 | while ((rxaddr->rxcs&RX_TREQ) == 0) | |
63e51da2 | 359 | ; |
9246378c | 360 | rxaddr->rxdb = (u_short)track; |
4deb63fb HS |
361 | } else { |
362 | rxc->rxc_state = RXS_FILL; /* write */ | |
363 | um->um_cmd = RX_FILL; | |
364 | (void) ubago(rxdinfo[unit]); | |
63e51da2 | 365 | } |
4deb63fb | 366 | #ifdef RXDEBUG |
91c2156c HS |
367 | printf("rxstart: flgs=0x%x, unit=%d, tr=%d, sc=%d, bl=%d, cnt=%d\n", |
368 | bp->b_flags, unit, track, sector, bp->b_blkno, bp->b_bcount); | |
4deb63fb | 369 | #endif |
63e51da2 SL |
370 | } |
371 | ||
372 | rxdgo(um) | |
373 | struct uba_ctlr *um; | |
374 | { | |
375 | register struct rxdevice *rxaddr = (struct rxdevice *)um->um_addr; | |
376 | int ubinfo = um->um_ubinfo; | |
0e653e06 | 377 | struct buf *bp = um->um_tab.b_actf->b_actf; |
63e51da2 SL |
378 | struct rx_softc *sc = &rx_softc[RXUNIT(bp->b_dev)]; |
379 | struct rx_ctlr *rxc = &rx_ctlr[um->um_ctlr]; | |
380 | ||
0e653e06 | 381 | rxaddr->rxcs = um->um_cmd | ((ubinfo & 0x30000) >> 4) | sc->sc_csbits; |
63e51da2 | 382 | if (rxc->rxc_state != RXS_RDERR) { |
9246378c | 383 | while ((rxaddr->rxcs&RX_TREQ) == 0) |
63e51da2 | 384 | ; |
91c2156c | 385 | rxaddr->rxdb = (u_short) bp->b_bcount >> 1; |
63e51da2 | 386 | } |
9246378c | 387 | while ((rxaddr->rxcs&RX_TREQ) == 0) |
63e51da2 | 388 | ; |
91c2156c | 389 | rxaddr->rxdb = (u_short) ubinfo; |
63e51da2 SL |
390 | } |
391 | ||
91c2156c HS |
392 | rxintr(ctlr) |
393 | int ctlr; | |
63e51da2 | 394 | { |
91c2156c HS |
395 | int unit, sector, track; |
396 | struct uba_ctlr *um = rxminfo[ctlr]; | |
9246378c | 397 | register struct rxdevice *rxaddr; |
0e653e06 | 398 | register struct buf *bp, *dp; |
91c2156c HS |
399 | register struct rx_softc *sc; |
400 | struct uba_device *ui; | |
9246378c SL |
401 | struct rxerr *er; |
402 | register struct rx_ctlr *rxc; | |
403 | ||
9246378c | 404 | if (!um->um_tab.b_active) |
63e51da2 | 405 | return; |
0e653e06 HS |
406 | dp = um->um_tab.b_actf; |
407 | if (!dp->b_active) | |
408 | return; | |
91c2156c HS |
409 | bp = dp->b_actf; |
410 | unit = RXUNIT(bp->b_dev); | |
411 | sc = &rx_softc[unit]; | |
412 | ui = rxdinfo[unit]; | |
9246378c SL |
413 | rxaddr = (struct rxdevice *)um->um_addr; |
414 | rxc = &rx_ctlr[um->um_ctlr]; | |
91c2156c | 415 | rxc->rxc_tocnt = 0; |
8606ef36 | 416 | er = &rxerr[unit]; |
4deb63fb | 417 | #ifdef RXDEBUG |
91c2156c HS |
418 | printf("rxintr: dev=0x%x, state=0x%x, status=0x%x\n", |
419 | bp->b_dev, rxc->rxc_state, rxaddr->rxcs); | |
4deb63fb | 420 | #endif |
9246378c | 421 | if ((rxaddr->rxcs & RX_ERR) && |
963989ee | 422 | (rxc->rxc_state != RXS_RDSTAT) && (rxc->rxc_state != RXS_RDERR)) |
9246378c | 423 | goto error; |
63e51da2 SL |
424 | switch (rxc->rxc_state) { |
425 | ||
9246378c SL |
426 | /* |
427 | * Incomplete commands. Perform next step | |
428 | * and return. Note that b_active is set on | |
429 | * entrance and, therefore, also on exit. | |
430 | */ | |
63e51da2 SL |
431 | case RXS_READ: |
432 | if (rxaddr->rxdb & RXES_DDMARK) | |
433 | sc->sc_flags |= RXF_DDMK; | |
434 | else | |
435 | sc->sc_flags &= ~RXF_DDMK; | |
436 | rxc->rxc_state = RXS_EMPTY; | |
437 | um->um_cmd = RX_EMPTY; | |
438 | (void) ubago(ui); | |
439 | return; | |
440 | ||
441 | case RXS_FILL: | |
442 | rxc->rxc_state = RXS_WRITE; | |
443 | if (sc->sc_flags & RXF_USEWDDS) { | |
444 | rxaddr->rxcs = RX_WDDS | sc->sc_csbits; | |
445 | sc->sc_flags &= ~RXF_USEWDDS; | |
446 | } else | |
447 | rxaddr->rxcs = RX_WRITE | sc->sc_csbits; | |
963989ee | 448 | rxmap(bp, §or, &track); |
9246378c | 449 | while ((rxaddr->rxcs&RX_TREQ) == 0) |
63e51da2 | 450 | ; |
9246378c SL |
451 | rxaddr->rxdb = sector; |
452 | while ((rxaddr->rxcs&RX_TREQ) == 0) | |
63e51da2 | 453 | ; |
9246378c | 454 | rxaddr->rxdb = track; |
63e51da2 SL |
455 | return; |
456 | ||
9246378c SL |
457 | /* |
458 | * Possibly completed command. | |
459 | */ | |
63e51da2 | 460 | case RXS_RDSTAT: |
9246378c | 461 | if (rxaddr->rxdb&RXES_READY) |
63e51da2 | 462 | goto rderr; |
4deb63fb | 463 | bp->b_error = EIO; |
63e51da2 | 464 | bp->b_flags |= B_ERROR; |
9246378c SL |
465 | goto done; |
466 | ||
467 | /* | |
468 | * Command completed. | |
469 | */ | |
470 | case RXS_EMPTY: | |
471 | case RXS_WRITE: | |
472 | case RXS_FORMAT: | |
473 | goto done; | |
63e51da2 SL |
474 | |
475 | case RXS_RDERR: | |
4deb63fb | 476 | bp = bp->b_back; /* kludge, see 'rderr:' */ |
963989ee HS |
477 | rxmap(bp, §or, &track); |
478 | printf("rx%d: hard error, trk %d psec %d ", | |
479 | unit, track, sector); | |
480 | printf("cs=%b, db=%b, err=", MASKREG(er->rxcs), | |
481 | RXCS_BITS, MASKREG(er->rxdb), RXES_BITS); | |
482 | printf("0x%x, 0x%x, 0x%x, 0x%x\n", MASKREG(er->rxxt[0]), | |
483 | MASKREG(er->rxxt[1]), MASKREG(er->rxxt[2]), | |
484 | MASKREG(er->rxxt[3])); | |
9246378c | 485 | goto done; |
63e51da2 SL |
486 | |
487 | default: | |
0e653e06 | 488 | printf("rx%d: state %d (reset)\n", unit, rxc->rxc_state); |
9246378c | 489 | rxreset(um->um_ubanum); |
63e51da2 SL |
490 | return; |
491 | } | |
63e51da2 SL |
492 | error: |
493 | /* | |
494 | * In case of an error: | |
495 | * (a) Give up now if a format (ioctl) was in progress, or if a | |
496 | * density error was detected. | |
497 | * (b) Retry up to nine times if a CRC (data) error was detected, | |
498 | * then give up if the error persists. | |
499 | * (c) In all other cases, reinitialize the drive and try the | |
500 | * operation once more before giving up. | |
501 | */ | |
9246378c | 502 | if (rxc->rxc_state == RXS_FORMAT || (rxaddr->rxdb&RXES_DENERR)) |
63e51da2 SL |
503 | goto giveup; |
504 | if (rxaddr->rxdb & RXES_CRCERR) { | |
63e51da2 SL |
505 | if (++bp->b_errcnt >= 10) |
506 | goto giveup; | |
507 | goto retry; | |
508 | } | |
509 | bp->b_errcnt += 9; | |
510 | if (bp->b_errcnt >= 10) | |
511 | goto giveup; | |
512 | rxaddr->rxcs = RX_INIT; | |
513 | /* no way to get an interrupt for "init done", so just wait */ | |
4deb63fb | 514 | while ((rxaddr->rxcs&RX_DONE) == 0) |
63e51da2 SL |
515 | ; |
516 | retry: | |
9246378c SL |
517 | /* |
518 | * In case we already have UNIBUS resources, give | |
519 | * them back since we reallocate things in rxstart. | |
8606ef36 HS |
520 | * Also, the active flag must be reset, otherwise rxstart |
521 | * will refuse to restart the transfer | |
9246378c SL |
522 | */ |
523 | if (um->um_ubinfo) | |
524 | ubadone(um); | |
8606ef36 | 525 | um->um_tab.b_active = 0; |
9246378c | 526 | rxstart(um); |
63e51da2 | 527 | return; |
9246378c | 528 | |
63e51da2 SL |
529 | giveup: |
530 | /* | |
531 | * Hard I/O error -- | |
9246378c SL |
532 | * Density errors are not noted on the console since the |
533 | * only way to determine the density of an unknown disk | |
534 | * is to try one density or the other at random and see | |
535 | * which one doesn't give a density error. | |
63e51da2 SL |
536 | */ |
537 | if (rxaddr->rxdb & RXES_DENERR) { | |
4deb63fb | 538 | bp->b_error = ENODEV; |
63e51da2 SL |
539 | bp->b_flags |= B_ERROR; |
540 | goto done; | |
541 | } | |
542 | rxc->rxc_state = RXS_RDSTAT; | |
543 | rxaddr->rxcs = RX_RDSTAT | sc->sc_csbits; | |
544 | return; | |
9246378c | 545 | |
63e51da2 SL |
546 | rderr: |
547 | /* | |
548 | * A hard error (other than not ready or density) has occurred. | |
549 | * Read the extended error status information. | |
550 | * Before doing this, save the current CS and DB register values, | |
551 | * because the read error status operation may modify them. | |
963989ee HS |
552 | * Insert buffer with request at the head of the queue, and |
553 | * save a pointer to the data buffer, so it can be restored | |
554 | * when the read error status operation is finished. | |
63e51da2 SL |
555 | */ |
556 | bp->b_error = EIO; | |
557 | bp->b_flags |= B_ERROR; | |
558 | ubadone(um); | |
4deb63fb HS |
559 | erxbuf[unit].b_back = bp; /* kludge to save the buffer pointer */ |
560 | /* while processing the error */ | |
63e51da2 SL |
561 | er->rxcs = rxaddr->rxcs; |
562 | er->rxdb = rxaddr->rxdb; | |
95c06320 | 563 | bp = &erxbuf[unit]; |
63e51da2 SL |
564 | bp->b_un.b_addr = (caddr_t)er->rxxt; |
565 | bp->b_bcount = sizeof (er->rxxt); | |
566 | bp->b_flags &= ~(B_DIRTY|B_UAREA|B_PHYS|B_PAGET); | |
963989ee HS |
567 | if (dp->b_actf == NULL) |
568 | dp->b_actl = bp; | |
569 | bp->b_forw = dp->b_actf; | |
570 | dp->b_actf = bp; | |
63e51da2 SL |
571 | rxc->rxc_state = RXS_RDERR; |
572 | um->um_cmd = RX_RDERR; | |
573 | (void) ubago(ui); | |
9246378c SL |
574 | return; |
575 | done: | |
576 | um->um_tab.b_active = 0; | |
0e653e06 HS |
577 | um->um_tab.b_errcnt = 0; |
578 | ubadone(um); | |
579 | if ((bp->b_resid -= NBPS) > 0) { | |
580 | bp->b_un.b_addr += NBPS; | |
581 | rxstart(um); | |
582 | return; | |
583 | } | |
584 | bp->b_un.b_addr = sc->sc_uaddr; | |
9246378c | 585 | bp->b_resid = 0; |
0e653e06 | 586 | bp->b_bcount = sc->sc_bcnt; |
963989ee | 587 | sc->sc_offset = 0; /* move this statement to a more appropriate place! */ |
9246378c SL |
588 | iodone(bp); |
589 | rxc->rxc_state = RXS_IDLE; | |
0e653e06 HS |
590 | um->um_tab.b_actf = dp->b_forw; |
591 | dp->b_active = 0; | |
592 | dp->b_errcnt = 0; | |
593 | dp->b_actf = bp->av_forw; | |
9246378c | 594 | /* |
963989ee | 595 | * If this unit has more work to do, |
9246378c SL |
596 | * start it up right away |
597 | */ | |
963989ee HS |
598 | if (dp->b_actf) |
599 | rxustart(ui); | |
600 | ||
601 | rxstart(um); | |
63e51da2 SL |
602 | } |
603 | ||
604 | /*ARGSUSED*/ | |
63e51da2 | 605 | |
91c2156c | 606 | /* |
963989ee HS |
607 | * Wake up every second, check if an interrupt is pending |
608 | * on one of the present controllers. | |
609 | * if it is, but nothing has happened increment a counter. | |
91c2156c | 610 | * If nothing happens for RX_MAXTIMEOUT seconds, |
963989ee HS |
611 | * call the interrupt routine with the 'dead' controller |
612 | * as an argument, thereby simulating an interrupt. | |
613 | * If this occurs, the error bit will probably be set | |
614 | * in the controller, and the interrupt routine will | |
615 | * be able to recover ( or at least report) the error | |
616 | * appropriately. | |
91c2156c | 617 | */ |
963989ee | 618 | rxtimo() |
63e51da2 | 619 | { |
963989ee HS |
620 | register struct rx_ctlr *rxc; |
621 | register struct uba_ctlr *um; | |
622 | int i; | |
623 | ||
624 | if (rxwstart > 0) { | |
625 | timeout(rxtimo, (caddr_t)0, hz); | |
626 | for (i=0; i<NFX; i++) { | |
627 | um = rxminfo[i]; | |
628 | if (um == 0 || um->um_alive || | |
629 | um->um_tab.b_active == 0) | |
630 | continue; | |
631 | rxc = &rx_ctlr[i]; | |
632 | if (++rxc->rxc_tocnt < RX_MAXTIMEOUT) { | |
633 | printf("fx%d: timeout\n", i); | |
634 | rxintr(i); | |
635 | } | |
636 | } | |
637 | } | |
63e51da2 SL |
638 | } |
639 | ||
640 | rxreset(uban) | |
641 | int uban; | |
642 | { | |
643 | register struct uba_ctlr *um; | |
644 | register struct rxdevice *rxaddr; | |
645 | register int ctlr; | |
646 | ||
647 | for (ctlr = 0; ctlr < NFX; ctlr++) { | |
648 | if ((um = rxminfo[ctlr]) == 0 || um->um_ubanum != uban || | |
649 | um->um_alive == 0) | |
650 | continue; | |
0e653e06 | 651 | if (um->um_ubinfo) |
9246378c | 652 | um->um_ubinfo = 0; |
63e51da2 SL |
653 | rx_ctlr[ctlr].rxc_state = RXS_IDLE; |
654 | rxaddr = (struct rxdevice *)um->um_addr; | |
9246378c | 655 | rxaddr->rxcs = RX_INIT; |
4deb63fb | 656 | while ((rxaddr->rxcs&RX_DONE) == 0) |
63e51da2 | 657 | ; |
9246378c | 658 | rxstart(um); |
63e51da2 SL |
659 | } |
660 | } | |
661 | ||
9246378c | 662 | rxread(dev, uio) |
63e51da2 | 663 | dev_t dev; |
9246378c | 664 | struct uio *uio; |
63e51da2 | 665 | { |
963989ee | 666 | int unit = RXUNIT(dev); |
0e653e06 | 667 | struct rx_softc *sc = &rx_softc[unit]; |
63e51da2 | 668 | |
9246378c SL |
669 | if (uio->uio_offset + uio->uio_resid > RXSIZE) |
670 | return (ENXIO); | |
671 | if (uio->uio_offset < 0 || (uio->uio_offset & SECMASK) != 0) | |
672 | return (EIO); | |
963989ee | 673 | sc->sc_offset = uio->uio_offset % DEV_BSIZE; |
0e653e06 | 674 | return (physio(rxstrategy, &rrxbuf[unit], dev, B_READ, minphys, uio)); |
63e51da2 SL |
675 | } |
676 | ||
9246378c | 677 | rxwrite(dev, uio) |
63e51da2 | 678 | dev_t dev; |
9246378c | 679 | struct uio *uio; |
63e51da2 | 680 | { |
0e653e06 HS |
681 | int unit = RXUNIT(dev); |
682 | struct rx_softc *sc = &rx_softc[unit]; | |
63e51da2 | 683 | |
9246378c SL |
684 | if (uio->uio_offset + uio->uio_resid > RXSIZE) |
685 | return (ENXIO); | |
686 | if (uio->uio_offset < 0 || (uio->uio_offset & SECMASK) != 0) | |
687 | return (EIO); | |
963989ee | 688 | sc->sc_offset = uio->uio_offset % DEV_BSIZE; |
0e653e06 | 689 | return(physio(rxstrategy, &rrxbuf[unit], dev, B_WRITE, minphys, uio)); |
63e51da2 SL |
690 | } |
691 | ||
692 | /* | |
693 | * Control routine: | |
694 | * processes three kinds of requests: | |
695 | * | |
735f89eb HS |
696 | * (1) Set density (i.e., format the diskette) according to |
697 | * that specified by the open device. | |
63e51da2 SL |
698 | * (2) Arrange for the next sector to be written with a deleted- |
699 | * data mark. | |
700 | * (3) Report whether the last sector read had a deleted-data mark | |
701 | * (by returning with an EIO error code if it did). | |
702 | * | |
703 | * Requests relating to deleted-data marks can be handled right here. | |
0e653e06 HS |
704 | * A "set density" (format) request, however, must additionally be |
705 | * processed through "rxstart", just like a read or write request. | |
63e51da2 SL |
706 | */ |
707 | /*ARGSUSED3*/ | |
9246378c | 708 | rxioctl(dev, cmd, data, flag) |
63e51da2 SL |
709 | dev_t dev; |
710 | int cmd; | |
9246378c | 711 | caddr_t data; |
63e51da2 SL |
712 | int flag; |
713 | { | |
714 | int unit = RXUNIT(dev); | |
715 | struct rx_softc *sc = &rx_softc[unit]; | |
63e51da2 SL |
716 | |
717 | switch (cmd) { | |
718 | ||
9246378c | 719 | case RXIOC_FORMAT: |
63e51da2 | 720 | if ((flag&FWRITE) == 0) |
9246378c | 721 | return (EBADF); |
95c06320 | 722 | return (rxformat(dev)); |
63e51da2 | 723 | |
9246378c SL |
724 | case RXIOC_WDDS: |
725 | sc->sc_flags |= RXF_USEWDDS; | |
726 | return (0); | |
63e51da2 | 727 | |
9246378c SL |
728 | case RXIOC_RDDSMK: |
729 | *(int *)data = sc->sc_flags & RXF_DDMK; | |
730 | return (0); | |
63e51da2 | 731 | } |
9246378c SL |
732 | return (ENXIO); |
733 | } | |
734 | ||
735 | /* | |
736 | * Initiate a format command. | |
737 | */ | |
95c06320 HS |
738 | rxformat(dev) |
739 | dev_t dev; | |
9246378c | 740 | { |
0e653e06 | 741 | int unit = RXUNIT(dev); |
9246378c | 742 | struct buf *bp; |
0e653e06 | 743 | struct rx_softc *sc = &rx_softc[unit]; |
9246378c | 744 | int s, error = 0; |
63e51da2 | 745 | |
0e653e06 | 746 | bp = &rrxbuf[unit]; |
63e51da2 SL |
747 | s = spl5(); |
748 | while (bp->b_flags & B_BUSY) | |
749 | sleep(bp, PRIBIO); | |
750 | bp->b_flags = B_BUSY | B_CTRL; | |
751 | splx(s); | |
9246378c | 752 | sc->sc_flags = RXS_FORMAT; |
63e51da2 SL |
753 | bp->b_dev = dev; |
754 | bp->b_error = 0; | |
9246378c | 755 | bp->b_resid = 0; |
63e51da2 SL |
756 | rxstrategy (bp); |
757 | iowait(bp); | |
9246378c SL |
758 | if (bp->b_flags & B_ERROR) |
759 | error = bp->b_error; | |
63e51da2 | 760 | bp->b_flags &= ~B_BUSY; |
9246378c SL |
761 | wakeup((caddr_t)bp); |
762 | return (error); | |
63e51da2 SL |
763 | } |
764 | #endif |