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