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