fix comment, Name server is two words
[unix-history] / usr / src / sys / vax / stand / hp.c
CommitLineData
8ae0e4b4
KM
1/*
2 * Copyright (c) 1982 Regents of the University of California.
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 *
f834e141 6 * @(#)hp.c 6.8 (Berkeley) %G%
8ae0e4b4 7 */
63c82e3f
HS
8
9/*
10 * RP??/RM?? disk driver
11 * with ECC handling and bad block forwarding.
12 * Also supports header io operations and
13 * commands to write check header and data.
14 */
63c82e3f
HS
15#include "../h/param.h"
16#include "../h/inode.h"
17#include "../h/fs.h"
18#include "../h/dkbad.h"
19
20#include "../vax/pte.h"
21#include "../vaxmba/hpreg.h"
22#include "../vaxmba/mbareg.h"
23
24#include "saio.h"
25#include "savax.h"
26
f834e141
MK
27#define RETRIES 27
28
63c82e3f
HS
29#define MASKREG(reg) ((reg)&0xffff)
30
356d90a8
SL
31#define MAXBADDESC 126
32#define SECTSIZ 512 /* sector size in bytes */
33#define HDRSIZ 4 /* number of bytes in sector header */
63c82e3f 34
86bcc486 35extern struct st hpst[];
f834e141 36extern short hptypes[];
63c82e3f 37
f834e141
MK
38#define RP06 (hptypes[sc->type] == MBDT_RP06 || hptypes[sc->type] == MBDT_RP05 \
39 || hptypes[sc->type] == MBDT_RP04)
40#define ML11 (hptypes[sc->type] == MBDT_ML11A)
41#define RM80 (hptypes[sc->type] == MBDT_RM80)
63c82e3f
HS
42
43u_char hp_offset[16] = {
44 HPOF_P400, HPOF_M400, HPOF_P400, HPOF_M400,
45 HPOF_P800, HPOF_M800, HPOF_P800, HPOF_M800,
46 HPOF_P1200, HPOF_M1200, HPOF_P1200, HPOF_M1200,
47 0, 0, 0, 0,
48};
49
356d90a8 50struct dkbad hpbad[MAXNMBA*8];
356d90a8 51
f834e141
MK
52struct hp_softc {
53 char type;
54 char gottype;
55 char ssect; /* 1 when on track w/skip sector */
56 char debug;
57# define HPF_BSEDEBUG 01 /* debugging bad sector forwarding */
58# define HPF_ECCDEBUG 02 /* debugging ecc correction */
59 int ecclim;
60 int retries;
61} hp_softc[MAXNMBA * 8];
356d90a8
SL
62
63int sectsiz;
63c82e3f 64
4b5bcdd9
SL
65/*
66 * When awaiting command completion, don't
67 * hang on to the status register since
356d90a8 68 * this ties up some controllers.
4b5bcdd9 69 */
356d90a8
SL
70#define HPWAIT(addr) \
71 while ((((addr)->hpds)&HPDS_DRY)==0) DELAY(500);
4b5bcdd9 72
63c82e3f
HS
73hpopen(io)
74 register struct iob *io;
75{
76 register unit = io->i_unit;
77 struct hpdevice *hpaddr = (struct hpdevice *)mbadrv(unit);
3857f7f3 78 register struct st *st;
f834e141 79 register struct hp_softc *sc = &hp_softc[unit];
63c82e3f
HS
80
81 mbainit(UNITTOMBA(unit));
f834e141 82 if (sc->gottype == 0) {
356d90a8 83 register i, type = hpaddr->hpdt & MBDT_TYPE;
63c82e3f
HS
84 struct iob tio;
85
86 for (i = 0; hptypes[i]; i++)
87 if (hptypes[i] == type)
88 goto found;
89 _stop("unknown drive type");
90found:
f834e141
MK
91 sc->retries = RETRIES;
92 sc->ecclim = 11;
93 sc->debug = 0;
7fc00e31
HS
94 hpaddr->hpcs1 = HP_DCLR|HP_GO; /* init drive */
95 hpaddr->hpcs1 = HP_PRESET|HP_GO;
96 if (!ML11)
97 hpaddr->hpof = HPOF_FMT22;
f834e141 98 sc->type = hpmaptype(hpaddr, i, UNITTODRIVE(unit));
63c82e3f 99 /*
356d90a8 100 * Read in the bad sector table.
63c82e3f 101 */
f834e141 102 st = &hpst[sc->type];
63c82e3f
HS
103 tio = *io;
104 tio.i_bn = st->nspc * st->ncyl - st->nsect;
ccc991c5 105 tio.i_ma = (char *)&hpbad[unit];
711717bf 106 tio.i_cc = sizeof (struct dkbad);
63c82e3f
HS
107 tio.i_flgs |= F_RDDATA;
108 for (i = 0; i < 5; i++) {
711717bf 109 if (hpstrategy(&tio, READ) == sizeof (struct dkbad))
63c82e3f
HS
110 break;
111 tio.i_bn += 2;
112 }
113 if (i == 5) {
114 printf("Unable to read bad sector table\n");
115 for (i = 0; i < MAXBADDESC; i++) {
116 hpbad[unit].bt_bad[i].bt_cyl = -1;
117 hpbad[unit].bt_bad[i].bt_trksec = -1;
118 }
f834e141
MK
119 }
120 sc->gottype = 1;
63c82e3f 121 }
f834e141 122 st = &hpst[sc->type];
63c82e3f
HS
123 if (io->i_boff < 0 || io->i_boff > 7 ||
124 st->off[io->i_boff]== -1)
125 _stop("hp bad minor");
126 io->i_boff = st->off[io->i_boff] * st->nspc;
127}
128
129hpstrategy(io, func)
130 register struct iob *io;
131{
132 register unit = io->i_unit;
133 struct mba_regs *mba = mbamba(unit);
356d90a8 134 daddr_t bn, startblock;
63c82e3f 135 struct hpdevice *hpaddr = (struct hpdevice *)mbadrv(unit);
f834e141
MK
136 register struct hp_softc *sc = &hp_softc[unit];
137 struct st *st = &hpst[sc->type];
138 int cn, tn, sn, bytecnt, bytesleft, rv;
63c82e3f
HS
139 char *membase;
140 int er1, er2, hprecal;
141
142 sectsiz = SECTSIZ;
143 if ((io->i_flgs & (F_HDR|F_HCHECK)) != 0)
144 sectsiz += HDRSIZ;
145 if ((hpaddr->hpds & HPDS_VV) == 0) {
146 hpaddr->hpcs1 = HP_DCLR|HP_GO;
147 hpaddr->hpcs1 = HP_PRESET|HP_GO;
9d78a350 148 if (!ML11)
63c82e3f
HS
149 hpaddr->hpof = HPOF_FMT22;
150 }
151 io->i_errcnt = 0;
f834e141
MK
152 sc->ssect = 0;
153 rv = bytecnt = io->i_cc;
63c82e3f
HS
154 membase = io->i_ma;
155 startblock = io->i_bn;
308847fc 156 hprecal = 0;
86bcc486 157
ccc991c5 158restart:
63c82e3f
HS
159 bn = io->i_bn;
160 cn = bn/st->nspc;
161 sn = bn%st->nspc;
162 tn = sn/st->nsect;
f834e141 163 sn = sn%st->nsect + sc->ssect;
63c82e3f 164
4b5bcdd9 165 HPWAIT(hpaddr);
ccc991c5 166 mba->mba_sr = -1;
7fc00e31 167 if (ML11)
63c82e3f
HS
168 hpaddr->hpda = bn;
169 else {
170 hpaddr->hpdc = cn;
171 hpaddr->hpda = (tn << 8) + sn;
172 }
f834e141
MK
173 if (mbastart(io, func) != 0) { /* start transfer */
174 rv = -1;
175 goto done;
176 }
4b5bcdd9 177 HPWAIT(hpaddr);
356d90a8
SL
178 /*
179 * Successful data transfer, return.
180 */
c5fc2df8
MK
181 if ((hpaddr->hpds&HPDS_ERR) == 0 && (mba->mba_sr&MBSR_EBITS) == 0)
182 goto done;
63c82e3f 183
356d90a8
SL
184 /*
185 * Error handling. Calculate location of error.
186 */
187 bytesleft = MASKREG(mba->mba_bcr);
188 if (bytesleft)
189 bytesleft |= 0xffff0000; /* sxt */
190 bn = io->i_bn + (io->i_cc + bytesleft) / sectsiz;
71da8ead
MK
191 er1 = MASKREG(hpaddr->hper1);
192 er2 = MASKREG(hpaddr->hper2);
193 if (er1 & (HPER1_DCK|HPER1_ECH))
194 bn--; /* Error is in Prev block */
63c82e3f
HS
195 cn = bn/st->nspc;
196 sn = bn%st->nspc;
197 tn = sn/st->nsect;
198 sn = sn%st->nsect;
f834e141
MK
199 if (sc->debug & (HPF_ECCDEBUG|HPF_BSEDEBUG)) {
200 printf("hp error: sn%d (cyl,trk,sec)=(%d,%d,%d) ds=%b\n",
201 bn, cn, tn, sn, MASKREG(hpaddr->hpds), HPDS_BITS);
356d90a8
SL
202 printf("er1=%b er2=%b\n", er1, HPER1_BITS, er2, HPER2_BITS);
203 printf("bytes left: %d, of 0x%x, da 0x%x\n",-bytesleft,
204 hpaddr->hpof, hpaddr->hpda);
205 }
63c82e3f
HS
206 if (er1 & HPER1_HCRC) {
207 er1 &= ~(HPER1_HCE|HPER1_FER);
208 er2 &= ~HPER2_BSE;
f834e141
MK
209 if ((io->i_flgs&F_NBSF) == 0 && hpecc(io, BSE) == 0)
210 goto success;
63c82e3f 211 }
86bcc486
SL
212 /*
213 * Give up early if drive write locked.
214 */
63c82e3f
HS
215 if (er1&HPER1_WLE) {
216 printf("hp%d: write locked\n", unit);
f834e141
MK
217 rv = -1;
218 goto done;
9d78a350 219 }
86bcc486 220 /*
f834e141 221 * Skip sector handling.
86bcc486 222 */
f834e141
MK
223 if (RM80 && (er2 & HPER2_SSE)) {
224 (void) hpecc(io, SSE);
225 sc->ssect = 1;
226 goto restart;
9d78a350 227 }
86bcc486 228 /*
f834e141
MK
229 * Attempt to forward bad sectors on anything but an ML11.
230 * Interpret format error bit as a bad block on RP06's.
86bcc486 231 */
f834e141
MK
232 if (((er2 & HPER2_BSE) && !ML11) ||
233 (MASKREG(er1) == HPER1_FER && RP06)) {
9d78a350 234 if (io->i_flgs & F_NBSF) {
63c82e3f
HS
235 io->i_error = EBSE;
236 goto hard;
237 }
238 if (hpecc(io, BSE) == 0)
239 goto success;
9d78a350
SL
240 io->i_error = EBSE;
241 goto hard;
242 }
86bcc486 243 /*
356d90a8 244 * ECC correction?
86bcc486 245 */
9d78a350 246 if ((er1 & (HPER1_DCK|HPER1_ECH)) == HPER1_DCK) {
4b5bcdd9 247 if (hpecc(io, ECC) == 0)
63c82e3f 248 goto success;
9d78a350 249 io->i_error = EECC;
71da8ead 250 goto hard;
f834e141
MK
251 }
252
253 /*
254 * If a hard error, or maximum retry count
255 * exceeded, clear controller state and
256 * pass back error to caller.
257 */
258 if (++io->i_errcnt > sc->retries || (er1 & HPER1_HARD) ||
259 (!ML11 && (er2 & HPER2_HARD)) || (ML11 && (io->i_errcnt >= 16))) {
260 io->i_error = EHER;
261 if (mba->mba_sr & (MBSR_WCKUP|MBSR_WCKLWR))
262 io->i_error = EWCK;
263hard:
264 io->i_errblk = bn + sc->ssect;
265 if (sc->debug & (HPF_BSEDEBUG|HPF_ECCDEBUG))
266 printf(" dc=%d, da=0x%x",MASKREG(hpaddr->hpdc),
267 MASKREG(hpaddr->hpda));
268 else {
269 printf("hp error: sn%d (cyl,trk,sec)=(%d,%d,%d) ds=%b \n",
270 bn, cn, tn, sn, MASKREG(hpaddr->hpds), HPDS_BITS);
271 printf("er1=%b er2=%b", er1, HPER1_BITS, er2, HPER2_BITS);
272 }
273 hpaddr->hpcs1 = HP_DCLR|HP_GO;
274 printf("\n");
275 rv = -1;
276 goto done;
277
278 }
308847fc 279 /* fall thru to retry */
63c82e3f 280 hpaddr->hpcs1 = HP_DCLR|HP_GO;
4b5bcdd9 281 HPWAIT(hpaddr);
86bcc486
SL
282
283 /*
284 * Every fourth retry recalibrate.
285 */
356d90a8 286 if (((io->i_errcnt & 07) == 4) ) {
63c82e3f 287 hpaddr->hpcs1 = HP_RECAL|HP_GO;
71da8ead 288 HPWAIT(hpaddr);
63c82e3f
HS
289 hpaddr->hpdc = cn;
290 hpaddr->hpcs1 = HP_SEEK|HP_GO;
71da8ead
MK
291 HPWAIT(hpaddr);
292 }
4b5bcdd9 293
71da8ead 294 if (io->i_errcnt >= 16 && (io->i_flgs & F_READ)) {
63c82e3f
HS
295 hpaddr->hpof = hp_offset[io->i_errcnt & 017]|HPOF_FMT22;
296 hpaddr->hpcs1 = HP_OFFSET|HP_GO;
71da8ead 297 HPWAIT(hpaddr);
63c82e3f 298 }
f834e141 299 if (sc->debug & (HPF_ECCDEBUG|HPF_BSEDEBUG))
71da8ead
MK
300 printf("restart: bn=%d, cc=%d, ma=0x%x hprecal=%d\n",
301 io->i_bn, io->i_cc, io->i_ma, hprecal);
f834e141 302 goto restart;
9d78a350 303
86bcc486
SL
304success:
305 /*
306 * On successful error recovery, bump
307 * block number to advance to next portion
308 * of i/o transfer.
309 */
63c82e3f
HS
310 bn++;
311 if ((bn-startblock) * sectsiz < bytecnt) {
63c82e3f 312 io->i_bn = bn;
63c82e3f
HS
313 io->i_ma = membase + (io->i_bn - startblock)*sectsiz;
314 io->i_cc = bytecnt - (io->i_bn - startblock)*sectsiz;
f834e141 315 if (sc->debug & (HPF_ECCDEBUG|HPF_BSEDEBUG))
356d90a8
SL
316 printf("restart: bn=%d, cc=%d, ma=0x%x hprecal=%d\n",
317 io->i_bn, io->i_cc, io->i_ma, hprecal);
ccc991c5 318 goto restart;
63c82e3f 319 }
c5fc2df8 320done:
71da8ead
MK
321 if (io->i_errcnt >= 16) {
322 hpaddr->hpcs1 = HP_RTC|HP_GO;
323 while (hpaddr->hpds & HPDS_PIP)
324 ;
325 }
f834e141 326 io->i_bn = startblock; /*reset i_bn to original */
2f1563bc 327 io->i_cc = bytecnt; /*reset i_cc to total count xfered*/
f834e141
MK
328 io->i_ma = membase; /*reset i_ma to original */
329 return (rv);
63c82e3f 330}
4b5bcdd9 331
63c82e3f
HS
332hpecc(io, flag)
333 register struct iob *io;
334 int flag;
335{
336 register unit = io->i_unit;
337 register struct mba_regs *mbp = mbamba(unit);
338 register struct hpdevice *rp = (struct hpdevice *)mbadrv(unit);
f834e141
MK
339 register struct hp_softc *sc = &hp_softc[unit];
340 register struct st *st = &hpst[sc->type];
9d78a350 341 int npf, bn, cn, tn, sn, bcr;
63c82e3f 342
356d90a8
SL
343 bcr = MASKREG(mbp->mba_bcr);
344 if (bcr)
345 bcr |= 0xffff0000; /* sxt */
9d78a350 346 npf = (bcr + io->i_cc) / sectsiz; /* # sectors read */
71da8ead
MK
347 if (flag == ECC)
348 npf--; /* Error is in prev block --ghg */
f834e141
MK
349 bn = io->i_bn + npf + sc->ssect; /* physical block #*/
350 if (sc->debug & HPF_ECCDEBUG)
356d90a8 351 printf("bcr=%d npf=%d ssect=%d sectsiz=%d i_cc=%d\n",
f834e141 352 bcr, npf, sc->ssect, sectsiz, io->i_cc);
86bcc486
SL
353 /*
354 * ECC correction logic.
355 */
356 if (flag == ECC) {
63c82e3f
HS
357 register int i;
358 caddr_t addr;
f834e141 359 int bit, o, mask;
63c82e3f 360
0cd55454 361 printf("hp%d: soft ecc sn%d\n", unit, bn);
63c82e3f 362 mask = MASKREG(rp->hpec2);
f834e141
MK
363 for (i = mask, bit = 0; i; i >>= 1)
364 if (i & 1)
365 bit++;
366 if (bit > sc->ecclim) {
367 printf("%d-bit error\n", bit);
368 return (1);
369 }
9d78a350 370 i = MASKREG(rp->hpec1) - 1; /* -1 makes 0 origin */
63c82e3f 371 bit = i&07;
356d90a8 372 o = (i & ~07) >> 3;
63c82e3f 373 rp->hpcs1 = HP_DCLR | HP_GO;
10860662
SL
374 while (o <sectsiz && npf*sectsiz + o < io->i_cc && bit > -11) {
375 addr = io->i_ma + (npf*sectsiz) + o;
10860662
SL
376 /*
377 * No data transfer occurs with a write check,
378 * so don't correct the resident copy of data.
379 */
356d90a8 380 if ((io->i_flgs & (F_CHECK|F_HCHECK)) == 0) {
f834e141 381 if (sc->debug & HPF_ECCDEBUG)
356d90a8
SL
382 printf("addr=%x old=%x ", addr,
383 (*addr & 0xff));
86bcc486 384 *addr ^= (mask << bit);
f834e141 385 if (sc->debug & HPF_ECCDEBUG)
356d90a8
SL
386 printf("new=%x\n",(*addr & 0xff));
387 }
10860662 388 o++, bit -= 8;
63c82e3f 389 }
10860662 390 return (0);
9d78a350 391 }
63c82e3f 392
9d78a350
SL
393 /*
394 * Skip sector error.
395 * Set skip-sector-inhibit and
396 * read next sector
397 */
86bcc486 398 if (flag == SSE) {
63c82e3f 399 rp->hpcs1 = HP_DCLR | HP_GO;
4b5bcdd9 400 HPWAIT(rp);
63c82e3f 401 rp->hpof |= HPOF_SSEI;
9d78a350 402 return (0);
86bcc486 403 }
63c82e3f 404
86bcc486
SL
405 /*
406 * Bad block forwarding.
407 */
408 if (flag == BSE) {
ccc991c5 409 int bbn;
9d78a350 410
ccc991c5 411 rp->hpcs1 = HP_DCLR | HP_GO;
f834e141 412 if (sc->debug & HPF_BSEDEBUG)
356d90a8 413 printf("hpecc: BSE @ bn %d\n", bn);
63c82e3f
HS
414 cn = bn/st->nspc;
415 sn = bn%st->nspc;
416 tn = sn/st->nsect;
ccc991c5
HS
417 sn = sn%st->nsect;
418 bcr += sectsiz;
419 if ((bbn = isbad(&hpbad[unit], cn, tn, sn)) < 0)
9d78a350 420 return (1);
ccc991c5
HS
421 bbn = st->ncyl*st->nspc - st->nsect - 1 - bbn;
422 cn = bbn/st->nspc;
423 sn = bbn%st->nspc;
424 tn = sn/st->nsect;
425 sn = sn%st->nsect;
426 io->i_cc = sectsiz;
427 io->i_ma += npf*sectsiz;
f834e141 428 if (sc->debug & HPF_BSEDEBUG)
356d90a8
SL
429 printf("revector to cn %d tn %d sn %d\n", cn, tn, sn);
430 rp->hpof &= ~HPOF_SSEI;
ccc991c5 431 mbp->mba_sr = -1;
63c82e3f
HS
432 rp->hpdc = cn;
433 rp->hpda = (tn<<8) + sn;
63c82e3f 434 mbastart(io,io->i_flgs);
356d90a8 435 io->i_errcnt = 0;
4b5bcdd9
SL
436 HPWAIT(rp);
437 return (rp->hpds&HPDS_ERR);
63c82e3f 438 }
9d78a350
SL
439 printf("hpecc: flag=%d\n", flag);
440 return (1);
63c82e3f 441}
86bcc486 442
63c82e3f
HS
443/*ARGSUSED*/
444hpioctl(io, cmd, arg)
445 struct iob *io;
446 int cmd;
447 caddr_t arg;
448{
7fc00e31 449 register unit = io->i_unit;
f834e141
MK
450 register struct hp_softc *sc = &hp_softc[unit];
451 struct st *st = &hpst[sc->type];
7fc00e31 452 struct mba_drv *drv = mbadrv(unit);
63c82e3f
HS
453
454 switch(cmd) {
455
356d90a8 456 case SAIODEBUG:
f834e141
MK
457 sc->debug = (int)arg;
458 break;
356d90a8 459
63c82e3f 460 case SAIODEVDATA:
f834e141
MK
461 if (drv->mbd_dt&MBDT_TAP)
462 return (ECMD);
463 *(struct st *)arg = *st;
464 break;
465
466 case SAIOGBADINFO:
467 if (drv->mbd_dt&MBDT_TAP)
468 return (ECMD);
469 *(struct dkbad *)arg = hpbad[unit];
470 break;
471
472 case SAIOECCLIM:
473 sc->ecclim = (int)arg;
474 break;
475
476 case SAIORETRIES:
477 sc->retries = (int)arg;
478 break;
63c82e3f 479
9d78a350
SL
480 case SAIOSSI: /* skip-sector-inhibit */
481 if (drv->mbd_dt&MBDT_TAP)
482 return (ECMD);
483 if ((io->i_flgs&F_SSI) == 0) {
484 /* make sure this is done once only */
485 io->i_flgs |= F_SSI;
486 st->nsect++;
487 st->nspc += st->ntrak;
4b5bcdd9 488 }
f834e141 489 break;
ccc991c5 490
9d78a350 491 case SAIONOSSI: /* remove skip-sector-inhibit */
ccc991c5
HS
492 if (io->i_flgs & F_SSI) {
493 io->i_flgs &= ~F_SSI;
494 drv->mbd_of &= ~HPOF_SSEI;
495 st->nsect--;
496 st->nspc -= st->ntrak;
497 }
f834e141 498 break;
ccc991c5 499
4b5bcdd9 500 case SAIOSSDEV: /* drive have skip sector? */
9d78a350 501 return (RM80 ? 0 : ECMD);
f834e141
MK
502
503 default:
504 return (ECMD);
63c82e3f 505 }
f834e141 506 return (0);
63c82e3f 507}