1 /* vd.c 7.10 88/06/14 */ 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 /* controllers */ 21 #define NDRIVE 8 /* drives per controller */ 22 23 #define VDADDR(ctlr) ((struct vddevice *)vdaddrs[ctlr]) 24 long vdaddrs[NVD] = { 0xffff2000, 0xffff2100, 0xffff2200, 0xffff2300 }; 25 26 u_char vdinit[NVD]; /* controller initialized */ 27 u_char vdtype[NVD]; /* controller type */ 28 u_char dkconfigured[NVD][NDRIVE]; /* unit configured */ 29 u_char dkflags[NVD][NDRIVE]; /* unit flags */ 30 31 static struct disklabel dklabel[NVD][NDRIVE]; /* pack label */ 32 static struct mdcb mdcb; 33 static struct dcb dcb; 34 static char lbuf[DEV_BSIZE]; 35 36 vdopen(io) 37 register struct iob *io; 38 { 39 register int ctlr = io->i_ctlr; 40 register struct dkinfo *dk; 41 register struct disklabel *lp, *dlp; 42 int error; 43 44 if ((u_int)io->i_adapt) 45 return (EADAPT); 46 if ((u_int)ctlr >= NVD) 47 return (ECTLR); 48 if (!vdinit[ctlr] && (error = vdreset_ctlr(ctlr, io->i_unit))) 49 return (error); 50 lp = &dklabel[io->i_ctlr][io->i_unit]; 51 if (!dkconfigured[io->i_ctlr][io->i_unit]) { 52 struct iob tio; 53 54 /* 55 * Read in the pack label. 56 */ 57 lp->d_secsize = 1024; 58 lp->d_nsectors = 72; 59 lp->d_ntracks = 24; 60 lp->d_ncylinders = 711; 61 lp->d_secpercyl = 72*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 return (ERDLAB); 71 dlp = (struct disklabel *)(lbuf + LABELOFFSET); 72 if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC) 73 #ifdef COMPAT_42 74 { 75 printf("dk%d: unlabeled\n", io->i_unit); 76 if (error = vdmaptype(io)) 77 return (error); 78 } 79 #else 80 return (EUNLAB); 81 #endif 82 else { 83 *lp = *dlp; 84 if (!vdreset_drive(io)) 85 return (ENXIO); 86 } 87 dkconfigured[io->i_ctlr][io->i_unit] = 1; 88 } 89 if (io->i_part < 0 || io->i_part >= lp->d_npartitions || 90 lp->d_partitions[io->i_part].p_size == 0) 91 return (EPART); 92 io->i_boff = 93 (lp->d_partitions[io->i_part].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 = NDRIVE - 1; i >= 0; i--) 136 dkconfigured[ctlr][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 = io->i_ctlr, slave = io->i_unit; 147 register struct disklabel *lp = &dklabel[io->i_ctlr][io->i_unit]; 148 register struct vddevice *vdaddr = VDADDR(ctlr); 149 int pass = 0, type = vdtype[ctlr], error; 150 int devflags = dkflags[ctlr][slave]; /* starts with 0 */ 151 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 | devflags; 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 (struct treset) / sizeof (long); 162 dcb.trail.rstrail.nsectors = lp->d_nsectors; 163 dcb.trail.rstrail.slip_sec = lp->d_trackskew; 164 dcb.trail.rstrail.recovery = VDRF_NORMAL; 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 dkflags[ctlr][slave] = devflags; 182 return (1); 183 } 184 if (devflags == 0) { 185 devflags = VD_ESDI; 186 goto again; 187 } 188 if (type == VDTYPE_SMDE && (vdaddr->vdstatus[slave] & STA_US) == 0) { 189 printf("dk%d: nonexistent drive\n", io->i_unit); 190 return (0); 191 } 192 if ((dcb.operrsta & (DCBS_OCYL|DCBS_NRDY)) == 0) { 193 vderror(io->i_unit, "config", &dcb); 194 return (0); 195 } 196 devflags = 0; 197 if (pass++) /* give up */ 198 return (0); 199 /* 200 * Try to spin up drive with remote command. 201 */ 202 if (!vdcmd(ctlr, 0, VDOP_START, 62)) { 203 vderror(io->i_unit, "start", &dcb); 204 return (0); 205 } 206 DELAY(62000000); 207 goto again; 208 } 209 210 vdcmd(ctlr, unit, cmd, time) 211 register int ctlr; 212 int unit, cmd, time; 213 { 214 register struct vddevice *vdaddr = VDADDR(ctlr); 215 216 dcb.opcode = cmd; 217 dcb.intflg = DCBINT_NONE; 218 dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 219 dcb.operrsta = 0; 220 dcb.devselect = unit | dkflags[ctlr][unit]; 221 dcb.trailcnt = 0; 222 mdcb.mdcb_head = &dcb; 223 mdcb.mdcb_status = 0; 224 VDGO(vdaddr, (u_long)&mdcb, vdtype[ctlr]); 225 if (!vdpoll(vdaddr, &dcb, time, vdtype[ctlr])) 226 _stop(" during initialization operation.\n"); 227 return ((dcb.operrsta & VDERR_HARD) == 0); 228 } 229 230 vdstrategy(io, cmd) 231 register struct iob *io; 232 int cmd; 233 { 234 register struct disklabel *lp; 235 int ctlr, cn, tn, sn, slave, retries = 0; 236 daddr_t bn; 237 struct vddevice *vdaddr; 238 239 if (io->i_cc == 0 || io->i_cc > 65535) { 240 printf("dk%d: invalid transfer size %d\n", io->i_unit, 241 io->i_cc); 242 io->i_error = EIO; 243 return (-1); 244 } 245 lp = &dklabel[io->i_ctlr][io->i_unit]; 246 bn = io->i_bn * (DEV_BSIZE / lp->d_secsize); 247 cn = bn / lp->d_secpercyl; 248 sn = bn % lp->d_secpercyl; 249 tn = sn / lp->d_nsectors; 250 sn = sn % lp->d_nsectors; 251 252 top: 253 dcb.opcode = (cmd == READ ? VDOP_RD : VDOP_WD); 254 dcb.intflg = DCBINT_NONE; 255 dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 256 dcb.operrsta = 0; 257 ctlr = io->i_ctlr; 258 slave = io->i_unit; 259 dcb.devselect = slave | dkflags[ctlr][slave]; 260 dcb.trailcnt = sizeof (struct trrw) / sizeof (int); 261 dcb.trail.rwtrail.memadr = (u_long)io->i_ma; 262 dcb.trail.rwtrail.wcount = (io->i_cc + 1) / sizeof (short); 263 dcb.trail.rwtrail.disk.cylinder = cn; 264 dcb.trail.rwtrail.disk.track = tn; 265 dcb.trail.rwtrail.disk.sector = sn; 266 mdcb.mdcb_head = &dcb; 267 mdcb.mdcb_status = 0; 268 vdaddr = VDADDR(ctlr); 269 VDGO(vdaddr, (u_long)&mdcb, vdtype[ctlr]); 270 if (!vdpoll(vdaddr, &dcb, 60, vdtype[ctlr])) 271 _stop(" during i/o operation.\n"); 272 if (dcb.operrsta & VDERR_HARD) { 273 if (retries++ == 0 && vdreset_ctlr(ctlr, io->i_unit) == 0 && 274 vdreset_drive(io)) 275 goto top; 276 vderror(io->i_unit, cmd == READ ? "read" : "write", &dcb); 277 io->i_error = EIO; 278 return (-1); 279 } 280 mtpr(PADC, 0); 281 return (io->i_cc); 282 } 283 284 vderror(unit, cmd, dcb) 285 int unit; 286 char *cmd; 287 struct dcb *dcb; 288 { 289 290 printf("dk%d: %s error; status %b", unit, cmd, 291 dcb->operrsta, VDERRBITS); 292 if (dcb->err_code) 293 printf(", code %x", dcb->err_code); 294 printf("\n"); 295 } 296 297 /* 298 * Poll controller until operation 299 * completes or timeout expires. 300 */ 301 vdpoll(vdaddr, dcb, t, type) 302 register struct vddevice *vdaddr; 303 register struct dcb *dcb; 304 register int t, type; 305 { 306 307 t *= 1000; 308 for (;;) { 309 uncache(&dcb->operrsta); 310 if (dcb->operrsta & (DCBS_DONE|DCBS_ABORT)) 311 break; 312 if (--t <= 0) { 313 printf("vd: controller timeout"); 314 VDABORT(vdaddr, type); 315 DELAY(30000); 316 uncache(&dcb->operrsta); 317 return (0); 318 } 319 DELAY(1000); 320 } 321 if (type == VDTYPE_SMDE) { 322 for (;;) { 323 uncache(&vdaddr->vdcsr); 324 if ((vdaddr->vdcsr & CS_GO) == 0) 325 break; 326 DELAY(50); 327 } 328 DELAY(300); 329 uncache(&dcb->err_code); 330 } 331 DELAY(200); 332 uncache(&dcb->operrsta); 333 return (1); 334 } 335 336 #ifdef COMPAT_42 337 struct dkcompat { 338 int nsectors; /* sectors per track */ 339 int ntracks; /* tracks per cylinder */ 340 int ncylinders; /* cylinders per drive */ 341 int secsize; /* sector size */ 342 #define NPART 2 343 int poff[NPART]; /* [a+b] for bootstrapping */ 344 } dkcompat[] = { 345 { 64, 20, 842, 512, 0, 61440 }, /* 2361a eagle */ 346 { 48, 24, 711, 512, 0, 61056 }, /* xsd */ 347 { 44, 20, 842, 512, 0, 52800 }, /* eagle */ 348 { 64, 10, 823, 512, 0, 38400 }, /* fuji 360 */ 349 { 32, 24, 711, 512, 0, 40704 }, /* xfd */ 350 { 32, 19, 823, 512, 0, 40128 }, /* smd */ 351 { 32, 10, 823, 512, 0, 19200 }, /* fsd */ 352 { 18, 15, 1224, 1024, 0, 21600 }, /* mxd */ 353 }; 354 #define NDKCOMPAT (sizeof (dkcompat) / sizeof (dkcompat[0])) 355 356 /* 357 * Identify and configure drive from above table 358 * by trying to read the last sector until a description 359 * is found for which we're successful. 360 */ 361 vdmaptype(io) 362 struct iob *io; 363 { 364 register struct disklabel *lp = &dklabel[io->i_ctlr][io->i_unit]; 365 register struct dkcompat *dp; 366 int i, ctlr, slave, type; 367 struct vddevice *vdaddr; 368 369 ctlr = io->i_ctlr; 370 slave = io->i_unit; 371 vdaddr = VDADDR(ctlr); 372 type = vdtype[ctlr]; 373 for (dp = dkcompat; dp < &dkcompat[NDKCOMPAT]; dp++) { 374 if (type == VDTYPE_VDDC && dp->nsectors != 32) 375 continue; 376 lp->d_nsectors = dp->nsectors; 377 lp->d_ntracks = dp->ntracks; 378 lp->d_ncylinders = dp->ncylinders; 379 lp->d_secsize = dp->secsize; 380 if (!vdreset_drive(io)) /* set drive parameters */ 381 return (EIO); 382 dcb.opcode = VDOP_RD; 383 dcb.intflg = DCBINT_NONE; 384 dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 385 dcb.devselect = slave | dkflags[ctlr][slave]; 386 dcb.operrsta = 0; 387 dcb.trailcnt = sizeof (struct trrw) / sizeof (long); 388 dcb.trail.rwtrail.memadr = (u_long)lbuf; 389 dcb.trail.rwtrail.wcount = lp->d_secsize / sizeof (short); 390 dcb.trail.rwtrail.disk.cylinder = dp->ncylinders - 2; 391 dcb.trail.rwtrail.disk.track = dp->ntracks - 1; 392 dcb.trail.rwtrail.disk.sector = dp->nsectors - 1; 393 mdcb.mdcb_head = &dcb; 394 mdcb.mdcb_status = 0; 395 VDGO(vdaddr, (u_long)&mdcb, type); 396 if (!vdpoll(vdaddr, &dcb, 60, type)) 397 _stop(" during i/o operation.\n"); 398 if (dcb.operrsta & VDERR_HARD) 399 continue; 400 /* simulate necessary parts of disk label */ 401 lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks; 402 lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders; 403 lp->d_npartitions = NPART; 404 for (i = 0; i < NPART; i++) { 405 lp->d_partitions[i].p_offset = dp->poff[i]; 406 lp->d_partitions[i].p_size = 407 lp->d_secperunit - dp->poff[i]; 408 } 409 return (0); 410 } 411 printf("dk%d: unknown drive type\n", io->i_unit); 412 return (ENXIO); 413 } 414 #endif 415