Annotation of sys/arch/vax/vsa/hdc9224.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: hdc9224.c,v 1.21 2007/06/20 20:13:41 miod Exp $ */
! 2: /* $NetBSD: hdc9224.c,v 1.16 2001/07/26 15:05:09 wiz Exp $ */
! 3: /*
! 4: * Copyright (c) 1996 Ludd, University of Lule}, Sweden.
! 5: * All rights reserved.
! 6: *
! 7: * This code is derived from software contributed to Ludd by Bertram Barth.
! 8: *
! 9: * Redistribution and use in source and binary forms, with or without
! 10: * modification, are permitted provided that the following conditions
! 11: * are met:
! 12: * 1. Redistributions of source code must retain the above copyright
! 13: * notice, this list of conditions and the following disclaimer.
! 14: * 2. Redistributions in binary form must reproduce the above copyright
! 15: * notice, this list of conditions and the following disclaimer in the
! 16: * documentation and/or other materials provided with the distribution.
! 17: * 3. All advertising materials mentioning features or use of this software
! 18: * must display the following acknowledgement:
! 19: * This product includes software developed at Ludd, University of
! 20: * Lule}, Sweden and its contributors.
! 21: * 4. The name of the author may not be used to endorse or promote products
! 22: * derived from this software without specific prior written permission
! 23: *
! 24: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 25: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 26: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 27: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
! 28: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 29: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 30: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 31: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 32: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
! 33: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 34: */
! 35:
! 36: /*
! 37: * with much help from (in alphabetical order):
! 38: * Jeremy
! 39: * Roger Ivie
! 40: * Rick Macklem
! 41: * Mike Young
! 42: *
! 43: * Rewritten by Ragge 25 Jun 2000. New features:
! 44: * - Uses interrupts instead of polling to signal ready.
! 45: * - Can cooperate with the SCSI routines WRT. the DMA area.
! 46: *
! 47: * TODO:
! 48: * - Floppy support missing.
! 49: * - Bad block forwarding missing.
! 50: * - Statistics collection.
! 51: */
! 52: #undef HDDEBUG
! 53:
! 54: #include <sys/param.h>
! 55: #include <sys/systm.h>
! 56: #include <sys/kernel.h>
! 57: #include <sys/conf.h>
! 58: #include <sys/file.h>
! 59: #include <sys/stat.h>
! 60: #include <sys/ioctl.h>
! 61: #include <sys/buf.h>
! 62: #include <sys/proc.h>
! 63: #include <sys/user.h>
! 64: #include <sys/device.h>
! 65: #include <sys/disklabel.h>
! 66: #include <sys/disk.h>
! 67: #include <sys/syslog.h>
! 68: #include <sys/reboot.h>
! 69:
! 70: #include <uvm/uvm_extern.h>
! 71:
! 72: #include <ufs/ufs/dinode.h> /* For BBSIZE */
! 73: #include <ufs/ffs/fs.h>
! 74:
! 75: #include <machine/pte.h>
! 76: #include <machine/sid.h>
! 77: #include <machine/cpu.h>
! 78: #include <machine/uvax.h>
! 79: #include <machine/ka410.h>
! 80: #include <machine/vsbus.h>
! 81: #include <machine/rpb.h>
! 82: #include <machine/scb.h>
! 83:
! 84: #include <arch/vax/mscp/mscp.h> /* For DEC disk encoding */
! 85:
! 86: #include <vax/vsa/hdc9224.h>
! 87:
! 88: /*
! 89: * on-disk geometry block
! 90: */
! 91: struct hdgeom {
! 92: char mbz[10]; /* 10 bytes of zero */
! 93: long xbn_count; /* number of XBNs */
! 94: long dbn_count; /* number of DBNs */
! 95: long lbn_count; /* number of LBNs (Logical-Block-Numbers) */
! 96: long rbn_count; /* number of RBNs (Replacement-Block-Numbers) */
! 97: short nspt; /* number of sectors per track */
! 98: short ntracks; /* number of tracks */
! 99: short ncylinders; /* number of cylinders */
! 100: short precomp; /* first cylinder for write precompensation */
! 101: short reduced; /* first cylinder for reduced write current */
! 102: short seek_rate; /* seek rate or zero for buffered seeks */
! 103: short crc_eec; /* 0 if CRC, 1 if ECC is being used */
! 104: short rct; /* "replacement control table" (RCT) */
! 105: short rct_ncopies; /* number of copies of the RCT */
! 106: long media_id; /* media identifier */
! 107: short interleave; /* sector-to-sector interleave */
! 108: short headskew; /* head-to-head skew */
! 109: short cylskew; /* cylinder-to-cylinder skew */
! 110: short gap0_size; /* size of GAP 0 in the MFM format */
! 111: short gap1_size; /* size of GAP 1 in the MFM format */
! 112: short gap2_size; /* size of GAP 2 in the MFM format */
! 113: short gap3_size; /* size of GAP 3 in the MFM format */
! 114: short sync_value; /* sync value used when formatting */
! 115: char reserved[32]; /* reserved for use by the RQDX formatter */
! 116: short serial_number; /* serial number */
! 117: #if 0 /* we don't need these 412 useless bytes ... */
! 118: char fill[412-2]; /* Filler bytes to the end of the block */
! 119: short checksum; /* checksum over the XBN */
! 120: #endif
! 121: } __packed;
! 122:
! 123: /*
! 124: * Software status
! 125: */
! 126: struct hdsoftc {
! 127: struct device sc_dev; /* must be here! (pseudo-OOP:) */
! 128: struct disk sc_disk; /* disklabel etc. */
! 129: struct hdgeom sc_xbn; /* on-disk geometry information */
! 130: int sc_drive; /* physical unit number */
! 131: };
! 132:
! 133: struct hdcsoftc {
! 134: struct device sc_dev; /* must be here (pseudo-OOP:) */
! 135: struct evcount sc_intrcnt;
! 136: struct vsbus_dma sc_vd;
! 137: vaddr_t sc_regs; /* register addresses */
! 138: struct buf sc_buf_queue;
! 139: struct buf *sc_active;
! 140: struct hdc9224_UDCreg sc_creg; /* (command) registers to be written */
! 141: struct hdc9224_UDCreg sc_sreg; /* (status) registers being read */
! 142: caddr_t sc_dmabase; /* */
! 143: int sc_dmasize;
! 144: caddr_t sc_bufaddr; /* Current in-core address */
! 145: daddr64_t sc_diskblk; /* Current block on disk */
! 146: int sc_bytecnt; /* How much left to transfer */
! 147: int sc_xfer; /* Current transfer size */
! 148: int sc_retries;
! 149: volatile u_char sc_status; /* last status from interrupt */
! 150: char sc_intbit;
! 151: };
! 152:
! 153: struct hdc_attach_args {
! 154: int ha_drive;
! 155: };
! 156:
! 157: /*
! 158: * prototypes for (almost) all the internal routines
! 159: */
! 160: int hdcmatch(struct device *, void *, void *);
! 161: void hdcattach(struct device *, struct device *, void *);
! 162: int hdcprint(void *, const char *);
! 163: int hdmatch(struct device *, void *, void *);
! 164: void hdattach(struct device *, struct device *, void *);
! 165: void hdcintr(void *);
! 166: int hdc_command(struct hdcsoftc *, int);
! 167: void hd_readgeom(struct hdcsoftc *, struct hdsoftc *);
! 168: #ifdef HDDEBUG
! 169: void hdc_printgeom( struct hdgeom *);
! 170: #endif
! 171: void hdc_writeregs(struct hdcsoftc *);
! 172: void hdcstart(struct hdcsoftc *, struct buf *);
! 173: int hdc_hdselect(struct hdcsoftc *, int);
! 174: void hdmakelabel(struct disklabel *, struct hdgeom *);
! 175: void hdc_writeregs(struct hdcsoftc *);
! 176: void hdc_readregs(struct hdcsoftc *);
! 177: void hdc_qstart(void *);
! 178:
! 179: bdev_decl(hd);
! 180: cdev_decl(hd);
! 181:
! 182: const struct cfattach hdc_ca = {
! 183: sizeof(struct hdcsoftc), hdcmatch, hdcattach
! 184: };
! 185:
! 186: struct cfdriver hdc_cd = {
! 187: NULL, "hdc", DV_DULL
! 188: };
! 189:
! 190: const struct cfattach hd_ca = {
! 191: sizeof(struct hdsoftc), hdmatch, hdattach
! 192: };
! 193:
! 194: struct cfdriver hd_cd = {
! 195: NULL, "hd", DV_DISK
! 196: };
! 197:
! 198: /* At least 0.7 uS between register accesses */
! 199: static int hd_dmasize, inq = 0; /* XXX should be in softc... but only 1 ctrl */
! 200: static int u;
! 201: #define WAIT asm("movl _u,_u;movl _u,_u;movl _u,_u; movl _u,_u")
! 202:
! 203: #define HDC_WREG(x) *(volatile char *)(sc->sc_regs) = (x)
! 204: #define HDC_RREG *(volatile char *)(sc->sc_regs)
! 205: #define HDC_WCMD(x) *(volatile char *)(sc->sc_regs + 4) = (x)
! 206: #define HDC_RSTAT *(volatile char *)(sc->sc_regs + 4)
! 207:
! 208: /*
! 209: * new-config's hdcmatch() is similar to old-config's hdcprobe(),
! 210: * thus we probe for the existence of the controller and reset it.
! 211: * NB: we can't initialize the controller yet, since space for hdcsoftc
! 212: * is not yet allocated. Thus we do this in hdcattach()...
! 213: */
! 214: int
! 215: hdcmatch(struct device *parent, void *vcf, void *aux)
! 216: {
! 217: static int matched = 0;
! 218: struct vsbus_attach_args *va = aux;
! 219: volatile char *hdc_csr = (char *)va->va_addr;
! 220: int i;
! 221:
! 222: if (vax_boardtype == VAX_BTYP_49 || vax_boardtype == VAX_BTYP_46 ||
! 223: vax_boardtype == VAX_BTYP_48 || vax_boardtype == VAX_BTYP_1303)
! 224: return (0);
! 225:
! 226: /* Can only match once due to DMA setup. This should not be an issue. */
! 227: if (matched != 0)
! 228: return (0);
! 229:
! 230: hdc_csr[4] = DKC_CMD_RESET; /* reset chip */
! 231: for (i = 0; i < 1000; i++) {
! 232: DELAY(1000);
! 233: if (hdc_csr[4] & DKC_ST_DONE)
! 234: break;
! 235: }
! 236: if (i == 100)
! 237: return 0; /* No response to reset */
! 238:
! 239: hdc_csr[4] = DKC_CMD_SETREGPTR|UDC_TERM;
! 240: WAIT;
! 241: hdc_csr[0] = UDC_TC_CRCPRE|UDC_TC_INTDONE;
! 242: WAIT;
! 243: hdc_csr[4] = DKC_CMD_DRDESELECT; /* Should be harmless */
! 244: DELAY(1000);
! 245: return (matched = 1);
! 246: }
! 247:
! 248: int
! 249: hdcprint(void *aux, const char *pnp)
! 250: {
! 251: struct hdc_attach_args *ha = aux;
! 252:
! 253: if (pnp != NULL)
! 254: printf("%s at %s drive %d",
! 255: ha->ha_drive == 2 ? "ry" : "hd", pnp, ha->ha_drive);
! 256:
! 257: return (UNCONF);
! 258: }
! 259:
! 260: /*
! 261: * hdc_attach() probes for all possible devices
! 262: */
! 263: void
! 264: hdcattach(struct device *parent, struct device *self, void *aux)
! 265: {
! 266: struct vsbus_attach_args *va = aux;
! 267: struct hdcsoftc *sc = (void *)self;
! 268: struct hdc_attach_args ha;
! 269: int status, i;
! 270:
! 271: u = 0; /* !!! - GCC */
! 272:
! 273: printf("\n");
! 274:
! 275: /*
! 276: * Get interrupt vector, enable instrumentation.
! 277: */
! 278: scb_vecalloc(va->va_cvec, hdcintr, sc, SCB_ISTACK, &sc->sc_intrcnt);
! 279: evcount_attach(&sc->sc_intrcnt, self->dv_xname, (void *)va->va_cvec,
! 280: &evcount_intr);
! 281:
! 282: sc->sc_regs = vax_map_physmem(va->va_paddr, 1);
! 283: sc->sc_dmabase = (caddr_t)va->va_dmaaddr;
! 284: sc->sc_dmasize = va->va_dmasize;
! 285: sc->sc_intbit = va->va_maskno;
! 286: hd_dmasize = min(MAXPHYS, sc->sc_dmasize); /* Used in hd_minphys */
! 287:
! 288: sc->sc_vd.vd_go = hdc_qstart;
! 289: sc->sc_vd.vd_arg = sc;
! 290:
! 291: /*
! 292: * Reset controller.
! 293: */
! 294: HDC_WCMD(DKC_CMD_RESET);
! 295: DELAY(1000);
! 296: status = HDC_RSTAT;
! 297: if (status != (DKC_ST_DONE|DKC_TC_SUCCESS)) {
! 298: printf("%s: RESET failed, status 0x%x\n",
! 299: sc->sc_dev.dv_xname, status);
! 300: return;
! 301: }
! 302:
! 303: /*
! 304: * now probe for all possible hard drives
! 305: */
! 306: for (i = 0; i < 4; i++) {
! 307: if (i == 2) /* Floppy, needs special handling */
! 308: continue;
! 309: HDC_WCMD(DKC_CMD_DRSELECT | i);
! 310: DELAY(1000);
! 311: status = HDC_RSTAT;
! 312: ha.ha_drive = i;
! 313: if ((status & DKC_ST_TERMCOD) == DKC_TC_SUCCESS)
! 314: config_found(self, (void *)&ha, hdcprint);
! 315: }
! 316: }
! 317:
! 318: /*
! 319: * hdmatch() probes for the existence of a HD-type disk/floppy
! 320: */
! 321: int
! 322: hdmatch(parent, vcf, aux)
! 323: struct device *parent;
! 324: void *vcf;
! 325: void *aux;
! 326: {
! 327: struct hdc_attach_args *ha = aux;
! 328: struct cfdata *cf = vcf;
! 329:
! 330: if (cf->cf_loc[0] != -1 &&
! 331: cf->cf_loc[0] != ha->ha_drive)
! 332: return 0;
! 333:
! 334: if (ha->ha_drive == 2) /* Always floppy, not supported */
! 335: return 0;
! 336:
! 337: return 1;
! 338: }
! 339:
! 340: #define HDMAJOR 19
! 341:
! 342: void
! 343: hdattach(struct device *parent, struct device *self, void *aux)
! 344: {
! 345: struct hdcsoftc *sc = (void*)parent;
! 346: struct hdsoftc *hd = (void*)self;
! 347: struct hdc_attach_args *ha = aux;
! 348: struct disklabel *dl;
! 349: char *msg;
! 350:
! 351: hd->sc_drive = ha->ha_drive;
! 352: /*
! 353: * Initialize and attach the disk structure.
! 354: */
! 355: hd->sc_disk.dk_name = hd->sc_dev.dv_xname;
! 356: disk_attach(&hd->sc_disk);
! 357:
! 358: /*
! 359: * if it's not a floppy then evaluate the on-disk geometry.
! 360: * if necessary correct the label...
! 361: */
! 362: hd_readgeom(sc, hd);
! 363: disk_printtype(hd->sc_drive, hd->sc_xbn.media_id);
! 364: dl = hd->sc_disk.dk_label;
! 365: hdmakelabel(dl, &hd->sc_xbn);
! 366: msg = readdisklabel(MAKEDISKDEV(HDMAJOR, hd->sc_dev.dv_unit, RAW_PART),
! 367: hdstrategy, dl, 0);
! 368: printf("%s: %luMB, %lu sectors\n",
! 369: hd->sc_dev.dv_xname, DL_GETDSIZE(dl) / (1048576 / DEV_BSIZE),
! 370: DL_GETDSIZE(dl));
! 371: if (msg) {
! 372: /*printf("%s: %s\n", hd->sc_dev.dv_xname, msg);*/
! 373: }
! 374: #ifdef HDDEBUG
! 375: hdc_printgeom(&hd->sc_xbn);
! 376: #endif
! 377: }
! 378:
! 379: void
! 380: hdcintr(void *arg)
! 381: {
! 382: struct hdcsoftc *sc = arg;
! 383: struct buf *bp;
! 384:
! 385: sc->sc_status = HDC_RSTAT;
! 386: if (sc->sc_active == 0)
! 387: return; /* Complain? */
! 388:
! 389: if ((sc->sc_status & (DKC_ST_INTPEND | DKC_ST_DONE)) !=
! 390: (DKC_ST_INTPEND | DKC_ST_DONE))
! 391: return; /* Why spurious ints sometimes??? */
! 392:
! 393: bp = sc->sc_active;
! 394: sc->sc_active = 0;
! 395: if ((sc->sc_status & DKC_ST_TERMCOD) != DKC_TC_SUCCESS) {
! 396: int i;
! 397: u_char *g = (u_char *)&sc->sc_sreg;
! 398:
! 399: if (sc->sc_retries++ < 3) { /* Allow 3 retries */
! 400: hdcstart(sc, bp);
! 401: return;
! 402: }
! 403: printf("%s: failed, status 0x%x\n",
! 404: sc->sc_dev.dv_xname, sc->sc_status);
! 405: hdc_readregs(sc);
! 406: for (i = 0; i < 10; i++)
! 407: printf("%i: %x\n", i, g[i]);
! 408: bp->b_flags |= B_ERROR;
! 409: bp->b_error = ENXIO;
! 410: bp->b_resid = bp->b_bcount;
! 411: biodone(bp);
! 412: vsbus_dma_intr();
! 413: return;
! 414: }
! 415:
! 416: if (bp->b_flags & B_READ) {
! 417: vsbus_copytoproc(bp->b_proc, sc->sc_dmabase, sc->sc_bufaddr,
! 418: sc->sc_xfer);
! 419: }
! 420: sc->sc_diskblk += (sc->sc_xfer/DEV_BSIZE);
! 421: sc->sc_bytecnt -= sc->sc_xfer;
! 422: sc->sc_bufaddr += sc->sc_xfer;
! 423:
! 424: if (sc->sc_bytecnt == 0) { /* Finished transfer */
! 425: biodone(bp);
! 426: vsbus_dma_intr();
! 427: } else
! 428: hdcstart(sc, bp);
! 429: }
! 430:
! 431: /*
! 432: *
! 433: */
! 434: void
! 435: hdstrategy(struct buf *bp)
! 436: {
! 437: struct hdsoftc *hd;
! 438: struct hdcsoftc *sc;
! 439: struct disklabel *lp;
! 440: int unit, s;
! 441:
! 442: unit = DISKUNIT(bp->b_dev);
! 443: if (unit > hd_cd.cd_ndevs || (hd = hd_cd.cd_devs[unit]) == NULL) {
! 444: bp->b_error = ENXIO;
! 445: bp->b_flags |= B_ERROR;
! 446: goto done;
! 447: }
! 448: sc = (void *)hd->sc_dev.dv_parent;
! 449:
! 450: lp = hd->sc_disk.dk_label;
! 451: if ((bounds_check_with_label(bp, hd->sc_disk.dk_label, 1)) <= 0)
! 452: goto done;
! 453:
! 454: if (bp->b_bcount == 0)
! 455: goto done;
! 456:
! 457: s = splbio();
! 458: disksort(&sc->sc_buf_queue, bp);
! 459: if (inq == 0) {
! 460: inq = 1;
! 461: vsbus_dma_start(&sc->sc_vd);
! 462: }
! 463: splx(s);
! 464: return;
! 465:
! 466: done:
! 467: s = splbio();
! 468: biodone(bp);
! 469: splx(s);
! 470: }
! 471:
! 472: void
! 473: hdc_qstart(void *arg)
! 474: {
! 475: struct hdcsoftc *sc = arg;
! 476: struct buf *dp;
! 477:
! 478: inq = 0;
! 479:
! 480: hdcstart(sc, NULL);
! 481: dp = &sc->sc_buf_queue;
! 482: if (dp->b_actf != NULL) {
! 483: vsbus_dma_start(&sc->sc_vd); /* More to go */
! 484: inq = 1;
! 485: }
! 486: }
! 487:
! 488: void
! 489: hdcstart(struct hdcsoftc *sc, struct buf *ob)
! 490: {
! 491: struct hdc9224_UDCreg *p = &sc->sc_creg;
! 492: struct disklabel *lp;
! 493: struct hdsoftc *hd;
! 494: struct buf *dp, *bp;
! 495: int cn, sn, tn, blks;
! 496: volatile char ch;
! 497: daddr64_t bn;
! 498:
! 499: splassert(IPL_BIO);
! 500:
! 501: if (sc->sc_active)
! 502: return; /* Already doing something */
! 503:
! 504: if (ob == NULL) {
! 505: dp = &sc->sc_buf_queue;
! 506: if ((bp = dp->b_actf) == NULL)
! 507: return; /* Nothing to do */
! 508:
! 509: dp->b_actf = bp->b_actf;
! 510: sc->sc_bufaddr = bp->b_data;
! 511: sc->sc_bytecnt = bp->b_bcount;
! 512: sc->sc_retries = 0;
! 513: bp->b_resid = 0;
! 514: } else
! 515: bp = ob;
! 516:
! 517: hd = hd_cd.cd_devs[DISKUNIT(bp->b_dev)];
! 518: lp = hd->sc_disk.dk_label;
! 519: hdc_hdselect(sc, hd->sc_drive);
! 520: sc->sc_active = bp;
! 521:
! 522: if (ob == NULL) {
! 523: sc->sc_diskblk = bp->b_blkno +
! 524: DL_GETPOFFSET(&lp->d_partitions[DISKPART(bp->b_dev)]);
! 525: }
! 526: bn = sc->sc_diskblk;
! 527:
! 528: if (bn != 0) {
! 529: cn = bn / lp->d_secpercyl;
! 530: sn = bn % lp->d_secpercyl;
! 531: tn = sn / lp->d_nsectors;
! 532: sn = sn % lp->d_nsectors;
! 533: } else
! 534: cn = sn = tn = 0;
! 535:
! 536: cn++; /* first cylinder is reserved */
! 537:
! 538: bzero(p, sizeof(struct hdc9224_UDCreg));
! 539:
! 540: /*
! 541: * Tricky thing: the controller itself only increases the sector
! 542: * number, not the track or cylinder number. Therefore the driver
! 543: * is not allowed to have transfers that crosses track boundaries.
! 544: */
! 545: blks = sc->sc_bytecnt / DEV_BSIZE;
! 546: if ((sn + blks) > lp->d_nsectors)
! 547: blks = lp->d_nsectors - sn;
! 548:
! 549: p->udc_dsect = sn;
! 550: p->udc_dcyl = cn & 0xff;
! 551: p->udc_dhead = ((cn >> 4) & 0x70) | tn;
! 552: p->udc_scnt = blks;
! 553:
! 554: p->udc_rtcnt = UDC_RC_RTRYCNT;
! 555: p->udc_mode = UDC_MD_HDD;
! 556: p->udc_term = UDC_TC_CRCPRE|UDC_TC_INTDONE|UDC_TC_TDELDAT|UDC_TC_TWRFLT;
! 557: hdc_writeregs(sc);
! 558:
! 559: /* Count up vars */
! 560: sc->sc_xfer = blks * DEV_BSIZE;
! 561:
! 562: ch = HDC_RSTAT; /* Avoid pending interrupts */
! 563: WAIT;
! 564: vsbus_clrintr(sc->sc_intbit); /* Clear pending int's */
! 565:
! 566: if (bp->b_flags & B_READ) {
! 567: HDC_WCMD(DKC_CMD_READ_HDD);
! 568: } else {
! 569: vsbus_copyfromproc(bp->b_proc, sc->sc_bufaddr, sc->sc_dmabase,
! 570: sc->sc_xfer);
! 571: HDC_WCMD(DKC_CMD_WRITE_HDD);
! 572: }
! 573: }
! 574:
! 575: void
! 576: hd_readgeom(struct hdcsoftc *sc, struct hdsoftc *hd)
! 577: {
! 578: struct hdc9224_UDCreg *p = &sc->sc_creg;
! 579:
! 580: hdc_hdselect(sc, hd->sc_drive); /* select drive right now */
! 581:
! 582: bzero(p, sizeof(struct hdc9224_UDCreg));
! 583:
! 584: p->udc_scnt = 1;
! 585: p->udc_rtcnt = UDC_RC_RTRYCNT;
! 586: p->udc_mode = UDC_MD_HDD;
! 587: p->udc_term = UDC_TC_CRCPRE|UDC_TC_INTDONE|UDC_TC_TDELDAT|UDC_TC_TWPROT;
! 588: hdc_writeregs(sc);
! 589: sc->sc_status = 0;
! 590: HDC_WCMD(DKC_CMD_READ_HDD|2);
! 591: while ((sc->sc_status & DKC_ST_INTPEND) == 0)
! 592: ;
! 593: bcopy(sc->sc_dmabase, &hd->sc_xbn, sizeof(struct hdgeom));
! 594: }
! 595:
! 596: #ifdef HDDEBUG
! 597: /*
! 598: * display the contents of the on-disk geometry structure
! 599: */
! 600: void
! 601: hdc_printgeom(p)
! 602: struct hdgeom *p;
! 603: {
! 604: printf("**DiskData** XBNs: %ld, DBNs: %ld, LBNs: %ld, RBNs: %ld\n",
! 605: p->xbn_count, p->dbn_count, p->lbn_count, p->rbn_count);
! 606: printf("sec/track: %d, tracks: %d, cyl: %d, precomp/reduced: %d/%d\n",
! 607: p->nspt, p->ntracks, p->ncylinders, p->precomp, p->reduced);
! 608: printf("seek-rate: %d, crc/eec: %s, RCT: %d, RCT-copies: %d\n",
! 609: p->seek_rate, p->crc_eec?"EEC":"CRC", p->rct, p->rct_ncopies);
! 610: printf("media-ID: %lx, interleave: %d, headskew: %d, cylskew: %d\n",
! 611: p->media_id, p->interleave, p->headskew, p->cylskew);
! 612: printf("gap0: %d, gap1: %d, gap2: %d, gap3: %d, sync-value: %d\n",
! 613: p->gap0_size, p->gap1_size, p->gap2_size, p->gap3_size,
! 614: p->sync_value);
! 615: }
! 616: #endif
! 617:
! 618: /*
! 619: * Return the size of a partition, if known, or -1 if not.
! 620: */
! 621: daddr64_t
! 622: hdsize(dev_t dev)
! 623: {
! 624: struct hdsoftc *hd;
! 625: int unit = DISKUNIT(dev);
! 626: int size;
! 627:
! 628: if (unit >= hd_cd.cd_ndevs || hd_cd.cd_devs[unit] == 0)
! 629: return -1;
! 630: hd = hd_cd.cd_devs[unit];
! 631: size = DL_GETPSIZE(&hd->sc_disk.dk_label->d_partitions[DISKPART(dev)]) *
! 632: (hd->sc_disk.dk_label->d_secsize / DEV_BSIZE);
! 633:
! 634: return (size);
! 635: }
! 636:
! 637: /*
! 638: *
! 639: */
! 640: int
! 641: hdopen(dev_t dev, int flag, int fmt, struct proc *p)
! 642: {
! 643: struct hdsoftc *hd;
! 644: int unit, part;
! 645:
! 646: unit = DISKUNIT(dev);
! 647: if (unit >= hd_cd.cd_ndevs)
! 648: return ENXIO;
! 649: hd = hd_cd.cd_devs[unit];
! 650: if (hd == 0)
! 651: return ENXIO;
! 652:
! 653: part = DISKPART(dev);
! 654: if (part >= hd->sc_disk.dk_label->d_npartitions)
! 655: return ENXIO;
! 656:
! 657: switch (fmt) {
! 658: case S_IFCHR:
! 659: hd->sc_disk.dk_copenmask |= (1 << part);
! 660: break;
! 661: case S_IFBLK:
! 662: hd->sc_disk.dk_bopenmask |= (1 << part);
! 663: break;
! 664: }
! 665: hd->sc_disk.dk_openmask =
! 666: hd->sc_disk.dk_copenmask | hd->sc_disk.dk_bopenmask;
! 667:
! 668: return 0;
! 669: }
! 670:
! 671: /*
! 672: *
! 673: */
! 674: int
! 675: hdclose(dev_t dev, int flag, int fmt, struct proc *p)
! 676: {
! 677: struct hdsoftc *hd;
! 678: int part;
! 679:
! 680: hd = hd_cd.cd_devs[DISKUNIT(dev)];
! 681: part = DISKPART(dev);
! 682:
! 683: switch (fmt) {
! 684: case S_IFCHR:
! 685: hd->sc_disk.dk_copenmask &= ~(1 << part);
! 686: break;
! 687: case S_IFBLK:
! 688: hd->sc_disk.dk_bopenmask &= ~(1 << part);
! 689: break;
! 690: }
! 691: hd->sc_disk.dk_openmask =
! 692: hd->sc_disk.dk_copenmask | hd->sc_disk.dk_bopenmask;
! 693:
! 694: return (0);
! 695: }
! 696:
! 697: /*
! 698: *
! 699: */
! 700: int
! 701: hdioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
! 702: {
! 703: struct hdsoftc *hd = hd_cd.cd_devs[DISKUNIT(dev)];
! 704: struct disklabel *lp = hd->sc_disk.dk_label;
! 705: int err = 0;
! 706:
! 707: switch (cmd) {
! 708: case DIOCGDINFO:
! 709: bcopy(lp, addr, sizeof (struct disklabel));
! 710: break;
! 711:
! 712: case DIOCGPART:
! 713: ((struct partinfo *)addr)->disklab = lp;
! 714: ((struct partinfo *)addr)->part =
! 715: &lp->d_partitions[DISKPART(dev)];
! 716: break;
! 717:
! 718: case DIOCWDINFO:
! 719: case DIOCSDINFO:
! 720: if ((flag & FWRITE) == 0)
! 721: return EBADF;
! 722: else
! 723: err = (cmd == DIOCSDINFO ?
! 724: setdisklabel(lp, (struct disklabel *)addr, 0) :
! 725: writedisklabel(dev, hdstrategy, lp));
! 726: break;
! 727:
! 728: case DIOCWLABEL:
! 729: if ((flag & FWRITE) == 0)
! 730: err = EBADF;
! 731: break;
! 732:
! 733: default:
! 734: err = ENOTTY;
! 735: break;
! 736: }
! 737: return err;
! 738: }
! 739:
! 740: /*
! 741: *
! 742: */
! 743: int
! 744: hdread(dev_t dev, struct uio *uio, int flag)
! 745: {
! 746: return (physio(hdstrategy, NULL, dev, B_READ, minphys, uio));
! 747: }
! 748:
! 749: /*
! 750: *
! 751: */
! 752: int
! 753: hdwrite(dev_t dev, struct uio *uio, int flag)
! 754: {
! 755: return (physio(hdstrategy, NULL, dev, B_WRITE, minphys, uio));
! 756: }
! 757:
! 758: /*
! 759: *
! 760: */
! 761: int
! 762: hddump(dev_t dev, daddr64_t daddr, caddr_t addr, size_t size)
! 763: {
! 764: return 0;
! 765: }
! 766:
! 767: /*
! 768: * we have to wait 0.7 usec between two accesses to any of the
! 769: * dkc-registers, on a VS2000 with 1 MIPS, this is roughly one
! 770: * instruction. Thus the loop-overhead will be enough...
! 771: */
! 772: void
! 773: hdc_readregs(struct hdcsoftc *sc)
! 774: {
! 775: int i;
! 776: char *p;
! 777:
! 778: HDC_WCMD(DKC_CMD_SETREGPTR);
! 779: WAIT;
! 780: p = (void *)&sc->sc_sreg;
! 781: for (i = 0; i < 10; i++) {
! 782: *p++ = HDC_RREG; /* dkc_reg auto-increments */
! 783: WAIT;
! 784: }
! 785: }
! 786:
! 787: void
! 788: hdc_writeregs(struct hdcsoftc *sc)
! 789: {
! 790: int i;
! 791: char *p;
! 792:
! 793: HDC_WCMD(DKC_CMD_SETREGPTR);
! 794: p = (void *)&sc->sc_creg;
! 795: for (i = 0; i < 10; i++) {
! 796: HDC_WREG(*p++); /* dkc_reg auto-increments */
! 797: WAIT;
! 798: }
! 799: }
! 800:
! 801: /*
! 802: * hdc_command() issues a command and polls the intreq-register
! 803: * to find when command has completed
! 804: */
! 805: int
! 806: hdc_command(struct hdcsoftc *sc, int cmd)
! 807: {
! 808: hdc_writeregs(sc); /* write the prepared registers */
! 809: HDC_WCMD(cmd);
! 810: WAIT;
! 811: return (0);
! 812: }
! 813:
! 814: int
! 815: hdc_hdselect(struct hdcsoftc *sc, int unit)
! 816: {
! 817: struct hdc9224_UDCreg *p = &sc->sc_creg;
! 818: int error;
! 819:
! 820: /*
! 821: * bring "creg" in some known-to-work state and
! 822: * select the drive with the DRIVE SELECT command.
! 823: */
! 824: bzero(p, sizeof(struct hdc9224_UDCreg));
! 825:
! 826: p->udc_rtcnt = UDC_RC_HDD_READ;
! 827: p->udc_mode = UDC_MD_HDD;
! 828: p->udc_term = UDC_TC_HDD;
! 829:
! 830: error = hdc_command(sc, DKC_CMD_DRSEL_HDD | unit);
! 831:
! 832: return (error);
! 833: }
! 834:
! 835: void
! 836: hdmakelabel(struct disklabel *dl, struct hdgeom *g)
! 837: {
! 838: int n, p = 0;
! 839:
! 840: dl->d_bbsize = BBSIZE;
! 841: dl->d_sbsize = SBSIZE;
! 842: dl->d_typename[p++] = MSCP_MID_CHAR(2, g->media_id);
! 843: dl->d_typename[p++] = MSCP_MID_CHAR(1, g->media_id);
! 844: if (MSCP_MID_ECH(0, g->media_id))
! 845: dl->d_typename[p++] = MSCP_MID_CHAR(0, g->media_id);
! 846: n = MSCP_MID_NUM(g->media_id);
! 847: if (n > 99) {
! 848: dl->d_typename[p++] = '1';
! 849: n -= 100;
! 850: }
! 851: if (n > 9) {
! 852: dl->d_typename[p++] = (n / 10) + '0';
! 853: n %= 10;
! 854: }
! 855: dl->d_typename[p++] = n + '0';
! 856: dl->d_typename[p] = 0;
! 857: dl->d_type = DTYPE_MSCP; /* XXX - what to use here??? */
! 858: dl->d_rpm = 3600;
! 859: dl->d_secsize = DEV_BSIZE;
! 860:
! 861: DL_SETDSIZE(dl, g->lbn_count);
! 862: dl->d_nsectors = g->nspt;
! 863: dl->d_ntracks = g->ntracks;
! 864: dl->d_secpercyl = dl->d_nsectors * dl->d_ntracks;
! 865: dl->d_ncylinders = DL_GETDSIZE(dl) / dl->d_secpercyl;
! 866:
! 867: dl->d_npartitions = MAXPARTITIONS;
! 868: DL_SETPSIZE(&dl->d_partitions[0], DL_GETDSIZE(dl));
! 869: DL_SETPSIZE(&dl->d_partitions[2], DL_GETDSIZE(dl));
! 870:
! 871: DL_SETPOFFSET(&dl->d_partitions[0], 0);
! 872: DL_SETPOFFSET(&dl->d_partitions[2], 0);
! 873: dl->d_interleave = dl->d_headswitch = 1;
! 874: dl->d_version = 1;
! 875: dl->d_magic = dl->d_magic2 = DISKMAGIC;
! 876: dl->d_checksum = dkcksum(dl);
! 877: }
CVSweb