diff options
-rw-r--r-- | sys/dev/esp/esp_sbus.c | 233 | ||||
-rw-r--r-- | sys/dev/esp/ncr53c9x.c | 833 | ||||
-rw-r--r-- | sys/dev/esp/ncr53c9xreg.h | 4 | ||||
-rw-r--r-- | sys/dev/esp/ncr53c9xvar.h | 64 | ||||
-rw-r--r-- | sys/dev/le/if_le_ledma.c | 62 | ||||
-rw-r--r-- | sys/sparc64/sbus/dma_sbus.c | 32 | ||||
-rw-r--r-- | sys/sparc64/sbus/lsi64854.c | 135 | ||||
-rw-r--r-- | sys/sparc64/sbus/lsi64854var.h | 15 |
8 files changed, 765 insertions, 613 deletions
diff --git a/sys/dev/esp/esp_sbus.c b/sys/dev/esp/esp_sbus.c index 962dab1..2033cc6 100644 --- a/sys/dev/esp/esp_sbus.c +++ b/sys/dev/esp/esp_sbus.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2004 Scott Long + * Copyright (c) 2005 Marius Strobl <marius@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -71,8 +72,9 @@ __FBSDID("$FreeBSD$"); #include <sys/systm.h> #include <sys/bus.h> #include <sys/kernel.h> +#include <sys/lock.h> #include <sys/module.h> -#include <sys/resource.h> +#include <sys/mutex.h> #include <dev/ofw/ofw_bus.h> #include <dev/ofw/openfirm.h> @@ -83,6 +85,7 @@ __FBSDID("$FreeBSD$"); #include <cam/cam.h> #include <cam/cam_ccb.h> #include <cam/scsi/scsi_all.h> +#include <cam/scsi/scsi_message.h> #include <sparc64/sbus/lsi64854reg.h> #include <sparc64/sbus/lsi64854var.h> @@ -97,12 +100,8 @@ struct esp_softc { struct ncr53c9x_softc sc_ncr53c9x; /* glue to MI code */ struct device *sc_dev; - int sc_rid; struct resource *sc_res; - bus_space_handle_t sc_regh; - bus_space_tag_t sc_regt; - int sc_irqrid; struct resource *sc_irqres; void *sc_irq; @@ -155,8 +154,6 @@ static driver_t esp_sbus_driver = { DRIVER_MODULE(esp, sbus, esp_sbus_driver, esp_devclass, 0, 0); MODULE_DEPEND(esp, sbus, 1, 1, 1); -MODULE_DEPEND(esp, cam, 1, 1, 1); - /* * Functions and the switch for the MI code */ @@ -170,9 +167,11 @@ static int esp_dma_setup(struct ncr53c9x_softc *sc, caddr_t *addr, static void esp_dma_go(struct ncr53c9x_softc *sc); static void esp_dma_stop(struct ncr53c9x_softc *sc); static int esp_dma_isactive(struct ncr53c9x_softc *sc); -static int espattach(struct esp_softc *esc, struct ncr53c9x_glue *gluep); +static int espattach(struct esp_softc *esc, + const struct ncr53c9x_glue *gluep); +static int espdetach(struct esp_softc *esc); -static struct ncr53c9x_glue esp_sbus_glue = { +static const struct ncr53c9x_glue esp_sbus_glue = { esp_read_reg, esp_write_reg, esp_dma_isintr, @@ -209,29 +208,16 @@ esp_sbus_attach(device_t dev) struct ncr53c9x_softc *sc; struct lsi64854_softc *lsc; device_t *children; - const char *name; - phandle_t node; - int burst, error, i, nchildren, slot; + int error, i, nchildren; 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; 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 - - if (strcmp(name, "SUNW,fas") == 0) { + if (strcmp(ofw_bus_get_name(dev), "SUNW,fas") == 0) { /* * Allocate space for DMA, in SUNW,fas there are no * separate DMA devices. @@ -250,20 +236,18 @@ esp_sbus_attach(device_t dev) */ /* Allocate DMA registers. */ - lsc->sc_rid = 0; + i = 0; if ((lsc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, - &lsc->sc_rid, RF_ACTIVE)) == NULL) { + &i, 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( bus_get_dma_tag(dev), /* parent */ - PAGE_SIZE, 0, /* alignment, boundary */ + 1, 0, /* alignment, boundary */ BUS_SPACE_MAXADDR, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ @@ -277,38 +261,31 @@ esp_sbus_attach(device_t dev) device_printf(dev, "cannot allocate parent DMA tag\n"); goto fail_sbus_lres; } - burst = sbus_get_burstsz(dev); + + i = sbus_get_burstsz(dev); #ifdef ESP_SBUS_DEBUG - printf("%s: burst 0x%x\n", __func__, burst); + printf("%s: burst 0x%x\n", __func__, i); #endif - lsc->sc_burst = (burst & SBUS_BURST_32) ? 32 : - (burst & SBUS_BURST_16) ? 16 : 0; + lsc->sc_burst = (i & SBUS_BURST_32) ? 32 : + (i & 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; + i = 1; if ((esc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, - &esc->sc_rid, RF_ACTIVE)) == NULL) { + &i, RF_ACTIVE)) == NULL) { device_printf(dev, "cannot allocate SCSI core registers\n"); error = ENXIO; - goto fail_sbus_lsi; + goto fail_sbus_lpdma; } - 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 @@ -319,10 +296,9 @@ esp_sbus_attach(device_t dev) 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 && + sbus_get_slot(children[i]) == sbus_get_slot(dev) && strcmp(ofw_bus_get_name(children[i]), "dma") == 0) { /* XXX hackery */ esc->sc_dma = (struct lsi64854_softc *) @@ -340,15 +316,13 @@ esp_sbus_attach(device_t dev) /* * Allocate SCSI core registers. */ - esc->sc_rid = 0; + i = 0; if ((esc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, - &esc->sc_rid, RF_ACTIVE)) == NULL) { + &i, 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); } error = espattach(esc, &esp_sbus_glue); @@ -360,15 +334,15 @@ esp_sbus_attach(device_t dev) return (0); fail_sbus_eres: - bus_release_resource(dev, SYS_RES_MEMORY, esc->sc_rid, esc->sc_res); - if (strcmp(name, "SUNW,fas") != 0) + bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(esc->sc_res), + esc->sc_res); + if (strcmp(ofw_bus_get_name(dev), "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); + bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(lsc->sc_res), + lsc->sc_res); fail_sbus_lsc: free(lsc, M_DEVBUF); return (error); @@ -378,28 +352,22 @@ 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); + error = espdetach(esc); 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); + bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(esc->sc_res), + 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); + bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(lsc->sc_res), + lsc->sc_res); free(lsc, M_DEVBUF); return (0); @@ -410,29 +378,18 @@ esp_dma_attach(device_t dev) { struct esp_softc *esc; struct ncr53c9x_softc *sc; - phandle_t node; - int error; + int error, i; esc = device_get_softc(dev); - bzero(esc, sizeof(struct esp_softc)); sc = &esc->sc_ncr53c9x; 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) { + if (OF_getprop(ofw_bus_get_node(dev), "clock-frequency", + &sc->sc_freq, sizeof(sc->sc_freq)) == -1) { printf("failed to query OFW for clock-frequency\n"); return (ENXIO); } -#ifdef ESP_SBUS_DEBUG - device_printf(dev, "%s: sc_id %d, freq %d\n", __func__, sc->sc_id, - sc->sc_freq); -#endif - /* XXX hackery */ esc->sc_dma = (struct lsi64854_softc *) device_get_softc(device_get_parent(dev)); @@ -441,14 +398,12 @@ esp_dma_attach(device_t dev) /* * Allocate SCSI core registers. */ - esc->sc_rid = 0; + i = 0; if ((esc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, - &esc->sc_rid, RF_ACTIVE)) == NULL) { + &i, 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); error = espattach(esc, &esp_sbus_glue); if (error != 0) { @@ -459,7 +414,8 @@ esp_dma_attach(device_t dev) return (0); fail_dma_eres: - bus_release_resource(dev, SYS_RES_MEMORY, esc->sc_rid, esc->sc_res); + bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(esc->sc_res), + esc->sc_res); return (error); } @@ -467,19 +423,15 @@ static int esp_dma_detach(device_t dev) { struct esp_softc *esc; - struct ncr53c9x_softc *sc; int error; esc = device_get_softc(dev); - sc = &esc->sc_ncr53c9x; - bus_teardown_intr(esc->sc_dev, esc->sc_irqres, esc->sc_irq); - error = ncr53c9x_detach(sc); + error = espdetach(esc); 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); + bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(esc->sc_res), + esc->sc_res); return (0); } @@ -499,11 +451,29 @@ esp_resume(device_t dev) } static int -espattach(struct esp_softc *esc, struct ncr53c9x_glue *gluep) +espattach(struct esp_softc *esc, const struct ncr53c9x_glue *gluep) { struct ncr53c9x_softc *sc = &esc->sc_ncr53c9x; unsigned int uid = 0; - int error; + int error, i; + + NCR_LOCK_INIT(sc); + + /* Attach the DMA engine. */ + error = lsi64854_attach(esc->sc_dma); + if (error != 0) { + device_printf(esc->sc_dev, "lsi64854_attach failed\n"); + goto fail_lock; + } + + if (OF_getprop(ofw_bus_get_node(esc->sc_dev), "scsi-initiator-id", + &sc->sc_id, sizeof(sc->sc_id)) == -1) + sc->sc_id = 7; + +#ifdef ESP_SBUS_DEBUG + device_printf(esc->sc_dev, "%s: sc_id %d, freq %d\n", + __func__, sc->sc_id, sc->sc_freq); +#endif /* * The `ESC' DMA chip must be reset before we can access @@ -598,7 +568,7 @@ espattach(struct esp_softc *esc, struct ncr53c9x_glue *gluep) */ device_printf(esc->sc_dev, "Unknown chip\n"); - return (ENXIO); + goto fail_lsi; } } } @@ -635,20 +605,20 @@ espattach(struct esp_softc *esc, struct ncr53c9x_glue *gluep) */ switch (sc->sc_rev) { case NCR_VARIANT_ESP100: - sc->sc_maxwidth = 0; + sc->sc_maxwidth = MSG_EXT_WDTR_BUS_8_BIT; sc->sc_maxxfer = 64 * 1024; sc->sc_minsync = 0; /* No synch on old chip? */ break; case NCR_VARIANT_ESP100A: - sc->sc_maxwidth = 0; + sc->sc_maxwidth = MSG_EXT_WDTR_BUS_8_BIT; 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_maxwidth = MSG_EXT_WDTR_BUS_8_BIT; sc->sc_maxxfer = 16 * 1024 * 1024; /* Min clocks/byte is 5 */ sc->sc_minsync = ncr53c9x_cpb2stp(sc, 5); @@ -670,28 +640,26 @@ espattach(struct esp_softc *esc, struct ncr53c9x_glue *gluep) sc->sc_features = NCR_F_FASTSCSI; sc->sc_cfg3 = NCRF9XCFG3_FCLK; sc->sc_cfg3_fscsi = NCRF9XCFG3_FSCSI; - sc->sc_maxwidth = 0; + sc->sc_maxwidth = MSG_EXT_WDTR_BUS_8_BIT; sc->sc_maxxfer = 16 * 1024 * 1024; break; case NCR_VARIANT_FAS366: - sc->sc_maxwidth = 1; + sc->sc_maxwidth = MSG_EXT_WDTR_BUS_16_BIT; sc->sc_maxxfer = 16 * 1024 * 1024; break; } - /* Limit minsync due to unsolved performance issues. */ - sc->sc_maxsync = sc->sc_minsync; - /* Establish interrupt channel. */ - esc->sc_irqrid = 0; + i = 0; if ((esc->sc_irqres = bus_alloc_resource_any(esc->sc_dev, SYS_RES_IRQ, - &esc->sc_irqrid, RF_SHAREABLE|RF_ACTIVE)) == NULL) { + &i, RF_SHAREABLE|RF_ACTIVE)) == NULL) { device_printf(esc->sc_dev, "cannot allocate interrupt\n"); - return (ENXIO); + goto fail_lsi; } if (bus_setup_intr(esc->sc_dev, esc->sc_irqres, - INTR_TYPE_BIO, NULL, ncr53c9x_intr, sc, &esc->sc_irq)) { + INTR_MPSAFE | INTR_TYPE_CAM, NULL, ncr53c9x_intr, sc, + &esc->sc_irq)) { device_printf(esc->sc_dev, "cannot set up interrupt\n"); error = ENXIO; goto fail_ires; @@ -714,19 +682,43 @@ espattach(struct esp_softc *esc, struct ncr53c9x_glue *gluep) 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); + bus_release_resource(esc->sc_dev, SYS_RES_IRQ, + rman_get_rid(esc->sc_irqres), esc->sc_irqres); + fail_lsi: + lsi64854_detach(esc->sc_dma); + fail_lock: + NCR_LOCK_DESTROY(sc); return (error); } +static int +espdetach(struct esp_softc *esc) +{ + struct ncr53c9x_softc *sc = &esc->sc_ncr53c9x; + int error; + + bus_teardown_intr(esc->sc_dev, esc->sc_irqres, esc->sc_irq); + error = ncr53c9x_detach(sc); + if (error != 0) + return (error); + error = lsi64854_detach(esc->sc_dma); + if (error != 0) + return (error); + NCR_LOCK_DESTROY(sc); + bus_release_resource(esc->sc_dev, SYS_RES_IRQ, + rman_get_rid(esc->sc_irqres), esc->sc_irqres); + + return (0); +} + /* * Glue functions */ #ifdef ESP_SBUS_DEBUG -int esp_sbus_debug = 0; +static int esp_sbus_debug = 0; -static struct { +static const struct { char *r_name; int r_flag; } esp__read_regnames [] = { @@ -748,7 +740,7 @@ static struct { { "TCX", 1}, /* f/3c */ }; -static struct { +static const struct { char *r_name; int r_flag; } esp__write_regnames[] = { @@ -777,13 +769,15 @@ esp_read_reg(struct ncr53c9x_softc *sc, int reg) struct esp_softc *esc = (struct esp_softc *)sc; u_char v; - v = bus_space_read_1(esc->sc_regt, esc->sc_regh, reg * 4); + v = bus_read_1(esc->sc_res, reg * 4); + #ifdef ESP_SBUS_DEBUG if (esp_sbus_debug && (reg < 0x10) && esp__read_regnames[reg].r_flag) - printf("RD:%x <%s> %x\n", reg * 4, - ((unsigned)reg < 0x10) ? esp__read_regnames[reg].r_name : "<***>", v); + printf("RD:%x <%s> %x\n", reg * 4, ((unsigned)reg < 0x10) ? + esp__read_regnames[reg].r_name : "<***>", v); #endif - return v; + + return (v); } static void @@ -793,10 +787,11 @@ esp_write_reg(struct ncr53c9x_softc *sc, int reg, u_char v) #ifdef ESP_SBUS_DEBUG if (esp_sbus_debug && (reg < 0x10) && esp__write_regnames[reg].r_flag) - printf("WR:%x <%s> %x\n", reg * 4, - ((unsigned)reg < 0x10) ? esp__write_regnames[reg].r_name : "<***>", v); + printf("WR:%x <%s> %x\n", reg * 4, ((unsigned)reg < 0x10) ? + esp__write_regnames[reg].r_name : "<***>", v); #endif - bus_space_write_1(esc->sc_regt, esc->sc_regh, reg * 4, v); + + bus_write_1(esc->sc_res, reg * 4, v); } static int diff --git a/sys/dev/esp/ncr53c9x.c b/sys/dev/esp/ncr53c9x.c index ab94a8c..542f6c6 100644 --- a/sys/dev/esp/ncr53c9x.c +++ b/sys/dev/esp/ncr53c9x.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2004 Scott Long + * Copyright (c) 2005, 2008 Marius Strobl <marius@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,7 +26,7 @@ * */ -/* $NetBSD: ncr53c9x.c,v 1.114 2005/02/27 00:27:02 perry Exp $ */ +/* $NetBSD: ncr53c9x.c,v 1.125 2007/01/09 12:53:12 itohy Exp $ */ /*- * Copyright (c) 1998, 2002 The NetBSD Foundation, Inc. @@ -111,8 +112,8 @@ __FBSDID("$FreeBSD$"); #include <sys/bus.h> #include <sys/kernel.h> #include <sys/malloc.h> -#include <sys/resource.h> #include <sys/lock.h> +#include <sys/module.h> #include <sys/mutex.h> #include <sys/queue.h> #include <sys/time.h> @@ -129,14 +130,22 @@ __FBSDID("$FreeBSD$"); #include <dev/esp/ncr53c9xreg.h> #include <dev/esp/ncr53c9xvar.h> -int ncr53c9x_debug = +MODULE_DEPEND(esp, cam, 1, 1, 1); + +#ifdef NCR53C9X_DEBUG +static int ncr53c9x_debug = NCR_SHOWMISC /* | NCR_SHOWPHASE | NCR_SHOWTRAC | NCR_SHOWCMDS */; -#ifdef DEBUG -int ncr53c9x_notag = 0; #endif static void ncr53c9x_abort(struct ncr53c9x_softc *sc, struct ncr53c9x_ecb *ecb); +static void ncr53c9x_action(struct cam_sim *sim, union ccb *ccb); +static void ncr53c9x_async(void *cbarg, uint32_t code, + struct cam_path *path, void *arg); +static void ncr53c9x_callout(void *arg); +static void ncr53c9x_clear(struct ncr53c9x_softc *sc, cam_status result); +static void ncr53c9x_clear_target(struct ncr53c9x_softc *sc, int target, + cam_status result); static void ncr53c9x_dequeue(struct ncr53c9x_softc *sc, struct ncr53c9x_ecb *ecb); static void ncr53c9x_done(struct ncr53c9x_softc *sc, @@ -145,17 +154,18 @@ static void ncr53c9x_free_ecb(struct ncr53c9x_softc *sc, struct ncr53c9x_ecb *ecb); static void ncr53c9x_msgin(struct ncr53c9x_softc *sc); static void ncr53c9x_msgout(struct ncr53c9x_softc *sc); +static void ncr53c9x_init(struct ncr53c9x_softc *sc, int doreset); +static void ncr53c9x_intr1(struct ncr53c9x_softc *sc); static void ncr53c9x_poll(struct cam_sim *sim); static int ncr53c9x_rdfifo(struct ncr53c9x_softc *sc, int how); static int ncr53c9x_reselect(struct ncr53c9x_softc *sc, int message, int tagtype, int tagid); +static void ncr53c9x_reset(struct ncr53c9x_softc *sc); static void ncr53c9x_sense(struct ncr53c9x_softc *sc, struct ncr53c9x_ecb *ecb); -static void ncr53c9x_scsi_reset(struct ncr53c9x_softc *sc); static void ncr53c9x_sched(struct ncr53c9x_softc *sc); static void ncr53c9x_select(struct ncr53c9x_softc *sc, struct ncr53c9x_ecb *ecb); -static void ncr53c9x_timeout(void *arg); static void ncr53c9x_watch(void *arg); static void ncr53c9x_wrfifo(struct ncr53c9x_softc *sc, u_char *p, int len); @@ -238,7 +248,12 @@ ncr53c9x_attach(struct ncr53c9x_softc *sc) struct ncr53c9x_ecb *ecb; int error, i; - mtx_init(&sc->sc_lock, "ncr", "ncr53c9x lock", MTX_DEF); + if (NCR_LOCK_INITIALIZED(sc) == 0) { + device_printf(sc->sc_dev, "mutex not initialized\n"); + return (ENXIO); + } + + callout_init_mtx(&sc->sc_watchdog, &sc->sc_lock, 0); /* * Note, the front-end has set us up to print the chip variation. @@ -292,8 +307,6 @@ ncr53c9x_attach(struct ncr53c9x_softc *sc) goto fail_imess; } - callout_init(&sc->sc_watchdog, 0); - /* * Treat NCR53C90 with the 86C01 DMA chip exactly as ESP100 * from now on. @@ -334,16 +347,19 @@ ncr53c9x_attach(struct ncr53c9x_softc *sc) } sim = cam_sim_alloc(ncr53c9x_action, ncr53c9x_poll, "esp", sc, - device_get_unit(sc->sc_dev), &Giant, 1, NCR_TAG_DEPTH, devq); + device_get_unit(sc->sc_dev), &sc->sc_lock, 1, NCR_TAG_DEPTH, devq); if (sim == NULL) { device_printf(sc->sc_dev, "cannot allocate SIM entry\n"); error = ENOMEM; goto fail_devq; } + + NCR_LOCK(sc); + if (xpt_bus_register(sim, sc->sc_dev, 0) != CAM_SUCCESS) { device_printf(sc->sc_dev, "cannot register bus\n"); error = EIO; - goto fail_sim; + goto fail_lock; } if (xpt_create_path(&path, NULL, cam_sim_path(sim), @@ -353,6 +369,13 @@ ncr53c9x_attach(struct ncr53c9x_softc *sc) goto fail_bus; } + if (xpt_register_async(AC_LOST_DEVICE, ncr53c9x_async, sim, path) != + CAM_REQ_CMP) { + device_printf(sc->sc_dev, "cannot register async handler\n"); + error = EIO; + goto fail_path; + } + sc->sc_sim = sim; sc->sc_path = path; @@ -371,7 +394,7 @@ ncr53c9x_attach(struct ncr53c9x_softc *sc) M_NOWAIT | M_ZERO)) == NULL) { device_printf(sc->sc_dev, "cannot allocate ECB array\n"); error = ENOMEM; - goto fail_path; + goto fail_async; } for (i = 0; i < NCR_TAG_DEPTH; i++) { ecb = &sc->ecb_array[i]; @@ -380,15 +403,20 @@ ncr53c9x_attach(struct ncr53c9x_softc *sc) TAILQ_INSERT_HEAD(&sc->free_list, ecb, free_links); } - callout_reset(&sc->sc_watchdog, 60*hz, ncr53c9x_watch, sc); + callout_reset(&sc->sc_watchdog, 60 * hz, ncr53c9x_watch, sc); + + NCR_UNLOCK(sc); return (0); +fail_async: + xpt_register_async(0, ncr53c9x_async, sim, path); fail_path: xpt_free_path(path); fail_bus: xpt_bus_deregister(cam_sim_path(sim)); -fail_sim: +fail_lock: + NCR_UNLOCK(sc); cam_sim_free(sim, TRUE); fail_devq: cam_simq_free(devq); @@ -406,13 +434,33 @@ fail_omess: int ncr53c9x_detach(struct ncr53c9x_softc *sc) { + struct ncr53c9x_linfo *li, *nextli; + int t; callout_drain(&sc->sc_watchdog); - mtx_lock(&sc->sc_lock); - ncr53c9x_init(sc, 1); - mtx_unlock(&sc->sc_lock); + + NCR_LOCK(sc); + + if (sc->sc_tinfo) { + /* Cancel all commands. */ + ncr53c9x_clear(sc, CAM_REQ_ABORTED); + + /* Free logical units. */ + for (t = 0; t < sc->sc_ntarg; t++) { + for (li = LIST_FIRST(&sc->sc_tinfo[t].luns); li; + li = nextli) { + nextli = LIST_NEXT(li, link); + free(li, M_DEVBUF); + } + } + } + + xpt_register_async(0, ncr53c9x_async, sc->sc_sim, sc->sc_path); xpt_free_path(sc->sc_path); xpt_bus_deregister(cam_sim_path(sc->sc_sim)); + + NCR_UNLOCK(sc); + cam_sim_free(sc->sc_sim, TRUE); free(sc->ecb_array, M_DEVBUF); free(sc->sc_tinfo, M_DEVBUF); @@ -420,7 +468,6 @@ ncr53c9x_detach(struct ncr53c9x_softc *sc) free(sc->sc_imess, M_DEVBUF); if (sc->sc_omess_self) free(sc->sc_omess, M_DEVBUF); - mtx_destroy(&sc->sc_lock); return (0); } @@ -433,10 +480,12 @@ ncr53c9x_detach(struct ncr53c9x_softc *sc) * After reset, registers are loaded with the defaults from the attach * routine above. */ -void +static void ncr53c9x_reset(struct ncr53c9x_softc *sc) { + NCR_LOCK_ASSERT(sc, MA_OWNED); + /* Reset DMA first. */ NCRDMA_RESET(sc); @@ -477,9 +526,11 @@ ncr53c9x_reset(struct ncr53c9x_softc *sc) sc->sc_features |= NCR_F_HASCFG3 | NCR_F_FASTSCSI | NCR_F_SELATN3; sc->sc_cfg3 = NCRFASCFG3_FASTCLK | NCRFASCFG3_OBAUTO; + if (sc->sc_id > 7) + sc->sc_cfg3 |= NCRFASCFG3_IDBIT3; sc->sc_cfg3_fscsi = NCRFASCFG3_FASTSCSI; NCR_WRITE_REG(sc, NCR_CFG3, sc->sc_cfg3); - sc->sc_cfg2 = 0; /* NCRCFG2_HMEFE | NCRCFG2_HME32 */ + sc->sc_cfg2 = NCRCFG2_HMEFE | NCRCFG2_HME32; NCR_WRITE_REG(sc, NCR_CFG2, sc->sc_cfg2); NCR_WRITE_REG(sc, NCR_CFG1, sc->sc_cfg1); NCR_WRITE_REG(sc, NCR_CCF, sc->sc_ccf); @@ -509,29 +560,73 @@ ncr53c9x_reset(struct ncr53c9x_softc *sc) } /* - * Reset the SCSI bus, but not the chip. + * Clear all commands. + */ +static void +ncr53c9x_clear(struct ncr53c9x_softc *sc, cam_status result) +{ + struct ncr53c9x_ecb *ecb; + int r; + + NCR_LOCK_ASSERT(sc, MA_OWNED); + + /* Cancel any active commands. */ + sc->sc_state = NCR_CLEANING; + sc->sc_msgify = 0; + if ((ecb = sc->sc_nexus) != NULL) { + ecb->ccb->ccb_h.status = result; + ncr53c9x_done(sc, ecb); + } + /* Cancel outstanding disconnected commands. */ + for (r = 0; r < sc->sc_ntarg; r++) + ncr53c9x_clear_target(sc, r, result); +} + +/* + * Clear all commands for a specific target. */ static void -ncr53c9x_scsi_reset(struct ncr53c9x_softc *sc) +ncr53c9x_clear_target(struct ncr53c9x_softc *sc, int target, + cam_status result) { + struct ncr53c9x_ecb *ecb; + struct ncr53c9x_linfo *li; + int i; - (*sc->sc_glue->gl_dma_stop)(sc); + NCR_LOCK_ASSERT(sc, MA_OWNED); - NCR_MISC(("%s: resetting SCSI bus\n", device_get_nameunit(sc->sc_dev))); - NCRCMD(sc, NCRCMD_RSTSCSI); - DELAY(250000); /* Give the bus a fighting chance to settle */ + /* Cancel outstanding disconnected commands on each LUN. */ + LIST_FOREACH(li, &sc->sc_tinfo[target].luns, link) { + if ((ecb = li->untagged) != NULL) { + li->untagged = NULL; + /* + * XXX should we terminate a command + * that never reached the disk? + */ + li->busy = 0; + ecb->ccb->ccb_h.status = result; + ncr53c9x_done(sc, ecb); + } + for (i = 0; i < NCR_TAG_DEPTH; i++) + if ((ecb = li->queued[i])) { + li->queued[i] = NULL; + ecb->ccb->ccb_h.status = result; + ncr53c9x_done(sc, ecb); + } + li->used = 0; + } } /* * Initialize ncr53c9x state machine. */ -void +static void ncr53c9x_init(struct ncr53c9x_softc *sc, int doreset) { - struct ncr53c9x_ecb *ecb; - struct ncr53c9x_linfo *li; struct ncr53c9x_tinfo *ti; - int i, r; + int r; + + NCR_LOCK_ASSERT(sc, MA_OWNED); NCR_MISC(("[NCR_INIT(%d) %d] ", doreset, sc->sc_state)); @@ -544,41 +639,8 @@ ncr53c9x_init(struct ncr53c9x_softc *sc, int doreset) for (r = 0; r < sc->sc_ntarg; r++) { LIST_INIT(&sc->sc_tinfo[r].luns); } - } else { - /* Cancel any active commands. */ - sc->sc_state = NCR_CLEANING; - sc->sc_msgify = 0; - if ((ecb = sc->sc_nexus) != NULL) { - ecb->ccb->ccb_h.status = CAM_CMD_TIMEOUT; - ncr53c9x_done(sc, ecb); - } - /* Cancel outstanding disconnected commands on each LUN. */ - for (r = 0; r < sc->sc_ntarg; r++) { - LIST_FOREACH(li, &sc->sc_tinfo[r].luns, link) { - if ((ecb = li->untagged) != NULL) { - li->untagged = NULL; - /* - * XXX - * - * Should we terminate a command - * that never reached the disk? - */ - li->busy = 0; - ecb->ccb->ccb_h.status = - CAM_CMD_TIMEOUT; - ncr53c9x_done(sc, ecb); - } - for (i = 0; i < 256; i++) - if ((ecb = li->queued[i])) { - li->queued[i] = NULL; - ecb->ccb->ccb_h.status = - CAM_CMD_TIMEOUT; - ncr53c9x_done(sc, ecb); - } - li->used = 0; - } - } - } + } else + ncr53c9x_clear(sc, CAM_CMD_TIMEOUT); /* * Reset the chip to a known state. @@ -589,27 +651,42 @@ ncr53c9x_init(struct ncr53c9x_softc *sc, int doreset) 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++) { - ti = &sc->sc_tinfo[r]; + /* + * If we're the first time through, set the default parameters + * for all targets. Otherwise we only clear their current transfer + * settings so we'll renegotiate their goal settings with the next + * command. + */ + if (sc->sc_state == 0) { + for (r = 0; r < sc->sc_ntarg; r++) { + ti = &sc->sc_tinfo[r]; /* XXX - config flags per target: low bits: no reselect; high bits: no synch */ - ti->flags = ((sc->sc_minsync != 0 && - (sc->sc_cfflags & (1 << ((r & 7) + 8))) == 0) ? - 0 : T_SYNCHOFF) | - ((sc->sc_cfflags & (1 << (r & 7))) == 0 ? - 0 : T_RSELECTOFF); -#ifdef DEBUG - if (ncr53c9x_notag) - ti->flags &= ~T_TAG; -#endif - ti->period = sc->sc_minsync; - ti->offset = 0; - ti->cfg3 = 0; + ti->flags = ((sc->sc_minsync != 0 && + (sc->sc_cfflags & (1 << ((r & 7) + 8))) == 0) ? + 0 : T_SYNCHOFF) | + ((sc->sc_cfflags & (1 << (r & 7))) == 0 ? + 0 : T_RSELECTOFF); + ti->curr.period = ti->goal.period = 0; + ti->curr.offset = ti->goal.offset = 0; + ti->curr.width = ti->goal.width = + MSG_EXT_WDTR_BUS_8_BIT; + } + } else { + for (r = 0; r < sc->sc_ntarg; r++) { + ti = &sc->sc_tinfo[r]; + ti->flags &= ~(T_SDTRSENT | T_WDTRSENT); + ti->curr.period = 0; + ti->curr.offset = 0; + ti->curr.width = MSG_EXT_WDTR_BUS_8_BIT; + } } if (doreset) { sc->sc_state = NCR_SBR; NCRCMD(sc, NCRCMD_RSTSCSI); + /* Give the bus a fighting chance to settle. */ + DELAY(250000); } else { sc->sc_state = NCR_IDLE; ncr53c9x_sched(sc); @@ -629,6 +706,8 @@ static inline void ncr53c9x_readregs(struct ncr53c9x_softc *sc) { + NCR_LOCK_ASSERT(sc, MA_OWNED); + sc->sc_espstat = NCR_READ_REG(sc, NCR_STAT); /* Only the step bits are of interest. */ sc->sc_espstep = NCR_READ_REG(sc, NCR_STEP) & NCRSTEP_MASK; @@ -659,6 +738,9 @@ static inline int ncr53c9x_stp2cpb(struct ncr53c9x_softc *sc, int period) { int v; + + NCR_LOCK_ASSERT(sc, MA_OWNED); + v = (sc->sc_freq * period) / 250; if (ncr53c9x_cpb2stp(sc, v) < period) /* Correct round-down error. */ @@ -669,18 +751,20 @@ ncr53c9x_stp2cpb(struct ncr53c9x_softc *sc, int period) static inline void ncr53c9x_setsync(struct ncr53c9x_softc *sc, struct ncr53c9x_tinfo *ti) { - u_char syncoff, synctp; - u_char cfg3 = sc->sc_cfg3 | ti->cfg3; + u_char cfg3, syncoff, synctp; + + NCR_LOCK_ASSERT(sc, MA_OWNED); - if (ti->flags & T_SYNCMODE) { - syncoff = ti->offset; - synctp = ncr53c9x_stp2cpb(sc, ti->period); + cfg3 = sc->sc_cfg3; + if (ti->curr.offset != 0) { + syncoff = ti->curr.offset; + synctp = ncr53c9x_stp2cpb(sc, ti->curr.period); if (sc->sc_features & NCR_F_FASTSCSI) { /* * If the period is 200ns or less (ti->period <= 50), * put the chip in Fast SCSI mode. */ - if (ti->period <= 50) + if (ti->curr.period <= 50) /* * There are (at least) 4 variations of the * configuration 3 register. The drive attach @@ -703,6 +787,11 @@ ncr53c9x_setsync(struct ncr53c9x_softc *sc, struct ncr53c9x_tinfo *ti) synctp = 0; } + if (ti->curr.width != MSG_EXT_WDTR_BUS_8_BIT) { + if (sc->sc_rev == NCR_VARIANT_FAS366) + cfg3 |= NCRFASCFG3_EWIDE; + } + if (sc->sc_features & NCR_F_HASCFG3) NCR_WRITE_REG(sc, NCR_CFG3, cfg3); @@ -727,18 +816,19 @@ ncr53c9x_select(struct ncr53c9x_softc *sc, struct ncr53c9x_ecb *ecb) int lun = ecb->ccb->ccb_h.target_lun; int target = ecb->ccb->ccb_h.target_id; + NCR_LOCK_ASSERT(sc, MA_OWNED); + NCR_TRACE(("[ncr53c9x_select(t%d,l%d,cmd:%x,tag:%x,%x)] ", target, lun, ecb->cmd.cmd.opcode, ecb->tag[0], ecb->tag[1])); ti = &sc->sc_tinfo[target]; sc->sc_state = NCR_SELECTING; /* - * Schedule the timeout now, the first time we will go away + * Schedule the callout now, the first time we will go away * expecting to come back due to an interrupt, because it is * always possible that the interrupt may never happen. */ - ecb->ccb->ccb_h.timeout_ch = - timeout(ncr53c9x_timeout, ecb, mstohz(ecb->timeout)); + callout_reset(&ecb->ch, mstohz(ecb->timeout), ncr53c9x_callout, ecb); /* * The docs say the target register is never reset, and I @@ -746,41 +836,24 @@ ncr53c9x_select(struct ncr53c9x_softc *sc, struct ncr53c9x_ecb *ecb) */ if (sc->sc_rev == NCR_VARIANT_FAS366) { NCRCMD(sc, NCRCMD_FLUSH); - NCR_WRITE_REG(sc, NCR_SELID, target | NCR_BUSID_HME); + NCR_WRITE_REG(sc, NCR_SELID, target | NCR_BUSID_HMEXC32 | + NCR_BUSID_HMEENCID); } else { NCR_WRITE_REG(sc, NCR_SELID, target); } - ncr53c9x_setsync(sc, ti); - - if ((ecb->flags & ECB_SENSE) != 0) { - /* - * For REQUEST SENSE, we should not send an IDENTIFY or - * otherwise mangle the target. There should be no MESSAGE IN - * phase. - */ - if (sc->sc_features & NCR_F_DMASELECT) { - /* setup DMA transfer for command */ - dmasize = clen = ecb->clen; - sc->sc_cmdlen = clen; - sc->sc_cmdp = (caddr_t)&ecb->cmd.cmd; - /* Program the SCSI counter */ - NCR_SET_COUNT(sc, dmasize); - - if (sc->sc_rev != NCR_VARIANT_FAS366) - NCRCMD(sc, NCRCMD_NOP | NCRCMD_DMA); - - /* And get the target's attention */ - NCRCMD(sc, NCRCMD_SELNATN | NCRCMD_DMA); - NCRDMA_SETUP(sc, &sc->sc_cmdp, &sc->sc_cmdlen, 0, - &dmasize); - NCRDMA_GO(sc); - } else { - ncr53c9x_wrfifo(sc, (u_char *)&ecb->cmd.cmd, ecb->clen); - NCRCMD(sc, NCRCMD_SELNATN); - } - return; + /* + * If we are requesting sense, force a renegotiation if we are + * currently using anything different from asynchronous at 8 bit + * as the target might have lost our transfer negotiations. + */ + if ((ecb->flags & ECB_SENSE) != 0 && (ti->curr.offset != 0 || + ti->curr.width != MSG_EXT_WDTR_BUS_8_BIT)) { + ti->curr.period = 0; + ti->curr.offset = 0; + ti->curr.width = MSG_EXT_WDTR_BUS_8_BIT; } + ncr53c9x_setsync(sc, ti); selatn3 = selatns = 0; if (ecb->tag[0] != 0) { @@ -792,7 +865,9 @@ ncr53c9x_select(struct ncr53c9x_softc *sc, struct ncr53c9x_ecb *ecb) selatns = 1; } - if (ti->flags & T_NEGOTIATE) { + if (ti->curr.period != ti->goal.period || + ti->curr.offset != ti->goal.offset || + ti->curr.width != ti->goal.width) { /* We have to use SELATNS to send sync/wide messages. */ selatn3 = 0; selatns = 1; @@ -819,7 +894,7 @@ ncr53c9x_select(struct ncr53c9x_softc *sc, struct ncr53c9x_ecb *ecb) dmasize = clen; sc->sc_cmdlen = clen; sc->sc_cmdp = cmd; - + NCRDMA_SETUP(sc, &sc->sc_cmdp, &sc->sc_cmdlen, 0, &dmasize); /* Program the SCSI counter. */ NCR_SET_COUNT(sc, dmasize); @@ -834,7 +909,6 @@ ncr53c9x_select(struct ncr53c9x_softc *sc, struct ncr53c9x_ecb *ecb) NCRCMD(sc, NCRCMD_SELATN3 | NCRCMD_DMA); } else NCRCMD(sc, NCRCMD_SELATN | NCRCMD_DMA); - NCRDMA_SETUP(sc, &sc->sc_cmdp, &sc->sc_cmdlen, 0, &dmasize); NCRDMA_GO(sc); return; } @@ -864,6 +938,8 @@ static void ncr53c9x_free_ecb(struct ncr53c9x_softc *sc, struct ncr53c9x_ecb *ecb) { + NCR_LOCK_ASSERT(sc, MA_OWNED); + ecb->flags = 0; TAILQ_INSERT_TAIL(&sc->free_list, ecb, free_links); } @@ -873,6 +949,8 @@ ncr53c9x_get_ecb(struct ncr53c9x_softc *sc) { struct ncr53c9x_ecb *ecb; + NCR_LOCK_ASSERT(sc, MA_OWNED); + ecb = TAILQ_FIRST(&sc->free_list); if (ecb) { if (ecb->flags != 0) @@ -895,7 +973,7 @@ ncr53c9x_get_ecb(struct ncr53c9x_softc *sc) * SCSI-commands. */ -void +static void ncr53c9x_action(struct cam_sim *sim, union ccb *ccb) { struct ccb_pathinq *cpi; @@ -908,21 +986,20 @@ ncr53c9x_action(struct cam_sim *sim, union ccb *ccb) struct ncr53c9x_tinfo *ti; int target; - NCR_TRACE(("[ncr53c9x_action %d]", ccb->ccb_h.func_code)); - sc = cam_sim_softc(sim); - mtx_lock(&sc->sc_lock); + + NCR_LOCK_ASSERT(sc, MA_OWNED); + + NCR_TRACE(("[ncr53c9x_action %d]", ccb->ccb_h.func_code)); switch (ccb->ccb_h.func_code) { case XPT_RESET_BUS: - ncr53c9x_scsi_reset(sc); + ncr53c9x_init(sc, 1); ccb->ccb_h.status = CAM_REQ_CMP; - mtx_unlock(&sc->sc_lock); xpt_done(ccb); return; case XPT_CALC_GEOMETRY: - mtx_unlock(&sc->sc_lock); cam_calc_geometry(&ccb->ccg, sc->sc_extended_geom); xpt_done(ccb); return; @@ -937,7 +1014,7 @@ ncr53c9x_action(struct cam_sim *sim, union ccb *ccb) cpi->hba_misc = 0; cpi->hba_eng_cnt = 0; cpi->max_target = sc->sc_ntarg - 1; - cpi->max_lun = 8; + cpi->max_lun = 7; cpi->initiator_id = sc->sc_id; cpi->bus_id = 0; cpi->base_transfer_speed = 3300; @@ -950,7 +1027,6 @@ ncr53c9x_action(struct cam_sim *sim, union ccb *ccb) cpi->protocol = PROTO_SCSI; cpi->protocol_version = SCSI_REV_2; ccb->ccb_h.status = CAM_REQ_CMP; - mtx_unlock(&sc->sc_lock); xpt_done(ccb); return; @@ -966,9 +1042,9 @@ ncr53c9x_action(struct cam_sim *sim, union ccb *ccb) cts->transport_version = 2; if (cts->type == CTS_TYPE_CURRENT_SETTINGS) { - spi->sync_period = ti->period; - spi->sync_offset = ti->offset; - spi->bus_width = ti->width; + spi->sync_period = ti->curr.period; + spi->sync_offset = ti->curr.offset; + spi->bus_width = ti->curr.width; if ((ti->flags & T_TAG) != 0) { spi->flags |= CTS_SPI_FLAGS_DISC_ENB; scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; @@ -977,8 +1053,13 @@ ncr53c9x_action(struct cam_sim *sim, union ccb *ccb) scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; } } else { - spi->sync_period = sc->sc_maxsync; - spi->sync_offset = sc->sc_maxoffset; + if ((ti->flags & T_SYNCHOFF) != 0) { + spi->sync_period = 0; + spi->sync_offset = 0; + } else { + spi->sync_period = sc->sc_minsync; + spi->sync_offset = sc->sc_maxoffset; + } spi->bus_width = sc->sc_maxwidth; spi->flags |= CTS_SPI_FLAGS_DISC_ENB; scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; @@ -990,31 +1071,26 @@ ncr53c9x_action(struct cam_sim *sim, union ccb *ccb) CTS_SPI_VALID_DISC; scsi->valid = CTS_SCSI_VALID_TQ; ccb->ccb_h.status = CAM_REQ_CMP; - mtx_unlock(&sc->sc_lock); xpt_done(ccb); return; case XPT_ABORT: - printf("XPT_ABORT called\n"); + device_printf(sc->sc_dev, "XPT_ABORT called\n"); ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; - mtx_unlock(&sc->sc_lock); xpt_done(ccb); return; case XPT_TERM_IO: - printf("XPT_TERM_IO called\n"); + device_printf(sc->sc_dev, "XPT_TERM_IO called\n"); ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; - mtx_unlock(&sc->sc_lock); xpt_done(ccb); return; case XPT_RESET_DEV: - printf("XPT_RESET_DEV called\n"); case XPT_SCSI_IO: if (ccb->ccb_h.target_id < 0 || ccb->ccb_h.target_id >= sc->sc_ntarg) { ccb->ccb_h.status = CAM_PATH_INVALID; - mtx_unlock(&sc->sc_lock); xpt_done(ccb); return; } @@ -1027,8 +1103,7 @@ ncr53c9x_action(struct cam_sim *sim, union ccb *ccb) if (ecb == NULL) { xpt_freeze_simq(sim, 1); ccb->ccb_h.status = CAM_REQUEUE_REQ; - printf("unable to allocate ecb\n"); - mtx_unlock(&sc->sc_lock); + device_printf(sc->sc_dev, "unable to allocate ecb\n"); xpt_done(ccb); return; } @@ -1079,35 +1154,23 @@ ncr53c9x_action(struct cam_sim *sim, union ccb *ccb) } if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) { - if (spi->bus_width != 0) { - NCR_MISC(("%s: target %d: wide negotiation\n", - device_get_nameunit(sc->sc_dev), target)); - if (sc->sc_rev == NCR_VARIANT_FAS366) { - ti->flags |= T_WIDE; - ti->width = 1; - } - } else { - ti->flags &= ~T_WIDE; - ti->width = 0; - } - ti->flags |= T_NEGOTIATE; + NCR_MISC(("%s: target %d: wide negotiation\n", + device_get_nameunit(sc->sc_dev), target)); + ti->goal.width = spi->bus_width; } if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) != 0) { NCR_MISC(("%s: target %d: sync period negotiation\n", device_get_nameunit(sc->sc_dev), target)); - ti->flags |= T_NEGOTIATE; - ti->period = spi->sync_period; + ti->goal.period = spi->sync_period; } if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0) { NCR_MISC(("%s: target %d: sync offset negotiation\n", device_get_nameunit(sc->sc_dev), target)); - ti->flags |= T_NEGOTIATE; - ti->offset = spi->sync_offset; + ti->goal.offset = spi->sync_offset; } - mtx_unlock(&sc->sc_lock); ccb->ccb_h.status = CAM_REQ_CMP; xpt_done(ccb); return; @@ -1116,12 +1179,9 @@ ncr53c9x_action(struct cam_sim *sim, union ccb *ccb) device_printf(sc->sc_dev, "Unhandled function code %d\n", ccb->ccb_h.func_code); ccb->ccb_h.status = CAM_PROVIDE_FAIL; - mtx_unlock(&sc->sc_lock); xpt_done(ccb); return; } - - mtx_unlock(&sc->sc_lock); } /* @@ -1132,10 +1192,51 @@ ncr53c9x_poll(struct cam_sim *sim) { struct ncr53c9x_softc *sc; - NCR_TRACE(("[ncr53c9x_poll] ")); sc = cam_sim_softc(sim); - if (NCRDMA_ISINTR(sc)) { - ncr53c9x_intr(sc); + + NCR_LOCK_ASSERT(sc, MA_OWNED); + + NCR_TRACE(("[ncr53c9x_poll] ")); + + if (NCRDMA_ISINTR(sc)) + ncr53c9x_intr1(sc); +} + +/* + * Asynchronous notification handler + */ +static void +ncr53c9x_async(void *cbarg, uint32_t code, struct cam_path *path, void *arg) +{ + struct ncr53c9x_softc *sc; + struct ncr53c9x_tinfo *ti; + int target; + + sc = cam_sim_softc(cbarg); + + NCR_LOCK_ASSERT(sc, MA_OWNED); + + switch (code) { + case AC_LOST_DEVICE: + target = xpt_path_target_id(path); + if (target < 0 || target >= sc->sc_ntarg) + break; + + /* Cancel outstanding disconnected commands. */ + ncr53c9x_clear_target(sc, target, CAM_REQ_ABORTED); + + /* Set the default parameters for the target. */ + ti = &sc->sc_tinfo[target]; +/* XXX - config flags per target: low bits: no reselect; high bits: no synch */ + ti->flags = ((sc->sc_minsync != 0 && + (sc->sc_cfflags & (1 << ((target & 7) + 8))) == 0) ? + 0 : T_SYNCHOFF) | + ((sc->sc_cfflags & (1 << (target & 7))) == 0 ? + 0 : T_RSELECTOFF); + ti->curr.period = ti->goal.period = 0; + ti->curr.offset = ti->goal.offset = 0; + ti->curr.width = ti->goal.width = MSG_EXT_WDTR_BUS_8_BIT; + break; } } @@ -1145,9 +1246,9 @@ ncr53c9x_poll(struct cam_sim *sim) /* * Schedule a SCSI operation. This has now been pulled out of the interrupt - * handler so that we may call it from ncr53c9x_scsipi_request and - * ncr53c9x_done. This may save us an unnecessary interrupt just to get - * things going. Should only be called when state == NCR_IDLE and at bio pl. + * handler so that we may call it from ncr53c9x_action and ncr53c9x_done. + * This may save us an unnecessary interrupt just to get things going. + * Should only be called when state == NCR_IDLE and with sc_lock held. */ static void ncr53c9x_sched(struct ncr53c9x_softc *sc) @@ -1157,6 +1258,8 @@ ncr53c9x_sched(struct ncr53c9x_softc *sc) struct ncr53c9x_tinfo *ti; int lun, tag; + NCR_LOCK_ASSERT(sc, MA_OWNED); + NCR_TRACE(("[ncr53c9x_sched] ")); if (sc->sc_state != NCR_IDLE) @@ -1166,15 +1269,12 @@ ncr53c9x_sched(struct ncr53c9x_softc *sc) * Find first ecb in ready queue that is for a target/lunit * combinations that is not busy. */ - for (ecb = TAILQ_FIRST(&sc->ready_list); ecb != NULL; - ecb = TAILQ_NEXT(ecb, chain)) { + TAILQ_FOREACH(ecb, &sc->ready_list, chain) { ti = &sc->sc_tinfo[ecb->ccb->ccb_h.target_id]; lun = ecb->ccb->ccb_h.target_lun; /* Select type of tag for this command */ - if ((ti->flags & (T_RSELECTOFF)) != 0) - tag = 0; - else if ((ti->flags & (T_TAG)) == 0) + if ((ti->flags & (T_RSELECTOFF | T_TAG)) != T_TAG) tag = 0; else if ((ecb->flags & ECB_SENSE) != 0) tag = 0; @@ -1254,6 +1354,8 @@ ncr53c9x_sense(struct ncr53c9x_softc *sc, struct ncr53c9x_ecb *ecb) struct scsi_request_sense *ss = (void *)&ecb->cmd.cmd; int lun; + NCR_LOCK_ASSERT(sc, MA_OWNED); + NCR_TRACE(("requesting sense ")); lun = ccb->ccb_h.target_lun; @@ -1297,57 +1399,65 @@ ncr53c9x_done(struct ncr53c9x_softc *sc, struct ncr53c9x_ecb *ecb) struct ncr53c9x_tinfo *ti; int lun; + NCR_LOCK_ASSERT(sc, MA_OWNED); + NCR_TRACE(("[ncr53c9x_done(status:%x)] ", ccb->ccb_h.status)); ti = &sc->sc_tinfo[ccb->ccb_h.target_id]; lun = ccb->ccb_h.target_lun; li = TINFO_LUN(ti, lun); - untimeout(ncr53c9x_timeout, ecb, ccb->ccb_h.timeout_ch); + callout_stop(&ecb->ch); /* * Now, if we've come here with no error code, i.e. we've kept the - * initial XS_NOERROR, and the status code signals that we should + * initial CAM_REQ_CMP, and the status code signals that we should * check sense, we'll need to set up a request sense cmd block and * push the command back into the ready queue *before* any other * commands for this target/lunit, else we lose the sense info. * We don't support chk sense conditions for the request sense cmd. */ if (ccb->ccb_h.status == CAM_REQ_CMP) { + ccb->csio.scsi_status = ecb->stat; if ((ecb->flags & ECB_ABORT) != 0) { ccb->ccb_h.status = CAM_CMD_TIMEOUT; } else if ((ecb->flags & ECB_SENSE) != 0 && (ecb->stat != SCSI_STATUS_CHECK_COND)) { - ccb->ccb_h.status = CAM_AUTOSNS_VALID; + ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND; + ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR | + CAM_AUTOSNS_VALID; } else if (ecb->stat == SCSI_STATUS_CHECK_COND) { if ((ecb->flags & ECB_SENSE) != 0) ccb->ccb_h.status = CAM_AUTOSENSE_FAIL; else { /* First, save the return values. */ ccb->csio.resid = ecb->dleft; - ncr53c9x_sense(sc, ecb); - return; + if ((ccb->ccb_h.flags & CAM_DIS_AUTOSENSE) == + 0) { + ncr53c9x_sense(sc, ecb); + return; + } + ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR; } } else { ccb->csio.resid = ecb->dleft; } -#if 0 - if (xs->status == SCSI_QUEUE_FULL || xs->status == XS_BUSY) - xs->error = XS_BUSY; -#endif + if (ecb->stat == SCSI_STATUS_QUEUE_FULL) + ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR; + else if (ecb->stat == SCSI_STATUS_BUSY) + ccb->ccb_h.status = CAM_SCSI_BUSY; } #ifdef NCR53C9X_DEBUG if (ncr53c9x_debug & NCR_SHOWTRAC) { if (ccb->csio.resid != 0) printf("resid=%d ", ccb->csio.resid); -#if 0 - if (xs->error == XS_SENSE) + if ((ccb->ccb_h.status & CAM_AUTOSNS_VALID) != 0) printf("sense=0x%02x\n", - xs->sense.scsi_sense.error_code); + ccb->csio.sense_data.error_code); else - printf("error=%d\n", xs->error); -#endif + printf("status SCSI=0x%x CAM=0x%x\n", + ccb->csio.scsi_status, ccb->ccb_h.status); } #endif @@ -1385,6 +1495,8 @@ ncr53c9x_dequeue(struct ncr53c9x_softc *sc, struct ncr53c9x_ecb *ecb) struct ncr53c9x_tinfo *ti; int64_t lun; + NCR_LOCK_ASSERT(sc, MA_OWNED); + ti = &sc->sc_tinfo[ecb->ccb->ccb_h.target_id]; lun = ecb->ccb->ccb_h.target_lun; li = TINFO_LUN(ti, lun); @@ -1408,6 +1520,7 @@ ncr53c9x_dequeue(struct ncr53c9x_softc *sc, struct ncr53c9x_ecb *ecb) li->queued[ecb->tag[1]] = NULL; li->used--; } + ecb->tag[0] = ecb->tag[1] = 0; if ((ecb->flags & ECB_READY) != 0) { ecb->flags &= ~ECB_READY; @@ -1434,6 +1547,9 @@ ncr53c9x_dequeue(struct ncr53c9x_softc *sc, struct ncr53c9x_ecb *ecb) static void ncr53c9x_flushfifo(struct ncr53c9x_softc *sc) { + + NCR_LOCK_ASSERT(sc, MA_OWNED); + NCR_TRACE(("[flushfifo] ")); NCRCMD(sc, NCRCMD_FLUSH); @@ -1449,6 +1565,8 @@ ncr53c9x_rdfifo(struct ncr53c9x_softc *sc, int how) u_char *ibuf; int i, n; + NCR_LOCK_ASSERT(sc, MA_OWNED); + switch (how) { case NCR_RDFIFO_START: ibuf = sc->sc_imess; @@ -1511,6 +1629,8 @@ ncr53c9x_wrfifo(struct ncr53c9x_softc *sc, u_char *p, int len) { int i; + NCR_LOCK_ASSERT(sc, MA_OWNED); + #ifdef NCR53C9X_DEBUG NCR_MSGS(("[wrfifo(%d):", len)); if (ncr53c9x_debug & NCR_SHOWMSGS) { @@ -1537,6 +1657,7 @@ ncr53c9x_reselect(struct ncr53c9x_softc *sc, int message, int tagtype, struct ncr53c9x_tinfo *ti; u_char lun, selid, target; + NCR_LOCK_ASSERT(sc, MA_OWNED); if (sc->sc_rev == NCR_VARIANT_FAS366) { target = sc->sc_selid; @@ -1651,6 +1772,8 @@ ncr53c9x_msgin(struct ncr53c9x_softc *sc) u_char *pb; int lun, plen; + NCR_LOCK_ASSERT(sc, MA_OWNED); + NCR_TRACE(("[ncr53c9x_msgin(curmsglen:%ld)] ", (long)sc->sc_imlen)); if (sc->sc_imlen == 0) { @@ -1678,7 +1801,8 @@ ncr53c9x_msgin(struct ncr53c9x_softc *sc) */ if ((sc->sc_flags & NCR_DROP_MSGI) != 0) { NCRCMD(sc, NCRCMD_MSGOK); - printf("<dropping msg byte %x>", sc->sc_imess[sc->sc_imlen]); + device_printf(sc->sc_dev, "<dropping msg byte %x>", + sc->sc_imess[sc->sc_imlen]); return; } @@ -1778,8 +1902,9 @@ gotit: "rejected: target %d\n", ecb->ccb->ccb_h.target_id); - sc->sc_flags &= ~NCR_SYNCHNEGO; - ti->flags &= ~(T_NEGOTIATE | T_SYNCMODE); + ti->flags &= ~T_SDTRSENT; + ti->curr.period = ti->goal.period = 0; + ti->curr.offset = ti->goal.offset = 0; ncr53c9x_setsync(sc, ti); break; @@ -1787,8 +1912,11 @@ gotit: device_printf(sc->sc_dev, "wide transfer " "rejected: target %d\n", ecb->ccb->ccb_h.target_id); - ti->flags &= ~(T_WIDE | T_WDTRSENT); - ti->width = 0; + + ti->flags &= ~T_WDTRSENT; + ti->curr.width = ti->goal.width = + MSG_EXT_WDTR_BUS_8_BIT; + ncr53c9x_setsync(sc, ti); break; case SEND_INIT_DET_ERR: @@ -1842,71 +1970,63 @@ gotit: sc->sc_imess[3], sc->sc_imess[4])); if (sc->sc_imess[1] != 3) goto reject; - ti->period = sc->sc_imess[3]; - ti->offset = sc->sc_imess[4]; - ti->flags &= ~T_NEGOTIATE; + ti->curr.period = sc->sc_imess[3]; + ti->curr.offset = sc->sc_imess[4]; if (sc->sc_minsync == 0 || - ti->offset == 0 || - ti->period > 124) { + ti->curr.offset == 0 || + ti->curr.period > 124) { #if 0 #ifdef NCR53C9X_DEBUG xpt_print_path(ecb->ccb->ccb_h.path); printf("async mode\n"); #endif #endif - ti->flags &= ~T_SYNCMODE; - if ((sc->sc_flags & NCR_SYNCHNEGO) == - 0) { + if ((ti->flags & T_SDTRSENT) == 0) { /* * target initiated negotiation */ - ti->offset = 0; + ti->curr.offset = 0; ncr53c9x_sched_msgout( SEND_SDTR); } } else { - ti->period = + ti->curr.period = ncr53c9x_cpb2stp(sc, ncr53c9x_stp2cpb(sc, - ti->period)); - if ((sc->sc_flags & NCR_SYNCHNEGO) == - 0) { + ti->curr.period)); + if ((ti->flags & T_SDTRSENT) == 0) { /* * target initiated negotiation */ - if (ti->period < sc->sc_minsync) - ti->period = + if (ti->curr.period < + sc->sc_minsync) + ti->curr.period = sc->sc_minsync; - if (ti->offset > 15) - ti->offset = 15; - ti->flags &= ~T_SYNCMODE; + if (ti->curr.offset > + sc->sc_maxoffset) + ti->curr.offset = + sc->sc_maxoffset; ncr53c9x_sched_msgout( SEND_SDTR); - } else { - /* We are sync. */ - ti->flags |= T_SYNCMODE; } } - sc->sc_flags &= ~NCR_SYNCHNEGO; + ti->flags &= ~T_SDTRSENT; + ti->goal.period = ti->curr.period; + ti->goal.offset = ti->curr.offset; ncr53c9x_setsync(sc, ti); break; case MSG_EXT_WDTR: -#ifdef NCR53C9X_DEBUG - device_printf(sc->sc_dev, "wide mode %d\n", - sc->sc_imess[3]); -#endif - if (sc->sc_imess[3] == 1) { - ti->cfg3 |= NCRFASCFG3_EWIDE; - ncr53c9x_setsync(sc, ti); - } else - ti->width = 0; - /* - * Device started width negotiation. - */ + NCR_MSGS(("wide mode %d ", sc->sc_imess[3])); + ti->curr.width = sc->sc_imess[3]; if (!(ti->flags & T_WDTRSENT)) + /* + * target initiated negotiation + */ ncr53c9x_sched_msgout(SEND_WDTR); - ti->flags &= ~(T_WIDE | T_WDTRSENT); + ti->flags &= ~T_WDTRSENT; + ti->goal.width = ti->curr.width; + ncr53c9x_setsync(sc, ti); break; default: @@ -1968,8 +2088,10 @@ gotit: } /* If we have more messages to send set ATN. */ - if (sc->sc_msgpriq) + if (sc->sc_msgpriq) { NCRCMD(sc, NCRCMD_SETATN); + sc->sc_flags |= NCR_ATN; + } /* Acknowledge last message byte. */ NCRCMD(sc, NCRCMD_MSGOK); @@ -1992,6 +2114,8 @@ ncr53c9x_msgout(struct ncr53c9x_softc *sc) int i; #endif + NCR_LOCK_ASSERT(sc, MA_OWNED); + NCR_TRACE(("[ncr53c9x_msgout(priq:%x, prevphase:%x)]", sc->sc_msgpriq, sc->sc_prevphase)); @@ -2033,13 +2157,9 @@ ncr53c9x_msgout(struct ncr53c9x_softc *sc) sc->sc_omess[0] = MSG_EXTENDED; sc->sc_omess[1] = MSG_EXT_SDTR_LEN; sc->sc_omess[2] = MSG_EXT_SDTR; - sc->sc_omess[3] = ti->period; - sc->sc_omess[4] = ti->offset; + sc->sc_omess[3] = ti->goal.period; + sc->sc_omess[4] = ti->goal.offset; sc->sc_omlen = 5; - if ((sc->sc_flags & NCR_SYNCHNEGO) == 0) { - ti->flags |= T_SYNCMODE; - ncr53c9x_setsync(sc, ti); - } break; case SEND_WDTR: @@ -2048,7 +2168,7 @@ ncr53c9x_msgout(struct ncr53c9x_softc *sc) sc->sc_omess[0] = MSG_EXTENDED; sc->sc_omess[1] = MSG_EXT_WDTR_LEN; sc->sc_omess[2] = MSG_EXT_WDTR; - sc->sc_omess[3] = ti->width; + sc->sc_omess[3] = ti->goal.width; sc->sc_omlen = 4; break; @@ -2078,10 +2198,9 @@ ncr53c9x_msgout(struct ncr53c9x_softc *sc) sc->sc_omess[0] = MSG_BUS_DEV_RESET; ecb = sc->sc_nexus; ti = &sc->sc_tinfo[ecb->ccb->ccb_h.target_id]; - ti->flags &= ~T_SYNCMODE; - if ((ti->flags & T_SYNCHOFF) == 0) - /* We can re-start sync negotiation. */ - ti->flags |= T_NEGOTIATE; + ti->curr.period = 0; + ti->curr.offset = 0; + ti->curr.width = MSG_EXT_WDTR_BUS_8_BIT; break; case SEND_PARITY_ERROR: @@ -2138,7 +2257,7 @@ ncr53c9x_msgout(struct ncr53c9x_softc *sc) NCRCMD(sc, NCRCMD_TRANS); } else { /* (Re)send the message. */ - size = min(sc->sc_omlen, sc->sc_maxxfer); + size = ulmin(sc->sc_omlen, sc->sc_maxxfer); NCRDMA_SETUP(sc, &sc->sc_omp, &sc->sc_omlen, 0, &size); /* Program the SCSI counter. */ NCR_SET_COUNT(sc, size); @@ -2150,6 +2269,21 @@ ncr53c9x_msgout(struct ncr53c9x_softc *sc) } } +void +ncr53c9x_intr(void *arg) +{ + struct ncr53c9x_softc *sc = arg; + + if (!NCRDMA_ISINTR(sc)) + return; + + NCR_LOCK(sc); + + ncr53c9x_intr1(sc); + + NCR_UNLOCK(sc); +} + /* * This is the most critical part of the driver, and has to know * how to deal with *all* error conditions and phases from the SCSI @@ -2159,10 +2293,9 @@ ncr53c9x_msgout(struct ncr53c9x_softc *sc) * * Most of this needs verifying. */ -void -ncr53c9x_intr(void *arg) +static void +ncr53c9x_intr1(struct ncr53c9x_softc *sc) { - struct ncr53c9x_softc *sc = arg; struct ncr53c9x_ecb *ecb; struct ncr53c9x_linfo *li; struct ncr53c9x_tinfo *ti; @@ -2171,12 +2304,10 @@ ncr53c9x_intr(void *arg) int i, nfifo; u_char msg; - NCR_INTS(("[ncr53c9x_intr: state %d]", sc->sc_state)); + NCR_LOCK_ASSERT(sc, MA_OWNED); - if (!NCRDMA_ISINTR(sc)) - return; + NCR_INTS(("[ncr53c9x_intr: state %d]", sc->sc_state)); - mtx_lock(&sc->sc_lock); again: /* and what do the registers say... */ ncr53c9x_readregs(sc); @@ -2206,10 +2337,10 @@ again: if (sc->sc_state != NCR_SBR) { device_printf(sc->sc_dev, "SCSI bus reset\n"); ncr53c9x_init(sc, 0); /* Restart everything. */ - goto out; + return; } #if 0 -/*XXX*/ printf("<expected bus reset: " +/*XXX*/ device_printf(sc->sc_dev, "<expected bus reset: " "[intr %x, stat %x, step %d]>\n", sc->sc_espintr, sc->sc_espstat, sc->sc_espstep); #endif @@ -2235,7 +2366,7 @@ again: ecb->ccb->ccb_h.status = CAM_SEL_TIMEOUT; ncr53c9x_done(sc, ecb); } - goto out; + return; } if ((sc->sc_espintr & NCRINTR_ILL) != 0) { @@ -2251,7 +2382,7 @@ again: "activated\n"); #endif sc->sc_flags &= ~NCR_EXPECT_ILLCMD; - goto out; + return; } /* Illegal command, out of sync? */ device_printf(sc->sc_dev, "illegal command: 0x%x " @@ -2262,8 +2393,7 @@ again: NCRCMD(sc, NCRCMD_FLUSH); DELAY(1); } - ncr53c9x_init(sc, 1); /* Restart everything. */ - goto out; + goto reset; } } sc->sc_flags &= ~NCR_EXPECT_ILLCMD; @@ -2278,12 +2408,11 @@ again: if (NCRDMA_ISACTIVE(sc)) { if (NCRDMA_INTR(sc) == -1) { device_printf(sc->sc_dev, "DMA error; resetting\n"); - ncr53c9x_init(sc, 1); - goto out; + goto reset; } /* If DMA active here, then go back to work... */ if (NCRDMA_ISACTIVE(sc)) - goto out; + return; if ((sc->sc_espstat & NCRSTAT_TC) == 0) { /* @@ -2333,7 +2462,7 @@ again: sc->sc_espstep, sc->sc_prevphase, ecb ? ecb->dleft : -1); - panic("esp: unrecoverable DMA error"); + goto reset; } } } @@ -2390,15 +2519,24 @@ again: goto finish; case NCR_CONNECTED: - if ((sc->sc_flags & NCR_SYNCHNEGO) != 0) { -#ifdef NCR53C9X_DEBUG - if (ecb != NULL) - xpt_print_path(ecb->ccb->ccb_h.path); - printf("sync nego not completed!\n"); -#endif + if (ecb != NULL) { ti = &sc->sc_tinfo[ecb->ccb->ccb_h.target_id]; - sc->sc_flags &= ~NCR_SYNCHNEGO; - ti->flags &= ~(T_NEGOTIATE | T_SYNCMODE); + if ((ti->flags & T_SDTRSENT) != 0) { + xpt_print_path(ecb->ccb->ccb_h.path); + printf("sync nego not completed!\n"); + ti->flags &= ~T_SDTRSENT; + ti->curr.period = ti->goal.period = 0; + ti->curr.offset = ti->goal.offset = 0; + ncr53c9x_setsync(sc, ti); + } + if ((ti->flags & T_WDTRSENT) != 0) { + xpt_print_path(ecb->ccb->ccb_h.path); + printf("wide nego not completed!\n"); + ti->flags &= ~T_WDTRSENT; + ti->curr.width = ti->goal.width = + MSG_EXT_WDTR_BUS_8_BIT; + ncr53c9x_setsync(sc, ti); + } } /* It may be OK to disconnect. */ @@ -2431,10 +2569,13 @@ again: goto reset; } printf("sending REQUEST SENSE\n"); - untimeout(ncr53c9x_timeout, ecb, - ecb->ccb->ccb_h.timeout_ch); + callout_stop(&ecb->ch); ncr53c9x_sense(sc, ecb); - goto out; + return; + } else if (ecb != NULL && + (ecb->flags & ECB_RESET) != 0) { + ecb->ccb->ccb_h.status = CAM_REQ_CMP; + goto finish; } ecb->ccb->ccb_h.status = CAM_CMD_TIMEOUT; @@ -2453,7 +2594,7 @@ again: switch (sc->sc_state) { case NCR_SBR: device_printf(sc->sc_dev, "waiting for Bus Reset to happen\n"); - goto out; + return; case NCR_RESELECTED: /* @@ -2461,8 +2602,7 @@ again: */ device_printf(sc->sc_dev, "unhandled reselect continuation, " "state %d, intr %02x\n", sc->sc_state, sc->sc_espintr); - ncr53c9x_init(sc, 1); - goto out; + goto reset; break; case NCR_IDENTIFIED: @@ -2479,8 +2619,7 @@ again: while (i-- > 0) printf("[%d] ", NCR_READ_REG(sc, NCR_FIFO)); - ncr53c9x_init(sc, 1); - goto out; + goto reset; } else goto msgin; @@ -2497,8 +2636,7 @@ again: */ if (sc->sc_state == NCR_SELECTING) { NCR_INTS(("backoff selector ")); - untimeout(ncr53c9x_timeout, ecb, - ecb->ccb->ccb_h.timeout_ch); + callout_stop(&ecb->ch); ncr53c9x_dequeue(sc, ecb); TAILQ_INSERT_HEAD(&sc->ready_list, ecb, chain); ecb->flags |= ECB_READY; @@ -2512,8 +2650,7 @@ again: */ device_printf(sc->sc_dev, "target didn't " "identify\n"); - ncr53c9x_init(sc, 1); - goto out; + goto reset; } /* * The C90 only inhibits FIFO writes until reselection @@ -2555,8 +2692,7 @@ again: sc->sc_espstat, sc->sc_espstep, sc->sc_prevphase); - ncr53c9x_init(sc, 1); - goto out; + goto reset; } sc->sc_selid = sc->sc_imess[0]; NCR_INTS(("selid=%02x ", sc->sc_selid)); @@ -2570,8 +2706,7 @@ again: device_printf(sc->sc_dev, "identify failed, " "state %d, intr %02x\n", sc->sc_state, sc->sc_espintr); - ncr53c9x_init(sc, 1); - goto out; + goto reset; } goto shortcut; /* i.e. next phase expected soon */ } @@ -2590,7 +2725,7 @@ again: */ if (sc->sc_state == NCR_IDLE && sc->sc_espstep == 0) - goto out; + return; panic("ncr53c9x: no nexus"); } @@ -2611,34 +2746,49 @@ again: break; case 1: - if ((ti->flags & T_NEGOTIATE) == 0 && + if (ti->curr.period == ti->goal.period && + ti->curr.offset == ti->goal.offset && + ti->curr.width == ti->goal.width && ecb->tag[0] == 0) { - device_printf(sc->sc_dev, "step 1 & " - "!NEG\n"); + device_printf(sc->sc_dev, "step 1 " + "and no negotiation to perform " + "or tag to send\n"); goto reset; } if (sc->sc_phase != MESSAGE_OUT_PHASE) { - device_printf(sc->sc_dev, "!MSGOUT\n"); + device_printf(sc->sc_dev, "step 1 " + "but not in MESSAGE_OUT_PHASE\n"); goto reset; } - if (ti->flags & T_WIDE) { - ti->flags |= T_WDTRSENT; - ncr53c9x_sched_msgout(SEND_WDTR); + sc->sc_prevphase = MESSAGE_OUT_PHASE; /* XXX */ + if (ecb->flags & ECB_RESET) { + /* + * A DEVICE RESET was scheduled and + * ATNS used. As SEND_DEV_RESET has + * the highest priority, the target + * will reset and disconnect and we + * will end up in ncr53c9x_done w/o + * negotiating or sending a TAG. So + * we just break here in order to + * avoid warnings about negotiation + * not having completed. + */ + ncr53c9x_sched_msgout(SEND_DEV_RESET); + break; } - if (ti->flags & T_NEGOTIATE) { - /* Start negotiating */ - sc->sc_flags |= NCR_SYNCHNEGO; - if (ecb->tag[0]) - ncr53c9x_sched_msgout( - SEND_TAG|SEND_SDTR); - else - ncr53c9x_sched_msgout( - SEND_SDTR); - } else { + if (ti->curr.width != ti->goal.width) { + ti->flags |= T_WDTRSENT | T_SDTRSENT; + ncr53c9x_sched_msgout(SEND_WDTR | + SEND_SDTR); + } + if (ti->curr.period != ti->goal.period || + ti->curr.offset != ti->goal.offset) { + ti->flags |= T_SDTRSENT; + ncr53c9x_sched_msgout(SEND_SDTR); + } + if (ecb->tag[0] != 0) /* Could not do ATN3 so send TAG. */ ncr53c9x_sched_msgout(SEND_TAG); - } - sc->sc_prevphase = MESSAGE_OUT_PHASE; /* XXXX */ break; case 3: @@ -2659,18 +2809,15 @@ again: /* Hope for the best... */ break; } - printf("(%s:%d:%d): selection failed;" - " %d left in FIFO " + xpt_print_path(ecb->ccb->ccb_h.path); + printf("selection failed; %d left in FIFO " "[intr %x, stat %x, step %d]\n", - device_get_nameunit(sc->sc_dev), - ecb->ccb->ccb_h.target_id, - ecb->ccb->ccb_h.target_lun, NCR_READ_REG(sc, NCR_FFLAG) & NCRFIFO_FF, sc->sc_espintr, sc->sc_espstat, sc->sc_espstep); NCRCMD(sc, NCRCMD_FLUSH); ncr53c9x_sched_msgout(SEND_ABORT); - goto out; + return; case 2: /* Select stuck at Command Phase. */ @@ -2679,17 +2826,15 @@ again: case 4: if (sc->sc_features & NCR_F_DMASELECT && - sc->sc_cmdlen != 0) - printf("(%s:%d:%d): select; " - "%lu left in DMA buffer " + sc->sc_cmdlen != 0) { + xpt_print_path(ecb->ccb->ccb_h.path); + printf("select; %lu left in DMA buffer " "[intr %x, stat %x, step %d]\n", - device_get_nameunit(sc->sc_dev), - ecb->ccb->ccb_h.target_id, - ecb->ccb->ccb_h.target_lun, (u_long)sc->sc_cmdlen, sc->sc_espintr, sc->sc_espstat, sc->sc_espstep); + } /* So far, everything went fine. */ break; } @@ -2710,7 +2855,7 @@ again: } if (sc->sc_state == NCR_IDLE) { device_printf(sc->sc_dev, "stray interrupt\n"); - goto out; + return; } break; @@ -2815,6 +2960,15 @@ msgin: NCRCMD(sc, NCRCMD_FLUSH); /* DELAY(1);*/ } + /* + * If we have more messages to send, e.g. WDTR or SDTR + * after we've sent a TAG, set ATN so we'll go back to + * MESSAGE_OUT_PHASE. + */ + if (sc->sc_msgpriq) { + NCRCMD(sc, NCRCMD_SETATN); + sc->sc_flags |= NCR_ATN; + } if (sc->sc_features & NCR_F_DMASELECT) { /* Setup DMA transfer for command. */ size = ecb->clen; @@ -2841,7 +2995,7 @@ msgin: case DATA_OUT_PHASE: NCR_PHASE(("DATA_OUT_PHASE [%ld] ", (long)sc->sc_dleft)); NCRCMD(sc, NCRCMD_FLUSH); - size = min(sc->sc_dleft, sc->sc_maxxfer); + size = ulmin(sc->sc_dleft, sc->sc_maxxfer); NCRDMA_SETUP(sc, &sc->sc_dp, &sc->sc_dleft, 0, &size); sc->sc_prevphase = DATA_OUT_PHASE; goto setup_xfer; @@ -2850,7 +3004,7 @@ msgin: NCR_PHASE(("DATA_IN_PHASE ")); if (sc->sc_rev == NCR_VARIANT_ESP100) NCRCMD(sc, NCRCMD_FLUSH); - size = min(sc->sc_dleft, sc->sc_maxxfer); + size = ulmin(sc->sc_dleft, sc->sc_maxxfer); NCRDMA_SETUP(sc, &sc->sc_dp, &sc->sc_dleft, 1, &size); sc->sc_prevphase = DATA_IN_PHASE; setup_xfer: @@ -2873,7 +3027,7 @@ msgin: NCRCMD(sc, (size == 0 ? NCRCMD_TRPAD : NCRCMD_TRANS) | NCRCMD_DMA); NCRDMA_GO(sc); - goto out; + return; case STATUS_PHASE: NCR_PHASE(("STATUS_PHASE ")); @@ -2891,22 +3045,20 @@ msgin: goto reset; } -out: - mtx_unlock(&sc->sc_lock); return; reset: ncr53c9x_init(sc, 1); - goto out; + return; finish: ncr53c9x_done(sc, ecb); - goto out; + return; sched: sc->sc_state = NCR_IDLE; ncr53c9x_sched(sc); - goto out; + return; shortcut: /* @@ -2929,13 +3081,14 @@ shortcut: goto again; microtime(&cur); } while (cur.tv_sec <= wait.tv_sec && cur.tv_usec <= wait.tv_usec); - goto out; } static void ncr53c9x_abort(struct ncr53c9x_softc *sc, struct ncr53c9x_ecb *ecb) { + NCR_LOCK_ASSERT(sc, MA_OWNED); + /* 2 secs for the abort */ ecb->timeout = NCR_ABORT_TIMEOUT; ecb->flags |= ECB_ABORT; @@ -2949,10 +3102,10 @@ ncr53c9x_abort(struct ncr53c9x_softc *sc, struct ncr53c9x_ecb *ecb) ncr53c9x_sched_msgout(SEND_ABORT); /* - * Reschedule timeout. + * Reschedule callout. */ - ecb->ccb->ccb_h.timeout_ch = - timeout(ncr53c9x_timeout, ecb, mstohz(ecb->timeout)); + callout_reset(&ecb->ch, mstohz(ecb->timeout), + ncr53c9x_callout, ecb); } else { /* * Just leave the command where it is. @@ -2965,13 +3118,16 @@ ncr53c9x_abort(struct ncr53c9x_softc *sc, struct ncr53c9x_ecb *ecb) } static void -ncr53c9x_timeout(void *arg) +ncr53c9x_callout(void *arg) { struct ncr53c9x_ecb *ecb = arg; union ccb *ccb = ecb->ccb; struct ncr53c9x_softc *sc = ecb->sc; - struct ncr53c9x_tinfo *ti = &sc->sc_tinfo[ccb->ccb_h.target_id]; + struct ncr53c9x_tinfo *ti; + + NCR_LOCK_ASSERT(sc, MA_OWNED); + ti = &sc->sc_tinfo[ccb->ccb_h.target_id]; xpt_print_path(ccb->ccb_h.path); device_printf(sc->sc_dev, "timed out [ecb %p (flags 0x%x, dleft %x, " "stat %x)], <state %d, nexus %p, phase(l %x, c %x, p %x), " @@ -2986,8 +3142,6 @@ ncr53c9x_timeout(void *arg) printf("TRACE: %s.", ecb->trace); #endif - mtx_lock(&sc->sc_lock); - if (ecb->flags & ECB_ABORT) { /* Abort timed out. */ printf(" AGAIN\n"); @@ -3000,17 +3154,14 @@ ncr53c9x_timeout(void *arg) /* Disable sync mode if stuck in a data phase. */ if (ecb == sc->sc_nexus && - (ti->flags & T_SYNCMODE) != 0 && - (sc->sc_phase & (MSGI|CDI)) == 0) { + ti->curr.offset != 0 && + (sc->sc_phase & (MSGI | CDI)) == 0) { /* XXX ASYNC CALLBACK! */ + ti->goal.offset = 0; xpt_print_path(ccb->ccb_h.path); printf("sync negotiation disabled\n"); - sc->sc_cfflags |= - (1 << ((ccb->ccb_h.target_id & 7) + 8)); } } - - mtx_unlock(&sc->sc_lock); } static void @@ -3022,10 +3173,11 @@ ncr53c9x_watch(void *arg) time_t old; int t; + NCR_LOCK_ASSERT(sc, MA_OWNED); + /* Delete any structures that have not been used in 10min. */ old = time_second - (10 * 60); - mtx_lock(&sc->sc_lock); for (t = 0; t < sc->sc_ntarg; t++) { ti = &sc->sc_tinfo[t]; li = LIST_FIRST(&ti->luns); @@ -3044,6 +3196,5 @@ ncr53c9x_watch(void *arg) li = LIST_NEXT(li, link); } } - mtx_unlock(&sc->sc_lock); callout_reset(&sc->sc_watchdog, 60 * hz, ncr53c9x_watch, sc); } diff --git a/sys/dev/esp/ncr53c9xreg.h b/sys/dev/esp/ncr53c9xreg.h index c24f807..008692f 100644 --- a/sys/dev/esp/ncr53c9xreg.h +++ b/sys/dev/esp/ncr53c9xreg.h @@ -84,8 +84,8 @@ #define NCRSTAT_PHASE 0x07 /* Phase bits */ #define NCR_SELID 0x04 /* WO - Select/Reselect Bus ID */ -#define NCR_BUSID_HME 0x10 /* XXX HME reselect ID */ -#define NCR_BUSID_HME32 0x40 /* XXX HME to select more than 16 */ +#define NCR_BUSID_HMEXC32 0x40 /* HME xfer counter is 32bit */ +#define NCR_BUSID_HMEENCID 0x10 /* HME encode reselection ID */ #define NCR_INTR 0x05 /* RO - Interrupt */ #define NCRINTR_SBR 0x80 /* SCSI Bus Reset */ diff --git a/sys/dev/esp/ncr53c9xvar.h b/sys/dev/esp/ncr53c9xvar.h index 1c81d92..7607e56 100644 --- a/sys/dev/esp/ncr53c9xvar.h +++ b/sys/dev/esp/ncr53c9xvar.h @@ -110,9 +110,9 @@ * ECB. Holds additional information for each SCSI command Comments: We * need a separate scsi command block because we may need to overwrite it * with a request sense command. Basicly, we refrain from fiddling with - * the scsipi_xfer struct (except do the expected updating of return values). - * We'll generally update: xs->{flags,resid,error,sense,status} and - * occasionally xs->retries. + * the ccb union (except do the expected updating of return values). + * We'll generally update: ccb->ccb_h.status and ccb->csio.{resid, + * scsi_status,sense_data}. */ struct ncr53c9x_ecb { /* These fields are preserved between alloc and free */ @@ -130,6 +130,7 @@ struct ncr53c9x_ecb { #define ECB_RESET 0x80 #define ECB_TENTATIVE_DONE 0x100 int timeout; + struct callout ch; struct { u_char msg[3]; /* Selection Id msg and tags */ @@ -180,6 +181,12 @@ struct ncr53c9x_linfo { struct ncr53c9x_ecb *queued[NCR_TAG_DEPTH]; }; +struct ncr53c9x_xinfo { + u_char period; + u_char offset; + u_char width; +}; + struct ncr53c9x_tinfo { int cmds; /* # of commands processed */ int dconns; /* # of disconnects */ @@ -187,18 +194,13 @@ struct ncr53c9x_tinfo { int perrs; /* # of parity errors */ int senses; /* # of request sense commands sent */ u_char flags; -#define T_NEGOTIATE 0x02 /* (Re)Negotiate synchronous options */ -#define T_SYNCMODE 0x08 /* SYNC mode has been negotiated */ -#define T_SYNCHOFF 0x10 /* SYNC mode for is permanently off */ -#define T_RSELECTOFF 0x20 /* RE-SELECT mode is off */ -#define T_TAG 0x40 /* Turn on TAG QUEUEs */ -#define T_WIDE 0x80 /* Negotiate wide options */ -#define T_WDTRSENT 0x04 /* WDTR message has been sent to */ - u_char period; /* Period suggestion */ - u_char offset; /* Offset suggestion */ - u_char cfg3; /* per target config 3 */ - u_char nextag; /* Next available tag */ - u_char width; /* width suggesion */ +#define T_SYNCHOFF 0x01 /* SYNC mode is permanently off */ +#define T_RSELECTOFF 0x02 /* RE-SELECT mode is off */ +#define T_TAG 0x04 /* Turn on TAG QUEUEs */ +#define T_SDTRSENT 0x08 /* SDTR message has been sent to */ +#define T_WDTRSENT 0x10 /* WDTR message has been sent to */ + struct ncr53c9x_xinfo curr; + struct ncr53c9x_xinfo goal; LIST_HEAD(lun_list, ncr53c9x_linfo) luns; struct ncr53c9x_linfo *lun[NCR_NLUN]; /* For speedy lookups */ }; @@ -352,7 +354,6 @@ struct ncr53c9x_softc { int sc_features; /* Chip features */ int sc_minsync; /* Minimum sync period / 4 */ int sc_maxxfer; /* Maximum transfer size */ - int sc_maxsync; /* Maximum sync period */ int sc_maxoffset; /* Maximum offset */ int sc_maxwidth; /* Maximum width */ int sc_extended_geom; /* Should we return extended geometry */ @@ -377,12 +378,10 @@ struct ncr53c9x_softc { /* values for sc_flags */ #define NCR_DROP_MSGI 0x01 /* Discard all msgs (parity err detected) */ #define NCR_ABORTING 0x02 /* Bailing out */ -#define NCR_DOINGDMA 0x04 /* The FIFO data path is active! */ -#define NCR_SYNCHNEGO 0x08 /* Synch negotiation in progress. */ -#define NCR_ICCS 0x10 /* Expect status phase results */ -#define NCR_WAITI 0x20 /* Waiting for non-DMA data to arrive */ -#define NCR_ATN 0x40 /* ATN asserted */ -#define NCR_EXPECT_ILLCMD 0x80 /* Expect Illegal Command Interrupt */ +#define NCR_ICCS 0x04 /* Expect status phase results */ +#define NCR_WAITI 0x08 /* Waiting for non-DMA data to arrive */ +#define NCR_ATN 0x10 /* ATN asserted */ +#define NCR_EXPECT_ILLCMD 0x20 /* Expect Illegal Command Interrupt */ /* values for sc_features */ #define NCR_F_HASCFG3 0x01 /* chip has CFG3 register */ @@ -397,9 +396,9 @@ struct ncr53c9x_softc { #define SEND_REJECT 0x0008 #define SEND_IDENTIFY 0x0010 #define SEND_ABORT 0x0020 -#define SEND_WDTR 0x0040 -#define SEND_SDTR 0x0080 -#define SEND_TAG 0x0100 +#define SEND_TAG 0x0040 +#define SEND_WDTR 0x0080 +#define SEND_SDTR 0x0100 /* SCSI Status codes */ #define ST_MASK 0x3e /* bit 0,6,7 is reserved */ @@ -444,6 +443,17 @@ struct ncr53c9x_softc { #endif /* + * Macros for locking + */ +#define NCR_LOCK_INIT(_sc) \ + mtx_init(&(_sc)->sc_lock, "ncr", "ncr53c9x lock", MTX_DEF); +#define NCR_LOCK_INITIALIZED(_sc) mtx_initialized(&(_sc)->sc_lock) +#define NCR_LOCK(_sc) mtx_lock(&(_sc)->sc_lock) +#define NCR_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_lock) +#define NCR_LOCK_ASSERT(_sc, _what) mtx_assert(&(_sc)->sc_lock, (_what)) +#define NCR_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_lock) + +/* * DMA macros for NCR53c9x */ #define NCRDMA_ISINTR(sc) (*(sc)->sc_glue->gl_dma_isintr)((sc)) @@ -452,6 +462,7 @@ struct ncr53c9x_softc { #define NCRDMA_SETUP(sc, addr, len, datain, dmasize) \ (*(sc)->sc_glue->gl_dma_setup)((sc), (addr), (len), (datain), (dmasize)) #define NCRDMA_GO(sc) (*(sc)->sc_glue->gl_dma_go)((sc)) +#define NCRDMA_STOP(sc) (*(sc)->sc_glue->gl_dma_stop)((sc)) #define NCRDMA_ISACTIVE(sc) (*(sc)->sc_glue->gl_dma_isactive)((sc)) /* @@ -463,9 +474,6 @@ struct ncr53c9x_softc { int ncr53c9x_attach(struct ncr53c9x_softc *sc); int ncr53c9x_detach(struct ncr53c9x_softc *sc); -void ncr53c9x_action(struct cam_sim *sim, union ccb *ccb); -void ncr53c9x_reset(struct ncr53c9x_softc *sc); void ncr53c9x_intr(void *arg); -void ncr53c9x_init(struct ncr53c9x_softc *sc, int doreset); #endif /* _DEV_IC_NCR53C9XVAR_H_ */ diff --git a/sys/dev/le/if_le_ledma.c b/sys/dev/le/if_le_ledma.c index affd5c8..b07e610 100644 --- a/sys/dev/le/if_le_ledma.c +++ b/sys/dev/le/if_le_ledma.c @@ -78,12 +78,8 @@ __FBSDID("$FreeBSD$"); struct le_dma_softc { struct am7990_softc sc_am7990; /* glue to MI code */ - int sc_rrid; struct resource *sc_rres; - bus_space_tag_t sc_regt; - bus_space_handle_t sc_regh; - int sc_irid; struct resource *sc_ires; void *sc_ih; @@ -115,6 +111,7 @@ static device_method_t le_dma_methods[] = { DEFINE_CLASS_0(le, le_dma_driver, le_dma_methods, sizeof(struct le_dma_softc)); DRIVER_MODULE(le, dma, le_dma_driver, le_devclass, 0, 0); +MODULE_DEPEND(le, dma, 1, 1, 1); MODULE_DEPEND(le, ether, 1, 1, 1); /* @@ -142,10 +139,9 @@ le_dma_wrcsr(struct lance_softc *sc, uint16_t port, uint16_t val) { struct le_dma_softc *lesc = (struct le_dma_softc *)sc; - bus_space_write_2(lesc->sc_regt, lesc->sc_regh, LEREG1_RAP, port); - bus_space_barrier(lesc->sc_regt, lesc->sc_regh, LEREG1_RAP, 2, - BUS_SPACE_BARRIER_WRITE); - bus_space_write_2(lesc->sc_regt, lesc->sc_regh, LEREG1_RDP, val); + bus_write_2(lesc->sc_rres, LEREG1_RAP, port); + bus_barrier(lesc->sc_rres, LEREG1_RAP, 2, BUS_SPACE_BARRIER_WRITE); + bus_write_2(lesc->sc_rres, LEREG1_RDP, val); } static uint16_t @@ -153,10 +149,9 @@ le_dma_rdcsr(struct lance_softc *sc, uint16_t port) { struct le_dma_softc *lesc = (struct le_dma_softc *)sc; - bus_space_write_2(lesc->sc_regt, lesc->sc_regh, LEREG1_RAP, port); - bus_space_barrier(lesc->sc_regt, lesc->sc_regh, LEREG1_RAP, 2, - BUS_SPACE_BARRIER_WRITE); - return (bus_space_read_2(lesc->sc_regt, lesc->sc_regh, LEREG1_RDP)); + bus_write_2(lesc->sc_rres, LEREG1_RAP, port); + bus_barrier(lesc->sc_rres, LEREG1_RAP, 2, BUS_SPACE_BARRIER_WRITE); + return (bus_read_2(lesc->sc_rres, LEREG1_RDP)); } static void @@ -238,7 +233,7 @@ le_dma_hwreset(struct lance_softc *sc) DMA_RESET(dma); /* Write bits 24-31 of Lance address. */ - bus_space_write_4(dma->sc_regt, dma->sc_regh, L64854_REG_ENBAR, + bus_write_4(dma->sc_res, L64854_REG_ENBAR, lesc->sc_laddr & 0xff000000); DMA_ENINTR(dma); @@ -319,7 +314,7 @@ le_dma_attach(device_t dev) struct le_dma_softc *lesc; struct lsi64854_softc *dma; struct lance_softc *sc; - int error; + int error, i; lesc = device_get_softc(dev); sc = &lesc->sc_am7990.lsc; @@ -334,25 +329,30 @@ le_dma_attach(device_t dev) lesc->sc_dma = dma; lesc->sc_dma->sc_client = lesc; - lesc->sc_rrid = 0; + i = 0; lesc->sc_rres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, - &lesc->sc_rrid, RF_ACTIVE); + &i, RF_ACTIVE); if (lesc->sc_rres == NULL) { device_printf(dev, "cannot allocate registers\n"); error = ENXIO; goto fail_mtx; } - lesc->sc_regt = rman_get_bustag(lesc->sc_rres); - lesc->sc_regh = rman_get_bushandle(lesc->sc_rres); - lesc->sc_irid = 0; + i = 0; if ((lesc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, - &lesc->sc_irid, RF_SHAREABLE | RF_ACTIVE)) == NULL) { + &i, RF_SHAREABLE | RF_ACTIVE)) == NULL) { device_printf(dev, "cannot allocate interrupt\n"); error = ENXIO; goto fail_rres; } + /* Attach the DMA engine. */ + error = lsi64854_attach(dma); + if (error != 0) { + device_printf(dev, "lsi64854_attach failed\n"); + goto fail_ires; + } + sc->sc_memsize = LEDMA_MEMSIZE; error = bus_dma_tag_create( dma->sc_parent_dmat, /* parent */ @@ -369,7 +369,7 @@ le_dma_attach(device_t dev) &lesc->sc_dmat); if (error != 0) { device_printf(dev, "cannot allocate buffer DMA tag\n"); - goto fail_ires; + goto fail_lsi; } error = bus_dmamem_alloc(lesc->sc_dmat, (void **)&sc->sc_mem, @@ -383,7 +383,7 @@ le_dma_attach(device_t dev) error = bus_dmamap_load(lesc->sc_dmat, lesc->sc_dmam, sc->sc_mem, sc->sc_memsize, le_dma_dma_callback, lesc, 0); if (error != 0 || lesc->sc_laddr == 0) { - device_printf(dev, "cannot load DMA buffer map\n"); + device_printf(dev, "cannot load DMA buffer map\n"); goto fail_dmem; } @@ -435,10 +435,14 @@ le_dma_attach(device_t dev) bus_dmamem_free(lesc->sc_dmat, sc->sc_mem, lesc->sc_dmam); fail_dtag: bus_dma_tag_destroy(lesc->sc_dmat); + fail_lsi: + lsi64854_detach(dma); fail_ires: - bus_release_resource(dev, SYS_RES_IRQ, lesc->sc_irid, lesc->sc_ires); + bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(lesc->sc_ires), + lesc->sc_ires); fail_rres: - bus_release_resource(dev, SYS_RES_MEMORY, lesc->sc_rrid, lesc->sc_rres); + bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(lesc->sc_rres), + lesc->sc_rres); fail_mtx: LE_LOCK_DESTROY(sc); return (error); @@ -449,6 +453,7 @@ le_dma_detach(device_t dev) { struct le_dma_softc *lesc; struct lance_softc *sc; + int error; lesc = device_get_softc(dev); sc = &lesc->sc_am7990.lsc; @@ -458,8 +463,13 @@ le_dma_detach(device_t dev) bus_dmamap_unload(lesc->sc_dmat, lesc->sc_dmam); bus_dmamem_free(lesc->sc_dmat, sc->sc_mem, lesc->sc_dmam); bus_dma_tag_destroy(lesc->sc_dmat); - bus_release_resource(dev, SYS_RES_IRQ, lesc->sc_irid, lesc->sc_ires); - bus_release_resource(dev, SYS_RES_MEMORY, lesc->sc_rrid, lesc->sc_rres); + error = lsi64854_detach(lesc->sc_dma); + if (error != 0) + return (error); + bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(lesc->sc_ires), + lesc->sc_ires); + bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(lesc->sc_rres), + lesc->sc_rres); LE_LOCK_DESTROY(sc); return (0); diff --git a/sys/sparc64/sbus/dma_sbus.c b/sys/sparc64/sbus/dma_sbus.c index 924fa27..4623995 100644 --- a/sys/sparc64/sbus/dma_sbus.c +++ b/sys/sparc64/sbus/dma_sbus.c @@ -70,7 +70,6 @@ __FBSDID("$FreeBSD$"); #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> @@ -178,7 +177,7 @@ dma_attach(device_t dev) char *cabletype; uint32_t csr; phandle_t child, node; - int error, burst, children; + int error, i; dsc = device_get_softc(dev); lsc = &dsc->sc_lsi64854; @@ -188,15 +187,13 @@ dma_attach(device_t 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, + i = 0; + lsc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &i, 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; @@ -246,23 +243,17 @@ dma_attach(device_t dev) goto fail_lres; } - burst = sbus_get_burstsz(dev); - lsc->sc_burst = (burst & SBUS_BURST_32) ? 32 : - (burst & SBUS_BURST_16) ? 16 : 0; + i = sbus_get_burstsz(dev); + lsc->sc_burst = (i & SBUS_BURST_32) ? 32 : + (i & 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; + i = 0; for (child = OF_child(node); child != 0; child = OF_peer(child)) { if ((ddi = dma_setup_dinfo(dev, dsc, child)) == NULL) continue; - if (children != 0) { + if (i != 0) { device_printf(dev, "<%s>: only one child per DMA channel supported\n", ddi->ddi_obdinfo.obd_name); @@ -276,14 +267,13 @@ dma_attach(device_t dev) continue; } device_set_ivars(cdev, ddi); - children++; + i++; } return (bus_generic_attach(dev)); - 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); + bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(lsc->sc_res), + lsc->sc_res); return (error); } diff --git a/sys/sparc64/sbus/lsi64854.c b/sys/sparc64/sbus/lsi64854.c index 7ee3bc1..94f28ba 100644 --- a/sys/sparc64/sbus/lsi64854.c +++ b/sys/sparc64/sbus/lsi64854.c @@ -70,9 +70,9 @@ __FBSDID("$FreeBSD$"); #include <sys/systm.h> #include <sys/bus.h> #include <sys/kernel.h> -#include <sys/resource.h> #include <sys/lock.h> #include <sys/mutex.h> +#include <sys/rman.h> #include <machine/bus.h> @@ -112,7 +112,7 @@ static int lsi64854_pp_intr(void *); /* * Finish attaching this DMA device. * Front-end must fill in these fields: - * sc_regs + * sc_res * sc_burst * sc_channel (one of SCSI, ENET, PP) * sc_client (one of SCSI, ENET, PP `soft_c' pointers) @@ -120,12 +120,24 @@ static int lsi64854_pp_intr(void *); int lsi64854_attach(struct lsi64854_softc *sc) { + bus_dma_lock_t *lockfunc; + struct ncr53c9x_softc *nsc; + void *lockfuncarg; uint32_t csr; int error; - /* Indirect functions */ + lockfunc = NULL; + lockfuncarg = NULL; + switch (sc->sc_channel) { case L64854_CHANNEL_SCSI: + nsc = sc->sc_client; + if (NCR_LOCK_INITIALIZED(nsc) == 0) { + device_printf(sc->sc_dev, "mutex not initialized\n"); + return (ENXIO); + } + lockfunc = busdma_lock_mutex; + lockfuncarg = &nsc->sc_lock; sc->intr = lsi64854_scsi_intr; sc->setup = lsi64854_setup; break; @@ -141,29 +153,32 @@ lsi64854_attach(struct lsi64854_softc *sc) } sc->reset = lsi64854_reset; - /* Allocate a dmamap */ - error = bus_dma_tag_create( - sc->sc_parent_dmat, /* parent */ - 1, 0, /* alignment, boundary */ - BUS_SPACE_MAXADDR, /* lowaddr */ - BUS_SPACE_MAXADDR, /* highaddr */ - NULL, NULL, /* filter, filterarg */ - MAX_DMA_SZ, /* maxsize */ - 1, /* nsegments */ - MAX_DMA_SZ, /* maxsegsize */ - BUS_DMA_ALLOCNOW, /* flags */ - NULL, NULL, /* lockfunc, lockarg */ - &sc->sc_buffer_dmat); - if (error != 0) { - device_printf(sc->sc_dev, "cannot allocate buffer DMA tag\n"); - return (error); - } - - 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"); - bus_dma_tag_destroy(sc->sc_buffer_dmat); - return (error); + if (sc->setup != NULL) { + error = bus_dma_tag_create( + sc->sc_parent_dmat, /* parent */ + 1, 0, /* alignment, boundary */ + BUS_SPACE_MAXADDR, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + MAX_DMA_SZ, /* maxsize */ + 1, /* nsegments */ + MAX_DMA_SZ, /* maxsegsize */ + BUS_DMA_ALLOCNOW, /* flags */ + lockfunc, lockfuncarg, /* lockfunc, lockfuncarg */ + &sc->sc_buffer_dmat); + if (error != 0) { + device_printf(sc->sc_dev, + "cannot allocate buffer DMA tag\n"); + return (error); + } + + 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"); + bus_dma_tag_destroy(sc->sc_buffer_dmat); + return (error); + } } csr = L64854_GCSR(sc); @@ -201,16 +216,20 @@ int lsi64854_detach(struct lsi64854_softc *sc) { - if (sc->setup) + if (sc->setup != NULL) { + bus_dmamap_sync(sc->sc_buffer_dmat, sc->sc_dmamap, + (L64854_GCSR(sc) & L64854_WRITE) != 0 ? + BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); 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); + bus_dmamap_destroy(sc->sc_buffer_dmat, sc->sc_dmamap); + bus_dma_tag_destroy(sc->sc_buffer_dmat); + } return (0); } /* - * DMAWAIT waits while condition is true + * DMAWAIT waits while condition is true. */ #define DMAWAIT(SC, COND, MSG, DONTPANIC) do if (COND) { \ int count = 500000; \ @@ -279,11 +298,12 @@ lsi64854_reset(struct lsi64854_softc *sc) DPRINTF(LDB_ANY, ("%s: csr 0x%x\n", __func__, csr)); - /* - * XXX is sync needed? - if (sc->sc_dmamap->dm_nsegs > 0) + if (sc->sc_dmasize != 0) { + bus_dmamap_sync(sc->sc_buffer_dmat, sc->sc_dmamap, + (csr & D_WRITE) != 0 ? BUS_DMASYNC_PREREAD : + BUS_DMASYNC_PREWRITE); bus_dmamap_unload(sc->sc_buffer_dmat, sc->sc_dmamap); - */ + } if (sc->sc_rev == DMAREV_HME) L64854_SCSR(sc, csr | D_HW_RESET_FAS366); @@ -332,7 +352,7 @@ lsi64854_reset(struct lsi64854_softc *sc) L64854_SCSR(sc, csr); if (sc->sc_rev == DMAREV_HME) { - bus_space_write_4(sc->sc_regt, sc->sc_regh, L64854_REG_ADDR, 0); + bus_write_4(sc->sc_res, L64854_REG_ADDR, 0); sc->sc_dmactl = csr; } sc->sc_active = 0; @@ -352,11 +372,10 @@ lsi64854_map_scsi(void *arg, bus_dma_segment_t *segs, int nseg, int error) bus_dmamap_sync(sc->sc_buffer_dmat, sc->sc_dmamap, sc->sc_datain ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); - bus_space_write_4(sc->sc_regt, sc->sc_regh, L64854_REG_ADDR, - segs[0].ds_addr); + bus_write_4(sc->sc_res, L64854_REG_ADDR, segs[0].ds_addr); } -#define DMAMAX(a) (MAX_DMA_SZ - ((a) & (MAX_DMA_SZ-1))) +#define DMAMAX(a) (MAX_DMA_SZ - ((a) & (MAX_DMA_SZ - 1))) /* * setup a DMA transfer */ @@ -382,7 +401,7 @@ lsi64854_setup(struct lsi64854_softc *sc, caddr_t *addr, size_t *len, * and we cannot cross a 16Mb boundary. */ *dmasize = sc->sc_dmasize = - ulmin(*dmasize, DMAMAX((size_t) *sc->sc_dmaaddr)); + ulmin(*dmasize, DMAMAX((size_t)*sc->sc_dmaaddr)); DPRINTF(LDB_ANY, ("%s: dmasize=%ld\n", __func__, (long)sc->sc_dmasize)); @@ -393,12 +412,11 @@ lsi64854_setup(struct lsi64854_softc *sc, caddr_t *addr, size_t *len, L64854_SCSR(sc, sc->sc_dmactl | L64854_RESET); L64854_SCSR(sc, sc->sc_dmactl); - bus_space_write_4(sc->sc_regt, sc->sc_regh, L64854_REG_CNT, - *dmasize); + bus_write_4(sc->sc_res, L64854_REG_CNT, *dmasize); } /* Program the DMA address */ - if (sc->sc_dmasize) + if (sc->sc_dmasize != 0) if (bus_dmamap_load(sc->sc_buffer_dmat, sc->sc_dmamap, *sc->sc_dmaaddr, sc->sc_dmasize, lsi64854_map_scsi, sc, 0)) panic("%s: cannot allocate DVMA address", __func__); @@ -408,8 +426,7 @@ lsi64854_setup(struct lsi64854_softc *sc, caddr_t *addr, size_t *len, bcnt = sc->sc_dmasize; if (((bcnt + (long)*sc->sc_dmaaddr) & PAGE_MASK_8K) != 0) bcnt = roundup(bcnt, PAGE_SIZE_8K); - bus_space_write_4(sc->sc_regt, sc->sc_regh, L64854_REG_CNT, - bcnt); + bus_write_4(sc->sc_res, L64854_REG_CNT, bcnt); } /* Setup DMA control register */ @@ -447,8 +464,7 @@ lsi64854_scsi_intr(void *arg) csr = L64854_GCSR(sc); DPRINTF(LDB_SCSI, ("%s: addr 0x%x, csr %b\n", __func__, - bus_space_read_4(sc->sc_regt, sc->sc_regh, L64854_REG_ADDR), csr, - DDMACSR_BITS)); + bus_read_4(sc->sc_res, L64854_REG_ADDR), csr, DDMACSR_BITS)); if (csr & (D_ERR_PEND|D_SLAVE_ERR)) { device_printf(sc->sc_dev, "error: csr=%b\n", csr, DDMACSR_BITS); @@ -530,14 +546,12 @@ lsi64854_scsi_intr(void *arg) (nsc->sc_cfg2 & NCRCFG2_FE) ? NCR_READ_REG(nsc, NCR_TCH) : 0, trans, resid)); -#if 0 /* XXX */ - if (sc->sc_dmamap->dm_nsegs > 0) { + if (sc->sc_dmasize != 0) { bus_dmamap_sync(sc->sc_buffer_dmat, sc->sc_dmamap, (csr & D_WRITE) != 0 ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(sc->sc_buffer_dmat, sc->sc_dmamap); } -#endif *sc->sc_dmalen -= trans; *sc->sc_dmaaddr += trans; @@ -604,11 +618,9 @@ lsi64854_map_pp(void *arg, bus_dma_segment_t *segs, int nsegs, int error) bus_dmamap_sync(sc->sc_buffer_dmat, sc->sc_dmamap, sc->sc_datain ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); - bus_space_write_4(sc->sc_regt, sc->sc_regh, L64854_REG_ADDR, - segs[0].ds_addr); + bus_write_4(sc->sc_res, L64854_REG_ADDR, segs[0].ds_addr); - bus_space_write_4(sc->sc_regt, sc->sc_regh, L64854_REG_CNT, - sc->sc_dmasize); + bus_write_4(sc->sc_res, L64854_REG_CNT, sc->sc_dmasize); } /* @@ -635,12 +647,12 @@ lsi64854_setup_pp(struct lsi64854_softc *sc, caddr_t *addr, size_t *len, * and we cannot cross a 16Mb boundary. */ *dmasize = sc->sc_dmasize = - ulmin(*dmasize, DMAMAX((size_t) *sc->sc_dmaaddr)); + ulmin(*dmasize, DMAMAX((size_t)*sc->sc_dmaaddr)); DPRINTF(LDB_PP, ("%s: dmasize=%ld\n", __func__, (long)sc->sc_dmasize)); /* Program the DMA address */ - if (sc->sc_dmasize) + if (sc->sc_dmasize != 0) if (bus_dmamap_load(sc->sc_buffer_dmat, sc->sc_dmamap, *sc->sc_dmaaddr, sc->sc_dmasize, lsi64854_map_pp, sc, 0)) panic("%s: pp cannot allocate DVMA address", __func__); @@ -680,12 +692,10 @@ lsi64854_pp_intr(void *arg) csr = L64854_GCSR(sc); DPRINTF(LDB_PP, ("%s: addr 0x%x, csr %b\n", __func__, - bus_space_read_4(sc->sc_regt, sc->sc_regh, L64854_REG_ADDR), csr, - PDMACSR_BITS)); + bus_read_4(sc->sc_res, L64854_REG_ADDR), csr, PDMACSR_BITS)); if (csr & (P_ERR_PEND|P_SLAVE_ERR)) { - resid = bus_space_read_4(sc->sc_regt, sc->sc_regh, - L64854_REG_CNT); + resid = bus_read_4(sc->sc_res, L64854_REG_CNT); device_printf(sc->sc_dev, "error: resid %d csr=%b\n", resid, csr, PDMACSR_BITS); csr &= ~P_EN_DMA; /* Stop DMA */ @@ -699,8 +709,7 @@ lsi64854_pp_intr(void *arg) if (sc->sc_active != 0) { DMA_DRAIN(sc, 0); - resid = bus_space_read_4(sc->sc_regt, sc->sc_regh, - L64854_REG_CNT); + resid = bus_read_4(sc->sc_res, L64854_REG_CNT); } /* DMA has stopped */ @@ -714,14 +723,12 @@ lsi64854_pp_intr(void *arg) *sc->sc_dmalen -= trans; *sc->sc_dmaaddr += trans; -#if 0 /* XXX */ - if (sc->sc_dmamap->dm_nsegs > 0) { + if (sc->sc_dmasize != 0) { bus_dmamap_sync(sc->sc_buffer_dmat, sc->sc_dmamap, (csr & D_WRITE) != 0 ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(sc->sc_buffer_dmat, sc->sc_dmamap); } -#endif return (ret != 0); } diff --git a/sys/sparc64/sbus/lsi64854var.h b/sys/sparc64/sbus/lsi64854var.h index 9cdd0e3..f0147e0 100644 --- a/sys/sparc64/sbus/lsi64854var.h +++ b/sys/sparc64/sbus/lsi64854var.h @@ -41,10 +41,7 @@ struct lsi64854_softc { device_t sc_dev; - int sc_rid; struct resource *sc_res; - bus_space_handle_t sc_regh; - bus_space_tag_t sc_regt; u_int sc_rev; /* revision */ int sc_burst; /* max suported burst size */ @@ -54,7 +51,7 @@ struct lsi64854_softc { #define L64854_CHANNEL_PP 3 void *sc_client; - int sc_active; /* DMA active ? */ + int sc_active; /* DMA active? */ bus_dmamap_t sc_dmamap; /* DMA map for bus_dma_* */ bus_dma_tag_t sc_parent_dmat; @@ -73,12 +70,8 @@ struct lsi64854_softc { int sc_dodrain; }; -#define L64854_GCSR(sc) \ - (bus_space_read_4((sc)->sc_regt, (sc)->sc_regh, L64854_REG_CSR)) - -#define L64854_SCSR(sc, csr) \ - bus_space_write_4((sc)->sc_regt, (sc)->sc_regh, L64854_REG_CSR, csr) - +#define L64854_GCSR(sc) bus_read_4((sc)->sc_res, L64854_REG_CSR) +#define L64854_SCSR(sc, csr) bus_write_4((sc)->sc_res, L64854_REG_CSR, csr) /* * DMA engine interface functions. @@ -86,7 +79,6 @@ struct lsi64854_softc { #define DMA_RESET(sc) (((sc)->reset)(sc)) #define DMA_INTR(sc) (((sc)->intr)(sc)) #define DMA_SETUP(sc, a, l, d, s) (((sc)->setup)(sc, a, l, d, s)) - #define DMA_ISACTIVE(sc) ((sc)->sc_active) #define DMA_ENINTR(sc) do { \ @@ -104,6 +96,5 @@ struct lsi64854_softc { sc->sc_active = 1; \ } while (0) - int lsi64854_attach(struct lsi64854_softc *); int lsi64854_detach(struct lsi64854_softc *); |