/* * SCCSID: @(#)hk.c 3.0 5/12/86 */ /********************************************************************** * Copyright (c) Digital Equipment Corporation 1984, 1985, 1986. * * All Rights Reserved. * * Reference "/usr/src/COPYRIGHT" for applicable restrictions. * **********************************************************************/ /* * RK06/7 standalone disk driver * Jerry Brenner * Fred Canter - modified for ECC & error recovery * 10/20/82 * Jerry Brenner - Bad block support added * 12/21/82 * Fred Canter - modified to get CSR address from devsw[].dv_csr * 7/4/84 */ #include <sys/param.h> #include <sys/inode.h> #include <sys/bads.h> #include "saio.h" struct device { int hkcs1; int hkwc; caddr_t hkba; int hkda; int hkcs2; int hkds; int hkerr; int hkas; int hkdc; int dum; int hkdb; int hkmr1; int hkec1; int hkec2; int hkmr2; int hkmr3; }; #define NHK 8 #define NHKSEC 22 #define NHKTRK 3 #define BHK6BN (22L*3L*411L) - 22L #define BHK7BN (22L*3L*815L) - 22L #define P400 020 #define M400 0220 #define P800 040 #define M800 0240 #define P1200 060 #define M1200 0260 #define GO 01 #ifdef SELECT #undef SELECT #endif #define SELECT 01 #define PAKACK 02 #define DCLR 04 #define RECAL 012 #define OFFSET 014 #define RCOM 020 #define WCOM 022 #define RHDR 024 #define WHDR 026 #define IEI 0100 #define CRDY 0200 #define CCLR 0100000 #define CERR 0100000 #define DLT 0100000 #define UPE 020000 #define NED 010000 #define PGE 02000 #define SCLR 040 #define SVAL 0100000 #define CDA 040000 #define PIP 020000 #define WLE 010000 #define DDT 0400 #define DRDY 0200 #define VV 0100 #define DOFST 04 #define DRA 01 #define DCK 0100000 #define DUNS 040000 #define OPI 020000 #define DTE 010000 #define DWLE 04000 #define BSE 0200 #define ECH 0100 #define SKI 02 #define DRTER 040 extern int dk_badf[]; extern struct dkbad dk_bad[]; extern struct dkres dkr[]; int hk_drvtyp[NHK]; char hk_openf; hkopen(io) register struct iob *io; { register struct device *hkaddr; register int unit; int cn, tn, sn, cnt, dkn; int hkcmd; daddr_t bn; hkaddr = devsw[io->i_ino.i_dev].dv_csr; unit = io->i_unit; if(hk_openf&(1<<unit)) return(0); hkaddr->hkcs2 = SCLR; while((hkaddr->hkcs1 & CRDY) == 0); hk_drvtyp[unit] = 0; hkaddr->hkcs2 = unit; hkaddr->hkcs1 = SELECT; while((hkaddr->hkcs1 & CRDY) == 0); if(hkaddr->hkcs1 & CERR && hkaddr->hkerr & DRTER) { hk_drvtyp[unit] = 02000; } hkaddr->hkcs2 = SCLR; while((hkaddr->hkcs1 & CRDY) == 0); hkaddr->hkcs2 = unit; hkaddr->hkcs1 = (hk_drvtyp[unit]|SELECT); while((hkaddr->hkcs1 & CRDY) == 0); if((hkaddr->hkds & VV) == 0) { hkaddr->hkcs1 = hk_drvtyp[unit]|PAKACK|GO; while((hkaddr->hkcs1 & CRDY) == 0); } if((dkn = dkn_set(io)) < 0) { printf("\nHK unit %d can't allocate bads structure!\n", unit); return(-1); } dk_bad[dkn].bt_mbz = -1; /* BAD_CMD is PHYSADR 0140000, would overwrite boot/sdload */ #ifndef BIGKERNEL if(segflag == 2) /* boot or sdload */ #else BIGKERNEL if(segflag == 3) /* boot or sdload */ #endif BIGKERNEL hkcmd = 0; /* BAD_CMD never used! */ else { hkcmd = BAD_CMD->r[0]&07; BAD_CMD->r[0] = 0; } bn = hk_drvtyp[unit]?BHK7BN:BHK6BN; for(cnt = 0; cnt < 5; cnt++){ cn = bn/(NHKSEC*NHKTRK); sn = bn%(NHKSEC*NHKTRK); tn = sn/NHKSEC; sn = sn%NHKSEC; hkaddr->hkba = &dk_bad[dkn]; hkaddr->hkwc = -(sizeof(struct dkbad)>>1); hkaddr->hkdc = cn; hkaddr->hkda = (tn<<8) | sn; hkaddr->hkcs2 = unit; #ifndef BIGKERNEL /* * If this is Boot: program (segflag == 2) all I/O starts at 128 KB, * otherwise set reads of bad sector file to 64 Kb boundry. */ if(segflag == 2) #else BIGKERNEL /* * If this is Boot: program (segflag == 3) all I/O starts at 196 KB, * otherwise set reads of bad sector file to 64 Kb boundry. */ if(segflag == 3) #endif BIGKERNEL hkaddr->hkcs1 = hk_drvtyp[unit]|(segflag << 8)|RCOM|GO; else hkaddr->hkcs1 = hk_drvtyp[unit]|(1 << 8)|RCOM|GO; while((hkaddr->hkcs1 & CRDY) == 0); if(hkaddr->hkcs1 & CERR){ if(hkcmd != BAD_CHK) hkeprt(hkaddr, unit); bn += 2; hkaddr->hkcs2 = SCLR; while((hkaddr->hkcs1 & CRDY) == 0); continue; } else{ cnt = 0; break; } } if(cnt >= 5) { if(hkcmd == BAD_CHK) /* dskinit reformating disk */ dk_bad[dkn].bt_mbz = -1;/* invalid bad sector file */ else { dk_badf[dkn] = 0; return(-1); } } if(dk_bad[dkn].bt_mbz || dk_bad[dkn].bt_flag || (dk_bad[dkn].bt_csnl == 0 && dk_bad[dkn].bt_csnh == 0) || (dk_bad[dkn].bt_badb[0].bt_cyl==0 && dk_bad[dkn].bt_badb[0].bt_trksec==0)) dk_bad[dkn].bt_mbz = -1; hk_openf |= 1<<unit; return(0); } hkclose(io) register struct iob *io; { int unit, dkn; if((dkn = dkn_set(io)) >= 0) dk_badf[dkn] = 0; unit = io->i_unit; hk_openf &= ~(1<<unit); } hkstrategy(io, func) register struct iob *io; { register struct device *hkaddr; register com; int i, unit, dkn; daddr_t bn, vbn; int sn, cn, tn, j, k, hkcmd, errcnt; int *rhdrpnt; hkaddr = devsw[io->i_ino.i_dev].dv_csr; /* BAD_CMD is PHYSADR 0140000, would overwrite boot/sdload */ #ifndef BIGKERNEL if(segflag == 2) /* boot or sdload */ #else BIGKERNEL if(segflag == 3) /* boot or sdload */ #endif BIGKERNEL hkcmd = 0; /* BAD_CMD never used! */ else { hkcmd = BAD_CMD->r[0]&07; BAD_CMD->r[0] = 0; } unit = io->i_unit; errcnt = 0; hkretry: hkaddr->hkcs2 = SCLR; while((hkaddr->hkcs1 & CRDY) == 0); hkaddr->hkcs2 = unit; hkaddr->hkcs1 = hk_drvtyp[unit]|SELECT; while((hkaddr->hkcs1 & CRDY) == 0); if((hkaddr->hkds & VV) == 0 || (hk_openf&(1<<unit)) == 0){ hk_openf &= ~(1<<unit); if(hkopen(io)) return(-1); } dkn = dkn_set(io); com = hk_drvtyp[unit]|(segflag << 8) | GO; switch(hkcmd & 070) { case BAD_VEC: hkaddr->hkwc = -(dkr[dkn].r_vcc>>1); hkaddr->hkba = dkr[dkn].r_vma; bn = dkr[dkn].r_vbn; if(func == READ) com |= RCOM; else com |= WCOM; break; case BAD_CON: hkcmd &= ~BAD_CON; hkaddr->hkwc = -(dkr[dkn].r_cc>>1); hkaddr->hkba = dkr[dkn].r_ma; bn = dkr[dkn].r_bn; if(func == READ) com |= RCOM; else com |= WCOM; break; default: bn = io->i_bn; hkaddr->hkba = io->i_ma; hkaddr->hkwc = -(io->i_cc>>1); if(hkcmd & BAD_FMT) { if(func == READ) com |= RHDR; else com |= WHDR; } else{ if(func == READ) com |= RCOM; else com |= WCOM; } break; } if(dk_bad[dkn].bt_mbz == 0 && (hkcmd&(BAD_CHK|BAD_VEC|BAD_FMT)) == 0 && func != READ) { if((bn + (io->i_cc/512)) >= (hk_drvtyp[unit]?BHK7BN:BHK6BN)- NHKSEC) { printf("HK %d error. bn = %D cc = %d",unit ,bn, io->i_cc); printf(" Would overwrite bad sector information\n"); return(-1); } } cn = bn/(NHKSEC*NHKTRK); sn = bn%(NHKSEC*NHKTRK); tn = sn/NHKSEC; sn = sn%NHKSEC; hkaddr->hkdc = cn; hkaddr->hkda = (tn<<8) | sn; hkaddr->hkcs2 = unit; if(hkcmd & BAD_FMT && func == READ){ rhdrpnt = io->i_ma; j = io->i_cc>>1; hkaddr->hkwc = -(j*2); for(k = 0; j > 0; ){ hkaddr->hkcs1 = com; while((hkaddr->hkcs1 & CRDY) == 0) ; if(hkaddr->hkcs1 & CERR){ hkeprt(hkaddr, unit); return(-1); } /* *(rhdrpnt++) = hkaddr->hkdb; sn = hkaddr->hkdb; *(rhdrpnt++) = sn; *(rhdrpnt++) = hkaddr->hkdb; */ fixhdr(rhdrpnt, hkaddr->hkdb); rhdrpnt++; sn = hkaddr->hkdb; fixhdr(rhdrpnt, sn); rhdrpnt++; fixhdr(rhdrpnt, hkaddr->hkdb); rhdrpnt++; j -= 3; if(k == 0 && (sn &037) != 0){ rhdrpnt = io->i_ma; j = io->i_cc >> 1; continue; } k++; } } else hkaddr->hkcs1 = com; while((hkaddr->hkcs1 & CRDY) == 0); if (hkaddr->hkcs1 & CERR) { if((hkaddr->hkerr & (DCK|ECH)) == DCK) { fixbad(io, hkaddr->hkwc, 0, dkn); /* do ECC */ k = hkaddr->hkec1 - 1; j = k & 017; k >>= 4; if((k >= 0) && (k < 256)) { if((hkcmd&BAD_NEC) == 0) { printf("HK %d ECC bn = %D\n",unit,dkr[dkn].r_bn - 1); fixecc(((dkr[dkn].r_ma-256)+k),(hkaddr->hkec2<<j)); fixecc(((dkr[dkn].r_ma-256)+(k+1)),(hkaddr->hkec2>>(16-j))); } /* TODO: call hkeprt() if ECC ignored (BAD_NEC set) */ if(dkr[dkn].r_cc > 0) { hkcmd |= BAD_CON; goto hkretry; } if(hkcmd & 070) goto hkcont; return(io->i_cc); } } if((hkaddr->hkerr & BSE) && (hkcmd & BAD_CHK) == 0 && dk_bad[dkn].bt_mbz == 0) { fixbad(io, hkaddr->hkwc, 1, dkn); cn = hkaddr->hkdc; tn = (hkaddr->hkda >> 8) &07; sn = hkaddr->hkda &037; if((j = isbad(&dk_bad[dkn],cn,tn,sn)) >= 0) { hkcmd |= BAD_VEC; dkr[dkn].r_vbn=((hk_drvtyp[unit]?BHK7BN:BHK6BN)-1)-j; goto hkretry; } } if(errcnt == 0) { hkeprt(hkaddr, unit); if((hkcmd & BAD_CHK) && (hkaddr->hkerr & 0100700)) { fixbad(io, hkaddr->hkwc, 0, dkn); if(hkaddr->hkerr &0100000) return(dkr[dkn].r_vcc - 512); return(dkr[dkn].r_vcc); } } if(++errcnt >= 10) { printf("\n(FATAL ERROR)\n"); return(-1); } goto hkretry; } hkcont: if(hkcmd&BAD_VEC) { if(dkr[dkn].r_cc > 0) { hkcmd &= ~BAD_VEC; hkcmd |= BAD_CON; goto hkretry; } } if(errcnt) printf("\n(RECOVERED by retry)\n"); return(io->i_cc); } hkeprt(hkaddr, unit) register struct device *hkaddr; { printf("HK unit %d disk error:\n", unit); printf("cs1=%o cs2=%o ds=%o err=%o ", hkaddr->hkcs1, hkaddr->hkcs2, hkaddr->hkds, hkaddr->hkerr); printf("hkdc=%d track=%d sect=%d\n", hkaddr->hkdc , (hkaddr->hkda&03400)>>8, hkaddr->hkda&037); }