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