1 /* $NetBSD: hp.c,v 1.12 1996/10/13 03:34:58 christos 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 55 #include <machine/trap.h> 56 #include <machine/pte.h> 57 #include <machine/mtpr.h> 58 #include <machine/cpu.h> 59 60 #include <vax/mba/mbavar.h> 61 #include <vax/mba/mbareg.h> 62 #include <vax/mba/hpreg.h> 63 64 #define HPMASK 0xffff 65 66 struct hp_softc { 67 struct device sc_dev; 68 struct disk sc_disk; 69 struct mba_device sc_md; /* Common struct used by mbaqueue. */ 70 int sc_wlabel; /* Disklabel area is writable */ 71 int sc_physnr; /* Physical disk number */ 72 }; 73 74 int hpmatch __P((struct device *, void *, void *)); 75 void hpattach __P((struct device *, struct device *, void *)); 76 void hpstrategy __P((struct buf *)); 77 void hpstart __P((struct mba_device *)); 78 int hpattn __P((struct mba_device *)); 79 enum xfer_action hpfinish __P((struct mba_device *, int, int *)); 80 int hpopen __P((dev_t, int, int)); 81 int hpclose __P((dev_t, int, int)); 82 int hpioctl __P((dev_t, u_long, caddr_t, int, struct proc *)); 83 int hpdump __P((dev_t, caddr_t, caddr_t, size_t)); 84 int hpread __P((dev_t, struct uio *)); 85 int hpwrite __P((dev_t, struct uio *)); 86 int hpsize __P((dev_t)); 87 88 struct cfdriver hp_cd = { 89 NULL, "hp", DV_DISK 90 }; 91 92 struct cfattach hp_ca = { 93 sizeof(struct hp_softc), hpmatch, hpattach 94 }; 95 96 /* 97 * Check if this is a disk drive; done by checking type from mbaattach. 98 */ 99 int 100 hpmatch(parent, match, aux) 101 struct device *parent; 102 void *match, *aux; 103 { 104 struct cfdata *cf = match; 105 struct mba_attach_args *ma = aux; 106 107 if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != ma->unit) 108 return 0; 109 110 if (ma->devtyp != MB_RP) 111 return 0; 112 113 return 1; 114 } 115 116 /* 117 * Disk drive found; fake a disklabel and try to read the real one. 118 * If the on-disk label can't be read; we lose. 119 */ 120 void 121 hpattach(parent, self, aux) 122 struct device *parent, *self; 123 void *aux; 124 { 125 struct hp_softc *sc = (void *)self; 126 struct mba_softc *ms = (void *)parent; 127 struct disklabel *dl; 128 struct mba_attach_args *ma = aux; 129 char *msg; 130 131 /* 132 * Init the common struct for both the adapter and its slaves. 133 */ 134 sc->sc_md.md_softc = (void *)sc; /* Pointer to this softc */ 135 sc->sc_md.md_mba = (void *)parent; /* Pointer to parent softc */ 136 sc->sc_md.md_start = hpstart; /* Disk start routine */ 137 sc->sc_md.md_attn = hpattn; /* Disk attention routine */ 138 sc->sc_md.md_finish = hpfinish; /* Disk xfer finish routine */ 139 140 ms->sc_md[ma->unit] = &sc->sc_md; /* Per-unit backpointer */ 141 142 sc->sc_physnr = ma->unit; 143 /* 144 * Init and attach the disk structure. 145 */ 146 sc->sc_disk.dk_name = sc->sc_dev.dv_xname; 147 disk_attach(&sc->sc_disk); 148 149 /* 150 * Fake a disklabel to be able to read in the real label. 151 */ 152 dl = sc->sc_disk.dk_label; 153 154 dl->d_secsize = DEV_BSIZE; 155 dl->d_ntracks = 1; 156 dl->d_nsectors = 32; 157 dl->d_secpercyl = 32; 158 159 /* 160 * Read in label. 161 */ 162 if ((msg = readdisklabel(makedev(0, self->dv_unit * 8), hpstrategy, 163 dl, NULL)) != NULL) 164 printf(": %s", msg); 165 printf(": %s, size = %d sectors\n", dl->d_typename, dl->d_secperunit); 166 } 167 168 169 void 170 hpstrategy(bp) 171 struct buf *bp; 172 { 173 struct hp_softc *sc; 174 struct buf *gp; 175 int unit, s; 176 177 unit = DISKUNIT(bp->b_dev); 178 sc = hp_cd.cd_devs[unit]; 179 180 if (bounds_check_with_label(bp, sc->sc_disk.dk_label, sc->sc_wlabel) 181 <= 0) 182 goto done; 183 s = splbio(); 184 185 gp = sc->sc_md.md_q.b_actf; 186 disksort(&sc->sc_md.md_q, bp); 187 if (gp == 0) 188 mbaqueue(&sc->sc_md); 189 190 splx(s); 191 return; 192 193 done: 194 bp->b_resid = bp->b_bcount; 195 biodone(bp); 196 } 197 198 /* 199 * Start transfer on given disk. Called from mbastart(). 200 */ 201 void 202 hpstart(md) 203 struct mba_device *md; 204 { 205 struct hp_softc *sc = md->md_softc; 206 struct mba_regs *mr = md->md_mba->sc_mbareg; 207 volatile struct hp_regs *hr; 208 struct disklabel *lp = sc->sc_disk.dk_label; 209 struct buf *bp = md->md_q.b_actf; 210 unsigned bn, cn, sn, tn; 211 int part = DISKPART(bp->b_dev); 212 213 /* 214 * Collect statistics. 215 */ 216 disk_busy(&sc->sc_disk); 217 sc->sc_disk.dk_seek++; 218 219 hr = (void *)&mr->mba_md[DISKUNIT(bp->b_dev)]; 220 221 bn = bp->b_blkno + lp->d_partitions[part].p_offset; 222 if (bn) { 223 cn = bn / lp->d_secpercyl; 224 sn = bn % lp->d_secpercyl; 225 tn = sn / lp->d_nsectors; 226 sn = sn % lp->d_nsectors; 227 } else 228 cn = sn = tn = 0; 229 230 hr->hp_dc = cn; 231 hr->hp_da = (tn << 8) | sn; 232 if (bp->b_flags & B_READ) 233 hr->hp_cs1 = HPCS_READ; /* GO */ 234 else 235 hr->hp_cs1 = HPCS_WRITE; 236 } 237 238 int 239 hpopen(dev, flag, fmt) 240 dev_t dev; 241 int flag, fmt; 242 { 243 struct hp_softc *sc; 244 int unit, part; 245 246 unit = DISKUNIT(dev); 247 if (unit >= hp_cd.cd_ndevs) 248 return ENXIO; 249 sc = hp_cd.cd_devs[unit]; 250 if (sc == 0) 251 return ENXIO; 252 253 part = DISKPART(dev); 254 255 if (part >= sc->sc_disk.dk_label->d_npartitions) 256 return ENXIO; 257 258 switch (fmt) { 259 case S_IFCHR: 260 sc->sc_disk.dk_copenmask |= (1 << part); 261 break; 262 263 case S_IFBLK: 264 sc->sc_disk.dk_bopenmask |= (1 << part); 265 break; 266 } 267 sc->sc_disk.dk_openmask = 268 sc->sc_disk.dk_copenmask | sc->sc_disk.dk_bopenmask; 269 270 return 0; 271 } 272 273 int 274 hpclose(dev, flag, fmt) 275 dev_t dev; 276 int flag, fmt; 277 { 278 struct hp_softc *sc; 279 int unit, part; 280 281 unit = DISKUNIT(dev); 282 sc = hp_cd.cd_devs[unit]; 283 284 part = DISKPART(dev); 285 286 switch (fmt) { 287 case S_IFCHR: 288 sc->sc_disk.dk_copenmask &= ~(1 << part); 289 break; 290 291 case S_IFBLK: 292 sc->sc_disk.dk_bopenmask &= ~(1 << part); 293 break; 294 } 295 sc->sc_disk.dk_openmask = 296 sc->sc_disk.dk_copenmask | sc->sc_disk.dk_bopenmask; 297 298 return 0; 299 } 300 301 int 302 hpioctl(dev, cmd, addr, flag, p) 303 dev_t dev; 304 u_long cmd; 305 caddr_t addr; 306 int flag; 307 struct proc *p; 308 { 309 struct hp_softc *sc = hp_cd.cd_devs[DISKUNIT(dev)]; 310 struct disklabel *lp = sc->sc_disk.dk_label; 311 int error; 312 313 switch (cmd) { 314 case DIOCGDINFO: 315 bcopy(lp, addr, sizeof (struct disklabel)); 316 return 0; 317 318 case DIOCGPART: 319 ((struct partinfo *)addr)->disklab = lp; 320 ((struct partinfo *)addr)->part = 321 &lp->d_partitions[DISKPART(dev)]; 322 break; 323 324 case DIOCSDINFO: 325 if ((flag & FWRITE) == 0) 326 return EBADF; 327 328 return setdisklabel(lp, (struct disklabel *)addr, 0, 0); 329 330 case DIOCWDINFO: 331 if ((flag & FWRITE) == 0) 332 error = EBADF; 333 else { 334 sc->sc_wlabel = 1; 335 error = writedisklabel(dev, hpstrategy, lp, 0); 336 sc->sc_wlabel = 0; 337 } 338 return error; 339 case DIOCWLABEL: 340 if ((flag & FWRITE) == 0) 341 return EBADF; 342 sc->sc_wlabel = 1; 343 break; 344 345 default: 346 printf("hpioctl: command %x\n", (unsigned int)cmd); 347 return ENOTTY; 348 } 349 return 0; 350 } 351 352 /* 353 * Called when a transfer is finished. Check if transfer went OK, 354 * Return info about what-to-do-now. 355 */ 356 enum xfer_action 357 hpfinish(md, mbasr, attn) 358 struct mba_device *md; 359 int mbasr, *attn; 360 { 361 struct hp_softc *sc = md->md_softc; 362 struct buf *bp = md->md_q.b_actf; 363 volatile struct mba_regs *mr = md->md_mba->sc_mbareg; 364 volatile struct hp_regs *hr = (void *)&mr->mba_md[DISKUNIT(bp->b_dev)]; 365 int er1, er2; 366 volatile int bc; /* to get GCC read whole longword */ 367 unsigned byte; 368 369 er1 = hr->hp_er1 & HPMASK; 370 er2 = hr->hp_er2 & HPMASK; 371 hr->hp_er1 = hr->hp_er2 = 0; 372 hper1: 373 switch (ffs(er1) - 1) { 374 case -1: 375 hr->hp_er1 = 0; 376 goto hper2; 377 378 case HPER1_DCK: /* Corrected? data read. Just notice. */ 379 bc = mr->mba_bc; 380 byte = ~(bc >> 16); 381 diskerr(buf, hp_cd.cd_name, "soft ecc", LOG_PRINTF, 382 btodb(bp->b_bcount - byte), sc->sc_disk.dk_label); 383 er1 &= ~(1<<HPER1_DCK); 384 er1 &= HPMASK; 385 break; 386 387 default: 388 printf("drive error :%s er1 %x er2 %x\n", 389 sc->sc_dev.dv_xname, er1, er2); 390 hr->hp_er1 = hr->hp_er2 = 0; 391 goto hper2; 392 } 393 goto hper1; 394 395 hper2: 396 mbasr &= ~(MBASR_DTBUSY|MBASR_DTCMP|MBASR_ATTN); 397 if (mbasr) 398 printf("massbuss error :%s %x\n", 399 sc->sc_dev.dv_xname, mbasr); 400 401 md->md_q.b_actf->b_resid = 0; 402 disk_unbusy(&sc->sc_disk, md->md_q.b_actf->b_bcount); 403 return XFER_FINISH; 404 } 405 406 /* 407 * Non-data transfer interrupt; like volume change. 408 */ 409 int 410 hpattn(md) 411 struct mba_device *md; 412 { 413 struct hp_softc *sc = md->md_softc; 414 struct mba_softc *ms = (void *)sc->sc_dev.dv_parent; 415 struct mba_regs *mr = ms->sc_mbareg; 416 struct hp_regs *hr = (void *)&mr->mba_md[sc->sc_dev.dv_unit]; 417 int er1, er2; 418 419 er1 = hr->hp_er1 & HPMASK; 420 er2 = hr->hp_er2 & HPMASK; 421 422 printf("%s: Attention! er1 %x er2 %x\n", 423 sc->sc_dev.dv_xname, er1, er2); 424 return 0; 425 } 426 427 428 int 429 hpsize(dev) 430 dev_t dev; 431 { 432 int size, unit = DISKUNIT(dev); 433 struct hp_softc *sc; 434 435 if (unit >= hp_cd.cd_ndevs || hp_cd.cd_devs[unit] == 0) 436 return -1; 437 438 sc = hp_cd.cd_devs[unit]; 439 size = sc->sc_disk.dk_label->d_partitions[DISKPART(dev)].p_size; 440 441 return size; 442 } 443 444 int 445 hpdump(dev, a1, a2, size) 446 dev_t dev; 447 caddr_t a1, a2; 448 size_t size; 449 { 450 printf("hpdump: Not implemented yet.\n"); 451 return 0; 452 } 453 454 int 455 hpread(dev, uio) 456 dev_t dev; 457 struct uio *uio; 458 { 459 return (physio(hpstrategy, NULL, dev, B_READ, minphys, uio)); 460 } 461 462 int 463 hpwrite(dev, uio) 464 dev_t dev; 465 struct uio *uio; 466 { 467 return (physio(hpstrategy, NULL, dev, B_WRITE, minphys, uio)); 468 } 469 470 /* 471 * Convert physical adapternr and unit to the unit number used by kernel. 472 */ 473 int 474 hp_getdev(mbanr, unit, uname) 475 int mbanr, unit; 476 char **uname; 477 { 478 struct mba_softc *ms; 479 struct hp_softc *sc; 480 int i; 481 482 for (i = 0; i < hp_cd.cd_ndevs; i++) { 483 if (hp_cd.cd_devs[i] == 0) 484 continue; 485 486 sc = hp_cd.cd_devs[i]; 487 ms = (void *)sc->sc_dev.dv_parent; 488 if (ms->sc_physnr == mbanr && sc->sc_physnr == unit) { 489 *uname = sc->sc_dev.dv_xname; 490 return i; 491 } 492 } 493 return -1; 494 } 495 496