1 /* $NetBSD: hp.c,v 1.15 1997/06/24 01:09:37 thorpej Exp $ */ 2 /* 3 * Copyright (c) 1996 Ludd, University of Lule}, Sweden. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed at Ludd, University of 17 * Lule}, Sweden and its contributors. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * Simple device driver routine for massbuss disks. 35 * TODO: 36 * Fix support for Standard DEC BAD144 bad block forwarding. 37 * Be able to to handle soft/hard transfer errors. 38 * Handle non-data transfer interrupts. 39 * Autoconfiguration of disk drives 'on the fly'. 40 * Handle disk media changes. 41 * Dual-port operations should be supported. 42 */ 43 #include <sys/param.h> 44 #include <sys/systm.h> 45 #include <sys/device.h> 46 #include <sys/disklabel.h> 47 #include <sys/disk.h> 48 #include <sys/dkio.h> 49 #include <sys/buf.h> 50 #include <sys/stat.h> 51 #include <sys/ioccom.h> 52 #include <sys/fcntl.h> 53 #include <sys/syslog.h> 54 #include <sys/reboot.h> 55 56 #include <machine/trap.h> 57 #include <machine/pte.h> 58 #include <machine/mtpr.h> 59 #include <machine/cpu.h> 60 #include <machine/rpb.h> 61 62 #include <vax/mba/mbavar.h> 63 #include <vax/mba/mbareg.h> 64 #include <vax/mba/hpreg.h> 65 66 #define HPMASK 0xffff 67 68 struct hp_softc { 69 struct device sc_dev; 70 struct disk sc_disk; 71 struct mba_device sc_md; /* Common struct used by mbaqueue. */ 72 int sc_wlabel; /* Disklabel area is writable */ 73 int sc_physnr; /* Physical disk number */ 74 }; 75 76 int hpmatch __P((struct device *, void *, void *)); 77 void hpattach __P((struct device *, struct device *, void *)); 78 void hpstrategy __P((struct buf *)); 79 void hpstart __P((struct mba_device *)); 80 int hpattn __P((struct mba_device *)); 81 enum xfer_action hpfinish __P((struct mba_device *, int, int *)); 82 int hpopen __P((dev_t, int, int)); 83 int hpclose __P((dev_t, int, int)); 84 int hpioctl __P((dev_t, u_long, caddr_t, int, struct proc *)); 85 int hpdump __P((dev_t, caddr_t, caddr_t, size_t)); 86 int hpread __P((dev_t, struct uio *)); 87 int hpwrite __P((dev_t, struct uio *)); 88 int hpsize __P((dev_t)); 89 90 struct cfdriver hp_cd = { 91 NULL, "hp", DV_DISK 92 }; 93 94 struct cfattach hp_ca = { 95 sizeof(struct hp_softc), hpmatch, hpattach 96 }; 97 98 /* 99 * Check if this is a disk drive; done by checking type from mbaattach. 100 */ 101 int 102 hpmatch(parent, match, aux) 103 struct device *parent; 104 void *match, *aux; 105 { 106 struct cfdata *cf = match; 107 struct mba_attach_args *ma = aux; 108 109 if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != ma->unit) 110 return 0; 111 112 if (ma->devtyp != MB_RP) 113 return 0; 114 115 return 1; 116 } 117 118 /* 119 * Disk drive found; fake a disklabel and try to read the real one. 120 * If the on-disk label can't be read; we lose. 121 */ 122 void 123 hpattach(parent, self, aux) 124 struct device *parent, *self; 125 void *aux; 126 { 127 struct hp_softc *sc = (void *)self; 128 struct mba_softc *ms = (void *)parent; 129 struct disklabel *dl; 130 struct mba_attach_args *ma = aux; 131 char *msg; 132 133 /* 134 * Init the common struct for both the adapter and its slaves. 135 */ 136 sc->sc_md.md_softc = (void *)sc; /* Pointer to this softc */ 137 sc->sc_md.md_mba = (void *)parent; /* Pointer to parent softc */ 138 sc->sc_md.md_start = hpstart; /* Disk start routine */ 139 sc->sc_md.md_attn = hpattn; /* Disk attention routine */ 140 sc->sc_md.md_finish = hpfinish; /* Disk xfer finish routine */ 141 142 ms->sc_md[ma->unit] = &sc->sc_md; /* Per-unit backpointer */ 143 144 sc->sc_physnr = ma->unit; 145 /* 146 * Init and attach the disk structure. 147 */ 148 sc->sc_disk.dk_name = sc->sc_dev.dv_xname; 149 disk_attach(&sc->sc_disk); 150 151 /* 152 * Fake a disklabel to be able to read in the real label. 153 */ 154 dl = sc->sc_disk.dk_label; 155 156 dl->d_secsize = DEV_BSIZE; 157 dl->d_ntracks = 1; 158 dl->d_nsectors = 32; 159 dl->d_secpercyl = 32; 160 161 /* 162 * Read in label. 163 */ 164 if ((msg = readdisklabel(makedev(0, self->dv_unit * 8), hpstrategy, 165 dl, NULL)) != NULL) 166 printf(": %s", msg); 167 printf(": %s, size = %d sectors\n", dl->d_typename, dl->d_secperunit); 168 /* 169 * check if this was what we booted from. 170 */ 171 if ((B_TYPE(bootdev) == BDEV_HP) && (ma->unit == B_UNIT(bootdev)) && 172 (ms->sc_physnr == B_ADAPTOR(bootdev))) 173 booted_from = self; 174 } 175 176 177 void 178 hpstrategy(bp) 179 struct buf *bp; 180 { 181 struct hp_softc *sc; 182 struct buf *gp; 183 int unit, s; 184 185 unit = DISKUNIT(bp->b_dev); 186 sc = hp_cd.cd_devs[unit]; 187 188 if (bounds_check_with_label(bp, sc->sc_disk.dk_label, sc->sc_wlabel) 189 <= 0) 190 goto done; 191 s = splbio(); 192 193 gp = sc->sc_md.md_q.b_actf; 194 disksort(&sc->sc_md.md_q, bp); 195 if (gp == 0) 196 mbaqueue(&sc->sc_md); 197 198 splx(s); 199 return; 200 201 done: 202 bp->b_resid = bp->b_bcount; 203 biodone(bp); 204 } 205 206 /* 207 * Start transfer on given disk. Called from mbastart(). 208 */ 209 void 210 hpstart(md) 211 struct mba_device *md; 212 { 213 struct hp_softc *sc = md->md_softc; 214 struct mba_regs *mr = md->md_mba->sc_mbareg; 215 volatile struct hp_regs *hr; 216 struct disklabel *lp = sc->sc_disk.dk_label; 217 struct buf *bp = md->md_q.b_actf; 218 unsigned bn, cn, sn, tn; 219 int part = DISKPART(bp->b_dev); 220 221 /* 222 * Collect statistics. 223 */ 224 disk_busy(&sc->sc_disk); 225 sc->sc_disk.dk_seek++; 226 227 hr = (void *)&mr->mba_md[DISKUNIT(bp->b_dev)]; 228 229 bn = bp->b_blkno + lp->d_partitions[part].p_offset; 230 if (bn) { 231 cn = bn / lp->d_secpercyl; 232 sn = bn % lp->d_secpercyl; 233 tn = sn / lp->d_nsectors; 234 sn = sn % lp->d_nsectors; 235 } else 236 cn = sn = tn = 0; 237 238 hr->hp_dc = cn; 239 hr->hp_da = (tn << 8) | sn; 240 if (bp->b_flags & B_READ) 241 hr->hp_cs1 = HPCS_READ; /* GO */ 242 else 243 hr->hp_cs1 = HPCS_WRITE; 244 } 245 246 int 247 hpopen(dev, flag, fmt) 248 dev_t dev; 249 int flag, fmt; 250 { 251 struct hp_softc *sc; 252 int unit, part; 253 254 unit = DISKUNIT(dev); 255 if (unit >= hp_cd.cd_ndevs) 256 return ENXIO; 257 sc = hp_cd.cd_devs[unit]; 258 if (sc == 0) 259 return ENXIO; 260 261 part = DISKPART(dev); 262 263 if (part >= sc->sc_disk.dk_label->d_npartitions) 264 return ENXIO; 265 266 switch (fmt) { 267 case S_IFCHR: 268 sc->sc_disk.dk_copenmask |= (1 << part); 269 break; 270 271 case S_IFBLK: 272 sc->sc_disk.dk_bopenmask |= (1 << part); 273 break; 274 } 275 sc->sc_disk.dk_openmask = 276 sc->sc_disk.dk_copenmask | sc->sc_disk.dk_bopenmask; 277 278 return 0; 279 } 280 281 int 282 hpclose(dev, flag, fmt) 283 dev_t dev; 284 int flag, fmt; 285 { 286 struct hp_softc *sc; 287 int unit, part; 288 289 unit = DISKUNIT(dev); 290 sc = hp_cd.cd_devs[unit]; 291 292 part = DISKPART(dev); 293 294 switch (fmt) { 295 case S_IFCHR: 296 sc->sc_disk.dk_copenmask &= ~(1 << part); 297 break; 298 299 case S_IFBLK: 300 sc->sc_disk.dk_bopenmask &= ~(1 << part); 301 break; 302 } 303 sc->sc_disk.dk_openmask = 304 sc->sc_disk.dk_copenmask | sc->sc_disk.dk_bopenmask; 305 306 return 0; 307 } 308 309 int 310 hpioctl(dev, cmd, addr, flag, p) 311 dev_t dev; 312 u_long cmd; 313 caddr_t addr; 314 int flag; 315 struct proc *p; 316 { 317 struct hp_softc *sc = hp_cd.cd_devs[DISKUNIT(dev)]; 318 struct disklabel *lp = sc->sc_disk.dk_label; 319 int error; 320 321 switch (cmd) { 322 case DIOCGDINFO: 323 bcopy(lp, addr, sizeof (struct disklabel)); 324 return 0; 325 326 case DIOCGPART: 327 ((struct partinfo *)addr)->disklab = lp; 328 ((struct partinfo *)addr)->part = 329 &lp->d_partitions[DISKPART(dev)]; 330 break; 331 332 case DIOCSDINFO: 333 if ((flag & FWRITE) == 0) 334 return EBADF; 335 336 return setdisklabel(lp, (struct disklabel *)addr, 0, 0); 337 338 case DIOCWDINFO: 339 if ((flag & FWRITE) == 0) 340 error = EBADF; 341 else { 342 sc->sc_wlabel = 1; 343 error = writedisklabel(dev, hpstrategy, lp, 0); 344 sc->sc_wlabel = 0; 345 } 346 return error; 347 case DIOCWLABEL: 348 if ((flag & FWRITE) == 0) 349 return EBADF; 350 sc->sc_wlabel = 1; 351 break; 352 353 default: 354 printf("hpioctl: command %x\n", (unsigned int)cmd); 355 return ENOTTY; 356 } 357 return 0; 358 } 359 360 /* 361 * Called when a transfer is finished. Check if transfer went OK, 362 * Return info about what-to-do-now. 363 */ 364 enum xfer_action 365 hpfinish(md, mbasr, attn) 366 struct mba_device *md; 367 int mbasr, *attn; 368 { 369 struct hp_softc *sc = md->md_softc; 370 struct buf *bp = md->md_q.b_actf; 371 volatile struct mba_regs *mr = md->md_mba->sc_mbareg; 372 volatile struct hp_regs *hr = (void *)&mr->mba_md[DISKUNIT(bp->b_dev)]; 373 int er1, er2; 374 volatile int bc; /* to get GCC read whole longword */ 375 unsigned byte; 376 377 er1 = hr->hp_er1 & HPMASK; 378 er2 = hr->hp_er2 & HPMASK; 379 hr->hp_er1 = hr->hp_er2 = 0; 380 hper1: 381 switch (ffs(er1) - 1) { 382 case -1: 383 hr->hp_er1 = 0; 384 goto hper2; 385 386 case HPER1_DCK: /* Corrected? data read. Just notice. */ 387 bc = mr->mba_bc; 388 byte = ~(bc >> 16); 389 diskerr(buf, hp_cd.cd_name, "soft ecc", LOG_PRINTF, 390 btodb(bp->b_bcount - byte), sc->sc_disk.dk_label); 391 er1 &= ~(1<<HPER1_DCK); 392 er1 &= HPMASK; 393 break; 394 395 default: 396 printf("drive error :%s er1 %x er2 %x\n", 397 sc->sc_dev.dv_xname, er1, er2); 398 hr->hp_er1 = hr->hp_er2 = 0; 399 goto hper2; 400 } 401 goto hper1; 402 403 hper2: 404 mbasr &= ~(MBASR_DTBUSY|MBASR_DTCMP|MBASR_ATTN); 405 if (mbasr) 406 printf("massbuss error :%s %x\n", 407 sc->sc_dev.dv_xname, mbasr); 408 409 md->md_q.b_actf->b_resid = 0; 410 disk_unbusy(&sc->sc_disk, md->md_q.b_actf->b_bcount); 411 return XFER_FINISH; 412 } 413 414 /* 415 * Non-data transfer interrupt; like volume change. 416 */ 417 int 418 hpattn(md) 419 struct mba_device *md; 420 { 421 struct hp_softc *sc = md->md_softc; 422 struct mba_softc *ms = (void *)sc->sc_dev.dv_parent; 423 struct mba_regs *mr = ms->sc_mbareg; 424 struct hp_regs *hr = (void *)&mr->mba_md[sc->sc_dev.dv_unit]; 425 int er1, er2; 426 427 er1 = hr->hp_er1 & HPMASK; 428 er2 = hr->hp_er2 & HPMASK; 429 430 printf("%s: Attention! er1 %x er2 %x\n", 431 sc->sc_dev.dv_xname, er1, er2); 432 return 0; 433 } 434 435 436 int 437 hpsize(dev) 438 dev_t dev; 439 { 440 int size, unit = DISKUNIT(dev); 441 struct hp_softc *sc; 442 443 if (unit >= hp_cd.cd_ndevs || hp_cd.cd_devs[unit] == 0) 444 return -1; 445 446 sc = hp_cd.cd_devs[unit]; 447 size = sc->sc_disk.dk_label->d_partitions[DISKPART(dev)].p_size * 448 (sc->sc_disk.dk_label->d_secsize / DEV_BSIZE); 449 450 return size; 451 } 452 453 int 454 hpdump(dev, a1, a2, size) 455 dev_t dev; 456 caddr_t a1, a2; 457 size_t size; 458 { 459 printf("hpdump: Not implemented yet.\n"); 460 return 0; 461 } 462 463 int 464 hpread(dev, uio) 465 dev_t dev; 466 struct uio *uio; 467 { 468 return (physio(hpstrategy, NULL, dev, B_READ, minphys, uio)); 469 } 470 471 int 472 hpwrite(dev, uio) 473 dev_t dev; 474 struct uio *uio; 475 { 476 return (physio(hpstrategy, NULL, dev, B_WRITE, minphys, uio)); 477 } 478