4.2 distribution
[unix-history] / usr / src / sys / vax / stand / hp.c
index bae9120..4330fda 100644 (file)
@@ -1,4 +1,4 @@
-/*     hp.c    4.13    83/02/17        */
+/*     hp.c    6.1     83/07/29        */
 
 /*
  * RP??/RM?? disk driver
 
 /*
  * RP??/RM?? disk driver
@@ -6,7 +6,6 @@
  * Also supports header io operations and
  * commands to write check header and data.
  */
  * Also supports header io operations and
  * commands to write check header and data.
  */
-
 #include "../h/param.h"
 #include "../h/inode.h"
 #include "../h/fs.h"
 #include "../h/param.h"
 #include "../h/inode.h"
 #include "../h/fs.h"
 
 #define        MASKREG(reg)    ((reg)&0xffff)
 
 
 #define        MASKREG(reg)    ((reg)&0xffff)
 
-#define MAXBADDESC     126
-#define SECTSIZ        512     /* sector size in bytes */
-#define HDRSIZ         4       /* number of bytes in sector header */
-#define MAXECC         5       /* the maximum number of bad bits accepted in
-                                * an ecc error when F_ECCLM is set */
+#define        MAXBADDESC      126
+#define        SECTSIZ         512     /* sector size in bytes */
+#define        HDRSIZ          4       /* number of bytes in sector header */
+#define        MAXECC          5       /* max # bits allow in ecc error w/ F_ECCLM */
 
 char   hp_type[MAXNMBA*8] = { 0 };
 
 char   hp_type[MAXNMBA*8] = { 0 };
+extern struct st hpst[];
+
+short  hptypes[] = {
+       MBDT_RM03,
+       MBDT_RM05,
+       MBDT_RP06,
+       MBDT_RM80,
+       MBDT_RP05,
+       MBDT_RP07,
+       MBDT_ML11A,
+       MBDT_ML11B,
+       -1,             /* 9755 */
+       -1,             /* 9730 */
+       -1,             /* Capricorn */
+       -1,             /* Eagle */
+       MBDT_RM02,      /* actually something else */
+       -1,             /* 9300 */
+       0
+};
 
 
-/* THIS SHOULD BE READ IN OFF THE PACK, PER DRIVE */
-short  hp6_off[8] =    { 0, 38, 0, -1, -1, -1, 118, -1 };
-short  rm3_off[8] =    { 0, 100, 0, -1, -1, -1, 310, -1 };
-short  rm5_off[8] =    { 0, 27, 0, 562, 589, 681, 562, 82 };
-short  rm80_off[8] =   { 0, 37, 0, -1, -1, -1, 115, 305 };
-short  hp7_off[8] =    { 0, 10, 0, 330, 340, 500, 330, 50 };
-short  ml_off[8] =     { 0, -1, -1, -1, -1, -1, -1, -1 };
-short  si9775_off[8] = { 0, 13, 0, -1, -1, -1, 40, 441 };
-short  si9730_off[8] = { 0, 50, 0, -1, -1, -1, -1, 155 };
-short  hpam_off[8] =   { 0, 32, 0, 668, 723, 778, 668, 98 };
-short  hpfj_off[8] =   { 0, 19, 0, -1, -1, -1, 398, 59 };
-/* END SHOULD BE READ IN */
-
-short  hptypes[] =
-    { MBDT_RM03, MBDT_RM05, MBDT_RP06, MBDT_RM80, MBDT_RP05, MBDT_RP07,
-      MBDT_ML11A, MBDT_ML11B, -1/*9755*/, -1/*9730*/, -1/*Capr*/,
-      -1/* eagle */, -1/* 48 sect eagle */, MBDT_RM02, 0};
-
-#define RP06 (hptypes[hp_type[unit]] <= MBDT_RP06)
-#define ML11 (hptypes[hp_type[unit]] == MBDT_ML11A)
-#define RM80 (hptypes[hp_type[unit]] == MBDT_RM80)
+#define        RP06 (hptypes[hp_type[unit]] <= MBDT_RP06)
+#define        ML11 (hptypes[hp_type[unit]] == MBDT_ML11A)
+#define        RM80 (hptypes[hp_type[unit]] == MBDT_RM80)
 
 u_char hp_offset[16] = {
     HPOF_P400, HPOF_M400, HPOF_P400, HPOF_M400,
 
 u_char hp_offset[16] = {
     HPOF_P400, HPOF_M400, HPOF_P400, HPOF_M400,
@@ -58,32 +57,22 @@ u_char      hp_offset[16] = {
     0, 0, 0, 0,
 };
 
     0, 0, 0, 0,
 };
 
-struct st hpst[] = {
-       32,     5,      32*5,   823,    rm3_off,        /* RM03 */
-       32,     19,     32*19,  823,    rm5_off,        /* RM05 */
-       22,     19,     22*19,  815,    hp6_off,        /* RP06 */
-       31,     14,     31*14,  559,    rm80_off,       /* RM80 */
-       22,     19,     22*19,  411,    hp6_off,        /* RP06 */
-       50,     32,     50*32,  630,    hp7_off,        /* RP07 */
-       1,      1,      1,      1,      ml_off,         /* ML11A */
-       1,      1,      1,      1,      ml_off,         /* ML11B */
-       32,     40,     32*40,  843,    si9775_off,     /* 9775 */
-       32,     10,     32*10,  823,    si9730_off,     /* 9730 */
-       32,     16,     32*16,  1024,   hpam_off,       /* capricorn */
-       43,     20,     43*20,  842,    hpfj_off,       /* Eagle */
-       48,     20,     48*20,  842,    hpfj_off,       /* modif. eagle */
-       1,      1,      1,      1,      0,      /* rm02 - not used */
-};
+struct dkbad hpbad[MAXNMBA*8];
+int    ssect[MAXNMBA*8];               /* 1 when on track w/skip sector */
 
 
-struct dkbad hpbad[MAXNMBA*8];
-int sectsiz;
+int    hpdebug[MAXNMBA*8];
+#define        HPF_BSEDEBUG    01      /* debugging bad sector forwarding */
+#define        HPF_ECCDEBUG    02      /* debugging ecc correction */
+
+int    sectsiz;
 
 /*
  * When awaiting command completion, don't
  * hang on to the status register since
 
 /*
  * When awaiting command completion, don't
  * hang on to the status register since
- * this ties up the controller.
+ * this ties up some controllers.
  */
  */
-#define        HPWAIT(addr)    while ((((addr)->hpds)&HPDS_DRY)==0) DELAY(500);
+#define        HPWAIT(addr) \
+       while ((((addr)->hpds)&HPDS_DRY)==0) DELAY(500);
 
 hpopen(io)
        register struct iob *io;
 
 hpopen(io)
        register struct iob *io;
@@ -94,8 +83,7 @@ hpopen(io)
 
        mbainit(UNITTOMBA(unit));
        if (hp_type[unit] == 0) {
 
        mbainit(UNITTOMBA(unit));
        if (hp_type[unit] == 0) {
-               register type = hpaddr->hpdt & MBDT_TYPE;
-               register int i;
+               register i, type = hpaddr->hpdt & MBDT_TYPE;
                struct iob tio;
 
                for (i = 0; hptypes[i]; i++)
                struct iob tio;
 
                for (i = 0; hptypes[i]; i++)
@@ -109,12 +97,9 @@ found:
                        hpaddr->hpof = HPOF_FMT22;
                hp_type[unit] = hpmaptype(hpaddr, i, unit);
                /*
                        hpaddr->hpof = HPOF_FMT22;
                hp_type[unit] = hpmaptype(hpaddr, i, unit);
                /*
-                * Read in the bad sector table:
-                *      copy the contents of the io structure
-                *      to tio for use during the bb pointer
-                *      read operation.
+                * Read in the bad sector table.
                 */
                 */
-               st = &hpst[i];
+               st = &hpst[hp_type[unit]];
                tio = *io;
                tio.i_bn = st->nspc * st->ncyl - st->nsect;
                tio.i_ma = (char *)&hpbad[unit];
                tio = *io;
                tio.i_bn = st->nspc * st->ncyl - st->nsect;
                tio.i_ma = (char *)&hpbad[unit];
@@ -139,76 +124,15 @@ found:
        io->i_boff = st->off[io->i_boff] * st->nspc;
 }
 
        io->i_boff = st->off[io->i_boff] * st->nspc;
 }
 
-hpmaptype(hpaddr, type, unit)
-       register struct hpdevice *hpaddr;
-       unsigned type;
-       int unit;
-{
-       int ntracks, hpsn;
-
-       /*
-        * Handle SI model byte stuff when
-        * we think it's an RM03 or RM05.
-        */
-       if (type == 0 || type == 1) {
-               hpsn = hpaddr->hpsn;
-               if ((hpsn & SIMB_LU) != unit)
-                       return (type);
-               switch ((hpsn & SIMB_MB) &~ (SIMB_S6|SIRM03|SIRM05)) {
-               case SI9775D:
-                       return (8);
-               case SI9730D:
-                       return (9);
-               case SI9766:
-                       hpaddr->hpcs1 = HP_RECAL|HP_GO;
-                       DELAY(100000);
-                       return (1);
-
-               case SI9762:
-                       return (0);
-               }
-               return (type);
-       }
-       /*
-        * RM03: EMULEX controller.  Map to correct
-        * drive type by checking the holding
-        * register for the disk geometry.
-        */
-       if (type == 13) {
-               hpaddr->hpcs1 = HP_NOP;
-               hpaddr->hphr = HPHR_MAXTRAK;
-               ntracks = MASKREG(hpaddr->hphr) + 1;
-               if (ntracks == 16)
-                       return (10);    /* AMPEX capricorn */
-               hpaddr->hphr = HPHR_MAXSECT;
-               ntracks = MASKREG(hpaddr->hphr) + 1;
-               if (ntracks == 48)
-                       return (12);    /* 48 sector Eagle */
-               if (ntracks == 43)
-                       return (11);    /* 43 sector Eagle */
-               printf("RM02 with %d sectors/track?\n", ntracks);
-               return (type);
-       }
-       /*
-        * ML11's all map to the same type.
-        */
-       if (type == 6 || type == 7)
-               return (6);
-       return (type);
-}
-
-int    ssect;          /* set to 1 if we are on a track with skip sectors */
-
 hpstrategy(io, func)
        register struct iob *io;
 {
        register unit = io->i_unit;
        struct mba_regs *mba = mbamba(unit);
 hpstrategy(io, func)
        register struct iob *io;
 {
        register unit = io->i_unit;
        struct mba_regs *mba = mbamba(unit);
-       daddr_t bn;
+       daddr_t bn, startblock;
        struct hpdevice *hpaddr = (struct hpdevice *)mbadrv(unit);
        struct st *st = &hpst[hp_type[unit]];
        int cn, tn, sn, bytecnt, bytesleft; 
        struct hpdevice *hpaddr = (struct hpdevice *)mbadrv(unit);
        struct st *st = &hpst[hp_type[unit]];
        int cn, tn, sn, bytecnt, bytesleft; 
-       daddr_t startblock;
        char *membase;
        int er1, er2, hprecal;
 
        char *membase;
        int er1, er2, hprecal;
 
@@ -222,17 +146,18 @@ hpstrategy(io, func)
                        hpaddr->hpof = HPOF_FMT22;
        }
        io->i_errcnt = 0;
                        hpaddr->hpof = HPOF_FMT22;
        }
        io->i_errcnt = 0;
-       ssect = 0;
+       ssect[unit] = 0;
        bytecnt = io->i_cc;
        membase = io->i_ma;
        startblock = io->i_bn;
        hprecal = 0;
        bytecnt = io->i_cc;
        membase = io->i_ma;
        startblock = io->i_bn;
        hprecal = 0;
+
 restart:
        bn = io->i_bn;
        cn = bn/st->nspc;
        sn = bn%st->nspc;
        tn = sn/st->nsect;
 restart:
        bn = io->i_bn;
        cn = bn/st->nspc;
        sn = bn%st->nspc;
        tn = sn/st->nsect;
-       sn = sn%st->nsect + ssect;
+       sn = sn%st->nsect + ssect[unit];
 
        HPWAIT(hpaddr);
        mba->mba_sr = -1;
 
        HPWAIT(hpaddr);
        mba->mba_sr = -1;
@@ -245,46 +170,64 @@ restart:
        if (mbastart(io, func) != 0)            /* start transfer */
                return (-1);
        HPWAIT(hpaddr);
        if (mbastart(io, func) != 0)            /* start transfer */
                return (-1);
        HPWAIT(hpaddr);
+       /*
+        * Successful data transfer, return.
+        */
        if ((hpaddr->hpds&HPDS_ERR) == 0 && (mba->mba_sr&MBSR_EBITS) == 0)
                return (bytecnt);
 
        if ((hpaddr->hpds&HPDS_ERR) == 0 && (mba->mba_sr&MBSR_EBITS) == 0)
                return (bytecnt);
 
-       /* ------- error handling ------- */
-
-       if (bytesleft = MASKREG(mba->mba_bcr>>16)) 
-               bytesleft |= 0xffff0000;        /* sign ext */
-       bn = io->i_bn + (io->i_cc + bytesleft)/sectsiz;
+       /*
+        * Error handling.  Calculate location of error.
+        */
+       bytesleft = MASKREG(mba->mba_bcr);
+       if (bytesleft) 
+               bytesleft |= 0xffff0000;        /* sxt */
+       bn = io->i_bn + (io->i_cc + bytesleft) / sectsiz;
        cn = bn/st->nspc;
        sn = bn%st->nspc;
        tn = sn/st->nsect;
        sn = sn%st->nsect;
        er1 = MASKREG(hpaddr->hper1);
        er2 = MASKREG(hpaddr->hper2);
        cn = bn/st->nspc;
        sn = bn%st->nspc;
        tn = sn/st->nsect;
        sn = sn%st->nsect;
        er1 = MASKREG(hpaddr->hper1);
        er2 = MASKREG(hpaddr->hper2);
-#ifdef HPDEBUG
-       printf("hp error: (cyl,trk,sec)=(%d,%d,%d) ds=%b \n",
-               cn, tn, sn, MASKREG(hpaddr->hpds), HPDS_BITS);
-       printf("er1=%b er2=%b", er1, HPER1_BITS, er2, HPER2_BITS);
-       printf("\nbytes left: %d, of 0x%x, da 0x%x",-bytesleft,
-       hpaddr->hpof, hpaddr->hpda);
-       printf("\n");
-#endif
+       if (hpdebug[unit] & (HPF_ECCDEBUG|HPF_BSEDEBUG)) {
+               printf("hp error: (cyl,trk,sec)=(%d,%d,%d) ds=%b\n",
+                       cn, tn, sn, MASKREG(hpaddr->hpds), HPDS_BITS);
+               printf("er1=%b er2=%b\n", er1, HPER1_BITS, er2, HPER2_BITS);
+               printf("bytes left: %d, of 0x%x, da 0x%x\n",-bytesleft,
+                       hpaddr->hpof, hpaddr->hpda);
+       }
        if (er1 & HPER1_HCRC) {
                er1 &= ~(HPER1_HCE|HPER1_FER);
                er2 &= ~HPER2_BSE;
        }
        if (er1 & HPER1_HCRC) {
                er1 &= ~(HPER1_HCE|HPER1_FER);
                er2 &= ~HPER2_BSE;
        }
+       /*
+        * Give up early if drive write locked.
+        */
        if (er1&HPER1_WLE) {
                printf("hp%d: write locked\n", unit);
                return (-1);
        }
        if (er1&HPER1_WLE) {
                printf("hp%d: write locked\n", unit);
                return (-1);
        }
+       /*
+        * Interpret format error bit as a bad block on RP06's.
+        */
        if (MASKREG(er1) == HPER1_FER && RP06)
                goto badsect;
        if (MASKREG(er1) == HPER1_FER && RP06)
                goto badsect;
+
+       /*
+        * If a hard error, or maximum retry count
+        * exceeded, clear controller state and
+        * pass back error to caller.
+        */
        if (++io->i_errcnt > 27 || (er1 & HPER1_HARD) ||
            (!ML11 && (er2 & HPER2_HARD))) {
        if (++io->i_errcnt > 27 || (er1 & HPER1_HARD) ||
            (!ML11 && (er2 & HPER2_HARD))) {
+               if ((io->i_flgs&F_NBSF) == 0 && hpecc(io, BSE) == 0)
+                       goto success;
 hard0:
                io->i_error = EHER;
                if (mba->mba_sr & (MBSR_WCKUP|MBSR_WCKLWR))
                        io->i_error = EWCK;
 hard:
 hard0:
                io->i_error = EHER;
                if (mba->mba_sr & (MBSR_WCKUP|MBSR_WCKLWR))
                        io->i_error = EWCK;
 hard:
-               io->i_errblk = bn + ssect;
+               io->i_errblk = bn + ssect[unit];
                printf("hp error: (cyl,trk,sec)=(%d,%d,%d) ds=%b \n",
                           cn, tn, sn, MASKREG(hpaddr->hpds), HPDS_BITS);
                printf("er1=%b er2=%b", er1, HPER1_BITS, er2, HPER2_BITS);
                printf("hp error: (cyl,trk,sec)=(%d,%d,%d) ds=%b \n",
                           cn, tn, sn, MASKREG(hpaddr->hpds), HPDS_BITS);
                printf("er1=%b er2=%b", er1, HPER1_BITS, er2, HPER2_BITS);
@@ -292,18 +235,24 @@ hard:
                        printf(" mr1=%o", MASKREG(hpaddr->hpmr));
                if (hpaddr->hpmr2)
                        printf(" mr2=%o", MASKREG(hpaddr->hpmr2));
                        printf(" mr1=%o", MASKREG(hpaddr->hpmr));
                if (hpaddr->hpmr2)
                        printf(" mr2=%o", MASKREG(hpaddr->hpmr2));
-#ifdef HPDEBUG
-               printf("dc: %d, da: 0x%x",MASKREG(hpaddr->hpdc),
-                 MASKREG(hpaddr->hpda));
-#endif
+               if (hpdebug[unit] & (HPF_BSEDEBUG|HPF_ECCDEBUG))
+                       printf(" dc=%d, da=0x%x",MASKREG(hpaddr->hpdc),
+                         MASKREG(hpaddr->hpda));
                hpaddr->hpcs1 = HP_DCLR|HP_GO;
                printf("\n");
                return (-1);
 
        }
                hpaddr->hpcs1 = HP_DCLR|HP_GO;
                printf("\n");
                return (-1);
 
        }
+       /*
+        * Attempt to forward bad sectors on
+        * anything but an ML11.  If drive
+        * supports skip sector handling, try to
+        * use it first; otherwise try the
+        * bad sector table.
+        */
        if ((er2 & HPER2_BSE) && !ML11) {
 badsect:
        if ((er2 & HPER2_BSE) && !ML11) {
 badsect:
-               if (!ssect && (er2&HPER2_SSE))
+               if (!ssect[unit] && (er2&HPER2_SSE))
                        goto skipsect;
                if (io->i_flgs & F_NBSF) {
                        io->i_error = EBSE;     
                        goto skipsect;
                if (io->i_flgs & F_NBSF) {
                        io->i_error = EBSE;     
@@ -314,12 +263,19 @@ badsect:
                io->i_error = EBSE;
                goto hard;
        }
                io->i_error = EBSE;
                goto hard;
        }
-       if (RM80 && er2&HPER2_SSE) {
+
+       /*
+        * Skip sector handling.
+        */
+       if (RM80 && (er2 & HPER2_SSE)) {
 skipsect:
                (void) hpecc(io, SSE);
 skipsect:
                (void) hpecc(io, SSE);
-               ssect = 1;
+               ssect[unit] = 1;
                goto success;
        }
                goto success;
        }
+       /*
+        * ECC correction?
+        */
        if ((er1 & (HPER1_DCK|HPER1_ECH)) == HPER1_DCK) {
                if (hpecc(io, ECC) == 0)
                        goto success;
        if ((er1 & (HPER1_DCK|HPER1_ECH)) == HPER1_DCK) {
                if (hpecc(io, ECC) == 0)
                        goto success;
@@ -331,11 +287,19 @@ skipsect:
        /* fall thru to retry */
        hpaddr->hpcs1 = HP_DCLR|HP_GO;
        HPWAIT(hpaddr);
        /* fall thru to retry */
        hpaddr->hpcs1 = HP_DCLR|HP_GO;
        HPWAIT(hpaddr);
-       if (((io->i_errcnt&07) == 4) ) {
+
+       /* 
+        * Every fourth retry recalibrate.
+        */
+       if (((io->i_errcnt & 07) == 4) ) {
                hpaddr->hpcs1 = HP_RECAL|HP_GO;
                hprecal = 1;
                goto again;
        }
                hpaddr->hpcs1 = HP_RECAL|HP_GO;
                hprecal = 1;
                goto again;
        }
+
+       /*
+        * Recalibration state machine.
+        */
        switch (hprecal) {
 
        case 1:
        switch (hprecal) {
 
        case 1:
@@ -364,17 +328,21 @@ skipsect:
        }
        goto again;
 
        }
        goto again;
 
-success:                               /* continue with the next block */
+success:
+       /*
+        * On successful error recovery, bump
+        * block number to advance to next portion
+        * of i/o transfer.
+        */
        bn++;
        if ((bn-startblock) * sectsiz < bytecnt) {
        bn++;
        if ((bn-startblock) * sectsiz < bytecnt) {
-again:                                 /* re-read same block */
+again:
                io->i_bn = bn;
                io->i_ma = membase + (io->i_bn - startblock)*sectsiz;
                io->i_cc = bytecnt - (io->i_bn - startblock)*sectsiz;
                io->i_bn = bn;
                io->i_ma = membase + (io->i_bn - startblock)*sectsiz;
                io->i_cc = bytecnt - (io->i_bn - startblock)*sectsiz;
-#ifdef HPDEBUG
-               printf("restart: bl %d, byte %d, mem 0x%x hprecal %d\n",
-                       io->i_bn, io->i_cc, io->i_ma, hprecal);
-#endif
+               if (hpdebug[unit] & (HPF_ECCDEBUG|HPF_BSEDEBUG))
+                       printf("restart: bn=%d, cc=%d, ma=0x%x hprecal=%d\n",
+                         io->i_bn, io->i_cc, io->i_ma, hprecal);
                goto restart;
        }
        return (bytecnt);
                goto restart;
        }
        return (bytecnt);
@@ -390,42 +358,47 @@ hpecc(io, flag)
        register struct st *st = &hpst[hp_type[unit]];
        int npf, bn, cn, tn, sn, bcr;
 
        register struct st *st = &hpst[hp_type[unit]];
        int npf, bn, cn, tn, sn, bcr;
 
-       if (bcr = MASKREG(mbp->mba_bcr>>16))
+       bcr = MASKREG(mbp->mba_bcr);
+       if (bcr)
                bcr |= 0xffff0000;              /* sxt */
        npf = (bcr + io->i_cc) / sectsiz;       /* # sectors read */
                bcr |= 0xffff0000;              /* sxt */
        npf = (bcr + io->i_cc) / sectsiz;       /* # sectors read */
-       bn = io->i_bn + npf + ssect;            /* physical block #*/
-       switch (flag) {
-
-       case ECC: {
+       bn = io->i_bn + npf + ssect[unit];      /* physical block #*/
+       if (hpdebug[unit]&HPF_ECCDEBUG)
+               printf("bcr=%d npf=%d ssect=%d sectsiz=%d i_cc=%d\n",
+                       bcr, npf, ssect[unit], sectsiz, io->i_cc);
+       /*
+        * ECC correction logic.
+        */
+       if (flag == ECC) {
                register int i;
                caddr_t addr;
                register int i;
                caddr_t addr;
-               int bit, byte, mask, ecccnt = 0;
+               int bit, o, mask, ecccnt = 0;
 
                printf("hp%d: soft ecc sn%d\n", unit, bn);
                mask = MASKREG(rp->hpec2);
                i = MASKREG(rp->hpec1) - 1;     /* -1 makes 0 origin */
                bit = i&07;
 
                printf("hp%d: soft ecc sn%d\n", unit, bn);
                mask = MASKREG(rp->hpec2);
                i = MASKREG(rp->hpec1) - 1;     /* -1 makes 0 origin */
                bit = i&07;
-               i = (i&~07)>>3;
-               byte = i;
+               o = (i & ~07) >> 3;
                rp->hpcs1 = HP_DCLR | HP_GO;
                rp->hpcs1 = HP_DCLR | HP_GO;
-               while (i <sectsiz && npf*sectsiz + i < io->i_cc && bit > -11) {
-                       addr = io->i_ma + (npf*sectsiz) + byte;
-#ifdef HPECCDEBUG
-                       printf("addr %x old:%x ",addr, (*addr&0xff));
-#endif
-                       if ((io->i_flgs & (F_CHECK|F_HCHECK)) == 0)
-                               *addr ^= (mask << bit); /* don't 'correct' mem-
-                                                        * ory during Wcheck */
-#ifdef HPECCDEBUG
-                       printf("new:%x\n",(*addr&0xff));
-#endif
-                       byte++;
-                       i++;
-                       bit -= 8;
+               while (o <sectsiz && npf*sectsiz + o < io->i_cc && bit > -11) {
+                       addr = io->i_ma + (npf*sectsiz) + o;
+                       /*
+                        * No data transfer occurs with a write check,
+                        * so don't correct the resident copy of data.
+                        */
+                       if ((io->i_flgs & (F_CHECK|F_HCHECK)) == 0) {
+                               if (hpdebug[unit] & HPF_ECCDEBUG)
+                                       printf("addr=%x old=%x ", addr,
+                                               (*addr & 0xff));
+                               *addr ^= (mask << bit);
+                               if (hpdebug[unit] & HPF_ECCDEBUG)
+                                       printf("new=%x\n",(*addr & 0xff));
+                       }
+                       o++, bit -= 8;
                        if ((io->i_flgs & F_ECCLM) && ecccnt++ >= MAXECC)
                                return (1);
                }
                        if ((io->i_flgs & F_ECCLM) && ecccnt++ >= MAXECC)
                                return (1);
                }
-               return(0);
+               return (0);
        }
 
        /*
        }
 
        /*
@@ -433,19 +406,22 @@ hpecc(io, flag)
         * Set skip-sector-inhibit and
         * read next sector
         */
         * Set skip-sector-inhibit and
         * read next sector
         */
-       case SSE:
+       if (flag == SSE) {
                rp->hpcs1 = HP_DCLR | HP_GO;
                HPWAIT(rp);
                rp->hpof |= HPOF_SSEI;
                return (0);     
                rp->hpcs1 = HP_DCLR | HP_GO;
                HPWAIT(rp);
                rp->hpof |= HPOF_SSEI;
                return (0);     
+       }
 
 
-       case BSE: {
+       /*
+        * Bad block forwarding.
+        */
+        if (flag == BSE) {
                int bbn;
 
                rp->hpcs1 = HP_DCLR | HP_GO;
                int bbn;
 
                rp->hpcs1 = HP_DCLR | HP_GO;
-#ifdef HPDEBUG
-               printf("hpecc: BSE @ bn %d\n", bn);
-#endif
+               if (hpdebug[unit] & HPF_BSEDEBUG)
+                       printf("hpecc: BSE @ bn %d\n", bn);
                cn = bn/st->nspc;
                sn = bn%st->nspc;
                tn = sn/st->nsect;
                cn = bn/st->nspc;
                sn = bn%st->nspc;
                tn = sn/st->nsect;
@@ -460,23 +436,21 @@ hpecc(io, flag)
                sn = sn%st->nsect;
                io->i_cc = sectsiz;
                io->i_ma += npf*sectsiz;
                sn = sn%st->nsect;
                io->i_cc = sectsiz;
                io->i_ma += npf*sectsiz;
-#ifdef HPDEBUG 
-               printf("revector to cn %d tn %d sn %d mem: 0x%x\n", 
-                       cn, tn, sn, io->i_ma);
-#endif 
-               rp->hpof &= ~HPOF_SSEI; /* clear skip sector inhibit if set */
+               if (hpdebug[unit] & HPF_BSEDEBUG)
+                       printf("revector to cn %d tn %d sn %d\n", cn, tn, sn);
+               rp->hpof &= ~HPOF_SSEI;
                mbp->mba_sr = -1;
                rp->hpdc = cn;
                rp->hpda = (tn<<8) + sn;
                mbastart(io,io->i_flgs);
                mbp->mba_sr = -1;
                rp->hpdc = cn;
                rp->hpda = (tn<<8) + sn;
                mbastart(io,io->i_flgs);
-               io->i_errcnt = 0;       /* error has been corrected */
+               io->i_errcnt = 0;
                HPWAIT(rp);
                return (rp->hpds&HPDS_ERR);
        }
                HPWAIT(rp);
                return (rp->hpds&HPDS_ERR);
        }
-       }
        printf("hpecc: flag=%d\n", flag);
        return (1);
 }
        printf("hpecc: flag=%d\n", flag);
        return (1);
 }
+
 /*ARGSUSED*/
 hpioctl(io, cmd, arg)
        struct iob *io;
 /*ARGSUSED*/
 hpioctl(io, cmd, arg)
        struct iob *io;
@@ -486,9 +460,18 @@ hpioctl(io, cmd, arg)
        register unit = io->i_unit;
        struct st *st = &hpst[hp_type[unit]], *tmp;
        struct mba_drv *drv = mbadrv(unit);
        register unit = io->i_unit;
        struct st *st = &hpst[hp_type[unit]], *tmp;
        struct mba_drv *drv = mbadrv(unit);
+       int flag;
 
        switch(cmd) {
 
 
        switch(cmd) {
 
+       case SAIODEBUG:
+               flag = (int)arg;
+               if (flag > 0)
+                       hpdebug[unit] |= flag;
+               else
+                       hpdebug[unit] &= ~flag;
+               return (0);
+
        case SAIODEVDATA:
                if ((drv->mbd_dt&MBDT_TAP) == 0) {
                        tmp = (struct st *)arg;
        case SAIODEVDATA:
                if ((drv->mbd_dt&MBDT_TAP) == 0) {
                        tmp = (struct st *)arg;