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