summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorfvdl <fvdl@NetBSD.org>1998-03-01 02:09:33 +0000
committerfvdl <fvdl@NetBSD.org>1998-03-01 02:09:33 +0000
commitb50e39fa455971dc1d2f274e343df8ab6c68424c (patch)
tree83f33c5c2babf5e87f4ed52b999950a2fdd2b4e2 /sys/dev
parent77eeaedfe830425b4c413fa839f958f29280d64c (diff)
Import 4.4BSD-Lite for reference
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/cd.c709
-rw-r--r--sys/dev/cdvar.h104
-rw-r--r--sys/dev/scsi/disk.h384
-rw-r--r--sys/dev/scsi/disktape.h260
-rw-r--r--sys/dev/scsi/printer.h59
-rw-r--r--sys/dev/scsi/processor.h63
-rw-r--r--sys/dev/scsi/scsi.h361
-rw-r--r--sys/dev/scsi/scsi_ioctl.h71
-rw-r--r--sys/dev/scsi/scsi_subr.c532
-rw-r--r--sys/dev/scsi/scsivar.h216
-rw-r--r--sys/dev/scsi/sd.c909
-rw-r--r--sys/dev/scsi/sdtrace.h92
-rw-r--r--sys/dev/scsi/tape.h150
13 files changed, 3910 insertions, 0 deletions
diff --git a/sys/dev/cd.c b/sys/dev/cd.c
new file mode 100644
index 00000000000..75b6b3f503e
--- /dev/null
+++ b/sys/dev/cd.c
@@ -0,0 +1,709 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * 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.
+ *
+ * from: Utah $Hdr: cd.c 1.6 90/11/28$
+ *
+ * @(#)cd.c 8.2 (Berkeley) 11/16/93
+ */
+
+/*
+ * "Concatenated" disk driver.
+ */
+#include "cd.h"
+#if NCD > 0
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/errno.h>
+#include <sys/dkstat.h>
+#include <sys/buf.h>
+#include <sys/malloc.h>
+#include <sys/conf.h>
+#include <sys/stat.h>
+#ifdef COMPAT_NOLABEL
+#include <sys/ioctl.h>
+#include <sys/disklabel.h>
+#include <sys/fcntl.h>
+#endif
+
+#include <dev/cdvar.h>
+
+#ifdef DEBUG
+int cddebug = 0x00;
+#define CDB_FOLLOW 0x01
+#define CDB_INIT 0x02
+#define CDB_IO 0x04
+#endif
+
+struct buf *cdbuffer();
+char *cddevtostr();
+void cdiodone();
+
+#define cdunit(x) ((minor(x) >> 3) & 0xf) /* for consistency */
+
+#define getcbuf() \
+ ((struct buf *)malloc(sizeof(struct buf), M_DEVBUF, M_WAITOK))
+#define putcbuf(bp) \
+ free((caddr_t)(bp), M_DEVBUF)
+
+struct cd_softc {
+ int sc_flags; /* flags */
+ size_t sc_size; /* size of cd */
+ int sc_ileave; /* interleave */
+ int sc_ncdisks; /* number of components */
+ struct cdcinfo sc_cinfo[NCDISKS]; /* component info */
+ struct cdiinfo *sc_itable; /* interleave table */
+ int sc_usecnt; /* number of requests active */
+ int sc_dk; /* disk index */
+};
+
+/* sc_flags */
+#define CDF_ALIVE 0x01
+#define CDF_INITED 0x02
+
+struct cd_softc *cd_softc;
+int numcd;
+
+/*
+ * Since this is called after auto-configuration of devices,
+ * we can handle the initialization here.
+ *
+ * XXX this will not work if you want to use a cd as your primary
+ * swap device since swapconf() has been called before now.
+ */
+void
+cdattach(num)
+ int num;
+{
+ char *mem;
+ register u_long size;
+ register struct cddevice *cd;
+ extern int dkn;
+
+ if (num <= 0)
+ return;
+ size = num * sizeof(struct cd_softc);
+ mem = malloc(size, M_DEVBUF, M_NOWAIT);
+ if (mem == NULL) {
+ printf("WARNING: no memory for concatonated disks\n");
+ return;
+ }
+ bzero(mem, size);
+ cd_softc = (struct cd_softc *)mem;
+ numcd = num;
+ for (cd = cddevice; cd->cd_unit >= 0; cd++) {
+ /*
+ * XXX
+ * Assign disk index first so that init routine
+ * can use it (saves having the driver drag around
+ * the cddevice pointer just to set up the dk_*
+ * info in the open routine).
+ */
+ if (dkn < DK_NDRIVE)
+ cd->cd_dk = dkn++;
+ else
+ cd->cd_dk = -1;
+ if (cdinit(cd))
+ printf("cd%d configured\n", cd->cd_unit);
+ else if (cd->cd_dk >= 0) {
+ cd->cd_dk = -1;
+ dkn--;
+ }
+ }
+}
+
+cdinit(cd)
+ struct cddevice *cd;
+{
+ register struct cd_softc *cs = &cd_softc[cd->cd_unit];
+ register struct cdcinfo *ci;
+ register size_t size;
+ register int ix;
+ size_t minsize;
+ dev_t dev;
+ struct bdevsw *bsw;
+ int error;
+ struct proc *p = curproc; /* XXX */
+
+#ifdef DEBUG
+ if (cddebug & (CDB_FOLLOW|CDB_INIT))
+ printf("cdinit: unit %d\n", cd->cd_unit);
+#endif
+ cs->sc_dk = cd->cd_dk;
+ cs->sc_size = 0;
+ cs->sc_ileave = cd->cd_interleave;
+ cs->sc_ncdisks = 0;
+ /*
+ * Verify that each component piece exists and record
+ * relevant information about it.
+ */
+ minsize = 0;
+ for (ix = 0; ix < NCDISKS; ix++) {
+ if ((dev = cd->cd_dev[ix]) == NODEV)
+ break;
+ ci = &cs->sc_cinfo[ix];
+ ci->ci_dev = dev;
+ bsw = &bdevsw[major(dev)];
+ /*
+ * Open the partition
+ */
+ if (bsw->d_open &&
+ (error = (*bsw->d_open)(dev, 0, S_IFBLK, p))) {
+ printf("cd%d: component %s open failed, error = %d\n",
+ cd->cd_unit, cddevtostr(dev), error);
+ return(0);
+ }
+ /*
+ * Calculate size (truncated to interleave boundary
+ * if necessary.
+ */
+ if (bsw->d_psize) {
+ size = (size_t) (*bsw->d_psize)(dev);
+ if ((int)size < 0)
+ size = 0;
+ } else
+ size = 0;
+ if (cs->sc_ileave > 1)
+ size -= size % cs->sc_ileave;
+ if (size == 0) {
+ printf("cd%d: not configured (component %s missing)\n",
+ cd->cd_unit, cddevtostr(dev));
+ return(0);
+ }
+#ifdef COMPAT_NOLABEL
+ /*
+ * XXX if this is a 'c' partition then we need to mark the
+ * label area writeable since there cannot be a label.
+ */
+ if ((minor(dev) & 7) == 2 && bsw->d_open) {
+ int i, flag;
+
+ for (i = 0; i < nchrdev; i++)
+ if (cdevsw[i].d_open == bsw->d_open)
+ break;
+ if (i != nchrdev && cdevsw[i].d_ioctl) {
+ flag = 1;
+ (void)(*cdevsw[i].d_ioctl)(dev, DIOCWLABEL,
+ (caddr_t)&flag, FWRITE, p);
+ }
+ }
+#endif
+ if (minsize == 0 || size < minsize)
+ minsize = size;
+ ci->ci_size = size;
+ cs->sc_size += size;
+ cs->sc_ncdisks++;
+ }
+ /*
+ * If uniform interleave is desired set all sizes to that of
+ * the smallest component.
+ */
+ if (cd->cd_flags & CDF_UNIFORM) {
+ for (ci = cs->sc_cinfo;
+ ci < &cs->sc_cinfo[cs->sc_ncdisks]; ci++)
+ ci->ci_size = minsize;
+ cs->sc_size = cs->sc_ncdisks * minsize;
+ }
+ /*
+ * Construct the interleave table
+ */
+ if (!cdinterleave(cs))
+ return(0);
+ if (cd->cd_dk >= 0)
+ dk_wpms[cd->cd_dk] = 32 * (60 * DEV_BSIZE / 2); /* XXX */
+ printf("cd%d: %d components ", cd->cd_unit, cs->sc_ncdisks);
+ for (ix = 0; ix < cs->sc_ncdisks; ix++)
+ printf("%c%s%c",
+ ix == 0 ? '(' : ' ',
+ cddevtostr(cs->sc_cinfo[ix].ci_dev),
+ ix == cs->sc_ncdisks - 1 ? ')' : ',');
+ printf(", %d blocks ", cs->sc_size);
+ if (cs->sc_ileave)
+ printf("interleaved at %d blocks\n", cs->sc_ileave);
+ else
+ printf("concatenated\n");
+ cs->sc_flags = CDF_ALIVE | CDF_INITED;
+ return(1);
+}
+
+/*
+ * XXX not really cd specific.
+ * Could be called something like bdevtostr in machine/conf.c.
+ */
+char *
+cddevtostr(dev)
+ dev_t dev;
+{
+ static char dbuf[5];
+
+ switch (major(dev)) {
+#ifdef hp300
+ case 2:
+ dbuf[0] = 'r'; dbuf[1] = 'd';
+ break;
+ case 4:
+ dbuf[0] = 's'; dbuf[1] = 'd';
+ break;
+ case 5:
+ dbuf[0] = 'c'; dbuf[1] = 'd';
+ break;
+ case 6:
+ dbuf[0] = 'v'; dbuf[1] = 'n';
+ break;
+#endif
+ default:
+ dbuf[0] = dbuf[1] = '?';
+ break;
+ }
+ dbuf[2] = (minor(dev) >> 3) + '0';
+ dbuf[3] = (minor(dev) & 7) + 'a';
+ dbuf[4] = '\0';
+ return (dbuf);
+}
+
+cdinterleave(cs)
+ register struct cd_softc *cs;
+{
+ register struct cdcinfo *ci, *smallci;
+ register struct cdiinfo *ii;
+ register daddr_t bn, lbn;
+ register int ix;
+ u_long size;
+
+#ifdef DEBUG
+ if (cddebug & CDB_INIT)
+ printf("cdinterleave(%x): ileave %d\n", cs, cs->sc_ileave);
+#endif
+ /*
+ * Allocate an interleave table.
+ * Chances are this is too big, but we don't care.
+ */
+ size = (cs->sc_ncdisks + 1) * sizeof(struct cdiinfo);
+ cs->sc_itable = (struct cdiinfo *)malloc(size, M_DEVBUF, M_WAITOK);
+ bzero((caddr_t)cs->sc_itable, size);
+ /*
+ * Trivial case: no interleave (actually interleave of disk size).
+ * Each table entry represent a single component in its entirety.
+ */
+ if (cs->sc_ileave == 0) {
+ bn = 0;
+ ii = cs->sc_itable;
+ for (ix = 0; ix < cs->sc_ncdisks; ix++) {
+ ii->ii_ndisk = 1;
+ ii->ii_startblk = bn;
+ ii->ii_startoff = 0;
+ ii->ii_index[0] = ix;
+ bn += cs->sc_cinfo[ix].ci_size;
+ ii++;
+ }
+ ii->ii_ndisk = 0;
+#ifdef DEBUG
+ if (cddebug & CDB_INIT)
+ printiinfo(cs->sc_itable);
+#endif
+ return(1);
+ }
+ /*
+ * The following isn't fast or pretty; it doesn't have to be.
+ */
+ size = 0;
+ bn = lbn = 0;
+ for (ii = cs->sc_itable; ; ii++) {
+ /*
+ * Locate the smallest of the remaining components
+ */
+ smallci = NULL;
+ for (ci = cs->sc_cinfo;
+ ci < &cs->sc_cinfo[cs->sc_ncdisks]; ci++)
+ if (ci->ci_size > size &&
+ (smallci == NULL ||
+ ci->ci_size < smallci->ci_size))
+ smallci = ci;
+ /*
+ * Nobody left, all done
+ */
+ if (smallci == NULL) {
+ ii->ii_ndisk = 0;
+ break;
+ }
+ /*
+ * Record starting logical block and component offset
+ */
+ ii->ii_startblk = bn / cs->sc_ileave;
+ ii->ii_startoff = lbn;
+ /*
+ * Determine how many disks take part in this interleave
+ * and record their indices.
+ */
+ ix = 0;
+ for (ci = cs->sc_cinfo;
+ ci < &cs->sc_cinfo[cs->sc_ncdisks]; ci++)
+ if (ci->ci_size >= smallci->ci_size)
+ ii->ii_index[ix++] = ci - cs->sc_cinfo;
+ ii->ii_ndisk = ix;
+ bn += ix * (smallci->ci_size - size);
+ lbn = smallci->ci_size / cs->sc_ileave;
+ size = smallci->ci_size;
+ }
+#ifdef DEBUG
+ if (cddebug & CDB_INIT)
+ printiinfo(cs->sc_itable);
+#endif
+ return(1);
+}
+
+#ifdef DEBUG
+printiinfo(ii)
+ struct cdiinfo *ii;
+{
+ register int ix, i;
+
+ for (ix = 0; ii->ii_ndisk; ix++, ii++) {
+ printf(" itab[%d]: #dk %d sblk %d soff %d",
+ ix, ii->ii_ndisk, ii->ii_startblk, ii->ii_startoff);
+ for (i = 0; i < ii->ii_ndisk; i++)
+ printf(" %d", ii->ii_index[i]);
+ printf("\n");
+ }
+}
+#endif
+
+cdopen(dev, flags)
+ dev_t dev;
+{
+ int unit = cdunit(dev);
+ register struct cd_softc *cs = &cd_softc[unit];
+
+#ifdef DEBUG
+ if (cddebug & CDB_FOLLOW)
+ printf("cdopen(%x, %x)\n", dev, flags);
+#endif
+ if (unit >= numcd || (cs->sc_flags & CDF_ALIVE) == 0)
+ return(ENXIO);
+ return(0);
+}
+
+cdstrategy(bp)
+ register struct buf *bp;
+{
+ register int unit = cdunit(bp->b_dev);
+ register struct cd_softc *cs = &cd_softc[unit];
+ register daddr_t bn;
+ register int sz, s;
+
+#ifdef DEBUG
+ if (cddebug & CDB_FOLLOW)
+ printf("cdstrategy(%x): unit %d\n", bp, unit);
+#endif
+ if ((cs->sc_flags & CDF_INITED) == 0) {
+ bp->b_error = ENXIO;
+ bp->b_flags |= B_ERROR;
+ goto done;
+ }
+ bn = bp->b_blkno;
+ sz = howmany(bp->b_bcount, DEV_BSIZE);
+ if (bn < 0 || bn + sz > cs->sc_size) {
+ sz = cs->sc_size - bn;
+ if (sz == 0) {
+ bp->b_resid = bp->b_bcount;
+ goto done;
+ }
+ if (sz < 0) {
+ bp->b_error = EINVAL;
+ bp->b_flags |= B_ERROR;
+ goto done;
+ }
+ bp->b_bcount = dbtob(sz);
+ }
+ bp->b_resid = bp->b_bcount;
+ /*
+ * "Start" the unit.
+ */
+ s = splbio();
+ cdstart(cs, bp);
+ splx(s);
+ return;
+done:
+ biodone(bp);
+}
+
+cdstart(cs, bp)
+ register struct cd_softc *cs;
+ register struct buf *bp;
+{
+ register long bcount, rcount;
+ struct buf *cbp;
+ caddr_t addr;
+ daddr_t bn;
+
+#ifdef DEBUG
+ if (cddebug & CDB_FOLLOW)
+ printf("cdstart(%x, %x)\n", cs, bp);
+#endif
+ /*
+ * Instumentation (not real meaningful)
+ */
+ cs->sc_usecnt++;
+ if (cs->sc_dk >= 0) {
+ dk_busy |= 1 << cs->sc_dk;
+ dk_xfer[cs->sc_dk]++;
+ dk_wds[cs->sc_dk] += bp->b_bcount >> 6;
+ }
+ /*
+ * Allocate component buffers and fire off the requests
+ */
+ bn = bp->b_blkno;
+ addr = bp->b_data;
+ for (bcount = bp->b_bcount; bcount > 0; bcount -= rcount) {
+ cbp = cdbuffer(cs, bp, bn, addr, bcount);
+ rcount = cbp->b_bcount;
+ (*bdevsw[major(cbp->b_dev)].d_strategy)(cbp);
+ bn += btodb(rcount);
+ addr += rcount;
+ }
+}
+
+/*
+ * Build a component buffer header.
+ */
+struct buf *
+cdbuffer(cs, bp, bn, addr, bcount)
+ register struct cd_softc *cs;
+ struct buf *bp;
+ daddr_t bn;
+ caddr_t addr;
+ long bcount;
+{
+ register struct cdcinfo *ci;
+ register struct buf *cbp;
+ register daddr_t cbn, cboff;
+
+#ifdef DEBUG
+ if (cddebug & CDB_IO)
+ printf("cdbuffer(%x, %x, %d, %x, %d)\n",
+ cs, bp, bn, addr, bcount);
+#endif
+ /*
+ * Determine which component bn falls in.
+ */
+ cbn = bn;
+ cboff = 0;
+ /*
+ * Serially concatenated
+ */
+ if (cs->sc_ileave == 0) {
+ register daddr_t sblk;
+
+ sblk = 0;
+ for (ci = cs->sc_cinfo; cbn >= sblk + ci->ci_size; ci++)
+ sblk += ci->ci_size;
+ cbn -= sblk;
+ }
+ /*
+ * Interleaved
+ */
+ else {
+ register struct cdiinfo *ii;
+ int cdisk, off;
+
+ cboff = cbn % cs->sc_ileave;
+ cbn /= cs->sc_ileave;
+ for (ii = cs->sc_itable; ii->ii_ndisk; ii++)
+ if (ii->ii_startblk > cbn)
+ break;
+ ii--;
+ off = cbn - ii->ii_startblk;
+ if (ii->ii_ndisk == 1) {
+ cdisk = ii->ii_index[0];
+ cbn = ii->ii_startoff + off;
+ } else {
+ cdisk = ii->ii_index[off % ii->ii_ndisk];
+ cbn = ii->ii_startoff + off / ii->ii_ndisk;
+ }
+ cbn *= cs->sc_ileave;
+ ci = &cs->sc_cinfo[cdisk];
+ }
+ /*
+ * Fill in the component buf structure.
+ */
+ cbp = getcbuf();
+ cbp->b_flags = bp->b_flags | B_CALL;
+ cbp->b_iodone = cdiodone;
+ cbp->b_proc = bp->b_proc;
+ cbp->b_dev = ci->ci_dev;
+ cbp->b_blkno = cbn + cboff;
+ cbp->b_data = addr;
+ cbp->b_vp = 0;
+ if (cs->sc_ileave == 0)
+ cbp->b_bcount = dbtob(ci->ci_size - cbn);
+ else
+ cbp->b_bcount = dbtob(cs->sc_ileave - cboff);
+ if (cbp->b_bcount > bcount)
+ cbp->b_bcount = bcount;
+ /*
+ * XXX context for cdiodone
+ */
+ cbp->b_saveaddr = (caddr_t)bp;
+ cbp->b_pfcent = ((cs - cd_softc) << 16) | (ci - cs->sc_cinfo);
+#ifdef DEBUG
+ if (cddebug & CDB_IO)
+ printf(" dev %x(u%d): cbp %x bn %d addr %x bcnt %d\n",
+ ci->ci_dev, ci-cs->sc_cinfo, cbp, cbp->b_blkno,
+ cbp->b_data, cbp->b_bcount);
+#endif
+ return(cbp);
+}
+
+cdintr(cs, bp)
+ register struct cd_softc *cs;
+ register struct buf *bp;
+{
+
+#ifdef DEBUG
+ if (cddebug & CDB_FOLLOW)
+ printf("cdintr(%x, %x)\n", cs, bp);
+#endif
+ /*
+ * Request is done for better or worse, wakeup the top half.
+ */
+ if (--cs->sc_usecnt == 0 && cs->sc_dk >= 0)
+ dk_busy &= ~(1 << cs->sc_dk);
+ if (bp->b_flags & B_ERROR)
+ bp->b_resid = bp->b_bcount;
+ biodone(bp);
+}
+
+/*
+ * Called by biodone at interrupt time.
+ * Mark the component as done and if all components are done,
+ * take a cd interrupt.
+ */
+void
+cdiodone(cbp)
+ register struct buf *cbp;
+{
+ register struct buf *bp = (struct buf *)cbp->b_saveaddr;/* XXX */
+ register int unit = (cbp->b_pfcent >> 16) & 0xFFFF; /* XXX */
+ int count, s;
+
+ s = splbio();
+#ifdef DEBUG
+ if (cddebug & CDB_FOLLOW)
+ printf("cdiodone(%x)\n", cbp);
+ if (cddebug & CDB_IO) {
+ printf("cdiodone: bp %x bcount %d resid %d\n",
+ bp, bp->b_bcount, bp->b_resid);
+ printf(" dev %x(u%d), cbp %x bn %d addr %x bcnt %d\n",
+ cbp->b_dev, cbp->b_pfcent & 0xFFFF, cbp,
+ cbp->b_blkno, cbp->b_data, cbp->b_bcount);
+ }
+#endif
+
+ if (cbp->b_flags & B_ERROR) {
+ bp->b_flags |= B_ERROR;
+ bp->b_error = biowait(cbp);
+#ifdef DEBUG
+ printf("cd%d: error %d on component %d\n",
+ unit, bp->b_error, cbp->b_pfcent & 0xFFFF);
+#endif
+ }
+ count = cbp->b_bcount;
+ putcbuf(cbp);
+
+ /*
+ * If all done, "interrupt".
+ */
+ bp->b_resid -= count;
+ if (bp->b_resid < 0)
+ panic("cdiodone: count");
+ if (bp->b_resid == 0)
+ cdintr(&cd_softc[unit], bp);
+ splx(s);
+}
+
+cdread(dev, uio)
+ dev_t dev;
+ struct uio *uio;
+{
+ register int unit = cdunit(dev);
+
+#ifdef DEBUG
+ if (cddebug & CDB_FOLLOW)
+ printf("cdread(%x, %x)\n", dev, uio);
+#endif
+ return(physio(cdstrategy, NULL, dev, B_READ, minphys, uio));
+}
+
+cdwrite(dev, uio)
+ dev_t dev;
+ struct uio *uio;
+{
+ register int unit = cdunit(dev);
+
+#ifdef DEBUG
+ if (cddebug & CDB_FOLLOW)
+ printf("cdwrite(%x, %x)\n", dev, uio);
+#endif
+ return(physio(cdstrategy, NULL, dev, B_WRITE, minphys, uio));
+}
+
+cdioctl(dev, cmd, data, flag)
+ dev_t dev;
+ int cmd;
+ caddr_t data;
+ int flag;
+{
+ return(EINVAL);
+}
+
+cdsize(dev)
+ dev_t dev;
+{
+ int unit = cdunit(dev);
+ register struct cd_softc *cs = &cd_softc[unit];
+
+ if (unit >= numcd || (cs->sc_flags & CDF_INITED) == 0)
+ return(-1);
+ return(cs->sc_size);
+}
+
+cddump(dev)
+{
+ return(ENXIO);
+}
+#endif
diff --git a/sys/dev/cdvar.h b/sys/dev/cdvar.h
new file mode 100644
index 00000000000..41c3d860733
--- /dev/null
+++ b/sys/dev/cdvar.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * 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.
+ *
+ * from: Utah $Hdr: cdvar.h 1.1 90/07/09$
+ *
+ * @(#)cdvar.h 8.1 (Berkeley) 6/10/93
+ */
+
+#define NCDISKS 8 /* max # of component disks */
+
+/*
+ * A concatenated disk is described at config time by this structure.
+ */
+struct cddevice {
+ int cd_unit; /* logical unit of this cd */
+ int cd_interleave; /* interleave (DEV_BSIZE blocks) */
+ int cd_flags; /* misc. information */
+ int cd_dk; /* disk number */
+ dev_t cd_dev[NCDISKS]; /* component devices */
+};
+
+/* cd_flags */
+#define CDF_SWAP 0x01 /* interleave should be dmmax */
+#define CDF_UNIFORM 0x02 /* use LCD of sizes for uniform interleave */
+
+/*
+ * Component info table.
+ * Describes a single component of a concatenated disk.
+ */
+struct cdcinfo {
+ dev_t ci_dev; /* devno */
+ size_t ci_size; /* size */
+};
+
+/*
+ * Interleave description table.
+ * Computed at boot time to speed irregular-interleave lookups.
+ * The idea is that we interleave in "groups". First we interleave
+ * evenly over all component disks up to the size of the smallest
+ * component (the first group), then we interleave evenly over all
+ * remaining disks up to the size of the next-smallest (second group),
+ * and so on.
+ *
+ * Each table entry describes the interleave characteristics of one
+ * of these groups. For example if a concatenated disk consisted of
+ * three components of 5, 3, and 7 DEV_BSIZE blocks interleaved at
+ * DEV_BSIZE (1), the table would have three entries:
+ *
+ * ndisk startblk startoff dev
+ * 3 0 0 0, 1, 2
+ * 2 9 3 0, 2
+ * 1 13 5 2
+ * 0 - - -
+ *
+ * which says that the first nine blocks (0-8) are interleaved over
+ * 3 disks (0, 1, 2) starting at block offset 0 on any component disk,
+ * the next 4 blocks (9-12) are interleaved over 2 disks (0, 2) starting
+ * at component block 3, and the remaining blocks (13-14) are on disk
+ * 2 starting at offset 5.
+ */
+struct cdiinfo {
+ int ii_ndisk; /* # of disks range is interleaved over */
+ daddr_t ii_startblk; /* starting scaled block # for range */
+ daddr_t ii_startoff; /* starting component offset (block #) */
+ char ii_index[NCDISKS];/* ordered list of components in range */
+};
+
+#ifdef KERNEL
+extern struct cddevice cddevice[];
+#endif
diff --git a/sys/dev/scsi/disk.h b/sys/dev/scsi/disk.h
new file mode 100644
index 00000000000..137cda96c04
--- /dev/null
+++ b/sys/dev/scsi/disk.h
@@ -0,0 +1,384 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * 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, Lawrence Berkeley Laboratories.
+ *
+ * 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.
+ *
+ * @(#)disk.h 8.1 (Berkeley) 6/10/93
+ *
+ * from: $Header: /cvsroot/src/sys/dev/scsi/Attic/disk.h,v 1.1.1.1 1998/03/01 02:09:34 fvdl Exp $ (LBL)
+ */
+
+/*
+ * SCSI definitions for Direct Access Devices (disks).
+ * This includes WORMs and CD-ROMs (although a few commands, such as
+ * format or write, are nonsensical on some).
+ *
+ * Commands defined in common headers (scsi.h or disktape.h) appear here
+ * as comments.
+ */
+
+ /* group 0 */
+/* CMD_TEST_UNIT_READY 0x00 test unit ready */
+#define CMD_REZERO 0x01 /* rezero unit */
+/* CMD_REQUEST_SENSE 0x03 request sense */
+#define CMD_FORMAT_UNIT 0x04 /* format unit (disk) */
+#define CMD_REASSIGN_BLOCKS 0x07 /* reassign blocks (disk, WORM) */
+#define CMD_READ6 0x08 /* read (6 byte cdb) */
+#define CMD_WRITE6 0x0a /* write (6 byte cdb) */
+#define CMD_SEEK6 0x0b /* seek (6 byte cdb) */
+/* CMD_INQUIRY 0x12 inquiry */
+/* CMD_MODE_SELECT 0x15 mode select */
+#define CMD_RESERVE 0x16 /* reserve */
+#define CMD_RELEASE 0x17 /* release */
+/* CMD_COPY 0x18 copy */
+/* CMD_MODE_SENSE 0x1a mode sense */
+#define CMD_SSU 0x1b /* start/stop unit */
+/* CMD_RECEIVE_DIAG 0x1c receive diagnostic results */
+/* CMD_SEND_DIAG 0x1d send diagnostic */
+#define CMD_PAMR 0x1e /* prevent/allow medium removal */
+
+ /* group 1 */
+#define CMD_READ_CAPACITY 0x25 /* read capacity */
+#define CMD_READ10 0x28 /* read (10 byte cdb) */
+#define CMD_WRITE10 0x2a /* write (10 byte cdb) */
+#define CMD_SEEK10 0x2b /* write (10 byte cdb) */
+#define CMD_WRITE_VERIFY 0x2e /* write and verify */
+#define CMD_VERIFY 0x2f /* verify */
+#define CMD_SEARCH_H 0x30 /* search data high */
+#define CMD_SEARCH_E 0x31 /* search data equal */
+#define CMD_SEARCH_L 0x32 /* search data low */
+#define CMD_SET_LIMITS 0x33 /* set limits */
+/* CMD_COMPARE 0x39 compare */
+#define CMD_COPY_VERIFY 0x3a /* copy and verify */
+
+/* this one is in van's but not in my 17B documents */
+#define CMD_READ_DEFECT_DATA 0x37 /* read defect data */ /* ??? */
+
+/*
+ * Structure of a FORMAT UNIT command (i.e., the cdb):
+ * byte 0: opcode<8>
+ * byte 1: lun<3> format_data<1> complete_list<1> defect_list_format<3>
+ * byte 2: vendor unique
+ * byte 3: interleave (MSB)
+ * byte 4: interleave (LSB)
+ * byte 5: control
+ */
+struct scsi_cdb_fu {
+ u_char cdb_cmd; /* SCSI_CMD_FU */
+ u_char cdb_lun_etc; /* lun+FD+CL+DLF */
+ u_char cdb_vu; /* vendor unique */
+ u_char cdb_ilvh; /* interleave (MSB) */
+ u_char cdb_ilvl; /* interleave (LSB) */
+ u_char cdb_ctrl; /* control byte */
+};
+
+/*
+ * If format data are supplied, they give either additional (cl=0) or
+ * new (cl=1) defect list in one of the following formats.
+ * Formats 1, 2, and 3 are the same as 0; formats 6 and 7 are
+ * vendor unique and reserved, respectively. (The `backwards'
+ * in `backwards compatible'...)
+ */
+#define SCSI_DLF_BLOCK 0 /* dlf = blocks */
+#define SCSI_DLF_BFI 4 /* dlf = bytes from index */
+#define SCSI_DLF_PS 5 /* dlf = physical sectors */
+
+/*
+ * Defect list header, block format (`defect block address').
+ *
+ * N.B.: this structure is also used for the Reassign Blocks command;
+ * there the `defect block address' becomes a `defect logical block address'.
+ */
+struct scsi_dlf_dba {
+ u_short dlf_xxx; /* reserved */
+ u_char dlf_lenh, /* defect list length (MSB) */
+ dlf_lenl; /* defect list length (LSB) */
+ struct scsi_dlf_dba_desc {
+ u_char dbah, /* defect block address (MSB) */
+ dbahm, /* defect block address */
+ dbalm, /* defect block address */
+ dbal; /* defect block address (LSB) */
+ } dlf_dba[1]; /* actually longer */
+};
+
+/*
+ * Defect list header, Bytes From Index format.
+ */
+struct scsi_dlf_bfi {
+ u_short dlf_xxx; /* reserved */
+ u_char dlf_lenh, /* defect list length (MSB) */
+ dlf_lenl; /* defect list length (LSB) */
+ struct scsi_dlf_bfi_desc {
+ u_char cylh, /* cylinder number of defect (MSB) */
+ cylm, /* cylinder number of defect */
+ cyll, /* cylinder number of defect (LSB) */
+ head, /* head number of defect */
+ bfih, /* defect bytes from index (MSB) */
+ bfihm, /* defect bytes from index */
+ bfilm, /* defect bytes from index */
+ bfil; /* defect bytes from index (LSB) */
+ } dlf_bfi[1]; /* actually longer */
+};
+
+/*
+ * Defect list header, Physical Sector format.
+ */
+struct scsi_dlf_ps {
+ u_short dlf_xxx; /* reserved */
+ u_char dlf_lenh, /* defect list length (MSB) */
+ dlf_lenl; /* defect list length (LSB) */
+ struct scsi_dlf_ps_desc {
+ u_char cylh, /* cylinder number of defect (MSB) */
+ cylm, /* cylinder number of defect */
+ cyll, /* cylinder number of defect (LSB) */
+ head, /* head number of defect */
+ dsnh, /* defect sector number (MSB) */
+ dsnhm, /* defect sector number */
+ dsnlm, /* defect sector number */
+ dsnl; /* defect sector number (LSB) */
+ } dlf_ps[1]; /* actually longer */
+};
+
+/*
+ * For MODE SENSE and MODE SELECT: Mode page codes for disks.
+ */
+/* 0x00 vendor specific */
+#define SCSI_MS_PC_RWERRREC 0x01 /* r/w error recovery parameters */
+/* SCSI_MS_PC_DR 0x02 disconnect/reconnect control */
+#define SCSI_MS_PC_FMT 0x03 /* format parameters */
+#define SCSI_MS_PC_RDGEOM 0x04 /* Rigid Disk geometry */
+#define SCSI_MS_PC_FD 0x05 /* flexible disk page */
+/* 0x06 reserved */
+#define SCSI_MS_PC_VERRREC 0x07 /* verify error recovery page */
+#define SCSI_MS_PC_CACHE 0x08 /* cache page */
+/* SCSI_MS_PC_PDEV 0x09 peripheral device page */
+/* SCSI_MS_PC_CTLMODE 0x0a control mode page */
+#define SCSI_MS_PC_MTSUPP 0x0b /* medium types supported */
+#define SCSI_MS_PC_NOTCH 0x0c /* notch page */
+/* 0x0d..0x1f reserved */
+/* 0x20..0x3e vendor specific */
+#define SCSI_MS_PC_CDCCACHECTL 0x38 /* CDC (Wren) cache control page */
+
+/*
+ * Structure of a Read/Write Error Recovery mode page.
+ * N.B.: CDC Wren V, at least, does not include write retry & time limit.
+ */
+struct scsi_page_rwerrrec {
+ u_char rw_flags, /* flags, see below */
+ rw_read_retry, /* read retry count */
+ rw_corr_span, /* correction span */
+ rw_hd_off, /* head offset count */
+ rw_ds_off, /* data strobe offset count */
+ rw_xxx0, /* reserved */
+ rw_write_retry, /* write retry count */
+ rw_xxx1, /* reserved */
+ rw_rtlh, /* recovery time limit (MSB) */
+ rw_rtll; /* recovery time limit (LSB) */
+};
+/* rw_flags */
+#define SCSI_RWE_AWRE 0x80 /* reallocate defective blocks on write */
+#define SCSI_RWE_ARRE 0x40 /* reallocate defective blocks on read */
+#define SCSI_RWE_TB 0x20 /* transfer unrecoverable block */
+#define SCSI_RWE_RC 0x10 /* recovery may not cause delay: may lie */
+#define SCSI_RWE_EER 0x08 /* use most expedient recovery, not best */
+#define SCSI_RWE_PER 0x04 /* report recovered errors */
+#define SCSI_RWE_DTE 0x02 /* stop after recovered error */
+#define SCSI_RWE_DCR 0x01 /* use ECC for detection only */
+
+/*
+ * Structure of a Format Device mode page.
+ */
+struct scsi_page_fmt {
+ u_char fmt_tpzh, /* tracks per zone (MSB) */
+ fmt_tpzl, /* tracks per zone (LSB) */
+ fmt_aspzh, /* alternate sectors per zone (MSB) */
+ fmt_aspzl, /* alternate sectors per zone (LSB) */
+ fmt_atpzh, /* alternate tracks per zone (MSB) */
+ fmt_atpzl, /* alternate tracks per zone (LSB) */
+ fmt_atpvh, /* alternate tracks per volume (MSB) */
+ fmt_atpvl, /* alternate tracks per volume (LSB) */
+ fmt_spth, /* sectors per track (MSB) */
+ fmt_sptl, /* sectors per track (LSB) */
+ fmt_dbppsh, /* data bytes per physical sector (MSB) */
+ fmt_dbppsl, /* data bytes per physical sector (LSB) */
+ fmt_ilh, /* interleave (MSB) */
+ fmt_ill, /* interleave (LSB) */
+ fmt_tsfh, /* track skew factor (MSB) */
+ fmt_tsfl, /* track skew factor (LSB) */
+ fmt_csfh, /* cylinder skew factor (MSB) */
+ fmt_csfl, /* cylinder skew factor (LSB) */
+ fmt_flags, /* flags, see below */
+ fmt_xxx[3]; /* reserved */
+};
+/* fmt_flags. Note, HSEC|SSEC meaning varies all over the map! */
+#define SCSI_FMT_HSEC 0x80 /* hard sector */
+#define SCSI_FMT_SSEC 0x40 /* soft sector */
+#define SCSI_FMT_RMB 0x20 /* removable media */
+#define SCSI_FMT_SURF 0x10 /* format by surface (vs. by cylinder) */
+/* 0x0f reserved */
+
+/*
+ * Structure of a Rigid Disk Geometry mode page.
+ * N.B.: CDC Wren V, at least, does not include rpm.
+ */
+struct scsi_page_rdgeom {
+ u_char rd_ncylh, /* number of cylinders (MSB) */
+ rd_ncylm, /* number of cylinders */
+ rd_ncyll, /* number of cylinders (LSB) */
+ rd_nheads, /* number of heads */
+ rd_wpcylh, /* start cyl for write precomp. (MSB) */
+ rd_wpcylm, /* start cyl for write precomp. */
+ rd_wpcyll, /* start cyl for write precomp. (LSB) */
+ rd_rwcylh, /* start cyl for reduced write current (MSB) */
+ rd_rwcylm, /* start cyl for reduced write current */
+ rd_rwcyll, /* start cyl for reduced write current (LSB) */
+ rd_steph, /* drive step rate (.1 us units) (MSB) */
+ rd_stepl, /* drive step rate (LSB) */
+ rd_lcylh, /* landing zone cylinder (MSB) */
+ rd_lcylm, /* landing zone cylinder */
+ rd_lcyll, /* landing zone cylinder (LSB) */
+ rd_rpl, /* spindle synch control, see below */
+ rd_roff, /* rotational offset (for rpl) */
+ rd_xxx1, /* reserved */
+ rd_rpmh, /* medium rotation rate (rpm) (MSB) */
+ rd_rpml, /* medium rotation rate (rpm) (LSB) */
+ rd_xxx2[2]; /* reserved */
+};
+/* values for rd_rpl. */
+#define SCSI_RD_RPL_MASK 0x03 /* mask for RPL field */
+#define SCSI_RD_RPL_NONE 0x00 /* sync disabled or not supported */
+#define SCSI_RD_RPL_SLAVE 0x01 /* disk is a Slave */
+#define SCSI_RD_RPL_MASTER 0x02 /* disk is a Master */
+#define SCSI_RD_RPL_MCONTROL 0x03 /* disk is a Master Control */
+
+/*
+ * Structure of a Verify Error Recovery mode page.
+ */
+struct scsi_page_verrrec {
+ u_char v_flags, /* flags, see below */
+ v_verify_retry, /* verify retry count */
+ v_corr_span, /* verify correction span */
+ v_xxx[5], /* reserved */
+ v_rtlh, /* verify recovery time limit (MSB) */
+ v_rtll; /* verify recovery time limit (LSB) */
+};
+#define SCSI_V_EER 0x08 /* use most expedient recovery, not best */
+#define SCSI_V_PER 0x04 /* report recovered errors */
+#define SCSI_V_DTE 0x02 /* stop after recovered error */
+#define SCSI_V_DCR 0x01 /* use ECC for detection only */
+
+/*
+ * Structure of a Caching mode page.
+ */
+struct scsi_page_cache {
+ u_char cache_flags, /* flags, see below */
+ cache_reten, /* cache retention priorities (rd + wr) */
+ cache_dptlh, /* disable prefetch transfer length (MSB) */
+ cache_dptll, /* disable prefetch transfer length (LSB) */
+ cache_minpfh, /* minimum prefetch (MSB) */
+ cache_minpfl, /* minimum prefetch (LSB) */
+ cache_maxpfh, /* maximum prefetch (MSB) */
+ cache_maxpfl, /* maximum prefetch (LSB) */
+ cache_mpch, /* maximum prefetch ceiling (MSB) */
+ cache_mpcl; /* maximum prefetch ceiling (LSB) */
+};
+#define SCSI_CACHE_WCE 0x04 /* write cache enable */
+#define SCSI_CACHE_MF 0x02 /* if set, prefetch depends on xfer length */
+#define SCSI_CACHE_RCD 0x01 /* read cache disable */
+
+#define SCSI_CACHE_RDPOLICY(x) ((x) >> 4)
+#define SCSI_CACHE_WRPOLICY(x) ((x) & 0xf)
+#define SCSI_CACHE_DEFAULT 0 /* use target default */
+#define SCSI_CACHE_KEEPPF 1 /* keep prefetch data over cmd data */
+#define SCSI_CACHE_KEEPCMD 15 /* keep cmd data over prefetch data */
+
+/*
+ * Structure of a Control Mode mode page.
+ */
+struct scsi_page_ctlmode {
+ u_char cm_rlec, /* report log-activity exception condition */
+ cm_qctl, /* queue control (below) */
+ cm_ecaaen, /* ECA and AEN flags (below) */
+ cm_xxx, /* reserved */
+ cm_aenholdh, /* AEN holdoff period (ms) (MSB) */
+ cm_aenholdl; /* AEN holdoff period (ms) (LSB) */
+};
+#define SCSI_CM_RLEC 0x01 /* RLEC flag occupies only low bit */
+#define SCSI_CM_QMOD(x) ((x) >> 4) /* queue algorithm modifier */
+#define SCSI_CM_QERR 0x02 /* abort cmd queue after error */
+#define SCSI_CM_DQUE 0x01 /* disable tagged queueing */
+#define SCSI_CM_ECA 0x80 /* enable Extended Contingent Alliance */
+#define SCSI_CM_RAENP 0x04 /* target may do Async Err Notif after init */
+#define SCSI_CM_UAAENP 0x02 /* target may do AEN for Unit Attention */
+#define SCSI_CM_EAENP 0x01 /* target may do AEN for deferred errors */
+
+/*
+ * Structure of a CDC-specific Cache Control mode page.
+ */
+struct scsi_page_CDCcachectlmode {
+ u_char ccm_flags, /* flags (below) */
+ ccm_pfthresh, /* prefetch threshold */
+ ccm_maxthresh, /* maximum threshold (?) */
+ ccm_maxpfmult, /* maximum prefetch multiplier */
+ ccm_minthresh, /* minimum thresold (?) */
+ ccm_minpfmult, /* minimum prefetch multiplier */
+ ccm_xxx[8]; /* reserved */
+};
+#define SCSI_CDC_CCM_WIE 0x40 /* write index enable */
+#define SCSI_CDC_CCM_CE 0x10 /* cache enable */
+#define SCSI_CDC_CCM_TBLSZ(x) ((x) & 0xf) /* table size */
+
+/*
+ * Bits in cdb_lenl for a READ CAPACITY command,
+ * and structure returned as data.
+ *
+ * If PMI is off, the lba in the cdb must be 0.
+ */
+#define SCSI_CMD_RC_PMI 0x01 /* Partial Medium Indicator */
+
+struct scsi_rc {
+ u_char rc_lbah; /* logical block address (MSB) */
+ u_char rc_lbahm; /* logical block address */
+ u_char rc_lbalm; /* logical block address */
+ u_char rc_lbal; /* logical block address (LSB) */
+ u_char rc_blh; /* block length (MSB) */
+ u_char rc_blhm; /* block length */
+ u_char rc_bllm; /* block length */
+ u_char rc_bll; /* block length (LSB) */
+};
diff --git a/sys/dev/scsi/disktape.h b/sys/dev/scsi/disktape.h
new file mode 100644
index 00000000000..26dd5bf437e
--- /dev/null
+++ b/sys/dev/scsi/disktape.h
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * 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, Lawrence Berkeley Laboratories.
+ *
+ * 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.
+ *
+ * @(#)disktape.h 8.1 (Berkeley) 6/10/93
+ *
+ * from: $Header: /cvsroot/src/sys/dev/scsi/Attic/disktape.h,v 1.1.1.1 1998/03/01 02:09:34 fvdl Exp $ (LBL)
+ */
+
+/*
+ * Commands common to disk and tape devices, but not other SCSI devices.
+ */
+#define CMD_MODE_SELECT6 0x15 /* mode select (6 byte cdb) */
+#define CMD_MODE_SENSE6 0x1a /* mode sense (6 byte cdb) */
+
+#define CMD_MODE_SELECT10 0x55 /* mode select (10 byte cdb) */
+#define CMD_MODE_SENSE10 0x5a /* mode sense (10 byte cdb) */
+
+/*
+ * Structure of MODE SELECT commands (i.e., the cdb; 6 & 10 byte flavors).
+ * The only difference is that the 10-byte version can give more parameter
+ * bytes.
+ */
+struct scsi_cdb_modeselect6 {
+ u_char cdb_cmd, /* 0x15 */
+ cdb_lun_flags, /* LUN + flags */
+ cdb_xxx[2], /* reserved */
+ cdb_len, /* parameter list length */
+ cdb_ctrl; /* control byte */
+};
+struct scsi_cdb_modeselect10 {
+ u_char cdb_cmd, /* 0x55 */
+ cdb_lun_flags, /* LUN + flags */
+ cdb_xxx[5], /* reserved */
+ cdb_lenh, /* parameter list length (MSB) */
+ cdb_lenl, /* parameter list length (LSB) */
+ cdb_ctrl; /* control byte */
+};
+/* flags in SCSI_MODESELECT commands */
+#define SCSI_MSEL_SCSI1_DATA 0x00 /* SCSI-1 data format */
+#define SCSI_MSEL_SCSI2_DATA 0x10 /* SCSI-2 data format */
+#define SCSI_MSEL_DONTSAVE 0x00 /* don't save pages */
+#define SCSI_MSEL_SAVEPAGES 0x01 /* save mode pages */
+
+/*
+ * Structure of MODE SENSE command (i.e., the cdb; 6 & 10 byte flavors).
+ * Again, the 10-byte version merely allows more parameter bytes.
+ * Note that these lengths include the MODE SENSE headers, while those
+ * for individual mode pages do not. (Consistency? What's that?)
+ */
+struct scsi_cdb_modesense6 {
+ u_char cdb_cmd, /* 0x1a */
+ cdb_lun_flags, /* logical unit number + flags */
+ cdb_pcc, /* page control & code */
+ cdb_xxx, /* reserved */
+ cdb_len, /* allocation length */
+ cdb_ctrl; /* control byte */
+};
+struct scsi_cdb_modesense10 {
+ u_char cdb_cmd, /* 0x5a */
+ cdb_lun_flags, /* logical unit number + flags */
+ cdb_pcc, /* page control & code */
+ cdb_xxx[4], /* reserved */
+ cdb_lenh, /* allocation length (MSB) */
+ cdb_lenl, /* allocation length (MSB) */
+ cdb_ctrl; /* control byte */
+};
+/* flags in SCSI_MODESENSE commands */
+#define SCSI_MSENSE_DBD 0x08 /* device returns db descriptors */
+
+/* page controls */
+#define SCSI_MSENSE_PCTL_CUR 0x00 /* return current parameters */
+#define SCSI_MSENSE_PCTL_VAR 0x40 /* return variable parameters */
+#define SCSI_MSENSE_PCTL_DFLT 0x80 /* return default parameters */
+#define SCSI_MSENSE_PCTL_SAVED 0xc0 /* return saved parameters */
+
+/*
+ * Both MODE_SENSE and MODE_SELECT use a Mode Parameter Header,
+ * followed by an array of Block Descriptors, followed by an array
+ * of Pages. We define structures for the Block Descriptor and Page
+ * header first, then the two (6 and 10 byte) Mode Parameter headers
+ * (not including the Block Descriptor(s) and any mode pages themselves).
+ */
+struct scsi_ms_bd { /* mode sense/select block descriptor */
+ u_char bd_dc, /* density code (tapes only) */
+ bd_nbh, /* number of blocks (MSB) */
+ bd_nbm, /* number of blocks */
+ bd_nbl, /* number of blocks (LSB) */
+ bd_xxx, /* reserved */
+ bd_blh, /* block length (MSB) */
+ bd_blm, /* block length */
+ bd_bll; /* block length (LSB) */
+};
+struct scsi_ms_page_hdr { /* mode sense/select page header */
+ u_char mp_psc, /* saveable flag + code */
+ mp_len; /* parameter length (excludes this header) */
+ /* followed by parameters */
+};
+#define SCSI_MS_MP_SAVEABLE 0x80 /* page can be saved */
+/* 0x40 reserved */
+#define SCSI_MS_PC_MASK 0x3f /* page code mask */
+
+/*
+ * Structure of returned mode sense6 / mode select6 (hence "ms6") data.
+ */
+struct scsi_ms6 {
+ u_char ms_len, /* total sense data length */
+ ms_mt, /* medium type (disks only?) */
+ ms_dsp, /* device specific parameter */
+ ms_bdl; /* block descriptor length (bytes) */
+ /* followed by block descriptors, if any */
+ /* followed by pages, if any */
+};
+/*
+ * Same, but for ms10.
+ */
+struct scsi_ms10 {
+ u_char ms_lenh, /* total sense length (MSB) */
+ ms_lenl, /* total sense length (LSB) */
+ ms_mt, /* medium type (disks only?) */
+ ms_dsp, /* device specific parameter */
+ ms_xxx[2], /* reserved */
+ ms_bdlh, /* block descriptor length (bytes) (MSB) */
+ ms_bdll; /* block descriptor length (bytes) (LSB) */
+ /* followed by block descriptors, if any */
+ /* followed by pages, if any */
+};
+
+/* values for the Medium Type field - disks */
+#define SCSI_MS_MT_DEFAULT 0x00 /* whatever is current */
+#define SCSI_MS_MT_SS 0x01 /* single sided, unspecified medium */
+#define SCSI_MS_MT_DS 0x02 /* double sided, unspecified medium */
+#define SCSI_MS_MT_8SSSD 0x05 /* 8" floppy, SSSD (X3.73-1980) */
+#define SCSI_MS_MT_8DSSD 0x06 /* 8" floppy, DSSD (X3B8-140) */
+#define SCSI_MS_MT_8SSDD 0x09 /* 8" floppy, SSDD (X3B8/78-139) */
+#define SCSI_MS_MT_8DSDD 0x0a /* 8" floppy, DSDD (X3.121-1984) */
+#define SCSI_MS_MT_5SSSD 0x0d /* 5.25" floppy, SSSD (X3.82-1980) */
+#define SCSI_MS_MT_5DSDD 0x12 /* 5.25" floppy, DSDD (X3.125-1984) */
+#define SCSI_MS_MT_5DSDD96 0x16 /* 5.25", DSDD, 96tpi (X3.126-198X) */
+#define SCSI_MS_MT_5DSQD 0x1a /* 5.25", DSQD, 96tpi (DIS 8630) */
+#define SCSI_MS_MT_3DS 0x1e /* 3.5", double sided (X3.137-198X) */
+
+/* values for the Medium Type field - tapes */
+#define SCSI_MS_MT_QIC_12T 0x40 /* 0.25", 12 tracks */
+#define SCSI_MS_MT_QIC_24T 0x44 /* 0.25", 24 tracks */
+
+/* values for the Device Specific Parameter field */
+#define SCSI_MS_DSP_WP 0x80 /* write protect (both disk & tape) */
+
+ /* if disk */
+#define SCSI_MS_DSP_DPO_FUA 0x10 /* cache flags DPO, FUA supported */
+
+ /* if tape */
+#define SCSI_MS_DSP_UNBUFFERED 0x00 /* unbuffered writes */
+#define SCSI_MS_DSP_BUFFERED 0x10 /* buffered writes */
+#define SCSI_MS_DSP_BUF2 0x20 /* buffered, for shared tapes */
+/* 0x30..0x70 reserved */
+#define SCSI_MS_DSP_SPEED_DFLT 0x00 /* use device default speed */
+#define SCSI_MS_DSP_SPEED_MASK 0x0f /* mask for non-default speeds */
+
+/* values for the Density Code field - tapes */
+#define SCSI_MS_DC_DEFAULT 0 /* use device default density */
+#define SCSI_MS_DC_9T_800BPI 1 /* 9 track, 800 bpi */
+#define SCSI_MS_DC_9T_1600BPI 2 /* 9 track, 1600 bpi */
+#define SCSI_MS_DC_9T_6250BPI 3 /* 9 track, 6250 bpi */
+#define SCSI_MS_DC_QIC_XX1 4 /* QIC-11? 4 or 9 track, 8000 bpi */
+#define SCSI_MS_DC_QIC_XX2 5 /* QIC-11? 4 or 9 track, 8000 bpi */
+#define SCSI_MS_DC_9T_3200BPI 6 /* 9 track, 3200 bpi */
+#define SCSI_MS_DC_QIC_XX3 7 /* QIC, 4 track, 6400 bpi */
+#define SCSI_MS_DC_CS_XX4 8 /* cassette 4 track, 8000 bpi */
+#define SCSI_MS_DC_HIC_XX5 9 /* half inch cartridge, 18 track */
+#define SCSI_MS_DC_HIC_XX6 10 /* HIC, 22 track, 6667 bpi */
+#define SCSI_MS_DC_QIC_XX7 11 /* QIC, 4 track, 1600 bpi */
+#define SCSI_MS_DC_HIC_XX8 12 /* HIC, 24 track, 12690 bpi */
+#define SCSI_MS_DC_HIC_XX9 13 /* HIC, 24 track, 25380 bpi */
+
+/*
+ * Common page codes.
+ */
+/* 0x01 device specific */
+#define SCSI_MS_PC_DR 0x02 /* disconnect/reconnect control */
+/* 0x03..0x08 device specific */
+#define SCSI_MS_PC_PDEV 0x09 /* peripheral device page */
+#define SCSI_MS_PC_CTLMODE 0x0a /* control mode page */
+/* 0x0b..0x1f device specific */
+/* 0x20..0x3e vendor specific */
+#define SCSI_MS_PC_ALL 0x3f /* all pages */
+
+/*
+ * Structure of a Disconnect/Reconnect Control mode page.
+ */
+struct scsi_page_dr {
+ u_char dr_full, /* buffer full ratio */
+ dr_empty, /* buffer empty ratio */
+ dr_inacth, /* bus inactivity timeout (MSB) */
+ dr_inactl, /* bus inactivity timeout (LSB) */
+ dr_disconh, /* disconnect time limit (MSB) */
+ dr_disconl, /* disconnect time limit (LSB) */
+ dr_conh, /* connect time limit (MSB) */
+ dr_conl, /* connect time limit (LSB) */
+ dr_bursth, /* maximum burst size (MSB) */
+ dr_burstl, /* maximum burst size (LSB) */
+ dr_dtdc, /* Data Transfer Disconnect Control (below) */
+ dr_xxx[3]; /* reserved */
+};
+/* Data Transfer Disconnect Control */
+#define SCSI_DR_DTDC_MASK 0x03 /* mask for valid bits */
+#define SCSI_DR_DTDC_NONE 0x00 /* no control */
+#define SCSI_DR_DTDC_NOTDATA 0x01 /* never during data transfer */
+#define SCSI_DR_DTDC_RSVD 0x02 /* reserved */
+#define SCSI_DR_DTDC_NOTD2 0x03 /* never during/after data transfer */
+
+/*
+ * Structure of a PREVENT/ALLOW MEDIUM REMOVAL command.
+ */
+struct scsi_cdb_pamr {
+ u_char cdb_cmd, /* 0x1e */
+ cdb_lun_xxx, /* logical unit number + reserved */
+ cdb_xxx1, /* reserved */
+ cdb_xxx2, /* reserved */
+ cdb_prevent, /* 1=prevent, 0=allow */
+ cdb_ctrl;
+};
diff --git a/sys/dev/scsi/printer.h b/sys/dev/scsi/printer.h
new file mode 100644
index 00000000000..b58f249505a
--- /dev/null
+++ b/sys/dev/scsi/printer.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * 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, Lawrence Berkeley Laboratories.
+ *
+ * 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.
+ *
+ * @(#)printer.h 8.1 (Berkeley) 6/10/93
+ *
+ * from: $Header: /cvsroot/src/sys/dev/scsi/Attic/printer.h,v 1.1.1.1 1998/03/01 02:09:34 fvdl Exp $ (LBL)
+ */
+
+/*
+ * SCSI definitions for Printer Devices.
+ */
+#define CMD_FORMAT 0x04 /* (set) format */
+#define CMD_PRINT 0x0a /* print */
+#define CMD_SLEW_PRINT 0x0b /* slew and print */
+#define CMD_FLUSH_BUFFER 0x10 /* flush buffer */
+#define CMD_RBD 0x14 /* recover buffered data */
+#define CMD_MODE_SELECT 0x15 /* mode select */
+#define CMD_RESERVE_UNIT 0x16 /* reserve unit */
+#define CMD_RELEASE_UNIT 0x17 /* release unit */
+#define CMD_MODE_SENSE 0x1a /* mode sense */
+#define CMD_STOP_PRINT 0x1b /* stop print */
diff --git a/sys/dev/scsi/processor.h b/sys/dev/scsi/processor.h
new file mode 100644
index 00000000000..55e96fd3bb9
--- /dev/null
+++ b/sys/dev/scsi/processor.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * 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, Lawrence Berkeley Laboratories.
+ *
+ * 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.
+ *
+ * @(#)processor.h 8.1 (Berkeley) 6/10/93
+ *
+ * from: $Header: /cvsroot/src/sys/dev/scsi/Attic/processor.h,v 1.1.1.1 1998/03/01 02:09:34 fvdl Exp $ (LBL)
+ */
+
+/*
+ * SCSI definitions for Processor Devices.
+ */
+#define CMD_RECEIVE 0x08 /* receive */
+#define CMD_SEND 0x0a /* send */
+
+/*
+ * Structure of a RECEIVE or SEND command (i.e., the cdb).
+ */
+struct scsi_cdb_rs {
+ u_char cdb_cmd, /* 0x8 or 0xa */
+ cdb_lun_xxx, /* logical unit number + reserved */
+ cdb_lenh, /* buffer or data length (MSB) */
+ cdb_lenm, /* buffer or data length */
+ cdb_lenl, /* buffer or data length (LSB) */
+ cdb_ctrl; /* control byte */
+};
diff --git a/sys/dev/scsi/scsi.h b/sys/dev/scsi/scsi.h
new file mode 100644
index 00000000000..04e8830789e
--- /dev/null
+++ b/sys/dev/scsi/scsi.h
@@ -0,0 +1,361 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * 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, Lawrence Berkeley Laboratories.
+ *
+ * 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.
+ *
+ * @(#)scsi.h 8.1 (Berkeley) 6/10/93
+ *
+ * from: $Header: /cvsroot/src/sys/dev/scsi/Attic/scsi.h,v 1.1.1.1 1998/03/01 02:09:34 fvdl Exp $ (LBL)
+ */
+
+/*
+ * Machine independent SCSI defintions.
+ */
+
+/*
+ * Mostly-generic command descriptor blocks (6 and 10 bytes).
+ * Note that no SCSI command uses the 12 byte variety, hence it
+ * is not defined here.
+ */
+struct scsi_cdb6 {
+ u_char cdb_cmd, /* command code */
+ cdb_lun_lbah, /* logical unit number, & lba (MSB) */
+ cdb_lbam, /* logical block address */
+ cdb_lbal, /* logical block address (LSB) */
+ cdb_len, /* transfer length */
+ cdb_ctrl; /* control byte */
+};
+
+struct scsi_cdb10 {
+ u_char cdb_cmd, /* command code */
+ cdb_lun_rel, /* logical unit number, rsvd, & reladr flag */
+ cdb_lbah, /* logical block address (MSB) */
+ cdb_lbahm, /* logical block address (high middle byte) */
+ cdb_lbalm, /* logical block address (low middle byte) */
+ cdb_lbal, /* logical block address (LSB) */
+ cdb_xxx, /* reserved */
+ cdb_lenh, /* transfer length (MSB) */
+ cdb_lenl, /* transfer length (LSB) */
+ cdb_ctrl; /* control byte */
+};
+
+/*
+ * SCSI `generic' cdb.
+ * The length of the cdb is implicit in the first byte (see scsivar.h).
+ * This is 16 bytes, rather than 10 or 12, just to help out alignment.
+ */
+struct scsi_cdb {
+ u_char cdb_bytes[16]; /* up to 16 bytes of command */
+};
+#define CDB6(cdb) ((struct scsi_cdb6 *)&(cdb)->cdb_bytes[0])
+#define CDB10(cdb) ((struct scsi_cdb10 *)&(cdb)->cdb_bytes[0])
+
+/*
+ * SCSI command (cdb_cmd/cdb_bytes[0]) byte definitions. Only those
+ * that are common across all devices are actually defined here.
+ * (The SCSI standard defines six groups of devices: direct access,
+ * sequential access, printer, processor, WORM direct access, and
+ * ROM direct access. DADs and SADs are basically `disk' and `tape';
+ * printers and processors are obvious; and WORMs and ROMs are really
+ * just disks that are missing one or two operations. A few commands
+ * are required of all devices; these are defined here, and the others
+ * are defined in separate headers.)
+ *
+ * Letter flags in parentheses in the comment column indicate:
+ * M = mandatory (command is implemented on all SCSI devices)
+ * E = extended (command implemented if SCSI device does extended SCSI)
+ * O = optional
+ * R = reserved to future SCSI standard
+ * V = vendor unique
+ * * = depends on device type
+ *
+ * Note that SCSI commands are broken into 8 `groups' given by bits 7..5.
+ * Group 0 is 6-byte commands, 1 is 10-byte commands, and 5 is 12-byte
+ * commands (of which none exist); groups 6 and 7 are vendor unique.
+ * Commands are normally just treated as a simple 8-bit number,
+ * but the size of the associated cdb is implied by the group.
+ */
+ /* group 0 */
+#define CMD_TEST_UNIT_READY 0x00 /* (O) test unit ready */
+/* 0x01 (*) */
+/* 0x02 (V) */
+#define CMD_REQUEST_SENSE 0x03 /* (M) request sense */
+/* 0x04..0x05 (*) */
+/* 0x06 (V) */
+/* 0x07..0x08 (*) */
+/* 0x09 (V) */
+/* 0x0a..0x0b (*) */
+/* 0x0c..0x0e (V) */
+/* 0x0f..0x11 (*) */
+#define CMD_INQUIRY 0x12 /* (E) inquiry */
+/* 0x13..0x17 (*) */
+#define CMD_COPY 0x18 /* (O) copy */
+/* 0x19..0x1b (*) */
+#define CMD_RECEIVE_DIAG 0x1c /* (O) receive diagnostic results */
+#define CMD_SEND_DIAG 0x1d /* (O) send diagnostic */
+/* 0x1e (*) */
+/* 0x1f (R) */
+ /* group 1 */
+/* 0x20..0x24 (V) */
+/* 0x25 (*) */
+/* 0x26..0x27 (V) */
+/* 0x28 (*) */
+/* 0x29 (V) */
+/* 0x2a..0x2b (*) */
+/* 0x2c..0x2d (V) */
+/* 0x2e..0x33 (*) */
+/* 0x34..0x37 (R) */
+#define CMD_COMPARE 0x38 /* (O) compare */
+#define CMD_COMPARE_VERIFY 0x39 /* (O) compare and verify */
+/* 0x3a..0x3f (R) */
+ /* group 2 (40-5f) reserved */
+ /* group 3 (60-7f) reserved */
+ /* group 4 (80-9f) reserved */
+ /* group 5 (a0-bf) reserved */
+ /* group 6 (c0-df) vendor unique */
+ /* group 7 (e0-ff) vendor unique */
+
+/*
+ * SCSI control byte.
+ * Bits 7 and 6 are vendor unique; bits 5, 4, 3, and 2 are reserved.
+ * Bit 1 may be 1 only if bit 0 is 1; if so, it tells the target to
+ * send a LINKED COMMAND COMPLETE (WITH FLAG) message. If not, but
+ * bit 0 is set, this tells the target to send a LINKED COMMAND COMPLETE
+ * message.
+ */
+#define CTRL_VU_MASK 0xc0 /* vendor unique */
+#define CTRL_RSVD 0x3c /* reserved, must be zero */
+#define CTRL_LCCF 0x02 /* send LCCF if sending LCC */
+#define CTRL_LINK 0x01 /* linked command */
+
+/*
+ * Generic sense: regular and extended.
+ * A sense operation returned an extended sense iff the error class
+ * is 7. The format is vendor unique unless the error code is 0.
+ * The regular and extended formats are completely different; we
+ * define macros to obtain values from them.
+ */
+struct scsi_sense {
+ u_char sn_vcc; /* valid bit, error class, & error code */
+ u_char sn_var[7]; /* bytes 1-3, or 1-7; variant formats */
+ u_char sn_addl[32-8]; /* additional sense data, if extended */
+};
+
+#define SENSE_ECLASS(sn) (((sn)->sn_vcc >> 4) & 7)
+#define SENSE_ECODE(sn) ((sn)->sn_vcc & 0xf)
+#define SENSE_ISXSENSE(sn) (SENSE_ECLASS(sn) == 7)
+
+/* for non-extended sense (`r'egular or `r'estricted sense) */
+#define RSENSE_LVALID(sn) ((sn)->sn_vcc & 0x80)
+#define RSENSE_VU(sn) ((sn)->sn_var[0] >> 5)
+#define RSENSE_LBA(sn) \
+ ((((sn)->sn_var[0] & 0x1f) << 16) | ((sn)->sn_var[1] << 8) | (sn)->sn_var[2])
+
+/* for extended sense */
+#define XSENSE_ISSTD(sn) (SENSE_ECODE(sn) == 0)
+ /* if not standard, cannot interpret it at all */
+#define XSENSE_IVALID(sn) ((sn)->sn_vcc & 0x80)
+#define XSENSE_SEG(sn) ((sn)->sn_var[0])
+#define XSENSE_FM(sn) ((sn)->sn_var[1] & 0x80) /* filemark */
+#define XSENSE_EOM(sn) ((sn)->sn_var[1] & 0x40) /* end of media */
+#define XSENSE_ILI(sn) ((sn)->sn_var[1] & 0x20) /* incor length ind */
+#define XSENSE_KEY(sn) ((sn)->sn_var[1] & 0x0f) /* sense key */
+#define XSENSE_INFO(sn) \
+ (((sn)->sn_var[2] << 24) | ((sn)->sn_var[3] << 16) | \
+ ((sn)->sn_var[4] << 8) | (sn)->sn_var[5])
+#define XSENSE_ADDL(sn) ((sn)->sn_var[6]) /* add'l sense len */
+
+/*
+ * SCSI INQUIRY data: general, and ANSI versions 1 and 2
+ * (including common command set).
+ */
+struct scsi_inquiry {
+ u_char si_type; /* peripheral device type (below) */
+ u_char si_qual; /* qualifier (see below) */
+ u_char si_version; /* version (see below) */
+ u_char si_v2info; /* scsi version 2 stuff (see below) */
+ u_char si_len; /* additional length */
+ u_char si_more[252-5]; /* actually si_len bytes */
+};
+struct scsi_inq_ansi {
+ u_char si_type; /* peripheral qualifier and device type */
+ u_char si_qual; /* RMB and device type qualifier */
+ u_char si_version; /* ISO, ECMA and ANSI-approved versions */
+ u_char si_v2info; /* ? */
+ u_char si_len; /* addition length */
+ char si_xxx1[2]; /* reserved */
+ char si_flags; /* (see below) */
+ char si_vendor[8]; /* vendor (blank padded) */
+ char si_product[16]; /* product (blank padded) */
+ char si_rev[4]; /* revision (blank padded) */
+
+ /* scsi version 2 stuff follows */
+ char si_vend1[20]; /* vendor specific */
+ char si_xxx2[40]; /* reserved */
+ char si_vend2[252-96]; /* vendor specific parameters */
+};
+
+/* peripheral device types */
+#define TYPE_QUAL_MASK 0xe0 /* peripheral qualifer mask */
+#define TYPE_TYPE_MASK 0x1f /* peripheral device type mask */
+#define TYPE_QUAL_NORM 0x00 /* device is normal */
+#define TYPE_QUAL_NOTCONN 0x20 /* not connected */
+#define TYPE_QUAL_XXX 0x40 /* reserved */
+#define TYPE_QUAL_NOLUN 0x60 /* logical unit not supported */
+#define TYPE_QUAL_VT4 0x80 /* vendor specific type 4 */
+#define TYPE_QUAL_VT5 0xa0 /* vendor specific type 5 */
+#define TYPE_QUAL_VT6 0xc0 /* vendor specific type 6 */
+#define TYPE_QUAL_VT7 0xe0 /* vendor specific type 7 */
+
+#define TYPE_DAD 0x00 /* direct access device (disk) */
+#define TYPE_SAD 0x01 /* sequential access device (tape) */
+#define TYPE_PRINTER 0x02 /* printer */
+#define TYPE_PROCESSOR 0x03 /* processor */
+#define TYPE_WORM 0x04 /* WORM disk */
+#define TYPE_ROM 0x05 /* CD-ROM disk */
+#define TYPE_SCANNER 0x06 /* scanner */
+#define TYPE_MO 0x07 /* magneto-optical */
+#define TYPE_JUKEBOX 0x08 /* medium changer */
+#define TYPE_LAN 0x09 /* communications device */
+#define TYPE_NP 0x1f /* unknown or no device */
+
+/* qualifiers */
+#define QUAL_RMB 0x80 /* removable medium bit */
+#define QUAL_MASK 0x7f /* mask for `user' bits */
+
+/* version (shifts and masks for subfields) */
+#define VER_ISO_SHIFT 6 /* ISO version: top 2 bits */
+#define VER_ISO_MASK 3
+#define VER_ECMA_SHIFT 3 /* ECMA version: middle 3 bits */
+#define VER_ECMA_MASK 7
+#define VER_ANSI_SHIFT 0 /* ANSI version: bottom 3 bits */
+#define VER_ANSI_MASK 7
+
+/* v2 info */
+#define V2INFO_AENC 0x80 /* device can accept AEN data */
+#define V2INFO_TRMIOP 0x40 /* supports TERMINATE I/O PROC msg */
+#define V2INFO_XXX 0x30 /* reserved */
+#define V2INFO_RDF_MASK 0x0f /* response data format mask */
+#define V2INFO_RDF_SCSI1 0x00 /* SCSI-1 standard INQUIRY data */
+#define V2INFO_RDF_CCS 0x01 /* common command set INQUIRY data */
+#define V2INFO_RDF_SCSI2 0x02 /* SCSI-2 standard INQUIRY data */
+
+/* flags */
+#define V2FLAG_RELADR 0x80 /* supports relative addressing */
+#define V2FLAG_WBUS32 0x40 /* supports 32 bit data xfer */
+#define V2FLAG_WBUS16 0x20 /* supports 32 bit data xfer */
+#define V2FLAG_SYNC 0x10 /* supports synchronous data xfer */
+#define V2FLAG_LINKED 0x08 /* supports linked commands */
+#define V2FLAG_XXX 0x04 /* reserved */
+#define V2FLAG_CMDQUE 0x02 /* supports tagged command queueing */
+#define V2FLAG_SOFTRESET 0x01 /* RST causes soft reset */
+
+/*
+ * SCSI message codes bytes. The `command complete' code is required;
+ * all others are optional. `Identify' is a flag bit, not a code (thus
+ * codes are actually at most 7 bits).
+ */
+#define MSG_IDENTIFY 0x80 /* flag => this is an identify msg */
+#define MSG_IDENTIFY_DR 0x40 /* IDENTIFY: flag => discon/resel ok */
+#define MSG_IDENTIFY_RSVD 0x38 /* IDENTIFY: these bits are reserved */
+#define MSG_IDENTIFY_LUN 0x07 /* IDENTIFY: these bits give LUN */
+
+#define MSG_CMD_COMPLETE 0x00 /* command complete */
+#define MSG_EXT_MESSAGE 0x01 /* extended message */
+#define MSG_SAVE_DATA_PTR 0x02 /* save data pointer */
+#define MSG_RESTORE_PTR 0x03 /* restore pointers */
+#define MSG_DISCONNECT 0x04 /* disconnect */
+#define MSG_INIT_DETECT_ERROR 0x05 /* initiator detected error */
+#define MSG_ABORT 0x06 /* abort */
+#define MSG_REJECT 0x07 /* message reject */
+#define MSG_NOOP 0x08 /* no operation */
+#define MSG_PARITY_ERROR 0x09 /* message parity error */
+#define MSG_LCC 0x0a /* linked command complete */
+#define MSG_LCCF 0x0b /* linked command complete (w/ flag) */
+#define MSG_BUS_DEVICE_RESET 0x0c /* bus device reset */
+#define MSG_ABORT_TAG 0x0d /* abort tagged msg */
+#define MSG_CLEAR_QUEUE 0x0e /* clear queue */
+#define MSG_INITIATE_RECOVERY 0x0f /* initiate recovery */
+#define MSG_RELEASE_RECOVERY 0x10 /* release recovery */
+#define MSG_TERMINATE_PROCESS 0x11 /* ? */
+#define MSG_SIMPLE_Q_TAG 0x20 /* ? */
+#define MSG_HEAD_Q_TAG 0x21 /* ? */
+#define MSG_ORDERED_Q_TAG 0x22 /* ? */
+#define MSG_IGNORE_WIDE_RESID 0x23 /* ? */
+
+/*
+ * SCSI extended message format.
+ */
+struct scsi_xmsg {
+ u_char xm_xmsg, /* value 1, i.e., SMSG_EXT_MESSAGE */
+ xm_len, /* length of this extended message */
+ xm_code, /* actual code */
+ xm_args[253]; /* actualy xm_len-1 bytes */
+};
+
+/*
+ * SCSI extended message codes.
+ */
+#define XMSG_MDP 0x00 /* modify data pointer */
+#define XMSG_SDTR 0x01 /* synchronous data transfer request */
+#define XMSG_XID 0x02 /* extended identify */
+
+/*
+ * SCSI status byte values. Bits 6, 5, and 0 are Vendor Unique.
+ */
+#define STS_EXT 0x80 /* flag => extended status valid */
+#define STS_MASK 0x1e /* mask for non-VU bits */
+#define STS_VU 0x61 /* mask for Vendor Unique bits */
+
+#define STS_GOOD 0x00 /* success, command done */
+#define STS_CHECKCOND 0x02 /* check condition (do a REQ SENSE) */
+#define STS_CONDMET 0x04 /* condition met (search succeeded) */
+ /* 0x06 reserved */
+#define STS_BUSY 0x08 /* busy */
+ /* 0x0a reserved */
+ /* 0x0c reserved */
+ /* 0x0e reserved */
+#define STS_INTERMED 0x10 /* succeeded, doing linked cmd */
+ /* 0x12 reserved */
+#define STS_INTERMED_CONDMET 0x14 /* condition met, doing linked cmd */
+ /* 0x16 reserved */
+#define STS_RESERV_CONFLICT 0x18 /* reservation conflict */
+ /* 0x1a reserved */
+ /* 0x1c reserved */
+ /* 0x1e reserved */
diff --git a/sys/dev/scsi/scsi_ioctl.h b/sys/dev/scsi/scsi_ioctl.h
new file mode 100644
index 00000000000..7fdffb368f0
--- /dev/null
+++ b/sys/dev/scsi/scsi_ioctl.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * 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, Lawrence Berkeley Laboratories.
+ *
+ * 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.
+ *
+ * @(#)scsi_ioctl.h 8.1 (Berkeley) 6/10/93
+ *
+ * from: $Header: /cvsroot/src/sys/dev/scsi/Attic/scsi_ioctl.h,v 1.1.1.1 1998/03/01 02:09:34 fvdl Exp $ (LBL)
+ */
+
+/*
+ * SCSI ioctls (`format' mode).
+ *
+ * Format mode allows a privileged process to issue direct SCSI commands
+ * to a drive (it is intended primarily to allow on-line formatting).
+ * SDIOCSFORMAT sets format mode (nonzero arg => on, zero arg => off).
+ * When in format mode, only the process that issued the SDIOCSFORMAT
+ * can read or write the drive.
+ *
+ * In format mode, the process is expected to
+ * - do SDIOCSCSICOMMAND to supply cdb for next SCSI op
+ * - do read or write as appropriate for cdb
+ * - if I/O error, optionally do SDIOCSENSE to get completion
+ * status and sense data from last SCSI operation.
+ */
+
+struct scsi_fmt_sense {
+ u_int status; /* completion status of last op */
+ u_char sense[28]; /* sense data (if any) from last op */
+};
+
+#define SDIOCSFORMAT _IOW('S', 1, int)
+#define SDIOCGFORMAT _IOR('S', 2, int)
+#define SDIOCSCSICOMMAND _IOW('S', 3, struct scsi_cdb)
+#define SDIOCSENSE _IOR('S', 4, struct scsi_fmt_sense)
diff --git a/sys/dev/scsi/scsi_subr.c b/sys/dev/scsi/scsi_subr.c
new file mode 100644
index 00000000000..63e36518b6c
--- /dev/null
+++ b/sys/dev/scsi/scsi_subr.c
@@ -0,0 +1,532 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * 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, Lawrence Berkeley Laboratories.
+ *
+ * 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.
+ *
+ * @(#)scsi_subr.c 8.1 (Berkeley) 6/16/93
+ *
+ * from: $Header: /cvsroot/src/sys/dev/scsi/Attic/scsi_subr.c,v 1.1.1.1 1998/03/01 02:09:34 fvdl Exp $ (LBL)
+ */
+
+/*
+ * Generic SCSI host adapter driver.
+ * Does almost nothing (most work is relegated to per-hba drivers).
+ */
+
+#include <sys/param.h>
+#include <sys/buf.h>
+#include <sys/device.h>
+
+#include <dev/scsi/scsi.h>
+#include <dev/scsi/scsivar.h>
+
+/*
+ * General subroutines, and scsi data.
+ */
+
+/* table of lengths of scsi commands */
+const char scsicmdlen[8] = { 6, 10, 0, 0, 0, 12, 0, 0 };
+
+/* table of lengths of scsi messages */
+const signed char scsimsglen[0x24] = {
+ SMLEN_DONE, /* MSG_CMD_COMPLETE */
+ SMLEN_EXTENDED, /* MSG_EXT_MESSAGE */
+ 1, /* MSG_SAVE_DATA_PTR */
+ 1, /* MSG_RESTORE_PTR */
+ 1, /* MSG_DISCONNECT */
+ 1, /* MSG_INIT_DETECT_ERROR */
+ 1, /* MSG_ABORT */
+ 1, /* MSG_REJECT */
+ 1, /* MSG_NOOP */
+ 1, /* MSG_PARITY_ERROR */
+ 1, /* MSG_LCC */
+ 1, /* MSG_LCCF */
+ 1, /* MSG_BUS_DEVICE_RESET */
+ 1, /* MSG_ABORT_TAG */
+ 1, /* MSG_CLEAR_QUEUE */
+ 1, /* MSG_INITIATE_RECOVERY */
+ 1, /* MSG_RELEASE_RECOVERY */
+ 1, /* MSG_TERMINATE_PROCESS */
+ SMLEN_UNDEF, /* 0x12 */
+ SMLEN_UNDEF, /* 0x13 */
+ SMLEN_UNDEF, /* 0x14 */
+ SMLEN_UNDEF, /* 0x15 */
+ SMLEN_UNDEF, /* 0x16 */
+ SMLEN_UNDEF, /* 0x17 */
+ SMLEN_UNDEF, /* 0x18 */
+ SMLEN_UNDEF, /* 0x19 */
+ SMLEN_UNDEF, /* 0x1a */
+ SMLEN_UNDEF, /* 0x1b */
+ SMLEN_UNDEF, /* 0x1c */
+ SMLEN_UNDEF, /* 0x1d */
+ SMLEN_UNDEF, /* 0x1e */
+ SMLEN_UNDEF, /* 0x1f */
+ 2, /* MSG_SIMPLE_QTAG */
+ 2, /* MSG_HEAD_QTAG */
+ 2, /* MSG_ORDERED_QTAG */
+ 2, /* MSG_IGNORE_WIDE_RESID */
+};
+
+/* definition of `tg' target driver for autoconfig */
+static int scsi_targmatch __P((struct device *, struct cfdata *, void *));
+static void scsi_targattach __P((struct device *, struct device *, void *));
+struct cfdriver tgcd =
+ { NULL, "tg", scsi_targmatch, scsi_targattach,
+ DV_DULL, sizeof(struct targ) };
+
+void scsi_targstart __P((struct device *, struct sq *, struct buf *,
+ scdgo_fn, struct device *));
+int scsi_targgo __P((struct device *, int targ,
+ scintr_fn, struct device *, struct buf *, int));
+void scsi_targintr __P((struct device *, int, int));
+void scsi_targrel __P((struct device *));
+
+#define NOBUF ((caddr_t)0)
+
+/*
+ * Perform a TEST UNIT READY immediate (polled) command
+ * on the given <target,unit> pair. Return the status byte
+ * returned, or -1 for none.
+ */
+int
+scsi_test_unit_ready(hba, targ, unit)
+ struct hba_softc *hba;
+ int targ, unit;
+{
+ struct scsi_cdb cdb;
+
+ CDB6(&cdb)->cdb_cmd = CMD_TEST_UNIT_READY;
+ CDB6(&cdb)->cdb_lun_lbah = unit << 5;
+ *(short *)&CDB6(&cdb)->cdb_lbam = 0;
+ *(short *)&CDB6(&cdb)->cdb_len = 0;
+ return (hba->hba_driver->hd_icmd(hba, targ, &cdb, NOBUF, 0, 0));
+}
+
+/*
+ * Request sense. The sense is to be written into the given buffer.
+ * The given length must be < 256.
+ */
+int
+scsi_request_sense(hba, targ, unit, buf, len)
+ struct hba_softc *hba;
+ int targ, unit;
+ caddr_t buf;
+ int len;
+{
+ struct scsi_cdb cdb;
+
+ CDB6(&cdb)->cdb_cmd = CMD_REQUEST_SENSE;
+ CDB6(&cdb)->cdb_lun_lbah = unit << 5;
+ *(short *)&CDB6(&cdb)->cdb_lbam = 0;
+ CDB6(&cdb)->cdb_len = len;
+ CDB6(&cdb)->cdb_ctrl = 0;
+ return (hba->hba_driver->hd_icmd(hba, targ, &cdb, buf, len, B_READ));
+}
+
+/*
+ * Called (indirectly, via config_found) from scsi_hbaattach.
+ * Print target number, and if no device was configured there,
+ * the hba as well.
+ */
+int
+scsi_targprint(aux, hba)
+ void *aux;
+ char *hba;
+{
+
+ if (hba) {
+ printf("target %d on %s", *(int *)aux, hba);
+ return (UNCONF);
+ }
+ printf(" target %d", *(int *)aux);
+ return (QUIET);
+}
+
+/*
+ * Print information about a unit found on some target.
+ * If the unit was not configured, `targ' is the name of the target
+ * on which the unit was found. If it was, targ is NULL and we
+ * let the unit's attach routine print the INQUIRE result if
+ * appropriate.
+ */
+static int
+scsi_unitprint(aux, targ)
+ void *aux;
+ char *targ;
+{
+ register struct scsi_attach_args *sa = aux;
+
+ if (targ) {
+ printf("unit %d at %s", sa->sa_unit, targ);
+ if ((sa->sa_inq_status & STS_MASK) == STS_GOOD) {
+ printf(" (");
+ scsi_printinq(&sa->sa_si);
+ printf(")");
+ }
+ return (UNCONF);
+ }
+ printf(" unit %d", sa->sa_unit);
+ return (QUIET);
+}
+
+/*
+ * Generic target-match.
+ */
+static int
+scsi_targmatch(parent, cf, aux)
+ struct device *parent;
+ register struct cfdata *cf;
+ void *aux;
+{
+ int targ = *(int *)aux;
+
+ return (cf->cf_loc[0] == targ || cf->cf_loc[0] == -1);
+}
+
+/*
+ * And now, a generic `target attach' routine.
+ * We assume that INQUIRY works.
+ */
+static void
+scsi_targattach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ register struct targ *t = (struct targ *)self;
+ register struct hba_softc *hba;
+ register struct hbadriver *hd;
+ register int targ, unit;
+ struct scsi_attach_args sa;
+ struct scsi_cdb si;
+
+ printf("\n");
+ t->t_targ = targ = *(int *)aux;
+ hba = (struct hba_softc *)parent;
+ hba->hba_targets[targ] = t;
+
+ /*
+ * Probe each of the 8 units using the sequence
+ * TEST UNIT READY
+ * REQUEST SENSE
+ * INQUIRY
+ * The first should not be necessary, but some SCSI devices
+ * refuse to speak until it is done. The second is only necessary
+ * if the first returns a CHECK CONDITION status, but we do it
+ * anyway.
+ */
+ hd = hba->hba_driver;
+ sa.sa_targ = targ;
+ CDB6(&si)->cdb_cmd = CMD_INQUIRY;
+ *(short *)&CDB6(&si)->cdb_lbam = 0;
+ CDB6(&si)->cdb_len = sizeof sa.sa_si;
+ CDB6(&si)->cdb_ctrl = 0;
+ for (unit = 0; unit < 8; unit++) {
+ if (scsi_test_unit_ready(hba, targ, unit) == -1)
+ continue;
+ sa.sa_unit = unit;
+ sa.sa_req_status = scsi_request_sense(hba, targ, unit,
+ (caddr_t)&sa.sa_sn, sizeof sa.sa_sn);
+ CDB6(&si)->cdb_lun_lbah = unit << 5;
+ sa.sa_inq_status = (*hd->hd_icmd)(hba, targ, &si,
+ (caddr_t)&sa.sa_si, sizeof sa.sa_si, B_READ);
+ if ((sa.sa_inq_status & STS_MASK) == STS_GOOD &&
+#ifdef notdef /* XXX don't know if this is a reasonable test */
+ (sa.sa_si.si_type & TYPE_QUAL_MASK) == TYPE_QUAL_NOTCONN &&
+#endif
+ (sa.sa_si.si_type & TYPE_TYPE_MASK) == TYPE_NP) {
+ continue;
+ }
+ config_found(&t->t_dev, (void *)&sa, scsi_unitprint);
+ }
+}
+
+/*
+ * Each unit calls scsi_establish to tell the hba and target of
+ * its existence.
+ */
+void
+scsi_establish(u, dev, unit)
+ register struct unit *u;
+ struct device *dev;
+ register int unit;
+{
+ register struct targ *t;
+ register struct hba_softc *hba;
+ register struct hbadriver *hbd;
+
+ u->u_dev = dev;
+ t = (struct targ *)dev->dv_parent;
+ hba = (struct hba_softc *)t->t_dev.dv_parent;
+ hbd = hba->hba_driver;
+ t->t_units[unit] = u;
+ if (t->t_nunits == 0) {
+ /*
+ * This is the first unit on the target. We can
+ * probably just call the hba start code, avoiding
+ * one level of calls and queueing. If we attach
+ * another target we will fix this in the code below.
+ */
+ u->u_start = hbd->hd_start;
+ u->u_go = hbd->hd_go;
+ u->u_rel = hbd->hd_rel;
+ u->u_updev = &hba->hba_dev;
+ t->t_firstunit = unit;
+ } else {
+ /*
+ * This is not the only unit on the target, so we
+ * must call the target start code rather than the
+ * hba start code. Fix the linkage on the first
+ * target too (possibly for the 2nd, 3rd, ..., time).
+ */
+ t->t_units[t->t_firstunit]->u_start = scsi_targstart;
+ t->t_units[t->t_firstunit]->u_go = scsi_targgo;
+ t->t_units[t->t_firstunit]->u_rel = scsi_targrel;
+ t->t_units[t->t_firstunit]->u_updev = &t->t_dev;
+ u->u_start = scsi_targstart;
+ u->u_go = scsi_targgo;
+ u->u_rel = scsi_targrel;
+ u->u_updev = &t->t_dev;
+ }
+ t->t_nunits++; /* another unit is alive */
+ u->u_unit = unit;
+ u->u_targ = t->t_targ; /* record target number, */
+ u->u_hba = hba; /* hba ... */
+ u->u_hbd = hbd; /* and driver */
+}
+
+/* NO DOUBT SOME OF THE STUFF PRINTED HERE IS USELESS */
+void
+scsi_printinq(inq)
+ register struct scsi_inquiry *inq;
+{
+ register int iso, ecma, ansi, t;
+ static char *types[] = { "disk", "tape", "printer", "processor",
+ "WORM", "ROM disk", "scanner", "magneto-optical",
+ "jukebox", "lan" };
+
+ if ((t = (inq->si_type & TYPE_QUAL_MASK)) != 0)
+ printf("type-qual=0x%x ", t);
+ t = inq->si_type & TYPE_TYPE_MASK;
+ if (t < sizeof types / sizeof *types)
+ printf("%s", types[t]);
+ else
+ printf("<type %d>", t);
+ if (inq->si_qual & QUAL_RMB)
+ printf(" (removable)");
+ printf(" qual=0x%x", inq->si_qual & QUAL_MASK);
+ iso = (inq->si_qual >> VER_ISO_SHIFT) & VER_ISO_MASK;
+ ecma = (inq->si_qual >> VER_ECMA_SHIFT) & VER_ECMA_MASK;
+ ansi = (inq->si_qual >> VER_ANSI_SHIFT) & VER_ANSI_MASK;
+ printf(" version=<iso %d, ecma %d, ansi %d>", iso, ecma, ansi);
+ if (ansi == 1 || ansi == 2) {
+ char v[9], p[17], r[5];
+
+ scsi_inq_ansi((struct scsi_inq_ansi *)inq, v, p, r);
+ printf(" vendor %s, product %s, rev %s", v, p, r);
+ }
+}
+
+/* copy a counted string but trim trailing blanks; make the dest a C string */
+static void
+scsi_str(src, dst, len)
+ register char *src, *dst;
+ register int len;
+{
+
+ while (src[len - 1] == ' ') {
+ if (--len == 0) {
+ *dst = 0;
+ return;
+ }
+ }
+ bcopy(src, dst, len);
+ dst[len] = 0;
+}
+
+void
+scsi_inq_ansi(si, vendor, product, rev)
+ register struct scsi_inq_ansi *si;
+ char *vendor, *product, *rev;
+{
+ register int i, len;
+
+ /* if too short, extend with blanks */
+ len = si->si_len + 5; /* 5 fixed; len is `additional' */
+ if (len < sizeof(*si))
+ for (i = len; i < sizeof *si; i++)
+ ((char *)si)[i] = ' ';
+ scsi_str(si->si_vendor, vendor, sizeof si->si_vendor);
+ scsi_str(si->si_product, product, sizeof si->si_product);
+ scsi_str(si->si_rev, rev, sizeof si->si_rev);
+}
+
+/*
+ * Tell all the devices on the given hba that it has been reset.
+ * SHOULD PROBABLY DO MORE HERE
+ */
+void
+scsi_reset_units(hba)
+ register struct hba_softc *hba;
+{
+ register int targ, unit;
+ register struct targ *t;
+ register struct unit *u;
+
+ for (targ = 0; targ < 8; targ++) {
+ if ((t = hba->hba_targets[targ]) == NULL)
+ continue;
+ for (unit = 0; unit < 8; unit++)
+ if ((u = t->t_units[unit]) != NULL)
+ (*u->u_driver->ud_reset)(u);
+ }
+}
+
+/*
+ * Start a unit on a target.
+ * If the target is busy, just enqueue the unit;
+ * once the target becomes free, we will call the hba start routine.
+ * Otherwise, call the hba start routine now, and then when the hba
+ * becomes free it will call the unit's dgo routine.
+ */
+void
+scsi_targstart(self, sq, bp, dgo, dev)
+ struct device *self;
+ register struct sq *sq;
+ struct buf *bp;
+ scdgo_fn dgo;
+ struct device *dev;
+{
+ register struct targ *t = (struct targ *)self;
+ register struct hba_softc *hba;
+
+ sq->sq_forw = NULL;
+ if (t->t_head == NULL)
+ t->t_head = sq;
+ else
+ t->t_tail->sq_forw = sq;
+ t->t_tail = sq;
+ if (t->t_busy == 0) {
+ t->t_busy = 1;
+ hba = (struct hba_softc *)t->t_dev.dv_parent;
+ (*hba->hba_driver->hd_start)(&hba->hba_dev, &t->t_forw, bp,
+ dgo, dev);
+ } else {
+ sq->sq_bp = bp;
+ sq->sq_dgo = dgo;
+ sq->sq_dev = dev;
+ }
+}
+
+/*
+ * The unit got the bus, and wants the hba to go.
+ * Remember its interrupt handler; substitute ours instead.
+ */
+int
+scsi_targgo(self, targ, intr, dev, bp, pad)
+ struct device *self;
+ int targ;
+ scintr_fn intr;
+ struct device *dev;
+ struct buf *bp;
+ int pad;
+{
+ register struct targ *t = (struct targ *)self;
+ register struct hba_softc *hba;
+
+ t->t_intr = intr;
+ t->t_intrdev = dev;
+ hba = (struct hba_softc *)t->t_dev.dv_parent;
+ return ((*hba->hba_driver->hd_go)(&hba->hba_dev, targ,
+ scsi_targintr, &t->t_dev, bp, pad));
+}
+
+/*
+ * The hba got an interrupt. Dequeue the unit from the target
+ * (the target is already off the hba queue) and then call the
+ * underlying interrupt handler.
+ */
+void
+scsi_targintr(self, stat, resid)
+ struct device *self;
+ int stat, resid;
+{
+ register struct targ *t = (struct targ *)self;
+ register struct hba_softc *hba;
+ register struct sq *sq;
+
+ sq = t->t_head;
+if (sq == NULL) panic("scsi_targintr");
+ t->t_head = sq = sq->sq_forw;
+ (*t->t_intr)(t->t_intrdev, stat, resid);
+ if (sq != NULL) {
+ hba = (struct hba_softc *)t->t_dev.dv_parent;
+ (*hba->hba_driver->hd_start)(&hba->hba_dev, &t->t_forw,
+ sq->sq_bp, sq->sq_dgo, sq->sq_dev);
+ } else
+ t->t_busy = 0;
+}
+
+/*
+ * The unit decided that it needed to `give up' its hold on the bus early.
+ */
+void
+scsi_targrel(self)
+ struct device *self;
+{
+ register struct targ *t = (struct targ *)self;
+ register struct hba_softc *hba;
+ register struct sq *sq;
+
+ hba = (struct hba_softc *)t->t_dev.dv_parent;
+ sq = t->t_head;
+if (sq == NULL) panic("scsi_targrel");
+ /*
+ * This target is at the head of the hba queue.
+ * Remove it by calling hba bus release. Then, if the
+ * target queue is not empty, put it back on the hba queue.
+ * (This produces round robin service.)
+ */
+ (*hba->hba_driver->hd_rel)(&hba->hba_dev);
+ sq = sq->sq_forw;
+ if ((t->t_head = sq) != NULL)
+ (*hba->hba_driver->hd_start)(&hba->hba_dev, &t->t_forw,
+ sq->sq_bp, sq->sq_dgo, sq->sq_dev);
+ else
+ t->t_busy = 0;
+}
diff --git a/sys/dev/scsi/scsivar.h b/sys/dev/scsi/scsivar.h
new file mode 100644
index 00000000000..d157c3471f2
--- /dev/null
+++ b/sys/dev/scsi/scsivar.h
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * 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, Lawrence Berkeley Laboratories.
+ *
+ * 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.
+ *
+ * @(#)scsivar.h 8.1 (Berkeley) 6/10/93
+ *
+ * from: $Header: /cvsroot/src/sys/dev/scsi/Attic/scsivar.h,v 1.1.1.1 1998/03/01 02:09:34 fvdl Exp $ (LBL)
+ */
+
+/*
+ * SCSI variables.
+ *
+ * Each SCSI Host Bus Adapter (hba) has:
+ * a target queue head and tail
+ * eight targets (for units to enqueue on)
+ * a list of all units on all targets
+ * its target number (the number cpu uses in initiating requests)
+ * a driver
+ * Each SCSI target has:
+ * a forward link so that it can sit on a SCSI host bus adapter queue
+ * a unit queue head and tail
+ * Each SCSI unit has:
+ * a forward link so that it can sit on a SCSI target queue
+ * a driver
+ * an hba & driver (so that we need not chase parent pointers)
+ */
+
+/*
+ * Downcalls. These are usually made from hba to unit, but can be
+ * hba->target->unit (when there are multiple units on a target).
+ */
+/* device go function (`you got bus') */
+typedef void (*scdgo_fn) __P((struct device *, struct scsi_cdb *));
+
+/* intr function (`you no got bus no more') */
+typedef void (*scintr_fn) __P((struct device *, int stat, int resid));
+
+/*
+ * Upcalls. These are usually made from unit to hba, but can be
+ * unit->target->hba.
+ */
+/* bus alloc function (`please get me bus') */
+struct sq; struct buf;
+typedef void (*scstart_fn) __P((struct device *, struct sq *, struct buf *,
+ scdgo_fn, struct device *));
+
+/* bus go function (`I have bus and I set up cmd, so start it up') */
+typedef int (*scbusgo_fn) __P((struct device *, int targ,
+ scintr_fn, struct device *,
+ struct buf *, int pad));
+
+/* bus release function (`I have bus but do not need it after all') */
+typedef void (*scbusrel_fn) __P((struct device *));
+
+/*
+ * SCSI Queue. This is an element in a queue of devices (targets
+ * and/or units) waiting for the bus.
+ */
+struct sq {
+ struct sq *sq_forw; /* forward link */
+ struct buf *sq_bp; /* buffer for transfer */
+ scdgo_fn sq_dgo; /* device-go to call when got bus */
+ struct device *sq_dev; /* device argument to sq_dgo */
+};
+
+struct hba_softc {
+ struct device hba_dev; /* generic part */
+ struct sq *hba_head, *hba_tail;/* io queue (u's/t's wanting bus) */
+ char hba_busy; /* true => will inspect qhead later */
+ struct targ *hba_targets[8]; /* the 8 possible targets */
+ struct hbadriver *hba_driver; /* hba driver */
+ scintr_fn hba_intr; /* current interrupt function */
+ struct device *hba_intrdev; /* arg 0 for hba_intr */
+};
+
+struct targ {
+ struct device t_dev; /* generic part */
+ struct sq t_forw; /* forward link, etc, on hba queue */
+ struct sq *t_head, *t_tail; /* io queue */
+ char t_busy; /* true => will inspect qhead later */
+ char t_targ; /* target number */
+ char t_nunits; /* count of live units */
+ char t_firstunit; /* the first live unit */
+ struct unit *t_units[8]; /* the 8 possible units */
+ scintr_fn t_intr; /* current interrupt function */
+ struct device *t_intrdev; /* arg 0 for t_intr */
+};
+
+/* since a unit may be a disk, tape, etc., it has only pointer to dev */
+struct unit {
+ struct device *u_dev; /* backpointer to generic */
+ int u_unit; /* unit number on target */
+ scstart_fn u_start; /* upcall to get bus */
+ scbusgo_fn u_go; /* upcall to use bus */
+ scbusrel_fn u_rel; /* upcall to release bus early */
+ struct device *u_updev; /* device for upcalls */
+ struct sq u_forw; /* forward link on target or hba q */
+ struct unitdriver *u_driver; /* unit driver */
+/* the following three fields are copied from target & hba, for quick lookup */
+ int u_targ; /* target number */
+ struct hba_softc *u_hba; /* hba, from parent */
+ struct hbadriver *u_hbd; /* hba driver, from parent */
+};
+
+/*
+ * SCSI hba driver.
+ */
+struct hbadriver {
+ /* immediate command; should not depend on receiving interrupts */
+ int (*hd_icmd) __P((struct hba_softc *, int targ,
+ struct scsi_cdb *cmd,
+ caddr_t addr, int len, int rw));
+ /* crash dump: like icmd(B_WRITE), but possibly from physmem */
+ int (*hd_dump) __P((struct hba_softc *, int targ,
+ struct scsi_cdb *cmd, caddr_t addr, int len));
+ scstart_fn hd_start; /* allocate DMA & bus */
+ scbusgo_fn hd_go; /* start DMA xfer on bus */
+ scbusrel_fn hd_rel; /* release bus early */
+ void (*hd_reset) __P((struct hba_softc *, int));
+};
+
+/*
+ * SCSI unit driver (`downcalls' from hba to unit).
+ */
+struct unitdriver {
+ void (*ud_reset) __P((struct unit *)); /* SCSI bus reset */
+};
+
+/*
+ * The generic SCSI target probe code passes the following to
+ * unit configuration `match' routines.
+ */
+struct scsi_attach_args {
+ int sa_targ; /* target number */
+ int sa_unit; /* unit number */
+ int sa_req_status; /* status from REQUEST SENSE */
+ struct scsi_sense sa_sn; /* contents from same */
+ int sa_inq_status; /* status from INQUIRY command */
+ struct scsi_inquiry sa_si; /* contents from same */
+};
+
+/*
+ * The SCSICMDLEN macro gives the SCSI-standard-defined length of
+ * a given SCSI command. This is 0 if the command is in an undefined
+ * group (see scsi.h).
+ */
+extern const char scsicmdlen[8];
+#define SCSICMDLEN(cmd) scsicmdlen[(cmd) >> 5]
+
+/*
+ * The SCSIMSGLEN macro gives the SCSI-standard-defined length of
+ * a given SCSI message byte. This is -1 if the message byte is
+ * undefined, -3 if it is an identify, -2 for an extended message,
+ * 0 if it is normal completion, otherwise positive.
+ */
+#define SMLEN_IDENTIFY -3
+#define SMLEN_EXTENDED -2
+#define SMLEN_UNDEF -1
+#define SMLEN_DONE 0
+extern const signed char scsimsglen[0x24];
+#define SCSIMSGLEN(msg) ((msg) & MSG_IDENTIFY ? SMLEN_IDENTIFY : \
+ (msg) > 0x24 ? SMLEN_UNDEF : scsimsglen[msg])
+
+/*
+ * Declarations for exported functions in scsi_subr.c
+ */
+int scsi_test_unit_ready __P((struct hba_softc *, int targ, int unit));
+int scsi_request_sense __P((struct hba_softc *, int, int, caddr_t, int));
+void scsi_hbaattach __P((struct hba_softc *));
+void scsi_establish __P((struct unit *, struct device *, int));
+void scsi_printinq __P((struct scsi_inquiry *));
+void scsi_inq_ansi __P((struct scsi_inq_ansi *, char *, char *, char *));
+void scsi_reset_units __P((struct hba_softc *));
+
+#define SCSI_FOUNDTARGET(hba, targ) { \
+ extern int scsi_targprint(void *, char *); \
+ int _t = targ; \
+ config_found(&(hba)->hba_dev, (void *)&_t, scsi_targprint); \
+}
diff --git a/sys/dev/scsi/sd.c b/sys/dev/scsi/sd.c
new file mode 100644
index 00000000000..6aa2d373cef
--- /dev/null
+++ b/sys/dev/scsi/sd.c
@@ -0,0 +1,909 @@
+/*
+ * Copyright (c) 1990, 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * 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, Lawrence Berkeley Laboratory.
+ *
+ * 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.
+ *
+ * @(#)sd.c 8.1 (Berkeley) 6/10/93
+ *
+ * from: $Header: /cvsroot/src/sys/dev/scsi/Attic/sd.c,v 1.1.1.1 1998/03/01 02:09:34 fvdl Exp $
+ */
+
+/*
+ * SCSI CCS (Command Command Set) disk driver.
+ *
+ * MACHINE INDEPENDENT (do not put machine dependent goo in here!)
+ *
+ * (from sd.c,v 1.7 90/12/15 14:11:26 van Exp)
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/buf.h>
+#include <sys/errno.h>
+#include <sys/device.h>
+#include <sys/disklabel.h>
+#include <sys/dkstat.h>
+#include <sys/disk.h>
+#include <sys/ioctl.h>
+#include <sys/malloc.h>
+
+#include <dev/scsi/scsi.h>
+#include <dev/scsi/disk.h>
+#include <dev/scsi/scsivar.h>
+#include <dev/scsi/scsi_ioctl.h>
+
+#include <machine/cpu.h>
+
+#include <dev/scsi/sdtrace.h>
+
+#ifdef sparc /* XXX */
+#define SUN_LABEL_HACK /* XXX */
+#endif /* XXX */
+
+#ifdef SUN_LABEL_HACK
+#include <sparc/sunos/sun_disklabel.h>
+#endif
+
+/*
+ * Per-disk variables.
+ *
+ * sd_dk contains all the `disk' specific stuff (label/partitions,
+ * transfer rate, etc). We need only things that are special to
+ * scsi disks. Note that our blocks are in terms of DEV_BSIZE blocks.
+ */
+struct sd_softc {
+ struct dkdevice sc_dk; /* base disk device, must be first */
+ struct unit sc_unit; /* scsi unit */
+ pid_t sc_format_pid; /* process using "format" mode */
+ u_char sc_type; /* drive type */
+ u_char sc_bshift; /* convert device blocks to DEV_BSIZE blks */
+ short sc_flags; /* see below */
+ u_int sc_blks; /* number of blocks on device */
+ int sc_blksize; /* device block size in bytes */
+
+ /* should be in dkdevice?? */
+ struct buf sc_tab; /* transfer queue */
+
+ /* statistics */
+ long sc_resets; /* number of times reset */
+ long sc_transfers; /* count of total transfers */
+ long sc_partials; /* count of `partial' transfers */
+
+ /* for user formatting */
+ struct scsi_cdb sc_cmd;
+ struct scsi_fmt_sense sc_sense;
+};
+
+#define SDF_ALIVE 1 /* drive OK for regular kernel use */
+
+/* definition of the autoconfig driver */
+int sdmatch __P((struct device *, struct cfdata *, void *));
+void sdattach __P((struct device *, struct device *, void *));
+
+struct cfdriver sdcd =
+ { NULL, "sd", sdmatch, sdattach, DV_DISK, sizeof(struct sd_softc) };
+
+/* definition of the unit driver, for hba */
+void sdigo __P((struct device *, struct scsi_cdb *));
+void sdgo __P((struct device *, struct scsi_cdb *));
+void sdintr __P((struct device *, int, int));
+void sdreset __P((struct unit *));
+
+static struct unitdriver sdunitdriver = { /*sdgo, sdintr*/ sdreset };
+
+/* definition of the disk driver, for kernel */
+void sdstrategy __P((struct buf *));
+
+static struct dkdriver sddkdriver = { sdstrategy };
+
+#ifdef DEBUG
+int sddebug = 1;
+#define SDB_ERROR 0x01
+#define SDB_PARTIAL 0x02
+#endif
+
+#define sdunit(x) (minor(x) >> 3)
+#define sdpart(x) (minor(x) & 0x7)
+
+#define b_cylin b_resid
+
+#define SDRETRY 2
+
+/*
+ * Table of scsi commands users are allowed to access via `format'
+ * mode. 0 means not legal. 1 means `immediate' (doesn't need dma).
+ * -1 means needs dma and/or wait for intr (i.e., `slow').
+ */
+static char legal_cmds[256] = {
+/***** 0 1 2 3 4 5 6 7 8 9 A B C D E F */
+/*00*/ 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/*10*/ 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
+/*20*/ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/*30*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/*40*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/*50*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/*60*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/*70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/*80*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/*90*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/*a0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/*b0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/*c0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/*d0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/*e0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/*f0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+int
+sdmatch(parent, cf, aux)
+ struct device *parent;
+ register struct cfdata *cf;
+ void *aux;
+{
+ register struct scsi_attach_args *sa = aux;
+#ifdef DEBUG
+ char *whynot;
+#endif
+
+ /*
+ * unit number must match, or be given as `any'
+ */
+ if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != sa->sa_unit)
+ return (0);
+ /*
+ * drive must be a disk, and of a kind we recognize
+ */
+ if ((sa->sa_inq_status & STS_MASK) != STS_GOOD) {
+#ifdef DEBUG
+ whynot = "INQUIRY failed";
+#endif
+ goto notdisk;
+ }
+
+ switch (sa->sa_si.si_type & TYPE_TYPE_MASK) {
+
+ case TYPE_DAD: /* disk */
+ case TYPE_WORM: /* WORM */
+ case TYPE_ROM: /* CD-ROM */
+ case TYPE_MO: /* Magneto-optical */
+ case TYPE_JUKEBOX: /* medium changer */
+ break;
+
+ default:
+ notdisk:
+#ifdef DEBUG
+ whynot = "not a disk";
+ printf("[not matching `sd' at unit %d: %s]\n",
+ sa->sa_unit, whynot);
+#endif
+ return (0);
+ }
+
+ /*
+ * It is a disk of some kind; take it. We will figure out
+ * the rest in the attach routine.
+ */
+ return (1);
+}
+
+/*
+ * Attach a disk (called after sdmatch returns true).
+ * Note that this routine is never reentered (so we can use statics).
+ */
+void
+sdattach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ register struct sd_softc *sc = (struct sd_softc *)self;
+ register struct scsi_attach_args *sa = aux;
+ register int i;
+ char vendor[10], drive[17], rev[5];
+ static u_char capbuf[8];
+ static struct scsi_cdb cap = { CMD_READ_CAPACITY };
+#ifdef SUN_LABEL_HACK
+ static struct scsi_cdb rd0 = { CMD_READ10, 0, 0, 0, 0, 0, 0, 0, 1, 0 };
+ caddr_t sector;
+#endif
+
+ /*
+ * Declare our existence.
+ */
+ sc->sc_unit.u_driver = &sdunitdriver;
+ scsi_establish(&sc->sc_unit, &sc->sc_dk.dk_dev, sa->sa_unit);
+
+ /*
+ * Figure out what kind of disk this is.
+ * We only accepted it if the inquiry succeeded, so
+ * we can inspect those fields.
+ */
+ i = (sa->sa_si.si_version >> VER_ANSI_SHIFT) & VER_ANSI_MASK;
+ if (i == 1 || i == 2) {
+ scsi_inq_ansi((struct scsi_inq_ansi *)&sa->sa_si,
+ vendor, drive, rev);
+ printf(": %s %s", vendor, drive);
+ /* XXX should we even ever bother printing this? */
+ if (rev[0])
+ printf(" %s", rev);
+ } else {
+ /* bleah */
+ bcopy("<unknown>", vendor, 10);
+ bcopy("<unknown>", drive, 10);
+ printf(": type 0x%x, qual 0x%x, ver %d",
+ sa->sa_si.si_type, sa->sa_si.si_qual,
+ sa->sa_si.si_version);
+ }
+
+ CDB10(&cap)->cdb_lun_rel = sc->sc_unit.u_unit << 5;
+ i = (*sc->sc_unit.u_hbd->hd_icmd)(sc->sc_unit.u_hba,
+ sc->sc_unit.u_targ, &cap, (char *)capbuf, sizeof capbuf, B_READ);
+ i &= STS_MASK;
+ if (i == STS_GOOD) {
+#define NUMBER(p) (((p)[0] << 24) | ((p)[1] << 16) | ((p)[2] << 8) | (p)[3])
+ sc->sc_blks = NUMBER(&capbuf[0]);
+ sc->sc_blksize = NUMBER(&capbuf[4]);
+ } else if (i == STS_CHECKCOND &&
+ (strcmp(vendor, "HP") == 0 && strcmp(drive, "S6300.650A") == 0)) {
+ /* XXX unformatted or nonexistent MO medium: fake it */
+ sc->sc_blks = 318664;
+ sc->sc_blksize = 1024;
+ } else {
+ /* XXX shouldn't bail for removable media */
+ printf(": unable to determine drive capacity [sts=%x]\n", i);
+ return;
+ }
+ /* return value from read capacity is last valid block, not nblocks */
+ sc->sc_blks++;
+ printf(", %u %d byte blocks\n", sc->sc_blks, sc->sc_blksize);
+ if (sc->sc_blksize != DEV_BSIZE) {
+ for (i = sc->sc_blksize; i > DEV_BSIZE; i >>= 1)
+ ++sc->sc_bshift;
+ if (i != DEV_BSIZE) {
+ printf("%s: blksize not multiple of %d: cannot use\n",
+ sc->sc_dk.dk_dev.dv_xname, DEV_BSIZE);
+ return;
+ }
+ sc->sc_blks <<= sc->sc_bshift;
+ }
+ sc->sc_type = sa->sa_si.si_type; /* sufficient? */
+
+ sc->sc_dk.dk_driver = &sddkdriver;
+#ifdef notyet
+ dk_establish(&sc->sc_dk);
+ /* READ DISK LABEL HERE, UNLESS REMOVABLE MEDIUM... NEEDS THOUGHT */
+#else
+ sc->sc_dk.dk_label.d_secsize = 512; /* XXX */
+ sc->sc_dk.dk_bps = (3600/60) * 32 * 512;/* XXX */
+
+#ifdef SUN_LABEL_HACK
+ sector = (caddr_t)malloc(sc->sc_blksize, M_DEVBUF, M_NOWAIT);
+ CDB10(&rd0)->cdb_lun_rel = sc->sc_unit.u_unit << 5;
+ i = (*sc->sc_unit.u_hbd->hd_icmd)(sc->sc_unit.u_hba,
+ sc->sc_unit.u_targ, &rd0, sector, sc->sc_blksize, B_READ);
+ if (i == STS_GOOD) {
+ printf("%s: <%s>\n", sc->sc_dk.dk_dev.dv_xname,
+ ((struct sun_disklabel *)sector)->sl_text);
+ if (sun_disklabel(sector, &sc->sc_dk.dk_label))
+ sc->sc_flags |= SDF_ALIVE;
+ else
+ printf("%s: sun_disklabel fails\n",
+ sc->sc_dk.dk_dev.dv_xname);
+ } else
+ printf("%s: could not read sector 0 for disk label\n",
+ sc->sc_dk.dk_dev.dv_xname);
+ free(sector, M_DEVBUF);
+#endif
+#endif /* notyet */
+}
+
+/*
+ * Reset a disk, after a SCSI bus reset.
+ *
+ * XXX untested and probably incomplete/incorrect
+ */
+void
+sdreset(u)
+ register struct unit *u;
+{
+ register struct sd_softc *sc = (struct sd_softc *)u->u_dev;
+
+ printf(" %s", sc->sc_dk.dk_dev.dv_xname);
+ sc->sc_resets++;
+}
+
+/* dev_t is short, must use prototype syntax */
+int
+sdopen(dev_t dev, int flags, int ifmt, struct proc *p)
+{
+ register int unit = sdunit(dev);
+ register struct sd_softc *sc;
+
+ if (unit >= sdcd.cd_ndevs || (sc = sdcd.cd_devs[unit]) == NULL)
+ return (ENXIO);
+ if ((sc->sc_flags & SDF_ALIVE) == 0 && suser(p->p_ucred, &p->p_acflag))
+ return (ENXIO);
+ return (0);
+}
+
+int
+sdclose(dev_t dev, int flags, int ifmt, struct proc *p)
+{
+ register struct sd_softc *sc = sdcd.cd_devs[sdunit(dev)];
+
+ sc->sc_format_pid = 0;
+ return (0);
+}
+
+/*
+ * This routine is called for partial block transfers and non-aligned
+ * transfers (the latter only being possible on devices with a block size
+ * larger than DEV_BSIZE). The operation is performed in three steps
+ * using a locally allocated buffer:
+ * 1. transfer any initial partial block
+ * 2. transfer full blocks
+ * 3. transfer any final partial block
+ */
+static void
+sdlblkstrat(bp, bsize)
+ register struct buf *bp;
+ register int bsize;
+{
+ register int bn, resid, boff, count;
+ register caddr_t addr, cbuf;
+ struct buf *tbp;
+
+ /* should probably use geteblk() here, but I fear consequences */
+ cbuf = (caddr_t)malloc(bsize, M_DEVBUF, M_WAITOK);
+ tbp = (struct buf *)malloc(sizeof *tbp, M_DEVBUF, M_WAITOK);
+ bzero((caddr_t)tbp, sizeof *tbp);
+ tbp->b_proc = curproc;
+ tbp->b_dev = bp->b_dev;
+ bn = bp->b_blkno;
+ resid = bp->b_bcount;
+ addr = bp->b_un.b_addr;
+#ifdef DEBUG
+ if (sddebug & SDB_PARTIAL)
+ printf("sdlblkstrat: bp %x flags %x bn %x resid %x addr %x\n",
+ bp, bp->b_flags, bn, resid, addr);
+#endif
+
+ while (resid > 0) {
+ boff = dbtob(bn) & (bsize - 1);
+ if (boff || resid < bsize) {
+ struct sd_softc *sc = sdcd.cd_devs[sdunit(bp->b_dev)];
+ sc->sc_partials++;
+ count = min(resid, bsize - boff);
+ tbp->b_flags = B_BUSY | B_READ;
+ tbp->b_blkno = bn - btodb(boff);
+ tbp->b_un.b_addr = cbuf;
+ tbp->b_bcount = bsize;
+#ifdef DEBUG
+ if (sddebug & SDB_PARTIAL)
+ printf(" readahead: bn %x cnt %x off %x addr %x\n",
+ tbp->b_blkno, count, boff, addr);
+#endif
+ sdstrategy(tbp);
+ biowait(tbp);
+ if (tbp->b_flags & B_ERROR) {
+ bp->b_flags |= B_ERROR;
+ bp->b_error = tbp->b_error;
+ break;
+ }
+ if (bp->b_flags & B_READ) {
+ bcopy(&cbuf[boff], addr, count);
+ goto done;
+ }
+ bcopy(addr, &cbuf[boff], count);
+#ifdef DEBUG
+ if (sddebug & SDB_PARTIAL)
+ printf(" writeback: bn %x cnt %x off %x addr %x\n",
+ tbp->b_blkno, count, boff, addr);
+#endif
+ } else {
+ count = resid & ~(bsize - 1);
+ tbp->b_blkno = bn;
+ tbp->b_un.b_addr = addr;
+ tbp->b_bcount = count;
+#ifdef DEBUG
+ if (sddebug & SDB_PARTIAL)
+ printf(" fulltrans: bn %x cnt %x addr %x\n",
+ tbp->b_blkno, count, addr);
+#endif
+ }
+ tbp->b_flags = B_BUSY | (bp->b_flags & B_READ);
+ sdstrategy(tbp);
+ biowait(tbp);
+ if (tbp->b_flags & B_ERROR) {
+ bp->b_flags |= B_ERROR;
+ bp->b_error = tbp->b_error;
+ break;
+ }
+done:
+ bn += btodb(count);
+ resid -= count;
+ addr += count;
+#ifdef DEBUG
+ if (sddebug & SDB_PARTIAL)
+ printf(" done: bn %x resid %x addr %x\n",
+ bn, resid, addr);
+#endif
+ }
+ free(cbuf, M_DEVBUF);
+ free((caddr_t)tbp, M_DEVBUF);
+ biodone(bp);
+}
+
+/*
+ * Start a transfer on sc as described by bp
+ * (i.e., call hba or target start).
+ * If in format mode, we may not need dma.
+ */
+#define sdstart(sc, bp) { \
+ SD_TRACE(T_START, sc, bp); \
+ if ((sc)->sc_format_pid && legal_cmds[(sc)->sc_cmd.cdb_bytes[0]] > 0) \
+ (*(sc)->sc_unit.u_start)((sc)->sc_unit.u_updev, \
+ &(sc)->sc_unit.u_forw, (struct buf *)NULL, \
+ sdigo, &(sc)->sc_dk.dk_dev); \
+ else \
+ (*(sc)->sc_unit.u_start)((sc)->sc_unit.u_updev, \
+ &(sc)->sc_unit.u_forw, bp, sdgo, &(sc)->sc_dk.dk_dev); \
+}
+
+void
+sdstrategy(bp)
+ register struct buf *bp;
+{
+ register struct sd_softc *sc = sdcd.cd_devs[sdunit(bp->b_dev)];
+ register int s;
+
+ if (sc->sc_format_pid) {
+ /* XXXXXXXXX SHOULD NOT COMPARE curproc IN HERE!?! */
+ /*
+ * In format mode, only allow the owner to mess
+ * with the drive. Skip all the partition checks.
+ */
+ if (sc->sc_format_pid != curproc->p_pid) {
+ bp->b_error = EPERM;
+ bp->b_flags |= B_ERROR;
+ biodone(bp);
+ return;
+ }
+ bp->b_cylin = 0;
+ } else {
+ register daddr_t bn = bp->b_blkno;
+ register int sz = howmany(bp->b_bcount, DEV_BSIZE);
+ register struct partition *p;
+
+ /*
+ * Make sure transfer is within partition.
+ * If it starts at the end, return EOF; if
+ * it extends past the end, truncate it.
+ */
+ p = &sc->sc_dk.dk_label.d_partitions[sdpart(bp->b_dev)];
+ if ((unsigned)bn >= p->p_size) {
+ if ((unsigned)bn > p->p_size) {
+ bp->b_error = EINVAL;
+ bp->b_flags |= B_ERROR;
+ } else
+ bp->b_resid = bp->b_bcount;
+ biodone(bp);
+ return;
+ }
+ if (bn + sz > p->p_size) {
+ sz = p->p_size - bn;
+ bp->b_bcount = dbtob(sz);
+ }
+ /*
+ * Non-aligned or partial-block transfers handled specially.
+ * SHOULD THIS BE AT A HIGHER LEVEL?
+ */
+ s = sc->sc_blksize - 1;
+ if ((dbtob(bn) & s) || (bp->b_bcount & s)) {
+ sdlblkstrat(bp, sc->sc_blksize);
+ return;
+ }
+ bp->b_cylin = (bn + p->p_offset) >> sc->sc_bshift;
+ }
+
+ /*
+ * Transfer valid, or format mode. Queue the request
+ * on the drive, and maybe try to start it.
+ */
+ s = splbio();
+ disksort(&sc->sc_tab, bp);
+ if (sc->sc_tab.b_active == 0) {
+ sc->sc_tab.b_active = 1;
+ sdstart(sc, bp);
+ }
+ splx(s);
+}
+
+int
+sderror(sc, stat)
+ register struct sd_softc *sc;
+ register int stat;
+{
+ register struct scsi_sense *sn;
+ int retry = 0;
+
+ sc->sc_sense.status = stat;
+ if ((stat & STS_MASK) == STS_CHECKCOND) {
+ sn = (struct scsi_sense *)sc->sc_sense.sense;
+ stat = scsi_request_sense(sc->sc_unit.u_hba,
+ sc->sc_unit.u_targ, sc->sc_unit.u_unit,
+ (caddr_t)sn, sizeof sc->sc_sense.sense);
+ sc->sc_sense.status = stat; /* ??? */
+ if ((stat & STS_MASK) != STS_GOOD) {
+ printf("%s: sense failed, status %x\n",
+ sc->sc_dk.dk_dev.dv_xname, stat);
+ return (0);
+ }
+ printf("%s: scsi sense class %d, code %d",
+ sc->sc_dk.dk_dev.dv_xname,
+ SENSE_ECLASS(sn), SENSE_ECODE(sn));
+ if (SENSE_ISXSENSE(sn) && XSENSE_ISSTD(sn)) {
+ int key;
+
+ /*
+ * Standard extended sense: can examine sense key
+ * and (if valid) info.
+ */
+ key = XSENSE_KEY(sn);
+ printf(", key %d", key);
+ if (XSENSE_IVALID(sn))
+ printf(", blk %d", XSENSE_INFO(sn));
+ /* no sense or recovered error, try again */
+ if (key == 0 || key == 1)
+ retry = 1;
+ }
+ printf("\n");
+ }
+ return (retry);
+}
+
+/*
+ * sdigo is called from the hba driver when it has got the scsi bus
+ * for us, and we were doing a format op that did not need dma.
+ */
+void
+sdigo(sc0, cdb)
+ struct device *sc0;
+ struct scsi_cdb *cdb;
+{
+ register struct sd_softc *sc = (struct sd_softc *)sc0;
+ register struct buf *bp = sc->sc_tab.b_actf;
+ register int stat;
+
+ stat = (*sc->sc_unit.u_hbd->hd_icmd)(sc->sc_unit.u_hba,
+ sc->sc_unit.u_targ, &sc->sc_cmd, bp->b_un.b_addr, bp->b_bcount,
+ bp->b_flags & B_READ);
+ sc->sc_sense.status = stat;
+ if (stat & 0xfe) { /* XXX */
+ (void) sderror(sc, stat);
+ bp->b_flags |= B_ERROR;
+ bp->b_error = EIO;
+ }
+ /*
+ * Done with SCSI bus, before we `ought' to be. Release it.
+ */
+ (*sc->sc_unit.u_rel)(sc->sc_unit.u_updev);
+ bp->b_resid = 0;
+ sc->sc_tab.b_errcnt = 0;
+ sc->sc_tab.b_actf = bp->b_actf;
+ biodone(bp);
+ if ((bp = sc->sc_tab.b_actf) == NULL)
+ sc->sc_tab.b_active = 0;
+ else
+ sdstart(sc, bp);
+}
+
+/*
+ * sdgo is called from the hba driver or target code when it has
+ * allocated the scsi bus and DMA resources and target datapath for us.
+ */
+void
+sdgo(sc0, cdb)
+ struct device *sc0;
+ register struct scsi_cdb *cdb;
+{
+ register struct sd_softc *sc = (struct sd_softc *)sc0;
+ register struct buf *bp = sc->sc_tab.b_actf;
+ register int n;
+ register unsigned int u;
+
+ SD_TRACE(T_MKCDB, sc, bp);
+ if (sc->sc_format_pid) {
+ *cdb = sc->sc_cmd;
+ n = 0;
+ } else {
+ CDB10(cdb)->cdb_cmd = bp->b_flags & B_READ ? CMD_READ10 :
+ CMD_WRITE10;
+ CDB10(cdb)->cdb_lun_rel = sc->sc_unit.u_unit << 5;
+ u = bp->b_cylin;
+ CDB10(cdb)->cdb_lbah = u >> 24;
+ CDB10(cdb)->cdb_lbahm = u >> 16;
+ CDB10(cdb)->cdb_lbalm = u >> 8;
+ CDB10(cdb)->cdb_lbal = u;
+ CDB10(cdb)->cdb_xxx = 0;
+ n = sc->sc_blksize - 1;
+ u = (bp->b_bcount + n) >> (DEV_BSHIFT + sc->sc_bshift);
+ CDB10(cdb)->cdb_lenh = u >> 8;
+ CDB10(cdb)->cdb_lenl = u;
+ CDB10(cdb)->cdb_ctrl = 0;
+ n = (bp->b_bcount & n) != 0;
+#ifdef DEBUG
+ if (n)
+ printf("%s: partial block xfer -- %x bytes\n",
+ sc->sc_dk.dk_dev.dv_xname, bp->b_bcount);
+#endif
+ sc->sc_transfers++;
+ }
+ if ((*sc->sc_unit.u_go)(sc->sc_unit.u_updev, sc->sc_unit.u_targ,
+ sdintr, (void *)sc, bp, n) == 0) {
+#ifdef notyet
+ sc->sc_dk.dk_busy = 1;
+ sc->sc_dk.dk_seek++; /* XXX */
+ sc->sc_dk.dk_xfer++;
+ sc->sc_dk.dk_wds += bp->b_bcount >> 6;
+#endif
+ return;
+ }
+ /*
+ * Some sort of nasty unrecoverable error: clobber the
+ * transfer. Call the bus release function first, though.
+ */
+ (*sc->sc_unit.u_rel)(sc->sc_unit.u_updev);
+#ifdef DEBUG
+ if (sddebug & SDB_ERROR)
+ printf("%s: sdgo: %s adr %d blk %d len %d ecnt %d\n",
+ sc->sc_dk.dk_dev.dv_xname,
+ bp->b_flags & B_READ? "read" : "write",
+ bp->b_un.b_addr, bp->b_cylin, bp->b_bcount,
+ sc->sc_tab.b_errcnt);
+#endif
+ bp->b_flags |= B_ERROR;
+ bp->b_error = EIO;
+ bp->b_resid = 0;
+ sc->sc_tab.b_errcnt = 0;
+ sc->sc_tab.b_actf = bp->b_actf;
+ biodone(bp);
+ if ((bp = sc->sc_tab.b_actf) == NULL)
+ sc->sc_tab.b_active = 0;
+ else
+ sdstart(sc, bp);
+}
+
+/*
+ * A transfer finished (or, someday, disconnected).
+ * We are already off the target/hba queues.
+ * Restart this one for error recovery, or start the next, as appropriate.
+ */
+void
+sdintr(sc0, stat, resid)
+ struct device *sc0;
+ int stat, resid;
+{
+ register struct sd_softc *sc = (struct sd_softc *)sc0;
+ register struct buf *bp = sc->sc_tab.b_actf;
+ int retry;
+
+ if (bp == NULL)
+ panic("sdintr");
+ SD_TRACE(T_INTR, sc, bp);
+#ifdef notyet
+ sc->sc_dk.dk_busy = 0;
+#endif
+ if ((stat & STS_MASK) != STS_GOOD) {
+#ifdef DEBUG
+ if (sddebug & SDB_ERROR)
+ printf("%s: sdintr scsi status 0x%x resid %d\n",
+ sc->sc_dk.dk_dev.dv_xname, stat, resid);
+#endif
+ retry = sderror(sc, stat);
+ if (retry && ++sc->sc_tab.b_errcnt <= SDRETRY) {
+ printf("%s: retry %d\n",
+ sc->sc_dk.dk_dev.dv_xname, sc->sc_tab.b_errcnt);
+ goto restart;
+ }
+ bp->b_flags |= B_ERROR;
+ bp->b_error = EIO;
+ }
+ bp->b_resid = resid;
+ sc->sc_tab.b_errcnt = 0;
+ sc->sc_tab.b_actf = bp->b_actf;
+ biodone(bp);
+ if ((bp = sc->sc_tab.b_actf) == NULL)
+ sc->sc_tab.b_active = 0;
+ else {
+restart:
+ sdstart(sc, bp);
+ }
+}
+
+int
+sdioctl(dev_t dev, int cmd, register caddr_t data, int flag, struct proc *p)
+{
+ register struct sd_softc *sc = sdcd.cd_devs[sdunit(dev)];
+#ifdef COMPAT_SUNOS
+ int error;
+
+ error = sun_dkioctl(&sc->sc_dk, cmd, data, sdpart(dev));
+ if (error >= 0)
+ return (error);
+#endif
+ switch (cmd) {
+
+ case SDIOCSFORMAT:
+ /* take this device into or out of "format" mode */
+ if (suser(p->p_ucred, &p->p_acflag))
+ return (EPERM);
+ if (*(int *)data) {
+ if (sc->sc_format_pid)
+ return (EPERM);
+ sc->sc_format_pid = p->p_pid;
+ } else
+ sc->sc_format_pid = 0;
+ break;
+
+ case SDIOCGFORMAT:
+ /* find out who has the device in format mode */
+ *(int *)data = sc->sc_format_pid;
+ break;
+
+ case SDIOCSCSICOMMAND:
+#define cdb ((struct scsi_cdb *)data)
+ /*
+ * Save what user gave us as SCSI cdb to use with next
+ * read or write to the char device. Be sure to replace
+ * the lun field with the actual unit number.
+ */
+ if (sc->sc_format_pid != p->p_pid)
+ return (EPERM);
+ if (legal_cmds[cdb->cdb_bytes[0]] == 0)
+ return (EINVAL);
+ sc->sc_cmd = *cdb;
+ sc->sc_cmd.cdb_bytes[1] =
+ (sc->sc_cmd.cdb_bytes[1] & ~(7 << 5)) |
+ (sc->sc_unit.u_unit << 5);
+#undef cdb
+ break;
+
+ case SDIOCSENSE:
+ /*
+ * return the SCSI sense data saved after the last
+ * operation that completed with "check condition" status.
+ */
+ sc->sc_sense = *(struct scsi_fmt_sense *)data;
+ break;
+
+ case DIOCGDINFO:
+ *(struct disklabel *)data = sc->sc_dk.dk_label;
+ break;
+
+ case DIOCGPART:
+ ((struct partinfo *)data)->disklab = &sc->sc_dk.dk_label;
+ ((struct partinfo *)data)->part =
+ &sc->sc_dk.dk_label.d_partitions[sdpart(dev)];
+ break;
+
+ default:
+ return (ENOTTY);
+ }
+ return (0);
+}
+
+int
+sdsize(dev_t dev)
+{
+ register int unit = sdunit(dev);
+ register struct sd_softc *sc;
+
+ if (unit >= sdcd.cd_ndevs || (sc = sdcd.cd_devs[unit]) == NULL ||
+ (sc->sc_flags & SDF_ALIVE) == 0)
+ return (-1);
+ return (sc->sc_dk.dk_label.d_partitions[sdpart(dev)].p_size);
+}
+
+/*
+ * Write `len' bytes from address `addr' to drive and partition in `dev',
+ * at block blkoff from the beginning of the partition. The address is
+ * either kernel virtual or physical (some machines may never use one or
+ * the other, but we need it in the protocol to stay machine-independent).
+ */
+int
+sddump(dev_t dev, daddr_t blkoff, caddr_t addr, int len)
+{
+ register struct sd_softc *sc;
+ register struct partition *p;
+ register daddr_t bn, n, nblks;
+ register struct hba_softc *hba;
+ register int stat, unit;
+ struct scsi_cdb cdb;
+
+ /* drive ok? */
+ unit = sdunit(dev);
+ if (unit >= sdcd.cd_ndevs || (sc = sdcd.cd_devs[unit]) == NULL ||
+ (sc->sc_flags & SDF_ALIVE) == 0)
+ return (ENXIO);
+
+ /* blocks in range? */
+ p = &sc->sc_dk.dk_label.d_partitions[sdpart(dev)];
+ n = (len + sc->sc_blksize - 1) >> DEV_BSHIFT;
+ if (blkoff < 0 || blkoff >= p->p_size || blkoff + n > p->p_size)
+ return (EINVAL);
+ bn = blkoff + p->p_offset;
+ bn >>= sc->sc_bshift;
+
+ /* scsi bus idle? */
+ hba = sc->sc_unit.u_hba;
+ if (hba->hba_head) {
+ (*hba->hba_driver->hd_reset)(hba, 0);
+ printf("[reset %s] ", sc->sc_dk.dk_dev.dv_xname);
+ }
+
+ CDB10(&cdb)->cdb_cmd = CMD_WRITE10;
+ CDB10(&cdb)->cdb_lun_rel = sc->sc_unit.u_unit << 5;
+ CDB10(&cdb)->cdb_xxx = 0;
+ CDB10(&cdb)->cdb_ctrl = 0;
+
+#define DUMP_MAX (32 * 1024) /* no more than 32k per write */
+ for (;;) {
+ if ((n = len) > DUMP_MAX)
+ n = DUMP_MAX;
+ CDB10(&cdb)->cdb_lbah = bn >> 24;
+ CDB10(&cdb)->cdb_lbahm = bn >> 16;
+ CDB10(&cdb)->cdb_lbalm = bn >> 8;
+ CDB10(&cdb)->cdb_lbal = bn;
+ nblks = n >> (DEV_BSHIFT + sc->sc_bshift);
+ CDB10(&cdb)->cdb_lenh = nblks >> 8;
+ CDB10(&cdb)->cdb_lenl = nblks;
+ stat = hba->hba_driver->hd_dump(hba, sc->sc_unit.u_targ,
+ &cdb, addr, n);
+ if ((stat & STS_MASK) != STS_GOOD) {
+ printf("%s: scsi write error 0x%x\ndump ",
+ sc->sc_dk.dk_dev.dv_xname, stat);
+ return (EIO);
+ }
+ if ((len -= n) == 0)
+ return (0);
+ addr += n;
+ bn += nblks;
+ }
+}
diff --git a/sys/dev/scsi/sdtrace.h b/sys/dev/scsi/sdtrace.h
new file mode 100644
index 00000000000..5b2e5c38b36
--- /dev/null
+++ b/sys/dev/scsi/sdtrace.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * 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, Lawrence Berkeley Laboratories.
+ *
+ * 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.
+ *
+ * @(#)sdtrace.h 8.1 (Berkeley) 6/10/93
+ *
+ * from: $Header: /cvsroot/src/sys/dev/scsi/Attic/sdtrace.h,v 1.1.1.1 1998/03/01 02:09:34 fvdl Exp $ (LBL)
+ */
+
+/*
+ * SCSI disk command tracing
+ */
+
+#if defined(SDTRACE) || !defined(KERNEL)
+struct sdtrace {
+ struct timeval time; /* timestamp */
+ u_int block; /* disk block */
+ u_int bcount; /* # bytes transferred */
+ u_char tcode; /* trace code */
+ u_char target; /* target number */
+ u_char unit; /* unit number on target */
+ u_char read; /* read operation */
+};
+
+#define T_START 0x01
+#define T_MKCDB 0x02
+#define T_INTR 0x03
+#endif
+
+#ifdef SDTRACE
+/* Allow kernel config to override number of entries */
+#ifndef NSDOPBUF
+#define NSDOPBUF 1024
+#endif
+
+struct sdtrace sdopbuf[NSDOPBUF];
+struct sdtrace *sdopptr = sdopbuf;
+int nsdopbuf = NSDOPBUF; /* for sdtrace */
+u_long sdopcnt;
+
+#define SD_TRACE(code, sc, bp) { \
+ if (++sdopptr >= &sdopbuf[NSDOPBUF]) \
+ sdopptr = sdopbuf; \
+ microtime(&sdopptr->time); \
+ sdopptr->tcode = code; \
+ sdopptr->read = bp->b_flags & B_READ; \
+ sdopptr->block = bp->b_blkno; \
+ sdopptr->bcount = bp->b_bcount; \
+ sdopptr->target = sc->sc_unit.u_targ; \
+ sdopptr->unit = sc->sc_unit.u_unit; \
+ ++sdopcnt; \
+}
+#else
+#define SD_TRACE(code, sc, bp) { }
+#endif
diff --git a/sys/dev/scsi/tape.h b/sys/dev/scsi/tape.h
new file mode 100644
index 00000000000..32d3d382725
--- /dev/null
+++ b/sys/dev/scsi/tape.h
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * 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, Lawrence Berkeley Laboratories.
+ *
+ * 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.
+ *
+ * @(#)tape.h 8.1 (Berkeley) 6/10/93
+ *
+ * from: $Header: /cvsroot/src/sys/dev/scsi/Attic/tape.h,v 1.1.1.1 1998/03/01 02:09:34 fvdl Exp $ (LBL)
+ */
+
+/*
+ * SCSI definitions for Sequential Access Devices (tapes).
+ *
+ * Commands defined in common headers (scsi.h or disktape.h) are omitted.
+ */
+#define CMD_REWIND 0x01 /* rewind */
+#define CMD_READ_BLOCK_LIMITS 0x05 /* read block limits */
+#define CMD_READ 0x08 /* read */
+#define CMD_WRITE 0x0a /* write */
+#define CMD_TRACK_SELECT 0x0b /* track select */
+#define CMD_READ_REVERSE 0x0f /* read reverse */
+#define CMD_WRITE_FILEMARK 0x10 /* write file marks */
+#define CMD_SPACE 0x11 /* space */
+#define CMD_VERIFY 0x13 /* verify */
+#define CMD_RBD 0x14 /* recover buffered data */
+#define CMD_RESERVE_UNIT 0x16 /* reserve unit */
+#define CMD_RELEASE_UNIT 0x17 /* release unit */
+/* CMD_COPY 0x18 copy (common to all scsi devs) */
+#define CMD_ERASE 0x19 /* erase */
+#define CMD_LOAD_UNLOAD 0x1b /* load/unload */
+#define CMD_PAMR 0x1e /* prevent/allow medium removal */
+
+/*
+ * Structure of READ, WRITE, READ REVERSE, RECOVER BUFFERED DATA
+ * commands (i.e., the cdb).
+ * Also used for VERIFY commands.
+ */
+struct scsi_cdb_rw {
+ u_char cdb_cmd, /* 0x08 or 0x0a or 0x0f or 0x13 or 0x14 */
+ cdb_lun_bf, /* LUN + reserved + bytecmp + fixed */
+ cdb_lenh, /* transfer length (MSB) */
+ cdb_lenm, /* transfer length */
+ cdb_lenl, /* transfer length (LSB) */
+ cdb_ctrl; /* control byte */
+};
+#define SCSI_RW_BYTECMP 0x02 /* byte compare flag if verify */
+#define SCSI_RW_FIXEDBLK 0x01 /* fixed block size for read/write */
+
+/*
+ * Structure of a TRACK SELECT command.
+ */
+struct scsi_cdb_ts {
+ u_char cdb_cmd, /* 0x0b */
+ cdb_lun_xxx, /* logical unit number + reserved */
+ cdb_xxx1, /* reserved */
+ cdb_xxx2, /* reserved */
+ cdb_track, /* track value */
+ cdb_ctrl; /* control byte */
+};
+
+/*
+ * Structure of a WRITE FILEMARKS command.
+ */
+struct scsi_cdb_wfm {
+ u_char cdb_cmd, /* 0x0b */
+ cdb_lun_xxx, /* logical unit number + reserved */
+ cdb_nfh, /* number of filemarks (MSB) */
+ cdb_nfm, /* number of filemarks */
+ cdb_nfl, /* number of filemarks (LSB) */
+ cdb_ctrl; /* control byte */
+};
+
+/*
+ * Structure of a SPACE command.
+ */
+struct scsi_cdb_space {
+ u_char cdb_cmd, /* 0x0b */
+ cdb_lun_code, /* LUN + reserved + 2-bit code */
+ cdb_counth, /* count (MSB) */
+ cdb_countm, /* count */
+ cdb_countl, /* count (LSB) */
+ cdb_ctrl; /* control byte */
+};
+#define SCSI_CMD_SPACE_BLOCKS 0 /* skip blocks */
+#define SCSI_CMD_SPACE_FMS 1 /* skip file marks */
+#define SCSI_CMD_SPACE_SFMS 2 /* skip sequential file marks */
+#define SCSI_CMD_SPACE_PEOD 3 /* skip to physical end of data */
+
+/*
+ * Structure of an ERASE command.
+ */
+struct scsi_cdb_erase {
+ u_char cdb_cmd, /* 0x0b */
+ cdb_lun_long, /* LUN + reserved + long-erase flag */
+ cdb_xxx1, /* reserved */
+ cdb_xxx2, /* reserved */
+ cdb_xxx3, /* reserved */
+ cdb_ctrl; /* control byte */
+};
+
+/*
+ * Structure of a LOAD/UNLOAD command.
+ */
+struct scsi_cdb_lu {
+ u_char cdb_cmd, /* 0x1b */
+ cdb_lun_immed, /* LUN + reserved + immediate flag */
+ cdb_xxx1, /* reserved */
+ cdb_xxx2, /* reserved */
+ cdb_rl, /* reserved + retension flag + load flag */
+ cdb_ctrl; /* control byte */
+};
+#define SCSI_LU_RL_RETEN 0x02 /* retension */
+#define SCSI_LU_RL_LOAD 0x01 /* load */
+#define SCSI_LU_RL_UNLOAD 0x00 /* unload (pseudo flag) */