summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/conf/files.sparc643
-rw-r--r--sys/dev/esp/esp_sbus.c458
-rw-r--r--sys/dev/esp/ncr53c9x.c125
-rw-r--r--sys/dev/esp/ncr53c9xreg.h2
-rw-r--r--sys/dev/esp/ncr53c9xvar.h8
-rw-r--r--sys/modules/esp/Makefile2
-rw-r--r--sys/sparc64/sbus/dma_sbus.c506
-rw-r--r--sys/sparc64/sbus/lsi64854.c41
-rw-r--r--sys/sparc64/sbus/lsi64854var.h7
9 files changed, 1009 insertions, 143 deletions
diff --git a/sys/conf/files.sparc64 b/sys/conf/files.sparc64
index 86157ae..74b05e8 100644
--- a/sys/conf/files.sparc64
+++ b/sys/conf/files.sparc64
@@ -65,8 +65,9 @@ sparc64/pci/ofw_pcib_subr.c optional pci
sparc64/pci/ofw_pcibus.c optional pci
sparc64/pci/ofw_pci_if.m optional pci
sparc64/pci/psycho.c optional pci
+sparc64/sbus/dma_sbus.c optional sbus
sparc64/sbus/sbus.c optional sbus
-sparc64/sbus/lsi64854.c optional esp sbus
+sparc64/sbus/lsi64854.c optional sbus
sparc64/sparc64/autoconf.c standard
sparc64/sparc64/bus_machdep.c standard
sparc64/sparc64/cache.c standard
diff --git a/sys/dev/esp/esp_sbus.c b/sys/dev/esp/esp_sbus.c
index 24a6a8f..cc92f19 100644
--- a/sys/dev/esp/esp_sbus.c
+++ b/sys/dev/esp/esp_sbus.c
@@ -109,18 +109,39 @@ struct esp_softc {
struct lsi64854_softc *sc_dma; /* pointer to my DMA */
};
-static int esp_sbus_probe(device_t);
+static devclass_t esp_devclass;
+
+static int esp_probe(device_t);
+static int esp_dma_attach(device_t);
+static int esp_dma_detach(device_t);
static int esp_sbus_attach(device_t);
static int esp_sbus_detach(device_t);
-static int esp_sbus_suspend(device_t);
-static int esp_sbus_resume(device_t);
+static int esp_suspend(device_t);
+static int esp_resume(device_t);
+
+static device_method_t esp_dma_methods[] = {
+ DEVMETHOD(device_probe, esp_probe),
+ DEVMETHOD(device_attach, esp_dma_attach),
+ DEVMETHOD(device_detach, esp_dma_detach),
+ DEVMETHOD(device_suspend, esp_suspend),
+ DEVMETHOD(device_resume, esp_resume),
+ {0, 0}
+};
+
+static driver_t esp_dma_driver = {
+ "esp",
+ esp_dma_methods,
+ sizeof(struct esp_softc)
+};
+
+DRIVER_MODULE(esp, dma, esp_dma_driver, esp_devclass, 0, 0);
static device_method_t esp_sbus_methods[] = {
- DEVMETHOD(device_probe, esp_sbus_probe),
+ DEVMETHOD(device_probe, esp_probe),
DEVMETHOD(device_attach, esp_sbus_attach),
DEVMETHOD(device_detach, esp_sbus_detach),
- DEVMETHOD(device_suspend, esp_sbus_suspend),
- DEVMETHOD(device_resume, esp_sbus_resume),
+ DEVMETHOD(device_suspend, esp_suspend),
+ DEVMETHOD(device_resume, esp_resume),
{0, 0}
};
@@ -130,7 +151,6 @@ static driver_t esp_sbus_driver = {
sizeof(struct esp_softc)
};
-static devclass_t esp_devclass;
DRIVER_MODULE(esp, sbus, esp_sbus_driver, esp_devclass, 0, 0);
/*
@@ -146,7 +166,7 @@ static int esp_dma_setup(struct ncr53c9x_softc *, caddr_t *, size_t *,
static void esp_dma_go(struct ncr53c9x_softc *);
static void esp_dma_stop(struct ncr53c9x_softc *);
static int esp_dma_isactive(struct ncr53c9x_softc *);
-static void espattach(struct esp_softc *, struct ncr53c9x_glue *);
+static int espattach(struct esp_softc *, struct ncr53c9x_glue *);
static struct ncr53c9x_glue esp_sbus_glue = {
esp_read_reg,
@@ -162,7 +182,7 @@ static struct ncr53c9x_glue esp_sbus_glue = {
};
static int
-esp_sbus_probe(device_t dev)
+esp_probe(device_t dev)
{
const char *name;
@@ -170,6 +190,9 @@ esp_sbus_probe(device_t dev)
if (strcmp("SUNW,fas", name) == 0) {
device_set_desc(dev, "Sun FAS366 Fast-Wide SCSI");
return (BUS_PROBE_DEFAULT);
+ } else if (strcmp("esp", name) == 0) {
+ device_set_desc(dev, "Sun ESP SCSI/Sun FAS Fast-SCSI");
+ return (BUS_PROBE_DEFAULT);
}
return (ENXIO);
@@ -181,126 +204,291 @@ esp_sbus_attach(device_t dev)
struct esp_softc *esc;
struct ncr53c9x_softc *sc;
struct lsi64854_softc *lsc;
+ device_t *children;
+ const char *name;
phandle_t node;
- int burst;
+ int burst, error, i, nchildren, slot;
esc = device_get_softc(dev);
bzero(esc, sizeof(struct esp_softc));
sc = &esc->sc_ncr53c9x;
+ lsc = NULL;
esc->sc_dev = dev;
+ name = ofw_bus_get_name(dev);
node = ofw_bus_get_node(dev);
if (OF_getprop(node, "initiator-id", &sc->sc_id,
sizeof(sc->sc_id)) == -1)
sc->sc_id = 7;
- if (OF_getprop(node, "clock-frequency", &sc->sc_freq,
- sizeof(sc->sc_freq)) == -1) {
- printf("failed to query OFW for clock-frequency\n");
- sc->sc_freq = sbus_get_clockfreq(dev);
- }
+ sc->sc_freq = sbus_get_clockfreq(dev);
#ifdef ESP_SBUS_DEBUG
device_printf(dev, "%s: sc_id %d, freq %d\n", __func__, sc->sc_id,
sc->sc_freq);
#endif
- /*
- * allocate space for DMA, in SUNW,fas there are no separate
- * DMA devices
- */
- lsc = malloc(sizeof (struct lsi64854_softc), M_DEVBUF,
- M_NOWAIT | M_ZERO);
- if (lsc == NULL) {
- device_printf(dev, "out of memory (lsi64854_softc)\n");
- return (ENOMEM);
+ if (strcmp(name, "SUNW,fas") == 0) {
+ /*
+ * Allocate space for DMA, in SUNW,fas there are no
+ * separate DMA devices.
+ */
+ lsc = malloc(sizeof (struct lsi64854_softc), M_DEVBUF,
+ M_NOWAIT | M_ZERO);
+ if (lsc == NULL) {
+ device_printf(dev, "out of memory (lsi64854_softc)\n");
+ return (ENOMEM);
+ }
+ esc->sc_dma = lsc;
+
+ /*
+ * SUNW,fas have 2 register spaces: DMA (lsi64854) and
+ * SCSI core (ncr53c9x).
+ */
+
+ /* Allocate DMA registers. */
+ lsc->sc_rid = 0;
+ if ((lsc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
+ &lsc->sc_rid, RF_ACTIVE)) == NULL) {
+ device_printf(dev, "cannot allocate DMA registers\n");
+ error = ENXIO;
+ goto fail_sbus_lsc;
+ }
+ lsc->sc_regt = rman_get_bustag(lsc->sc_res);
+ lsc->sc_regh = rman_get_bushandle(lsc->sc_res);
+
+ /* Create a parent DMA tag based on this bus. */
+ error = bus_dma_tag_create(
+ NULL, /* parent */
+ PAGE_SIZE, 0, /* alignment, boundary */
+ BUS_SPACE_MAXADDR, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ BUS_SPACE_MAXSIZE_32BIT, /* maxsize */
+ 0, /* nsegments */
+ BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */
+ 0, /* flags */
+ NULL, NULL, /* no locking */
+ &lsc->sc_parent_dmat);
+ if (error != 0) {
+ device_printf(dev, "cannot allocate parent DMA tag\n");
+ goto fail_sbus_lres;
+ }
+ burst = sbus_get_burstsz(dev);
+
+#ifdef ESP_SBUS_DEBUG
+ printf("%s: burst 0x%x\n", __func__, burst);
+#endif
+
+ lsc->sc_burst = (burst & SBUS_BURST_32) ? 32 :
+ (burst & SBUS_BURST_16) ? 16 : 0;
+
+ lsc->sc_channel = L64854_CHANNEL_SCSI;
+ lsc->sc_client = sc;
+ lsc->sc_dev = dev;
+
+ error = lsi64854_attach(lsc);
+ if (error != 0) {
+ device_printf(dev, "lsi64854_attach failed\n");
+ goto fail_sbus_lpdma;
+ }
+
+ /*
+ * Allocate SCSI core registers.
+ */
+ esc->sc_rid = 1;
+ if ((esc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
+ &esc->sc_rid, RF_ACTIVE)) == NULL) {
+ device_printf(dev,
+ "cannot allocate SCSI core registers\n");
+ error = ENXIO;
+ goto fail_sbus_lsi;
+ }
+ esc->sc_regt = rman_get_bustag(esc->sc_res);
+ esc->sc_regh = rman_get_bushandle(esc->sc_res);
+ } else {
+ /*
+ * Search accompanying DMA engine. It should have been
+ * already attached otherwise there isn't much we can do.
+ */
+ if (device_get_children(device_get_parent(dev), &children,
+ &nchildren) != 0) {
+ device_printf(dev, "cannot determine siblings\n");
+ return (ENXIO);
+ }
+ slot = sbus_get_slot(dev);
+ for (i = 0; i < nchildren; i++) {
+ if (device_is_attached(children[i]) &&
+ sbus_get_slot(children[i]) == slot &&
+ strcmp(ofw_bus_get_name(children[i]), "dma") == 0) {
+ /* XXX hackery */
+ esc->sc_dma = (struct lsi64854_softc *)
+ device_get_softc(children[i]);
+ break;
+ }
+ }
+ free(children, M_TEMP);
+ if (esc->sc_dma == NULL) {
+ device_printf(dev, "cannot find DMA engine\n");
+ return (ENXIO);
+ }
+ esc->sc_dma->sc_client = sc;
+
+ /*
+ * Allocate SCSI core registers.
+ */
+ esc->sc_rid = 0;
+ if ((esc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
+ &esc->sc_rid, RF_ACTIVE)) == NULL) {
+ device_printf(dev,
+ "cannot allocate SCSI core registers\n");
+ return (ENXIO);
+ }
+ esc->sc_regt = rman_get_bustag(esc->sc_res);
+ esc->sc_regh = rman_get_bushandle(esc->sc_res);
}
- esc->sc_dma = lsc;
- /*
- * fas has 2 register spaces: DMA (lsi64854) and SCSI core (ncr53c9x)
- */
+ error = espattach(esc, &esp_sbus_glue);
+ if (error != 0) {
+ device_printf(dev, "espattach failed\n");
+ goto fail_sbus_eres;
+ }
+
+ return (0);
+
+ fail_sbus_eres:
+ bus_release_resource(dev, SYS_RES_MEMORY, esc->sc_rid, esc->sc_res);
+ if (strcmp(name, "SUNW,fas") != 0)
+ return (error);
+ fail_sbus_lsi:
+ lsi64854_detach(lsc);
+ fail_sbus_lpdma:
+ bus_dma_tag_destroy(lsc->sc_parent_dmat);
+ fail_sbus_lres:
+ bus_release_resource(dev, SYS_RES_MEMORY, lsc->sc_rid, lsc->sc_res);
+ fail_sbus_lsc:
+ free(lsc, M_DEVBUF);
+ return (error);
+}
+
+static int
+esp_sbus_detach(device_t dev)
+{
+ struct esp_softc *esc;
+ struct ncr53c9x_softc *sc;
+ struct lsi64854_softc *lsc;
+ int error;
+
+ esc = device_get_softc(dev);
+ sc = &esc->sc_ncr53c9x;
+ lsc = esc->sc_dma;
+
+ bus_teardown_intr(esc->sc_dev, esc->sc_irqres, esc->sc_irq);
+ error = ncr53c9x_detach(sc);
+ if (error != 0)
+ return (error);
+ bus_release_resource(esc->sc_dev, SYS_RES_IRQ, esc->sc_irqrid,
+ esc->sc_irqres);
+ bus_release_resource(dev, SYS_RES_MEMORY, esc->sc_rid, esc->sc_res);
+ if (strcmp(ofw_bus_get_name(dev), "SUNW,fas") != 0)
+ return (0);
+ error = lsi64854_detach(lsc);
+ if (error != 0)
+ return (error);
+ bus_dma_tag_destroy(lsc->sc_parent_dmat);
+ bus_release_resource(dev, SYS_RES_MEMORY, lsc->sc_rid, lsc->sc_res);
+ free(lsc, M_DEVBUF);
+
+ return (0);
+}
+
+static int
+esp_dma_attach(device_t dev)
+{
+ struct esp_softc *esc;
+ struct ncr53c9x_softc *sc;
+ phandle_t node;
+ int error;
+
+ esc = device_get_softc(dev);
+ bzero(esc, sizeof(struct esp_softc));
+ sc = &esc->sc_ncr53c9x;
- /* allocate DMA registers */
- lsc->sc_rid = 0;
- if ((lsc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
- &lsc->sc_rid, RF_ACTIVE)) == NULL) {
- device_printf(dev, "cannot allocate DMA registers\n");
- free(lsc, M_DEVBUF);
+ esc->sc_dev = dev;
+ node = ofw_bus_get_node(dev);
+ if (OF_getprop(node, "initiator-id", &sc->sc_id,
+ sizeof(sc->sc_id)) == -1)
+ sc->sc_id = 7;
+ if (OF_getprop(node, "clock-frequency", &sc->sc_freq,
+ sizeof(sc->sc_freq)) == -1) {
+ printf("failed to query OFW for clock-frequency\n");
return (ENXIO);
}
- lsc->sc_regt = rman_get_bustag(lsc->sc_res);
- lsc->sc_regh = rman_get_bushandle(lsc->sc_res);
-
- /* Create a parent DMA tag based on this bus */
- if (bus_dma_tag_create(
- NULL, /* parent */
- PAGE_SIZE, 0, /* alignment, boundary */
- BUS_SPACE_MAXADDR, /* lowaddr */
- BUS_SPACE_MAXADDR, /* highaddr */
- NULL, NULL, /* filter, filterarg */
- BUS_SPACE_MAXSIZE_32BIT, /* maxsize */
- 0, /* nsegments */
- BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */
- 0, /* flags */
- NULL, NULL, /* no locking */
- &lsc->sc_parent_dmat)) {
- device_printf(dev, "cannot allocate parent DMA tag\n");
- free(lsc, M_DEVBUF);
- return (ENOMEM);
- }
- burst = sbus_get_burstsz(dev);
#ifdef ESP_SBUS_DEBUG
- printf("%s: burst 0x%x\n", __func__, burst);
+ device_printf(dev, "%s: sc_id %d, freq %d\n", __func__, sc->sc_id,
+ sc->sc_freq);
#endif
- lsc->sc_burst = (burst & SBUS_BURST_32) ? 32 :
- (burst & SBUS_BURST_16) ? 16 : 0;
-
- lsc->sc_channel = L64854_CHANNEL_SCSI;
- lsc->sc_client = sc;
- lsc->sc_dev = dev;
-
- lsi64854_attach(lsc);
+ /* XXX hackery */
+ esc->sc_dma = (struct lsi64854_softc *)
+ device_get_softc(device_get_parent(dev));
+ esc->sc_dma->sc_client = sc;
/*
- * allocate SCSI core registers
+ * Allocate SCSI core registers.
*/
- esc->sc_rid = 1;
+ esc->sc_rid = 0;
if ((esc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
&esc->sc_rid, RF_ACTIVE)) == NULL) {
device_printf(dev, "cannot allocate SCSI core registers\n");
- free(lsc, M_DEVBUF);
return (ENXIO);
}
esc->sc_regt = rman_get_bustag(esc->sc_res);
esc->sc_regh = rman_get_bushandle(esc->sc_res);
- espattach(esc, &esp_sbus_glue);
+ error = espattach(esc, &esp_sbus_glue);
+ if (error != 0) {
+ device_printf(dev, "espattach failed\n");
+ goto fail_dma_eres;
+ }
return (0);
+
+ fail_dma_eres:
+ bus_release_resource(dev, SYS_RES_MEMORY, esc->sc_rid, esc->sc_res);
+ return (error);
}
static int
-esp_sbus_detach(device_t dev)
+esp_dma_detach(device_t dev)
{
- struct ncr53c9x_softc *sc;
struct esp_softc *esc;
+ struct ncr53c9x_softc *sc;
+ int error;
esc = device_get_softc(dev);
sc = &esc->sc_ncr53c9x;
- return (ncr53c9x_detach(sc, 0));
+
+ bus_teardown_intr(esc->sc_dev, esc->sc_irqres, esc->sc_irq);
+ error = ncr53c9x_detach(sc);
+ if (error != 0)
+ return (error);
+ bus_release_resource(esc->sc_dev, SYS_RES_IRQ, esc->sc_irqrid,
+ esc->sc_irqres);
+ bus_release_resource(dev, SYS_RES_MEMORY, esc->sc_rid, esc->sc_res);
+
+ return (0);
}
static int
-esp_sbus_suspend(device_t dev)
+esp_suspend(device_t dev)
{
return (ENXIO);
}
static int
-esp_sbus_resume(device_t dev)
+esp_resume(device_t dev)
{
return (ENXIO);
@@ -309,11 +497,19 @@ esp_sbus_resume(device_t dev)
/*
* Attach this instance, and then all the sub-devices
*/
-static void
+static int
espattach(struct esp_softc *esc, struct ncr53c9x_glue *gluep)
{
struct ncr53c9x_softc *sc = &esc->sc_ncr53c9x;
unsigned int uid = 0;
+ int error;
+
+ /*
+ * 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);
/*
* Set up glue for MI code early; we use some of it here.
@@ -330,13 +526,30 @@ espattach(struct esp_softc *esc, struct ncr53c9x_glue *gluep)
*/
/*
+ * Read the part-unique ID code of the SCSI chip. The contained
+ * value is only valid if all of the following conditions are met:
+ * - After power-up or chip reset.
+ * - Before any value is written to this register.
+ * - The NCRCFG2_FE bit is set.
+ * - A (NCRCMD_NOP | NCRCMD_DMA) command has been issued.
+ */
+ NCRCMD(sc, NCRCMD_RSTCHIP);
+ NCRCMD(sc, NCRCMD_NOP);
+ sc->sc_cfg2 = NCRCFG2_FE;
+ NCR_WRITE_REG(sc, NCR_CFG2, sc->sc_cfg2);
+ NCRCMD(sc, NCRCMD_NOP | NCRCMD_DMA);
+ uid = NCR_READ_REG(sc, NCR_UID);
+
+ /*
* 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;
+ NCR_WRITE_REG(sc, NCR_CFG1, sc->sc_cfg1);
+ sc->sc_cfg2 = 0;
+ NCR_WRITE_REG(sc, NCR_CFG2, sc->sc_cfg2);
sc->sc_cfg2 = NCRCFG2_SCSI2 | NCRCFG2_RPE;
- sc->sc_cfg3 = NCRCFG3_CDB;
NCR_WRITE_REG(sc, NCR_CFG2, sc->sc_cfg2);
if ((NCR_READ_REG(sc, NCR_CFG2) & ~NCRCFG2_RSVD) !=
@@ -357,15 +570,33 @@ espattach(struct esp_softc *esc, struct ncr53c9x_glue *gluep)
sc->sc_cfg2 |= NCRCFG2_FE;
sc->sc_cfg3 = 0;
NCR_WRITE_REG(sc, NCR_CFG3, sc->sc_cfg3);
- sc->sc_rev = NCR_VARIANT_ESP200;
-
- /*
- * XXX spec says it's valid after power up or chip
- * reset.
- */
- uid = NCR_READ_REG(sc, NCR_UID);
- if (((uid & 0xf8) >> 3) == 0x0a) /* XXX */
- sc->sc_rev = NCR_VARIANT_FAS366;
+ if (sc->sc_freq <= 25)
+ sc->sc_rev = NCR_VARIANT_ESP200;
+ else {
+ switch ((uid & 0xf8) >> 3) {
+ case 0x00:
+ sc->sc_rev = NCR_VARIANT_FAS100A;
+ break;
+ case 0x02:
+ if ((uid & 0x07) == 0x02)
+ sc->sc_rev = NCR_VARIANT_FAS216;
+ else
+ sc->sc_rev = NCR_VARIANT_FAS236;
+ break;
+ case 0x0a:
+ sc->sc_rev = NCR_VARIANT_FAS366;
+ break;
+ default:
+ /*
+ * We could just treat unknown chips
+ * as ESP200 but then we would most
+ * likely drive them out of specs.
+ */
+ device_printf(esc->sc_dev,
+ "Unknown chip\n");
+ return (ENXIO);
+ }
+ }
}
}
@@ -390,10 +621,7 @@ espattach(struct esp_softc *esc, struct ncr53c9x_glue *gluep)
*/
sc->sc_minsync = 1000 / sc->sc_freq;
- /* limit minsync due to unsolved performance issues */
- sc->sc_maxsync = sc->sc_minsync;
sc->sc_maxoffset = 15;
-
sc->sc_extended_geom = 1;
/*
@@ -409,31 +637,60 @@ espattach(struct esp_softc *esc, struct ncr53c9x_glue *gluep)
break;
case NCR_VARIANT_ESP100A:
- sc->sc_maxwidth = 1;
+ sc->sc_maxwidth = 0;
sc->sc_maxxfer = 64 * 1024;
/* Min clocks/byte is 5 */
sc->sc_minsync = ncr53c9x_cpb2stp(sc, 5);
break;
case NCR_VARIANT_ESP200:
+ sc->sc_maxwidth = 0;
+ sc->sc_maxxfer = 16 * 1024 * 1024;
+ /* Min clocks/byte is 5 */
+ sc->sc_minsync = ncr53c9x_cpb2stp(sc, 5);
+ break;
+
+ case NCR_VARIANT_FAS100A:
+ case NCR_VARIANT_FAS216:
+ case NCR_VARIANT_FAS236:
+ /*
+ * The onboard SCSI chips in Sun Ultra 1 are actually
+ * documented to be NCR53C9X which use NCRCFG3_FCLK and
+ * NCRCFG3_FSCSI. BSD/OS however probes these chips as
+ * FAS100A and uses NCRF9XCFG3_FCLK and NCRF9XCFG3_FSCSI
+ * instead which seems to be correct as otherwise sync
+ * negotiation just doesn't work. Using NCRF9XCFG3_FCLK
+ * and NCRF9XCFG3_FSCSI with these chips in fact also
+ * yields Fast-SCSI speed.
+ */
+ sc->sc_features = NCR_F_FASTSCSI;
+ sc->sc_cfg3 = NCRF9XCFG3_FCLK;
+ sc->sc_cfg3_fscsi = NCRF9XCFG3_FSCSI;
+ sc->sc_maxwidth = 0;
+ sc->sc_maxxfer = 16 * 1024 * 1024;
+ break;
+
case NCR_VARIANT_FAS366:
sc->sc_maxwidth = 1;
sc->sc_maxxfer = 16 * 1024 * 1024;
- /* XXX - do actually set FAST* bits */
break;
}
+ /* Limit minsync due to unsolved performance issues. */
+ sc->sc_maxsync = sc->sc_minsync;
+
/* Establish interrupt channel */
esc->sc_irqrid = 0;
if ((esc->sc_irqres = bus_alloc_resource_any(esc->sc_dev, SYS_RES_IRQ,
&esc->sc_irqrid, RF_SHAREABLE|RF_ACTIVE)) == NULL) {
- device_printf(esc->sc_dev, "Cannot allocate interrupt\n");
- return;
+ device_printf(esc->sc_dev, "cannot allocate interrupt\n");
+ return (ENXIO);
}
if (bus_setup_intr(esc->sc_dev, esc->sc_irqres,
INTR_TYPE_BIO|INTR_MPSAFE, ncr53c9x_intr, sc, &esc->sc_irq)) {
- device_printf(esc->sc_dev, "Cannot set up interrupt\n");
- return;
+ device_printf(esc->sc_dev, "cannot set up interrupt\n");
+ error = ENXIO;
+ goto fail_ires;
}
/* Turn on target selection using the `DMA' method */
@@ -442,7 +699,20 @@ espattach(struct esp_softc *esc, struct ncr53c9x_glue *gluep)
/* Do the common parts of attachment. */
sc->sc_dev = esc->sc_dev;
- ncr53c9x_attach(sc);
+ error = ncr53c9x_attach(sc);
+ if (error != 0) {
+ device_printf(esc->sc_dev, "ncr53c9x_attach failed\n");
+ goto fail_intr;
+ }
+
+ return (0);
+
+ fail_intr:
+ bus_teardown_intr(esc->sc_dev, esc->sc_irqres, esc->sc_irq);
+ fail_ires:
+ bus_release_resource(esc->sc_dev, SYS_RES_IRQ, esc->sc_irqrid,
+ esc->sc_irqres);
+ return (error);
}
/*
diff --git a/sys/dev/esp/ncr53c9x.c b/sys/dev/esp/ncr53c9x.c
index 9d587a7..010e9c6 100644
--- a/sys/dev/esp/ncr53c9x.c
+++ b/sys/dev/esp/ncr53c9x.c
@@ -25,7 +25,7 @@
*
*/
-/* $NetBSD: ncr53c9x.c,v 1.110 2003/11/02 11:07:45 wiz Exp $ */
+/* $NetBSD: ncr53c9x.c,v 1.114 2005/02/27 00:27:02 perry Exp $ */
/*-
* Copyright (c) 1998, 2002 The NetBSD Foundation, Inc.
@@ -200,6 +200,8 @@ static const char *ncr53c9x_variant_names[] = {
"AM53C974",
"FAS366/HME",
"NCR53C90 (86C01)",
+ "FAS100A",
+ "FAS236",
};
/*
@@ -225,7 +227,7 @@ ncr53c9x_attach(struct ncr53c9x_softc *sc)
struct cam_sim *sim;
struct cam_path *path;
struct ncr53c9x_ecb *ecb;
- int i;
+ int error, i;
mtx_init(&sc->sc_lock, "ncr", "ncr53c9x lock", MTX_DEF);
@@ -249,18 +251,36 @@ ncr53c9x_attach(struct ncr53c9x_softc *sc)
* handling in the DMA engines. Note that that ncr53c9x_msgout()
* can request a 1 byte DMA transfer.
*/
- if (sc->sc_omess == NULL)
+ if (sc->sc_omess == NULL) {
+ sc->sc_omess_self = 1;
sc->sc_omess = malloc(NCR_MAX_MSG_LEN, M_DEVBUF, M_NOWAIT);
+ if (sc->sc_omess == NULL) {
+ device_printf(sc->sc_dev,
+ "cannot allocate MSGOUT buffer\n");
+ return (ENOMEM);
+ }
+ } else
+ sc->sc_omess_self = 0;
- if (sc->sc_imess == NULL)
+ if (sc->sc_imess == NULL) {
+ sc->sc_imess_self = 1;
sc->sc_imess = malloc(NCR_MAX_MSG_LEN + 1, M_DEVBUF, M_NOWAIT);
+ if (sc->sc_imess == NULL) {
+ device_printf(sc->sc_dev,
+ "cannot allocate MSGIN buffer\n");
+ error = ENOMEM;
+ goto fail_omess;
+ }
+ } else
+ sc->sc_imess_self = 0;
sc->sc_tinfo = malloc(sc->sc_ntarg * sizeof(sc->sc_tinfo[0]),
M_DEVBUF, M_NOWAIT | M_ZERO);
-
- if (!sc->sc_omess || !sc->sc_imess || !sc->sc_tinfo) {
- printf("out of memory\n");
- return (ENOMEM);
+ if (sc->sc_tinfo == NULL) {
+ device_printf(sc->sc_dev,
+ "cannot allocate target info buffer\n");
+ error = ENOMEM;
+ goto fail_imess;
}
callout_init(&sc->sc_watchdog, 0);
@@ -298,27 +318,32 @@ ncr53c9x_attach(struct ncr53c9x_softc *sc)
* Register with CAM
*/
devq = cam_simq_alloc(sc->sc_ntarg);
- if (devq == NULL)
- return (ENOMEM);
+ if (devq == NULL) {
+ device_printf(sc->sc_dev, "cannot allocate device queue\n");
+ error = ENOMEM;
+ goto fail_tinfo;
+ }
sim = cam_sim_alloc(ncr53c9x_action, ncr53c9x_poll, "esp", sc,
device_get_unit(sc->sc_dev), 1,
NCR_TAG_DEPTH, devq);
if (sim == NULL) {
- cam_simq_free(devq);
- return (ENOMEM);
+ device_printf(sc->sc_dev, "cannot allocate SIM entry\n");
+ error = ENOMEM;
+ goto fail_devq;
}
if (xpt_bus_register(sim, 0) != CAM_SUCCESS) {
- cam_sim_free(sim, TRUE);
- return (EIO);
+ device_printf(sc->sc_dev, "cannot register bus\n");
+ error = EIO;
+ goto fail_sim;
}
if (xpt_create_path(&path, NULL, cam_sim_path(sim),
CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD)
!= CAM_REQ_CMP) {
- xpt_bus_deregister(cam_sim_path(sim));
- cam_sim_free(sim, TRUE);
- return (EIO);
+ device_printf(sc->sc_dev, "cannot create path\n");
+ error = EIO;
+ goto fail_bus;
}
sc->sc_sim = sim;
@@ -335,7 +360,8 @@ ncr53c9x_attach(struct ncr53c9x_softc *sc)
if ((sc->ecb_array = malloc(sizeof(struct ncr53c9x_ecb) * NCR_TAG_DEPTH,
M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL) {
device_printf(sc->sc_dev, "cannot allocate ECB array\n");
- return (ENOMEM);
+ error = ENOMEM;
+ goto fail_path;
}
for (i = 0; i < NCR_TAG_DEPTH; i++) {
ecb = &sc->ecb_array[i];
@@ -347,18 +373,46 @@ ncr53c9x_attach(struct ncr53c9x_softc *sc)
callout_reset(&sc->sc_watchdog, 60*hz, ncr53c9x_watch, sc);
return (0);
+
+fail_path:
+ xpt_free_path(path);
+fail_bus:
+ xpt_bus_deregister(cam_sim_path(sim));
+fail_sim:
+ cam_sim_free(sim, TRUE);
+fail_devq:
+ cam_simq_free(devq);
+fail_tinfo:
+ free(sc->sc_tinfo, M_DEVBUF);
+fail_imess:
+ if (sc->sc_imess_self)
+ free(sc->sc_imess, M_DEVBUF);
+fail_omess:
+ if (sc->sc_omess_self)
+ free(sc->sc_omess, M_DEVBUF);
+ return (error);
}
int
-ncr53c9x_detach(struct ncr53c9x_softc *sc, int flags)
+ncr53c9x_detach(struct ncr53c9x_softc *sc)
{
-#if 0 /* don't allow detach for now */
- free(sc->sc_imess, M_DEVBUF);
- free(sc->sc_omess, M_DEVBUF);
-#endif
+ callout_drain(&sc->sc_watchdog);
+ mtx_lock(&sc->sc_lock);
+ ncr53c9x_init(sc, 1);
+ mtx_unlock(&sc->sc_lock);
+ xpt_free_path(sc->sc_path);
+ xpt_bus_deregister(cam_sim_path(sc->sc_sim));
+ cam_sim_free(sc->sc_sim, TRUE);
+ free(sc->ecb_array, M_DEVBUF);
+ free(sc->sc_tinfo, M_DEVBUF);
+ if (sc->sc_imess_self)
+ free(sc->sc_imess, M_DEVBUF);
+ if (sc->sc_omess_self)
+ free(sc->sc_omess, M_DEVBUF);
+ mtx_destroy(&sc->sc_lock);
- return (EINVAL);
+ return (0);
}
/*
@@ -388,7 +442,9 @@ ncr53c9x_reset(struct ncr53c9x_softc *sc)
NCR_WRITE_REG(sc, NCR_CFG5, sc->sc_cfg5 | NCRCFG5_SINT);
NCR_WRITE_REG(sc, NCR_CFG4, sc->sc_cfg4);
case NCR_VARIANT_AM53C974:
+ case NCR_VARIANT_FAS100A:
case NCR_VARIANT_FAS216:
+ case NCR_VARIANT_FAS236:
case NCR_VARIANT_NCR53C94:
case NCR_VARIANT_NCR53C96:
case NCR_VARIANT_ESP200:
@@ -515,7 +571,10 @@ ncr53c9x_init(struct ncr53c9x_softc *sc, int doreset)
*/
ncr53c9x_reset(sc);
+ sc->sc_flags = 0;
+ sc->sc_msgpriq = sc->sc_msgout = sc->sc_msgoutq = 0;
sc->sc_phase = sc->sc_prevphase = INVALID_PHASE;
+
for (r = 0; r < sc->sc_ntarg; r++) {
struct ncr53c9x_tinfo *ti = &sc->sc_tinfo[r];
/* XXX - config flags per target: low bits: no reselect; high bits: no synch */
@@ -1793,8 +1852,7 @@ gotit:
/*
* target initiated negotiation
*/
- if (ti->period <
- sc->sc_minsync)
+ if (ti->period < sc->sc_minsync)
ti->period =
sc->sc_minsync;
if (ti->offset > 15)
@@ -2494,9 +2552,17 @@ again:
* Arbitration won; examine the `step' register
* to determine how far the selection could progress.
*/
- ecb = sc->sc_nexus;
- if (ecb == NULL)
+ if (ecb == NULL) {
+ /*
+ * When doing path inquiry during boot
+ * FAS100A trigger a stray interrupt which
+ * we just ignore instead of panicing.
+ */
+ if (sc->sc_state == NCR_IDLE &&
+ sc->sc_espstep == 0)
+ goto out;
panic("ncr53c9x: no nexus");
+ }
ti = &sc->sc_tinfo[ecb->ccb->ccb_h.target_id];
@@ -2613,8 +2679,7 @@ again:
}
if (sc->sc_state == NCR_IDLE) {
device_printf(sc->sc_dev, "stray interrupt\n");
- mtx_unlock(&sc->sc_lock);
- return;
+ goto out;
}
break;
diff --git a/sys/dev/esp/ncr53c9xreg.h b/sys/dev/esp/ncr53c9xreg.h
index 647bef8..c24f807 100644
--- a/sys/dev/esp/ncr53c9xreg.h
+++ b/sys/dev/esp/ncr53c9xreg.h
@@ -173,7 +173,7 @@
#define NCRESPCFG3_ADMA 0x02 /* Alternate DMA Mode */
#define NCRESPCFG3_T8M 0x01 /* Threshold 8 Mode */
-/* Config #3 also different on NCR53CF9x/FAS216 */
+/* Config #3 also different on NCR53CF9x/FAS100A/FAS216/FAS236 */
#define NCR_F9XCFG3 0x0c /* RW - Configuration #3 */
#define NCRF9XCFG3_IDM 0x80 /* ID Message Res Check */
#define NCRF9XCFG3_QTE 0x40 /* Queue Tag Enable */
diff --git a/sys/dev/esp/ncr53c9xvar.h b/sys/dev/esp/ncr53c9xvar.h
index fc58848..79afcee 100644
--- a/sys/dev/esp/ncr53c9xvar.h
+++ b/sys/dev/esp/ncr53c9xvar.h
@@ -99,7 +99,9 @@
#define NCR_VARIANT_AM53C974 8
#define NCR_VARIANT_FAS366 9
#define NCR_VARIANT_NCR53C90_86C01 10
-#define NCR_VARIANT_MAX 11
+#define NCR_VARIANT_FAS100A 11
+#define NCR_VARIANT_FAS236 12
+#define NCR_VARIANT_MAX 13
/* XXX Max tag depth. Should this be defined in the register header? */
#define NCR_TAG_DEPTH 256
@@ -333,9 +335,11 @@ struct ncr53c9x_softc {
u_short sc_msgoutq; /* What messages have been sent so far? */
u_char *sc_omess; /* MSGOUT buffer */
+ int sc_omess_self; /* MSGOUT buffer is self-allocated */
caddr_t sc_omp; /* Message pointer (for multibyte messages) */
size_t sc_omlen;
u_char *sc_imess; /* MSGIN buffer */
+ int sc_imess_self; /* MSGIN buffer is self-allocated */
caddr_t sc_imp; /* Message pointer (for multibyte messages) */
size_t sc_imlen;
@@ -459,7 +463,7 @@ struct ncr53c9x_softc {
((250 * (cpb)) / (sc)->sc_freq)
int ncr53c9x_attach(struct ncr53c9x_softc *);
-int ncr53c9x_detach(struct ncr53c9x_softc *, int);
+int ncr53c9x_detach(struct ncr53c9x_softc *);
void ncr53c9x_action(struct cam_sim *, union ccb *);
void ncr53c9x_reset(struct ncr53c9x_softc *);
void ncr53c9x_intr(void *);
diff --git a/sys/modules/esp/Makefile b/sys/modules/esp/Makefile
index 3b36ce3..2685b09 100644
--- a/sys/modules/esp/Makefile
+++ b/sys/modules/esp/Makefile
@@ -9,7 +9,7 @@ SRCS+= opt_ddb.h opt_cam.h
SRCS+= device_if.h bus_if.h
.if ${MACHINE_ARCH} == "sparc64"
-SRCS+= esp_sbus.c lsi64854.c ofw_bus_if.h
+SRCS+= esp_sbus.c ofw_bus_if.h
.endif
.include <bsd.kmod.mk>
diff --git a/sys/sparc64/sbus/dma_sbus.c b/sys/sparc64/sbus/dma_sbus.c
new file mode 100644
index 0000000..9f34a8fc
--- /dev/null
+++ b/sys/sparc64/sbus/dma_sbus.c
@@ -0,0 +1,506 @@
+/* $OpenBSD: dma_sbus.c,v 1.12 2005/03/03 01:41:45 miod Exp $ */
+/* $NetBSD: dma_sbus.c,v 1.5 2000/07/09 20:57:42 pk Exp $ */
+
+/*-
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 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.
+ */
+
+/*-
+ * Copyright (c) 1994 Peter Galbavy. All rights reserved.
+ * Copyright (c) 2005 Marius Strobl <marius@FreeBSD.org>. 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.
+ *
+ * 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/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/openfirm.h>
+
+#include <machine/bus.h>
+#include <machine/bus_common.h>
+#include <machine/resource.h>
+
+#include <sparc64/sbus/lsi64854reg.h>
+#include <sparc64/sbus/lsi64854var.h>
+#include <sparc64/sbus/ofw_sbus.h>
+#include <sparc64/sbus/sbusreg.h>
+#include <sparc64/sbus/sbusvar.h>
+
+struct dma_devinfo {
+ char *ddi_compat; /* PROM compatible */
+ char *ddi_model; /* PROM model */
+ char *ddi_name; /* PROM name */
+ phandle_t ddi_node; /* PROM node */
+ char *ddi_type; /* PROM device_type */
+
+ struct resource_list ddi_rl;
+};
+
+struct dma_softc {
+ struct lsi64854_softc sc_lsi64854; /* base device */
+ int sc_ign;
+ int sc_slot;
+};
+
+static devclass_t dma_devclass;
+
+static device_probe_t dma_probe;
+static device_attach_t dma_attach;
+static bus_print_child_t dma_print_child;
+static bus_probe_nomatch_t dma_probe_nomatch;
+static bus_get_resource_list_t dma_get_resource_list;
+#if 0
+static bus_setup_intr_t dma_setup_intr;
+#endif
+static ofw_bus_get_compat_t dma_get_compat;
+static ofw_bus_get_model_t dma_get_model;
+static ofw_bus_get_name_t dma_get_name;
+static ofw_bus_get_node_t dma_get_node;
+static ofw_bus_get_type_t dma_get_type;
+
+static struct dma_devinfo *dma_setup_dinfo(device_t, phandle_t, char *);
+static void dma_destroy_dinfo(struct dma_devinfo *);
+
+static device_method_t dma_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, dma_probe),
+ DEVMETHOD(device_attach, dma_attach),
+
+ /* Bus interface */
+ DEVMETHOD(bus_print_child, dma_print_child),
+ DEVMETHOD(bus_probe_nomatch, dma_probe_nomatch),
+#if 0
+ DEVMETHOD(bus_setup_intr, dma_setup_intr),
+#else
+ DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
+#endif
+ DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
+ DEVMETHOD(bus_alloc_resource, bus_generic_rl_alloc_resource),
+ DEVMETHOD(bus_release_resource, bus_generic_rl_release_resource),
+ DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
+ DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
+ DEVMETHOD(bus_get_resource_list, dma_get_resource_list),
+ DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource),
+
+ /* ofw_bus interface */
+ DEVMETHOD(ofw_bus_get_compat, dma_get_compat),
+ DEVMETHOD(ofw_bus_get_model, dma_get_model),
+ DEVMETHOD(ofw_bus_get_name, dma_get_name),
+ DEVMETHOD(ofw_bus_get_node, dma_get_node),
+ DEVMETHOD(ofw_bus_get_type, dma_get_type),
+
+ { 0, 0 }
+};
+
+static driver_t dma_driver = {
+ "dma",
+ dma_methods,
+ sizeof(struct dma_softc),
+};
+
+DRIVER_MODULE(dma, sbus, dma_driver, dma_devclass, 0, 0);
+
+static int
+dma_probe(device_t dev)
+{
+ const char *name;
+
+ name = ofw_bus_get_name(dev);
+ if (strcmp(name, "espdma") == 0 || strcmp(name, "dma") == 0 ||
+ strcmp(name, "ledma") == 0) {
+ device_set_desc_copy(dev, name);
+ return (0);
+ }
+ return (ENXIO);
+}
+
+static int
+dma_attach(device_t dev)
+{
+ struct dma_softc *dsc;
+ struct lsi64854_softc *lsc;
+ struct dma_devinfo *ddi;
+ device_t cdev;
+ const char *name;
+ char *cabletype, *cname;
+ uint32_t csr;
+ phandle_t child, node;
+ int error, burst, children;
+
+ dsc = device_get_softc(dev);
+ bzero(dsc, sizeof(struct dma_softc));
+ lsc = &dsc->sc_lsi64854;
+
+ name = ofw_bus_get_name(dev);
+ node = ofw_bus_get_node(dev);
+ dsc->sc_ign = sbus_get_ign(dev);
+ dsc->sc_slot = sbus_get_slot(dev);
+
+ lsc->sc_rid = 0;
+ lsc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &lsc->sc_rid,
+ RF_ACTIVE);
+ if (lsc->sc_res == NULL) {
+ device_printf(dev, "cannot allocate resources\n");
+ return (ENXIO);
+ }
+ lsc->sc_regt = rman_get_bustag(lsc->sc_res);
+ lsc->sc_regh = rman_get_bushandle(lsc->sc_res);
+
+ if (strcmp(name, "espdma") == 0 || strcmp(name, "dma") == 0)
+ lsc->sc_channel = L64854_CHANNEL_SCSI;
+ else if (strcmp(name, "ledma") == 0) {
+ /*
+ * Check to see which cable type is currently active and
+ * set the appropriate bit in the ledma csr so that it
+ * gets used. If we didn't netboot, the PROM won't have
+ * the "cable-selection" property; default to TP and then
+ * the user can change it via a "media" option to ifconfig.
+ */
+ csr = L64854_GCSR(lsc);
+ if ((OF_getprop_alloc(node, "cable-selection", 1,
+ (void **)&cabletype)) == -1) {
+ /* assume TP if nothing there */
+ csr |= E_TP_AUI;
+ } else {
+ if (strcmp(cabletype, "aui") == 0)
+ csr &= ~E_TP_AUI;
+ else
+ csr |= E_TP_AUI;
+ free(cabletype, M_OFWPROP);
+ }
+ L64854_SCSR(lsc, csr);
+ DELAY(20000); /* manual says we need a 20ms delay */
+ lsc->sc_channel = L64854_CHANNEL_ENET;
+ } else {
+ device_printf(dev, "unsupported DMA channel\n");
+ error = ENXIO;
+ goto fail_lres;
+ }
+
+ error = bus_dma_tag_create(
+ NULL, /* parent */
+ PAGE_SIZE, 0, /* alignment, boundary */
+ BUS_SPACE_MAXADDR, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ BUS_SPACE_MAXSIZE_32BIT, /* maxsize */
+ 0, /* nsegments */
+ BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */
+ 0, /* flags */
+ NULL, NULL, /* no locking */
+ &lsc->sc_parent_dmat);
+ if (error != 0) {
+ device_printf(dev, "cannot allocate parent DMA tag\n");
+ goto fail_lres;
+ }
+
+ burst = sbus_get_burstsz(dev);
+ lsc->sc_burst = (burst & SBUS_BURST_32) ? 32 :
+ (burst & SBUS_BURST_16) ? 16 : 0;
+ lsc->sc_dev = dev;
+
+ error = lsi64854_attach(lsc);
+ if (error != 0) {
+ device_printf(dev, "lsi64854_attach failed\n");
+ goto fail_lpdma;
+ }
+
+ /* Attach children. */
+ children = 0;
+ for (child = OF_child(node); child != 0; child = OF_peer(child)) {
+ if ((OF_getprop_alloc(child, "name", 1, (void **)&cname)) == -1)
+ continue;
+ if ((ddi = dma_setup_dinfo(dev, child, cname)) == NULL) {
+ device_printf(dev, "<%s>: incomplete\n", cname);
+ free(cname, M_OFWPROP);
+ continue;
+ }
+ if (children != 0) {
+ device_printf(dev, "<%s>: only one child per DMA "
+ "channel supported\n", cname);
+ dma_destroy_dinfo(ddi);
+ free(cname, M_OFWPROP);
+ continue;
+ }
+ if ((cdev = device_add_child(dev, NULL, -1)) == NULL) {
+ device_printf(dev, "<%s>: device_add_child failed\n",
+ cname);
+ dma_destroy_dinfo(ddi);
+ free(cname, M_OFWPROP);
+ continue;
+ }
+ device_set_ivars(cdev, ddi);
+ children++;
+ }
+ error = bus_generic_attach(dev);
+ if (error != 0) {
+ device_printf(dev, "bus_generic_attach failed\n");
+ goto fail_lsi;
+ }
+
+ return (0);
+
+ fail_lsi:
+ lsi64854_detach(lsc);
+ fail_lpdma:
+ bus_dma_tag_destroy(lsc->sc_parent_dmat);
+ fail_lres:
+ bus_release_resource(dev, SYS_RES_MEMORY, lsc->sc_rid, lsc->sc_res);
+ return (error);
+}
+
+static struct dma_devinfo *
+dma_setup_dinfo(device_t dev, phandle_t node, char *name)
+{
+ struct dma_softc *dsc;
+ struct dma_devinfo *ddi;
+ struct sbus_regs *reg;
+ uint32_t base, iv, *intr;
+ int i, nreg, nintr, slot, rslot;
+
+ dsc = device_get_softc(dev);
+
+ ddi = malloc(sizeof(*ddi), M_DEVBUF, M_WAITOK | M_ZERO);
+ if (ddi == NULL)
+ return (NULL);
+ resource_list_init(&ddi->ddi_rl);
+ ddi->ddi_name = name;
+ ddi->ddi_node = node;
+ OF_getprop_alloc(node, "compatible", 1, (void **)&ddi->ddi_compat);
+ OF_getprop_alloc(node, "device_type", 1, (void **)&ddi->ddi_type);
+ OF_getprop_alloc(node, "model", 1, (void **)&ddi->ddi_model);
+ slot = -1;
+ nreg = OF_getprop_alloc(node, "reg", sizeof(*reg), (void **)&reg);
+ if (nreg == -1) {
+ dma_destroy_dinfo(ddi);
+ return (NULL);
+ }
+ for (i = 0; i < nreg; i++) {
+ base = reg[i].sbr_offset;
+ if (SBUS_ABS(base)) {
+ rslot = SBUS_ABS_TO_SLOT(base);
+ base = SBUS_ABS_TO_OFFSET(base);
+ } else
+ rslot = reg[i].sbr_slot;
+ if (slot != -1 && slot != rslot) {
+ device_printf(dev, "<%s>: multiple slots\n", name);
+ free(reg, M_OFWPROP);
+ dma_destroy_dinfo(ddi);
+ return (NULL);
+ }
+ slot = rslot;
+
+ resource_list_add(&ddi->ddi_rl, SYS_RES_MEMORY, i, base,
+ base + reg[i].sbr_size, reg[i].sbr_size);
+ }
+ free(reg, M_OFWPROP);
+ if (slot != dsc->sc_slot) {
+ device_printf(dev, "<%s>: parent and child slot do not match\n",
+ name);
+ dma_destroy_dinfo(ddi);
+ return (NULL);
+ }
+
+ /*
+ * The `interrupts' property contains the SBus interrupt level.
+ */
+ nintr = OF_getprop_alloc(node, "interrupts", sizeof(*intr),
+ (void **)&intr);
+ if (nintr != -1) {
+ for (i = 0; i < nintr; i++) {
+ iv = intr[i];
+ /*
+ * SBus card devices need the slot number encoded into
+ * the vector as this is generally not done.
+ */
+ if ((iv & INTMAP_OBIO_MASK) == 0)
+ iv |= slot << 3;
+ /* Set the IGN as appropriate. */
+ iv |= dsc->sc_ign << INTMAP_IGN_SHIFT;
+ resource_list_add(&ddi->ddi_rl, SYS_RES_IRQ, i,
+ iv, iv, 1);
+ }
+ free(intr, M_OFWPROP);
+ }
+ return (ddi);
+}
+
+static void
+dma_destroy_dinfo(struct dma_devinfo *dinfo)
+{
+
+ resource_list_free(&dinfo->ddi_rl);
+ if (dinfo->ddi_compat != NULL)
+ free(dinfo->ddi_compat, M_OFWPROP);
+ if (dinfo->ddi_model != NULL)
+ free(dinfo->ddi_model, M_OFWPROP);
+ if (dinfo->ddi_type != NULL)
+ free(dinfo->ddi_type, M_OFWPROP);
+ free(dinfo, M_DEVBUF);
+}
+
+static int
+dma_print_child(device_t dev, device_t child)
+{
+ struct dma_devinfo *ddi;
+ struct resource_list *rl;
+ int rv;
+
+ ddi = device_get_ivars(child);
+ rl = &ddi->ddi_rl;
+ rv = bus_print_child_header(dev, child);
+ rv += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx");
+ rv += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld");
+ rv += bus_print_child_footer(dev, child);
+ return (rv);
+}
+
+static void
+dma_probe_nomatch(device_t dev, device_t child)
+{
+ struct dma_devinfo *ddi;
+ struct resource_list *rl;
+
+ ddi = device_get_ivars(child);
+ rl = &ddi->ddi_rl;
+ device_printf(dev, "<%s>", ddi->ddi_name);
+ resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx");
+ resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld");
+ printf(" type %s (no driver attached)\n",
+ ddi->ddi_type != NULL ? ddi->ddi_type : "unknown");
+}
+
+static struct resource_list *
+dma_get_resource_list(device_t dev, device_t child)
+{
+ struct dma_devinfo *ddi;
+
+ ddi = device_get_ivars(child);
+ return (&ddi->ddi_rl);
+}
+
+#if 0
+static int
+dma_setup_intr(device_t dev, device_t child, struct resource *ires, int flags,
+ driver_intr_t *intr, void *arg, void **cookiep)
+{
+ struct lsi64854_softc *sc;
+
+ sc = (struct lsi64854_softc *)device_get_softc(dev);
+ /* XXX - for now only le; do ESP later */
+ if (sc->sc_channel == L64854_CHANNEL_ENET) {
+ sc->sc_intrchain = intr;
+ sc->sc_intrchainarg = arg;
+ intr = (driver_intr_t *)lsi64854_enet_intr;
+ arg = sc;
+ }
+
+ return (BUS_SETUP_INTR(device_get_parent(dev), child, ires, flags,
+ intr, arg, cookiep));
+}
+#endif
+
+static const char *
+dma_get_compat(device_t bus, device_t dev)
+{
+ struct dma_devinfo *dinfo;
+
+ dinfo = device_get_ivars(dev);
+ return (dinfo->ddi_compat);
+}
+
+static const char *
+dma_get_model(device_t bus, device_t dev)
+{
+ struct dma_devinfo *dinfo;
+
+ dinfo = device_get_ivars(dev);
+ return (dinfo->ddi_model);
+}
+
+static const char *
+dma_get_name(device_t bus, device_t dev)
+{
+ struct dma_devinfo *dinfo;
+
+ dinfo = device_get_ivars(dev);
+ return (dinfo->ddi_name);
+}
+
+static phandle_t
+dma_get_node(device_t bus, device_t dev)
+{
+ struct dma_devinfo *dinfo;
+
+ dinfo = device_get_ivars(dev);
+ return (dinfo->ddi_node);
+}
+
+static const char *
+dma_get_type(device_t bus, device_t dev)
+{
+ struct dma_devinfo *dinfo;
+
+ dinfo = device_get_ivars(dev);
+ return (dinfo->ddi_type);
+}
diff --git a/sys/sparc64/sbus/lsi64854.c b/sys/sparc64/sbus/lsi64854.c
index 1e70cfc..72bf36c 100644
--- a/sys/sparc64/sbus/lsi64854.c
+++ b/sys/sparc64/sbus/lsi64854.c
@@ -113,10 +113,11 @@ int lsi64854debug = 0;
* sc_channel (one of SCSI, ENET, PP)
* sc_client (one of SCSI, ENET, PP `soft_c' pointers)
*/
-void
+int
lsi64854_attach(struct lsi64854_softc *sc)
{
uint32_t csr;
+ int error;
/* Indirect functions */
switch (sc->sc_channel) {
@@ -136,7 +137,7 @@ lsi64854_attach(struct lsi64854_softc *sc)
sc->reset = lsi64854_reset;
/* Allocate a dmamap */
- if (bus_dma_tag_create(
+ error = bus_dma_tag_create(
sc->sc_parent_dmat, /* parent */
1, 0, /* alignment, boundary */
BUS_SPACE_MAXADDR, /* lowaddr */
@@ -147,27 +148,30 @@ lsi64854_attach(struct lsi64854_softc *sc)
MAX_DMA_SZ, /* maxsegsize */
BUS_DMA_ALLOCNOW, /* flags */
NULL, NULL, /* lockfunc, lockarg */
- &sc->sc_buffer_dmat)) {
+ &sc->sc_buffer_dmat);
+ if (error != 0) {
device_printf(sc->sc_dev, "cannot allocate buffer DMA tag\n");
- return;
+ return (error);
}
- if (bus_dmamap_create(sc->sc_buffer_dmat, 0, &sc->sc_dmamap) != 0) {
+ error = bus_dmamap_create(sc->sc_buffer_dmat, 0, &sc->sc_dmamap);
+ if (error != 0) {
device_printf(sc->sc_dev, "DMA map create failed\n");
- return;
+ bus_dma_tag_destroy(sc->sc_buffer_dmat);
+ return (error);
}
csr = L64854_GCSR(sc);
sc->sc_rev = csr & L64854_DEVID;
if (sc->sc_rev == DMAREV_HME)
- return;
+ return (0);
device_printf(sc->sc_dev, "DMA rev. ");
switch (sc->sc_rev) {
case DMAREV_0:
printf("0");
break;
case DMAREV_ESC:
- printf("esc");
+ printf("ESC");
break;
case DMAREV_1:
printf("1");
@@ -184,6 +188,20 @@ lsi64854_attach(struct lsi64854_softc *sc)
DPRINTF(LDB_ANY, (", burst 0x%x, csr 0x%x", sc->sc_burst, csr));
printf("\n");
+
+ return (0);
+}
+
+int
+lsi64854_detach(struct lsi64854_softc *sc)
+{
+
+ if (sc->setup)
+ bus_dmamap_unload(sc->sc_buffer_dmat, sc->sc_dmamap);
+ bus_dmamap_destroy(sc->sc_buffer_dmat, sc->sc_dmamap);
+ bus_dma_tag_destroy(sc->sc_buffer_dmat);
+
+ return (0);
}
/*
@@ -265,7 +283,6 @@ lsi64854_reset(struct lsi64854_softc *sc)
if (sc->sc_rev == DMAREV_HME)
L64854_SCSR(sc, csr | D_HW_RESET_FAS366);
-
csr |= L64854_RESET; /* reset DMA */
L64854_SCSR(sc, csr);
DELAY(200); /* > 10 Sbus clocks(?) */
@@ -490,7 +507,7 @@ lsi64854_scsi_intr(void *arg)
}
trans = sc->sc_dmasize - resid;
- if (trans < 0) { /* transferred < 0 ? */
+ if (trans < 0) { /* transfered < 0? */
#if 0
/*
* This situation can happen in perfectly normal operation
@@ -566,7 +583,9 @@ lsi64854_enet_intr(void *arg)
DELAY(1);
}
- return (rv | (*sc->sc_intrchain)(sc->sc_intrchainarg));
+ (*sc->sc_intrchain)(sc->sc_intrchainarg);
+
+ return (rv);
}
static void
diff --git a/sys/sparc64/sbus/lsi64854var.h b/sys/sparc64/sbus/lsi64854var.h
index d7fc9ce..3b5e20c 100644
--- a/sys/sparc64/sbus/lsi64854var.h
+++ b/sys/sparc64/sbus/lsi64854var.h
@@ -69,8 +69,8 @@ struct lsi64854_softc {
int, size_t *); /* DMA setup */
int (*intr)(void *); /* interrupt handler */
- int (*sc_intrchain)(void *); /* next handler in intr chain */
- void *sc_intrchainarg; /* arg for next intr handler */
+ driver_intr_t *sc_intrchain; /* next handler in intr chain */
+ void *sc_intrchainarg; /* arg for next intr handler */
u_int sc_dmactl;
};
@@ -107,7 +107,8 @@ struct lsi64854_softc {
} while (0)
-void lsi64854_attach(struct lsi64854_softc *);
+int lsi64854_attach(struct lsi64854_softc *);
+int lsi64854_detach(struct lsi64854_softc *);
int lsi64854_scsi_intr(void *);
int lsi64854_enet_intr(void *);
int lsi64854_pp_intr(void *);
OpenPOWER on IntegriCloud