Index: sys/arch/arm/broadcom/bcm2835_emmc.c
===================================================================
RCS file: /cvsroot/src/sys/arch/arm/broadcom/bcm2835_emmc.c,v
retrieving revision 1.26
diff -u -r1.26 bcm2835_emmc.c
--- sys/arch/arm/broadcom/bcm2835_emmc.c	3 Aug 2015 10:27:32 -0000	1.26
+++ sys/arch/arm/broadcom/bcm2835_emmc.c	9 Aug 2015 11:41:00 -0000
@@ -82,7 +82,7 @@
 static void bcmemmc_attach_i(device_t);
 #if NBCMDMAC > 0
 static int bcmemmc_xfer_data_dma(struct sdhc_softc *, struct sdmmc_command *);
-static void bcmemmc_dma_done(void *);
+static void bcmemmc_dma_done(uint32_t, uint32_t, void *);
 #endif
 
 CFATTACH_DECL_NEW(bcmemmc, sizeof(struct bcmemmc_softc),
@@ -309,7 +309,10 @@
 	sc->sc_state = EMMC_DMA_STATE_BUSY;
 	bcm_dmac_set_conblk_addr(sc->sc_dmac,
 	    sc->sc_dmamap->dm_segs[0].ds_addr);
-	bcm_dmac_transfer(sc->sc_dmac);
+	error = bcm_dmac_transfer(sc->sc_dmac);
+	if (error)
+		return error;
+
 	while (sc->sc_state == EMMC_DMA_STATE_BUSY) {
 		error = cv_timedwait(&sc->sc_cv, plock, hz * 10);
 		if (error == EWOULDBLOCK) {
@@ -328,14 +331,19 @@
 }
 
 static void
-bcmemmc_dma_done(void *arg)
+bcmemmc_dma_done(uint32_t status, uint32_t error, void *arg)
 {
 	struct bcmemmc_softc * const sc = arg;
 	kmutex_t *plock = sdhc_host_lock(sc->sc_hosts[0]);
 
+	if (status != (DMAC_CS_INT|DMAC_CS_END))
+		device_printf(sc->sc.sc_dev, "status %#x error %#x\n",
+			status,error);
+
 	mutex_enter(plock);
 	KASSERT(sc->sc_state == EMMC_DMA_STATE_BUSY);
-	sc->sc_state = EMMC_DMA_STATE_IDLE;
+	if (status & DMAC_CS_END)
+		sc->sc_state = EMMC_DMA_STATE_IDLE;
 	cv_broadcast(&sc->sc_cv);
 	mutex_exit(plock);
 }
Index: sys/arch/arm/broadcom/bcm2835_dmac.c
===================================================================
RCS file: /cvsroot/src/sys/arch/arm/broadcom/bcm2835_dmac.c,v
retrieving revision 1.12
diff -u -r1.12 bcm2835_dmac.c
--- sys/arch/arm/broadcom/bcm2835_dmac.c	2 Aug 2015 16:46:12 -0000	1.12
+++ sys/arch/arm/broadcom/bcm2835_dmac.c	9 Aug 2015 11:41:00 -0000
@@ -53,7 +53,7 @@
 	struct bcm_dmac_softc *ch_sc;
 	void *ch_ih;
 	uint8_t ch_index;
-	void (*ch_callback)(void *);
+	void (*ch_callback)(uint32_t, uint32_t, void *);
 	void *ch_callbackarg;
 	uint32_t ch_debug;
 };
@@ -165,23 +165,26 @@
 {
 	struct bcm_dmac_channel *ch = priv;
 	struct bcm_dmac_softc *sc = ch->ch_sc;
-	uint32_t cs;
+	uint32_t cs, ce;
 
 	cs = DMAC_READ(sc, DMAC_CS(ch->ch_index));
-	if (!(cs & DMAC_CS_INTMASK))
-		return 0;
-
 	DMAC_WRITE(sc, DMAC_CS(ch->ch_index), cs);
+	cs &= DMAC_CS_INT | DMAC_CS_END | DMAC_CS_ERROR;
+
+	ce = DMAC_READ(sc, DMAC_DEBUG(ch->ch_index));
+	ce &= DMAC_DEBUG_READ_ERROR | DMAC_DEBUG_FIFO_ERROR
+	    | DMAC_DEBUG_READ_LAST_NOT_SET_ERROR;
+	DMAC_WRITE(sc, DMAC_DEBUG(ch->ch_index), ce);
 
 	if (ch->ch_callback)
-		ch->ch_callback(ch->ch_callbackarg);
+		ch->ch_callback(cs, ce, ch->ch_callbackarg);
 
 	return 1;
 }
 
 struct bcm_dmac_channel *
-bcm_dmac_alloc(enum bcm_dmac_type type, int ipl, void (*cb)(void *),
-    void *cbarg)
+bcm_dmac_alloc(enum bcm_dmac_type type, int ipl,
+    void (*cb)(uint32_t, uint32_t, void *), void *cbarg)
 {
 	struct bcm_dmac_softc *sc;
 	struct bcm_dmac_channel *ch = NULL;
@@ -234,9 +237,9 @@
 
 	bcm_dmac_halt(ch);
 
+	/* reset chip */
 	val = DMAC_READ(sc, DMAC_CS(ch->ch_index));
 	val |= DMAC_CS_RESET;
-	val |= DMAC_CS_ABORT;
 	val &= ~DMAC_CS_ACTIVE;
 	DMAC_WRITE(sc, DMAC_CS(ch->ch_index), val);
 
@@ -276,9 +279,21 @@
 bcm_dmac_halt(struct bcm_dmac_channel *ch)
 {
 	struct bcm_dmac_softc *sc = ch->ch_sc;
+	uint32_t val;
 
-	DMAC_WRITE(sc, DMAC_CS(ch->ch_index), DMAC_CS_RESET|DMAC_CS_ABORT);
-	bcm_dmac_set_conblk_addr(ch, 0);
+	/* pause DMA */
+	val = DMAC_READ(sc, DMAC_CS(ch->ch_index));
+	val &= ~DMAC_CS_ACTIVE;
+	DMAC_WRITE(sc, DMAC_CS(ch->ch_index), val);
+
+	/* wait for paused state ? */
+
+	/* end descriptor chain */
+	DMAC_WRITE(sc, DMAC_NEXTCONBK(ch->ch_index), 0);
+
+	/* resume DMA that then stops */
+	val |= DMAC_CS_ACTIVE | DMAC_CS_ABORT;
+	DMAC_WRITE(sc, DMAC_CS(ch->ch_index), val);
 }
 
 #if defined(DDB)
Index: sys/arch/arm/broadcom/bcm2835_dmac.h
===================================================================
RCS file: /cvsroot/src/sys/arch/arm/broadcom/bcm2835_dmac.h,v
retrieving revision 1.3
diff -u -r1.3 bcm2835_dmac.h
--- sys/arch/arm/broadcom/bcm2835_dmac.h	12 Sep 2014 19:33:45 -0000	1.3
+++ sys/arch/arm/broadcom/bcm2835_dmac.h	9 Aug 2015 11:41:00 -0000
@@ -102,7 +102,7 @@
 struct bcm_dmac_channel;
 
 struct bcm_dmac_channel *bcm_dmac_alloc(enum bcm_dmac_type, int,
-					void (*)(void *), void *);
+				void (*)(uint32_t, uint32_t, void *), void *);
 void bcm_dmac_free(struct bcm_dmac_channel *);
 void bcm_dmac_set_conblk_addr(struct bcm_dmac_channel *, bus_addr_t);
 int bcm_dmac_transfer(struct bcm_dmac_channel *);
