1 /* $NetBSD: rl.c,v 1.5 2000/06/05 00:09:18 matt Exp $ */ 2 3 /* 4 * Copyright (c) 2000 Ludd, University of Lule}, Sweden. 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 * RL11/RLV11/RLV12 disk controller driver and 35 * RL01/RL02 disk device driver. 36 * 37 * TODO: 38 * Handle disk errors more gracefully 39 * Do overlapping seeks on multiple drives 40 * 41 * Implementation comments: 42 * 43 */ 44 45 #include <sys/param.h> 46 #include <sys/device.h> 47 #include <sys/systm.h> 48 #include <sys/conf.h> 49 #include <sys/disk.h> 50 #include <sys/disklabel.h> 51 #include <sys/buf.h> 52 #include <sys/stat.h> 53 #include <sys/dkio.h> 54 #include <sys/fcntl.h> 55 56 #include <ufs/ufs/dinode.h> 57 #include <ufs/ffs/fs.h> 58 59 #include <machine/bus.h> 60 61 #include <dev/qbus/ubavar.h> 62 #include <dev/qbus/rlreg.h> 63 64 #include "ioconf.h" 65 #include "locators.h" 66 67 struct rlc_softc { 68 struct device sc_dev; 69 struct evcnt sc_intrcnt; 70 bus_space_tag_t sc_iot; 71 bus_space_handle_t sc_ioh; 72 bus_dma_tag_t sc_dmat; 73 bus_dmamap_t sc_dmam; 74 struct buf_queue sc_q; /* Queue of waiting bufs */ 75 struct buf *sc_active; /* Currently active buf */ 76 caddr_t sc_bufaddr; /* Current in-core address */ 77 int sc_diskblk; /* Current block on disk */ 78 int sc_bytecnt; /* How much left to transfer */ 79 }; 80 81 struct rl_softc { 82 struct device rc_dev; 83 struct disk rc_disk; 84 int rc_state; 85 int rc_head; 86 int rc_cyl; 87 int rc_hwid; 88 }; 89 90 static int rlcmatch(struct device *, struct cfdata *, void *); 91 static void rlcattach(struct device *, struct device *, void *); 92 static int rlcprint(void *, const char *); 93 static void rlcintr(void *); 94 static int rlmatch(struct device *, struct cfdata *, void *); 95 static void rlattach(struct device *, struct device *, void *); 96 static void rlcstart(struct rlc_softc *, struct buf *); 97 static void waitcrdy(struct rlc_softc *); 98 static void rlreset(struct device *); 99 cdev_decl(rl); 100 bdev_decl(rl); 101 102 struct cfattach rlc_ca = { 103 sizeof(struct rlc_softc), rlcmatch, rlcattach 104 }; 105 106 struct cfattach rl_ca = { 107 sizeof(struct rl_softc), rlmatch, rlattach 108 }; 109 110 struct rlc_attach_args { 111 u_int16_t type; 112 int hwid; 113 }; 114 115 #define MAXRLXFER (RL_BPS * RL_SPT) 116 #define RLMAJOR 14 117 118 #define RL_WREG(reg, val) \ 119 bus_space_write_2(sc->sc_iot, sc->sc_ioh, (reg), (val)) 120 #define RL_RREG(reg) \ 121 bus_space_read_2(sc->sc_iot, sc->sc_ioh, (reg)) 122 123 void 124 waitcrdy(struct rlc_softc *sc) 125 { 126 int i; 127 128 for (i = 0; i < 1000; i++) { 129 DELAY(10000); 130 if (RL_RREG(RL_CS) & RLCS_CRDY) 131 return; 132 } 133 printf("%s: never got ready\n", sc->sc_dev.dv_xname); /* ?panic? */ 134 } 135 136 int 137 rlcprint(void *aux, const char *name) 138 { 139 struct rlc_attach_args *ra = aux; 140 141 if (name) 142 printf("RL0%d at %s", ra->type & RLMP_DT ? '2' : '1', name); 143 printf(" drive %d", ra->hwid); 144 return UNCONF; 145 } 146 147 /* 148 * Force the controller to interrupt. 149 */ 150 int 151 rlcmatch(struct device *parent, struct cfdata *cf, void *aux) 152 { 153 struct uba_attach_args *ua = aux; 154 struct rlc_softc ssc, *sc = &ssc; 155 int i; 156 157 sc->sc_iot = ua->ua_iot; 158 sc->sc_ioh = ua->ua_ioh; 159 /* Force interrupt by issuing a "Get Status" command */ 160 RL_WREG(RL_DA, RLDA_GS); 161 RL_WREG(RL_CS, RLCS_GS|RLCS_IE); 162 163 for (i = 0; i < 100; i++) { 164 DELAY(100000); 165 if (RL_RREG(RL_CS) & RLCS_CRDY) 166 return 1; 167 } 168 return 0; 169 } 170 171 void 172 rlcattach(struct device *parent, struct device *self, void *aux) 173 { 174 struct rlc_softc *sc = (struct rlc_softc *)self; 175 struct uba_attach_args *ua = aux; 176 struct rlc_attach_args ra; 177 int i, error; 178 179 sc->sc_iot = ua->ua_iot; 180 sc->sc_ioh = ua->ua_ioh; 181 sc->sc_dmat = ua->ua_dmat; 182 uba_intr_establish(ua->ua_icookie, ua->ua_cvec, 183 rlcintr, sc, &sc->sc_intrcnt); 184 evcnt_attach_dynamic(&sc->sc_intrcnt, EVCNT_TYPE_INTR, ua->ua_evcnt, 185 sc->sc_dev.dv_xname, "intr"); 186 printf("\n"); 187 188 /* 189 * The RL11 can only have one transfer going at a time, 190 * and max transfer size is one track, so only one dmamap 191 * is needed. 192 */ 193 error = bus_dmamap_create(sc->sc_dmat, MAXRLXFER, 1, MAXRLXFER, 0, 194 BUS_DMA_ALLOCNOW, &sc->sc_dmam); 195 if (error) { 196 printf(": Failed to allocate DMA map, error %d\n", error); 197 return; 198 } 199 BUFQ_INIT(&sc->sc_q); 200 for (i = 0; i < RL_MAXDPC; i++) { 201 waitcrdy(sc); 202 RL_WREG(RL_DA, RLDA_GS|RLDA_RST); 203 RL_WREG(RL_CS, RLCS_GS|(i << RLCS_USHFT)); 204 waitcrdy(sc); 205 ra.type = RL_RREG(RL_MP); 206 ra.hwid = i; 207 if ((RL_RREG(RL_CS) & RLCS_ERR) == 0) 208 config_found(&sc->sc_dev, &ra, rlcprint); 209 } 210 } 211 212 int 213 rlmatch(struct device *parent, struct cfdata *cf, void *aux) 214 { 215 struct rlc_attach_args *ra = aux; 216 217 if (cf->cf_loc[RLCCF_DRIVE] != RLCCF_DRIVE_DEFAULT && 218 cf->cf_loc[RLCCF_DRIVE] != ra->hwid) 219 return 0; 220 return 1; 221 } 222 223 void 224 rlattach(struct device *parent, struct device *self, void *aux) 225 { 226 struct rl_softc *rc = (struct rl_softc *)self; 227 struct rlc_attach_args *ra = aux; 228 struct disklabel *dl; 229 230 uba_reset_establish(rlreset, self); 231 232 rc->rc_hwid = ra->hwid; 233 rc->rc_disk.dk_name = rc->rc_dev.dv_xname; 234 disk_attach(&rc->rc_disk); 235 dl = rc->rc_disk.dk_label; 236 dl->d_npartitions = 3; 237 strcpy(dl->d_typename, "RL01"); 238 if (ra->type & RLMP_DT) 239 dl->d_typename[3] = '2'; 240 dl->d_secsize = DEV_BSIZE; /* XXX - wrong, but OK for now */ 241 dl->d_nsectors = RL_SPT/2; 242 dl->d_ntracks = RL_SPD; 243 dl->d_ncylinders = ra->type & RLMP_DT ? RL_TPS02 : RL_TPS01; 244 dl->d_secpercyl = dl->d_nsectors * dl->d_ntracks; 245 dl->d_secperunit = dl->d_ncylinders * dl->d_secpercyl; 246 dl->d_partitions[0].p_size = dl->d_partitions[2].p_size = 247 dl->d_secperunit; 248 dl->d_partitions[0].p_offset = dl->d_partitions[2].p_offset = 0; 249 dl->d_interleave = dl->d_headswitch = 1; 250 dl->d_bbsize = BBSIZE; 251 dl->d_sbsize = SBSIZE; 252 dl->d_rpm = 2400; 253 dl->d_type = DTYPE_DEC; 254 printf(": %s\n", dl->d_typename); 255 } 256 257 int 258 rlopen(dev_t dev, int flag, int fmt, struct proc *p) 259 { 260 int part, unit, mask; 261 struct disklabel *dl; 262 struct rlc_softc *sc; 263 struct rl_softc *rc; 264 char *msg; 265 /* 266 * Make sure this is a reasonable open request. 267 */ 268 unit = DISKUNIT(dev); 269 if (unit >= rl_cd.cd_ndevs) 270 return ENXIO; 271 rc = rl_cd.cd_devs[unit]; 272 if (rc == 0) 273 return ENXIO; 274 275 sc = (struct rlc_softc *)rc->rc_dev.dv_parent; 276 /* XXX - check that the disk actually is useable */ 277 /* 278 * If this is the first open; read in where on the disk we are. 279 */ 280 dl = rc->rc_disk.dk_label; 281 if (rc->rc_state == DK_CLOSED) { 282 u_int16_t mp; 283 RL_WREG(RL_CS, RLCS_RHDR|(rc->rc_hwid << RLCS_USHFT)); 284 waitcrdy(sc); 285 mp = RL_RREG(RL_MP); 286 rc->rc_head = ((mp & RLMP_HS) == RLMP_HS); 287 rc->rc_cyl = (mp >> 7) & 0777; 288 rc->rc_state = DK_OPEN; 289 /* Get disk label */ 290 printf("%s: ", rc->rc_dev.dv_xname); 291 if ((msg = readdisklabel(MAKEDISKDEV(RLMAJOR, 292 rc->rc_dev.dv_unit, RAW_PART), rlstrategy, dl, NULL))) 293 printf("%s: ", msg); 294 printf("size %d sectors\n", dl->d_secperunit); 295 } 296 part = DISKPART(dev); 297 if (part >= dl->d_npartitions) 298 return ENXIO; 299 300 mask = 1 << part; 301 switch (fmt) { 302 case S_IFCHR: 303 rc->rc_disk.dk_copenmask |= mask; 304 break; 305 case S_IFBLK: 306 rc->rc_disk.dk_bopenmask |= mask; 307 break; 308 } 309 rc->rc_disk.dk_openmask |= mask; 310 return 0; 311 } 312 313 int 314 rlclose(dev_t dev, int flag, int fmt, struct proc *p) 315 { 316 int unit = DISKUNIT(dev); 317 struct rl_softc *rc = rl_cd.cd_devs[unit]; 318 int mask = (1 << DISKPART(dev)); 319 320 switch (fmt) { 321 case S_IFCHR: 322 rc->rc_disk.dk_copenmask &= ~mask; 323 break; 324 case S_IFBLK: 325 rc->rc_disk.dk_bopenmask &= ~mask; 326 break; 327 } 328 rc->rc_disk.dk_openmask = 329 rc->rc_disk.dk_copenmask | rc->rc_disk.dk_bopenmask; 330 331 if (rc->rc_disk.dk_openmask == 0) 332 rc->rc_state = DK_CLOSED; /* May change pack */ 333 return 0; 334 } 335 336 void 337 rlstrategy(struct buf *bp) 338 { 339 struct disklabel *lp; 340 struct rlc_softc *sc; 341 struct rl_softc *rc; 342 int unit, s, err; 343 /* 344 * Make sure this is a reasonable drive to use. 345 */ 346 unit = DISKUNIT(bp->b_dev); 347 if (unit > rl_cd.cd_ndevs || (rc = rl_cd.cd_devs[unit]) == NULL) { 348 bp->b_error = ENXIO; 349 bp->b_flags |= B_ERROR; 350 goto done; 351 } 352 if (rc->rc_state != DK_OPEN) /* How did we end up here at all? */ 353 panic("rlstrategy: state impossible"); 354 355 lp = rc->rc_disk.dk_label; 356 if ((err = bounds_check_with_label(bp, lp, 1)) <= 0) 357 goto done; 358 359 if (bp->b_bcount == 0) 360 goto done; 361 362 bp->b_rawblkno = 363 bp->b_blkno + lp->d_partitions[DISKPART(bp->b_dev)].p_offset; 364 bp->b_cylinder = bp->b_rawblkno / lp->d_secpercyl; 365 sc = (struct rlc_softc *)rc->rc_dev.dv_parent; 366 367 s = splimp(); 368 disksort_cylinder(&sc->sc_q, bp); 369 rlcstart(sc, 0); 370 splx(s); 371 return; 372 373 done: biodone(bp); 374 } 375 376 int 377 rlioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) 378 { 379 struct rl_softc *rc = rl_cd.cd_devs[DISKUNIT(dev)]; 380 struct disklabel *lp = rc->rc_disk.dk_label; 381 int err = 0; 382 383 switch (cmd) { 384 case DIOCGDINFO: 385 bcopy(lp, addr, sizeof (struct disklabel)); 386 break; 387 388 case DIOCGPART: 389 ((struct partinfo *)addr)->disklab = lp; 390 ((struct partinfo *)addr)->part = 391 &lp->d_partitions[DISKPART(dev)]; 392 break; 393 394 case DIOCSDINFO: 395 case DIOCWDINFO: 396 if ((flag & FWRITE) == 0) 397 err = EBADF; 398 else 399 err = (cmd == DIOCSDINFO ? 400 setdisklabel(lp, (struct disklabel *)addr, 0, 0) : 401 writedisklabel(dev, rlstrategy, lp, 0)); 402 break; 403 404 case DIOCWLABEL: 405 if ((flag & FWRITE) == 0) 406 err = EBADF; 407 break; 408 409 default: 410 err = ENOTTY; 411 } 412 return err; 413 } 414 415 int 416 rlsize(dev_t dev) 417 { 418 struct disklabel *dl; 419 struct rl_softc *rc; 420 int size, unit = DISKUNIT(dev); 421 422 if ((unit >= rl_cd.cd_ndevs) || ((rc = rl_cd.cd_devs[unit]) == 0)) 423 return -1; 424 dl = rc->rc_disk.dk_label; 425 size = dl->d_partitions[DISKPART(dev)].p_size * 426 (dl->d_secsize / DEV_BSIZE); 427 return size; 428 } 429 430 int 431 rldump(dev_t dev, daddr_t blkno, caddr_t va, size_t size) 432 { 433 /* Not likely... */ 434 return 0; 435 } 436 437 int 438 rlread(dev_t dev, struct uio *uio, int ioflag) 439 { 440 return (physio(rlstrategy, NULL, dev, B_READ, minphys, uio)); 441 } 442 443 int 444 rlwrite(dev_t dev, struct uio *uio, int ioflag) 445 { 446 return (physio(rlstrategy, NULL, dev, B_WRITE, minphys, uio)); 447 } 448 449 static char *rlerr[] = { 450 "no", 451 "operation incomplete", 452 "read data CRC", 453 "header CRC", 454 "data late", 455 "header not found", 456 "", 457 "", 458 "non-existant memory", 459 "memory parity error", 460 "", 461 "", 462 "", 463 "", 464 "", 465 "", 466 }; 467 468 void 469 rlcintr(void *arg) 470 { 471 struct rlc_softc *sc = arg; 472 struct buf *bp; 473 u_int16_t cs; 474 475 bp = sc->sc_active; 476 if (bp == 0) { 477 printf("%s: strange interrupt\n", sc->sc_dev.dv_xname); 478 return; 479 } 480 bus_dmamap_unload(sc->sc_dmat, sc->sc_dmam); 481 sc->sc_active = 0; 482 cs = RL_RREG(RL_CS); 483 if (cs & RLCS_ERR) { 484 int error = (cs & RLCS_ERRMSK) >> 10; 485 486 printf("%s: %s\n", sc->sc_dev.dv_xname, rlerr[error]); 487 bp->b_flags |= B_ERROR; 488 bp->b_error = EIO; 489 bp->b_resid = bp->b_bcount; 490 sc->sc_bytecnt = 0; 491 } 492 if (sc->sc_bytecnt == 0) /* Finished transfer */ 493 biodone(bp); 494 rlcstart(sc, sc->sc_bytecnt ? bp : 0); 495 } 496 497 /* 498 * Start routine. First position the disk to the given position, 499 * then start reading/writing. An optimization would be to be able 500 * to handle overlapping seeks between disks. 501 */ 502 void 503 rlcstart(struct rlc_softc *sc, struct buf *ob) 504 { 505 struct disklabel *lp; 506 struct rl_softc *rc; 507 struct buf *bp; 508 int bn, cn, sn, tn, blks, err; 509 510 if (sc->sc_active) 511 return; /* Already doing something */ 512 513 if (ob == 0) { 514 bp = BUFQ_FIRST(&sc->sc_q); 515 if (bp == NULL) 516 return; /* Nothing to do */ 517 BUFQ_REMOVE(&sc->sc_q, bp); 518 sc->sc_bufaddr = bp->b_data; 519 sc->sc_diskblk = bp->b_rawblkno; 520 sc->sc_bytecnt = bp->b_bcount; 521 bp->b_resid = 0; 522 } else 523 bp = ob; 524 sc->sc_active = bp; 525 526 rc = rl_cd.cd_devs[DISKUNIT(bp->b_dev)]; 527 bn = sc->sc_diskblk; 528 lp = rc->rc_disk.dk_label; 529 if (bn) { 530 cn = bn / lp->d_secpercyl; 531 sn = bn % lp->d_secpercyl; 532 tn = sn / lp->d_nsectors; 533 sn = sn % lp->d_nsectors; 534 } else 535 cn = sn = tn = 0; 536 537 /* 538 * Check if we have to position disk first. 539 */ 540 if (rc->rc_cyl != cn || rc->rc_head != tn) { 541 u_int16_t da = RLDA_SEEK; 542 if (cn > rc->rc_cyl) 543 da |= ((cn - rc->rc_cyl) << RLDA_CYLSHFT) | RLDA_DIR; 544 else 545 da |= ((rc->rc_cyl - cn) << RLDA_CYLSHFT); 546 if (tn) 547 da |= RLDA_HSSEEK; 548 waitcrdy(sc); 549 RL_WREG(RL_DA, da); 550 RL_WREG(RL_CS, RLCS_SEEK | (rc->rc_hwid << RLCS_USHFT)); 551 waitcrdy(sc); 552 rc->rc_cyl = cn; 553 rc->rc_head = tn; 554 } 555 RL_WREG(RL_DA, (cn << RLDA_CYLSHFT) | (tn ? RLDA_HSRW : 0) | (sn << 1)); 556 blks = sc->sc_bytecnt/DEV_BSIZE; 557 558 if (sn + blks > RL_SPT/2) 559 blks = RL_SPT/2 - sn; 560 RL_WREG(RL_MP, -(blks*DEV_BSIZE)/2); 561 err = bus_dmamap_load(sc->sc_dmat, sc->sc_dmam, sc->sc_bufaddr, 562 (blks*DEV_BSIZE), bp->b_proc, BUS_DMA_NOWAIT); 563 if (err) 564 panic("%s: bus_dmamap_load failed: %d", 565 sc->sc_dev.dv_xname, err); 566 RL_WREG(RL_BA, (sc->sc_dmam->dm_segs[0].ds_addr & 0xffff)); 567 568 /* Count up vars */ 569 sc->sc_bufaddr += (blks*DEV_BSIZE); 570 sc->sc_diskblk += blks; 571 sc->sc_bytecnt -= (blks*DEV_BSIZE); 572 573 if (bp->b_flags & B_READ) 574 RL_WREG(RL_CS, RLCS_IE|RLCS_RD|(rc->rc_hwid << RLCS_USHFT)); 575 else 576 RL_WREG(RL_CS, RLCS_IE|RLCS_WD|(rc->rc_hwid << RLCS_USHFT)); 577 } 578 579 void 580 rlreset(struct device *dev) 581 { 582 struct rl_softc *rc = (struct rl_softc *)dev; 583 struct rlc_softc *sc = (struct rlc_softc *)rc->rc_dev.dv_parent; 584 u_int16_t mp; 585 586 if (rc->rc_state != DK_OPEN) 587 return; 588 RL_WREG(RL_CS, RLCS_RHDR|(rc->rc_hwid << RLCS_USHFT)); 589 waitcrdy(sc); 590 mp = RL_RREG(RL_MP); 591 rc->rc_head = ((mp & RLMP_HS) == RLMP_HS); 592 rc->rc_cyl = (mp >> 7) & 0777; 593 if (sc->sc_active == 0) 594 return; 595 596 BUFQ_INSERT_HEAD(&sc->sc_q, sc->sc_active); 597 sc->sc_active = 0; 598 rlcstart(sc, 0); 599 } 600