diff options
| author | fvdl <fvdl@NetBSD.org> | 1998-03-01 02:09:33 +0000 |
|---|---|---|
| committer | fvdl <fvdl@NetBSD.org> | 1998-03-01 02:09:33 +0000 |
| commit | b50e39fa455971dc1d2f274e343df8ab6c68424c (patch) | |
| tree | 83f33c5c2babf5e87f4ed52b999950a2fdd2b4e2 /sys/dev | |
| parent | 77eeaedfe830425b4c413fa839f958f29280d64c (diff) | |
Import 4.4BSD-Lite for reference
Diffstat (limited to 'sys/dev')
| -rw-r--r-- | sys/dev/cd.c | 709 | ||||
| -rw-r--r-- | sys/dev/cdvar.h | 104 | ||||
| -rw-r--r-- | sys/dev/scsi/disk.h | 384 | ||||
| -rw-r--r-- | sys/dev/scsi/disktape.h | 260 | ||||
| -rw-r--r-- | sys/dev/scsi/printer.h | 59 | ||||
| -rw-r--r-- | sys/dev/scsi/processor.h | 63 | ||||
| -rw-r--r-- | sys/dev/scsi/scsi.h | 361 | ||||
| -rw-r--r-- | sys/dev/scsi/scsi_ioctl.h | 71 | ||||
| -rw-r--r-- | sys/dev/scsi/scsi_subr.c | 532 | ||||
| -rw-r--r-- | sys/dev/scsi/scsivar.h | 216 | ||||
| -rw-r--r-- | sys/dev/scsi/sd.c | 909 | ||||
| -rw-r--r-- | sys/dev/scsi/sdtrace.h | 92 | ||||
| -rw-r--r-- | sys/dev/scsi/tape.h | 150 |
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) */ |
