/*
* Copyright (c) 1995 Allen Briggs
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Allen Briggs
* 4. 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.
*
* Derived from atari5380.c for the mac68k port of NetBSD.
*
*/
/*
* Back for more punishment.
*/
PID("pdma_cleanup1");
run_main(cur_softc);
PID("pdma_cleanup2");
}
#endif
static int
pdma_ready(void)
{
#if USE_PDMA
SC_REQ *reqp = connected;
int dmstat, idstat;
extern u_char ncr5380_no_parchk;
PID("pdma_ready0");
if (pdma_5380_dir) {
PID("pdma_ready1.");
/*
* For a phase mis-match, ATN is a "don't care," IRQ is 1 and
* all other bits in the Bus & Status Register are 0. Also,
* the current SCSI Bus Status Register has a 1 for BSY and
* REQ. Since we're just checking that this interrupt isn't a
* reselection or a reset, we just check for either.
*/
dmstat = GET_5380_REG(NCR5380_DMSTAT);
idstat = GET_5380_REG(NCR5380_IDSTAT);
if ( ((dmstat & (0xff & ~SC_ATN_STAT)) == SC_IRQ_SET)
&& ((idstat & (SC_S_BSY|SC_S_REQ))
== (SC_S_BSY | SC_S_REQ)) ) {
PID("pdma_ready2");
pdma_cleanup();
return 1;
} else if (PH_IN(reqp->phase) && (dmstat & SC_PAR_ERR)) {
if (!(ncr5380_no_parchk & (1 << reqp->targ_id)))
/* XXX: Should be parity error ???? */
reqp->xs->error = XS_DRIVER_STUFFUP;
PID("pdma_ready3");
/* XXX: is this the right reaction? */
pdma_cleanup();
return 1;
} else if ( !(idstat & SC_S_REQ)
|| (((idstat>>2) & 7) != reqp->phase)) {
#ifdef DIAGNOSTIC
/* XXX: is this the right reaction? Can this happen? */
scsi_show();
printf("Unexpected phase change.\n");
#endif
reqp->xs->error = XS_DRIVER_STUFFUP;
pdma_cleanup();
return 1;
} else {
scsi_show();
panic("Spurious interrupt during PDMA xfer.");
}
} else
PID("pdma_ready4");
#endif
return 0;
}
/*
* This is the meat of the PDMA transfer.
* When we get here, we shove data as fast as the mac can take it.
* We depend on several things:
* * All macs after the Mac Plus that have a 5380 chip should have a general
* logic IC that handshakes data for blind transfers.
* * If the SCSI controller finishes sending/receiving data before we do,
* the same general logic IC will generate a /BERR for us in short order.
* * The fault address for said /BERR minus the base address for the
* transfer will be the amount of data that was actually written.
*
* We use the nofault flag and the setjmp/longjmp in locore.s so we can
* detect and handle the bus error for early termination of a command.
* This is usually caused by a disconnecting target.
*/
static void
do_ncr5380_drq_intr(void *p)
{
#if USE_PDMA
extern int *nofault, m68k_fault_addr;
label_t faultbuf;
register int count;
volatile u_int32_t *long_drq;
u_int32_t *long_data;
volatile u_int8_t *drq;
u_int8_t *data;
/*
* Setup for a possible bus error caused by SCSI controller
* switching out of DATA-IN/OUT before we're done with the
* current transfer.
*/
nofault = (int *) &faultbuf;
static int
transfer_pdma(u_char *phasep, u_char *data, u_long *count)
{
SC_REQ *reqp = connected;
int len = *count, s, scsi_timeout = SCSI_TIMEOUT_VAL;
if (pdma_5380_dir) {
panic("ncrscsi: transfer_pdma called when operation already "
"pending.");
}
PID("transfer_pdma0")
/*
* Don't bother with PDMA if we can't sleep or for small transfers.
*/
if (reqp->dr_flag & DRIVER_NOINT) {
PID("pdma, falling back to transfer_pio.")
transfer_pio(phasep, data, count, 0);
return -1;
}
/*
* We are probably already at spl2(), so this is likely a no-op.
* Paranoia.
*/
s = splbio();
scsi_idisable();
/*
* Match phases with target.
*/
SET_5380_REG(NCR5380_TCOM, *phasep);
/*
* Wait until target asserts BSY.
*/
while ( ((GET_5380_REG(NCR5380_IDSTAT) & SC_S_BSY) == 0)
&& (--scsi_timeout) );
if (!scsi_timeout) {
#if DIAGNOSTIC
printf("scsi timeout: waiting for BSY in %s.\n",
(*phasep == PH_DATAOUT) ? "pdma_out" : "pdma_in");
#endif
goto scsi_timeout_error;
}
/*
* Tell the driver that we're in DMA mode.
*/
reqp->dr_flag |= DRIVER_IN_DMA;
/*
* Load transfer values for DRQ interrupt handlers.
*/
pending_5380_data = data;
pending_5380_count = len;
/*
* Set the transfer function to be called on DRQ interrupts.
* And note that we're waiting.
*/
switch (*phasep) {
default:
panic("Unexpected phase in transfer_pdma.");
case PH_DATAOUT:
pdma_5380_dir = 1;
SET_5380_REG(NCR5380_ICOM, GET_5380_REG(NCR5380_ICOM)|SC_ADTB);
SET_5380_REG(NCR5380_MODE, GET_5380_REG(NCR5380_MODE)|SC_M_DMA);
SET_5380_REG(NCR5380_DMSTAT, 0);
break;
case PH_DATAIN:
pdma_5380_dir = 2;
SET_5380_REG(NCR5380_ICOM, 0);
SET_5380_REG(NCR5380_MODE, GET_5380_REG(NCR5380_MODE)|SC_M_DMA);
SET_5380_REG(NCR5380_IRCV, 0);
break;
}
PID("waiting for interrupt.")
/*
* Now that we're set up, enable interrupts and drop processor
* priority back down.
*/
scsi_ienable();
splx(s);
return 0;
scsi_timeout_error:
/*
* Clear the DMA mode.
*/
SET_5380_REG(NCR5380_MODE, GET_5380_REG(NCR5380_MODE) & ~SC_M_DMA);
return -1;
}
#endif /* if USE_PDMA */
/* Include general routines. */
#include <mac68k/dev/ncr5380.c>