BSD 4_4 release
[unix-history] / usr / src / sys / hp300 / dev / scsi.c
index 777e763..883d2ef 100644 (file)
@@ -1,15 +1,44 @@
 /*
 /*
- * Copyright (c) 1990 The Regents of the University of California.
- * 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.
  *
  *
  * This code is derived from software contributed to Berkeley by
  * Van Jacobson of Lawrence Berkeley Laboratory.
  *
- * %sccs.include.redist.c%
+ * 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.
  *
  *
- *     @(#)scsi.c      7.4 (Berkeley) %G%
+ * 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.1 (Berkeley) 6/10/93
  */
 
  */
 
+#ifndef DEBUG
+#define DEBUG
+#endif
 /*
  * HP9000/3xx 98658 SCSI host adaptor driver.
  */
 /*
  * HP9000/3xx 98658 SCSI host adaptor driver.
  */
 #if NSCSI > 0
 
 #ifndef lint
 #if NSCSI > 0
 
 #ifndef lint
-static char rcsid[] = "$Header: scsi.c,v 1.4 91/01/17 12:50:18 mike Exp $";
+static char rcsid[] = "$Header: /usr/src/sys/hp300/dev/RCS/scsi.c,v 1.2 92/04/10 20:48:29 mike Exp $";
 #endif
 
 #endif
 
-#include "sys/param.h"
-#include "sys/systm.h"
-#include "sys/buf.h"
-#include "device.h"
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/buf.h>
 
 
-#include "scsivar.h"
-#include "scsireg.h"
-#include "dmavar.h"
+#include <hp/dev/device.h>
 
 
-#include "../include/cpu.h"
-#include "../hp300/isr.h"
+#include <hp300/dev/scsivar.h>
+#include <hp300/dev/scsireg.h>
+#include <hp300/dev/dmavar.h>
+
+#include <machine/cpu.h>
+#include <hp300/hp300/isr.h>
 
 /*
  * SCSI delays
 
 /*
  * SCSI delays
@@ -41,10 +71,8 @@ static char rcsid[] = "$Header: scsi.c,v 1.4 91/01/17 12:50:18 mike Exp $";
 #define        SCSI_INIT_WAIT  50000   /* wait per step (both) during init */
 
 extern void isrlink();
 #define        SCSI_INIT_WAIT  50000   /* wait per step (both) during init */
 
 extern void isrlink();
-extern void printf();
 extern void _insque();
 extern void _remque();
 extern void _insque();
 extern void _remque();
-extern void bzero();
 
 int    scsiinit(), scsigo(), scsiintr(), scsixfer();
 void   scsistart(), scsidone(), scsifree(), scsireset();
 
 int    scsiinit(), scsigo(), scsiintr(), scsixfer();
 void   scsistart(), scsidone(), scsifree(), scsireset();
@@ -92,6 +120,8 @@ scsiabort(hs, hd, where)
        char *where;
 {
        int len;
        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("scsi%d: abort from %s: phase=0x%x, ssts=0x%x, ints=0x%x\n",
        u_char junk;
 
        printf("scsi%d: abort from %s: phase=0x%x, ssts=0x%x, ints=0x%x\n",
@@ -108,13 +138,21 @@ scsiabort(hs, hd, where)
        len = (hd->scsi_tch << 16) | (hd->scsi_tcm << 8) | hd->scsi_tcl;
 
        /* for that many bus cycles, try to send an abort msg */
        len = (hd->scsi_tch << 16) | (hd->scsi_tcm << 8) | hd->scsi_tcl;
 
        /* for that many bus cycles, try to send an abort msg */
-       for (len += 1024; (hd->scsi_ssts & SSTS_INITIATOR) && --len >= 0; ) {
+       for (startlen = (len += 1024); (hd->scsi_ssts & SSTS_INITIATOR) && --len >= 0; ) {
                hd->scsi_scmd = SCMD_SET_ATN;
                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);
                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) == MESG_OUT_PHASE)
                        hd->scsi_scmd = SCMD_RST_ATN;
                hd->scsi_pctl = hd->scsi_psns & PHASE;
@@ -202,6 +240,11 @@ scsiinit(hc)
        scsi_isr[hc->hp_unit].isr_arg = hc->hp_unit;
        isrlink(&scsi_isr[hc->hp_unit]);
        scsireset(hc->hp_unit);
        scsi_isr[hc->hp_unit].isr_arg = hc->hp_unit;
        isrlink(&scsi_isr[hc->hp_unit]);
        scsireset(hc->hp_unit);
+       /*
+        * 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;
        return(1);
 }
 
        return(1);
 }
 
@@ -700,6 +743,14 @@ finishxfer(hs, hd, target)
        DELAY(1);
        hd->scsi_sctl &=~ SCTL_CTRLRST;
        hd->scsi_hconf = 0;
        DELAY(1);
        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 occuring...  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;
        hs->sc_stat[0] = 0xff;
        hs->sc_msg[0] = 0xff;
        hd->scsi_csr = 0;
@@ -870,6 +921,7 @@ scsiustart(unit)
        register struct scsi_softc *hs = &scsi_softc[unit];
 
        hs->sc_dq.dq_ctlr = DMA0 | DMA1;
        register struct scsi_softc *hs = &scsi_softc[unit];
 
        hs->sc_dq.dq_ctlr = DMA0 | DMA1;
+       hs->sc_flags |= SCSI_HAVEDMA;
        if (dmareq(&hs->sc_dq))
                return(1);
        return(0);
        if (dmareq(&hs->sc_dq))
                return(1);
        return(0);
@@ -902,7 +954,10 @@ scsigo(ctlr, slave, unit, bp, cdb, pad)
 
        /* 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)) {
 
        /* 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)) {
-               dmafree(&hs->sc_dq);
+               if (hs->sc_flags & SCSI_HAVEDMA) {
+                       hs->sc_flags &=~ SCSI_HAVEDMA;
+                       dmafree(&hs->sc_dq);
+               }
                return (1);
        }
        /*
                return (1);
        }
        /*
@@ -1035,6 +1090,7 @@ out:
        return (0);
 abort:
        scsiabort(hs, hd, "go");
        return (0);
 abort:
        scsiabort(hs, hd, "go");
+       hs->sc_flags &=~ SCSI_HAVEDMA;
        dmafree(&hs->sc_dq);
        return (1);
 }
        dmafree(&hs->sc_dq);
        return (1);
 }
@@ -1083,7 +1139,7 @@ scsiintr(unit)
 #endif
                dq = hs->sc_sq.dq_forw;
                finishxfer(hs, hd, dq->dq_slave);
 #endif
                dq = hs->sc_sq.dq_forw;
                finishxfer(hs, hd, dq->dq_slave);
-               hs->sc_flags &=~ SCSI_IO;
+               hs->sc_flags &=~ (SCSI_IO|SCSI_HAVEDMA);
                dmafree(&hs->sc_dq);
                (dq->dq_driver->d_intr)(dq->dq_unit, hs->sc_stat[0]);
        } else {
                dmafree(&hs->sc_dq);
                (dq->dq_driver->d_intr)(dq->dq_unit, hs->sc_stat[0]);
        } else {
@@ -1093,7 +1149,7 @@ scsiintr(unit)
                scsierror(hs, hd, ints);
                scsiabort(hs, hd, "intr");
                if (hs->sc_flags & SCSI_IO) {
                scsierror(hs, hd, ints);
                scsiabort(hs, hd, "intr");
                if (hs->sc_flags & SCSI_IO) {
-                       hs->sc_flags &=~ SCSI_IO;
+                       hs->sc_flags &=~ (SCSI_IO|SCSI_HAVEDMA);
                        dmafree(&hs->sc_dq);
                        dq = hs->sc_sq.dq_forw;
                        (dq->dq_driver->d_intr)(dq->dq_unit, -1);
                        dmafree(&hs->sc_dq);
                        dq = hs->sc_sq.dq_forw;
                        (dq->dq_driver->d_intr)(dq->dq_unit, -1);
@@ -1132,12 +1188,20 @@ scsi_tt_oddio(ctlr, slave, unit, buf, len, b_flags, freedma)
        u_char iphase;
        int stat;
 
        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.
         */
        /*
         * First free any DMA channel that was allocated.
         * We can't use DMA to do this transfer.
         */
-       if (freedma)
+       if (freedma) {
+               hs->sc_flags &=~ SCSI_HAVEDMA;
                dmafree(hs->sc_dq);
                dmafree(hs->sc_dq);
+       }
        /*
         * Initialize command block
         */
        /*
         * Initialize command block
         */