|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1988 The Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * This code is derived from software contributed to Berkeley by ! 6: * Computer Consoles Inc. ! 7: * ! 8: * Redistribution is only permitted until one year after the first shipment ! 9: * of 4.4BSD by the Regents. Otherwise, redistribution and use in source and ! 10: * binary forms are permitted provided that: (1) source distributions retain ! 11: * this entire copyright notice and comment, and (2) distributions including ! 12: * binaries display the following acknowledgement: This product includes ! 13: * software developed by the University of California, Berkeley and its ! 14: * contributors'' in the documentation or other materials provided with the ! 15: * distribution and in all advertising materials mentioning features or use ! 16: * of this software. Neither the name of the University nor the names of ! 17: * its contributors may be used to endorse or promote products derived from ! 18: * this software without specific prior written permission. ! 19: * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED ! 20: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF ! 21: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 22: * ! 23: * @(#)vd.c 7.16 (Berkeley) 6/30/90 ! 24: */ ! 25: ! 26: /* ! 27: * Stand alone driver for the VDDC/SMDE controller ! 28: */ ! 29: #include "machine/mtpr.h" ! 30: ! 31: #include "sys/param.h" ! 32: #include "sys/time.h" ! 33: #include "sys/buf.h" ! 34: #include "sys/disklabel.h" ! 35: #include "saio.h" ! 36: ! 37: #include "tahoevba/vdreg.h" ! 38: #include "tahoevba/vbaparam.h" ! 39: ! 40: #define COMPAT_42 1 ! 41: ! 42: #define NVD 4 /* controllers */ ! 43: #define NDRIVE 8 /* drives per controller */ ! 44: ! 45: #define VDADDR(ctlr) ((struct vddevice *)vdaddrs[ctlr]) ! 46: long vdaddrs[NVD] = { 0xffff2000, 0xffff2100, 0xffff2200, 0xffff2300 }; ! 47: ! 48: u_char vdinit[NVD]; /* controller initialized */ ! 49: u_char vdtype[NVD]; /* controller type */ ! 50: u_char dkconfigured[NVD][NDRIVE]; /* unit configured */ ! 51: u_char dkflags[NVD][NDRIVE]; /* unit flags */ ! 52: ! 53: static struct disklabel dklabel[NVD][NDRIVE]; /* pack label */ ! 54: static struct mdcb mdcb; ! 55: static struct dcb dcb; ! 56: static char lbuf[DEV_BSIZE]; ! 57: ! 58: vdopen(io) ! 59: register struct iob *io; ! 60: { ! 61: register int ctlr = io->i_ctlr; ! 62: register struct dkinfo *dk; ! 63: register struct disklabel *lp, *dlp; ! 64: int error; ! 65: ! 66: if ((u_int)io->i_adapt) ! 67: return (EADAPT); ! 68: if ((u_int)ctlr >= NVD) ! 69: return (ECTLR); ! 70: if (!vdinit[ctlr] && (error = vdreset_ctlr(ctlr, io->i_unit))) ! 71: return (error); ! 72: lp = &dklabel[io->i_ctlr][io->i_unit]; ! 73: if (!dkconfigured[io->i_ctlr][io->i_unit]) { ! 74: struct iob tio; ! 75: ! 76: /* ! 77: * Read in the pack label. ! 78: */ ! 79: lp->d_secsize = 1024; ! 80: lp->d_nsectors = 72; ! 81: lp->d_ntracks = 24; ! 82: lp->d_ncylinders = 711; ! 83: lp->d_secpercyl = 72*24; ! 84: if (!vdreset_drive(io)) ! 85: return (ENXIO); ! 86: tio = *io; ! 87: tio.i_bn = LABELSECTOR; ! 88: tio.i_ma = lbuf; ! 89: tio.i_cc = DEV_BSIZE; ! 90: tio.i_flgs |= F_RDDATA; ! 91: if (vdstrategy(&tio, READ) != DEV_BSIZE) ! 92: return (ERDLAB); ! 93: dlp = (struct disklabel *)(lbuf + LABELOFFSET); ! 94: if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC) ! 95: #ifdef COMPAT_42 ! 96: { ! 97: printf("dk%d: unlabeled\n", io->i_unit); ! 98: if (error = vdmaptype(io)) ! 99: return (error); ! 100: } ! 101: #else ! 102: return (EUNLAB); ! 103: #endif ! 104: else { ! 105: *lp = *dlp; ! 106: if (!vdreset_drive(io)) ! 107: return (ENXIO); ! 108: } ! 109: dkconfigured[io->i_ctlr][io->i_unit] = 1; ! 110: } ! 111: if (io->i_part < 0 || io->i_part >= lp->d_npartitions || ! 112: lp->d_partitions[io->i_part].p_size == 0) ! 113: return (EPART); ! 114: io->i_boff = ! 115: (lp->d_partitions[io->i_part].p_offset * lp->d_secsize) / DEV_BSIZE; ! 116: return (0); ! 117: } ! 118: ! 119: /* ! 120: * Reset and initialize the controller. ! 121: */ ! 122: vdreset_ctlr(ctlr, unit) ! 123: register int ctlr, unit; ! 124: { ! 125: register int i; ! 126: register struct vddevice *vdaddr = VDADDR(ctlr); ! 127: ! 128: if (badaddr(vdaddr, 2)) { ! 129: printf("vd%d: %x: invalid csr\n", ctlr, vdaddr); ! 130: return (ENXIO); ! 131: } ! 132: /* probe further to find what kind of controller it is */ ! 133: vdaddr->vdreset = 0xffffffff; ! 134: DELAY(1000000); ! 135: if (vdaddr->vdreset != 0xffffffff) { ! 136: vdtype[ctlr] = VDTYPE_VDDC; ! 137: DELAY(1000000); ! 138: } else { ! 139: vdtype[ctlr] = VDTYPE_SMDE; ! 140: vdaddr->vdrstclr = 0; ! 141: DELAY(3000000); ! 142: vdaddr->vdcsr = 0; ! 143: vdaddr->vdtcf_mdcb = AM_ENPDA; ! 144: vdaddr->vdtcf_dcb = AM_ENPDA; ! 145: vdaddr->vdtcf_trail = AM_ENPDA; ! 146: vdaddr->vdtcf_data = AM_ENPDA; ! 147: vdaddr->vdccf = CCF_SEN | CCF_DIU | CCF_STS | ! 148: XMD_32BIT | BSZ_16WRD | ! 149: CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR; ! 150: } ! 151: if (!vdcmd(ctlr, 0, VDOP_INIT, 10) || ! 152: !vdcmd(ctlr, 0, VDOP_DIAG, 10)) { ! 153: vderror(unit, dcb.opcode == VDOP_INIT ? "init" : "diag", &dcb); ! 154: return (EIO); ! 155: } ! 156: vdinit[ctlr] = 1; ! 157: for (i = NDRIVE - 1; i >= 0; i--) ! 158: dkconfigured[ctlr][i] = 0; ! 159: return (0); ! 160: } ! 161: ! 162: /* ! 163: * Reset and configure a drive's parameters. ! 164: */ ! 165: vdreset_drive(io) ! 166: register struct iob *io; ! 167: { ! 168: register int ctlr = io->i_ctlr, slave = io->i_unit; ! 169: register struct disklabel *lp = &dklabel[io->i_ctlr][io->i_unit]; ! 170: register struct vddevice *vdaddr = VDADDR(ctlr); ! 171: int pass = 0, type = vdtype[ctlr], error; ! 172: int devflags = dkflags[ctlr][slave]; /* starts with 0 */ ! 173: ! 174: again: ! 175: dcb.opcode = VDOP_CONFIG; /* command */ ! 176: dcb.intflg = DCBINT_NONE; ! 177: dcb.nxtdcb = (struct dcb *)0; /* end of chain */ ! 178: dcb.operrsta = 0; ! 179: dcb.devselect = slave | devflags; ! 180: dcb.trail.rstrail.ncyl = lp->d_ncylinders; ! 181: dcb.trail.rstrail.nsurfaces = lp->d_ntracks; ! 182: if (type == VDTYPE_SMDE) { ! 183: dcb.trailcnt = sizeof (struct treset) / sizeof (long); ! 184: dcb.trail.rstrail.nsectors = lp->d_nsectors; ! 185: dcb.trail.rstrail.slip_sec = lp->d_trackskew; ! 186: dcb.trail.rstrail.recovery = VDRF_NORMAL; ! 187: } else ! 188: dcb.trailcnt = 2; /* XXX */ ! 189: mdcb.mdcb_head = &dcb; ! 190: mdcb.mdcb_status = 0; ! 191: VDGO(vdaddr, (u_long)&mdcb, type); ! 192: if (!vdpoll(vdaddr, &dcb, 10, type)) { ! 193: if (pass++ != 0) { ! 194: printf(" during drive configuration.\n"); ! 195: return (0); ! 196: } ! 197: VDRESET(vdaddr, type); ! 198: if (error = vdreset_ctlr(ctlr, io->i_unit)) ! 199: return (error); ! 200: goto again; ! 201: } ! 202: if ((dcb.operrsta & VDERR_HARD) == 0) { /* success */ ! 203: dkflags[ctlr][slave] = devflags; ! 204: return (1); ! 205: } ! 206: if (devflags == 0) { ! 207: devflags = VD_ESDI; ! 208: goto again; ! 209: } ! 210: if (type == VDTYPE_SMDE && (vdaddr->vdstatus[slave] & STA_US) == 0) { ! 211: printf("dk%d: nonexistent drive\n", io->i_unit); ! 212: return (0); ! 213: } ! 214: if ((dcb.operrsta & (DCBS_OCYL|DCBS_NRDY)) == 0) { ! 215: vderror(io->i_unit, "config", &dcb); ! 216: return (0); ! 217: } ! 218: devflags = 0; ! 219: if (pass++) /* give up */ ! 220: return (0); ! 221: /* ! 222: * Try to spin up drive with remote command. ! 223: */ ! 224: if (!vdcmd(ctlr, 0, VDOP_START, 62)) { ! 225: vderror(io->i_unit, "start", &dcb); ! 226: return (0); ! 227: } ! 228: DELAY(62000000); ! 229: goto again; ! 230: } ! 231: ! 232: vdcmd(ctlr, unit, cmd, time) ! 233: register int ctlr; ! 234: int unit, cmd, time; ! 235: { ! 236: register struct vddevice *vdaddr = VDADDR(ctlr); ! 237: ! 238: dcb.opcode = cmd; ! 239: dcb.intflg = DCBINT_NONE; ! 240: dcb.nxtdcb = (struct dcb *)0; /* end of chain */ ! 241: dcb.operrsta = 0; ! 242: dcb.devselect = unit | dkflags[ctlr][unit]; ! 243: dcb.trailcnt = 0; ! 244: mdcb.mdcb_head = &dcb; ! 245: mdcb.mdcb_status = 0; ! 246: VDGO(vdaddr, (u_long)&mdcb, vdtype[ctlr]); ! 247: if (!vdpoll(vdaddr, &dcb, time, vdtype[ctlr])) ! 248: _stop(" during initialization operation.\n"); ! 249: return ((dcb.operrsta & VDERR_HARD) == 0); ! 250: } ! 251: ! 252: vdstrategy(io, cmd) ! 253: register struct iob *io; ! 254: int cmd; ! 255: { ! 256: register struct disklabel *lp; ! 257: int ctlr, cn, tn, sn, slave, retries = 0; ! 258: daddr_t bn; ! 259: struct vddevice *vdaddr; ! 260: ! 261: if (io->i_cc == 0 || io->i_cc > 65535) { ! 262: printf("dk%d: invalid transfer size %d\n", io->i_unit, ! 263: io->i_cc); ! 264: io->i_error = EIO; ! 265: return (-1); ! 266: } ! 267: lp = &dklabel[io->i_ctlr][io->i_unit]; ! 268: bn = io->i_bn * (DEV_BSIZE / lp->d_secsize); ! 269: cn = bn / lp->d_secpercyl; ! 270: sn = bn % lp->d_secpercyl; ! 271: tn = sn / lp->d_nsectors; ! 272: sn = sn % lp->d_nsectors; ! 273: ! 274: top: ! 275: dcb.opcode = (cmd == READ ? VDOP_RD : VDOP_WD); ! 276: dcb.intflg = DCBINT_NONE; ! 277: dcb.nxtdcb = (struct dcb *)0; /* end of chain */ ! 278: dcb.operrsta = 0; ! 279: ctlr = io->i_ctlr; ! 280: slave = io->i_unit; ! 281: dcb.devselect = slave | dkflags[ctlr][slave]; ! 282: dcb.trailcnt = sizeof (struct trrw) / sizeof (int); ! 283: dcb.trail.rwtrail.memadr = (u_long)io->i_ma; ! 284: dcb.trail.rwtrail.wcount = (io->i_cc + 1) / sizeof (short); ! 285: dcb.trail.rwtrail.disk.cylinder = cn; ! 286: dcb.trail.rwtrail.disk.track = tn; ! 287: dcb.trail.rwtrail.disk.sector = sn; ! 288: mdcb.mdcb_head = &dcb; ! 289: mdcb.mdcb_status = 0; ! 290: vdaddr = VDADDR(ctlr); ! 291: VDGO(vdaddr, (u_long)&mdcb, vdtype[ctlr]); ! 292: if (!vdpoll(vdaddr, &dcb, 60, vdtype[ctlr])) ! 293: _stop(" during i/o operation.\n"); ! 294: if (dcb.operrsta & VDERR_HARD) { ! 295: if (retries++ == 0 && vdreset_ctlr(ctlr, io->i_unit) == 0 && ! 296: vdreset_drive(io)) ! 297: goto top; ! 298: vderror(io->i_unit, cmd == READ ? "read" : "write", &dcb); ! 299: io->i_error = EIO; ! 300: return (-1); ! 301: } ! 302: mtpr(PADC, 0); ! 303: return (io->i_cc); ! 304: } ! 305: ! 306: vderror(unit, cmd, dcb) ! 307: int unit; ! 308: char *cmd; ! 309: struct dcb *dcb; ! 310: { ! 311: ! 312: printf("dk%d: %s error; status %b", unit, cmd, ! 313: dcb->operrsta, VDERRBITS); ! 314: if (dcb->err_code) ! 315: printf(", code %x", dcb->err_code); ! 316: printf("\n"); ! 317: } ! 318: ! 319: /* ! 320: * Poll controller until operation ! 321: * completes or timeout expires. ! 322: */ ! 323: vdpoll(vdaddr, dcb, t, type) ! 324: register struct vddevice *vdaddr; ! 325: register struct dcb *dcb; ! 326: register int t, type; ! 327: { ! 328: ! 329: t *= 1000; ! 330: for (;;) { ! 331: uncache(&dcb->operrsta); ! 332: if (dcb->operrsta & (DCBS_DONE|DCBS_ABORT)) ! 333: break; ! 334: if (--t <= 0) { ! 335: printf("vd: controller timeout"); ! 336: VDABORT(vdaddr, type); ! 337: DELAY(30000); ! 338: uncache(&dcb->operrsta); ! 339: return (0); ! 340: } ! 341: DELAY(1000); ! 342: } ! 343: if (type == VDTYPE_SMDE) { ! 344: for (;;) { ! 345: uncache(&vdaddr->vdcsr); ! 346: if ((vdaddr->vdcsr & CS_GO) == 0) ! 347: break; ! 348: DELAY(50); ! 349: } ! 350: DELAY(300); ! 351: uncache(&dcb->err_code); ! 352: } ! 353: DELAY(200); ! 354: uncache(&dcb->operrsta); ! 355: return (1); ! 356: } ! 357: ! 358: #ifdef COMPAT_42 ! 359: struct dkcompat { ! 360: int nsectors; /* sectors per track */ ! 361: int ntracks; /* tracks per cylinder */ ! 362: int ncylinders; /* cylinders per drive */ ! 363: int secsize; /* sector size */ ! 364: #define NPART 2 ! 365: int poff[NPART]; /* [a+b] for bootstrapping */ ! 366: } dkcompat[] = { ! 367: { 64, 20, 842, 512, 0, 61440 }, /* 2361a eagle */ ! 368: { 48, 24, 711, 512, 0, 61056 }, /* xsd */ ! 369: { 44, 20, 842, 512, 0, 52800 }, /* eagle */ ! 370: { 64, 10, 823, 512, 0, 38400 }, /* fuji 360 */ ! 371: { 32, 24, 711, 512, 0, 40704 }, /* xfd */ ! 372: { 32, 19, 823, 512, 0, 40128 }, /* smd */ ! 373: { 32, 10, 823, 512, 0, 19200 }, /* fsd */ ! 374: { 18, 15, 1224, 1024, 0, 21600 }, /* mxd */ ! 375: }; ! 376: #define NDKCOMPAT (sizeof (dkcompat) / sizeof (dkcompat[0])) ! 377: ! 378: /* ! 379: * Identify and configure drive from above table ! 380: * by trying to read the last sector until a description ! 381: * is found for which we're successful. ! 382: */ ! 383: vdmaptype(io) ! 384: struct iob *io; ! 385: { ! 386: register struct disklabel *lp = &dklabel[io->i_ctlr][io->i_unit]; ! 387: register struct dkcompat *dp; ! 388: int i, ctlr, slave, type; ! 389: struct vddevice *vdaddr; ! 390: ! 391: ctlr = io->i_ctlr; ! 392: slave = io->i_unit; ! 393: vdaddr = VDADDR(ctlr); ! 394: type = vdtype[ctlr]; ! 395: for (dp = dkcompat; dp < &dkcompat[NDKCOMPAT]; dp++) { ! 396: if (type == VDTYPE_VDDC && dp->nsectors != 32) ! 397: continue; ! 398: lp->d_nsectors = dp->nsectors; ! 399: lp->d_ntracks = dp->ntracks; ! 400: lp->d_ncylinders = dp->ncylinders; ! 401: lp->d_secsize = dp->secsize; ! 402: if (!vdreset_drive(io)) /* set drive parameters */ ! 403: return (EIO); ! 404: dcb.opcode = VDOP_RD; ! 405: dcb.intflg = DCBINT_NONE; ! 406: dcb.nxtdcb = (struct dcb *)0; /* end of chain */ ! 407: dcb.devselect = slave | dkflags[ctlr][slave]; ! 408: dcb.operrsta = 0; ! 409: dcb.trailcnt = sizeof (struct trrw) / sizeof (long); ! 410: dcb.trail.rwtrail.memadr = (u_long)lbuf; ! 411: dcb.trail.rwtrail.wcount = lp->d_secsize / sizeof (short); ! 412: dcb.trail.rwtrail.disk.cylinder = dp->ncylinders - 2; ! 413: dcb.trail.rwtrail.disk.track = dp->ntracks - 1; ! 414: dcb.trail.rwtrail.disk.sector = dp->nsectors - 1; ! 415: mdcb.mdcb_head = &dcb; ! 416: mdcb.mdcb_status = 0; ! 417: VDGO(vdaddr, (u_long)&mdcb, type); ! 418: if (!vdpoll(vdaddr, &dcb, 60, type)) ! 419: _stop(" during i/o operation.\n"); ! 420: if (dcb.operrsta & VDERR_HARD) ! 421: continue; ! 422: /* simulate necessary parts of disk label */ ! 423: lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks; ! 424: lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders; ! 425: lp->d_npartitions = NPART; ! 426: for (i = 0; i < NPART; i++) { ! 427: lp->d_partitions[i].p_offset = dp->poff[i]; ! 428: lp->d_partitions[i].p_size = ! 429: lp->d_secperunit - dp->poff[i]; ! 430: } ! 431: return (0); ! 432: } ! 433: printf("dk%d: unknown drive type\n", io->i_unit); ! 434: return (ENXIO); ! 435: } ! 436: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.