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: * @(#)ra.c 2.8 (2.11BSD GTE) 1998/1/30 7: */ 8: 9: /* 10: * MSCP disk device driver (rx23, rx33, rx50, rd??, ra??, rz??) 11: */ 12: #include "../h/param.h" 13: #include "../machine/mscp.h" 14: #include "../pdpuba/rareg.h" 15: #include "saio.h" 16: 17: #define NRA 2 18: #define RA_SMASK (RA_STEP4|RA_STEP3|RA_STEP2|RA_STEP1) 19: 20: struct radevice *RAcsr[NRA + 1] = 21: { 22: (struct radevice *)0172150, 23: (struct radevice *)0, 24: (struct radevice *)-1 25: }; 26: 27: /* 28: * RA Communications Area 29: */ 30: struct rdca { 31: short ca_xxx1; /* unused */ 32: char ca_xxx2; /* unused */ 33: char ca_bdp; /* BDP to purge */ 34: short ca_cmdint; /* command queue transition interrupt flag */ 35: short ca_rspint; /* response queue transition interrupt flag */ 36: short ca_rspl; /* response descriptors */ 37: short ca_rsph; 38: short ca_cmdl; /* command descriptors */ 39: short ca_cmdh; 40: }; 41: 42: #define ca_ringbase ca_rspl 43: 44: #define RA_OWN 0x8000 /* RQ owns this descriptor */ 45: #define RA_INT 0x4000 /* allow interrupt on ring transition */ 46: 47: static struct ra { 48: struct rdca ra_ca; 49: struct mscp ra_rsp; 50: struct mscp ra_cmd; 51: } rd[NRA]; 52: 53: static u_char rainit[NRA]; 54: static int mx(); 55: 56: /* 57: * This contains the volume size in sectors of units which have been 58: * brought online. This value is used at default label generation time 59: * along with the results of a 'get unit status' command to compute the 60: * "geometry" of the drive. 61: */ 62: static long raonline[NRA][8]; 63: 64: raopen(io) 65: register struct iob *io; 66: { 67: register struct radevice *raaddr; 68: register struct ra *racom; 69: struct disklabel *lp = &io->i_label; 70: int i, ctlr, unit, bae, lo16; 71: 72: ctlr = io->i_ctlr; 73: unit = io->i_unit; 74: if (genopen(NRA, io) < 0) 75: return(-1); 76: raaddr = RAcsr[ctlr]; 77: racom = &rd[ctlr]; 78: 79: if (rainit[ctlr] == 0) { 80: again: raaddr->raip = 0; 81: if (ra_step(raaddr, RA_STEP1, 1)) 82: goto again; 83: raaddr->rasa = RA_ERR | (0154/4); 84: if (ra_step(raaddr, RA_STEP2, 2)) 85: goto again; 86: iomapadr(&racom->ra_ca.ca_ringbase, &bae, &lo16); 87: raaddr->rasa = lo16; 88: if (ra_step(raaddr, RA_STEP3, 3)) 89: goto again; 90: raaddr->rasa = bae; 91: if (ra_step(raaddr, RA_STEP4, 4)) 92: goto again; 93: raaddr->rasa = RA_GO; 94: if (racmd(M_OP_STCON, io) < 0) { 95: printf("%s STCON err\n", devname(io)); 96: return(-1); 97: } 98: rainit[ctlr] = 1; 99: } 100: 101: if (raonline[ctlr][unit] == 0) 102: if (ramount(io) == -1) 103: return(-1); 104: if (devlabel(io, READLABEL) == -1) 105: return(-1); 106: io->i_boff = lp->d_partitions[io->i_part].p_offset; 107: return(0); 108: } 109: 110: raclose(io) 111: register struct iob *io; 112: { 113: raonline[io->i_ctlr][io->i_unit] = 0; 114: return(0); 115: } 116: 117: ramount(io) 118: register struct iob *io; 119: { 120: register int ctlr = io->i_ctlr; 121: register int unit = io->i_unit; 122: 123: if (racmd(M_OP_ONLIN, io) < 0) { 124: printf("%s !online\n", devname(io)); 125: return(-1); 126: } 127: raonline[ctlr][unit] = rd[ctlr].ra_rsp.m_uslow + 128: ((long)(rd[ctlr].ra_rsp.m_ushigh) << 16); 129: return(0); 130: } 131: 132: racmd(op, io) 133: int op; 134: struct iob *io; 135: { 136: register struct mscp *mp; 137: int ctlr = io->i_ctlr; 138: int unit = io->i_unit; 139: register struct ra *racom = &rd[ctlr]; 140: struct radevice *csr = RAcsr[ctlr]; 141: int i, bae, lo16; 142: 143: racom->ra_cmd.m_opcode = op; 144: racom->ra_cmd.m_unit = unit; 145: racom->ra_cmd.m_cntflgs = 0; 146: racom->ra_rsp.m_header.mscp_msglen = sizeof(struct mscp); 147: racom->ra_cmd.m_header.mscp_msglen = sizeof(struct mscp); 148: 149: iomapadr(&racom->ra_rsp.m_cmdref, &bae, &lo16); 150: racom->ra_ca.ca_rspl = lo16; 151: racom->ra_ca.ca_rsph = RA_OWN | bae; 152: 153: iomapadr(&racom->ra_cmd.m_cmdref, &bae, &lo16); 154: racom->ra_ca.ca_cmdl = lo16; 155: racom->ra_ca.ca_cmdh = RA_OWN | bae; 156: 157: i = csr->raip; 158: 159: mp = &racom->ra_rsp; 160: while (1) { 161: while (racom->ra_ca.ca_cmdh & RA_OWN) { 162: delay(200); /* SA access delay */ 163: if (csr->rasa & (RA_ERR|RA_SMASK)) 164: goto fail; 165: } 166: while (racom->ra_ca.ca_rsph & RA_OWN) { 167: delay(200); /* SA access delay */ 168: if (csr->rasa & (RA_ERR|RA_SMASK)) 169: goto fail; 170: } 171: racom->ra_ca.ca_cmdint = 0; 172: racom->ra_ca.ca_rspint = 0; 173: if (mp->m_opcode == (op | M_OP_END)) 174: break; 175: printf("%s rsp %x op %x ignored\n", devname(io), 176: mp->m_header.mscp_credits & 0xf0, mp->m_opcode); 177: racom->ra_ca.ca_rsph |= RA_OWN; 178: } 179: if ((mp->m_status & M_ST_MASK) != M_ST_SUCC) { 180: printf("%s err op=%x sts=%x\n", devname(io), 181: mp->m_opcode, mp->m_status); 182: return(-1); 183: } 184: return(0); 185: fail: 186: printf("%s rasa=%x\n", devname(io), csr->rasa); 187: } 188: 189: rastrategy(io, func) 190: register struct iob *io; 191: int func; 192: { 193: register struct mscp *mp; 194: struct ra *racom; 195: int bae, lo16, i; 196: 197: i = deveovchk(io); /* check for end of volume/partition */ 198: if (i <= 0) 199: return(i); 200: 201: racom = &rd[io->i_ctlr]; 202: mp = &racom->ra_cmd; 203: iomapadr(io->i_ma, &bae, &lo16); 204: mp->m_lbn_l = loint(io->i_bn); 205: mp->m_lbn_h = hiint(io->i_bn); 206: mp->m_bytecnt = io->i_cc; 207: mp->m_buf_l = lo16; 208: mp->m_buf_h = bae; 209: if (racmd(func == READ ? M_OP_READ : M_OP_WRITE, io) < 0) 210: return(-1); 211: return(io->i_cc); 212: } 213: 214: ra_step(csr, mask, step) 215: register struct radevice *csr; 216: int mask, step; 217: { 218: register int cnt; 219: 220: for (cnt = 0; (csr->rasa & mask) == 0; ) 221: { 222: delay(2000); 223: cnt++; 224: if (cnt < 5000) 225: continue; 226: printf("ra(%o) fail step %d. retrying\n",csr,step); 227: return(1); 228: } 229: return(0); 230: } 231: 232: /* 233: * This routine is called by the general 'devlabel' routine out of conf.c 234: * and is used by the standalone disklabel program to initialize the 235: * default disklabel. The MSCP driver does not need geometry info but 236: * it is almost trivial (because the drive has already been brought online by 237: * 'raopen') to fetch the required information with a 'get unit status' 238: * command. 239: */ 240: 241: ralabel(io) 242: struct iob *io; 243: { 244: register struct disklabel *lp = &io->i_label; 245: register char *cp, *dp; 246: daddr_t nblks = raonline[io->i_ctlr][io->i_unit]; 247: struct mscp *mp = &rd[io->i_ctlr].ra_rsp; 248: int nameid, numid; 249: 250: lp->d_type = DTYPE_MSCP; 251: lp->d_partitions[0].p_size = nblks; /* span the drive with 'a' */ 252: /* lp->d_secperunit = nblks; /* size of entire volume */ 253: 254: if (racmd(M_OP_GTUNT, io) != 0) 255: { 256: printf("%s GTUNT failed\n", devname(io)); 257: return(-1); 258: } 259: /* 260: * Yes it's a lot of code but since the standalone utilities (at least 'restor') 261: * are likely going to end up split I/D anyhow why not get the information. 262: * 263: * sectors/track 264: * tracks/group * group/cyl = tracks/cyl 265: * sectors/track * tracks/cyl = sectors/cyl 266: * sectors / sectors/cyl = cyl 267: */ 268: lp->d_nsectors = mp->m_track; 269: lp->d_ntracks = mp->m_group * mp->m_cylinder; 270: lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks; 271: lp->d_ncylinders = nblks / lp->d_secpercyl; 272: nameid = (((loint(mp->m_mediaid) & 0x3f) << 9) | 273: ((hiint(mp->m_mediaid) >> 7) & 0x1ff)); 274: numid = hiint(mp->m_mediaid) & 0x7f; 275: /* 276: * Next put 'RA81' or 'RD54', etc into the typename field. 277: */ 278: cp = lp->d_typename; 279: *cp++ = mx(nameid, 2); 280: *cp++ = mx(nameid, 1); 281: dp = itoa(numid); 282: while (*cp++ = *dp++) 283: ; 284: *cp = mx(nameid, 0); 285: if (*cp != ' ') 286: cp++; 287: *cp = '\0'; 288: return(0); 289: } 290: 291: /* 292: * this is a routine rather than a macro to save space - shifting, etc 293: * generates a lot of code. 294: */ 295: 296: static 297: mx(l, i) 298: int l, i; 299: { 300: register int c; 301: 302: c = (l >> (5 * i)) & 0x1f; 303: if (c == 0) 304: c = ' ' - '@'; 305: return(c + '@'); 306: }