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