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