/*
* Copyright (c) 1997 Michael L. Hitch
* Copyright (c) 1982, 1990 The Regents of the University of California.
* 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. 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.
*
*/
/* Maximum DMA transfer length to reduce impact on high-speed serial input */
u_long cbsc_max_dma = 1024;
extern int ser_open_speed;
u_long cbsc_cnt_pio = 0; /* number of PIO transfers */
u_long cbsc_cnt_dma = 0; /* number of DMA transfers */
u_long cbsc_cnt_dma2 = 0; /* number of DMA transfers broken up */
u_long cbsc_cnt_dma3 = 0; /* number of pages combined */
/*
* Attach this instance, and then all the sub-devices
*/
void
cbscattach(device_t parent, device_t self, void *aux)
{
struct cbsc_softc *csc = device_private(self);
struct ncr53c9x_softc *sc = &csc->sc_ncr53c9x;
struct zbus_args *zap;
extern u_long scsi_nosync;
extern int shift_nosync;
extern int ncr53c9x_debug;
/*
* Set up the glue for MI code early; we use some of it here.
*/
sc->sc_dev = self;
sc->sc_glue = &cbsc_glue;
/*
* Save the regs
*/
zap = aux;
csc->sc_reg = &((volatile uint8_t *)zap->va)[0xf400];
csc->sc_dmabase = &csc->sc_reg[0x400];
sc->sc_freq = 40; /* Clocked at 40 MHz */
aprint_normal(": address %p", csc->sc_reg);
sc->sc_id = 7;
/*
* It is necessary to try to load the 2nd config register here,
* to find out what rev the FAS chip is, else the ncr53c9x_reset
* will not set up the defaults correctly.
*/
sc->sc_cfg1 = sc->sc_id | NCRCFG1_PARENB;
sc->sc_cfg2 = NCRCFG2_SCSI2 | NCRCFG2_FE;
sc->sc_cfg3 = 0x08 /*FCLK*/ | NCRESPCFG3_FSCSI | NCRESPCFG3_CDB;
sc->sc_rev = NCR_VARIANT_FAS216;
/*
* This is the value used to start sync negotiations
* Note that the NCR register "SYNCTP" is programmed
* in "clocks per byte", and has a minimum value of 4.
* The SCSI period used in negotiation is one-fourth
* of the time (in nanoseconds) needed to transfer one byte.
* Since the chip's clock is given in MHz, we have the following
* formula: 4 * period = (1000 / freq) * 4
*/
sc->sc_minsync = 1000 / sc->sc_freq;
/*
* get flags from -I argument and set cf_flags.
* NOTE: low 8 bits are to disable disconnect, and the next
* 8 bits are to disable sync.
*/
device_cfdata(self)->cf_flags |= (scsi_nosync >> shift_nosync)
& 0xffff;
shift_nosync += 16;
/* Use next 16 bits of -I argument to set ncr53c9x_debug flags */
ncr53c9x_debug |= (scsi_nosync >> shift_nosync) & 0xffff;
shift_nosync += 16;
/*
* Now try to attach all the sub-devices
*/
sc->sc_adapter.adapt_request = ncr53c9x_scsipi_request;
sc->sc_adapter.adapt_minphys = minphys;
ncr53c9x_attach(sc);
}
csc->sc_dmaaddr = addr;
csc->sc_pdmalen = len;
csc->sc_datain = datain;
csc->sc_dmasize = *dmasize;
/*
* DMA can be nasty for high-speed serial input, so limit the
* size of this DMA operation if the serial port is running at
* a high speed (higher than 19200 for now - should be adjusted
* based on CPU type and speed?).
* XXX - add serial speed check XXX
*/
if (ser_open_speed > 19200 && cbsc_max_dma != 0 &&
csc->sc_dmasize > cbsc_max_dma)
csc->sc_dmasize = cbsc_max_dma;
ptr = *addr; /* Kernel virtual address */
pa = kvtop(ptr); /* Physical address of DMA */
xfer = uimin(csc->sc_dmasize, PAGE_SIZE - (pa & (PAGE_SIZE - 1)));
csc->sc_xfr_align = 0;
/*
* If output and unaligned, stuff odd byte into FIFO
*/
if (datain == 0 && (int)ptr & 1) {
NCR_DMA(("cbsc_dma_setup: align byte written to fifo\n"));
pa++;
xfer--; /* XXXX CHECK THIS !!!! XXXX */
csc->sc_reg[NCR_FIFO * 4] = *ptr++;
}
/*
* If unaligned address, read unaligned bytes into alignment buffer
*/
else if ((int)ptr & 1) {
pa = kvtop((void *)&csc->sc_alignbuf);
xfer = csc->sc_dmasize = uimin(xfer, sizeof(csc->sc_alignbuf));
NCR_DMA(("cbsc_dma_setup: align read by %d bytes\n", xfer));
csc->sc_xfr_align = 1;
}
++cbsc_cnt_dma; /* number of DMA operations */
while (xfer < csc->sc_dmasize) {
if ((pa + xfer) != kvtop(*addr + xfer))
break;
if ((csc->sc_dmasize - xfer) < PAGE_SIZE)
xfer = csc->sc_dmasize;
else
xfer += PAGE_SIZE;
++cbsc_cnt_dma3;
}
if (xfer != *len)
++cbsc_cnt_dma2;