1 /* $NetBSD: hp.c,v 1.52 2014/12/31 20:37:52 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 44 #include <sys/cdefs.h> 45 __KERNEL_RCSID(0, "$NetBSD: hp.c,v 1.52 2014/12/31 20:37:52 christos Exp $"); 46 47 #include <sys/param.h> 48 #include <sys/systm.h> 49 #include <sys/bus.h> 50 #include <sys/cpu.h> 51 #include <sys/device.h> 52 #include <sys/disklabel.h> 53 #include <sys/disk.h> 54 #include <sys/dkio.h> 55 #include <sys/buf.h> 56 #include <sys/bufq.h> 57 #include <sys/stat.h> 58 #include <sys/ioccom.h> 59 #include <sys/fcntl.h> 60 #include <sys/conf.h> 61 #include <sys/event.h> 62 #include <sys/syslog.h> 63 64 #include <vax/mba/mbavar.h> 65 #include <vax/mba/mbareg.h> 66 #include <vax/mba/hpreg.h> 67 68 #include "ioconf.h" 69 #include "locators.h" 70 71 struct hp_softc { 72 device_t sc_dev; 73 struct disk sc_disk; 74 bus_space_tag_t sc_iot; 75 bus_space_handle_t sc_ioh; 76 struct mba_device sc_md; /* Common struct used by mbaqueue. */ 77 int sc_wlabel; /* Disklabel area is writable */ 78 }; 79 80 int hpmatch(device_t, cfdata_t, void *); 81 void hpattach(device_t, device_t, void *); 82 void hpstart(struct mba_device *); 83 int hpattn(struct mba_device *); 84 enum xfer_action hpfinish(struct mba_device *, int, int *); 85 86 CFATTACH_DECL_NEW(hp, sizeof(struct hp_softc), 87 hpmatch, hpattach, NULL, NULL); 88 89 static dev_type_open(hpopen); 90 static dev_type_close(hpclose); 91 static dev_type_read(hpread); 92 static dev_type_write(hpwrite); 93 static dev_type_ioctl(hpioctl); 94 static dev_type_strategy(hpstrategy); 95 static dev_type_size(hppsize); 96 97 const struct bdevsw hp_bdevsw = { 98 .d_open = hpopen, 99 .d_close = hpclose, 100 .d_strategy = hpstrategy, 101 .d_ioctl = hpioctl, 102 .d_dump = nulldump, 103 .d_psize = hppsize, 104 .d_discard = nodiscard, 105 .d_flag = D_DISK 106 }; 107 108 const struct cdevsw hp_cdevsw = { 109 .d_open = hpopen, 110 .d_close = hpclose, 111 .d_read = hpread, 112 .d_write = hpwrite, 113 .d_ioctl = hpioctl, 114 .d_stop = nostop, 115 .d_tty = notty, 116 .d_poll = nopoll, 117 .d_mmap = nommap, 118 .d_kqfilter = nokqfilter, 119 .d_discard = nodiscard, 120 .d_flag = D_DISK 121 }; 122 123 #define HP_WCSR(reg, val) \ 124 bus_space_write_4(sc->sc_iot, sc->sc_ioh, (reg), (val)) 125 #define HP_RCSR(reg) \ 126 bus_space_read_4(sc->sc_iot, sc->sc_ioh, (reg)) 127 128 129 /* 130 * Check if this is a disk drive; done by checking type from mbaattach. 131 */ 132 int 133 hpmatch(device_t parent, cfdata_t cf, void *aux) 134 { 135 struct mba_attach_args * const ma = aux; 136 137 if (cf->cf_loc[MBACF_DRIVE] != MBACF_DRIVE_DEFAULT && 138 cf->cf_loc[MBACF_DRIVE] != ma->ma_unit) 139 return 0; 140 141 if (ma->ma_devtyp != MB_RP) 142 return 0; 143 144 return 1; 145 } 146 147 /* 148 * Disk drive found; fake a disklabel and try to read the real one. 149 * If the on-disk label can't be read; we lose. 150 */ 151 void 152 hpattach(device_t parent, device_t self, void *aux) 153 { 154 struct hp_softc * const sc = device_private(self); 155 struct mba_softc * const ms = device_private(parent); 156 struct mba_attach_args * const ma = aux; 157 struct disklabel *dl; 158 const char *msg; 159 160 sc->sc_dev = self; 161 sc->sc_iot = ma->ma_iot; 162 sc->sc_ioh = ma->ma_ioh; 163 164 /* 165 * Init the common struct for both the adapter and its slaves. 166 */ 167 bufq_alloc(&sc->sc_md.md_q, "disksort", BUFQ_SORT_CYLINDER); 168 sc->sc_md.md_softc = sc; /* Pointer to this softc */ 169 sc->sc_md.md_mba = ms; /* Pointer to parent softc */ 170 sc->sc_md.md_start = hpstart; /* Disk start routine */ 171 sc->sc_md.md_attn = hpattn; /* Disk attention routine */ 172 sc->sc_md.md_finish = hpfinish; /* Disk xfer finish routine */ 173 174 ms->sc_md[ma->ma_unit] = &sc->sc_md; /* Per-unit backpointer */ 175 176 /* 177 * Init and attach the disk structure. 178 */ 179 disk_init(&sc->sc_disk, device_xname(sc->sc_dev), NULL); 180 disk_attach(&sc->sc_disk); 181 182 /* 183 * Fake a disklabel to be able to read in the real label. 184 */ 185 dl = sc->sc_disk.dk_label; 186 187 dl->d_secsize = DEV_BSIZE; 188 dl->d_ntracks = 1; 189 dl->d_nsectors = 32; 190 dl->d_secpercyl = 32; 191 192 /* 193 * Read in label. 194 */ 195 if ((msg = readdisklabel(makedev(0, device_unit(self) * 8), hpstrategy, 196 dl, NULL)) != NULL) 197 printf(": %s", msg); 198 printf(": %s, size = %d sectors\n", dl->d_typename, dl->d_secperunit); 199 } 200 201 202 void 203 hpstrategy(struct buf *bp) 204 { 205 struct hp_softc *sc; 206 struct buf *gp; 207 struct disklabel *lp; 208 int unit, s, err; 209 210 unit = DISKUNIT(bp->b_dev); 211 sc = device_lookup_private(&hp_cd, unit); 212 lp = sc->sc_disk.dk_label; 213 214 err = bounds_check_with_label(&sc->sc_disk, bp, sc->sc_wlabel); 215 if (err <= 0) 216 goto done; 217 218 bp->b_rawblkno = 219 bp->b_blkno + lp->d_partitions[DISKPART(bp->b_dev)].p_offset; 220 bp->b_cylinder = bp->b_rawblkno / lp->d_secpercyl; 221 222 s = splbio(); 223 224 gp = bufq_peek(sc->sc_md.md_q); 225 bufq_put(sc->sc_md.md_q, bp); 226 if (gp == 0) 227 mbaqueue(&sc->sc_md); 228 229 splx(s); 230 return; 231 232 done: 233 bp->b_resid = bp->b_bcount; 234 biodone(bp); 235 } 236 237 /* 238 * Start transfer on given disk. Called from mbastart(). 239 */ 240 void 241 hpstart(struct mba_device *md) 242 { 243 struct hp_softc * const sc = md->md_softc; 244 struct disklabel * const lp = sc->sc_disk.dk_label; 245 struct buf *bp = bufq_peek(md->md_q); 246 unsigned bn, cn, sn, tn; 247 248 /* 249 * Collect statistics. 250 */ 251 disk_busy(&sc->sc_disk); 252 iostat_seek(sc->sc_disk.dk_stats); 253 254 bn = bp->b_rawblkno; 255 if (bn) { 256 cn = bn / lp->d_secpercyl; 257 sn = bn % lp->d_secpercyl; 258 tn = sn / lp->d_nsectors; 259 sn = sn % lp->d_nsectors; 260 } else 261 cn = sn = tn = 0; 262 263 HP_WCSR(HP_DC, cn); 264 HP_WCSR(HP_DA, (tn << 8) | sn); 265 if (bp->b_flags & B_READ) 266 HP_WCSR(HP_CS1, HPCS_READ); 267 else 268 HP_WCSR(HP_CS1, HPCS_WRITE); 269 } 270 271 int 272 hpopen(dev_t dev, int flag, int fmt, struct lwp *l) 273 { 274 struct hp_softc *sc; 275 int part = DISKPART(dev); 276 277 sc = device_lookup_private(&hp_cd, DISKUNIT(dev)); 278 if (sc == NULL) 279 return ENXIO; 280 281 if (part >= sc->sc_disk.dk_label->d_npartitions) 282 return ENXIO; 283 284 switch (fmt) { 285 case S_IFCHR: 286 sc->sc_disk.dk_copenmask |= (1 << part); 287 break; 288 289 case S_IFBLK: 290 sc->sc_disk.dk_bopenmask |= (1 << part); 291 break; 292 } 293 sc->sc_disk.dk_openmask = 294 sc->sc_disk.dk_copenmask | sc->sc_disk.dk_bopenmask; 295 296 return 0; 297 } 298 299 int 300 hpclose(dev_t dev, int flag, int fmt, struct lwp *l) 301 { 302 struct hp_softc * const sc = device_lookup_private(&hp_cd, DISKUNIT(dev)); 303 const int part = DISKPART(dev); 304 305 switch (fmt) { 306 case S_IFCHR: 307 sc->sc_disk.dk_copenmask &= ~(1 << part); 308 break; 309 310 case S_IFBLK: 311 sc->sc_disk.dk_bopenmask &= ~(1 << part); 312 break; 313 } 314 sc->sc_disk.dk_openmask = 315 sc->sc_disk.dk_copenmask | sc->sc_disk.dk_bopenmask; 316 317 return 0; 318 } 319 320 int 321 hpioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l) 322 { 323 struct hp_softc * const sc = device_lookup_private(&hp_cd, DISKUNIT(dev)); 324 struct disklabel * const lp = sc->sc_disk.dk_label; 325 int error; 326 327 error = disk_ioctl(&sc->sc_disk, dev, cmd, addr, flag, l); 328 if (error != EPASSTHROUGH) 329 return error; 330 331 switch (cmd) { 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 return ENOTTY; 355 } 356 return 0; 357 } 358 359 /* 360 * Called when a transfer is finished. Check if transfer went OK, 361 * Return info about what-to-do-now. 362 */ 363 enum xfer_action 364 hpfinish(struct mba_device *md, int mbasr, int *attn) 365 { 366 struct hp_softc * const sc = md->md_softc; 367 struct buf *bp = bufq_peek(md->md_q); 368 int er1, er2, bc; 369 unsigned byte; 370 371 er1 = HP_RCSR(HP_ER1); 372 er2 = HP_RCSR(HP_ER2); 373 HP_WCSR(HP_ER1, 0); 374 HP_WCSR(HP_ER2, 0); 375 376 hper1: 377 switch (ffs(er1) - 1) { 378 case -1: 379 HP_WCSR(HP_ER1, 0); 380 goto hper2; 381 382 case HPER1_DCK: /* Corrected? data read. Just notice. */ 383 bc = bus_space_read_4(md->md_mba->sc_iot, 384 md->md_mba->sc_ioh, MBA_BC); 385 byte = ~(bc >> 16); 386 diskerr(bp, hp_cd.cd_name, "soft ecc", LOG_PRINTF, 387 btodb(bp->b_bcount - byte), sc->sc_disk.dk_label); 388 er1 &= ~(1<<HPER1_DCK); 389 break; 390 391 default: 392 aprint_error_dev(sc->sc_dev, "drive error: er1 %x er2 %x\n", 393 er1, er2); 394 HP_WCSR(HP_ER1, 0); 395 HP_WCSR(HP_ER2, 0); 396 goto hper2; 397 } 398 goto hper1; 399 400 hper2: 401 mbasr &= ~(MBASR_DTBUSY|MBASR_DTCMP|MBASR_ATTN); 402 if (mbasr) 403 aprint_error_dev(sc->sc_dev, "massbuss error: %x\n", mbasr); 404 405 bufq_peek(md->md_q)->b_resid = 0; 406 disk_unbusy(&sc->sc_disk, bufq_peek(md->md_q)->b_bcount, 407 (bp->b_flags & B_READ)); 408 return XFER_FINISH; 409 } 410 411 /* 412 * Non-data transfer interrupt; like volume change. 413 */ 414 int 415 hpattn(struct mba_device *md) 416 { 417 struct hp_softc * const sc = md->md_softc; 418 int er1, er2; 419 420 er1 = HP_RCSR(HP_ER1); 421 er2 = HP_RCSR(HP_ER2); 422 423 aprint_error_dev(sc->sc_dev, "Attention! er1 %x er2 %x\n", er1, er2); 424 return 0; 425 } 426 427 428 int 429 hppsize(dev_t dev) 430 { 431 struct hp_softc * const sc = device_lookup_private(&hp_cd, DISKUNIT(dev)); 432 const int part = DISKPART(dev); 433 434 if (sc == NULL || part >= sc->sc_disk.dk_label->d_npartitions) 435 return -1; 436 437 return sc->sc_disk.dk_label->d_partitions[part].p_size * 438 (sc->sc_disk.dk_label->d_secsize / DEV_BSIZE); 439 } 440 441 int 442 hpread(dev_t dev, struct uio *uio, int ioflag) 443 { 444 return (physio(hpstrategy, NULL, dev, B_READ, minphys, uio)); 445 } 446 447 int 448 hpwrite(dev_t dev, struct uio *uio, int ioflag) 449 { 450 return (physio(hpstrategy, NULL, dev, B_WRITE, minphys, uio)); 451 } 452