1*11179Ssam /* hp.c 4.16 83/02/20 */ 210334Shelge 310334Shelge /* 410334Shelge * RP??/RM?? disk driver 510334Shelge * with ECC handling and bad block forwarding. 610334Shelge * Also supports header io operations and 710334Shelge * commands to write check header and data. 810334Shelge */ 910334Shelge 1010334Shelge #include "../h/param.h" 1110334Shelge #include "../h/inode.h" 1210334Shelge #include "../h/fs.h" 1310334Shelge #include "../h/dkbad.h" 1410334Shelge 1510334Shelge #include "../vax/pte.h" 1610334Shelge #include "../vaxmba/hpreg.h" 1710334Shelge #include "../vaxmba/mbareg.h" 1810334Shelge 1910334Shelge #include "saio.h" 2010334Shelge #include "savax.h" 2110334Shelge 2210334Shelge #define MASKREG(reg) ((reg)&0xffff) 2310334Shelge 2410334Shelge #define MAXBADDESC 126 2510334Shelge #define SECTSIZ 512 /* sector size in bytes */ 2610334Shelge #define HDRSIZ 4 /* number of bytes in sector header */ 2711140Ssam #define MAXECC 5 /* max # bits allow in ecc error w/ F_ECCLM */ 2810334Shelge 2910334Shelge char hp_type[MAXNMBA*8] = { 0 }; 3011140Ssam extern struct st hpst[]; 3110334Shelge 3211115Ssam short hptypes[] = { 3311115Ssam MBDT_RM03, MBDT_RM05, MBDT_RP06, MBDT_RM80, 3411115Ssam MBDT_RP05, MBDT_RP07, MBDT_ML11A, MBDT_ML11B, 3511115Ssam -1 /*9755*/, -1 /*9730*/, -1 /*Cap*/, -1 /* Eagle */, 3611115Ssam -1 /* Eagle */, MBDT_RM02, 0 3711115Ssam }; 3810334Shelge 3910626Shelge #define RP06 (hptypes[hp_type[unit]] <= MBDT_RP06) 4010626Shelge #define ML11 (hptypes[hp_type[unit]] == MBDT_ML11A) 4110626Shelge #define RM80 (hptypes[hp_type[unit]] == MBDT_RM80) 4210334Shelge 4310334Shelge u_char hp_offset[16] = { 4410334Shelge HPOF_P400, HPOF_M400, HPOF_P400, HPOF_M400, 4510334Shelge HPOF_P800, HPOF_M800, HPOF_P800, HPOF_M800, 4610334Shelge HPOF_P1200, HPOF_M1200, HPOF_P1200, HPOF_M1200, 4710334Shelge 0, 0, 0, 0, 4810334Shelge }; 4910334Shelge 5010334Shelge struct dkbad hpbad[MAXNMBA*8]; 5110334Shelge int sectsiz; 5210334Shelge 5310864Ssam /* 5410864Ssam * When awaiting command completion, don't 5510864Ssam * hang on to the status register since 5610864Ssam * this ties up the controller. 5710864Ssam */ 5810864Ssam #define HPWAIT(addr) while ((((addr)->hpds)&HPDS_DRY)==0) DELAY(500); 5910864Ssam 6010334Shelge hpopen(io) 6110334Shelge register struct iob *io; 6210334Shelge { 6310334Shelge register unit = io->i_unit; 6410334Shelge struct hpdevice *hpaddr = (struct hpdevice *)mbadrv(unit); 6510353Shelge register struct st *st; 6610334Shelge 6710334Shelge mbainit(UNITTOMBA(unit)); 6810334Shelge if (hp_type[unit] == 0) { 6910334Shelge register type = hpaddr->hpdt & MBDT_TYPE; 7010334Shelge register int i; 7110334Shelge struct iob tio; 7210334Shelge 7310334Shelge for (i = 0; hptypes[i]; i++) 7410334Shelge if (hptypes[i] == type) 7510334Shelge goto found; 7610334Shelge _stop("unknown drive type"); 7710334Shelge found: 7810647Shelge hpaddr->hpcs1 = HP_DCLR|HP_GO; /* init drive */ 7910647Shelge hpaddr->hpcs1 = HP_PRESET|HP_GO; 8010647Shelge if (!ML11) 8110647Shelge hpaddr->hpof = HPOF_FMT22; 8211113Shelge hp_type[unit] = hpmaptype(hpaddr, i, unit); 8310334Shelge /* 8410334Shelge * Read in the bad sector table: 8510334Shelge * copy the contents of the io structure 8610334Shelge * to tio for use during the bb pointer 8710334Shelge * read operation. 8810334Shelge */ 8911140Ssam st = &hpst[hp_type[unit]]; 9010334Shelge tio = *io; 9110334Shelge tio.i_bn = st->nspc * st->ncyl - st->nsect; 9210626Shelge tio.i_ma = (char *)&hpbad[unit]; 9310628Shelge tio.i_cc = sizeof (struct dkbad); 9410334Shelge tio.i_flgs |= F_RDDATA; 9510334Shelge for (i = 0; i < 5; i++) { 9610628Shelge if (hpstrategy(&tio, READ) == sizeof (struct dkbad)) 9710334Shelge break; 9810334Shelge tio.i_bn += 2; 9910334Shelge } 10010334Shelge if (i == 5) { 10110334Shelge printf("Unable to read bad sector table\n"); 10210334Shelge for (i = 0; i < MAXBADDESC; i++) { 10310334Shelge hpbad[unit].bt_bad[i].bt_cyl = -1; 10410334Shelge hpbad[unit].bt_bad[i].bt_trksec = -1; 10510334Shelge } 10610334Shelge } 10710334Shelge } 10810334Shelge if (io->i_boff < 0 || io->i_boff > 7 || 10910334Shelge st->off[io->i_boff]== -1) 11010334Shelge _stop("hp bad minor"); 11110334Shelge io->i_boff = st->off[io->i_boff] * st->nspc; 11210334Shelge } 11310334Shelge 11410647Shelge int ssect; /* set to 1 if we are on a track with skip sectors */ 11510647Shelge 11610334Shelge hpstrategy(io, func) 11710334Shelge register struct iob *io; 11810334Shelge { 11910334Shelge register unit = io->i_unit; 12010334Shelge struct mba_regs *mba = mbamba(unit); 12110334Shelge daddr_t bn; 12210334Shelge struct hpdevice *hpaddr = (struct hpdevice *)mbadrv(unit); 12310353Shelge struct st *st = &hpst[hp_type[unit]]; 12410334Shelge int cn, tn, sn, bytecnt, bytesleft; 12510334Shelge daddr_t startblock; 12610334Shelge char *membase; 12710334Shelge int er1, er2, hprecal; 12810334Shelge 12910334Shelge sectsiz = SECTSIZ; 13010334Shelge if ((io->i_flgs & (F_HDR|F_HCHECK)) != 0) 13110334Shelge sectsiz += HDRSIZ; 13210334Shelge if ((hpaddr->hpds & HPDS_VV) == 0) { 13310334Shelge hpaddr->hpcs1 = HP_DCLR|HP_GO; 13410334Shelge hpaddr->hpcs1 = HP_PRESET|HP_GO; 13511084Ssam if (!ML11) 13610334Shelge hpaddr->hpof = HPOF_FMT22; 13710334Shelge } 13810334Shelge io->i_errcnt = 0; 13910647Shelge ssect = 0; 14010334Shelge bytecnt = io->i_cc; 14110334Shelge membase = io->i_ma; 14210334Shelge startblock = io->i_bn; 14310608Ssam hprecal = 0; 14411140Ssam 14510626Shelge restart: 14610334Shelge bn = io->i_bn; 14710334Shelge cn = bn/st->nspc; 14810334Shelge sn = bn%st->nspc; 14910334Shelge tn = sn/st->nsect; 15010647Shelge sn = sn%st->nsect + ssect; 15110334Shelge 15210864Ssam HPWAIT(hpaddr); 15310626Shelge mba->mba_sr = -1; 15410647Shelge if (ML11) 15510334Shelge hpaddr->hpda = bn; 15610334Shelge else { 15710334Shelge hpaddr->hpdc = cn; 15810334Shelge hpaddr->hpda = (tn << 8) + sn; 15910334Shelge } 16010334Shelge if (mbastart(io, func) != 0) /* start transfer */ 16110334Shelge return (-1); 16210864Ssam HPWAIT(hpaddr); 16311084Ssam if ((hpaddr->hpds&HPDS_ERR) == 0 && (mba->mba_sr&MBSR_EBITS) == 0) 16411084Ssam return (bytecnt); 16510334Shelge 16610334Shelge /* ------- error handling ------- */ 16710334Shelge 16810334Shelge if (bytesleft = MASKREG(mba->mba_bcr>>16)) 16910334Shelge bytesleft |= 0xffff0000; /* sign ext */ 17010334Shelge bn = io->i_bn + (io->i_cc + bytesleft)/sectsiz; 17110334Shelge cn = bn/st->nspc; 17210334Shelge sn = bn%st->nspc; 17310334Shelge tn = sn/st->nsect; 17410334Shelge sn = sn%st->nsect; 17510334Shelge er1 = MASKREG(hpaddr->hper1); 17610334Shelge er2 = MASKREG(hpaddr->hper2); 17710334Shelge #ifdef HPDEBUG 17810334Shelge printf("hp error: (cyl,trk,sec)=(%d,%d,%d) ds=%b \n", 17910334Shelge cn, tn, sn, MASKREG(hpaddr->hpds), HPDS_BITS); 18010626Shelge printf("er1=%b er2=%b", er1, HPER1_BITS, er2, HPER2_BITS); 18110626Shelge printf("\nbytes left: %d, of 0x%x, da 0x%x",-bytesleft, 18210626Shelge hpaddr->hpof, hpaddr->hpda); 18310334Shelge printf("\n"); 18410334Shelge #endif 18510334Shelge if (er1 & HPER1_HCRC) { 18610334Shelge er1 &= ~(HPER1_HCE|HPER1_FER); 18710334Shelge er2 &= ~HPER2_BSE; 18810334Shelge } 18911140Ssam /* 19011140Ssam * Give up early if drive write locked. 19111140Ssam */ 19210334Shelge if (er1&HPER1_WLE) { 19310334Shelge printf("hp%d: write locked\n", unit); 19411084Ssam return (-1); 19511084Ssam } 19611140Ssam /* 19711140Ssam * No bad sector handling on RP06's yet. 19811140Ssam */ 19911084Ssam if (MASKREG(er1) == HPER1_FER && RP06) 20010334Shelge goto badsect; 20111140Ssam 20211140Ssam /* 20311140Ssam * If a hard error, or maximum retry count 20411140Ssam * exceeded, clear controller state and 20511140Ssam * pass back error to caller. 20611140Ssam */ 20711084Ssam if (++io->i_errcnt > 27 || (er1 & HPER1_HARD) || 20811084Ssam (!ML11 && (er2 & HPER2_HARD))) { 209*11179Ssam if ((io->i_flgs&F_NBSF) == 0 && hpecc(io, BSE) == 0) 210*11179Ssam goto success; 21110608Ssam hard0: 21210334Shelge io->i_error = EHER; 21311084Ssam if (mba->mba_sr & (MBSR_WCKUP|MBSR_WCKLWR)) 21410334Shelge io->i_error = EWCK; 21510334Shelge hard: 21610647Shelge io->i_errblk = bn + ssect; 21710334Shelge printf("hp error: (cyl,trk,sec)=(%d,%d,%d) ds=%b \n", 21810334Shelge cn, tn, sn, MASKREG(hpaddr->hpds), HPDS_BITS); 21911084Ssam printf("er1=%b er2=%b", er1, HPER1_BITS, er2, HPER2_BITS); 22010334Shelge if (hpaddr->hpmr) 22110626Shelge printf(" mr1=%o", MASKREG(hpaddr->hpmr)); 22210334Shelge if (hpaddr->hpmr2) 22310626Shelge printf(" mr2=%o", MASKREG(hpaddr->hpmr2)); 22410626Shelge #ifdef HPDEBUG 22510626Shelge printf("dc: %d, da: 0x%x",MASKREG(hpaddr->hpdc), 22611084Ssam MASKREG(hpaddr->hpda)); 22710626Shelge #endif 22810626Shelge hpaddr->hpcs1 = HP_DCLR|HP_GO; 22910334Shelge printf("\n"); 23011084Ssam return (-1); 23110334Shelge 23211084Ssam } 23311140Ssam /* 23411140Ssam * Attempt to forward bad sectors on 23511140Ssam * anything but an ML11. If drive 23611140Ssam * supports skip sector handling, try to 23711140Ssam * use it first; otherwise try the 23811140Ssam * bad sector table. 23911140Ssam */ 24011084Ssam if ((er2 & HPER2_BSE) && !ML11) { 24110334Shelge badsect: 24210647Shelge if (!ssect && (er2&HPER2_SSE)) 24310647Shelge goto skipsect; 24411084Ssam if (io->i_flgs & F_NBSF) { 24510334Shelge io->i_error = EBSE; 24610334Shelge goto hard; 24710334Shelge } 24810334Shelge if (hpecc(io, BSE) == 0) 24910334Shelge goto success; 25011084Ssam io->i_error = EBSE; 25111084Ssam goto hard; 25211084Ssam } 25311140Ssam 25411140Ssam /* 25511140Ssam * Skip sector handling. 25611140Ssam */ 25711084Ssam if (RM80 && er2&HPER2_SSE) { 25810647Shelge skipsect: 25910334Shelge (void) hpecc(io, SSE); 26011084Ssam ssect = 1; 26110334Shelge goto success; 26211084Ssam } 26311140Ssam /* 26411140Ssam * ECC correction. 26511140Ssam */ 26611084Ssam if ((er1 & (HPER1_DCK|HPER1_ECH)) == HPER1_DCK) { 26710864Ssam if (hpecc(io, ECC) == 0) 26810334Shelge goto success; 26911084Ssam io->i_error = EECC; 27011084Ssam return (-1); 27110608Ssam } 27210608Ssam if (ML11 && (io->i_errcnt >= 16)) 27311084Ssam goto hard0; 27410608Ssam /* fall thru to retry */ 27510334Shelge hpaddr->hpcs1 = HP_DCLR|HP_GO; 27610864Ssam HPWAIT(hpaddr); 27711140Ssam 27811140Ssam /* 27911140Ssam * Every fourth retry recalibrate. 28011140Ssam */ 28110608Ssam if (((io->i_errcnt&07) == 4) ) { 28210334Shelge hpaddr->hpcs1 = HP_RECAL|HP_GO; 28310608Ssam hprecal = 1; 28411084Ssam goto again; 28510334Shelge } 28611140Ssam 28711140Ssam /* 28811140Ssam * Recalibration state machine. 28911140Ssam */ 29010334Shelge switch (hprecal) { 29110334Shelge 29210334Shelge case 1: 29310334Shelge hpaddr->hpdc = cn; 29410334Shelge hpaddr->hpcs1 = HP_SEEK|HP_GO; 29511084Ssam hprecal = 2; 29611084Ssam goto again; 29710864Ssam 29810334Shelge case 2: 29910608Ssam if (io->i_errcnt < 16 || (io->i_flgs & F_READ) == 0) 30010334Shelge goto donerecal; 30110334Shelge hpaddr->hpof = hp_offset[io->i_errcnt & 017]|HPOF_FMT22; 30210334Shelge hpaddr->hpcs1 = HP_OFFSET|HP_GO; 30311084Ssam hprecal = 3; 30411084Ssam goto again; 30510864Ssam 30611084Ssam case 3: 30710334Shelge donerecal: 30810334Shelge hprecal = 0; 30911084Ssam goto again; 31010334Shelge } 31110608Ssam if (io->i_errcnt >= 16) { 31210608Ssam hpaddr->hpcs1 = HP_RTC|HP_GO; 31310608Ssam while (hpaddr->hpds & HPDS_PIP) 31410608Ssam ; 31510334Shelge } 31611084Ssam goto again; 31711084Ssam 31811140Ssam success: 31911140Ssam /* 32011140Ssam * On successful error recovery, bump 32111140Ssam * block number to advance to next portion 32211140Ssam * of i/o transfer. 32311140Ssam */ 32410334Shelge bn++; 32510334Shelge if ((bn-startblock) * sectsiz < bytecnt) { 32611140Ssam again: 32710334Shelge io->i_bn = bn; 32810334Shelge io->i_ma = membase + (io->i_bn - startblock)*sectsiz; 32910334Shelge io->i_cc = bytecnt - (io->i_bn - startblock)*sectsiz; 33010334Shelge #ifdef HPDEBUG 33110608Ssam printf("restart: bl %d, byte %d, mem 0x%x hprecal %d\n", 33210608Ssam io->i_bn, io->i_cc, io->i_ma, hprecal); 33310334Shelge #endif 33410626Shelge goto restart; 33510334Shelge } 33610334Shelge return (bytecnt); 33710334Shelge } 33810864Ssam 33910334Shelge hpecc(io, flag) 34010334Shelge register struct iob *io; 34110334Shelge int flag; 34210334Shelge { 34310334Shelge register unit = io->i_unit; 34410334Shelge register struct mba_regs *mbp = mbamba(unit); 34510334Shelge register struct hpdevice *rp = (struct hpdevice *)mbadrv(unit); 34610353Shelge register struct st *st = &hpst[hp_type[unit]]; 34711084Ssam int npf, bn, cn, tn, sn, bcr; 34810334Shelge 34910334Shelge if (bcr = MASKREG(mbp->mba_bcr>>16)) 350*11179Ssam bcr |= 0xffff0000; /* sign extend */ 35111084Ssam npf = (bcr + io->i_cc) / sectsiz; /* # sectors read */ 35211084Ssam bn = io->i_bn + npf + ssect; /* physical block #*/ 353*11179Ssam #ifdef HPECCDEBUG 354*11179Ssam printf("bcr %d npf %d ssect %d sectsiz %d i_cc %d\n", bcr, npf, 355*11179Ssam ssect, sectsiz, io->i_cc); 356*11179Ssam #endif 35711084Ssam 35811140Ssam /* 35911140Ssam * ECC correction logic. 36011140Ssam */ 36111140Ssam if (flag == ECC) { 36210334Shelge register int i; 36310334Shelge caddr_t addr; 364*11179Ssam int bit, o, mask, ecccnt = 0; 36510334Shelge 36610413Shelge printf("hp%d: soft ecc sn%d\n", unit, bn); 36710334Shelge mask = MASKREG(rp->hpec2); 36811084Ssam i = MASKREG(rp->hpec1) - 1; /* -1 makes 0 origin */ 36910334Shelge bit = i&07; 370*11179Ssam o = (i&~07) >> 3; 37110334Shelge rp->hpcs1 = HP_DCLR | HP_GO; 372*11179Ssam while (o <sectsiz && npf*sectsiz + o < io->i_cc && bit > -11) { 373*11179Ssam addr = io->i_ma + (npf*sectsiz) + o; 37410334Shelge #ifdef HPECCDEBUG 37510334Shelge printf("addr %x old:%x ",addr, (*addr&0xff)); 37610334Shelge #endif 377*11179Ssam /* 378*11179Ssam * No data transfer occurs with a write check, 379*11179Ssam * so don't correct the resident copy of data. 380*11179Ssam */ 38110334Shelge if ((io->i_flgs & (F_CHECK|F_HCHECK)) == 0) 38211140Ssam *addr ^= (mask << bit); 38310334Shelge #ifdef HPECCDEBUG 38410334Shelge printf("new:%x\n",(*addr&0xff)); 38510334Shelge #endif 386*11179Ssam o++, bit -= 8; 38711109Ssam if ((io->i_flgs & F_ECCLM) && ecccnt++ >= MAXECC) 38811084Ssam return (1); 38910334Shelge } 390*11179Ssam return (0); 39111084Ssam } 39210334Shelge 39311084Ssam /* 39411084Ssam * Skip sector error. 39511084Ssam * Set skip-sector-inhibit and 39611084Ssam * read next sector 39711084Ssam */ 39811140Ssam if (flag == SSE) { 39910334Shelge rp->hpcs1 = HP_DCLR | HP_GO; 40010864Ssam HPWAIT(rp); 40110334Shelge rp->hpof |= HPOF_SSEI; 40211084Ssam return (0); 40311140Ssam } 40410334Shelge 40511140Ssam /* 40611140Ssam * Bad block forwarding. 40711140Ssam */ 40811140Ssam if (flag == BSE) { 40910626Shelge int bbn; 41011084Ssam 41110626Shelge rp->hpcs1 = HP_DCLR | HP_GO; 41210334Shelge #ifdef HPDEBUG 41310334Shelge printf("hpecc: BSE @ bn %d\n", bn); 41410334Shelge #endif 41510334Shelge cn = bn/st->nspc; 41610334Shelge sn = bn%st->nspc; 41710334Shelge tn = sn/st->nsect; 41810626Shelge sn = sn%st->nsect; 41910626Shelge bcr += sectsiz; 42010626Shelge if ((bbn = isbad(&hpbad[unit], cn, tn, sn)) < 0) 42111084Ssam return (1); 42210626Shelge bbn = st->ncyl*st->nspc - st->nsect - 1 - bbn; 42310626Shelge cn = bbn/st->nspc; 42410626Shelge sn = bbn%st->nspc; 42510626Shelge tn = sn/st->nsect; 42610626Shelge sn = sn%st->nsect; 42710626Shelge io->i_cc = sectsiz; 42810626Shelge io->i_ma += npf*sectsiz; 42910626Shelge #ifdef HPDEBUG 43010626Shelge printf("revector to cn %d tn %d sn %d mem: 0x%x\n", 43110626Shelge cn, tn, sn, io->i_ma); 43210626Shelge #endif 43310647Shelge rp->hpof &= ~HPOF_SSEI; /* clear skip sector inhibit if set */ 43410626Shelge mbp->mba_sr = -1; 43510334Shelge rp->hpdc = cn; 43610334Shelge rp->hpda = (tn<<8) + sn; 43710334Shelge mbastart(io,io->i_flgs); 43810334Shelge io->i_errcnt = 0; /* error has been corrected */ 43910864Ssam HPWAIT(rp); 44010864Ssam return (rp->hpds&HPDS_ERR); 44110334Shelge } 44211084Ssam printf("hpecc: flag=%d\n", flag); 44311084Ssam return (1); 44410334Shelge } 44511140Ssam 44610334Shelge /*ARGSUSED*/ 44710334Shelge hpioctl(io, cmd, arg) 44810334Shelge struct iob *io; 44910334Shelge int cmd; 45010334Shelge caddr_t arg; 45110334Shelge { 45210647Shelge register unit = io->i_unit; 45310647Shelge struct st *st = &hpst[hp_type[unit]], *tmp; 45410647Shelge struct mba_drv *drv = mbadrv(unit); 45510334Shelge 45610334Shelge switch(cmd) { 45710334Shelge 45810334Shelge case SAIODEVDATA: 45910334Shelge if ((drv->mbd_dt&MBDT_TAP) == 0) { 46010353Shelge tmp = (struct st *)arg; 46110353Shelge *tmp = *st; 46211084Ssam return (0); 46310334Shelge } 46411084Ssam return (ECMD); 46510334Shelge 46611084Ssam case SAIOSSI: /* skip-sector-inhibit */ 46711084Ssam if (drv->mbd_dt&MBDT_TAP) 46811084Ssam return (ECMD); 46911084Ssam if ((io->i_flgs&F_SSI) == 0) { 47011084Ssam /* make sure this is done once only */ 47111084Ssam io->i_flgs |= F_SSI; 47211084Ssam st->nsect++; 47311084Ssam st->nspc += st->ntrak; 47410864Ssam } 47511084Ssam return (0); 47610626Shelge 47711084Ssam case SAIONOSSI: /* remove skip-sector-inhibit */ 47810626Shelge if (io->i_flgs & F_SSI) { 47910626Shelge io->i_flgs &= ~F_SSI; 48010626Shelge drv->mbd_of &= ~HPOF_SSEI; 48110626Shelge st->nsect--; 48210626Shelge st->nspc -= st->ntrak; 48310626Shelge } 48410626Shelge return(0); 48510626Shelge 48610864Ssam case SAIOSSDEV: /* drive have skip sector? */ 48711084Ssam return (RM80 ? 0 : ECMD); 48810334Shelge } 48911084Ssam return (ECMD); 49010334Shelge } 491