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