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