home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (c) 1988 The Regents of the University of California.
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Harris Corp.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * @(#)hd.c 7.12 (Berkeley) 12/16/90
- */
-
- #include "hd.h"
-
- #if NHD > 0
- #include "sys/param.h"
- #include "sys/buf.h"
- #include "sys/conf.h"
- #include "sys/dkstat.h"
- #include "sys/disklabel.h"
- #include "sys/file.h"
- #include "sys/systm.h"
- #include "sys/vmmac.h"
- #include "sys/time.h"
- #include "sys/proc.h"
- #include "sys/uio.h"
- #include "sys/syslog.h"
- #include "sys/kernel.h"
- #include "sys/ioctl.h"
- #include "sys/stat.h"
- #include "sys/errno.h"
-
- #include "../include/cpu.h"
- #include "../include/mtpr.h"
-
- #include "../vba/vbavar.h"
- #include "../vba/hdreg.h"
-
- #define b_cylin b_resid
-
- #define hdunit(dev) (minor(dev)>>3)
- #define hdpart(dev) (minor(dev)&0x07)
- #define hdminor(unit, part) (((unit)<<3)|(part))
-
- struct vba_ctlr *hdcminfo[NHDC];
- struct vba_device *hddinfo[NHD];
- int hdcprobe(), hdslave(), hdattach(), hddgo(), hdstrategy();
- long hdstd[] = { 0 };
- struct vba_driver hdcdriver =
- { hdcprobe, hdslave, hdattach, hddgo, hdstd, "hd", hddinfo, "hdc", hdcminfo };
-
- /*
- * Per-controller state.
- */
- struct hdcsoftc {
- u_short hdc_flags;
- #define HDC_INIT 0x01 /* controller initialized */
- #define HDC_STARTED 0x02 /* start command issued */
- #define HDC_LOCKED 0x04 /* locked for direct controller access */
- #define HDC_WAIT 0x08 /* someone needs direct controller access */
- u_short hdc_wticks; /* timeout */
- struct master_mcb *hdc_mcbp; /* address of controller mcb */
- struct registers *hdc_reg; /* base address of i/o regs */
- struct vb_buf hdc_rbuf; /* vba resources */
- struct master_mcb hdc_mcb; /* controller mcb */
- } hdcsoftc[NHDC];
-
- #define HDCMAXTIME 20 /* max time for operation, sec. */
- #define HDCINTERRUPT 0xf0 /* interrupt vector */
-
- /*
- * Per-drive state; probably everything should be "hd_", not "dk_",
- * but it's not worth it, and dk is a better mnemonic for disk anyway.
- */
- struct dksoftc {
- #ifdef COMPAT_42
- u_short dk_def_cyl; /* definition track cylinder address */
- #endif
- int dk_state; /* open fsm */
- u_short dk_bshift; /* shift for * (DEV_BSIZE / sectorsize) XXX */
- int dk_wlabel; /* if label sector is writeable */
- u_long dk_copenpart; /* character units open on this drive */
- u_long dk_bopenpart; /* block units open on this drive */
- u_long dk_openpart; /* all units open on this drive */
- int dk_unit; /* unit# */
- int dk_ctlr; /* controller# */
- int dk_format; /* if format program is using disk */
- struct buf dk_utab; /* i/o queue header */
- struct disklabel dk_label; /* disklabel for this disk */
- struct mcb dk_mcb; /* disk mcb */
- } dksoftc[NHD];
-
- /*
- * Drive states. Used during steps of open/initialization.
- * States < OPEN (> 0) are transient, during an open operation.
- * OPENRAW is used for unlabeled disks, to allow format operations.
- */
- #define CLOSED 0 /* disk is closed */
- #define WANTOPEN 1 /* open requested, not started */
- #define WANTOPENRAW 2 /* open requested, no label */
- #define RDLABEL 3 /* reading pack label */
- #define OPEN 4 /* intialized and ready */
- #define OPENRAW 5 /* open, no label */
-
- int hdcwstart, hdcwatch();
-
- /* see if the controller is really there, if so, init it. */
- /* ARGSUSED */
- hdcprobe(reg, vm)
- caddr_t reg;
- /* register */ struct vba_ctlr *vm;
- {
- register int br, cvec; /* must be r12, r11 */
- register struct hdcsoftc *hdc;
- static struct module_id id;
- struct pte *dummypte;
- caddr_t putl;
-
- /* initialize the hdc controller structure. */
- hdc = &hdcsoftc[vm->um_ctlr];
- if (!vbmemalloc(1, reg, &dummypte, &putl)) {
- printf("hdc%d: vbmemalloc failed.\n", vm->um_ctlr);
- return(0);
- }
- hdc->hdc_reg = (struct registers *)putl;
-
- /*
- * try and ping the MID register; side effect of wbadaddr is to read
- * the module id; the controller is bad if it's not an hdc, the hdc's
- * writeable control store is not loaded, or the hdc failed the
- * functional integrity test;
- */
- if (wbadaddr(&hdc->hdc_reg->module_id, 4,
- vtoph((struct process *)NULL, &id)))
- return(0);
- DELAY(10000);
- mtpr(PADC, 0);
- if (id.module_id != (u_char)HDC_MID) {
- printf("hdc%d: bad module id; id = %x.\n",
- vm->um_ctlr, id.module_id);
- return(0);
- }
- if (id.code_rev == (u_char)0xff) {
- printf("hdc%d: micro-code not loaded.\n", vm->um_ctlr);
- return(0);
- }
- if (id.fit != (u_char)0xff) {
- printf("hdc%d: FIT test failed.\n", vm->um_ctlr);
- return(0);
- }
-
- /* reset that pup; flag as inited */
- hdc->hdc_reg->soft_reset = 0;
- DELAY(1000000);
- hdc->hdc_flags |= HDC_INIT;
-
- /* allocate page tables and i/o buffer. */
- if (!vbainit(&hdc->hdc_rbuf, MAXPHYS, VB_32BIT|VB_SCATTER)) {
- printf("hdc%d: vbainit failed\n", vm->um_ctlr);
- return (0);
- }
-
- /* set pointer to master control block */
- hdc->hdc_mcbp =
- (struct master_mcb *)vtoph((struct proc *)NULL, &hdc->hdc_mcb);
-
- br = 0x17, cvec = HDCINTERRUPT + vm->um_ctlr; /* XXX */
- return(sizeof(struct registers));
- }
-
- /* ARGSUSED */
- hdslave(vi, vdaddr)
- struct vba_device *vi;
- struct vddevice *vdaddr;
- {
- register struct mcb *mcb;
- register struct disklabel *lp;
- register struct dksoftc *dk;
- static struct status status;
-
- dk = &dksoftc[vi->ui_unit];
- dk->dk_unit = vi->ui_unit;
- dk->dk_ctlr = vi->ui_ctlr;
-
- mcb = &dk->dk_mcb;
- mcb->command = HCMD_STATUS;
- mcb->chain[0].wcount = sizeof(struct status) / sizeof(long);
- mcb->chain[0].memadr = (u_long)vtoph((struct process *)0, &status);
- if (hdimcb(dk)) {
- printf(" (no status)\n");
- return(0);
- }
-
- /*
- * Report the drive down if anything in the drive status looks bad.
- * If the drive is offline and it is not on cylinder, then the drive
- * is not there. If there is a fault condition, the hdc will try to
- * clear it when we read the disklabel information.
- */
- if (!(status.drs&DRS_ONLINE)) {
- if (status.drs&DRS_ON_CYLINDER)
- printf(" (not online)\n");
- return(0);
- }
- if (status.drs&DRS_FAULT)
- printf(" (clearing fault)");
-
- lp = &dk->dk_label;
- #ifdef RAW_SIZE
- lp->d_secsize = status.bytes_per_sec;
- #else
- lp->d_secsize = 512;
- #endif
- lp->d_nsectors = status.max_sector + 1;
- lp->d_ntracks = status.max_head + 1;
- lp->d_ncylinders = status.max_cyl + 1;
- lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
- lp->d_npartitions = 1;
- lp->d_partitions[0].p_offset = 0;
- lp->d_partitions[0].p_size = LABELSECTOR + 1;
- lp->d_rpm = status.rpm;
- lp->d_typename[0] = 'h';
- lp->d_typename[1] = 'd';
- lp->d_typename[2] = '\0';
- #ifdef COMPAT_42
- dk->dk_def_cyl = status.def_cyl;
- #endif
- return(1);
- }
-
- hdattach(vi)
- register struct vba_device *vi;
- {
- register struct dksoftc *dk;
- register struct disklabel *lp;
- register int unit;
-
- unit = vi->ui_unit;
- if (hdinit(hdminor(unit, 0), 0)) {
- printf(": unknown drive type");
- return;
- }
- dk = &dksoftc[unit];
- lp = &dk->dk_label;
- hd_setsecsize(dk, lp);
- if (dk->dk_state == OPEN)
- printf(": %s <secsize %d, ntrak %d, ncyl %d, nsec %d>",
- lp->d_typename, lp->d_secsize, lp->d_ntracks,
- lp->d_ncylinders, lp->d_nsectors);
-
- /*
- * (60 / rpm) / (sectors per track * (bytes per sector / 2))
- */
- if (vi->ui_dk >= 0)
- dk_wpms[vi->ui_dk] =
- (lp->d_rpm * lp->d_nsectors * lp->d_secsize) / 120;
- #ifdef notyet
- addswap(makedev(HDMAJOR, hdminor(unit, 0)), lp);
- #endif
- }
-
- hdopen(dev, flags, fmt)
- dev_t dev;
- int flags, fmt;
- {
- register struct disklabel *lp;
- register struct dksoftc *dk;
- register struct partition *pp;
- register int unit;
- struct vba_device *vi;
- int s, error, part = hdpart(dev), mask = 1 << part;
- daddr_t start, end;
-
- unit = hdunit(dev);
- if (unit >= NHD || (vi = hddinfo[unit]) == 0 || vi->ui_alive == 0)
- return(ENXIO);
- dk = &dksoftc[unit];
- lp = &dk->dk_label;
- s = spl7();
- while (dk->dk_state != OPEN && dk->dk_state != OPENRAW &&
- dk->dk_state != CLOSED)
- if (error = tsleep((caddr_t)dk, (PZERO+1) | PCATCH,
- devopn, 0)) {
- splx(s);
- return (error);
- }
- splx(s);
- if (dk->dk_state != OPEN && dk->dk_state != OPENRAW)
- if (error = hdinit(dev, flags))
- return(error);
-
- if (hdcwstart == 0) {
- timeout(hdcwatch, (caddr_t)0, hz);
- hdcwstart++;
- }
- /*
- * Warn if a partion is opened that overlaps another partition
- * which is open unless one is the "raw" partition (whole disk).
- */
- #define RAWPART 8 /* 'x' partition */ /* XXX */
- if ((dk->dk_openpart & mask) == 0 && part != RAWPART) {
- pp = &lp->d_partitions[part];
- start = pp->p_offset;
- end = pp->p_offset + pp->p_size;
- for (pp = lp->d_partitions;
- pp < &lp->d_partitions[lp->d_npartitions]; pp++) {
- if (pp->p_offset + pp->p_size <= start ||
- pp->p_offset >= end)
- continue;
- if (pp - lp->d_partitions == RAWPART)
- continue;
- if (dk->dk_openpart & (1 << (pp - lp->d_partitions)))
- log(LOG_WARNING,
- "hd%d%c: overlaps open partition (%c)\n",
- unit, part + 'a',
- pp - lp->d_partitions + 'a');
- }
- }
- if (part >= lp->d_npartitions)
- return(ENXIO);
- dk->dk_openpart |= mask;
- switch (fmt) {
- case S_IFCHR:
- dk->dk_copenpart |= mask;
- break;
- case S_IFBLK:
- dk->dk_bopenpart |= mask;
- break;
- }
- return(0);
- }
-
- /* ARGSUSED */
- hdclose(dev, flags, fmt)
- dev_t dev;
- int flags, fmt;
- {
- register struct dksoftc *dk;
- int mask;
-
- dk = &dksoftc[hdunit(dev)];
- mask = 1 << hdpart(dev);
- switch (fmt) {
- case S_IFCHR:
- dk->dk_copenpart &= ~mask;
- break;
- case S_IFBLK:
- dk->dk_bopenpart &= ~mask;
- break;
- }
- if (((dk->dk_copenpart | dk->dk_bopenpart) & mask) == 0)
- dk->dk_openpart &= ~mask;
- /*
- * Should wait for i/o to complete on this partition
- * even if others are open, but wait for work on blkflush().
- */
- if (dk->dk_openpart == 0) {
- int s = spl7();
- while (dk->dk_utab.b_actf)
- sleep((caddr_t)dk, PZERO-1);
- splx(s);
- dk->dk_state = CLOSED;
- dk->dk_wlabel = 0;
- }
- return(0);
- }
-
- hdinit(dev, flags)
- dev_t dev;
- int flags;
- {
- register struct dksoftc *dk;
- register struct disklabel *lp;
- struct vba_device *vi;
- int error, unit;
- char *msg, *readdisklabel();
- extern int cold;
-
- vi = hddinfo[unit = hdunit(dev)];
- dk = &dksoftc[unit];
- dk->dk_unit = vi->ui_slave;
- dk->dk_ctlr = vi->ui_ctlr;
-
- if (flags & O_NDELAY) {
- dk->dk_state = OPENRAW;
- return(0);
- }
-
- error = 0;
- lp = &dk->dk_label;
- dk->dk_state = RDLABEL;
- if (msg = readdisklabel(dev, hdstrategy, lp)) {
- if (cold) {
- printf(": %s\n", msg);
- dk->dk_state = CLOSED;
- } else {
- log(LOG_ERR, "hd%d: %s\n", unit, msg);
- dk->dk_state = OPENRAW;
- }
- #ifdef COMPAT_42
- hdclock(vi->ui_ctlr);
- if (!(error = hdreadgeometry(dk)))
- dk->dk_state = OPEN;
- hdcunlock(vi->ui_ctlr);
- #endif
- } else
- dk->dk_state = OPEN;
- wakeup((caddr_t)dk);
- return(error);
- }
-
- hd_setsecsize(dk, lp)
- register struct dksoftc *dk;
- struct disklabel *lp;
- {
- register int mul;
-
- /*
- * Calculate scaling shift for mapping
- * DEV_BSIZE blocks to drive sectors.
- */
- mul = DEV_BSIZE / lp->d_secsize;
- dk->dk_bshift = 0;
- while ((mul >>= 1) > 0)
- dk->dk_bshift++;
- }
-
- /* ARGSUSED */
- hddgo(vm)
- struct vba_device *vm;
- {}
-
- extern int name_ext;
- hdstrategy(bp)
- register struct buf *bp;
- {
- register struct vba_device *vi;
- register struct disklabel *lp;
- register struct dksoftc *dk;
- struct buf *dp;
- register int unit;
- daddr_t sn, sz, maxsz;
- int part, s;
-
- vi = hddinfo[unit = hdunit(bp->b_dev)];
- if (unit >= NHD || vi == 0 || vi->ui_alive == 0) {
- bp->b_error = ENXIO;
- goto bad;
- }
- dk = &dksoftc[unit];
- if (dk->dk_state < OPEN)
- goto q;
- if (dk->dk_state != OPEN && (bp->b_flags & B_READ) == 0) {
- bp->b_error = EROFS;
- goto bad;
- }
- part = hdpart(bp->b_dev);
- if ((dk->dk_openpart & (1 << part)) == 0) {
- bp->b_error = ENODEV;
- goto bad;
- }
- lp = &dk->dk_label;
- sz = (bp->b_bcount + lp->d_secsize - 1) / lp->d_secsize;
- maxsz = lp->d_partitions[part].p_size;
- sn = bp->b_blkno << dk->dk_bshift;
- if (sn + lp->d_partitions[part].p_offset <= LABELSECTOR &&
- #if LABELSECTOR != 0
- sn + lp->d_partitions[part].p_offset + sz > LABELSECTOR &&
- #endif
- (bp->b_flags & B_READ) == 0 && dk->dk_wlabel == 0) {
- bp->b_error = EROFS;
- goto bad;
- }
- if (sn < 0 || sn + sz > maxsz) {
- if (sn == maxsz) {
- bp->b_resid = bp->b_bcount;
- goto done;
- }
- sz = maxsz - sn;
- if (sz <= 0) {
- bp->b_error = EINVAL;
- goto bad;
- }
- bp->b_bcount = sz * lp->d_secsize;
- }
- bp->b_cylin = (sn + lp->d_partitions[part].p_offset) / lp->d_secpercyl;
-
- q: s = spl7();
- dp = &dk->dk_utab;
- disksort(dp, bp);
- if (!dp->b_active) {
- (void)hdustart(vi);
- if (!vi->ui_mi->um_tab.b_active)
- hdcstart(vi->ui_mi);
- }
- splx(s);
- return;
- bad:
- bp->b_flags |= B_ERROR;
- done:
- biodone(bp);
- }
-
- hdustart(vi)
- register struct vba_device *vi;
- {
- register struct buf *bp, *dp;
- register struct vba_ctlr *vm;
- register struct dksoftc *dk;
-
- dk = &dksoftc[vi->ui_unit];
- dp = &dk->dk_utab;
-
- /* if queue empty, nothing to do. impossible? */
- if (dp->b_actf == NULL)
- return;
-
- /* place on controller transfer queue */
- vm = vi->ui_mi;
- if (vm->um_tab.b_actf == NULL)
- vm->um_tab.b_actf = dp;
- else
- vm->um_tab.b_actl->b_forw = dp;
- vm->um_tab.b_actl = dp;
- dp->b_forw = NULL;
- dp->b_active++;
- }
-
- hdcstart(vm)
- register struct vba_ctlr *vm;
- {
- register struct buf *bp;
- register struct dksoftc *dk;
- register struct disklabel *lp;
- register struct master_mcb *master;
- register struct mcb *mcb;
- struct vba_device *vi;
- struct hdcsoftc *hdc;
- struct buf *dp;
- int sn;
-
- /* pull a request off the controller queue */
- for (;;) {
- if ((dp = vm->um_tab.b_actf) == NULL)
- return;
- if (bp = dp->b_actf)
- break;
- vm->um_tab.b_actf = dp->b_forw;
- }
-
- /* mark controller active */
- vm->um_tab.b_active++;
-
- vi = hddinfo[hdunit(bp->b_dev)];
- dk = &dksoftc[vi->ui_unit];
- lp = &dk->dk_label;
- sn = bp->b_blkno << dk->dk_bshift;
-
- /* fill in mcb */
- mcb = &dk->dk_mcb;
- mcb->forw_phaddr = 0;
- /* mcb->priority = 0; */
- mcb->interrupt = 1;
- mcb->command = (bp->b_flags & B_READ) ? HCMD_READ:HCMD_WRITE;
- mcb->cyl = bp->b_cylin;
- /* assumes partition starts on cylinder boundary */
- mcb->head = (sn / lp->d_nsectors) % lp->d_ntracks;
- mcb->sector = sn % lp->d_nsectors;
- mcb->drive = vi->ui_slave;
- /* mcb->context = 0; /* what do we want on interrupt? */
-
- hdc = &hdcsoftc[vm->um_ctlr];
- if (!hd_sgsetup(bp, &hdc->hdc_rbuf, mcb->chain)) {
- mcb->chain[0].wcount = (bp->b_bcount+3) >> 2;
- mcb->chain[0].memadr =
- vbasetup(bp, &hdc->hdc_rbuf, (int)lp->d_secsize);
- }
-
- if (vi->ui_dk >= 0) {
- dk_busy |= 1<<vi->ui_dk;
- dk_xfer[vi->ui_dk]++;
- dk_wds[vi->ui_dk] += bp->b_bcount>>6;
- }
-
- master = &hdc->hdc_mcb;
- master->mcw = MCL_QUEUED;
- master->interrupt = HDCINTERRUPT + vm->um_ctlr;
- master->forw_phaddr = (u_long)vtoph((struct proc *)NULL, mcb);
- hdc->hdc_reg->master_mcb = (u_long)hdc->hdc_mcbp;
- }
-
- /*
- * Wait for controller to finish current operation
- * so that direct controller accesses can be done.
- */
- hdclock(ctlr)
- int ctlr;
- {
- register struct vba_ctlr *vm = hdcminfo[ctlr];
- register struct hdcsoftc *hdc;
- int s;
-
- hdc = &hdcsoftc[ctlr];
- s = spl7();
- while (vm->um_tab.b_active || hdc->hdc_flags & HDC_LOCKED) {
- hdc->hdc_flags |= HDC_WAIT;
- sleep((caddr_t)hdc, PRIBIO);
- }
- hdc->hdc_flags |= HDC_LOCKED;
- splx(s);
- }
-
- /*
- * Continue normal operations after pausing for
- * munging the controller directly.
- */
- hdcunlock(ctlr)
- int ctlr;
- {
- register struct vba_ctlr *vm;
- register struct hdcsoftc *hdc = &hdcsoftc[ctlr];
-
- hdc->hdc_flags &= ~HDC_LOCKED;
- if (hdc->hdc_flags & HDC_WAIT) {
- hdc->hdc_flags &= ~HDC_WAIT;
- wakeup((caddr_t)hdc);
- } else {
- vm = hdcminfo[ctlr];
- if (vm->um_tab.b_actf)
- hdcstart(vm);
- }
- }
-
- hdintr(ctlr)
- int ctlr;
- {
- register struct buf *bp, *dp;
- register struct vba_ctlr *vm;
- register struct vba_device *vi;
- register struct hdcsoftc *hdc;
- register struct mcb *mcb;
- struct master_mcb *master;
- register int status;
- int timedout;
- struct dksoftc *dk;
-
- hdc = &hdcsoftc[ctlr];
- master = &hdc->hdc_mcb;
- uncache(&master->mcs);
- uncache(&master->context);
-
- vm = hdcminfo[ctlr];
- if (!vm->um_tab.b_active || !(master->mcs&MCS_DONE)) {
- printf("hd%d: stray interrupt\n", ctlr);
- return;
- }
-
- dp = vm->um_tab.b_actf;
- bp = dp->b_actf;
- vi = hddinfo[hdunit(bp->b_dev)];
- dk = &dksoftc[vi->ui_unit];
- if (vi->ui_dk >= 0)
- dk_busy &= ~(1<<vi->ui_dk);
- timedout = (hdc->hdc_wticks >= HDCMAXTIME);
-
- mcb = &dk->dk_mcb;
-
- if (master->mcs & (MCS_SOFTERROR | MCS_FATALERROR) || timedout)
- hdcerror(ctlr, *(u_long *)master->xstatus);
- else
- hdc->hdc_wticks = 0;
- if (vm->um_tab.b_active) {
- vm->um_tab.b_active = 0;
- vm->um_tab.b_actf = dp->b_forw;
- dp->b_active = 0;
- dp->b_errcnt = 0;
- dp->b_actf = bp->av_forw;
- bp->b_resid = 0;
- vbadone(bp, &hdc->hdc_rbuf);
- biodone(bp);
- /* start up now, if more work to do */
- if (dp->b_actf)
- hdustart(vi);
- else if (dk->dk_openpart == 0)
- wakeup((caddr_t)dk);
- }
- /* if there are devices ready to transfer, start the controller. */
- if (hdc->hdc_flags & HDC_WAIT) {
- hdc->hdc_flags &= ~HDC_WAIT;
- wakeup((caddr_t)hdc);
- } else if (vm->um_tab.b_actf)
- hdcstart(vm);
- }
-
- hdioctl(dev, cmd, data, flag)
- dev_t dev;
- int cmd, flag;
- caddr_t data;
- {
- register int unit;
- register struct dksoftc *dk;
- register struct disklabel *lp;
- int error;
-
- unit = hdunit(dev);
- dk = &dksoftc[unit];
- lp = &dk->dk_label;
- error = 0;
- switch (cmd) {
- case DIOCGDINFO:
- *(struct disklabel *)data = *lp;
- break;
- case DIOCGPART:
- ((struct partinfo *)data)->disklab = lp;
- ((struct partinfo *)data)->part =
- &lp->d_partitions[hdpart(dev)];
- break;
- case DIOCSDINFO:
- if ((flag & FWRITE) == 0)
- error = EBADF;
- else
- error = setdisklabel(lp, (struct disklabel *)data,
- (dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart);
- if (error == 0 && dk->dk_state == OPENRAW)
- dk->dk_state = OPEN;
- break;
- case DIOCWLABEL:
- if ((flag & FWRITE) == 0)
- error = EBADF;
- else
- dk->dk_wlabel = *(int *)data;
- break;
- case DIOCWDINFO:
- if ((flag & FWRITE) == 0)
- error = EBADF;
- else if ((error = setdisklabel(lp, (struct disklabel *)data,
- (dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart)) == 0) {
- int wlab;
-
- if (error == 0 && dk->dk_state == OPENRAW)
- dk->dk_state = OPEN;
- /* simulate opening partition 0 so write succeeds */
- dk->dk_openpart |= (1 << 0); /* XXX */
- wlab = dk->dk_wlabel;
- dk->dk_wlabel = 1;
- error = writedisklabel(dev, hdstrategy, lp);
- dk->dk_openpart = dk->dk_copenpart | dk->dk_bopenpart;
- dk->dk_wlabel = wlab;
- }
- break;
- default:
- error = ENOTTY;
- break;
- }
- return (error);
- }
-
- /*
- * Watch for lost interrupts.
- */
- hdcwatch()
- {
- register struct hdcsoftc *hdc;
- register struct vba_ctlr **vmp;
- register int ctlr;
- int s;
-
- timeout(hdcwatch, (caddr_t)0, hz);
- for (vmp = hdcminfo, hdc = hdcsoftc, ctlr = 0; ctlr < NHDC;
- ++ctlr, ++vmp, ++hdc) {
- if (*vmp == 0 || (*vmp)->um_alive == 0)
- continue;
- s = spl7();
- if ((*vmp)->um_tab.b_active &&
- hdc->hdc_wticks++ >= HDCMAXTIME) {
- printf("hd%d: lost interrupt\n", ctlr);
- hdintr(ctlr);
- }
- splx(s);
- }
- }
-
- hddump(dev)
- dev_t dev;
- {
- return(ENXIO);
- }
-
- hdsize(dev)
- dev_t dev;
- {
- register int unit = hdunit(dev);
- register struct dksoftc *dk;
- struct vba_device *vi;
- struct disklabel *lp;
-
- if (unit >= NHD || (vi = hddinfo[unit]) == 0 || vi->ui_alive == 0 ||
- (dk = &dksoftc[unit])->dk_state != OPEN)
- return (-1);
- lp = &dk->dk_label;
- return ((int)lp->d_partitions[hdpart(dev)].p_size >> dk->dk_bshift);
- }
-
- hdimcb(dk)
- register struct dksoftc *dk;
- {
- register struct master_mcb *master;
- register struct mcb *mcb;
- register struct hdcsoftc *hdc;
- int timeout;
-
- /* fill in mcb */
- mcb = &dk->dk_mcb;
- mcb->interrupt = 0;
- mcb->forw_phaddr = 0;
- mcb->drive = dk->dk_unit;
-
- hdc = &hdcsoftc[dk->dk_ctlr];
- master = &hdc->hdc_mcb;
-
- /* fill in master mcb */
- master->mcw = MCL_IMMEDIATE;
- master->forw_phaddr = (u_long)vtoph((struct proc *)NULL, mcb);
- master->mcs = 0;
-
- /* kick controller and wait */
- hdc->hdc_reg->master_mcb = (u_long)hdc->hdc_mcbp;
- for (timeout = 15000; timeout; --timeout) {
- DELAY(1000);
- mtpr(PADC, 0);
- if (master->mcs&MCS_FATALERROR) {
- printf("hdc%d: fatal error\n", dk->dk_ctlr);
- hdcerror(dk->dk_ctlr, *(u_long *)master->xstatus);
- return(1);
- }
- if (master->mcs&MCS_DONE)
- return(0);
- }
- printf("hdc%d: timed out\n", dk->dk_ctlr);
- return(1);
- }
-
- hdcerror(ctlr, code)
- int ctlr;
- u_long code;
- {
- printf("hd%d: error %lx\n", ctlr, code);
- }
-
- #ifdef COMPAT_42
- hdreadgeometry(dk)
- struct dksoftc *dk;
- {
- static geometry_sector geometry;
- register struct mcb *mcb;
- register struct disklabel *lp;
- geometry_block *geo;
- int cnt;
-
- /*
- * Read the geometry block (at head = 0 sector = 0 of the drive
- * definition cylinder), validate it (must have the correct version
- * number, header, and checksum).
- */
- mcb = &dk->dk_mcb;
- mcb->command = HCMD_READ;
- mcb->cyl = dk->dk_def_cyl;
- mcb->head = 0;
- mcb->sector = 0;
- mcb->chain[0].wcount = sizeof(geometry_sector) / sizeof(long);
- mcb->chain[0].memadr = (u_long)vtoph((struct process *)0, &geometry);
- /* mcb->chain[0].memadr = (long)&geometry; */
- if (hdimcb(dk)) {
- printf("hd%d: can't read default geometry.\n", dk->dk_unit);
- return(1);
- }
- geo = &geometry.geometry_block;
- if (geo->version > 64000 || geo->version < 0) {
- printf("hd%d: bad default geometry version#.\n", dk->dk_unit);
- return(1);
- }
- if (bcmp(&geo->id[0], GB_ID, GB_ID_LEN)) {
- printf("hd%d: bad default geometry header.\n", dk->dk_unit);
- return(1);
- }
- GB_CHECKSUM(geo, cnt);
- if (geometry.checksum != cnt) {
- printf("hd%d: bad default geometry checksum.\n", dk->dk_unit);
- return(1);
- }
- lp = &dk->dk_label;
-
- /* 1K block in Harris geometry; convert to sectors for disklabels */
- for (cnt = 0; cnt < GB_MAXPART; cnt++) {
- lp->d_partitions[cnt].p_offset =
- geo->partition[cnt].start * (1024 / lp->d_secsize);
- lp->d_partitions[cnt].p_size =
- geo->partition[cnt].length * (1024 / lp->d_secsize);
- }
- lp->d_npartitions = GB_MAXPART;
- return(0);
- }
- #endif /* COMPAT_42 */
- #endif /* NHD */
-