diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2004-08-03 21:46:59 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2004-08-03 21:46:59 +0000 |
commit | e710973823a9bbc5e904b1e829a0707e61ff21c5 (patch) | |
tree | b089733d9e628b19e64a9e7909e96308a3f8877f /sys | |
parent | 64d5018aaa427d0e10165c038e59678b058e4f55 (diff) |
Replace the old 4.4BSD scsi code used on hp300 with a ``real'' driver
interfaced with the MI scsi code.
Adapted from NetBSD with some changes (especially to get tape and old
cd-rom drives to not cause the driver to spin during probe).
Tested by millert@ and I, ok millert@
Diffstat (limited to 'sys')
-rw-r--r-- | sys/arch/hp300/conf/GENERIC | 14 | ||||
-rw-r--r-- | sys/arch/hp300/conf/RAMDISK | 11 | ||||
-rw-r--r-- | sys/arch/hp300/conf/files.hp300 | 33 | ||||
-rw-r--r-- | sys/arch/hp300/dev/ac.c | 507 | ||||
-rw-r--r-- | sys/arch/hp300/dev/acioctl.h | 85 | ||||
-rw-r--r-- | sys/arch/hp300/dev/acvar.h | 96 | ||||
-rw-r--r-- | sys/arch/hp300/dev/hp98265reg.h (renamed from sys/arch/hp300/dev/sdvar.h) | 87 | ||||
-rw-r--r-- | sys/arch/hp300/dev/mb89352.c | 2025 | ||||
-rw-r--r-- | sys/arch/hp300/dev/mb89352reg.h | 238 | ||||
-rw-r--r-- | sys/arch/hp300/dev/mb89352var.h | 217 | ||||
-rw-r--r-- | sys/arch/hp300/dev/scsi.c | 1541 | ||||
-rw-r--r-- | sys/arch/hp300/dev/scsireg.h | 477 | ||||
-rw-r--r-- | sys/arch/hp300/dev/scsivar.h | 91 | ||||
-rw-r--r-- | sys/arch/hp300/dev/sd.c | 1271 | ||||
-rw-r--r-- | sys/arch/hp300/dev/spc.c | 276 | ||||
-rw-r--r-- | sys/arch/hp300/dev/st.c | 1413 | ||||
-rw-r--r-- | sys/arch/hp300/dev/stvar.h | 220 | ||||
-rw-r--r-- | sys/arch/hp300/hp300/autoconf.c | 131 | ||||
-rw-r--r-- | sys/arch/hp300/hp300/conf.c | 25 |
19 files changed, 2881 insertions, 5877 deletions
diff --git a/sys/arch/hp300/conf/GENERIC b/sys/arch/hp300/conf/GENERIC index c68b4a85fa6..9ea6c96e91c 100644 --- a/sys/arch/hp300/conf/GENERIC +++ b/sys/arch/hp300/conf/GENERIC @@ -1,4 +1,4 @@ -# $OpenBSD: GENERIC,v 1.30 2001/12/06 01:03:42 miod Exp $ +# $OpenBSD: GENERIC,v 1.31 2004/08/03 21:46:54 miod Exp $ # $NetBSD: GENERIC,v 1.23 1997/01/31 06:12:57 thorpej Exp $ # # Generic kernel - one size fits all. @@ -110,8 +110,12 @@ ct* at hpibbus? slave ? punit ? # HP-IB cartridge tapes mt* at hpibbus? slave ? punit ? # HP-IB 9-track tape ppi0 at hpibbus0 slave 5 punit 0 # HP-IB plotter -oscsi* at dio? scode ? # Old HP SCSI +spc* at dio? scode ? # SCSI controller +scsibus* at spc? -sd* at oscsi? target ? lun ? # SCSI disks -st* at oscsi? target ? lun ? # SCSI tapes -ac* at oscsi? target ? lun ? # SCSI changers +sd* at scsibus? target ? lun ? # SCSI disks +st* at scsibus? target ? lun ? # SCSI tapes +cd* at scsibus? target ? lun ? # SCSI CD-ROMs +ch* at scsibus? target ? lun ? # SCSI changer devices +ss* at scsibus? target ? lun ? # SCSI scanners +uk* at scsibus? target ? lun ? # unknown SCSI devices diff --git a/sys/arch/hp300/conf/RAMDISK b/sys/arch/hp300/conf/RAMDISK index f295f330e13..f98fb63c77f 100644 --- a/sys/arch/hp300/conf/RAMDISK +++ b/sys/arch/hp300/conf/RAMDISK @@ -1,4 +1,4 @@ -# $OpenBSD: RAMDISK,v 1.15 2001/11/25 23:23:45 miod Exp $ +# $OpenBSD: RAMDISK,v 1.16 2004/08/03 21:46:54 miod Exp $ # # Ram disk kernel. # @@ -117,11 +117,12 @@ hd* at hpibbus? slave ? punit ? # HP-IB disks ct* at hpibbus? slave ? punit ? # HP-IB cartridge tapes mt* at hpibbus? slave ? punit ? # HP-IB 9-track tape -oscsi* at dio? scode ? # Old HP SCSI +spc* at dio? scode ? # SCSI controller +scsibus* at spc? -sd* at oscsi? target ? lun ? # SCSI disks -st* at oscsi? target ? lun ? # SCSI tapes -ac* at oscsi? target ? lun ? # SCSI changers +sd* at scsibus? target ? lun ? # SCSI disks +st* at scsibus? target ? lun ? # SCSI tapes +cd* at scsibus? target ? lun ? # SCSI CD-ROMs pseudo-device loop 1 # network loopback pseudo-device pty 16 # pseudo-terminals diff --git a/sys/arch/hp300/conf/files.hp300 b/sys/arch/hp300/conf/files.hp300 index fa24df6bebe..025e4098110 100644 --- a/sys/arch/hp300/conf/files.hp300 +++ b/sys/arch/hp300/conf/files.hp300 @@ -1,4 +1,4 @@ -# $OpenBSD: files.hp300,v 1.21 2004/07/10 03:40:32 deraadt Exp $ +# $OpenBSD: files.hp300,v 1.22 2004/08/03 21:46:54 miod Exp $ # $NetBSD: files.hp300,v 1.28 1997/05/12 08:23:28 thorpej Exp $ # # hp300-specific configuration info @@ -8,9 +8,6 @@ maxpartitions 16 maxusers 2 8 64 -# NOTE! The order of these lines is significant! Don't change them -# unless you absolutely know what you're doing! - # # Mainbus # @@ -130,12 +127,10 @@ file arch/hp300/dev/hpib.c hpibbus device ct: tape attach ct at hpibbus file arch/hp300/dev/ct.c ct needs-flag -major {ct = 0} device mt: tape attach mt at hpibbus file arch/hp300/dev/mt.c mt needs-flag -major {mt = 1} device hd: disk attach hd at hpibbus @@ -149,24 +144,16 @@ file arch/hp300/dev/ppi.c ppi needs-flag # RAM disk major {rd = 8} -# Old HP SCSI layer -device oscsi { target = -1, lun = -1 } -attach oscsi at dio -file arch/hp300/dev/scsi.c oscsi - -# Old HP SCSI devices -device sd: disk -attach sd at oscsi -file arch/hp300/dev/sd.c sd needs-flag -major {sd = 4} +# SCSI devices +include "scsi/files.scsi" -device st: tape -attach st at oscsi -file arch/hp300/dev/st.c st needs-flag +device spc: scsi +attach spc at dio +file arch/hp300/dev/spc.c spc needs-flag +file arch/hp300/dev/mb89352.c spc -device ac -attach ac at oscsi -file arch/hp300/dev/ac.c ac needs-flag +major {sd = 4} +major {cd = 9} # Human (Hilarious) Interface Loop # XXX should be a real device @@ -198,8 +185,6 @@ file arch/hp300/dev/dma.c file dev/cons.c file dev/cninit.c -major {vnd = 6} - # # HP-UX binary compatibility # diff --git a/sys/arch/hp300/dev/ac.c b/sys/arch/hp300/dev/ac.c deleted file mode 100644 index 79afe6b15cf..00000000000 --- a/sys/arch/hp300/dev/ac.c +++ /dev/null @@ -1,507 +0,0 @@ -/* $OpenBSD: ac.c,v 1.13 2003/06/02 23:27:44 millert Exp $ */ -/* $NetBSD: ac.c,v 1.9 1997/04/02 22:37:21 scottr Exp $ */ - -/* - * Copyright (c) 1996, 1997 Jason R. Thorpe. All rights reserved. - * Copyright (c) 1991 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. 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: ac.c 1.5 92/01/21$ - * - * @(#)ac.c 8.2 (Berkeley) 1/12/94 - */ - -/* - * SCSI driver for MO autochanger. - * - * Very crude. Because of the lack of connect/disconnect support in the - * scsi driver, this driver can tie up the SCSI bus for a long time. It - * also grabs a DMA channel and holds it for the duration even though it - * never uses it. - */ - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/buf.h> -#include <sys/device.h> -#include <sys/errno.h> -#include <sys/ioctl.h> -#include <sys/kernel.h> -#include <sys/malloc.h> - -#include <sys/conf.h> - -#include <hp300/dev/scsireg.h> -#include <hp300/dev/scsivar.h> -#include <hp300/dev/acioctl.h> -#include <hp300/dev/acvar.h> - -bdev_decl(ac); -cdev_decl(ac); - -static int acmatch(struct device *, void *, void *); -static void acattach(struct device *, struct device *, void *); - -struct cfattach ac_ca = { - sizeof(struct ac_softc), acmatch, acattach -}; - -struct cfdriver ac_cd = { - NULL, "ac", DV_DULL -}; - -void acstart(void *); -void acgo(void *); -void acintr(void *, int); - -#ifdef DEBUG -int ac_debug = 0x0000; -#define ACD_FOLLOW 0x0001 -#define ACD_OPEN 0x0002 -#endif - -static int -acmatch(parent, match, aux) - struct device *parent; - void *match, *aux; -{ - struct oscsi_attach_args *osa = aux; - - if (osa->osa_inqbuf->type != 8 || osa->osa_inqbuf->qual != 0x80 || - osa->osa_inqbuf->version != 2) - return (0); - - return (1); -} - -static void -acattach(parent, self, aux) - struct device *parent, *self; - void *aux; -{ - struct ac_softc *sc = (struct ac_softc *)self; - struct oscsi_attach_args *osa = aux; - - printf("\n"); - - sc->sc_target = osa->osa_target; - sc->sc_lun = osa->osa_lun; - - /* Initialize SCSI queue entry. */ - sc->sc_sq.sq_softc = sc; - sc->sc_sq.sq_target = sc->sc_target; - sc->sc_sq.sq_lun = sc->sc_lun; - sc->sc_sq.sq_start = acstart; - sc->sc_sq.sq_go = acgo; - sc->sc_sq.sq_intr = acintr; - - sc->sc_bp = (struct buf *)malloc(sizeof(struct buf), - M_DEVBUF, M_NOWAIT); - sc->sc_cmd = (struct scsi_fmt_cdb *)malloc(sizeof(struct scsi_fmt_cdb), - M_DEVBUF, M_NOWAIT); - - if (sc->sc_bp == NULL || sc->sc_cmd == NULL) { - printf("%s: memory allocation failed\n", sc->sc_dev.dv_xname); - return; - } - - sc->sc_flags = ACF_ALIVE; -} - -/*ARGSUSED*/ -int -acopen(dev, flag, mode, p) - dev_t dev; - int flag, mode; - struct proc *p; -{ - int unit = minor(dev); - struct ac_softc *sc; - - if (unit >= ac_cd.cd_ndevs || - (sc = ac_cd.cd_devs[unit]) == NULL || - (sc->sc_flags & ACF_ALIVE) == 0) - return (ENXIO); - - if (sc->sc_flags & ACF_OPEN) - return (EBUSY); - - /* - * Since acgeteinfo can block we mark the changer open now. - */ - sc->sc_flags |= ACF_OPEN; - if (acgeteinfo(dev)) { - sc->sc_flags &= ~ACF_OPEN; - return(EIO); - } - return (0); -} - -/*ARGSUSED*/ -int -acclose(dev, flag, mode, p) - dev_t dev; - int flag, mode; - struct proc *p; -{ - struct ac_softc *sc = ac_cd.cd_devs[minor(dev)]; - - sc->sc_flags &= ~ACF_OPEN; - return (0); -} - -#define ACRESLEN(ep) \ - (8 + (ep)->nmte*12 + (ep)->nse*12 + (ep)->niee*12 + (ep)->ndte*20) - -/*ARGSUSED*/ -int -acioctl(dev, cmd, data, flag, p) - dev_t dev; - u_long cmd; - caddr_t data; - int flag; - struct proc *p; -{ - struct ac_softc *sc = ac_cd.cd_devs[minor(dev)]; - char *dp; - int dlen, error = 0; - - switch (cmd) { - - default: - return (EINVAL); - - /* perform an init element status and mode sense to reset state */ - case ACIOCINIT: - error = accommand(dev, ACCMD_INITES, (caddr_t)0, 0); - if (!error) - error = acgeteinfo(dev); - break; - - /* copy internal element information */ - case ACIOCGINFO: - *(struct acinfo *)data = sc->sc_einfo; - break; - - case ACIOCRAWES: - { - struct acbuffer *acbp = (struct acbuffer *)data; - - dlen = ACRESLEN(&sc->sc_einfo); - dp = (char *) malloc(dlen, M_DEVBUF, M_WAITOK); - error = accommand(dev, ACCMD_READES, dp, dlen); - if (!error) { - dlen = *(int *)&dp[4] + 8; - if (dlen > acbp->buflen) - dlen = acbp->buflen; - error = copyout(dp, acbp->bufptr, dlen); - } - break; - } - - case ACIOCGSTAT: - { - struct acbuffer *acbp = (struct acbuffer *)data; - - dlen = ACRESLEN(&sc->sc_einfo); - dp = (char *) malloc(dlen, M_DEVBUF, M_WAITOK); - error = accommand(dev, ACCMD_READES, dp, dlen); - if (!error) { - int ne; - char *tbuf; - - ne = sc->sc_einfo.nmte + sc->sc_einfo.nse + - sc->sc_einfo.niee + sc->sc_einfo.ndte; - dlen = ne * sizeof(struct aceltstat); - tbuf = (char *) malloc(dlen, M_DEVBUF, M_WAITOK); - acconvert(dp, tbuf, ne); - if (dlen > acbp->buflen) - dlen = acbp->buflen; - error = copyout(tbuf, acbp->bufptr, dlen); - free(tbuf, M_DEVBUF); - } - free(dp, M_DEVBUF); - break; - } - - case ACIOCMOVE: - error = accommand(dev, ACCMD_MOVEM, data, - sizeof(struct acmove)); - break; - } - return(error); -} - -int -accommand(dev, command, bufp, buflen) - dev_t dev; - int command; - char *bufp; - int buflen; -{ - int unit = minor(dev); - struct ac_softc *sc = ac_cd.cd_devs[unit]; - struct buf *bp = sc->sc_bp; - struct scsi_fmt_cdb *cmd = sc->sc_cmd; - int error; - -#ifdef DEBUG - if (ac_debug & ACD_FOLLOW) - printf("accommand(dev=%x, cmd=%x, buf=%p, buflen=%x)\n", - dev, command, bufp, buflen); -#endif - if (sc->sc_flags & ACF_ACTIVE) - panic("accommand: active!"); - - sc->sc_flags |= ACF_ACTIVE; - bzero((caddr_t)cmd->cdb, sizeof(cmd->cdb)); - cmd->cdb[0] = command; - - switch (command) { - case ACCMD_INITES: - cmd->len = 6; - break; - case ACCMD_READES: - cmd->len = 12; - *(short *)&cmd->cdb[2] = 0; - *(short *)&cmd->cdb[4] = - sc->sc_einfo.nmte + sc->sc_einfo.nse + - sc->sc_einfo.niee + sc->sc_einfo.ndte; - cmd->cdb[7] = buflen >> 16; - cmd->cdb[8] = buflen >> 8; - cmd->cdb[9] = buflen; - break; - case ACCMD_MODESENSE: - cmd->len = 6; - cmd->cdb[2] = 0x3F; /* all pages */ - cmd->cdb[4] = buflen; - break; - case ACCMD_MOVEM: - cmd->len = 12; - *(short *)&cmd->cdb[2] = sc->sc_picker; - *(short *)&cmd->cdb[4] = *(short *)&bufp[0]; - *(short *)&cmd->cdb[6] = *(short *)&bufp[2]; - if (*(short *)&bufp[4] & AC_INVERT) - cmd->cdb[10] = 1; - bufp = 0; - buflen = 0; - break; - default: - panic("accommand: bad command"); - } - bp->b_flags = B_BUSY|B_READ; - bp->b_dev = dev; - bp->b_un.b_addr = bufp; - bp->b_bcount = buflen; - bp->b_resid = 0; - bp->b_blkno = 0; - bp->b_error = 0; - LIST_INIT(&bp->b_dep); - if (scsireq(sc->sc_dev.dv_parent, &sc->sc_sq)) - acstart(sc); - error = biowait(bp); - sc->sc_flags &= ~ACF_ACTIVE; - return (error); -} - -void -acstart(arg) - void *arg; -{ - struct ac_softc *sc = arg; - -#ifdef DEBUG - if (ac_debug & ACD_FOLLOW) - printf("acstart(unit=%x)\n", sc->sc_dev.dv_unit); -#endif - if (scsiustart(sc->sc_dev.dv_parent->dv_unit)) - acgo(arg); -} - -void -acgo(arg) - void *arg; -{ - struct ac_softc *sc = arg; - struct buf *bp = sc->sc_bp; - int stat; - int s; - -#ifdef DEBUG - if (ac_debug & ACD_FOLLOW) - printf("acgo(unit=%x): ", sc->sc_dev.dv_unit); -#endif - stat = scsigo(sc->sc_dev.dv_parent->dv_unit, sc->sc_target, - sc->sc_lun, bp, sc->sc_cmd, 0); -#ifdef DEBUG - if (ac_debug & ACD_FOLLOW) - printf("scsigo returns %x\n", stat); -#endif - if (stat) { - bp->b_error = EIO; - bp->b_flags |= B_ERROR; - s = splbio(); - biodone(bp); - splx(s); - scsifree(sc->sc_dev.dv_parent, &sc->sc_sq); - } -} - -void -acintr(arg, stat) - void *arg; - int stat; -{ - struct ac_softc *sc = arg; - struct buf *bp = sc->sc_bp; - u_char sensebuf[78]; - struct scsi_xsense *sp; - -#ifdef DEBUG - if (ac_debug & ACD_FOLLOW) - printf("acintr(unit=%x, stat=%x)\n", sc->sc_dev.dv_unit, stat); -#endif - switch (stat) { - case 0: - bp->b_resid = 0; - break; - case STS_CHECKCOND: - scsi_request_sense(sc->sc_dev.dv_parent->dv_unit, - sc->sc_target, sc->sc_lun, sensebuf, sizeof sensebuf); - sp = (struct scsi_xsense *)sensebuf; - printf("%s: acintr sense key=%x, ac=%x, acq=%x\n", - sc->sc_dev.dv_xname, sp->key, sp->info4, sp->len); - bp->b_flags |= B_ERROR; - bp->b_error = EIO; - break; - default: - printf("%s: acintr unknown status 0x%x\n", sc->sc_dev.dv_xname, - stat); - break; - } - biodone(sc->sc_bp); - scsifree(sc->sc_dev.dv_parent, &sc->sc_sq); -} - -int -acgeteinfo(dev) - dev_t dev; -{ - struct ac_softc *sc = ac_cd.cd_devs[minor(dev)]; - char *bp; - char msbuf[48]; - int error; - - bzero(msbuf, sizeof msbuf); - error = accommand(dev, ACCMD_MODESENSE, msbuf, sizeof msbuf); - if (error) - return(error); - bp = &msbuf[4]; - while (bp < &msbuf[48]) { - switch (bp[0] & 0x3F) { - case 0x1D: - sc->sc_einfo = *(struct acinfo *)&bp[2]; - sc->sc_picker = sc->sc_einfo.fmte; /* XXX */ - return(0); - case 0x1E: - bp += 4; - break; - case 0x1F: - bp += 20; - break; - default: - printf("acgeteinfo: bad page type %x\n", bp[0]); - return(EIO); - } - } - return(EIO); -} - -void -acconvert(sbuf, dbuf, ne) - char *sbuf, *dbuf; - int ne; -{ - struct aceltstat *ep = (struct aceltstat *)dbuf; - struct ac_restatphdr *phdr; - struct ac_restatdb *dbp; - struct ac_restathdr *hdr; -#ifdef DEBUG - int bcount; -#endif - - hdr = (struct ac_restathdr *)&sbuf[0]; - sbuf += sizeof *hdr; -#ifdef DEBUG - if (ac_debug & ACD_FOLLOW) - printf("element status: first=%d, num=%d, len=%ld\n", - hdr->ac_felt, hdr->ac_nelt, hdr->ac_bcount); - if (hdr->ac_nelt != ne) { - printf("acconvert: # of elements, %d != %d\n", - hdr->ac_nelt, ne); - if (hdr->ac_nelt < ne) - ne = hdr->ac_nelt; - } - bcount = hdr->ac_bcount; -#endif - while (ne) { - phdr = (struct ac_restatphdr *)sbuf; - sbuf += sizeof *phdr; -#ifdef DEBUG - bcount -= sizeof *phdr; -#endif - dbp = (struct ac_restatdb *)sbuf; - sbuf += phdr->ac_bcount; -#ifdef DEBUG - bcount -= phdr->ac_bcount; -#endif - while (dbp < (struct ac_restatdb *)sbuf) { - ep->type = phdr->ac_type; - ep->eaddr = dbp->ac_eaddr; - ep->flags = 0; - if (dbp->ac_full) - ep->flags |= AC_FULL; - if (dbp->ac_exc) - ep->flags |= AC_ERROR; - if (dbp->ac_acc) - ep->flags |= AC_ACCESS; - dbp = (struct ac_restatdb *) - ((char *)dbp + phdr->ac_dlen); - ep++; - ne--; - } -#ifdef DEBUG - if (ne < 0 || bcount < 0) - panic("acconvert: inconsistent"); -#endif - } -} diff --git a/sys/arch/hp300/dev/acioctl.h b/sys/arch/hp300/dev/acioctl.h deleted file mode 100644 index ac7c7d29bed..00000000000 --- a/sys/arch/hp300/dev/acioctl.h +++ /dev/null @@ -1,85 +0,0 @@ -/* $OpenBSD: acioctl.h,v 1.4 2003/11/07 10:16:45 jmc Exp $ */ -/* $NetBSD: acioctl.h,v 1.2 1994/10/26 07:23:25 cgd Exp $ */ - -/* - * Copyright (c) 1991 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. 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: acioctl.h 1.1 91/06/19$ - * - * @(#)acioctl.h 8.1 (Berkeley) 6/10/93 - */ - -struct acinfo { - short fmte; /* 1st medium transport elt (picker) */ - short nmte; /* # medium transport elts */ - short fse; /* 1st storage elt (slot) */ - short nse; /* # storage elts */ - short fiee; /* 1st import/export elt (mailslot) */ - short niee; /* # import/export elts */ - short fdte; /* 1st data transport elt (drive) */ - short ndte; /* # data transport elts */ -}; - -struct aceltstat { - short eaddr; /* element address */ - char type; /* type of element */ - char flags; /* flags */ -}; - -/* types */ -#define AC_MTE 0x01 /* picker */ -#define AC_SE 0x02 /* slot */ -#define AC_IEE 0x03 /* mailslot */ -#define AC_DTE 0x04 /* drive */ -/* flags */ -#define AC_FULL 0x01 /* media present */ -#define AC_ERROR 0x04 /* error accessing element */ -#define AC_ACCESS 0x08 /* element accessible */ -#define AC_INVERT 0x80 /* media inverted prior to insertion */ - -struct acmove { - short srcelem; - short dstelem; - short flags; -}; - -struct acbuffer { - char *bufptr; - int buflen; -}; - -#define ACIOCINIT _IO('A', 0x1) /* init elt status */ -#define ACIOCGINFO _IOR('A', 0x2, struct acinfo) /* mode sense */ -#define ACIOCGSTAT _IOW('A', 0x3, struct acbuffer) /* read elem status */ -#define ACIOCMOVE _IOW('A', 0x4, struct acmove) /* move elem */ -#define ACIOCRAWES _IOW('A', 0x5, struct acbuffer) /* raw element stat */ diff --git a/sys/arch/hp300/dev/acvar.h b/sys/arch/hp300/dev/acvar.h deleted file mode 100644 index 2680fbd05f5..00000000000 --- a/sys/arch/hp300/dev/acvar.h +++ /dev/null @@ -1,96 +0,0 @@ -/* $OpenBSD: acvar.h,v 1.6 2003/06/02 23:27:44 millert Exp $ */ -/* $NetBSD: acvar.h,v 1.4 1997/03/31 07:32:15 scottr Exp $ */ - -/* - * Copyright (c) 1991 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. 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: acvar.h 1.1 91/06/19$ - * - * @(#)acvar.h 8.1 (Berkeley) 6/10/93 - */ - -struct ac_softc { - struct device sc_dev; - int sc_target; - int sc_lun; - int sc_flags; - struct buf *sc_bp; - struct scsi_fmt_cdb *sc_cmd; - struct acinfo sc_einfo; - short sc_picker; - struct scsiqueue sc_sq; -}; - -#define ACF_ALIVE 0x01 -#define ACF_OPEN 0x02 -#define ACF_ACTIVE 0x04 - -#define ACCMD_INITES 0x07 -#define ACCMD_MODESENSE 0x1A -#define ACCMD_READES 0xB8 -#define ACCMD_MOVEM 0xA5 - -struct ac_restathdr { - short ac_felt; /* first element reported */ - short ac_nelt; /* number of elements reported */ - long ac_bcount; /* length of report (really only 24 bits) */ -}; - -struct ac_restatphdr { - char ac_type; /* type code */ - char ac_res; - short ac_dlen; /* element descriptor length */ - long ac_bcount; /* byte count (really only 24 bits) */ -}; - -struct ac_restatdb { - short ac_eaddr; /* element address */ - u_int ac_res1:2, - ac_ie:1, /* import enabled (IEE only) */ - ac_ee:1, /* export enabled (IEE only) */ - ac_acc:1, /* accessible from MTE */ - ac_exc:1, /* element in abnormal state */ - ac_imp:1, /* 1 == user inserted medium (IEE only) */ - ac_full:1; /* element contains media */ -}; - -#ifdef _KERNEL -int accommand(dev_t, int, char *, int); - -void acstart(void *); -void acgo(void *); -void acintr(void *, int); - -int acgeteinfo(dev_t); -void acconvert(char *, char *, int); -#endif /* _KERNEL */ diff --git a/sys/arch/hp300/dev/sdvar.h b/sys/arch/hp300/dev/hp98265reg.h index e74377b04e3..f8b6dbcf00b 100644 --- a/sys/arch/hp300/dev/sdvar.h +++ b/sys/arch/hp300/dev/hp98265reg.h @@ -1,5 +1,5 @@ -/* $OpenBSD: sdvar.h,v 1.12 2003/06/02 23:27:45 millert Exp $ */ -/* $NetBSD: sdvar.h,v 1.7 1997/03/31 07:40:07 scottr Exp $ */ +/* $OpenBSD: hp98265reg.h,v 1.1 2004/08/03 21:46:56 miod Exp $ */ +/* $NetBSD: hp98265reg.h,v 1.1 2003/08/01 01:18:45 tsutsui Exp $ */ /* * Copyright (c) 1990, 1993 @@ -32,63 +32,40 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)sdvar.h 8.1 (Berkeley) 6/10/93 + * @(#)scsireg.h 8.1 (Berkeley) 6/10/93 */ -struct sdstats { - long sdresets; - long sdtransfers; - long sdpartials; -}; - -struct sd_softc { - struct device sc_dev; - struct disk sc_dkdev; - struct scsiqueue sc_sq; - int sc_format_pid; /* process using "format" mode */ - short sc_flags; - short sc_type; /* drive type */ - int sc_target; /* SCSI target */ - int sc_lun; /* SCSI lun */ - u_short sc_bshift; /* convert device blocks to DEV_BSIZE blks */ - u_int sc_blks; /* number of blocks on device */ - int sc_blksize; /* device block size in bytes */ - u_int sc_heads; /* number of heads (tracks) */ - u_int sc_cyls; /* number of cylinders */ - struct buf sc_tab; /* buffer queue */ - struct sdstats sc_stats; /* debugging stats */ - struct scsi_fmt_cdb sc_cmdstore; - struct scsi_fmt_sense sc_sensestore; -}; - -/* sc_flags values */ -#define SDF_ALIVE 0x01 -#define SDF_OPENING 0x02 -#define SDF_CLOSING 0x04 -#define SDF_WANTED 0x08 -#define SDF_WLABEL 0x10 -#define SDF_RMEDIA 0x20 -#define SDF_ERROR 0x40 - -#define SDUNIT(x) DISKUNIT(x) -#define SDPART(x) DISKPART(x) -#define SDLABELDEV(d) MAKEDISKDEV(major(d), SDUNIT(d), RAW_PART) - -#define b_cylin b_resid +/* + * HP 98265A SCSI Interface Hardware Description. + */ -#define SDRETRY 2 +#define SPC_OFFSET 32 +#define SPC_SIZE (32 * 2) /* XXX */ -#ifdef _KERNEL -/* sd.c */ -void sdustart(int); +#define HPSCSI_ID 0x00 +#define ID_MASK 0x1f +#define SCSI_ID 0x07 +#define ID_WORD_DMA 0x20 -void sdstart(void *); -void sdgo(void *); -void sdintr(void *, int); +#define HPSCSI_CSR 0x01 +#define CSR_IE 0x80 +#define CSR_IR 0x40 +#define SCSI_IPL(csr) ((((csr) >> 4) & 3) + 3) +#define CSR_DMA32 0x08 +#define CSR_DMAIN 0x04 +#define CSR_DE1 0x02 +#define CSR_DE0 0x01 -int sdgetcapacity(struct sd_softc *, dev_t); -int sdgetinfo(dev_t, struct sd_softc *, struct disklabel *, int); +#define HPSCSI_WRAP 0x02 +#define WRAP_REQ 0x80 +#define WRAP_ACK 0x40 +#define WRAP_BSY 0x08 +#define WRAP_MSG 0x04 +#define WRAP_CD 0x02 +#define WRAP_IO 0x01 -/* sd_compat.c */ -void sdmakedisklabel(int, struct disklabel *); -#endif /* _KERNEL */ +#define HPSCSI_HCONF 0x03 +#define HCONF_TP 0x80 +#define SCSI_SYNC_XFER(hconf) (((hconf) >> 5) & 3) +#define HCONF_SD 0x10 +#define HCONF_PARITY 0x08 diff --git a/sys/arch/hp300/dev/mb89352.c b/sys/arch/hp300/dev/mb89352.c new file mode 100644 index 00000000000..5f9cdff8258 --- /dev/null +++ b/sys/arch/hp300/dev/mb89352.c @@ -0,0 +1,2025 @@ +/* $OpenBSD: mb89352.c,v 1.1 2004/08/03 21:46:56 miod Exp $ */ +/* $NetBSD: mb89352.c,v 1.5 2000/03/23 07:01:31 thorpej Exp $ */ +/* NecBSD: mb89352.c,v 1.4 1998/03/14 07:31:20 kmatsuda Exp */ + +/*- + * Copyright (c) 1996,97,98,99 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Charles M. Hannum, Masaru Oki and Kouichi Matsuda. + * + * 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 Charles M. Hannum. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Copyright (c) 1994 Jarle Greipsland + * All rights reserved. + * + * 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. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ +/* + * [NetBSD for NEC PC-98 series] + * Copyright (c) 1996, 1997, 1998 + * NetBSD/pc98 porting staff. All rights reserved. + * Copyright (c) 1996, 1997, 1998 + * Kouichi Matsuda. All rights reserved. + */ + +/* + * Acknowledgements: Many of the algorithms used in this driver are + * inspired by the work of Julian Elischer (julian@tfs.com) and + * Charles Hannum (mycroft@duality.gnu.ai.mit.edu). Thanks a million! + */ + +/* + * A few customizable items: + */ + +/* Synchronous data transfers? */ +#define SPC_USE_SYNCHRONOUS 0 +#define SPC_SYNC_REQ_ACK_OFS 8 + +/* Wide data transfers? */ +#define SPC_USE_WIDE 0 +#define SPC_MAX_WIDTH 0 + +/* Max attempts made to transmit a message */ +#define SPC_MSG_MAX_ATTEMPT 3 /* Not used now XXX */ + +/* + * Some spin loop parameters (essentially how long to wait some places) + * The problem(?) is that sometimes we expect either to be able to transmit a + * byte or to get a new one from the SCSI bus pretty soon. In order to avoid + * returning from the interrupt just to get yanked back for the next byte we + * may spin in the interrupt routine waiting for this byte to come. How long? + * This is really (SCSI) device and processor dependent. Tuneable, I guess. + */ +#define SPC_MSGIN_SPIN 1 /* Will spinwait upto ?ms for a new msg byte */ +#define SPC_MSGOUT_SPIN 1 + +/* + * Include debug functions? At the end of this file there are a bunch of + * functions that will print out various information regarding queued SCSI + * commands, driver state and chip contents. You can call them from the + * kernel debugger. If you set SPC_DEBUG to 0 they are not included (the + * kernel uses less memory) but you lose the debugging facilities. + */ +/* #define SPC_DEBUG */ + +#define SPC_ABORT_TIMEOUT 2000 /* time to wait for abort */ + +/* threshold length for DMA transfer */ +#define SPC_MIN_DMA_LEN 32 + +/* End of customizable parameters */ + +/* + * MB89352 SCSI Protocol Controller (SPC) routines. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/errno.h> +#include <sys/ioctl.h> +#include <sys/device.h> +#include <sys/buf.h> +#include <sys/proc.h> +#include <sys/user.h> +#include <sys/queue.h> + +#include <machine/intr.h> + +#include <scsi/scsi_all.h> +#include <scsi/scsi_message.h> +#include <scsi/scsiconf.h> + +#include <hp300/dev/mb89352reg.h> +#include <hp300/dev/mb89352var.h> + +#ifdef SPC_DEBUG +int spc_debug = 0x00; /* SPC_SHOWSTART|SPC_SHOWMISC|SPC_SHOWTRACE; */ +#endif + +void spc_done (struct spc_softc *, struct spc_acb *); +void spc_dequeue (struct spc_softc *, struct spc_acb *); +int spc_scsi_cmd (struct scsi_xfer *); +int spc_poll (struct spc_softc *, struct scsi_xfer *, int); +void spc_sched_msgout(struct spc_softc *, u_char); +void spc_setsync(struct spc_softc *, struct spc_tinfo *); +void spc_select (struct spc_softc *, struct spc_acb *); +void spc_timeout (void *); +void spc_scsi_reset (struct spc_softc *); +void spc_reset (struct spc_softc *); +void spc_free_acb (struct spc_softc *, struct spc_acb *, int); +struct spc_acb* spc_get_acb(struct spc_softc *, int); +int spc_reselect (struct spc_softc *, int); +void spc_sense (struct spc_softc *, struct spc_acb *); +void spc_msgin (struct spc_softc *); +void spc_abort (struct spc_softc *, struct spc_acb *); +void spc_msgout (struct spc_softc *); +int spc_dataout_pio (struct spc_softc *, u_char *, int); +int spc_datain_pio (struct spc_softc *, u_char *, int); +void spc_process_intr(void *, u_char); +#ifdef SPC_DEBUG +void spc_print_acb (struct spc_acb *); +void spc_dump_driver (struct spc_softc *); +void spc_dump89352 (struct spc_softc *); +void spc_show_scsi_cmd(struct spc_acb *); +void spc_print_active_acb(void); +#endif + +extern struct cfdriver spc_cd; + +struct scsi_device spc_dev = { + NULL, /* Use default error handler */ + NULL, /* have a queue, served by this */ + NULL, /* have no async handler */ + NULL, /* Use default 'done' routine */ +}; + +struct scsi_adapter spc_switch = { + spc_scsi_cmd, + minphys, + NULL, + NULL +}; + +/* + * INITIALIZATION ROUTINES (probe, attach ++) + */ + +void +spc_attach(struct spc_softc *sc) +{ + SPC_TRACE(("spc_attach ")); + sc->sc_state = SPC_INIT; + + sc->sc_freq = 20; /* XXX Assume 20 MHz. */ + +#if SPC_USE_SYNCHRONOUS + /* + * These are the bounds of the sync period, based on the frequency of + * the chip's clock input and the size and offset of the sync period + * register. + * + * For a 20MHz clock, this gives us 25, or 100nS, or 10MB/s, as a + * maximum transfer rate, and 112.5, or 450nS, or 2.22MB/s, as a + * minimum transfer rate. + */ + sc->sc_minsync = (2 * 250) / sc->sc_freq; + sc->sc_maxsync = (9 * 250) / sc->sc_freq; +#endif + + spc_init(sc); /* Init chip and driver */ + + /* + * Fill in the adapter. + */ + sc->sc_link.adapter_softc = sc; + sc->sc_link.adapter_target = sc->sc_initiator; + sc->sc_link.adapter = &spc_switch; + sc->sc_link.device = &spc_dev; + sc->sc_link.openings = 2; + + /* + * ask the adapter what subunits are present + */ + config_found(&sc->sc_dev, &sc->sc_link, scsiprint); +} + +/* + * Initialize MB89352 chip itself + * The following conditions should hold: + * spc_isa_probe should have succeeded, i.e. the iobase address in spc_softc + * must be valid. + */ +void +spc_reset(struct spc_softc *sc) +{ + SPC_TRACE(("spc_reset ")); + /* + * Disable interrupts then reset the FUJITSU chip. + */ + spc_write(SCTL, SCTL_DISABLE | SCTL_CTRLRST); + spc_write(SCMD, 0); + spc_write(TMOD, 0); + spc_write(PCTL, 0); + spc_write(TEMP, 0); + spc_write(TCH, 0); + spc_write(TCM, 0); + spc_write(TCL, 0); + spc_write(INTS, 0); + spc_write(SCTL, + SCTL_DISABLE | SCTL_ABRT_ENAB | SCTL_PARITY_ENAB | SCTL_RESEL_ENAB); + spc_write(BDID, sc->sc_initiator); + delay(400); + spc_write(SCTL, spc_read(SCTL) & ~SCTL_DISABLE); +} + + +/* + * Pull the SCSI RST line for 500us. + */ +void +spc_scsi_reset(struct spc_softc *sc) +{ + SPC_TRACE(("spc_scsi_reset ")); + spc_write(SCMD, spc_read(SCMD) | SCMD_RST); + delay(500); + spc_write(SCMD, spc_read(SCMD) & ~SCMD_RST); + delay(50); +} + +/* + * Initialize spc SCSI driver. + */ +void +spc_init(struct spc_softc *sc) +{ + struct spc_acb *acb; + int r; + + SPC_TRACE(("spc_init ")); + spc_reset(sc); + spc_scsi_reset(sc); + spc_reset(sc); + + if (sc->sc_state == SPC_INIT) { + /* First time through; initialize. */ + TAILQ_INIT(&sc->ready_list); + TAILQ_INIT(&sc->nexus_list); + TAILQ_INIT(&sc->free_list); + sc->sc_nexus = NULL; + acb = sc->sc_acb; + bzero(acb, sizeof(sc->sc_acb)); + for (r = 0; r < sizeof(sc->sc_acb) / sizeof(*acb); r++) { + TAILQ_INSERT_TAIL(&sc->free_list, acb, chain); + acb++; + } + bzero(&sc->sc_tinfo, sizeof(sc->sc_tinfo)); + } else { + /* Cancel any active commands. */ + sc->sc_state = SPC_CLEANING; + if ((acb = sc->sc_nexus) != NULL) { + acb->xs->error = XS_DRIVER_STUFFUP; + timeout_del(&acb->xs->stimeout); + spc_done(sc, acb); + } + while ((acb = TAILQ_FIRST(&sc->nexus_list)) != NULL) { + acb->xs->error = XS_DRIVER_STUFFUP; + timeout_del(&acb->xs->stimeout); + spc_done(sc, acb); + } + } + + sc->sc_prevphase = PH_INVALID; + for (r = 0; r < 8; r++) { + struct spc_tinfo *ti = &sc->sc_tinfo[r]; + + ti->flags = 0; +#if SPC_USE_SYNCHRONOUS + ti->flags |= DO_SYNC; + ti->period = sc->sc_minsync; + ti->offset = SPC_SYNC_REQ_ACK_OFS; +#else + ti->period = ti->offset = 0; +#endif +#if SPC_USE_WIDE + ti->flags |= DO_WIDE; + ti->width = SPC_MAX_WIDTH; +#else + ti->width = 0; +#endif + } + + sc->sc_state = SPC_IDLE; + spc_write(SCTL, spc_read(SCTL) | SCTL_INTR_ENAB); +} + +void +spc_free_acb(struct spc_softc *sc, struct spc_acb *acb, int flags) +{ + int s; + + SPC_TRACE(("spc_free_acb ")); + s = splbio(); + + acb->flags = 0; + TAILQ_INSERT_HEAD(&sc->free_list, acb, chain); + + /* + * If there were none, wake anybody waiting for one to come free, + * starting with queued entries. + */ + if (acb->chain.tqe_next == 0) + wakeup(&sc->free_list); + + splx(s); +} + +struct spc_acb * +spc_get_acb(struct spc_softc *sc, int flags) +{ + struct spc_acb *acb; + int s; + + SPC_TRACE(("spc_get_acb ")); + s = splbio(); + + while ((acb = TAILQ_FIRST(&sc->free_list)) == NULL && + (flags & SCSI_NOSLEEP) == 0) + tsleep(&sc->free_list, PRIBIO, "spcacb", 0); + if (acb) { + TAILQ_REMOVE(&sc->free_list, acb, chain); + acb->flags |= ACB_ALLOC; + } + + splx(s); + return acb; +} + +/* + * DRIVER FUNCTIONS CALLABLE FROM HIGHER LEVEL DRIVERS + */ + +/* + * Expected sequence: + * 1) Command inserted into ready list + * 2) Command selected for execution + * 3) Command won arbitration and has selected target device + * 4) Send message out (identify message, eventually also sync.negotiations) + * 5) Send command + * 5a) Receive disconnect message, disconnect. + * 5b) Reselected by target + * 5c) Receive identify message from target. + * 6) Send or receive data + * 7) Receive status + * 8) Receive message (command complete etc.) + * 9) If status == SCSI_CHECK construct a synthetic request sense SCSI cmd. + * Repeat 2-8 (no disconnects please...) + */ + +/* + * Start a SCSI-command + * This function is called by the higher level SCSI-driver to queue/run + * SCSI-commands. + */ +int +spc_scsi_cmd(struct scsi_xfer *xs) +{ + struct scsi_link *sc_link = xs->sc_link; + struct spc_softc *sc = sc_link->adapter_softc; + struct spc_acb *acb; + int s, flags; + + SPC_TRACE(("spc_scsi_cmd ")); + SPC_CMDS(("[0x%x, %d]->%d ", (int)xs->cmd->opcode, xs->cmdlen, + sc_link->target)); + + flags = xs->flags; + if ((acb = spc_get_acb(sc, flags)) == NULL) { + xs->error = XS_DRIVER_STUFFUP; + return TRY_AGAIN_LATER; + } + + /* Initialize acb */ + acb->xs = xs; + acb->timeout = xs->timeout; + + if (xs->flags & SCSI_RESET) { + acb->flags |= ACB_RESET; + acb->scsi_cmd_length = 0; + acb->data_length = 0; + } else { + bcopy(xs->cmd, &acb->scsi_cmd, xs->cmdlen); + acb->scsi_cmd_length = xs->cmdlen; + acb->data_addr = xs->data; + acb->data_length = xs->datalen; + } + acb->target_stat = 0; + + s = splbio(); + + TAILQ_INSERT_TAIL(&sc->ready_list, acb, chain); + /* + * Start scheduling unless a queue process is in progress. + */ + if (sc->sc_state == SPC_IDLE) + spc_sched(sc); + /* + * After successful sending, check if we should return just now. + * If so, return SUCCESSFULLY_QUEUED. + */ + + splx(s); + + if ((flags & SCSI_POLL) == 0) + return SUCCESSFULLY_QUEUED; + + /* Not allowed to use interrupts, use polling instead */ + s = splbio(); + if (spc_poll(sc, xs, acb->timeout)) { + spc_timeout(acb); + if (spc_poll(sc, xs, acb->timeout)) + spc_timeout(acb); + } + splx(s); + return COMPLETE; +} + +/* + * Used when interrupt driven I/O isn't allowed, e.g. during boot. + */ +int +spc_poll(struct spc_softc *sc, struct scsi_xfer *xs, int count) +{ + u_char intr; + + SPC_TRACE(("spc_poll ")); + while (count) { + /* + * If we had interrupts enabled, would we + * have got an interrupt? + */ + intr = spc_read(INTS); + if (intr != 0) + spc_process_intr(sc, intr); + if ((xs->flags & ITSDONE) != 0) + return 0; + delay(1000); + count--; + } + return 1; +} + +/* + * LOW LEVEL SCSI UTILITIES + */ + +void +spc_sched_msgout(struct spc_softc *sc, u_char m) +{ + SPC_TRACE(("spc_sched_msgout ")); + if (sc->sc_msgpriq == 0) + spc_write(SCMD, SCMD_SET_ATN); + sc->sc_msgpriq |= m; +} + +/* + * Set synchronous transfer offset and period. + */ +void +spc_setsync(struct spc_softc *sc, struct spc_tinfo *ti) +{ +#if SPC_USE_SYNCHRONOUS + SPC_TRACE(("spc_setsync ")); + if (ti->offset != 0) + spc_write(TMOD, + ((ti->period * sc->sc_freq) / 250 - 2) << 4 | ti->offset); + else + spc_write(TMOD, 0); +#endif +} + +/* + * Start a selection. This is used by spc_sched() to select an idle target, + * and by spc_done() to immediately reselect a target to get sense information. + */ +void +spc_select(struct spc_softc *sc, struct spc_acb *acb) +{ + struct scsi_link *sc_link = acb->xs->sc_link; + int target = sc_link->target; + struct spc_tinfo *ti = &sc->sc_tinfo[target]; + + SPC_TRACE(("spc_select ")); + spc_setsync(sc, ti); + +#if 0 + spc_write(SCMD, SCMD_SET_ATN); +#endif + + spc_write(PCTL, 0); + spc_write(TEMP, (1 << sc->sc_initiator) | (1 << target)); + +#ifdef hp300 + /* Select timeout hardcoded to 2ms */ + spc_write(TCH, 15); + spc_write(TCM, 32); + spc_write(TCL, 4); +#else + /* + * Setup BSY timeout (selection timeout). + * 250ms according to the SCSI specification. + * T = (X * 256 + 15) * Tclf * 2 (Tclf = 200ns on x68k) + * To setup 256ms timeout, + * 128000ns/200ns = X * 256 + 15 + * 640 - 15 = X * 256 + * X = 625 / 256 + * X = 2 + 113 / 256 + * ==> tch = 2, tcm = 113 (correct?) + */ + /* Time to the information transfer phase start. */ + /* XXX These values should be calculated from sc_freq */ + spc_write(TCH, 2); + spc_write(TCM, 113); + spc_write(TCL, 3); +#endif + spc_write(SCMD, SCMD_SELECT); + + sc->sc_state = SPC_SELECTING; +} + +int +spc_reselect(struct spc_softc *sc, int message) +{ + u_char selid, target, lun; + struct spc_acb *acb; + struct scsi_link *sc_link; + struct spc_tinfo *ti; + + SPC_TRACE(("spc_reselect ")); + /* + * The SCSI chip made a snapshot of the data bus while the reselection + * was being negotiated. This enables us to determine which target did + * the reselect. + */ + selid = sc->sc_selid & ~(1 << sc->sc_initiator); + if (selid & (selid - 1)) { + printf("%s: reselect with invalid selid %02x; " + "sending DEVICE RESET\n", sc->sc_dev.dv_xname, selid); + SPC_BREAK(); + goto reset; + } + + /* + * Search wait queue for disconnected cmd + * The list should be short, so I haven't bothered with + * any more sophisticated structures than a simple + * singly linked list. + */ + target = ffs(selid) - 1; + lun = message & 0x07; + TAILQ_FOREACH(acb, &sc->nexus_list, chain) { + sc_link = acb->xs->sc_link; + if (sc_link->target == target && + sc_link->lun == lun) + break; + } + if (acb == NULL) { + printf("%s: reselect from target %d lun %d with no nexus; " + "sending ABORT\n", sc->sc_dev.dv_xname, target, lun); + SPC_BREAK(); + goto abort; + } + + /* Make this nexus active again. */ + TAILQ_REMOVE(&sc->nexus_list, acb, chain); + sc->sc_state = SPC_CONNECTED; + sc->sc_nexus = acb; + ti = &sc->sc_tinfo[target]; + ti->lubusy |= (1 << lun); + spc_setsync(sc, ti); + + if (acb->flags & ACB_RESET) + spc_sched_msgout(sc, SEND_DEV_RESET); + else if (acb->flags & ACB_ABORT) + spc_sched_msgout(sc, SEND_ABORT); + + /* Do an implicit RESTORE POINTERS. */ + sc->sc_dp = acb->data_addr; + sc->sc_dleft = acb->data_length; + sc->sc_cp = (u_char *)&acb->scsi_cmd; + sc->sc_cleft = acb->scsi_cmd_length; + + return (0); + +reset: + spc_sched_msgout(sc, SEND_DEV_RESET); + return (1); + +abort: + spc_sched_msgout(sc, SEND_ABORT); + return (1); +} + +/* + * Schedule a SCSI operation. This has now been pulled out of the interrupt + * handler so that we may call it from spc_scsi_cmd and spc_done. This may + * save us an unnecessary interrupt just to get things going. Should only be + * called when state == SPC_IDLE and at bio pl. + */ +void +spc_sched(struct spc_softc *sc) +{ + struct spc_acb *acb; + struct scsi_link *sc_link; + struct spc_tinfo *ti; + + /* missing the hw, just return and wait for our hw */ + if (sc->sc_flags & SPC_INACTIVE) + return; + SPC_TRACE(("spc_sched ")); + /* + * Find first acb in ready queue that is for a target/lunit pair that + * is not busy. + */ + TAILQ_FOREACH(acb, &sc->ready_list, chain) { + sc_link = acb->xs->sc_link; + ti = &sc->sc_tinfo[sc_link->target]; + if ((ti->lubusy & (1 << sc_link->lun)) == 0) { + SPC_MISC(("selecting %d:%d ", + sc_link->target, sc_link->lun)); + TAILQ_REMOVE(&sc->ready_list, acb, chain); + sc->sc_nexus = acb; + spc_select(sc, acb); + return; + } else + SPC_MISC(("%d:%d busy\n", + sc_link->target, sc_link->lun)); + } + SPC_MISC(("idle ")); + /* Nothing to start; just enable reselections and wait. */ +} + +void +spc_sense(struct spc_softc *sc, struct spc_acb *acb) +{ + struct scsi_xfer *xs = acb->xs; + struct scsi_link *sc_link = xs->sc_link; + struct spc_tinfo *ti = &sc->sc_tinfo[sc_link->target]; + struct scsi_sense *ss = (void *)&acb->scsi_cmd; + + SPC_MISC(("requesting sense ")); + /* Next, setup a request sense command block */ + bzero(ss, sizeof(*ss)); + ss->opcode = REQUEST_SENSE; + ss->byte2 = sc_link->lun << 5; + ss->length = sizeof(struct scsi_sense_data); + acb->scsi_cmd_length = sizeof(*ss); + acb->data_addr = (char *)&xs->sense; + acb->data_length = sizeof(struct scsi_sense_data); + acb->flags |= ACB_SENSE; + ti->senses++; + if (acb->flags & ACB_NEXUS) + ti->lubusy &= ~(1 << sc_link->lun); + if (acb == sc->sc_nexus) { + spc_select(sc, acb); + } else { + spc_dequeue(sc, acb); + TAILQ_INSERT_HEAD(&sc->ready_list, acb, chain); + if (sc->sc_state == SPC_IDLE) + spc_sched(sc); + } +} + +/* + * POST PROCESSING OF SCSI_CMD (usually current) + */ +void +spc_done(struct spc_softc *sc, struct spc_acb *acb) +{ + struct scsi_xfer *xs = acb->xs; + struct scsi_link *sc_link = xs->sc_link; + struct spc_tinfo *ti = &sc->sc_tinfo[sc_link->target]; + + SPC_TRACE(("spc_done ")); + + /* + * Now, if we've come here with no error code, i.e. we've kept the + * initial XS_NOERROR, and the status code signals that we should + * check sense, we'll need to set up a request sense cmd block and + * push the command back into the ready queue *before* any other + * commands for this target/lunit, else we lose the sense info. + * We don't support chk sense conditions for the request sense cmd. + */ + if (xs->error == XS_NOERROR) { + if (acb->flags & ACB_ABORT) { + xs->error = XS_DRIVER_STUFFUP; + } else if (acb->flags & ACB_SENSE) { + xs->error = XS_SENSE; + } else { + switch (acb->target_stat) { + case SCSI_CHECK: + /* First, save the return values */ + xs->resid = acb->data_length; + xs->status = acb->target_stat; + spc_sense(sc, acb); + return; + case SCSI_BUSY: + xs->error = XS_BUSY; + break; + case SCSI_OK: + xs->resid = acb->data_length; + break; + default: + xs->error = XS_DRIVER_STUFFUP; +#ifdef SPC_DEBUG + printf("%s: spc_done: bad stat 0x%x\n", + sc->sc_dev.dv_xname, acb->target_stat); +#endif + break; + } + } + } + + xs->flags |= ITSDONE; + +#ifdef SPC_DEBUG + if ((spc_debug & SPC_SHOWMISC) != 0) { + if (xs->resid != 0) + printf("resid=%d ", xs->resid); + if (xs->error == XS_SENSE) + printf("sense=0x%02x\n", xs->sense.error_code); + else + printf("error=%d\n", xs->error); + } +#endif + + /* + * Remove the ACB from whatever queue it happens to be on. + */ + if (acb->flags & ACB_NEXUS) + ti->lubusy &= ~(1 << sc_link->lun); + if (acb == sc->sc_nexus) { + sc->sc_nexus = NULL; + sc->sc_state = SPC_IDLE; + spc_sched(sc); + } else + spc_dequeue(sc, acb); + + spc_free_acb(sc, acb, xs->flags); + ti->cmds++; + scsi_done(xs); +} + +void +spc_dequeue(struct spc_softc *sc, struct spc_acb *acb) +{ + SPC_TRACE(("spc_dequeue ")); + if (acb->flags & ACB_NEXUS) + TAILQ_REMOVE(&sc->nexus_list, acb, chain); + else + TAILQ_REMOVE(&sc->ready_list, acb, chain); +} + +/* + * INTERRUPT/PROTOCOL ENGINE + */ + +#define IS1BYTEMSG(m) (((m) != 0x01 && (m) < 0x20) || (m) >= 0x80) +#define IS2BYTEMSG(m) (((m) & 0xf0) == 0x20) +#define ISEXTMSG(m) ((m) == 0x01) + +/* + * Precondition: + * The SCSI bus is already in the MSGI phase and there is a message byte + * on the bus, along with an asserted REQ signal. + */ +void +spc_msgin(struct spc_softc *sc) +{ + int n; + u_int8_t msg; + + SPC_TRACE(("spc_msgin ")); + + if (sc->sc_prevphase == PH_MSGIN) { + /* This is a continuation of the previous message. */ + n = sc->sc_imp - sc->sc_imess; + goto nextbyte; + } + + /* This is a new MESSAGE IN phase. Clean up our state. */ + sc->sc_flags &= ~SPC_DROP_MSGIN; + +nextmsg: + n = 0; + sc->sc_imp = &sc->sc_imess[n]; + +nextbyte: + /* + * Read a whole message, but don't ack the last byte. If we reject the + * message, we have to assert ATN during the message transfer phase + * itself. + */ + for (;;) { + if (spc_read(INTS) != 0) { + /* + * Target left MESSAGE IN, probably because it + * a) noticed our ATN signal, or + * b) ran out of messages. + */ + goto out; + } + /* If parity error, just dump everything on the floor. */ + if ((spc_read(SERR) & (SERR_SCSI_PAR|SERR_SPC_PAR)) != 0) { + sc->sc_flags |= SPC_DROP_MSGIN; + spc_sched_msgout(sc, SEND_PARITY_ERROR); + } + + /* send TRANSFER command. */ + spc_write(TCH, 0); + spc_write(TCM, 0); + spc_write(TCL, 1); + spc_write(PCTL, sc->sc_phase | PCTL_BFINT_ENAB); + spc_write(SCMD, SCMD_XFR | SCMD_PROG_XFR); /* XXX */ + + for (;;) { + if ((spc_read(SSTS) & SSTS_DREG_EMPTY) == 0) + break; + if (spc_read(INTS) != 0) + goto out; + } + + /* Gather incoming message bytes if needed. */ + if ((sc->sc_flags & SPC_DROP_MSGIN) == 0) { + if (n >= SPC_MAX_MSG_LEN) { + msg = spc_read(DREG); + sc->sc_flags |= SPC_DROP_MSGIN; + spc_sched_msgout(sc, SEND_REJECT); + } else { + *sc->sc_imp++ = spc_read(DREG); + n++; + /* + * This testing is suboptimal, but most + * messages will be of the one byte variety, so + * it should not affect performance + * significantly. + */ + if (n == 1 && IS1BYTEMSG(sc->sc_imess[0])) + break; + if (n == 2 && IS2BYTEMSG(sc->sc_imess[0])) + break; + if (n >= 3 && ISEXTMSG(sc->sc_imess[0]) && + n == sc->sc_imess[1] + 2) + break; + } + } else + msg = spc_read(DREG); + + /* + * If we reach this spot we're either: + * a) in the middle of a multi-byte message, or + * b) dropping bytes. + */ + + /* Ack the last byte read. */ +#if 0 + spc_write(SCMD, SCMD_RST_ACK); +#endif + } + + SPC_MISC(("n=%d imess=0x%02x ", n, sc->sc_imess[0])); + + /* We now have a complete message. Parse it. */ + switch (sc->sc_state) { + struct spc_acb *acb; + struct scsi_link *sc_link; + struct spc_tinfo *ti; + + case SPC_CONNECTED: + SPC_ASSERT(sc->sc_nexus != NULL); + acb = sc->sc_nexus; + ti = &sc->sc_tinfo[acb->xs->sc_link->target]; + + switch (sc->sc_imess[0]) { + case MSG_CMDCOMPLETE: + if (sc->sc_dleft < 0) { + sc_link = acb->xs->sc_link; + printf("%s: %d extra bytes from %d:%d\n", + sc->sc_dev.dv_xname, -sc->sc_dleft, + sc_link->target, sc_link->lun); + sc->sc_dleft = 0; + } + acb->xs->resid = acb->data_length = sc->sc_dleft; + sc->sc_state = SPC_CMDCOMPLETE; + break; + + case MSG_PARITY_ERROR: + /* Resend the last message. */ + spc_sched_msgout(sc, sc->sc_lastmsg); + break; + + case MSG_MESSAGE_REJECT: + SPC_MISC(("message rejected %02x ", sc->sc_lastmsg)); + switch (sc->sc_lastmsg) { +#if SPC_USE_SYNCHRONOUS + SPC_USE_WIDE + case SEND_IDENTIFY: + ti->flags &= ~(DO_SYNC | DO_WIDE); + ti->period = ti->offset = 0; + spc_setsync(sc, ti); + ti->width = 0; + break; +#endif +#if SPC_USE_SYNCHRONOUS + case SEND_SDTR: + ti->flags &= ~DO_SYNC; + ti->period = ti->offset = 0; + spc_setsync(sc, ti); + break; +#endif +#if SPC_USE_WIDE + case SEND_WDTR: + ti->flags &= ~DO_WIDE; + ti->width = 0; + break; +#endif + case SEND_INIT_DET_ERR: + spc_sched_msgout(sc, SEND_ABORT); + break; + } + break; + + case MSG_NOOP: + break; + + case MSG_DISCONNECT: + ti->dconns++; + sc->sc_state = SPC_DISCONNECT; + break; + + case MSG_SAVEDATAPOINTER: + acb->data_addr = sc->sc_dp; + acb->data_length = sc->sc_dleft; + break; + + case MSG_RESTOREPOINTERS: + sc->sc_dp = acb->data_addr; + sc->sc_dleft = acb->data_length; + sc->sc_cp = (u_char *)&acb->scsi_cmd; + sc->sc_cleft = acb->scsi_cmd_length; + break; + + case MSG_EXTENDED: + switch (sc->sc_imess[2]) { +#if SPC_USE_SYNCHRONOUS + case MSG_EXT_SDTR: + if (sc->sc_imess[1] != 3) + goto reject; + ti->period = sc->sc_imess[3]; + ti->offset = sc->sc_imess[4]; + ti->flags &= ~DO_SYNC; + if (ti->offset == 0) { + } else if (ti->period < sc->sc_minsync || + ti->period > sc->sc_maxsync || + ti->offset > 8) { + ti->period = ti->offset = 0; + spc_sched_msgout(sc, SEND_SDTR); + } else { + sc_print_addr(acb->xs->sc_link); + printf("sync, offset %d, " + "period %dnsec\n", + ti->offset, ti->period * 4); + } + spc_setsync(sc, ti); + break; +#endif + +#if SPC_USE_WIDE + case MSG_EXT_WDTR: + if (sc->sc_imess[1] != 2) + goto reject; + ti->width = sc->sc_imess[3]; + ti->flags &= ~DO_WIDE; + if (ti->width == 0) { + } else if (ti->width > SPC_MAX_WIDTH) { + ti->width = 0; + spc_sched_msgout(sc, SEND_WDTR); + } else { + sc_print_addr(acb->xs->sc_link); + printf("wide, width %d\n", + 1 << (3 + ti->width)); + } + break; +#endif + + default: + printf("%s: unrecognized MESSAGE EXTENDED; " + "sending REJECT\n", sc->sc_dev.dv_xname); + SPC_BREAK(); + goto reject; + } + break; + + default: + printf("%s: unrecognized MESSAGE; sending REJECT\n", + sc->sc_dev.dv_xname); + SPC_BREAK(); + reject: + spc_sched_msgout(sc, SEND_REJECT); + break; + } + break; + + case SPC_RESELECTED: + if (!MSG_ISIDENTIFY(sc->sc_imess[0])) { + printf("%s: reselect without IDENTIFY; " + "sending DEVICE RESET\n", sc->sc_dev.dv_xname); + SPC_BREAK(); + goto reset; + } + + (void) spc_reselect(sc, sc->sc_imess[0]); + break; + + default: + printf("%s: unexpected MESSAGE IN; sending DEVICE RESET\n", + sc->sc_dev.dv_xname); + SPC_BREAK(); + reset: + spc_sched_msgout(sc, SEND_DEV_RESET); + break; + +#ifdef notdef + abort: + spc_sched_msgout(sc, SEND_ABORT); + break; +#endif + } + + /* Ack the last message byte. */ +#if 0 + spc_write(SCMD, SCMD_RST_ACK); +#endif + + /* Go get the next message, if any. */ + goto nextmsg; + +out: + spc_write(SCMD, SCMD_RST_ACK); + SPC_MISC(("n=%d imess=0x%02x ", n, sc->sc_imess[0])); + + while ((spc_read(SSTS) & SSTS_ACTIVE) == SSTS_INITIATOR) + ; /* XXX needs timeout */ +} + +/* + * Send the highest priority, scheduled message. + */ +void +spc_msgout(struct spc_softc *sc) +{ +#if SPC_USE_SYNCHRONOUS + struct spc_tinfo *ti; +#endif + int n; + + SPC_TRACE(("spc_msgout ")); + + if (sc->sc_prevphase == PH_MSGOUT) { + if (sc->sc_omp == sc->sc_omess) { + /* + * This is a retransmission. + * + * We get here if the target stayed in MESSAGE OUT + * phase. Section 5.1.9.2 of the SCSI 2 spec indicates + * that all of the previously transmitted messages must + * be sent again, in the same order. Therefore, we + * requeue all the previously transmitted messages, and + * start again from the top. Our simple priority + * scheme keeps the messages in the right order. + */ + SPC_MISC(("retransmitting ")); + sc->sc_msgpriq |= sc->sc_msgoutq; + /* + * Set ATN. If we're just sending a trivial 1-byte + * message, we'll clear ATN later on anyway. + */ + spc_write(SCMD, SCMD_SET_ATN); /* XXX? */ + } else { + /* This is a continuation of the previous message. */ + n = sc->sc_omp - sc->sc_omess; + goto nextbyte; + } + } + + /* No messages transmitted so far. */ + sc->sc_msgoutq = 0; + sc->sc_lastmsg = 0; + +nextmsg: + /* Pick up highest priority message. */ + sc->sc_currmsg = sc->sc_msgpriq & -sc->sc_msgpriq; + sc->sc_msgpriq &= ~sc->sc_currmsg; + sc->sc_msgoutq |= sc->sc_currmsg; + + /* Build the outgoing message data. */ + switch (sc->sc_currmsg) { + case SEND_IDENTIFY: + SPC_ASSERT(sc->sc_nexus != NULL); + sc->sc_omess[0] = + MSG_IDENTIFY(sc->sc_nexus->xs->sc_link->lun, 1); + n = 1; + break; + +#if SPC_USE_SYNCHRONOUS + case SEND_SDTR: + SPC_ASSERT(sc->sc_nexus != NULL); + ti = &sc->sc_tinfo[sc->sc_nexus->xs->sc_link->target]; + sc->sc_omess[4] = MSG_EXTENDED; + sc->sc_omess[3] = MSG_EXT_SDTR_LEN; + sc->sc_omess[2] = MSG_EXT_SDTR; + sc->sc_omess[1] = ti->period >> 2; + sc->sc_omess[0] = ti->offset; + n = 5; + break; +#endif + +#if SPC_USE_WIDE + case SEND_WDTR: + SPC_ASSERT(sc->sc_nexus != NULL); + ti = &sc->sc_tinfo[sc->sc_nexus->xs->sc_link->target]; + sc->sc_omess[3] = MSG_EXTENDED; + sc->sc_omess[2] = MSG_EXT_WDTR_LEN; + sc->sc_omess[1] = MSG_EXT_WDTR; + sc->sc_omess[0] = ti->width; + n = 4; + break; +#endif + + case SEND_DEV_RESET: + sc->sc_flags |= SPC_ABORTING; + sc->sc_omess[0] = MSG_BUS_DEV_RESET; + n = 1; + break; + + case SEND_REJECT: + sc->sc_omess[0] = MSG_MESSAGE_REJECT; + n = 1; + break; + + case SEND_PARITY_ERROR: + sc->sc_omess[0] = MSG_PARITY_ERROR; + n = 1; + break; + + case SEND_INIT_DET_ERR: + sc->sc_omess[0] = MSG_INITIATOR_DET_ERR; + n = 1; + break; + + case SEND_ABORT: + sc->sc_flags |= SPC_ABORTING; + sc->sc_omess[0] = MSG_ABORT; + n = 1; + break; + + default: + printf("%s: unexpected MESSAGE OUT; sending NOOP\n", + sc->sc_dev.dv_xname); + SPC_BREAK(); + sc->sc_omess[0] = MSG_NOOP; + n = 1; + break; + } + sc->sc_omp = &sc->sc_omess[n]; + +nextbyte: + /* Send message bytes. */ + /* send TRANSFER command. */ + spc_write(TCH, n >> 16); + spc_write(TCM, n >> 8); + spc_write(TCL, n); + spc_write(PCTL, sc->sc_phase | PCTL_BFINT_ENAB); + spc_write(SCMD, SCMD_XFR | SCMD_PROG_XFR | SCMD_ICPT_XFR); + for (;;) { + if ((spc_read(SSTS) & SSTS_BUSY) != 0) + break; + if (spc_read(INTS) != 0) + goto out; + } + for (;;) { +#if 0 + for (;;) { + if ((spc_read(PSNS) & PSNS_REQ) != 0) + break; + /* Wait for REQINIT. XXX Need timeout. */ + } +#endif + if (spc_read(INTS) != 0) { + /* + * Target left MESSAGE OUT, possibly to reject + * our message. + * + * If this is the last message being sent, then we + * deassert ATN, since either the target is going to + * ignore this message, or it's going to ask for a + * retransmission via MESSAGE PARITY ERROR (in which + * case we reassert ATN anyway). + */ +#if 0 + if (sc->sc_msgpriq == 0) + spc_write(SCMD, SCMD_RST_ATN); +#endif + goto out; + } + +#if 0 + /* Clear ATN before last byte if this is the last message. */ + if (n == 1 && sc->sc_msgpriq == 0) + spc_write(SCMD, SCMD_RST_ATN); +#endif + + while ((spc_read(SSTS) & SSTS_DREG_FULL) != 0) + ; + /* Send message byte. */ + spc_write(DREG, *--sc->sc_omp); + --n; + /* Keep track of the last message we've sent any bytes of. */ + sc->sc_lastmsg = sc->sc_currmsg; +#if 0 + /* Wait for ACK to be negated. XXX Need timeout. */ + while ((spc_read(PSNS) & ACKI) != 0) + ; +#endif + + if (n == 0) + break; + } + + /* We get here only if the entire message has been transmitted. */ + if (sc->sc_msgpriq != 0) { + /* There are more outgoing messages. */ + goto nextmsg; + } + + /* + * The last message has been transmitted. We need to remember the last + * message transmitted (in case the target switches to MESSAGE IN phase + * and sends a MESSAGE REJECT), and the list of messages transmitted + * this time around (in case the target stays in MESSAGE OUT phase to + * request a retransmit). + */ + +out: + /* Disable REQ/ACK protocol. */ + return; +} + +/* + * spc_dataout_pio: perform a data transfer using the FIFO datapath in the spc + * Precondition: The SCSI bus should be in the DOUT phase, with REQ asserted + * and ACK deasserted (i.e. waiting for a data byte). + * + * This new revision has been optimized (I tried) to make the common case fast, + * and the rarer cases (as a result) somewhat more complex. + */ +int +spc_dataout_pio(struct spc_softc *sc, u_char *p, int n) +{ + u_char intstat = 0; + int out = 0; +#define DOUTAMOUNT 8 /* Full FIFO */ + + SPC_TRACE(("spc_dataout_pio ")); + /* send TRANSFER command. */ + spc_write(TCH, n >> 16); + spc_write(TCM, n >> 8); + spc_write(TCL, n); + spc_write(PCTL, sc->sc_phase | PCTL_BFINT_ENAB); + spc_write(SCMD, SCMD_XFR | SCMD_PROG_XFR | SCMD_ICPT_XFR); /* XXX */ + for (;;) { + if ((spc_read(SSTS) & SSTS_BUSY) != 0) + break; + if (spc_read(INTS) != 0) + break; + } + + /* + * I have tried to make the main loop as tight as possible. This + * means that some of the code following the loop is a bit more + * complex than otherwise. + */ + while (n > 0) { + int xfer; + + for (;;) { + intstat = spc_read(INTS); + /* Wait till buffer is empty. */ + if ((spc_read(SSTS) & SSTS_DREG_EMPTY) != 0) + break; + /* Break on interrupt. */ + if (intstat != 0) + goto phasechange; + } + + xfer = min(DOUTAMOUNT, n); + + SPC_MISC(("%d> ", xfer)); + + n -= xfer; + out += xfer; + + while (xfer-- > 0) + spc_write(DREG, *p++); + } + + if (out == 0) { + for (;;) { + if (spc_read(INTS) != 0) + break; + } + SPC_MISC(("extra data ")); + } else { + /* See the bytes off chip */ + for (;;) { + /* Wait till buffer is empty. */ + if ((spc_read(SSTS) & SSTS_DREG_EMPTY) != 0) + break; + intstat = spc_read(INTS); + /* Break on interrupt. */ + if (intstat != 0) + goto phasechange; + } + } + +phasechange: + /* Stop the FIFO data path. */ + + if (intstat != 0) { + /* Some sort of phase change. */ + int amount; + + amount = ((spc_read(TCH) << 16) | + (spc_read(TCM) << 8) | spc_read(TCL)); + if (amount > 0) { + out -= amount; + SPC_MISC(("+%d ", amount)); + } + } + + return out; +} + +/* + * spc_datain_pio: perform data transfers using the FIFO datapath in the spc + * Precondition: The SCSI bus should be in the DIN phase, with REQ asserted + * and ACK deasserted (i.e. at least one byte is ready). + * + * For now, uses a pretty dumb algorithm, hangs around until all data has been + * transferred. This, is OK for fast targets, but not so smart for slow + * targets which don't disconnect or for huge transfers. + */ +int +spc_datain_pio(struct spc_softc *sc, u_char *p, int n) +{ + int in = 0; + u_int8_t intstat, sstat; +#define DINAMOUNT 8 /* Full FIFO */ + + SPC_TRACE(("spc_datain_pio ")); + /* send TRANSFER command. */ + spc_write(TCH, n >> 16); + spc_write(TCM, n >> 8); + spc_write(TCL, n); + spc_write(PCTL, sc->sc_phase | PCTL_BFINT_ENAB); + spc_write(SCMD, SCMD_XFR | SCMD_PROG_XFR); /* XXX */ + for (;;) { + if ((spc_read(SSTS) & SSTS_BUSY) != 0) + break; + if (spc_read(INTS) != 0) + goto phasechange; + } + + /* + * We leave this loop if one or more of the following is true: + * a) phase != PH_DATAIN && FIFOs are empty + * b) reset has occurred or busfree is detected. + */ + while (n > 0) { + int xfer; + + /* Wait for fifo half full or phase mismatch */ + for (;;) { + /* XXX needs timeout */ + intstat = spc_read(INTS); + sstat = spc_read(SSTS); + if (intstat != 0 || + (sstat & SSTS_DREG_FULL) != 0 || + (sstat & SSTS_DREG_EMPTY) == 0) + break; + } + + if (intstat != 0) + goto phasechange; + + if (sstat & SSTS_DREG_FULL) { + xfer = DINAMOUNT; + n -= xfer; + in += xfer; + while (xfer-- > 0) + *p++ = spc_read(DREG); + } + while (n > 0 && (spc_read(SSTS) & SSTS_DREG_EMPTY) == 0) { + n--; + in++; + *p++ = spc_read(DREG); + } + } + + /* + * Some SCSI-devices are rude enough to transfer more data than what + * was requested, e.g. 2048 bytes from a CD-ROM instead of the + * requested 512. Test for progress, i.e. real transfers. If no real + * transfers have been performed (n is probably already zero) and the + * FIFO is not empty, waste some bytes.... + */ + if (in == 0) { + for (;;) { + /* XXX needs timeout */ + if (spc_read(INTS) != 0) + break; + } + SPC_MISC(("extra data ")); + } + +phasechange: + /* Stop the FIFO data path. */ + + return in; +} + +/* + * Catch an interrupt from the adaptor + */ +/* + * This is the workhorse routine of the driver. + * Deficiencies (for now): + * 1) always uses programmed I/O + */ +int +spc_intr(void *arg) +{ + struct spc_softc *sc = arg; + u_char ints; + + SPC_TRACE(("spc_intr ")); + + /* + * Disable interrupt. + */ + spc_write(SCTL, spc_read(SCTL) & ~SCTL_INTR_ENAB); + + ints = spc_read(INTS); + if (ints != 0) + spc_process_intr(arg, ints); +else printf("spc_intr: 0\n"); + + spc_write(SCTL, spc_read(SCTL) | SCTL_INTR_ENAB); + return 1; +} + +void +spc_process_intr(void *arg, u_char ints) +{ + struct spc_softc *sc = arg; + struct spc_acb *acb; + struct scsi_link *sc_link; + struct spc_tinfo *ti; + int n; + + SPC_TRACE(("spc_process_intr ")); + + if (sc->sc_dma_done != NULL && + sc->sc_state == SPC_CONNECTED && + (sc->sc_flags & SPC_DOINGDMA) != 0 && + (sc->sc_phase == PH_DATAOUT || sc->sc_phase == PH_DATAIN)) { + (*sc->sc_dma_done)(sc); + } + + goto start; + +loop: + /* + * Loop until transfer completion. + */ + /* + * First check for abnormal conditions, such as reset. + */ + ints = spc_read(INTS); +start: + SPC_MISC(("ints = 0x%x ", ints)); + + if ((ints & INTS_RST) != 0) { + printf("%s: SCSI bus reset\n", sc->sc_dev.dv_xname); + goto reset; + } + + /* + * Check for less serious errors. + */ + if ((spc_read(SERR) & (SERR_SCSI_PAR|SERR_SPC_PAR)) + != 0) { + printf("%s: SCSI bus parity error\n", sc->sc_dev.dv_xname); + if (sc->sc_prevphase == PH_MSGIN) { + sc->sc_flags |= SPC_DROP_MSGIN; + spc_sched_msgout(sc, SEND_PARITY_ERROR); + } else + spc_sched_msgout(sc, SEND_INIT_DET_ERR); + } + + /* + * If we're not already busy doing something test for the following + * conditions: + * 1) We have been reselected by something + * 2) We have selected something successfully + * 3) Our selection process has timed out + * 4) This is really a bus free interrupt just to get a new command + * going? + * 5) Spurious interrupt? + */ + switch (sc->sc_state) { + case SPC_IDLE: + case SPC_SELECTING: + SPC_MISC(("ints:0x%02x ", ints)); + + if ((ints & INTS_SEL) != 0) { + /* + * We don't currently support target mode. + */ + printf("%s: target mode selected; going to BUS FREE\n", + sc->sc_dev.dv_xname); + + goto sched; + } else if ((ints & INTS_RESEL) != 0) { + SPC_MISC(("reselected ")); + + /* + * If we're trying to select a target ourselves, + * push our command back into the ready list. + */ + if (sc->sc_state == SPC_SELECTING) { + SPC_MISC(("backoff selector ")); + SPC_ASSERT(sc->sc_nexus != NULL); + acb = sc->sc_nexus; + sc->sc_nexus = NULL; + TAILQ_INSERT_HEAD(&sc->ready_list, acb, chain); + } + + /* Save reselection ID. */ + sc->sc_selid = spc_read(TEMP); + + sc->sc_state = SPC_RESELECTED; + } else if ((ints & INTS_CMD_DONE) != 0) { + SPC_MISC(("selected ")); + + /* + * We have selected a target. Things to do: + * a) Determine what message(s) to send. + * b) Verify that we're still selecting the target. + * c) Mark device as busy. + */ + if (sc->sc_state != SPC_SELECTING) { + printf("%s: selection out while idle; " + "resetting\n", sc->sc_dev.dv_xname); + SPC_BREAK(); + goto reset; + } + SPC_ASSERT(sc->sc_nexus != NULL); + acb = sc->sc_nexus; + sc_link = acb->xs->sc_link; + ti = &sc->sc_tinfo[sc_link->target]; + + sc->sc_msgpriq = SEND_IDENTIFY; + if (acb->flags & ACB_RESET) + sc->sc_msgpriq |= SEND_DEV_RESET; + else if (acb->flags & ACB_ABORT) + sc->sc_msgpriq |= SEND_ABORT; + else { +#if SPC_USE_SYNCHRONOUS + if ((ti->flags & DO_SYNC) != 0) + sc->sc_msgpriq |= SEND_SDTR; +#endif +#if SPC_USE_WIDE + if ((ti->flags & DO_WIDE) != 0) + sc->sc_msgpriq |= SEND_WDTR; +#endif + } + + acb->flags |= ACB_NEXUS; + ti->lubusy |= (1 << sc_link->lun); + + /* Do an implicit RESTORE POINTERS. */ + sc->sc_dp = acb->data_addr; + sc->sc_dleft = acb->data_length; + sc->sc_cp = (u_char *)&acb->scsi_cmd; + sc->sc_cleft = acb->scsi_cmd_length; + + /* On our first connection, schedule a timeout. */ + if ((acb->xs->flags & SCSI_POLL) == 0) { + timeout_set(&acb->xs->stimeout, spc_timeout, + acb); + timeout_add(&acb->xs->stimeout, + (acb->timeout * hz) / 1000); + } + sc->sc_state = SPC_CONNECTED; + } else if ((ints & INTS_TIMEOUT) != 0) { + SPC_MISC(("selection timeout ")); + + if (sc->sc_state != SPC_SELECTING) { + printf("%s: selection timeout while idle; " + "resetting\n", sc->sc_dev.dv_xname); + SPC_BREAK(); + goto reset; + } + SPC_ASSERT(sc->sc_nexus != NULL); + acb = sc->sc_nexus; + + delay(250); + + acb->xs->error = XS_SELTIMEOUT; + goto finish; + } else { + if (sc->sc_state != SPC_IDLE) { + printf("%s: BUS FREE while not idle; " + "state=%d\n", + sc->sc_dev.dv_xname, sc->sc_state); + SPC_BREAK(); + goto out; + } + + goto sched; + } + + /* + * Turn off selection stuff, and prepare to catch bus free + * interrupts, parity errors, and phase changes. + */ + + sc->sc_flags = 0; + sc->sc_prevphase = PH_INVALID; + goto dophase; + } + + if ((ints & INTS_DISCON) != 0) { + /* disable disconnect interrupt */ + spc_write(PCTL, spc_read(PCTL) & ~PCTL_BFINT_ENAB); + /* XXX reset interrput */ + spc_write(INTS, ints); + + switch (sc->sc_state) { + case SPC_RESELECTED: + goto sched; + + case SPC_CONNECTED: + SPC_ASSERT(sc->sc_nexus != NULL); + acb = sc->sc_nexus; + +#if SPC_USE_SYNCHRONOUS + SPC_USE_WIDE + if (sc->sc_prevphase == PH_MSGOUT) { + /* + * If the target went to BUS FREE phase during + * or immediately after sending a SDTR or WDTR + * message, disable negotiation. + */ + sc_link = acb->xs->sc_link; + ti = &sc->sc_tinfo[sc_link->target]; + switch (sc->sc_lastmsg) { +#if SPC_USE_SYNCHRONOUS + case SEND_SDTR: + ti->flags &= ~DO_SYNC; + ti->period = ti->offset = 0; + break; +#endif +#if SPC_USE_WIDE + case SEND_WDTR: + ti->flags &= ~DO_WIDE; + ti->width = 0; + break; +#endif + } + } +#endif + + if ((sc->sc_flags & SPC_ABORTING) == 0) { + /* + * Section 5.1.1 of the SCSI 2 spec suggests + * issuing a REQUEST SENSE following an + * unexpected disconnect. Some devices go into + * a contingent allegiance condition when + * disconnecting, and this is necessary to + * clean up their state. + */ + printf("%s: unexpected disconnect; " + "sending REQUEST SENSE\n", + sc->sc_dev.dv_xname); + SPC_BREAK(); + spc_sense(sc, acb); + goto out; + } + + acb->xs->error = XS_DRIVER_STUFFUP; + goto finish; + + case SPC_DISCONNECT: + SPC_ASSERT(sc->sc_nexus != NULL); + acb = sc->sc_nexus; + TAILQ_INSERT_HEAD(&sc->nexus_list, acb, chain); + sc->sc_nexus = NULL; + goto sched; + + case SPC_CMDCOMPLETE: + SPC_ASSERT(sc->sc_nexus != NULL); + acb = sc->sc_nexus; + goto finish; + } + } + else if ((ints & INTS_CMD_DONE) != 0 && + sc->sc_prevphase == PH_MSGIN && + sc->sc_state != SPC_CONNECTED) + goto out; + +dophase: +#if 0 + if ((spc_read(PSNS) & PSNS_REQ) == 0) { + /* Wait for REQINIT. */ + goto out; + } +#else + spc_write(INTS, ints); + while ((spc_read(PSNS) & PSNS_REQ) == 0) + delay(1); /* need timeout XXX */ +#endif + + /* + * State transition. + */ + sc->sc_phase = spc_read(PSNS) & PH_MASK; +#if 0 + spc_write(PCTL, sc->sc_phase); +#endif + + SPC_MISC(("phase=%d\n", sc->sc_phase)); + switch (sc->sc_phase) { + case PH_MSGOUT: + if (sc->sc_state != SPC_CONNECTED && + sc->sc_state != SPC_RESELECTED) + break; + spc_msgout(sc); + sc->sc_prevphase = PH_MSGOUT; + goto loop; + + case PH_MSGIN: + if (sc->sc_state != SPC_CONNECTED && + sc->sc_state != SPC_RESELECTED) + break; + spc_msgin(sc); + sc->sc_prevphase = PH_MSGIN; + goto loop; + + case PH_CMD: + if (sc->sc_state != SPC_CONNECTED) + break; +#ifdef SPC_DEBUG + if ((spc_debug & SPC_SHOWMISC) != 0) { + SPC_ASSERT(sc->sc_nexus != NULL); + acb = sc->sc_nexus; + printf("cmd=0x%02x+%d ", + acb->scsi_cmd.opcode, acb->scsi_cmd_length - 1); + } +#endif + n = spc_dataout_pio(sc, sc->sc_cp, sc->sc_cleft); + sc->sc_cp += n; + sc->sc_cleft -= n; + sc->sc_prevphase = PH_CMD; + goto loop; + + case PH_DATAOUT: + if (sc->sc_state != SPC_CONNECTED) + break; + SPC_MISC(("dataout dleft=%d ", sc->sc_dleft)); + if (sc->sc_dma_start != NULL && + sc->sc_dleft > SPC_MIN_DMA_LEN) { + (*sc->sc_dma_start)(sc, sc->sc_dp, sc->sc_dleft, 0); + sc->sc_prevphase = PH_DATAOUT; + goto out; + } + n = spc_dataout_pio(sc, sc->sc_dp, sc->sc_dleft); + sc->sc_dp += n; + sc->sc_dleft -= n; + sc->sc_prevphase = PH_DATAOUT; + goto loop; + + case PH_DATAIN: + if (sc->sc_state != SPC_CONNECTED) + break; + SPC_MISC(("datain ")); + if (sc->sc_dma_start != NULL && + sc->sc_dleft > SPC_MIN_DMA_LEN) { + (*sc->sc_dma_start)(sc, sc->sc_dp, sc->sc_dleft, 1); + sc->sc_prevphase = PH_DATAIN; + goto out; + } + n = spc_datain_pio(sc, sc->sc_dp, sc->sc_dleft); + sc->sc_dp += n; + sc->sc_dleft -= n; + sc->sc_prevphase = PH_DATAIN; + goto loop; + + case PH_STAT: + if (sc->sc_state != SPC_CONNECTED) + break; + SPC_ASSERT(sc->sc_nexus != NULL); + acb = sc->sc_nexus; + spc_datain_pio(sc, &acb->target_stat, 1); + + SPC_MISC(("target_stat=0x%02x ", acb->target_stat)); + sc->sc_prevphase = PH_STAT; + goto loop; + } + + printf("%s: unexpected bus phase; resetting\n", sc->sc_dev.dv_xname); + SPC_BREAK(); +reset: + spc_init(sc); + return; + +finish: + timeout_del(&acb->xs->stimeout); + spc_write(INTS, ints); + ints = 0; + spc_done(sc, acb); + return; + +sched: + sc->sc_state = SPC_IDLE; + spc_sched(sc); + goto out; + +out: + if (ints != 0) + spc_write(INTS, ints); +} + +void +spc_abort(struct spc_softc *sc, struct spc_acb *acb) +{ + /* 2 secs for the abort */ + acb->timeout = SPC_ABORT_TIMEOUT; + acb->flags |= ACB_ABORT; + + if (acb == sc->sc_nexus) { + /* + * If we're still selecting, the message will be scheduled + * after selection is complete. + */ + if (sc->sc_state == SPC_CONNECTED) + spc_sched_msgout(sc, SEND_ABORT); + } else { + spc_dequeue(sc, acb); + TAILQ_INSERT_HEAD(&sc->ready_list, acb, chain); + if (sc->sc_state == SPC_IDLE) + spc_sched(sc); + } +} + +void +spc_timeout(void *arg) +{ + struct spc_acb *acb = arg; + struct scsi_xfer *xs = acb->xs; + struct scsi_link *sc_link = xs->sc_link; + struct spc_softc *sc = sc_link->adapter_softc; + int s; + + sc_print_addr(sc_link); + printf("timed out"); + + s = splbio(); + + if (acb->flags & ACB_ABORT) { + /* abort timed out */ + printf(" AGAIN\n"); + /* XXX Must reset! */ + } else { + /* abort the operation that has timed out */ + printf("\n"); + acb->xs->error = XS_TIMEOUT; + spc_abort(sc, acb); + } + + splx(s); +} + +#ifdef SPC_DEBUG +/* + * The following functions are mostly used for debugging purposes, either + * directly called from the driver or from the kernel debugger. + */ + +void +spc_show_scsi_cmd(struct spc_acb *acb) +{ + u_char *b = (u_char *)&acb->scsi_cmd; + struct scsi_link *sc_link = acb->xs->sc_link; + int i; + + sc_print_addr(sc_link); + if ((acb->xs->flags & SCSI_RESET) == 0) { + for (i = 0; i < acb->scsi_cmd_length; i++) { + if (i) + printf(","); + printf("%x", b[i]); + } + printf("\n"); + } else + printf("RESET\n"); +} + +void +spc_print_acb(struct spc_acb *acb) +{ + printf("acb@%p xs=%p flags=%x", acb, acb->xs, acb->flags); + printf(" dp=%p dleft=%d target_stat=%x\n", + acb->data_addr, acb->data_length, acb->target_stat); + spc_show_scsi_cmd(acb); +} + +void +spc_print_active_acb(void) +{ + struct spc_acb *acb; + struct spc_softc *sc = spc_cd.cd_devs[0]; /* XXX */ + + printf("ready list:\n"); + TAILQ_FOREACH(acb, &sc->ready_list, chain) + spc_print_acb(acb); + printf("nexus:\n"); + if (sc->sc_nexus != NULL) + spc_print_acb(sc->sc_nexus); + printf("nexus list:\n"); + TAILQ_FOREACH(acb, &sc->nexus_list, chain) + spc_print_acb(acb); +} + +void +spc_dump89352(struct spc_softc *sc) +{ + printf("mb89352: BDID=%x SCTL=%x SCMD=%x TMOD=%x\n", + spc_read(BDID), spc_read(SCTL), spc_read(SCMD), spc_read(TMOD)); + printf(" INTS=%x PSNS=%x SSTS=%x SERR=%x PCTL=%x\n", + spc_read(INTS), spc_read(PSNS), spc_read(SSTS), spc_read(SERR), + spc_read(PCTL)); + printf(" MBC=%x DREG=%x TEMP=%x TCH=%x TCM=%x\n", + spc_read(MBC), +#if 0 + spc_read(DREG), +#else + 0, +#endif + spc_read(TEMP), spc_read(TCH), spc_read(TCM)); + printf(" TCL=%x EXBF=%x\n", spc_read(TCL), spc_read(EXBF)); +} + +void +spc_dump_driver(struct spc_softc *sc) +{ + struct spc_tinfo *ti; + int i; + + printf("nexus=%p prevphase=%x\n", sc->sc_nexus, sc->sc_prevphase); + printf("state=%x msgin=%x msgpriq=%x msgoutq=%x lastmsg=%x " + "currmsg=%x\n", sc->sc_state, sc->sc_imess[0], + sc->sc_msgpriq, sc->sc_msgoutq, sc->sc_lastmsg, sc->sc_currmsg); + for (i = 0; i < 7; i++) { + ti = &sc->sc_tinfo[i]; + printf("tinfo%d: %d cmds %d disconnects %d timeouts", + i, ti->cmds, ti->dconns, ti->touts); + printf(" %d senses flags=%x\n", ti->senses, ti->flags); + } +} +#endif diff --git a/sys/arch/hp300/dev/mb89352reg.h b/sys/arch/hp300/dev/mb89352reg.h new file mode 100644 index 00000000000..3c24aca2b25 --- /dev/null +++ b/sys/arch/hp300/dev/mb89352reg.h @@ -0,0 +1,238 @@ +/* $OpenBSD: mb89352reg.h,v 1.1 2004/08/03 21:46:56 miod Exp $ */ +/* $NetBSD: mb89352reg.h,v 1.3 2003/08/07 16:31:02 agc Exp $ */ +/* NecBSD: mb89352reg.h,v 1.3 1998/03/14 07:04:34 kmatsuda Exp */ + +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Charles M. Hannum, Masaru Oki and Kouichi Matsuda. + * + * This code is derived from software contributed to Berkeley by + * Van Jacobson of 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. 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. + * + * @(#)scsireg.h 8.1 (Berkeley) 6/10/93 + */ + +/*- + * Copyright (c) 1996,97,98,99 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Charles M. Hannum, Masaru Oki and Kouichi Matsuda. + * + * This code is derived from software contributed to Berkeley by + * Van Jacobson of 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. + * + * @(#)scsireg.h 8.1 (Berkeley) 6/10/93 + */ +/* + * [NetBSD for NEC PC-98 series] + * Copyright (c) 1996, 1997, 1998 + * NetBSD/pc98 porting staff. All rights reserved. + * Copyright (c) 1996, 1997, 1998 + * Kouichi Matsuda. All rights reserved. + */ + +/* + * FUJITSU MB89352A SCSI Protocol Controller Hardware Description. + */ + +/* Definitions, most of them has turned out to be unneccesary, but here they + * are anyway. + */ + +#define BDID 0x00 /* Bus Device ID (R/W) */ +#define SCTL 0x01 /* SPC Control register (R/W) */ +#define SCMD 0x02 /* Command Register (R/W) */ +#define TMOD 0x03 /* Transmit Mode Register (synch models) */ +#define INTS 0x04 /* Interrupt sense (R); Interrupt Reset (W) */ +#define PSNS 0x05 /* Phase Sense (R); SPC Diagnostic Control (W) */ +#define SSTS 0x06 /* SPC status (R/O) */ +#define SERR 0x07 /* SPC error status (R/O) */ +#define PCTL 0x08 /* Phase Control (R/W) */ +#define MBC 0x09 /* Modified Byte Counter (R/O) */ +#define DREG 0x0a /* Data Register (R/W) */ +#define TEMP 0x0b /* Temporary Register (R/W) */ +#define TCH 0x0c /* Transfer Counter High (R/W) */ +#define TCM 0x0d /* Transfer Counter Middle (R/W) */ +#define TCL 0x0e /* Transfer Counter Low (R/W) */ +#define EXBF 0x0f /* External Buffer (synch models) */ + +/* What all the bits do */ + +/* SCSI_BDID */ +/* SCSI selection/reselection ID (both target *and* initiator) */ +#define SELID7 0x80 +#define SELID6 0x40 +#define SELID5 0x20 +#define SELID4 0x10 +#define SELID3 0x08 +#define SELID2 0x04 +#define SELID1 0x02 +#define SELID0 0x01 + +/* SCSI_SCTL */ +#define SCTL_DISABLE 0x80 +#define SCTL_CTRLRST 0x40 +#define SCTL_DIAG 0x20 +#define SCTL_ABRT_ENAB 0x10 +#define SCTL_PARITY_ENAB 0x08 +#define SCTL_SEL_ENAB 0x04 +#define SCTL_RESEL_ENAB 0x02 +#define SCTL_INTR_ENAB 0x01 + +/* SCSI_SCMD */ +#define SCMD_RST 0x10 +#define SCMD_ICPT_XFR 0x08 +#define SCMD_PROG_XFR 0x04 +#define SCMD_PAD 0x01 /* if initiator */ +#define SCMD_PERR_STOP 0x01 /* if target */ + /* command codes */ +#define SCMD_BUS_REL 0x00 +#define SCMD_SELECT 0x20 +#define SCMD_RST_ATN 0x40 +#define SCMD_SET_ATN 0x60 +#define SCMD_XFR 0x80 +#define SCMD_XFR_PAUSE 0xa0 +#define SCMD_RST_ACK 0xc0 +#define SCMD_SET_ACK 0xe0 + +/* SCSI_TMOD */ +#define TMOD_SYNC 0x80 + +/* SCSI_INTS */ +#define INTS_SEL 0x80 +#define INTS_RESEL 0x40 +#define INTS_DISCON 0x20 +#define INTS_CMD_DONE 0x10 +#define INTS_SRV_REQ 0x08 +#define INTS_TIMEOUT 0x04 +#define INTS_HARD_ERR 0x02 +#define INTS_RST 0x01 + +/* SCSI_PSNS */ +#define PSNS_REQ 0x80 +#define PSNS_ACK 0x40 +#define PSNS_ATN 0x20 +#define PSNS_SEL 0x10 +#define PSNS_BSY 0x08 + +/* PSNS */ +#define REQI 0x80 +#define ACKI 0x40 +#define ATNI 0x20 +#define SELI 0x10 +#define BSYI 0x08 +#define MSGI 0x04 +#define CDI 0x02 +#define IOI 0x01 + +/* Important! The 3 most significant bits of this register, in initiator mode, + * represents the "expected" SCSI bus phase and can be used to trigger phase + * mismatch and phase change interrupts. But more important: If there is a + * phase mismatch the chip will not transfer any data! This is actually a nice + * feature as it gives us a bit more control over what is happening when we are + * bursting data (in) through the FIFOs and the phase suddenly changes from + * DATA IN to STATUS or MESSAGE IN. The transfer will stop and wait for the + * proper phase to be set in this register instead of dumping the bits into the + * FIFOs. + */ +#if 0 +#define REQO 0x80 +#define ACKO 0x40 +#define ATNO 0x20 +#define SELO 0x10 +#define BSYO 0x08 +#endif +/* PCTL */ +#define MSGO 0x04 +#define CDO 0x02 +#define IOO 0x01 + +/* Information transfer phases */ +#define PH_DATAOUT (0) +#define PH_DATAIN (IOI) +#define PH_CMD (CDI) +#define PH_STAT (CDI | IOI) +#define PH_MSGOUT (MSGI | CDI) +#define PH_MSGIN (MSGI | CDI | IOI) + +#define PH_MASK (MSGI | CDI | IOI) + +#define PH_INVALID 0xff + +/* SCSI_SSTS */ +#define SSTS_INITIATOR 0x80 +#define SSTS_TARGET 0x40 +#define SSTS_BUSY 0x20 +#define SSTS_XFR 0x10 +#define SSTS_ACTIVE (SSTS_INITIATOR|SSTS_XFR) +#define SSTS_RST 0x08 +#define SSTS_TCZERO 0x04 +#define SSTS_DREG_FULL 0x02 +#define SSTS_DREG_EMPTY 0x01 + +/* SCSI_SERR */ +#define SERR_SCSI_PAR 0x80 +#define SERR_SPC_PAR 0x40 +#define SERR_TC_PAR 0x08 +#define SERR_PHASE_ERR 0x04 +#define SERR_SHORT_XFR 0x02 +#define SERR_OFFSET 0x01 + +/* SCSI_PCTL */ +#define PCTL_BFINT_ENAB 0x80 diff --git a/sys/arch/hp300/dev/mb89352var.h b/sys/arch/hp300/dev/mb89352var.h new file mode 100644 index 00000000000..2cbd8df450d --- /dev/null +++ b/sys/arch/hp300/dev/mb89352var.h @@ -0,0 +1,217 @@ +/* $OpenBSD: mb89352var.h,v 1.1 2004/08/03 21:46:56 miod Exp $ */ +/* $NetBSD: mb89352var.h,v 1.6 2003/08/02 12:48:09 tsutsui Exp $ */ +/* NecBSD: mb89352var.h,v 1.4 1998/03/14 07:31:22 kmatsuda Exp */ + +/*- + * Copyright (c) 1996,97,98,99 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Charles M. Hannum, Masaru Oki and Kouichi Matsuda. + * + * 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 Charles M. Hannum. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Copyright (c) 1994 Jarle Greipsland + * All rights reserved. + * + * 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. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ +/* + * [NetBSD for NEC PC-98 series] + * Copyright (c) 1996, 1997, 1998 + * NetBSD/pc98 porting staff. All rights reserved. + * Copyright (c) 1996, 1997, 1998 + * Kouich Matsuda. All rights reserved. + */ + +#ifndef _MB89352VAR_H_ +#define _MB89352VAR_H_ + +/* + * ACB. Holds additional information for each SCSI command Comments: We + * need a separate scsi command block because we may need to overwrite it + * with a request sense command. Basicly, we refrain from fiddling with + * the scsi_xfer struct (except do the expected updating of return values). + * We'll generally update: xs->{flags,resid,error,sense,status} and + * occasionally xs->retries. + */ +struct spc_acb { + struct scsi_generic scsi_cmd; + int scsi_cmd_length; + u_char *data_addr; /* Saved data pointer */ + int data_length; /* Residue */ + + u_char target_stat; /* SCSI status byte */ + +#ifdef notdef + struct spc_dma_seg dma[SPC_NSEG]; /* Physical addresses+len */ +#endif + + TAILQ_ENTRY(spc_acb) chain; + struct scsi_xfer *xs; /* SCSI xfer ctrl block from above */ + int flags; +#define ACB_ALLOC 0x01 +#define ACB_NEXUS 0x02 +#define ACB_SENSE 0x04 +#define ACB_ABORT 0x40 +#define ACB_RESET 0x80 + int timeout; +}; + +/* + * Some info about each (possible) target on the SCSI bus. This should + * probably have been a "per target+lunit" structure, but we'll leave it at + * this for now. + */ +struct spc_tinfo { + int cmds; /* #commands processed */ + int dconns; /* #disconnects */ + int touts; /* #timeouts */ + int perrs; /* #parity errors */ + int senses; /* #request sense commands sent */ + ushort lubusy; /* What local units/subr. are busy? */ + u_char flags; +#define DO_SYNC 0x01 /* (Re)Negotiate synchronous options */ +#define DO_WIDE 0x02 /* (Re)Negotiate wide options */ + u_char period; /* Period suggestion */ + u_char offset; /* Offset suggestion */ + u_char width; /* Width suggestion */ +}; + +struct spc_softc { + struct device sc_dev; + + volatile u_int8_t *sc_regs; + + struct scsi_link sc_link; /* prototype for subdevs */ + + TAILQ_HEAD(, spc_acb) free_list, ready_list, nexus_list; + struct spc_acb *sc_nexus; /* current command */ + struct spc_acb sc_acb[8]; + struct spc_tinfo sc_tinfo[8]; + + /* Data about the current nexus (updated for every cmd switch) */ + u_char *sc_dp; /* Current data pointer */ + size_t sc_dleft; /* Data bytes left to transfer */ + u_char *sc_cp; /* Current command pointer */ + size_t sc_cleft; /* Command bytes left to transfer */ + + /* Adapter state */ + u_char sc_phase; /* Current bus phase */ + u_char sc_prevphase; /* Previous bus phase */ + u_char sc_state; /* State applicable to the adapter */ +#define SPC_INIT 0 +#define SPC_IDLE 1 +#define SPC_SELECTING 2 /* SCSI command is arbiting */ +#define SPC_RESELECTED 3 /* Has been reselected */ +#define SPC_CONNECTED 4 /* Actively using the SCSI bus */ +#define SPC_DISCONNECT 5 /* MSG_DISCONNECT received */ +#define SPC_CMDCOMPLETE 6 /* MSG_CMDCOMPLETE received */ +#define SPC_CLEANING 7 + u_char sc_flags; +#define SPC_DROP_MSGIN 0x01 /* Discard all msgs (parity err detected) */ +#define SPC_ABORTING 0x02 /* Bailing out */ +#define SPC_DOINGDMA 0x04 /* doing DMA */ +#define SPC_INACTIVE 0x80 /* The FIFO data path is active! */ + u_char sc_selid; /* Reselection ID */ + + /* Message stuff */ + u_char sc_msgpriq; /* Messages we want to send */ + u_char sc_msgoutq; /* Messages sent during last MESSAGE OUT */ + u_char sc_lastmsg; /* Message last transmitted */ + u_char sc_currmsg; /* Message currently ready to transmit */ +#define SEND_DEV_RESET 0x01 +#define SEND_PARITY_ERROR 0x02 +#define SEND_INIT_DET_ERR 0x04 +#define SEND_REJECT 0x08 +#define SEND_IDENTIFY 0x10 +#define SEND_ABORT 0x20 +#define SEND_SDTR 0x40 +#define SEND_WDTR 0x80 +#define SPC_MAX_MSG_LEN 8 + u_char sc_omess[SPC_MAX_MSG_LEN]; + u_char *sc_omp; /* Outgoing message pointer */ + u_char sc_imess[SPC_MAX_MSG_LEN]; + u_char *sc_imp; /* Incoming message pointer */ + + /* Hardware stuff */ + int sc_initiator; /* Our scsi id */ + int sc_freq; /* Clock frequency in MHz */ + int sc_minsync; /* Minimum sync period / 4 */ + int sc_maxsync; /* Maximum sync period / 4 */ + + /* DMA function set from MD code */ + void (*sc_dma_start)(struct spc_softc *, void *, size_t, int); + void (*sc_dma_done)(struct spc_softc *); +}; + +#ifdef SPC_DEBUG +#define SPC_SHOWACBS 0x01 +#define SPC_SHOWINTS 0x02 +#define SPC_SHOWCMDS 0x04 +#define SPC_SHOWMISC 0x08 +#define SPC_SHOWTRACE 0x10 +#define SPC_SHOWSTART 0x20 +#define SPC_DOBREAK 0x40 +extern int spc_debug; /* SPC_SHOWSTART|SPC_SHOWMISC|SPC_SHOWTRACE; */ +#define SPC_PRINT(b, s) do {if ((spc_debug & (b)) != 0) printf s;} while (0) +#define SPC_BREAK() do {if ((spc_debug & SPC_DOBREAK) != 0) Debugger();} while (0) +#define SPC_ASSERT(x) do {if (x) {} else {printf("%s at line %d: assertion failed\n", sc->sc_dev.dv_xname, __LINE__); Debugger();}} while (0) +#else +#define SPC_PRINT(b, s) +#define SPC_BREAK() +#define SPC_ASSERT(x) +#endif + +#define SPC_ACBS(s) SPC_PRINT(SPC_SHOWACBS, s) +#define SPC_INTS(s) SPC_PRINT(SPC_SHOWINTS, s) +#define SPC_CMDS(s) SPC_PRINT(SPC_SHOWCMDS, s) +#define SPC_MISC(s) SPC_PRINT(SPC_SHOWMISC, s) +#define SPC_TRACE(s) SPC_PRINT(SPC_SHOWTRACE, s) +#define SPC_START(s) SPC_PRINT(SPC_SHOWSTART, s) + +void spc_attach(struct spc_softc *); +int spc_intr(void *); +void spc_init(struct spc_softc *); +void spc_sched(struct spc_softc *); +int spc_scsi_cmd(struct scsi_xfer *); +void spc_minphys(struct buf *); + +#define SPC_ADDRESS(o) (sc->sc_regs + ((o) << 1) + 1) +#define spc_read(o) *(volatile u_int8_t *)(SPC_ADDRESS(o)) +#define spc_write(o, v) *(volatile u_int8_t *)(SPC_ADDRESS(o)) = (v) + +#endif /* _MB89352VAR_H_ */ diff --git a/sys/arch/hp300/dev/scsi.c b/sys/arch/hp300/dev/scsi.c deleted file mode 100644 index 2492ba758d0..00000000000 --- a/sys/arch/hp300/dev/scsi.c +++ /dev/null @@ -1,1541 +0,0 @@ -/* $OpenBSD: scsi.c,v 1.16 2003/10/26 15:07:25 jmc Exp $ */ -/* $NetBSD: scsi.c,v 1.21 1997/05/05 21:08:26 thorpej Exp $ */ - -/* - * Copyright (c) 1996, 1997 Jason R. Thorpe. All rights reserved. - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Van Jacobson of 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. 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.c 8.2 (Berkeley) 1/12/94 - */ - -/* - * HP 9000/3xx 98658 SCSI host adaptor driver. - */ - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/buf.h> -#include <sys/device.h> - -#include <machine/autoconf.h> -#include <machine/cpu.h> -#include <machine/intr.h> -#include <machine/hp300spu.h> - -#include <hp300/dev/dioreg.h> -#include <hp300/dev/diovar.h> -#include <hp300/dev/diodevs.h> - -#include <hp300/dev/dmavar.h> - -#include <hp300/dev/scsireg.h> -#include <hp300/dev/scsivar.h> - -struct scsi_softc { - struct device sc_dev; /* generic device glue */ - volatile struct scsidevice *sc_regs; /* card registers */ - struct dmaqueue sc_dq; /* our entry in DMA job queue */ - TAILQ_HEAD(, scsiqueue) sc_queue; /* job queue */ - u_char sc_flags; - u_char sc_sync; - u_char sc_scsi_addr; - u_char sc_scsiid; /* XXX unencoded copy of sc_scsi_addr */ - u_char sc_stat[2]; - u_char sc_msg[7]; -}; - -/* sc_flags */ -#define SCSI_IO 0x80 /* DMA I/O in progress */ -#define SCSI_DMA32 0x40 /* 32-bit DMA should be used */ -#define SCSI_HAVEDMA 0x04 /* controller has DMA channel */ -#ifdef DEBUG -#define SCSI_PAD 0x02 /* 'padded' transfer in progress */ -#endif -#define SCSI_ALIVE 0x01 /* controller initialized */ - -/* - * SCSI delays - * In u-seconds, primarily for state changes on the SPC. - */ -#define SCSI_CMD_WAIT 10000 /* wait per step of 'immediate' cmds */ -#define SCSI_DATA_WAIT 10000 /* wait per data in/out step */ -#define SCSI_INIT_WAIT 50000 /* wait per step (both) during init */ - -static void scsiabort(int, struct scsi_softc *, - volatile struct scsidevice *, char *); -static void scsierror(struct scsi_softc *, - volatile struct scsidevice *, u_char); -static int issue_select(volatile struct scsidevice *, - u_char, u_char); -static int wait_for_select(volatile struct scsidevice *); -static int ixfer_start(volatile struct scsidevice *, - int, u_char, int); -static int ixfer_out(volatile struct scsidevice *, int, u_char *); -static void ixfer_in(volatile struct scsidevice *, int, u_char *); -static int mxfer_in(volatile struct scsidevice *, - int, u_char *, u_char); -static int scsiicmd(struct scsi_softc *, int, u_char *, int, - u_char *, int, u_char); -static void finishxfer(struct scsi_softc *, - volatile struct scsidevice *, int); - -int scsimatch(struct device *, void *, void *); -void scsiattach(struct device *, struct device *, void *); -void scsi_attach_children(struct scsi_softc *); -int scsisubmatch(struct device *, void *, void *); - -struct cfattach oscsi_ca = { - sizeof(struct scsi_softc), scsimatch, scsiattach -}; - -struct cfdriver oscsi_cd = { - NULL, "oscsi", DV_DULL -}; - -int scsi_cmd_wait = SCSI_CMD_WAIT; -int scsi_data_wait = SCSI_DATA_WAIT; -int scsi_init_wait = SCSI_INIT_WAIT; - -int scsi_nosync = 1; /* inhibit sync xfers if 1 */ -int scsi_pridma = 0; /* use "priority" dma */ - -#ifdef DEBUG -int scsi_debug = 0; -#define WAITHIST -#endif - -#ifdef WAITHIST -#define MAXWAIT 1022 -u_int ixstart_wait[MAXWAIT+2]; -u_int ixin_wait[MAXWAIT+2]; -u_int ixout_wait[MAXWAIT+2]; -u_int mxin_wait[MAXWAIT+2]; -u_int mxin2_wait[MAXWAIT+2]; -u_int cxin_wait[MAXWAIT+2]; -u_int fxfr_wait[MAXWAIT+2]; -u_int sgo_wait[MAXWAIT+2]; -#define HIST(h,w) (++h[((w)>MAXWAIT? MAXWAIT : ((w) < 0 ? -1 : (w))) + 1]); -#else -#define HIST(h,w) -#endif - -#define b_cylin b_resid - -static void -scsiabort(target, hs, hd, where) - int target; - struct scsi_softc *hs; - volatile struct scsidevice *hd; - char *where; -{ - int len; - int maxtries; /* XXX - kludge till I understand whats *supposed* to happen */ - int startlen; /* XXX - kludge till I understand whats *supposed* to happen */ - u_char junk; - - printf("%s: ", hs->sc_dev.dv_xname); - if (target != -1) - printf("targ %d ", target); - printf("abort from %s: phase=0x%x, ssts=0x%x, ints=0x%x\n", - where, hd->scsi_psns, hd->scsi_ssts, hd->scsi_ints); - - hd->scsi_ints = hd->scsi_ints; - hd->scsi_csr = 0; - if (hd->scsi_psns == 0 || (hd->scsi_ssts & SSTS_INITIATOR) == 0) - /* no longer connected to scsi target */ - return; - - /* get the number of bytes remaining in current xfer + fudge */ - len = (hd->scsi_tch << 16) | (hd->scsi_tcm << 8) | hd->scsi_tcl; - - /* for that many bus cycles, try to send an abort msg */ - for (startlen = (len += 1024); (hd->scsi_ssts & SSTS_INITIATOR) && --len >= 0; ) { - hd->scsi_scmd = SCMD_SET_ATN; - maxtries = 1000; - while ((hd->scsi_psns & PSNS_REQ) == 0) { - if (! (hd->scsi_ssts & SSTS_INITIATOR)) - goto out; - DELAY(1); - if (--maxtries == 0) { - printf("-- scsiabort gave up after 1000 tries (startlen = %d len = %d)\n", - startlen, len); - goto out2; - } - - } -out2: - if ((hd->scsi_psns & PHASE) == MESG_OUT_PHASE) - hd->scsi_scmd = SCMD_RST_ATN; - hd->scsi_pctl = hd->scsi_psns & PHASE; - if (hd->scsi_psns & PHASE_IO) { - /* one of the input phases - read & discard a byte */ - hd->scsi_scmd = SCMD_SET_ACK; - if (hd->scsi_tmod == 0) - while (hd->scsi_psns & PSNS_REQ) - DELAY(1); - junk = hd->scsi_temp; - } else { - /* one of the output phases - send an abort msg */ - hd->scsi_temp = MSG_ABORT; - hd->scsi_scmd = SCMD_SET_ACK; - if (hd->scsi_tmod == 0) - while (hd->scsi_psns & PSNS_REQ) - DELAY(1); - } - hd->scsi_scmd = SCMD_RST_ACK; - } -out: - /* - * Either the abort was successful & the bus is disconnected or - * the device didn't listen. If the latter, announce the problem. - * Either way, reset the card & the SPC. - */ - if (len < 0 && hs) - printf("%s: abort failed. phase=0x%x, ssts=0x%x\n", - hs->sc_dev.dv_xname, hd->scsi_psns, hd->scsi_ssts); - - if (! ((junk = hd->scsi_ints) & INTS_RESEL)) { - hd->scsi_sctl |= SCTL_CTRLRST; - DELAY(2); - hd->scsi_sctl &=~ SCTL_CTRLRST; - hd->scsi_hconf = 0; - hd->scsi_ints = hd->scsi_ints; - } -} - -/* - * XXX Set/reset long delays. - * - * if delay == 0, reset default delays - * if delay < 0, set both delays to default long initialization values - * if delay > 0, set both delays to this value - * - * Used when a devices is expected to respond slowly (e.g. during - * initialization). - */ -void -scsi_delay(delay) - int delay; -{ - static int saved_cmd_wait, saved_data_wait; - - if (delay) { - saved_cmd_wait = scsi_cmd_wait; - saved_data_wait = scsi_data_wait; - if (delay > 0) - scsi_cmd_wait = scsi_data_wait = delay; - else - scsi_cmd_wait = scsi_data_wait = scsi_init_wait; - } else { - scsi_cmd_wait = saved_cmd_wait; - scsi_data_wait = saved_data_wait; - } -} - -int -scsimatch(parent, match, aux) - struct device *parent; - void *match, *aux; -{ - struct dio_attach_args *da = aux; - - switch (da->da_id) { - case DIO_DEVICE_ID_SCSI0: - case DIO_DEVICE_ID_SCSI1: - case DIO_DEVICE_ID_SCSI2: - case DIO_DEVICE_ID_SCSI3: - return (1); - } - - return (0); -} - -void -scsiattach(parent, self, aux) - struct device *parent, *self; - void *aux; -{ - struct scsi_softc *hs = (struct scsi_softc *)self; - struct dio_attach_args *da = aux; - struct scsidevice *hd; - int ipl, unit = self->dv_unit; - - /* - * Set up DMA job queue entry. - */ - hs->sc_dq.dq_softc = hs; - hs->sc_dq.dq_start = scsistart; - hs->sc_dq.dq_done = scsidone; - - /* Initialize request queue. */ - TAILQ_INIT(&hs->sc_queue); - - /* Map the device. */ - hd = (struct scsidevice *)iomap(dio_scodetopa(da->da_scode), - da->da_size); - if (hd == NULL) { - printf("\n%s: can't map registers\n", self->dv_xname); - return; - } - ipl = DIO_IPL(hd); - - printf(" ipl %d", ipl); - - hs->sc_regs = hd; - - /* Establish the interrupt handler. */ - (void) dio_intr_establish(scsiintr, hs, ipl, IPL_BIO); - - /* Reset the controller. */ - scsireset(unit); - - /* - * Print information about what we've found. - */ - printf(":"); - if (hs->sc_flags & SCSI_DMA32) - printf(" 32 bit dma, "); - - switch (hs->sc_sync) { - case 0: - printf("async"); - break; - - case (TMOD_SYNC | 0x3e): - printf("250ns sync"); - break; - - case (TMOD_SYNC | 0x5e): - printf("375ns sync"); - break; - - case (TMOD_SYNC | 0x7d): - printf("500ns sync"); - break; - - default: - panic("scsiattach: unknown sync param 0x%x", hs->sc_sync); - } - - if ((hd->scsi_hconf & HCONF_PARITY) == 0) - printf(", no parity"); - - printf(", scsi id %d\n", hs->sc_scsiid); - - /* - * XXX scale initialization wait according to CPU speed. - * Should we do this for all wait? Should we do this at all? - */ - scsi_init_wait *= (cpuspeed / 8); - - /* - * Find and attach devices on the SCSI bus. - */ - scsi_attach_children(hs); -} - -void -scsi_attach_children(sc) - struct scsi_softc *sc; -{ - struct oscsi_attach_args osa; - struct scsi_inquiry inqbuf; - int target, lun; - - /* - * Look for devices on the SCSI bus. - */ - - for (target = 0; target < 8; target++) { - /* Skip target used by controller. */ - if (target == sc->sc_scsiid) - continue; - - for (lun = 0; lun < 1 /* XXX */; lun++) { - bzero(&inqbuf, sizeof(inqbuf)); - if (scsi_probe_device(sc->sc_dev.dv_unit, - target, lun, &inqbuf, sizeof(inqbuf))) { - /* - * XXX First command on some tapes - * XXX always fails. (Or, at least, - * XXX that's what the old Utah "st" - * XXX driver claimed.) - */ - bzero(&inqbuf, sizeof(inqbuf)); - if (scsi_probe_device(sc->sc_dev.dv_unit, - target, lun, &inqbuf, sizeof(inqbuf))) - continue; - } - - /* - * There is a device here; find a driver - * to match it. - */ - osa.osa_target = target; - osa.osa_lun = lun; - osa.osa_inqbuf = &inqbuf; - (void)config_found_sm(&sc->sc_dev, &osa, - scsi_print, scsisubmatch); - } - } -} - -int -scsisubmatch(parent, match, aux) - struct device *parent; - void *match, *aux; -{ - struct cfdata *cf = match; - struct oscsi_attach_args *osa = aux; - - if (cf->cf_loc[0] != -1 && - cf->cf_loc[0] != osa->osa_target) - return (0); - - if (cf->cf_loc[1] != -1 && - cf->cf_loc[1] != osa->osa_lun) - return (0); - - return ((*cf->cf_attach->ca_match)(parent, match, aux)); -} - -int -scsi_print(aux, pnp) - void *aux; - const char *pnp; -{ - struct oscsi_attach_args *osa = aux; - struct scsi_inquiry *inqbuf = osa->osa_inqbuf; - char vendor[9], product[17], revision[5]; - - if (pnp == NULL) - printf(" targ %d lun %d: ", osa->osa_target, osa->osa_lun); - - bzero(vendor, sizeof(vendor)); - bzero(product, sizeof(product)); - bzero(revision, sizeof(revision)); - switch (inqbuf->version) { - case 1: - case 2: - scsi_str(inqbuf->vendor_id, vendor, sizeof(inqbuf->vendor_id)); - scsi_str(inqbuf->product_id, product, - sizeof(inqbuf->product_id)); - scsi_str(inqbuf->rev, revision, sizeof(inqbuf->rev)); - printf("<%s, %s, %s>", vendor, product, revision); - if (inqbuf->version == 2) - printf(" (SCSI-2)"); - break; - default: - printf("type 0x%x, qual 0x%x, ver %d", - inqbuf->type, inqbuf->qual, inqbuf->version); - } - if (pnp != NULL) - printf(" at %s targ %d lun %d", - pnp, osa->osa_target, osa->osa_lun); - - return (UNCONF); -} - -void -scsireset(unit) - int unit; -{ - struct scsi_softc *hs = oscsi_cd.cd_devs[unit]; - volatile struct scsidevice *hd = hs->sc_regs; - u_int i; - - if (hs->sc_flags & SCSI_ALIVE) - scsiabort(-1, hs, hd, "reset"); - - hd->scsi_id = 0xFF; - DELAY(100); - /* - * Disable interrupts then reset the FUJI chip. - */ - hd->scsi_csr = 0; - hd->scsi_sctl = SCTL_DISABLE | SCTL_CTRLRST; - hd->scsi_scmd = 0; - hd->scsi_tmod = 0; - hd->scsi_pctl = 0; - hd->scsi_temp = 0; - hd->scsi_tch = 0; - hd->scsi_tcm = 0; - hd->scsi_tcl = 0; - hd->scsi_ints = 0; - - if ((hd->scsi_id & ID_WORD_DMA) == 0) - hs->sc_flags |= SCSI_DMA32; - - /* Determine Max Synchronous Transfer Rate */ - if (scsi_nosync) - i = 3; - else - i = SCSI_SYNC_XFER(hd->scsi_hconf); - switch (i) { - case 0: - hs->sc_sync = TMOD_SYNC | 0x3e; /* 250 nsecs */ - break; - case 1: - hs->sc_sync = TMOD_SYNC | 0x5e; /* 375 nsecs */ - break; - case 2: - hs->sc_sync = TMOD_SYNC | 0x7d; /* 500 nsecs */ - break; - case 3: - hs->sc_sync = 0; - break; - } - - /* - * Configure the FUJI chip with its SCSI address, all - * interrupts enabled & appropriate parity. - */ - i = (~hd->scsi_hconf) & 0x7; - hs->sc_scsi_addr = 1 << i; - hd->scsi_bdid = i; - hs->sc_scsiid = i; - if (hd->scsi_hconf & HCONF_PARITY) - hd->scsi_sctl = SCTL_DISABLE | SCTL_ABRT_ENAB | - SCTL_SEL_ENAB | SCTL_RESEL_ENAB | - SCTL_INTR_ENAB | SCTL_PARITY_ENAB; - else - hd->scsi_sctl = SCTL_DISABLE | SCTL_ABRT_ENAB | - SCTL_SEL_ENAB | SCTL_RESEL_ENAB | - SCTL_INTR_ENAB; - - hd->scsi_sctl &=~ SCTL_DISABLE; - hs->sc_flags |= SCSI_ALIVE; -} - -static void -scsierror(hs, hd, ints) - struct scsi_softc *hs; - volatile struct scsidevice *hd; - u_char ints; -{ - char *sep = ""; - - printf("%s: ", hs->sc_dev.dv_xname); - if (ints & INTS_RST) { - DELAY(100); - if (hd->scsi_hconf & HCONF_SD) - printf("spurious RST interrupt"); - else - printf("hardware error - check fuse"); - sep = ", "; - } - if ((ints & INTS_HARD_ERR) || hd->scsi_serr) { - if (hd->scsi_serr & SERR_SCSI_PAR) { - printf("%sparity err", sep); - sep = ", "; - } - if (hd->scsi_serr & SERR_SPC_PAR) { - printf("%sSPC parity err", sep); - sep = ", "; - } - if (hd->scsi_serr & SERR_TC_PAR) { - printf("%sTC parity err", sep); - sep = ", "; - } - if (hd->scsi_serr & SERR_PHASE_ERR) { - printf("%sphase err", sep); - sep = ", "; - } - if (hd->scsi_serr & SERR_SHORT_XFR) { - printf("%ssync short transfer err", sep); - sep = ", "; - } - if (hd->scsi_serr & SERR_OFFSET) { - printf("%ssync offset error", sep); - sep = ", "; - } - } - if (ints & INTS_TIMEOUT) - printf("%sSPC select timeout error", sep); - if (ints & INTS_SRV_REQ) - printf("%sspurious SRV_REQ interrupt", sep); - if (ints & INTS_CMD_DONE) - printf("%sspurious CMD_DONE interrupt", sep); - if (ints & INTS_DISCON) - printf("%sspurious disconnect interrupt", sep); - if (ints & INTS_RESEL) - printf("%sspurious reselect interrupt", sep); - if (ints & INTS_SEL) - printf("%sspurious select interrupt", sep); - printf("\n"); -} - -static int -issue_select(hd, target, our_addr) - volatile struct scsidevice *hd; - u_char target, our_addr; -{ - if (hd->scsi_ssts & (SSTS_INITIATOR|SSTS_TARGET|SSTS_BUSY)) - return (1); - - if (hd->scsi_ints & INTS_DISCON) - hd->scsi_ints = INTS_DISCON; - - hd->scsi_pctl = 0; - hd->scsi_temp = (1 << target) | our_addr; - /* select timeout is hardcoded to 2ms */ - hd->scsi_tch = 15; - hd->scsi_tcm = 32; - hd->scsi_tcl = 4; - - hd->scsi_scmd = SCMD_SELECT; - return (0); -} - -static int -wait_for_select(hd) - volatile struct scsidevice *hd; -{ - u_char ints; - - while ((ints = hd->scsi_ints) == 0) - DELAY(1); - hd->scsi_ints = ints; - return (!(hd->scsi_ssts & SSTS_INITIATOR)); -} - -static int -ixfer_start(hd, len, phase, wait) - volatile struct scsidevice *hd; - int len; - u_char phase; - int wait; -{ - - hd->scsi_tch = len >> 16; - hd->scsi_tcm = len >> 8; - hd->scsi_tcl = len; - hd->scsi_pctl = phase; - hd->scsi_tmod = 0; /*XXX*/ - hd->scsi_scmd = SCMD_XFR | SCMD_PROG_XFR; - - /* wait for xfer to start or svc_req interrupt */ - while ((hd->scsi_ssts & SSTS_BUSY) == 0) { - if (hd->scsi_ints || --wait < 0) { -#ifdef DEBUG - if (scsi_debug) - printf("ixfer_start fail: i%x, w%d\n", - hd->scsi_ints, wait); -#endif - HIST(ixstart_wait, wait) - return (0); - } - DELAY(1); - } - HIST(ixstart_wait, wait) - return (1); -} - -static int -ixfer_out(hd, len, buf) - volatile struct scsidevice *hd; - int len; - u_char *buf; -{ - int wait = scsi_data_wait; - - for (; len > 0; --len) { - while (hd->scsi_ssts & SSTS_DREG_FULL) { - if (hd->scsi_ints || --wait < 0) { -#ifdef DEBUG - if (scsi_debug) - printf("ixfer_out fail: l%d i%x w%d\n", - len, hd->scsi_ints, wait); -#endif - HIST(ixout_wait, wait) - return (len); - } - DELAY(1); - } - hd->scsi_dreg = *buf++; - } - HIST(ixout_wait, wait) - return (0); -} - -static void -ixfer_in(hd, len, buf) - volatile struct scsidevice *hd; - int len; - u_char *buf; -{ - int wait = scsi_data_wait; - - for (; len > 0; --len) { - while (hd->scsi_ssts & SSTS_DREG_EMPTY) { - if (hd->scsi_ints || --wait < 0) { - while (! (hd->scsi_ssts & SSTS_DREG_EMPTY)) { - *buf++ = hd->scsi_dreg; - --len; - } -#ifdef DEBUG - if (scsi_debug) - printf("ixfer_in fail: l%d i%x w%d\n", - len, hd->scsi_ints, wait); -#endif - HIST(ixin_wait, wait) - return; - } - DELAY(1); - } - *buf++ = hd->scsi_dreg; - } - HIST(ixin_wait, wait) -} - -static int -mxfer_in(hd, len, buf, phase) - volatile struct scsidevice *hd; - int len; - u_char *buf; - u_char phase; -{ - int wait = scsi_cmd_wait; - int i; - - hd->scsi_tmod = 0; - for (i = 0; i < len; ++i) { - /* - * manual says: reset ATN before ACK is sent. - */ - if (hd->scsi_psns & PSNS_ATN) - hd->scsi_scmd = SCMD_RST_ATN; - /* - * wait for the request line (which says the target - * wants to give us data). If the phase changes while - * we're waiting, we're done. - */ - while ((hd->scsi_psns & PSNS_REQ) == 0) { - if (--wait < 0) { - HIST(mxin_wait, wait) - return (-1); - } - if ((hd->scsi_psns & PHASE) != phase || - (hd->scsi_ssts & SSTS_INITIATOR) == 0) - goto out; - - DELAY(1); - } - /* - * set ack (which says we're ready for the data, wait for - * req to go away (target says data is available), grab the - * data, then reset ack (say we've got the data). - */ - hd->scsi_pctl = phase; - hd->scsi_scmd = SCMD_SET_ACK; - while (hd->scsi_psns & PSNS_REQ) { - if (--wait < 0) { - HIST(mxin_wait, wait) - return (-2); - } - DELAY(1); - } - *buf++ = hd->scsi_temp; - hd->scsi_scmd = SCMD_RST_ACK; - } -out: - HIST(mxin_wait, wait) - /* - * Wait for manual transfer to finish. - * Avoids occasional "unexpected phase" errors in finishxfer - * formerly addressed by per-slave delays. - */ - wait = scsi_cmd_wait; - while ((hd->scsi_ssts & SSTS_ACTIVE) == SSTS_INITIATOR) { - if (--wait < 0) - break; - DELAY(1); - } - HIST(mxin2_wait, wait) - return (i); -} - -/* - * SCSI 'immediate' command: issue a command to some SCSI device - * and get back an 'immediate' response (i.e., do programmed xfer - * to get the response data). 'cbuf' is a buffer containing a scsi - * command of length clen bytes. 'buf' is a buffer of length 'len' - * bytes for data. The transfer direction is determined by the device - * (i.e., by the scsi bus data xfer phase). If 'len' is zero, the - * command must supply no data. 'xferphase' is the bus phase the - * caller expects to happen after the command is issued. It should - * be one of DATA_IN_PHASE, DATA_OUT_PHASE or STATUS_PHASE. - */ -static int -scsiicmd(hs, target, cbuf, clen, buf, len, xferphase) - struct scsi_softc *hs; - int target; - u_char *cbuf; - int clen; - u_char *buf; - int len; - u_char xferphase; -{ - volatile struct scsidevice *hd = hs->sc_regs; - u_char phase, ints; - int wait; - - /* select the SCSI bus (it's an error if bus isn't free) */ - if (issue_select(hd, target, hs->sc_scsi_addr)) - return (-1); - if (wait_for_select(hd)) - return (-1); - /* - * Wait for a phase change (or error) then let the device - * sequence us through the various SCSI phases. - */ - hs->sc_stat[0] = 0xff; - hs->sc_msg[0] = 0xff; - phase = CMD_PHASE; - while (1) { - wait = scsi_cmd_wait; - switch (phase) { - - case CMD_PHASE: - if (ixfer_start(hd, clen, phase, wait)) - if (ixfer_out(hd, clen, cbuf)) - goto abort; - phase = xferphase; - break; - - case DATA_IN_PHASE: - if (len <= 0) - goto abort; - wait = scsi_data_wait; - if (ixfer_start(hd, len, phase, wait) || - !(hd->scsi_ssts & SSTS_DREG_EMPTY)) - ixfer_in(hd, len, buf); - phase = STATUS_PHASE; - break; - - case DATA_OUT_PHASE: - if (len <= 0) - goto abort; - wait = scsi_data_wait; - if (ixfer_start(hd, len, phase, wait)) { - if (ixfer_out(hd, len, buf)) - goto abort; - } - phase = STATUS_PHASE; - break; - - case STATUS_PHASE: - wait = scsi_data_wait; - if (ixfer_start(hd, sizeof(hs->sc_stat), phase, wait) || - !(hd->scsi_ssts & SSTS_DREG_EMPTY)) - ixfer_in(hd, sizeof(hs->sc_stat), hs->sc_stat); - phase = MESG_IN_PHASE; - break; - - case MESG_IN_PHASE: - if (ixfer_start(hd, sizeof(hs->sc_msg), phase, wait) || - !(hd->scsi_ssts & SSTS_DREG_EMPTY)) { - ixfer_in(hd, sizeof(hs->sc_msg), hs->sc_msg); - hd->scsi_scmd = SCMD_RST_ACK; - } - phase = BUS_FREE_PHASE; - break; - - case BUS_FREE_PHASE: - goto out; - - default: - printf("%s: unexpected phase %d in icmd from %d\n", - hs->sc_dev.dv_xname, phase, target); - goto abort; - } - /* wait for last command to complete */ - while ((ints = hd->scsi_ints) == 0) { - if (--wait < 0) { - HIST(cxin_wait, wait) - goto abort; - } - DELAY(1); - } - HIST(cxin_wait, wait) - hd->scsi_ints = ints; - if (ints & INTS_SRV_REQ) - phase = hd->scsi_psns & PHASE; - else if (ints & INTS_DISCON) - goto out; - else if ((ints & INTS_CMD_DONE) == 0) { - scsierror(hs, hd, ints); - goto abort; - } - } -abort: - scsiabort(target, hs, hd, "icmd"); -out: - return (hs->sc_stat[0]); -} - -/* - * Finish SCSI xfer command: After the completion interrupt from - * a read/write operation, sequence through the final phases in - * programmed i/o. This routine is a lot like scsiicmd except we - * skip (and don't allow) the select, cmd out and data in/out phases. - */ -static void -finishxfer(hs, hd, target) - struct scsi_softc *hs; - volatile struct scsidevice *hd; - int target; -{ - u_char phase, ints; - - /* - * We specified padding xfer so we ended with either a phase - * change interrupt (normal case) or an error interrupt (handled - * elsewhere). Reset the board dma logic then try to get the - * completion status & command done msg. The reset confuses - * the SPC REQ/ACK logic so we have to do any status/msg input - * operations via 'manual xfer'. - */ - if (hd->scsi_ssts & SSTS_BUSY) { - int wait = scsi_cmd_wait; - - /* wait for dma operation to finish */ - while (hd->scsi_ssts & SSTS_BUSY) { - if (--wait < 0) { -#ifdef DEBUG - if (scsi_debug) - printf("finishxfer fail: ssts %x\n", - hd->scsi_ssts); -#endif - HIST(fxfr_wait, wait) - goto abort; - } - } - HIST(fxfr_wait, wait) - } - hd->scsi_scmd |= SCMD_PROG_XFR; - hd->scsi_sctl |= SCTL_CTRLRST; - DELAY(2); - hd->scsi_sctl &=~ SCTL_CTRLRST; - hd->scsi_hconf = 0; - /* - * The following delay is definitely needed when trying to - * write on a write protected disk (in the optical jukebox anyways), - * but we shall see if other unexplained machine freezeups - * also stop occurring... A value of 5 seems to work but - * 10 seems safer considering the potential consequences. - */ - DELAY(10); - hs->sc_stat[0] = 0xff; - hs->sc_msg[0] = 0xff; - hd->scsi_csr = 0; - hd->scsi_ints = ints = hd->scsi_ints; - while (1) { - phase = hd->scsi_psns & PHASE; - switch (phase) { - - case STATUS_PHASE: - if (mxfer_in(hd, sizeof(hs->sc_stat), - (u_char *)hs->sc_stat, phase) <= 0) - goto abort; - break; - - case MESG_IN_PHASE: - if (mxfer_in(hd, sizeof(hs->sc_msg), - (u_char *)hs->sc_msg, phase) < 0) - goto abort; - break; - - case BUS_FREE_PHASE: - return; - - default: - printf("%s: unexpected phase %d in finishxfer from %d\n", - hs->sc_dev.dv_xname, phase, target); - goto abort; - } - if ((ints = hd->scsi_ints)) { - hd->scsi_ints = ints; - if (ints & INTS_DISCON) - return; - else if (ints & ~(INTS_SRV_REQ|INTS_CMD_DONE)) { - scsierror(hs, hd, ints); - break; - } - } - if ((hd->scsi_ssts & SSTS_INITIATOR) == 0) - return; - } -abort: - scsiabort(target, hs, hd, "finishxfer"); - hs->sc_stat[0] = 0xfe; -} - -int -scsi_test_unit_rdy(ctlr, slave, unit) - int ctlr, slave, unit; -{ - struct scsi_softc *hs = oscsi_cd.cd_devs[ctlr]; - static struct scsi_cdb6 cdb = { CMD_TEST_UNIT_READY }; - - cdb.lun = unit; - return (scsiicmd(hs, slave, (u_char *)&cdb, sizeof(cdb), - (u_char *)0, 0, STATUS_PHASE)); -} - -int -scsi_request_sense(ctlr, slave, unit, buf, len) - int ctlr, slave, unit; - u_char *buf; - u_int len; -{ - struct scsi_softc *hs = oscsi_cd.cd_devs[ctlr]; - static struct scsi_cdb6 cdb = { CMD_REQUEST_SENSE }; - - cdb.lun = unit; - cdb.len = len; - return (scsiicmd(hs, slave, (u_char *)&cdb, sizeof(cdb), - buf, len, DATA_IN_PHASE)); -} - -int -scsi_immed_command(ctlr, slave, unit, cdb, buf, len, rd) - int ctlr, slave, unit, rd; - struct scsi_fmt_cdb *cdb; - u_char *buf; - u_int len; -{ - struct scsi_softc *hs = oscsi_cd.cd_devs[ctlr]; - - cdb->cdb[1] |= unit << 5; - return (scsiicmd(hs, slave, cdb->cdb, cdb->len, buf, len, - rd != 0? DATA_IN_PHASE : DATA_OUT_PHASE)); -} - -/* - * The following routines are test-and-transfer i/o versions of read/write - * for things like reading disk labels and writing core dumps. The - * routine scsigo should be used for normal data transfers, NOT these - * routines. - */ -int -scsi_tt_read(ctlr, slave, unit, buf, len, blk, bshift) - int ctlr, slave, unit; - u_char *buf; - u_int len; - daddr_t blk; - int bshift; -{ - struct scsi_softc *hs = oscsi_cd.cd_devs[ctlr]; - struct scsi_cdb10 cdb; - int stat; - int old_wait = scsi_data_wait; - - scsi_data_wait = 300000; - bzero(&cdb, sizeof(cdb)); - cdb.cmd = CMD_READ_EXT; - cdb.lun = unit; - blk >>= bshift; - cdb.lbah = blk >> 24; - cdb.lbahm = blk >> 16; - cdb.lbalm = blk >> 8; - cdb.lbal = blk; - cdb.lenh = len >> (8 + DEV_BSHIFT + bshift); - cdb.lenl = len >> (DEV_BSHIFT + bshift); - stat = scsiicmd(hs, slave, (u_char *)&cdb, sizeof(cdb), - buf, len, DATA_IN_PHASE); - scsi_data_wait = old_wait; - return (stat); -} - -int -scsi_tt_write(ctlr, slave, unit, buf, len, blk, bshift) - int ctlr, slave, unit; - u_char *buf; - u_int len; - daddr_t blk; - int bshift; -{ - struct scsi_softc *hs = oscsi_cd.cd_devs[ctlr]; - struct scsi_cdb10 cdb; - int stat; - int old_wait = scsi_data_wait; - - scsi_data_wait = 300000; - - bzero(&cdb, sizeof(cdb)); - cdb.cmd = CMD_WRITE_EXT; - cdb.lun = unit; - blk >>= bshift; - cdb.lbah = blk >> 24; - cdb.lbahm = blk >> 16; - cdb.lbalm = blk >> 8; - cdb.lbal = blk; - cdb.lenh = len >> (8 + DEV_BSHIFT + bshift); - cdb.lenl = len >> (DEV_BSHIFT + bshift); - stat = scsiicmd(hs, slave, (u_char *)&cdb, sizeof(cdb), - buf, len, DATA_OUT_PHASE); - scsi_data_wait = old_wait; - return (stat); -} - -int -scsireq(pdev, sq) - struct device *pdev; - struct scsiqueue *sq; -{ - struct scsi_softc *hs = (struct scsi_softc *)pdev; - int s; - - s = splhigh(); /* XXXthorpej */ - TAILQ_INSERT_TAIL(&hs->sc_queue, sq, sq_list); - splx(s); - - if (hs->sc_queue.tqh_first == sq) - return (1); - - return (0); -} - -int -scsiustart(unit) - int unit; -{ - struct scsi_softc *hs = oscsi_cd.cd_devs[unit]; - - hs->sc_dq.dq_chan = DMA0 | DMA1; - hs->sc_flags |= SCSI_HAVEDMA; - if (dmareq(&hs->sc_dq)) - return(1); - return(0); -} - -void -scsistart(arg) - void *arg; -{ - struct scsi_softc *hs = arg; - struct scsiqueue *sq; - - sq = hs->sc_queue.tqh_first; - (sq->sq_go)(sq->sq_softc); -} - -int -scsigo(ctlr, slave, unit, bp, cdb, pad) - int ctlr, slave, unit; - struct buf *bp; - struct scsi_fmt_cdb *cdb; - int pad; -{ - struct scsi_softc *hs = oscsi_cd.cd_devs[ctlr]; - volatile struct scsidevice *hd = hs->sc_regs; - int i, dmaflags; - u_char phase, ints, cmd; - - cdb->cdb[1] |= unit << 5; - - /* select the SCSI bus (it's an error if bus isn't free) */ - if (issue_select(hd, slave, hs->sc_scsi_addr) || wait_for_select(hd)) { - if (hs->sc_flags & SCSI_HAVEDMA) { - hs->sc_flags &=~ SCSI_HAVEDMA; - dmafree(&hs->sc_dq); - } - return (1); - } - /* - * Wait for a phase change (or error) then let the device - * sequence us through command phase (we may have to take - * a msg in/out before doing the command). If the disk has - * to do a seek, it may be a long time until we get a change - * to data phase so, in the absense of an explicit phase - * change, we assume data phase will be coming up and tell - * the SPC to start a transfer whenever it does. We'll get - * a service required interrupt later if this assumption is - * wrong. Otherwise we'll get a service required int when - * the transfer changes to status phase. - */ - phase = CMD_PHASE; - while (1) { - int wait = scsi_cmd_wait; - - switch (phase) { - - case CMD_PHASE: - if (ixfer_start(hd, cdb->len, phase, wait)) - if (ixfer_out(hd, cdb->len, cdb->cdb)) - goto abort; - break; - - case MESG_IN_PHASE: - if (ixfer_start(hd, sizeof(hs->sc_msg), phase, wait)|| - !(hd->scsi_ssts & SSTS_DREG_EMPTY)) { - ixfer_in(hd, sizeof(hs->sc_msg), hs->sc_msg); - hd->scsi_scmd = SCMD_RST_ACK; - } - phase = BUS_FREE_PHASE; - break; - - case DATA_IN_PHASE: - case DATA_OUT_PHASE: - goto out; - - default: - printf("%s: unexpected phase %d in go from %d\n", - hs->sc_dev.dv_xname, phase, slave); - goto abort; - } - while ((ints = hd->scsi_ints) == 0) { - if (--wait < 0) { - HIST(sgo_wait, wait) - goto abort; - } - DELAY(1); - } - HIST(sgo_wait, wait) - hd->scsi_ints = ints; - if (ints & INTS_SRV_REQ) - phase = hd->scsi_psns & PHASE; - else if (ints & INTS_CMD_DONE) - goto out; - else { - scsierror(hs, hd, ints); - goto abort; - } - } -out: - /* - * Reset the card dma logic, setup the dma channel then - * get the dio part of the card set for a dma xfer. - */ - hd->scsi_hconf = 0; - cmd = CSR_IE; - dmaflags = DMAGO_NOINT; - if (scsi_pridma) - dmaflags |= DMAGO_PRI; - if (bp->b_flags & B_READ) - dmaflags |= DMAGO_READ; - if ((hs->sc_flags & SCSI_DMA32) && - ((int)bp->b_un.b_addr & 3) == 0 && (bp->b_bcount & 3) == 0) { - cmd |= CSR_DMA32; - dmaflags |= DMAGO_LWORD; - } else - dmaflags |= DMAGO_WORD; - dmago(hs->sc_dq.dq_chan, bp->b_un.b_addr, bp->b_bcount, dmaflags); - - if (bp->b_flags & B_READ) { - cmd |= CSR_DMAIN; - phase = DATA_IN_PHASE; - } else - phase = DATA_OUT_PHASE; - /* - * DMA enable bits must be set after size and direction bits. - */ - hd->scsi_csr = cmd; - hd->scsi_csr |= (CSR_DE0 << hs->sc_dq.dq_chan); - /* - * Setup the SPC for the transfer. We don't want to take - * first a command complete then a service required interrupt - * at the end of the transfer so we try to disable the cmd - * complete by setting the transfer counter to more bytes - * than we expect. (XXX - This strategy may have to be - * modified to deal with devices that return variable length - * blocks, e.g., some tape drives.) - */ - cmd = SCMD_XFR; - i = (unsigned)bp->b_bcount; - if (pad) { - cmd |= SCMD_PAD; - /* - * XXX - If we don't do this, the last 2 or 4 bytes - * (depending on word/lword DMA) of a read get trashed. - * It looks like it is necessary for the DMA to complete - * before the SPC goes into "pad mode"??? Note: if we - * also do this on a write, the request never completes. - */ - if (bp->b_flags & B_READ) - i += 2; -#ifdef DEBUG - hs->sc_flags |= SCSI_PAD; - if (i & 1) - printf("%s: odd byte count: %d bytes @ %ld\n", - hs->sc_dev.dv_xname, i, bp->b_cylin); -#endif - } else - i += 4; - hd->scsi_tch = i >> 16; - hd->scsi_tcm = i >> 8; - hd->scsi_tcl = i; - hd->scsi_pctl = phase; - hd->scsi_tmod = 0; - hd->scsi_scmd = cmd; - hs->sc_flags |= SCSI_IO; - return (0); -abort: - scsiabort(slave, hs, hd, "go"); - hs->sc_flags &=~ SCSI_HAVEDMA; - dmafree(&hs->sc_dq); - return (1); -} - -void -scsidone(arg) - void *arg; -{ - struct scsi_softc *hs = arg; - volatile struct scsidevice *hd = hs->sc_regs; - -#ifdef DEBUG - if (scsi_debug) - printf("%s: done called!\n", hs->sc_dev.dv_xname); -#endif - /* dma operation is done -- turn off card dma */ - hd->scsi_csr &=~ (CSR_DE1|CSR_DE0); -} - -int -scsiintr(arg) - void *arg; -{ - struct scsi_softc *hs = arg; - volatile struct scsidevice *hd = hs->sc_regs; - u_char ints; - struct scsiqueue *sq; - - if ((hd->scsi_csr & (CSR_IE|CSR_IR)) != (CSR_IE|CSR_IR)) - return (0); - - sq = hs->sc_queue.tqh_first; - - ints = hd->scsi_ints; - if ((ints & INTS_SRV_REQ) && (hs->sc_flags & SCSI_IO)) { - /* - * this should be the normal i/o completion case. - * get the status & cmd complete msg then let the - * device driver look at what happened. - */ -#ifdef DEBUG - int len = (hd->scsi_tch << 16) | (hd->scsi_tcm << 8) | - hd->scsi_tcl; - if (!(hs->sc_flags & SCSI_PAD)) - len -= 4; - hs->sc_flags &=~ SCSI_PAD; -#endif - finishxfer(hs, hd, sq->sq_target); - hs->sc_flags &=~ (SCSI_IO|SCSI_HAVEDMA); - dmafree(&hs->sc_dq); - (sq->sq_intr)(sq->sq_softc, hs->sc_stat[0]); - } else { - /* Something unexpected happened -- deal with it. */ - hd->scsi_ints = ints; - hd->scsi_csr = 0; - scsierror(hs, hd, ints); - scsiabort(sq->sq_target, hs, hd, "intr"); - if (hs->sc_flags & SCSI_IO) { - hs->sc_flags &=~ (SCSI_IO|SCSI_HAVEDMA); - dmafree(&hs->sc_dq); - (sq->sq_intr)(sq->sq_softc, -1); - } - } - return(1); -} - -void -scsifree(pdev, sq) - struct device *pdev; - struct scsiqueue *sq; -{ - struct scsi_softc *hs = (struct scsi_softc *)pdev; - int s; - - s = splhigh(); /* XXXthorpej */ - TAILQ_REMOVE(&hs->sc_queue, sq, sq_list); - splx(s); - - if ((sq = hs->sc_queue.tqh_first) != NULL) - (*sq->sq_start)(sq->sq_softc); -} - -/* - * (XXX) The following routine is needed for the SCSI tape driver - * to read odd-size records. - */ - -#include "st.h" -#if NST > 0 -int -scsi_tt_oddio(ctlr, slave, unit, buf, len, b_flags, freedma) - int ctlr, slave, unit, b_flags, freedma; - u_char *buf; - u_int len; -{ - struct scsi_softc *hs = oscsi_cd.cd_devs[ctlr]; - struct scsi_cdb6 cdb; - u_char iphase; - int stat; - -#ifdef DEBUG - if ((freedma && (hs->sc_flags & SCSI_HAVEDMA) == 0) || - (!freedma && (hs->sc_flags & SCSI_HAVEDMA))) - printf("oddio: freedma (%d) inconsistency (flags=%x)\n", - freedma, hs->sc_flags); -#endif - /* - * First free any DMA channel that was allocated. - * We can't use DMA to do this transfer. - */ - if (freedma) { - hs->sc_flags &=~ SCSI_HAVEDMA; - dmafree(&hs->sc_dq); - } - /* - * Initialize command block - */ - bzero(&cdb, sizeof(cdb)); - cdb.lun = unit; - cdb.lbam = (len >> 16) & 0xff; - cdb.lbal = (len >> 8) & 0xff; - cdb.len = len & 0xff; - if (buf == 0) { - cdb.cmd = CMD_SPACE; - cdb.lun |= 0x00; - len = 0; - iphase = MESG_IN_PHASE; - } else if (b_flags & B_READ) { - cdb.cmd = CMD_READ; - iphase = DATA_IN_PHASE; - } else { - cdb.cmd = CMD_WRITE; - iphase = DATA_OUT_PHASE; - } - /* - * Perform command (with very long delays) - */ - scsi_delay(30000000); - stat = scsiicmd(hs, slave, (u_char *)&cdb, sizeof(cdb), - buf, len, iphase); - scsi_delay(0); - return (stat); -} -#endif - -/* - * Copy a counted string, trimming the trailing space, and turn - * the result into a C-style string. - */ -void -scsi_str(src, dst, len) - char *src, *dst; - size_t len; -{ - - while (src[len - 1] == ' ') { - if (--len == 0) { - *dst = '\0'; - return; - } - } - bcopy(src, dst, len); - dst[len] = '\0'; -} - -/* - * Probe for a device at the given ctlr/target/lun, and fill in the inqbuf. - */ -int -scsi_probe_device(ctlr, targ, lun, inqbuf, inqlen) - int ctlr, targ, lun; - struct scsi_inquiry *inqbuf; - int inqlen; -{ - static struct scsi_fmt_cdb inq = { - 6, { CMD_INQUIRY, 0, 0, 0, 0, 0 } - }; - int i, tries = 10, isrm = 0; - - inq.cdb[4] = inqlen & 0xff; - - scsi_delay(-1); - - /* - * See if the unit exists. - */ - while ((i = scsi_test_unit_rdy(ctlr, targ, lun)) != 0) { - if (i == -1 || --tries < 0) { - if (isrm) - break; - /* doesn't exist or not a CCS device */ - goto failed; - } - if (i == STS_CHECKCOND) { - u_char sensebuf[128]; - struct scsi_xsense *sp = - (struct scsi_xsense *)sensebuf; - - scsi_request_sense(ctlr, targ, lun, (u_char *)sensebuf, - sizeof(sensebuf)); - if (sp->class == 7) { - switch (sp->key) { - /* - * Not ready -- might be removable media - * device with no media. Assume as much, - * if it really isn't, the inquiry command - * below will fail. - */ - case 2: - isrm = 1; - break; - /* drive doing an RTZ -- give it a while */ - case 6: - delay(1000000); - break; - default: - break; - } - } - } - delay(1000); - } - - /* - * Find out about the device. - */ - if (scsi_immed_command(ctlr, targ, lun, &inq, (u_char *)inqbuf, - inqlen, B_READ)) - goto failed; - - scsi_delay(0); - return (0); - - failed: - scsi_delay(0); - return (-1); -} diff --git a/sys/arch/hp300/dev/scsireg.h b/sys/arch/hp300/dev/scsireg.h deleted file mode 100644 index 03a246c4660..00000000000 --- a/sys/arch/hp300/dev/scsireg.h +++ /dev/null @@ -1,477 +0,0 @@ -/* $OpenBSD: scsireg.h,v 1.3 2003/06/02 23:27:45 millert Exp $ */ -/* $NetBSD: scsireg.h,v 1.4 1994/10/26 07:24:59 cgd Exp $ */ - -/* - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Van Jacobson of 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. 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. - * - * @(#)scsireg.h 8.1 (Berkeley) 6/10/93 - */ - -/* - * HP 98265A SCSI Interface Hardware Description. - */ - -struct scsidevice { - u_char p0, scsi_id; -#define ID_MASK 0x1f -#define SCSI_ID 0x07 -#define ID_WORD_DMA 0x20 - u_char p2, scsi_csr; -#define CSR_IE 0x80 -#define CSR_IR 0x40 -#define SCSI_IPL(csr) ((((csr)>>4)&3)+3) -#define CSR_DMA32 0x08 -#define CSR_DMAIN 0x04 -#define CSR_DE1 0x02 -#define CSR_DE0 0x01 - u_char p4, scsi_wrap; -#define WRAP_REQ 0x80 -#define WRAP_ACK 0x40 -#define WRAP_BSY 0x08 -#define WRAP_MSG 0x04 -#define WRAP_CD 0x02 -#define WRAP_IO 0x01 - u_char p6, scsi_hconf; -#define HCONF_TP 0x80 -#define SCSI_SYNC_XFER(hconf) (((hconf)>>5)&3) -#define HCONF_SD 0x10 -#define HCONF_PARITY 0x08 - u_char p8[24]; - u_char p32, scsi_bdid; - u_char p34, scsi_sctl; -#define SCTL_DISABLE 0x80 -#define SCTL_CTRLRST 0x40 -#define SCTL_DIAG 0x20 -#define SCTL_ABRT_ENAB 0x10 -#define SCTL_PARITY_ENAB 0x08 -#define SCTL_SEL_ENAB 0x04 -#define SCTL_RESEL_ENAB 0x02 -#define SCTL_INTR_ENAB 0x01 - u_char p36, scsi_scmd; -#define SCMD_RST 0x10 -#define SCMD_ICPT_XFR 0x08 -#define SCMD_PROG_XFR 0x04 -#define SCMD_PAD 0x01 /* if initiator */ -#define SCMD_PERR_STOP 0x01 /* if target */ - /* command codes */ -#define SCMD_BUS_REL 0x00 -#define SCMD_SELECT 0x20 -#define SCMD_RST_ATN 0x40 -#define SCMD_SET_ATN 0x60 -#define SCMD_XFR 0x80 -#define SCMD_XFR_PAUSE 0xa0 -#define SCMD_RST_ACK 0xc0 -#define SCMD_SET_ACK 0xe0 - u_char p38, scsi_tmod; -#define TMOD_SYNC 0x80 - u_char p40, scsi_ints; -#define INTS_SEL 0x80 -#define INTS_RESEL 0x40 -#define INTS_DISCON 0x20 -#define INTS_CMD_DONE 0x10 -#define INTS_SRV_REQ 0x08 -#define INTS_TIMEOUT 0x04 -#define INTS_HARD_ERR 0x02 -#define INTS_RST 0x01 - u_char p42, scsi_psns; -#define PSNS_REQ 0x80 -#define PSNS_ACK 0x40 -#define PSNS_ATN 0x20 -#define PSNS_SEL 0x10 -#define PSNS_BSY 0x08 - u_char p44, scsi_ssts; -#define SSTS_INITIATOR 0x80 -#define SSTS_TARGET 0x40 -#define SSTS_BUSY 0x20 -#define SSTS_XFR 0x10 -#define SSTS_ACTIVE (SSTS_INITIATOR|SSTS_XFR) -#define SSTS_RST 0x08 -#define SSTS_TCZERO 0x04 -#define SSTS_DREG_FULL 0x02 -#define SSTS_DREG_EMPTY 0x01 - u_char p46, scsi_serr; -#define SERR_SCSI_PAR 0x80 -#define SERR_SPC_PAR 0x40 -#define SERR_TC_PAR 0x08 -#define SERR_PHASE_ERR 0x04 -#define SERR_SHORT_XFR 0x02 -#define SERR_OFFSET 0x01 - u_char p48, scsi_pctl; -#define PCTL_BFINT_ENAB 0x80 - u_char p50, scsi_mbc; - u_char p52, scsi_dreg; - u_char p54, scsi_temp; - u_char p56, scsi_tch; - u_char p58, scsi_tcm; - u_char p60, scsi_tcl; - u_char p62, scsi_exbf; -}; - -/* psns/pctl phase lines as bits */ -#define PHASE_MSG 0x04 -#define PHASE_CD 0x02 /* =1 if 'command' */ -#define PHASE_IO 0x01 /* =1 if data inbound */ -/* Phase lines as values */ -#define PHASE 0x07 /* mask for psns/pctl phase */ -#define DATA_OUT_PHASE 0x00 -#define DATA_IN_PHASE 0x01 -#define CMD_PHASE 0x02 -#define STATUS_PHASE 0x03 -#define BUS_FREE_PHASE 0x04 -#define ARB_SEL_PHASE 0x05 /* Fuji chip combines arbitration with sel. */ -#define MESG_OUT_PHASE 0x06 -#define MESG_IN_PHASE 0x07 - -/* SCSI Messages */ - -#define MSG_CMD_COMPLETE 0x00 -#define MSG_EXT_MESSAGE 0x01 -#define MSG_SAVE_DATA_PTR 0x02 -#define MSG_RESTORE_PTR 0x03 -#define MSG_DISCONNECT 0x04 -#define MSG_INIT_DETECT_ERROR 0x05 -#define MSG_ABORT 0x06 -#define MSG_REJECT 0x07 -#define MSG_NOOP 0x08 -#define MSG_PARITY_ERROR 0x09 -#define MSG_BUS_DEVICE_RESET 0x0C -#define MSG_IDENTIFY 0x80 -#define MSG_IDENTIFY_DR 0xc0 /* (disconnect/reconnect allowed) */ -#define MSG_SYNC_REQ 0x01 - -/* SCSI Commands */ - -#define CMD_TEST_UNIT_READY 0x00 -#define CMD_REQUEST_SENSE 0x03 -#define CMD_INQUIRY 0x12 -#define CMD_SEND_DIAGNOSTIC 0x1D - -#define CMD_REWIND 0x01 -#define CMD_REZERO 0x01 -#define CMD_FORMAT_UNIT 0x04 -#define CMD_READ_BLOCK_LIMITS 0x05 -#define CMD_REASSIGN_BLOCKS 0x07 -#define CMD_READ 0x08 -#define CMD_WRITE 0x0A -#define CMD_WRITE_FILEMARK 0x10 -#define CMD_SPACE 0x11 -#define CMD_MODE_SELECT 0x15 -#define CMD_RELEASE_UNIT 0x17 -#define CMD_ERASE 0x19 -#define CMD_MODE_SENSE 0x1A -#define CMD_LOADUNLOAD 0x1B -#define CMD_RECEIVE_DIAG 0x1C -#define CMD_SEND_DIAG 0x1D -#define CMD_P_A_MEDIA_REMOVAL 0x1E -#define CMD_READ_CAPACITY 0x25 -#define CMD_READ_EXT 0x28 -#define CMD_WRITE_EXT 0x2A -#define CMD_READ_DEFECT_DATA 0x37 -#define SD_MANUFAC_DEFECTS 0x14000000 -#define SD_GROWN_DEFECTS 0x0c000000 -#define CMD_READ_BUFFER 0x3B -#define CMD_WRITE_BUFFER 0x3C -#define CMD_READ_FULL 0xF0 -#define CMD_MEDIA_TEST 0xF1 -#define CMD_ACCESS_LOG 0xF2 -#define CMD_WRITE_FULL 0xFC -#define CMD_MANAGE_PRIMARY 0xFD -#define CMD_EXECUTE_DATA 0xFE - -/* SCSI status bits */ - -#define STS_CHECKCOND 0x02 /* Check Condition (ie., read sense) */ -#define STS_CONDMET 0x04 /* Condition Met (ie., search worked) */ -#define STS_BUSY 0x08 -#define STS_INTERMED 0x10 /* Intermediate status sent */ -#define STS_EXT 0x80 /* Extended status valid */ - -/* command descriptor blocks */ - -struct scsi_cdb6 { - u_char cmd; /* command code */ - u_char lun: 3, /* logical unit on ctlr */ - lbah: 5; /* msb of read/write logical block addr */ - u_char lbam; /* middle byte of l.b.a. */ - u_char lbal; /* lsb of l.b.a. */ - u_char len; /* transfer length */ - u_char xtra; -}; - -struct scsi_cdb10 { - u_char cmd; /* command code */ - u_char lun: 3, /* logical unit on ctlr */ - : 4, - rel: 1; /* l.b.a. is relative addr if =1 */ - u_char lbah; /* msb of read/write logical block addr */ - u_char lbahm; /* high middle byte of l.b.a. */ - u_char lbalm; /* low middle byte of l.b.a. */ - u_char lbal; /* lsb of l.b.a. */ - u_char reserved; - u_char lenh; /* msb transfer length */ - u_char lenl; /* lsb transfer length */ - u_char xtra; -}; - -/* basic sense data */ - -struct scsi_sense { - u_char valid: 1, /* l.b.a. is valid */ - class: 3, - code: 4; - u_char vu: 4, /* vendor unique */ - lbah: 4; - u_char lbam; - u_char lbal; -}; - -struct scsi_xsense { - u_char valid: 1, /* l.b.a. is valid */ - class: 3, - code: 4; - u_char segment; - u_char filemark: 1, - eom: 1, - ili: 1, /* illegal length indicator */ - rsvd: 1, - key: 4; - u_char info1; - u_char info2; - u_char info3; - u_char info4; - u_char len; /* additional sense length */ -}; - -/* inquiry data */ -struct scsi_inquiry { - u_char type; - u_char qual; - u_char version; - u_char rsvd; - u_char len; - char class[3]; - char vendor_id[8]; - char product_id[16]; - char rev[4]; -}; - -struct scsi_format_parms { /* physical BFI format */ - u_short reserved; - u_short list_len; - struct defect { - unsigned cyl : 24; - unsigned head : 8; - long bytes_from_index; - } defect[127]; -} format_parms; - -struct scsi_reassign_parms { - u_short reserved; - u_short list_len; /* length in bytes of defects only */ - struct new_defect { - unsigned lba; /* logical block address */ - } new_defect[2]; -} reassign_parms; - -struct scsi_modesel_hdr { - u_char rsvd1; - u_char media_type; - u_char rsvd2; - u_char block_desc_len; - u_int density : 8; - u_int number_blocks :24; - u_int rsvd3 : 8; - u_int block_length :24; -}; - -struct scsi_modesense_hdr { - u_char len; - u_char media_type; - u_char wp : 1; - u_char rsvd1 : 7; - u_char block_desc_len; - u_int density : 8; - u_int number_blocks :24; - u_int rsvd2 : 8; - u_int block_length :24; -}; - -/* - * Mode Select / Mode sense "pages" - */ - -/* - * Page One - Error Recovery Parameters - */ -struct scsi_err_recovery { - u_char page_savable : 1; /* save parameters */ - u_char reserved : 1; - u_char page_code : 6; /* = 0x01 */ - u_char page_length; /* = 6 */ - u_char awre : 1; /* auto write realloc enabled */ - u_char arre : 1; /* auto read realloc enabled */ - u_char tb : 1; /* transfer block */ - u_char rc : 1; /* read continuous */ - u_char eec : 1; /* enable early correction */ - u_char per : 1; /* post error */ - u_char dte : 1; /* disable transfer on error */ - u_char dcr : 1; /* disable correction */ - u_char retry_count; - u_char correction_span; - u_char head_offset_count; - u_char strobe_offset_count; - u_char recovery_time_limit; -}; - -/* - * Page Two - Disconnect / Reconnect Control Parameters - */ -struct scsi_disco_reco { - u_char page_savable : 1; /* save parameters */ - u_char rsvd : 1; - u_char page_code : 6; /* = 0x02 */ - u_char page_length; /* = 10 */ - u_char buffer_full_ratio; /* write, how full before reconnect? */ - u_char buffer_empty_ratio; /* read, how full before reconnect? */ - - u_short bus_inactivity_limit; /* how much bus time for busy */ - u_short disconnect_time_limit; /* min to remain disconnected */ - u_short connect_time_limit; /* min to remain connected */ - u_short reserved_1; -}; - -/* - * Page Three - Direct Access Device Format Parameters - */ -struct scsi_format { - u_char page_savable : 1; /* save parameters */ - u_char rsvd : 1; - u_char page_code : 6; /* = 0x03 */ - u_char page_length; /* = 22 */ - u_short tracks_per_zone; /* Handling of Defects Fields */ - u_short alt_sect_zone; - u_short alt_tracks_zone; - u_short alt_tracks_vol; - u_short sect_track; /* Track Format Field */ - u_short data_sect; /* Sector Format Fields */ - u_short interleave; - u_short track_skew_factor; - u_short cyl_skew_factor; - u_char ssec : 1; /* Drive Type Field */ - u_char hsec : 1; - u_char rmb : 1; - u_char surf : 1; - u_char ins : 1; - u_char reserved_1 : 3; - u_char reserved_2; - u_char reserved_3; - u_char reserved_4; -}; - -/* - * Page Four - Rigid Disk Drive Geometry Parameters - */ -struct scsi_geometry { - u_char page_savable : 1; /* save parameters */ - u_char rsvd : 1; - u_char page_code : 6; /* = 0x04 */ - u_char page_length; /* = 18 */ - u_char cyl_ub; /* number of cylinders */ - u_char cyl_mb; - u_char cyl_lb; - u_char heads; /* number of heads */ - u_char precomp_cyl_ub; /* cylinder to start precomp */ - u_char precomp_cyl_mb; - u_char precomp_cyl_lb; - u_char current_cyl_ub; /* cyl to start reduced current */ - u_char current_cyl_mb; - u_char current_cyl_lb; - u_short step_rate; /* drive step rate */ - u_char landing_cyl_ub; /* landing zone cylinder */ - u_char landing_cyl_mb; - u_char landing_cyl_lb; - u_char reserved_1; - u_char reserved_2; - u_char reserved_3; -}; - -/* - * Page 0x38 - Cache Control Parameters - */ -struct scsi_cache { - u_char page_savable : 1; /* save parameters */ - u_char rsvd : 1; - u_char page_code : 6; /* = 0x38 */ - u_char page_length; /* = 14 */ - u_char rsvd_1 : 1; - u_char wie : 1; /* write index enable */ - u_char rsvd_2 : 1; - u_char ce : 1; /* cache enable */ - u_char table_size : 4; - u_char prefetch_threshold; - u_char maximum_threshold; - u_char maximumprefetch_multiplier; - u_char minimum_threshold; - u_char minimum_prefetch_multiplier; - u_char reserved[8]; -}; - -/* - * Control for SCSI "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 with a non-zero arg will put the drive - * into format mode; a zero arg will take it out. When in format - * mode, only the process that issued the SDIOCFORMAT can read or - * write the drive. - * - * In format mode, 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_cdb { - int len; /* cdb length (in bytes) */ - u_char cdb[28]; /* cdb to use on next read/write */ -}; - -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', 0x1, int) -#define SDIOCGFORMAT _IOR('S', 0x2, int) -#define SDIOCSCSICOMMAND _IOW('S', 0x3, struct scsi_fmt_cdb) -#define SDIOCSENSE _IOR('S', 0x4, struct scsi_fmt_sense) diff --git a/sys/arch/hp300/dev/scsivar.h b/sys/arch/hp300/dev/scsivar.h deleted file mode 100644 index 6beeeae655f..00000000000 --- a/sys/arch/hp300/dev/scsivar.h +++ /dev/null @@ -1,91 +0,0 @@ -/* $OpenBSD: scsivar.h,v 1.7 2003/06/02 23:27:45 millert Exp $ */ -/* $NetBSD: scsivar.h,v 1.7 1997/03/31 07:40:05 scottr Exp $ */ - -/* - * Copyright (c) 1997 Jason R. Thorpe. All rights reserved. - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Van Jacobson of 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. 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 - */ - -#include <sys/queue.h> - -/* - * A SCSI job queue entry. Target drivers each have of of these, - * used to queue requests with the initiator. - */ -struct scsiqueue { - TAILQ_ENTRY(scsiqueue) sq_list; /* entry on queue */ - void *sq_softc; /* target's softc */ - int sq_target; /* target on bus */ - int sq_lun; /* lun on target */ - - /* - * Callbacks used to start and stop the target driver. - */ - void (*sq_start)(void *); - void (*sq_go)(void *); - void (*sq_intr)(void *, int); -}; - -struct scsi_inquiry; -struct scsi_fmt_cdb; - -struct oscsi_attach_args { - int osa_target; /* target */ - int osa_lun; /* logical unit */ - /* inquiry data */ - struct scsi_inquiry *osa_inqbuf; -}; - -#ifdef _KERNEL -int scsi_print(void *, const char *); - -void scsi_delay(int); -void scsistart(void *); -void scsireset(int); -int scsi_test_unit_rdy(int, int, int); -int scsi_request_sense(int, int, int, u_char *, u_int); -int scsi_immed_command(int, int, int, struct scsi_fmt_cdb *, - u_char *, u_int, int); -int scsi_tt_read(int, int, int, u_char *, u_int, daddr_t, int); -int scsi_tt_write(int, int, int, u_char *, u_int, daddr_t, int); -int scsireq(struct device *, struct scsiqueue *); -int scsiustart(int); -void scsistart(void *); -int scsigo(int, int, int, struct buf *, struct scsi_fmt_cdb *, int); -void scsidone(void *); -int scsiintr(void *); -void scsifree(struct device *, struct scsiqueue *); -int scsi_tt_oddio(int, int, int, u_char *, u_int, int, int); -void scsi_str(char *, char *, size_t); -int scsi_probe_device(int, int, int, struct scsi_inquiry *, int); -#endif diff --git a/sys/arch/hp300/dev/sd.c b/sys/arch/hp300/dev/sd.c deleted file mode 100644 index ceeb8aa0e02..00000000000 --- a/sys/arch/hp300/dev/sd.c +++ /dev/null @@ -1,1271 +0,0 @@ -/* $OpenBSD: sd.c,v 1.33 2004/02/15 02:56:13 tedu Exp $ */ -/* $NetBSD: sd.c,v 1.34 1997/07/10 18:14:10 kleink Exp $ */ - -/* - * Copyright (c) 1996, 1997 Jason R. Thorpe. All rights reserved. - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Van Jacobson of 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. 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.5 (Berkeley) 5/19/94 - */ - -/* - * SCSI CCS (Command Command Set) disk driver. - */ - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/buf.h> -#include <sys/device.h> -#include <sys/disk.h> -#include <sys/disklabel.h> -#include <sys/fcntl.h> -#include <sys/ioctl.h> -#include <sys/malloc.h> -#include <sys/proc.h> -#include <sys/stat.h> - -#include <ufs/ffs/fs.h> /* for BBSIZE and SBSIZE */ - -#include <sys/conf.h> - -#include <hp300/dev/scsireg.h> -#include <hp300/dev/scsivar.h> -#include <hp300/dev/sdvar.h> - -#ifdef USELEDS -#include <hp300/hp300/leds.h> -#endif - -int sdmatch(struct device *, void *, void *); -void sdattach(struct device *, struct device *, void *); - -struct cfattach sd_ca = { - sizeof(struct sd_softc), sdmatch, sdattach -}; - -struct cfdriver sd_cd = { - NULL, "sd", DV_DISK -}; - -#ifdef DEBUG -int sddebug = 1; -#define SDB_ERROR 0x01 -#define SDB_PARTIAL 0x02 -#define SDB_CAPACITY 0x04 -#endif - -static struct scsi_fmt_cdb sd_read_cmd = { 10, { CMD_READ_EXT } }; -static struct scsi_fmt_cdb sd_write_cmd = { 10, { CMD_WRITE_EXT } }; - -/* - * 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. - */ -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, -}; - -bdev_decl(sd); -cdev_decl(sd); - -void sdreset(struct sd_softc *); - -static void sdgetgeom(struct sd_softc *); -static void sdlblkstrat(struct buf *, int); -static int sderror(struct sd_softc *, int); -static void sdfinish(struct sd_softc *, struct buf *); - -/* - * Perform a mode-sense on page 0x04 (rigid geometry). - */ -static void -sdgetgeom(sc) - struct sd_softc *sc; -{ - struct scsi_mode_sense_geom { - struct scsi_modesense_hdr header; - struct scsi_geometry geom; - } sensebuf; - struct scsi_fmt_cdb modesense_geom; - int ctlr, slave, unit; - - /* XXX - if we try to do this in the declaration gcc uses memset() */ - bzero(&modesense_geom, sizeof(modesense_geom)); - modesense_geom.len = 6; - modesense_geom.cdb[0] = CMD_MODE_SENSE; - modesense_geom.cdb[2] = 0x04; - modesense_geom.cdb[4] = sizeof(sensebuf); - - ctlr = sc->sc_dev.dv_parent->dv_unit; - slave = sc->sc_target; - unit = sc->sc_lun; - - scsi_delay(-1); /* XXX */ - (void)scsi_immed_command(ctlr, slave, unit, &modesense_geom, - (u_char *)&sensebuf, sizeof(sensebuf), B_READ); - scsi_delay(0); /* XXX */ - - sc->sc_heads = sensebuf.geom.heads; - sc->sc_cyls = (sensebuf.geom.cyl_ub << 16) | - (sensebuf.geom.cyl_mb << 8) | sensebuf.geom.cyl_lb; -} - -int -sdmatch(parent, match, aux) - struct device *parent; - void *match, *aux; -{ - struct oscsi_attach_args *osa = aux; - - switch (osa->osa_inqbuf->type) { - case 0: /* disk */ - case 4: /* WORM */ - case 5: /* CD-ROM */ - case 7: /* Magneto-optical */ - break; - default: /* not a disk */ - return 0; - } - - return (1); -} - -void -sdattach(parent, self, aux) - struct device *parent, *self; - void *aux; -{ - struct sd_softc *sc = (struct sd_softc *)self; - struct oscsi_attach_args *osa = aux; - - /* - * XXX formerly 0 meant unused but now pid 0 can legitimately - * use this interface (sdgetcapacity). - */ - sc->sc_format_pid = -1; - sc->sc_flags = 0; - - sc->sc_target = osa->osa_target; - sc->sc_lun = osa->osa_lun; - sc->sc_type = osa->osa_inqbuf->type; - - if (osa->osa_inqbuf->qual & 0x80) - sc->sc_flags |= SDF_RMEDIA; - - printf("\n"); - - /* Initialize the SCSI queue entry. */ - sc->sc_sq.sq_softc = sc; - sc->sc_sq.sq_target = sc->sc_target; - sc->sc_sq.sq_lun = sc->sc_lun; - sc->sc_sq.sq_start = sdstart; - sc->sc_sq.sq_go = sdgo; - sc->sc_sq.sq_intr = sdintr; - - if (sdgetcapacity(sc, NODEV) < 0) { - printf("%s: getcapacity failed!\n", sc->sc_dev.dv_xname); - return; - } - - /* - * Print out some additional information. - */ - printf("%s: ", sc->sc_dev.dv_xname); - switch (sc->sc_type) { - case 4: - printf("WORM, "); - break; - - case 5: - printf("CD-ROM, "); - break; - - case 7: - printf("Magneto-optical, "); - break; - - default: - printf("%d cylinders, %d heads, ", - sc->sc_cyls, sc->sc_heads); - } - if (sc->sc_blks) - printf("%d blocks, %d bytes/block\n", - sc->sc_blks >> sc->sc_bshift, sc->sc_blksize); - else - printf("drive empty\n"); - - /* Initialize the disk structure. */ - sc->sc_dkdev.dk_name = sc->sc_dev.dv_xname; - - /* Attach the disk. */ - disk_attach(&sc->sc_dkdev); - - dk_establish(&sc->sc_dkdev, &sc->sc_dev); /* XXX */ - - sc->sc_flags |= SDF_ALIVE; -} - -void -sdreset(sc) - struct sd_softc *sc; -{ - sc->sc_stats.sdresets++; -} - -/* - * Determine capacity of a drive. - * Returns -1 on a failure, 0 on success, 1 on a failure that is probably - * due to missing media. - */ -int -sdgetcapacity(sc, dev) - struct sd_softc *sc; - dev_t dev; -{ - static struct scsi_fmt_cdb cap = { - 10, - { CMD_READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0 } - }; - u_char *capbuf; - int i, capbufsize; - - /* - * Cannot use stack space for this buffer since stack KVA may not - * be valid (i.e. in context of this process) when the operation - * actually starts. - */ - capbufsize = 8; - capbuf = malloc(capbufsize, M_DEVBUF, M_WAITOK); - - if (dev == NODEV) { - scsi_delay(-1); /* XXX */ - i = scsi_immed_command(sc->sc_dev.dv_parent->dv_unit, - sc->sc_target, sc->sc_lun, &cap, capbuf, - capbufsize, B_READ); - scsi_delay(0); /* XXX */ - } else { - struct buf *bp; - - /* - * XXX this is horrible - */ - if (sc->sc_format_pid >= 0) - panic("sdgetcapacity"); - bp = malloc(sizeof *bp, M_DEVBUF, M_WAITOK); - sc->sc_format_pid = curproc->p_pid; - bcopy(&cap, &sc->sc_cmdstore, sizeof cap); - bp->b_dev = dev; - bp->b_flags = B_READ | B_BUSY; - bp->b_un.b_addr = (caddr_t)capbuf; - bp->b_bcount = capbufsize; - LIST_INIT(&bp->b_dep); - sdstrategy(bp); - i = biowait(bp) ? sc->sc_sensestore.status : 0; - free(bp, M_DEVBUF); - sc->sc_format_pid = -1; - } - if (i) { - if (i != STS_CHECKCOND || (sc->sc_flags & SDF_RMEDIA) == 0) { -#ifdef DEBUG - if (sddebug & SDB_CAPACITY) - printf("%s: read_capacity returns %d\n", - sc->sc_dev.dv_xname, i); -#endif - free(capbuf, M_DEVBUF); - return (-1); - } - /* - * XXX assume unformatted or non-existent media - */ - sc->sc_blks = 0; - sc->sc_blksize = DEV_BSIZE; - sc->sc_bshift = 0; -#ifdef DEBUG - if (sddebug & SDB_CAPACITY) - printf("%s: removable media not present\n", - sc->sc_dev.dv_xname); -#endif - free(capbuf, M_DEVBUF); - return (1); - } - sc->sc_blks = *(u_int *)&capbuf[0]; - sc->sc_blksize = *(int *)&capbuf[4]; - free(capbuf, M_DEVBUF); - sc->sc_bshift = 0; - - /* return value of read capacity is last valid block number */ - sc->sc_blks++; - - if (sc->sc_blksize != DEV_BSIZE) { - if (sc->sc_blksize < DEV_BSIZE) { - printf("%s: need at least %d byte blocks - %s\n", - sc->sc_dev.dv_xname, DEV_BSIZE, "drive ignored"); - return (-1); - } - for (i = sc->sc_blksize; i > DEV_BSIZE; i >>= 1) - ++sc->sc_bshift; - sc->sc_blks <<= sc->sc_bshift; - } -#ifdef DEBUG - if (sddebug & SDB_CAPACITY) - printf("%s: blks=%d, blksize=%d, bshift=%d\n", - sc->sc_dev.dv_xname, sc->sc_blks, sc->sc_blksize, - sc->sc_bshift); -#endif - sc->sc_heads = sc->sc_cyls = 0; - sdgetgeom(sc); - return (0); -} - -/* - * Read or constuct a disklabel - */ -int -sdgetinfo(dev, sc, lp, spoofonly) - dev_t dev; - struct sd_softc *sc; - struct disklabel *lp; - int spoofonly; -{ - char *errstring; - - bzero((caddr_t)lp, sizeof *lp); - errstring = NULL; - - /* - * If removable media or the size unavailable at boot time - * (i.e. unformatted hard disk), attempt to set the capacity - * now. - */ - if ((sc->sc_flags & SDF_RMEDIA) || sc->sc_blks == 0) { - switch (sdgetcapacity(sc, dev)) { - case 0: - break; - case -1: - /* - * Hard error, just return (open will fail). - */ - return (EIO); - case 1: - /* - * XXX return 0 so open can continue just in case - * the media is unformatted and we want to format it. - * We set the error flag so they cannot do much else. - */ - sc->sc_flags |= SDF_ERROR; - /* XXX set magic here or it will never be set */ - lp->d_magic = DISKMAGIC; - lp->d_magic2 = DISKMAGIC; - errstring = "unformatted/missing media"; - break; - } - } - - /* - * Create a default disk label based on scsi info. - * This will get overridden if there is a real label on the disk. - */ - if (errstring == NULL) { - /* XXX we can open a device even without SDF_ALIVE */ - if (sc->sc_blksize == 0) - sc->sc_blksize = DEV_BSIZE; - - /* Fill in info from disk geometry if it exists. */ - lp->d_secperunit = sc->sc_blks >> sc->sc_bshift; - if (lp->d_secperunit > 0 && sc->sc_heads > 0 && sc->sc_cyls > 0) { - lp->d_ntracks = sc->sc_heads; - lp->d_ncylinders = sc->sc_cyls; - lp->d_nsectors = lp->d_secperunit / - (lp->d_ntracks * lp->d_ncylinders); - /* - * We must make sure d_nsectors is a sane value. - * Adjust d_ncylinders to be reasonable if we - * monkey with d_nsectors. - */ - if (lp->d_nsectors < 1) { - lp->d_nsectors = 32; - lp->d_ncylinders = lp->d_secperunit / - ( lp->d_ntracks * lp->d_nsectors); - if (lp->d_ncylinders == 0) - lp->d_ncylinders = sc->sc_cyls; - } - } else { - lp->d_ntracks = 20; - lp->d_ncylinders = 1; - lp->d_nsectors = 32; - } - - switch (sc->sc_type) { - case 4: - strncpy(lp->d_typename, "SCSI WORM", sizeof lp->d_typename); - break; - case 5: - strncpy(lp->d_typename, "SCSI CD-ROM", sizeof lp->d_typename); - break; - case 7: - strncpy(lp->d_typename, "SCSI optical", sizeof lp->d_typename); - break; - default: - strncpy(lp->d_typename, "SCSI disk", sizeof lp->d_typename); - break; - } - lp->d_type = DTYPE_SCSI; - strncpy(lp->d_packname, "fictitious", sizeof lp->d_packname); - lp->d_secsize = sc->sc_blksize; - lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks; - lp->d_rpm = 3600; - lp->d_interleave = 1; - - /* XXX - these values for BBSIZE and SBSIZE assume ffs */ - lp->d_bbsize = BBSIZE; - lp->d_sbsize = SBSIZE; - - lp->d_partitions[RAW_PART].p_offset = 0; - if (lp->d_secperunit > 0) - lp->d_partitions[RAW_PART].p_size = - lp->d_secperunit * (lp->d_secsize / DEV_BSIZE); - else - lp->d_partitions[RAW_PART].p_size = - roundup(LABELSECTOR+1, btodb(sc->sc_blksize)); - lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED; - lp->d_npartitions = RAW_PART + 1; - - lp->d_magic = DISKMAGIC; - lp->d_magic2 = DISKMAGIC; - lp->d_checksum = dkcksum(lp); - - errstring = readdisklabel(SDLABELDEV(dev), sdstrategy, lp, NULL, - spoofonly); - } - - if (errstring) { - printf("%s: WARNING: %s, defining `c' partition as entire disk\n", - sc->sc_dev.dv_xname, errstring); - /* XXX reset partition info as readdisklabel screws with it */ - lp->d_partitions[0].p_size = 0; - lp->d_partitions[RAW_PART].p_offset = 0; - lp->d_partitions[RAW_PART].p_size = - lp->d_secperunit * (lp->d_secsize / DEV_BSIZE); - lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED; - lp->d_npartitions = RAW_PART + 1; - lp->d_checksum = dkcksum(lp); - } - - return(0); -} - -int -sdopen(dev, flags, mode, p) - dev_t dev; - int flags, mode; - struct proc *p; -{ - int unit = SDUNIT(dev); - struct sd_softc *sc; - int error, mask, part; - - if (unit >= sd_cd.cd_ndevs || - (sc = sd_cd.cd_devs[unit]) == NULL || - (sc->sc_flags & SDF_ALIVE) == 0) - return (ENXIO); - - /* - * Wait for any pending opens/closes to complete - */ - while (sc->sc_flags & (SDF_OPENING|SDF_CLOSING)) - tsleep((caddr_t)sc, PRIBIO, "sdopen", 0); - - /* - * On first open, get label and partition info. - * We may block reading the label, so be careful - * to stop any other opens. - */ - if (sc->sc_dkdev.dk_openmask == 0) { - sc->sc_flags |= SDF_OPENING; - error = sdgetinfo(dev, sc, sc->sc_dkdev.dk_label, 0); - sc->sc_flags &= ~SDF_OPENING; - wakeup((caddr_t)sc); - if (error) - return(error); - } - - part = SDPART(dev); - mask = 1 << part; - - /* Check that the partition exists. */ - if (part != RAW_PART && - (part >= sc->sc_dkdev.dk_label->d_npartitions || - sc->sc_dkdev.dk_label->d_partitions[part].p_fstype == FS_UNUSED)) - return (ENXIO); - - /* Ensure only one open at a time. */ - switch (mode) { - case S_IFCHR: - sc->sc_dkdev.dk_copenmask |= mask; - break; - case S_IFBLK: - sc->sc_dkdev.dk_bopenmask |= mask; - break; - } - sc->sc_dkdev.dk_openmask = - sc->sc_dkdev.dk_copenmask | sc->sc_dkdev.dk_bopenmask; - - return(0); -} - -int -sdclose(dev, flag, mode, p) - dev_t dev; - int flag, mode; - struct proc *p; -{ - int unit = SDUNIT(dev); - struct sd_softc *sc = sd_cd.cd_devs[unit]; - struct disk *dk = &sc->sc_dkdev; - int mask, s; - - mask = 1 << SDPART(dev); - if (mode == S_IFCHR) - dk->dk_copenmask &= ~mask; - else - dk->dk_bopenmask &= ~mask; - dk->dk_openmask = dk->dk_copenmask | dk->dk_bopenmask; - /* - * On last close, we wait for all activity to cease since - * the label/parition info will become invalid. Since we - * might sleep, we must block any opens while we are here. - * Note we don't have to about other closes since we know - * we are the last one. - */ - if (dk->dk_openmask == 0) { - sc->sc_flags |= SDF_CLOSING; - s = splbio(); - while (sc->sc_tab.b_active) { - sc->sc_flags |= SDF_WANTED; - tsleep((caddr_t)&sc->sc_tab, PRIBIO, "sdclose", 0); - } - splx(s); - sc->sc_flags &= ~(SDF_CLOSING|SDF_ERROR); - wakeup((caddr_t)sc); - } - sc->sc_format_pid = -1; - 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) - struct buf *bp; - int bsize; -{ - struct sd_softc *sc = sd_cd.cd_devs[SDUNIT(bp->b_dev)]; - struct buf *cbp = (struct buf *)malloc(sizeof(struct buf), - M_DEVBUF, M_WAITOK); - caddr_t cbuf = (caddr_t)malloc(bsize, M_DEVBUF, M_WAITOK); - int bn, resid; - caddr_t addr; - - bzero((caddr_t)cbp, sizeof(*cbp)); - cbp->b_proc = curproc; /* XXX */ - cbp->b_dev = bp->b_dev; - LIST_INIT(&cbp->b_dep); - bn = bp->b_blkno; - resid = bp->b_bcount; - addr = bp->b_un.b_addr; -#ifdef DEBUG - if (sddebug & SDB_PARTIAL) - printf("sdlblkstrat: bp %p flags %lx bn %x resid %x addr %p\n", - bp, bp->b_flags, bn, resid, addr); -#endif - - while (resid > 0) { - int boff = dbtob(bn) & (bsize - 1); - int count; - - if (boff || resid < bsize) { - sc->sc_stats.sdpartials++; - count = min(resid, bsize - boff); - cbp->b_flags = B_BUSY | B_PHYS | B_READ; - cbp->b_blkno = bn - btodb(boff); - cbp->b_un.b_addr = cbuf; - cbp->b_bcount = bsize; -#ifdef DEBUG - if (sddebug & SDB_PARTIAL) - printf(" readahead: bn %x cnt %x off %x addr %p\n", - cbp->b_blkno, count, boff, addr); -#endif - sdstrategy(cbp); - biowait(cbp); - if (cbp->b_flags & B_ERROR) { - bp->b_flags |= B_ERROR; - bp->b_error = cbp->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 %p\n", - cbp->b_blkno, count, boff, addr); -#endif - } else { - count = resid & ~(bsize - 1); - cbp->b_blkno = bn; - cbp->b_un.b_addr = addr; - cbp->b_bcount = count; -#ifdef DEBUG - if (sddebug & SDB_PARTIAL) - printf(" fulltrans: bn %x cnt %x addr %p\n", - cbp->b_blkno, count, addr); -#endif - } - cbp->b_flags = B_BUSY | B_PHYS | (bp->b_flags & B_READ); - sdstrategy(cbp); - biowait(cbp); - if (cbp->b_flags & B_ERROR) { - bp->b_flags |= B_ERROR; - bp->b_error = cbp->b_error; - break; - } -done: - bn += btodb(count); - resid -= count; - addr += count; -#ifdef DEBUG - if (sddebug & SDB_PARTIAL) - printf(" done: bn %x resid %x addr %p\n", - bn, resid, addr); -#endif - } - free(cbuf, M_DEVBUF); - free(cbp, M_DEVBUF); -} - -void -sdstrategy(bp) - struct buf *bp; -{ - int unit = SDUNIT(bp->b_dev); - struct sd_softc *sc = sd_cd.cd_devs[unit]; - struct buf *dp = &sc->sc_tab; - struct partition *pinfo; - daddr_t bn; - int sz, s; - int offset; - - if (sc->sc_format_pid >= 0) { - if (sc->sc_format_pid != curproc->p_pid) { /* XXX */ - bp->b_error = EPERM; - goto bad; - } - bp->b_cylin = 0; - } else { - if (sc->sc_flags & SDF_ERROR) { - bp->b_error = EIO; - goto bad; - } - bn = bp->b_blkno; - sz = howmany(bp->b_bcount, DEV_BSIZE); - pinfo = &sc->sc_dkdev.dk_label->d_partitions[SDPART(bp->b_dev)]; - - /* Don't perform partition translation on RAW_PART. */ - offset = (SDPART(bp->b_dev) == RAW_PART) ? 0 : pinfo->p_offset; - - if (SDPART(bp->b_dev) != RAW_PART) { - /* - * XXX This block of code belongs in - * XXX bounds_check_with_label() - */ - - if (bn < 0 || bn + sz > pinfo->p_size) { - sz = pinfo->p_size - bn; - if (sz == 0) { - bp->b_resid = bp->b_bcount; - goto done; - } - if (sz < 0) { - bp->b_error = EINVAL; - goto bad; - } - bp->b_bcount = dbtob(sz); - } - /* - * Check for write to write protected label - */ - if (bn + offset <= LABELSECTOR && -#if LABELSECTOR != 0 - bn + offset + sz > LABELSECTOR && -#endif - !(bp->b_flags & B_READ) && - !(sc->sc_flags & SDF_WLABEL)) { - bp->b_error = EROFS; - goto bad; - } - } - /* - * Non-aligned or partial-block transfers handled specially. - */ - s = sc->sc_blksize - 1; - if ((dbtob(bn) & s) || (bp->b_bcount & s)) { - sdlblkstrat(bp, sc->sc_blksize); - goto done; - } - bp->b_cylin = (bn + offset) >> sc->sc_bshift; - } - s = splbio(); - disksort(dp, bp); - if (dp->b_active == 0) { - dp->b_active = 1; - sdustart(unit); - } - splx(s); - return; -bad: - bp->b_flags |= B_ERROR; -done: - s = splbio(); - biodone(bp); - splx(s); -} - -void -sdustart(unit) - int unit; -{ - struct sd_softc *sc = sd_cd.cd_devs[unit]; - - if (scsireq(sc->sc_dev.dv_parent, &sc->sc_sq)) - sdstart(sc); -} - -/* - * Return: - * 0 if not really an error - * <0 if we should do a retry - * >0 if a fatal error - */ -static int -sderror(sc, stat) - struct sd_softc *sc; - int stat; -{ - int cond = 1; - - sc->sc_sensestore.status = stat; - if (stat & STS_CHECKCOND) { - struct scsi_xsense *sp; - - scsi_request_sense(sc->sc_dev.dv_parent->dv_unit, - sc->sc_target, sc->sc_lun, sc->sc_sensestore.sense, - sizeof(sc->sc_sensestore.sense)); - sp = (struct scsi_xsense *)(sc->sc_sensestore.sense); - printf("%s: scsi sense class %d, code %d", sc->sc_dev.dv_xname, - sp->class, sp->code); - if (sp->class == 7) { - printf(", key %d", sp->key); - if (sp->valid) - printf(", blk %d", *(int *)&sp->info1); - switch (sp->key) { - /* no sense, try again */ - case 0: - cond = -1; - break; - /* recovered error, not a problem */ - case 1: - cond = 0; - break; - /* possible media change */ - case 6: - /* - * For removable media, if we are doing the - * first open (i.e. reading the label) go - * ahead and retry, otherwise someone has - * changed the media out from under us and - * we should abort any further operations - * until a close is done. - */ - if (sc->sc_flags & SDF_RMEDIA) { - if (sc->sc_flags & SDF_OPENING) - cond = -1; - else - sc->sc_flags |= SDF_ERROR; - } - break; - } - } - printf("\n"); - } - return(cond); -} - -static void -sdfinish(sc, bp) - struct sd_softc *sc; - struct buf *bp; -{ - struct buf *dp = &sc->sc_tab; - - dp->b_errcnt = 0; - dp->b_actf = bp->b_actf; - bp->b_resid = 0; - biodone(bp); - scsifree(sc->sc_dev.dv_parent, &sc->sc_sq); - if (dp->b_actf) - sdustart(sc->sc_dev.dv_unit); - else { - dp->b_active = 0; - if (sc->sc_flags & SDF_WANTED) { - sc->sc_flags &= ~SDF_WANTED; - wakeup((caddr_t)dp); - } - } -} - -void -sdstart(arg) - void *arg; -{ - struct sd_softc *sc = arg; - - /* - * we have the SCSI bus -- in format mode, we may or may not need dma - * so check now. - */ - if (sc->sc_format_pid >= 0 && legal_cmds[sc->sc_cmdstore.cdb[0]] > 0) { - struct buf *bp = sc->sc_tab.b_actf; - int sts; - - sc->sc_tab.b_errcnt = 0; - while (1) { - sts = scsi_immed_command(sc->sc_dev.dv_parent->dv_unit, - sc->sc_target, sc->sc_lun, &sc->sc_cmdstore, - bp->b_un.b_addr, bp->b_bcount, - bp->b_flags & B_READ); - sc->sc_sensestore.status = sts; - if ((sts & 0xfe) == 0 || - (sts = sderror(sc, sts)) == 0) - break; - if (sts > 0 || sc->sc_tab.b_errcnt++ >= SDRETRY) { - bp->b_flags |= B_ERROR; - bp->b_error = EIO; - break; - } - } - sdfinish(sc, bp); - - } else if (scsiustart(sc->sc_dev.dv_parent->dv_unit)) - sdgo(sc); -} - -void -sdgo(arg) - void *arg; -{ - struct sd_softc *sc = arg; - struct buf *bp = sc->sc_tab.b_actf; - int pad; - struct scsi_fmt_cdb *cmd; - - if (sc->sc_format_pid >= 0) { - cmd = &sc->sc_cmdstore; - pad = 0; - } else { - /* - * Drive is in an error state, abort all operations - */ - if (sc->sc_flags & SDF_ERROR) { - bp->b_flags |= B_ERROR; - bp->b_error = EIO; - sdfinish(sc, bp); - return; - } - cmd = bp->b_flags & B_READ? &sd_read_cmd : &sd_write_cmd; - *(int *)(&cmd->cdb[2]) = bp->b_cylin; - pad = howmany(bp->b_bcount, sc->sc_blksize); - *(u_short *)(&cmd->cdb[7]) = pad; - pad = (bp->b_bcount & (sc->sc_blksize - 1)) != 0; -#ifdef DEBUG - if (pad) - printf("%s: partial block xfer -- %lx bytes\n", - sc->sc_dev.dv_xname, bp->b_bcount); -#endif - sc->sc_stats.sdtransfers++; - } -#ifdef USELEDS - ledcontrol(0, 0, LED_DISK); -#endif - if (scsigo(sc->sc_dev.dv_parent->dv_unit, sc->sc_target, sc->sc_lun, - bp, cmd, pad) == 0) { - /* Instrumentation. */ - disk_busy(&sc->sc_dkdev); - sc->sc_dkdev.dk_seek++; /* XXX */ - return; - } -#ifdef DEBUG - if (sddebug & SDB_ERROR) - printf("%s: sdstart: %s adr %p blk %ld len %ld ecnt %ld\n", - sc->sc_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; - sdfinish(sc, bp); -} - -void -sdintr(arg, stat) - void *arg; - int stat; -{ - struct sd_softc *sc = arg; - struct buf *bp = sc->sc_tab.b_actf; - int cond; - - if (bp == NULL) { - printf("%s: bp == NULL\n", sc->sc_dev.dv_xname); - return; - } - - disk_unbusy(&sc->sc_dkdev, (bp->b_bcount - bp->b_resid), - (bp->b_flags & B_READ)); - - if (stat) { -#ifdef DEBUG - if (sddebug & SDB_ERROR) - printf("%s: sdintr: bad scsi status 0x%x\n", - sc->sc_dev.dv_xname, stat); -#endif - cond = sderror(sc, stat); - if (cond) { - if (cond < 0 && sc->sc_tab.b_errcnt++ < SDRETRY) { -#ifdef DEBUG - if (sddebug & SDB_ERROR) - printf("%s: retry #%ld\n", - sc->sc_dev.dv_xname, - sc->sc_tab.b_errcnt); -#endif - sdstart(sc); - return; - } - bp->b_flags |= B_ERROR; - bp->b_error = EIO; - } - } - sdfinish(sc, bp); -} - -int -sdread(dev, uio, flags) - dev_t dev; - struct uio *uio; - int flags; -{ - int unit = SDUNIT(dev); - struct sd_softc *sc = sd_cd.cd_devs[unit]; - int pid; - - if ((pid = sc->sc_format_pid) >= 0 && - pid != uio->uio_procp->p_pid) - return (EPERM); - - return (physio(sdstrategy, NULL, dev, B_READ, minphys, uio)); -} - -int -sdwrite(dev, uio, flags) - dev_t dev; - struct uio *uio; - int flags; -{ - int unit = SDUNIT(dev); - struct sd_softc *sc = sd_cd.cd_devs[unit]; - int pid; - - if ((pid = sc->sc_format_pid) >= 0 && - pid != uio->uio_procp->p_pid) - return (EPERM); - - return (physio(sdstrategy, NULL, dev, B_WRITE, minphys, uio)); -} - -int -sdioctl(dev, cmd, data, flag, p) - dev_t dev; - u_long cmd; - caddr_t data; - int flag; - struct proc *p; -{ - int unit = SDUNIT(dev); - struct sd_softc *sc = sd_cd.cd_devs[unit]; - struct disklabel *lp = sc->sc_dkdev.dk_label; - int error, flags; - - switch (cmd) { - case DIOCGPDINFO: - error = sdgetinfo(dev, sc, (struct disklabel *)data, 1); - return (error); - - case DIOCGDINFO: - *(struct disklabel *)data = *lp; - return (0); - - case DIOCGPART: - ((struct partinfo *)data)->disklab = lp; - ((struct partinfo *)data)->part = - &lp->d_partitions[SDPART(dev)]; - return (0); - - case DIOCWLABEL: - if ((flag & FWRITE) == 0) - return (EBADF); - if (*(int *)data) - sc->sc_flags |= SDF_WLABEL; - else - sc->sc_flags &= ~SDF_WLABEL; - return (0); - - case DIOCSDINFO: - if ((flag & FWRITE) == 0) - return (EBADF); - error = setdisklabel(lp, (struct disklabel *)data, - (sc->sc_flags & SDF_WLABEL) ? 0 - : sc->sc_dkdev.dk_openmask, - (struct cpu_disklabel *)0); - return (error); - - case DIOCWDINFO: - if ((flag & FWRITE) == 0) - return (EBADF); - error = setdisklabel(lp, (struct disklabel *)data, - (sc->sc_flags & SDF_WLABEL) ? 0 - : sc->sc_dkdev.dk_openmask, - (struct cpu_disklabel *)0); - if (error) - return (error); - flags = sc->sc_flags; - sc->sc_flags = SDF_ALIVE | SDF_WLABEL; - error = writedisklabel(SDLABELDEV(dev), sdstrategy, lp, - (struct cpu_disklabel *)0); - sc->sc_flags = flags; - return (error); - - case SDIOCSFORMAT: - /* take this device into or out of "format" mode */ - if (suser(p, 0)) - return(EPERM); - - if (*(int *)data) { - if (sc->sc_format_pid >= 0) - return (EPERM); - sc->sc_format_pid = p->p_pid; - } else - sc->sc_format_pid = -1; - return (0); - - case SDIOCGFORMAT: - /* find out who has the device in format mode */ - *(int *)data = sc->sc_format_pid; - return (0); - - case SDIOCSCSICOMMAND: - /* - * Save what user gave us as SCSI cdb to use with next - * read or write to the char device. - */ - if (sc->sc_format_pid != p->p_pid) - return (EPERM); - if (legal_cmds[((struct scsi_fmt_cdb *)data)->cdb[0]] == 0) - return (EINVAL); - bcopy(data, &sc->sc_cmdstore, sizeof(struct scsi_fmt_cdb)); - return (0); - - case SDIOCSENSE: - /* - * return the SCSI sense data saved after the last - * operation that completed with "check condition" status. - */ - bcopy(&sc->sc_sensestore, data, sizeof(sc->sc_sensestore)); - return (0); - - default: - return (EINVAL); - - } - /*NOTREACHED*/ -} - -int -sdsize(dev) - dev_t dev; -{ - int unit = SDUNIT(dev); - struct sd_softc *sc = sd_cd.cd_devs[unit]; - int psize, didopen = 0; - - if (unit >= sd_cd.cd_ndevs || - (sc = sd_cd.cd_devs[unit]) == NULL || - (sc->sc_flags & SDF_ALIVE) == 0) - return (-1); - - /* - * We get called very early on (via swapconf) - * without the device being open so we may need - * to handle it here. - */ - if (sc->sc_dkdev.dk_openmask == 0) { - if (sdopen(dev, FREAD|FWRITE, S_IFBLK, NULL)) - return(-1); - didopen = 1; - } - psize = sc->sc_dkdev.dk_label->d_partitions[SDPART(dev)].p_size * - (sc->sc_dkdev.dk_label->d_secsize / DEV_BSIZE); - if (didopen) - (void) sdclose(dev, FREAD|FWRITE, S_IFBLK, NULL); - return (psize); -} - -static int sddoingadump; /* simple mutex */ - -/* - * Non-interrupt driven, non-dma dump routine. - */ -int -sddump(dev, blkno, va, size) - dev_t dev; - daddr_t blkno; - caddr_t va; - size_t size; -{ - int sectorsize; /* size of a disk sector */ - int nsects; /* number of sectors in partition */ - int sectoff; /* sector offset of partition */ - int totwrt; /* total number of sectors left to write */ - int nwrt; /* current number of sectors to write */ - int unit, part; - struct sd_softc *sc; - struct disklabel *lp; - char stat; - - /* Check for recursive dump; if so, punt. */ - if (sddoingadump) - return (EFAULT); - sddoingadump = 1; - - /* Decompose unit and partition. */ - unit = SDUNIT(dev); - part = SDPART(dev); - - /* Make sure device is ok. */ - if (unit >= sd_cd.cd_ndevs || - (sc = sd_cd.cd_devs[unit]) == NULL || - (sc->sc_flags & SDF_ALIVE) == 0) - return (ENXIO); - - /* - * Convert to disk sectors. Request must be a multiple of size. - */ - lp = sc->sc_dkdev.dk_label; - sectorsize = lp->d_secsize; - if ((size % sectorsize) != 0) - return (EFAULT); - totwrt = size / sectorsize; - blkno = dbtob(blkno) / sectorsize; /* blkno in DEV_BSIZE units */ - - nsects = lp->d_partitions[part].p_size; - sectoff = lp->d_partitions[part].p_offset; - - /* Check transfer bounds against partition size. */ - if ((blkno < 0) || (blkno + totwrt) > nsects) - return (EINVAL); - - /* Offset block number to start of partition. */ - blkno += sectoff; - - while (totwrt > 0) { - nwrt = totwrt; /* XXX */ -#ifndef SD_DUMP_NOT_TRUSTED - /* - * Send the data. Note the `0' argument for bshift; - * we've done the necessary conversion above. - */ - stat = scsi_tt_write(sc->sc_dev.dv_parent->dv_unit, - sc->sc_target, sc->sc_lun, va, nwrt * sectorsize, - blkno, 0); - if (stat) { - printf("\nsddump: scsi write error 0x%x\n", stat); - return (EIO); - } -#else /* SD_DUMP_NOT_TRUSTED */ - /* Lets just talk about it first. */ - printf("%s: dump addr %p, blk %d\n", sc->sc_dev.dv_xname, - va, blkno); - delay(500 * 1000); /* half a second */ -#endif /* SD_DUMP_NOT_TRUSTED */ - - /* update block count */ - totwrt -= nwrt; - blkno += nwrt; - va += sectorsize * nwrt; - } - sddoingadump = 0; - return (0); -} diff --git a/sys/arch/hp300/dev/spc.c b/sys/arch/hp300/dev/spc.c new file mode 100644 index 00000000000..08e95a11182 --- /dev/null +++ b/sys/arch/hp300/dev/spc.c @@ -0,0 +1,276 @@ +/* $OpenBSD: spc.c,v 1.1 2004/08/03 21:46:56 miod Exp $ */ +/* $NetBSD: spc.c,v 1.2 2003/11/17 14:37:59 tsutsui Exp $ */ + +/* + * Copyright (c) 2003 Izumi Tsutsui. + * All rights reserved. + * + * 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. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/buf.h> + +#include <machine/autoconf.h> +#include <machine/cpu.h> +#include <machine/intr.h> + +#include <hp300/dev/dioreg.h> +#include <hp300/dev/diovar.h> +#include <hp300/dev/diodevs.h> + +#include <scsi/scsi_all.h> +#include <scsi/scsi_message.h> +#include <scsi/scsiconf.h> + +#include <hp300/dev/mb89352reg.h> +#include <hp300/dev/mb89352var.h> + +#include <hp300/dev/hp98265reg.h> +#include <hp300/dev/dmareg.h> +#include <hp300/dev/dmavar.h> + +int spc_dio_match(struct device *, void *, void *); +void spc_dio_attach(struct device *, struct device *, void *); +void spc_dio_dmastart(struct spc_softc *, void *, size_t, int); +void spc_dio_dmadone(struct spc_softc *); +void spc_dio_dmago(void *); +void spc_dio_dmastop(void *); +int spc_dio_intr(void *); + +#define HPSPC_ADDRESS(o) (dsc->sc_dregs + ((o) << 1) + 1) +#define hpspc_read(o) *(volatile u_int8_t *)(HPSPC_ADDRESS(o)) +#define hpspc_write(o, v) *(volatile u_int8_t *)(HPSPC_ADDRESS(o)) = (v) + +struct spc_dio_softc { + struct spc_softc sc_spc; /* MI spc softc */ + volatile u_int8_t *sc_dregs; /* Complete registers */ + + struct dmaqueue sc_dq; /* DMA job queue */ + u_int sc_dflags; /* DMA flags */ +#define SCSI_DMA32 0x01 /* 32-bit DMA should be used */ +#define SCSI_HAVEDMA 0x02 /* controller has DMA channel */ +#define SCSI_DATAIN 0x04 /* DMA direction */ +}; + +struct cfattach spc_ca = { + sizeof(struct spc_dio_softc), spc_dio_match, spc_dio_attach +}; + +struct cfdriver spc_cd = { + NULL, "spc", DV_DULL +}; + +int +spc_dio_match(struct device *parent, void *vcf, void *aux) +{ + struct dio_attach_args *da = aux; + + switch (da->da_id) { + case DIO_DEVICE_ID_SCSI0: + case DIO_DEVICE_ID_SCSI1: + case DIO_DEVICE_ID_SCSI2: + case DIO_DEVICE_ID_SCSI3: + return 1; + } + + return 0; +} + +void +spc_dio_attach(struct device *parent, struct device *self, void *aux) +{ + struct spc_dio_softc *dsc = (struct spc_dio_softc *)self; + struct spc_softc *sc = &dsc->sc_spc; + struct dio_attach_args *da = aux; + int ipl; + u_int8_t id; + + dsc->sc_dregs = (u_int8_t *)iomap(dio_scodetopa(da->da_scode), + da->da_size); + if (dsc->sc_dregs == NULL) { + printf(": can't map SCSI registers\n"); + return; + } + sc->sc_regs = dsc->sc_dregs + SPC_OFFSET; + + ipl = DIO_IPL(sc->sc_regs); + printf(" ipl %d: 98265A SCSI", ipl); + + hpspc_write(HPSCSI_ID, 0xff); + DELAY(100); + id = hpspc_read(HPSCSI_ID); + if ((id & ID_WORD_DMA) == 0) { + printf(", 32-bit DMA"); + dsc->sc_dflags |= SCSI_DMA32; + } + id &= ID_MASK; + printf(", SCSI ID %d\n", id); + + sc->sc_initiator = id; + + sc->sc_dma_start = spc_dio_dmastart; + sc->sc_dma_done = spc_dio_dmadone; + + dsc->sc_dq.dq_softc = dsc; + dsc->sc_dq.dq_start = spc_dio_dmago; + dsc->sc_dq.dq_done = spc_dio_dmastop; + + hpspc_write(HPSCSI_CSR, 0x00); + hpspc_write(HPSCSI_HCONF, 0x00); + + dio_intr_establish(spc_dio_intr, (void *)dsc, ipl, IPL_BIO); + + spc_attach(sc); + + /* Enable SPC interrupts. */ + hpspc_write(HPSCSI_CSR, CSR_IE); +} + +void +spc_dio_dmastart(struct spc_softc *sc, void *addr, size_t size, int datain) +{ + struct spc_dio_softc *dsc = (struct spc_dio_softc *)sc; + + dsc->sc_dq.dq_chan = DMA0 | DMA1; + dsc->sc_dflags |= SCSI_HAVEDMA; + if (datain) + dsc->sc_dflags |= SCSI_DATAIN; + else + dsc->sc_dflags &= ~SCSI_DATAIN; + + if (dmareq(&dsc->sc_dq) != 0) + /* DMA channel is available, so start DMA immediately */ + spc_dio_dmago((void *)dsc); + /* else dma start function will be called later from dmafree(). */ +} + +void +spc_dio_dmago(void *arg) +{ + struct spc_dio_softc *dsc = (struct spc_dio_softc *)arg; + struct spc_softc *sc = &dsc->sc_spc; + int len, chan; + u_int32_t dmaflags; + u_int8_t cmd; + + hpspc_write(HPSCSI_HCONF, 0); + + cmd = CSR_IE; + dmaflags = DMAGO_NOINT; + chan = dsc->sc_dq.dq_chan; + if ((dsc->sc_dflags & SCSI_DATAIN) != 0) { + cmd |= CSR_DMAIN; + dmaflags |= DMAGO_READ; + } + if ((dsc->sc_dflags & SCSI_DMA32) != 0 && + ((u_int)sc->sc_dp & 3) == 0 && + (sc->sc_dleft & 3) == 0) { + cmd |= CSR_DMA32; + dmaflags |= DMAGO_LWORD; + } else + dmaflags |= DMAGO_WORD; + + dmago(chan, sc->sc_dp, sc->sc_dleft, dmaflags); + + hpspc_write(HPSCSI_CSR, cmd); + cmd |= (chan == 0) ? CSR_DE0 : CSR_DE1; + hpspc_write(HPSCSI_CSR, cmd); + + cmd = SCMD_XFR; + len = sc->sc_dleft; + + spc_write(TCH, len >> 16); + spc_write(TCM, len >> 8); + spc_write(TCL, len); + spc_write(PCTL, sc->sc_phase | PCTL_BFINT_ENAB); + spc_write(SCMD, cmd); + + sc->sc_flags |= SPC_DOINGDMA; +} + +void +spc_dio_dmadone(struct spc_softc *sc) +{ + struct spc_dio_softc *dsc = (struct spc_dio_softc *)sc; + int resid, trans; + u_int8_t cmd; + + /* wait DMA complete */ + if ((spc_read(SSTS) & SSTS_BUSY) != 0) { + int timeout = 1000; /* XXX how long? */ + while ((spc_read(SSTS) & SSTS_BUSY) != 0) { + if (--timeout < 0) + printf("%s: DMA complete timeout\n", + sc->sc_dev.dv_xname); + DELAY(1); + } + } + + if ((dsc->sc_dflags & SCSI_HAVEDMA) != 0) { + dmafree(&dsc->sc_dq); + dsc->sc_dflags &= ~SCSI_HAVEDMA; + } + + cmd = hpspc_read(HPSCSI_CSR); + cmd &= ~(CSR_DE1 | CSR_DE0); + hpspc_write(HPSCSI_CSR, cmd); + + resid = spc_read(TCH) << 16 | + spc_read(TCM) << 8 | + spc_read(TCL); + trans = sc->sc_dleft - resid; + sc->sc_dp += trans; + sc->sc_dleft -= trans; + + sc->sc_flags &= ~SPC_DOINGDMA; +} + +void +spc_dio_dmastop(void *arg) +{ + struct spc_dio_softc *dsc = (struct spc_dio_softc *)arg; + struct spc_softc *sc = &dsc->sc_spc; + u_int8_t cmd; + + cmd = hpspc_read(HPSCSI_CSR); + cmd &= ~(CSR_DE1 | CSR_DE0); + hpspc_write(HPSCSI_CSR, cmd); + + dsc->sc_dflags &= ~SCSI_HAVEDMA; + sc->sc_flags &= ~SPC_DOINGDMA; +} + +int +spc_dio_intr(void *arg) +{ + struct spc_dio_softc *dsc = (struct spc_dio_softc *)arg; + + /* if we are sharing the ipl level, this interrupt may not be for us. */ + if ((hpspc_read(HPSCSI_CSR) & (CSR_IE | CSR_IR)) != (CSR_IE | CSR_IR)) + return 0; + + return spc_intr(arg); +} diff --git a/sys/arch/hp300/dev/st.c b/sys/arch/hp300/dev/st.c deleted file mode 100644 index 937349e0ef2..00000000000 --- a/sys/arch/hp300/dev/st.c +++ /dev/null @@ -1,1413 +0,0 @@ -/* $OpenBSD: st.c,v 1.18 2003/12/22 20:38:07 jmc Exp $ */ -/* $NetBSD: st.c,v 1.22 1997/04/02 22:37:38 scottr Exp $ */ - -/* - * Copyright (c) 1996, 1997 Jason R. Thorpe. All rights reserved. - * Copyright (c) 1990 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. 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: st.c 1.11 92/01/21$ - * - * @(#)st.c 8.3 (Berkeley) 1/12/94 - */ - -/* - * SCSI CCS (Command Command Set) tape driver. - * - * Specific to Exabyte: - * mt status: residual="Mbytes to LEOM" - * minor bit 4 [b1bbbb] (aka /dev/rst16) selects short filemarks - * minor bit 5 [1bbbbb] (aka /dev/rst32) selects fix block mode, 1k blocks. - * - * Archive drive: - * can read both QIC-24 and QIC-II. But only writes - * QIC-24. - * - * Supports Archive Viper QIC-150 tape drive, but scsi.c reports selection - * errors. - * - * Supports Archive Python DAT drive, but will sometimes hang machine. - * - * Supports HP 35450A DAT drive, but will sometimes hang machine. - * Partitioning of tape not supported. - * Vendor unique support has not been added. - * - * - * Supports Archive VIPER (QIC-150). - * Mostly Supports Archive PYTHON (DAT). - * Hangs if write after spin down. - * Need scsi.c that does connect/disconnect. - */ - -/* - * support for the block device not implemented - */ - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/buf.h> -#include <sys/file.h> -#include <sys/proc.h> -#include <sys/ioctl.h> -#include <sys/tty.h> -#include <sys/mtio.h> -#include <sys/kernel.h> -#include <sys/tprintf.h> -#include <sys/device.h> - -#include <sys/conf.h> - -#include <hp300/dev/scsireg.h> -#include <hp300/dev/scsivar.h> -#include <hp300/dev/stvar.h> - -static struct scsi_fmt_cdb st_read_cmd = { 6, { CMD_READ } }; -static struct scsi_fmt_cdb st_write_cmd = { 6, { CMD_WRITE } }; - -#define UNIT(x) (minor(x) & 3) -#define stpunit(x) ((x) & 7) - -#define STDEV_NOREWIND 0x04 -#define STDEV_HIDENSITY 0x08 -#define STDEV_EXSFMK 0x10 -#define STDEV_FIXEDBLK 0x20 - -#ifdef DEBUG -int st_debug = 0x0000; -#define ST_OPEN 0x0001 -#define ST_GO 0x0002 -#define ST_FMKS 0x0004 -#define ST_OPENSTAT 0x0008 -#define ST_BRESID 0x0010 -#define ST_ODDIO 0x0020 -#endif - -/* - * Patchable variable. If an even length read is requested a dma transfer is - * used. Only after the read will we find out if the read had an odd number - * of bytes. The HP98658 hardware cannot do odd length transfers, the last - * byte of the data will always be 0x00. Normally, the driver will complain - * about such transfers and return EIO. However, if st_dmaoddretry is non- - * zero, the driver will try and issue a BSR and then re-read the data using - * 'programmed transfer mode'. In most cases this works, however for unknown - * reasons it will hang the machine in certain cases. - * - * Note: - * Odd length read requests are always done using programmed transfer mode. - */ -int st_dmaoddretry = 0; - -/* - * Exabyte only: - * From adb can have access to fixed vs. variable length modes. - * Use 0x400 for 1k (best capacity) fixed length records. - * In st_open, if minor bit 4 set then 1k records are used. - * If st_exblken is set to anything other then 0 we are in fixed length mode. - * Minor bit 5 requests 1K fixed-length, overriding any setting of st_exblklen. - */ -int st_exblklen = 0; - -/* exabyte here for adb access, set at open time */ -#define EX_CT 0x80 /* international cart - more space W/P6 */ -#define EX_ND 0x20 /* no disconnect */ -#define EX_NBE 0x08 /* no busy enable */ -#define EX_EBD 0x04 /* even byte disconnect */ -#define EX_PE 0x02 /* parity enable */ -#define EX_NAL 0x01 /* no auto load */ -int st_exvup = (EX_CT|EX_ND|EX_NBE); /* vendor unique parameters */ - -/* - * motion and reconnect thresholds guidelines: - * write operation; lower motion threshold for faster transfer - * raise reconnect threshold for slower transfer - * read operation; lower motion threshold for slower transfer - * raise reconnect threshold for faster transfer - */ -int st_exmotthr = 0x80; /* motion threshold, 0x80 default */ -int st_exreconthr = 0xa0; /* reconnect threshold, 0xa0 default */ -int st_exgapthr = 7; /* gap threshold, 7 default */ -#ifdef TTI -int st_extti = 0x01; /* bitmask of unit numbers, do extra */ - /* sensing so TTi display gets updated */ -#endif - -bdev_decl(st); -cdev_decl(st); - -#ifdef DEBUG -void dumpxsense(struct st_xsense *); -void prtmodsel(struct mode_select_data *, int); -void prtmodstat(struct mode_sense *); -#endif /* DEBUG */ - -static void stfinish(struct st_softc *, struct buf *); -static void sterror(struct st_softc *, int); -static int stmatch(struct device *, void *, void *); -static void stattach(struct device *, struct device *, void *); - -struct cfattach st_ca = { - sizeof(struct st_softc), stmatch, stattach -}; - -struct cfdriver st_cd = { - NULL, "st", DV_TAPE -}; - -static int -stmatch(parent, match, aux) - struct device *parent; - void *match, *aux; -{ - struct oscsi_attach_args *osa = aux; - - if ((osa->osa_inqbuf->type != 0x01 || /* sequential access device */ - osa->osa_inqbuf->qual != 0x80 || /* removable media */ - (osa->osa_inqbuf->version != 0x01 && - osa->osa_inqbuf->version != 0x02)) && - (osa->osa_inqbuf->type != 0x01 || /* M4 ??! */ - /* - * the M4 is a little too smart (ass?) for its own good: - * qual codes: - * 0x80: you can take the tape out (unit not online) - * 0xf8: online and at 6250bpi - * 0xf9: online and at 1600bpi - */ - osa->osa_inqbuf->version != 0x09)) /* M4 tape */ - return (0); - - return (1); -} - -static void -stattach(parent, self, aux) - struct device *parent, *self; - void *aux; -{ - struct st_softc *sc = (struct st_softc *)self; - struct oscsi_attach_args *osa = aux; - char vendor[9], product[17], revision[5]; - int stat; - static int havest = 0; - - printf("\n"); - - sc->sc_tab.b_actb = &sc->sc_tab.b_actf; - - bzero(vendor, sizeof(vendor)); - bzero(product, sizeof(product)); - bzero(revision, sizeof(revision)); - - scsi_str(osa->osa_inqbuf->vendor_id, vendor, - sizeof(osa->osa_inqbuf->vendor_id)); - scsi_str(osa->osa_inqbuf->product_id, product, - sizeof(osa->osa_inqbuf->product_id)); - scsi_str(osa->osa_inqbuf->rev, revision, - sizeof(osa->osa_inqbuf->rev)); - - sc->sc_target = osa->osa_target; - sc->sc_lun = osa->osa_lun; - - /* Initialize SCSI queue entry. */ - sc->sc_sq.sq_softc = sc; - sc->sc_sq.sq_target = sc->sc_target; - sc->sc_sq.sq_lun = sc->sc_lun; - sc->sc_sq.sq_start = ststart; - sc->sc_sq.sq_go = stgo; - sc->sc_sq.sq_intr = stintr; - - if (bcmp("EXB-8200", product, 8) == 0) { - sc->sc_tapeid = MT_ISEXABYTE; - sc->sc_datalen[CMD_REQUEST_SENSE] = 26; - sc->sc_datalen[CMD_INQUIRY] = 52; - sc->sc_datalen[CMD_MODE_SELECT] = 17; - sc->sc_datalen[CMD_MODE_SENSE] = 17; - } else if (bcmp("VIPER 150", product, 9) == 0 || - bcmp("VIPER 60", product, 8) == 0) { - sc->sc_tapeid = MT_ISVIPER1; - sc->sc_datalen[CMD_REQUEST_SENSE] = 14; - sc->sc_datalen[CMD_INQUIRY] = 36; - sc->sc_datalen[CMD_MODE_SELECT] = 12; - sc->sc_datalen[CMD_MODE_SENSE] = 12; - } else if (bcmp("Python 25501", product, 12) == 0 || - bcmp("Python 28849", product, 12) == 0) { - sc->sc_tapeid = MT_ISPYTHON; - sc->sc_datalen[CMD_REQUEST_SENSE] = 14; - sc->sc_datalen[CMD_INQUIRY] = 36; - sc->sc_datalen[CMD_MODE_SELECT] = 12; - sc->sc_datalen[CMD_MODE_SENSE] = 12; - } else if (bcmp("HP35450A", product, 8) == 0) { - /* XXX "extra" stat makes the HP drive happy at boot time */ - stat = scsi_test_unit_rdy(sc->sc_dev.dv_parent->dv_unit, - sc->sc_target, sc->sc_lun); - sc->sc_tapeid = MT_ISHPDAT; - sc->sc_datalen[CMD_REQUEST_SENSE] = 14; - sc->sc_datalen[CMD_INQUIRY] = 36; - sc->sc_datalen[CMD_MODE_SELECT] = 12; - sc->sc_datalen[CMD_MODE_SENSE] = 12; - } else if (bcmp("123107 SCSI", product, 11) == 0 || - bcmp("OPEN REEL TAPE", product, 14) == 0) { - sc->sc_tapeid = MT_ISMFOUR; - sc->sc_datalen[CMD_REQUEST_SENSE] = 8; - sc->sc_datalen[CMD_INQUIRY] = 5; - sc->sc_datalen[CMD_MODE_SELECT] = 12; - sc->sc_datalen[CMD_MODE_SENSE] = 12; - } else { - printf("%s: Unsupported tape device, faking it\n", - sc->sc_dev.dv_xname); - sc->sc_tapeid = MT_ISAR; - sc->sc_datalen[CMD_REQUEST_SENSE] = 8; - sc->sc_datalen[CMD_INQUIRY] = 5; - sc->sc_datalen[CMD_MODE_SELECT] = 12; - sc->sc_datalen[CMD_MODE_SENSE] = 12; - } - - sc->sc_filepos = 0; - - /* load xsense */ - scsi_delay(-1); - stxsense(sc->sc_dev.dv_parent->dv_unit, sc->sc_target, sc->sc_lun, sc); - scsi_delay(0); - - /* XXX if we have a tape, we must up the delays in the HA driver */ - if (!havest) { - havest = 1; - scsi_delay(20000); - } - - sc->sc_blkno = 0; - sc->sc_flags = STF_ALIVE; -} - -int -stopen(dev, flag, type, p) - dev_t dev; - int flag, type; - struct proc *p; -{ - struct st_softc *sc; - struct st_xsense *xsense; - int count; - int stat; - int ctlr, slave, unit; - struct mode_select_data msd; - struct mode_sense mode; - int modlen; - int error; - static struct scsi_fmt_cdb modsel = { - 6, - { CMD_MODE_SELECT, 0, 0, 0, sizeof(msd), 0 } - }; - static struct scsi_fmt_cdb modsense = { - 6, - { CMD_MODE_SENSE, 0, 0, 0, sizeof(mode), 0 } - }; - - if (UNIT(dev) >= st_cd.cd_ndevs || - (sc = st_cd.cd_devs[UNIT(dev)]) == NULL || - (sc->sc_flags & STF_ALIVE) == 0) - return (ENXIO); - - if (sc->sc_flags & STF_OPEN) - return (EBUSY); - - ctlr = sc->sc_dev.dv_parent->dv_unit; - slave = sc->sc_target; - unit = sc->sc_lun; - xsense = &sc->sc_sense; - - /* - * Be prepared to print error messages - */ - sc->sc_ctty = tprintf_open(p); - - /* do a mode sense to get current */ - modlen = sc->sc_datalen[CMD_MODE_SENSE]; - modsense.cdb[4] = modlen; - stat = scsi_immed_command(ctlr, slave, unit, &modsense, - (u_char *)&mode, modlen, B_READ); - - /* do a mode sense to get current */ - modlen = sc->sc_datalen[CMD_MODE_SENSE]; - modsense.cdb[4] = modlen; - stat = scsi_immed_command(ctlr, slave, unit, &modsense, - (u_char *)&mode, modlen, B_READ); - - /* set record length */ - switch (sc->sc_tapeid) { - case MT_ISAR: - sc->sc_blklen = 512; - break; - case MT_ISEXABYTE: - if (minor(dev) & STDEV_FIXEDBLK) - sc->sc_blklen = 0x400; - else - sc->sc_blklen = st_exblklen; - break; - case MT_ISHPDAT: - sc->sc_blklen = 512; - break; - case MT_ISVIPER1: - sc->sc_blklen = 512; - break; - case MT_ISPYTHON: - sc->sc_blklen = 512; - break; - case MT_ISMFOUR: - sc->sc_blklen = 0; - break; - default: - if ((mode.md.blklen2 << 16 | - mode.md.blklen1 << 8 | - mode.md.blklen0) != 0) - sc->sc_blklen = mode.md.blklen2 << 16 | - mode.md.blklen1 << 8 | - mode.md.blklen0; - else - sc->sc_blklen = 512; - } - - /* setup for mode select */ - msd.rsvd1 = 0; - msd.rsvd2 = 0; - msd.rsvd3 = 0; - msd.buff = 1; - msd.speed = 0; - msd.blkdeslen = 0x08; - msd.density = 0; - msd.blks2 = 0; - msd.blks1 = 0; - msd.blks0 = 0; - msd.rsvd4 = 0; - msd.blklen2 = (sc->sc_blklen >> 16) & 0xff; - msd.blklen1 = (sc->sc_blklen >> 8) & 0xff; - msd.blklen0 = sc->sc_blklen & 0xff; - - /* - * Do we have any density problems? - */ - - switch (sc->sc_tapeid) { - case MT_ISAR: - if (minor(dev) & STDEV_HIDENSITY) - msd.density = 0x5; - else { - if (flag & FWRITE) { - uprintf("Can only write QIC-24\n"); - return(EIO); - } - msd.density = 0x4; - } - break; - case MT_ISEXABYTE: - if (minor(dev) & STDEV_HIDENSITY) - uprintf("EXB-8200 density support only\n"); - msd.vupb = (u_char)st_exvup; - msd.rsvd5 = 0; - msd.p5 = 0; - msd.motionthres = (u_char)st_exmotthr; - msd.reconthres = (u_char)st_exreconthr; - msd.gapthres = (u_char)st_exgapthr; - break; - case MT_ISHPDAT: - case MT_ISVIPER1: - case MT_ISPYTHON: - if (minor(dev) & STDEV_HIDENSITY) - uprintf("Only one density supported\n"); - break; - case MT_ISMFOUR: - break; /* XXX could do density select? */ - default: - uprintf("Unsupported drive\n"); - return(EIO); - } - - modlen = sc->sc_datalen[CMD_MODE_SELECT]; - modsel.cdb[4] = modlen; - - /* mode select */ - count = 0; -retryselect: - stat = scsi_immed_command(ctlr, slave, unit, &modsel, - (u_char *)&msd, modlen, B_WRITE); - /* - * First command after power cycle, bus reset or tape change - * will error. Try command again - */ - if (stat == STS_CHECKCOND) { - sc->sc_filepos = 0; - stxsense(ctlr, slave, unit, sc); - stat = scsi_immed_command(ctlr, slave, unit, &modsel, - (u_char *)&msd, modlen, B_WRITE); -#ifdef DEBUG - if (stat && (st_debug & ST_OPEN)) - printf("stopen: stat on mode select 0x%x second try\n", stat); -#endif - if (stat == STS_CHECKCOND) { - stxsense(ctlr, slave, unit, sc); - prtkey(sc); - } - if (stat) - return(EIO); - } - if (stat == -1 || stat == STS_BUSY) { - /* - * XXX it might just be that the bus is busy because - * another tape is doing a command. This would change - * with connect/disconnect, ie. the other drive would - * not hold onto the bus. - * - * Sleep on lbolt for up to 20 minutes (max time to FSF - * an exabyte to EOT: 16:xx minutes) - */ - if (++count > 60*20) { - uprintf("SCSI bus timeout\n"); - return(EBUSY); - } - if ((error = tsleep((caddr_t)&lbolt, PZERO | PCATCH, - "st_scsiwait", 0))) - return (error); - goto retryselect; - } - - /* drive ready ? */ - stat = scsi_test_unit_rdy(ctlr, slave, unit); - - if (stat == STS_CHECKCOND) { - stxsense(ctlr, slave, unit, sc); - switch (sc->sc_tapeid) { - case MT_ISEXABYTE: - if ((xsense->sc_xsense.key & XSK_NOTRDY) && - xsense->exb_xsense.tnp) - uprintf("no cartridge\n"); - else if (xsense->sc_xsense.key & XSK_NOTRDY) - uprintf("cartridge not loaded\n"); - else if (xsense->sc_xsense.key & XSK_UNTATTEN) { - uprintf("new cart/power interrupt\n"); - stat = 0; - } else if ((xsense->sc_xsense.key & XSK_UNTATTEN) && - xsense->exb_xsense.tnp) - uprintf("cartridge unloading\n"); - else - prtkey(sc); - break; - case MT_ISMFOUR: - case MT_ISAR: - if (xsense->sc_xsense.key & XSK_UNTATTEN) - stat = scsi_test_unit_rdy(ctlr, slave, unit); - if (stat == STS_CHECKCOND) { - stxsense(ctlr, slave, unit, sc); - if (xsense->sc_xsense.key) - prtkey(sc); - } else { - sc->sc_filepos = 0; /* new tape */ - stat = 0; - } - break; - case MT_ISHPDAT: - case MT_ISVIPER1: - case MT_ISPYTHON: - if (xsense->sc_xsense.key & XSK_UNTATTEN) - stat = scsi_test_unit_rdy(ctlr, slave, unit); - if (stat == STS_CHECKCOND) { - stxsense(ctlr, slave, unit, sc); - if (xsense->sc_xsense.key) - prtkey(sc); - } - break; - default: - uprintf("%s: not ready\n", sc->sc_dev.dv_xname); - prtkey(sc); - break; - } - } - if (stat) - return(EIO); - - /* mode sense */ - modlen = sc->sc_datalen[CMD_MODE_SENSE]; - modsense.cdb[4] = modlen; - stat = scsi_immed_command(ctlr, slave, unit, &modsense, - (u_char *)&mode, modlen, B_READ); -#ifdef DEBUG - if (st_debug & ST_OPENSTAT) - prtmodstat(&mode); -#endif - - if (stat == STS_CHECKCOND) { - stxsense(ctlr, slave, unit, sc); -#ifdef DEBUG - if (st_debug & ST_OPEN) - dumpxsense(xsense); -#endif - } - if (stat) - return(EIO); - - if ((flag & FWRITE) && mode.md.wp) { - uprintf("st:%d write protected\n", UNIT(dev)); - return(EACCES); - } - - /* save total number of blocks on tape */ - sc->sc_numblks = mode.md.numblk2 << 16 | - mode.md.numblk1 << 8 | - mode.md.numblk0; - - if (xsense->sc_xsense.eom && !(sc->sc_flags & STF_LEOT)) - sc->sc_filepos = 0; -#ifdef DEBUG - if (st_debug & ST_FMKS) - printf("%s: open filepos = %d\n", sc->sc_dev.dv_xname, - sc->sc_filepos); -#endif - - sc->sc_flags |= (STF_OPEN); - if (flag & FWRITE) - sc->sc_flags |= STF_WMODE; - sc->sc_flags &= ~STF_MOVED; - -#ifdef TTI - /* make stats available, also lit up TTi display */ - sc->sc_tticntdwn = 100; -#endif - stxsense(ctlr, slave, unit, sc); - - return(0); -} - -/*ARGSUSED*/ -int -stclose(dev, flag, mode, p) - dev_t dev; - int flag, mode; - struct proc *p; -{ - struct st_softc *sc = st_cd.cd_devs[UNIT(dev)]; - int hit = 0; - - if ((sc->sc_flags & (STF_WMODE|STF_WRTTN)) == (STF_WMODE|STF_WRTTN)) { - /* - * Cartridge tapes don't do double EOFs on EOT. - * We assume that variable-block devices use double EOF. - */ - stcommand(dev, MTWEOF, 1); - if (sc->sc_blklen == 0) { - stcommand(dev, MTWEOF, 1); - stcommand(dev, MTBSR, 1); - } - hit++; - } - if ((minor(dev) & STDEV_NOREWIND) == 0) { - stcommand(dev, MTREW, 1); - hit++; - } -#ifdef NOTDEF - /* wait until more stable before trying [XXX Needed ?] */ - if (!hit && (sc->sc_flags & SFT_WMODE)) - /* force out any buffered write data */ - stcommand(dev, MTFSR, 0); -#endif - /* make stats available */ - stxsense(sc->sc_dev.dv_parent->dv_unit, sc->sc_target, sc->sc_lun, sc); - - sc->sc_flags &= ~(STF_OPEN|STF_WMODE|STF_WRTTN); - tprintf_close(sc->sc_ctty); - return(0); /* XXX */ -} - -void -ststrategy(bp) - struct buf *bp; -{ - struct st_softc *sc; - struct buf *dp; - int unit, s; - - unit = UNIT(bp->b_dev); - sc = st_cd.cd_devs[unit]; - - dp = &sc->sc_tab; - bp->b_actf = NULL; - s = splbio(); - bp->b_actb = dp->b_actb; - *dp->b_actb = bp; - dp->b_actb = &bp->b_actf; - if (dp->b_active == 0) { - dp->b_active = 1; - stustart(unit); - } - splx(s); -} - -void -stustart(unit) - int unit; -{ - struct st_softc *sc = st_cd.cd_devs[unit]; - - if (scsireq(sc->sc_dev.dv_parent, &sc->sc_sq)) - ststart(sc); -} - -void -ststart(arg) - void *arg; -{ - struct st_softc *sc = arg; - - if (scsiustart(sc->sc_dev.dv_parent->dv_unit)) - stgo(arg); -} - -void -stgo(arg) - void *arg; -{ - struct st_softc *sc = arg; - struct scsi_fmt_cdb *cmd; - struct buf *bp = sc->sc_tab.b_actf; - int pad, stat; - long nblks; - - if (sc->sc_flags & STF_CMD) { - cmd = &sc->sc_cmdstore; - pad = 0; - } else { - cmd = bp->b_flags & B_READ ? &st_read_cmd : &st_write_cmd; - if (sc->sc_blklen) - cmd->cdb[1] |= 0x01; /* fixed mode */ - else - cmd->cdb[1] &= 0xfe; - if (bp->b_flags & B_READ) - sc->sc_flags &= ~STF_WRTTN; - else - sc->sc_flags |= STF_WRTTN; - - if (sc->sc_blklen) { /* fixed mode */ - nblks = bp->b_bcount / sc->sc_blklen; - if (bp->b_bcount % sc->sc_blklen) { - tprintf(sc->sc_ctty, - "%s: I/O not block aligned %d/%ld\n", - sc->sc_dev.dv_xname, sc->sc_blklen, - bp->b_bcount); - cmd->cdb[1] &= 0xfe; /* force error */ - } - } else /* variable len */ - nblks = bp->b_bcount; - - *(u_char *)(&cmd->cdb[2]) = (u_char) (nblks >> 16); - *(u_char *)(&cmd->cdb[3]) = (u_char) (nblks >> 8); - *(u_char *)(&cmd->cdb[4]) = (u_char) nblks; - /* - * Always Zero. We are either writing in variable - * length mode we are writing in fixed block mode, - * or we are going to do odd length IO and are not - * going to use DMA. - */ - pad = 0; - } - -#ifdef DEBUG - if (st_debug & ST_GO) - printf("stgo: cmd len %d [0]0x%x [1]0x%x [2]0x%x [3]0x%x [4]0x%x [5]0x%x\n", - cmd->len, cmd->cdb[0], cmd->cdb[1], cmd->cdb[2], - cmd->cdb[3], cmd->cdb[4], cmd->cdb[5]); -#endif - - sc->sc_flags |= STF_MOVED; - if (bp->b_bcount & 1) { -#ifdef DEBUG - if (st_debug & ST_ODDIO) - printf("%s: stgo: odd count %ld using manual transfer\n", - sc->sc_dev.dv_xname, bp->b_bcount); -#endif - stat = scsi_tt_oddio(sc->sc_dev.dv_parent->dv_unit, - sc->sc_target, sc->sc_lun, bp->b_un.b_addr, bp->b_bcount, - bp->b_flags, 1); - if (stat == 0) { - bp->b_resid = 0; - stfinish(sc, bp); - } - } else - stat = scsigo(sc->sc_dev.dv_parent->dv_unit, - sc->sc_target, sc->sc_lun, bp, cmd, pad); - if (stat) { - bp->b_error = EIO; - bp->b_flags |= B_ERROR; - stxsense(sc->sc_dev.dv_parent->dv_unit, sc->sc_target, - sc->sc_lun, sc); - sterror(sc, stat); - stfinish(sc, bp); - } -} - -static void -stfinish(sc, bp) - struct st_softc *sc; - struct buf *bp; -{ - struct buf *dp; - - sc->sc_tab.b_errcnt = 0; - if ((dp = bp->b_actf)) - dp->b_actb = bp->b_actb; - else - sc->sc_tab.b_actb = bp->b_actb; - *bp->b_actb = dp; - biodone(bp); - scsifree(sc->sc_dev.dv_parent, &sc->sc_sq); - if (sc->sc_tab.b_actf) - stustart(sc->sc_dev.dv_unit); - else - sc->sc_tab.b_active = 0; -} - -int -stread(dev, uio, flags) - dev_t dev; - struct uio *uio; - int flags; -{ - - return (physio(ststrategy, NULL, dev, B_READ, minphys, uio)); -} - -int -stwrite(dev, uio, flags) - dev_t dev; - struct uio *uio; - int flags; -{ - - /* XXX: check for hardware write-protect? */ - return (physio(ststrategy, NULL, dev, B_WRITE, minphys, uio)); -} - -/*ARGSUSED*/ -int -stdump(dev_t dev, daddr_t blkno, caddr_t va, size_t size) -{ - return(ENXIO); -} - -/*ARGSUSED*/ -int -stioctl(dev, cmd, data, flag, p) - dev_t dev; - u_long cmd; - caddr_t data; - int flag; - struct proc *p; -{ - struct st_softc *sc = st_cd.cd_devs[UNIT(dev)]; - int cnt; - struct mtget *mtget; - struct st_xsense *xp = &sc->sc_sense; - struct mtop *op; - long resid = 0; /* XXX compiler complains needlessly :-( */ - - switch (cmd) { - - /* tape operation */ - case MTIOCTOP: - op = (struct mtop *)data; - switch (op->mt_op) { - - case MTBSR: - case MTFSR: - if (sc->sc_tapeid == MT_ISAR) - return(ENXIO); - case MTWEOF: - case MTFSF: - case MTBSF: - cnt = (int)op->mt_count; - break; - - case MTREW: - case MTOFFL: - cnt = 1; - break; - - case MTNOP: - return(0); - default: - return(EINVAL); - } - if (cnt <= 0) - return(EINVAL); - stcommand(dev, (u_int)op->mt_op, cnt); - break; - - /* drive status */ - case MTIOCGET: - mtget = (struct mtget *)data; - stxsense(sc->sc_dev.dv_parent->dv_unit, sc->sc_target, - sc->sc_lun, sc); - mtget->mt_type = sc->sc_tapeid; - mtget->mt_dsreg = 0; - mtget->mt_erreg = ((xp->sc_xsense.valid << 15) | - (xp->sc_xsense.filemark << 14) | - (xp->sc_xsense.eom << 13) | - (xp->sc_xsense.ili << 12) | - (xp->sc_xsense.key << 8)); - - if (sc->sc_tapeid == MT_ISEXABYTE) { - mtget->mt_dsreg = sc->sc_flags; - resid = (xp->exb_xsense.tplft2 << 16 | - xp->exb_xsense.tplft1 << 8 | - xp->exb_xsense.tplft0); - mtget->mt_resid = resid / 1000; - mtget->mt_erreg |= (((xp->exb_xsense.rwerrcnt2 << 16 | - xp->exb_xsense.rwerrcnt1 << 8 | - xp->exb_xsense.rwerrcnt0) * 100) / - (sc->sc_numblks - resid)) & 0xff; - } else if (xp->sc_xsense.valid) { - resid = ((xp->sc_xsense.info1 << 24) | - (xp->sc_xsense.info2 << 16) | - (xp->sc_xsense.info3 << 8) | - (xp->sc_xsense.info4)); - if (sc->sc_blklen) /* if fixed mode */ - resid *= sc->sc_blklen; - mtget->mt_resid = resid; - } else - mtget->mt_resid = 0; - break; - - default: - return(ENXIO); - } - return(0); -} - -void -stintr(arg, stat) - void *arg; - int stat; -{ - struct st_softc *sc = arg; - struct st_xsense *xp = &sc->sc_sense; - struct buf *bp = sc->sc_tab.b_actf; - -#ifdef DEBUG - if (bp == NULL) { - printf("%s: bp == NULL\n", sc->sc_dev.dv_xname); - return; - } -#endif - switch (stat) { - /* scsi command completed ok */ - case 0: - bp->b_resid = 0; - break; - - /* more status */ - case STS_CHECKCOND: - stxsense(sc->sc_dev.dv_parent->dv_unit, sc->sc_target, - sc->sc_lun, sc); - if (xp->sc_xsense.valid) { - bp->b_resid = (u_long)((xp->sc_xsense.info1 << 24) | - (xp->sc_xsense.info2 << 16) | - (xp->sc_xsense.info3 << 8) | - (xp->sc_xsense.info4)); - if (sc->sc_blklen) /* fixed mode */ - bp->b_resid *= sc->sc_blklen; - } - if (xp->sc_xsense.filemark) { - sc->sc_filepos++; - break; - } - if (xp->sc_xsense.key != XSK_NOSENCE - && xp->sc_xsense.key != XSK_NOTUSED1 - && xp->sc_xsense.key != XSK_NOTUSEDC - && xp->sc_xsense.key != XSK_NOTUSEDE) { - sterror(sc, stat); - bp->b_flags |= B_ERROR; - bp->b_error = EIO; - break; - } - if (xp->sc_xsense.ili) { - /* - * Fixed length blocks, an error. - */ - if (sc->sc_blklen) { - tprintf(sc->sc_ctty, - "%s: Incorrect Length Indicator, blkcnt diff %d\n", - sc->sc_dev.dv_xname, - sc->sc_blklen - bp->b_resid); - bp->b_flags |= B_ERROR; - bp->b_error = EIO; - break; - } - /* - * Variable length but read more than requested, - * an error. (XXX ??? wrong for 9 track?) - */ - if (bp->b_resid < 0) { - bp->b_resid = 0; - bp->b_flags |= B_ERROR; - bp->b_error = ENOMEM; - break; - } - /* - * Variable length and odd, may require special - * handling. - */ - if (bp->b_resid & 1 && (sc->sc_tapeid != MT_ISAR)) { - /* - * Normal behavior, treat as an error. - */ - if (!st_dmaoddretry) { - tprintf(sc->sc_ctty, - "%s: Odd length read %ld\n", - sc->sc_dev.dv_xname, - bp->b_bcount - bp->b_resid); - bp->b_error = EIO; - bp->b_flags |= B_ERROR; - break; - } - /* - * Attempt to back up and re-read using oddio. - */ -#ifdef DEBUG - if (st_debug & ST_ODDIO) - printf("%s: stintr odd count %ld, do BSR then oddio\n", - sc->sc_dev.dv_xname, - bp->b_bcount - bp->b_resid); -#endif - stat = - scsi_tt_oddio(sc->sc_dev.dv_parent->dv_unit, - sc->sc_target, sc->sc_lun, 0, -1, 0, 0); - if (stat == 0) - stat = scsi_tt_oddio( - sc->sc_dev.dv_parent->dv_unit, - sc->sc_target, sc->sc_lun, - bp->b_un.b_addr, - bp->b_bcount - bp->b_resid, - bp->b_flags, 0); - if (stat) { - bp->b_error = EIO; - bp->b_flags |= B_ERROR; - stxsense(sc->sc_dev.dv_parent->dv_unit, - sc->sc_target, sc->sc_lun, sc); - sterror(sc, stat); - } - } - break; - } - if (xp->sc_xsense.eom) { - bp->b_flags |= B_ERROR; - bp->b_error = ENOSPC; - break; - } - tprintf(sc->sc_ctty, "%s: unknown scsi error\n", - sc->sc_dev.dv_xname); - bp->b_flags |= B_ERROR; - bp->b_error = EIO; - break; - - default: - printf("%s: stintr unknown stat 0x%x\n", sc->sc_dev.dv_xname, - stat); - break; - } -#ifdef DEBUG - if ((st_debug & ST_BRESID) && bp->b_resid != 0) - printf("b_resid %u b_flags 0x%lx b_error 0x%x\n", - bp->b_resid, bp->b_flags, bp->b_error); -#endif - /* asked for more filemarks then on tape */ - if (bp->b_resid != 0 && - (sc->sc_flags & STF_CMD) && sc->sc_cmd == CMD_SPACE) { - sc->sc_filepos -= bp->b_resid; - if (sc->sc_filepos < 0) - sc->sc_filepos = 0; - } - -#ifdef TTI - if (st_extti & (1 << sc->sc_dev.dv_unit) && - sc->sc_type == MT_ISEXABYTE) /* to make display lit up */ - /* - * XXX severe performance penality for this. - * Try and throttle by not calling stxsense on every intr. - * Mostly for TTi we, get a stxsense call in open and close. - */ - if (sc->sc_tticntdwn-- == 0) { - stxsense(sc->sc_dev.dv_parent->dv_unit, - sc->sc_target, sc->sc_lun, sc); - sc->sc_tticntdwn = 100; - } -#endif - - stfinish(sc, bp); -} - -void -stcommand(dev, command, cnt) - dev_t dev; - u_int command; - int cnt; -{ - struct st_softc *sc = st_cd.cd_devs[UNIT(dev)]; - struct buf *bp = &sc->sc_bufstore; - struct scsi_fmt_cdb *cmd = &sc->sc_cmdstore; - int cmdcnt, s; - - cmd->len = 6; /* all tape commands are cdb6 */ - cmd->cdb[1] = sc->sc_lun; - cmd->cdb[2] = cmd->cdb[3] = cmd->cdb[4] = cmd->cdb[5] = 0; - cmdcnt = 0; - - /* - * XXX Assumption is that everything except Archive can take - * repeat count in cdb block. - */ - switch (command) { - case MTWEOF: - cmd->cdb[0] = CMD_WRITE_FILEMARK; - if (sc->sc_tapeid != MT_ISAR) { - cmdcnt = cnt; - cnt = 1; - } else - cmdcnt = 1; - *(u_char *)(&cmd->cdb[2]) = (u_char) (cmdcnt >> 16); - *(u_char *)(&cmd->cdb[3]) = (u_char) (cmdcnt >> 8); - *(u_char *)(&cmd->cdb[4]) = (u_char) cmdcnt; - - if (sc->sc_tapeid == MT_ISEXABYTE && - (minor(dev) & STDEV_EXSFMK)) /* short filemarks */ - cmd->cdb[5] |= 0x80; - else - cmd->cdb[5] &= 0x7f; - break; - case MTBSF: - /* Archive can't back up, will not get to BSR case */ - if (sc->sc_tapeid == MT_ISAR) { - if ((sc->sc_filepos - cnt) < 0) { - stcommand(dev, MTREW, 1); - return; - } - cmdcnt = sc->sc_filepos - cnt + 1; - stcommand(dev, MTREW, 1); - stcommand(dev, MTFSF, cmdcnt); - return; - } - case MTBSR: - case MTFSR: - case MTFSF: - if (command == MTBSF || command == MTBSR) - cnt = cnt * (-1); /* backward move */ - if (command == MTFSF || command == MTBSF) - cmd->cdb[1] |= 0x01; /* filemarks */ - else - cmd->cdb[1] |= 0x00; /* logical blocks */ - if (sc->sc_tapeid != MT_ISAR) { - cmdcnt = cnt; - cnt = 1; - } else - cmdcnt = 1; - *(u_char *)(&cmd->cdb[2]) = (u_char) (cmdcnt >> 16); - *(u_char *)(&cmd->cdb[3]) = (u_char) (cmdcnt >> 8); - *(u_char *)(&cmd->cdb[4]) = (u_char) cmdcnt; - cmd->cdb[0] = CMD_SPACE; - break; - case MTREW: - cmd->cdb[0] = CMD_REWIND; - sc->sc_filepos = 0; - break; - case MTOFFL: - cmd->cdb[0] = CMD_LOADUNLOAD; - sc->sc_filepos = 0; - break; - default: - printf("%s: stcommand bad command 0x%x\n", - sc->sc_dev.dv_xname, command); - } - - sc->sc_flags |= STF_CMD; - sc->sc_cmd = cmd->cdb[0]; - - sc->sc_bp = bp; -again: -#ifdef DEBUG - if (st_debug & ST_FMKS) - printf("%s: stcommand filepos %d cmdcnt %d cnt %d\n", - sc->sc_dev.dv_xname, sc->sc_filepos, cmdcnt, cnt); -#endif - s = splbio(); - while (bp->b_flags & B_BUSY) { - if (bp->b_flags & B_DONE) - break; - bp->b_flags |= B_WANTED; - tsleep((caddr_t)bp, PRIBIO, "stcommand", 0); - } - bp->b_flags = B_BUSY|B_READ; - splx(s); - bp->b_dev = dev; - bp->b_bcount = 0; - bp->b_resid = 0; - bp->b_blkno = 0; - bp->b_error = 0; - ststrategy(bp); - biowait(bp); - if (bp->b_flags & B_WANTED) - wakeup((caddr_t)bp); - bp->b_flags &= B_ERROR; - - if (command == MTWEOF || command == MTFSF || command == MTBSF) - sc->sc_filepos += cmdcnt; - - if (--cnt > 0) - goto again; - - sc->sc_flags |= STF_MOVED; - sc->sc_flags &= ~(STF_CMD|STF_WRTTN); -} - -static void -sterror(sc, stat) - struct st_softc *sc; - int stat; -{ - /* stxsense must have been called before sterror() */ - if (stat & STS_CHECKCOND) - prtkey(sc); - else if (stat) - tprintf(sc->sc_ctty, - "%s: bad scsi status 0x%x\n", sc->sc_dev.dv_xname, - stat); - - if ((sc->sc_flags & STF_CMD) && sc->sc_cmd == CMD_SPACE) /* fsf */ - sc->sc_filepos--; -} - -void -stxsense(ctlr, slave, unit, sc) - int ctlr, slave, unit; - struct st_softc *sc; -{ - unsigned len; - - len = sc->sc_datalen[CMD_REQUEST_SENSE]; - scsi_request_sense(ctlr, slave, unit, (u_char *)&sc->sc_sense, len); -} - -void -prtkey(sc) - struct st_softc *sc; -{ - struct st_xsense *xp = &sc->sc_sense; - - switch (xp->sc_xsense.key) { - case XSK_NOSENCE: - break; - case XSK_NOTUSED1: - case XSK_NOTUSEDC: - case XSK_NOTUSEDE: - break; - case XSK_REVERVED: - tprintf(sc->sc_ctty, "%s: Reserved sense key 0x%x\n", - sc->sc_dev.dv_xname, xp->sc_xsense.key); - break; - case XSK_NOTRDY: - tprintf(sc->sc_ctty, "%s: NOT READY\n", sc->sc_dev.dv_xname); - break; - case XSK_MEDERR: - tprintf(sc->sc_ctty, "%s: MEDIUM ERROR\n", sc->sc_dev.dv_xname); - break; - case XSK_HRDWERR: - tprintf(sc->sc_ctty, "%s: HARDWARE ERROR\n", - sc->sc_dev.dv_xname); - break; - case XSK_ILLREQ: - tprintf(sc->sc_ctty, "%s: ILLEGAL REQUEST\n", - sc->sc_dev.dv_xname); - break; - case XSK_UNTATTEN: - tprintf(sc->sc_ctty, "%s: UNIT ATTENTION\n", - sc->sc_dev.dv_xname); - break; - case XSK_DATAPROT: - tprintf(sc->sc_ctty, "%s: DATA PROTECT\n", sc->sc_dev.dv_xname); - break; - case XSK_BLNKCHK: - tprintf(sc->sc_ctty, "%s: BLANK CHECK\n", sc->sc_dev.dv_xname); - break; - case XSK_VENDOR: - tprintf(sc->sc_ctty, "%s: VENDER UNIQUE SENSE KEY ", - sc->sc_dev.dv_xname); - switch (sc->sc_tapeid) { - case MT_ISEXABYTE: - tprintf(sc->sc_ctty, "Exabyte: "); - if (xp->exb_xsense.xfr) - tprintf(sc->sc_ctty, - "Transfer Abort Error\n"); - if (xp->exb_xsense.tmd) - tprintf(sc->sc_ctty, - "Tape Mark Detect Error\n"); - break; - default: - tprintf(sc->sc_ctty, "\n"); - } - break; - case XSK_CPYABORT: - tprintf(sc->sc_ctty, "%s: COPY ABORTED\n", sc->sc_dev.dv_xname); - break; - case XSK_ABORTCMD: - tprintf(sc->sc_ctty, "%s: ABORTED COMMAND\n", - sc->sc_dev.dv_xname); - break; - case XSK_VOLOVER: - tprintf(sc->sc_ctty, "%s: VOLUME OVERFLOW\n", - sc->sc_dev.dv_xname); - break; - default: - tprintf(sc->sc_ctty, "%s: unknown sense key 0x%x\n", - sc->sc_dev.dv_xname, xp->sc_xsense.key); - } - if (sc->sc_tapeid == MT_ISEXABYTE) { - if (xp->exb_xsense.bpe) - tprintf(sc->sc_ctty, "%s: Bus Parity Error", - sc->sc_dev.dv_xname); - if (xp->exb_xsense.fpe) - tprintf(sc->sc_ctty, - "%s: Formatted Buffer Parity Error", - sc->sc_dev.dv_xname); - if (xp->exb_xsense.eco) - tprintf(sc->sc_ctty, "%s: Error Counter Overflow", - sc->sc_dev.dv_xname); - if (xp->exb_xsense.tme) - tprintf(sc->sc_ctty, "%s: Tape Motion Error", - sc->sc_dev.dv_xname); - if (xp->exb_xsense.xfr) - tprintf(sc->sc_ctty, "%s: Transfer About Error", - sc->sc_dev.dv_xname); - if (xp->exb_xsense.tmd) - tprintf(sc->sc_ctty, "%s: Tape Mark Detect Error", - sc->sc_dev.dv_xname); - if (xp->exb_xsense.fmke) - tprintf(sc->sc_ctty, "%s: Filemark Error", - sc->sc_dev.dv_xname); - if (xp->exb_xsense.ure) - tprintf(sc->sc_ctty, "%s: Under Run Error", - sc->sc_dev.dv_xname); - if (xp->exb_xsense.sse) - tprintf(sc->sc_ctty, "%s: Servo System Error", - sc->sc_dev.dv_xname); - if (xp->exb_xsense.fe) - tprintf(sc->sc_ctty, "%s: Formatter Error", - sc->sc_dev.dv_xname); - if (xp->exb_xsense.wseb) - tprintf(sc->sc_ctty, "%s: WSEB Error", - sc->sc_dev.dv_xname); - if (xp->exb_xsense.wseo) - tprintf(sc->sc_ctty, "%s: WSEO Error", - sc->sc_dev.dv_xname); - } -} - -#ifdef DEBUG -void -dumpxsense(sensebuf) - struct st_xsense *sensebuf; -{ - struct st_xsense *xp = sensebuf; - - printf("valid 0x%x errorclass 0x%x errorcode 0x%x\n", - xp->sc_xsense.valid, - xp->sc_xsense.class, xp->sc_xsense.code); - printf("seg number 0x%x\n", xp->sc_xsense.segment); - printf("FMK 0x%x EOM 0x%x ILI 0x%x RSVD 0x%x sensekey 0x%x\n", - xp->sc_xsense.filemark, xp->sc_xsense.eom, xp->sc_xsense.ili, - xp->sc_xsense.rsvd, xp->sc_xsense.key); - printf("info 0x%lx\n", - (u_long)((xp->sc_xsense.info1<<24)|(xp->sc_xsense.info2<<16)| - (xp->sc_xsense.info3<<8)|(xp->sc_xsense.info4)) ); - printf("ASenseL 0x%x\n", xp->sc_xsense.len); - - if (xp->sc_xsense.len != 0x12) /* MT_ISEXB Exabyte only ?? */ - return; /* What about others */ - - printf("ASenseC 0x%x\n", xp->exb_xsense.addsens); - printf("AsenseQ 0x%x\n", xp->exb_xsense.addsensq); - printf("R/W Errors 0x%lx\n", - (u_long)((xp->exb_xsense.rwerrcnt2<<16)| - (xp->exb_xsense.rwerrcnt1<<8)| - (xp->exb_xsense.rwerrcnt1)) ); - printf("PF 0x%x BPE 0x%x FPE 0x%x ME 0x%x ECO 0x%x TME 0x%x TNP 0x%x BOT 0x%x\n", - xp->exb_xsense.pf, xp->exb_xsense.bpe, xp->exb_xsense.fpe, - xp->exb_xsense.me, xp->exb_xsense.eco, xp->exb_xsense.tme, - xp->exb_xsense.tnp, xp->exb_xsense.bot); - printf("XFR 0x%x TMD 0x%x WP 0x%x FMKE 0x%x URE 0x%x WE1 0x%x SSE 0x%x FE 0x%x\n", - xp->exb_xsense.xfr, xp->exb_xsense.tmd, xp->exb_xsense.wp, - xp->exb_xsense.fmke, xp->exb_xsense.ure, xp->exb_xsense.we1, - xp->exb_xsense.sse, xp->exb_xsense.fe); - printf("WSEB 0x%x WSEO 0x%x\n", - xp->exb_xsense.wseb, xp->exb_xsense.wseo); - printf("Remaining Tape 0x%lx\n", - (u_long)((xp->exb_xsense.tplft2<<16)| - (xp->exb_xsense.tplft1<<8)| - (xp->exb_xsense.tplft0)) ); -} - -void -prtmodsel(msd, modlen) - struct mode_select_data *msd; - int modlen; -{ - printf("Modsel command. len is 0x%x.\n", modlen); - printf("rsvd1 0x%x rsvd2 0x%x rsvd3 0x%x buffered 0x%x speed 0x%x bckdeslen 0x%x\n", - msd->rsvd1,msd->rsvd2,msd->rsvd3,msd->buff,msd->speed,msd->blkdeslen); - printf("density 0x%x blks2 0x%x blks1 0x%x blks0 0x%x rsvd 0x%x blklen2 0x%x blklen1 0x%x blklen0 0x%x\n", - msd->density,msd->blks2,msd->blks1,msd->blks0,msd->rsvd4,msd->blklen2,msd->blklen1,msd->blklen0); - printf("vupb 0x%x rsvd 0x%x p5 0x%x motionthres 0x%x reconthres 0x%x gapthres 0x%x \n", - msd->vupb,msd->rsvd5,msd->p5,msd->motionthres,msd->reconthres,msd->gapthres); -} - -void -prtmodstat(mode) - struct mode_sense *mode; -{ - printf("Mode Status\n"); - printf("sdl 0x%x medtype 0x%x wp 0x%x bfmd 0x%x speed 0x%x bdl 0x%x\n", - mode->md.sdl, mode->md.medtype, mode->md.wp, mode->md.bfmd, - mode->md.speed, mode->md.bdl); - printf("dencod 0x%x numblk 0x%x blklen 0x%x\n", - mode->md.dencod, - (mode->md.numblk2<<16)|(mode->md.numblk1<<8)|(mode->md.numblk0), - (mode->md.blklen2<<16)|(mode->md.blklen1<<8)|(mode->md.blklen0) ); - printf("ct 0x%x nd 0x%x nbe 0x%x edb 0x%x pe 0x%x nal 0x%x p5 0x%x\n", - mode->ex.ct, mode->ex.nd, mode->ex.nbe, - mode->ex.ebd, mode->ex.pe, mode->ex.nal, mode->ex.p5); - printf("motionthres 0x%x reconthres 0x%x gapthres 0x%x\n", - mode->ex.motionthres, mode->ex.reconthres, mode->ex.gapthres); -} -#endif /* DEBUG */ diff --git a/sys/arch/hp300/dev/stvar.h b/sys/arch/hp300/dev/stvar.h deleted file mode 100644 index d2e3eb38f37..00000000000 --- a/sys/arch/hp300/dev/stvar.h +++ /dev/null @@ -1,220 +0,0 @@ -/* $OpenBSD: stvar.h,v 1.5 2003/06/02 23:27:45 millert Exp $ */ -/* $NetBSD: stvar.h,v 1.6 1997/04/02 22:37:40 scottr Exp $ */ - -/* - * Copyright (c) 1990 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. 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. - * - * @(#)stvar.h 8.1 (Berkeley) 6/10/93 - */ - -/* - * stvar.h scsi tape driver - */ -struct exb_xsense { - u_char reserved8; - u_char reserved9; - u_char reserved10; - u_char reserved11; - u_char addsens; - u_char addsensq; - u_char reserved14; - u_char reserved15; - u_char rwerrcnt2; - u_char rwerrcnt1; - u_char rwerrcnt0; - u_char pf: 1, - bpe: 1, - fpe: 1, - me: 1, - eco: 1, - tme: 1, - tnp: 1, - bot: 1; - u_char xfr: 1, - tmd: 1, - wp: 1, - fmke: 1, - ure: 1, - we1: 1, - sse: 1, - fe: 1; - u_char rsvd: 6, - wseb: 1, - wseo: 1; - u_char reserved22; - u_char tplft2; - u_char tplft1; - u_char tplft0; -}; - -/* xsense sense key */ -#define XSK_NOSENCE 0x0 -#define XSK_NOTUSED1 0x1 -#define XSK_NOTRDY 0x2 -#define XSK_MEDERR 0x3 -#define XSK_HRDWERR 0x4 -#define XSK_ILLREQ 0x5 -#define XSK_UNTATTEN 0x6 -#define XSK_DATAPROT 0x7 -#define XSK_BLNKCHK 0x8 -#define XSK_VENDOR 0x9 -#define XSK_CPYABORT 0xa -#define XSK_ABORTCMD 0xb -#define XSK_NOTUSEDC 0xc -#define XSK_VOLOVER 0xd -#define XSK_NOTUSEDE 0xe -#define XSK_REVERVED 0xf - -struct exb_inquiry { - char venderunique[16]; -}; - -struct st_mode { - u_char sdl; - u_char medtype; - u_char wp: 1, /* write protect */ - bfmd: 3, /* buffered write mode */ - speed: 4; - u_char bdl; - u_char dencod; - u_char numblk2; /* number of blocks */ - u_char numblk1; - u_char numblk0; - u_char rsvd1; - u_char blklen2; /* block length */ - u_char blklen1; - u_char blklen0; -}; - -struct st_mode_exvup { - /* vender unique */ - u_char ct: 1, /* international cartridge */ - rs1: 1, - nd: 1, /* no disconnect, date transfer */ - rs2: 1, - nbe: 1, /* no busy enable */ - ebd: 1, /* even byte disconnect */ - pe: 1, /* parity enable */ - nal: 1; /* no auto load */ - u_char rsvd: 7, - p5: 1; - u_char motionthres; - u_char reconthres; - u_char gapthres; -}; - -struct mode_select_data { - u_char rsvd1; - u_char rsvd2; - u_char rsvd3: 1, - buff: 3, - speed: 4; - u_char blkdeslen; - u_char density; - u_char blks2; - u_char blks1; - u_char blks0; - u_char rsvd4; - u_char blklen2; - u_char blklen1; - u_char blklen0; - u_char vupb; - u_char rsvd5: 7, - p5: 1; - u_char motionthres; - u_char reconthres; - u_char gapthres; -}; - -struct mode_sense { - struct st_mode md; - struct st_mode_exvup ex; -}; - -#define EXDS_BITS \ -"\20\20\ -\7MOVED\6LEOT\5CMD\4WRTTN\3WMODE\2OPEN\1ALIV" - -#define EXER_BITS \ -"\20\20VAL\17FMK\16EOM\15ILI\14KEY3\13KEY2\12KEY1\11KEY0\ -\10RETRY7\7RETRY6\6RETRY5\5RETRY4\4RETRY3\3RETRY2\2RETRY1\1RETRY0" - -struct st_xsense { - struct scsi_xsense sc_xsense; /* data from sense */ - struct exb_xsense exb_xsense; /* additional info from exabyte */ -}; - -struct st_softc { - struct device sc_dev; - struct scsiqueue sc_sq; - long sc_blkno; /* (possible block device support?) */ - long sc_resid; /* (possible block device support?) */ - int sc_flags; - int sc_blklen; /* 0 = variable len records */ - int sc_filepos; /* file position on tape */ - long sc_numblks; /* number of blocks on tape */ - short sc_type; /* ansi scsi type */ - int sc_target; - int sc_lun; - short sc_tapeid; /* tape drive id */ - char sc_datalen[32]; /* additional data length on some commands */ - short sc_tticntdwn; /* interrupts between TTi display updates */ - tpr_t sc_ctty; - struct buf *sc_bp; - u_char sc_cmd; - struct st_xsense sc_sense; - struct scsi_fmt_cdb sc_cmdstore; - struct buf sc_tab; /* buffer queue */ - struct buf sc_bufstore; /* XXX buffer storage */ -}; - -/* softc flags */ -#define STF_ALIVE 0x0001 -#define STF_OPEN 0x0002 -#define STF_WMODE 0x0004 -#define STF_WRTTN 0x0008 -#define STF_CMD 0x0010 -#define STF_LEOT 0x0020 -#define STF_MOVED 0x0040 - -#ifdef _KERNEL -void stcommand(dev_t, u_int, int); -void stustart(int); - -void ststart(void *); -void stgo(void *); -void stintr(void *, int); - -void stxsense(int, int, int, struct st_softc *); -void prtkey(struct st_softc *); -#endif /* _KERNEL */ diff --git a/sys/arch/hp300/hp300/autoconf.c b/sys/arch/hp300/hp300/autoconf.c index 4f429cec6c8..20140db6314 100644 --- a/sys/arch/hp300/hp300/autoconf.c +++ b/sys/arch/hp300/hp300/autoconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: autoconf.c,v 1.25 2003/06/02 23:27:45 millert Exp $ */ +/* $OpenBSD: autoconf.c,v 1.26 2004/08/03 21:46:58 miod Exp $ */ /* $NetBSD: autoconf.c,v 1.45 1999/04/10 17:31:02 kleink Exp $ */ /* @@ -93,14 +93,14 @@ #include <hp300/dev/hilvar.h> #include <hp300/dev/hpibvar.h> -#include <hp300/dev/scsivar.h> +#include <scsi/scsi_all.h> +#include <scsi/scsiconf.h> /* * The following several variables are related to * the configuration process, and are used in initializing * the machine. */ -int cold; /* if 1, still working on cold-start */ struct extent *extio; @@ -340,16 +340,16 @@ device_register(dev, aux) goto linkup; } - if (bcmp(dev->dv_xname, "fhpib", 5) == 0 || - bcmp(dev->dv_xname, "nhpib", 5) == 0 || - bcmp(dev->dv_xname, "oscsi", 5) == 0) { + if (strncmp(dev->dv_xname, "fhpib", 5) == 0 || + strncmp(dev->dv_xname, "nhpib", 5) == 0 || + strncmp(dev->dv_xname, "spc", 3) == 0) { struct dio_attach_args *da = aux; dd->dd_scode = da->da_scode; goto linkup; } - if (bcmp(dev->dv_xname, "hd", 2) == 0) { + if (strncmp(dev->dv_xname, "hd", 2) == 0) { struct hpibbus_attach_args *ha = aux; dd->dd_slave = ha->ha_slave; @@ -357,11 +357,13 @@ device_register(dev, aux) goto linkup; } - if (bcmp(dev->dv_xname, "sd", 2) == 0) { - struct oscsi_attach_args *osa = aux; + if (strncmp(dev->dv_xname, "cd", 2) == 0 || + strncmp(dev->dv_xname, "sd", 2) == 0 || + strncmp(dev->dv_xname, "st", 2) == 0) { + struct scsibus_attach_args *sa = aux; - dd->dd_slave = osa->osa_target; - dd->dd_punit = osa->osa_lun; + dd->dd_slave = sa->sa_sc_link->target; + dd->dd_punit = sa->sa_sc_link->lun; goto linkup; } @@ -374,13 +376,13 @@ device_register(dev, aux) linkup: LIST_INSERT_HEAD(&dev_data_list, dd, dd_list); - if (bcmp(dev->dv_xname, "fhpib", 5) == 0 || - bcmp(dev->dv_xname, "nhpib", 5) == 0) { + if (strncmp(dev->dv_xname, "fhpib", 5) == 0 || + strncmp(dev->dv_xname, "nhpib", 5) == 0) { dev_data_insert(dd, &dev_data_list_hpib); return; } - if (bcmp(dev->dv_xname, "oscsi", 5) == 0) { + if (strncmp(dev->dv_xname, "spc", 3) == 0) { dev_data_insert(dd, &dev_data_list_scsi); return; } @@ -417,7 +419,9 @@ struct nam2blk { { "ct", 0 }, { "hd", 2 }, { "sd", 4 }, + { "st", 7 }, { "rd", 8 }, + { "cd", 9 }, }; static int @@ -860,16 +864,18 @@ findbootdev() if (booted_device == NULL) return; +#ifdef DIAGNOSTIC /* * Sanity check. */ - if ((type == 0 && bcmp(booted_device->dv_xname, "ct", 2)) || - (type == 2 && bcmp(booted_device->dv_xname, "hd", 2))) { + if ((type == 0 && strncmp(booted_device->dv_xname, "ct", 2)) || + (type == 2 && strncmp(booted_device->dv_xname, "hd", 2))) { printf("WARNING: boot device/type mismatch!\n"); printf("device = %s, type = %d\n", booted_device->dv_xname, type); booted_device = NULL; } +#endif return; } @@ -882,15 +888,19 @@ findbootdev() if (booted_device == NULL) return; +#ifdef DIAGNOSTIC /* * Sanity check. */ - if ((type == 4 && bcmp(booted_device->dv_xname, "sd", 2))) { + if (strncmp(booted_device->dv_xname, "cd", 2) != 0 && + strncmp(booted_device->dv_xname, "sd", 2) != 0 && + strncmp(booted_device->dv_xname, "st", 2) != 0) { printf("WARNING: boot device/type mismatch!\n"); printf("device = %s, type = %d\n", booted_device->dv_xname, type); booted_device = NULL; } +#endif return; } @@ -925,23 +935,11 @@ findbootdev_slave(ddlist, ctlr, slave, punit) for (dd = dev_data_list.lh_first; dd != NULL; dd = dd->dd_list.le_next) { /* - * XXX We don't yet have the extra bus indirection - * XXX for SCSI, so we have to do a little bit of - * XXX extra work. + * "sd" / "st" / "cd" -> "scsibus" -> "spc" + * "hd" -> "hpibbus" -> "fhpib" */ - if (bcmp(dd->dd_dev->dv_xname, "sd", 2) == 0) { - /* - * "sd" -> "oscsi" - */ - if (dd->dd_dev->dv_parent != cdd->dd_dev) - continue; - } else { - /* - * "hd" -> "hpibbus" -> "fhpib" - */ - if (dd->dd_dev->dv_parent->dv_parent != cdd->dd_dev) - continue; - } + if (dd->dd_dev->dv_parent->dv_parent != cdd->dd_dev) + continue; if (dd->dd_slave == slave && dd->dd_punit == punit) { @@ -965,13 +963,13 @@ setbootdev() * * 0 == ct * 2 == hd - * 4 == sd + * 4 == scsi * 6 == le * - * Allare bdevsw major numbers, except for le, which - * is just special. - * - * We can't mount root on a tape, so we ignore those. + * All are bdevsw major numbers, except for le, which + * is just special. SCSI needs specific care since the + * ROM wants to see 4, but depending upon the real device + * we booted from, we might have a different major value. */ /* @@ -999,9 +997,12 @@ setbootdev() /* * Determine device type. */ - if (bcmp(root_device->dv_xname, "hd", 2) == 0) + if (strncmp(root_device->dv_xname, "hd", 2) == 0) type = 2; - else if (bcmp(root_device->dv_xname, "sd", 2) == 0) + else if (strncmp(root_device->dv_xname, "cd", 2) == 0 || + strncmp(root_device->dv_xname, "sd", 2) == 0 || + strncmp(root_device->dv_xname, "st", 2) == 0) + /* force scsi disk regardless of the actual device */ type = 4; else { printf("WARNING: strange root device!\n"); @@ -1010,43 +1011,20 @@ setbootdev() /* * Get parent's info. + * + * "hd" -> "hpibbus" -> "fhpib" + * "sd" / "cd" / "st" -> "scsibus" -> "spc" */ - switch (type) { - case 2: - /* - * "hd" -> "hpibbus" -> "fhpib" - */ - for (cdd = dev_data_list_hpib.lh_first, ctlr = 0; - cdd != NULL; cdd = cdd->dd_clist.le_next, ctlr++) { - if (cdd->dd_dev == root_device->dv_parent->dv_parent) { - /* - * Found it! - */ - bootdev = MAKEBOOTDEV(type, - ctlr, dd->dd_slave, dd->dd_punit, - DISKPART(rootdev)); - break; - } - } - break; - - case 4: - /* - * "sd" -> "oscsi" - */ - for (cdd = dev_data_list_scsi.lh_first, ctlr = 0; - cdd != NULL; cdd = cdd->dd_clist.le_next, ctlr++) { - if (cdd->dd_dev == root_device->dv_parent) { - /* - * Found it! - */ - bootdev = MAKEBOOTDEV(type, - ctlr, dd->dd_slave, dd->dd_punit, - DISKPART(rootdev)); - break; - } + for (cdd = dev_data_list_hpib.lh_first, ctlr = 0; + cdd != NULL; cdd = cdd->dd_clist.le_next, ctlr++) { + if (cdd->dd_dev == root_device->dv_parent->dv_parent) { + /* + * Found it! + */ + bootdev = MAKEBOOTDEV(type, ctlr, dd->dd_slave, + dd->dd_punit, DISKPART(rootdev)); + break; } - break; } out: @@ -1086,8 +1064,7 @@ dev_data_insert(dd, ddlist) #ifdef DIAGNOSTIC if (dd->dd_scode < 0 || dd->dd_scode > 255) { - printf("bogus select code for %s\n", dd->dd_dev->dv_xname); - panic("dev_data_insert"); + panic("bogus select code for %s", dd->dd_dev->dv_xname); } #endif diff --git a/sys/arch/hp300/hp300/conf.c b/sys/arch/hp300/hp300/conf.c index 46fb9b97a81..a95ae75b598 100644 --- a/sys/arch/hp300/hp300/conf.c +++ b/sys/arch/hp300/hp300/conf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: conf.c,v 1.35 2004/02/10 01:31:21 millert Exp $ */ +/* $OpenBSD: conf.c,v 1.36 2004/08/03 21:46:58 miod Exp $ */ /* $NetBSD: conf.c,v 1.39 1997/05/12 08:17:53 thorpej Exp $ */ /*- @@ -40,17 +40,21 @@ #include <sys/conf.h> #include <sys/vnode.h> +#include "ccd.h" +#include "cd.h" +#include "ch.h" #include "ct.h" bdev_decl(ct); #include "mt.h" bdev_decl(mt); #include "hd.h" bdev_decl(hd); +#include "rd.h" #include "sd.h" -#include "ccd.h" -#include "vnd.h" +#include "ss.h" #include "st.h" -#include "rd.h" +#include "uk.h" +#include "vnd.h" struct bdevsw bdevsw[] = { @@ -63,12 +67,13 @@ struct bdevsw bdevsw[] = bdev_disk_init(NVND,vnd), /* 6: vnode disk driver */ bdev_tape_init(NST,st), /* 7: SCSI tape */ bdev_disk_init(NRD,rd), /* 8: RAM disk */ - bdev_lkm_dummy(), /* 9 */ + bdev_disk_init(NCD,cd), /* 9: SCSI CD-ROM */ bdev_lkm_dummy(), /* 10 */ bdev_lkm_dummy(), /* 11 */ bdev_lkm_dummy(), /* 12 */ bdev_lkm_dummy(), /* 13 */ bdev_lkm_dummy(), /* 14 */ + bdev_lkm_dummy(), /* 15 */ }; int nblkdev = sizeof(bdevsw) / sizeof(bdevsw[0]); @@ -146,7 +151,7 @@ struct cdevsw cdevsw[] = cdev_tty_init(NDCM,dcm), /* 15: 4-port serial */ cdev_tape_init(NMT,mt), /* 16: magnetic reel tape */ cdev_disk_init(NCCD,ccd), /* 17: concatenated disk */ - cdev_notdef(), /* 18 */ + cdev_disk_init(NCD,cd), /* 18: SCSI CD-ROM */ cdev_disk_init(NVND,vnd), /* 19: vnode disk driver */ cdev_tape_init(NST,st), /* 20: SCSI tape */ cdev_fd_init(1,filedesc), /* 21: file descriptor pseudo-device */ @@ -165,9 +170,9 @@ struct cdevsw cdevsw[] = cdev_disk_init(NRD,rd), /* 34: RAM disk */ cdev_tty_init(NAPCI,apci), /* 35: Apollo APCI UARTs */ cdev_ksyms_init(NKSYMS,ksyms), /* 36: Kernel symbols device */ - cdev_notdef(), /* 37 */ - cdev_notdef(), /* 38 */ - cdev_notdef(), /* 39 */ + cdev_uk_init(NUK,uk), /* 37 */ + cdev_ss_init(NSS,ss), /* 38 */ + cdev_ch_init(NCH,ch), /* 39 */ cdev_notdef(), /* 40 */ cdev_notdef(), /* 41 */ cdev_notdef(), /* 42 */ @@ -252,7 +257,7 @@ int chrtoblktbl[] = { /* 15 */ NODEV, /* 16 */ NODEV, /* 17 */ 5, - /* 18 */ NODEV, + /* 18 */ 9, /* 19 */ 6, /* 20 */ 7, /* 21 */ NODEV, |