4.3- plus start of autoconfig
[unix-history] / usr / src / sys / tahoe / vba / vd.c
CommitLineData
9d915fad 1/* vd.c 1.2 86/01/05 */
210a9f40
SL
2
3#include "fsd.h"
4#if NVD > 0
5/*
9d915fad
SL
6 * VDDC - Versabus SMD/ESMD driver.
7 */
8#include "../tahoe/mtpr.h"
9#include "../tahoe/pte.h"
10
11#include "param.h"
12#include "buf.h"
13#include "cmap.h"
14#include "conf.h"
15#include "dir.h"
16#include "dk.h"
17#include "map.h"
18#include "systm.h"
19#include "user.h"
20#include "vmmac.h"
21#include "proc.h"
22#include "uio.h"
23
24#include "../tahoevba/vbavar.h"
25#define VDGENDATA
26#include "../tahoevba/vddcreg.h"
27#undef VDGENDATA
28
29#define MAX_BLOCKSIZE (MAXBPTE*NBPG)
30#define DUMPSIZE 64 /* controller limit */
210a9f40
SL
31
32#define VDUNIT(x) (minor(x) >> 3)
9d915fad
SL
33#define FILSYS(x) (minor(x) & 0x07)
34#define PHYS(x) (vtoph((struct proc *)0, (unsigned)(x)))
35#define TRUE 1
36#define FALSE 0
210a9f40 37
9d915fad
SL
38#define CTLR_ERROR 1
39#define DRIVE_ERROR 2
40#define HARD_DATA_ERROR 3
41#define SOFT_DATA_ERROR 4
42
43#define b_cylin b_resid
44#define b_daddr b_error
210a9f40
SL
45
46struct vba_ctlr *vdminfo[NVD];
47struct vba_device *vddinfo[NFSD];
9d915fad
SL
48int vdprobe(), vdslave(), vdattach(), vddgo();
49struct vba_driver vddriver =
50 { vdprobe, vdslave, vdattach, vddgo, vddcaddr, "smd/fsd",
51 vddinfo, "vd", vdminfo };
210a9f40
SL
52
53/*
9d915fad
SL
54 * Per-drive state.
55 */
56typedef struct {
57 struct buf raw_q_element;
58 short sec_per_blk;
59 short sec_per_cyl;
60 char status;
61 struct buf xfer_queue;
62 int drive_type;
63 fs_tab info;
64} unit_tab;
210a9f40
SL
65
66/*
9d915fad
SL
67 * Per-controller state.
68 */
69typedef struct {
70 char ctlr_type; /* controller type */
71 char *map; /* i/o page map */
72 char *utl; /* mapped i/o space */
73 u_int cur_slave:8; /* last active unit number */
74 u_int int_expected:1; /* expect an interupt */
75 u_int ctlr_started:1; /* start command was issued */
76 u_int overlap_seeks:1;/* should overlap seeks */
77 u_int off_cylinder:16;/* off cylinder bit map */
78 u_int unit_type[16]; /* slave types */
79 u_int cur_cyl[16]; /* cylinder last selected */
80 long cur_trk[16]; /* track last selected */
81 fmt_mdcb ctlr_mdcb; /* controller mdcb */
82 fmt_dcb ctlr_dcb; /* r/w dcb */
83 fmt_dcb seek_dcb[4]; /* dcbs for overlapped seeks */
84 /* buffer for raw/swap i/o */
85 char rawbuf[MAX_BLOCKSIZE];
86} ctlr_tab;
87
88extern char vd0utl[];
89#if NVD > 1
90extern char vd1utl[];
91#endif
92#if NVD > 2
93extern char vd2utl[];
94#endif
95#if NVD > 3
96extern char vd3utl[];
97#endif
210a9f40 98
9d915fad
SL
99#define VDCINIT(map, utl) { \
100 UNKNOWN, (char *)map, utl, 0, FALSE, FALSE, TRUE, 0, \
101 { UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, \
102 UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN } \
103}
104ctlr_tab vdctlr_info[NVD] = {
105 VDCINIT(VD0map, vd0utl),
106#if NVD > 1
107 VDCINIT(VD1map, vd1utl),
108#endif
109#if NVD > 2
110 VDCINIT(VD2map, vd2utl),
111#endif
112#if NVD > 3
113 VDCINIT(VD3map, vd3utl),
114#endif
210a9f40
SL
115};
116
9d915fad 117unit_tab vdunit_info[NFSD];
210a9f40
SL
118
119/*
9d915fad
SL
120 * See if the controller is really there; if so, initialize it.
121 */
122vdprobe(addr)
123 cdr *addr;
210a9f40 124{
9d915fad
SL
125 if (badaddr((caddr_t)addr, 2))
126 return (0);
127 addr->cdr_reset = 0xffffffff;
128 DELAY(1000000);
129 if (addr->cdr_reset != (unsigned)0xffffffff) {
130 DELAY(1000000);
131 } else {
132 addr->cdr_reserved = 0x0;
133 DELAY(3000000);
210a9f40 134 }
9d915fad
SL
135 return (sizeof (cdr));
136}
210a9f40
SL
137
138/*
139 * See if a drive is really there
9d915fad
SL
140 * Try to reset/configure the drive, then test its status.
141 */
142vdslave(vi, addr)
143 register struct vba_device *vi;
144 register cdr *addr;
210a9f40 145{
9d915fad
SL
146 register ctlr_tab *ci = &vdctlr_info[vi->ui_ctlr];
147 register unit_tab *ui = &vdunit_info[vi->ui_unit];
148 register fmt_mdcb *mdcb = &ci->ctlr_mdcb;
149 register fmt_dcb *dcb = &ci->ctlr_dcb;
150 register int type;
151
152 if (ci->ctlr_type == UNKNOWN) {
153 addr->cdr_reset = 0xffffffff;
154 DELAY(1000000);
155 if (addr->cdr_reset != (unsigned)0xffffffff) {
156 ci->ctlr_type = SMDCTLR;
157 ci->overlap_seeks = 0;
158 DELAY(1000000);
159 } else {
160 ci->overlap_seeks = 1;
161 ci->ctlr_type = SMD_ECTLR;
162 addr->cdr_reserved = 0x0;
163 DELAY(3000000);
164 addr->cdr_csr = 0;
165 addr->mdcb_tcf = AM_ENPDA;
166 addr->dcb_tcf = AM_ENPDA;
167 addr->trail_tcf = AM_ENPDA;
168 addr->data_tcf = AM_ENPDA;
169 addr->cdr_ccf = CCF_STS | XMD_32BIT | BSZ_16WRD |
170 CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR;
171 }
172 if (vdnotrailer(addr,
173 vi->ui_ctlr, vi->ui_slave, INIT, 10) & HRDERR) {
174 printf("vd%d: init error\n", vi->ui_unit);
175 return (0);
176 }
177 if (vdnotrailer(addr,
178 vi->ui_ctlr, vi->ui_slave, DIAG, 10) & HRDERR) {
179 printf("vd%d: diagnostic error\n", vi->ui_unit);
180 return (0);
181 }
210a9f40 182 }
210a9f40 183 /*
210a9f40 184 * Seek on all drive types starting from the largest one.
9d915fad 185 * a successful seek to the last sector/cylinder/track verifies
210a9f40
SL
186 * the drive type connected to this port.
187 */
9d915fad
SL
188 for (type = 0; type < nvddrv; type++) {
189 /* XXX */
190 if (ci->ctlr_type == SMDCTLR && vdst[type].nsec != 32)
191 continue;
192 /* XXX */
193 if (!vdconfigure_drive(addr, vi->ui_ctlr, vi->ui_slave, type,0))
194 return (0);
195 dcb->opcode = (short)RD;
210a9f40 196 dcb->intflg = NOINT;
9d915fad 197 dcb->nxtdcb = (fmt_dcb *)0; /* end of chain */
210a9f40 198 dcb->operrsta = 0;
9d915fad
SL
199 dcb->devselect = (char)(vi->ui_slave);
200 dcb->trailcnt = (char)(sizeof (trrw) / sizeof (long));
201 dcb->trail.rwtrail.memadr = (char *)PHYS(ci->rawbuf);
202 dcb->trail.rwtrail.wcount = vdst[type].secsize/sizeof(short);
203 dcb->trail.rwtrail.disk.cylinder = vdst[type].ncyl - 2;
204 dcb->trail.rwtrail.disk.track = vdst[type].ntrak - 1;
205 dcb->trail.rwtrail.disk.sector = vdst[type].nsec - 1;
206 mdcb->firstdcb = (fmt_dcb *)(PHYS(dcb));
207 mdcb->vddcstat = 0;
208 VDDC_ATTENTION(addr, (fmt_mdcb *)(PHYS(mdcb)), ci->ctlr_type);
209 POLLTILLDONE(addr, dcb, 60, ci->ctlr_type);
210 if (vdtimeout <= 0)
211 printf(" during probe\n");
212 if ((dcb->operrsta&HRDERR) == 0)
210a9f40
SL
213 break;
214 }
9d915fad
SL
215 if (type >= nvddrv) {
216 /*
217 * If reached here, a drive which is not defined in the
210a9f40
SL
218 * 'vdst' tables is connected. Cannot set it's type.
219 */
9d915fad
SL
220 printf("vd%d: unknown drive type\n", vi->ui_unit);
221 return (0);
222 }
223 ui->drive_type = type;
224 ui->info = vdst[type];
225 ui->sec_per_blk = DEV_BSIZE / ui->info.secsize;
226 vi->ui_type = type;
227 vi->ui_dk = 1;
228 vddriver.ud_dname = ui->info.type_name;
229 return (1);
230}
231
232vdconfigure_drive(addr, ctlr, slave, type, pass)
233 register cdr *addr;
234 int ctlr, slave, type, pass;
235{
236 register ctlr_tab *ci = &vdctlr_info[ctlr];
237
238 ci->ctlr_dcb.opcode = RSTCFG; /* command */
239 ci->ctlr_dcb.intflg = NOINT;
240 ci->ctlr_dcb.nxtdcb = (fmt_dcb *)0; /* end of chain */
241 ci->ctlr_dcb.operrsta = 0;
242 ci->ctlr_dcb.devselect = (char)slave;
243 ci->ctlr_dcb.trail.rstrail.ncyl = vdst[type].ncyl;
244 ci->ctlr_dcb.trail.rstrail.nsurfaces = vdst[type].ntrak;
245 if (ci->ctlr_type == SMD_ECTLR) {
246 ci->ctlr_dcb.trailcnt = (char)4;
247 ci->ctlr_dcb.trail.rstrail.nsectors = vdst[type].nsec;
248 ci->ctlr_dcb.trail.rstrail.slip_sec = vdst[type].nslip;
249 } else
250 ci->ctlr_dcb.trailcnt = (char)2;
251 ci->ctlr_mdcb.firstdcb = (fmt_dcb *)(PHYS(&ci->ctlr_dcb));
252 ci->ctlr_mdcb.vddcstat = 0;
253 VDDC_ATTENTION(addr, (fmt_mdcb *)(PHYS(&ci->ctlr_mdcb)), ci->ctlr_type);
254 POLLTILLDONE(addr, &ci->ctlr_dcb, 5, ci->ctlr_type);
255 if (vdtimeout <= 0) {
256 printf(" during config\n");
257 return (0);
258 }
259 if (ci->ctlr_dcb.operrsta & HRDERR) {
260 if ((ci->ctlr_dcb.operrsta & (NOTCYLERR|DRVNRDY)) == 0)
261 printf("vd%d: drive %d: config error\n", ctlr, slave);
262 else if (pass == 0) {
263 vdstart_drive(addr, ctlr, slave);
264 return (vdconfigure_drive(addr, ctlr, slave, type, 1));
265 } else if (pass == 2)
266 return (vdconfigure_drive(addr, ctlr, slave, type, 3));
267 return (0);
268 }
269 return (1);
270}
271
272vdstart_drive(addr, ctlr, slave)
273 cdr *addr;
274 register int ctlr, slave;
275{
276 int error = 0;
277
278 printf("vd%d: starting drive %d, wait...", ctlr, slave);
279 if (vdctlr_info[ctlr].ctlr_started) {
280printf("DELAY(5500000)...");
281 DELAY(5500000);
282 goto done;
283 }
284 vdctlr_info[ctlr].ctlr_started = 1;
285 error = vdnotrailer(addr, ctlr, 0, VDSTART, (slave*6)+62) & HRDERR;
286 if (!error) {
287printf("DELAY(%d)...", (slave * 5500000) + 62000000);
288 DELAY((slave * 5500000) + 62000000);
289 }
290done:
291 printf("\n");
292 return (error == 0);
293}
294
295vdnotrailer(addr, ctlr, unit, function, time)
296 register cdr *addr;
297 int ctlr, unit, function, time;
298{
299 fmt_mdcb *mdcb = &vdctlr_info[ctlr].ctlr_mdcb;
300 fmt_dcb *dcb = &vdctlr_info[ctlr].ctlr_dcb;
301 int type = vdctlr_info[ctlr].ctlr_type;
302
303 dcb->opcode = function; /* command */
304 dcb->intflg = NOINT;
305 dcb->nxtdcb = (fmt_dcb *)0; /* end of chain */
306 dcb->operrsta = 0;
307 dcb->devselect = (char)unit;
308 dcb->trailcnt = (char)0;
309 mdcb->firstdcb = (fmt_dcb *)(PHYS(dcb));
310 mdcb->vddcstat = 0;
311 VDDC_ATTENTION(addr, (fmt_mdcb *)(PHYS(mdcb)), type);
312 POLLTILLDONE(addr, dcb, time, type);
313 if (vdtimeout <= 0) {
314 printf(" during init\n");
315 return (DCBCMP|ANYERR|HRDERR|OPABRT);
210a9f40 316 }
9d915fad 317 return (dcb->operrsta);
210a9f40
SL
318}
319
9d915fad
SL
320vdattach(vi)
321 register struct vba_device *vi;
210a9f40 322{
9d915fad
SL
323 register unit_tab *ui = &vdunit_info[vi->ui_unit];
324 register ctlr_tab *ci = &vdctlr_info[vi->ui_ctlr];
325 register struct buf *cq = &vi->ui_mi->um_tab;
326 register struct buf *uq = cq->b_forw;
327 register struct buf *start_queue = uq;
328 register fs_tab *fs = &ui->info;
329
330 ui->info = vdst[vi->ui_type];
331 ui->sec_per_blk = DEV_BSIZE / ui->info.secsize;
332 ui->sec_per_cyl = ui->info.nsec * ui->info.ntrak;
333 ui->xfer_queue.b_dev = vi->ui_slave;
334 ci->unit_type[vi->ui_slave] = vi->ui_type;
335 /* load unit into controller's active unit list */
336 if (uq == NULL) {
337 cq->b_forw = &ui->xfer_queue;
338 ui->xfer_queue.b_forw = &ui->xfer_queue;
339 ui->xfer_queue.b_back = &ui->xfer_queue;
340 } else {
341 while (uq->b_forw != start_queue)
342 uq = uq->b_forw;
343 ui->xfer_queue.b_forw = start_queue;
344 ui->xfer_queue.b_back = uq;
345 uq->b_forw = &ui->xfer_queue;
346 start_queue->b_back = &ui->xfer_queue;
347 }
348 /*
349 * (60 / rpm) / (number of sectors per track * (bytes per sector / 2))
350 */
351 dk_mspw[vi->ui_unit] = 120.0 / (fs->rpm * fs->nsec * fs->secsize);
210a9f40
SL
352}
353
9d915fad 354/*ARGSUSED*/
210a9f40 355vddgo(um)
9d915fad 356 struct vba_ctlr *um;
210a9f40 357{
9d915fad 358
210a9f40
SL
359}
360
361vdstrategy(bp)
9d915fad 362 register struct buf *bp;
210a9f40 363{
9d915fad
SL
364 register int unit = VDUNIT(bp->b_dev);
365 register struct vba_device *vi = vddinfo[unit];
366 register par_tab *par;
367 register unit_tab *ui;
368 register fs_tab *fs;
369 register int blks, bn, s;
370
371 if (bp->b_bcount == 0 || vi == 0 || vi->ui_alive == 0)
372 goto bad;
373 ui = &vdunit_info[unit];
374 fs = &ui->info;
375 par = &fs->partition[FILSYS(bp->b_dev)];
376 blks = (bp->b_bcount + DEV_BSIZE-1) >> DEV_BSHIFT;
377 if (bp->b_blkno + blks >= par->par_len) {
378 blks = par->par_len - bp->b_blkno;
379 if (blks <= 0)
380 goto bad;
381 bp->b_bcount = blks * DEV_BSIZE;
210a9f40 382 }
9d915fad
SL
383 bn = bp->b_blkno + par->par_start;
384 bn *= ui->sec_per_blk;
385 bp->b_daddr = (bn / fs->nsec) % fs->ntrak;
386 bp->b_cylin = bn / ui->sec_per_cyl;
387 vbasetup(bp, ui->info.secsize);
388 s = spl7();
389 if (ui->xfer_queue.av_forw == NULL) {
390 register ctlr_tab *ci = &vdctlr_info[vi->ui_ctlr];
391 int slave = vi->ui_slave;
392
393 if (bp->b_cylin != ci->cur_cyl[slave] ||
394 bp->b_daddr != ci->cur_trk[slave])
395 ci->off_cylinder |= 1 << slave;
396 }
397 bp->b_daddr |= (bn % fs->nsec) << 8;
398 disksort(&ui->xfer_queue, bp);
399 if (!vddinfo[unit]->ui_mi->um_tab.b_active++) {
400 splx(s);
401 vdstart(vddinfo[unit]->ui_mi);
402 } else
403 splx(s);
210a9f40 404 return;
9d915fad
SL
405bad:
406 bp->b_flags |= B_ERROR, bp->b_error = ENXIO;
407 bp->b_resid = bp->b_bcount;
210a9f40 408 iodone(bp);
210a9f40
SL
409}
410
210a9f40
SL
411/*
412 * Start up a transfer on a drive.
413 */
9d915fad
SL
414vdstart(ci)
415 register struct vba_ctlr *ci;
416{
417 register struct buf *cq = &ci->um_tab;
418 register struct buf *uq = cq->b_forw;
419
420 /* search for next ready unit */
421 cq->b_forw = cq->b_forw->b_forw;
422 uq = cq->b_forw;
423 do {
424 if (uq->av_forw != NULL) {
425 cq->b_forw = uq;
426 vdexecute(ci, uq);
427 return;
428 }
429 uq = uq->b_forw;
430 } while (uq != cq->b_forw);
431}
432
433/*
434 * Initiate seeks for all drives off-cylinder.
435 */
436vdload_seeks(ci, uq)
437 register ctlr_tab *ci;
438 register struct buf *uq;
439{
440 register int unit, slave, nseeks;
441 register fmt_dcb *dcb;
442 register struct buf *bp;
443 register struct buf *start_queue = uq;
444
445 nseeks = 0;
446 do {
447 bp = uq->av_forw;
448 if (bp != NULL) {
449 unit = VDUNIT(bp->b_dev);
450 slave = vddinfo[unit]->ui_slave;
451 if (ci->off_cylinder & (1 << slave)) {
452 ci->off_cylinder &= ~(1 << slave);
453 if (ci->cur_cyl[slave] != bp->b_cylin) {
454 ci->cur_cyl[slave] = bp->b_cylin;
455 dk_seek[unit]++;
456 }
457 ci->cur_trk[slave] = bp->b_daddr&0xff;
458 dcb = &ci->seek_dcb[nseeks++];
459 dcb->opcode = SEEK;
460 dcb->intflg = NOINT | INT_PBA;
461 dcb->operrsta = 0;
462 dcb->devselect = (char)slave;
463 dcb->trailcnt = (char)1;
464 dcb->trail.sktrail.skaddr.cylinder =
465 bp->b_cylin;
466 dcb->trail.sktrail.skaddr.track =
467 bp->b_daddr & 0xff;
468 dcb->trail.sktrail.skaddr.sector = 0;
469 }
470 }
471 uq = uq->b_forw;
472 } while (uq != start_queue && nseeks < 4);
473 return (nseeks);
474}
475
476extern vd_int_timeout();
477/*
478 * Execute the next command on the unit queue uq.
479 */
480vdexecute(controller_info, uq)
481 register struct vba_ctlr *controller_info;
482 register struct buf *uq;
210a9f40 483{
9d915fad
SL
484 register struct buf *bp = uq->av_forw;
485 register int ctlr = controller_info->um_ctlr;
486 register ctlr_tab *ci = &vdctlr_info[ctlr];
487 register int unit = VDUNIT(bp->b_dev);
488 register int slave = vddinfo[unit]->ui_slave;
489 register fmt_mdcb *mdcb = &ci->ctlr_mdcb;
490 register fmt_dcb *dcb = &ci->ctlr_dcb;
491
210a9f40 492 /*
9d915fad
SL
493 * If there are overlapped seeks to perform, shuffle
494 * them to the front of the queue and get them started
495 * before any data transfers (to get some parallelism).
210a9f40 496 */
9d915fad
SL
497 if ((ci->off_cylinder & ~(1<<slave)) && ci->overlap_seeks) {
498 register int i, nseeks;
499
500 /* setup seek requests in seek-q */
501 nseeks = vdload_seeks(ci, uq);
502 /* place at the front of the master q */
503 mdcb->firstdcb = (fmt_dcb *)PHYS(&ci->seek_dcb[0]);
504 /* shuffle any remaining seeks up in the seek-q */
505 for (i = 1; i < nseeks; i++)
506 ci->seek_dcb[i-1].nxtdcb =
507 (fmt_dcb *)PHYS(&ci->seek_dcb[i]);
508 ci->seek_dcb[nseeks-1].nxtdcb = (fmt_dcb *)PHYS(dcb);
509 } else {
510 if (bp->b_cylin != ci->cur_cyl[slave]) {
511 ci->cur_cyl[slave] = bp->b_cylin;
512 dk_seek[unit]++;
513 }
514 ci->cur_trk[slave] = bp->b_daddr & 0xff;
515 ci->off_cylinder = 0;
516 mdcb->firstdcb = (fmt_dcb *)(PHYS(dcb));
210a9f40 517 }
210a9f40 518 dcb->opcode = (bp->b_flags & B_READ) ? RD : WD;
9d915fad
SL
519 dcb->intflg = INTDONE;
520 dcb->nxtdcb = (fmt_dcb *)0; /* end of chain */
210a9f40 521 dcb->operrsta = 0;
9d915fad
SL
522 dcb->devselect = (char)slave;
523 dcb->trailcnt = (char)(sizeof (trrw) / sizeof (long));
524 dcb->trail.rwtrail.memadr = (char *)
525 vbastart(bp, ci->rawbuf, (long *)ci->map, ci->utl);
526 dcb->trail.rwtrail.wcount = (short)((bp->b_bcount+1) / sizeof (short));
527 dcb->trail.rwtrail.disk.cylinder = bp->b_cylin;
528 dcb->trail.rwtrail.disk.track = bp->b_daddr & 0xff;
529 dcb->trail.rwtrail.disk.sector = bp->b_daddr >> 8;
530 mdcb->vddcstat = 0;
531 dk_wds[unit] += bp->b_bcount / 32;
532 ci->int_expected = 1;
533 timeout(vd_int_timeout, (caddr_t)ctlr, 20*60);
534 dk_busy |= 1 << unit;
210a9f40
SL
535#ifdef VDDCPERF
536 scope_out(1);
537#endif
9d915fad
SL
538 VDDC_ATTENTION((cdr *)(vdminfo[ctlr]->um_addr),
539 (fmt_mdcb *)(PHYS(mdcb)), ci->ctlr_type);
210a9f40
SL
540}
541
9d915fad
SL
542/*
543 * Watch for lost interrupts.
544 */
545vd_int_timeout(ctlr)
546 register int ctlr;
547{
548 register ctlr_tab *ci = &vdctlr_info[ctlr];
549 register fmt_dcb *dcb = &ci->ctlr_dcb;
550
551 uncache(&dcb->operrsta);
552 printf("vd%d: lost interupt, status %x", ctlr, dcb->operrsta);
553 if (ci->ctlr_type == SMD_ECTLR) {
554 uncache(&dcb->err_code);
555 printf(", error code %x", dcb->err_code);
556 }
557 printf("\n");
558 if ((dcb->operrsta&DCBCMP) == 0) {
559 VDDC_ABORT((cdr *)(vdminfo[ctlr]->um_addr), ci->ctlr_type);
560 dcb->operrsta |= DCBUSC | DCBABT | ANYERR | HRDERR | CTLRERR;
561 }
562 vdintr(ctlr);
563}
210a9f40
SL
564
565/*
566 * Handle a disk interrupt.
567 */
9d915fad
SL
568vdintr(ctlr)
569 register int ctlr;
210a9f40 570{
9d915fad
SL
571 register ctlr_tab *ci;
572 register struct buf *cq, *uq, *bp;
573 register int slave, unit;
574 register fmt_mdcb *mdcb;
575 register fmt_dcb *dcb;
576 int code, s;
577
578 untimeout(vd_int_timeout, (caddr_t)ctlr);
210a9f40
SL
579#ifdef VDDCPERF
580 scope_out(2);
581#endif
9d915fad
SL
582 ci = &vdctlr_info[ctlr];
583 if (!ci->int_expected) {
584 printf("vd%d: stray interrupt\n", ctlr);
210a9f40
SL
585 return;
586 }
9d915fad
SL
587 /*
588 * Take first request off controller's queue.
589 */
590 cq = &vdminfo[ctlr]->um_tab;
591 uq = cq->b_forw;
592 bp = uq->av_forw;
210a9f40 593 unit = VDUNIT(bp->b_dev);
9d915fad
SL
594 dk_busy &= ~(1 << unit);
595 dk_xfer[unit]++;
596 ci->int_expected = 0;
597 /* find associated control blocks */
598 mdcb = &ci->ctlr_mdcb, uncache(&mdcb->intdcb);
599 dcb = &ci->ctlr_dcb, uncache(&dcb->operrsta);
600 if (ci->ctlr_type == SMD_ECTLR)
601 uncache(&dcb->err_code);
602 slave = uq->b_dev;
603 switch (code = vddecode_error(dcb)) {
604
605 case CTLR_ERROR:
606 case DRIVE_ERROR:
607 if (cq->b_errcnt >= 2)
608 vdhard_error(ci, bp, dcb);
609 if (code == CTLR_ERROR)
610 vdreset_ctlr((cdr *)vdminfo[ctlr]->um_addr, ctlr);
611 else
612 reset_drive((cdr *)vdminfo[ctlr]->um_addr, ctlr,
613 slave, 2);
614 if (cq->b_errcnt++ < 2) { /* retry error */
615 cq->b_forw = uq->b_back;
616 vdstart(vdminfo[ctlr]);
617 return;
618 }
619 bp->b_resid = bp->b_bcount;
620 break;
621
622 case HARD_DATA_ERROR:
623 vdhard_error(ci, bp, dcb);
624 bp->b_resid = 0;
625 break;
626
627 case SOFT_DATA_ERROR:
628 vdsoft_error(ci, bp, dcb);
629 /* fall thru... */
630
631 default: /* operation completed */
632 bp->b_error = 0;
633 bp->b_resid = 0;
634 break;
210a9f40 635 }
9d915fad
SL
636 vbadone(bp, ci->rawbuf, (long *)ci->map, ci->utl);
637 /*
638 * Take next request on this unit q, or, if none,
639 * the next request on the next active unit q.
640 */
641 s = spl7();
642 uq->av_forw = bp->av_forw;
643 if (uq->av_back != bp) {
644 register struct buf *next;
645
646 unit = VDUNIT(uq->av_forw->b_dev);
647 slave = vddinfo[unit]->ui_slave;
648 next = uq->av_forw;
649 if (next->b_cylin != ci->cur_cyl[slave] ||
650 (next->b_daddr & 0xff) != ci->cur_trk[slave])
651 ci->off_cylinder |= 1 << slave;
652 } else
653 uq->av_back = NULL;
654 splx(s);
655 /* reset controller state */
656 cq->b_errcnt = 0;
657 cq->b_active--;
210a9f40
SL
658#ifdef VDDCPERF
659 scope_out(3);
660#endif
9d915fad
SL
661 if (bp->b_flags & B_ERROR)
662 bp->b_error = EIO;
210a9f40 663 iodone(bp);
9d915fad
SL
664 vdstart(vdminfo[ctlr]);
665}
666
667/*
668 * Convert controller status to internal operation/error code.
669 */
670vddecode_error(dcb)
671 register fmt_dcb *dcb;
672{
673
674 if (dcb->operrsta & HRDERR) {
675 if (dcb->operrsta & (HCRCERR | HCMPERR | UCDATERR | WPTERR |
676 DSEEKERR | NOTCYLERR |DRVNRDY | INVDADR))
677 return (DRIVE_ERROR);
678 if (dcb->operrsta & (CTLRERR | OPABRT | INVCMD | DNEMEM))
679 return (CTLR_ERROR);
680 return (HARD_DATA_ERROR);
681 }
682 if (dcb->operrsta & SFTERR)
683 return (SOFT_DATA_ERROR);
684 return (0);
685}
686
687/*
688 * Report a hard error.
689 */
690vdhard_error(ci, bp, dcb)
691 ctlr_tab *ci;
692 register struct buf *bp;
693 register fmt_dcb *dcb;
694{
695 unit_tab *ui = &vdunit_info[VDUNIT(bp->b_dev)];
696
697 bp->b_flags |= B_ERROR;
698 harderr(bp, ui->info.type_name);
699 printf("status %x", dcb->operrsta);
700 if (ci->ctlr_type == SMD_ECTLR)
701 printf(" ecode %x", dcb->err_code);
702 printf("\n");
210a9f40
SL
703}
704
9d915fad
SL
705/*
706 * Report a soft error.
707 */
708vdsoft_error(ci, bp, dcb)
709 ctlr_tab *ci;
710 register struct buf *bp;
711 register fmt_dcb *dcb;
712{
713 unit_tab *ui = &vdunit_info[VDUNIT(bp->b_dev)];
714
715 printf("%s%d%c: soft error sn%d status %x", ui->info.type_name,
716 dkunit(bp), 'a'+(minor(bp->b_dev)&07), bp->b_blkno,
717 dcb->operrsta);
718 if (ci->ctlr_type == SMD_ECTLR)
719 printf(" ecode %x", dcb->err_code);
720 printf("\n");
721}
722
723/*ARGSUSED*/
724vdopen(dev, flag)
725 dev_t dev;
726 int flag;
727{
728 register unit = VDUNIT(dev);
729 register struct vba_device *vi = vddinfo[unit];
730
731 if (vi == 0 || vi->ui_alive == 0 || vi->ui_type >= nvddrv)
732 return (ENXIO);
733 if (vdunit_info[unit].info.partition[FILSYS(dev)].par_len == 0)
734 return (ENXIO);
735 return (0);
736}
210a9f40
SL
737
738vdread(dev, uio)
9d915fad
SL
739 dev_t dev;
740 struct uio *uio;
210a9f40
SL
741{
742 register int unit = VDUNIT(dev);
9d915fad 743 register unit_tab *ui = &vdunit_info[unit];
210a9f40
SL
744
745 if (unit >= NFSD)
9d915fad
SL
746 return (ENXIO);
747 return (physio(vdstrategy, &ui->raw_q_element, dev, B_READ,
748 minphys, uio));
210a9f40
SL
749}
750
751vdwrite(dev, uio)
9d915fad
SL
752 dev_t dev;
753 struct uio *uio;
210a9f40
SL
754{
755 register int unit = VDUNIT(dev);
9d915fad 756 register unit_tab *ui = &vdunit_info[unit];
210a9f40
SL
757
758 if (unit >= NFSD)
9d915fad
SL
759 return (ENXIO);
760 return (physio(vdstrategy, &ui->raw_q_element, dev, B_WRITE,
761 minphys, uio));
210a9f40
SL
762}
763
210a9f40 764/*
9d915fad 765 * Crash dump.
210a9f40 766 */
9d915fad
SL
767vddump(dev)
768 dev_t dev;
210a9f40 769{
9d915fad
SL
770 register int unit = VDUNIT(dev);
771 register unit_tab *ui = &vdunit_info[unit];
772 register fs_tab *fs = &ui->info;
773 register int ctlr = vddinfo[unit]->ui_ctlr;
774 register struct vba_ctlr *vba_vdctlr_info = vdminfo[ctlr];
775 register int filsys = FILSYS(dev);
776 register cdr *addr = (cdr *)(vba_vdctlr_info->um_addr);
777 register int cur_blk, blkcount, blocks;
778 caddr_t memaddr;
779
780 vdreset_ctlr(addr, ctlr);
210a9f40 781 blkcount = maxfree - 2; /* In 1k byte pages */
9d915fad
SL
782 if (dumplo + blkcount > fs->partition[filsys].par_len) {
783 blkcount = fs->partition[filsys].par_len - dumplo;
784 printf("vd%d: Dump truncated to %dMB\n", unit, blkcount/1024);
785 }
786 cur_blk = fs->partition[filsys].par_start + dumplo;
787 memaddr = 0;
210a9f40 788 while (blkcount > 0) {
9d915fad
SL
789 blocks = MIN(blkcount, DUMPSIZE);
790 if (!vdwrite_block(addr, ctlr, unit, memaddr, cur_blk, blocks))
791 return (EIO);
792 blkcount -= blocks;
793 memaddr += blocks * NBPG;
794 cur_blk += blocks;
210a9f40 795 }
9d915fad 796 return (0);
210a9f40
SL
797}
798
9d915fad
SL
799/*
800 * Write a block to disk during a crash dump.
801 */
802vdwrite_block(caddr, ctlr, unit, addr, block, blocks)
803 register cdr *caddr;
804 register int ctlr, unit;
805 register caddr_t addr;
806 register int block, blocks;
210a9f40 807{
9d915fad
SL
808 register fmt_mdcb *mdcb = &vdctlr_info[ctlr].ctlr_mdcb;
809 register fmt_dcb *dcb = &vdctlr_info[ctlr].ctlr_dcb;
810 register unit_tab *ui = &vdunit_info[unit];
811 register fs_tab *fs = &ui->info;
812
813 block *= (int)ui->sec_per_blk;
814 blocks *= (int)ui->sec_per_blk;
815 mdcb->firstdcb = (fmt_dcb *)(PHYS(dcb));
816 dcb->intflg = NOINT;
817 dcb->opcode = WD;
818 dcb->operrsta = 0;
819 dcb->devselect = (char)(vddinfo[unit])->ui_slave;
820 dcb->trailcnt = (char)(sizeof (trrw) / sizeof (long));
821 dcb->trail.rwtrail.memadr = addr;
822 dcb->trail.rwtrail.wcount = (short)
823 ((blocks * fs->secsize)/ sizeof (short));
824 dcb->trail.rwtrail.disk.cylinder = (short)(block / ui->sec_per_cyl);
825 dcb->trail.rwtrail.disk.track = (char)((block / fs->nsec) % fs->ntrak);
826 dcb->trail.rwtrail.disk.sector = (char)(block % fs->nsec);
827 VDDC_ATTENTION(caddr, (fmt_mdcb *)(PHYS(mdcb)),
828 vdctlr_info[ctlr].ctlr_type);
829 POLLTILLDONE(caddr, dcb, 5, vdctlr_info[ctlr].ctlr_type);
830 if (vdtimeout <= 0) {
831 printf(" during dump\n");
832 return (0);
833 }
834 if (dcb->operrsta & HRDERR) {
835 printf("vd%d: hard error, status %x\n", unit, dcb->operrsta);
836 return (0);
837 }
838 return (1);
210a9f40
SL
839}
840
841vdsize(dev)
9d915fad 842 dev_t dev;
210a9f40 843{
9d915fad 844 struct vba_device *vi = vddinfo[VDUNIT(dev)];
210a9f40 845
9d915fad
SL
846 if (vi == 0 || vi->ui_alive == 0 || vi->ui_type >= nvddrv)
847 return (-1);
848 return (vdunit_info[VDUNIT(dev)].info.partition[FILSYS(dev)].par_len);
210a9f40
SL
849}
850
9d915fad
SL
851/*
852 * Perform a controller reset.
853 */
854vdreset_ctlr(addr, ctlr)
855 register cdr *addr;
856 register int ctlr;
210a9f40 857{
9d915fad
SL
858 register struct buf *cq = &vdminfo[ctlr]->um_tab;
859 register struct buf *uq = cq->b_forw;
860 register ctlr_tab *ci = &vdctlr_info[ctlr];
861
862 VDDC_RESET(addr, ci->ctlr_type);
863 ci->ctlr_started = 0;
864 if (ci->ctlr_type == SMD_ECTLR) {
865 addr->cdr_csr = 0;
866 addr->mdcb_tcf = AM_ENPDA;
867 addr->dcb_tcf = AM_ENPDA;
868 addr->trail_tcf = AM_ENPDA;
869 addr->data_tcf = AM_ENPDA;
870 addr->cdr_ccf = CCF_STS | XMD_32BIT | BSZ_16WRD |
871 CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR;
872 }
873 if (vdnotrailer(addr, ctlr, 0, INIT, 10) & HRDERR) {
874 printf("failed to init\n");
875 return (0);
876 }
877 if (vdnotrailer(addr, ctlr, 0, DIAG, 10) & HRDERR) {
878 printf("diagnostic error\n");
879 return (0);
880 }
881 /* reset all units attached to controller */
882 uq = cq->b_forw;
883 do {
884 reset_drive(addr, ctlr, uq->b_dev, 0);
885 uq = uq->b_forw;
886 } while (uq != cq->b_forw);
887 return (1);
888}
210a9f40 889
9d915fad
SL
890/*
891 * Perform a reset on a drive.
892 */
893reset_drive(addr, ctlr, slave, start)
894 register cdr *addr;
895 register int ctlr, slave, start;
896{
897 register int type = vdctlr_info[ctlr].unit_type[slave];
898
899 if (type == UNKNOWN)
900 return;
901 if (!vdconfigure_drive(addr, ctlr, slave, type, start))
902 printf("vd%d: drive %d: couldn't reset\n", ctlr, slave);
903}
904
905#ifdef notdef
906/*
907 * Dump the mdcb and DCB for diagnostic purposes.
908 */
909vdprintdcb(lp)
910 register long *lp;
911{
912 register int i, dcb, tc;
913
914 for (dcb = 0; lp; lp = (long *)(*lp), dcb++) {
915 lp = (long *)((long)lp | 0xc0000000);
916 printf("\nDump of dcb%d@%x:", dcb, lp);
917 for (i = 0, tc = lp[3] & 0xff; i < tc+7; i++)
918 printf(" %lx", lp[i]);
919 printf("\n");
210a9f40 920 }
9d915fad 921 DELAY(1750000);
210a9f40
SL
922}
923#endif
9d915fad 924#endif