simpler, cleaner iostat interface
[unix-history] / usr / src / sys / vax / mba / hp.c
CommitLineData
15c4ad30 1/* hp.c 3.14 %G% */
04b9d53d
BJ
2
3/*
5c777efe 4 * RP06/RM03/RM05 disk driver
04b9d53d
BJ
5 */
6
7#include "../h/param.h"
8#include "../h/systm.h"
41888f16 9#include "../h/dk.h"
04b9d53d
BJ
10#include "../h/buf.h"
11#include "../h/conf.h"
12#include "../h/dir.h"
13#include "../h/user.h"
14#include "../h/map.h"
80e7c811 15#include "../h/pte.h"
04b9d53d
BJ
16#include "../h/mba.h"
17#include "../h/mtpr.h"
80e7c811 18#include "../h/vm.h"
04b9d53d
BJ
19
20#define DK_N 0
99a08e2d 21#define DK_NMAX 1
04b9d53d
BJ
22
23struct device
24{
25 int hpcs1; /* control and Status register 1 */
26 int hpds; /* Drive Status */
27 int hper1; /* Error register 1 */
28 int hpmr; /* Maintenance */
29 int hpas; /* Attention Summary */
30 int hpda; /* Desired address register */
31 int hpdt; /* Drive type */
32 int hpla; /* Look ahead */
33 int hpsn; /* serial number */
34 int hpof; /* Offset register */
35 int hpdc; /* Desired Cylinder address register */
36 int hpcc; /* Current Cylinder */
37 int hper2; /* Error register 2 */
38 int hper3; /* Error register 3 */
39 int hpec1; /* Burst error bit position */
40 int hpec2; /* Burst error bit pattern */
41};
42
80e7c811
BJ
43#define HPMBA MBA0
44#define HPMBANUM 0
45
2796e11a 46#define NHP 2
04b9d53d
BJ
47#define RP 022
48#define RM 024
5c777efe 49#define RM5 027
04b9d53d
BJ
50#define NSECT 22
51#define NTRAC 19
52#define NRMSECT 32
53#define NRMTRAC 5
41888f16
BJ
54
55#define _hpSDIST 3
56#define _hpRDIST 6
57
58int hpSDIST = _hpSDIST;
59int hpRDIST = _hpRDIST;
60int hpseek;
04b9d53d
BJ
61
62struct size
63{
64 daddr_t nblocks;
65 int cyloff;
66} hp_sizes[8] =
67{
5c777efe
BJ
68 15884, 0, /* A=cyl 0 thru 37 */
69 33440, 38, /* B=cyl 38 thru 117 */
70 340670, 0, /* C=cyl 0 thru 814 */
04b9d53d 71 0, 0,
04b9d53d
BJ
72 0, 0,
73 0, 0,
5c777efe 74 291346, 118, /* G=cyl 118 thru 814 */
04b9d53d 75 0, 0,
04b9d53d 76}, rm_sizes[8] = {
5c777efe
BJ
77 15884, 0, /* A=cyl 0 thru 99 */
78 33440, 100, /* B=cyl 100 thru 309 */
79 131680, 0, /* C=cyl 0 thru 822 */
04b9d53d
BJ
80 0, 0,
81 0, 0,
82 0, 0,
5c777efe 83 82080, 310, /* G=cyl 310 thru 822 */
04b9d53d 84 0, 0,
5c777efe
BJ
85}, rm5_sizes[8] = {
86 15884, 0, /* A=cyl 0 thru 26 */
87 33440, 27, /* B=cyl 27 thru 81 */
88 500992, 0, /* C=cyl 0 thru 823 */
89 15884, 562, /* D=cyl 562 thru 588 */
90 55936, 589, /* E=cyl 589 thru 680 */
91 86944, 681, /* F=cyl 681 thru 823 */
92 159296, 562, /* G=cyl 562 thru 823 */
93 291346, 82, /* H=cyl 82 thru 561 */
04b9d53d
BJ
94};
95
96#define P400 020
97#define M400 0220
98#define P800 040
99#define M800 0240
100#define P1200 060
101#define M1200 0260
102int hp_offset[16] =
103{
104 P400, M400, P400, M400,
105 P800, M800, P800, M800,
106 P1200, M1200, P1200, M1200,
107 0, 0, 0, 0,
108};
109
110struct buf hptab;
111struct buf rhpbuf;
112struct buf hputab[NHP];
113char hp_type[NHP]; /* drive type */
114
115#define GO 01
116#define PRESET 020
117#define RTC 016
118#define OFFSET 014
41888f16 119#define SEEK 04
04b9d53d
BJ
120#define SEARCH 030
121#define RECAL 06
122#define DCLR 010
123#define WCOM 060
124#define RCOM 070
125
126#define IE 0100
127#define PIP 020000
128#define DRY 0200
129#define ERR 040000
130#define TRE 040000
131#define DCK 0100000
132#define WLE 04000
133#define ECH 0100
134#define VV 0100
135#define DPR 0400
136#define MOL 010000
137#define FMT22 010000
138
139#define b_cylin b_resid
140
141#ifdef INTRLVE
142daddr_t dkblock();
143#endif
144
145hpstrategy(bp)
146register struct buf *bp;
147{
148 register struct buf *dp;
149 register unit, xunit, nspc;
150 long sz, bn;
151 struct size *sizes;
152
80e7c811
BJ
153 if ((mbaact&(1<<HPMBANUM)) == 0)
154 mbainit(HPMBANUM);
04b9d53d
BJ
155 xunit = minor(bp->b_dev) & 077;
156 sz = bp->b_bcount;
157 sz = (sz+511) >> 9;
158 unit = dkunit(bp);
159 if (hp_type[unit] == 0) {
160 struct device *hpaddr;
161
162 /* determine device type */
80e7c811 163 hpaddr = mbadev(HPMBA, unit);
04b9d53d
BJ
164 hp_type[unit] = hpaddr->hpdt;
165 }
5c777efe
BJ
166 switch (hp_type[unit]) {
167
168 case RM:
04b9d53d
BJ
169 sizes = rm_sizes;
170 nspc = NRMSECT*NRMTRAC;
5c777efe
BJ
171 break;
172 case RM5:
173 sizes = rm5_sizes;
174 nspc = NRMSECT*NTRAC;
175 break;
176 case RP:
04b9d53d
BJ
177 sizes = hp_sizes;
178 nspc = NSECT*NTRAC;
5c777efe
BJ
179 break;
180 default:
181 printf("hp: unknown device type 0%o\n", hp_type[unit]);
182 u.u_error = ENXIO;
183 unit = NHP+1; /* force error */
04b9d53d
BJ
184 }
185 if (unit >= NHP ||
186 bp->b_blkno < 0 ||
187 (bn = dkblock(bp))+sz > sizes[xunit&07].nblocks) {
188 bp->b_flags |= B_ERROR;
189 iodone(bp);
190 return;
191 }
192 bp->b_cylin = bn/nspc + sizes[xunit&07].cyloff;
193 dp = &hputab[unit];
81263dba 194 (void) spl5();
04b9d53d
BJ
195 disksort(dp, bp);
196 if (dp->b_active == 0) {
197 hpustart(unit);
198 if(hptab.b_active == 0)
199 hpstart();
200 }
81263dba 201 (void) spl0();
04b9d53d
BJ
202}
203
204hpustart(unit)
205register unit;
206{
207 register struct buf *bp, *dp;
208 register struct device *hpaddr;
209 daddr_t bn;
210 int sn, cn, csn;
211
212 ((struct mba_regs *)MBA0)->mba_cr |= MBAIE;
80e7c811
BJ
213 hpaddr = mbadev(HPMBA, 0);
214 hpaddr->hpas = 1<<unit;
04b9d53d
BJ
215
216 if(unit >= NHP)
217 return;
99a08e2d
BJ
218 if (unit+DK_N <= DK_NMAX)
219 dk_busy &= ~(1<<(unit+DK_N));
04b9d53d
BJ
220 dp = &hputab[unit];
221 if((bp=dp->b_actf) == NULL)
222 return;
80e7c811 223 hpaddr = mbadev(HPMBA, unit);
04b9d53d
BJ
224 if((hpaddr->hpds & VV) == 0) {
225 hpaddr->hpcs1 = PRESET|GO;
226 hpaddr->hpof = FMT22;
227 }
228 if(dp->b_active)
229 goto done;
230 dp->b_active++;
231 if ((hpaddr->hpds & (DPR|MOL)) != (DPR|MOL))
232 goto done;
233
234 bn = dkblock(bp);
235 cn = bp->b_cylin;
5c777efe
BJ
236 switch (hp_type[unit]) {
237
238 case RM:
04b9d53d 239 sn = bn%(NRMSECT*NRMTRAC);
41888f16 240 sn = (sn+NRMSECT-hpSDIST)%NRMSECT;
5c777efe
BJ
241 break;
242 case RM5:
243 sn = bn%(NRMSECT*NTRAC);
244 sn = (sn+NRMSECT-hpSDIST)%NRMSECT;
245 break;
246 case RP:
04b9d53d 247 sn = bn%(NSECT*NTRAC);
41888f16 248 sn = (sn+NSECT-hpSDIST)%NSECT;
5c777efe
BJ
249 break;
250 default:
251 panic("hpustart");
04b9d53d
BJ
252 }
253
254 if(cn - (hpaddr->hpdc & 0xffff))
255 goto search;
41888f16
BJ
256 else if (hpseek)
257 goto done;
258 csn = ((hpaddr->hpla & 0xffff)>>6) - sn + 1;
04b9d53d
BJ
259 if(csn < 0)
260 csn += NSECT;
41888f16 261 if(csn > NSECT-hpRDIST)
04b9d53d
BJ
262 goto done;
263
264search:
265 hpaddr->hpdc = cn;
41888f16
BJ
266 if (hpseek)
267 hpaddr->hpcs1 = SEEK|GO;
268 else {
269 hpaddr->hpda = sn;
270 hpaddr->hpcs1 = SEARCH|GO;
271 }
04b9d53d 272 unit += DK_N;
99a08e2d
BJ
273 if (unit <= DK_NMAX && DK_N+NHP <= DK_NMAX) {
274 dk_busy |= 1<<unit;
275 dk_numb[unit]++;
276 }
04b9d53d
BJ
277 return;
278
279done:
280 dp->b_forw = NULL;
281 if(hptab.b_actf == NULL)
99a08e2d
BJ
282 hptab.b_actf = dp;
283 else
04b9d53d
BJ
284 hptab.b_actl->b_forw = dp;
285 hptab.b_actl = dp;
286}
287
288hpstart()
289{
290 register struct buf *bp, *dp;
291 register unit;
292 register struct device *hpaddr;
293 daddr_t bn;
294 int dn, sn, tn, cn, nspc, ns;
295
296loop:
297 if ((dp = hptab.b_actf) == NULL)
298 return;
299 if ((bp = dp->b_actf) == NULL) {
300 hptab.b_actf = dp->b_forw;
301 goto loop;
302 }
303 hptab.b_active++;
304 unit = minor(bp->b_dev) & 077;
305 dn = dkunit(bp);
306 bn = dkblock(bp);
5c777efe
BJ
307 switch (hp_type[dn]) {
308 case RM:
04b9d53d
BJ
309 nspc = NRMSECT*NRMTRAC;
310 ns = NRMSECT;
311 cn = rm_sizes[unit&07].cyloff;
5c777efe
BJ
312 break;
313 case RM5:
314 nspc = NRMSECT*NTRAC;
315 ns = NRMSECT;
316 cn = rm5_sizes[unit&07].cyloff;
317 break;
318 case RP:
04b9d53d
BJ
319 nspc = NSECT*NTRAC;
320 ns = NSECT;
321 cn = hp_sizes[unit&07].cyloff;
5c777efe
BJ
322 break;
323 default:
324 panic("hpstart");
04b9d53d
BJ
325 }
326 cn += bn/nspc;
327 sn = bn%nspc;
328 tn = sn/ns;
329 sn = sn%ns;
330
80e7c811 331 hpaddr = mbadev(HPMBA, dn);
04b9d53d
BJ
332 if ((hpaddr->hpds & (DPR|MOL)) != (DPR|MOL)) {
333 hptab.b_active = 0;
334 hptab.b_errcnt = 0;
335 dp->b_actf = bp->av_forw;
336 bp->b_flags |= B_ERROR;
337 iodone(bp);
338 goto loop;
339 }
15c4ad30 340 if(hptab.b_errcnt >= 16 && (bp->b_flags&B_WRITE) == 0) {
04b9d53d 341 hpaddr->hpof = hp_offset[hptab.b_errcnt & 017] | FMT22;
80e7c811 342 HPMBA->mba_cr &= ~MBAIE;
04b9d53d
BJ
343 hpaddr->hpcs1 = OFFSET|GO;
344 while(hpaddr->hpds & PIP)
345 ;
80e7c811 346 HPMBA->mba_cr |= MBAIE;
04b9d53d
BJ
347 }
348 hpaddr->hpdc = cn;
349 hpaddr->hpda = (tn << 8) + sn;
350 mbastart(bp, (int *)hpaddr);
351
99a08e2d
BJ
352 unit = dn+DK_N;
353 if (NHP+DK_N == DK_NMAX)
354 unit = NHP+DK_N;
355 if (unit <= DK_NMAX) {
356 dk_busy |= 1<<unit;
357 dk_numb[unit]++;
358 dk_wds[unit] += bp->b_bcount>>6;
359 }
04b9d53d
BJ
360}
361
362hpintr(mbastat, as)
363{
364 register struct buf *bp, *dp;
365 register unit;
366 register struct device *hpaddr;
367
368 if(hptab.b_active) {
04b9d53d
BJ
369 dp = hptab.b_actf;
370 bp = dp->b_actf;
371 unit = dkunit(bp);
99a08e2d
BJ
372 if (DK_N+NHP == DK_NMAX)
373 dk_busy &= ~(1<<(DK_N+NHP));
374 else if (DK_N+unit <= DK_NMAX)
375 dk_busy &= ~(1<<(DK_N+unit));
80e7c811
BJ
376 hpaddr = mbadev(HPMBA, unit);
377 if (hpaddr->hpds & ERR || mbastat & MBAEBITS) {
04b9d53d
BJ
378 while((hpaddr->hpds & DRY) == 0)
379 ;
380 if(++hptab.b_errcnt > 28 || hpaddr->hper1&WLE)
80e7c811
BJ
381 bp->b_flags |= B_ERROR;
382 else
04b9d53d
BJ
383 hptab.b_active = 0;
384 if(hptab.b_errcnt > 27)
385 deverror(bp, mbastat, hpaddr->hper1);
386 if ((hpaddr->hper1&0xffff) == DCK) {
387 if (hpecc(hpaddr, bp))
388 return;
389 }
390 hpaddr->hpcs1 = DCLR|GO;
391 if((hptab.b_errcnt&07) == 4) {
80e7c811 392 HPMBA->mba_cr &= ~MBAIE;
04b9d53d
BJ
393 hpaddr->hpcs1 = RECAL|GO;
394 while(hpaddr->hpds & PIP)
395 ;
80e7c811 396 HPMBA->mba_cr |= MBAIE;
04b9d53d
BJ
397 }
398 }
399 if(hptab.b_active) {
400 if(hptab.b_errcnt) {
80e7c811 401 HPMBA->mba_cr &= ~MBAIE;
04b9d53d
BJ
402 hpaddr->hpcs1 = RTC|GO;
403 while(hpaddr->hpds & PIP)
404 ;
80e7c811 405 HPMBA->mba_cr |= MBAIE;
04b9d53d
BJ
406 }
407 hptab.b_active = 0;
408 hptab.b_errcnt = 0;
409 hptab.b_actf = dp->b_forw;
410 dp->b_active = 0;
411 dp->b_errcnt = 0;
412 dp->b_actf = bp->av_forw;
80e7c811 413 bp->b_resid = -HPMBA->mba_bcr & 0xffff;
04b9d53d
BJ
414 iodone(bp);
415 if(dp->b_actf)
416 hpustart(unit);
417 }
418 as &= ~(1<<unit);
419 } else {
420 if(as == 0)
80e7c811 421 HPMBA->mba_cr |= MBAIE;
04b9d53d
BJ
422 }
423 for(unit=0; unit<NHP; unit++)
424 if(as & (1<<unit))
425 hpustart(unit);
426 hpstart();
427}
428
429hpread(dev)
430{
431
432 physio(hpstrategy, &rhpbuf, dev, B_READ, minphys);
433}
434
435hpwrite(dev)
436{
437
438 physio(hpstrategy, &rhpbuf, dev, B_WRITE, minphys);
439}
440
441hpecc(rp, bp)
442register struct device *rp;
443register struct buf *bp;
444{
80e7c811
BJ
445 struct mba_regs *mbp = HPMBA;
446 register int i;
447 caddr_t addr;
448 int reg, bit, byte, npf, mask, o;
449 int dn, bn, cn, tn, sn, ns, nt;
5f3edb0e 450 extern char buffers[NBUF][BSIZE];
80e7c811 451 struct pte mpte;
fa1d69d6 452 int bcr;
80e7c811
BJ
453
454 /*
455 * Npf is the number of sectors transferred before the sector
456 * containing the ECC error, and reg is the MBA register
457 * mapping (the first part of)the transfer.
458 * O is offset within a memory page of the first byte transferred.
459 */
fa1d69d6
BJ
460 bcr = mbp->mba_bcr & 0xffff;
461 if (bcr)
462 bcr |= 0xffff0000; /* sxt */
acecdc5c
BJ
463 npf = btop(bcr + bp->b_bcount) - 1;
464 printf("bcr %d npf %d\n", bcr, npf);
80e7c811
BJ
465 if (bp->b_flags&B_PHYS)
466 reg = 128 + npf;
467 else
468 reg = btop(bp->b_un.b_addr - buffers[0]) + npf;
469 o = (int)bp->b_un.b_addr & PGOFSET;
470 printf("%D ", bp->b_blkno + npf);
04b9d53d
BJ
471 prdev("ECC", bp->b_dev);
472 mask = rp->hpec2&0xffff;
473 if (mask == 0) {
474 rp->hpof = FMT22;
80e7c811 475 return (0);
04b9d53d 476 }
80e7c811
BJ
477
478 /*
479 * Compute the byte and bit position of the error.
480 * The variable i is the byte offset in the transfer,
481 * the variable byte is the offset from a page boundary
482 * in main memory.
483 */
484 i = (rp->hpec1&0xffff) - 1; /* -1 makes 0 origin */
acecdc5c 485 bit = i&07;
80e7c811
BJ
486 i = (i&~07)>>3;
487 byte = i + o;
488 /*
489 * Correct while possible bits remain of mask. Since mask
490 * contains 11 bits, we continue while the bit offset is > -11.
491 * Also watch out for end of this block and the end of the whole
492 * transfer.
493 */
494 while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) {
495 mpte = mbp->mba_map[reg+btop(byte)];
496 addr = ptob(mpte.pg_pfnum) + (byte & PGOFSET);
497 putmemc(addr, getmemc(addr)^(mask<<bit));
498 byte++;
499 i++;
500 bit -= 8;
04b9d53d 501 }
80e7c811 502 hptab.b_active++; /* Either complete or continuing */
acecdc5c 503 if (bcr == 0)
80e7c811
BJ
504 return (0);
505 /*
506 * Have to continue the transfer... clear the drive,
507 * and compute the position where the transfer is to continue.
508 * We have completed npf+1 sectores of the transfer already;
509 * restart at offset o of next sector (i.e. in MBA register reg+1).
510 */
511 rp->hpcs1 = DCLR|GO;
512 dn = dkunit(bp);
513 bn = dkblock(bp);
5c777efe
BJ
514 switch (hp_type[dn]) {
515
516 case RM:
517 ns = NRMSECT; nt = NRMTRAC; break;
518 case RM5:
519 ns = NRMSECT; nt = NTRAC; break;
520 case RP:
521 ns = NSECT; nt = NTRAC; break;
522 default:
523 panic("hpecc");
04b9d53d 524 }
80e7c811
BJ
525 cn = bp->b_cylin;
526 sn = bn%(ns*nt) + npf + 1;
527 tn = sn/ns;
528 sn %= ns;
529 cn += tn/nt;
530 tn %= nt;
531 rp->hpdc = cn;
532 rp->hpda = (tn<<8) + sn;
533 mbp->mba_sr = -1;
534 mbp->mba_var = (int)ptob(reg+1) + o;
535 rp->hpcs1 = RCOM|GO;
536 return (1);
04b9d53d 537}