1 /* vd.c 7.6 87/02/18 */ 2 3 /* 4 * Stand alone driver for the VDDC/SMDE controller 5 */ 6 #include "../machine/mtpr.h" 7 8 #include "param.h" 9 #include "inode.h" 10 #include "fs.h" 11 #include "disklabel.h" 12 #include "saio.h" 13 14 #include "../tahoevba/vdreg.h" 15 #include "../tahoevba/vbaparam.h" 16 17 #define COMPAT_42 1 18 19 #define NVD 4 20 #define NDRIVE 8 /* drives per controller */ 21 #define VDSLAVE(x) ((x) % NDRIVE) 22 #define VDCTLR(x) ((x) / NDRIVE) 23 24 #define VDADDR(ctlr) ((struct vddevice *)vdaddrs[ctlr]) 25 long vdaddrs[NVD] = { 0xffff2000, 0xffff2100, 0xffff2200, 0xffff2300 }; 26 27 u_char vdinit[NVD]; /* controller initialized */ 28 u_char vdtype[NVD]; /* controller type */ 29 u_char dkconfigured[NVD*NDRIVE]; /* unit configured */ 30 struct disklabel dklabel[NVD*NDRIVE]; /* pack label */ 31 32 struct mdcb mdcb; 33 struct dcb dcb; 34 char lbuf[DEV_BSIZE]; 35 36 vdopen(io) 37 register struct iob *io; 38 { 39 register int ctlr = VDCTLR(io->i_unit); 40 register struct dkinfo *dk; 41 register struct disklabel *lp; 42 int error; 43 44 if (ctlr >= NVD) { 45 printf("invalid controller number\n"); 46 return (ENXIO); 47 } 48 if (!vdinit[ctlr] && (error = vdreset_ctlr(ctlr, io->i_unit))) 49 return (error); 50 lp = &dklabel[io->i_unit]; 51 if (!dkconfigured[io->i_unit]) { 52 struct iob tio; 53 54 /* 55 * Read in the pack label. 56 */ 57 lp->d_secsize = 512; 58 lp->d_nsectors = 32; 59 lp->d_ntracks = 24; 60 lp->d_ncylinders = 711; 61 lp->d_secpercyl = 32*24; 62 if (!vdreset_drive(io)) 63 return (ENXIO); 64 tio = *io; 65 tio.i_bn = LABELSECTOR; 66 tio.i_ma = lbuf; 67 tio.i_cc = DEV_BSIZE; 68 tio.i_flgs |= F_RDDATA; 69 if (vdstrategy(&tio, READ) != DEV_BSIZE) { 70 printf("can't read disk label"); 71 return (EIO); 72 } 73 *lp = *(struct disklabel *)(lbuf + LABELOFFSET); 74 if (lp->d_magic != DISKMAGIC || lp->d_magic2 != DISKMAGIC) { 75 printf("dk%d: unlabeled\n", io->i_unit); 76 #ifdef COMPAT_42 77 if (error = vdmaptype(io)) 78 return (error); 79 #else 80 return (ENXIO); 81 #endif 82 } 83 if (!vdreset_drive(io)) 84 return (ENXIO); 85 dkconfigured[io->i_unit] = 1; 86 } 87 if (io->i_boff < 0 || io->i_boff >= lp->d_npartitions || 88 lp->d_partitions[io->i_boff].p_size == 0) { 89 printf("dk bad minor"); 90 return (EUNIT); 91 } 92 io->i_boff = 93 (lp->d_partitions[io->i_boff].p_offset * lp->d_secsize) / DEV_BSIZE; 94 return (0); 95 } 96 97 /* 98 * Reset and initialize the controller. 99 */ 100 vdreset_ctlr(ctlr, unit) 101 register int ctlr, unit; 102 { 103 register int i; 104 register struct vddevice *vdaddr = VDADDR(ctlr); 105 106 if (badaddr(vdaddr, 2)) { 107 printf("vd%d: %x: invalid csr\n", ctlr, vdaddr); 108 return (ENXIO); 109 } 110 /* probe further to find what kind of controller it is */ 111 vdaddr->vdreset = 0xffffffff; 112 DELAY(1000000); 113 if (vdaddr->vdreset != 0xffffffff) { 114 vdtype[ctlr] = VDTYPE_VDDC; 115 DELAY(1000000); 116 } else { 117 vdtype[ctlr] = VDTYPE_SMDE; 118 vdaddr->vdrstclr = 0; 119 DELAY(3000000); 120 vdaddr->vdcsr = 0; 121 vdaddr->vdtcf_mdcb = AM_ENPDA; 122 vdaddr->vdtcf_dcb = AM_ENPDA; 123 vdaddr->vdtcf_trail = AM_ENPDA; 124 vdaddr->vdtcf_data = AM_ENPDA; 125 vdaddr->vdccf = CCF_SEN | CCF_DER | CCF_STS | 126 XMD_32BIT | BSZ_16WRD | 127 CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR; 128 } 129 if (!vdcmd(ctlr, 0, VDOP_INIT, 10) || 130 !vdcmd(ctlr, 0, VDOP_DIAG, 10)) { 131 vderror(unit, dcb.opcode == VDOP_INIT ? "init" : "diag", &dcb); 132 return (EIO); 133 } 134 vdinit[ctlr] = 1; 135 for (i = unit = ctlr * NDRIVE; i < unit + NDRIVE; i++) 136 dkconfigured[i] = 0; 137 return (0); 138 } 139 140 /* 141 * Reset and configure a drive's parameters. 142 */ 143 vdreset_drive(io) 144 register struct iob *io; 145 { 146 register int ctlr = VDCTLR(io->i_unit), slave = VDSLAVE(io->i_unit); 147 register struct disklabel *lp; 148 register struct vddevice *vdaddr = VDADDR(ctlr); 149 int pass = 0, type = vdtype[ctlr], error; 150 151 lp = &dklabel[io->i_unit]; 152 again: 153 dcb.opcode = VDOP_CONFIG; /* command */ 154 dcb.intflg = DCBINT_NONE; 155 dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 156 dcb.operrsta = 0; 157 dcb.devselect = slave; 158 dcb.trail.rstrail.ncyl = lp->d_ncylinders; 159 dcb.trail.rstrail.nsurfaces = lp->d_ntracks; 160 if (type == VDTYPE_SMDE) { 161 dcb.trailcnt = sizeof (treset) / sizeof (long); 162 dcb.trail.rstrail.nsectors = lp->d_nsectors; 163 dcb.trail.rstrail.slip_sec = 0; /* XXX */ 164 dcb.trail.rstrail.recovery = 0x18f; /* ??? */ 165 } else 166 dcb.trailcnt = 2; /* XXX */ 167 mdcb.mdcb_head = &dcb; 168 mdcb.mdcb_status = 0; 169 VDGO(vdaddr, (u_long)&mdcb, type); 170 if (!vdpoll(vdaddr, &dcb, 10, type)) { 171 if (pass++ != 0) { 172 printf(" during drive configuration.\n"); 173 return (0); 174 } 175 VDRESET(vdaddr, type); 176 if (error = vdreset_ctlr(ctlr, io->i_unit)) 177 return (error); 178 goto again; 179 } 180 if ((dcb.operrsta & VDERR_HARD) == 0) /* success */ 181 return (1); 182 if (type == VDTYPE_SMDE && (vdaddr->vdstatus[slave] & STA_US) == 0) { 183 printf("dk%d: nonexistent drive\n", io->i_unit); 184 return (0); 185 } 186 if ((dcb.operrsta & (DCBS_OCYL|DCBS_NRDY)) == 0) { 187 vderror(io->i_unit, "config", &dcb); 188 return (0); 189 } 190 if (pass++) /* give up */ 191 return (0); 192 /* 193 * Try to spin up drive with remote command. 194 */ 195 if (!vdcmd(ctlr, 0, VDOP_START, 62)) { 196 vderror(io->i_unit, "start", &dcb); 197 return (0); 198 } 199 DELAY(62000000); 200 goto again; 201 } 202 203 vdcmd(ctlr, unit, cmd, time) 204 register int ctlr; 205 int unit, cmd, time; 206 { 207 register struct vddevice *vdaddr = VDADDR(ctlr); 208 209 dcb.opcode = cmd; 210 dcb.intflg = DCBINT_NONE; 211 dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 212 dcb.operrsta = 0; 213 dcb.devselect = unit; 214 dcb.trailcnt = 0; 215 mdcb.mdcb_head = &dcb; 216 mdcb.mdcb_status = 0; 217 VDGO(vdaddr, (u_long)&mdcb, vdtype[ctlr]); 218 if (!vdpoll(vdaddr, &dcb, time, vdtype[ctlr])) 219 _stop(" during initialization operation.\n"); 220 return ((dcb.operrsta & VDERR_HARD) == 0); 221 } 222 223 vdstrategy(io, cmd) 224 register struct iob *io; 225 int cmd; 226 { 227 register struct disklabel *lp; 228 int ctlr, cn, tn, sn; 229 daddr_t bn; 230 struct vddevice *vdaddr; 231 232 if (io->i_cc == 0 || io->i_cc > 65535) { 233 printf("dk%d: invalid transfer size %d\n", io->i_unit, 234 io->i_cc); 235 io->i_error = EIO; 236 return (-1); 237 } 238 lp = &dklabel[io->i_unit]; 239 bn = io->i_bn * (DEV_BSIZE / lp->d_secsize); 240 cn = bn / lp->d_secpercyl; 241 sn = bn % lp->d_secpercyl; 242 tn = sn / lp->d_nsectors; 243 sn = sn % lp->d_nsectors; 244 245 dcb.opcode = (cmd == READ ? VDOP_RD : VDOP_WD); 246 dcb.intflg = DCBINT_NONE; 247 dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 248 dcb.operrsta = 0; 249 dcb.devselect = VDSLAVE(io->i_unit); 250 dcb.trailcnt = sizeof (trrw) / sizeof (int); 251 dcb.trail.rwtrail.memadr = io->i_ma; 252 dcb.trail.rwtrail.wcount = (io->i_cc + 1) / sizeof (short); 253 dcb.trail.rwtrail.disk.cylinder = cn; 254 dcb.trail.rwtrail.disk.track = tn; 255 dcb.trail.rwtrail.disk.sector = sn; 256 mdcb.mdcb_head = &dcb; 257 mdcb.mdcb_status = 0; 258 ctlr = VDCTLR(io->i_unit); 259 vdaddr = VDADDR(ctlr); 260 VDGO(vdaddr, (u_long)&mdcb, vdtype[ctlr]); 261 if (!vdpoll(vdaddr, &dcb, 60, vdtype[ctlr])) 262 _stop(" during i/o operation.\n"); 263 if (dcb.operrsta & VDERR_HARD) { 264 vderror(io->i_unit, cmd == READ ? "read" : "write", &dcb); 265 io->i_error = EIO; 266 return (-1); 267 } 268 mtpr(PADC, 0); 269 return (io->i_cc); 270 } 271 272 vderror(unit, cmd, dcb) 273 int unit; 274 char *cmd; 275 struct dcb *dcb; 276 { 277 278 printf("dk%d: %s error; status %b", unit, cmd, 279 dcb->operrsta, VDERRBITS); 280 if (dcb->err_code) 281 printf(", code %x", dcb->err_code); 282 printf("\n"); 283 } 284 285 /* 286 * Poll controller until operation 287 * completes or timeout expires. 288 */ 289 vdpoll(vdaddr, dcb, t, type) 290 register struct vddevice *vdaddr; 291 register struct dcb *dcb; 292 register int t, type; 293 { 294 295 t *= 1000; 296 for (;;) { 297 uncache(&dcb->operrsta); 298 if (dcb->operrsta & (DCBS_DONE|DCBS_ABORT)) 299 break; 300 if (--t <= 0) { 301 printf("vd: controller timeout"); 302 VDABORT(vdaddr, type); 303 DELAY(30000); 304 uncache(&dcb->operrsta); 305 return (0); 306 } 307 DELAY(1000); 308 } 309 if (type == VDTYPE_SMDE) { 310 for (;;) { 311 uncache(&vdaddr->vdcsr); 312 if ((vdaddr->vdcsr & CS_GO) == 0) 313 break; 314 DELAY(50); 315 } 316 DELAY(300); 317 uncache(&dcb->err_code); 318 } 319 DELAY(200); 320 uncache(&dcb->operrsta); 321 return (1); 322 } 323 324 #ifdef COMPAT_42 325 struct dkcompat { 326 int nsectors; /* sectors per track */ 327 int ntracks; /* tracks per cylinder */ 328 int ncylinders; /* cylinders per drive */ 329 #define NPART 2 330 int poff[NPART]; /* [a+b] for bootstrapping */ 331 } dkcompat[] = { 332 { 48, 24, 711, 0, 61056 }, /* xsd */ 333 { 44, 20, 842, 0, 52800 }, /* eagle */ 334 { 64, 10, 823, 0, 38400 }, /* fuji 360 */ 335 { 32, 24, 711, 0, 40704 }, /* xfd */ 336 { 32, 19, 823, 0, 40128 }, /* smd */ 337 { 32, 10, 823, 0, 19200 }, /* fsd */ 338 }; 339 #define NDKCOMPAT (sizeof (dkcompat) / sizeof (dkcompat[0])) 340 341 /* 342 * Identify and configure drive from above table 343 * by trying to read the last sector until a description 344 * is found for which we're successful. 345 */ 346 vdmaptype(io) 347 struct iob *io; 348 { 349 register struct disklabel *lp = &dklabel[io->i_unit]; 350 register struct dkcompat *dp; 351 int i, ctlr, type; 352 struct vddevice *vdaddr; 353 354 ctlr = VDCTLR(io->i_unit); 355 vdaddr = VDADDR(ctlr); 356 type = vdtype[ctlr]; 357 for (dp = dkcompat; dp < &dkcompat[NDKCOMPAT]; dp++) { 358 if (type == VDTYPE_VDDC && dp->nsectors != 32) 359 continue; 360 lp->d_nsectors = dp->nsectors; 361 lp->d_ntracks = dp->ntracks; 362 lp->d_ncylinders = dp->ncylinders; 363 if (!vdreset_drive(io)) /* set drive parameters */ 364 return (EIO); 365 dcb.opcode = VDOP_RD; 366 dcb.intflg = DCBINT_NONE; 367 dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 368 dcb.devselect = VDSLAVE(io->i_unit); 369 dcb.operrsta = 0; 370 dcb.trailcnt = sizeof (trrw) / sizeof (long); 371 dcb.trail.rwtrail.memadr = lbuf; 372 dcb.trail.rwtrail.wcount = sizeof (lbuf) / sizeof (short); 373 dcb.trail.rwtrail.disk.cylinder = dp->ncylinders - 2; 374 dcb.trail.rwtrail.disk.track = dp->ntracks - 1; 375 dcb.trail.rwtrail.disk.sector = dp->nsectors - 1; 376 mdcb.mdcb_head = &dcb; 377 mdcb.mdcb_status = 0; 378 VDGO(vdaddr, (u_long)&mdcb, type); 379 if (!vdpoll(vdaddr, &dcb, 60, type)) 380 _stop(" during i/o operation.\n"); 381 if (dcb.operrsta & VDERR_HARD) 382 continue; 383 /* simulate necessary parts of disk label */ 384 lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks; 385 lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders; 386 lp->d_npartitions = NPART; 387 for (i = 0; i < NPART; i++) { 388 lp->d_partitions[i].p_offset = dp->poff[i]; 389 lp->d_partitions[i].p_size = 390 lp->d_secperunit - dp->poff[i]; 391 } 392 return (0); 393 } 394 printf("dk%d: unknown drive type\n", io->i_unit); 395 return (ENXIO); 396 } 397 #endif 398