1*32604Skarels /* vd.c 7.8 87/11/12 */ 229567Ssam 325873Ssam /* 430521Ssam * Stand alone driver for the VDDC/SMDE controller 529567Ssam */ 625873Ssam #include "../machine/mtpr.h" 725873Ssam 825873Ssam #include "param.h" 925873Ssam #include "inode.h" 1025873Ssam #include "fs.h" 1130823Skarels #include "buf.h" 1230521Ssam #include "disklabel.h" 1330521Ssam #include "saio.h" 1430521Ssam 1525931Ssam #include "../tahoevba/vdreg.h" 1625931Ssam #include "../tahoevba/vbaparam.h" 1725873Ssam 1830521Ssam #define COMPAT_42 1 1925873Ssam 2030521Ssam #define NVD 4 2130521Ssam #define NDRIVE 8 /* drives per controller */ 2230521Ssam #define VDSLAVE(x) ((x) % NDRIVE) 2330521Ssam #define VDCTLR(x) ((x) / NDRIVE) 2425873Ssam 2530521Ssam #define VDADDR(ctlr) ((struct vddevice *)vdaddrs[ctlr]) 2630521Ssam long vdaddrs[NVD] = { 0xffff2000, 0xffff2100, 0xffff2200, 0xffff2300 }; 2725873Ssam 2830521Ssam u_char vdinit[NVD]; /* controller initialized */ 2930521Ssam u_char vdtype[NVD]; /* controller type */ 3030521Ssam u_char dkconfigured[NVD*NDRIVE]; /* unit configured */ 31*32604Skarels u_char dkflags[NVD][NDRIVE]; /* unit flags */ 3225873Ssam 33*32604Skarels static struct disklabel dklabel[NVD*NDRIVE]; /* pack label */ 34*32604Skarels static struct mdcb mdcb; 35*32604Skarels static struct dcb dcb; 36*32604Skarels static char lbuf[DEV_BSIZE]; 3725873Ssam 3825873Ssam vdopen(io) 3929567Ssam register struct iob *io; 4025873Ssam { 4130521Ssam register int ctlr = VDCTLR(io->i_unit); 4230521Ssam register struct dkinfo *dk; 4330823Skarels register struct disklabel *lp, *dlp; 4430521Ssam int error; 4525873Ssam 4629567Ssam if (ctlr >= NVD) { 4730521Ssam printf("invalid controller number\n"); 4830521Ssam return (ENXIO); 4925873Ssam } 5030521Ssam if (!vdinit[ctlr] && (error = vdreset_ctlr(ctlr, io->i_unit))) 5130521Ssam return (error); 5230521Ssam lp = &dklabel[io->i_unit]; 5330521Ssam if (!dkconfigured[io->i_unit]) { 5430521Ssam struct iob tio; 5530521Ssam 5630521Ssam /* 5730521Ssam * Read in the pack label. 5830521Ssam */ 59*32604Skarels lp->d_secsize = 1024; 60*32604Skarels lp->d_nsectors = 72; 6130521Ssam lp->d_ntracks = 24; 6230521Ssam lp->d_ncylinders = 711; 63*32604Skarels lp->d_secpercyl = 72*24; 6430521Ssam if (!vdreset_drive(io)) 6530521Ssam return (ENXIO); 6630521Ssam tio = *io; 6730521Ssam tio.i_bn = LABELSECTOR; 6830521Ssam tio.i_ma = lbuf; 6930521Ssam tio.i_cc = DEV_BSIZE; 7030521Ssam tio.i_flgs |= F_RDDATA; 7130521Ssam if (vdstrategy(&tio, READ) != DEV_BSIZE) { 72*32604Skarels printf("dk%d: can't read disk label\n", io->i_unit); 7330521Ssam return (EIO); 7430521Ssam } 7530823Skarels dlp = (struct disklabel *)(lbuf + LABELOFFSET); 7630823Skarels if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC) { 7730521Ssam #ifdef COMPAT_42 7830521Ssam if (error = vdmaptype(io)) 7930521Ssam return (error); 8030521Ssam #else 8130823Skarels printf("dk%d: unlabeled\n", io->i_unit); 8230521Ssam return (ENXIO); 8330521Ssam #endif 84*32604Skarels } else { 8530823Skarels *lp = *dlp; 86*32604Skarels if (!vdreset_drive(io)) 87*32604Skarels return (ENXIO); 88*32604Skarels } 8930521Ssam dkconfigured[io->i_unit] = 1; 9025873Ssam } 9130521Ssam if (io->i_boff < 0 || io->i_boff >= lp->d_npartitions || 9230521Ssam lp->d_partitions[io->i_boff].p_size == 0) { 9330823Skarels printf("dk%d: bad minor\n", io->i_unit); 9430521Ssam return (EUNIT); 9525873Ssam } 9630521Ssam io->i_boff = 9730521Ssam (lp->d_partitions[io->i_boff].p_offset * lp->d_secsize) / DEV_BSIZE; 9830521Ssam return (0); 9925873Ssam } 10025873Ssam 10130521Ssam /* 10230521Ssam * Reset and initialize the controller. 10330521Ssam */ 10430521Ssam vdreset_ctlr(ctlr, unit) 10530521Ssam register int ctlr, unit; 10625873Ssam { 10730521Ssam register int i; 10830521Ssam register struct vddevice *vdaddr = VDADDR(ctlr); 10925873Ssam 11030521Ssam if (badaddr(vdaddr, 2)) { 11130521Ssam printf("vd%d: %x: invalid csr\n", ctlr, vdaddr); 11230521Ssam return (ENXIO); 11325873Ssam } 11430521Ssam /* probe further to find what kind of controller it is */ 11530521Ssam vdaddr->vdreset = 0xffffffff; 11625873Ssam DELAY(1000000); 11730521Ssam if (vdaddr->vdreset != 0xffffffff) { 11830521Ssam vdtype[ctlr] = VDTYPE_VDDC; 11925873Ssam DELAY(1000000); 12029567Ssam } else { 12130521Ssam vdtype[ctlr] = VDTYPE_SMDE; 12230521Ssam vdaddr->vdrstclr = 0; 12325873Ssam DELAY(3000000); 12430521Ssam vdaddr->vdcsr = 0; 12530521Ssam vdaddr->vdtcf_mdcb = AM_ENPDA; 12630521Ssam vdaddr->vdtcf_dcb = AM_ENPDA; 12730521Ssam vdaddr->vdtcf_trail = AM_ENPDA; 12830521Ssam vdaddr->vdtcf_data = AM_ENPDA; 12930521Ssam vdaddr->vdccf = CCF_SEN | CCF_DER | CCF_STS | 13030521Ssam XMD_32BIT | BSZ_16WRD | 13130521Ssam CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR; 13225873Ssam } 13330521Ssam if (!vdcmd(ctlr, 0, VDOP_INIT, 10) || 13430521Ssam !vdcmd(ctlr, 0, VDOP_DIAG, 10)) { 13530521Ssam vderror(unit, dcb.opcode == VDOP_INIT ? "init" : "diag", &dcb); 13630521Ssam return (EIO); 13725873Ssam } 13830521Ssam vdinit[ctlr] = 1; 13930521Ssam for (i = unit = ctlr * NDRIVE; i < unit + NDRIVE; i++) 14030521Ssam dkconfigured[i] = 0; 14130521Ssam return (0); 14225873Ssam } 14325873Ssam 14430521Ssam /* 14530521Ssam * Reset and configure a drive's parameters. 14630521Ssam */ 14730521Ssam vdreset_drive(io) 14829567Ssam register struct iob *io; 14925873Ssam { 15030521Ssam register int ctlr = VDCTLR(io->i_unit), slave = VDSLAVE(io->i_unit); 151*32604Skarels register struct disklabel *lp = &dklabel[io->i_unit]; 15230521Ssam register struct vddevice *vdaddr = VDADDR(ctlr); 15330521Ssam int pass = 0, type = vdtype[ctlr], error; 154*32604Skarels int devflags = dkflags[ctlr][slave]; /* starts with 0 */ 15525873Ssam 15630521Ssam again: 15730521Ssam dcb.opcode = VDOP_CONFIG; /* command */ 15830521Ssam dcb.intflg = DCBINT_NONE; 15930521Ssam dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 16030521Ssam dcb.operrsta = 0; 161*32604Skarels dcb.devselect = slave | devflags; 16230521Ssam dcb.trail.rstrail.ncyl = lp->d_ncylinders; 16330521Ssam dcb.trail.rstrail.nsurfaces = lp->d_ntracks; 16430521Ssam if (type == VDTYPE_SMDE) { 16530823Skarels dcb.trailcnt = sizeof (struct treset) / sizeof (long); 16630521Ssam dcb.trail.rstrail.nsectors = lp->d_nsectors; 167*32604Skarels dcb.trail.rstrail.slip_sec = lp->d_trackskew; 168*32604Skarels dcb.trail.rstrail.recovery = VDRF_NORMAL; 16930521Ssam } else 17030521Ssam dcb.trailcnt = 2; /* XXX */ 17130521Ssam mdcb.mdcb_head = &dcb; 17230521Ssam mdcb.mdcb_status = 0; 17330521Ssam VDGO(vdaddr, (u_long)&mdcb, type); 17430521Ssam if (!vdpoll(vdaddr, &dcb, 10, type)) { 17530521Ssam if (pass++ != 0) { 17630521Ssam printf(" during drive configuration.\n"); 17730521Ssam return (0); 17830521Ssam } 17930521Ssam VDRESET(vdaddr, type); 18030521Ssam if (error = vdreset_ctlr(ctlr, io->i_unit)) 18130521Ssam return (error); 18230521Ssam goto again; 18325873Ssam } 184*32604Skarels if ((dcb.operrsta & VDERR_HARD) == 0) { /* success */ 185*32604Skarels dkflags[ctlr][slave] = devflags; 18630521Ssam return (1); 187*32604Skarels } 188*32604Skarels if (devflags == 0) { 189*32604Skarels devflags = VD_ESDI; 190*32604Skarels goto again; 191*32604Skarels } 19230521Ssam if (type == VDTYPE_SMDE && (vdaddr->vdstatus[slave] & STA_US) == 0) { 19330521Ssam printf("dk%d: nonexistent drive\n", io->i_unit); 19430521Ssam return (0); 19525873Ssam } 19630521Ssam if ((dcb.operrsta & (DCBS_OCYL|DCBS_NRDY)) == 0) { 19730521Ssam vderror(io->i_unit, "config", &dcb); 19830521Ssam return (0); 19930521Ssam } 200*32604Skarels devflags = 0; 20130521Ssam if (pass++) /* give up */ 20230521Ssam return (0); 20330521Ssam /* 20430521Ssam * Try to spin up drive with remote command. 20530521Ssam */ 20630521Ssam if (!vdcmd(ctlr, 0, VDOP_START, 62)) { 20730521Ssam vderror(io->i_unit, "start", &dcb); 20830521Ssam return (0); 20930521Ssam } 21029984Skarels DELAY(62000000); 21130521Ssam goto again; 21225873Ssam } 21325873Ssam 21430521Ssam vdcmd(ctlr, unit, cmd, time) 21530521Ssam register int ctlr; 21630521Ssam int unit, cmd, time; 21725873Ssam { 21830521Ssam register struct vddevice *vdaddr = VDADDR(ctlr); 21925873Ssam 22030521Ssam dcb.opcode = cmd; 22130521Ssam dcb.intflg = DCBINT_NONE; 22230521Ssam dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 22325873Ssam dcb.operrsta = 0; 224*32604Skarels dcb.devselect = unit | dkflags[ctlr][unit]; 22530521Ssam dcb.trailcnt = 0; 22630521Ssam mdcb.mdcb_head = &dcb; 22730521Ssam mdcb.mdcb_status = 0; 22830521Ssam VDGO(vdaddr, (u_long)&mdcb, vdtype[ctlr]); 22930521Ssam if (!vdpoll(vdaddr, &dcb, time, vdtype[ctlr])) 23030521Ssam _stop(" during initialization operation.\n"); 23130521Ssam return ((dcb.operrsta & VDERR_HARD) == 0); 23225873Ssam } 23325873Ssam 23430521Ssam vdstrategy(io, cmd) 23529567Ssam register struct iob *io; 23630521Ssam int cmd; 23725873Ssam { 23830521Ssam register struct disklabel *lp; 239*32604Skarels int ctlr, cn, tn, sn, slave, retries = 0; 24030521Ssam daddr_t bn; 24130521Ssam struct vddevice *vdaddr; 24225873Ssam 24329567Ssam if (io->i_cc == 0 || io->i_cc > 65535) { 24429567Ssam printf("dk%d: invalid transfer size %d\n", io->i_unit, 24529567Ssam io->i_cc); 24630521Ssam io->i_error = EIO; 24730521Ssam return (-1); 24829567Ssam } 24930521Ssam lp = &dklabel[io->i_unit]; 25030521Ssam bn = io->i_bn * (DEV_BSIZE / lp->d_secsize); 25130521Ssam cn = bn / lp->d_secpercyl; 25230521Ssam sn = bn % lp->d_secpercyl; 25330521Ssam tn = sn / lp->d_nsectors; 25430521Ssam sn = sn % lp->d_nsectors; 25530521Ssam 256*32604Skarels top: 25730521Ssam dcb.opcode = (cmd == READ ? VDOP_RD : VDOP_WD); 25830521Ssam dcb.intflg = DCBINT_NONE; 25930521Ssam dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 26030521Ssam dcb.operrsta = 0; 261*32604Skarels ctlr = VDCTLR(io->i_unit); 262*32604Skarels slave = VDSLAVE(io->i_unit); 263*32604Skarels dcb.devselect = slave | dkflags[ctlr][slave]; 26430823Skarels dcb.trailcnt = sizeof (struct trrw) / sizeof (int); 26530823Skarels dcb.trail.rwtrail.memadr = (u_long)io->i_ma; 26630521Ssam dcb.trail.rwtrail.wcount = (io->i_cc + 1) / sizeof (short); 26730521Ssam dcb.trail.rwtrail.disk.cylinder = cn; 26830521Ssam dcb.trail.rwtrail.disk.track = tn; 26930521Ssam dcb.trail.rwtrail.disk.sector = sn; 27030521Ssam mdcb.mdcb_head = &dcb; 27130521Ssam mdcb.mdcb_status = 0; 27230521Ssam vdaddr = VDADDR(ctlr); 27330521Ssam VDGO(vdaddr, (u_long)&mdcb, vdtype[ctlr]); 27430521Ssam if (!vdpoll(vdaddr, &dcb, 60, vdtype[ctlr])) 27530521Ssam _stop(" during i/o operation.\n"); 27630521Ssam if (dcb.operrsta & VDERR_HARD) { 277*32604Skarels if (retries++ == 0 && vdreset_ctlr(ctlr, io->i_unit) == 0 && 278*32604Skarels vdreset_drive(io)) 279*32604Skarels goto top; 28030521Ssam vderror(io->i_unit, cmd == READ ? "read" : "write", &dcb); 28130312Ssam io->i_error = EIO; 28229567Ssam return (-1); 28325873Ssam } 28425873Ssam mtpr(PADC, 0); 28529567Ssam return (io->i_cc); 28625873Ssam } 28725873Ssam 28830521Ssam vderror(unit, cmd, dcb) 28929567Ssam int unit; 29030521Ssam char *cmd; 29130521Ssam struct dcb *dcb; 29225873Ssam { 29329567Ssam 29430521Ssam printf("dk%d: %s error; status %b", unit, cmd, 29530521Ssam dcb->operrsta, VDERRBITS); 29630521Ssam if (dcb->err_code) 29730521Ssam printf(", code %x", dcb->err_code); 29825873Ssam printf("\n"); 29925873Ssam } 30025873Ssam 30125873Ssam /* 30230521Ssam * Poll controller until operation 30330521Ssam * completes or timeout expires. 30429567Ssam */ 30530521Ssam vdpoll(vdaddr, dcb, t, type) 30630521Ssam register struct vddevice *vdaddr; 30730521Ssam register struct dcb *dcb; 30825931Ssam register int t, type; 30925931Ssam { 31025931Ssam 31125931Ssam t *= 1000; 31230312Ssam for (;;) { 31325931Ssam uncache(&dcb->operrsta); 31430521Ssam if (dcb->operrsta & (DCBS_DONE|DCBS_ABORT)) 31530312Ssam break; 31625931Ssam if (--t <= 0) { 31725931Ssam printf("vd: controller timeout"); 31830521Ssam VDABORT(vdaddr, type); 31925931Ssam DELAY(30000); 32025931Ssam uncache(&dcb->operrsta); 32125931Ssam return (0); 32225931Ssam } 32330312Ssam DELAY(1000); 32425931Ssam } 32530521Ssam if (type == VDTYPE_SMDE) { 32630312Ssam for (;;) { 32730521Ssam uncache(&vdaddr->vdcsr); 32830521Ssam if ((vdaddr->vdcsr & CS_GO) == 0) 32930312Ssam break; 33025931Ssam DELAY(50); 33125931Ssam } 33225931Ssam DELAY(300); 33329984Skarels uncache(&dcb->err_code); 33425931Ssam } 33525931Ssam DELAY(200); 33625931Ssam uncache(&dcb->operrsta); 33725931Ssam return (1); 33825931Ssam } 33930521Ssam 34030521Ssam #ifdef COMPAT_42 34130521Ssam struct dkcompat { 34230521Ssam int nsectors; /* sectors per track */ 34330521Ssam int ntracks; /* tracks per cylinder */ 34430521Ssam int ncylinders; /* cylinders per drive */ 345*32604Skarels int secsize; /* sector size */ 34630521Ssam #define NPART 2 34730521Ssam int poff[NPART]; /* [a+b] for bootstrapping */ 34830521Ssam } dkcompat[] = { 349*32604Skarels { 48, 24, 711, 512, 0, 61056 }, /* xsd */ 350*32604Skarels { 44, 20, 842, 512, 0, 52800 }, /* eagle */ 351*32604Skarels { 64, 10, 823, 512, 0, 38400 }, /* fuji 360 */ 352*32604Skarels { 32, 24, 711, 512, 0, 40704 }, /* xfd */ 353*32604Skarels { 32, 19, 823, 512, 0, 40128 }, /* smd */ 354*32604Skarels { 32, 10, 823, 512, 0, 19200 }, /* fsd */ 355*32604Skarels { 18, 15, 1224, 1024, 0, 21600 }, /* mxd */ 35630521Ssam }; 35730521Ssam #define NDKCOMPAT (sizeof (dkcompat) / sizeof (dkcompat[0])) 35830521Ssam 35930521Ssam /* 36030521Ssam * Identify and configure drive from above table 36130521Ssam * by trying to read the last sector until a description 36230521Ssam * is found for which we're successful. 36330521Ssam */ 36430521Ssam vdmaptype(io) 36530521Ssam struct iob *io; 36630521Ssam { 36730521Ssam register struct disklabel *lp = &dklabel[io->i_unit]; 36830521Ssam register struct dkcompat *dp; 369*32604Skarels int i, ctlr, slave, type; 37030521Ssam struct vddevice *vdaddr; 37130521Ssam 37230521Ssam ctlr = VDCTLR(io->i_unit); 373*32604Skarels slave = VDSLAVE(io->i_unit); 37430521Ssam vdaddr = VDADDR(ctlr); 37530521Ssam type = vdtype[ctlr]; 37630521Ssam for (dp = dkcompat; dp < &dkcompat[NDKCOMPAT]; dp++) { 37730521Ssam if (type == VDTYPE_VDDC && dp->nsectors != 32) 37830521Ssam continue; 37930521Ssam lp->d_nsectors = dp->nsectors; 38030521Ssam lp->d_ntracks = dp->ntracks; 38130521Ssam lp->d_ncylinders = dp->ncylinders; 382*32604Skarels lp->d_secsize = dp->secsize; 38330521Ssam if (!vdreset_drive(io)) /* set drive parameters */ 38430521Ssam return (EIO); 38530521Ssam dcb.opcode = VDOP_RD; 38630521Ssam dcb.intflg = DCBINT_NONE; 38730521Ssam dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 388*32604Skarels dcb.devselect = slave | dkflags[ctlr][slave]; 38930521Ssam dcb.operrsta = 0; 39030823Skarels dcb.trailcnt = sizeof (struct trrw) / sizeof (long); 39130823Skarels dcb.trail.rwtrail.memadr = (u_long)lbuf; 392*32604Skarels dcb.trail.rwtrail.wcount = lp->d_secsize / sizeof (short); 39330521Ssam dcb.trail.rwtrail.disk.cylinder = dp->ncylinders - 2; 39430521Ssam dcb.trail.rwtrail.disk.track = dp->ntracks - 1; 39530521Ssam dcb.trail.rwtrail.disk.sector = dp->nsectors - 1; 39630521Ssam mdcb.mdcb_head = &dcb; 39730521Ssam mdcb.mdcb_status = 0; 39830521Ssam VDGO(vdaddr, (u_long)&mdcb, type); 39930521Ssam if (!vdpoll(vdaddr, &dcb, 60, type)) 40030521Ssam _stop(" during i/o operation.\n"); 40130521Ssam if (dcb.operrsta & VDERR_HARD) 40230521Ssam continue; 40330521Ssam /* simulate necessary parts of disk label */ 40430521Ssam lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks; 40530521Ssam lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders; 40630521Ssam lp->d_npartitions = NPART; 40730521Ssam for (i = 0; i < NPART; i++) { 40830521Ssam lp->d_partitions[i].p_offset = dp->poff[i]; 40930521Ssam lp->d_partitions[i].p_size = 41030521Ssam lp->d_secperunit - dp->poff[i]; 41130521Ssam } 41230521Ssam return (0); 41330521Ssam } 41430521Ssam printf("dk%d: unknown drive type\n", io->i_unit); 41530521Ssam return (ENXIO); 41630521Ssam } 41730521Ssam #endif 418