summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorragge <ragge@NetBSD.org>1999-05-29 19:11:41 +0000
committerragge <ragge@NetBSD.org>1999-05-29 19:11:41 +0000
commit29cdff1acd9aa06a295ff493e64f94651a3a31d7 (patch)
tree982055baa47e75f8239946b9f8464a14273728a5 /sys/dev
parent6c8c62c541846b3cae136382df6a27947e8a0adc (diff)
Copied from ../../arch/vax/mscp/mscp_disk.c,v
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/mscp/mscp_disk.c1008
1 files changed, 1008 insertions, 0 deletions
diff --git a/sys/dev/mscp/mscp_disk.c b/sys/dev/mscp/mscp_disk.c
new file mode 100644
index 00000000000..e1a2ea8db07
--- /dev/null
+++ b/sys/dev/mscp/mscp_disk.c
@@ -0,0 +1,1008 @@
+/* $NetBSD: mscp_disk.c,v 1.20 1999/05/29 19:11:41 ragge Exp $ */
+/*
+ * Copyright (c) 1996 Ludd, University of Lule}, Sweden.
+ * Copyright (c) 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * 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.
+ *
+ * @(#)uda.c 7.32 (Berkeley) 2/13/91
+ */
+
+/*
+ * RA disk device driver
+ * RX MSCP floppy disk device driver
+ */
+
+/*
+ * TODO
+ * write bad block forwarding code
+ */
+
+#include <sys/param.h>
+#include <sys/buf.h>
+#include <sys/device.h>
+#include <sys/disk.h>
+#include <sys/disklabel.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/fcntl.h>
+#include <sys/reboot.h>
+#include <sys/proc.h>
+#include <sys/systm.h>
+
+#include <ufs/ufs/dinode.h>
+#include <ufs/ffs/fs.h>
+
+#include <machine/cpu.h>
+#include <machine/rpb.h>
+
+#include <vax/mscp/mscp.h>
+#include <vax/mscp/mscpvar.h>
+
+#include "locators.h"
+#include "ioconf.h"
+#include "ra.h"
+
+#define RAMAJOR 9 /* RA major device number XXX */
+
+/*
+ * Drive status, per drive
+ */
+struct ra_softc {
+ struct device ra_dev; /* Autoconf struct */
+ struct disk ra_disk;
+ int ra_state; /* open/closed state */
+ u_long ra_mediaid; /* media id */
+ int ra_hwunit; /* Hardware unit number */
+ int ra_havelabel; /* true if we have a label */
+ int ra_wlabel; /* label sector is currently writable */
+};
+
+#define rx_softc ra_softc
+
+void rxattach __P((struct device *, struct device *, void *));
+int rx_putonline __P((struct rx_softc *));
+void rrmakelabel __P((struct disklabel *, long));
+
+#if NRA
+
+int ramatch __P((struct device *, struct cfdata *, void *));
+void raattach __P((struct device *, struct device *, void *));
+int raopen __P((dev_t, int, int, struct proc *));
+int raclose __P((dev_t, int, int, struct proc *));
+void rastrategy __P((struct buf *));
+int raread __P((dev_t, struct uio *));
+int rawrite __P((dev_t, struct uio *));
+int raioctl __P((dev_t, int, caddr_t, int, struct proc *));
+int radump __P((dev_t, daddr_t, caddr_t, size_t));
+int rasize __P((dev_t));
+int ra_putonline __P((struct ra_softc *));
+
+struct cfattach ra_ca = {
+ sizeof(struct ra_softc), ramatch, raattach
+};
+
+/*
+ * More driver definitions, for generic MSCP code.
+ */
+
+int
+ramatch(parent, cf, aux)
+ struct device *parent;
+ struct cfdata *cf;
+ void *aux;
+{
+ struct drive_attach_args *da = aux;
+ struct mscp *mp = da->da_mp;
+
+ if ((da->da_typ & MSCPBUS_DISK) == 0)
+ return 0;
+ if (cf->cf_loc[MSCPBUSCF_DRIVE] != MSCPBUSCF_DRIVE_DEFAULT &&
+ cf->cf_loc[MSCPBUSCF_DRIVE] != mp->mscp_unit)
+ return 0;
+ /*
+ * Check if this disk is a floppy; then don't configure it.
+ * Seems to be a safe way to test it per Chris Torek.
+ */
+ if (MSCP_MID_ECH(1, mp->mscp_guse.guse_mediaid) == 'X' - '@')
+ return 0;
+ return 1;
+}
+
+/*
+ * The attach routine only checks and prints drive type.
+ * Bringing the disk online is done when the disk is accessed
+ * the first time.
+ */
+void
+raattach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct ra_softc *ra = (void *)self;
+ struct mscp_softc *mi = (void *)parent;
+
+ rxattach(parent, self, aux);
+ /*
+ * Find out if we booted from this disk.
+ */
+ if ((B_TYPE(bootdev) == BDEV_UDA) && (ra->ra_hwunit == B_UNIT(bootdev))
+ && (mi->mi_ctlrnr == B_CONTROLLER(bootdev))
+ && (mi->mi_adapnr == B_ADAPTOR(bootdev)))
+ booted_from = self;
+}
+
+/*
+ * (Try to) put the drive online. This is done the first time the
+ * drive is opened, or if it har fallen offline.
+ */
+int
+ra_putonline(ra)
+ struct ra_softc *ra;
+{
+ struct disklabel *dl;
+ char *msg;
+
+ if (rx_putonline(ra) != MSCP_DONE)
+ return MSCP_FAILED;
+
+ dl = ra->ra_disk.dk_label;
+
+ ra->ra_state = DK_RDLABEL;
+ printf("%s", ra->ra_dev.dv_xname);
+ if ((msg = readdisklabel(MAKEDISKDEV(RAMAJOR, ra->ra_dev.dv_unit,
+ RAW_PART), rastrategy, dl, NULL)) != NULL)
+ printf(": %s", msg);
+ else {
+ ra->ra_havelabel = 1;
+ ra->ra_state = DK_OPEN;
+ }
+
+ printf(": size %d sectors\n", dl->d_secperunit);
+
+ return MSCP_DONE;
+}
+
+/*
+ * Open a drive.
+ */
+/*ARGSUSED*/
+int
+raopen(dev, flag, fmt, p)
+ dev_t dev;
+ int flag, fmt;
+ struct proc *p;
+{
+ register struct ra_softc *ra;
+ int part, unit, mask;
+ /*
+ * Make sure this is a reasonable open request.
+ */
+ unit = DISKUNIT(dev);
+ if (unit >= ra_cd.cd_ndevs)
+ return ENXIO;
+ ra = ra_cd.cd_devs[unit];
+ if (ra == 0)
+ return ENXIO;
+
+ /*
+ * If this is the first open; we must first try to put
+ * the disk online (and read the label).
+ */
+ if (ra->ra_state == DK_CLOSED)
+ if (ra_putonline(ra) == MSCP_FAILED)
+ return ENXIO;
+
+ /* If the disk has no label; allow writing everywhere */
+ if (ra->ra_havelabel == 0)
+ ra->ra_wlabel = 1;
+
+ part = DISKPART(dev);
+ if (part >= ra->ra_disk.dk_label->d_npartitions)
+ return ENXIO;
+
+ /*
+ * Wait for the state to settle
+ */
+#if notyet
+ while (ra->ra_state != DK_OPEN)
+ if ((error = tsleep((caddr_t)ra, (PZERO + 1) | PCATCH,
+ devopn, 0))) {
+ splx(s);
+ return (error);
+ }
+#endif
+
+ mask = 1 << part;
+
+ switch (fmt) {
+ case S_IFCHR:
+ ra->ra_disk.dk_copenmask |= mask;
+ break;
+ case S_IFBLK:
+ ra->ra_disk.dk_bopenmask |= mask;
+ break;
+ }
+ ra->ra_disk.dk_openmask |= mask;
+ return 0;
+}
+
+/* ARGSUSED */
+int
+raclose(dev, flags, fmt, p)
+ dev_t dev;
+ int flags, fmt;
+ struct proc *p;
+{
+ register int unit = DISKUNIT(dev);
+ register struct ra_softc *ra = ra_cd.cd_devs[unit];
+ int mask = (1 << DISKPART(dev));
+
+ switch (fmt) {
+ case S_IFCHR:
+ ra->ra_disk.dk_copenmask &= ~mask;
+ break;
+ case S_IFBLK:
+ ra->ra_disk.dk_bopenmask &= ~mask;
+ break;
+ }
+ ra->ra_disk.dk_openmask =
+ ra->ra_disk.dk_copenmask | ra->ra_disk.dk_bopenmask;
+
+ /*
+ * Should wait for I/O to complete on this partition even if
+ * others are open, but wait for work on blkflush().
+ */
+#if notyet
+ if (ra->ra_openpart == 0) {
+ s = splbio();
+ while (udautab[unit].b_actf)
+ sleep((caddr_t)&udautab[unit], PZERO - 1);
+ splx(s);
+ ra->ra_state = CLOSED;
+ ra->ra_wlabel = 0;
+ }
+#endif
+ return (0);
+}
+
+/*
+ * Queue a transfer request, and if possible, hand it to the controller.
+ */
+void
+rastrategy(bp)
+ register struct buf *bp;
+{
+ register int unit;
+ register struct ra_softc *ra;
+ /*
+ * Make sure this is a reasonable drive to use.
+ */
+ unit = DISKUNIT(bp->b_dev);
+ if (unit > ra_cd.cd_ndevs || (ra = ra_cd.cd_devs[unit]) == NULL) {
+ bp->b_error = ENXIO;
+ bp->b_flags |= B_ERROR;
+ goto done;
+ }
+ /*
+ * If drive is open `raw' or reading label, let it at it.
+ */
+ if (ra->ra_state == DK_RDLABEL) {
+ mscp_strategy(bp, ra->ra_dev.dv_parent);
+ return;
+ }
+
+ /* If disk is not online, try to put it online */
+ if (ra->ra_state == DK_CLOSED)
+ if (ra_putonline(ra) == MSCP_FAILED) {
+ bp->b_flags |= B_ERROR;
+ bp->b_error = EIO;
+ goto done;
+ }
+
+ /*
+ * Determine the size of the transfer, and make sure it is
+ * within the boundaries of the partition.
+ */
+ if (bounds_check_with_label(bp, ra->ra_disk.dk_label,
+ ra->ra_wlabel) <= 0)
+ goto done;
+
+ /* Make some statistics... /bqt */
+ ra->ra_disk.dk_xfer++;
+ ra->ra_disk.dk_bytes += bp->b_bcount;
+ mscp_strategy(bp, ra->ra_dev.dv_parent);
+ return;
+
+done:
+ biodone(bp);
+}
+
+int
+raread(dev, uio)
+ dev_t dev;
+ struct uio *uio;
+{
+
+ return (physio(rastrategy, NULL, dev, B_READ, minphys, uio));
+}
+
+int
+rawrite(dev, uio)
+ dev_t dev;
+ struct uio *uio;
+{
+
+ return (physio(rastrategy, NULL, dev, B_WRITE, minphys, uio));
+}
+
+/*
+ * I/O controls.
+ */
+int
+raioctl(dev, cmd, data, flag, p)
+ dev_t dev;
+ int cmd;
+ caddr_t data;
+ int flag;
+ struct proc *p;
+{
+ register int unit = DISKUNIT(dev);
+ register struct disklabel *lp, *tp;
+ register struct ra_softc *ra = ra_cd.cd_devs[unit];
+ int error = 0;
+
+ lp = ra->ra_disk.dk_label;
+
+ switch (cmd) {
+
+ case DIOCGDINFO:
+ bcopy(lp, data, sizeof (struct disklabel));
+ break;
+
+ case DIOCGPART:
+ ((struct partinfo *)data)->disklab = lp;
+ ((struct partinfo *)data)->part =
+ &lp->d_partitions[DISKPART(dev)];
+ break;
+
+ case DIOCWDINFO:
+ case DIOCSDINFO:
+ if ((flag & FWRITE) == 0)
+ error = EBADF;
+ else {
+ error = setdisklabel(lp, (struct disklabel *)data,0,0);
+ if ((error == 0) && (cmd == DIOCWDINFO)) {
+ ra->ra_wlabel = 1;
+ error = writedisklabel(dev, rastrategy, lp,0);
+ ra->ra_wlabel = 0;
+ }
+ }
+ break;
+
+ case DIOCWLABEL:
+ if ((flag & FWRITE) == 0)
+ error = EBADF;
+ else
+ ra->ra_wlabel = 1;
+ break;
+
+ case DIOCGDEFLABEL:
+ tp = (struct disklabel *)data;
+ bzero(data, sizeof(struct disklabel));
+ tp->d_secsize = lp->d_secsize;
+ tp->d_nsectors = lp->d_nsectors;
+ tp->d_ntracks = lp->d_ntracks;
+ tp->d_ncylinders = lp->d_ncylinders;
+ tp->d_secpercyl = lp->d_secpercyl;
+ tp->d_secperunit = lp->d_secperunit;
+ tp->d_type = DTYPE_MSCP;
+ tp->d_rpm = 3600;
+ rrmakelabel(tp, ra->ra_mediaid);
+ break;
+
+ default:
+ error = ENOTTY;
+ break;
+ }
+ return (error);
+}
+
+
+int
+radump(dev, blkno, va, size)
+ dev_t dev;
+ daddr_t blkno;
+ caddr_t va;
+ size_t size;
+{
+ return ENXIO;
+}
+
+/*
+ * Return the size of a partition, if known, or -1 if not.
+ */
+int
+rasize(dev)
+ dev_t dev;
+{
+ register int unit = DISKUNIT(dev);
+ struct ra_softc *ra;
+
+ if (unit >= ra_cd.cd_ndevs || ra_cd.cd_devs[unit] == 0)
+ return -1;
+
+ ra = ra_cd.cd_devs[unit];
+
+ if (ra->ra_state == DK_CLOSED)
+ if (ra_putonline(ra) == MSCP_FAILED)
+ return -1;
+
+ return ra->ra_disk.dk_label->d_partitions[DISKPART(dev)].p_size *
+ (ra->ra_disk.dk_label->d_secsize / DEV_BSIZE);
+}
+
+#endif /* NRA */
+
+#if NRX
+
+int rxmatch __P((struct device *, struct cfdata *, void *));
+int rxopen __P((dev_t, int, int, struct proc *));
+int rxclose __P((dev_t, int, int, struct proc *));
+void rxstrategy __P((struct buf *));
+int rxread __P((dev_t, struct uio *));
+int rxwrite __P((dev_t, struct uio *));
+int rxioctl __P((dev_t, int, caddr_t, int, struct proc *));
+int rxdump __P((dev_t, daddr_t, caddr_t, size_t));
+int rxsize __P((dev_t));
+
+struct cfattach rx_ca = {
+ sizeof(struct rx_softc), rxmatch, rxattach
+};
+
+/*
+ * More driver definitions, for generic MSCP code.
+ */
+
+int
+rxmatch(parent, cf, aux)
+ struct device *parent;
+ struct cfdata *cf;
+ void *aux;
+{
+ struct drive_attach_args *da = aux;
+ struct mscp *mp = da->da_mp;
+
+ if ((da->da_typ & MSCPBUS_DISK) == 0)
+ return 0;
+ if (cf->cf_loc[MSCPBUSCF_DRIVE] != MSCPBUSCF_DRIVE_DEFAULT &&
+ cf->cf_loc[MSCPBUSCF_DRIVE] != mp->mscp_unit)
+ return 0;
+ /*
+ * Check if this disk is a floppy; then configure it.
+ * Seems to be a safe way to test it per Chris Torek.
+ */
+ if (MSCP_MID_ECH(1, mp->mscp_guse.guse_mediaid) == 'X' - '@')
+ return 1;
+ return 0;
+}
+
+#endif /* NRX */
+
+/*
+ * The attach routine only checks and prints drive type.
+ * Bringing the disk online is done when the disk is accessed
+ * the first time.
+ */
+void
+rxattach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct rx_softc *rx = (void *)self;
+ struct drive_attach_args *da = aux;
+ struct mscp *mp = da->da_mp;
+ struct mscp_softc *mi = (void *)parent;
+ struct disklabel *dl;
+
+ rx->ra_mediaid = mp->mscp_guse.guse_mediaid;
+ rx->ra_state = DK_CLOSED;
+ rx->ra_hwunit = mp->mscp_unit;
+ mi->mi_dp[mp->mscp_unit] = self;
+
+ rx->ra_disk.dk_name = rx->ra_dev.dv_xname;
+ disk_attach((struct disk *)&rx->ra_disk);
+
+ /* Fill in what we know. The actual size is gotten later */
+ dl = rx->ra_disk.dk_label;
+
+ dl->d_secsize = DEV_BSIZE;
+ dl->d_nsectors = mp->mscp_guse.guse_nspt;
+ dl->d_ntracks = mp->mscp_guse.guse_ngpc * mp->mscp_guse.guse_group;
+ dl->d_secpercyl = dl->d_nsectors * dl->d_ntracks;
+ disk_printtype(mp->mscp_unit, mp->mscp_guse.guse_mediaid);
+#ifdef DEBUG
+ printf("%s: nspt %d group %d ngpc %d rct %d nrpt %d nrct %d\n",
+ self->dv_xname, mp->mscp_guse.guse_nspt, mp->mscp_guse.guse_group,
+ mp->mscp_guse.guse_ngpc, mp->mscp_guse.guse_rctsize,
+ mp->mscp_guse.guse_nrpt, mp->mscp_guse.guse_nrct);
+#endif
+}
+
+/*
+ * (Try to) put the drive online. This is done the first time the
+ * drive is opened, or if it har fallen offline.
+ */
+int
+rx_putonline(rx)
+ struct rx_softc *rx;
+{
+ struct mscp *mp;
+ struct mscp_softc *mi = (struct mscp_softc *)rx->ra_dev.dv_parent;
+ volatile int i;
+
+ rx->ra_state = DK_CLOSED;
+ mp = mscp_getcp(mi, MSCP_WAIT);
+ mp->mscp_opcode = M_OP_ONLINE;
+ mp->mscp_unit = rx->ra_hwunit;
+ mp->mscp_cmdref = 1;
+ *mp->mscp_addr |= MSCP_OWN | MSCP_INT;
+
+ /* Poll away */
+ i = *mi->mi_ip;
+ if (tsleep(&rx->ra_dev.dv_unit, PRIBIO, "rxonline", 100*100))
+ rx->ra_state = DK_CLOSED;
+
+ if (rx->ra_state == DK_CLOSED)
+ return MSCP_FAILED;
+
+ return MSCP_DONE;
+}
+
+#if NRX
+
+/*
+ * Open a drive.
+ */
+/*ARGSUSED*/
+int
+rxopen(dev, flag, fmt, p)
+ dev_t dev;
+ int flag, fmt;
+ struct proc *p;
+{
+ register struct rx_softc *rx;
+ int unit;
+
+ /*
+ * Make sure this is a reasonable open request.
+ */
+ unit = DISKUNIT(dev);
+ if (unit >= rx_cd.cd_ndevs)
+ return ENXIO;
+ rx = rx_cd.cd_devs[unit];
+ if (rx == 0)
+ return ENXIO;
+
+ /*
+ * If this is the first open; we must first try to put
+ * the disk online (and read the label).
+ */
+ if (rx->ra_state == DK_CLOSED)
+ if (rx_putonline(rx) == MSCP_FAILED)
+ return ENXIO;
+
+ return 0;
+}
+
+/* ARGSUSED */
+int
+rxclose(dev, flags, fmt, p)
+ dev_t dev;
+ int flags, fmt;
+ struct proc *p;
+{
+ return (0);
+}
+
+/*
+ * Queue a transfer request, and if possible, hand it to the controller.
+ *
+ * This routine is broken into two so that the internal version
+ * udastrat1() can be called by the (nonexistent, as yet) bad block
+ * revectoring routine.
+ */
+void
+rxstrategy(bp)
+ register struct buf *bp;
+{
+ register int unit;
+ register struct rx_softc *rx;
+
+ /*
+ * Make sure this is a reasonable drive to use.
+ */
+ unit = DISKUNIT(bp->b_dev);
+ if (unit > rx_cd.cd_ndevs || (rx = rx_cd.cd_devs[unit]) == NULL) {
+ bp->b_error = ENXIO;
+ bp->b_flags |= B_ERROR;
+ goto done;
+ }
+
+ /* If disk is not online, try to put it online */
+ if (rx->ra_state == DK_CLOSED)
+ if (rx_putonline(rx) == MSCP_FAILED) {
+ bp->b_flags |= B_ERROR;
+ bp->b_error = EIO;
+ goto done;
+ }
+
+ /*
+ * Determine the size of the transfer, and make sure it is
+ * within the boundaries of the partition.
+ */
+ if (bp->b_blkno >= rx->ra_disk.dk_label->d_secperunit) {
+ bp->b_resid = bp->b_bcount;
+ goto done;
+ }
+
+ /* Make some statistics... /bqt */
+ rx->ra_disk.dk_xfer++;
+ rx->ra_disk.dk_bytes += bp->b_bcount;
+ mscp_strategy(bp, rx->ra_dev.dv_parent);
+ return;
+
+done:
+ biodone(bp);
+}
+
+int
+rxread(dev, uio)
+ dev_t dev;
+ struct uio *uio;
+{
+
+ return (physio(rxstrategy, NULL, dev, B_READ, minphys, uio));
+}
+
+int
+rxwrite(dev, uio)
+ dev_t dev;
+ struct uio *uio;
+{
+
+ return (physio(rxstrategy, NULL, dev, B_WRITE, minphys, uio));
+}
+
+/*
+ * I/O controls.
+ */
+int
+rxioctl(dev, cmd, data, flag, p)
+ dev_t dev;
+ int cmd;
+ caddr_t data;
+ int flag;
+ struct proc *p;
+{
+ register int unit = DISKUNIT(dev);
+ register struct disklabel *lp;
+ register struct rx_softc *rx = rx_cd.cd_devs[unit];
+ int error = 0;
+
+ lp = rx->ra_disk.dk_label;
+
+ switch (cmd) {
+
+ case DIOCGDINFO:
+ bcopy(lp, data, sizeof (struct disklabel));
+ break;
+
+ case DIOCGPART:
+ ((struct partinfo *)data)->disklab = lp;
+ ((struct partinfo *)data)->part =
+ &lp->d_partitions[DISKPART(dev)];
+ break;
+
+
+ case DIOCWDINFO:
+ case DIOCSDINFO:
+ case DIOCWLABEL:
+ break;
+
+ default:
+ error = ENOTTY;
+ break;
+ }
+ return (error);
+}
+
+int
+rxdump(dev, blkno, va, size)
+ dev_t dev;
+ daddr_t blkno;
+ caddr_t va;
+ size_t size;
+{
+
+ /* Not likely. */
+ return ENXIO;
+}
+
+int
+rxsize(dev)
+ dev_t dev;
+{
+
+ return -1;
+}
+
+#endif /* NRX */
+
+void rrdgram __P((struct device *, struct mscp *, struct mscp_softc *));
+void rriodone __P((struct device *, struct buf *));
+int rronline __P((struct device *, struct mscp *));
+int rrgotstatus __P((struct device *, struct mscp *));
+void rrreplace __P((struct device *, struct mscp *));
+int rrioerror __P((struct device *, struct mscp *, struct buf *));
+void rrfillin __P((struct buf *, struct mscp *));
+void rrbb __P((struct device *, struct mscp *, struct buf *));
+
+
+struct mscp_device ra_device = {
+ rrdgram,
+ rriodone,
+ rronline,
+ rrgotstatus,
+ rrreplace,
+ rrioerror,
+ rrbb,
+ rrfillin,
+};
+
+/*
+ * Handle an error datagram.
+ * This can come from an unconfigured drive as well.
+ */
+void
+rrdgram(usc, mp, mi)
+ struct device *usc;
+ struct mscp *mp;
+ struct mscp_softc *mi;
+{
+ if (mscp_decodeerror(usc == NULL?"unconf disk" : usc->dv_xname, mp, mi))
+ return;
+ /*
+ * SDI status information bytes 10 and 11 are the microprocessor
+ * error code and front panel code respectively. These vary per
+ * drive type and are printed purely for field service information.
+ */
+ if (mp->mscp_format == M_FM_SDI)
+ printf("\tsdi uproc error code 0x%x, front panel code 0x%x\n",
+ mp->mscp_erd.erd_sdistat[10],
+ mp->mscp_erd.erd_sdistat[11]);
+}
+
+void
+rriodone(usc, bp)
+ struct device *usc;
+ struct buf *bp;
+{
+
+ biodone(bp);
+}
+
+/*
+ * A drive came on line. Check its type and size. Return DONE if
+ * we think the drive is truly on line. In any case, awaken anyone
+ * sleeping on the drive on-line-ness.
+ */
+int
+rronline(usc, mp)
+ struct device *usc;
+ struct mscp *mp;
+{
+ struct rx_softc *rx = (struct rx_softc *)usc;
+ struct disklabel *dl;
+
+ wakeup((caddr_t)&usc->dv_unit);
+ if ((mp->mscp_status & M_ST_MASK) != M_ST_SUCCESS) {
+ printf("%s: attempt to bring on line failed: ", usc->dv_xname);
+ mscp_printevent(mp);
+ return (MSCP_FAILED);
+ }
+
+ rx->ra_state = DK_OPEN;
+
+ dl = rx->ra_disk.dk_label;
+ dl->d_secperunit = (daddr_t)mp->mscp_onle.onle_unitsize;
+
+ if (dl->d_secpercyl) {
+ dl->d_ncylinders = dl->d_secperunit/dl->d_secpercyl;
+ dl->d_type = DTYPE_MSCP;
+ dl->d_rpm = 3600;
+ } else {
+ dl->d_type = DTYPE_FLOPPY;
+ dl->d_rpm = 300;
+ }
+ rrmakelabel(dl, rx->ra_mediaid);
+
+ return (MSCP_DONE);
+}
+
+void
+rrmakelabel(dl, type)
+ struct disklabel *dl;
+ long type;
+{
+ int n, p = 0;
+
+ dl->d_bbsize = BBSIZE;
+ dl->d_sbsize = SBSIZE;
+
+ /* Create the disk name for disklabel. Phew... */
+ dl->d_typename[p++] = MSCP_MID_CHAR(2, type);
+ dl->d_typename[p++] = MSCP_MID_CHAR(1, type);
+ if (MSCP_MID_ECH(0, type))
+ dl->d_typename[p++] = MSCP_MID_CHAR(0, type);
+ n = MSCP_MID_NUM(type);
+ if (n > 99) {
+ dl->d_typename[p++] = '1';
+ n -= 100;
+ }
+ if (n > 9) {
+ dl->d_typename[p++] = (n / 10) + '0';
+ n %= 10;
+ }
+ dl->d_typename[p++] = n + '0';
+ dl->d_typename[p] = 0;
+ dl->d_npartitions = MAXPARTITIONS;
+ dl->d_partitions[0].p_size = dl->d_partitions[2].p_size =
+ dl->d_secperunit;
+ dl->d_partitions[0].p_offset = dl->d_partitions[2].p_offset = 0;
+ dl->d_interleave = dl->d_headswitch = 1;
+ dl->d_magic = dl->d_magic2 = DISKMAGIC;
+ dl->d_checksum = dkcksum(dl);
+}
+
+/*
+ * We got some (configured) unit's status. Return DONE if it succeeded.
+ */
+int
+rrgotstatus(usc, mp)
+ register struct device *usc;
+ register struct mscp *mp;
+{
+ if ((mp->mscp_status & M_ST_MASK) != M_ST_SUCCESS) {
+ printf("%s: attempt to get status failed: ", usc->dv_xname);
+ mscp_printevent(mp);
+ return (MSCP_FAILED);
+ }
+ /* record for (future) bad block forwarding and whatever else */
+#ifdef notyet
+ uda_rasave(ui->ui_unit, mp, 1);
+#endif
+ return (MSCP_DONE);
+}
+
+/*
+ * A replace operation finished.
+ */
+/*ARGSUSED*/
+void
+rrreplace(usc, mp)
+ struct device *usc;
+ struct mscp *mp;
+{
+
+ panic("udareplace");
+}
+
+/*
+ * A transfer failed. We get a chance to fix or restart it.
+ * Need to write the bad block forwaring code first....
+ */
+/*ARGSUSED*/
+int
+rrioerror(usc, mp, bp)
+ register struct device *usc;
+ register struct mscp *mp;
+ struct buf *bp;
+{
+ struct ra_softc *ra = (void *)usc;
+ int code = mp->mscp_event;
+
+ switch (code & M_ST_MASK) {
+ /* The unit has fallen offline. Try to figure out why. */
+ case M_ST_OFFLINE:
+ bp->b_flags |= B_ERROR;
+ bp->b_error = EIO;
+ ra->ra_state = DK_CLOSED;
+ if (code & M_OFFLINE_UNMOUNTED)
+ printf("%s: not mounted/spun down\n", usc->dv_xname);
+ if (code & M_OFFLINE_DUPLICATE)
+ printf("%s: duplicate unit number!!!\n", usc->dv_xname);
+ return MSCP_DONE;
+
+ case M_ST_AVAILABLE:
+ ra->ra_state = DK_CLOSED; /* Force another online */
+ return MSCP_DONE;
+
+ default:
+ printf("%s:", usc->dv_xname);
+ break;
+ }
+ return (MSCP_FAILED);
+}
+
+/*
+ * Fill in disk addresses in a mscp packet waiting for transfer.
+ */
+void
+rrfillin(bp, mp)
+ struct buf *bp;
+ struct mscp *mp;
+{
+ struct rx_softc *rx = 0; /* Wall */
+ struct disklabel *lp;
+ int unit = DISKUNIT(bp->b_dev);
+ int part = DISKPART(bp->b_dev);
+
+#if NRA
+ if (major(bp->b_dev) == RAMAJOR)
+ rx = ra_cd.cd_devs[unit];
+#endif
+#if NRX
+ if (major(bp->b_dev) != RAMAJOR)
+ rx = rx_cd.cd_devs[unit];
+#endif
+ lp = rx->ra_disk.dk_label;
+
+ mp->mscp_seq.seq_lbn = lp->d_partitions[part].p_offset + bp->b_blkno;
+ mp->mscp_unit = rx->ra_hwunit;
+ mp->mscp_seq.seq_bytecount = bp->b_bcount;
+}
+
+/*
+ * A bad block related operation finished.
+ */
+/*ARGSUSED*/
+void
+rrbb(usc, mp, bp)
+ struct device *usc;
+ struct mscp *mp;
+ struct buf *bp;
+{
+
+ panic("udabb");
+}