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