From owner-svn-src-stable@FreeBSD.ORG Sun Nov 16 14:55:59 2008 Return-Path: Delivered-To: svn-src-stable@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 8074C1065670; Sun, 16 Nov 2008 14:55:59 +0000 (UTC) (envelope-from marius@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 713AF8FC19; Sun, 16 Nov 2008 14:55:59 +0000 (UTC) (envelope-from marius@FreeBSD.org) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id mAGEtxQB056643; Sun, 16 Nov 2008 14:55:59 GMT (envelope-from marius@svn.freebsd.org) Received: (from marius@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id mAGEtxSt056640; Sun, 16 Nov 2008 14:55:59 GMT (envelope-from marius@svn.freebsd.org) Message-Id: <200811161455.mAGEtxSt056640@svn.freebsd.org> From: Marius Strobl Date: Sun, 16 Nov 2008 14:55:59 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-7@freebsd.org X-SVN-Group: stable-7 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r185001 - in stable/7/sys: . dev/esp dev/le modules/cxgb sparc64/sbus X-BeenThere: svn-src-stable@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for all the -stable branches of the src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 16 Nov 2008 14:55:59 -0000 Author: marius Date: Sun Nov 16 14:55:58 2008 New Revision: 185001 URL: http://svn.freebsd.org/changeset/base/185001 Log: MFC: r182876 Adapt the locking of esp(4) to MPSAFE cam(4) (so that ncr53c9x_intr() actually is INTR_MPSAFE now) and fix a couple of bugs which lead to panics, amongst other improvements. Approved by: re (kib) Modified: stable/7/sys/ (props changed) stable/7/sys/dev/esp/esp_sbus.c stable/7/sys/dev/esp/ncr53c9x.c stable/7/sys/dev/esp/ncr53c9xreg.h stable/7/sys/dev/esp/ncr53c9xvar.h stable/7/sys/dev/le/if_le_ledma.c stable/7/sys/modules/cxgb/ (props changed) stable/7/sys/sparc64/sbus/dma_sbus.c stable/7/sys/sparc64/sbus/lsi64854.c stable/7/sys/sparc64/sbus/lsi64854var.h Modified: stable/7/sys/dev/esp/esp_sbus.c ============================================================================== --- stable/7/sys/dev/esp/esp_sbus.c Sun Nov 16 14:43:33 2008 (r185000) +++ stable/7/sys/dev/esp/esp_sbus.c Sun Nov 16 14:55:58 2008 (r185001) @@ -1,5 +1,6 @@ /*- * Copyright (c) 2004 Scott Long + * Copyright (c) 2005 Marius Strobl * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -71,8 +72,9 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include -#include +#include #include #include @@ -83,6 +85,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -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 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 */ device_printf(esc->sc_dev, "Unknown chip\n"); - return (ENXIO); + goto fail_lsi; } } } @@ -635,20 +605,20 @@ espattach(struct esp_softc *esc, struct */ 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 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|INTR_MPSAFE, 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 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, 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, #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 Modified: stable/7/sys/dev/esp/ncr53c9x.c ============================================================================== --- stable/7/sys/dev/esp/ncr53c9x.c Sun Nov 16 14:43:33 2008 (r185000) +++ stable/7/sys/dev/esp/ncr53c9x.c Sun Nov 16 14:55:58 2008 (r185001) @@ -1,5 +1,6 @@ /*- * Copyright (c) 2004 Scott Long + * Copyright (c) 2005, 2008 Marius Strobl * 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 #include #include -#include #include +#include #include #include #include @@ -129,14 +130,22 @@ __FBSDID("$FreeBSD$"); #include #include -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 ncr 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 *s 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 *s 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 *s } 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 *s 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 *s 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 *s 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 *s 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 *s * 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_scsi_reset(struct ncr53c9x_softc *sc) +ncr53c9x_clear(struct ncr53c9x_softc *sc, cam_status result) { + struct ncr53c9x_ecb *ecb; + int r; - (*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 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); } /* - * Initialize ncr53c9x state machine. + * Clear all commands for a specific target. */ -void -ncr53c9x_init(struct ncr53c9x_softc *sc, int doreset) +static void +ncr53c9x_clear_target(struct ncr53c9x_softc *sc, int target, + cam_status result) { struct ncr53c9x_ecb *ecb; struct ncr53c9x_linfo *li; + int i; + + NCR_LOCK_ASSERT(sc, MA_OWNED); + + /* 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. + */ +static void +ncr53c9x_init(struct ncr53c9x_softc *sc, int doreset) +{ 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, 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, 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 * 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; - if (ti->flags & T_SYNCMODE) { - syncoff = ti->offset; - synctp = ncr53c9x_stp2cpb(sc, ti->period); + NCR_LOCK_ASSERT(sc, MA_OWNED); + + 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 * synctp = 0; } *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***