[Midnightbsd-cvs] src: dev/firewire: Merge changes with freebsd 7

laffer1 at midnightbsd.org laffer1 at midnightbsd.org
Sun Nov 30 11:27:38 EST 2008


Log Message:
-----------
Merge changes with freebsd 7

Modified Files:
--------------
    src/sys/dev/firewire:
        00README (r1.1.1.1 -> r1.2)
        firewire.c (r1.3 -> r1.4)
        firewire.h (r1.2 -> r1.3)
        firewirereg.h (r1.2 -> r1.3)
        fwcrom.c (r1.1.1.1 -> r1.2)
        fwdev.c (r1.4 -> r1.5)
        fwdma.c (r1.2 -> r1.3)
        fwmem.c (r1.1.1.1 -> r1.2)
        fwohci.c (r1.2 -> r1.3)
        fwohci_pci.c (r1.1.1.1 -> r1.2)
        fwohcireg.h (r1.1.1.1 -> r1.2)
        fwohcivar.h (r1.1.1.1 -> r1.2)
        if_fwe.c (r1.1.1.1 -> r1.2)
        if_fwevar.h (r1.1.1.1 -> r1.2)
        if_fwip.c (r1.1.1.1 -> r1.2)
        if_fwipvar.h (r1.1.1.1 -> r1.2)
        sbp.c (r1.1.1.1 -> r1.2)
        sbp_targ.c (r1.1.1.1 -> r1.2)

-------------- next part --------------
Index: if_fwevar.h
===================================================================
RCS file: /home/cvs/src/sys/dev/firewire/if_fwevar.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/dev/firewire/if_fwevar.h -L sys/dev/firewire/if_fwevar.h -u -r1.1.1.1 -r1.2
--- sys/dev/firewire/if_fwevar.h
+++ sys/dev/firewire/if_fwevar.h
@@ -31,14 +31,14 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  * 
- * $FreeBSD: src/sys/dev/firewire/if_fwevar.h,v 1.5 2005/06/10 16:49:08 brooks Exp $
+ * $FreeBSD: src/sys/dev/firewire/if_fwevar.h,v 1.6 2007/06/06 14:31:36 simokawa Exp $
  */
 
 #ifndef _NET_IF_FWEVAR_H_
 #define _NET_IF_FWEVAR_H_
 
 struct fwe_softc {
-	/* XXX this must be first for fd.post_explore() */
+	/* XXX this must be the first for fd.post_explore() */
 	struct firewire_dev_comm fd;
 	short stream_ch;
 	short dma_ch;
@@ -48,5 +48,8 @@
 		struct ifnet *ifp;
 		struct fwe_softc *fwe;
 	} eth_softc;
+	struct mtx mtx;
 };
+#define FWE_LOCK(fwe)	mtx_lock(&(fwe)->mtx)
+#define FWE_UNLOCK(fwe)	mtx_unlock(&(fwe)->mtx)
 #endif /* !_NET_IF_FWEVAR_H_ */
Index: fwohci.c
===================================================================
RCS file: /home/cvs/src/sys/dev/firewire/fwohci.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L sys/dev/firewire/fwohci.c -L sys/dev/firewire/fwohci.c -u -r1.2 -r1.3
--- sys/dev/firewire/fwohci.c
+++ sys/dev/firewire/fwohci.c
@@ -31,7 +31,7 @@
  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  * 
- * $FreeBSD: src/sys/dev/firewire/fwohci.c,v 1.81 2005/03/29 01:44:59 sam Exp $
+ * $FreeBSD: src/sys/dev/firewire/fwohci.c,v 1.93 2007/06/08 09:04:30 simokawa Exp $
  *
  */
 
@@ -47,10 +47,12 @@
 #include <sys/mbuf.h>
 #include <sys/malloc.h>
 #include <sys/sockio.h>
+#include <sys/sysctl.h>
 #include <sys/bus.h>
 #include <sys/kernel.h>
 #include <sys/conf.h>
 #include <sys/endian.h>
+#include <sys/kdb.h>
 
 #include <machine/bus.h>
 
@@ -76,6 +78,15 @@
 
 #undef OHCI_DEBUG
 
+static int nocyclemaster = 0;
+int firewire_phydma_enable = 1;
+SYSCTL_DECL(_hw_firewire);
+SYSCTL_INT(_hw_firewire, OID_AUTO, nocyclemaster, CTLFLAG_RW, &nocyclemaster, 0,
+        "Do not send cycle start packets");
+SYSCTL_INT(_hw_firewire, OID_AUTO, phydma_enable, CTLFLAG_RW,
+	&firewire_phydma_enable, 1, "Allow physical request DMA from firewire");
+TUNABLE_INT("hw.firewire.phydma_enable", &firewire_phydma_enable);
+
 static char dbcode[16][0x10]={"OUTM", "OUTL","INPM","INPL",
 		"STOR","LOAD","NOP ","STOP",};
 
@@ -84,7 +95,7 @@
 static char dbcond[4][0x10]={"NEV","C=1", "C=0", "ALL"};
 char fwohcicode[32][0x20]={
 	"No stat","Undef","long","miss Ack err",
-	"underrun","overrun","desc err", "data read err",
+	"FIFO underrun","FIFO overrun","desc err", "data read err",
 	"data write err","bus reset","timeout","tcode err",
 	"Undef","Undef","unknown event","flushed",
 	"Undef","ack complete","ack pend","Undef",
@@ -97,23 +108,23 @@
 uint32_t tagbit[4] = { 1 << 28, 1 << 29, 1 << 30, 1 << 31};
 
 static struct tcode_info tinfo[] = {
-/*		hdr_len block 	flag*/
-/* 0 WREQQ  */ {16,	FWTI_REQ | FWTI_TLABEL},
-/* 1 WREQB  */ {16,	FWTI_REQ | FWTI_TLABEL | FWTI_BLOCK_ASY},
-/* 2 WRES   */ {12,	FWTI_RES},
-/* 3 XXX    */ { 0,	0},
-/* 4 RREQQ  */ {12,	FWTI_REQ | FWTI_TLABEL},
-/* 5 RREQB  */ {16,	FWTI_REQ | FWTI_TLABEL},
-/* 6 RRESQ  */ {16,	FWTI_RES},
-/* 7 RRESB  */ {16,	FWTI_RES | FWTI_BLOCK_ASY},
-/* 8 CYCS   */ { 0,	0},
-/* 9 LREQ   */ {16,	FWTI_REQ | FWTI_TLABEL | FWTI_BLOCK_ASY},
-/* a STREAM */ { 4,	FWTI_REQ | FWTI_BLOCK_STR},
-/* b LRES   */ {16,	FWTI_RES | FWTI_BLOCK_ASY},
-/* c XXX    */ { 0,	0},
-/* d XXX    */ { 0, 	0},
-/* e PHY    */ {12,	FWTI_REQ},
-/* f XXX    */ { 0,	0}
+/*		hdr_len block 	flag	valid_response */
+/* 0 WREQQ  */ {16,	FWTI_REQ | FWTI_TLABEL,	FWTCODE_WRES},
+/* 1 WREQB  */ {16,	FWTI_REQ | FWTI_TLABEL | FWTI_BLOCK_ASY, FWTCODE_WRES},
+/* 2 WRES   */ {12,	FWTI_RES, 0xff},
+/* 3 XXX    */ { 0,	0, 0xff},
+/* 4 RREQQ  */ {12,	FWTI_REQ | FWTI_TLABEL, FWTCODE_RRESQ},
+/* 5 RREQB  */ {16,	FWTI_REQ | FWTI_TLABEL, FWTCODE_RRESB},
+/* 6 RRESQ  */ {16,	FWTI_RES, 0xff},
+/* 7 RRESB  */ {16,	FWTI_RES | FWTI_BLOCK_ASY, 0xff},
+/* 8 CYCS   */ { 0,	0, 0xff},
+/* 9 LREQ   */ {16,	FWTI_REQ | FWTI_TLABEL | FWTI_BLOCK_ASY, FWTCODE_LRES},
+/* a STREAM */ { 4,	FWTI_REQ | FWTI_BLOCK_STR, 0xff},
+/* b LRES   */ {16,	FWTI_RES | FWTI_BLOCK_ASY, 0xff},
+/* c XXX    */ { 0,	0, 0xff},
+/* d XXX    */ { 0, 	0, 0xff},
+/* e PHY    */ {12,	FWTI_REQ, 0xff},
+/* f XXX    */ { 0,	0, 0xff}
 };
 
 #define OHCI_WRITE_SIGMASK 0xffff0000
@@ -153,9 +164,9 @@
 static void fwohci_rbuf_update (struct fwohci_softc *, int);
 static void fwohci_tbuf_update (struct fwohci_softc *, int);
 void fwohci_txbufdb (struct fwohci_softc *, int , struct fw_bulkxfer *);
-#if FWOHCI_TASKQUEUE
-static void fwohci_complete(void *, int);
-#endif
+static void fwohci_task_busreset(void *, int);
+static void fwohci_task_sid(void *, int);
+static void fwohci_task_dma(void *, int);
 
 /*
  * memory allocated for DMA programs
@@ -258,6 +269,7 @@
 /*
  * Communication with PHY device
  */
+/* XXX need lock for phy access */
 static uint32_t
 fwphy_wrdata( struct fwohci_softc *sc, uint32_t addr, uint32_t data)
 {
@@ -423,6 +435,8 @@
  *    It is not actually available port on your PC .
  */
 	OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_LPS);
+	DELAY(500);
+
 	reg = fwphy_rddata(sc, FW_PHY_SPD_REG);
 
 	if((reg >> 5) != 7 ){
@@ -581,11 +595,13 @@
 
 
 	/* Enable interrupts */
-	OWRITE(sc, FWOHCI_INTMASK,
-			OHCI_INT_ERR  | OHCI_INT_PHY_SID 
+	sc->intmask =  (OHCI_INT_ERR  | OHCI_INT_PHY_SID
 			| OHCI_INT_DMA_ATRQ | OHCI_INT_DMA_ATRS 
 			| OHCI_INT_DMA_PRRQ | OHCI_INT_DMA_PRRS
 			| OHCI_INT_PHY_BUS_R | OHCI_INT_PW_ERR);
+	sc->intmask |=  OHCI_INT_DMA_IR | OHCI_INT_DMA_IT;
+	sc->intmask |=	OHCI_INT_CYC_LOST | OHCI_INT_PHY_INT;
+	OWRITE(sc, FWOHCI_INTMASK, sc->intmask);
 	fwohci_set_intr(&sc->fc, 1);
 
 }
@@ -597,10 +613,6 @@
 	uint32_t reg;
 	uint8_t ui[8];
 
-#if FWOHCI_TASKQUEUE
-	TASK_INIT(&sc->fwohci_task_complete, 0, fwohci_complete, sc);
-#endif
-
 /* OHCI version */
 	reg = OREAD(sc, OHCI_VERSION);
 	mver = (reg >> 16) & 0xff;
@@ -753,6 +765,15 @@
 
 	sc->intmask = sc->irstat = sc->itstat = 0;
 
+	/* Init task queue */
+	sc->fc.taskqueue = taskqueue_create_fast("fw_taskq", M_WAITOK,
+		taskqueue_thread_enqueue, &sc->fc.taskqueue);
+	taskqueue_start_threads(&sc->fc.taskqueue, 1, PI_NET, "fw%d_taskq",
+					device_get_unit(dev));
+	TASK_INIT(&sc->fwohci_task_busreset, 2, fwohci_task_busreset, sc);
+	TASK_INIT(&sc->fwohci_task_sid, 1, fwohci_task_sid, sc);
+	TASK_INIT(&sc->fwohci_task_dma, 0, fwohci_task_dma, sc);
+
 	fw_init(&sc->fc);
 	fwohci_reset(sc, dev);
 
@@ -794,6 +815,14 @@
 		fwohci_db_free(&sc->it[i]);
 		fwohci_db_free(&sc->ir[i]);
 	}
+	if (sc->fc.taskqueue != NULL) {
+		taskqueue_drain(sc->fc.taskqueue, &sc->fwohci_task_busreset);
+		taskqueue_drain(sc->fc.taskqueue, &sc->fwohci_task_sid);
+		taskqueue_drain(sc->fc.taskqueue, &sc->fwohci_task_dma);
+		taskqueue_drain(sc->fc.taskqueue, &sc->fc.task_timeout);
+		taskqueue_free(sc->fc.taskqueue);
+		sc->fc.taskqueue = NULL;
+	}
 
 	return 0;
 }
@@ -852,6 +881,8 @@
 	struct tcode_info *info;
 	static int maxdesc=0;
 
+	FW_GLOCK_ASSERT(&sc->fc);
+
 	if(&sc->atrq == dbch){
 		off = OHCI_ATQOFF;
 	}else if(&sc->atrs == dbch){
@@ -870,12 +901,14 @@
 	if(xfer == NULL){
 		goto kick;
 	}
+#if 0
 	if(dbch->xferq.queued == 0 ){
 		device_printf(sc->fc.dev, "TX queue empty\n");
 	}
+#endif
 	STAILQ_REMOVE_HEAD(&dbch->xferq.q, link);
 	db_tr->xfer = xfer;
-	xfer->state = FWXF_START;
+	xfer->flag = FWXF_START;
 
 	fp = &xfer->send.hdr;
 	tcode = fp->mode.common.tcode;
@@ -985,6 +1018,7 @@
 		LAST_DB(dbch->pdb_tr, db);
  		FWOHCI_DMA_SET(db->db.desc.depend, db_tr->dbcnt);
 	}
+	dbch->xferq.queued ++;
 	dbch->pdb_tr = db_tr;
 	db_tr = STAILQ_NEXT(db_tr, link);
 	if(db_tr != dbch->bottom){
@@ -1018,7 +1052,9 @@
 fwohci_start_atq(struct firewire_comm *fc)
 {
 	struct fwohci_softc *sc = (struct fwohci_softc *)fc;
+	FW_GLOCK(&sc->fc);
 	fwohci_start( sc, &(sc->atrq));
+	FW_GUNLOCK(&sc->fc);
 	return;
 }
 
@@ -1026,7 +1062,9 @@
 fwohci_start_ats(struct firewire_comm *fc)
 {
 	struct fwohci_softc *sc = (struct fwohci_softc *)fc;
+	FW_GLOCK(&sc->fc);
 	fwohci_start( sc, &(sc->atrs));
+	FW_GUNLOCK(&sc->fc);
 	return;
 }
 
@@ -1060,7 +1098,7 @@
 		LAST_DB(tr, db);
 		status = FWOHCI_DMA_READ(db->db.desc.res) >> OHCI_STATUS_SHIFT;
 		if(!(status & OHCI_CNTL_DMA_ACTIVE)){
-			if (fc->status != FWBUSRESET) 
+			if (fc->status != FWBUSINIT) 
 				/* maybe out of order?? */
 				goto out;
 		}
@@ -1068,7 +1106,7 @@
 			BUS_DMASYNC_POSTWRITE);
 		bus_dmamap_unload(dbch->dmat, tr->dma_map);
 #if 1
-		if (firewire_debug)
+		if (firewire_debug > 1)
 			dump_db(sc, ch);
 #endif
 		if(status & OHCI_CNTL_DMA_DEAD) {
@@ -1114,26 +1152,23 @@
 		}
 		if (tr->xfer != NULL) {
 			xfer = tr->xfer;
-			if (xfer->state == FWXF_RCVD) {
+			if (xfer->flag & FWXF_RCVD) {
 #if 0
 				if (firewire_debug)
 					printf("already rcvd\n");
 #endif
 				fw_xfer_done(xfer);
 			} else {
-				xfer->state = FWXF_SENT;
-				if (err == EBUSY && fc->status != FWBUSRESET) {
-					xfer->state = FWXF_BUSY;
+				microtime(&xfer->tv);
+				xfer->flag = FWXF_SENT;
+				if (err == EBUSY) {
+					xfer->flag = FWXF_BUSY;
 					xfer->resp = err;
-					if (xfer->retry_req != NULL)
-						xfer->retry_req(xfer);
-					else {
-						xfer->recv.pay_len = 0;
-						fw_xfer_done(xfer);
-					}
+					xfer->recv.pay_len = 0;
+					fw_xfer_done(xfer);
 				} else if (stat != FWOHCIEV_ACKPEND) {
 					if (stat != FWOHCIEV_ACKCOMPL)
-						xfer->state = FWXF_SENTERR;
+						xfer->flag = FWXF_SENTERR;
 					xfer->resp = err;
 					xfer->recv.pay_len = 0;
 					fw_xfer_done(xfer);
@@ -1146,7 +1181,9 @@
 		} else {
 			printf("this shouldn't happen\n");
 		}
+		FW_GLOCK(fc);
 		dbch->xferq.queued --;
+		FW_GUNLOCK(fc);
 		tr->xfer = NULL;
 
 		packets ++;
@@ -1163,7 +1200,9 @@
 	if ((dbch->flags & FWOHCI_DBCH_FULL) && packets > 0) {
 		printf("make free slot\n");
 		dbch->flags &= ~FWOHCI_DBCH_FULL;
+		FW_GLOCK(fc);
 		fwohci_start(sc, dbch);
+		FW_GUNLOCK(fc);
 	}
 	splx(s);
 }
@@ -1217,7 +1256,7 @@
 			/*flags*/ 0,
 #if defined(__FreeBSD__) && __FreeBSD_version >= 501102
 			/*lockfunc*/busdma_lock_mutex,
-			/*lockarg*/&Giant,
+			/*lockarg*/FW_GMTX(&sc->fc),
 #endif
 			&dbch->dmat))
 		return;
@@ -1280,14 +1319,13 @@
 fwohci_itx_disable(struct firewire_comm *fc, int dmach)
 {
 	struct fwohci_softc *sc = (struct fwohci_softc *)fc;
-	int sleepch;
 
 	OWRITE(sc, OHCI_ITCTLCLR(dmach), 
 			OHCI_CNTL_DMA_RUN | OHCI_CNTL_CYCMATCH_S);
 	OWRITE(sc, OHCI_IT_MASKCLR, 1 << dmach);
 	OWRITE(sc, OHCI_IT_STATCLR, 1 << dmach);
 	/* XXX we cannot free buffers until the DMA really stops */
-	tsleep((void *)&sleepch, FWPRI, "fwitxd", hz);
+	pause("fwitxd", hz);
 	fwohci_db_free(&sc->it[dmach]);
 	sc->it[dmach].xferq.flag &= ~FWXFERQ_RUNNING;
 	return 0;
@@ -1297,13 +1335,12 @@
 fwohci_irx_disable(struct firewire_comm *fc, int dmach)
 {
 	struct fwohci_softc *sc = (struct fwohci_softc *)fc;
-	int sleepch;
 
 	OWRITE(sc, OHCI_IRCTLCLR(dmach), OHCI_CNTL_DMA_RUN);
 	OWRITE(sc, OHCI_IR_MASKCLR, 1 << dmach);
 	OWRITE(sc, OHCI_IR_STATCLR, 1 << dmach);
 	/* XXX we cannot free buffers until the DMA really stops */
-	tsleep((void *)&sleepch, FWPRI, "fwirxd", hz);
+	pause("fwirxd", hz);
 	fwohci_db_free(&sc->ir[dmach]);
 	sc->ir[dmach].xferq.flag &= ~FWXFERQ_RUNNING;
 	return 0;
@@ -1506,6 +1543,7 @@
 		fwohci_db_init(sc, dbch);
 		if ((dbch->flags & FWOHCI_DBCH_INIT) == 0)
 			return ENOMEM;
+
 		err = fwohci_tx_enable(sc, dbch);
 	}
 	if(err)
@@ -1513,6 +1551,7 @@
 
 	ldesc = dbch->ndesc - 1;
 	s = splfw();
+	FW_GLOCK(fc);
 	prev = STAILQ_LAST(&it->stdma, fw_bulkxfer, link);
 	while  ((chunk = STAILQ_FIRST(&it->stvalid)) != NULL) {
 		struct fwohcidb *db;
@@ -1539,6 +1578,7 @@
 		STAILQ_INSERT_TAIL(&it->stdma, chunk, link);
 		prev = chunk;
 	}
+	FW_GUNLOCK(fc);
 	fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREWRITE);
 	fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREREAD);
 	splx(s);
@@ -1560,7 +1600,7 @@
 	first = STAILQ_FIRST(&it->stdma);
 	OWRITE(sc, OHCI_ITCMD(dmach),
 		((struct fwohcidb_tr *)(first->start))->bus_addr | dbch->ndesc);
-	if (firewire_debug) {
+	if (firewire_debug > 1) {
 		printf("fwohci_itxbuf_enable: kick 0x%08x\n", stat);
 #if 1
 		dump_dma(sc, ITX_CH + dmach);
@@ -1586,7 +1626,7 @@
 #else
 		OWRITE(sc, OHCI_ITCTL(dmach), OHCI_CNTL_DMA_RUN);
 #endif
-		if (firewire_debug) {
+		if (firewire_debug > 1) {
 			printf("cycle_match: 0x%04x->0x%04x\n",
 						cycle_now, cycle_match);
 			dump_dma(sc, ITX_CH + dmach);
@@ -1640,6 +1680,8 @@
 
 	ldesc = dbch->ndesc - 1;
 	s = splfw();
+	if ((ir->flag & FWXFERQ_HANDLER) == 0)
+		FW_GLOCK(fc);
 	prev = STAILQ_LAST(&ir->stdma, fw_bulkxfer, link);
 	while  ((chunk = STAILQ_FIRST(&ir->stfree)) != NULL) {
 		struct fwohcidb *db;
@@ -1667,6 +1709,8 @@
 		STAILQ_INSERT_TAIL(&ir->stdma, chunk, link);
 		prev = chunk;
 	}
+	if ((ir->flag & FWXFERQ_HANDLER) == 0)
+		FW_GUNLOCK(fc);
 	fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREWRITE);
 	fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREREAD);
 	splx(s);
@@ -1712,9 +1756,10 @@
 		OWRITE(sc,  OHCI_ITCTLCLR(i), OHCI_CNTL_DMA_RUN);
 	}
 
-/* FLUSH FIFO and reset Transmitter/Reciever */
-	OWRITE(sc,  OHCI_HCCCTL, OHCI_HCC_RESET);
+	if (sc->fc.arq !=0 && sc->fc.arq->maxq > 0)
+		fw_drain_txq(&sc->fc);
 
+#if 0 /* Let dcons(4) be accessed */  
 /* Stop interrupt */
 	OWRITE(sc, FWOHCI_INTMASKCLR,
 			OHCI_INT_EN | OHCI_INT_ERR | OHCI_INT_PHY_SID
@@ -1724,8 +1769,9 @@
 			| OHCI_INT_DMA_ARRQ | OHCI_INT_DMA_ARRS 
 			| OHCI_INT_PHY_BUS_R);
 
-	if (sc->fc.arq !=0 && sc->fc.arq->maxq > 0)
-		fw_drain_txq(&sc->fc);
+/* FLUSH FIFO and reset Transmitter/Reciever */
+	OWRITE(sc,  OHCI_HCCCTL, OHCI_HCC_RESET);
+#endif
 
 /* XXX Link down?  Bus reset? */
 	return 0;
@@ -1760,15 +1806,10 @@
 	return 0;
 }
 
-#define ACK_ALL
+#ifdef OHCI_DEBUG
 static void
-fwohci_intr_body(struct fwohci_softc *sc, uint32_t stat, int count)
+fwohci_dump_intr(struct fwohci_softc *sc, uint32_t stat)
 {
-	uint32_t irstat, itstat;
-	u_int i;
-	struct firewire_comm *fc = (struct firewire_comm *)sc;
-
-#ifdef OHCI_DEBUG
 	if(stat & OREAD(sc, FWOHCI_INTMASK))
 		device_printf(fc->dev, "INTERRUPT < %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s> 0x%08x, 0x%08x\n",
 			stat & OHCI_INT_EN ? "DMA_EN ":"",
@@ -1794,11 +1835,16 @@
 			stat & OHCI_INT_DMA_ATRQ  ? "DMA_ATRQ " :"",
 			stat, OREAD(sc, FWOHCI_INTMASK) 
 		);
+}
 #endif
-/* Bus reset */
-	if(stat & OHCI_INT_PHY_BUS_R ){
-		if (fc->status == FWBUSRESET)
-			goto busresetout;
+static void
+fwohci_intr_core(struct fwohci_softc *sc, uint32_t stat, int count)
+{
+	struct firewire_comm *fc = (struct firewire_comm *)sc;
+	uint32_t node_id, plen;
+
+	if ((stat & OHCI_INT_PHY_BUS_R) && (fc->status != FWBUSRESET)) {
+		fc->status = FWBUSRESET;
 		/* Disable bus reset interrupt until sid recv. */
 		OWRITE(sc, FWOHCI_INTMASKCLR,  OHCI_INT_PHY_BUS_R);
 	
@@ -1811,24 +1857,73 @@
 		OWRITE(sc,  OHCI_ATSCTLCLR, OHCI_CNTL_DMA_RUN);
 		sc->atrs.xferq.flag &= ~FWXFERQ_RUNNING;
 
-#ifndef ACK_ALL
+		if (!kdb_active)
+			taskqueue_enqueue(sc->fc.taskqueue, &sc->fwohci_task_busreset);
+	}
+	if (stat & OHCI_INT_PHY_SID) {
+		/* Enable bus reset interrupt */
 		OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_PHY_BUS_R);
-#endif
-		fw_busreset(fc, FWBUSRESET);
-		OWRITE(sc, OHCI_CROMHDR, ntohl(sc->fc.config_rom[0]));
-		OWRITE(sc, OHCI_BUS_OPT, ntohl(sc->fc.config_rom[2]));
-	}
-busresetout:
-	if((stat & OHCI_INT_DMA_IR )){
-#ifndef ACK_ALL
-		OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_DMA_IR);
-#endif
-#if defined(__DragonFly__) || __FreeBSD_version < 500000
-		irstat = sc->irstat;
-		sc->irstat = 0;
-#else
+		OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_PHY_BUS_R);
+
+		/* Allow async. request to us */
+		OWRITE(sc, OHCI_AREQHI, 1 << 31);
+		if (firewire_phydma_enable) {
+			/* allow from all nodes */
+			OWRITE(sc, OHCI_PREQHI, 0x7fffffff);
+			OWRITE(sc, OHCI_PREQLO, 0xffffffff);
+			/* 0 to 4GB region */
+			OWRITE(sc, OHCI_PREQUPPER, 0x10000);
+		}
+		/* Set ATRetries register */
+		OWRITE(sc, OHCI_ATRETRY, 1<<(13+16) | 0xfff);
+
+		/*
+		 * Checking whether the node is root or not. If root, turn on 
+		 * cycle master.
+		 */
+		node_id = OREAD(sc, FWOHCI_NODEID);
+		plen = OREAD(sc, OHCI_SID_CNT);
+
+		fc->nodeid = node_id & 0x3f;
+		device_printf(fc->dev, "node_id=0x%08x, gen=%d, ",
+			node_id, (plen >> 16) & 0xff);
+		if (!(node_id & OHCI_NODE_VALID)) {
+			printf("Bus reset failure\n");
+			goto sidout;
+		}
+
+		/* cycle timer */
+		sc->cycle_lost = 0;
+		OWRITE(sc, FWOHCI_INTMASK,  OHCI_INT_CYC_LOST);
+		if ((node_id & OHCI_NODE_ROOT) && !nocyclemaster) {
+			printf("CYCLEMASTER mode\n");
+			OWRITE(sc, OHCI_LNKCTL,
+				OHCI_CNTL_CYCMTR | OHCI_CNTL_CYCTIMER);
+		} else {
+			printf("non CYCLEMASTER mode\n");
+			OWRITE(sc, OHCI_LNKCTLCLR, OHCI_CNTL_CYCMTR);
+			OWRITE(sc, OHCI_LNKCTL, OHCI_CNTL_CYCTIMER);
+		}
+
+		fc->status = FWBUSINIT;
+
+		if (!kdb_active)
+			taskqueue_enqueue(sc->fc.taskqueue, &sc->fwohci_task_sid);
+	}
+sidout:
+	if ((stat & ~(OHCI_INT_PHY_BUS_R | OHCI_INT_PHY_SID)) && (!kdb_active))
+		taskqueue_enqueue(sc->fc.taskqueue, &sc->fwohci_task_dma);
+}
+
+static void
+fwohci_intr_dma(struct fwohci_softc *sc, uint32_t stat, int count)
+{
+	uint32_t irstat, itstat;
+	u_int i;
+	struct firewire_comm *fc = (struct firewire_comm *)sc;
+
+	if (stat & OHCI_INT_DMA_IR) {
 		irstat = atomic_readandclear_int(&sc->irstat);
-#endif
 		for(i = 0; i < fc->nisodma ; i++){
 			struct fwohci_dbch *dbch;
 
@@ -1843,149 +1938,112 @@
 			}
 		}
 	}
-	if((stat & OHCI_INT_DMA_IT )){
-#ifndef ACK_ALL
-		OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_DMA_IT);
-#endif
-#if defined(__DragonFly__) || __FreeBSD_version < 500000
-		itstat = sc->itstat;
-		sc->itstat = 0;
-#else
+	if (stat & OHCI_INT_DMA_IT) {
 		itstat = atomic_readandclear_int(&sc->itstat);
-#endif
 		for(i = 0; i < fc->nisodma ; i++){
 			if((itstat & (1 << i)) != 0){
 				fwohci_tbuf_update(sc, i);
 			}
 		}
 	}
-	if((stat & OHCI_INT_DMA_PRRS )){
-#ifndef ACK_ALL
-		OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_DMA_PRRS);
-#endif
+	if (stat & OHCI_INT_DMA_PRRS) {
 #if 0
 		dump_dma(sc, ARRS_CH);
 		dump_db(sc, ARRS_CH);
 #endif
 		fwohci_arcv(sc, &sc->arrs, count);
 	}
-	if((stat & OHCI_INT_DMA_PRRQ )){
-#ifndef ACK_ALL
-		OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_DMA_PRRQ);
-#endif
+	if (stat & OHCI_INT_DMA_PRRQ) {
 #if 0
 		dump_dma(sc, ARRQ_CH);
 		dump_db(sc, ARRQ_CH);
 #endif
 		fwohci_arcv(sc, &sc->arrq, count);
 	}
-	if(stat & OHCI_INT_PHY_SID){
-		uint32_t *buf, node_id;
-		int plen;
-
-#ifndef ACK_ALL
-		OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_PHY_SID);
+	if (stat & OHCI_INT_CYC_LOST) {
+		if (sc->cycle_lost >= 0)
+			sc->cycle_lost ++;
+		if (sc->cycle_lost > 10) {
+			sc->cycle_lost = -1;
+#if 0
+			OWRITE(sc, OHCI_LNKCTLCLR, OHCI_CNTL_CYCTIMER);
 #endif
-		/* Enable bus reset interrupt */
-		OWRITE(sc, FWOHCI_INTMASK,  OHCI_INT_PHY_BUS_R);
-		/* Allow async. request to us */
-		OWRITE(sc, OHCI_AREQHI, 1 << 31);
-		/* XXX insecure ?? */
-		OWRITE(sc, OHCI_PREQHI, 0x7fffffff);
-		OWRITE(sc, OHCI_PREQLO, 0xffffffff);
-		OWRITE(sc, OHCI_PREQUPPER, 0x10000);
-		/* Set ATRetries register */
-		OWRITE(sc, OHCI_ATRETRY, 1<<(13+16) | 0xfff);
-/*
-** Checking whether the node is root or not. If root, turn on 
-** cycle master.
-*/
-		node_id = OREAD(sc, FWOHCI_NODEID);
-		plen = OREAD(sc, OHCI_SID_CNT);
-
-		device_printf(fc->dev, "node_id=0x%08x, gen=%d, ",
-			node_id, (plen >> 16) & 0xff);
-		if (!(node_id & OHCI_NODE_VALID)) {
-			printf("Bus reset failure\n");
-			goto sidout;
-		}
-		if (node_id & OHCI_NODE_ROOT) {
-			printf("CYCLEMASTER mode\n");
-			OWRITE(sc, OHCI_LNKCTL,
-				OHCI_CNTL_CYCMTR | OHCI_CNTL_CYCTIMER);
-		} else {
-			printf("non CYCLEMASTER mode\n");
-			OWRITE(sc, OHCI_LNKCTLCLR, OHCI_CNTL_CYCMTR);
-			OWRITE(sc, OHCI_LNKCTL, OHCI_CNTL_CYCTIMER);
+			OWRITE(sc, FWOHCI_INTMASKCLR,  OHCI_INT_CYC_LOST);
+			device_printf(fc->dev, "too many cycle lost, "
+			 "no cycle master presents?\n");
 		}
-		fc->nodeid = node_id & 0x3f;
-
-		if (plen & OHCI_SID_ERR) {
-			device_printf(fc->dev, "SID Error\n");
-			goto sidout;
-		}
-		plen &= OHCI_SID_CNT_MASK;
-		if (plen < 4 || plen > OHCI_SIDSIZE) {
-			device_printf(fc->dev, "invalid SID len = %d\n", plen);
-			goto sidout;
-		}
-		plen -= 4; /* chop control info */
-		buf = (uint32_t *)malloc(OHCI_SIDSIZE, M_FW, M_NOWAIT);
-		if (buf == NULL) {
-			device_printf(fc->dev, "malloc failed\n");
-			goto sidout;
-		}
-		for (i = 0; i < plen / 4; i ++)
-			buf[i] = FWOHCI_DMA_READ(sc->sid_buf[i+1]);
-#if 1 /* XXX needed?? */
-		/* pending all pre-bus_reset packets */
-		fwohci_txd(sc, &sc->atrq);
-		fwohci_txd(sc, &sc->atrs);
-		fwohci_arcv(sc, &sc->arrs, -1);
-		fwohci_arcv(sc, &sc->arrq, -1);
-		fw_drain_txq(fc);
-#endif
-		fw_sidrcv(fc, buf, plen);
-		free(buf, M_FW);
 	}
-sidout:
-	if((stat & OHCI_INT_DMA_ATRQ )){
-#ifndef ACK_ALL
-		OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_DMA_ATRQ);
-#endif
+	if (stat & OHCI_INT_DMA_ATRQ) {
 		fwohci_txd(sc, &(sc->atrq));
 	}
-	if((stat & OHCI_INT_DMA_ATRS )){
-#ifndef ACK_ALL
-		OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_DMA_ATRS);
-#endif
+	if (stat & OHCI_INT_DMA_ATRS) {
 		fwohci_txd(sc, &(sc->atrs));
 	}
-	if((stat & OHCI_INT_PW_ERR )){
-#ifndef ACK_ALL
-		OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_PW_ERR);
-#endif
+	if (stat & OHCI_INT_PW_ERR) {
 		device_printf(fc->dev, "posted write error\n");
 	}
-	if((stat & OHCI_INT_ERR )){
-#ifndef ACK_ALL
-		OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_ERR);
-#endif
+	if (stat & OHCI_INT_ERR) {
 		device_printf(fc->dev, "unrecoverable error\n");
 	}
-	if((stat & OHCI_INT_PHY_INT)) {
-#ifndef ACK_ALL
-		OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_PHY_INT);
-#endif
+	if (stat & OHCI_INT_PHY_INT) {
 		device_printf(fc->dev, "phy int\n");
 	}
 
 	return;
 }
 
-#if FWOHCI_TASKQUEUE
 static void
-fwohci_complete(void *arg, int pending)
+fwohci_task_busreset(void *arg, int pending)
+{
+	struct fwohci_softc *sc = (struct fwohci_softc *)arg;
+
+	fw_busreset(&sc->fc, FWBUSRESET);
+	OWRITE(sc, OHCI_CROMHDR, ntohl(sc->fc.config_rom[0]));
+	OWRITE(sc, OHCI_BUS_OPT, ntohl(sc->fc.config_rom[2]));
+}
+
+static void
+fwohci_task_sid(void *arg, int pending)
+{
+	struct fwohci_softc *sc = (struct fwohci_softc *)arg;
+	struct firewire_comm *fc = &sc->fc;
+	uint32_t *buf;
+	int i, plen;
+
+
+	plen = OREAD(sc, OHCI_SID_CNT);
+
+	if (plen & OHCI_SID_ERR) {
+		device_printf(fc->dev, "SID Error\n");
+		return;
+	}
+	plen &= OHCI_SID_CNT_MASK;
+	if (plen < 4 || plen > OHCI_SIDSIZE) {
+		device_printf(fc->dev, "invalid SID len = %d\n", plen);
+		return;
+	}
+	plen -= 4; /* chop control info */
+	buf = (uint32_t *)malloc(OHCI_SIDSIZE, M_FW, M_NOWAIT);
+	if (buf == NULL) {
+		device_printf(fc->dev, "malloc failed\n");
+		return;
+	}
+	for (i = 0; i < plen / 4; i ++)
+		buf[i] = FWOHCI_DMA_READ(sc->sid_buf[i+1]);
+#if 1 /* XXX needed?? */
+	/* pending all pre-bus_reset packets */
+	fwohci_txd(sc, &sc->atrq);
+	fwohci_txd(sc, &sc->atrs);
+	fwohci_arcv(sc, &sc->arrs, -1);
+	fwohci_arcv(sc, &sc->arrq, -1);
+	fw_drain_txq(fc);
+#endif
+	fw_sidrcv(fc, buf, plen);
+	free(buf, M_FW);
+}
+
+static void
+fwohci_task_dma(void *arg, int pending)
 {
 	struct fwohci_softc *sc = (struct fwohci_softc *)arg;
 	uint32_t stat;
@@ -1993,15 +2051,14 @@
 again:
 	stat = atomic_readandclear_int(&sc->intstat);
 	if (stat)
-		fwohci_intr_body(sc, stat, -1);
+		fwohci_intr_dma(sc, stat, -1);
 	else
 		return;
 	goto again;
 }
-#endif
 
-static uint32_t
-fwochi_check_stat(struct fwohci_softc *sc)
+static int
+fwohci_check_stat(struct fwohci_softc *sc)
 {
 	uint32_t stat, irstat, itstat;
 
@@ -2009,12 +2066,16 @@
 	if (stat == 0xffffffff) {
 		device_printf(sc->fc.dev, 
 			"device physically ejected?\n");
-		return(stat);
+		return (FILTER_STRAY);
 	}
-#ifdef ACK_ALL
 	if (stat)
-		OWRITE(sc, FWOHCI_INTSTATCLR, stat);
-#endif
+		OWRITE(sc, FWOHCI_INTSTATCLR, stat & ~OHCI_INT_PHY_BUS_R);
+
+	stat &= sc->intmask;
+	if (stat == 0)
+		return (FILTER_STRAY);
+
+	atomic_set_int(&sc->intstat, stat);
 	if (stat & OHCI_INT_DMA_IR) {
 		irstat = OREAD(sc, OHCI_IR_STAT);
 		OWRITE(sc, OHCI_IR_STATCLR, irstat);
@@ -2025,68 +2086,34 @@
 		OWRITE(sc, OHCI_IT_STATCLR, itstat);
 		atomic_set_int(&sc->itstat, itstat);
 	}
-	return(stat);
+
+	fwohci_intr_core(sc, stat, -1);
+	return (FILTER_HANDLED);
 }
 
-void
-fwohci_intr(void *arg)
+int
+fwohci_filt(void *arg)
 {
 	struct fwohci_softc *sc = (struct fwohci_softc *)arg;
-	uint32_t stat;
-#if !FWOHCI_TASKQUEUE
-	uint32_t bus_reset = 0;
-#endif
 
 	if (!(sc->intmask & OHCI_INT_EN)) {
 		/* polling mode */
-		return;
+		return (FILTER_STRAY);
 	}
+	return (fwohci_check_stat(sc));
+}
 
-#if !FWOHCI_TASKQUEUE
-again:
-#endif
-	stat = fwochi_check_stat(sc);
-	if (stat == 0 || stat == 0xffffffff)
-		return;
-#if FWOHCI_TASKQUEUE
-	atomic_set_int(&sc->intstat, stat);
-	/* XXX mask bus reset intr. during bus reset phase */
-	if (stat)
-		taskqueue_enqueue(taskqueue_swi_giant, &sc->fwohci_task_complete);
-#else
-	/* We cannot clear bus reset event during bus reset phase */
-	if ((stat & ~bus_reset) == 0)
-		return;
-	bus_reset = stat & OHCI_INT_PHY_BUS_R;
-	fwohci_intr_body(sc, stat, -1);
-	goto again;
-#endif
+void
+fwohci_intr(void *arg)
+{
+	fwohci_filt(arg);
 }
 
 void
 fwohci_poll(struct firewire_comm *fc, int quick, int count)
 {
-	int s;
-	uint32_t stat;
-	struct fwohci_softc *sc;
-
-
-	sc = (struct fwohci_softc *)fc;
-	stat = OHCI_INT_DMA_IR | OHCI_INT_DMA_IT |
-		OHCI_INT_DMA_PRRS | OHCI_INT_DMA_PRRQ |
-		OHCI_INT_DMA_ATRQ | OHCI_INT_DMA_ATRS;
-#if 0
-	if (!quick) {
-#else
-	if (1) {
-#endif
-		stat = fwochi_check_stat(sc);
-		if (stat == 0 || stat == 0xffffffff)
-			return;
-	}
-	s = splfw();
-	fwohci_intr_body(sc, stat, count);
-	splx(s);
+	struct fwohci_softc *sc = (struct fwohci_softc *)fc;
+	fwohci_check_stat(sc);
 }
 
 static void
@@ -2119,6 +2146,7 @@
 	it = fc->it[dmach];
 	ldesc = sc->it[dmach].ndesc - 1;
 	s = splfw(); /* unnecessary ? */
+	FW_GLOCK(fc);
 	fwdma_sync_multiseg_all(sc->it[dmach].am, BUS_DMASYNC_POSTREAD);
 	if (firewire_debug)
 		dump_db(sc, ITX_CH + dmach);
@@ -2147,6 +2175,7 @@
 		STAILQ_INSERT_TAIL(&it->stfree, chunk, link);
 		w++;
 	}
+	FW_GUNLOCK(fc);
 	splx(s);
 	if (w)
 		wakeup(it);
@@ -2160,14 +2189,17 @@
 	struct fw_bulkxfer *chunk;
 	struct fw_xferq *ir;
 	uint32_t stat;
-	int s, w=0, ldesc;
+	int s, w = 0, ldesc;
 
 	ir = fc->ir[dmach];
 	ldesc = sc->ir[dmach].ndesc - 1;
+
 #if 0
 	dump_db(sc, dmach);
 #endif
 	s = splfw();
+	if ((ir->flag & FWXFERQ_HANDLER) == 0)
+		FW_GLOCK(fc);
 	fwdma_sync_multiseg_all(sc->ir[dmach].am, BUS_DMASYNC_POSTREAD);
 	while ((chunk = STAILQ_FIRST(&ir->stdma)) != NULL) {
 		db_tr = (struct fwohcidb_tr *)chunk->end;
@@ -2202,13 +2234,16 @@
 		}
 		w++;
 	}
+	if ((ir->flag & FWXFERQ_HANDLER) == 0)
+		FW_GUNLOCK(fc);
 	splx(s);
-	if (w) {
-		if (ir->flag & FWXFERQ_HANDLER) 
-			ir->hand(ir);
-		else
-			wakeup(ir);
-	}
+	if (w == 0)
+		return;
+
+	if (ir->flag & FWXFERQ_HANDLER) 
+		ir->hand(ir);
+	else
+		wakeup(ir);
 }
 
 void
@@ -2465,6 +2500,8 @@
 	unsigned short chtag;
 	int idb;
 
+	FW_GLOCK_ASSERT(&sc->fc);
+
 	dbch = &sc->it[dmach];
 	chtag = sc->it[dmach].xferq.flag & 0xff;
 
@@ -2661,13 +2698,16 @@
 	if ((info->flag & FWTI_BLOCK_ASY) != 0)
 		r += roundup2(fp->mode.wreqb.len, sizeof(uint32_t));
 
-	if (r == sizeof(uint32_t))
+	if (r == sizeof(uint32_t)) {
 		/* XXX */
 		device_printf(sc->fc.dev, "Unknown tcode %d\n",
 						fp->mode.common.tcode);
+		return (-1);
+	}
 
 	if (r > dbch->xferq.psize) {
 		device_printf(sc->fc.dev, "Invalid packet length %d\n", r);
+		return (-1);
 		/* panic ? */
 	}
 
@@ -2675,7 +2715,8 @@
 }
 
 static void
-fwohci_arcv_free_buf(struct fwohci_dbch *dbch, struct fwohcidb_tr *db_tr)
+fwohci_arcv_free_buf(struct fwohci_softc *sc, struct fwohci_dbch *dbch,
+    struct fwohcidb_tr *db_tr, uint32_t off, int wake)
 {
 	struct fwohcidb *db = &db_tr->db[0];
 
@@ -2684,6 +2725,9 @@
 	FWOHCI_DMA_SET(dbch->bottom->db[0].db.desc.depend, 1);
 	fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREWRITE);
 	dbch->bottom = db_tr;
+
+	if (wake)
+		OWRITE(sc, OHCI_DMACTL(off), OHCI_CNTL_DMA_WAKE);
 }
 
 static void
@@ -2695,7 +2739,7 @@
 	int nvec;
 	struct fw_pkt *fp;
 	uint8_t *ld;
-	uint32_t stat, off, status;
+	uint32_t stat, off, status, event;
 	u_int spd;
 	int len, plen, hlen, pcnt, offset;
 	int s;
@@ -2718,10 +2762,13 @@
 	fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_POSTWRITE);
 	status = FWOHCI_DMA_READ(db_tr->db[0].db.desc.res) >> OHCI_STATUS_SHIFT;
 	resCount = FWOHCI_DMA_READ(db_tr->db[0].db.desc.res) & OHCI_COUNT_MASK;
+	while (status & OHCI_CNTL_DMA_ACTIVE) {
 #if 0
-	printf("status 0x%04x, resCount 0x%04x\n", status, resCount);
+
+		if (off == OHCI_ARQOFF)
+			printf("buf 0x%08x, status 0x%04x, resCount 0x%04x\n",
+			    db_tr->bus_addr, status, resCount);
 #endif
-	while (status & OHCI_CNTL_DMA_ACTIVE) {
 		len = dbch->xferq.psize - resCount;
 		ld = (uint8_t *)db_tr->buf;
 		if (dbch->pdb_tr == NULL) {
@@ -2761,8 +2808,9 @@
 					ld += rlen;
 					len -= rlen;
 					hlen = fwohci_arcv_swap(&pktbuf, sizeof(pktbuf));
-					if (hlen < 0) {
-						printf("hlen < 0 shouldn't happen");
+					if (hlen <= 0) {
+						printf("hlen should be positive.");
+						goto err;
 					}
 					offset = sizeof(pktbuf);
 					vec[0].iov_base = (char *)&pktbuf;
@@ -2780,16 +2828,16 @@
 				fp=(struct fw_pkt *)ld;
 				hlen = fwohci_arcv_swap(fp, len);
 				if (hlen == 0)
-					/* XXX need reset */
-					goto out;
+					goto err;
 				if (hlen < 0) {
 					dbch->pdb_tr = db_tr;
 					dbch->buf_offset = - dbch->buf_offset;
 					/* sanity check */
-					if (resCount != 0) 
-						printf("resCount = %d !?\n",
-						    resCount);
-					/* XXX clear pdb_tr */
+					if (resCount != 0)  {
+						printf("resCount=%d hlen=%d\n",
+						    resCount, hlen);
+						    goto err;
+					}
 					goto out;
 				}
 				offset = 0;
@@ -2801,8 +2849,7 @@
 				= sizeof(fw_pkt) so this shouldn't happens */
 				printf("plen(%d) is negative! offset=%d\n",
 				    plen, offset);
-				/* XXX clear pdb_tr */
-				goto out;
+				goto err;
 			}
 			if (plen > 0) {
 				len -= plen;
@@ -2811,10 +2858,12 @@
 					if (firewire_debug)
 						printf("splitted payload\n");
 					/* sanity check */
-					if (resCount != 0) 
-						printf("resCount = %d !?\n",
-						    resCount);
-					/* XXX clear pdb_tr */
+					if (resCount != 0)  {
+						printf("resCount=%d plen=%d"
+						    " len=%d\n",
+						    resCount, plen, len);
+						goto err;
+					}
 					goto out;
 				}
 				vec[nvec].iov_base = ld;
@@ -2827,18 +2876,14 @@
 				printf("nvec == 0\n");
 
 /* DMA result-code will be written at the tail of packet */
-#if BYTE_ORDER == BIG_ENDIAN
-			stat = FWOHCI_DMA_READ(((struct fwohci_trailer *)(ld - sizeof(struct fwohci_trailer)))->stat) >> 16;
-#else
-			stat = ((struct fwohci_trailer *)(ld - sizeof(struct fwohci_trailer)))->stat;
-#endif
+			stat = FWOHCI_DMA_READ(*(uint32_t *)(ld - sizeof(struct fwohci_trailer)));
 #if 0
 			printf("plen: %d, stat %x\n",
 			    plen ,stat);
 #endif
-			spd = (stat >> 5) & 0x3;
-			stat &= 0x1f;
-			switch(stat){
+			spd = (stat >> 21) & 0x3;
+			event = (stat >> 16) & 0x1f;
+			switch (event) {
 			case FWOHCIEV_ACKPEND:
 #if 0
 				printf("fwohci_arcv: ack pending tcode=0x%x..\n", fp->mode.common.tcode);
@@ -2859,19 +2904,28 @@
 				break;
 			}
 			case FWOHCIEV_BUSRST:
-				if (sc->fc.status != FWBUSRESET) 
+				if ((sc->fc.status != FWBUSRESET) &&
+				    (sc->fc.status != FWBUSINIT))
 					printf("got BUSRST packet!?\n");
 				break;
 			default:
-				device_printf(sc->fc.dev, "Async DMA Receive error err = %02x %s\n", stat, fwohcicode[stat]);
-#if 0 /* XXX */
-				goto out;
+				device_printf(sc->fc.dev,
+				    "Async DMA Receive error err=%02x %s"
+				    " plen=%d offset=%d len=%d status=0x%08x"
+				    " tcode=0x%x, stat=0x%08x\n",
+				    event, fwohcicode[event], plen,
+				    dbch->buf_offset, len,
+				    OREAD(sc, OHCI_DMACTL(off)),
+				    fp->mode.common.tcode, stat);
+#if 1 /* XXX */
+				goto err;
 #endif
 				break;
 			}
 			pcnt ++;
 			if (dbch->pdb_tr != NULL) {
-				fwohci_arcv_free_buf(dbch, dbch->pdb_tr);
+				fwohci_arcv_free_buf(sc, dbch, dbch->pdb_tr,
+				    off, 1);
 				dbch->pdb_tr = NULL;
 			}
 
@@ -2880,7 +2934,7 @@
 		if (resCount == 0) {
 			/* done on this buffer */
 			if (dbch->pdb_tr == NULL) {
-				fwohci_arcv_free_buf(dbch, db_tr);
+				fwohci_arcv_free_buf(sc, dbch, db_tr, off, 1);
 				dbch->buf_offset = 0;
 			} else
 				if (dbch->pdb_tr != db_tr)
@@ -2903,4 +2957,24 @@
 		printf("fwohci_arcv: no packets\n");
 #endif
 	splx(s);
+	return;
+
+err:
+	device_printf(sc->fc.dev, "AR DMA status=%x, ",
+					OREAD(sc, OHCI_DMACTL(off)));
+	dbch->pdb_tr = NULL;
+	/* skip until resCount != 0 */
+	printf(" skip buffer");
+	while (resCount == 0) {
+		printf(" #");
+		fwohci_arcv_free_buf(sc, dbch, db_tr, off, 0);
+		db_tr = STAILQ_NEXT(db_tr, link);
+		resCount = FWOHCI_DMA_READ(db_tr->db[0].db.desc.res)
+						& OHCI_COUNT_MASK;
+	} while (resCount == 0)
+	printf(" done\n");
+	dbch->top = db_tr;
+	dbch->buf_offset = dbch->xferq.psize - resCount;
+	OWRITE(sc, OHCI_DMACTL(off), OHCI_CNTL_DMA_WAKE);
+	splx(s);
 }
Index: sbp_targ.c
===================================================================
RCS file: /home/cvs/src/sys/dev/firewire/sbp_targ.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/dev/firewire/sbp_targ.c -L sys/dev/firewire/sbp_targ.c -u -r1.1.1.1 -r1.2
--- sys/dev/firewire/sbp_targ.c
+++ sys/dev/firewire/sbp_targ.c
@@ -31,7 +31,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  * 
- * $FreeBSD: src/sys/dev/firewire/sbp_targ.c,v 1.8 2005/01/06 01:42:41 imp Exp $
+ * $FreeBSD: src/sys/dev/firewire/sbp_targ.c,v 1.16 2007/06/17 05:55:50 scottl Exp $
  */
 
 #include <sys/param.h>
@@ -140,7 +140,10 @@
 	struct sbp_targ_lstate *lstate[MAX_LUN];
 	struct sbp_targ_lstate *black_hole;
 	struct sbp_targ_login *logins[MAX_LOGINS];
+	struct mtx mtx;
 };
+#define SBP_LOCK(sc) mtx_lock(&(sc)->mtx)
+#define SBP_UNLOCK(sc) mtx_unlock(&(sc)->mtx)
 
 struct corb4 {
 #if BYTE_ORDER == BIG_ENDIAN
@@ -215,6 +218,7 @@
 static void sbp_targ_recv(struct fw_xfer *);
 static void sbp_targ_fetch_orb(struct sbp_targ_softc *, struct fw_device *,
     uint16_t, uint32_t, struct sbp_targ_login *, int);
+static void sbp_targ_abort(struct sbp_targ_softc *, struct orb_info *);
 
 static void
 sbp_targ_identify(driver_t *driver, device_t parent)
@@ -289,8 +293,10 @@
 	unit = &sc->unit;
 
 	if ((sc->flags & F_FREEZED) == 0) {
+		SBP_LOCK(sc);
 		sc->flags |= F_FREEZED;
 		xpt_freeze_simq(sc->sim, /*count*/1);
+		SBP_UNLOCK(sc);
 	} else {
 		printf("%s: already freezed\n", __func__);
 	}
@@ -321,6 +327,7 @@
 		login = sc->logins[i];
 		if (login == NULL)
 			continue;
+		sbp_targ_abort(sc, STAILQ_FIRST(&login->orbs));
 		if (login->flags & F_LOGIN) {
 			login->flags |= F_HOLD;
 			callout_reset(&login->hold_callout,
@@ -336,8 +343,10 @@
 	struct sbp_targ_softc *sc;
 
 	sc = (struct sbp_targ_softc *)arg;
+	SBP_LOCK(sc);
 	sc->flags &= ~F_FREEZED;
 	xpt_release_simq(sc->sim, /*run queue*/TRUE);
+	SBP_UNLOCK(sc);
 	return;
 }
 
@@ -484,10 +493,19 @@
 #endif
 }
 
+
+static __inline void
+sbp_targ_remove_orb_info_locked(struct sbp_targ_login *login, struct orb_info *orbi)
+{
+	STAILQ_REMOVE(&login->orbs, orbi, orb_info, link);
+}
+
 static __inline void
 sbp_targ_remove_orb_info(struct sbp_targ_login *login, struct orb_info *orbi)
 {
+	SBP_LOCK(orbi->sc);
 	STAILQ_REMOVE(&login->orbs, orbi, orb_info, link);
+	SBP_UNLOCK(orbi->sc);
 }
 
 /*
@@ -518,19 +536,21 @@
 	STAILQ_FOREACH(orbi, &login->orbs, link)
 		if (orbi->orb_lo == tag_id)
 			goto found;
-	printf("%s: orb not found tag_id=0x%08x\n", __func__, tag_id);
+	printf("%s: orb not found tag_id=0x%08x init_id=%d\n",
+				 __func__, tag_id, init_id);
 	return (NULL);
 found:
 	return (orbi);
 }
 
 static void
-sbp_targ_abort(struct orb_info *orbi)
+sbp_targ_abort(struct sbp_targ_softc *sc, struct orb_info *orbi)
 {
 	struct orb_info *norbi;
 
+	SBP_LOCK(sc);
 	for (; orbi != NULL; orbi = norbi) {
-		printf("%s: status=%d\n", __func__, orbi->state);
+		printf("%s: status=%d ccb=%p\n", __func__, orbi->state, orbi->ccb);
 		norbi = STAILQ_NEXT(orbi, link);
 		if (orbi->state != ORBI_STATUS_ABORTED) {
 			if (orbi->ccb != NULL) {
@@ -538,13 +558,16 @@
 				xpt_done(orbi->ccb);
 				orbi->ccb = NULL;
 			}
+#if 0
 			if (orbi->state <= ORBI_STATUS_ATIO) {
-				sbp_targ_remove_orb_info(orbi->login, orbi);
+				sbp_targ_remove_orb_info_locked(orbi->login, orbi);
 				free(orbi, M_SBP_TARG);
 			} else
+#endif
 				orbi->state = ORBI_STATUS_ABORTED;
 		}
 	}
+	SBP_UNLOCK(sc);
 }
 
 static void
@@ -585,6 +608,9 @@
 sbp_targ_send_status(struct orb_info *orbi, union ccb *ccb)
 {
 	struct sbp_status *sbp_status;
+#if	0
+	struct orb_info *norbi;
+#endif
 
 	sbp_status = &orbi->status;
 
@@ -614,7 +640,24 @@
 		sbp_cmd_status->status = ccb->csio.scsi_status;
 		sense = &ccb->csio.sense_data;
 
-		sbp_targ_abort(STAILQ_NEXT(orbi, link));
+#if 0		/* XXX What we should do? */
+#if 0
+		sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link));
+#else
+		norbi = STAILQ_NEXT(orbi, link);
+		while (norbi) {
+			printf("%s: status=%d\n", __func__, norbi->state);
+			if (norbi->ccb != NULL) {
+				norbi->ccb->ccb_h.status = CAM_REQ_ABORTED;
+				xpt_done(norbi->ccb);
+				norbi->ccb = NULL;
+			}
+			sbp_targ_remove_orb_info_locked(orbi->login, norbi);
+			norbi = STAILQ_NEXT(norbi, link);
+			free(norbi, M_SBP_TARG);
+		}
+#endif
+#endif
 
 		if ((sense->error_code & SSD_ERRCODE) == SSD_CURRENT_ERROR)
 			sbp_cmd_status->sfmt = SBP_SFMT_CURR;
@@ -653,11 +696,11 @@
 		    sbp_status->status);
 	}
 
-	sbp_targ_status_FIFO(orbi,
-	    orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/1);
-
 	if (orbi->page_table != NULL)
 		free(orbi->page_table, M_SBP_TARG);
+
+	sbp_targ_status_FIFO(orbi,
+	    orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/1);
 }
 
 static void
@@ -677,13 +720,14 @@
 		orbi->status.resp = SBP_TRANS_FAIL;
 		orbi->status.status = OBJ_DATA | SBE_TIMEOUT/*XXX*/;
 		orbi->status.dead = 1;
-		sbp_targ_abort(STAILQ_NEXT(orbi, link));
+		sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link));
 	}
 
 	orbi->refcount --;
 
 	ccb = orbi->ccb;
 	if (orbi->refcount == 0) {
+		orbi->ccb = NULL;
 		if (orbi->state == ORBI_STATUS_ABORTED) {
 			if (debug)
 				printf("%s: orbi aborted\n", __func__);
@@ -695,14 +739,18 @@
 			if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0)
 				sbp_targ_send_status(orbi, ccb);
 			ccb->ccb_h.status = CAM_REQ_CMP;
+			SBP_LOCK(orbi->sc);
 			xpt_done(ccb);
+			SBP_UNLOCK(orbi->sc);
 		} else {
 			orbi->status.len = 1;
 			sbp_targ_status_FIFO(orbi,
 		    	    orbi->login->fifo_hi, orbi->login->fifo_lo,
 			    /*dequeue*/1);
 			ccb->ccb_h.status = CAM_REQ_ABORTED;
+			SBP_LOCK(orbi->sc);
 			xpt_done(ccb);
+			SBP_UNLOCK(orbi->sc);
 		}
 	}
 
@@ -823,7 +871,7 @@
 		orbi->status.status = OBJ_PT | SBE_TIMEOUT/*XXX*/;
 		orbi->status.dead = 1;
 		orbi->status.len = 1;
-		sbp_targ_abort(STAILQ_NEXT(orbi, link));
+		sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link));
 
 		sbp_targ_status_FIFO(orbi,
 		    orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/1);
@@ -901,7 +949,8 @@
 		struct orb_info *orbi;
 
 		if (debug)
-			printf("%s: XPT_CONT_TARGET_IO\n", __func__);
+			printf("%s: XPT_CONT_TARGET_IO (0x%08x)\n",
+					 __func__, ccb->csio.tag_id);
 
 		if (status != CAM_REQ_CMP) {
 			ccb->ccb_h.status = status;
@@ -919,8 +968,10 @@
 		if (orbi->state == ORBI_STATUS_ABORTED) {
 			if (debug)
 				printf("%s: ctio aborted\n", __func__);
-			sbp_targ_remove_orb_info(orbi->login, orbi);
+			sbp_targ_remove_orb_info_locked(orbi->login, orbi);
 			free(orbi, M_SBP_TARG);
+			ccb->ccb_h.status = CAM_REQ_ABORTED;
+			xpt_done(ccb);
 			break;
 		}
 		orbi->state = ORBI_STATUS_CTIO;
@@ -966,8 +1017,12 @@
 			    sbp_targ_cam_done);
 
 		if (ccb_dir == CAM_DIR_NONE) {
-			if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0)
+			if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) {
+				/* XXX */
+				SBP_UNLOCK(sc);
 				sbp_targ_send_status(orbi, ccb);
+				SBP_LOCK(sc);
+			}
 			ccb->ccb_h.status = CAM_REQ_CMP;
 			xpt_done(ccb);
 		}
@@ -1106,7 +1161,7 @@
 		orbi->status.status = OBJ_ORB | SBE_TIMEOUT/*XXX*/;
 		orbi->status.dead = 1;
 		orbi->status.len = 1;
-		sbp_targ_abort(STAILQ_NEXT(orbi, link));
+		sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link));
 
 		sbp_targ_status_FIFO(orbi,
 		    orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/1);
@@ -1115,10 +1170,16 @@
 	}
 	fp = &xfer->recv.hdr;
 
+	atio = orbi->atio;
+
 	if (orbi->state == ORBI_STATUS_ABORTED) {
 		printf("%s: aborted\n", __func__);
 		sbp_targ_remove_orb_info(orbi->login, orbi);
 		free(orbi, M_SBP_TARG);
+		atio->ccb_h.status = CAM_REQ_ABORTED;
+		SBP_LOCK(orbi->sc);
+		xpt_done((union ccb*)atio);
+		SBP_UNLOCK(orbi->sc);
 		goto done0;
 	}
 	orbi->state = ORBI_STATUS_ATIO;
@@ -1134,7 +1195,6 @@
 		printf("%s: rq_fmt(%d) != 0\n", __func__, orb4->rq_fmt);
 	}
 
-	atio = orbi->atio;
 	atio->ccb_h.target_id = 0; /* XXX */
 	atio->ccb_h.target_lun = orbi->login->lstate->lun;
 	atio->sense_len = 0;
@@ -1143,10 +1203,10 @@
 	atio->init_id = orbi->login->id;
 
 	atio->ccb_h.flags = CAM_TAG_ACTION_VALID;
-	bytes = (char *)&orb[5];
+	bytes = (u_char *)&orb[5];
 	if (debug)
-		printf("%s: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
-		    __func__,
+		printf("%s: %p %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+		    __func__, (void *)atio,
 		    bytes[0], bytes[1], bytes[2], bytes[3], bytes[4],
 		    bytes[5], bytes[6], bytes[7], bytes[8], bytes[9]);
 	switch (bytes[0] >> 5) {
@@ -1191,7 +1251,9 @@
 	orbi->data_lo = orb[3];
 	orbi->orb4 = *orb4;
 
+	SBP_LOCK(orbi->sc);
 	xpt_done((union ccb*)atio);
+	SBP_UNLOCK(orbi->sc);
 done0:
 	fw_xfer_free(xfer);
 	return;
@@ -1226,6 +1288,7 @@
 		return (NULL);
 	}
 
+	login->id = i;
 	login->fwdev = fwdev;
 	login->lstate = lstate;
 	login->last_hi = 0xffff;
@@ -1255,7 +1318,7 @@
 		orbi->status.status = OBJ_ORB | SBE_TIMEOUT/*XXX*/;
 		orbi->status.dead = 1;
 		orbi->status.len = 1;
-		sbp_targ_abort(STAILQ_NEXT(orbi, link));
+		sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link));
 
 		sbp_targ_status_FIFO(orbi,
 		    orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/0);
@@ -1308,6 +1371,7 @@
 			orbi->status.len = 1;
 			break;
 		}
+		printf("%s: login id=%d\n", __func__, login->id);
 
 		login->fifo_hi = orb[6];
 		login->fifo_lo = orb[7];
@@ -1317,10 +1381,10 @@
 		login->loginres.cmd_lo = htonl(SBP_TARG_BIND_LO(login->id));
 		login->loginres.recon_hold = htons(login->hold_sec);
 
+		STAILQ_INSERT_TAIL(&lstate->logins, login, link);
 		fwmem_write_block(orbi->fwdev, NULL, /*spd*/2, orb[2], orb[3],
 		    sizeof(struct sbp_login_res), (void *)&login->loginres,
 		    fw_asy_callback_free);
-		STAILQ_INSERT_TAIL(&lstate->logins, login, link);
 		/* XXX return status after loginres is successfully written */
 		break;
 	}
@@ -1417,9 +1481,11 @@
 		login->last_lo = orb_lo;
 		login->flags |= F_LINK_ACTIVE;
 		/* dequeue */
+		SBP_LOCK(sc);
 		orbi->atio = (struct ccb_accept_tio *)
 		    SLIST_FIRST(&login->lstate->accept_tios);
 		if (orbi->atio == NULL) {
+			SBP_UNLOCK(sc);
 			printf("%s: no free atio\n", __func__);
 			login->lstate->flags |= F_ATIO_STARVED;
 			login->flags |= F_ATIO_STARVED;
@@ -1430,10 +1496,11 @@
 			break;
 		}
 		SLIST_REMOVE_HEAD(&login->lstate->accept_tios, sim_links.sle);
+		STAILQ_INSERT_TAIL(&login->orbs, orbi, link);
+		SBP_UNLOCK(sc);
 		fwmem_read_block(fwdev, (void *)orbi, /*spd*/2, orb_hi, orb_lo,
 		    sizeof(uint32_t) * 8, &orbi->orb[0],
 		    sbp_targ_cmd_handler);
-		STAILQ_INSERT_TAIL(&login->orbs, orbi, link);
 		break;
 	case FETCH_POINTER:
 		orbi->state = ORBI_STATUS_POINTER;
@@ -1458,7 +1525,7 @@
 	sc = (struct sbp_targ_softc *)xfer->sc;
 	fw_xfer_unload(xfer);
 	xfer->recv.pay_len = SBP_TARG_RECV_LEN;
-	xfer->act.hand = sbp_targ_recv;
+	xfer->hand = sbp_targ_recv;
 	s = splfw();
 	STAILQ_INSERT_TAIL(&sc->fwb.xferlist, xfer, link);
 	splx(s);
@@ -1488,7 +1555,7 @@
 	switch (reg) {
 	case 0x08:	/* ORB_POINTER */
 		if (debug)
-			printf("%s: ORB_POINTER\n", __func__);
+			printf("%s: ORB_POINTER(%d)\n", __func__, login_id);
 		if ((login->flags & F_LINK_ACTIVE) != 0) {
 			if (debug)
 				printf("link active (ORB_POINTER)\n");
@@ -1501,14 +1568,14 @@
 		break;
 	case 0x04:	/* AGENT_RESET */
 		if (debug)
-			printf("%s: AGENT RESET\n", __func__);
+			printf("%s: AGENT RESET(%d)\n", __func__, login_id);
 		login->last_hi = 0xffff;
 		login->last_lo = 0xffffffff;
-		sbp_targ_abort(STAILQ_FIRST(&login->orbs));
+		sbp_targ_abort(sc, STAILQ_FIRST(&login->orbs));
 		break;
 	case 0x10:	/* DOORBELL */
 		if (debug)
-			printf("%s: DOORBELL\n", __func__);
+			printf("%s: DOORBELL(%d)\n", __func__, login_id);
 		if (login->last_hi == 0xffff &&
 		    login->last_lo == 0xffffffff) {
 			printf("%s: no previous pointer(DOORBELL)\n",
@@ -1525,13 +1592,15 @@
 		    login, FETCH_POINTER);
 		break;
 	case 0x00:	/* AGENT_STATE */
-		printf("%s: AGENT_STATE (ignore)\n", __func__);
+		printf("%s: AGENT_STATE (%d:ignore)\n", __func__, login_id);
 		break;
 	case 0x14:	/* UNSOLICITED_STATE_ENABLE */
-		printf("%s: UNSOLICITED_STATE_ENABLE (ignore)\n", __func__);
+		printf("%s: UNSOLICITED_STATE_ENABLE (%d:ignore)\n",
+							 __func__, login_id);
 		break;
 	default:
-		printf("%s: invalid register %d\n", __func__, reg);
+		printf("%s: invalid register %d(%d)\n",
+						 __func__, reg, login_id);
 		rtcode = RESP_ADDRESS_ERROR;
 	}
 
@@ -1560,7 +1629,6 @@
 	return(0);
 }
 
-
 static void
 sbp_targ_recv(struct fw_xfer *xfer)
 {
@@ -1581,6 +1649,7 @@
 		goto done;
 	}
 	lo = fp->mode.wreqb.dest_lo;
+
 	if (lo == SBP_TARG_BIND_LO(-1))
 		rtcode = sbp_targ_mgm(xfer, fwdev);
 	else if (lo >= SBP_TARG_BIND_LO(0))
@@ -1594,8 +1663,7 @@
 		printf("%s: rtcode = %d\n", __func__, rtcode);
 	sfp = &xfer->send.hdr;
 	xfer->send.spd = 2; /* XXX */
-	xfer->act.hand = sbp_targ_resp_callback;
-	xfer->retry_req = fw_asybusy;
+	xfer->hand = sbp_targ_resp_callback;
 	sfp->mode.wres.dst = fp->mode.wreqb.src;
 	sfp->mode.wres.tlrt = fp->mode.wreqb.tlrt;
 	sfp->mode.wres.tcode = FWTCODE_WRES;
@@ -1611,30 +1679,31 @@
 {
 	struct sbp_targ_softc *sc;
 	struct cam_devq *devq;
-	struct fw_xfer *xfer;
-	int i;
+	struct firewire_comm *fc;
 
         sc = (struct sbp_targ_softc *) device_get_softc(dev);
 	bzero((void *)sc, sizeof(struct sbp_targ_softc));
 
-	sc->fd.fc = device_get_ivars(dev);
+	mtx_init(&sc->mtx, "sbp_targ", NULL, MTX_DEF);
+	sc->fd.fc = fc = device_get_ivars(dev);
 	sc->fd.dev = dev;
 	sc->fd.post_explore = (void *) sbp_targ_post_explore;
 	sc->fd.post_busreset = (void *) sbp_targ_post_busreset;
 
-        devq = cam_simq_alloc(/*maxopenings*/1);
+        devq = cam_simq_alloc(/*maxopenings*/MAX_LUN*MAX_INITIATORS);
 	if (devq == NULL)
 		return (ENXIO);
 
 	sc->sim = cam_sim_alloc(sbp_targ_action, sbp_targ_poll,
-	    "sbp_targ", sc, device_get_unit(dev),
+	    "sbp_targ", sc, device_get_unit(dev), &sc->mtx,
 	    /*untagged*/ 1, /*tagged*/ 1, devq);
 	if (sc->sim == NULL) {
 		cam_simq_free(devq);
 		return (ENXIO);
 	}
 
-	if (xpt_bus_register(sc->sim, /*bus*/0) != CAM_SUCCESS)
+	SBP_LOCK(sc);
+	if (xpt_bus_register(sc->sim, dev, /*bus*/0) != CAM_SUCCESS)
 		goto fail;
 
 	if (xpt_create_path(&sc->path, /*periph*/ NULL, cam_sim_path(sc->sim),
@@ -1642,26 +1711,21 @@
 		xpt_bus_deregister(cam_sim_path(sc->sim));
 		goto fail;
 	}
+	SBP_UNLOCK(sc);
 
 	sc->fwb.start = SBP_TARG_BIND_START;
 	sc->fwb.end = SBP_TARG_BIND_END;
-	sc->fwb.act_type = FWACT_XFER;
 
 	/* pre-allocate xfer */
 	STAILQ_INIT(&sc->fwb.xferlist);
-	for (i = 0; i < MAX_LUN /* XXX */; i ++) {
-		xfer = fw_xfer_alloc_buf(M_SBP_TARG,
-			/* send */ 0,
-			/* recv */ SBP_TARG_RECV_LEN);
-		xfer->act.hand = sbp_targ_recv;
-		xfer->fc = sc->fd.fc;
-		xfer->sc = (caddr_t)sc;
-		STAILQ_INSERT_TAIL(&sc->fwb.xferlist, xfer, link);
-	}
-	fw_bindadd(sc->fd.fc, &sc->fwb);
+	fw_xferlist_add(&sc->fwb.xferlist, M_SBP_TARG,
+	    /*send*/ 0, /*recv*/ SBP_TARG_RECV_LEN, MAX_LUN /* XXX */,
+	    fc, (void *)sc, sbp_targ_recv);
+	fw_bindadd(fc, &sc->fwb);
 	return 0;
 
 fail:
+	SBP_UNLOCK(sc);
 	cam_sim_free(sc->sim, /*free_devq*/TRUE);
 	return (ENXIO);
 }
@@ -1671,14 +1735,15 @@
 {
 	struct sbp_targ_softc *sc;
 	struct sbp_targ_lstate *lstate;
-	struct fw_xfer *xfer, *next;
 	int i;
 
 	sc = (struct sbp_targ_softc *)device_get_softc(dev);
 	sc->fd.post_busreset = NULL;
 
+	SBP_LOCK(sc);
 	xpt_free_path(sc->path);
 	xpt_bus_deregister(cam_sim_path(sc->sim));
+	SBP_UNLOCK(sc);
 	cam_sim_free(sc->sim, /*free_devq*/TRUE); 
 
 	for (i = 0; i < MAX_LUN; i ++) {
@@ -1693,13 +1758,10 @@
 		free(sc->black_hole, M_SBP_TARG);
 	}
 			
-	for (xfer = STAILQ_FIRST(&sc->fwb.xferlist);
-	    xfer != NULL; xfer = next) {
-		next = STAILQ_NEXT(xfer, link);
-		fw_xfer_free_buf(xfer);
-	}
-	STAILQ_INIT(&sc->fwb.xferlist);
 	fw_bindremove(sc->fd.fc, &sc->fwb);
+	fw_xferlist_remove(&sc->fwb.xferlist);
+
+	mtx_destroy(&sc->mtx);
 
 	return 0;
 }
Index: fwmem.c
===================================================================
RCS file: /home/cvs/src/sys/dev/firewire/fwmem.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/dev/firewire/fwmem.c -L sys/dev/firewire/fwmem.c -u -r1.1.1.1 -r1.2
--- sys/dev/firewire/fwmem.c
+++ sys/dev/firewire/fwmem.c
@@ -35,7 +35,7 @@
 
 #ifdef __FreeBSD__
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/dev/firewire/fwmem.c,v 1.31 2005/01/06 01:42:41 imp Exp $");
+__FBSDID("$FreeBSD: src/sys/dev/firewire/fwmem.c,v 1.34 2007/06/06 14:31:36 simokawa Exp $");
 #endif
 
 #include <sys/param.h>
@@ -90,6 +90,7 @@
 
 struct fwmem_softc {
 	struct fw_eui64 eui;
+	struct firewire_softc *sc;
 	int refcount;
 };
 
@@ -114,8 +115,7 @@
 		xfer->send.spd = fwdev->speed;
 	else
 		xfer->send.spd = min(spd, fwdev->speed);
-	xfer->act.hand = hand;
-	xfer->retry_req = fw_asybusy;
+	xfer->hand = hand;
 	xfer->sc = sc;
 	xfer->send.pay_len = slen;
 	xfer->recv.pay_len = rlen;
@@ -277,20 +277,33 @@
 fwmem_open (struct cdev *dev, int flags, int fmt, fw_proc *td)
 {
 	struct fwmem_softc *fms;
+	struct firewire_softc *sc;
+	int unit = DEV2UNIT(dev);
+
+	sc = devclass_get_softc(firewire_devclass, unit);
+	if (sc == NULL)
+		return (ENXIO);
 
+	FW_GLOCK(sc->fc);
 	if (dev->si_drv1 != NULL) {
-		if ((flags & FWRITE) != 0)
-			return (EBUSY);
+		if ((flags & FWRITE) != 0) {
+			FW_GUNLOCK(sc->fc);
+			return(EBUSY);
+		}
+		FW_GUNLOCK(sc->fc);
 		fms = (struct fwmem_softc *)dev->si_drv1;
 		fms->refcount ++;
 	} else {
-		fms = (struct fwmem_softc *)malloc(sizeof(struct fwmem_softc),
-							M_FWMEM, M_WAITOK);
-		if (fms == NULL)
-			return ENOMEM;
-		bcopy(&fwmem_eui64, &fms->eui, sizeof(struct fw_eui64));
-		dev->si_drv1 = (void *)fms;
+		dev->si_drv1 = (void *)-1;
+		FW_GUNLOCK(sc->fc);
+		dev->si_drv1 = malloc(sizeof(struct fwmem_softc),
+						 M_FWMEM, M_WAITOK);
+		if (dev->si_drv1 == NULL)
+			return(ENOMEM);
 		dev->si_iosize_max = DFLTPHYS;
+		fms = (struct fwmem_softc *)dev->si_drv1;
+		bcopy(&fwmem_eui64, &fms->eui, sizeof(struct fw_eui64));
+		fms->sc = sc;
 		fms->refcount = 1;
 	}
 	if (fwmem_debug)
@@ -305,7 +318,10 @@
 	struct fwmem_softc *fms;
 
 	fms = (struct fwmem_softc *)dev->si_drv1;
+
+	FW_GLOCK(fms->sc->fc);
 	fms->refcount --;
+	FW_GUNLOCK(fms->sc->fc);
 	if (fwmem_debug)
 		printf("%s: refcount=%d\n", __func__, fms->refcount);
 	if (fms->refcount < 1) {
@@ -339,22 +355,18 @@
 void
 fwmem_strategy(struct bio *bp)
 {
-	struct firewire_softc *sc;
 	struct fwmem_softc *fms;
 	struct fw_device *fwdev;
 	struct fw_xfer *xfer;
 	struct cdev *dev;
-	int unit, err=0, s, iolen;
+	int err=0, s, iolen;
 
 	dev = bp->bio_dev;
 	/* XXX check request length */
 
-        unit = DEV2UNIT(dev);
-	sc = devclass_get_softc(firewire_devclass, unit);
-
 	s = splfw();
 	fms = (struct fwmem_softc *)dev->si_drv1;
-	fwdev = fw_noderesolve_eui64(sc->fc, &fms->eui);
+	fwdev = fw_noderesolve_eui64(fms->sc->fc, &fms->eui);
 	if (fwdev == NULL) {
 		if (fwmem_debug)
 			printf("fwmem: no such device ID:%08x%08x\n",
Index: firewirereg.h
===================================================================
RCS file: /home/cvs/src/sys/dev/firewire/firewirereg.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -L sys/dev/firewire/firewirereg.h -L sys/dev/firewire/firewirereg.h -u -r1.2 -r1.3
--- sys/dev/firewire/firewirereg.h
+++ sys/dev/firewire/firewirereg.h
@@ -31,7 +31,7 @@
  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  * 
- * $FreeBSD: src/sys/dev/firewire/firewirereg.h,v 1.37.2.1 2005/08/13 21:24:15 rwatson Exp $
+ * $FreeBSD: src/sys/dev/firewire/firewirereg.h,v 1.50 2007/07/20 03:42:57 simokawa Exp $
  *
  */
 
@@ -47,9 +47,13 @@
 #endif
 
 #include <sys/uio.h>
+#include <sys/mutex.h>
+#include <sys/taskqueue.h>
 
 #define	splfw splimp
 
+STAILQ_HEAD(fw_xferlist, fw_xfer);
+
 struct fw_device{
 	uint16_t dst;
 	struct fw_eui64 eui;
@@ -96,6 +100,7 @@
 #define FWTI_TLABEL	(1 << 2)
 #define FWTI_BLOCK_STR	(1 << 3)
 #define FWTI_BLOCK_ASY	(1 << 4)
+	u_char valid_res;
 };
 
 struct firewire_comm{
@@ -110,18 +115,9 @@
 	u_int irm;
 	u_int max_node;
 	u_int max_hop;
-	u_int max_asyretry;
 #define FWPHYASYST (1 << 0)
-	u_int retry_count;
-	uint32_t ongobus:10,
-		  ongonode:6,
-		  ongoaddr:16;
-	struct fw_device *ongodev;
-	struct fw_eui64 ongoeui;
-#define	FWMAXCSRDIR     16
-	SLIST_HEAD(, csrdir) ongocsr;
-	SLIST_HEAD(, csrdir) csrfree;
 	uint32_t status;
+#define	FWBUSDETACH	(-2)
 #define	FWBUSNOTREADY	(-1)
 #define	FWBUSRESET	0
 #define	FWBUSINIT	1
@@ -136,7 +132,9 @@
 	struct fw_eui64 eui;
 	struct fw_xferq
 		*arq, *atq, *ars, *ats, *it[FW_MAX_DMACH],*ir[FW_MAX_DMACH];
-	STAILQ_HEAD(, tlabel) tlabels[0x40];
+	struct fw_xferlist tlabels[0x40];
+	u_char last_tlabel[0x40];
+	struct mtx tlabel_lock;
 	STAILQ_HEAD(, fw_bind) binds;
 	STAILQ_HEAD(, fw_device) devices;
 	u_int  sid_cnt;
@@ -152,7 +150,7 @@
 	struct callout busprobe_callout;
 	struct callout bmr_callout;
 	struct callout timeout_callout;
-	struct callout retry_probe_callout;
+	struct task task_timeout;
 	uint32_t (*cyctimer) (struct  firewire_comm *);
 	void (*ibr) (struct firewire_comm *);
 	uint32_t (*set_bmr) (struct firewire_comm *, uint32_t);
@@ -168,14 +166,17 @@
 	void (*itx_post) (struct firewire_comm *, uint32_t *);
 	struct tcode_info *tcode;
 	bus_dma_tag_t dmat;
+	struct mtx mtx;
+	struct mtx wait_lock;
+	struct taskqueue *taskqueue;
+	struct proc *probe_thread;
 };
 #define CSRARC(sc, offset) ((sc)->csr_arc[(offset)/4])
 
-struct csrdir{
-	uint32_t ongoaddr;
-	uint32_t off;
-	SLIST_ENTRY(csrdir) link;
-};
+#define FW_GMTX(fc)		(&(fc)->mtx)
+#define FW_GLOCK(fc)		mtx_lock(FW_GMTX(fc))
+#define FW_GUNLOCK(fc)		mtx_unlock(FW_GMTX(fc))
+#define FW_GLOCK_ASSERT(fc)	mtx_assert(FW_GMTX(fc), MA_OWNED)
 
 struct fw_xferq {
 	int flag;
@@ -193,11 +194,10 @@
 #define FWXFERQ_WAKEUP (1 << 17)
 	void (*start) (struct firewire_comm*);
 	int dmach;
-	STAILQ_HEAD(, fw_xfer) q;
+	struct fw_xferlist q;
 	u_int queued;
 	u_int maxq;
 	u_int psize;
-	STAILQ_HEAD(, fw_bind) binds;
 	struct fwdma_alloc_multi *buf;
 	u_int bnchunk;
 	u_int bnpacket;
@@ -220,22 +220,13 @@
 	int resp;
 };
 
-struct tlabel{
-	struct fw_xfer  *xfer;
-	STAILQ_ENTRY(tlabel) link;
-};
-
 struct fw_bind{
 	u_int64_t start;
 	u_int64_t end;
-	STAILQ_HEAD(, fw_xfer) xferlist;
+	struct fw_xferlist xferlist;
 	STAILQ_ENTRY(fw_bind) fclist;
 	STAILQ_ENTRY(fw_bind) chlist;
-#define FWACT_NULL	0
-#define FWACT_XFER	2
-#define FWACT_CH	3
-	uint8_t act_type;
-	uint8_t sub;
+	void *sc;
 };
 
 struct fw_xfer{
@@ -244,20 +235,18 @@
 	struct fw_xferq *q;
 	struct timeval tv;
 	int8_t resp;
-#define FWXF_INIT 0
-#define FWXF_INQ 1
-#define FWXF_START 2
-#define FWXF_SENT 3
-#define FWXF_SENTERR 4
-#define FWXF_BUSY 8
-#define FWXF_RCVD 10
-	uint8_t state;
-	uint8_t retry;
-	uint8_t tl;
-	void (*retry_req) (struct fw_xfer *);
-	union{
-		void (*hand) (struct fw_xfer *);
-	} act;
+#define FWXF_INIT	0x00
+#define FWXF_INQ	0x01
+#define FWXF_START	0x02
+#define FWXF_SENT	0x04
+#define FWXF_SENTERR	0x08
+#define FWXF_BUSY	0x10
+#define FWXF_RCVD	0x20
+
+#define FWXF_WAKE	0x80
+	uint8_t flag;
+	int8_t tl;
+	void (*hand) (struct fw_xfer *);
 	struct {
 		struct fw_pkt hdr;
 		uint32_t *payload;
@@ -266,6 +255,7 @@
 	} send, recv;
 	struct mbuf *mbuf;
 	STAILQ_ENTRY(fw_xfer) link;
+	STAILQ_ENTRY(fw_xfer) tlabel;
 	struct malloc_type *malloc;
 };
 
@@ -287,15 +277,18 @@
 void fw_init (struct firewire_comm *);
 int fw_tbuf_update (struct firewire_comm *, int, int);
 int fw_rbuf_update (struct firewire_comm *, int, int);
-void fw_asybusy (struct fw_xfer *);
 int fw_bindadd (struct firewire_comm *, struct fw_bind *);
 int fw_bindremove (struct firewire_comm *, struct fw_bind *);
+int fw_xferlist_add (struct fw_xferlist *, struct malloc_type *, int, int, int,
+    struct firewire_comm *, void *, void (*)(struct fw_xfer *));
+void fw_xferlist_remove (struct fw_xferlist *);
 int fw_asyreq (struct firewire_comm *, int, struct fw_xfer*);
 void fw_busreset (struct firewire_comm *, uint32_t);
 uint16_t fw_crc16 (uint32_t *, uint32_t);
 void fw_xfer_timeout (void *);
 void fw_xfer_done (struct fw_xfer *);
-void fw_asy_callback (struct fw_xfer *);
+void fw_xferwake (struct fw_xfer *);
+int fw_xferwait (struct fw_xfer *);
 void fw_asy_callback_free (struct fw_xfer *);
 struct fw_device *fw_noderesolve_nodeid (struct firewire_comm *, int);
 struct fw_device *fw_noderesolve_eui64 (struct firewire_comm *, struct fw_eui64 *);
@@ -304,9 +297,11 @@
 int fwdev_makedev (struct firewire_softc *);
 int fwdev_destroydev (struct firewire_softc *);
 void fwdev_clone (void *, struct ucred *, char *, int, struct cdev **);
+int fw_open_isodma(struct firewire_comm *, int);
 
 extern int firewire_debug;
 extern devclass_t firewire_devclass;
+extern int firewire_phydma_enable;
 
 #ifdef __DragonFly__
 #define		FWPRI		PCATCH
@@ -317,7 +312,7 @@
 #if defined(__DragonFly__) || __FreeBSD_version < 500000
 #define CALLOUT_INIT(x) callout_init(x)
 #else
-#define CALLOUT_INIT(x) callout_init(x, 0 /* mpsafe */)
+#define CALLOUT_INIT(x) callout_init(x, 1 /* mpsafe */)
 #endif
 
 #if defined(__DragonFly__) || __FreeBSD_version < 500000
Index: sbp.c
===================================================================
RCS file: /home/cvs/src/sys/dev/firewire/sbp.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/dev/firewire/sbp.c -L sys/dev/firewire/sbp.c -u -r1.1.1.1 -r1.2
--- sys/dev/firewire/sbp.c
+++ sys/dev/firewire/sbp.c
@@ -31,7 +31,7 @@
  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  * 
- * $FreeBSD: src/sys/dev/firewire/sbp.c,v 1.81 2005/01/06 01:42:41 imp Exp $
+ * $FreeBSD: src/sys/dev/firewire/sbp.c,v 1.97 2007/06/17 05:55:50 scottl Exp $
  *
  */
 
@@ -91,6 +91,7 @@
  * because of CAM_SCSI2_MAXLUN in cam_xpt.c
  */
 #define SBP_NUM_LUNS 64
+#define SBP_MAXPHYS  MIN(MAXPHYS, (512*1024) /* 512KB */)
 #define SBP_DMA_SIZE PAGE_SIZE
 #define SBP_LOGIN_SIZE sizeof(struct sbp_login_res)
 #define SBP_QUEUE_LEN ((SBP_DMA_SIZE - SBP_LOGIN_SIZE) / sizeof(struct sbp_ocb))
@@ -161,9 +162,9 @@
 
 #define SBP_SEG_MAX rounddown(0xffff, PAGE_SIZE)
 #ifdef __sparc64__ /* iommu */
-#define SBP_IND_MAX howmany(MAXPHYS, SBP_SEG_MAX)
+#define SBP_IND_MAX howmany(SBP_MAXPHYS, SBP_SEG_MAX)
 #else
-#define SBP_IND_MAX howmany(MAXPHYS, PAGE_SIZE)
+#define SBP_IND_MAX howmany(SBP_MAXPHYS, PAGE_SIZE)
 #endif
 struct sbp_ocb {
 	STAILQ_ENTRY(sbp_ocb)	ocb;
@@ -244,7 +245,10 @@
 	struct timeval last_busreset;
 #define SIMQ_FREEZED 1
 	int flags;
+	struct mtx mtx;
 };
+#define SBP_LOCK(sbp) mtx_lock(&(sbp)->mtx)
+#define SBP_UNLOCK(sbp) mtx_unlock(&(sbp)->mtx)
 
 static void sbp_post_explore (void *);
 static void sbp_recv (struct fw_xfer *);
@@ -258,6 +262,7 @@
 static void sbp_free_ocb (struct sbp_dev *, struct sbp_ocb *);
 static void sbp_abort_ocb (struct sbp_ocb *, int);
 static void sbp_abort_all_ocbs (struct sbp_dev *, int);
+static struct fw_xfer * sbp_write_cmd_locked (struct sbp_dev *, int, int);
 static struct fw_xfer * sbp_write_cmd (struct sbp_dev *, int, int);
 static struct sbp_ocb * sbp_get_ocb (struct sbp_dev *);
 static struct sbp_ocb * sbp_enqueue_ocb (struct sbp_dev *, struct sbp_ocb *);
@@ -698,8 +703,8 @@
 	if (t.tv_sec >= 0 && t.tv_usec > 0)
 		ticks = (t.tv_sec * 1000 + t.tv_usec / 1000) * hz / 1000;
 SBP_DEBUG(0)
-	printf("%s: sec = %ld usec = %ld ticks = %d\n", __func__,
-	    t.tv_sec, t.tv_usec, ticks);
+	printf("%s: sec = %jd usec = %ld ticks = %d\n", __func__,
+	    (intmax_t)t.tv_sec, t.tv_usec, ticks);
 END_DEBUG
 	callout_reset(&sdev->login_callout, ticks,
 			sbp_login_callout, (void *)(sdev));
@@ -735,8 +740,10 @@
 			continue;
 		if (alive && (sdev->status != SBP_DEV_DEAD)) {
 			if (sdev->path != NULL) {
+				SBP_LOCK(sbp);
 				xpt_freeze_devq(sdev->path, 1);
 				sdev->freeze ++;
+				SBP_UNLOCK(sbp);
 			}
 			sbp_probe_lun(sdev);
 SBP_DEBUG(0)
@@ -768,8 +775,10 @@
 				printf("lost target\n");
 END_DEBUG
 				if (sdev->path) {
+					SBP_LOCK(sbp);
 					xpt_freeze_devq(sdev->path, 1);
 					sdev->freeze ++;
+					SBP_UNLOCK(sbp);
 				}
 				sdev->status = SBP_DEV_RETRY;
 				sbp_abort_all_ocbs(sdev, CAM_SCSI_BUS_RESET);
@@ -797,8 +806,10 @@
 	printf("sbp_post_busreset\n");
 END_DEBUG
 	if ((sbp->sim->flags & SIMQ_FREEZED) == 0) {
+		SBP_LOCK(sbp);
 		xpt_freeze_simq(sbp->sim, /*count*/1);
 		sbp->sim->flags |= SIMQ_FREEZED;
+		SBP_UNLOCK(sbp);
 	}
 	microtime(&sbp->last_busreset);
 }
@@ -814,6 +825,10 @@
 SBP_DEBUG(0)
 	printf("sbp_post_explore (sbp_cold=%d)\n", sbp_cold);
 END_DEBUG
+	/* We need physical access */
+	if (!firewire_phydma_enable)
+		return;
+
 	if (sbp_cold > 0)
 		sbp_cold --;
 
@@ -869,8 +884,10 @@
 		if (target->num_lun == 0)
 			sbp_free_target(target);
 	}
+	SBP_LOCK(sbp);
 	xpt_release_simq(sbp->sim, /*run queue*/TRUE);
 	sbp->sim->flags &= ~SIMQ_FREEZED;
+	SBP_UNLOCK(sbp);
 }
 
 #if NEED_RESPONSE
@@ -900,7 +917,9 @@
 	sdev = (struct sbp_dev *)xfer->sc;
 	fw_xfer_unload(xfer);
 	s = splfw();
+	SBP_LOCK(sdev->target->sbp);
 	STAILQ_INSERT_TAIL(&sdev->target->xferlist, xfer, link);
+	SBP_UNLOCK(sdev->target->sbp);
 	splx(s);
 }
 
@@ -935,7 +954,7 @@
 END_DEBUG
 
 	xfer = sbp_write_cmd(sdev, FWTCODE_WREQQ, 0);
-	xfer->act.hand = sbp_reset_start_callback;
+	xfer->hand = sbp_reset_start_callback;
 	fp = &xfer->send.hdr;
 	fp->mode.wreqq.dest_hi = 0xffff;
 	fp->mode.wreqq.dest_lo = 0xf0000000 | RESET_START;
@@ -1042,9 +1061,11 @@
 	ccb->ccb_h.ccb_sdev_ptr = sdev;
 
 	/* The scan is in progress now. */
+	SBP_LOCK(target->sbp);
 	xpt_action(ccb);
 	xpt_release_devq(sdev->path, sdev->freeze, TRUE);
 	sdev->freeze = 1;
+	SBP_UNLOCK(target->sbp);
 }
 
 static __inline void
@@ -1107,8 +1128,10 @@
 
 	sbp_xfer_free(xfer);
 	if (sdev->path) {
+		SBP_LOCK(sdev->target->sbp);
 		xpt_release_devq(sdev->path, sdev->freeze, TRUE);
 		sdev->freeze = 0;
+		SBP_UNLOCK(sdev->target->sbp);
 	}
 }
 
@@ -1126,9 +1149,9 @@
 	if (xfer == NULL)
 		return;
 	if (sdev->status == SBP_DEV_ATTACHED || sdev->status == SBP_DEV_PROBE)
-		xfer->act.hand = sbp_agent_reset_callback;
+		xfer->hand = sbp_agent_reset_callback;
 	else
-		xfer->act.hand = sbp_do_attach;
+		xfer->hand = sbp_do_attach;
 	fp = &xfer->send.hdr;
 	fp->mode.wreqq.data = htonl(0xf);
 	fw_asyreq(xfer->fc, -1, xfer);
@@ -1160,7 +1183,7 @@
 END_DEBUG
 	xfer = sbp_write_cmd(sdev, FWTCODE_WREQQ, 0);
 
-	xfer->act.hand = sbp_busy_timeout_callback;
+	xfer->hand = sbp_busy_timeout_callback;
 	fp = &xfer->send.hdr;
 	fp->mode.wreqq.dest_hi = 0xffff;
 	fp->mode.wreqq.dest_lo = 0xf0000000 | BUSY_TIMEOUT;
@@ -1174,7 +1197,7 @@
 	struct sbp_dev *sdev;
 	sdev = (struct sbp_dev *)xfer->sc;
 
-SBP_DEBUG(1)
+SBP_DEBUG(2)
 	sbp_show_sdev_info(sdev, 2);
 	printf("%s\n", __func__);
 END_DEBUG
@@ -1183,6 +1206,8 @@
 		printf("%s: xfer->resp = %d\n", __func__, xfer->resp);
 	}
 	sbp_xfer_free(xfer);
+
+	SBP_LOCK(sdev->target->sbp);
 	sdev->flags &= ~ORB_POINTER_ACTIVE;
 
 	if ((sdev->flags & ORB_POINTER_NEED) != 0) {
@@ -1193,6 +1218,7 @@
 		if (ocb != NULL)
 			sbp_orb_pointer(sdev, ocb);
 	}
+	SBP_UNLOCK(sdev->target->sbp);
 	return;
 }
 
@@ -1206,6 +1232,8 @@
 	printf("%s: 0x%08x\n", __func__, (uint32_t)ocb->bus_addr);
 END_DEBUG
 
+	mtx_assert(&sdev->target->sbp->mtx, MA_OWNED);
+
 	if ((sdev->flags & ORB_POINTER_ACTIVE) != 0) {
 SBP_DEBUG(0)
 		printf("%s: orb pointer active\n", __func__);
@@ -1215,10 +1243,10 @@
 	}
 
 	sdev->flags |= ORB_POINTER_ACTIVE;
-	xfer = sbp_write_cmd(sdev, FWTCODE_WREQB, 0x08);
+	xfer = sbp_write_cmd_locked(sdev, FWTCODE_WREQB, 0x08);
 	if (xfer == NULL)
 		return;
-	xfer->act.hand = sbp_orb_pointer_callback;
+	xfer->hand = sbp_orb_pointer_callback;
 
 	fp = &xfer->send.hdr;
 	fp->mode.wreqb.len = 8;
@@ -1252,7 +1280,9 @@
 	sdev->flags &= ~ORB_DOORBELL_ACTIVE;
 	if ((sdev->flags & ORB_DOORBELL_NEED) != 0) {
 		sdev->flags &= ~ORB_DOORBELL_NEED;
+		SBP_LOCK(sdev->target->sbp);
 		sbp_doorbell(sdev);
+		SBP_UNLOCK(sdev->target->sbp);
 	}
 	return;
 }
@@ -1272,23 +1302,25 @@
 		return;
 	}
 	sdev->flags |= ORB_DOORBELL_ACTIVE;
-	xfer = sbp_write_cmd(sdev, FWTCODE_WREQQ, 0x10);
+	xfer = sbp_write_cmd_locked(sdev, FWTCODE_WREQQ, 0x10);
 	if (xfer == NULL)
 		return;
-	xfer->act.hand = sbp_doorbell_callback;
+	xfer->hand = sbp_doorbell_callback;
 	fp = &xfer->send.hdr;
 	fp->mode.wreqq.data = htonl(0xf);
 	fw_asyreq(xfer->fc, -1, xfer);
 }
 
 static struct fw_xfer *
-sbp_write_cmd(struct sbp_dev *sdev, int tcode, int offset)
+sbp_write_cmd_locked(struct sbp_dev *sdev, int tcode, int offset)
 {
 	struct fw_xfer *xfer;
 	struct fw_pkt *fp;
 	struct sbp_target *target;
 	int s, new = 0;
 
+	mtx_assert(&sdev->target->sbp->mtx, MA_OWNED);
+
 	target = sdev->target;
 	s = splfw();
 	xfer = STAILQ_FIRST(&target->xferlist);
@@ -1313,13 +1345,10 @@
 	}
 	splx(s);
 
-	microtime(&xfer->tv);
-
 	if (new) {
 		xfer->recv.pay_len = 0;
 		xfer->send.spd = min(sdev->target->fwdev->speed, max_speed);
 		xfer->fc = sdev->target->sbp->fd.fc;
-		xfer->retry_req = fw_asybusy;
 	}
 
 	if (tcode == FWTCODE_WREQB)
@@ -1340,6 +1369,19 @@
 
 }
 
+static struct fw_xfer *
+sbp_write_cmd(struct sbp_dev *sdev, int tcode, int offset)
+{
+	struct sbp_softc *sbp = sdev->target->sbp;
+	struct fw_xfer *xfer;
+
+	SBP_LOCK(sbp);
+	xfer = sbp_write_cmd_locked(sdev, tcode, offset);
+	SBP_UNLOCK(sbp);
+
+	return (xfer);
+}
+
 static void
 sbp_mgm_orb(struct sbp_dev *sdev, int func, struct sbp_ocb *aocb)
 {
@@ -1353,20 +1395,25 @@
 	nid = target->sbp->fd.fc->nodeid | FWLOCALBUS;
 
 	s = splfw();
+	SBP_LOCK(target->sbp);
 	if (func == ORB_FUN_RUNQUEUE) {
 		ocb = STAILQ_FIRST(&target->mgm_ocb_queue);
 		if (target->mgm_ocb_cur != NULL || ocb == NULL) {
+			SBP_UNLOCK(target->sbp);
 			splx(s);
 			return;
 		}
 		STAILQ_REMOVE_HEAD(&target->mgm_ocb_queue, ocb);
+		SBP_UNLOCK(target->sbp);
 		goto start;
 	}
 	if ((ocb = sbp_get_ocb(sdev)) == NULL) {
+		SBP_UNLOCK(target->sbp);
 		splx(s);
 		/* XXX */
 		return;
 	}
+	SBP_UNLOCK(target->sbp);
 	ocb->flags = OCB_ACT_MGM;
 	ocb->sdev = sdev;
 
@@ -1404,7 +1451,9 @@
 
 	if (target->mgm_ocb_cur != NULL) {
 		/* there is a standing ORB */
+		SBP_LOCK(target->sbp);
 		STAILQ_INSERT_TAIL(&sdev->target->mgm_ocb_queue, ocb, ocb);
+		SBP_UNLOCK(target->sbp);
 		splx(s);
 		return;
 	}
@@ -1418,7 +1467,7 @@
 	if(xfer == NULL){
 		return;
 	}
-	xfer->act.hand = sbp_mgm_callback;
+	xfer->hand = sbp_mgm_callback;
 
 	fp = &xfer->send.hdr;
 	fp->mode.wreqb.dest_hi = sdev->target->mgm_hi;
@@ -1738,8 +1787,10 @@
 	/* we have to reset the fetch agent if it's dead */
 	if (sbp_status->dead) {
 		if (sdev->path) {
+			SBP_LOCK(sbp);
 			xpt_freeze_devq(sdev->path, 1);
 			sdev->freeze ++;
+			SBP_UNLOCK(sbp);
 		}
 		reset_agent = 1;
 	}
@@ -1847,7 +1898,9 @@
 				/* fix up inq data */
 				if (ccb->csio.cdb_io.cdb_bytes[0] == INQUIRY)
 					sbp_fix_inq_data(ocb);
+				SBP_LOCK(sbp);
 				xpt_done(ccb);
+				SBP_UNLOCK(sbp);
 			}
 			break;
 		default:
@@ -1876,8 +1929,7 @@
 	sfp->mode.wres.dst = rfp->mode.wreqb.src;
 	xfer->dst = sfp->mode.wres.dst;
 	xfer->spd = min(sdev->target->fwdev->speed, max_speed);
-	xfer->act.hand = sbp_loginres_callback;
-	xfer->retry_req = fw_asybusy;
+	xfer->hand = sbp_loginres_callback;
 
 	sfp->mode.wres.tlrt = rfp->mode.wreqb.tlrt;
 	sfp->mode.wres.tcode = FWTCODE_WRES;
@@ -1887,6 +1939,7 @@
 	fw_asyreq(xfer->fc, -1, xfer);
 #else
 	/* recycle */
+	/* we don't need a lock here because bottom half is serialized */
 	STAILQ_INSERT_TAIL(&sbp->fwb.xferlist, xfer, link);
 #endif
 
@@ -1911,9 +1964,17 @@
 {
 	struct sbp_softc *sbp;
 	struct cam_devq *devq;
-	struct fw_xfer *xfer;
+	struct firewire_comm *fc;
 	int i, s, error;
 
+	if (DFLTPHYS > SBP_MAXPHYS)
+		device_printf(dev, "Warning, DFLTPHYS(%dKB) is larger than "
+			"SBP_MAXPHYS(%dKB).\n", DFLTPHYS / 1024,
+			SBP_MAXPHYS / 1024);
+
+	if (!firewire_phydma_enable)
+		device_printf(dev, "Warning, hw.firewire.phydma_enable must be 1 "
+			"for SBP over FireWire.\n");
 SBP_DEBUG(0)
 	printf("sbp_attach (cold=%d)\n", cold);
 END_DEBUG
@@ -1923,12 +1984,13 @@
 	sbp = ((struct sbp_softc *)device_get_softc(dev));
 	bzero(sbp, sizeof(struct sbp_softc));
 	sbp->fd.dev = dev;
-	sbp->fd.fc = device_get_ivars(dev);
+	sbp->fd.fc = fc = device_get_ivars(dev);
+	mtx_init(&sbp->mtx, "sbp", NULL, MTX_DEF);
 
 	if (max_speed < 0)
-		max_speed = sbp->fd.fc->speed;
+		max_speed = fc->speed;
 
-	error = bus_dma_tag_create(/*parent*/sbp->fd.fc->dmat,
+	error = bus_dma_tag_create(/*parent*/fc->dmat,
 				/* XXX shoud be 4 for sane backend? */
 				/*alignment*/1,
 				/*boundary*/0,
@@ -1940,7 +2002,7 @@
 				/*flags*/BUS_DMA_ALLOCNOW,
 #if defined(__FreeBSD__) && __FreeBSD_version >= 501102
 				/*lockfunc*/busdma_lock_mutex,
-				/*lockarg*/&Giant,
+				/*lockarg*/&sbp->mtx,
 #endif
 				&sbp->dmat);
 	if (error != 0) {
@@ -1960,6 +2022,7 @@
 
 	sbp->sim = cam_sim_alloc(sbp_action, sbp_poll, "sbp", sbp,
 				 device_get_unit(dev),
+				 &sbp->mtx,
 				 /*untagged*/ 1,
 				 /*tagged*/ SBP_QUEUE_LEN - 1,
 				 devq);
@@ -1969,8 +2032,8 @@
 		return (ENXIO);
 	}
 
-
-	if (xpt_bus_register(sbp->sim, /*bus*/0) != CAM_SUCCESS)
+	SBP_LOCK(sbp);
+	if (xpt_bus_register(sbp->sim, dev, /*bus*/0) != CAM_SUCCESS)
 		goto fail;
 
 	if (xpt_create_path(&sbp->path, xpt_periph, cam_sim_path(sbp->sim),
@@ -1978,39 +2041,35 @@
 		xpt_bus_deregister(cam_sim_path(sbp->sim));
 		goto fail;
 	}
+	SBP_UNLOCK(sbp);
 
 	/* We reserve 16 bit space (4 bytes X 64 targets X 256 luns) */
 	sbp->fwb.start = ((u_int64_t)SBP_BIND_HI << 32) | SBP_DEV2ADDR(0, 0);
 	sbp->fwb.end = sbp->fwb.start + 0xffff;
-	sbp->fwb.act_type = FWACT_XFER;
 	/* pre-allocate xfer */
 	STAILQ_INIT(&sbp->fwb.xferlist);
-	for (i = 0; i < SBP_NUM_OCB/2; i ++) {
-		xfer = fw_xfer_alloc_buf(M_SBP,
-			/* send */0,
-			/* recv */SBP_RECV_LEN);
-		xfer->act.hand = sbp_recv;
-#if NEED_RESPONSE
-		xfer->fc = sbp->fd.fc;
-#endif
-		xfer->sc = (caddr_t)sbp;
-		STAILQ_INSERT_TAIL(&sbp->fwb.xferlist, xfer, link);
-	}
-	fw_bindadd(sbp->fd.fc, &sbp->fwb);
+	fw_xferlist_add(&sbp->fwb.xferlist, M_SBP,
+	    /*send*/ 0, /*recv*/ SBP_RECV_LEN, SBP_NUM_OCB/2,
+	    fc, (void *)sbp, sbp_recv);
+
+	fw_bindadd(fc, &sbp->fwb);
 
 	sbp->fd.post_busreset = sbp_post_busreset;
 	sbp->fd.post_explore = sbp_post_explore;
 
-	if (sbp->fd.fc->status != -1) {
+	if (fc->status != -1) {
 		s = splfw();
 		sbp_post_busreset((void *)sbp);
 		sbp_post_explore((void *)sbp);
 		splx(s);
 	}
+	SBP_LOCK(sbp);
 	xpt_async(AC_BUS_RESET, sbp->path, /*arg*/ NULL);
+	SBP_UNLOCK(sbp);
 
 	return (0);
 fail:
+	SBP_UNLOCK(sbp);
 	cam_sim_free(sbp->sim, /*free_devq*/TRUE);
 	return (ENXIO);
 }
@@ -2097,7 +2156,6 @@
 {
 	struct sbp_softc *sbp = ((struct sbp_softc *)device_get_softc(dev));
 	struct firewire_comm *fc = sbp->fd.fc;
-	struct fw_xfer *xfer, *next;
 	int i;
 
 SBP_DEBUG(0)
@@ -2106,28 +2164,27 @@
 
 	for (i = 0; i < SBP_NUM_TARGETS; i ++) 
 		sbp_cam_detach_target(&sbp->targets[i]);
+
+	SBP_LOCK(sbp);
 	xpt_async(AC_LOST_DEVICE, sbp->path, NULL);
 	xpt_free_path(sbp->path);
 	xpt_bus_deregister(cam_sim_path(sbp->sim));
-	cam_sim_free(sbp->sim, /*free_devq*/ TRUE),
+	cam_sim_free(sbp->sim, /*free_devq*/ TRUE);
+	SBP_UNLOCK(sbp);
 
 	sbp_logout_all(sbp);
 
 	/* XXX wait for logout completion */
-	tsleep(&i, FWPRI, "sbpdtc", hz/2);
+	pause("sbpdtc", hz/2);
 
 	for (i = 0 ; i < SBP_NUM_TARGETS ; i ++)
 		sbp_free_target(&sbp->targets[i]);
 
-	for (xfer = STAILQ_FIRST(&sbp->fwb.xferlist);
-				xfer != NULL; xfer = next) {
-		next = STAILQ_NEXT(xfer, link);
-		fw_xfer_free_buf(xfer);
-	}
-	STAILQ_INIT(&sbp->fwb.xferlist);
 	fw_bindremove(fc, &sbp->fwb);
+	fw_xferlist_remove(&sbp->fwb.xferlist);
 
 	bus_dma_tag_destroy(sbp->dmat);
+	mtx_destroy(&sbp->mtx);
 
 	return (0);
 }
@@ -2141,15 +2198,17 @@
 		return;
 	if (sdev->status == SBP_DEV_RESET)
 		return;
+	sbp_abort_all_ocbs(sdev, CAM_DEV_NOT_THERE);
 	if (sdev->path) {
+		SBP_LOCK(sdev->target->sbp);
 		xpt_release_devq(sdev->path,
 				 sdev->freeze, TRUE);
 		sdev->freeze = 0;
 		xpt_async(AC_LOST_DEVICE, sdev->path, NULL);
 		xpt_free_path(sdev->path);
 		sdev->path = NULL;
+		SBP_UNLOCK(sdev->target->sbp);
 	}
-	sbp_abort_all_ocbs(sdev, CAM_DEV_NOT_THERE);
 }
 
 static void
@@ -2182,8 +2241,10 @@
 			continue;
 		if (tsdev->status == SBP_DEV_RESET)
 			continue;
+		SBP_LOCK(target->sbp);
 		xpt_freeze_devq(tsdev->path, 1);
 		tsdev->freeze ++;
+		SBP_UNLOCK(target->sbp);
 		sbp_abort_all_ocbs(tsdev, CAM_CMD_TIMEOUT);
 		if (method == 2)
 			tsdev->status = SBP_DEV_LOGIN;
@@ -2238,8 +2299,10 @@
 	switch(sdev->timeout) {
 	case 1:
 		printf("agent reset\n");
+		SBP_LOCK(sdev->target->sbp);
 		xpt_freeze_devq(sdev->path, 1);
 		sdev->freeze ++;
+		SBP_UNLOCK(sdev->target->sbp);
 		sbp_abort_all_ocbs(sdev, CAM_CMD_TIMEOUT);
 		sbp_agent_reset(sdev);
 		break;
@@ -2343,6 +2406,7 @@
 		void *cdb;
 
 		csio = &ccb->csio;
+		mtx_assert(sim->mtx, MA_OWNED);
 
 SBP_DEBUG(2)
 		printf("%s:%d:%d XPT_SCSI_IO: "
@@ -2384,10 +2448,12 @@
 		}
 #endif
 		if ((ocb = sbp_get_ocb(sdev)) == NULL) {
-			ccb->ccb_h.status = CAM_REQUEUE_REQ;
+			ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
 			if (sdev->freeze == 0) {
+				SBP_LOCK(sdev->target->sbp);
 				xpt_freeze_devq(sdev->path, 1);
 				sdev->freeze ++;
+				SBP_UNLOCK(sdev->target->sbp);
 			}
 			xpt_done(ccb);
 			return;
@@ -2527,6 +2593,10 @@
 		strncpy(cpi->hba_vid, "SBP", HBA_IDLEN);
 		strncpy(cpi->dev_name, sim->sim_name, DEV_IDLEN);
 		cpi->unit_number = sim->unit_number;
+                cpi->transport = XPORT_SPI;	/* XX should have a FireWire */
+                cpi->transport_version = 2;
+                cpi->protocol = PROTO_SCSI;
+                cpi->protocol_version = SCSI_REV_2;
 
 		cpi->ccb_h.status = CAM_REQ_CMP;
 		xpt_done(ccb);
@@ -2535,15 +2605,24 @@
 	case XPT_GET_TRAN_SETTINGS:
 	{
 		struct ccb_trans_settings *cts = &ccb->cts;
+		struct ccb_trans_settings_scsi *scsi =
+		    &cts->proto_specific.scsi;
+		struct ccb_trans_settings_spi *spi =
+		    &cts->xport_specific.spi;
+
+		cts->protocol = PROTO_SCSI;
+		cts->protocol_version = SCSI_REV_2;
+		cts->transport = XPORT_SPI;	/* should have a FireWire */
+		cts->transport_version = 2;
+		spi->valid = CTS_SPI_VALID_DISC;
+		spi->flags = CTS_SPI_FLAGS_DISC_ENB;
+		scsi->valid = CTS_SCSI_VALID_TQ;
+		scsi->flags = CTS_SCSI_FLAGS_TAG_ENB;
 SBP_DEBUG(1)
 		printf("%s:%d:%d XPT_GET_TRAN_SETTINGS:.\n",
 			device_get_nameunit(sbp->fd.dev),
 			ccb->ccb_h.target_id, ccb->ccb_h.target_lun);
 END_DEBUG
-		/* Enable disconnect and tagged queuing */
-		cts->valid = CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID;
-		cts->flags = CCB_TRANS_DISC_ENB | CCB_TRANS_TAG_ENB;
-
 		cts->ccb_h.status = CAM_REQ_CMP;
 		xpt_done(ccb);
 		break;
@@ -2679,6 +2758,7 @@
 #endif
 	    __func__, ntohl(sbp_status->orb_lo), sbp_status->src);
 END_DEBUG
+	SBP_LOCK(sdev->target->sbp);
 	for (ocb = STAILQ_FIRST(&sdev->ocbs); ocb != NULL; ocb = next) {
 		next = STAILQ_NEXT(ocb, ocb);
 		flags = ocb->flags;
@@ -2715,8 +2795,11 @@
 				 * XXX this is not correct for unordered
 				 * execution. 
 				 */
-				if (sdev->last_ocb != NULL)
+				if (sdev->last_ocb != NULL) {
+					SBP_UNLOCK(sdev->target->sbp);
 					sbp_free_ocb(sdev, sdev->last_ocb);
+					SBP_LOCK(sdev->target->sbp);
+				}
 				sdev->last_ocb = ocb;
 				if (next != NULL &&
 				    sbp_status->src == SRC_NO_NEXT)
@@ -2726,6 +2809,7 @@
 		} else
 			order ++;
 	}
+	SBP_UNLOCK(sdev->target->sbp);
 	splx(s);
 SBP_DEBUG(0)
 	if (ocb && order > 0) {
@@ -2742,6 +2826,7 @@
 	int s = splfw();
 	struct sbp_ocb *prev, *prev2;
 
+	mtx_assert(&sdev->target->sbp->mtx, MA_OWNED);
 SBP_DEBUG(1)
 	sbp_show_sdev_info(sdev, 2);
 #if defined(__DragonFly__) || __FreeBSD_version < 500000
@@ -2760,8 +2845,8 @@
 	if (use_doorbell && prev == NULL)
 		prev2 = sdev->last_ocb;
 
-	if (prev2 != NULL) {
-SBP_DEBUG(2)
+	if (prev2 != NULL && (ocb->sdev->flags & ORB_LINK_DEAD) == 0) {
+SBP_DEBUG(1)
 #if defined(__DragonFly__) || __FreeBSD_version < 500000
 		printf("linking chain 0x%x -> 0x%x\n",
 		    prev2->bus_addr, ocb->bus_addr);
@@ -2770,8 +2855,13 @@
 		    (uintmax_t)prev2->bus_addr, (uintmax_t)ocb->bus_addr);
 #endif
 END_DEBUG
-		prev2->orb[1] = htonl(ocb->bus_addr);
-		prev2->orb[0] = 0;
+		/*
+		 * Suppress compiler optimization so that orb[1] must be written first.
+		 * XXX We may need an explicit memory barrier for other architectures
+		 * other than i386/amd64.
+		 */
+		*(volatile uint32_t *)&prev2->orb[1] = htonl(ocb->bus_addr);
+		*(volatile uint32_t *)&prev2->orb[0] = 0;
 	}
 	splx(s);
 
@@ -2783,6 +2873,8 @@
 {
 	struct sbp_ocb *ocb;
 	int s = splfw();
+
+	mtx_assert(&sdev->target->sbp->mtx, MA_OWNED);
 	ocb = STAILQ_FIRST(&sdev->free_ocbs);
 	if (ocb == NULL) {
 		sdev->flags |= ORB_SHORTAGE;
@@ -2801,6 +2893,8 @@
 {
 	ocb->flags = 0;
 	ocb->ccb = NULL;
+
+	SBP_LOCK(sdev->target->sbp);
 	STAILQ_INSERT_TAIL(&sdev->free_ocbs, ocb, ocb);
 	if ((sdev->flags & ORB_SHORTAGE) != 0) {
 		int count;
@@ -2810,6 +2904,7 @@
 		sdev->freeze = 0;
 		xpt_release_devq(sdev->path, count, TRUE);
 	}
+	SBP_UNLOCK(sdev->target->sbp);
 }
 
 static void
@@ -2840,7 +2935,9 @@
 		untimeout(sbp_timeout, (caddr_t)ocb,
 					ocb->ccb->ccb_h.timeout_ch);
 		ocb->ccb->ccb_h.status = status;
+		SBP_LOCK(sdev->target->sbp);
 		xpt_done(ocb->ccb);
+		SBP_UNLOCK(sdev->target->sbp);
 	}
 	sbp_free_ocb(sdev, ocb);
 }
@@ -2854,8 +2951,12 @@
 
 	s = splfw();
 
-	bcopy(&sdev->ocbs, &temp, sizeof(temp));
+	STAILQ_INIT(&temp);
+	SBP_LOCK(sdev->target->sbp);
+	STAILQ_CONCAT(&temp, &sdev->ocbs);
 	STAILQ_INIT(&sdev->ocbs);
+	SBP_UNLOCK(sdev->target->sbp);
+
 	for (ocb = STAILQ_FIRST(&temp); ocb != NULL; ocb = next) {
 		next = STAILQ_NEXT(ocb, ocb);
 		sbp_abort_ocb(ocb, status);
Index: if_fwip.c
===================================================================
RCS file: /home/cvs/src/sys/dev/firewire/if_fwip.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/dev/firewire/if_fwip.c -L sys/dev/firewire/if_fwip.c -u -r1.1.1.1 -r1.2
--- sys/dev/firewire/if_fwip.c
+++ sys/dev/firewire/if_fwip.c
@@ -33,7 +33,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  * 
- * $FreeBSD: src/sys/dev/firewire/if_fwip.c,v 1.7.2.3 2005/10/07 14:00:03 glebius Exp $
+ * $FreeBSD: src/sys/dev/firewire/if_fwip.c,v 1.16 2007/06/06 14:31:36 simokawa Exp $
  */
 
 #ifdef HAVE_KERNEL_OPTION_HEADERS
@@ -161,6 +161,7 @@
 	if (ifp == NULL)
 		return (ENOSPC);
 
+	mtx_init(&fwip->mtx, "fwip", NULL, MTX_DEF);
 	/* XXX */
 	fwip->dma_ch = -1;
 
@@ -197,8 +198,7 @@
 	ifp->if_init = fwip_init;
 	ifp->if_start = fwip_start;
 	ifp->if_ioctl = fwip_ioctl;
-	ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST|
-	    IFF_NEEDSGIANT);
+	ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST);
 	ifp->if_snd.ifq_maxlen = TX_MAX_QUEUE;
 #ifdef DEVICE_POLLING
 	ifp->if_capabilities |= IFCAP_POLLING;
@@ -282,6 +282,7 @@
 	fwip_stop(fwip);
 	firewire_ifdetach(ifp);
 	if_free(ifp);
+	mtx_destroy(&fwip->mtx);
 
 	splx(s);
 	return 0;
@@ -303,17 +304,11 @@
 	fc = fwip->fd.fc;
 #define START 0
 	if (fwip->dma_ch < 0) {
-		for (i = START; i < fc->nisodma; i ++) {
-			xferq = fc->ir[i];
-			if ((xferq->flag & FWXFERQ_OPEN) == 0)
-				goto found;
-		}
-		printf("no free dma channel\n");
-		return;
-found:
-		fwip->dma_ch = i;
-		/* allocate DMA channel and init packet mode */
-		xferq->flag |= FWXFERQ_OPEN | FWXFERQ_EXTBUF |
+		fwip->dma_ch = fw_open_isodma(fc, /* tx */0);
+		if (fwip->dma_ch < 0)
+			return;
+		xferq = fc->ir[fwip->dma_ch];
+		xferq->flag |= FWXFERQ_EXTBUF |
 				FWXFERQ_HANDLER | FWXFERQ_STREAM;
 		xferq->flag &= ~0xff;
 		xferq->flag |= broadcast_channel & 0xff;
@@ -354,7 +349,6 @@
 
 		fwip->fwb.start = INET_FIFO;
 		fwip->fwb.end = INET_FIFO + 16384; /* S3200 packet size */
-		fwip->fwb.act_type = FWACT_XFER;
 
 		/* pre-allocate xfer */
 		STAILQ_INIT(&fwip->fwb.xferlist);
@@ -365,7 +359,7 @@
 			m = m_getcl(M_TRYWAIT, MT_DATA, M_PKTHDR);
 			xfer->recv.payload = mtod(m, uint32_t *);
 			xfer->recv.pay_len = MCLBYTES;
-			xfer->act.hand = fwip_unicast_input;
+			xfer->hand = fwip_unicast_input;
 			xfer->fc = fc;
 			xfer->sc = (caddr_t)fwip;
 			xfer->mbuf = m;
@@ -380,9 +374,8 @@
 				break;
 			xfer->send.spd = tx_speed;
 			xfer->fc = fwip->fd.fc;
-			xfer->retry_req = fw_asybusy;
 			xfer->sc = (caddr_t)fwip;
-			xfer->act.hand = fwip_output_callback;
+			xfer->hand = fwip_output_callback;
 			STAILQ_INSERT_TAIL(&fwip->xferlist, xfer, link);
 		}
 	} else
@@ -524,8 +517,6 @@
 	struct ifnet *ifp;
 	int s;
 
-	GIANT_REQUIRED;
-
 	fwip = (struct fwip_softc *)xfer->sc;
 	ifp = fwip->fw_softc.fwip_ifp;
 	/* XXX error check */
@@ -537,12 +528,15 @@
 	fw_xfer_unload(xfer);
 
 	s = splimp();
+	FWIP_LOCK(fwip);
 	STAILQ_INSERT_TAIL(&fwip->xferlist, xfer, link);
+	FWIP_UNLOCK(fwip);
 	splx(s);
 
 	/* for queue full */
-	if (ifp->if_snd.ifq_head != NULL)
+	if (ifp->if_snd.ifq_head != NULL) {
 		fwip_start(ifp);
+	}
 }
 
 static void
@@ -551,8 +545,6 @@
 	struct fwip_softc *fwip = ((struct fwip_eth_softc *)ifp->if_softc)->fwip;
 	int s;
 
-	GIANT_REQUIRED;
-
 	FWIPDEBUG(ifp, "starting\n");
 
 	if (fwip->dma_ch < 0) {
@@ -605,19 +597,29 @@
 	int error;
 	int i = 0;
 
-	GIANT_REQUIRED;
-
 	xfer = NULL;
-	xferq = fwip->fd.fc->atq;
-	while (xferq->queued < xferq->maxq - 1) {
+	xferq = fc->atq;
+	while ((xferq->queued < xferq->maxq - 1) &&
+			(ifp->if_snd.ifq_head != NULL)) {
+		FWIP_LOCK(fwip);
 		xfer = STAILQ_FIRST(&fwip->xferlist);
 		if (xfer == NULL) {
+			FWIP_UNLOCK(fwip);
+#if 0
 			printf("if_fwip: lack of xfer\n");
-			return;
+#endif
+			break;
 		}
+		STAILQ_REMOVE_HEAD(&fwip->xferlist, link);
+		FWIP_UNLOCK(fwip);
+
 		IF_DEQUEUE(&ifp->if_snd, m);
-		if (m == NULL)
+		if (m == NULL) {
+			FWIP_LOCK(fwip);
+			STAILQ_INSERT_HEAD(&fwip->xferlist, xfer, link);
+			FWIP_UNLOCK(fwip);
 			break;
+		}
 
 		/*
 		 * Dig out the link-level address which
@@ -631,7 +633,6 @@
 		else
 			destfw = (struct fw_hwaddr *) (mtag + 1);
 
-		STAILQ_REMOVE_HEAD(&fwip->xferlist, link);
 
 		/*
 		 * We don't do any bpf stuff here - the generic code
@@ -724,7 +725,9 @@
 			 * for later transmission.
 			 */
 			xfer->mbuf = 0;
+			FWIP_LOCK(fwip);
 			STAILQ_INSERT_TAIL(&fwip->xferlist, xfer, link);
+			FWIP_UNLOCK(fwip);
 			IF_PREPEND(&ifp->if_snd, m);
 			break;
 		}
@@ -743,13 +746,8 @@
 	if (i > 1)
 		printf("%d queued\n", i);
 #endif
-	if (i > 0) {
-#if 1
+	if (i > 0)
 		xferq->start(fc);
-#else
-		taskqueue_enqueue(taskqueue_swi_giant, &fwip->start_send);
-#endif
-	}
 }
 
 static void
@@ -757,7 +755,6 @@
 {
 	struct fwip_softc *fwip = arg;
 
-	GIANT_REQUIRED;
 	fwip->fd.fc->atq->start(fwip->fd.fc);
 }
 
@@ -774,7 +771,6 @@
 	uint16_t src;
 	uint32_t *p;
 
-	GIANT_REQUIRED;
 
 	fwip = (struct fwip_softc *)xferq->sc;
 	ifp = fwip->fw_softc.fwip_ifp;
@@ -838,7 +834,7 @@
 		 * Record the sender ID for possible BPF usage.
 		 */
 		src = ntohl(p[1]) >> 16;
-		if (ifp->if_bpf) {
+		if (bpf_peers_present(ifp->if_bpf)) {
 			mtag = m_tag_alloc(MTAG_FIREWIRE,
 			    MTAG_FIREWIRE_SENDER_EUID,
 			    2*sizeof(uint32_t), M_NOWAIT);
@@ -876,8 +872,6 @@
 {
 	struct mbuf *m;
 
-	GIANT_REQUIRED;
-
 	/*
 	 * We have finished with a unicast xfer. Allocate a new
 	 * cluster and stick it on the back of the input queue.
@@ -902,8 +896,6 @@
 	//struct fw_pkt *sfp;
 	int rtcode;
 
-	GIANT_REQUIRED;
-
 	fwip = (struct fwip_softc *)xfer->sc;
 	ifp = fwip->fw_softc.fwip_ifp;
 	m = xfer->mbuf;
@@ -939,7 +931,7 @@
 		return;
 	}
 
-	if (ifp->if_bpf) {
+	if (bpf_peers_present(ifp->if_bpf)) {
 		/*
 		 * Record the sender ID for possible BPF usage.
 		 */
Index: fwohcivar.h
===================================================================
RCS file: /home/cvs/src/sys/dev/firewire/fwohcivar.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/dev/firewire/fwohcivar.h -L sys/dev/firewire/fwohcivar.h -u -r1.1.1.1 -r1.2
--- sys/dev/firewire/fwohcivar.h
+++ sys/dev/firewire/fwohcivar.h
@@ -31,17 +31,16 @@
  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  * 
- * $FreeBSD: src/sys/dev/firewire/fwohcivar.h,v 1.14 2005/01/06 01:42:41 imp Exp $
+ * $FreeBSD: src/sys/dev/firewire/fwohcivar.h,v 1.16 2007/06/06 14:31:36 simokawa Exp $
  *
  */
 
-#if defined(__DragonFly__) || __FreeBSD_version < 500000
-#define FWOHCI_TASKQUEUE        0
-#else
-#define FWOHCI_TASKQUEUE        1
-#endif
-#if FWOHCI_TASKQUEUE
 #include <sys/taskqueue.h>
+
+#if defined(__DragonFly__) ||  __FreeBSD_version < 700043
+#define FWOHCI_INTFILT	0
+#else
+#define FWOHCI_INTFILT	1
 #endif
 
 typedef struct fwohci_softc {
@@ -77,13 +76,15 @@
 	struct fwdma_alloc crom_dma;
 	struct fwdma_alloc dummy_dma;
 	uint32_t intmask, irstat, itstat;
-#if FWOHCI_TASKQUEUE
 	uint32_t intstat;
-	struct task fwohci_task_complete;
-#endif
+	struct task fwohci_task_busreset;
+	struct task fwohci_task_sid;
+	struct task fwohci_task_dma;
+	int cycle_lost;
 } fwohci_softc_t;
 
 void fwohci_intr (void *arg);
+int fwohci_filt (void *arg);
 int fwohci_init (struct fwohci_softc *, device_t);
 void fwohci_poll (struct firewire_comm *, int, int);
 void fwohci_reset (struct fwohci_softc *, device_t);
Index: fwdev.c
===================================================================
RCS file: /home/cvs/src/sys/dev/firewire/fwdev.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -L sys/dev/firewire/fwdev.c -L sys/dev/firewire/fwdev.c -u -r1.4 -r1.5
--- sys/dev/firewire/fwdev.c
+++ sys/dev/firewire/fwdev.c
@@ -31,7 +31,7 @@
  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  * 
- * $FreeBSD: src/sys/dev/firewire/fwdev.c,v 1.46.2.1 2005/08/13 21:24:15 rwatson Exp $
+ * $FreeBSD: src/sys/dev/firewire/fwdev.c,v 1.52 2007/06/06 14:31:36 simokawa Exp $
  *
  */
 
@@ -98,7 +98,7 @@
 	.d_mmap =	fw_mmap,
 	.d_strategy =	fw_strategy,
 	.d_name =	"fw",
-	.d_flags =	D_MEM | D_NEEDGIANT
+	.d_flags =	D_MEM
 #else
 #define CDEV_MAJOR 127
 	fw_open, fw_close, fw_read, fw_write, fw_ioctl,
@@ -108,9 +108,12 @@
 };
 
 struct fw_drv1 {
+	struct firewire_comm *fc;
 	struct fw_xferq *ir;
 	struct fw_xferq *it;
 	struct fw_isobufreq bufreq;
+	STAILQ_HEAD(, fw_bind) binds;
+	STAILQ_HEAD(, fw_xfer) rq;
 };
 
 static int
@@ -181,12 +184,29 @@
 fw_open (struct cdev *dev, int flags, int fmt, fw_proc *td)
 {
 	int err = 0;
+	int unit = DEV2UNIT(dev);
+	struct fw_drv1 *d;
+	struct firewire_softc *sc;
 
 	if (DEV_FWMEM(dev))
 		return fwmem_open(dev, flags, fmt, td);
 
-	if (dev->si_drv1 != NULL)
+	sc = devclass_get_softc(firewire_devclass, unit);
+	if (sc == NULL)
+		return (ENXIO);
+
+	FW_GLOCK(sc->fc);
+	if (dev->si_drv1 != NULL) {
+		FW_GUNLOCK(sc->fc);
 		return (EBUSY);
+	}
+	/* set dummy value for allocation */
+	dev->si_drv1 = (void *)-1;
+	FW_GUNLOCK(sc->fc);
+
+	dev->si_drv1 = malloc(sizeof(struct fw_drv1), M_FW, M_WAITOK | M_ZERO);
+	if (dev->si_drv1 == NULL)
+		return (ENOMEM);
 
 #if defined(__FreeBSD__) && __FreeBSD_version >= 500000
 	if ((dev->si_flags & SI_NAMED) == 0) {
@@ -198,8 +218,10 @@
 			"fw%d.%d", unit, sub);
 	}
 #endif
-
-	dev->si_drv1 = malloc(sizeof(struct fw_drv1), M_FW, M_WAITOK | M_ZERO);
+	d = (struct fw_drv1 *)dev->si_drv1;
+	d->fc = sc->fc;
+	STAILQ_INIT(&d->binds);
+	STAILQ_INIT(&d->rq);
 
 	return err;
 }
@@ -207,10 +229,8 @@
 static int
 fw_close (struct cdev *dev, int flags, int fmt, fw_proc *td)
 {
-	struct firewire_softc *sc;
 	struct firewire_comm *fc;
 	struct fw_drv1 *d;
-	int unit = DEV2UNIT(dev);
 	struct fw_xfer *xfer;
 	struct fw_bind *fwb;
 	int err = 0;
@@ -218,10 +238,17 @@
 	if (DEV_FWMEM(dev))
 		return fwmem_close(dev, flags, fmt, td);
 
-	sc = devclass_get_softc(firewire_devclass, unit);
-	fc = sc->fc;
 	d = (struct fw_drv1 *)dev->si_drv1;
+	fc = d->fc;
 
+	/* remove binding */
+	for (fwb = STAILQ_FIRST(&d->binds); fwb != NULL;
+			fwb = STAILQ_FIRST(&d->binds)) {
+		fw_bindremove(fc, fwb);
+		STAILQ_REMOVE_HEAD(&d->binds, chlist);
+		fw_xferlist_remove(&fwb->xferlist);
+		free(fwb, M_FW);
+	}
 	if (d->ir != NULL) {
 		struct fw_xferq *ir = d->ir;
 
@@ -242,13 +269,6 @@
 			xfer->resp = 0;
 			fw_xfer_done(xfer);
 		}
-		/* remove binding */
-		for (fwb = STAILQ_FIRST(&ir->binds); fwb != NULL;
-				fwb = STAILQ_FIRST(&ir->binds)) {
-			STAILQ_REMOVE(&fc->binds, fwb, fw_bind, fclist);
-			STAILQ_REMOVE_HEAD(&ir->binds, chlist);
-			free(fwb, M_FW);
-		}
 		ir->flag &= ~(FWXFERQ_OPEN |
 			FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK);
 		d->ir = NULL;
@@ -275,30 +295,77 @@
 	return err;
 }
 
+static int
+fw_read_async(struct fw_drv1 *d, struct uio *uio, int ioflag)
+{
+	int err = 0, s;
+	struct fw_xfer *xfer;
+	struct fw_bind *fwb;
+	struct fw_pkt *fp;
+	struct tcode_info *tinfo;
+
+	FW_GLOCK(d->fc);
+	while ((xfer = STAILQ_FIRST(&d->rq)) == NULL && err == 0)
+		err = msleep(&d->rq, FW_GMTX(d->fc), FWPRI, "fwra", 0);
+
+	if (err != 0) {
+		FW_GUNLOCK(d->fc);
+		return (err);
+	}
+
+	s = splfw();
+	STAILQ_REMOVE_HEAD(&d->rq, link);
+	FW_GUNLOCK(xfer->fc);
+	splx(s);
+	fp = &xfer->recv.hdr;
+#if 0 /* for GASP ?? */
+	if (fc->irx_post != NULL)
+		fc->irx_post(fc, fp->mode.ld);
+#endif
+	tinfo = &xfer->fc->tcode[fp->mode.hdr.tcode];
+	err = uiomove((void *)fp, tinfo->hdr_len, uio);
+	if (err)
+		goto out;
+	err = uiomove((void *)xfer->recv.payload, xfer->recv.pay_len, uio);
+
+out:
+	/* recycle this xfer */
+	fwb = (struct fw_bind *)xfer->sc;
+	fw_xfer_unload(xfer);
+	xfer->recv.pay_len = PAGE_SIZE;
+	FW_GLOCK(xfer->fc);
+	STAILQ_INSERT_TAIL(&fwb->xferlist, xfer, link);
+	FW_GUNLOCK(xfer->fc);
+	return (err);
+}
+
 /*
  * read request.
  */
 static int
 fw_read (struct cdev *dev, struct uio *uio, int ioflag)
 {
-	struct firewire_softc *sc;
+	struct fw_drv1 *d;
 	struct fw_xferq *ir;
-	struct fw_xfer *xfer;
+	struct firewire_comm *fc;
 	int err = 0, s, slept = 0;
-	int unit = DEV2UNIT(dev);
 	struct fw_pkt *fp;
 
 	if (DEV_FWMEM(dev))
-		return physio(dev, uio, ioflag);
+		return (physio(dev, uio, ioflag));
 
-	sc = devclass_get_softc(firewire_devclass, unit);
+	d = (struct fw_drv1 *)dev->si_drv1;
+	fc = d->fc;
+	ir = d->ir;
 
-	ir = ((struct fw_drv1 *)dev->si_drv1)->ir;
-	if (ir == NULL || ir->buf == NULL)
+	if (ir == NULL)
+		return (fw_read_async(d, uio, ioflag));
+
+	if (ir->buf == NULL)
 		return (EIO);
 
+	FW_GLOCK(fc);
 readloop:
-	xfer = STAILQ_FIRST(&ir->q);
 	if (ir->stproc == NULL) {
 		/* iso bulkxfer */
 		ir->stproc = STAILQ_FIRST(&ir->stvalid);
@@ -309,39 +376,26 @@
 			ir->queued = 0;
 		}
 	}
-	if (xfer == NULL && ir->stproc == NULL) {
+	if (ir->stproc == NULL) {
 		/* no data avaliable */
 		if (slept == 0) {
 			slept = 1;
 			ir->flag |= FWXFERQ_WAKEUP;
-			err = tsleep(ir, FWPRI, "fw_read", hz);
+			err = msleep(ir, FW_GMTX(fc), FWPRI, "fw_read", hz);
 			ir->flag &= ~FWXFERQ_WAKEUP;
 			if (err == 0)
 				goto readloop;
 		} else if (slept == 1)
 			err = EIO;
+		FW_GUNLOCK(fc);
 		return err;
-	} else if(xfer != NULL) {
-#if 0 /* XXX broken */
-		/* per packet mode or FWACT_CH bind?*/
-		s = splfw();
-		ir->queued --;
-		STAILQ_REMOVE_HEAD(&ir->q, link);
-		splx(s);
-		fp = &xfer->recv.hdr;
-		if (sc->fc->irx_post != NULL)
-			sc->fc->irx_post(sc->fc, fp->mode.ld);
-		err = uiomove((void *)fp, 1 /* XXX header size */, uio);
-		/* XXX copy payload too */
-		/* XXX we should recycle this xfer */
-#endif
-		fw_xfer_free( xfer);
 	} else if(ir->stproc != NULL) {
 		/* iso bulkxfer */
+		FW_GUNLOCK(fc);
 		fp = (struct fw_pkt *)fwdma_v_addr(ir->buf, 
 				ir->stproc->poffset + ir->queued);
-		if(sc->fc->irx_post != NULL)
-			sc->fc->irx_post(sc->fc, fp->mode.ld);
+		if(fc->irx_post != NULL)
+			fc->irx_post(fc, fp->mode.ld);
 		if(fp->mode.stream.len == 0){
 			err = EIO;
 			return err;
@@ -353,11 +407,12 @@
 			s = splfw();
 			STAILQ_INSERT_TAIL(&ir->stfree, ir->stproc, link);
 			splx(s);
-			sc->fc->irx_enable(sc->fc, ir->dmach);
+			fc->irx_enable(fc, ir->dmach);
 			ir->stproc = NULL;
 		}
 		if (uio->uio_resid >= ir->psize) {
 			slept = -1;
+			FW_GLOCK(fc);
 			goto readloop;
 		}
 	}
@@ -365,24 +420,85 @@
 }
 
 static int
+fw_write_async(struct fw_drv1 *d, struct uio *uio, int ioflag)
+{
+	struct fw_xfer *xfer;
+	struct fw_pkt pkt;
+	struct tcode_info *tinfo;
+	int err;
+
+	bzero(&pkt, sizeof(struct fw_pkt));
+	if ((err = uiomove((caddr_t)&pkt, sizeof(uint32_t), uio)))
+		return (err);
+	tinfo = &d->fc->tcode[pkt.mode.hdr.tcode];
+	if ((err = uiomove((caddr_t)&pkt + sizeof(uint32_t),
+	    tinfo->hdr_len - sizeof(uint32_t), uio)))
+		return (err);
+
+	if ((xfer = fw_xfer_alloc_buf(M_FWXFER, uio->uio_resid,
+	    PAGE_SIZE/*XXX*/)) == NULL)
+		return (ENOMEM);
+
+	bcopy(&pkt, &xfer->send.hdr, sizeof(struct fw_pkt));
+	xfer->send.pay_len = uio->uio_resid;
+	if (uio->uio_resid > 0) {
+		if ((err = uiomove((caddr_t)&xfer->send.payload[0],
+		    uio->uio_resid, uio)));
+			goto out;
+	}
+
+	xfer->fc = d->fc;
+	xfer->sc = NULL;
+	xfer->hand = fw_xferwake;
+	xfer->send.spd = 2 /* XXX */;
+
+	if ((err = fw_asyreq(xfer->fc, -1, xfer)))
+		goto out;
+
+	if ((err = fw_xferwait(xfer)))
+		goto out;
+
+	if (xfer->resp != 0) {
+		err = xfer->resp;
+		goto out;
+	}
+
+	if (xfer->flag & FWXF_RCVD) {
+		FW_GLOCK(xfer->fc);
+		STAILQ_INSERT_TAIL(&d->rq, xfer, link);
+		FW_GUNLOCK(xfer->fc);
+		return (0);
+	}
+
+out:
+	fw_xfer_free(xfer);
+	return (err);
+}
+
+static int
 fw_write (struct cdev *dev, struct uio *uio, int ioflag)
 {
 	int err = 0;
-	struct firewire_softc *sc;
-	int unit = DEV2UNIT(dev);
 	int s, slept = 0;
+	struct fw_drv1 *d;
 	struct fw_pkt *fp;
 	struct firewire_comm *fc;
 	struct fw_xferq *it;
 
 	if (DEV_FWMEM(dev))
-		return physio(dev, uio, ioflag);
+		return (physio(dev, uio, ioflag));
 
-	sc = devclass_get_softc(firewire_devclass, unit);
-	fc = sc->fc;
-	it = ((struct fw_drv1 *)dev->si_drv1)->it;
-	if (it == NULL || it->buf == NULL)
+	d = (struct fw_drv1 *)dev->si_drv1;
+	fc = d->fc;
+	it = d->it;
+
+	if (it == NULL)
+		return (fw_write_async(d, uio, ioflag));
+
+	if (it->buf == NULL)
 		return (EIO);
+
+	FW_GLOCK(fc);
 isoloop:
 	if (it->stproc == NULL) {
 		it->stproc = STAILQ_FIRST(&it->stfree);
@@ -393,18 +509,21 @@
 			it->queued = 0;
 		} else if (slept == 0) {
 			slept = 1;
-			err = sc->fc->itx_enable(sc->fc, it->dmach);
+#if 0	/* XXX to avoid lock recursion */
+			err = fc->itx_enable(fc, it->dmach);
 			if (err)
-				return err;
-			err = tsleep(it, FWPRI, "fw_write", hz);
+				goto out;
+#endif
+			err = msleep(it, FW_GMTX(fc), FWPRI, "fw_write", hz);
 			if (err)
-				return err;
+				goto out;
 			goto isoloop;
 		} else {
 			err = EIO;
-			return err;
+			goto out;
 		}
 	}
+	FW_GUNLOCK(fc);
 	fp = (struct fw_pkt *)fwdma_v_addr(it->buf,
 			it->stproc->poffset + it->queued);
 	err = uiomove((caddr_t)fp, sizeof(struct fw_isohdr), uio);
@@ -416,25 +535,43 @@
 		STAILQ_INSERT_TAIL(&it->stvalid, it->stproc, link);
 		splx(s);
 		it->stproc = NULL;
-		err = sc->fc->itx_enable(sc->fc, it->dmach);
+		err = fc->itx_enable(fc, it->dmach);
 	}
 	if (uio->uio_resid >= sizeof(struct fw_isohdr)) {
 		slept = 0;
+		FW_GLOCK(fc);
 		goto isoloop;
 	}
 	return err;
+
+out:
+	FW_GUNLOCK(fc);
+	return err;
 }
+
+static void
+fw_hand(struct fw_xfer *xfer)
+{
+	struct fw_bind *fwb;
+	struct fw_drv1 *d;
+
+	fwb = (struct fw_bind *)xfer->sc;
+	d = (struct fw_drv1 *)fwb->sc;
+	FW_GLOCK(xfer->fc);
+	STAILQ_INSERT_TAIL(&d->rq, xfer, link);
+	FW_GUNLOCK(xfer->fc);
+	wakeup(&d->rq);
+}
+
 /*
  * ioctl support.
  */
 int
 fw_ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
 {
-	struct firewire_softc *sc;
 	struct firewire_comm *fc;
 	struct fw_drv1 *d;
-	int unit = DEV2UNIT(dev);
-	int s, i, len, err = 0;
+	int i, len, err = 0;
 	struct fw_device *fwdev;
 	struct fw_bind *fwb;
 	struct fw_xferq *ir, *it;
@@ -456,28 +593,25 @@
 	if (!data)
 		return(EINVAL);
 
-	sc = devclass_get_softc(firewire_devclass, unit);
-	fc = sc->fc;
 	d = (struct fw_drv1 *)dev->si_drv1;
+	fc = d->fc;
 	ir = d->ir;
 	it = d->it;
 
 	switch (cmd) {
 	case FW_STSTREAM:
 		if (it == NULL) {
-			for (i = 0; i < fc->nisodma; i ++) {
-				it = fc->it[i];
-				if ((it->flag & FWXFERQ_OPEN) == 0)
-					 break;
-	                }	
-			if (i >= fc->nisodma) {
+			i = fw_open_isodma(fc, /* tx */1);
+			if (i < 0) {
 				err = EBUSY;
 				break;
 			}
+			it = fc->it[i];
 			err = fwdev_allocbuf(fc, it, &d->bufreq.tx);
-			if (err)
+			if (err) {
+				it->flag &= ~FWXFERQ_OPEN;
 				break;
-			it->flag |=  FWXFERQ_OPEN;
+			}
 		}
 		it->flag &= ~0xff;
 		it->flag |= (0x3f & ichreq->ch);
@@ -493,19 +627,17 @@
 		break;
 	case FW_SRSTREAM:
 		if (ir == NULL) {
-			for (i = 0; i < fc->nisodma; i ++) {
-				ir = fc->ir[i];
-				if ((ir->flag & FWXFERQ_OPEN) == 0)
-					break;
-			}	
-			if (i >= fc->nisodma) {
+			i = fw_open_isodma(fc, /* tx */0);
+			if (i < 0) {
 				err = EBUSY;
 				break;
 			}
+			ir = fc->ir[i];
 			err = fwdev_allocbuf(fc, ir, &d->bufreq.rx);
-			if (err)
+			if (err) {
+				ir->flag &= ~FWXFERQ_OPEN;
 				break;
-			ir->flag |=  FWXFERQ_OPEN;
+			}
 		}
 		ir->flag &= ~0xff;
 		ir->flag |= (0x3f & ichreq->ch);
@@ -543,7 +675,7 @@
 		int pay_len = 0;
 
 		fp = &asyreq->pkt;
-		tinfo = &sc->fc->tcode[fp->mode.hdr.tcode];
+		tinfo = &fc->tcode[fp->mode.hdr.tcode];
 
 		if ((tinfo->flag & FWTI_BLOCK_ASY) != 0)
 			pay_len = MAX(0, asyreq->req.len - tinfo->hdr_len);
@@ -556,10 +688,10 @@
 		case FWASREQNODE:
 			break;
 		case FWASREQEUI:
-			fwdev = fw_noderesolve_eui64(sc->fc,
+			fwdev = fw_noderesolve_eui64(fc,
 						&asyreq->req.dst.eui);
 			if (fwdev == NULL) {
-				device_printf(sc->fc->bdev,
+				device_printf(fc->bdev,
 					"cannot find node\n");
 				err = EINVAL;
 				goto out;
@@ -579,11 +711,11 @@
 			bcopy((char *)fp + tinfo->hdr_len,
 			    (void *)xfer->send.payload, pay_len);
 		xfer->send.spd = asyreq->req.sped;
-		xfer->act.hand = fw_asy_callback;
+		xfer->hand = fw_xferwake;
 
-		if ((err = fw_asyreq(sc->fc, -1, xfer)) != 0)
+		if ((err = fw_asyreq(fc, -1, xfer)) != 0)
 			goto out;
-		if ((err = tsleep(xfer, FWPRI, "asyreq", hz)) != 0)
+		if ((err = fw_xferwait(xfer)) != 0)
 			goto out;
 		if (xfer->resp != 0) {
 			err = EIO;
@@ -593,7 +725,7 @@
 			goto out;
 
 		/* copy response */
-		tinfo = &sc->fc->tcode[xfer->recv.hdr.mode.hdr.tcode];
+		tinfo = &fc->tcode[xfer->recv.hdr.mode.hdr.tcode];
 		if (xfer->recv.hdr.mode.hdr.tcode == FWTCODE_RRESB ||
 		    xfer->recv.hdr.mode.hdr.tcode == FWTCODE_LRES) {
 			pay_len = xfer->recv.pay_len;
@@ -614,17 +746,18 @@
 		break;
 	}
 	case FW_IBUSRST:
-		sc->fc->ibr(sc->fc);
+		fc->ibr(fc);
 		break;
 	case FW_CBINDADDR:
-		fwb = fw_bindlookup(sc->fc,
+		fwb = fw_bindlookup(fc,
 				bindreq->start.hi, bindreq->start.lo);
 		if(fwb == NULL){
 			err = EINVAL;
 			break;
 		}
-		STAILQ_REMOVE(&sc->fc->binds, fwb, fw_bind, fclist);
-		STAILQ_REMOVE(&ir->binds, fwb, fw_bind, chlist);
+		fw_bindremove(fc, fwb);
+		STAILQ_REMOVE(&d->binds, fwb, fw_bind, chlist);
+		fw_xferlist_remove(&fwb->xferlist);
 		free(fwb, M_FW);
 		break;
 	case FW_SBINDADDR:
@@ -636,7 +769,7 @@
 			err = EINVAL;
 			break;
 		}
-		fwb = (struct fw_bind *)malloc(sizeof (struct fw_bind), M_FW, M_NOWAIT);
+		fwb = (struct fw_bind *)malloc(sizeof (struct fw_bind), M_FW, M_WAITOK);
 		if(fwb == NULL){
 			err = ENOMEM;
 			break;
@@ -644,34 +777,26 @@
 		fwb->start = ((u_int64_t)bindreq->start.hi << 32) |
 		    bindreq->start.lo;
 		fwb->end = fwb->start +  bindreq->len;
-		/* XXX */
-		fwb->sub = ir->dmach;
-		fwb->act_type = FWACT_CH;
-
-		/* XXX alloc buf */
-		xfer = fw_xfer_alloc(M_FWXFER);
-		if(xfer == NULL){
-			free(fwb, M_FW);
-			return (ENOMEM);
-		}
-		xfer->fc = sc->fc;
-
-		s = splfw();
-		/* XXX broken. need multiple xfer */
+		fwb->sc = (void *)d;
 		STAILQ_INIT(&fwb->xferlist);
-		STAILQ_INSERT_TAIL(&fwb->xferlist, xfer, link);
-		splx(s);
-		err = fw_bindadd(sc->fc, fwb);
+		err = fw_bindadd(fc, fwb);
+		if (err == 0) {
+			fw_xferlist_add(&fwb->xferlist, M_FWXFER,
+			    /* XXX */
+			    PAGE_SIZE, PAGE_SIZE, 5,
+			    fc, (void *)fwb, fw_hand);
+			STAILQ_INSERT_TAIL(&d->binds, fwb, chlist);
+		}
 		break;
 	case FW_GDEVLST:
 		i = len = 1;
 		/* myself */
 		devinfo = &fwdevlst->dev[0];
-		devinfo->dst = sc->fc->nodeid;
+		devinfo->dst = fc->nodeid;
 		devinfo->status = 0;	/* XXX */
-		devinfo->eui.hi = sc->fc->eui.hi;
-		devinfo->eui.lo = sc->fc->eui.lo;
-		STAILQ_FOREACH(fwdev, &sc->fc->devices, link) {
+		devinfo->eui.hi = fc->eui.hi;
+		devinfo->eui.lo = fc->eui.lo;
+		STAILQ_FOREACH(fwdev, &fc->devices, link) {
 			if(len < FW_MAX_DEVLST){
 				devinfo = &fwdevlst->dev[len++];
 				devinfo->dst = fwdev->dst;
@@ -686,15 +811,15 @@
 		fwdevlst->info_len = len;
 		break;
 	case FW_GTPMAP:
-		bcopy(sc->fc->topology_map, data,
-				(sc->fc->topology_map->crc_len + 1) * 4);
+		bcopy(fc->topology_map, data,
+				(fc->topology_map->crc_len + 1) * 4);
 		break;
 	case FW_GCROM:
-		STAILQ_FOREACH(fwdev, &sc->fc->devices, link)
+		STAILQ_FOREACH(fwdev, &fc->devices, link)
 			if (FW_EUI64_EQUAL(fwdev->eui, crom_buf->eui))
 				break;
 		if (fwdev == NULL) {
-			if (!FW_EUI64_EQUAL(sc->fc->eui, crom_buf->eui)) {
+			if (!FW_EUI64_EQUAL(fc->eui, crom_buf->eui)) {
 				err = FWNODE_INVAL;
 				break;
 			}
@@ -703,7 +828,7 @@
 			len = CROMSIZE;
 			for (i = 0; i < CROMSIZE/4; i++)
 				((uint32_t *)ptr)[i]
-					= ntohl(sc->fc->config_rom[i]);
+					= ntohl(fc->config_rom[i]);
 		} else {
 			/* found */
 			ptr = (void *)&fwdev->csrrom[0];
@@ -722,7 +847,7 @@
 			free(ptr, M_FW);
 		break;
 	default:
-		sc->fc->ioctl (dev, cmd, data, flag, td);
+		fc->ioctl (dev, cmd, data, flag, td);
 		break;
 	}
 	return err;
@@ -730,16 +855,13 @@
 int
 fw_poll(struct cdev *dev, int events, fw_proc *td)
 {
-	struct firewire_softc *sc;
 	struct fw_xferq *ir;
 	int revents;
 	int tmp;
-	int unit = DEV2UNIT(dev);
 
 	if (DEV_FWMEM(dev))
 		return fwmem_poll(dev, events, td);
 
-	sc = devclass_get_softc(firewire_devclass, unit);
 	ir = ((struct fw_drv1 *)dev->si_drv1)->ir;
 	revents = 0;
 	tmp = POLLIN | POLLRDNORM;
@@ -765,8 +887,6 @@
 fw_mmap (struct cdev *dev, vm_offset_t offset, vm_paddr_t *paddr, int nproto)
 #endif
 {  
-	struct firewire_softc *sc;
-	int unit = DEV2UNIT(dev);
 
 	if (DEV_FWMEM(dev))
 #if defined(__DragonFly__) || __FreeBSD_version < 500102
@@ -775,8 +895,6 @@
 		return fwmem_mmap(dev, offset, paddr, nproto);
 #endif
 
-	sc = devclass_get_softc(firewire_devclass, unit);
-
 	return EINVAL;
 }
 
Index: fwcrom.c
===================================================================
RCS file: /home/cvs/src/sys/dev/firewire/fwcrom.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/dev/firewire/fwcrom.c -L sys/dev/firewire/fwcrom.c -u -r1.1.1.1 -r1.2
--- sys/dev/firewire/fwcrom.c
+++ sys/dev/firewire/fwcrom.c
@@ -34,7 +34,7 @@
 
 #ifdef __FreeBSD__
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/dev/firewire/fwcrom.c,v 1.13 2004/10/22 15:39:39 simokawa Exp $");
+__FBSDID("$FreeBSD: src/sys/dev/firewire/fwcrom.c,v 1.14 2006/02/04 21:37:39 imp Exp $");
 #endif
 
 #include <sys/param.h>
@@ -409,13 +409,15 @@
 int
 crom_add_entry(struct crom_chunk *chunk, int key, int val)
 {
-	struct csrreg *reg;
-	uint32_t i;
+	union
+	{
+		struct csrreg reg;
+		uint32_t i;
+	} foo;
 	
-	reg = (struct csrreg *)&i;
-	reg->key = key;
-	reg->val = val;
-	return(crom_add_quad(chunk, (uint32_t) i));
+	foo.reg.key = key;
+	foo.reg.val = val;
+	return (crom_add_quad(chunk, foo.i));
 }
 
 int
Index: fwohci_pci.c
===================================================================
RCS file: /home/cvs/src/sys/dev/firewire/fwohci_pci.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/dev/firewire/fwohci_pci.c -L sys/dev/firewire/fwohci_pci.c -u -r1.1.1.1 -r1.2
--- sys/dev/firewire/fwohci_pci.c
+++ sys/dev/firewire/fwohci_pci.c
@@ -31,7 +31,7 @@
  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  * 
- * $FreeBSD: src/sys/dev/firewire/fwohci_pci.c,v 1.52 2005/05/20 12:37:16 marius Exp $
+ * $FreeBSD: src/sys/dev/firewire/fwohci_pci.c,v 1.60 2007/06/06 14:31:36 simokawa Exp $
  */
 
 #define BOUNCE_BUFFER_TEST	0
@@ -169,8 +169,8 @@
 		return BUS_PROBE_DEFAULT;
 	}
 	if (id == (FW_VENDORID_SONY | FW_DEVICE_CXD1947)) {
-		device_set_desc(dev, "Sony i.LINK (CXD1947)");
-		return BUS_PROBE_DEFAULT;
+		device_printf(dev, "Sony i.LINK (CXD1947) not supported\n");
+		return ENXIO;
 	}
 	if (id == (FW_VENDORID_SONY | FW_DEVICE_CXD3222)) {
 		device_set_desc(dev, "Sony i.LINK (CXD3222)");
@@ -241,11 +241,9 @@
 	uint16_t cmd;
 
 	cmd = pci_read_config(self, PCIR_COMMAND, 2);
-	cmd |= PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN | PCIM_CMD_MWRICEN |
-		PCIM_CMD_SERRESPEN | PCIM_CMD_PERRESPEN;
+	cmd |= PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN | PCIM_CMD_MWRICEN;
 #if 1  /* for broken hardware */
 	cmd &= ~PCIM_CMD_MWRICEN; 
-	cmd &= ~(PCIM_CMD_SERRESPEN | PCIM_CMD_PERRESPEN);
 #endif
 	pci_write_config(self, PCIR_COMMAND, cmd, 2);
 
@@ -304,6 +302,7 @@
 		firewire_debug = bootverbose;
 #endif
 
+	mtx_init(FW_GMTX(&sc->fc), "firewire", NULL, MTX_DEF);
 	fwohci_pci_init(self);
 
 	rid = PCI_CBMEM;
@@ -337,12 +336,12 @@
 
 
 	err = bus_setup_intr(self, sc->irq_res,
-#if FWOHCI_TASKQUEUE
 			INTR_TYPE_NET | INTR_MPSAFE,
+#if FWOHCI_INTFILT
+		     fwohci_filt, NULL, sc, &sc->ih);
 #else
-			INTR_TYPE_NET,
+		     NULL, (driver_intr_t *) fwohci_intr, sc, &sc->ih);
 #endif
-		     (driver_intr_t *) fwohci_intr, sc, &sc->ih);
 #if defined(__DragonFly__) || __FreeBSD_version < 500000
 	/* XXX splcam() should mask this irq for sbp.c*/
 	err = bus_setup_intr(self, sc->irq_res, INTR_TYPE_CAM,
@@ -357,7 +356,13 @@
 		return ENXIO;
 	}
 
-	err = bus_dma_tag_create(/*parent*/NULL, /*alignment*/1,
+	err = bus_dma_tag_create(
+#if defined(__FreeBSD__) && __FreeBSD_version >= 700020
+				/*parent*/bus_get_dma_tag(self),
+#else
+				/*parent*/NULL,
+#endif
+				/*alignment*/1,
 				/*boundary*/0,
 #if BOUNCE_BUFFER_TEST
 				/*lowaddr*/BUS_SPACE_MAXADDR_24BIT,
@@ -372,7 +377,7 @@
 				/*flags*/BUS_DMA_ALLOCNOW,
 #if defined(__FreeBSD__) && __FreeBSD_version >= 501102
 				/*lockfunc*/busdma_lock_mutex,
-				/*lockarg*/&Giant,
+				/*lockarg*/FW_GMTX(&sc->fc),
 #endif
 				&sc->fc.dmat);
 	if (err != 0) {
@@ -420,19 +425,18 @@
 				  FWOHCI_INTMASKCLR, OHCI_INT_EN);
 
 	if (sc->irq_res) {
-		int err = bus_teardown_intr(self, sc->irq_res, sc->ih);
-		if (err)
-			/* XXX or should we panic? */
-			device_printf(self, "Could not tear down irq, %d\n",
-				      err);
+		int err;
+		if (sc->ih) {
+			err = bus_teardown_intr(self, sc->irq_res, sc->ih);
+			if (err)
+				device_printf(self,
+					 "Could not tear down irq, %d\n", err);
 #if defined(__DragonFly__) || __FreeBSD_version < 500000
-		bus_teardown_intr(self, sc->irq_res, sc->ih_cam);
-		bus_teardown_intr(self, sc->irq_res, sc->ih_bio);
+			bus_teardown_intr(self, sc->irq_res, sc->ih_cam);
+			bus_teardown_intr(self, sc->irq_res, sc->ih_bio);
 #endif
-		sc->ih = NULL;
-	}
-
-	if (sc->irq_res) {
+			sc->ih = NULL;
+		}
 		bus_release_resource(self, SYS_RES_IRQ, 0, sc->irq_res);
 		sc->irq_res = NULL;
 	}
@@ -445,6 +449,7 @@
 	}
 
 	fwohci_detach(sc, self);
+	mtx_destroy(FW_GMTX(&sc->fc));
 	splx(s);
 
 	return 0;
@@ -489,7 +494,7 @@
 {
 	struct fwohci_softc *sc;
 	device_t child;
-	int s, err = 0;
+	int err = 0;
 
 	sc = (struct fwohci_softc *)device_get_softc(dev);
 	child = device_add_child(dev, name, unit);
@@ -512,10 +517,13 @@
 	 * Clear the bus reset event flag to start transactions even when
 	 * interrupt is disabled during the boot process.
 	 */
-	DELAY(250); /* 2 cycles */
-	s = splfw();
-	fwohci_poll((void *)sc, 0, -1);
-	splx(s);
+	if (cold) {
+		int s;
+		DELAY(250); /* 2 cycles */
+		s = splfw();
+		fwohci_poll((void *)sc, 0, -1);
+		splx(s);
+	}
 
 	return (child);
 }
Index: fwohcireg.h
===================================================================
RCS file: /home/cvs/src/sys/dev/firewire/fwohcireg.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/dev/firewire/fwohcireg.h -L sys/dev/firewire/fwohcireg.h -u -r1.1.1.1 -r1.2
--- sys/dev/firewire/fwohcireg.h
+++ sys/dev/firewire/fwohcireg.h
@@ -31,7 +31,7 @@
  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  * 
- * $FreeBSD: src/sys/dev/firewire/fwohcireg.h,v 1.22 2005/05/20 12:37:16 marius Exp $
+ * $FreeBSD: src/sys/dev/firewire/fwohcireg.h,v 1.23 2007/04/30 14:06:30 simokawa Exp $
  *
  */
 #define		PCI_CBMEM		PCIR_BAR(0)
@@ -396,8 +396,13 @@
 	}mode;
 };
 struct fwohci_trailer{
+#if BYTE_ORDER == BIG_ENDIAN
+	uint32_t stat:16,
+		  time:16;
+#else
 	uint32_t time:16,
 		  stat:16;
+#endif
 };
 
 #define	OHCI_CNTL_CYCSRC	(0x1 << 22)
Index: firewire.c
===================================================================
RCS file: /home/cvs/src/sys/dev/firewire/firewire.c,v
retrieving revision 1.3
retrieving revision 1.4
diff -L sys/dev/firewire/firewire.c -L sys/dev/firewire/firewire.c -u -r1.3 -r1.4
--- sys/dev/firewire/firewire.c
+++ sys/dev/firewire/firewire.c
@@ -31,7 +31,7 @@
  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  * 
- * $FreeBSD: src/sys/dev/firewire/firewire.c,v 1.80.2.1 2005/11/28 06:41:40 simokawa Exp $
+ * $FreeBSD: src/sys/dev/firewire/firewire.c,v 1.100 2007/07/20 03:42:57 simokawa Exp $
  *
  */
 
@@ -44,6 +44,9 @@
 #include <sys/malloc.h>
 #include <sys/conf.h>
 #include <sys/sysctl.h>
+#include <sys/kthread.h>
+
+#include <sys/kdb.h>
 
 #if defined(__DragonFly__) || __FreeBSD_version < 500000
 #include <machine/clock.h>	/* for DELAY() */
@@ -94,6 +97,7 @@
 static int firewire_attach      (device_t);
 static int firewire_detach      (device_t);
 static int firewire_resume      (device_t);
+static void firewire_xfer_timeout(void *, int);
 #if 0
 static int firewire_shutdown    (device_t);
 #endif
@@ -103,15 +107,13 @@
 static void fw_asystart (struct fw_xfer *);
 static int fw_get_tlabel (struct firewire_comm *, struct fw_xfer *);
 static void fw_bus_probe (struct firewire_comm *);
-static void fw_bus_explore (struct firewire_comm *);
-static void fw_bus_explore_callback (struct fw_xfer *);
 static void fw_attach_dev (struct firewire_comm *);
+static void fw_bus_probe_thread(void *);
 #ifdef FW_VMACCESS
 static void fw_vmaccess (struct fw_xfer *);
 #endif
-struct fw_xfer *asyreqq (struct firewire_comm *, uint8_t, uint8_t, uint8_t,
-	uint32_t, uint32_t, void (*)(struct fw_xfer *));
 static int fw_bmr (struct firewire_comm *);
+static void fw_dump_hdr(struct fw_pkt *, char *);
 
 static device_method_t firewire_methods[] = {
 	/* Device interface */
@@ -180,9 +182,11 @@
 	int s;
 
 	s = splfw();
+	FW_GLOCK(fc);
 	STAILQ_FOREACH(fwdev, &fc->devices, link)
 		if (FW_EUI64_EQUAL(fwdev->eui, *eui))
 			break;
+	FW_GUNLOCK(fc);
 	splx(s);
 
 	if(fwdev == NULL) return NULL;
@@ -198,14 +202,14 @@
 {
 	int err = 0;
 	struct fw_xferq *xferq;
-	int tl = 0, len;
+	int len;
 	struct fw_pkt *fp;
 	int tcode;
 	struct tcode_info *info;
 
 	if(xfer == NULL) return EINVAL;
-	if(xfer->act.hand == NULL){
-		printf("act.hand == NULL\n");
+	if(xfer->hand == NULL){
+		printf("hand == NULL\n");
 		return EINVAL;
 	}
 	fp = &xfer->send.hdr;
@@ -216,6 +220,17 @@
 		printf("invalid tcode=%x\n", tcode);
 		return EINVAL;
 	}
+
+	/* XXX allow bus explore packets only after bus rest */
+	if ((fc->status < FWBUSEXPLORE) &&
+	    ((tcode != FWTCODE_RREQQ) || (fp->mode.rreqq.dest_hi != 0xffff) ||
+	    (fp->mode.rreqq.dest_lo  < 0xf0000000) ||
+	    (fp->mode.rreqq.dest_lo >= 0xf0001000))) {
+		xfer->resp = EAGAIN;
+		xfer->flag = FWXF_BUSY;
+		return (EAGAIN);
+	}
+
 	if (info->flag & FWTI_REQ)
 		xferq = fc->atq;
 	else
@@ -244,20 +259,18 @@
 	if(!(xferq->queued < xferq->maxq)){
 		device_printf(fc->bdev, "Discard a packet (queued=%d)\n",
 			xferq->queued);
-		return EINVAL;
+		return EAGAIN;
 	}
 
+	xfer->tl = -1;
 	if (info->flag & FWTI_TLABEL) {
-		if ((tl = fw_get_tlabel(fc, xfer)) == -1)
+		if (fw_get_tlabel(fc, xfer) < 0)
 			return EAGAIN;
-		fp->mode.hdr.tlrt = tl << 2;
 	}
 
-	xfer->tl = tl;
 	xfer->resp = 0;
 	xfer->fc = fc;
 	xfer->q = xferq;
-	xfer->retry_req = fw_asybusy;
 
 	fw_asystart(xfer);
 	return err;
@@ -266,23 +279,30 @@
  * Wakeup blocked process.
  */
 void
-fw_asy_callback(struct fw_xfer *xfer){
+fw_xferwake(struct fw_xfer *xfer)
+{
+	struct mtx *lock = &xfer->fc->wait_lock;
+
+	mtx_lock(lock);
+	xfer->flag |= FWXF_WAKE;
+	mtx_unlock(lock);
+
 	wakeup(xfer);
 	return;
 }
-/*
- * Postpone to later retry.
- */
-void fw_asybusy(struct fw_xfer *xfer){
-	printf("fw_asybusy\n");
-/*
-	xfer->ch =  timeout((timeout_t *)fw_asystart, (void *)xfer, 20000);
-*/
-#if 0
-	DELAY(20000);
-#endif
-	fw_asystart(xfer);
-	return;
+
+int
+fw_xferwait(struct fw_xfer *xfer)
+{
+	struct mtx *lock = &xfer->fc->wait_lock;
+	int err = 0;
+
+	mtx_lock(lock);
+	if ((xfer->flag & FWXF_WAKE) == 0)
+		err = msleep((void *)xfer, lock, PWAIT|PCATCH, "fw_xferwait", 0);
+	mtx_unlock(lock);
+
+	return (err);
 }
 
 /*
@@ -293,27 +313,15 @@
 {
 	struct firewire_comm *fc = xfer->fc;
 	int s;
-	if(xfer->retry++ >= fc->max_asyretry){
-		device_printf(fc->bdev, "max_asyretry exceeded\n");
-		xfer->resp = EBUSY;
-		xfer->state = FWXF_BUSY;
-		xfer->act.hand(xfer);
-		return;
-	}
-#if 0 /* XXX allow bus explore packets only after bus rest */
-	if (fc->status < FWBUSEXPLORE) {
-		xfer->resp = EAGAIN;
-		xfer->state = FWXF_BUSY;
-		if (xfer->act.hand != NULL)
-			xfer->act.hand(xfer);
-		return;
-	}
-#endif
-	microtime(&xfer->tv);
 	s = splfw();
-	xfer->state = FWXF_INQ;
+	/* Protect from interrupt/timeout */
+	FW_GLOCK(fc);
+	xfer->flag = FWXF_INQ;
 	STAILQ_INSERT_TAIL(&xfer->q->q, xfer, link);
+#if 0
 	xfer->q->queued ++;
+#endif
+	FW_GUNLOCK(fc);
 	splx(s);
 	/* XXX just queue for mbuf */
 	if (xfer->mbuf == NULL)
@@ -335,12 +343,13 @@
 }
 
 static void
-firewire_xfer_timeout(struct firewire_comm *fc)
+firewire_xfer_timeout(void *arg, int pending)
 {
-	struct fw_xfer *xfer;
-	struct tlabel *tl;
+	struct firewire_comm *fc = (struct firewire_comm *)arg;
+	struct fw_xfer *xfer, *txfer;
 	struct timeval tv;
 	struct timeval split_timeout;
+	STAILQ_HEAD(, fw_xfer) xfer_timeout;
 	int i, s;
 
 	split_timeout.tv_sec = 0;
@@ -348,34 +357,41 @@
 
 	microtime(&tv);
 	timevalsub(&tv, &split_timeout);
+	STAILQ_INIT(&xfer_timeout);
 
 	s = splfw();
+	mtx_lock(&fc->tlabel_lock);
 	for (i = 0; i < 0x40; i ++) {
-		while ((tl = STAILQ_FIRST(&fc->tlabels[i])) != NULL) {
-			xfer = tl->xfer;
+		while ((xfer = STAILQ_FIRST(&fc->tlabels[i])) != NULL) {
+			if ((xfer->flag & FWXF_SENT) == 0)
+				/* not sent yet */
+				break;
 			if (timevalcmp(&xfer->tv, &tv, >))
 				/* the rests are newer than this */
 				break;
-			if (xfer->state == FWXF_START)
-				/* not sent yet */
-				break;
 			device_printf(fc->bdev,
-				"split transaction timeout dst=0x%x tl=0x%x state=%d\n",
-				xfer->send.hdr.mode.hdr.dst, i, xfer->state);
+				"split transaction timeout: "
+				"tl=0x%x flag=0x%02x\n", i, xfer->flag);
+			fw_dump_hdr(&xfer->send.hdr, "send");
 			xfer->resp = ETIMEDOUT;
-			STAILQ_REMOVE_HEAD(&fc->tlabels[i], link);
-			fw_xfer_done(xfer);
+			STAILQ_REMOVE_HEAD(&fc->tlabels[i], tlabel);
+			STAILQ_INSERT_TAIL(&xfer_timeout, xfer, tlabel);
 		}
 	}
+	mtx_unlock(&fc->tlabel_lock);
 	splx(s);
+	fc->timeout(fc);
+
+	STAILQ_FOREACH_SAFE(xfer, &xfer_timeout, tlabel, txfer)
+		xfer->hand(xfer);	
 }
 
-#define WATCHDOC_HZ 10
+#define WATCHDOG_HZ 10
 static void
 firewire_watchdog(void *arg)
 {
 	struct firewire_comm *fc;
-	static int watchdoc_clock = 0;
+	static int watchdog_clock = 0;
 
 	fc = (struct firewire_comm *)arg;
 
@@ -384,13 +400,12 @@
 	 * We encounter a timeout easily. To avoid this,
 	 * ignore clock interrupt for a while.
 	 */
-	if (watchdoc_clock > WATCHDOC_HZ * 15) {
-		firewire_xfer_timeout(fc);
-		fc->timeout(fc);
-	} else
-		watchdoc_clock ++;
+	if (watchdog_clock > WATCHDOG_HZ * 15)
+		taskqueue_enqueue(fc->taskqueue, &fc->task_timeout);
+	else
+		watchdog_clock ++;
 
-	callout_reset(&fc->timeout_callout, hz / WATCHDOC_HZ,
+	callout_reset(&fc->timeout_callout, hz / WATCHDOG_HZ,
 			(void *)firewire_watchdog, (void *)fc);
 }
 
@@ -414,14 +429,20 @@
 
 	fwdev_makedev(sc);
 
-	CALLOUT_INIT(&sc->fc->timeout_callout);
-	CALLOUT_INIT(&sc->fc->bmr_callout);
-	CALLOUT_INIT(&sc->fc->retry_probe_callout);
-	CALLOUT_INIT(&sc->fc->busprobe_callout);
+	mtx_init(&fc->wait_lock, "fwwait", NULL, MTX_DEF);
+	mtx_init(&fc->tlabel_lock, "fwtlabel", NULL, MTX_DEF);
+	CALLOUT_INIT(&fc->timeout_callout);
+	CALLOUT_INIT(&fc->bmr_callout);
+	CALLOUT_INIT(&fc->busprobe_callout);
+	TASK_INIT(&fc->task_timeout, 0, firewire_xfer_timeout, (void *)fc);
 
 	callout_reset(&sc->fc->timeout_callout, hz,
 			(void *)firewire_watchdog, (void *)sc->fc);
 
+	/* create thread */
+	kthread_create(fw_bus_probe_thread, (void *)fc, &fc->probe_thread,
+		0, 0, "fw%d_probe", unit);
+
 	/* Locate our children */
 	bus_generic_probe(dev);
 
@@ -474,35 +495,41 @@
 firewire_detach(device_t dev)
 {
 	struct firewire_softc *sc;
-	struct csrdir *csrd, *next;
+	struct firewire_comm *fc;
 	struct fw_device *fwdev, *fwdev_next;
 	int err;
 
 	sc = (struct firewire_softc *)device_get_softc(dev);
+	fc = sc->fc;
+	mtx_lock(&fc->wait_lock);
+	fc->status = FWBUSDETACH;
+	wakeup(fc);
+	if (msleep(fc->probe_thread, &fc->wait_lock, PWAIT, "fwthr", hz * 60))
+		printf("firewire probe thread didn't die\n");
+	mtx_unlock(&fc->wait_lock);
+
 	if ((err = fwdev_destroydev(sc)) != 0)
 		return err;
 
 	if ((err = bus_generic_detach(dev)) != 0)
 		return err;
 
-	callout_stop(&sc->fc->timeout_callout);
-	callout_stop(&sc->fc->bmr_callout);
-	callout_stop(&sc->fc->retry_probe_callout);
-	callout_stop(&sc->fc->busprobe_callout);
+	callout_stop(&fc->timeout_callout);
+	callout_stop(&fc->bmr_callout);
+	callout_stop(&fc->busprobe_callout);
 
 	/* XXX xfree_free and untimeout on all xfers */
-	for (fwdev = STAILQ_FIRST(&sc->fc->devices); fwdev != NULL;
+	for (fwdev = STAILQ_FIRST(&fc->devices); fwdev != NULL;
 							fwdev = fwdev_next) {
 		fwdev_next = STAILQ_NEXT(fwdev, link);
 		free(fwdev, M_FW);
 	}
-	for (csrd = SLIST_FIRST(&sc->fc->csrfree); csrd != NULL; csrd = next) {
-		next = SLIST_NEXT(csrd, link);
-		free(csrd, M_FW);
-	}
-	free(sc->fc->topology_map, M_FW);
-	free(sc->fc->speed_map, M_FW);
-	free(sc->fc->crom_src_buf, M_FW);
+	free(fc->topology_map, M_FW);
+	free(fc->speed_map, M_FW);
+	free(fc->crom_src_buf, M_FW);
+
+	mtx_destroy(&fc->tlabel_lock);
+	mtx_destroy(&fc->wait_lock);
 	return(0);
 }
 #if 0
@@ -521,8 +548,11 @@
 
 	while ((xfer = STAILQ_FIRST(&xferq->q)) != NULL) {
 		STAILQ_REMOVE_HEAD(&xferq->q, link);
+#if 0
 		xferq->queued --;
+#endif
 		xfer->resp = EAGAIN;
+		xfer->flag = FWXF_SENTERR;
 		fw_xfer_done(xfer);
 	}
 }
@@ -530,12 +560,32 @@
 void
 fw_drain_txq(struct firewire_comm *fc)
 {
+	struct fw_xfer *xfer, *txfer;
+	STAILQ_HEAD(, fw_xfer) xfer_drain;
 	int i;
 
+	STAILQ_INIT(&xfer_drain);
+
+	FW_GLOCK(fc);
 	fw_xferq_drain(fc->atq);
 	fw_xferq_drain(fc->ats);
 	for(i = 0; i < fc->nisodma; i++)
 		fw_xferq_drain(fc->it[i]);
+	FW_GUNLOCK(fc);
+
+	mtx_lock(&fc->tlabel_lock);
+	for (i = 0; i < 0x40; i ++)
+		while ((xfer = STAILQ_FIRST(&fc->tlabels[i])) != NULL) {
+			if (firewire_debug)
+				printf("tl=%d flag=%d\n", i, xfer->flag);
+			xfer->resp = EAGAIN;
+			STAILQ_REMOVE_HEAD(&fc->tlabels[i], tlabel);
+			STAILQ_INSERT_TAIL(&xfer_drain, xfer, tlabel);
+		}
+	mtx_unlock(&fc->tlabel_lock);
+
+	STAILQ_FOREACH_SAFE(xfer, &xfer_drain, tlabel, txfer)
+		xfer->hand(xfer);	
 }
 
 static void
@@ -704,14 +754,11 @@
 void fw_init(struct firewire_comm *fc)
 {
 	int i;
-	struct csrdir *csrd;
 #ifdef FW_VMACCESS
 	struct fw_xfer *xfer;
 	struct fw_bind *fwb;
 #endif
 
-	fc->max_asyretry = FW_MAXASYRTY;
-
 	fc->arq->queued = 0;
 	fc->ars->queued = 0;
 	fc->atq->queued = 0;
@@ -745,9 +792,6 @@
 
 		STAILQ_INIT(&fc->it[i]->q);
 		STAILQ_INIT(&fc->ir[i]->q);
-
-		STAILQ_INIT(&fc->it[i]->binds);
-		STAILQ_INIT(&fc->ir[i]->binds);
 	}
 
 	fc->arq->maxq = FWMAXQUEUE;
@@ -773,15 +817,6 @@
 
 	STAILQ_INIT(&fc->devices);
 
-/* Initialize csr ROM work space */
-	SLIST_INIT(&fc->ongocsr);
-	SLIST_INIT(&fc->csrfree);
-	for( i = 0 ; i < FWMAXCSRDIR ; i++){
-		csrd = (struct csrdir *) malloc(sizeof(struct csrdir), M_FW,M_NOWAIT);
-		if(csrd == NULL) break;
-		SLIST_INSERT_HEAD(&fc->csrfree, csrd, link);
-	}
-
 /* Initialize Async handlers */
 	STAILQ_INIT(&fc->binds);
 	for( i = 0 ; i < 0x40 ; i++){
@@ -814,7 +849,7 @@
 		fw_xfer_free(xfer);
 		return;
 	}
-	xfer->act.hand = fw_vmaccess;
+	xfer->hand = fw_vmaccess;
 	xfer->fc = fc;
 	xfer->sc = NULL;
 
@@ -836,13 +871,17 @@
 fw_bindlookup(struct firewire_comm *fc, uint16_t dest_hi, uint32_t dest_lo)
 {
 	u_int64_t addr;
-	struct fw_bind *tfw;
+	struct fw_bind *tfw, *r = NULL;
 
 	addr = ((u_int64_t)dest_hi << 32) | dest_lo;
+	FW_GLOCK(fc);
 	STAILQ_FOREACH(tfw, &fc->binds, fclist)
-		if (tfw->act_type != FWACT_NULL && BIND_CMP(addr, tfw) == 0)
-			return(tfw);
-	return(NULL);
+		if (BIND_CMP(addr, tfw) == 0) {
+			r = tfw;
+			break;
+		}
+	FW_GUNLOCK(fc);
+	return(r);
 }
 
 /*
@@ -852,33 +891,29 @@
 fw_bindadd(struct firewire_comm *fc, struct fw_bind *fwb)
 {
 	struct fw_bind *tfw, *prev = NULL;
+	int r = 0;
 
 	if (fwb->start > fwb->end) {
 		printf("%s: invalid range\n", __func__);
 		return EINVAL;
 	}
 
+	FW_GLOCK(fc);
 	STAILQ_FOREACH(tfw, &fc->binds, fclist) {
 		if (fwb->end < tfw->start)
 			break;
 		prev = tfw;
 	}
-	if (prev == NULL) {
+	if (prev == NULL)
 		STAILQ_INSERT_HEAD(&fc->binds, fwb, fclist);
-		goto out;
-	}
-	if (prev->end < fwb->start) {
+	else if (prev->end < fwb->start)
 		STAILQ_INSERT_AFTER(&fc->binds, prev, fwb, fclist);
-		goto out;
+	else {
+		printf("%s: bind failed\n", __func__);
+		r = EBUSY;
 	}
-
-	printf("%s: bind failed\n", __func__);
-	return (EBUSY);
-
-out:
-	if (fwb->act_type == FWACT_CH)
-		STAILQ_INSERT_HEAD(&fc->ir[fwb->sub]->binds, fwb, chlist);
-	return (0);
+	FW_GUNLOCK(fc);
+	return (r);
 }
 
 /*
@@ -894,6 +929,7 @@
 	int s;
 
 	s = splfw();
+	FW_GLOCK(fc);
 	STAILQ_FOREACH(tfw, &fc->binds, fclist)
 		if (tfw == fwb) {
 			STAILQ_REMOVE(&fc->binds, fwb, fw_bind, fclist);
@@ -901,6 +937,7 @@
 		}
 
 	printf("%s: no such binding\n", __func__);
+	FW_GUNLOCK(fc);
 	splx(s);
 	return (1);
 found:
@@ -912,29 +949,92 @@
 	}
 	STAILQ_INIT(&fwb->xferlist);
 #endif
+	FW_GUNLOCK(fc);
 
 	splx(s);
 	return 0;
 }
 
+int
+fw_xferlist_add(struct fw_xferlist *q, struct malloc_type *type,
+    int slen, int rlen, int n,
+    struct firewire_comm *fc, void *sc, void (*hand)(struct fw_xfer *))
+{
+	int i, s;
+	struct fw_xfer *xfer;
+
+	for (i = 0; i < n; i++) {
+		xfer = fw_xfer_alloc_buf(type, slen, rlen);
+		if (xfer == NULL)
+			return (n);
+		xfer->fc = fc;
+		xfer->sc = sc;
+		xfer->hand = hand;
+		s = splfw();
+		STAILQ_INSERT_TAIL(q, xfer, link);
+		splx(s);
+	}
+	return (n);
+}
+
+void
+fw_xferlist_remove(struct fw_xferlist *q)
+{
+	struct fw_xfer *xfer, *next;
+
+	for (xfer = STAILQ_FIRST(q); xfer != NULL; xfer = next) {
+                next = STAILQ_NEXT(xfer, link);
+                fw_xfer_free_buf(xfer);
+        }
+        STAILQ_INIT(q);
+}
+/*
+ * dump packet header
+ */
+static void
+fw_dump_hdr(struct fw_pkt *fp, char *prefix)
+{
+	printf("%s: dst=0x%02x tl=0x%02x rt=%d tcode=0x%x pri=0x%x "
+	    "src=0x%03x\n", prefix,
+	    fp->mode.hdr.dst & 0x3f,
+	    fp->mode.hdr.tlrt >> 2, fp->mode.hdr.tlrt & 3,
+	    fp->mode.hdr.tcode, fp->mode.hdr.pri,
+	    fp->mode.hdr.src);
+}
+
 /*
  * To free transaction label.
  */
 static void
 fw_tl_free(struct firewire_comm *fc, struct fw_xfer *xfer)
 {
-	struct tlabel *tl;
-	int s = splfw();
+	struct fw_xfer *txfer;
+	int s;
 
-	for( tl = STAILQ_FIRST(&fc->tlabels[xfer->tl]); tl != NULL;
-		tl = STAILQ_NEXT(tl, link)){
-		if(tl->xfer == xfer){
-			STAILQ_REMOVE(&fc->tlabels[xfer->tl], tl, tlabel, link);
-			free(tl, M_FW);
-			splx(s);
-			return;
-		}
+	if (xfer->tl < 0)
+		return;
+
+	s = splfw();
+	mtx_lock(&fc->tlabel_lock);
+#if 1	/* make sure the label is allocated */
+	STAILQ_FOREACH(txfer, &fc->tlabels[xfer->tl], tlabel)
+		if(txfer == xfer)
+			break;
+	if (txfer == NULL) {
+		printf("%s: the xfer is not in the queue "
+		    "(tlabel=%d, flag=0x%x)\n",
+		    __FUNCTION__, xfer->tl, xfer->flag);
+		fw_dump_hdr(&xfer->send.hdr, "send");
+		fw_dump_hdr(&xfer->recv.hdr, "recv");
+		kdb_backtrace();
+		mtx_unlock(&fc->tlabel_lock);
+		splx(s);
+		return;
 	}
+#endif
+
+	STAILQ_REMOVE(&fc->tlabels[xfer->tl], xfer, fw_xfer, tlabel);
+	mtx_unlock(&fc->tlabel_lock);
 	splx(s);
 	return;
 }
@@ -943,22 +1043,33 @@
  * To obtain XFER structure by transaction label.
  */
 static struct fw_xfer *
-fw_tl2xfer(struct firewire_comm *fc, int node, int tlabel)
+fw_tl2xfer(struct firewire_comm *fc, int node, int tlabel, int tcode)
 {
 	struct fw_xfer *xfer;
-	struct tlabel *tl;
 	int s = splfw();
+	int req;
 
-	for( tl = STAILQ_FIRST(&fc->tlabels[tlabel]); tl != NULL;
-		tl = STAILQ_NEXT(tl, link)){
-		if(tl->xfer->send.hdr.mode.hdr.dst == node){
-			xfer = tl->xfer;
+	mtx_lock(&fc->tlabel_lock);
+	STAILQ_FOREACH(xfer, &fc->tlabels[tlabel], tlabel)
+		if(xfer->send.hdr.mode.hdr.dst == node) {
+			mtx_unlock(&fc->tlabel_lock);
 			splx(s);
+			KASSERT(xfer->tl == tlabel,
+				("xfer->tl 0x%x != 0x%x", xfer->tl, tlabel));
+			/* extra sanity check */
+			req = xfer->send.hdr.mode.hdr.tcode;
+			if (xfer->fc->tcode[req].valid_res != tcode) {
+				printf("%s: invalid response tcode "
+				    "(0x%x for 0x%x)\n", __FUNCTION__,
+				    tcode, req);
+				return(NULL);
+			}
+			
 			if (firewire_debug > 2)
 				printf("fw_tl2xfer: found tl=%d\n", tlabel);
 			return(xfer);
 		}
-	}
+	mtx_unlock(&fc->tlabel_lock);
 	if (firewire_debug > 1)
 		printf("fw_tl2xfer: not found tl=%d\n", tlabel);
 	splx(s);
@@ -1017,15 +1128,16 @@
 void
 fw_xfer_done(struct fw_xfer *xfer)
 {
-	if (xfer->act.hand == NULL) {
-		printf("act.hand == NULL\n");
+	if (xfer->hand == NULL) {
+		printf("hand == NULL\n");
 		return;
 	}
 
 	if (xfer->fc == NULL)
 		panic("fw_xfer_done: why xfer->fc is NULL?");
 
-	xfer->act.hand(xfer);
+	fw_tl_free(xfer->fc, xfer);
+	xfer->hand(xfer);
 }
 
 void
@@ -1034,16 +1146,20 @@
 	int s;
 
 	if(xfer == NULL ) return;
-	if(xfer->state == FWXF_INQ){
+	if(xfer->flag & FWXF_INQ){
 		printf("fw_xfer_free FWXF_INQ\n");
 		s = splfw();
+		FW_GLOCK(xfer->fc);
 		STAILQ_REMOVE(&xfer->q->q, xfer, fw_xfer, link);
+#if 0
 		xfer->q->queued --;
+#endif
+		FW_GUNLOCK(xfer->fc);
 		splx(s);
 	}
 	if (xfer->fc != NULL) {
 #if 1
-		if(xfer->state == FWXF_START)
+		if(xfer->flag & FWXF_START)
 			/*
 			 * This could happen if:
 			 *  1. We call fwohci_arcv() before fwohci_txd().
@@ -1051,11 +1167,9 @@
 			 */
 			printf("fw_xfer_free FWXF_START\n");
 #endif
-		fw_tl_free(xfer->fc, xfer);
 	}
-	xfer->state = FWXF_INIT;
+	xfer->flag = FWXF_INIT;
 	xfer->resp = 0;
-	xfer->retry = 0;
 }
 /*
  * To free IEEE1394 XFER structure. 
@@ -1092,8 +1206,8 @@
 fw_asy_callback_free(struct fw_xfer *xfer)
 {
 #if 0
-	printf("asyreq done state=%d resp=%d\n",
-				xfer->state, xfer->resp);
+	printf("asyreq done flag=0x%02x resp=%d\n",
+				xfer->flag, xfer->resp);
 #endif
 	fw_xfer_free(xfer);
 }
@@ -1113,8 +1227,7 @@
 	if (xfer == NULL)
 		return;
 	xfer->fc = fc;
-	xfer->retry_req = fw_asybusy;
-	xfer->act.hand = fw_asy_callback_free;
+	xfer->hand = fw_asy_callback_free;
 
 	fp = &xfer->send.hdr;
 	fp->mode.ld[1] = 0;
@@ -1160,7 +1273,6 @@
 	u_int i, j, node, c_port = 0, i_branch = 0;
 
 	fc->sid_cnt = len /(sizeof(uint32_t) * 2);
-	fc->status = FWBUSINIT;
 	fc->max_node = fc->nodeid & 0x3f;
 	CSRARC(fc, NODE_IDS) = ((uint32_t)fc->nodeid) << 16;
 	fc->status = FWBUSCYMELECT;
@@ -1277,7 +1389,6 @@
 
 	s = splfw();
 	fc->status = FWBUSEXPLORE;
-	fc->retry_count = 0;
 
 	/* Invalidate all devices, just after bus reset. */
 	STAILQ_FOREACH(fwdev, &fc->devices, link)
@@ -1285,105 +1396,146 @@
 			fwdev->status = FWDEVINVAL;
 			fwdev->rcnt = 0;
 		}
-
-	fc->ongonode = 0;
-	fc->ongoaddr = CSRROMOFF;
-	fc->ongodev = NULL;
-	fc->ongoeui.hi = 0xffffffff; fc->ongoeui.lo = 0xffffffff;
-	fw_bus_explore(fc);
 	splx(s);
+
+	wakeup((void *)fc);
 }
 
-/*
- * Find the self_id packet for a node, ignoring sequels.
- */
-static union fw_self_id *
-fw_find_self_id(struct firewire_comm *fc, int node)
+static int
+fw_explore_read_quads(struct fw_device *fwdev, int offset,
+    uint32_t *quad, int n)
 {
-	uint32_t i;
-	union fw_self_id *s;
+	struct fw_xfer *xfer;
+	uint32_t tmp;
+	int i, error;
 
-	for (i = 0; i < fc->topology_map->self_id_count; i++) {
-		s = &fc->topology_map->self_id[i];
-		if (s->p0.sequel)
-			continue;
-		if (s->p0.phy_id == node)
-			return s;
+	for (i = 0; i < n; i ++, offset += sizeof(uint32_t)) {
+		xfer = fwmem_read_quad(fwdev, NULL, -1,
+		    0xffff, 0xf0000000 | offset, (void *)&tmp,
+		    fw_xferwake);
+		if (xfer == NULL)
+			return (-1);
+		fw_xferwait(xfer);
+
+		if (xfer->resp == 0)
+			quad[i] = ntohl(tmp);
+
+		error = xfer->resp;
+		fw_xfer_free(xfer);
+		if (error)
+			return (error);
 	}
-	return 0;
+	return (0);
 }
 
-/*
- * To collect device informations on the IEEE1394 bus. 
- */
-static void
-fw_bus_explore(struct firewire_comm *fc )
-{
-	int err = 0;
-	struct fw_device *fwdev, *pfwdev, *tfwdev;
-	uint32_t addr;
-	struct fw_xfer *xfer;
-	struct fw_pkt *fp;
-	union fw_self_id *fwsid;
 
-	if(fc->status != FWBUSEXPLORE)
-		return;
+static int
+fw_explore_csrblock(struct fw_device *fwdev, int offset, int recur)
+{
+	int err, i, off;
+	struct csrdirectory *dir;
+	struct csrreg *reg;
+
+	dir = (struct csrdirectory *)&fwdev->csrrom[offset/sizeof(uint32_t)];
+	err = fw_explore_read_quads(fwdev, CSRROMOFF + offset,
+	    (uint32_t *)dir, 1);
+	if (err)
+		return (-1);
+
+	offset += sizeof(uint32_t);
+	reg = (struct csrreg *)&fwdev->csrrom[offset/sizeof(uint32_t)];
+	err = fw_explore_read_quads(fwdev, CSRROMOFF + offset,
+	    (uint32_t *)reg, dir->crc_len);
+	if (err)
+		return (-1);
+
+	/* XXX check CRC */
+
+	off = CSRROMOFF + offset + sizeof(uint32_t) * (dir->crc_len - 1);
+	if (fwdev->rommax < off)
+		fwdev->rommax = off;
+
+	if (recur == 0)
+		return (0);
+
+	for (i = 0; i < dir->crc_len; i ++, offset += sizeof(uint32_t)) {
+		if ((reg[i].key & CSRTYPE_MASK) == CSRTYPE_D)
+			recur = 1;
+		else if ((reg[i].key & CSRTYPE_MASK) == CSRTYPE_L)
+			recur = 0;
+		else
+			continue;
 
-loop:
-	if(fc->ongonode == fc->nodeid) fc->ongonode++;
+		off = offset + reg[i].val * sizeof(uint32_t);
+		if (off > CROMSIZE) {
+			printf("%s: invalid offset %d\n", __FUNCTION__, off);
+			return(-1);
+		}
+		err = fw_explore_csrblock(fwdev, off, recur);
+		if (err)
+			return (-1);
+	}
+	return (0);
+}
 
-	if(fc->ongonode > fc->max_node) goto done;
-	if(fc->ongonode >= 0x3f) goto done;
+static int
+fw_explore_node(struct fw_device *dfwdev)
+{
+	struct firewire_comm *fc;
+	struct fw_device *fwdev, *pfwdev, *tfwdev;
+	uint32_t *csr;
+	struct csrhdr *hdr;
+	struct bus_info *binfo;
+	int err, node, spd;
+
+	fc = dfwdev->fc;
+	csr = dfwdev->csrrom;
+	node = dfwdev->dst;
+
+	/* First quad */
+	err = fw_explore_read_quads(dfwdev, CSRROMOFF, &csr[0], 1);
+	if (err)
+		return (-1);
+	hdr = (struct csrhdr *)&csr[0];
+	if (hdr->info_len != 4) {
+		if (firewire_debug)
+			printf("node%d: wrong bus info len(%d)\n",
+			    node, hdr->info_len);
+		return (-1);
+	}
 
-	/* check link */
-	/* XXX we need to check phy_id first */
-	fwsid = fw_find_self_id(fc, fc->ongonode);
-	if (!fwsid || !fwsid->p0.link_active) {
+	/* bus info */
+	err = fw_explore_read_quads(dfwdev, CSRROMOFF + 0x04, &csr[1], 4);
+	if (err)
+		return (-1);
+	binfo = (struct bus_info *)&csr[1];
+	if (binfo->bus_name != CSR_BUS_NAME_IEEE1394) {
 		if (firewire_debug)
-			printf("node%d: link down\n", fc->ongonode);
-		fc->ongonode++;
-		goto loop;
-	}
-
-	if(fc->ongoaddr <= CSRROMOFF &&
-		fc->ongoeui.hi == 0xffffffff &&
-		fc->ongoeui.lo == 0xffffffff ){
-		fc->ongoaddr = CSRROMOFF;
-		addr = 0xf0000000 | fc->ongoaddr;
-	}else if(fc->ongoeui.hi == 0xffffffff ){
-		fc->ongoaddr = CSRROMOFF + 0xc;
-		addr = 0xf0000000 | fc->ongoaddr;
-	}else if(fc->ongoeui.lo == 0xffffffff ){
-		fc->ongoaddr = CSRROMOFF + 0x10;
-		addr = 0xf0000000 | fc->ongoaddr;
-	}else if(fc->ongodev == NULL){
-		STAILQ_FOREACH(fwdev, &fc->devices, link)
-			if (FW_EUI64_EQUAL(fwdev->eui, fc->ongoeui))
-				break;
-		if(fwdev != NULL){
-			fwdev->dst = fc->ongonode;
-			fwdev->status = FWDEVINIT;
-			fc->ongodev = fwdev;
-			fc->ongoaddr = CSRROMOFF;
-			addr = 0xf0000000 | fc->ongoaddr;
-			goto dorequest;
-		}
+			printf("node%d: invalid bus name 0x%08x\n",
+			    node, binfo->bus_name);
+		return (-1);
+	}
+	spd = fc->speed_map->speed[fc->nodeid][node];
+	STAILQ_FOREACH(fwdev, &fc->devices, link)
+		if (FW_EUI64_EQUAL(fwdev->eui, binfo->eui64))
+			break;
+	if (fwdev == NULL) {
+		/* new device */
 		fwdev = malloc(sizeof(struct fw_device), M_FW,
-							M_NOWAIT | M_ZERO);
-		if(fwdev == NULL)
-			return;
+						M_NOWAIT | M_ZERO);
+		if (fwdev == NULL) {
+			if (firewire_debug)
+				printf("node%d: no memory\n", node);
+			return (-1);
+		}
 		fwdev->fc = fc;
-		fwdev->rommax = 0;
-		fwdev->dst = fc->ongonode;
-		fwdev->eui.hi = fc->ongoeui.hi; fwdev->eui.lo = fc->ongoeui.lo;
-		fwdev->status = FWDEVINIT;
-		fwdev->speed = fc->speed_map->speed[fc->nodeid][fc->ongonode];
-
+		fwdev->eui = binfo->eui64;
+		/* inesrt into sorted fwdev list */
 		pfwdev = NULL;
 		STAILQ_FOREACH(tfwdev, &fc->devices, link) {
 			if (tfwdev->eui.hi > fwdev->eui.hi ||
-					(tfwdev->eui.hi == fwdev->eui.hi &&
-					tfwdev->eui.lo > fwdev->eui.lo))
+				(tfwdev->eui.hi == fwdev->eui.hi &&
+				tfwdev->eui.lo > fwdev->eui.lo))
 				break;
 			pfwdev = tfwdev;
 		}
@@ -1393,263 +1545,123 @@
 			STAILQ_INSERT_AFTER(&fc->devices, pfwdev, fwdev, link);
 
 		device_printf(fc->bdev, "New %s device ID:%08x%08x\n",
-			linkspeed[fwdev->speed],
-			fc->ongoeui.hi, fc->ongoeui.lo);
-
-		fc->ongodev = fwdev;
-		fc->ongoaddr = CSRROMOFF;
-		addr = 0xf0000000 | fc->ongoaddr;
-	}else{
-		addr = 0xf0000000 | fc->ongoaddr;
+		    linkspeed[spd],
+		    fwdev->eui.hi, fwdev->eui.lo);
 	}
-dorequest:
-#if 0
-	xfer = asyreqq(fc, FWSPD_S100, 0, 0,
-		((FWLOCALBUS | fc->ongonode) << 16) | 0xffff , addr,
-		fw_bus_explore_callback);
-	if(xfer == NULL) goto done;
-#else
-	xfer = fw_xfer_alloc(M_FWXFER);
-	if(xfer == NULL){
-		goto done;
-	}
-	xfer->send.spd = 0;
-	fp = &xfer->send.hdr;
-	fp->mode.rreqq.dest_hi = 0xffff;
-	fp->mode.rreqq.tlrt = 0;
-	fp->mode.rreqq.tcode = FWTCODE_RREQQ;
-	fp->mode.rreqq.pri = 0;
-	fp->mode.rreqq.src = 0;
-	fp->mode.rreqq.dst = FWLOCALBUS | fc->ongonode;
-	fp->mode.rreqq.dest_lo = addr;
-	xfer->act.hand = fw_bus_explore_callback;
+	fwdev->dst = node;
+	fwdev->status = FWDEVINIT;
+	fwdev->speed = spd;
 
-	if (firewire_debug)
-		printf("node%d: explore addr=0x%x\n",
-				fc->ongonode, fc->ongoaddr);
-	err = fw_asyreq(fc, -1, xfer);
-	if(err){
-		fw_xfer_free( xfer);
-		return;
+	/* unchanged ? */
+	if (bcmp(&csr[0], &fwdev->csrrom[0], sizeof(uint32_t) * 5) == 0) {
+		if (firewire_debug)
+			printf("node%d: crom unchanged\n", node);
+		return (0);
 	}
-#endif
-	return;
-done:
-	/* fw_attach_devs */
-	fc->status = FWBUSEXPDONE;
-	if (firewire_debug)
-		printf("bus_explore done\n");
-	fw_attach_dev(fc);
-	return;
 
-}
+	bzero(&fwdev->csrrom[0], CROMSIZE);
 
-/* Portable Async. request read quad */
-struct fw_xfer *
-asyreqq(struct firewire_comm *fc, uint8_t spd, uint8_t tl, uint8_t rt,
-	uint32_t addr_hi, uint32_t addr_lo,
-	void (*hand) (struct fw_xfer*))
-{
-	struct fw_xfer *xfer;
-	struct fw_pkt *fp;
-	int err;
+	/* copy first quad and bus info block */
+	bcopy(&csr[0], &fwdev->csrrom[0], sizeof(uint32_t) * 5);
+	fwdev->rommax = CSRROMOFF + sizeof(uint32_t) * 4;
 
-	xfer = fw_xfer_alloc(M_FWXFER);
-	if (xfer == NULL)
-		return NULL;
+	err = fw_explore_csrblock(fwdev, 0x14, 1); /* root directory */
 
-	xfer->send.spd = spd; /* XXX:min(spd, fc->spd) */
-	fp = &xfer->send.hdr;
-	fp->mode.rreqq.dest_hi = addr_hi & 0xffff;
-	if(tl & FWP_TL_VALID){
-		fp->mode.rreqq.tlrt = (tl & 0x3f) << 2;
-	}else{
-		fp->mode.rreqq.tlrt = 0;
+	if (err) {
+		fwdev->status = FWDEVINVAL;
+		fwdev->csrrom[0] = 0;
 	}
-	fp->mode.rreqq.tlrt |= rt & 0x3;
-	fp->mode.rreqq.tcode = FWTCODE_RREQQ;
-	fp->mode.rreqq.pri = 0;
-	fp->mode.rreqq.src = 0;
-	fp->mode.rreqq.dst = addr_hi >> 16;
-	fp->mode.rreqq.dest_lo = addr_lo;
-	xfer->act.hand = hand;
+	return (err);
 
-	err = fw_asyreq(fc, -1, xfer);
-	if(err){
-		fw_xfer_free( xfer);
-		return NULL;
-	}
-	return xfer;
 }
 
 /*
- * Callback for the IEEE1394 bus information collection. 
+ * Find the self_id packet for a node, ignoring sequels.
  */
-static void
-fw_bus_explore_callback(struct fw_xfer *xfer)
+static union fw_self_id *
+fw_find_self_id(struct firewire_comm *fc, int node)
 {
-	struct firewire_comm *fc;
-	struct fw_pkt *sfp,*rfp;
-	struct csrhdr *chdr;
-	struct csrdir *csrd;
-	struct csrreg *csrreg;
-	uint32_t offset;
+	uint32_t i;
+	union fw_self_id *s;
 
-	
-	if(xfer == NULL) {
-		printf("xfer == NULL\n");
-		return;
+	for (i = 0; i < fc->topology_map->self_id_count; i++) {
+		s = &fc->topology_map->self_id[i];
+		if (s->p0.sequel)
+			continue;
+		if (s->p0.phy_id == node)
+			return s;
 	}
-	fc = xfer->fc;
+	return 0;
+}
 
-	if (firewire_debug)
-		printf("node%d: callback addr=0x%x\n",
-			fc->ongonode, fc->ongoaddr);
+static void
+fw_explore(struct firewire_comm *fc)
+{
+	int node, err, s, i, todo, todo2, trys;
+	char nodes[63];
+	struct fw_device dfwdev;
+	union fw_self_id *fwsid;
 
-	if(xfer->resp != 0){
-		device_printf(fc->bdev,
-		    "bus_explore node=%d addr=0x%x resp=%d retry=%d\n",
-		    fc->ongonode, fc->ongoaddr, xfer->resp, xfer->retry);
-		if (xfer->retry < fc->max_asyretry) {
-			fw_asystart(xfer);
-			return;
+	todo = 0;
+	/* setup dummy fwdev */
+	dfwdev.fc = fc;
+	dfwdev.speed = 0;
+	dfwdev.maxrec = 8; /* 512 */
+	dfwdev.status = FWDEVINIT;
+
+	for (node = 0; node <= fc->max_node; node ++) {
+		/* We don't probe myself and linkdown nodes */
+		if (node == fc->nodeid)
+			continue;
+		fwsid = fw_find_self_id(fc, node);
+		if (!fwsid || !fwsid->p0.link_active) {
+			if (firewire_debug)
+				printf("node%d: link down\n", node);
+			continue;
 		}
-		goto errnode;
+		nodes[todo++] = node;
 	}
 
-	sfp = &xfer->send.hdr;
-	rfp = &xfer->recv.hdr;
-#if 0
-	{
-		uint32_t *qld;
-		int i;
-		qld = (uint32_t *)xfer->recv.buf;
-		printf("len:%d\n", xfer->recv.len);
-		for( i = 0 ; i <= xfer->recv.len && i < 32; i+= 4){
-			printf("0x%08x ", rfp->mode.ld[i/4]);
-			if((i % 16) == 15) printf("\n");
+	s = splfw();
+	for (trys = 0; todo > 0 && trys < 3; trys ++) {
+		todo2 = 0;
+		for (i = 0; i < todo; i ++) {
+			dfwdev.dst = nodes[i];
+			err = fw_explore_node(&dfwdev);
+			if (err)
+				nodes[todo2++] = nodes[i];
+			if (firewire_debug)
+				printf("%s: node %d, err = %d\n",
+					__FUNCTION__, node, err);
 		}
-		if((i % 16) != 15) printf("\n");
+		todo = todo2;
 	}
-#endif
-	if(fc->ongodev == NULL){
-		if(sfp->mode.rreqq.dest_lo == (0xf0000000 | CSRROMOFF)){
-			rfp->mode.rresq.data = ntohl(rfp->mode.rresq.data);
-			chdr = (struct csrhdr *)(&rfp->mode.rresq.data);
-/* If CSR is minimal confinguration, more investigation is not needed. */
-			if(chdr->info_len == 1){
-				if (firewire_debug)
-					printf("node%d: minimal config\n",
-								fc->ongonode);
-				goto nextnode;
-			}else{
-				fc->ongoaddr = CSRROMOFF + 0xc;
-			}
-		}else if(sfp->mode.rreqq.dest_lo == (0xf0000000 |(CSRROMOFF + 0xc))){
-			fc->ongoeui.hi = ntohl(rfp->mode.rresq.data);
-			fc->ongoaddr = CSRROMOFF + 0x10;
-		}else if(sfp->mode.rreqq.dest_lo == (0xf0000000 |(CSRROMOFF + 0x10))){
-			fc->ongoeui.lo = ntohl(rfp->mode.rresq.data);
-			if (fc->ongoeui.hi == 0 && fc->ongoeui.lo == 0) {
-				if (firewire_debug)
-					printf("node%d: eui64 is zero.\n",
-							fc->ongonode);
-				goto nextnode;
-			}
-			fc->ongoaddr = CSRROMOFF;
-		}
-	}else{
-		if (fc->ongoaddr == CSRROMOFF &&
-		    fc->ongodev->csrrom[0] == ntohl(rfp->mode.rresq.data)) {
-			fc->ongodev->status = FWDEVATTACHED;
-			goto nextnode;
-		}
-		fc->ongodev->csrrom[(fc->ongoaddr - CSRROMOFF)/4] = ntohl(rfp->mode.rresq.data);
-		if(fc->ongoaddr > fc->ongodev->rommax){
-			fc->ongodev->rommax = fc->ongoaddr;
-		}
-		csrd = SLIST_FIRST(&fc->ongocsr);
-		if((csrd = SLIST_FIRST(&fc->ongocsr)) == NULL){
-			chdr = (struct csrhdr *)(fc->ongodev->csrrom);
-			offset = CSRROMOFF;
-		}else{
-			chdr = (struct csrhdr *)&fc->ongodev->csrrom[(csrd->off - CSRROMOFF)/4];
-			offset = csrd->off;
-		}
-		if(fc->ongoaddr > (CSRROMOFF + 0x14) && fc->ongoaddr != offset){
-			csrreg = (struct csrreg *)&fc->ongodev->csrrom[(fc->ongoaddr - CSRROMOFF)/4];
-			if( csrreg->key == 0x81 || csrreg->key == 0xd1){
-				csrd = SLIST_FIRST(&fc->csrfree);
-				if(csrd == NULL){
-					goto nextnode;
-				}else{
-					csrd->ongoaddr = fc->ongoaddr;
-					fc->ongoaddr += csrreg->val * 4;
-					csrd->off = fc->ongoaddr;
-					SLIST_REMOVE_HEAD(&fc->csrfree, link);
-					SLIST_INSERT_HEAD(&fc->ongocsr, csrd, link);
-					goto nextaddr;
-				}
-			}
-		}
-		fc->ongoaddr += 4;
-		if(((fc->ongoaddr - offset)/4 > chdr->crc_len) &&
-				(fc->ongodev->rommax < 0x414)){
-			if(fc->ongodev->rommax <= 0x414){
-				csrd = SLIST_FIRST(&fc->csrfree);
-				if(csrd == NULL) goto nextnode;
-				csrd->off = fc->ongoaddr;
-				csrd->ongoaddr = fc->ongoaddr;
-				SLIST_REMOVE_HEAD(&fc->csrfree, link);
-				SLIST_INSERT_HEAD(&fc->ongocsr, csrd, link);
-			}
-			goto nextaddr;
-		}
+	splx(s);
+}
 
-		while(((fc->ongoaddr - offset)/4 > chdr->crc_len)){
-			if(csrd == NULL){
-				goto nextnode;
-			};
-			fc->ongoaddr = csrd->ongoaddr + 4;
-			SLIST_REMOVE_HEAD(&fc->ongocsr, link);
-			SLIST_INSERT_HEAD(&fc->csrfree, csrd, link);
-			csrd = SLIST_FIRST(&fc->ongocsr);
-			if((csrd = SLIST_FIRST(&fc->ongocsr)) == NULL){
-				chdr = (struct csrhdr *)(fc->ongodev->csrrom);
-				offset = CSRROMOFF;
-			}else{
-				chdr = (struct csrhdr *)&(fc->ongodev->csrrom[(csrd->off - CSRROMOFF)/4]);
-				offset = csrd->off;
-			}
-		}
-		if((fc->ongoaddr - CSRROMOFF) > CSRROMSIZE){
-			goto nextnode;
+
+static void
+fw_bus_probe_thread(void *arg)
+{
+	struct firewire_comm *fc;
+
+	fc = (struct firewire_comm *)arg;
+
+	mtx_lock(&fc->wait_lock);
+	while (fc->status != FWBUSDETACH) {
+		if (fc->status == FWBUSEXPLORE) {
+			mtx_unlock(&fc->wait_lock);
+			fw_explore(fc);
+			fc->status = FWBUSEXPDONE;
+			if (firewire_debug)
+				printf("bus_explore done\n");
+			fw_attach_dev(fc);
+			mtx_lock(&fc->wait_lock);
 		}
+		msleep((void *)fc, &fc->wait_lock, PWAIT|PCATCH, "-", 0);
 	}
-nextaddr:
-	fw_xfer_free( xfer);
-	fw_bus_explore(fc);
-	return;
-errnode:
-	fc->retry_count++;
-	if (fc->ongodev != NULL) {
-		fc->ongodev->status = FWDEVINVAL;
-		/* Invalidate ROM */
-		fc->ongodev->csrrom[0] = 0;
-	}
-nextnode:
-	fw_xfer_free( xfer);
-	fc->ongonode++;
-/* housekeeping work space */
-	fc->ongoaddr = CSRROMOFF;
-	fc->ongodev = NULL;
-	fc->ongoeui.hi = 0xffffffff; fc->ongoeui.lo = 0xffffffff;
-	while((csrd = SLIST_FIRST(&fc->ongocsr)) != NULL){
-		SLIST_REMOVE_HEAD(&fc->ongocsr, link);
-		SLIST_INSERT_HEAD(&fc->csrfree, csrd, link);
-	}
-	fw_bus_explore(fc);
-	return;
+	mtx_unlock(&fc->wait_lock);
+	kthread_exit(0);
 }
 
 /*
@@ -1694,14 +1706,6 @@
 	}
 	free(devlistp, M_TEMP);
 
-	if (fc->retry_count > 0) {
-		device_printf(fc->bdev, "bus_explore failed for %d nodes\n",
-		    fc->retry_count);
-#if 0
-		callout_reset(&fc->retry_probe_callout, hz*2,
-					(void *)fc->ibr, (void *)fc);
-#endif
-	}
 	return;
 }
 
@@ -1711,40 +1715,34 @@
 static int
 fw_get_tlabel(struct firewire_comm *fc, struct fw_xfer *xfer)
 {
-	u_int i;
-	struct tlabel *tl, *tmptl;
+	u_int dst, new_tlabel;
+	struct fw_xfer *txfer;
 	int s;
-	static uint32_t label = 0;
 
+	dst = xfer->send.hdr.mode.hdr.dst & 0x3f;
 	s = splfw();
-	for( i = 0 ; i < 0x40 ; i ++){
-		label = (label + 1) & 0x3f;
-		for(tmptl = STAILQ_FIRST(&fc->tlabels[label]);
-			tmptl != NULL; tmptl = STAILQ_NEXT(tmptl, link)){
-			if (tmptl->xfer->send.hdr.mode.hdr.dst ==
-			    xfer->send.hdr.mode.hdr.dst)
+	mtx_lock(&fc->tlabel_lock);
+	new_tlabel = (fc->last_tlabel[dst] + 1) & 0x3f;
+	STAILQ_FOREACH(txfer, &fc->tlabels[new_tlabel], tlabel)
+		if ((txfer->send.hdr.mode.hdr.dst & 0x3f) == dst)
 				break;
-		}
-		if(tmptl == NULL) {
-			tl = malloc(sizeof(struct tlabel),M_FW,M_NOWAIT);
-			if (tl == NULL) {
-				splx(s);
-				return (-1);
-			}
-			tl->xfer = xfer;
-			STAILQ_INSERT_TAIL(&fc->tlabels[label], tl, link);
-			splx(s);
-			if (firewire_debug > 1)
-				printf("fw_get_tlabel: dst=%d tl=%d\n",
-				    xfer->send.hdr.mode.hdr.dst, label);
-			return(label);
-		}
+	if(txfer == NULL) {
+		fc->last_tlabel[dst] = new_tlabel;
+		STAILQ_INSERT_TAIL(&fc->tlabels[new_tlabel], xfer, tlabel);
+		mtx_unlock(&fc->tlabel_lock);
+		splx(s);
+		xfer->tl = new_tlabel;
+		xfer->send.hdr.mode.hdr.tlrt = new_tlabel << 2;
+		if (firewire_debug > 1)
+			printf("fw_get_tlabel: dst=%d tl=%d\n", dst, new_tlabel);
+		return (new_tlabel);
 	}
+	mtx_unlock(&fc->tlabel_lock);
 	splx(s);
 
 	if (firewire_debug > 1)
 		printf("fw_get_tlabel: no free tlabel\n");
-	return(-1);
+	return (-1);
 }
 
 static void
@@ -1755,7 +1753,7 @@
 	struct tcode_info *tinfo;
 	u_int res, i, len, plen;
 
-	rb->xfer->recv.spd -= rb->spd;
+	rb->xfer->recv.spd = rb->spd;
 
 	pkt = (struct fw_pkt *)rb->vec->iov_base;
 	tinfo = &rb->fc->tcode[pkt->mode.hdr.tcode];
@@ -1809,7 +1807,7 @@
 {
 	struct fw_pkt *fp, *resfp;
 	struct fw_bind *bind;
-	int tcode, s;
+	int tcode;
 	int i, len, oldstate;
 #if 0
 	{
@@ -1832,7 +1830,7 @@
 	case FWTCODE_RRESB:
 	case FWTCODE_LRES:
 		rb->xfer = fw_tl2xfer(rb->fc, fp->mode.hdr.src,
-					fp->mode.hdr.tlrt >> 2);
+				fp->mode.hdr.tlrt >> 2, fp->mode.hdr.tcode);
 		if(rb->xfer == NULL) {
 			printf("fw_rcv: unknown response "
 			    "%s(%x) src=0x%x tl=0x%x rt=%d data=0x%x\n",
@@ -1841,16 +1839,16 @@
 			    fp->mode.hdr.tlrt >> 2,
 			    fp->mode.hdr.tlrt & 3,
 			    fp->mode.rresq.data);
-#if 1
+#if 0
 			printf("try ad-hoc work around!!\n");
 			rb->xfer = fw_tl2xfer(rb->fc, fp->mode.hdr.src,
 					(fp->mode.hdr.tlrt >> 2)^3);
 			if (rb->xfer == NULL) {
 				printf("no use...\n");
-				goto err;
+				return;
 			}
 #else
-			goto err;
+			return;
 #endif
 		}
 		fw_rcv_copy(rb);
@@ -1859,8 +1857,8 @@
 		else
 			rb->xfer->resp = 0;
 		/* make sure the packet is drained in AT queue */
-		oldstate = rb->xfer->state;
-		rb->xfer->state = FWXF_RCVD;
+		oldstate = rb->xfer->flag;
+		rb->xfer->flag = FWXF_RCVD;
 		switch (oldstate) {
 		case FWXF_SENT:
 			fw_xfer_done(rb->xfer);
@@ -1872,7 +1870,7 @@
 #endif
 			break;
 		default:
-			printf("unexpected state %d\n", rb->xfer->state);
+			printf("unexpected flag 0x%02x\n", rb->xfer->flag);
 		}
 		return;
 	case FWTCODE_WREQQ:
@@ -1892,9 +1890,9 @@
 			    fp->mode.wreqq.dest_hi, fp->mode.wreqq.dest_lo,
 			    tcode_str[tcode], tcode,
 			    fp->mode.hdr.src, ntohl(fp->mode.wreqq.data));
-			if (rb->fc->status == FWBUSRESET) {
+			if (rb->fc->status == FWBUSINIT) {
 				printf("fw_rcv: cannot respond(bus reset)!\n");
-				goto err;
+				return;
 			}
 			rb->xfer = fw_xfer_alloc(M_FWXFER);
 			if(rb->xfer == NULL){
@@ -1925,62 +1923,29 @@
 			resfp->mode.rresb.extcode = 0;
 			resfp->mode.rresb.len = 0;
 /*
-			rb->xfer->act.hand = fw_asy_callback;
+			rb->xfer->hand = fw_xferwake;
 */
-			rb->xfer->act.hand = fw_xfer_free;
+			rb->xfer->hand = fw_xfer_free;
 			if(fw_asyreq(rb->fc, -1, rb->xfer)){
 				fw_xfer_free(rb->xfer);
 				return;
 			}
-			goto err;
+			return;
 		}
 		len = 0;
 		for (i = 0; i < rb->nvec; i ++)
 			len += rb->vec[i].iov_len;
-		switch(bind->act_type){
-		case FWACT_XFER:
-			/* splfw()?? */
-			rb->xfer = STAILQ_FIRST(&bind->xferlist);
-			if (rb->xfer == NULL) {
-				printf("Discard a packet for this bind.\n");
-				goto err;
-			}
-			STAILQ_REMOVE_HEAD(&bind->xferlist, link);
-			fw_rcv_copy(rb);
-			rb->xfer->act.hand(rb->xfer);
-			return;
-			break;
-		case FWACT_CH:
-			if(rb->fc->ir[bind->sub]->queued >=
-				rb->fc->ir[bind->sub]->maxq){
-				device_printf(rb->fc->bdev,
-					"Discard a packet %x %d\n",
-					bind->sub,
-					rb->fc->ir[bind->sub]->queued);
-				goto err;
-			}
-			rb->xfer = STAILQ_FIRST(&bind->xferlist);
-			if (rb->xfer == NULL) {
-				printf("Discard packet for this bind\n");
-				goto err;
-			}
-			STAILQ_REMOVE_HEAD(&bind->xferlist, link);
-			fw_rcv_copy(rb);
-			s = splfw();
-			rb->fc->ir[bind->sub]->queued++;
-			STAILQ_INSERT_TAIL(&rb->fc->ir[bind->sub]->q,
-			    rb->xfer, link);
-			splx(s);
-
-			wakeup((caddr_t)rb->fc->ir[bind->sub]);
-
+		rb->xfer = STAILQ_FIRST(&bind->xferlist);
+		if (rb->xfer == NULL) {
+#if 1
+			printf("Discard a packet for this bind.\n");
+#endif
 			return;
-			break;
-		default:
-			goto err;
-			break;
 		}
-		break;
+		STAILQ_REMOVE_HEAD(&bind->xferlist, link);
+		fw_rcv_copy(rb);
+		rb->xfer->hand(rb->xfer);
+		return;
 #if 0 /* shouldn't happen ?? or for GASP */
 	case FWTCODE_STREAM:
 	{
@@ -1993,13 +1958,14 @@
 #endif
 		if(xferq->queued >= xferq->maxq) {
 			printf("receive queue is full\n");
-			goto err;
+			return;
 		}
 		/* XXX get xfer from xfer queue, we don't need copy for 
 			per packet mode */
 		rb->xfer = fw_xfer_alloc_buf(M_FWXFER, 0, /* XXX */
 						vec[0].iov_len);
-		if (rb->xfer == NULL) goto err;
+		if (rb->xfer == NULL)
+			return;
 		fw_rcv_copy(rb)
 		s = splfw();
 		xferq->queued++;
@@ -2027,8 +1993,6 @@
 		printf("fw_rcv: unknow tcode %d\n", tcode);
 		break;
 	}
-err:
-	return;
 }
 
 /*
@@ -2095,7 +2059,7 @@
 	fp->mode.lreq.dest_lo = 0xf0000000 | BUS_MGR_ID;
 	xfer->send.payload[0] = htonl(0x3f);
 	xfer->send.payload[1] = htonl(fc->nodeid);
-	xfer->act.hand = fw_try_bmr_callback;
+	xfer->hand = fw_try_bmr_callback;
 
 	err = fw_asyreq(fc, -1, xfer);
 	if(err){
@@ -2170,8 +2134,7 @@
 	}
 	sfp->mode.hdr.dst = rfp->mode.hdr.src;
 	xfer->dst = ntohs(rfp->mode.hdr.src);
-	xfer->act.hand = fw_xfer_free;
-	xfer->retry_req = fw_asybusy;
+	xfer->hand = fw_xfer_free;
 
 	sfp->mode.hdr.tlrt = rfp->mode.hdr.tlrt;
 	sfp->mode.hdr.pri = 0;
@@ -2253,6 +2216,34 @@
 	return 0;
 }
 
+int
+fw_open_isodma(struct firewire_comm *fc, int tx)
+{
+	struct fw_xferq **xferqa;
+	struct fw_xferq *xferq;
+	int i;
+
+	if (tx)
+		xferqa = &fc->it[0];
+	else
+		xferqa = &fc->ir[0];
+
+	FW_GLOCK(fc);
+	for (i = 0; i < fc->nisodma; i ++) {
+		xferq = xferqa[i];
+		if ((xferq->flag & FWXFERQ_OPEN) == 0) {
+			xferq->flag |= FWXFERQ_OPEN;
+			break;
+		}
+	}
+	if (i == fc->nisodma) {
+		printf("no free dma channel (tx=%d)\n", tx);
+		i = -1;
+	}
+	FW_GUNLOCK(fc);
+	return (i);
+}
+
 static int
 fw_modevent(module_t mode, int type, void *data)
 {
Index: fwdma.c
===================================================================
RCS file: /home/cvs/src/sys/dev/firewire/fwdma.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L sys/dev/firewire/fwdma.c -L sys/dev/firewire/fwdma.c -u -r1.2 -r1.3
--- sys/dev/firewire/fwdma.c
+++ sys/dev/firewire/fwdma.c
@@ -35,7 +35,7 @@
 
 #ifdef __FreeBSD__
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/dev/firewire/fwdma.c,v 1.7 2005/01/06 01:42:41 imp Exp $");
+__FBSDID("$FreeBSD: src/sys/dev/firewire/fwdma.c,v 1.9 2007/06/06 14:31:36 simokawa Exp $");
 #endif
 
 #include <sys/param.h>
@@ -92,7 +92,7 @@
 		/*flags*/ BUS_DMA_ALLOCNOW,
 #if defined(__FreeBSD__) && __FreeBSD_version >= 501102 
 		/*lockfunc*/busdma_lock_mutex,
-		/*lockarg*/&Giant,
+		/*lockarg*/FW_GMTX(fc),
 #endif
 		&dma->dma_tag);
 	if (err) {
@@ -190,7 +190,7 @@
 			/*flags*/ BUS_DMA_ALLOCNOW,
 #if defined(__FreeBSD__) && __FreeBSD_version >= 501102
 			/*lockfunc*/busdma_lock_mutex,
-			/*lockarg*/&Giant,
+			/*lockarg*/FW_GMTX(fc),
 #endif
 			&am->dma_tag)) {
 		printf("fwdma_malloc_multiseg: tag_create failed\n");
Index: 00README
===================================================================
RCS file: /home/cvs/src/sys/dev/firewire/00README,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/dev/firewire/00README -L sys/dev/firewire/00README -u -r1.1.1.1 -r1.2
--- sys/dev/firewire/00README
+++ sys/dev/firewire/00README
@@ -1,4 +1,4 @@
-$FreeBSD: src/sys/dev/firewire/00README,v 1.1.16.1 2005/10/07 14:00:03 glebius Exp $
+$FreeBSD: src/sys/dev/firewire/00README,v 1.2 2005/10/01 18:56:16 glebius Exp $
 
 IEEE 1394 support for FreeBSD-5.X and 4.X.
 
Index: if_fwe.c
===================================================================
RCS file: /home/cvs/src/sys/dev/firewire/if_fwe.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/dev/firewire/if_fwe.c -L sys/dev/firewire/if_fwe.c -u -r1.1.1.1 -r1.2
--- sys/dev/firewire/if_fwe.c
+++ sys/dev/firewire/if_fwe.c
@@ -31,7 +31,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  * 
- * $FreeBSD: src/sys/dev/firewire/if_fwe.c,v 1.37.2.2 2005/10/07 14:00:03 glebius Exp $
+ * $FreeBSD: src/sys/dev/firewire/if_fwe.c,v 1.44 2007/06/06 14:31:36 simokawa Exp $
  */
 
 #ifdef HAVE_KERNEL_OPTION_HEADERS
@@ -157,6 +157,7 @@
 	unit = device_get_unit(dev);
 
 	bzero(fwe, sizeof(struct fwe_softc));
+	mtx_init(&fwe->mtx, "fwe", NULL, MTX_DEF);
 	/* XXX */
 	fwe->stream_ch = stream_ch;
 	fwe->dma_ch = -1;
@@ -213,8 +214,7 @@
 	ifp->if_start = fwe_start;
 	ifp->if_ioctl = fwe_ioctl;
 	ifp->if_mtu = ETHERMTU;
-	ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST|
-	    IFF_NEEDSGIANT);
+	ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST);
 	ifp->if_snd.ifq_maxlen = TX_MAX_QUEUE;
 
 	s = splimp();
@@ -228,7 +228,7 @@
         /* Tell the upper layer(s) we support long frames. */
 	ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header);
 #if defined(__FreeBSD__) && __FreeBSD_version >= 500000
-	ifp->if_capabilities |= IFCAP_VLAN_MTU & IFCAP_POLLING;
+	ifp->if_capabilities |= IFCAP_VLAN_MTU | IFCAP_POLLING;
 	ifp->if_capenable |= IFCAP_VLAN_MTU;
 #endif
 
@@ -305,6 +305,7 @@
 #endif
 
 	splx(s);
+	mtx_destroy(&fwe->mtx);
 	return 0;
 }
 
@@ -325,22 +326,15 @@
 	ifp->if_flags |= IFF_PROMISC;
 
 	fc = fwe->fd.fc;
-#define START 0
 	if (fwe->dma_ch < 0) {
-		for (i = START; i < fc->nisodma; i ++) {
-			xferq = fc->ir[i];
-			if ((xferq->flag & FWXFERQ_OPEN) == 0)
-				goto found;
-		}
-		printf("no free dma channel\n");
-		return;
-found:
-		fwe->dma_ch = i;
+		fwe->dma_ch = fw_open_isodma(fc, /* tx */0);
+		if (fwe->dma_ch < 0)
+			return;
+		xferq = fc->ir[fwe->dma_ch];
+		xferq->flag |= FWXFERQ_EXTBUF |
+				FWXFERQ_HANDLER | FWXFERQ_STREAM;
 		fwe->stream_ch = stream_ch;
 		fwe->pkt_hdr.mode.stream.chtag = fwe->stream_ch;
-		/* allocate DMA channel and init packet mode */
-		xferq->flag |= FWXFERQ_OPEN | FWXFERQ_EXTBUF |
-				FWXFERQ_HANDLER | FWXFERQ_STREAM;
 		xferq->flag &= ~0xff;
 		xferq->flag |= fwe->stream_ch & 0xff;
 		/* register fwe_input handler */
@@ -375,7 +369,7 @@
 				STAILQ_INSERT_TAIL(&xferq->stfree,
 						&xferq->bulkxfer[i], link);
 			} else
-				printf("fwe_as_input: m_getcl failed\n");
+				printf("%s: m_getcl failed\n", __FUNCTION__);
 		}
 		STAILQ_INIT(&fwe->xferlist);
 		for (i = 0; i < TX_MAX_QUEUE; i++) {
@@ -384,9 +378,8 @@
 				break;
 			xfer->send.spd = tx_speed;
 			xfer->fc = fwe->fd.fc;
-			xfer->retry_req = fw_asybusy;
 			xfer->sc = (caddr_t)fwe;
-			xfer->act.hand = fwe_output_callback;
+			xfer->hand = fwe_output_callback;
 			STAILQ_INSERT_TAIL(&fwe->xferlist, xfer, link);
 		}
 	} else
@@ -471,7 +464,6 @@
 				fc->set_intr(fc, 0);
 				ifp->if_capenable |= IFCAP_POLLING;
 				return (error);
-				
 			}
 			if (!(ifr->ifr_reqcap & IFCAP_POLLING) &&
 			    ifp->if_capenable & IFCAP_POLLING) {
@@ -522,7 +514,9 @@
 	fw_xfer_unload(xfer);
 
 	s = splimp();
+	FWE_LOCK(fwe);
 	STAILQ_INSERT_TAIL(&fwe->xferlist, xfer, link);
+	FWE_UNLOCK(fwe);
 	splx(s);
 
 	/* for queue full */
@@ -536,8 +530,6 @@
 	struct fwe_softc *fwe = ((struct fwe_eth_softc *)ifp->if_softc)->fwe;
 	int s;
 
-	GIANT_REQUIRED;
-
 	FWEDEBUG(ifp, "starting\n");
 
 	if (fwe->dma_ch < 0) {
@@ -591,16 +583,27 @@
 
 	xfer = NULL;
 	xferq = fwe->fd.fc->atq;
-	while (xferq->queued < xferq->maxq - 1) {
+	while ((xferq->queued < xferq->maxq - 1) &&
+			(ifp->if_snd.ifq_head != NULL)) {
+		FWE_LOCK(fwe);
 		xfer = STAILQ_FIRST(&fwe->xferlist);
 		if (xfer == NULL) {
+#if 0
 			printf("if_fwe: lack of xfer\n");
-			return;
+#endif
+			FWE_UNLOCK(fwe);
+			break;
 		}
+		STAILQ_REMOVE_HEAD(&fwe->xferlist, link);
+		FWE_UNLOCK(fwe);
+
 		IF_DEQUEUE(&ifp->if_snd, m);
-		if (m == NULL)
+		if (m == NULL) {
+			FWE_LOCK(fwe);
+			STAILQ_INSERT_HEAD(&fwe->xferlist, xfer, link);
+			FWE_UNLOCK(fwe);
 			break;
-		STAILQ_REMOVE_HEAD(&fwe->xferlist, link);
+		}
 #if defined(__DragonFly__) || __FreeBSD_version < 500000
 		if (ifp->if_bpf != NULL)
 			bpf_mtap(ifp, m);
@@ -651,6 +654,7 @@
 	fwe = (struct fwe_softc *)xferq->sc;
 	ifp = fwe->eth_softc.ifp;
 
+	/* We do not need a lock here because the bottom half is serialized */
 	while ((sxfer = STAILQ_FIRST(&xferq->stvalid)) != NULL) {
 		STAILQ_REMOVE_HEAD(&xferq->stvalid, link);
 		fp = mtod(sxfer->mbuf, struct fw_pkt *);
@@ -664,7 +668,7 @@
 			m0->m_len = m0->m_pkthdr.len = m0->m_ext.ext_size;
 			STAILQ_INSERT_TAIL(&xferq->stfree, sxfer, link);
 		} else
-			printf("fwe_as_input: m_getcl failed\n");
+			printf("%s: m_getcl failed\n", __FUNCTION__);
 
 		if (sxfer->resp != 0 || fp->mode.stream.len <
 		    ETHER_ALIGN + sizeof(struct ether_header)) {
@@ -674,7 +678,7 @@
 		}
 
 		m->m_data += HDR_LEN + ETHER_ALIGN;
-		c = mtod(m, char *);
+		c = mtod(m, u_char *);
 #if defined(__DragonFly__) || __FreeBSD_version < 500000
 		eh = (struct ether_header *)c;
 		m->m_data += sizeof(struct ether_header);
Index: firewire.h
===================================================================
RCS file: /home/cvs/src/sys/dev/firewire/firewire.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -L sys/dev/firewire/firewire.h -L sys/dev/firewire/firewire.h -u -r1.2 -r1.3
--- sys/dev/firewire/firewire.h
+++ sys/dev/firewire/firewire.h
@@ -31,7 +31,7 @@
  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  * 
- * $FreeBSD: src/sys/dev/firewire/firewire.h,v 1.20 2005/01/06 01:42:41 imp Exp $
+ * $FreeBSD: src/sys/dev/firewire/firewire.h,v 1.21 2007/04/24 12:15:05 simokawa Exp $
  *
  */
 
Index: if_fwipvar.h
===================================================================
RCS file: /home/cvs/src/sys/dev/firewire/if_fwipvar.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/dev/firewire/if_fwipvar.h -L sys/dev/firewire/if_fwipvar.h -u -r1.1.1.1 -r1.2
--- sys/dev/firewire/if_fwipvar.h
+++ sys/dev/firewire/if_fwipvar.h
@@ -33,7 +33,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  * 
- * $FreeBSD: src/sys/dev/firewire/if_fwipvar.h,v 1.4 2005/06/10 16:49:08 brooks Exp $
+ * $FreeBSD: src/sys/dev/firewire/if_fwipvar.h,v 1.5 2007/06/06 14:31:36 simokawa Exp $
  */
 
 #ifndef _NET_IF_FWIPVAR_H_
@@ -58,5 +58,8 @@
 		struct ifnet *fwip_ifp;
 		struct fwip_softc *fwip;
 	} fw_softc;
+	struct mtx mtx;
 };
+#define FWIP_LOCK(fwip)   mtx_lock(&(fwip)->mtx)
+#define FWIP_UNLOCK(fwip) mtx_unlock(&(fwip)->mtx)
 #endif /* !_NET_IF_FWIPVAR_H_ */


More information about the Midnightbsd-cvs mailing list