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