diff options
-rw-r--r-- | sys/conf/files.sparc64 | 3 | ||||
-rw-r--r-- | sys/dev/esp/esp_sbus.c | 458 | ||||
-rw-r--r-- | sys/dev/esp/ncr53c9x.c | 125 | ||||
-rw-r--r-- | sys/dev/esp/ncr53c9xreg.h | 2 | ||||
-rw-r--r-- | sys/dev/esp/ncr53c9xvar.h | 8 | ||||
-rw-r--r-- | sys/modules/esp/Makefile | 2 | ||||
-rw-r--r-- | sys/sparc64/sbus/dma_sbus.c | 506 | ||||
-rw-r--r-- | sys/sparc64/sbus/lsi64854.c | 41 | ||||
-rw-r--r-- | sys/sparc64/sbus/lsi64854var.h | 7 |
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 **)®); + 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 *); |