/*-
* Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Charles M. Hannum; Jason R. Thorpe of the Numerical Aerospace
* Simulation Facility, NASA Ames Research Center; Paul Kranenburg.
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
*/
/*
* fas has 2 register spaces: dma(lsi64854) and
* SCSI core (ncr53c9x)
*/
if (sa->sa_nreg != 2) {
aprint_error(": %d register spaces\n", sa->sa_nreg);
return;
}
/*
* allocate space for dma, in SUNW,fas there are no separate
* dma device
*/
lsc = malloc(sizeof(struct lsi64854_softc), M_DEVBUF, M_WAITOK);
lsc->sc_dev = malloc(sizeof(struct device), M_DEVBUF,
M_WAITOK | M_ZERO);
esc->sc_dma = lsc;
/*
* XXX is this common(from bpp.c), the same in dma_sbus...etc.
*
* Get transfer burst size from PROM and plug it into the
* controller registers. This is needed on the Sun4m; do
* others need it too?
*/
sbusburst = sbsc->sc_burst;
if (sbusburst == 0)
sbusburst = SBUS_BURST_32 - 1; /* 1->16 */
if (sa->sa_nintr == 0) {
aprint_error(": no interrupt property\n");
return;
}
esc->sc_pri = sa->sa_pri;
espattach(esc, &esp_sbus_glue);
return;
}
/*
* Find the DMA by poking around the dma device structures
*
* What happens here is that if the dma driver has not been
* configured, then this returns a NULL pointer. Then when the
* dma actually gets configured, it does the opposing test, and
* if the sc->sc_esp field in its softc is NULL, then tries to
* find the matching esp driver.
*/
dma_dev = device_find_by_driver_unit("dma", device_unit(self));
if (dma_dev == NULL) {
aprint_error(": no corresponding DMA device\n");
return;
}
esc->sc_dma = device_private(dma_dev);
esc->sc_dma->sc_client = sc;
/*
* The `ESC' DMA chip must be reset before we can access
* the esp registers.
*/
if (esc->sc_dma->sc_rev == DMAREV_ESC)
DMA_RESET(esc->sc_dma);
/*
* Map my registers in, if they aren't already in virtual
* address space.
*/
if (sa->sa_npromvaddrs) {
sbus_promaddr_to_handle(sa->sa_bustag,
sa->sa_promvaddrs[0], &esc->sc_reg);
} else {
if (sbus_bus_map(sa->sa_bustag,
sa->sa_slot, sa->sa_offset, sa->sa_size,
0, &esc->sc_reg) != 0) {
aprint_error(": cannot map registers\n");
return;
}
}
if (sa->sa_nintr == 0) {
/*
* No interrupt properties: we quit; this might
* happen on e.g. a Sparc X terminal.
*/
aprint_error(": no interrupt property\n");
return;
}
/*
* Map my registers in, if they aren't already in virtual
* address space.
*/
if (sa->sa_npromvaddrs) {
sbus_promaddr_to_handle(sa->sa_bustag,
sa->sa_promvaddrs[0], &esc->sc_reg);
} else {
if (sbus_bus_map(sa->sa_bustag,
sa->sa_slot, sa->sa_offset, sa->sa_size,
0, &esc->sc_reg) != 0) {
aprint_error(": cannot map registers\n");
return;
}
}
if (sa->sa_nintr == 0) {
/*
* No interrupt properties: we quit; this might
* happen on e.g. a Sparc X terminal.
*/
aprint_error(": no interrupt property\n");
return;
}
esc->sc_pri = sa->sa_pri;
espattach(esc, &esp_sbus_glue);
}
/*
* Attach this instance, and then all the sub-devices
*/
void
espattach(struct esp_softc *esc, struct ncr53c9x_glue *gluep)
{
struct ncr53c9x_softc *sc = &esc->sc_ncr53c9x;
unsigned int uid = 0;
/*
* Set up glue for MI code early; we use some of it here.
*/
sc->sc_glue = gluep;
/* gimme MHz */
sc->sc_freq /= 1000000;
/*
* XXX More of this should be in ncr53c9x_attach(), but
* XXX should we really poke around the chip that much in
* XXX the MI code? Think about this more...
*/
/*
* It is necessary to try to load the 2nd config register here,
* to find out what rev the esp 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_RPE;
sc->sc_cfg3 = NCRCFG3_CDB;
NCR_WRITE_REG(sc, NCR_CFG2, sc->sc_cfg2);
/*
* XXX minsync and maxxfer _should_ be set up in MI code,
* XXX but it appears to have some dependency on what sort
* XXX of DMA we're hooked up to, etc.
*/
/*
* 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;
/*
* Alas, we must now modify the value a bit, because it's
* only valid when can switch on FASTCLK and FASTSCSI bits
* in config register 3...
*/
switch (sc->sc_rev) {
case NCR_VARIANT_ESP100:
sc->sc_maxxfer = 64 * 1024;
sc->sc_minsync = 0; /* No synch on old chip? */
break;
case NCR_VARIANT_ESP100A:
sc->sc_maxxfer = 64 * 1024;
/* Min clocks/byte is 5 */
sc->sc_minsync = ncr53c9x_cpb2stp(sc, 5);
break;
case NCR_VARIANT_ESP200:
case NCR_VARIANT_FAS366:
sc->sc_maxxfer = 16 * 1024 * 1024;
/* XXX - do actually set FAST* bits */
break;
}
/* Turn on target selection using the `dma' method */
if (sc->sc_rev != NCR_VARIANT_FAS366)
sc->sc_features |= NCR_F_DMASELECT;
/* Do the common parts of attachment. */
sc->sc_adapter.adapt_minphys = minphys;
sc->sc_adapter.adapt_request = ncr53c9x_scsipi_request;
ncr53c9x_attach(sc);
}