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