1: /* 2: * Copyright (c) 1986 Regents of the University of California. 3: * All rights reserved. The Berkeley software License Agreement 4: * specifies the terms and conditions for redistribution. 5: * 6: * @(#)xp.c 2.3 (2.11BSD) 1996/3/8 7: */ 8: 9: /* 10: * SMD disk driver 11: */ 12: #include "../h/param.h" 13: #include "../pdpuba/hpreg.h" 14: #include "../machine/iopage.h" 15: #include "saio.h" 16: 17: #define NXP 2 18: 19: struct hpdevice *XPcsr[NXP + 1] = 20: { 21: (struct hpdevice *)0176700, 22: (struct hpdevice *)0, 23: (struct hpdevice *)-1 24: }; 25: 26: static char xpinit[NXP][8]; /* XXX */ 27: 28: xpopen(io) 29: register struct iob *io; 30: { 31: register struct disklabel *lp = &io->i_label; 32: register struct hpdevice *xpaddr; 33: int dummy; 34: 35: if (genopen(NXP, io) < 0) 36: return(-1); 37: /* 38: * If this is the first access for the drive check to see if it is 39: * present. If the drive is present then read the label. 40: */ 41: if (xpinit[io->i_ctlr][io->i_unit] == 0) 42: { 43: xpaddr = XPcsr[io->i_ctlr]; 44: xpaddr->hpcs1.w = HP_NOP; 45: xpaddr->hpcs2.w = io->i_unit; 46: xpaddr->hpcs1.w = HP_GO; 47: delay(6000); 48: dummy = xpaddr->hpds; 49: if (xpaddr->hpcs2.w & HPCS2_NED) 50: { 51: xpaddr->hpcs2.w = HPCS2_CLR; 52: return(-1); 53: } 54: if (devlabel(io, READLABEL) == -1) 55: return(-1); 56: xpinit[io->i_ctlr][io->i_unit] = 1; 57: } 58: io->i_boff = lp->d_partitions[io->i_part].p_offset; 59: return(0); 60: } 61: 62: xpclose(io) 63: struct iob *io; 64: { 65: 66: xpinit[io->i_ctlr][io->i_unit] = 0; 67: return(0); 68: } 69: 70: xpstrategy(io, func) 71: register struct iob *io; 72: { 73: int i; 74: daddr_t bn; 75: int sn, cn, tn, bae, lo16; 76: register struct hpdevice *xpaddr = XPcsr[io->i_ctlr]; 77: register struct disklabel *lp = &io->i_label; 78: 79: i = deveovchk(io); 80: if (i <= 0) 81: return(i); 82: 83: bn = io->i_bn; 84: xpaddr->hpcs2.w = io->i_unit; 85: 86: if ((xpaddr->hpds & HPDS_VV) == 0) { 87: xpaddr->hpcs1.c[0] = HP_PRESET|HP_GO; 88: xpaddr->hpof = HPOF_FMT22; 89: } 90: cn = bn / lp->d_secpercyl; 91: sn = bn % lp->d_secpercyl; 92: tn = sn / lp->d_nsectors; 93: sn = sn % lp->d_nsectors; 94: 95: iomapadr(io->i_ma, &bae, &lo16); 96: xpaddr->hpdc = cn; 97: xpaddr->hpda = (tn << 8) + sn; 98: xpaddr->hpba = (caddr_t)lo16; 99: xpaddr->hpwc = -(io->i_cc>>1); 100: i = (bae << 8) | HP_GO; 101: if (func == READ) 102: i |= HP_RCOM; 103: else if (func == WRITE) 104: i |= HP_WCOM; 105: xpaddr->hpcs1.w = i; 106: while ((xpaddr->hpcs1.w & HP_RDY) == 0) 107: continue; 108: if (xpaddr->hpcs1.w & HP_TRE) { 109: printf("%s err cy=%d tr=%d sc=%d cs2=%o er1=%o\n", 110: devname(io), cn, tn, sn, xpaddr->hpcs2, 111: xpaddr->hper1); 112: return(-1); 113: } 114: return(io->i_cc); 115: } 116: 117: /* 118: * ALL drive type identification has been removed from the kernel's XP 119: * driver and placed here. 120: * 121: * These tables are used to provide "the best guess" of the geometry 122: * of the drive. DEC RP0{4,5,6,7} and RM0{3,5} drives will match exactly. 123: * Non DEC controllers (performing an emulation) often use the DEC drive 124: * type to mean completely different geometry/capacity drives. 125: */ 126: 127: struct xpst 128: { 129: int flags; /* flags: XP_CC, XP_NOSEARCH */ 130: int ncyl; /* number of cylinders */ 131: int nspc; /* number of sectors per cylinder */ 132: int ntpc; /* number of tracks per cylinder */ 133: int nspt; /* number of sectors per track */ 134: daddr_t nspd; /* number of sectors per drive */ 135: }; 136: 137: static struct xpst rp04_st = { XP_CC, 411, 22 * 19, 19, 22, 411L * 22 * 19 }; 138: /* rp05 uses same table as rp04 */ 139: static struct xpst rp06_st = { XP_CC, 815, 22 * 19, 19, 22, 815L * 22 * 19 }; 140: static struct xpst rp07_st = { XP_CC, 630, 50 * 32, 32, 50, 630L * 50 * 32 }; 141: 142: static struct xpst rm02_st; /* filled in dynamically */ 143: static struct xpst rm03_st = { 0, 823, 32 * 5, 5, 32, 823L * 32 * 5 }; 144: static struct xpst rm05_st = { 0, 823, 32 * 19, 19, 32, 823L * 32 * 19 }; 145: static struct xpst rm80_st = { 0, 559, 31 * 14, 14, 31, 559L * 31 * 14 }; 146: 147: /* 148: * SI controller stuff - likely not used any longer and will probably go away 149: * eventually (when the D space is needed for something more important). 150: */ 151: 152: static struct xpst cdc9775_st = { 0, 843, 32 * 40, 40, 32, 843L * 32 * 40 }; 153: static struct xpst cdc9730_st = { 0, 823, 32 * 10, 10, 32, 823L * 32 * 10 }; 154: static struct xpst cdc9766_st = { 0, 823, 32 * 19, 19, 32, 823L * 32 * 19 }; 155: static struct xpst cdc9762_st = { 0, 823, 32 * 5, 5, 32, 823L * 32 * 5 }; 156: static struct xpst capric_st = { 0, 1024, 32 * 16, 16, 32, 1024L * 32 * 16 }; 157: static struct xpst eagle_st = { 0, 842, 48 * 20, 20, 48, 842L * 48 * 20 }; 158: 159: /* 160: * A "default". If none of the above are useable then a default geometry 161: * suitable for writing a label (sector 1) is used. 162: */ 163: 164: static struct xpst default_st = { 0, 1, 2 * 1, 1, 2, 2 }; 165: 166: /* 167: * This routine does not return an error (-1). If the drive is totally 168: * unrecognizeable then the default above is used. 169: */ 170: 171: xplabel(io) 172: struct iob *io; 173: { 174: register struct xpst *st = NULL; 175: int type, xpsn; 176: register struct hpdevice *xpaddr = XPcsr[io->i_ctlr]; 177: register struct disklabel *lp; 178: 179: type = xpaddr->hpdt & 077; 180: switch (type) 181: { 182: case HPDT_RP04: /* 020 */ 183: case HPDT_RP05: /* 021 */ 184: st = &rp04_st; 185: break; 186: case HPDT_RP06: /* 022 */ 187: st = &rp06_st; 188: break; 189: case HPDT_RP07: /* 042 */ 190: st = &rp07_st; 191: break; 192: case HPDT_RM80: /* 026 */ 193: st = &rm80_st; 194: break; 195: case HPDT_RM05: /* 027 */ 196: st = &rm05_st; 197: break; 198: case HPDT_RM03: /* 024 */ 199: st = &rm03_st; 200: break; 201: case HPDT_RM02: /* 025 */ 202: /* 203: * Borrowing a quote from 4BSD: 204: * "We know this isn't a dec controller, so we can assume sanity." 205: */ 206: st = &rm02_st; 207: xpaddr->hpcs1.w = HP_NOP; 208: xpaddr->hpcs2.w = io->i_unit; 209: 210: xpaddr->rmhr = HPHR_MAXTRAK; 211: st->ntpc = xpaddr->rmhr + 1; 212: 213: xpaddr->rmhr = HPHR_MAXSECT; 214: st->nspt = xpaddr->rmhr + 1; 215: 216: xpaddr->rmhr = HPHR_MAXCYL; 217: st->ncyl = xpaddr->rmhr + 1; 218: 219: xpaddr->hpcs1.w = HP_DCLR | HP_GO; 220: 221: st->nspc = st->nspt * st->ntpc; 222: st->nspd = (long)st->nspc * st->ncyl; 223: printf("type: RM02 c=%d t/c=%d s/t=%d\n", st->ncyl, 224: st->ntpc, st->nspt); 225: break; 226: default: 227: printf("%s unknown drive type: %d -- ", 228: devname(io), type); 229: printf("using 1 cyl, 1 trk, 2 sec/trk\n"); 230: st = &default_st; 231: break; 232: } 233: 234: /* 235: * Handle SI model byte stuff when we think it's an RM05 or RM03. Is any 236: * one still using one of these? Is it worth all this code? 237: */ 238: if (type == HPDT_RM05 || type == HPDT_RM03) 239: { 240: xpsn = xpaddr->hpsn; 241: if ((xpsn & SIMB_LU) != io->i_unit) 242: goto notsi; 243: switch ((xpsn & SIMB_MB) &~ (SIMB_S6|SIRM03|SIRM05)) 244: { 245: case SI9775D: 246: st = &cdc9775_st; 247: break; 248: case SI9730D: 249: st = &cdc9730_st; 250: break; 251: case SI9766: 252: st = &cdc9766_st; 253: break; 254: case SI9762: 255: st = &cdc9762_st; 256: break; 257: case SICAPD: 258: st = &capric_st; 259: break; 260: case SI9751D: 261: st = &eagle_st; 262: break; 263: default: 264: printf("%s unknown SI drive model %d -- ", 265: devname(io), xpsn); 266: printf("using 1 cyl, 1 trk, 2 sec/trk\n"); 267: st = &default_st; 268: break; 269: } 270: } 271: notsi: 272: lp = &io->i_label; 273: lp->d_type = DTYPE_SMD; 274: lp->d_secsize = 512; /* XXX */ 275: lp->d_secperunit = st->nspd; 276: lp->d_partitions[0].p_size = st->nspd; 277: lp->d_nsectors = st->nspt; 278: lp->d_ntracks = st->ntpc; 279: lp->d_secpercyl = st->nspc; 280: lp->d_ncylinders = st->ncyl; 281: lp->d_drivedata[0] = st->flags; 282: strcpy(lp->d_typename, "SMD"); 283: return(0); 284: }