BSD 4_2 development
[unix-history] / usr / src / sys / vaxuba / rl.c
CommitLineData
c6306105
C
1/* rl.c 6.1 83/07/29 */
2
3#include "rl.h"
4#if NRL > 0
5/*
6 * UNIBUS RL02 disk driver
7 */
8#include "../machine/pte.h"
9
10#include "../h/param.h"
11#include "../h/systm.h"
12#include "../h/dk.h"
13#include "../h/dkbad.h"
14#include "../h/buf.h"
15#include "../h/conf.h"
16#include "../h/dir.h"
17#include "../h/user.h"
18#include "../h/map.h"
19#include "../h/vm.h"
20#include "../h/cmap.h"
21#include "../h/uio.h"
22#include "../h/kernel.h"
23
24#include "../vax/cpu.h"
25#include "../vax/nexus.h"
26#include "../vaxuba/ubavar.h"
27#include "../vaxuba/ubareg.h"
28#include "../vaxuba/rlreg.h"
29
30/* Pending Controller items and statistics */
31struct rl_softc {
32 int rl_softas; /* Attention sumary, (seeks pending) */
33 int rl_ndrive; /* Number of drives on controller */
34 int rl_wticks; /* Monitor time for function */
35} rl_softc[NHL];
36
37/*
38 * State of controller from last transfer.
39 * Since only one transfer can be done at a time per
40 * controller, only allocate one for each controller.
41 */
42struct rl_stat {
43 short rl_cyl[4]; /* Current cylinder for each drive */
44 short rl_dn; /* drive number currently transferring */
45 short rl_cylnhd; /* current cylinder and head of transfer */
46 u_short rl_bleft; /* bytes left to transfer */
47 u_short rl_bpart; /* bytes transferred */
48} rl_stat[NHL];
49
50/* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */
51/* Last cylinder not used. Saved for Bad Sector File */
52struct size {
53 daddr_t nblocks;
54 int cyloff;
55} rl02_sizes[8] = {
56 15884, 0, /* A=cyl 0 thru 397 */
57 4520, 398, /* B=cyl 398 thru 510 */
58 -1, 0, /* C=cyl 0 thru 511 */
59 4520, 398, /* D=cyl 398 thru 510 */
60 0, 0, /* F= Not Defined */
61 20440, 0, /* G=cyl 0 thru 510 */
62 0, 0, /* H= Not Defined */
63};
64/* END OF STUFF WHICH SHOULD BE READ IN PER DISK */
65
66int rlprobe(), rlslave(), rlattach(), rldgo(), rlintr();
67struct uba_ctlr *rlminfo[NHL];
68struct uba_device *rldinfo[NRL];
69struct uba_device *rlip[NHL][4];
70
71/* RL02 driver structure */
72u_short rlstd[] = { 0174400 };
73struct uba_driver hldriver =
74 { rlprobe, rlslave, rlattach, rldgo, rlstd, "rl", rldinfo, "hl", rlminfo };
75
76/* User table per controller */
77struct buf rlutab[NRL];
78
79/* RL02 drive structure */
80struct RL02 {
81 short nbpt; /* Number of 512 byte blocks/track */
82 short ntrak;
83 short nbpc; /* Number of 512 byte blocks/cylinder */
84 short ncyl;
85 short btrak; /* Number of bytes/track */
86 struct size *sizes;
87} rl02 = {
88 20, 2, 40, 512, 20*512, rl02_sizes /* rl02/DEC*/
89};
90
91struct buf rrlbuf[NRL];
92
93#define b_cylin b_resid /* Last seek as CYL<<1 | HD */
94
95#ifdef INTRLVE
96daddr_t dkblock();
97#endif
98
99int rlwstart, rlwatch(); /* Have started guardian */
100
101/* Check that controller exists */
102/*ARGSUSED*/
103rlprobe(reg)
104 caddr_t reg;
105{
106 register int br, cvec;
107
108#ifdef lint
109 br = 0; cvec = br; br = cvec;
110 rlintr(0);
111#endif
112 ((struct rldevice *)reg)->rlcs = RL_IE | RL_NOOP;
113 DELAY(10);
114 ((struct rldevice *)reg)->rlcs &= ~RL_IE;
115 return (sizeof (struct rldevice));
116}
117
118rlslave(ui, reg)
119 struct uba_device *ui;
120 caddr_t reg;
121{
122 register struct rldevice *rladdr = (struct rldevice *)reg;
123 short ctr = 0;
124
125 /*
126 * DEC reports that:
127 * For some unknown reason the RL02 (seems to be only drive 1)
128 * does not return a valid drive status the first time that a
129 * GET STATUS request is issued for the drive, in fact it can
130 * take up to three or more GET STATUS requests to obtain the
131 * correct status.
132 * In order to overcome this, the driver has been modified to
133 * issue a GET STATUS request and validate the drive status
134 * returned. If a valid status is not returned after eight
135 * attempts, then an error message is printed.
136 */
137 do {
138 rladdr->rlda.getstat = RL_RESET;
139 rladdr->rlcs = (ui->ui_slave <<8) | RL_GETSTAT; /* Get status*/
140 rlwait(rladdr);
141 } while ((rladdr->rlmp.getstat&RLMP_STATUS) != RLMP_STATOK && ++ctr<8);
142 if ((rladdr->rlcs & RL_DE) || (ctr >= 8))
143 return (0);
144 if ((rladdr->rlmp.getstat & RLMP_DT) == 0 ) {
145 printf("rl%d: rl01's not supported\n", ui->ui_slave);
146 return(0);
147 }
148 return (1);
149}
150
151rlattach(ui)
152 register struct uba_device *ui;
153{
154 register struct rldevice *rladdr;
155
156 if (rlwstart == 0) {
157 timeout(rlwatch, (caddr_t)0, hz);
158 rlwstart++;
159 }
160 /* Initialize iostat values */
161 if (ui->ui_dk >= 0)
162 dk_mspw[ui->ui_dk] = .000003906; /* 16bit transfer time? */
163 rlip[ui->ui_ctlr][ui->ui_slave] = ui;
164 rl_softc[ui->ui_ctlr].rl_ndrive++;
165 rladdr = (struct rldevice *)ui->ui_addr;
166 /* reset controller */
167 rladdr->rlda.getstat = RL_RESET; /* SHOULD BE REPEATED? */
168 rladdr->rlcs = (ui->ui_slave << 8) | RL_GETSTAT; /* Reset DE bit */
169 rlwait(rladdr);
170 /* determine disk posistion */
171 rladdr->rlcs = (ui->ui_slave << 8) | RL_RHDR;
172 rlwait(rladdr);
173 /* save disk drive posistion */
174 rl_stat[ui->ui_ctlr].rl_cyl[ui->ui_slave] =
175 (rladdr->rlmp.readhdr & 0177700) >> 6;
176 rl_stat[ui->ui_ctlr].rl_dn = -1;
177}
178
179rlopen(dev)
180 dev_t dev;
181{
182 register int unit = minor(dev) >> 3;
183 register struct uba_device *ui;
184
185 if (unit >= NRL || (ui = rldinfo[unit]) == 0 || ui->ui_alive == 0)
186 return (ENXIO);
187 return (0);
188}
189
190rlstrategy(bp)
191 register struct buf *bp;
192{
193 register struct uba_device *ui;
194 register int drive;
195 register struct buf *dp;
196 int partition = minor(bp->b_dev) & 07, s;
197 long bn, sz;
198
199 sz = (bp->b_bcount+511) >> 9;
200 drive = dkunit(bp);
201 if (drive >= NRL)
202 goto bad;
203 ui = rldinfo[drive];
204 if (ui == 0 || ui->ui_alive == 0)
205 goto bad;
206 if (bp->b_blkno < 0 ||
207 (bn = dkblock(bp))+sz > rl02.sizes[partition].nblocks)
208 goto bad;
209 /* bn is in 512 byte block size */
210 bp->b_cylin = bn/rl02.nbpc + rl02.sizes[partition].cyloff;
211 s = spl5();
212 dp = &rlutab[ui->ui_unit];
213 disksort(dp, bp);
214 if (dp->b_active == 0) {
215 rlustart(ui);
216 bp = &ui->ui_mi->um_tab;
217 if (bp->b_actf && bp->b_active == 0)
218 rlstart(ui->ui_mi);
219 }
220 splx(s);
221 return;
222
223bad:
224 bp->b_flags |= B_ERROR;
225 iodone(bp);
226 return;
227}
228
229/*
230 * Unit start routine.
231 * Seek the drive to be where the data is
232 * and then generate another interrupt
233 * to actually start the transfer.
234 */
235rlustart(ui)
236 register struct uba_device *ui;
237{
238 register struct buf *bp, *dp;
239 register struct uba_ctlr *um;
240 register struct rldevice *rladdr;
241 daddr_t bn;
242 short hd, diff;
243
244 if (ui == 0)
245 return;
246 um = ui->ui_mi;
247 dk_busy &= ~(1 << ui->ui_dk);
248 dp = &rlutab[ui->ui_unit];
249 if ((bp = dp->b_actf) == NULL)
250 return;
251 /*
252 * If the controller is active, just remember
253 * that this device has to be positioned...
254 */
255 if (um->um_tab.b_active) {
256 rl_softc[um->um_ctlr].rl_softas |= 1<<ui->ui_slave;
257 return;
258 }
259 /*
260 * If we have already positioned this drive,
261 * then just put it on the ready queue.
262 */
263 if (dp->b_active)
264 goto done;
265 dp->b_active = 1; /* positioning drive */
266 rladdr = (struct rldevice *)um->um_addr;
267
268 /*
269 * Figure out where this transfer is going to
270 * and see if we are seeked correctly.
271 */
272 bn = dkblock(bp); /* Block # desired */
273 /*
274 * Map 512 byte logical disk blocks
275 * to 256 byte sectors (rl02's are stupid).
276 */
277 hd = (bn / rl02.nbpt) & 1; /* Get head required */
278 diff = (rl_stat[um->um_ctlr].rl_cyl[ui->ui_slave] >> 1) - bp->b_cylin;
279 if ( diff == 0 && (rl_stat[um->um_ctlr].rl_cyl[ui->ui_slave] & 1) == hd)
280 goto done; /* on cylinder and head */
281 /*
282 * Not at correct position.
283 */
284 rl_stat[um->um_ctlr].rl_cyl[ui->ui_slave] = (bp->b_cylin << 1) | hd;
285 if (diff < 0)
286 rladdr->rlda.seek = -diff << 7 | RLDA_HGH | hd << 4;
287 else
288 rladdr->rlda.seek = diff << 7 | RLDA_LOW | hd << 4;
289 rladdr->rlcs = (ui->ui_slave << 8) | RL_SEEK;
290
291 /*
292 * Mark unit busy for iostat.
293 */
294 if (ui->ui_dk >= 0) {
295 dk_busy |= 1<<ui->ui_dk;
296 dk_seek[ui->ui_dk]++;
297 }
298 rlwait(rladdr);
299done:
300 /*
301 * Device is ready to go.
302 * Put it on the ready queue for the controller
303 * (unless its already there.)
304 */
305 if (dp->b_active != 2) {
306 dp->b_forw = NULL;
307 if (um->um_tab.b_actf == NULL)
308 um->um_tab.b_actf = dp;
309 else
310 um->um_tab.b_actl->b_forw = dp;
311 um->um_tab.b_actl = dp;
312 dp->b_active = 2; /* Request on ready queue */
313 }
314}
315
316/*
317 * Start up a transfer on a drive.
318 */
319rlstart(um)
320 register struct uba_ctlr *um;
321{
322 register struct buf *bp, *dp;
323 register struct uba_device *ui;
324 register struct rldevice *rladdr;
325 register struct rl_stat *st = &rl_stat[um->um_ctlr];
326 daddr_t bn;
327 short sn, cyl, cmd;
328
329loop:
330 if ((dp = um->um_tab.b_actf) == NULL) {
331 st->rl_dn = -1;
332 st->rl_cylnhd = 0;
333 st->rl_bleft = 0;
334 st->rl_bpart = 0;
335 return;
336 }
337 if ((bp = dp->b_actf) == NULL) {
338 um->um_tab.b_actf = dp->b_forw;
339 goto loop;
340 }
341 /*
342 * Mark controller busy, and
343 * determine destination.
344 */
345 um->um_tab.b_active++;
346 ui = rldinfo[dkunit(bp)]; /* Controller */
347 bn = dkblock(bp); /* 512 byte Block number */
348 cyl = bp->b_cylin << 1; /* Cylinder */
349 cyl |= (bn / rl02.nbpt) & 1; /* Get head required */
350 sn = (bn % rl02.nbpt) << 1; /* Sector number */
351 rladdr = (struct rldevice *)ui->ui_addr;
352 rlwait(rladdr);
353 rladdr->rlda.rw = cyl<<6 | sn;
354 /* save away current transfers drive status */
355 st->rl_dn = ui->ui_slave;
356 st->rl_cylnhd = cyl;
357 st->rl_bleft = bp->b_bcount;
358 st->rl_bpart = rl02.btrak - (sn * NRLBPSC);
359 /*
360 * RL02 must seek between cylinders and between tracks,
361 * determine maximum data transfer at this time.
362 */
363 if (st->rl_bleft < st->rl_bpart)
364 st->rl_bpart = st->rl_bleft;
365 rladdr->rlmp.rw = -(st->rl_bpart >> 1);
366 if (bp->b_flags & B_READ)
367 cmd = RL_IE | RL_READ | (ui->ui_slave << 8);
368 else
369 cmd = RL_IE | RL_WRITE | (ui->ui_slave << 8);
370 um->um_cmd = cmd;
371 (void) ubago(ui);
372}
373
374rldgo(um)
375 register struct uba_ctlr *um;
376{
377 register struct rldevice *rladdr = (struct rldevice *)um->um_addr;
378
379 rladdr->rlba = um->um_ubinfo;
380 rladdr->rlcs = um->um_cmd|((um->um_ubinfo>>12)&RL_BAE);
381}
382
383/*
384 * Handle a disk interrupt.
385 */
386rlintr(rl21)
387 register rl21;
388{
389 register struct buf *bp, *dp;
390 register struct uba_ctlr *um = rlminfo[rl21];
391 register struct uba_device *ui;
392 register struct rldevice *rladdr = (struct rldevice *)um->um_addr;
393 register unit;
394 struct rl_softc *rl = &rl_softc[um->um_ctlr];
395 struct rl_stat *st = &rl_stat[um->um_ctlr];
396 int as = rl->rl_softas, status;
397
398 rl->rl_wticks = 0;
399 rl->rl_softas = 0;
400 dp = um->um_tab.b_actf;
401 bp = dp->b_actf;
402 ui = rldinfo[dkunit(bp)];
403 dk_busy &= ~(1 << ui->ui_dk);
404
405 /*
406 * Check for and process errors on
407 * either the drive or the controller.
408 */
409 if (rladdr->rlcs & RL_ERR) {
410 u_short err;
411 rlwait(rladdr);
412 err = rladdr->rlcs;
413 /* get staus and reset controller */
414 rladdr->rlda.getstat = RL_GSTAT;
415 rladdr->rlcs = (ui->ui_slave << 8) | RL_GETSTAT;
416 rlwait(rladdr);
417 status = rladdr->rlmp.getstat;
418 /* reset drive */
419 rladdr->rlda.getstat = RL_RESET;
420 rladdr->rlcs = (ui->ui_slave <<8) | RL_GETSTAT; /* Get status*/
421 rlwait(rladdr);
422 if ((status & RLMP_WL) == RLMP_WL) {
423 /*
424 * Give up on write protected devices
425 * immediately.
426 */
427 printf("rl%d: write protected\n", dkunit(bp));
428 bp->b_flags |= B_ERROR;
429 } else if (++um->um_tab.b_errcnt > 10) {
430 /*
431 * After 10 retries give up.
432 */
433 harderr(bp, "rl");
434 printf("cs=%b mp=%b\n", err, RLCS_BITS,
435 status, RLER_BITS);
436 bp->b_flags |= B_ERROR;
437 } else
438 um->um_tab.b_active = 0; /* force retry */
439 /* determine disk position */
440 rladdr->rlcs = (ui->ui_slave << 8) | RL_RHDR;
441 rlwait(rladdr);
442 /* save disk drive position */
443 st->rl_cyl[ui->ui_slave] =
444 (rladdr->rlmp.readhdr & 0177700) >> 6;
445 }
446 /*
447 * If still ``active'', then don't need any more retries.
448 */
449 if (um->um_tab.b_active) {
450 /* RL02 check if more data from previous request */
451 if ((bp->b_flags & B_ERROR) == 0 &&
452 (int)(st->rl_bleft -= st->rl_bpart) > 0) {
453 /*
454 * The following code was modeled from the rk07
455 * driver when an ECC error occured. It has to
456 * fix the bits then restart the transfer which is
457 * what we have to do (restart transfer).
458 */
459 int reg, npf, o, cmd, ubaddr, diff, head;
460
461 /* seek to next head/track */
462 /* increment head and/or cylinder */
463 st->rl_cylnhd++;
464 diff = (st->rl_cyl[ui->ui_slave] >> 1) -
465 (st->rl_cylnhd >> 1);
466 st->rl_cyl[ui->ui_slave] = st->rl_cylnhd;
467 head = st->rl_cylnhd & 1;
468 rlwait(rladdr);
469 if (diff < 0)
470 rladdr->rlda.seek =
471 -diff << 7 | RLDA_HGH | head << 4;
472 else
473 rladdr->rlda.seek =
474 diff << 7 | RLDA_LOW | head << 4;
475 rladdr->rlcs = (ui->ui_slave << 8) | RL_SEEK;
476 npf = btop( bp->b_bcount - st->rl_bleft );
477 reg = btop(um->um_ubinfo&0x3ffff) + npf;
478 o = (int)bp->b_un.b_addr & PGOFSET;
479 ubapurge(um);
480 um->um_tab.b_active++;
481 rlwait(rladdr);
482 rladdr->rlda.rw = st->rl_cylnhd << 6;
483 if (st->rl_bleft < (st->rl_bpart = rl02.btrak))
484 st->rl_bpart = st->rl_bleft;
485 rladdr->rlmp.rw = -(st->rl_bpart >> 1);
486 cmd = (bp->b_flags&B_READ ? RL_READ : RL_WRITE) |
487 RL_IE | (ui->ui_slave << 8);
488 ubaddr = (int)ptob(reg) + o;
489 cmd |= ((ubaddr >> 12) & RL_BAE);
490 rladdr->rlba = ubaddr;
491 rladdr->rlcs = cmd;
492 return;
493 }
494 um->um_tab.b_active = 0;
495 um->um_tab.b_errcnt = 0;
496 dp->b_active = 0;
497 dp->b_errcnt = 0;
498 /* "b_resid" words remaining after error */
499 bp->b_resid = st->rl_bleft;
500 um->um_tab.b_actf = dp->b_forw;
501 dp->b_actf = bp->av_forw;
502 st->rl_dn = -1;
503 st->rl_bpart = st->rl_bleft = 0;
504 iodone(bp);
505 /*
506 * If this unit has more work to do,
507 * then start it up right away.
508 */
509 if (dp->b_actf)
510 rlustart(ui);
511 as &= ~(1<<ui->ui_slave);
512 } else
513 as |= (1<<ui->ui_slave);
514 ubadone(um);
515 /* reset state info */
516 st->rl_dn = -1;
517 st->rl_cylnhd = st->rl_bpart = st->rl_bleft = 0;
518 /*
519 * Process other units which need attention.
520 * For each unit which needs attention, call
521 * the unit start routine to place the slave
522 * on the controller device queue.
523 */
524 while (unit = ffs(as)) {
525 unit--; /* was 1 origin */
526 as &= ~(1<<unit);
527 rlustart(rlip[rl21][unit]);
528 }
529 /*
530 * If the controller is not transferring, but
531 * there are devices ready to transfer, start
532 * the controller.
533 */
534 if (um->um_tab.b_actf && um->um_tab.b_active == 0)
535 rlstart(um);
536}
537
538rlwait(rladdr)
539 register struct rldevice *rladdr;
540{
541
542 while ((rladdr->rlcs & RL_CRDY) == 0)
543 ;
544}
545
546rlread(dev, uio)
547 dev_t dev;
548 struct uio *uio;
549{
550 register int unit = minor(dev) >> 3;
551
552 if (unit >= NRL)
553 return (ENXIO);
554 return (physio(rlstrategy, &rrlbuf[unit], dev, B_READ, minphys, uio));
555}
556
557rlwrite(dev, uio)
558 dev_t dev;
559 struct uio *uio;
560{
561 register int unit = minor(dev) >> 3;
562
563 if (unit >= NRL)
564 return (ENXIO);
565 return (physio(rlstrategy, &rrlbuf[unit], dev, B_WRITE, minphys, uio));
566}
567
568/*
569 * Reset driver after UBA init.
570 * Cancel software state of all pending transfers
571 * and restart all units and the controller.
572 */
573rlreset(uban)
574 int uban;
575{
576 register struct uba_ctlr *um;
577 register struct uba_device *ui;
578 register struct rldevice *rladdr;
579 register struct rl_stat *st;
580 register int rl21, unit;
581
582 for (rl21 = 0; rl21 < NHL; rl21++) {
583 if ((um = rlminfo[rl21]) == 0 || um->um_ubanum != uban ||
584 um->um_alive == 0)
585 continue;
586 printf(" hl%d", rl21);
587 rladdr = (struct rldevice *)um->um_addr;
588 st = &rl_stat[rl21];
589 um->um_tab.b_active = 0;
590 um->um_tab.b_actf = um->um_tab.b_actl = 0;
591 if (um->um_ubinfo) {
592 printf("<%d>", (um->um_ubinfo>>28)&0xf);
593 um->um_ubinfo = 0;
594 }
595 /* reset controller */
596 st->rl_dn = -1;
597 st->rl_cylnhd = 0;
598 st->rl_bleft = 0;
599 st->rl_bpart = 0;
600 rlwait(rladdr);
601 for (unit = 0; unit < NRL; unit++) {
602 rladdr->rlcs = (unit << 8) | RL_GETSTAT;
603 rlwait(rladdr);
604 /* Determine disk posistion */
605 rladdr->rlcs = (unit << 8) | RL_RHDR;
606 rlwait(rladdr);
607 /* save disk drive posistion */
608 st->rl_cyl[unit] =
609 (rladdr->rlmp.readhdr & 0177700) >> 6;
610 if ((ui = rldinfo[unit]) == 0)
611 continue;
612 if (ui->ui_alive == 0 || ui->ui_mi != um)
613 continue;
614 rlutab[unit].b_active = 0;
615 rlustart(ui);
616 }
617 rlstart(um);
618 }
619}
620
621/*
622 * Wake up every second and if an interrupt is pending
623 * but nothing has happened increment a counter.
624 * If nothing happens for 20 seconds, reset the UNIBUS
625 * and begin anew.
626 */
627rlwatch()
628{
629 register struct uba_ctlr *um;
630 register rl21, unit;
631 register struct rl_softc *rl;
632
633 timeout(rlwatch, (caddr_t)0, hz);
634 for (rl21 = 0; rl21 < NHL; rl21++) {
635 um = rlminfo[rl21];
636 if (um == 0 || um->um_alive == 0)
637 continue;
638 rl = &rl_softc[rl21];
639 if (um->um_tab.b_active == 0) {
640 for (unit = 0; unit < NRL; unit++)
641 if (rlutab[unit].b_active &&
642 rldinfo[unit]->ui_mi == um)
643 goto active;
644 rl->rl_wticks = 0;
645 continue;
646 }
647active:
648 rl->rl_wticks++;
649 if (rl->rl_wticks >= 20) {
650 rl->rl_wticks = 0;
651 printf("hl%d: lost interrupt\n", rl21);
652 ubareset(um->um_ubanum);
653 }
654 }
655}
656
657/*ARGSUSED*/
658rldump(dev)
659 dev_t dev;
660{
661
662 /* don't think there is room on swap for it anyway. */
663}
664
665rlsize(dev)
666 dev_t dev;
667{
668 register int unit = minor(dev) >> 3;
669 register struct uba_device *ui;
670
671 if (unit >= NRL || (ui = rldinfo[unit]) == 0 || ui->ui_alive == 0)
672 return (-1);
673 return (rl02.sizes[minor(dev) & 07].nblocks);
674}
675#endif