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