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