Sync DragonFly and FreeBSD-current's FireWire driver.
authorJoerg Sonnenberger <joerg@dragonflybsd.org>
Thu, 5 Feb 2004 13:32:08 +0000 (13:32 +0000)
committerJoerg Sonnenberger <joerg@dragonflybsd.org>
Thu, 5 Feb 2004 13:32:08 +0000 (13:32 +0000)
Patch submitted by Hidetoshi Shimokawa <simokawa@sat.t.u-tokyo.ac.jp>

Modified to leave the sbp hack inplace.

19 files changed:
sys/bus/firewire/firewire.c
sys/bus/firewire/firewire.h
sys/bus/firewire/firewire_phy.h
sys/bus/firewire/firewirereg.h
sys/bus/firewire/fwcrom.c
sys/bus/firewire/fwdev.c
sys/bus/firewire/fwdma.c
sys/bus/firewire/fwdma.h
sys/bus/firewire/fwmem.c
sys/bus/firewire/fwmem.h
sys/bus/firewire/fwohci.c
sys/bus/firewire/fwohci_pci.c
sys/bus/firewire/fwohcireg.h
sys/bus/firewire/fwohcivar.h
sys/bus/firewire/iec13213.h
sys/bus/firewire/iec68113.h
sys/dev/disk/sbp/Makefile
sys/dev/disk/sbp/sbp.c
sys/dev/netif/fwe/if_fwe.c

index e36dc52..f90b741 100644 (file)
  * 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.3.2.22 2003/05/12 04:16:30 simokawa Exp $
- * $DragonFly: src/sys/bus/firewire/firewire.c,v 1.4 2003/08/27 11:42:34 rob Exp $
+ * $FreeBSD: src/sys/dev/firewire/firewire.c,v 1.68 2004/01/08 14:58:09 simokawa Exp $
+ * $DragonFly: src/sys/bus/firewire/firewire.c,v 1.5 2004/02/05 13:32:07 joerg Exp $
  *
  */
 
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/types.h>
-#include <sys/mbuf.h>
-#include <sys/socket.h>
-#include <sys/socketvar.h>
 
 #include <sys/kernel.h>
 #include <sys/malloc.h>
 #include <sys/conf.h>
 #include <sys/sysctl.h>
 
-#include <machine/cpufunc.h>    /* for rdtsc proto for clock.h below */
-#include <machine/clock.h>
+#if __FreeBSD_version < 500000
+#include <machine/clock.h>     /* for DELAY() */
+#endif
 
 #include <sys/bus.h>           /* used by smbus and newbus */
 #include <machine/bus.h>
 
+#ifdef __DragonFly__
 #include "firewire.h"
 #include "firewirereg.h"
 #include "fwmem.h"
 #include "iec13213.h"
 #include "iec68113.h"
+#else
+#include <dev/firewire/firewire.h>
+#include <dev/firewire/firewirereg.h>
+#include <dev/firewire/fwmem.h>
+#include <dev/firewire/iec13213.h>
+#include <dev/firewire/iec68113.h>
+#endif
+
+struct crom_src_buf {
+       struct crom_src src;
+       struct crom_chunk root;
+       struct crom_chunk vendor;
+       struct crom_chunk hw;
+};
 
-int firewire_debug=0, try_bmr=1;
+int firewire_debug=0, try_bmr=1, hold_count=3;
 SYSCTL_INT(_debug, OID_AUTO, firewire_debug, CTLFLAG_RW, &firewire_debug, 0,
        "FireWire driver debug flag");
 SYSCTL_NODE(_hw, OID_AUTO, firewire, CTLFLAG_RD, 0, "FireWire Subsystem");
 SYSCTL_INT(_hw_firewire, OID_AUTO, try_bmr, CTLFLAG_RW, &try_bmr, 0,
        "Try to be a bus manager");
+SYSCTL_INT(_hw_firewire, OID_AUTO, hold_count, CTLFLAG_RW, &hold_count, 0,
+       "Number of count of bus resets for removing lost device information");
 
 MALLOC_DEFINE(M_FW, "firewire", "FireWire");
 MALLOC_DEFINE(M_FWXFER, "fw_xfer", "XFER/FireWire");
 
 #define FW_MAXASYRTY 4
-#define FW_MAXDEVRCNT 4
 
 devclass_t firewire_devclass;
 
-static int firewire_match      (device_t);
+static void firewire_identify  (driver_t *, device_t);
+static int firewire_probe      (device_t);
 static int firewire_attach      (device_t);
 static int firewire_detach      (device_t);
+static int firewire_resume      (device_t);
 #if 0
 static int firewire_shutdown    (device_t);
 #endif
@@ -99,11 +115,12 @@ static int fw_bmr (struct firewire_comm *);
 
 static device_method_t firewire_methods[] = {
        /* Device interface */
-       DEVMETHOD(device_probe,         firewire_match),
+       DEVMETHOD(device_identify,      firewire_identify),
+       DEVMETHOD(device_probe,         firewire_probe),
        DEVMETHOD(device_attach,        firewire_attach),
        DEVMETHOD(device_detach,        firewire_detach),
        DEVMETHOD(device_suspend,       bus_generic_suspend),
-       DEVMETHOD(device_resume,        bus_generic_resume),
+       DEVMETHOD(device_resume,        firewire_resume),
        DEVMETHOD(device_shutdown,      bus_generic_shutdown),
 
        /* Bus interface */
@@ -112,15 +129,23 @@ static device_method_t firewire_methods[] = {
 
        { 0, 0 }
 };
-char linkspeed[7][0x10]={"S100","S200","S400","S800","S1600","S3200","Unknown"};
+char *linkspeed[] = {
+       "S100", "S200", "S400", "S800",
+       "S1600", "S3200", "undef", "undef"
+};
+
+static char *tcode_str[] = {
+       "WREQQ", "WREQB", "WRES",   "undef",
+       "RREQQ", "RREQB", "RRESQ",  "RRESB",
+       "CYCS",  "LREQ",  "STREAM", "LRES",
+       "undef", "undef", "PHY",    "undef"
+};
 
 /* IEEE-1394a Table C-2 Gap count as a function of hops*/
 #define MAX_GAPHOP 15
 u_int gap_cnt[] = { 5,  5,  7,  8, 10, 13, 16, 18,
                   21, 24, 26, 29, 32, 35, 37, 40};
 
-extern struct cdevsw firewire_cdevsw;
-
 static driver_t firewire_driver = {
        "firewire",
        firewire_methods,
@@ -138,12 +163,10 @@ fw_noderesolve_nodeid(struct firewire_comm *fc, int dst)
 
        s = splfw();
        STAILQ_FOREACH(fwdev, &fc->devices, link)
-               if (fwdev->dst == dst)
+               if (fwdev->dst == dst && fwdev->status != FWDEVINVAL)
                        break;
        splx(s);
 
-       if(fwdev == NULL) return NULL;
-       if(fwdev->status == FWDEVINVAL) return NULL;
        return fwdev;
 }
 
@@ -181,20 +204,16 @@ fw_asyreq(struct firewire_comm *fc, int sub, struct fw_xfer *xfer)
        struct tcode_info *info;
 
        if(xfer == NULL) return EINVAL;
-       if(xfer->send.len > MAXREC(fc->maxrec)){
-               printf("send.len > maxrec\n");
-               return EINVAL;
-       }
        if(xfer->act.hand == NULL){
                printf("act.hand == NULL\n");
                return EINVAL;
        }
-       fp = (struct fw_pkt *)xfer->send.buf;
+       fp = &xfer->send.hdr;
 
        tcode = fp->mode.common.tcode & 0xf;
        info = &fc->tcode[tcode];
        if (info->flag == 0) {
-               printf("invalid tcode=%d\n", tcode);
+               printf("invalid tcode=%x\n", tcode);
                return EINVAL;
        }
        if (info->flag & FWTI_REQ)
@@ -202,16 +221,21 @@ fw_asyreq(struct firewire_comm *fc, int sub, struct fw_xfer *xfer)
        else
                xferq = fc->ats;
        len = info->hdr_len;
+       if (xfer->send.pay_len > MAXREC(fc->maxrec)) {
+               printf("send.pay_len > maxrec\n");
+               return EINVAL;
+       }
        if (info->flag & FWTI_BLOCK_STR)
-               len += fp->mode.stream.len;
+               len = fp->mode.stream.len;
        else if (info->flag & FWTI_BLOCK_ASY)
-               len += fp->mode.rresb.len;
-       if( len >  xfer->send.len ){
-               printf("len(%d) > send.len(%d) (tcode=%d)\n",
-                               len, xfer->send.len, tcode);
+               len = fp->mode.rresb.len;
+       else
+               len = 0;
+       if (len != xfer->send.pay_len){
+               printf("len(%d) != send.pay_len(%d) %s(%x)\n",
+                   len, xfer->send.pay_len, tcode_str[tcode], tcode);
                return EINVAL; 
        }
-       xfer->send.len = len;
 
        if(xferq->start == NULL){
                printf("xferq->start == NULL\n");
@@ -223,7 +247,7 @@ fw_asyreq(struct firewire_comm *fc, int sub, struct fw_xfer *xfer)
                return EINVAL;
        }
 
-
+       microtime(&xfer->tv);
        if (info->flag & FWTI_TLABEL) {
                if((tl = fw_get_tlabel(fc, xfer)) == -1 )
                        return EIO;
@@ -255,7 +279,9 @@ void fw_asybusy(struct fw_xfer *xfer){
 /*
        xfer->ch =  timeout((timeout_t *)fw_asystart, (void *)xfer, 20000);
 */
+#if 0
        DELAY(20000);
+#endif
        fw_asystart(xfer);
        return;
 }
@@ -295,11 +321,17 @@ fw_asystart(struct fw_xfer *xfer)
        return;
 }
 
+static void
+firewire_identify(driver_t *driver, device_t parent)
+{
+       BUS_ADD_CHILD(parent, 0, "firewire", -1);
+}
+
 static int
-firewire_match( device_t dev )
+firewire_probe(device_t dev)
 {
        device_set_desc(dev, "IEEE1394(FireWire) bus");
-       return -140;
+       return (0);
 }
 
 static void
@@ -311,8 +343,8 @@ firewire_xfer_timeout(struct firewire_comm *fc)
        struct timeval split_timeout;
        int i, s;
 
-       split_timeout.tv_sec = 6;
-       split_timeout.tv_usec = 0;
+       split_timeout.tv_sec = 0;
+       split_timeout.tv_usec = 200 * 1000;      /* 200 msec */
 
        microtime(&tv);
        timevalsub(&tv, &split_timeout);
@@ -324,9 +356,12 @@ firewire_xfer_timeout(struct firewire_comm *fc)
                        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\n",
-                               xfer->dst, i);
+                               "split transaction timeout dst=0x%x tl=0x%x state=%d\n",
+                               xfer->send.hdr.mode.hdr.dst, i, xfer->state);
                        xfer->resp = ETIMEDOUT;
                        STAILQ_REMOVE_HEAD(&fc->tlabels[i], link);
                        fw_xfer_done(xfer);
@@ -335,15 +370,27 @@ firewire_xfer_timeout(struct firewire_comm *fc)
        splx(s);
 }
 
+#define WATCHDOC_HZ 10
 static void
 firewire_watchdog(void *arg)
 {
        struct firewire_comm *fc;
+       static int watchdoc_clock = 0;
 
        fc = (struct firewire_comm *)arg;
-       firewire_xfer_timeout(fc);
-       fc->timeout(fc);
-       callout_reset(&fc->timeout_callout, hz,
+
+       /*
+        * At boot stage, the device interrupt is disabled and
+        * 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 ++;
+
+       callout_reset(&fc->timeout_callout, hz / WATCHDOC_HZ,
                        (void *)firewire_watchdog, (void *)fc);
 }
 
@@ -351,44 +398,22 @@ firewire_watchdog(void *arg)
  * The attach routine.
  */
 static int
-firewire_attach( device_t dev )
+firewire_attach(device_t dev)
 {
-       int i, unitmask, mn;
+       int unit;
        struct firewire_softc *sc = device_get_softc(dev);
        device_t pa = device_get_parent(dev);
        struct firewire_comm *fc;
-       dev_t d;
 
        fc = (struct firewire_comm *)device_get_softc(pa);
        sc->fc = fc;
-       fc->status = -1;
-
-       unitmask = UNIT2MIN(device_get_unit(dev));
+       fc->status = FWBUSNOTREADY;
 
+       unit = device_get_unit(dev);
        if( fc->nisodma > FWMAXNDMA) fc->nisodma = FWMAXNDMA;
-       for ( i = 0 ; i < fc->nisodma ; i++ ){
-               mn = unitmask | i;
-               /* XXX device name should be improved */
-               d = make_dev(&firewire_cdevsw, unit2minor(mn),
-                       UID_ROOT, GID_OPERATOR, 0660,
-                       "fw%x", mn);
-#if __FreeBSD_version >= 500000
-               if (i == 0)
-                       sc->dev = d;
-               else
-                       dev_depends(sc->dev, d);
-#else
-               sc->dev[i] = d;
-#endif
-       }
-       d = make_dev(&firewire_cdevsw, unit2minor(unitmask | FWMEM_FLAG),
-                       UID_ROOT, GID_OPERATOR, 0660,
-                       "fwmem%d", device_get_unit(dev));
-#if __FreeBSD_version >= 500000
-       dev_depends(sc->dev, d);
-#else
-       sc->dev[i] = d;
-#endif
+
+       fwdev_makedev(sc);
+
        CALLOUT_INIT(&sc->fc->timeout_callout);
        CALLOUT_INIT(&sc->fc->bmr_callout);
        CALLOUT_INIT(&sc->fc->retry_probe_callout);
@@ -404,6 +429,7 @@ firewire_attach( device_t dev )
        bus_generic_attach(dev);
 
        /* bus_reset */
+       fw_busreset(fc);
        fc->ibr(fc);
 
        return 0;
@@ -428,34 +454,42 @@ firewire_add_child(device_t dev, int order, const char *name, int unit)
        return child;
 }
 
+static int
+firewire_resume(device_t dev)
+{
+       struct firewire_softc *sc;
+
+       sc = (struct firewire_softc *)device_get_softc(dev);
+       sc->fc->status = FWBUSNOTREADY;
+       
+       bus_generic_resume(dev);
+
+       return(0);
+}
+
 /*
  * Dettach it.
  */
 static int
-firewire_detach( device_t dev )
+firewire_detach(device_t dev)
 {
        struct firewire_softc *sc;
        struct csrdir *csrd, *next;
        struct fw_device *fwdev, *fwdev_next;
+       int err;
 
        sc = (struct firewire_softc *)device_get_softc(dev);
+       if ((err = fwdev_destroydev(sc)) != 0)
+               return err;
 
-       bus_generic_detach(dev);
+       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);
 
-#if __FreeBSD_version >= 500000
-       destroy_dev(sc->dev);
-#else
-       {
-               int j;
-               for (j = 0 ; j < sc->fc->nisodma + 1; j++)
-                       destroy_dev(sc->dev[j]);
-       }
-#endif
        /* XXX xfree_free and untimeout on all xfers */
        for (fwdev = STAILQ_FIRST(&sc->fc->devices); fwdev != NULL;
                                                        fwdev = fwdev_next) {
@@ -468,6 +502,7 @@ firewire_detach( device_t dev )
        }
        free(sc->fc->topology_map, M_FW);
        free(sc->fc->speed_map, M_FW);
+       free(sc->fc->crom_src_buf, M_FW);
        return(0);
 }
 #if 0
@@ -503,25 +538,11 @@ fw_drain_txq(struct firewire_comm *fc)
                fw_xferq_drain(fc->it[i]);
 }
 
-/*
- * Called after bus reset.
- */
-void
-fw_busreset(struct firewire_comm *fc)
+static void
+fw_reset_csr(struct firewire_comm *fc)
 {
-       struct firewire_dev_comm *fdc;
-       device_t *devlistp;
-       int devcnt;
        int i;
 
-       switch(fc->status){
-       case FWBUSMGRELECT:
-               callout_stop(&fc->bmr_callout);
-               break;
-       default:
-               break;
-       }
-       fc->status = FWBUSRESET;
        CSRARC(fc, STATE_CLEAR)
                        = 1 << 23 | 0 << 17 | 1 << 16 | 1 << 15 | 1 << 14 ;
        CSRARC(fc, STATE_SET) = CSRARC(fc, STATE_CLEAR);
@@ -560,6 +581,94 @@ fw_busreset(struct firewire_comm *fc)
 
        CSRARC(fc, STATE_CLEAR) &= ~(1 << 23 | 1 << 15 | 1 << 14 );
        CSRARC(fc, STATE_SET) = CSRARC(fc, STATE_CLEAR);
+}
+
+static void
+fw_init_crom(struct firewire_comm *fc)
+{
+       struct crom_src *src;
+
+       fc->crom_src_buf = (struct crom_src_buf *)
+               malloc(sizeof(struct crom_src_buf), M_FW, M_WAITOK | M_ZERO);
+       if (fc->crom_src_buf == NULL)
+               return;
+
+       src = &fc->crom_src_buf->src;
+       bzero(src, sizeof(struct crom_src));
+
+       /* BUS info sample */
+       src->hdr.info_len = 4;
+
+       src->businfo.bus_name = CSR_BUS_NAME_IEEE1394;
+
+       src->businfo.irmc = 1;
+       src->businfo.cmc = 1;
+       src->businfo.isc = 1;
+       src->businfo.bmc = 1;
+       src->businfo.pmc = 0;
+       src->businfo.cyc_clk_acc = 100;
+       src->businfo.max_rec = fc->maxrec;
+       src->businfo.max_rom = MAXROM_4;
+       src->businfo.generation = 1;
+       src->businfo.link_spd = fc->speed;
+
+       src->businfo.eui64.hi = fc->eui.hi;
+       src->businfo.eui64.lo = fc->eui.lo;
+
+       STAILQ_INIT(&src->chunk_list);
+
+       fc->crom_src = src;
+       fc->crom_root = &fc->crom_src_buf->root;
+}
+
+static void
+fw_reset_crom(struct firewire_comm *fc)
+{
+       struct crom_src_buf *buf;
+       struct crom_src *src;
+       struct crom_chunk *root;
+
+       if (fc->crom_src_buf == NULL)
+               fw_init_crom(fc);
+
+       buf =  fc->crom_src_buf;
+       src = fc->crom_src;
+       root = fc->crom_root;
+
+       STAILQ_INIT(&src->chunk_list);
+
+       bzero(root, sizeof(struct crom_chunk));
+       crom_add_chunk(src, NULL, root, 0);
+       crom_add_entry(root, CSRKEY_NCAP, 0x0083c0); /* XXX */
+       /* private company_id */
+       crom_add_entry(root, CSRKEY_VENDOR, CSRVAL_VENDOR_PRIVATE);
+       crom_add_simple_text(src, root, &buf->vendor, "FreeBSD Project");
+       crom_add_entry(root, CSRKEY_HW, __FreeBSD_version);
+       crom_add_simple_text(src, root, &buf->hw, hostname);
+}
+
+/*
+ * Called after bus reset.
+ */
+void
+fw_busreset(struct firewire_comm *fc)
+{
+       struct firewire_dev_comm *fdc;
+       struct crom_src *src;
+       device_t *devlistp;
+       void *newrom;
+       int i, devcnt;
+
+       switch(fc->status){
+       case FWBUSMGRELECT:
+               callout_stop(&fc->bmr_callout);
+               break;
+       default:
+               break;
+       }
+       fc->status = FWBUSRESET;
+       fw_reset_csr(fc);
+       fw_reset_crom(fc);
 
        if (device_get_children(fc->bdev, &devlistp, &devcnt) == 0) {
                for( i = 0 ; i < devcnt ; i++)
@@ -570,6 +679,20 @@ fw_busreset(struct firewire_comm *fc)
                        }
                free(devlistp, M_TEMP);
        }
+
+       newrom = malloc(CROMSIZE, M_FW, M_NOWAIT | M_ZERO);
+       src = &fc->crom_src_buf->src;
+       crom_load(src, (u_int32_t *)newrom, CROMSIZE);
+       if (bcmp(newrom, fc->config_rom, CROMSIZE) != 0) {
+               /* bump generation and reload */
+               src->businfo.generation ++;
+               /* generation must be between 0x2 and 0xF */
+               if (src->businfo.generation < 2)
+                       src->businfo.generation ++;
+               crom_load(src, (u_int32_t *)newrom, CROMSIZE);
+               bcopy(newrom, (void *)fc->config_rom, CROMSIZE);
+       }
+       free(newrom, M_FW);
 }
 
 /* Call once after reboot */
@@ -644,7 +767,6 @@ void fw_init(struct firewire_comm *fc)
        CSRARC(fc, SPED_MAP + 4) = 1;
 
        STAILQ_INIT(&fc->devices);
-       STAILQ_INIT(&fc->pending);
 
 /* Initialize csr ROM work space */
        SLIST_INIT(&fc->ongocsr);
@@ -676,6 +798,7 @@ void fw_init(struct firewire_comm *fc)
        }
 #endif
 
+       fc->crom_src_buf = NULL;
 
 #ifdef FW_VMACCESS
        xfer = fw_xfer_alloc();
@@ -697,22 +820,22 @@ void fw_init(struct firewire_comm *fc)
 #endif
 }
 
+#define BIND_CMP(addr, fwb) (((addr) < (fwb)->start)?-1:\
+    ((fwb)->end < (addr))?1:0)
+
 /*
  * To lookup binded process from IEEE1394 address.
  */
 struct fw_bind *
-fw_bindlookup(struct firewire_comm *fc, u_int32_t dest_hi, u_int32_t dest_lo)
+fw_bindlookup(struct firewire_comm *fc, u_int16_t dest_hi, u_int32_t dest_lo)
 {
+       u_int64_t addr;
        struct fw_bind *tfw;
-       for(tfw = STAILQ_FIRST(&fc->binds) ; tfw != NULL ;
-               tfw = STAILQ_NEXT(tfw, fclist)){
-               if (tfw->act_type != FWACT_NULL &&
-                       tfw->start_hi == dest_hi &&
-                       tfw->start_lo <= dest_lo &&
-                       (tfw->start_lo + tfw->addrlen) > dest_lo){
+
+       addr = ((u_int64_t)dest_hi << 32) | dest_lo;
+       STAILQ_FOREACH(tfw, &fc->binds, fclist)
+               if (tfw->act_type != FWACT_NULL && BIND_CMP(addr, tfw) == 0)
                        return(tfw);
-               }
-       }
        return(NULL);
 }
 
@@ -722,45 +845,34 @@ fw_bindlookup(struct firewire_comm *fc, u_int32_t dest_hi, u_int32_t dest_lo)
 int
 fw_bindadd(struct firewire_comm *fc, struct fw_bind *fwb)
 {
-       struct fw_bind *tfw, *tfw2 = NULL;
-       int err = 0;
-       tfw = STAILQ_FIRST(&fc->binds);
-       if(tfw == NULL){
-               STAILQ_INSERT_HEAD(&fc->binds, fwb, fclist);
-               goto out;
+       struct fw_bind *tfw, *prev = NULL;
+
+       if (fwb->start > fwb->end) {
+               printf("%s: invalid range\n", __FUNCTION__);
+               return EINVAL;
        }
-       if((tfw->start_hi > fwb->start_hi) ||
-               (tfw->start_hi == fwb->start_hi &&
-               (tfw->start_lo > (fwb->start_lo + fwb->addrlen)))){
+
+       STAILQ_FOREACH(tfw, &fc->binds, fclist) {
+               if (fwb->end < tfw->start)
+                       break;
+               prev = tfw;
+       }
+       if (prev == NULL) {
                STAILQ_INSERT_HEAD(&fc->binds, fwb, fclist);
                goto out;
        }
-       for(; tfw != NULL; tfw = STAILQ_NEXT(tfw, fclist)){
-               if((tfw->start_hi < fwb->start_hi) ||
-                  (tfw->start_hi == fwb->start_hi &&
-                   (tfw->start_lo + tfw->addrlen) < fwb->start_lo)){
-                  tfw2 = STAILQ_NEXT(tfw, fclist);
-                       if(tfw2 == NULL)
-                               break;
-                       if((tfw2->start_hi > fwb->start_hi) ||
-                          (tfw2->start_hi == fwb->start_hi &&
-                           tfw2->start_lo > (fwb->start_lo + fwb->addrlen))){
-                               break;
-                       }else{
-                               err = EBUSY;
-                               goto out;
-                       }
-               }
-       }
-       if(tfw != NULL){
-               STAILQ_INSERT_AFTER(&fc->binds, tfw, fwb, fclist);
-       }else{
-               STAILQ_INSERT_TAIL(&fc->binds, fwb, fclist);
+       if (prev->end < fwb->start) {
+               STAILQ_INSERT_AFTER(&fc->binds, prev, fwb, fclist);
+               goto out;
        }
+
+       printf("%s: bind failed\n", __FUNCTION__);
+       return (EBUSY);
+
 out:
-       if (!err && fwb->act_type == FWACT_CH)
+       if (fwb->act_type == FWACT_CH)
                STAILQ_INSERT_HEAD(&fc->ir[fwb->sub]->binds, fwb, chlist);
-       return err;
+       return (0);
 }
 
 /*
@@ -769,18 +881,31 @@ out:
 int
 fw_bindremove(struct firewire_comm *fc, struct fw_bind *fwb)
 {
-       int s;
+#if 0
        struct fw_xfer *xfer, *next;
+#endif
+       struct fw_bind *tfw;
+       int s;
 
        s = splfw();
-       /* shall we check the existance? */
-       STAILQ_REMOVE(&fc->binds, fwb, fw_bind, fclist);
+       STAILQ_FOREACH(tfw, &fc->binds, fclist)
+               if (tfw == fwb) {
+                       STAILQ_REMOVE(&fc->binds, fwb, fw_bind, fclist);
+                       goto found;
+               }
+
+       printf("%s: no such bind\n", __FUNCTION__);
+       splx(s);
+       return (1);
+found:
+#if 0
        /* shall we do this? */
        for (xfer = STAILQ_FIRST(&fwb->xferlist); xfer != NULL; xfer = next) {
                next = STAILQ_NEXT(xfer, link);
                fw_xfer_free(xfer);
        }
        STAILQ_INIT(&fwb->xferlist);
+#endif
 
        splx(s);
        return 0;
@@ -820,7 +945,7 @@ fw_tl2xfer(struct firewire_comm *fc, int node, int tlabel)
 
        for( tl = STAILQ_FIRST(&fc->tlabels[tlabel]); tl != NULL;
                tl = STAILQ_NEXT(tl, link)){
-               if(tl->xfer->dst == node){
+               if(tl->xfer->send.hdr.mode.hdr.dst == node){
                        xfer = tl->xfer;
                        splx(s);
                        if (firewire_debug > 2)
@@ -846,7 +971,6 @@ fw_xfer_alloc(struct malloc_type *type)
        if (xfer == NULL)
                return xfer;
 
-       microtime(&xfer->tv);
        xfer->malloc = type;
 
        return xfer;
@@ -858,22 +982,22 @@ fw_xfer_alloc_buf(struct malloc_type *type, int send_len, int recv_len)
        struct fw_xfer *xfer;
 
        xfer = fw_xfer_alloc(type);
-       xfer->send.len = send_len;
-       xfer->recv.len = recv_len;
+       xfer->send.pay_len = send_len;
+       xfer->recv.pay_len = recv_len;
        if (xfer == NULL)
                return(NULL);
-       if (send_len) {
-               xfer->send.buf = malloc(send_len, type, M_NOWAIT | M_ZERO);
-               if (xfer->send.buf == NULL) {
+       if (send_len > 0) {
+               xfer->send.payload = malloc(send_len, type, M_NOWAIT | M_ZERO);
+               if (xfer->send.payload == NULL) {
                        fw_xfer_free(xfer);
                        return(NULL);
                }
        }
-       if (recv_len) {
-               xfer->recv.buf = malloc(recv_len, type, M_NOWAIT);
-               if (xfer->recv.buf == NULL) {
-                       if (xfer->send.buf != NULL)
-                               free(xfer->send.buf, type);
+       if (recv_len > 0) {
+               xfer->recv.payload = malloc(recv_len, type, M_NOWAIT);
+               if (xfer->recv.payload == NULL) {
+                       if (xfer->send.payload != NULL)
+                               free(xfer->send.payload, type);
                        fw_xfer_free(xfer);
                        return(NULL);
                }
@@ -887,18 +1011,15 @@ fw_xfer_alloc_buf(struct malloc_type *type, int send_len, int recv_len)
 void
 fw_xfer_done(struct fw_xfer *xfer)
 {
-       if (xfer->act.hand == NULL)
+       if (xfer->act.hand == NULL) {
+               printf("act.hand == NULL\n");
                return;
-
-       if (xfer->fc->status != FWBUSRESET)
-               xfer->act.hand(xfer);
-       else {
-               printf("fw_xfer_done: pending\n");
-               if (xfer->fc != NULL)
-                       STAILQ_INSERT_TAIL(&xfer->fc->pending, xfer, link);
-               else
-                       panic("fw_xfer_done: why xfer->fc is NULL?");
        }
+
+       if (xfer->fc == NULL)
+               panic("fw_xfer_done: why xfer->fc is NULL?");
+
+       xfer->act.hand(xfer);
 }
 
 void
@@ -934,20 +1055,34 @@ fw_xfer_unload(struct fw_xfer* xfer)
  * To free IEEE1394 XFER structure. 
  */
 void
-fw_xfer_free( struct fw_xfer* xfer)
+fw_xfer_free_buf( struct fw_xfer* xfer)
 {
-       if(xfer == NULL ) return;
+       if (xfer == NULL) {
+               printf("%s: xfer == NULL\n", __FUNCTION__);
+               return;
+       }
        fw_xfer_unload(xfer);
-       if(xfer->send.buf != NULL){
-               free(xfer->send.buf, xfer->malloc);
+       if(xfer->send.payload != NULL){
+               free(xfer->send.payload, xfer->malloc);
        }
-       if(xfer->recv.buf != NULL){
-               free(xfer->recv.buf, xfer->malloc);
+       if(xfer->recv.payload != NULL){
+               free(xfer->recv.payload, xfer->malloc);
        }
        free(xfer, xfer->malloc);
 }
 
-static void
+void
+fw_xfer_free( struct fw_xfer* xfer)
+{
+       if (xfer == NULL) {
+               printf("%s: xfer == NULL\n", __FUNCTION__);
+               return;
+       }
+       fw_xfer_unload(xfer);
+       free(xfer, xfer->malloc);
+}
+
+void
 fw_asy_callback_free(struct fw_xfer *xfer)
 {
 #if 0
@@ -968,14 +1103,14 @@ fw_phy_config(struct firewire_comm *fc, int root_node, int gap_count)
 
        fc->status = FWBUSPHYCONF;
 
-       xfer = fw_xfer_alloc_buf(M_FWXFER, 12, 0);
+       xfer = fw_xfer_alloc(M_FWXFER);
        if (xfer == NULL)
                return;
        xfer->fc = fc;
        xfer->retry_req = fw_asybusy;
        xfer->act.hand = fw_asy_callback_free;
 
-       fp = (struct fw_pkt *)xfer->send.buf;
+       fp = &xfer->send.hdr;
        fp->mode.ld[1] = 0;
        if (root_node >= 0)
                fp->mode.ld[1] |= (root_node & 0x3f) << 24 | 1 << 23;
@@ -1132,28 +1267,19 @@ static void
 fw_bus_probe(struct firewire_comm *fc)
 {
        int s;
-       struct fw_device *fwdev, *next;
+       struct fw_device *fwdev;
 
        s = splfw();
        fc->status = FWBUSEXPLORE;
        fc->retry_count = 0;
 
-/*
- * Invalidate all devices, just after bus reset. Devices 
- * to be removed has not been seen longer time.
- */
-       for (fwdev = STAILQ_FIRST(&fc->devices); fwdev != NULL; fwdev = next) {
-               next = STAILQ_NEXT(fwdev, link);
+       /* Invalidate all devices, just after bus reset. */
+       STAILQ_FOREACH(fwdev, &fc->devices, link)
                if (fwdev->status != FWDEVINVAL) {
                        fwdev->status = FWDEVINVAL;
                        fwdev->rcnt = 0;
-               } else if(fwdev->rcnt < FW_MAXDEVRCNT) {
-                       fwdev->rcnt ++;
-               } else {
-                       STAILQ_REMOVE(&fc->devices, fwdev, fw_device, link);
-                       free(fwdev, M_FW);
                }
-       }
+
        fc->ongonode = 0;
        fc->ongoaddr = CSRROMOFF;
        fc->ongodev = NULL;
@@ -1209,14 +1335,14 @@ loop:
                                break;
                if(fwdev != NULL){
                        fwdev->dst = fc->ongonode;
-                       fwdev->status = FWDEVATTACHED;
-                       fc->ongonode++;
+                       fwdev->status = FWDEVINIT;
+                       fc->ongodev = fwdev;
                        fc->ongoaddr = CSRROMOFF;
-                       fc->ongodev = NULL;
-                       fc->ongoeui.hi = 0xffffffff; fc->ongoeui.lo = 0xffffffff;
-                       goto loop;
+                       addr = 0xf0000000 | fc->ongoaddr;
+                       goto dorequest;
                }
-               fwdev = malloc(sizeof(struct fw_device), M_FW, M_NOWAIT);
+               fwdev = malloc(sizeof(struct fw_device), M_FW,
+                                                       M_NOWAIT | M_ZERO);
                if(fwdev == NULL)
                        return;
                fwdev->fc = fc;
@@ -1249,25 +1375,25 @@ loop:
        }else{
                addr = 0xf0000000 | fc->ongoaddr;
        }
+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_buf(M_FWXFER, 16, 16);
+       xfer = fw_xfer_alloc(M_FWXFER);
        if(xfer == NULL){
                goto done;
        }
-       xfer->spd = 0;
-       fp = (struct fw_pkt *)xfer->send.buf;
+       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;
-       xfer->dst = FWLOCALBUS | fc->ongonode;
-       fp->mode.rreqq.dst = xfer->dst;
+       fp->mode.rreqq.dst = FWLOCALBUS | fc->ongonode;
        fp->mode.rreqq.dest_lo = addr;
        xfer->act.hand = fw_bus_explore_callback;
 
@@ -1301,12 +1427,12 @@ asyreqq(struct firewire_comm *fc, u_int8_t spd, u_int8_t tl, u_int8_t rt,
        struct fw_pkt *fp;
        int err;
 
-       xfer = fw_xfer_alloc_buf(M_FWXFER, 16, 16);
+       xfer = fw_xfer_alloc(M_FWXFER);
        if (xfer == NULL)
                return NULL;
 
-       xfer->spd = spd; /* XXX:min(spd, fc->spd) */
-       fp = (struct fw_pkt *)xfer->send.buf;
+       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;
@@ -1317,8 +1443,7 @@ asyreqq(struct firewire_comm *fc, u_int8_t spd, u_int8_t tl, u_int8_t rt,
        fp->mode.rreqq.tcode = FWTCODE_RREQQ;
        fp->mode.rreqq.pri = 0;
        fp->mode.rreqq.src = 0;
-       xfer->dst = addr_hi >> 16;
-       fp->mode.rreqq.dst = xfer->dst;
+       fp->mode.rreqq.dst = addr_hi >> 16;
        fp->mode.rreqq.dest_lo = addr_lo;
        xfer->act.hand = hand;
 
@@ -1360,19 +1485,8 @@ fw_bus_explore_callback(struct fw_xfer *xfer)
                goto errnode;
        }
 
-       if(xfer->send.buf == NULL){
-               printf("node%d: send.buf=NULL addr=0x%x\n",
-                       fc->ongonode, fc->ongoaddr);
-               goto errnode;
-       }
-       sfp = (struct fw_pkt *)xfer->send.buf;
-
-       if(xfer->recv.buf == NULL){
-               printf("node%d: recv.buf=NULL addr=0x%x\n",
-                       fc->ongonode, fc->ongoaddr);
-               goto errnode;
-       }
-       rfp = (struct fw_pkt *)xfer->recv.buf;
+       sfp = &xfer->send.hdr;
+       rfp = &xfer->recv.hdr;
 #if 0
        {
                u_int32_t *qld;
@@ -1413,6 +1527,11 @@ fw_bus_explore_callback(struct fw_xfer *xfer)
                        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;
@@ -1504,16 +1623,29 @@ nextnode:
 static void
 fw_attach_dev(struct firewire_comm *fc)
 {
-       struct fw_device *fwdev;
-       struct fw_xfer *xfer;
+       struct fw_device *fwdev, *next;
        int i, err;
        device_t *devlistp;
        int devcnt;
        struct firewire_dev_comm *fdc;
 
-       STAILQ_FOREACH(fwdev, &fc->devices, link)
-               if (fwdev->status == FWDEVINIT)
+       for (fwdev = STAILQ_FIRST(&fc->devices); fwdev != NULL; fwdev = next) {
+               next = STAILQ_NEXT(fwdev, link);
+               if (fwdev->status == FWDEVINIT) {
                        fwdev->status = FWDEVATTACHED;
+               } else if (fwdev->status == FWDEVINVAL) {
+                       fwdev->rcnt ++;
+                       if (fwdev->rcnt > hold_count) {
+                               /*
+                                * Remove devices which have not been seen
+                                * for a while.
+                                */
+                               STAILQ_REMOVE(&fc->devices, fwdev, fw_device,
+                                   link);
+                               free(fwdev, M_FW);
+                       }
+               }
+       }
 
        err = device_get_children(fc->bdev, &devlistp, &devcnt);
        if( err != 0 )
@@ -1527,16 +1659,6 @@ fw_attach_dev(struct firewire_comm *fc)
        }
        free(devlistp, M_TEMP);
 
-       /* call pending handlers */
-       i = 0;
-       while ((xfer = STAILQ_FIRST(&fc->pending))) {
-               STAILQ_REMOVE_HEAD(&fc->pending, link);
-               i++;
-               if (xfer->act.hand)
-                       xfer->act.hand(xfer);
-       }
-       if (i > 0)
-               printf("fw_attach_dev: %d pending handlers called\n", i);
        if (fc->retry_count > 0) {
                printf("probe failed for %d node\n", fc->retry_count);
 #if 0
@@ -1563,7 +1685,9 @@ fw_get_tlabel(struct firewire_comm *fc, struct fw_xfer *xfer)
                label = (label + 1) & 0x3f;
                for(tmptl = STAILQ_FIRST(&fc->tlabels[label]);
                        tmptl != NULL; tmptl = STAILQ_NEXT(tmptl, link)){
-                       if(tmptl->xfer->dst == xfer->dst) break;
+                       if (tmptl->xfer->send.hdr.mode.hdr.dst ==
+                           xfer->send.hdr.mode.hdr.dst)
+                               break;
                }
                if(tmptl == NULL) {
                        tl = malloc(sizeof(struct tlabel),M_FW,M_NOWAIT);
@@ -1576,7 +1700,7 @@ fw_get_tlabel(struct firewire_comm *fc, struct fw_xfer *xfer)
                        splx(s);
                        if (firewire_debug > 1)
                                printf("fw_get_tlabel: dst=%d tl=%d\n",
-                                               xfer->dst, label);
+                                   xfer->send.hdr.mode.hdr.dst, label);
                        return(label);
                }
        }
@@ -1587,39 +1711,67 @@ fw_get_tlabel(struct firewire_comm *fc, struct fw_xfer *xfer)
 }
 
 static void
-fw_rcv_copy(struct fw_xfer *xfer, struct iovec *vec, int nvec)
+fw_rcv_copy(struct fw_rcv_buf *rb)
 {
-       char *p;
-       int res, i, len;
+       struct fw_pkt *pkt;
+       u_char *p;
+       struct tcode_info *tinfo;
+       u_int res, i, len, plen;
+
+       rb->xfer->recv.spd -= rb->spd;
+
+       pkt = (struct fw_pkt *)rb->vec->iov_base;
+       tinfo = &rb->fc->tcode[pkt->mode.hdr.tcode];
+
+       /* Copy header */ 
+       p = (u_char *)&rb->xfer->recv.hdr;
+       bcopy(rb->vec->iov_base, p, tinfo->hdr_len);
+       (u_char *)rb->vec->iov_base += tinfo->hdr_len;
+       rb->vec->iov_len -= tinfo->hdr_len;
+
+       /* Copy payload */
+       p = (u_char *)rb->xfer->recv.payload;
+       res = rb->xfer->recv.pay_len;
+
+       /* special handling for RRESQ */
+       if (pkt->mode.hdr.tcode == FWTCODE_RRESQ &&
+           p != NULL && res >= sizeof(u_int32_t)) {
+               *(u_int32_t *)p = pkt->mode.rresq.data;
+               rb->xfer->recv.pay_len = sizeof(u_int32_t);
+               return;
+       }
 
-       p = xfer->recv.buf;
-       res = xfer->recv.len;
-       for (i = 0; i < nvec; i++, vec++) {
-               len = vec->iov_len;
+       if ((tinfo->flag & FWTI_BLOCK_ASY) == 0)
+               return;
+
+       plen = pkt->mode.rresb.len;
+
+       for (i = 0; i < rb->nvec; i++, rb->vec++) {
+               len = MIN(rb->vec->iov_len, plen);
                if (res < len) {
                        printf("rcv buffer(%d) is %d bytes short.\n",
-                                               xfer->recv.len, len - res);
+                           rb->xfer->recv.pay_len, len - res);
                        len = res;
                }
-               bcopy(vec->iov_base, p, len);
+               bcopy(rb->vec->iov_base, p, len);
                p += len;
                res -= len;
-               if (res <= 0)
+               plen -= len;
+               if (res == 0 || plen == 0)
                        break;
        }
-       xfer->recv.len -= res;
+       rb->xfer->recv.pay_len -= res;
+
 }
 
 /*
  * Generic packet receving process.
  */
 void
-fw_rcv(struct firewire_comm *fc, struct iovec *vec, int nvec, u_int sub, u_int spd)
+fw_rcv(struct fw_rcv_buf *rb)
 {
        struct fw_pkt *fp, *resfp;
-       struct fw_xfer *xfer;
        struct fw_bind *bind;
-       struct firewire_softc *sc;
        int tcode, s;
        int i, len, oldstate;
 #if 0
@@ -1635,39 +1787,28 @@ fw_rcv(struct firewire_comm *fc, struct iovec *vec, int nvec, u_int sub, u_int s
                if((i % 16) != 15) printf("\n");
        }
 #endif
-       fp = (struct fw_pkt *)vec[0].iov_base;
+       fp = (struct fw_pkt *)rb->vec[0].iov_base;
        tcode = fp->mode.common.tcode;
-#if 0 /* XXX this check is not valid for RRESQ and WREQQ */
-       if (vec[0].iov_len < fc->tcode[tcode].hdr_len) {
-#if __FreeBSD_version >= 500000
-               printf("fw_rcv: iov_len(%zu) is less than"
-#else
-               printf("fw_rcv: iov_len(%u) is less than"
-#endif
-                       " hdr_len(%d:tcode=%d)\n", vec[0].iov_len,
-                       fc->tcode[tcode].hdr_len, tcode);
-       }
-#endif
        switch (tcode) {
        case FWTCODE_WRES:
        case FWTCODE_RRESQ:
        case FWTCODE_RRESB:
        case FWTCODE_LRES:
-               xfer = fw_tl2xfer(fc, fp->mode.hdr.src,
+               rb->xfer = fw_tl2xfer(rb->fc, fp->mode.hdr.src,
                                        fp->mode.hdr.tlrt >> 2);
-               if(xfer == NULL) {
+               if(rb->xfer == NULL) {
                        printf("fw_rcv: unknown response "
-                                       "tcode=%d src=0x%x tl=0x%x rt=%d data=0x%x\n",
-                                       tcode,
-                                       fp->mode.hdr.src,
-                                       fp->mode.hdr.tlrt >> 2,
-                                       fp->mode.hdr.tlrt & 3,
-                                       fp->mode.rresq.data);
+                           "%s(%x) src=0x%x tl=0x%x rt=%d data=0x%x\n",
+                           tcode_str[tcode], tcode,
+                           fp->mode.hdr.src,
+                           fp->mode.hdr.tlrt >> 2,
+                           fp->mode.hdr.tlrt & 3,
+                           fp->mode.rresq.data);
 #if 1
                        printf("try ad-hoc work around!!\n");
-                       xfer = fw_tl2xfer(fc, fp->mode.hdr.src,
+                       rb->xfer = fw_tl2xfer(rb->fc, fp->mode.hdr.src,
                                        (fp->mode.hdr.tlrt >> 2)^3);
-                       if (xfer == NULL) {
+                       if (rb->xfer == NULL) {
                                printf("no use...\n");
                                goto err;
                        }
@@ -1675,21 +1816,26 @@ fw_rcv(struct firewire_comm *fc, struct iovec *vec, int nvec, u_int sub, u_int s
                        goto err;
 #endif
                }
-               fw_rcv_copy(xfer, vec, nvec);
-               xfer->resp = 0;
+               fw_rcv_copy(rb);
+               if (rb->xfer->recv.hdr.mode.wres.rtcode != RESP_CMP)
+                       rb->xfer->resp = EIO;
+               else
+                       rb->xfer->resp = 0;
                /* make sure the packet is drained in AT queue */
-               oldstate = xfer->state;
-               xfer->state = FWXF_RCVD;
+               oldstate = rb->xfer->state;
+               rb->xfer->state = FWXF_RCVD;
                switch (oldstate) {
                case FWXF_SENT:
-                       fw_xfer_done(xfer);
+                       fw_xfer_done(rb->xfer);
                        break;
                case FWXF_START:
+#if 0
                        if (firewire_debug)
-                               printf("not sent yet\n");
+                               printf("not sent yet tl=%x\n", rb->xfer->tl);
+#endif
                        break;
                default:
-                       printf("unexpected state %d\n", xfer->state);
+                       printf("unexpected state %d\n", rb->xfer->state);
                }
                return;
        case FWTCODE_WREQQ:
@@ -1697,107 +1843,99 @@ fw_rcv(struct firewire_comm *fc, struct iovec *vec, int nvec, u_int sub, u_int s
        case FWTCODE_RREQQ:
        case FWTCODE_RREQB:
        case FWTCODE_LREQ:
-               bind = fw_bindlookup(fc, fp->mode.rreqq.dest_hi,
+               bind = fw_bindlookup(rb->fc, fp->mode.rreqq.dest_hi,
                        fp->mode.rreqq.dest_lo);
                if(bind == NULL){
+                       printf("Unknown service addr 0x%04x:0x%08x %s(%x)"
 #if __FreeBSD_version >= 500000
-                       printf("Unknown service addr 0x%08x:0x%08x tcode=%x src=0x%x data=%x\n",
+                           " src=0x%x data=%x\n",
 #else
-                       printf("Unknown service addr 0x%08x:0x%08x tcode=%x src=0x%x data=%lx\n",
+                           " src=0x%x data=%lx\n",
 #endif
-                               fp->mode.wreqq.dest_hi,
-                               fp->mode.wreqq.dest_lo,
-                               tcode,
-                               fp->mode.hdr.src,
-                               ntohl(fp->mode.wreqq.data));
-                       if (fc->status == FWBUSRESET) {
+                           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) {
                                printf("fw_rcv: cannot respond(bus reset)!\n");
                                goto err;
                        }
-                       xfer = fw_xfer_alloc_buf(M_FWXFER, 16, 0);
-                       if(xfer == NULL){
+                       rb->xfer = fw_xfer_alloc(M_FWXFER);
+                       if(rb->xfer == NULL){
                                return;
                        }
-                       xfer->spd = spd;
-                       resfp = (struct fw_pkt *)xfer->send.buf;
+                       rb->xfer->send.spd = rb->spd;
+                       rb->xfer->send.pay_len = 0;
+                       resfp = &rb->xfer->send.hdr;
                        switch (tcode) {
                        case FWTCODE_WREQQ:
                        case FWTCODE_WREQB:
                                resfp->mode.hdr.tcode = FWTCODE_WRES;
-                               xfer->send.len = 12;
                                break;
                        case FWTCODE_RREQQ:
                                resfp->mode.hdr.tcode = FWTCODE_RRESQ;
-                               xfer->send.len = 16;
                                break;
                        case FWTCODE_RREQB:
                                resfp->mode.hdr.tcode = FWTCODE_RRESB;
-                               xfer->send.len = 16;
                                break;
                        case FWTCODE_LREQ:
                                resfp->mode.hdr.tcode = FWTCODE_LRES;
-                               xfer->send.len = 16;
                                break;
                        }
                        resfp->mode.hdr.dst = fp->mode.hdr.src;
                        resfp->mode.hdr.tlrt = fp->mode.hdr.tlrt;
                        resfp->mode.hdr.pri = fp->mode.hdr.pri;
-                       resfp->mode.rresb.rtcode = 7;
+                       resfp->mode.rresb.rtcode = RESP_ADDRESS_ERROR;
                        resfp->mode.rresb.extcode = 0;
                        resfp->mode.rresb.len = 0;
 /*
-                       xfer->act.hand = fw_asy_callback;
+                       rb->xfer->act.hand = fw_asy_callback;
 */
-                       xfer->act.hand = fw_xfer_free;
-                       if(fw_asyreq(fc, -1, xfer)){
-                               fw_xfer_free( xfer);
+                       rb->xfer->act.hand = fw_xfer_free;
+                       if(fw_asyreq(rb->fc, -1, rb->xfer)){
+                               fw_xfer_free(rb->xfer);
                                return;
                        }
                        goto err;
                }
                len = 0;
-               for (i = 0; i < nvec; i ++)
-                       len += vec[i].iov_len;
+               for (i = 0; i < rb->nvec; i ++)
+                       len += rb->vec[i].iov_len;
                switch(bind->act_type){
                case FWACT_XFER:
                        /* splfw()?? */
-                       xfer = STAILQ_FIRST(&bind->xferlist);
-                       if (xfer == NULL) {
+                       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(xfer, vec, nvec);
-                       xfer->spd = spd;
-                       if (fc->status != FWBUSRESET)
-                               xfer->act.hand(xfer);
-                       else
-                               STAILQ_INSERT_TAIL(&fc->pending, xfer, link);
+                       fw_rcv_copy(rb);
+                       rb->xfer->act.hand(rb->xfer);
                        return;
                        break;
                case FWACT_CH:
-                       if(fc->ir[bind->sub]->queued >=
-                               fc->ir[bind->sub]->maxq){
-                               device_printf(fc->bdev,
+                       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,
-                                       fc->ir[bind->sub]->queued);
+                                       rb->fc->ir[bind->sub]->queued);
                                goto err;
                        }
-                       xfer = STAILQ_FIRST(&bind->xferlist);
-                       if (xfer == NULL) {
+                       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(xfer, vec, nvec);
-                       xfer->spd = spd;
+                       fw_rcv_copy(rb);
                        s = splfw();
-                       fc->ir[bind->sub]->queued++;
-                       STAILQ_INSERT_TAIL(&fc->ir[bind->sub]->q, xfer, link);
+                       rb->fc->ir[bind->sub]->queued++;
+                       STAILQ_INSERT_TAIL(&rb->fc->ir[bind->sub]->q,
+                           rb->xfer, link);
                        splx(s);
 
-                       wakeup((caddr_t)fc->ir[bind->sub]);
+                       wakeup((caddr_t)rb->fc->ir[bind->sub]);
 
                        return;
                        break;
@@ -1806,11 +1944,12 @@ fw_rcv(struct firewire_comm *fc, struct iovec *vec, int nvec, u_int sub, u_int s
                        break;
                }
                break;
+#if 0 /* shouldn't happen ?? or for GASP */
        case FWTCODE_STREAM:
        {
                struct fw_xferq *xferq;
 
-               xferq = fc->ir[sub];
+               xferq = rb->fc->ir[sub];
 #if 0
                printf("stream rcv dma %d len %d off %d spd %d\n",
                        sub, len, off, spd);
@@ -1821,22 +1960,21 @@ fw_rcv(struct firewire_comm *fc, struct iovec *vec, int nvec, u_int sub, u_int s
                }
                /* XXX get xfer from xfer queue, we don't need copy for 
                        per packet mode */
-               xfer = fw_xfer_alloc_buf(M_FWXFER, 0, /* XXX */
+               rb->xfer = fw_xfer_alloc_buf(M_FWXFER, 0, /* XXX */
                                                vec[0].iov_len);
-               if(xfer == NULL) goto err;
-               fw_rcv_copy(xfer, vec, nvec);
-               xfer->spd = spd;
+               if (rb->xfer == NULL) goto err;
+               fw_rcv_copy(rb)
                s = splfw();
                xferq->queued++;
-               STAILQ_INSERT_TAIL(&xferq->q, xfer, link);
+               STAILQ_INSERT_TAIL(&xferq->q, rb->xfer, link);
                splx(s);
-               sc = device_get_softc(fc->bdev);
+               sc = device_get_softc(rb->fc->bdev);
 #if __FreeBSD_version >= 500000
                if (SEL_WAITING(&xferq->rsel))
 #else
                if (&xferq->rsel.si_pid != 0)
 #endif
-                       selwakeup(&xferq->rsel);
+                       selwakeuppri(&xferq->rsel, FWPRI);
                if (xferq->flag & FWXFERQ_WAKEUP) {
                        xferq->flag &= ~FWXFERQ_WAKEUP;
                        wakeup((caddr_t)xferq);
@@ -1847,6 +1985,7 @@ fw_rcv(struct firewire_comm *fc, struct iovec *vec, int nvec, u_int sub, u_int s
                return;
                break;
        }
+#endif
        default:
                printf("fw_rcv: unknow tcode %d\n", tcode);
                break;
@@ -1861,7 +2000,6 @@ err:
 static void
 fw_try_bmr_callback(struct fw_xfer *xfer)
 {
-       struct fw_pkt *rfp;
        struct firewire_comm *fc;
        int bmr;
 
@@ -1870,26 +2008,23 @@ fw_try_bmr_callback(struct fw_xfer *xfer)
        fc = xfer->fc;
        if (xfer->resp != 0)
                goto error;
-       if (xfer->send.buf == NULL)
-               goto error;
-       if (xfer->recv.buf == NULL)
+       if (xfer->recv.payload == NULL)
                goto error;
-       rfp = (struct fw_pkt *)xfer->recv.buf;
-       if (rfp->mode.lres.rtcode != FWRCODE_COMPLETE)
+       if (xfer->recv.hdr.mode.lres.rtcode != FWRCODE_COMPLETE)
                goto error;
 
-       bmr = ntohl(rfp->mode.lres.payload[0]);
+       bmr = ntohl(xfer->recv.payload[0]);
        if (bmr == 0x3f)
                bmr = fc->nodeid;
 
        CSRARC(fc, BUS_MGR_ID) = fc->set_bmr(fc, bmr & 0x3f);
-       fw_xfer_free(xfer);
+       fw_xfer_free_buf(xfer);
        fw_bmr(fc);
        return;
 
 error:
        device_printf(fc->bdev, "bus manager election failed\n");
-       fw_xfer_free(xfer);
+       fw_xfer_free_buf(xfer);
 }
 
 
@@ -1904,31 +2039,30 @@ fw_try_bmr(void *arg)
        struct fw_pkt *fp;
        int err = 0;
 
-       xfer = fw_xfer_alloc_buf(M_FWXFER, 24, 20);
+       xfer = fw_xfer_alloc_buf(M_FWXFER, 8, 4);
        if(xfer == NULL){
                return;
        }
-       xfer->spd = 0;
+       xfer->send.spd = 0;
        fc->status = FWBUSMGRELECT;
 
-       fp = (struct fw_pkt *)xfer->send.buf;
+       fp = &xfer->send.hdr;
        fp->mode.lreq.dest_hi = 0xffff;
        fp->mode.lreq.tlrt = 0;
        fp->mode.lreq.tcode = FWTCODE_LREQ;
        fp->mode.lreq.pri = 0;
        fp->mode.lreq.src = 0;
        fp->mode.lreq.len = 8;
-       fp->mode.lreq.extcode = FW_LREQ_CMPSWAP;
-       xfer->dst = FWLOCALBUS | fc->irm;
-       fp->mode.lreq.dst = xfer->dst;
+       fp->mode.lreq.extcode = EXTCODE_CMP_SWAP;
+       fp->mode.lreq.dst = FWLOCALBUS | fc->irm;
        fp->mode.lreq.dest_lo = 0xf0000000 | BUS_MGR_ID;
-       fp->mode.lreq.payload[0] = htonl(0x3f);
-       fp->mode.lreq.payload[1] = htonl(fc->nodeid);
+       xfer->send.payload[0] = htonl(0x3f);
+       xfer->send.payload[1] = htonl(fc->nodeid);
        xfer->act.hand = fw_try_bmr_callback;
 
        err = fw_asyreq(fc, -1, xfer);
        if(err){
-               fw_xfer_freexfer);
+               fw_xfer_free_buf(xfer);
                return;
        }
        return;
@@ -2035,6 +2169,7 @@ fw_bmr(struct firewire_comm *fc)
        struct fw_device fwdev;
        union fw_self_id *self_id;
        int cmstr;
+       u_int32_t quad;
 
        /* Check to see if the current root node is cycle master capable */
        self_id = &fc->topology_map->self_id[fc->max_node];
@@ -2074,12 +2209,40 @@ fw_bmr(struct firewire_comm *fc)
        fwdev.maxrec = 8; /* 512 */
        fwdev.status = FWDEVINIT;
        /* Set cmstr bit on the cycle master */
+       quad = htonl(1 << 8);
        fwmem_write_quad(&fwdev, NULL, 0/*spd*/,
-               0xffff, 0xf0000000 | STATE_SET, htonl(1 << 8),
-               fw_asy_callback_free);
+               0xffff, 0xf0000000 | STATE_SET, &quad, fw_asy_callback_free);
 
        return 0;
 }
 
-DRIVER_MODULE(firewire,fwohci,firewire_driver,firewire_devclass,0,0);
+static int
+fw_modevent(module_t mode, int type, void *data)
+{
+       int err = 0;
+#if __FreeBSD_version >= 500000
+       static eventhandler_tag fwdev_ehtag = NULL;
+#endif
+
+       switch (type) {
+       case MOD_LOAD:
+#if __FreeBSD_version >= 500000
+               fwdev_ehtag = EVENTHANDLER_REGISTER(dev_clone,
+                                               fwdev_clone, 0, 1000);
+#endif
+               break;
+       case MOD_UNLOAD:
+#if __FreeBSD_version >= 500000
+               if (fwdev_ehtag != NULL)
+                       EVENTHANDLER_DEREGISTER(dev_clone, fwdev_ehtag);
+#endif
+               break;
+       case MOD_SHUTDOWN:
+               break;
+       }
+       return (err);
+}
+
+DECLARE_DUMMY_MODULE(firewire);
+DRIVER_MODULE(firewire,fwohci,firewire_driver,firewire_devclass,fw_modevent,0);
 MODULE_VERSION(firewire, 1);
index becf94b..4e856f8 100644 (file)
@@ -31,8 +31,8 @@
  * 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.2.2.8 2003/04/28 03:29:18 simokawa Exp $
- * $DragonFly: src/sys/bus/firewire/firewire.h,v 1.2 2003/06/17 04:28:25 dillon Exp $
+ * $FreeBSD: src/sys/dev/firewire/firewire.h,v 1.17 2003/11/07 09:01:41 simokawa Exp $
+ * $DragonFly: src/sys/bus/firewire/firewire.h,v 1.3 2004/02/05 13:32:07 joerg Exp $
  *
  */
 
@@ -48,7 +48,7 @@ struct fw_isochreq {
 };
 
 struct fw_isobufreq {
-       struct {
+       struct fw_bufspec {
                unsigned int nchunk;
                unsigned int npacket;
                unsigned int psize;
@@ -72,7 +72,7 @@ struct fw_reg_req_t {
 
 #define MAXREC(x)      (2 << (x))
 #define FWPMAX_S400 (2048 + 20)        /* MAXREC plus space for control data */
-#define FWMAXQUEUE 64
+#define FWMAXQUEUE 128
 
 #define        FWLOCALBUS      0xffc0
 
@@ -191,12 +191,6 @@ struct fw_pkt {
                        BIT16x2(src, dest_hi);
                        u_int32_t dest_lo;
                        BIT16x2(len, extcode);
-#define FW_LREQ_MSKSWAP        1
-#define FW_LREQ_CMPSWAP        2
-#define FW_LREQ_FTADD  3
-#define FW_LREQ_LTADD  4
-#define FW_LREQ_BDADD  5
-#define FW_LREQ_WRADD  6
                        u_int32_t payload[0];
                } lreq;
                struct {
@@ -216,6 +210,33 @@ struct fw_pkt {
        } mode;
 };
 
+/*
+ * Response code (rtcode)
+ */
+/* The node has successfully completed the command. */
+#define        RESP_CMP                0
+/* A resource conflict was detected. The request may be retried. */
+#define        RESP_CONFLICT_ERROR     4
+/* Hardware error, data is unavailable. */
+#define        RESP_DATA_ERROR         5
+/* A field in the request packet header was set to an unsupported or incorrect
+ * value, or an invalid transaction was attempted (e.g., a write to a read-only
+ * address). */
+#define        RESP_TYPE_ERROR         6
+/* The destination offset field in the request was set to an address not
+ * accessible in the destination node. */
+#define        RESP_ADDRESS_ERROR      7
+
+/*
+ * Extended transaction code (extcode)
+ */
+#define EXTCODE_MASK_SWAP      1
+#define EXTCODE_CMP_SWAP       2
+#define EXTCODE_FETCH_ADD      3
+#define EXTCODE_LITTLE_ADD     4
+#define EXTCODE_BOUNDED_ADD    5
+#define EXTCODE_WRAP_ADD       6
+
 struct fw_eui64 {
        u_int32_t hi, lo;
 };
@@ -382,6 +403,8 @@ struct fw_crom_buf {
 
 #define FWOHCI_RDREG   _IOWR('S', 80, struct fw_reg_req_t)
 #define FWOHCI_WRREG   _IOWR('S', 81, struct fw_reg_req_t)
+#define FWOHCI_RDPHYREG        _IOWR('S', 82, struct fw_reg_req_t)
+#define FWOHCI_WRPHYREG        _IOWR('S', 83, struct fw_reg_req_t)
 
 #define DUMPDMA                _IOWR('S', 82, u_int32_t)
 
@@ -394,9 +417,10 @@ struct fw_crom_buf {
 #define unit2minor(x)  (((x) & 0xff) | (((x) << 8) & ~0xffff))
 #endif
 
-#define UNIT2MIN(x)    (((x) & 0xff) << 8)
+#define MAKEMINOR(f, u, s)     \
+       unit2minor((f) | (((u) & 0xff) << 8) | (s & 0xff))
 #define DEV2UNIT(x)    ((dev2unit(x) & 0xff00) >> 8)
-#define DEV2DMACH(x)   (dev2unit(x) & 0xff)
+#define DEV2SUB(x)     (dev2unit(x) & 0xff)
 
 #define FWMEM_FLAG     0x10000
 #define DEV_FWMEM(x)   (dev2unit(x) & FWMEM_FLAG)
index 21307fb..fca3f71 100644 (file)
@@ -30,8 +30,8 @@
  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  * 
- * $FreeBSD: src/sys/dev/firewire/firewire_phy.h,v 1.1.2.2 2003/04/28 03:29:18 simokawa Exp $
- * $DragonFly: src/sys/bus/firewire/firewire_phy.h,v 1.2 2003/06/17 04:28:25 dillon Exp $
+ * $FreeBSD: src/sys/dev/firewire/firewire_phy.h,v 1.2 2003/04/17 03:38:02 simokawa Exp $
+ * $DragonFly: src/sys/bus/firewire/firewire_phy.h,v 1.3 2004/02/05 13:32:07 joerg Exp $
  *
  */
 
index bd1cc49..237f73d 100644 (file)
  * 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.1.2.14 2003/05/01 06:24:37 simokawa Exp $
- * $DragonFly: src/sys/bus/firewire/firewirereg.h,v 1.5 2003/08/27 11:42:34 rob Exp $
+ * $FreeBSD: src/sys/dev/firewire/firewirereg.h,v 1.33 2004/01/06 14:30:46 simokawa Exp $
+ * $DragonFly: src/sys/bus/firewire/firewirereg.h,v 1.6 2004/02/05 13:32:07 joerg Exp $
  *
  */
 
-#if __FreeBSD_version >= 500000
+#ifdef __DragonFly__
+typedef d_thread_t fw_proc;
+#elif __FreeBSD_version >= 500000
 typedef        struct thread fw_proc;
-#include <sys/selinfo.h>
 #else
-typedef        struct thread fw_proc;
-#include <sys/select.h>
+typedef        struct proc fw_proc;
 #endif
 
+#include <sys/select.h>
 #include <sys/uio.h>
 
 #define        splfw splimp
@@ -71,8 +72,6 @@ struct fw_device{
 struct firewire_softc {
 #if __FreeBSD_version >= 500000
        dev_t dev;
-#else
-       dev_t dev[FWMAXNDMA+1];
 #endif
        struct firewire_comm *fc;
 };
@@ -122,6 +121,7 @@ struct firewire_comm{
        SLIST_HEAD(, csrdir) ongocsr;
        SLIST_HEAD(, csrdir) csrfree;
        u_int32_t status;
+#define        FWBUSNOTREADY   (-1)
 #define        FWBUSRESET      0
 #define        FWBUSINIT       1
 #define        FWBUSCYMELECT   2
@@ -138,12 +138,14 @@ struct firewire_comm{
        STAILQ_HEAD(, tlabel) tlabels[0x40];
        STAILQ_HEAD(, fw_bind) binds;
        STAILQ_HEAD(, fw_device) devices;
-       STAILQ_HEAD(, fw_xfer)  pending;
        u_int  sid_cnt;
 #define CSRSIZE 0x4000
        u_int32_t csr_arc[CSRSIZE/4];
 #define CROMSIZE 0x400
        u_int32_t *config_rom;
+       struct crom_src_buf *crom_src_buf;
+       struct crom_src *crom_src;
+       struct crom_chunk *crom_root;
        struct fw_topology_map *topology_map;
        struct fw_speed_map *speed_map;
        struct callout busprobe_callout;
@@ -188,8 +190,8 @@ struct fw_xferq {
 
 #define FWXFERQ_HANDLER (1 << 16)
 #define FWXFERQ_WAKEUP (1 << 17)
-
        void (*start) (struct firewire_comm*);
+       int dmach;
        STAILQ_HEAD(, fw_xfer) q;
        u_int queued;
        u_int maxq;
@@ -223,7 +225,8 @@ struct tlabel{
 };
 
 struct fw_bind{
-       u_int32_t start_hi, start_lo, addrlen;
+       u_int64_t start;
+       u_int64_t end;
        STAILQ_HEAD(, fw_xfer) xferlist;
        STAILQ_ENTRY(fw_bind) fclist;
        STAILQ_ENTRY(fw_bind) chlist;
@@ -239,9 +242,6 @@ struct fw_xfer{
        struct firewire_comm *fc;
        struct fw_xferq *q;
        struct timeval tv;
-       /* XXX should be removed */
-       u_int32_t dst; /* XXX for if_fwe */
-       u_int8_t spd;
        int8_t resp;
 #define FWXF_INIT 0
 #define FWXF_INQ 1
@@ -258,16 +258,28 @@ struct fw_xfer{
                void (*hand) (struct fw_xfer *);
        } act;
        struct {
-               int len;
-               caddr_t buf;
+               struct fw_pkt hdr;
+               u_int32_t *payload;
+               u_int16_t pay_len;
+               u_int8_t spd;
        } send, recv;
        struct mbuf *mbuf;
        STAILQ_ENTRY(fw_xfer) link;
        struct malloc_type *malloc;
 };
+
+struct fw_rcv_buf {
+       struct firewire_comm *fc;
+       struct fw_xfer *xfer;
+       struct iovec *vec;
+       u_int nvec;
+       u_int8_t spd;
+};
+
 void fw_sidrcv (struct firewire_comm *, u_int32_t *, u_int);
-void fw_rcv (struct firewire_comm *, struct iovec *, int, u_int, u_int);
+void fw_rcv (struct fw_rcv_buf *);
 void fw_xfer_unload ( struct fw_xfer*);
+void fw_xfer_free_buf ( struct fw_xfer*);
 void fw_xfer_free ( struct fw_xfer*);
 struct fw_xfer *fw_xfer_alloc (struct malloc_type *);
 struct fw_xfer *fw_xfer_alloc_buf (struct malloc_type *, int, int);
@@ -283,16 +295,23 @@ u_int16_t fw_crc16 (u_int32_t *, u_int32_t);
 void fw_xfer_timeout (void *);
 void fw_xfer_done (struct fw_xfer *);
 void fw_asy_callback (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 *);
-struct fw_bind *fw_bindlookup (struct firewire_comm *, u_int32_t, u_int32_t);
+struct fw_bind *fw_bindlookup (struct firewire_comm *, u_int16_t, u_int32_t);
 void fw_drain_txq (struct firewire_comm *);
-
+int fwdev_makedev (struct firewire_softc *);
+int fwdev_destroydev (struct firewire_softc *);
+void fwdev_clone (void *, char *, int, dev_t *);
 
 extern int firewire_debug;
 extern devclass_t firewire_devclass;
 
-#define        FWPRI   PCATCH
+#ifdef __DragonFly__
+#define                FWPRI           PCATCH
+#else
+#define                FWPRI           ((PZERO+8)|PCATCH)
+#endif
 
 #if __FreeBSD_version >= 500000
 #define CALLOUT_INIT(x) callout_init(x, 0 /* mpsafe */)
@@ -300,5 +319,24 @@ extern devclass_t firewire_devclass;
 #define CALLOUT_INIT(x) callout_init(x)
 #endif
 
+#if __FreeBSD_version < 500000
+/* compatibility shim for 4.X */
+#define bio buf
+#define bio_bcount b_bcount
+#define bio_cmd b_flags
+#define bio_count b_count
+#define bio_data b_data
+#define bio_dev b_dev
+#define bio_error b_error
+#define bio_flags b_flags
+#define bio_offset b_offset
+#define bio_resid b_resid
+#define BIO_ERROR B_ERROR
+#define BIO_READ B_READ
+#define BIO_WRITE B_WRITE
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#define MAX(a,b) (((a)>(b))?(a):(b))
+#endif
+
 MALLOC_DECLARE(M_FW);
 MALLOC_DECLARE(M_FWXFER);
index 72a501d..6389517 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*-
  * Copyright (c) 2002-2003
  *     Hidetoshi Shimokawa. All rights reserved.
  * 
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  * 
- * $FreeBSD: src/sys/dev/firewire/fwcrom.c,v 1.2.2.2 2003/04/28 03:29:18 simokawa Exp $
- * $DragonFly: src/sys/bus/firewire/fwcrom.c,v 1.3 2003/08/07 21:16:45 dillon Exp $
+ * $DragonFly: src/sys/bus/firewire/fwcrom.c,v 1.4 2004/02/05 13:32:07 joerg Exp $
  */
 
+#ifndef __DragonFly__
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/sys/dev/firewire/fwcrom.c,v 1.9 2003/10/02 04:06:55 simokawa Exp $");
+#endif
+
 #include <sys/param.h>
 #if defined(_KERNEL) || defined(TEST)
 #include <sys/queue.h>
 #include <stdlib.h>
 #include <string.h>
 #endif
+
+#ifdef __DragonFly__
 #include "firewire.h"
 #include "iec13213.h"
+#else
+#include <dev/firewire/firewire.h>
+#include <dev/firewire/iec13213.h>
+#endif
+
+#define MAX_ROM (1024 - sizeof(u_int32_t) * 5)
+#define CROM_END(cc) ((vm_offset_t)(cc)->stack[0].dir + MAX_ROM - 1)
 
 void
 crom_init_context(struct crom_context *cc, u_int32_t *p)
@@ -94,12 +107,12 @@ crom_next(struct crom_context *cc)
                return;
        reg = crom_get(cc);
        if ((reg->key & CSRTYPE_MASK) == CSRTYPE_D) {
-               cc->depth ++;
-               if (cc->depth > CROM_MAX_DEPTH) {
+               if (cc->depth >= CROM_MAX_DEPTH) {
                        printf("crom_next: too deep\n");
-                       cc->depth --;
                        goto again;
                }
+               cc->depth ++;
+
                ptr = &cc->stack[cc->depth];
                ptr->dir = (struct csrdirectory *) (reg + reg->val);
                ptr->index = 0;
@@ -109,8 +122,13 @@ again:
        ptr = &cc->stack[cc->depth];
        ptr->index ++;
 check:
-       if (ptr->index < ptr->dir->crc_len)
+       if (ptr->index < ptr->dir->crc_len &&
+                       (vm_offset_t)crom_get(cc) <= CROM_END(cc))
                return;
+
+       if (ptr->index < ptr->dir->crc_len)
+               printf("crom_next: bound check failed\n");
+
        if (cc->depth > 0) {
                cc->depth--;
                goto again;
@@ -174,12 +192,18 @@ crom_parse_text(struct crom_context *cc, char *buf, int len)
                return;
 
        reg = crom_get(cc);
-       if (reg->key != CROM_TEXTLEAF) {
+       if (reg->key != CROM_TEXTLEAF ||
+                       (vm_offset_t)(reg + reg->val) > CROM_END(cc)) {
                strncpy(buf, nullstr, len);
                return;
        }
        textleaf = (struct csrtext *)(reg + reg->val);
 
+       if ((vm_offset_t)textleaf + textleaf->crc_len > CROM_END(cc)) {
+               strncpy(buf, nullstr, len);
+               return;
+       }
+
        /* XXX should check spec and type */
 
        bp = (u_int32_t *)&buf[0];
@@ -410,6 +434,7 @@ crom_add_chunk(struct crom_src *src, struct crom_chunk *parent,
        return(index);
 }
 
+#define MAX_TEXT ((CROM_MAX_CHUNK_LEN + 1) * 4 - sizeof(struct csrtext))
 int
 crom_add_simple_text(struct crom_src *src, struct crom_chunk *parent,
                                struct crom_chunk *chunk, char *buf)
@@ -417,9 +442,9 @@ crom_add_simple_text(struct crom_src *src, struct crom_chunk *parent,
        struct csrtext *tl;
        u_int32_t *p;
        int len, i;
+       char t[MAX_TEXT];
 
        len = strlen(buf);
-#define MAX_TEXT ((CROM_MAX_CHUNK_LEN + 1) * 4 - sizeof(struct csrtext))
        if (len > MAX_TEXT) {
 #if __FreeBSD_version < 500000
                printf("text(%d) trancated to %d.\n", len, MAX_TEXT);
@@ -434,8 +459,10 @@ crom_add_simple_text(struct crom_src *src, struct crom_chunk *parent,
        tl->spec_id = 0;
        tl->spec_type = 0;
        tl->lang_id = 0;
-       p = (u_int32_t *) buf;
-       for (i = 0; i < howmany(len, sizeof(u_int32_t)) / 4; i ++)
+       bzero(&t[0], roundup2(len, sizeof(u_int32_t)));
+       bcopy(buf, &t[0], len);
+       p = (u_int32_t *)&t[0];
+       for (i = 0; i < howmany(len, sizeof(u_int32_t)); i ++)
                tl->text[i] = ntohl(*p++);
        return (crom_add_chunk(src, parent, chunk, CROM_TEXTLEAF));
 }
@@ -457,8 +484,9 @@ crom_load(struct crom_src *src, u_int32_t *buf, int maxlen)
 {
        struct crom_chunk *chunk, *parent;
        struct csrhdr *hdr;
-#if 0
+#ifdef _KERNEL
        u_int32_t *ptr;
+       int i;
 #endif
        int count, offset;
        int len;
@@ -495,9 +523,9 @@ crom_load(struct crom_src *src, u_int32_t *buf, int maxlen)
        }
        hdr = (struct csrhdr *)buf;
        hdr->crc_len = count - 1;
-       hdr->crc = crom_crc(buf + 1, hdr->crc_len);
+       hdr->crc = crom_crc(&buf[1], hdr->crc_len);
 
-#if 0
+#ifdef _KERNEL
        /* byte swap */
        ptr = buf;
        for (i = 0; i < count; i ++) {
index 658307c..95cad9e 100644 (file)
@@ -31,8 +31,8 @@
  * 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.2.4.11 2003/04/28 03:29:18 simokawa Exp $
- * $DragonFly: src/sys/bus/firewire/fwdev.c,v 1.5 2003/08/07 21:16:45 dillon Exp $
+ * $FreeBSD: src/sys/dev/firewire/fwdev.c,v 1.36 2004/01/22 14:41:17 simokawa Exp $
+ * $DragonFly: src/sys/bus/firewire/fwdev.c,v 1.6 2004/02/05 13:32:07 joerg Exp $
  *
  */
 
 #include <sys/systm.h>
 #include <sys/types.h>
 #include <sys/mbuf.h>
+#if __FreeBSD_version < 500000
+#include <sys/buf.h>
+#else
+#include <sys/bio.h>
+#endif
 
 #include <sys/kernel.h>
 #include <sys/malloc.h>
 #include <sys/conf.h>
-#include <sys/proc.h>
 #include <sys/poll.h>
 
 #include <sys/bus.h>
+#include <sys/ctype.h>
 #include <machine/bus.h>
 
 #include <sys/ioccom.h>
 
+#ifdef __DragonFly__
 #include "firewire.h"
 #include "firewirereg.h"
 #include "fwdma.h"
 #include "fwmem.h"
 #include "iec68113.h"
+#else
+#include <dev/firewire/firewire.h>
+#include <dev/firewire/firewirereg.h>
+#include <dev/firewire/fwdma.h>
+#include <dev/firewire/fwmem.h>
+#include <dev/firewire/iec68113.h>
+#endif
 
 #define CDEV_MAJOR 127
 #define        FWNODE_INVAL 0xffff
@@ -68,9 +81,15 @@ static       d_poll_t        fw_poll;
 static d_read_t        fw_read;        /* for Isochronous packet */
 static d_write_t       fw_write;
 static d_mmap_t        fw_mmap;
+static d_strategy_t    fw_strategy;
 
 struct cdevsw firewire_cdevsw = 
 {
+#ifdef __DragonFly__
+       "fw", CDEV_MAJOR, D_MEM, NULL, 0,
+       fw_open, fw_close, fw_read, fw_write, fw_ioctl,
+       fw_poll, fw_mmap, fw_strategy, nodump, nopsize,
+#else
 #if __FreeBSD_version >= 500104
        .d_open =       fw_open,
        .d_close =      fw_close,
@@ -79,44 +98,112 @@ struct cdevsw firewire_cdevsw =
        .d_ioctl =      fw_ioctl,
        .d_poll =       fw_poll,
        .d_mmap =       fw_mmap,
+       .d_strategy =   fw_strategy,
        .d_name =       "fw",
        .d_maj =        CDEV_MAJOR,
        .d_flags =      D_MEM
 #else
-       "fw", CDEV_MAJOR, D_MEM, NULL, 0,
        fw_open, fw_close, fw_read, fw_write, fw_ioctl,
-       fw_poll, fw_mmap, nostrategy, nodump, nopsize,
+       fw_poll, fw_mmap, fw_strategy, "fw", CDEV_MAJOR,
+       nodump, nopsize, D_MEM, -1
+#endif
 #endif
 };
 
+struct fw_drv1 {
+       struct fw_xferq *ir;
+       struct fw_xferq *it;
+       struct fw_isobufreq bufreq;
+};
+
 static int
-fw_open (dev_t dev, int flags, int fmt, fw_proc *td)
+fwdev_allocbuf(struct firewire_comm *fc, struct fw_xferq *q,
+       struct fw_bufspec *b)
 {
-       struct firewire_softc *sc;
-       int unit = DEV2UNIT(dev);
-       int sub = DEV2DMACH(dev);
+       int i;
+
+       if (q->flag & (FWXFERQ_RUNNING | FWXFERQ_EXTBUF))
+               return(EBUSY);
+
+       q->bulkxfer = (struct fw_bulkxfer *) malloc(
+               sizeof(struct fw_bulkxfer) * b->nchunk,
+               M_FW, M_WAITOK);
+       if (q->bulkxfer == NULL)
+               return(ENOMEM);
+
+       b->psize = roundup2(b->psize, sizeof(u_int32_t));
+       q->buf = fwdma_malloc_multiseg(fc, sizeof(u_int32_t),
+                       b->psize, b->nchunk * b->npacket, BUS_DMA_WAITOK);
+
+       if (q->buf == NULL) {
+               free(q->bulkxfer, M_FW);
+               q->bulkxfer = NULL;
+               return(ENOMEM);
+       }
+       q->bnchunk = b->nchunk;
+       q->bnpacket = b->npacket;
+       q->psize = (b->psize + 3) & ~3;
+       q->queued = 0;
+
+       STAILQ_INIT(&q->stvalid);
+       STAILQ_INIT(&q->stfree);
+       STAILQ_INIT(&q->stdma);
+       q->stproc = NULL;
+
+       for(i = 0 ; i < q->bnchunk; i++){
+               q->bulkxfer[i].poffset = i * q->bnpacket;
+               q->bulkxfer[i].mbuf = NULL;
+               STAILQ_INSERT_TAIL(&q->stfree, &q->bulkxfer[i], link);
+       }
+
+       q->flag &= ~FWXFERQ_MODEMASK;
+       q->flag |= FWXFERQ_STREAM;
+       q->flag |= FWXFERQ_EXTBUF;
+
+       return (0);
+}
 
+static int
+fwdev_freebuf(struct fw_xferq *q)
+{
+       if (q->flag & FWXFERQ_EXTBUF) {
+               if (q->buf != NULL)
+                       fwdma_free_multiseg(q->buf);
+               q->buf = NULL;
+               free(q->bulkxfer, M_FW);
+               q->bulkxfer = NULL;
+               q->flag &= ~FWXFERQ_EXTBUF;
+               q->psize = 0;
+               q->maxq = FWMAXQUEUE;
+       }
+       return (0);
+}
+
+
+static int
+fw_open (dev_t dev, int flags, int fmt, fw_proc *td)
+{
        int err = 0;
 
        if (DEV_FWMEM(dev))
                return fwmem_open(dev, flags, fmt, td);
 
-       sc = devclass_get_softc(firewire_devclass, unit);
-       if(sc->fc->ir[sub]->flag & FWXFERQ_OPEN){
-               err = EBUSY;
-               return err;
-       }
-       if(sc->fc->it[sub]->flag & FWXFERQ_OPEN){
-               err = EBUSY;
-               return err;
-       }
-       if(sc->fc->ir[sub]->flag & FWXFERQ_MODEMASK){
-               err = EBUSY;
-               return err;
+       if (dev->si_drv1 != NULL)
+               return (EBUSY);
+
+#if __FreeBSD_version >= 500000
+       if ((dev->si_flags & SI_NAMED) == 0) {
+               int unit = DEV2UNIT(dev);
+               int sub = DEV2SUB(dev);
+
+               make_dev(&firewire_cdevsw, minor(dev),
+                       UID_ROOT, GID_OPERATOR, 0660,
+                       "fw%d.%d", unit, sub);
        }
-/* Default is per packet mode */
-       sc->fc->ir[sub]->flag |= FWXFERQ_OPEN;
-       sc->fc->it[sub]->flag |= FWXFERQ_OPEN;
+#endif
+
+       dev->si_drv1 = malloc(sizeof(struct fw_drv1), M_FW, M_WAITOK | M_ZERO);
+
        return err;
 }
 
@@ -124,8 +211,9 @@ static int
 fw_close (dev_t dev, int flags, int fmt, fw_proc *td)
 {
        struct firewire_softc *sc;
+       struct firewire_comm *fc;
+       struct fw_drv1 *d;
        int unit = DEV2UNIT(dev);
-       int sub = DEV2DMACH(dev);
        struct fw_xfer *xfer;
        struct fw_bind *fwb;
        int err = 0;
@@ -134,60 +222,59 @@ fw_close (dev_t dev, int flags, int fmt, fw_proc *td)
                return fwmem_close(dev, flags, fmt, td);
 
        sc = devclass_get_softc(firewire_devclass, unit);
-       if(!(sc->fc->ir[sub]->flag & FWXFERQ_OPEN)){
-               err = EINVAL;
-               return err;
-       }
-       sc->fc->ir[sub]->flag &= ~FWXFERQ_OPEN;
-       if(!(sc->fc->it[sub]->flag & FWXFERQ_OPEN)){
-               err = EINVAL;
-               return err;
-       }
-       sc->fc->it[sub]->flag &= ~FWXFERQ_OPEN;
+       fc = sc->fc;
+       d = (struct fw_drv1 *)dev->si_drv1;
 
-       if(sc->fc->ir[sub]->flag & FWXFERQ_RUNNING){
-               sc->fc->irx_disable(sc->fc, sub);
-       }
-       if(sc->fc->it[sub]->flag & FWXFERQ_RUNNING){
-               sc->fc->it[sub]->flag &= ~FWXFERQ_RUNNING;
-               sc->fc->itx_disable(sc->fc, sub);
-       }
-       if(sc->fc->ir[sub]->flag & FWXFERQ_EXTBUF){
-               if (sc->fc->ir[sub]->buf != NULL)
-                       fwdma_free_multiseg(sc->fc->ir[sub]->buf);
-               sc->fc->ir[sub]->buf = NULL;
-               free(sc->fc->ir[sub]->bulkxfer, M_FW);
-               sc->fc->ir[sub]->bulkxfer = NULL;
-               sc->fc->ir[sub]->flag &= ~FWXFERQ_EXTBUF;
-               sc->fc->ir[sub]->psize = PAGE_SIZE;
-               sc->fc->ir[sub]->maxq = FWMAXQUEUE;
-       }
-       if(sc->fc->it[sub]->flag & FWXFERQ_EXTBUF){
-               if (sc->fc->it[sub]->buf != NULL)
-                       fwdma_free_multiseg(sc->fc->it[sub]->buf);
-               sc->fc->it[sub]->buf = NULL;
-               free(sc->fc->it[sub]->bulkxfer, M_FW);
-               sc->fc->it[sub]->bulkxfer = NULL;
-               sc->fc->it[sub]->flag &= ~FWXFERQ_EXTBUF;
-               sc->fc->it[sub]->psize = 0;
-               sc->fc->it[sub]->maxq = FWMAXQUEUE;
-       }
-       for(xfer = STAILQ_FIRST(&sc->fc->ir[sub]->q);
-               xfer != NULL; xfer = STAILQ_FIRST(&sc->fc->ir[sub]->q)){
-               sc->fc->ir[sub]->queued--;
-               STAILQ_REMOVE_HEAD(&sc->fc->ir[sub]->q, link);
+       if (d->ir != NULL) {
+               struct fw_xferq *ir = d->ir;
+
+               if ((ir->flag & FWXFERQ_OPEN) == 0)
+                       return (EINVAL);
+               if (ir->flag & FWXFERQ_RUNNING) {
+                       ir->flag &= ~FWXFERQ_RUNNING;
+                       fc->irx_disable(fc, ir->dmach);
+               }
+               /* free extbuf */
+               fwdev_freebuf(ir);
+               /* drain receiving buffer */
+               for (xfer = STAILQ_FIRST(&ir->q);
+                       xfer != NULL; xfer = STAILQ_FIRST(&ir->q)) {
+                       ir->queued --;
+                       STAILQ_REMOVE_HEAD(&ir->q, link);
+
+                       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;
 
-               xfer->resp = 0;
-               fw_xfer_done(xfer);
        }
-       for(fwb = STAILQ_FIRST(&sc->fc->ir[sub]->binds); fwb != NULL;
-               fwb = STAILQ_FIRST(&sc->fc->ir[sub]->binds)){
-               STAILQ_REMOVE(&sc->fc->binds, fwb, fw_bind, fclist);
-               STAILQ_REMOVE_HEAD(&sc->fc->ir[sub]->binds, chlist);
-               free(fwb, M_FW);
+       if (d->it != NULL) {
+               struct fw_xferq *it = d->it;
+
+               if ((it->flag & FWXFERQ_OPEN) == 0)
+                       return (EINVAL);
+               if (it->flag & FWXFERQ_RUNNING) {
+                       it->flag &= ~FWXFERQ_RUNNING;
+                       fc->itx_disable(fc, it->dmach);
+               }
+               /* free extbuf */
+               fwdev_freebuf(it);
+               it->flag &= ~(FWXFERQ_OPEN |
+                       FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK);
+               d->it = NULL;
        }
-       sc->fc->ir[sub]->flag &= ~(FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK);
-       sc->fc->it[sub]->flag &= ~(FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK);
+       free(dev->si_drv1, M_FW);
+       dev->si_drv1 = NULL;
+
        return err;
 }
 
@@ -202,15 +289,16 @@ fw_read (dev_t dev, struct uio *uio, int ioflag)
        struct fw_xfer *xfer;
        int err = 0, s, slept = 0;
        int unit = DEV2UNIT(dev);
-       int sub = DEV2DMACH(dev);
        struct fw_pkt *fp;
 
        if (DEV_FWMEM(dev))
-               return fwmem_read(dev, uio, ioflag);
+               return physio(dev, uio, ioflag);
 
        sc = devclass_get_softc(firewire_devclass, unit);
 
-       ir = sc->fc->ir[sub];
+       ir = ((struct fw_drv1 *)dev->si_drv1)->ir;
+       if (ir == NULL || ir->buf == NULL)
+               return (EIO);
 
 readloop:
        xfer = STAILQ_FIRST(&ir->q);
@@ -237,16 +325,19 @@ readloop:
                        err = EIO;
                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 = (struct fw_pkt *)xfer->recv.buf;
-               if(sc->fc->irx_post != NULL)
+               fp = &xfer->recv.hdr;
+               if (sc->fc->irx_post != NULL)
                        sc->fc->irx_post(sc->fc, fp->mode.ld);
-               err = uiomove(xfer->recv.buf, xfer->recv.len, uio);
+               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 */
@@ -265,7 +356,7 @@ readloop:
                        s = splfw();
                        STAILQ_INSERT_TAIL(&ir->stfree, ir->stproc, link);
                        splx(s);
-                       sc->fc->irx_enable(sc->fc, sub);
+                       sc->fc->irx_enable(sc->fc, ir->dmach);
                        ir->stproc = NULL;
                }
                if (uio->uio_resid >= ir->psize) {
@@ -282,18 +373,19 @@ fw_write (dev_t dev, struct uio *uio, int ioflag)
        int err = 0;
        struct firewire_softc *sc;
        int unit = DEV2UNIT(dev);
-       int sub = DEV2DMACH(dev);
        int s, slept = 0;
        struct fw_pkt *fp;
        struct firewire_comm *fc;
        struct fw_xferq *it;
 
        if (DEV_FWMEM(dev))
-               return fwmem_write(dev, uio, ioflag);
+               return physio(dev, uio, ioflag);
 
        sc = devclass_get_softc(firewire_devclass, unit);
        fc = sc->fc;
-       it = sc->fc->it[sub];
+       it = ((struct fw_drv1 *)dev->si_drv1)->it;
+       if (it == NULL || it->buf == NULL)
+               return (EIO);
 isoloop:
        if (it->stproc == NULL) {
                it->stproc = STAILQ_FIRST(&it->stfree);
@@ -304,7 +396,7 @@ isoloop:
                        it->queued = 0;
                } else if (slept == 0) {
                        slept = 1;
-                       err = sc->fc->itx_enable(sc->fc, sub);
+                       err = sc->fc->itx_enable(sc->fc, it->dmach);
                        if (err)
                                return err;
                        err = tsleep(it, FWPRI, "fw_write", hz);
@@ -327,7 +419,7 @@ isoloop:
                STAILQ_INSERT_TAIL(&it->stvalid, it->stproc, link);
                splx(s);
                it->stproc = NULL;
-               err = sc->fc->itx_enable(sc->fc, sub);
+               err = sc->fc->itx_enable(sc->fc, it->dmach);
        }
        if (uio->uio_resid >= sizeof(struct fw_isohdr)) {
                slept = 0;
@@ -335,7 +427,6 @@ isoloop:
        }
        return err;
 }
-
 /*
  * ioctl support.
  */
@@ -343,8 +434,9 @@ int
 fw_ioctl (dev_t 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 sub = DEV2DMACH(dev);
        int s, i, len, err = 0;
        struct fw_device *fwdev;
        struct fw_bind *fwb;
@@ -352,6 +444,7 @@ fw_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
        struct fw_xfer *xfer;
        struct fw_pkt *fp;
        struct fw_devinfo *devinfo;
+       void *ptr;
 
        struct fw_devlstreq *fwdevlst = (struct fw_devlstreq *)data;
        struct fw_asyreq *asyreq = (struct fw_asyreq *)data;
@@ -363,158 +456,107 @@ fw_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
        if (DEV_FWMEM(dev))
                return fwmem_ioctl(dev, cmd, data, flag, td);
 
-       sc = devclass_get_softc(firewire_devclass, unit);
        if (!data)
                return(EINVAL);
 
+       sc = devclass_get_softc(firewire_devclass, unit);
+       fc = sc->fc;
+       d = (struct fw_drv1 *)dev->si_drv1;
+       ir = d->ir;
+       it = d->it;
+
        switch (cmd) {
        case FW_STSTREAM:
-               sc->fc->it[sub]->flag &= ~0xff;
-               sc->fc->it[sub]->flag |= (0x3f & ichreq->ch);
-               sc->fc->it[sub]->flag |= ((0x3 & ichreq->tag) << 6);
-               err = 0;
+               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) {
+                               err = EBUSY;
+                               break;
+                       }
+                       err = fwdev_allocbuf(fc, it, &d->bufreq.tx);
+                       if (err)
+                               break;
+                       it->flag |=  FWXFERQ_OPEN;
+               }
+               it->flag &= ~0xff;
+               it->flag |= (0x3f & ichreq->ch);
+               it->flag |= ((0x3 & ichreq->tag) << 6);
+               d->it = it;
                break;
        case FW_GTSTREAM:
-               ichreq->ch = sc->fc->it[sub]->flag & 0x3f;
-               ichreq->tag =(sc->fc->it[sub]->flag) >> 2 & 0x3;
-               err = 0;
+               if (it != NULL) {
+                       ichreq->ch = it->flag & 0x3f;
+                       ichreq->tag = it->flag >> 2 & 0x3;
+               } else
+                       err = EINVAL;
                break;
        case FW_SRSTREAM:
-               sc->fc->ir[sub]->flag &= ~0xff;
-               sc->fc->ir[sub]->flag |= (0x3f & ichreq->ch);
-               sc->fc->ir[sub]->flag |= ((0x3 & ichreq->tag) << 6);
-               err = sc->fc->irx_enable(sc->fc, sub);
+               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) {
+                               err = EBUSY;
+                               break;
+                       }
+                       err = fwdev_allocbuf(fc, ir, &d->bufreq.rx);
+                       if (err)
+                               break;
+                       ir->flag |=  FWXFERQ_OPEN;
+               }
+               ir->flag &= ~0xff;
+               ir->flag |= (0x3f & ichreq->ch);
+               ir->flag |= ((0x3 & ichreq->tag) << 6);
+               d->ir = ir;
+               err = fc->irx_enable(fc, ir->dmach);
                break;
        case FW_GRSTREAM:
-               ichreq->ch = sc->fc->ir[sub]->flag & 0x3f;
-               ichreq->tag =(sc->fc->ir[sub]->flag) >> 2 & 0x3;
-               err = 0;
+               if (d->ir != NULL) {
+                       ichreq->ch = ir->flag & 0x3f;
+                       ichreq->tag = ir->flag >> 2 & 0x3;
+               } else
+                       err = EINVAL;
                break;
        case FW_SSTBUF:
-               ir = sc->fc->ir[sub];
-               it = sc->fc->it[sub];
-
-               if(ir->flag & FWXFERQ_RUNNING || it->flag & FWXFERQ_RUNNING){
-                       return(EBUSY);
-               }
-               if((ir->flag & FWXFERQ_EXTBUF) || (it->flag & FWXFERQ_EXTBUF)){
-                       return(EBUSY);
-               }
-               if((ibufreq->rx.nchunk *
-                       ibufreq->rx.psize * ibufreq->rx.npacket) +
-                  (ibufreq->tx.nchunk *
-                       ibufreq->tx.psize * ibufreq->tx.npacket) <= 0){
-                               return(EINVAL);
-               }
-               ir->bulkxfer
-                       = (struct fw_bulkxfer *)malloc(sizeof(struct fw_bulkxfer) * ibufreq->rx.nchunk, M_FW, M_WAITOK);
-               if(ir->bulkxfer == NULL){
-                       return(ENOMEM);
-               }
-               it->bulkxfer
-                       = (struct fw_bulkxfer *)malloc(sizeof(struct fw_bulkxfer) * ibufreq->tx.nchunk, M_FW, M_WAITOK);
-               if(it->bulkxfer == NULL){
-                       return(ENOMEM);
-               }
-               if (ibufreq->rx.psize > 0) {
-                       ibufreq->rx.psize = roundup2(ibufreq->rx.psize,
-                                                       sizeof(u_int32_t));
-                       ir->buf = fwdma_malloc_multiseg(
-                               sc->fc, sizeof(u_int32_t),
-                               ibufreq->rx.psize,
-                               ibufreq->rx.nchunk * ibufreq->rx.npacket,
-                               BUS_DMA_WAITOK);
-
-                       if(ir->buf == NULL){
-                               free(ir->bulkxfer, M_FW);
-                               free(it->bulkxfer, M_FW);
-                               ir->bulkxfer = NULL;
-                               it->bulkxfer = NULL;
-                               it->buf = NULL;
-                               return(ENOMEM);
-                       }
+               bcopy(ibufreq, &d->bufreq, sizeof(d->bufreq));
+               break;
+       case FW_GSTBUF:
+               bzero(&ibufreq->rx, sizeof(ibufreq->rx));
+               if (ir != NULL) {
+                       ibufreq->rx.nchunk = ir->bnchunk;
+                       ibufreq->rx.npacket = ir->bnpacket;
+                       ibufreq->rx.psize = ir->psize;
                }
-               if (ibufreq->tx.psize > 0) {
-                       ibufreq->tx.psize = roundup2(ibufreq->tx.psize,
-                                                       sizeof(u_int32_t));
-                       it->buf = fwdma_malloc_multiseg(
-                               sc->fc, sizeof(u_int32_t),
-                               ibufreq->tx.psize,
-                               ibufreq->tx.nchunk * ibufreq->tx.npacket,
-                               BUS_DMA_WAITOK);
-
-                       if(it->buf == NULL){
-                               free(ir->bulkxfer, M_FW);
-                               free(it->bulkxfer, M_FW);
-                               fwdma_free_multiseg(ir->buf);
-                               ir->bulkxfer = NULL;
-                               it->bulkxfer = NULL;
-                               it->buf = NULL;
-                               return(ENOMEM);
-                       }
+               bzero(&ibufreq->tx, sizeof(ibufreq->tx));
+               if (it != NULL) {
+                       ibufreq->tx.nchunk = it->bnchunk;
+                       ibufreq->tx.npacket = it->bnpacket;
+                       ibufreq->tx.psize = it->psize;
                }
+               break;
+       case FW_ASYREQ:
+       {
+               struct tcode_info *tinfo;
+               int pay_len = 0;
 
-               ir->bnchunk = ibufreq->rx.nchunk;
-               ir->bnpacket = ibufreq->rx.npacket;
-               ir->psize = (ibufreq->rx.psize + 3) & ~3;
-               ir->queued = 0;
-
-               it->bnchunk = ibufreq->tx.nchunk;
-               it->bnpacket = ibufreq->tx.npacket;
-               it->psize = (ibufreq->tx.psize + 3) & ~3;
-               it->queued = 0;
-
-               STAILQ_INIT(&ir->stvalid);
-               STAILQ_INIT(&ir->stfree);
-               STAILQ_INIT(&ir->stdma);
-               ir->stproc = NULL;
+               fp = &asyreq->pkt;
+               tinfo = &sc->fc->tcode[fp->mode.hdr.tcode];
 
-               STAILQ_INIT(&it->stvalid);
-               STAILQ_INIT(&it->stfree);
-               STAILQ_INIT(&it->stdma);
-               it->stproc = NULL;
+               if ((tinfo->flag & FWTI_BLOCK_ASY) != 0)
+                       pay_len = MAX(0, asyreq->req.len - tinfo->hdr_len);
 
-               for(i = 0 ; i < sc->fc->ir[sub]->bnchunk; i++){
-                       ir->bulkxfer[i].poffset = i * ir->bnpacket;
-                       ir->bulkxfer[i].mbuf = NULL;
-                       STAILQ_INSERT_TAIL(&ir->stfree,
-                                       &ir->bulkxfer[i], link);
-               }
-               for(i = 0 ; i < sc->fc->it[sub]->bnchunk; i++){
-                       it->bulkxfer[i].poffset = i * it->bnpacket;
-                       it->bulkxfer[i].mbuf = NULL;
-                       STAILQ_INSERT_TAIL(&it->stfree,
-                                       &it->bulkxfer[i], link);
-               }
-               ir->flag &= ~FWXFERQ_MODEMASK;
-               ir->flag |= FWXFERQ_STREAM;
-               ir->flag |= FWXFERQ_EXTBUF;
-
-               it->flag &= ~FWXFERQ_MODEMASK;
-               it->flag |= FWXFERQ_STREAM;
-               it->flag |= FWXFERQ_EXTBUF;
-               err = 0;
-               break;
-       case FW_GSTBUF:
-               ibufreq->rx.nchunk = sc->fc->ir[sub]->bnchunk;
-               ibufreq->rx.npacket = sc->fc->ir[sub]->bnpacket;
-               ibufreq->rx.psize = sc->fc->ir[sub]->psize;
+               xfer = fw_xfer_alloc_buf(M_FWXFER, pay_len, PAGE_SIZE/*XXX*/);
+               if (xfer == NULL)
+                       return (ENOMEM);
 
-               ibufreq->tx.nchunk = sc->fc->it[sub]->bnchunk;
-               ibufreq->tx.npacket = sc->fc->it[sub]->bnpacket;
-               ibufreq->tx.psize = sc->fc->it[sub]->psize;
-               break;
-       case FW_ASYREQ:
-               xfer = fw_xfer_alloc_buf(M_FWXFER, asyreq->req.len,
-                                                       PAGE_SIZE /* XXX */);
-               if(xfer == NULL){
-                       err = ENOMEM;
-                       return err;
-               }
-               fp = &asyreq->pkt;
                switch (asyreq->req.type) {
                case FWASREQNODE:
-                       xfer->dst = fp->mode.hdr.dst;
                        break;
                case FWASREQEUI:
                        fwdev = fw_noderesolve_eui64(sc->fc,
@@ -523,10 +565,9 @@ fw_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
                                device_printf(sc->fc->bdev,
                                        "cannot find node\n");
                                err = EINVAL;
-                               goto error;
+                               goto out;
                        }
-                       xfer->dst = FWLOCALBUS | fwdev->dst;
-                       fp->mode.hdr.dst = xfer->dst;
+                       fp->mode.hdr.dst = FWLOCALBUS | fwdev->dst;
                        break;
                case FWASRESTL:
                        /* XXX what's this? */
@@ -535,26 +576,38 @@ fw_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
                        /* nothing to do */
                        break;
                }
-               xfer->spd = asyreq->req.sped;
-               bcopy(fp, xfer->send.buf, xfer->send.len);
+
+               bcopy(fp, (void *)&xfer->send.hdr, tinfo->hdr_len);
+               if (pay_len > 0)
+                       bcopy((char *)fp + tinfo->hdr_len,
+                           (void *)&xfer->send.payload, pay_len);
+               xfer->send.spd = asyreq->req.sped;
                xfer->act.hand = fw_asy_callback;
-               err = fw_asyreq(sc->fc, sub, xfer);
-               if(err){
-                       fw_xfer_free( xfer);
-                       return err;
-               }
-               err = tsleep(xfer, FWPRI, "asyreq", hz);
-               if(err == 0){
-                       if(asyreq->req.len >= xfer->recv.len){
-                               asyreq->req.len = xfer->recv.len;
-                       }else{
-                               err = EINVAL;
-                       }
-                       bcopy(xfer->recv.buf, fp, asyreq->req.len);
+
+               if ((err = fw_asyreq(sc->fc, -1, xfer)) != 0)
+                       goto out;
+               if ((err = tsleep(xfer, FWPRI, "asyreq", hz)) != 0)
+                       goto out;
+               if (xfer->resp != 0) {
+                       err = EIO;
+                       goto out;
                }
-error:
-               fw_xfer_free( xfer);
+               if ((tinfo->flag & FWTI_TLABEL) == 0)
+                       goto out;
+
+               /* copy response */
+               tinfo = &sc->fc->tcode[xfer->recv.hdr.mode.hdr.tcode];
+               if (asyreq->req.len >= xfer->recv.pay_len + tinfo->hdr_len)
+                       asyreq->req.len = xfer->recv.pay_len;
+               else
+                       err = EINVAL;
+               bcopy(&xfer->recv.hdr, fp, tinfo->hdr_len);
+               bcopy(xfer->recv.payload, (char *)fp + tinfo->hdr_len,
+                   MAX(0, asyreq->req.len - tinfo->hdr_len));
+out:
+               fw_xfer_free_buf(xfer);
                break;
+       }
        case FW_IBUSRST:
                sc->fc->ibr(sc->fc);
                break;
@@ -566,7 +619,7 @@ error:
                        break;
                }
                STAILQ_REMOVE(&sc->fc->binds, fwb, fw_bind, fclist);
-               STAILQ_REMOVE(&sc->fc->ir[sub]->binds, fwb, fw_bind, chlist);
+               STAILQ_REMOVE(&ir->binds, fwb, fw_bind, chlist);
                free(fwb, M_FW);
                break;
        case FW_SBINDADDR:
@@ -583,16 +636,18 @@ error:
                        err = ENOMEM;
                        break;
                }
-               fwb->start_hi = bindreq->start.hi;
-               fwb->start_lo = bindreq->start.lo;
-               fwb->addrlen = bindreq->len;
-               fwb->sub = sub;
+               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){
-                       err = ENOMEM;
-                       return err;
+                       free(fwb, M_FW);
+                       return (ENOMEM);
                }
                xfer->fc = sc->fc;
 
@@ -634,18 +689,32 @@ error:
                        if (FW_EUI64_EQUAL(fwdev->eui, crom_buf->eui))
                                break;
                if (fwdev == NULL) {
-                       err = FWNODE_INVAL;
-                       break;
+                       if (!FW_EUI64_EQUAL(sc->fc->eui, crom_buf->eui)) {
+                               err = FWNODE_INVAL;
+                               break;
+                       }
+                       /* myself */
+                       ptr = malloc(CROMSIZE, M_FW, M_WAITOK);
+                       len = CROMSIZE;
+                       for (i = 0; i < CROMSIZE/4; i++)
+                               ((u_int32_t *)ptr)[i]
+                                       = ntohl(sc->fc->config_rom[i]);
+               } else {
+                       /* found */
+                       ptr = (void *)&fwdev->csrrom[0];
+                       if (fwdev->rommax < CSRROMOFF)
+                               len = 0;
+                       else
+                               len = fwdev->rommax - CSRROMOFF + 4;
                }
-               if (fwdev->rommax < CSRROMOFF)
-                       len = 0;
-               else
-                       len = fwdev->rommax - CSRROMOFF + 4;
                if (crom_buf->len < len)
                        len = crom_buf->len;
                else
                        crom_buf->len = len;
-               err = copyout(&fwdev->csrrom[0], crom_buf->ptr, len);
+               err = copyout(ptr, crom_buf->ptr, len);
+               if (fwdev == NULL)
+                       /* myself */
+                       free(ptr, M_FW);
                break;
        default:
                sc->fc->ioctl (dev, cmd, data, flag, td);
@@ -656,23 +725,24 @@ error:
 int
 fw_poll(dev_t dev, int events, fw_proc *td)
 {
+       struct firewire_softc *sc;
+       struct fw_xferq *ir;
        int revents;
        int tmp;
        int unit = DEV2UNIT(dev);
-       int sub = DEV2DMACH(dev);
-       struct firewire_softc *sc;
 
        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;
        if (events & tmp) {
-               if (STAILQ_FIRST(&sc->fc->ir[sub]->q) != NULL)
+               if (STAILQ_FIRST(&ir->q) != NULL)
                        revents |= tmp;
                else
-                       selrecord(td, &sc->fc->ir[sub]->rsel); /* YYY */
+                       selrecord(td, &ir->rsel);
        }
        tmp = POLLOUT | POLLWRNORM;
        if (events & tmp) {
@@ -690,7 +760,7 @@ fw_mmap (dev_t dev, vm_offset_t offset, int nproto)
 fw_mmap (dev_t dev, vm_offset_t offset, vm_paddr_t *paddr, int nproto)
 #endif
 {  
-       struct firewire_softc *fc;
+       struct firewire_softc *sc;
        int unit = DEV2UNIT(dev);
 
        if (DEV_FWMEM(dev))
@@ -700,7 +770,108 @@ fw_mmap (dev_t dev, vm_offset_t offset, vm_paddr_t *paddr, int nproto)
                return fwmem_mmap(dev, offset, paddr, nproto);
 #endif
 
-       fc = devclass_get_softc(firewire_devclass, unit);
+       sc = devclass_get_softc(firewire_devclass, unit);
 
        return EINVAL;
 }
+
+static void
+fw_strategy(struct bio *bp)
+{
+       dev_t dev;
+
+       dev = bp->bio_dev;
+       if (DEV_FWMEM(dev)) {
+               fwmem_strategy(bp);
+               return;
+       }
+
+       bp->bio_error = EOPNOTSUPP;
+       bp->bio_flags |= BIO_ERROR;
+       bp->bio_resid = bp->bio_bcount;
+       biodone(bp);
+}
+
+int
+fwdev_makedev(struct firewire_softc *sc)
+{
+       int err = 0;
+
+#if __FreeBSD_version >= 500000
+       dev_t d;
+       int unit;
+
+       unit = device_get_unit(sc->fc->bdev);
+       sc->dev = make_dev(&firewire_cdevsw, MAKEMINOR(0, unit, 0),
+                       UID_ROOT, GID_OPERATOR, 0660,
+                       "fw%d.%d", unit, 0);
+       d = make_dev(&firewire_cdevsw,
+                       MAKEMINOR(FWMEM_FLAG, unit, 0),
+                       UID_ROOT, GID_OPERATOR, 0660,
+                       "fwmem%d.%d", unit, 0);
+       dev_depends(sc->dev, d);
+       make_dev_alias(sc->dev, "fw%d", unit);
+       make_dev_alias(d, "fwmem%d", unit);
+#else
+       cdevsw_add(&firewire_cdevsw);
+#endif
+
+       return (err);
+}
+
+int
+fwdev_destroydev(struct firewire_softc *sc)
+{
+       int err = 0;
+
+#if __FreeBSD_version >= 500000
+       destroy_dev(sc->dev);
+#else
+       cdevsw_remove(&firewire_cdevsw);
+#endif
+       return (err);
+}
+
+#if __FreeBSD_version >= 500000
+#define NDEVTYPE 2
+void
+fwdev_clone(void *arg, char *name, int namelen, dev_t *dev)
+{
+       struct firewire_softc *sc;
+       char *devnames[NDEVTYPE] = {"fw", "fwmem"};
+       char *subp = NULL;
+       int devflag[NDEVTYPE] = {0, FWMEM_FLAG};
+       int i, unit = 0, sub = 0;
+
+       if (*dev != NODEV)
+               return;
+
+       for (i = 0; i < NDEVTYPE; i++)
+               if (dev_stdclone(name, &subp, devnames[i], &unit) == 2)
+                       goto found;
+       /* not match */
+       return;
+found:
+
+       if (subp == NULL || *subp++ != '.')
+               return;
+
+       /* /dev/fwU.S */
+       while (isdigit(*subp)) {
+               sub *= 10;
+               sub += *subp++ - '0';
+       }
+       if (*subp != '\0')
+               return;
+
+       sc = devclass_get_softc(firewire_devclass, unit);
+       if (sc == NULL)
+               return;
+       *dev = make_dev(&firewire_cdevsw, MAKEMINOR(devflag[i], unit, sub),
+                      UID_ROOT, GID_OPERATOR, 0660,
+                      "%s%d.%d", devnames[i], unit, sub);
+       (*dev)->si_flags |= SI_CHEAPCLONE;
+       dev_depends(sc->dev, *dev);
+       return;
+}
+#endif
index af61f35..2512c6a 100644 (file)
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  * 
- * $FreeBSD: src/sys/dev/firewire/fwdma.c,v 1.1.2.1 2003/04/28 03:29:18 simokawa Exp $
- * $DragonFly: src/sys/bus/firewire/fwdma.c,v 1.3 2003/08/07 21:16:45 dillon Exp $
+ * $DragonFly: src/sys/bus/firewire/fwdma.c,v 1.4 2004/02/05 13:32:07 joerg Exp $
  */
+
+#ifndef __DragonFly__
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/sys/dev/firewire/fwdma.c,v 1.5 2003/08/24 17:46:07 obrien Exp $");
+#endif
+
 #include <sys/param.h>
 #include <sys/systm.h>
+#include <sys/conf.h>
 #include <sys/types.h>
 #include <sys/kernel.h>
 #include <sys/malloc.h>
+#if __FreeBSD_version >= 501102 
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#endif
 
 #include <sys/bus.h>
 #include <machine/bus.h>
 
-#include "firewire.h"
-#include "firewirereg.h"
-#include "fwdma.h"
+#ifdef __DragonFly__
+#include <bus/firewire/firewire.h>
+#include <bus/firewire/firewirereg.h>
+#include <bus/firewire/fwdma.h>
+#else
+#include <dev/firewire/firewire.h>
+#include <dev/firewire/firewirereg.h>
+#include <dev/firewire/fwdma.h>
+#endif
 
 static void
 fwdma_map_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
@@ -75,7 +91,12 @@ fwdma_malloc(struct firewire_comm *fc, int alignment, bus_size_t size,
                /*maxsize*/ size,
                /*nsegments*/ 1,
                /*maxsegsz*/ BUS_SPACE_MAXSIZE_32BIT,
-               /*flags*/ BUS_DMA_ALLOCNOW, &dma->dma_tag);
+               /*flags*/ BUS_DMA_ALLOCNOW,
+#if __FreeBSD_version >= 501102 
+               /*lockfunc*/busdma_lock_mutex,
+               /*lockarg*/&Giant,
+#endif
+               &dma->dma_tag);
        if (err) {
                printf("fwdma_malloc: failed(1)\n");
                return(NULL);
@@ -168,7 +189,12 @@ fwdma_malloc_multiseg(struct firewire_comm *fc, int alignment,
                        /*maxsize*/ ssize,
                        /*nsegments*/ 1,
                        /*maxsegsz*/ BUS_SPACE_MAXSIZE_32BIT,
-                       /*flags*/ BUS_DMA_ALLOCNOW, &am->dma_tag)) {
+                       /*flags*/ BUS_DMA_ALLOCNOW,
+#if __FreeBSD_version >= 501102
+                       /*lockfunc*/busdma_lock_mutex,
+                       /*lockarg*/&Giant,
+#endif
+                       &am->dma_tag)) {
                printf("fwdma_malloc_multiseg: tag_create failed\n");
                free(am, M_FW);
                return(NULL);
index 563829f..b8b2ec4 100644 (file)
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  * 
- * $FreeBSD: src/sys/dev/firewire/fwdma.h,v 1.1.2.1 2003/04/28 03:29:18 simokawa Exp $
- * $DragonFly: src/sys/bus/firewire/fwdma.h,v 1.2 2003/06/17 04:28:25 dillon Exp $
+ * $FreeBSD: src/sys/dev/firewire/fwdma.h,v 1.2 2003/05/27 16:34:52 scottl Exp $
+ * $DragonFly: src/sys/bus/firewire/fwdma.h,v 1.3 2004/02/05 13:32:08 joerg Exp $
  */
 
-#if __FreeBSD_version >= 500111
-typedef int bus_dmasync_op_t;
-#endif
-
 struct fwdma_alloc {
        bus_dma_tag_t   dma_tag;
        bus_dmamap_t    dma_map;
index e2dcec2..c95b358 100644 (file)
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  * 
- * $FreeBSD: src/sys/dev/firewire/fwmem.c,v 1.1.2.9 2003/04/28 03:29:18 simokawa Exp $
- * $DragonFly: src/sys/bus/firewire/fwmem.c,v 1.3 2003/08/07 21:16:45 dillon Exp $
+ * $DragonFly: src/sys/bus/firewire/fwmem.c,v 1.4 2004/02/05 13:32:08 joerg Exp $
  */
 
+#ifndef __DragonFly__
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/sys/dev/firewire/fwmem.c,v 1.26 2004/01/05 14:21:18 simokawa Exp $");
+#endif
+
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/types.h>
 #include <sys/malloc.h>
 #include <sys/conf.h>
 #include <sys/sysctl.h>
+#if __FreeBSD_version < 500000
+#include <sys/buf.h>
+#else
+#include <sys/bio.h>
+#endif
 
 #include <sys/bus.h>
 #include <machine/bus.h>
 #include <sys/signal.h>
 #include <sys/mman.h>
 #include <sys/ioccom.h>
+#include <sys/fcntl.h>
 
+#ifdef __DragonFly__
 #include "firewire.h"
 #include "firewirereg.h"
 #include "fwmem.h"
+#else
+#include <dev/firewire/firewire.h>
+#include <dev/firewire/firewirereg.h>
+#include <dev/firewire/fwmem.h>
+#endif
 
 static int fwmem_speed=2, fwmem_debug=0;
 static struct fw_eui64 fwmem_eui64;
@@ -69,6 +85,15 @@ SYSCTL_INT(_hw_firewire_fwmem, OID_AUTO, speed, CTLFLAG_RW, &fwmem_speed, 0,
 SYSCTL_INT(_debug, OID_AUTO, fwmem_debug, CTLFLAG_RW, &fwmem_debug, 0,
        "Fwmem driver debug flag");
 
+MALLOC_DEFINE(M_FWMEM, "fwmem", "fwmem/FireWire");
+
+#define MAXLEN (512 << fwmem_speed)
+
+struct fwmem_softc {
+       struct fw_eui64 eui;
+       int refcount;
+};
+
 static struct fw_xfer *
 fwmem_xfer_req(
        struct fw_device *fwdev,
@@ -80,19 +105,21 @@ fwmem_xfer_req(
 {
        struct fw_xfer *xfer;
 
-       xfer = fw_xfer_alloc_buf(M_FWXFER, slen, rlen);
+       xfer = fw_xfer_alloc(M_FWMEM);
        if (xfer == NULL)
                return NULL;
 
        xfer->fc = fwdev->fc;
-       xfer->dst = FWLOCALBUS | fwdev->dst;
+       xfer->send.hdr.mode.hdr.dst = FWLOCALBUS | fwdev->dst;
        if (spd < 0)
-               xfer->spd = fwdev->speed;
+               xfer->send.spd = fwdev->speed;
        else
-               xfer->spd = min(spd, fwdev->speed);
+               xfer->send.spd = min(spd, fwdev->speed);
        xfer->act.hand = hand;
        xfer->retry_req = fw_asybusy;
        xfer->sc = sc;
+       xfer->send.pay_len = slen;
+       xfer->recv.pay_len = rlen;
 
        return xfer;
 }
@@ -104,21 +131,25 @@ fwmem_read_quad(
        u_int8_t spd,
        u_int16_t dst_hi,
        u_int32_t dst_lo,
+       void *data,
        void (*hand)(struct fw_xfer *))
 {
        struct fw_xfer *xfer;
        struct fw_pkt *fp;
 
-       xfer = fwmem_xfer_req(fwdev, sc, spd, 12, 16, hand);
-       if (xfer == NULL)
+       xfer = fwmem_xfer_req(fwdev, (void *)sc, spd, 0, 4, hand);
+       if (xfer == NULL) {
                return NULL;
+       }
 
-       fp = (struct fw_pkt *)xfer->send.buf;
+       fp = &xfer->send.hdr;
        fp->mode.rreqq.tcode = FWTCODE_RREQQ;
-       fp->mode.rreqq.dst = xfer->dst;
        fp->mode.rreqq.dest_hi = dst_hi;
        fp->mode.rreqq.dest_lo = dst_lo;
 
+       xfer->send.payload = NULL;
+       xfer->recv.payload = (u_int32_t *)data;
+
        if (fwmem_debug)
                printf("fwmem_read_quad: %d %04x:%08x\n", fwdev->dst,
                                dst_hi, dst_lo);
@@ -137,27 +168,27 @@ fwmem_write_quad(
        u_int8_t spd,
        u_int16_t dst_hi,
        u_int32_t dst_lo,
-       u_int32_t data,
+       void *data,
        void (*hand)(struct fw_xfer *))
 {
        struct fw_xfer *xfer;
        struct fw_pkt *fp;
 
-       xfer = fwmem_xfer_req(fwdev, sc, spd, 16, 12, hand);
+       xfer = fwmem_xfer_req(fwdev, sc, spd, 0, 0, hand);
        if (xfer == NULL)
                return NULL;
 
-       fp = (struct fw_pkt *)xfer->send.buf;
+       fp = &xfer->send.hdr;
        fp->mode.wreqq.tcode = FWTCODE_WREQQ;
-       fp->mode.wreqq.dst = xfer->dst;
        fp->mode.wreqq.dest_hi = dst_hi;
        fp->mode.wreqq.dest_lo = dst_lo;
+       fp->mode.wreqq.data = *(u_int32_t *)data;
 
-       fp->mode.wreqq.data = data;
+       xfer->send.payload = xfer->recv.payload = NULL;
 
        if (fwmem_debug)
                printf("fwmem_write_quad: %d %04x:%08x %08x\n", fwdev->dst,
-                       dst_hi, dst_lo, data);
+                       dst_hi, dst_lo, *(u_int32_t *)data);
 
        if (fw_asyreq(xfer->fc, -1, xfer) == 0)
                return xfer;
@@ -174,21 +205,25 @@ fwmem_read_block(
        u_int16_t dst_hi,
        u_int32_t dst_lo,
        int len,
+       void *data,
        void (*hand)(struct fw_xfer *))
 {
        struct fw_xfer *xfer;
        struct fw_pkt *fp;
-
-       xfer = fwmem_xfer_req(fwdev, sc, spd, 16, roundup2(16+len,4), hand);
+       
+       xfer = fwmem_xfer_req(fwdev, sc, spd, 0, roundup2(len, 4), hand);
        if (xfer == NULL)
                return NULL;
 
-       fp = (struct fw_pkt *)xfer->send.buf;
+       fp = &xfer->send.hdr;
        fp->mode.rreqb.tcode = FWTCODE_RREQB;
-       fp->mode.rreqb.dst = xfer->dst;
        fp->mode.rreqb.dest_hi = dst_hi;
        fp->mode.rreqb.dest_lo = dst_lo;
        fp->mode.rreqb.len = len;
+       fp->mode.rreqb.extcode = 0;
+
+       xfer->send.payload = NULL;
+       xfer->recv.payload = data;
 
        if (fwmem_debug)
                printf("fwmem_read_block: %d %04x:%08x %d\n", fwdev->dst,
@@ -208,23 +243,25 @@ fwmem_write_block(
        u_int16_t dst_hi,
        u_int32_t dst_lo,
        int len,
-       char *data,
+       void *data,
        void (*hand)(struct fw_xfer *))
 {
        struct fw_xfer *xfer;
        struct fw_pkt *fp;
 
-       xfer = fwmem_xfer_req(fwdev, sc, spd, roundup(16+len, 4), 12, hand);
+       xfer = fwmem_xfer_req(fwdev, sc, spd, len, 0, hand);
        if (xfer == NULL)
                return NULL;
 
-       fp = (struct fw_pkt *)xfer->send.buf;
+       fp = &xfer->send.hdr;
        fp->mode.wreqb.tcode = FWTCODE_WREQB;
-       fp->mode.wreqb.dst = xfer->dst;
        fp->mode.wreqb.dest_hi = dst_hi;
        fp->mode.wreqb.dest_lo = dst_lo;
        fp->mode.wreqb.len = len;
-       bcopy(data, &fp->mode.wreqb.payload[0], len);
+       fp->mode.wreqb.extcode = 0;
+
+       xfer->send.payload = data;
+       xfer->recv.payload = NULL;
 
        if (fwmem_debug)
                printf("fwmem_write_block: %d %04x:%08x %d\n", fwdev->dst,
@@ -240,14 +277,25 @@ fwmem_write_block(
 int
 fwmem_open (dev_t dev, int flags, int fmt, fw_proc *td)
 {
-       struct fw_eui64 *eui;
-
-       eui = (struct fw_eui64 *)malloc(sizeof(struct fw_eui64),
-                                                       M_FW, M_WAITOK);
-       if (eui == NULL)
-               return ENOMEM;
-       bcopy(&fwmem_eui64, eui, sizeof(struct fw_eui64));
-       dev->si_drv1 = (void *)eui;
+       struct fwmem_softc *fms;
+
+       if (dev->si_drv1 != NULL) {
+               if ((flags & FWRITE) != 0)
+                       return (EBUSY);
+               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_iosize_max = DFLTPHYS;
+               fms->refcount = 1;
+       }
+       if (fwmem_debug)
+               printf("%s: refcount=%d\n", __FUNCTION__, fms->refcount);
 
        return (0);
 }
@@ -255,149 +303,122 @@ fwmem_open (dev_t dev, int flags, int fmt, fw_proc *td)
 int
 fwmem_close (dev_t dev, int flags, int fmt, fw_proc *td)
 {
-       free(dev->si_drv1, M_FW);
+       struct fwmem_softc *fms;
+
+       fms = (struct fwmem_softc *)dev->si_drv1;
+       fms->refcount --;
+       if (fwmem_debug)
+               printf("%s: refcount=%d\n", __FUNCTION__, fms->refcount);
+       if (fms->refcount < 1) {
+               free(dev->si_drv1, M_FW);
+               dev->si_drv1 = NULL;
+       }
+
        return (0);
 }
 
-#define MAXLEN 2048
-#define USE_QUAD 0
-int
-fwmem_read (dev_t dev, struct uio *uio, int ioflag)
+
+static void
+fwmem_biodone(struct fw_xfer *xfer)
 {
-       struct firewire_softc *sc;
-       struct fw_device *fwdev;
-       struct fw_xfer *xfer;
-       int err = 0;
-        int unit = DEV2UNIT(dev);
-       u_int16_t dst_hi;
-       u_int32_t dst_lo;
-       off_t offset;
-       int len;
+       struct bio *bp;
 
-       sc = devclass_get_softc(firewire_devclass, unit);
-       fwdev = fw_noderesolve_eui64(sc->fc, (struct fw_eui64 *)dev->si_drv1);
-       if (fwdev == NULL) {
+       bp = (struct bio *)xfer->sc;
+       bp->bio_error = xfer->resp;
+
+       if (bp->bio_error != 0) {
                if (fwmem_debug)
-                       printf("fwmem: no such device ID:%08x%08x\n",
-                                       fwmem_eui64.hi, fwmem_eui64.lo);
-               return EINVAL;
+                       printf("%s: err=%d\n", __FUNCTION__, bp->bio_error);
+               bp->bio_flags |= BIO_ERROR;
+               bp->bio_resid = bp->bio_bcount;
        }
 
-       while(uio->uio_resid > 0 && !err) {
-               offset = uio->uio_offset;
-               dst_hi = (offset >> 32) & 0xffff;
-               dst_lo = offset & 0xffffffff;
-               len = uio->uio_resid;
-               if (len == 4 && (dst_lo & 3) == 0) {
-                       xfer = fwmem_read_quad(fwdev, NULL, fwmem_speed,
-                               dst_hi, dst_lo, fw_asy_callback);
-                       if (xfer == NULL) {
-                               err = EINVAL;
-                               break;
-                       }
-                       err = tsleep((caddr_t)xfer, FWPRI, "fwmrq", 0);
-                       if (xfer->recv.buf == NULL)
-                               err = EIO;
-                       else if (xfer->resp != 0)
-                               err = xfer->resp;
-                       else if (err == 0)
-                               err = uiomove(xfer->recv.buf + 4*3, 4, uio);
-               } else {
-                       if (len > MAXLEN)
-                               len = MAXLEN;
-                       xfer = fwmem_read_block(fwdev, NULL, fwmem_speed,
-                               dst_hi, dst_lo, len, fw_asy_callback);
-                       if (xfer == NULL) {
-                               err = EINVAL;
-                               break;
-                       }
-                       err = tsleep((caddr_t)xfer, FWPRI, "fwmrb", 0);
-                       if (xfer->recv.buf == NULL)
-                               err = EIO;
-                       else if (xfer->resp != 0)
-                               err = xfer->resp;
-                       else if (err == 0)
-                               err = uiomove(xfer->recv.buf + 4*4, len, uio);
-               }
-               fw_xfer_free(xfer);
-       }
-       return err;
+       fw_xfer_free(xfer);
+       biodone(bp);
 }
-int
-fwmem_write (dev_t dev, struct uio *uio, int ioflag)
+
+void
+fwmem_strategy(struct bio *bp)
 {
        struct firewire_softc *sc;
+       struct fwmem_softc *fms;
        struct fw_device *fwdev;
        struct fw_xfer *xfer;
-       int err = 0;
-        int unit = DEV2UNIT(dev);
-       u_int16_t dst_hi;
-       u_int32_t dst_lo, quad;
-       char *data;
-       off_t offset;
-       int len;
+       dev_t dev;
+       int unit, err=0, s, iolen;
+
+       dev = bp->bio_dev;
+       /* XXX check request length */
 
+        unit = DEV2UNIT(dev);
        sc = devclass_get_softc(firewire_devclass, unit);
-       fwdev = fw_noderesolve_eui64(sc->fc, (struct fw_eui64 *)dev->si_drv1);
+
+       s = splfw();
+       fms = (struct fwmem_softc *)dev->si_drv1;
+       fwdev = fw_noderesolve_eui64(sc->fc, &fms->eui);
        if (fwdev == NULL) {
                if (fwmem_debug)
                        printf("fwmem: no such device ID:%08x%08x\n",
-                                       fwmem_eui64.hi, fwmem_eui64.lo);
-               return EINVAL;
+                                       fms->eui.hi, fms->eui.lo);
+               err = EINVAL;
+               goto error;
        }
 
-       data = malloc(MAXLEN, M_FW, M_WAITOK);
-       if (data == NULL)
-               return ENOMEM;
-
-       while(uio->uio_resid > 0 && !err) {
-               offset = uio->uio_offset;
-               dst_hi = (offset >> 32) & 0xffff;
-               dst_lo = offset & 0xffffffff;
-               len = uio->uio_resid;
-               if (len == 4 && (dst_lo & 3) == 0) {
-                       err = uiomove((char *)&quad, sizeof(quad), uio);
-                       xfer = fwmem_write_quad(fwdev, NULL, fwmem_speed,
-                               dst_hi, dst_lo, quad, fw_asy_callback);
-                       if (xfer == NULL) {
-                               err = EINVAL;
-                               break;
-                       }
-                       err = tsleep((caddr_t)xfer, FWPRI, "fwmwq", 0);
-                       if (xfer->resp != 0)
-                               err = xfer->resp;
-               } else {
-                       if (len > MAXLEN)
-                               len = MAXLEN;
-                       err = uiomove(data, len, uio);
-                       if (err)
-                               break;
-                       xfer = fwmem_write_block(fwdev, NULL, fwmem_speed,
-                               dst_hi, dst_lo, len, data, fw_asy_callback);
-                       if (xfer == NULL) {
-                               err = EINVAL;
-                               break;
-                       }
-                       err = tsleep((caddr_t)xfer, FWPRI, "fwmwb", 0);
-                       if (xfer->resp != 0)
-                               err = xfer->resp;
-               }
-               fw_xfer_free(xfer);
+       iolen = MIN(bp->bio_bcount, MAXLEN);
+       if ((bp->bio_cmd & BIO_READ) == BIO_READ) {
+               if (iolen == 4 && (bp->bio_offset & 3) == 0)
+                       xfer = fwmem_read_quad(fwdev,
+                           (void *) bp, fwmem_speed,
+                           bp->bio_offset >> 32, bp->bio_offset & 0xffffffff,
+                           bp->bio_data, fwmem_biodone);
+               else
+                       xfer = fwmem_read_block(fwdev,
+                           (void *) bp, fwmem_speed,
+                           bp->bio_offset >> 32, bp->bio_offset & 0xffffffff,
+                           iolen, bp->bio_data, fwmem_biodone);
+       } else {
+               if (iolen == 4 && (bp->bio_offset & 3) == 0)
+                       xfer = fwmem_write_quad(fwdev,
+                           (void *)bp, fwmem_speed,
+                           bp->bio_offset >> 32, bp->bio_offset & 0xffffffff,
+                           bp->bio_data, fwmem_biodone);
+               else
+                       xfer = fwmem_write_block(fwdev,
+                           (void *)bp, fwmem_speed,
+                           bp->bio_offset >> 32, bp->bio_offset & 0xffffffff,
+                           iolen, bp->bio_data, fwmem_biodone);
+       }
+       if (xfer == NULL) {
+               err = EIO;
+               goto error;
+       }
+       /* XXX */
+       bp->bio_resid = bp->bio_bcount - iolen;
+error:
+       splx(s);
+       if (err != 0) {
+               if (fwmem_debug)
+                       printf("%s: err=%d\n", __FUNCTION__, err);
+               bp->bio_error = err;
+               bp->bio_flags |= BIO_ERROR;
+               bp->bio_resid = bp->bio_bcount;
+               biodone(bp);
        }
-       free(data, M_FW);
-       return err;
 }
 
 int
 fwmem_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
 {
+       struct fwmem_softc *fms;
        int err = 0;
+
+       fms = (struct fwmem_softc *)dev->si_drv1;
        switch (cmd) {
        case FW_SDEUI64:
-               bcopy(data, dev->si_drv1, sizeof(struct fw_eui64));
+               bcopy(data, &fms->eui, sizeof(struct fw_eui64));
                break;
        case FW_GDEUI64:
-               bcopy(dev->si_drv1, data, sizeof(struct fw_eui64));
+               bcopy(&fms->eui, data, sizeof(struct fw_eui64));
                break;
        default:
                err = EINVAL;
index b305be2..c26d3ba 100644 (file)
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  * 
- * $FreeBSD: src/sys/dev/firewire/fwmem.h,v 1.1.2.4 2003/04/28 03:29:18 simokawa Exp $
- * $DragonFly: src/sys/bus/firewire/fwmem.h,v 1.2 2003/06/17 04:28:25 dillon Exp $
+ * $FreeBSD: src/sys/dev/firewire/fwmem.h,v 1.6 2003/10/02 04:06:56 simokawa Exp $
+ * $DragonFly: src/sys/bus/firewire/fwmem.h,v 1.3 2004/02/05 13:32:08 joerg Exp $
  */
 
 struct fw_xfer *fwmem_read_quad(struct fw_device *, caddr_t, u_int8_t,
-       u_int16_t, u_int32_t, void (*)(struct fw_xfer *));
+       u_int16_t, u_int32_t, void *, void (*)(struct fw_xfer *));
 struct fw_xfer *fwmem_write_quad(struct fw_device *, caddr_t, u_int8_t,
-       u_int16_t, u_int32_t, u_int32_t, void (*)(struct fw_xfer *));
+       u_int16_t, u_int32_t, void *, void (*)(struct fw_xfer *));
 struct fw_xfer *fwmem_read_block(struct fw_device *, caddr_t, u_int8_t,
-       u_int16_t, u_int32_t, int, void (*)(struct fw_xfer *));
+       u_int16_t, u_int32_t, int, void *, void (*)(struct fw_xfer *));
 struct fw_xfer *fwmem_write_block(struct fw_device *, caddr_t, u_int8_t,
-       u_int16_t, u_int32_t, int, char *, void (*)(struct fw_xfer *));
+       u_int16_t, u_int32_t, int, void *, void (*)(struct fw_xfer *));
 
 d_open_t       fwmem_open;
 d_close_t      fwmem_close;
@@ -51,3 +51,4 @@ d_read_t      fwmem_read;
 d_write_t      fwmem_write;
 d_poll_t       fwmem_poll;
 d_mmap_t       fwmem_mmap;
+d_strategy_t   fwmem_strategy;
index 6705717..4188577 100644 (file)
@@ -31,9 +31,9 @@
  * 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.72 2004/01/22 14:41:17 simokawa Exp $
  * $FreeBSD: src/sys/dev/firewire/fwohci.c,v 1.1.2.19 2003/05/01 06:24:37 simokawa Exp $
- * $DragonFly: src/sys/bus/firewire/fwohci.c,v 1.4 2003/08/27 11:42:34 rob Exp $
- *
+ * $DragonFly: src/sys/bus/firewire/fwohci.c,v 1.5 2004/02/05 13:32:08 joerg Exp $
  */
 
 #define ATRQ_CH 0
 #define IRX_CH 0x24
 
 #include <sys/param.h>
-#include <sys/proc.h>
 #include <sys/systm.h>
-#include <sys/types.h>
 #include <sys/mbuf.h>
-#include <sys/mman.h> 
-#include <sys/socket.h>
-#include <sys/socketvar.h>
-#include <sys/signalvar.h> 
 #include <sys/malloc.h>
 #include <sys/sockio.h>
 #include <sys/bus.h>
 #include <sys/endian.h>
 
 #include <machine/bus.h>
-#include <machine/resource.h>
-#include <sys/rman.h>
 
-#include <machine/cpufunc.h>            /* for rdtsc proto for clock.h below */
-#include <machine/clock.h>
-#include <bus/pci/pcivar.h>
-#include <bus/pci/pcireg.h>
+#if __FreeBSD_version < 500000
+#include <machine/clock.h>             /* for DELAY() */
+#endif
 
+#ifdef __DragonFly__
 #include "firewire.h"
 #include "firewirereg.h"
 #include "fwdma.h"
 #include "fwohcireg.h"
 #include "fwohcivar.h"
 #include "firewire_phy.h"
-
-#include "iec68113.h"
+#else
+#include <dev/firewire/firewire.h>
+#include <dev/firewire/firewirereg.h>
+#include <dev/firewire/fwdma.h>
+#include <dev/firewire/fwohcireg.h>
+#include <dev/firewire/fwohcivar.h>
+#include <dev/firewire/firewire_phy.h>
+#endif
 
 #undef OHCI_DEBUG
 
@@ -95,8 +93,8 @@ char fwohcicode[32][0x20]={
        "Undef","Undef","Undef","ack tardy",
        "Undef","ack data_err","ack type_err",""};
 
-#define MAX_SPEED 2
-extern char linkspeed[MAX_SPEED+1][0x10];
+#define MAX_SPEED 3
+extern char *linkspeed[];
 u_int32_t tagbit[4] = { 1 << 28, 1 << 29, 1 << 30, 1 << 31};
 
 static struct tcode_info tinfo[] = {
@@ -145,13 +143,12 @@ static void fwohci_irx_post (struct firewire_comm *, u_int32_t *);
 static int fwohci_itxbuf_enable (struct firewire_comm *, int);
 static int fwohci_itx_disable (struct firewire_comm *, int);
 static void fwohci_timeout (void *);
-static void fwohci_poll (struct firewire_comm *, int, int);
 static void fwohci_set_intr (struct firewire_comm *, int);
 
 static int fwohci_add_rx_buf (struct fwohci_dbch *, struct fwohcidb_tr *, int, struct fwdma_alloc *);
 static int fwohci_add_tx_buf (struct fwohci_dbch *, struct fwohcidb_tr *, int);
 static void    dump_db (struct fwohci_softc *, u_int32_t);
-static void    print_db (struct fwohcidb_tr *, volatile struct fwohcidb *, u_int32_t , u_int32_t);
+static void    print_db (struct fwohcidb_tr *, struct fwohcidb *, u_int32_t , u_int32_t);
 static void    dump_dma (struct fwohci_softc *, u_int32_t);
 static u_int32_t fwohci_cyctimer (struct firewire_comm *);
 static void fwohci_rbuf_update (struct fwohci_softc *, int);
@@ -166,9 +163,7 @@ static void fwohci_complete(void *, int);
  */
 #define DMA_PROG_ALLOC         (8 * PAGE_SIZE)
 
-/* #define NDB 1024 */
 #define NDB FWMAXQUEUE
-#define NDVDB (DVBUF * NDB)
 
 #define        OHCI_VERSION            0x00
 #define        OHCI_ATRETRY            0x08
@@ -345,7 +340,7 @@ again:
        }
        if (bootverbose || retry >= MAX_RETRY)
                device_printf(sc->fc.dev, 
-                       "fwphy_rddata: loop=%d, retry=%d\n", i, retry);
+                   "fwphy_rddata: 0x%x loop=%d, retry=%d\n", addr, i, retry);
 #undef MAX_RETRY
        return((fun >> PHYDEV_RDDATA )& 0xff);
 }
@@ -395,7 +390,22 @@ fwohci_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
                        err = EINVAL;
                }
                break;
+/* Read/Write Phy registers */
+#define OHCI_MAX_PHY_REG 0xf
+       case FWOHCI_RDPHYREG:
+               if (reg->addr <= OHCI_MAX_PHY_REG)
+                       reg->data = fwphy_rddata(fc, reg->addr);
+               else
+                       err = EINVAL;
+               break;
+       case FWOHCI_WRPHYREG:
+               if (reg->addr <= OHCI_MAX_PHY_REG)
+                       reg->data = fwphy_wrdata(fc, reg->addr, reg->data);
+               else
+                       err = EINVAL;
+               break;
        default:
+               err = EINVAL;
                break;
        }
        return err;
@@ -537,7 +547,6 @@ fwohci_reset(struct fwohci_softc *sc, device_t dev)
        OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_POSTWR);
        OWRITE(sc, OHCI_SID_BUF, sc->sid_dma.bus_addr);
        OWRITE(sc, OHCI_LNKCTL, OHCI_CNTL_SID);
-       fw_busreset(&sc->fc);
 
        /* Enable link */
        OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_LINKEN);
@@ -551,10 +560,17 @@ fwohci_reset(struct fwohci_softc *sc, device_t dev)
        /* Initialize async TX */
        OWRITE(sc, OHCI_ATQCTLCLR, OHCI_CNTL_DMA_RUN | OHCI_CNTL_DMA_DEAD);
        OWRITE(sc, OHCI_ATSCTLCLR, OHCI_CNTL_DMA_RUN | OHCI_CNTL_DMA_DEAD);
+
        /* AT Retries */
        OWRITE(sc, FWOHCI_RETRY,
                /* CycleLimit   PhyRespRetries ATRespRetries ATReqRetries */
                (0xffff << 16 ) | (0x0f << 8) | (0x0f << 4) | 0x0f) ;
+
+       sc->atrq.top = STAILQ_FIRST(&sc->atrq.db_trq);
+       sc->atrs.top = STAILQ_FIRST(&sc->atrs.db_trq);
+       sc->atrq.bottom = sc->atrq.top;
+       sc->atrs.bottom = sc->atrs.top;
+
        for( i = 0, db_tr = sc->atrq.top; i < sc->atrq.ndb ;
                                i ++, db_tr = STAILQ_NEXT(db_tr, link)){
                db_tr->xfer = NULL;
@@ -578,7 +594,7 @@ fwohci_reset(struct fwohci_softc *sc, device_t dev)
 int
 fwohci_init(struct fwohci_softc *sc, device_t dev)
 {
-       int i;
+       int i, mver;
        u_int32_t reg;
        u_int8_t ui[8];
 
@@ -586,9 +602,15 @@ fwohci_init(struct fwohci_softc *sc, device_t dev)
        TASK_INIT(&sc->fwohci_task_complete, 0, fwohci_complete, sc);
 #endif
 
+/* OHCI version */
        reg = OREAD(sc, OHCI_VERSION);
+       mver = (reg >> 16) & 0xff;
        device_printf(dev, "OHCI version %x.%x (ROM=%d)\n",
-                       (reg>>16) & 0xff, reg & 0xff, (reg>>24) & 1);
+                       mver, reg & 0xff, (reg>>24) & 1);
+       if (mver < 1 || mver > 9) {
+               device_printf(dev, "invalid OHCI version\n");
+               return (ENXIO);
+       }
 
 /* Available Isochrounous DMA channel probe */
        OWRITE(sc, OHCI_IT_MASK, 0xffffffff);
@@ -601,6 +623,8 @@ fwohci_init(struct fwohci_softc *sc, device_t dev)
                        break;
        sc->fc.nisodma = i;
        device_printf(dev, "No. of Isochronous channel is %d.\n", i);
+       if (i == 0)
+               return (ENXIO);
 
        sc->fc.arq = &sc->arrq.xferq;
        sc->fc.ars = &sc->arrs.xferq;
@@ -622,6 +646,11 @@ fwohci_init(struct fwohci_softc *sc, device_t dev)
        sc->atrq.xferq.buf = NULL;
        sc->atrs.xferq.buf = NULL;
 
+       sc->arrq.xferq.dmach = -1;
+       sc->arrs.xferq.dmach = -1;
+       sc->atrq.xferq.dmach = -1;
+       sc->atrs.xferq.dmach = -1;
+
        sc->arrq.ndesc = 1;
        sc->arrs.ndesc = 1;
        sc->atrq.ndesc = 8;     /* equal to maximum of mbuf chains */
@@ -635,6 +664,8 @@ fwohci_init(struct fwohci_softc *sc, device_t dev)
        for( i = 0 ; i < sc->fc.nisodma ; i ++ ){
                sc->fc.it[i] = &sc->it[i].xferq;
                sc->fc.ir[i] = &sc->ir[i].xferq;
+               sc->it[i].xferq.dmach = i;
+               sc->ir[i].xferq.dmach = i;
                sc->it[i].ndb = 0;
                sc->ir[i].ndb = 0;
        }
@@ -649,7 +680,8 @@ fwohci_init(struct fwohci_softc *sc, device_t dev)
                return ENOMEM;
        }
 
-#if 1
+#if 0
+       bzero(&sc->fc.config_rom[0], CROMSIZE);
        sc->fc.config_rom[1] = 0x31333934;
        sc->fc.config_rom[2] = 0xf000a002;
        sc->fc.config_rom[3] = OREAD(sc, OHCI_EUID_HI);
@@ -777,7 +809,7 @@ static void
 fwohci_execute_db(void *arg, bus_dma_segment_t *segs, int nseg, int error)
 {
        struct fwohcidb_tr *db_tr;
-       volatile struct fwohcidb *db;
+       struct fwohcidb *db;
        bus_dma_segment_t *s;
        int i;
 
@@ -809,14 +841,15 @@ static void
 fwohci_start(struct fwohci_softc *sc, struct fwohci_dbch *dbch)
 {
        int i, s;
-       int tcode, hdr_len, pl_off, pl_len;
+       int tcode, hdr_len, pl_off;
        int fsegment = -1;
        u_int32_t off;
        struct fw_xfer *xfer;
        struct fw_pkt *fp;
-       volatile struct fwohci_txpkthdr *ohcifp;
+       struct fwohci_txpkthdr *ohcifp;
        struct fwohcidb_tr *db_tr;
-       volatile struct fwohcidb *db;
+       struct fwohcidb *db;
+       u_int32_t *ld;
        struct tcode_info *info;
        static int maxdesc=0;
 
@@ -845,23 +878,26 @@ txloop:
        db_tr->xfer = xfer;
        xfer->state = FWXF_START;
 
-       fp = (struct fw_pkt *)xfer->send.buf;
+       fp = &xfer->send.hdr;
        tcode = fp->mode.common.tcode;
 
-       ohcifp = (volatile struct fwohci_txpkthdr *) db_tr->db[1].db.immed;
+       ohcifp = (struct fwohci_txpkthdr *) db_tr->db[1].db.immed;
        info = &tinfo[tcode];
        hdr_len = pl_off = info->hdr_len;
-       for( i = 0 ; i < pl_off ; i+= 4){
-               ohcifp->mode.ld[i/4] = fp->mode.ld[i/4];
-       }
-       ohcifp->mode.common.spd = xfer->spd;
+
+       ld = &ohcifp->mode.ld[0];
+       ld[0] = ld[1] = ld[2] = ld[3] = 0;
+       for( i = 0 ; i < pl_off ; i+= 4)
+               ld[i/4] = fp->mode.ld[i/4];
+
+       ohcifp->mode.common.spd = xfer->send.spd & 0x7;
        if (tcode == FWTCODE_STREAM ){
                hdr_len = 8;
                ohcifp->mode.stream.len = fp->mode.stream.len;
        } else if (tcode == FWTCODE_PHY) {
                hdr_len = 12;
-               ohcifp->mode.ld[1] = fp->mode.ld[1];
-               ohcifp->mode.ld[2] = fp->mode.ld[2];
+               ld[1] = fp->mode.ld[1];
+               ld[2] = fp->mode.ld[2];
                ohcifp->mode.common.spd = 0;
                ohcifp->mode.common.tcode = FWOHCITCODE_PHY;
        } else {
@@ -872,6 +908,7 @@ txloop:
        db = &db_tr->db[0];
        FWOHCI_DMA_WRITE(db->db.desc.cmd,
                        OHCI_OUTPUT_MORE | OHCI_KEY_ST2 | hdr_len);
+       FWOHCI_DMA_WRITE(db->db.desc.addr, 0);
        FWOHCI_DMA_WRITE(db->db.desc.res, 0);
 /* Specify bound timer of asy. responce */
        if(&sc->atrs == dbch){
@@ -882,22 +919,18 @@ txloop:
        if (tcode == FWTCODE_WREQQ || tcode == FWTCODE_RRESQ)
                hdr_len = 12;
        for (i = 0; i < hdr_len/4; i ++)
-               FWOHCI_DMA_WRITE(ohcifp->mode.ld[i], ohcifp->mode.ld[i]);
+               FWOHCI_DMA_WRITE(ld[i], ld[i]);
 #endif
 
 again:
        db_tr->dbcnt = 2;
        db = &db_tr->db[db_tr->dbcnt];
-       pl_len = xfer->send.len - pl_off;
-       if (pl_len > 0) {
+       if (xfer->send.pay_len > 0) {
                int err;
                /* handle payload */
                if (xfer->mbuf == NULL) {
-                       caddr_t pl_addr;
-
-                       pl_addr = xfer->send.buf + pl_off;
                        err = bus_dmamap_load(dbch->dmat, db_tr->dma_map,
-                               pl_addr, pl_len,
+                               &xfer->send.payload[0], xfer->send.pay_len,
                                fwohci_execute_db, db_tr,
                                /*flags*/0);
                } else {
@@ -1003,7 +1036,7 @@ fwohci_txd(struct fwohci_softc *sc, struct fwohci_dbch *dbch)
 {
        int s, ch, err = 0;
        struct fwohcidb_tr *tr;
-       volatile struct fwohcidb *db;
+       struct fwohcidb *db;
        struct fw_xfer *xfer;
        u_int32_t off;
        u_int stat, status;
@@ -1035,8 +1068,9 @@ fwohci_txd(struct fwohci_softc *sc, struct fwohci_dbch *dbch)
                bus_dmamap_sync(dbch->dmat, tr->dma_map,
                        BUS_DMASYNC_POSTWRITE);
                bus_dmamap_unload(dbch->dmat, tr->dma_map);
-#if 0
-               dump_db(sc, ch);
+#if 1
+               if (firewire_debug)
+                       dump_db(sc, ch);
 #endif
                if(status & OHCI_CNTL_DMA_DEAD) {
                        /* Stop DMA */
@@ -1082,8 +1116,10 @@ fwohci_txd(struct fwohci_softc *sc, struct fwohci_dbch *dbch)
                if (tr->xfer != NULL) {
                        xfer = tr->xfer;
                        if (xfer->state == FWXF_RCVD) {
+#if 0
                                if (firewire_debug)
                                        printf("already rcvd\n");
+#endif
                                fw_xfer_done(xfer);
                        } else {
                                xfer->state = FWXF_SENT;
@@ -1093,14 +1129,14 @@ fwohci_txd(struct fwohci_softc *sc, struct fwohci_dbch *dbch)
                                        if (xfer->retry_req != NULL)
                                                xfer->retry_req(xfer);
                                        else {
-                                               xfer->recv.len = 0;
+                                               xfer->recv.pay_len = 0;
                                                fw_xfer_done(xfer);
                                        }
                                } else if (stat != FWOHCIEV_ACKPEND) {
                                        if (stat != FWOHCIEV_ACKCOMPL)
                                                xfer->state = FWXF_SENTERR;
                                        xfer->resp = err;
-                                       xfer->recv.len = 0;
+                                       xfer->recv.pay_len = 0;
                                        fw_xfer_done(xfer);
                                }
                        }
@@ -1179,7 +1215,12 @@ fwohci_db_init(struct fwohci_softc *sc, struct fwohci_dbch *dbch)
                        /*maxsize*/ dbch->xferq.psize,
                        /*nsegments*/ dbch->ndesc > 3 ? dbch->ndesc - 2 : 1,
                        /*maxsegsz*/ MAX_REQCOUNT,
-                       /*flags*/ 0, &dbch->dmat))
+                       /*flags*/ 0,
+#if __FreeBSD_version >= 501102
+                       /*lockfunc*/busdma_lock_mutex,
+                       /*lockarg*/&Giant,
+#endif
+                       &dbch->dmat))
                return;
 
        /* allocate DB entries and attach one to each DMA channels */
@@ -1198,6 +1239,7 @@ fwohci_db_init(struct fwohci_softc *sc, struct fwohci_dbch *dbch)
                DB_SIZE(dbch), dbch->ndb, BUS_DMA_WAITOK);
        if (dbch->am == NULL) {
                printf("fwohci_db_init: fwdma_malloc_multiseg failed\n");
+               free(db_tr, M_FW);
                return;
        }
        /* Attach DB to DMA ch. */
@@ -1282,9 +1324,9 @@ fwohci_tx_enable(struct fwohci_softc *sc, struct fwohci_dbch *dbch)
 {
        int err = 0;
        int idb, z, i, dmach = 0, ldesc;
-       u_int32_t off = NULL;
+       u_int32_t off = 0;
        struct fwohcidb_tr *db_tr;
-       volatile struct fwohcidb *db;
+       struct fwohcidb *db;
 
        if(!(dbch->xferq.flag & FWXFERQ_EXTBUF)){
                err = EINVAL;
@@ -1297,7 +1339,7 @@ fwohci_tx_enable(struct fwohci_softc *sc, struct fwohci_dbch *dbch)
                        break;
                }
        }
-       if(off == NULL){
+       if(off == 0){
                err = EINVAL;
                return err;
        }
@@ -1341,9 +1383,9 @@ fwohci_rx_enable(struct fwohci_softc *sc, struct fwohci_dbch *dbch)
 {
        int err = 0;
        int idb, z, i, dmach = 0, ldesc;
-       u_int32_t off = NULL;
+       u_int32_t off = 0;
        struct fwohcidb_tr *db_tr;
-       volatile struct fwohcidb *db;
+       struct fwohcidb *db;
 
        z = dbch->ndesc;
        if(&sc->arrq == dbch){
@@ -1358,7 +1400,7 @@ fwohci_rx_enable(struct fwohci_softc *sc, struct fwohci_dbch *dbch)
                        }
                }
        }
-       if(off == NULL){
+       if(off == 0){
                err = EINVAL;
                return err;
        }
@@ -1474,7 +1516,7 @@ fwohci_itxbuf_enable(struct firewire_comm *fc, int dmach)
        s = splfw();
        prev = STAILQ_LAST(&it->stdma, fw_bulkxfer, link);
        while  ((chunk = STAILQ_FIRST(&it->stvalid)) != NULL) {
-               volatile struct fwohcidb *db;
+               struct fwohcidb *db;
 
                fwdma_sync_multiseg(it->buf, chunk->poffset, it->bnpacket,
                                        BUS_DMASYNC_PREWRITE);
@@ -1601,7 +1643,7 @@ fwohci_irx_enable(struct firewire_comm *fc, int dmach)
        s = splfw();
        prev = STAILQ_LAST(&ir->stdma, fw_bulkxfer, link);
        while  ((chunk = STAILQ_FIRST(&ir->stfree)) != NULL) {
-               volatile struct fwohcidb *db;
+               struct fwohcidb *db;
 
 #if 1 /* XXX for if_fwe */
                if (chunk->mbuf != NULL) {
@@ -1682,6 +1724,10 @@ fwohci_stop(struct fwohci_softc *sc, device_t dev)
                        | OHCI_INT_DMA_PRRQ | OHCI_INT_DMA_PRRS
                        | 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);
+
 /* XXX Link down?  Bus reset? */
        return 0;
 }
@@ -1690,14 +1736,22 @@ int
 fwohci_resume(struct fwohci_softc *sc, device_t dev)
 {
        int i;
+       struct fw_xferq *ir;
+       struct fw_bulkxfer *chunk;
 
        fwohci_reset(sc, dev);
        /* XXX resume isochronus receive automatically. (how about TX?) */
        for(i = 0; i < sc->fc.nisodma; i ++) {
-               if((sc->ir[i].xferq.flag & FWXFERQ_RUNNING) != 0) {
+               ir = &sc->ir[i].xferq;
+               if((ir->flag & FWXFERQ_RUNNING) != 0) {
                        device_printf(sc->fc.dev,
                                "resume iso receive ch: %d\n", i);
-                       sc->ir[i].xferq.flag &= ~FWXFERQ_RUNNING;
+                       ir->flag &= ~FWXFERQ_RUNNING;
+                       /* requeue stdma to stfree */
+                       while((chunk = STAILQ_FIRST(&ir->stdma)) != NULL) {
+                               STAILQ_REMOVE_HEAD(&ir->stdma, link);
+                               STAILQ_INSERT_TAIL(&ir->stfree, chunk, link);
+                       }
                        sc->fc.irx_enable(&sc->fc, i);
                }
        }
@@ -1762,6 +1816,8 @@ fwohci_intr_body(struct fwohci_softc *sc, u_int32_t stat, int count)
                OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_PHY_BUS_R);
 #endif
                fw_busreset(fc);
+               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 )){
@@ -2008,7 +2064,7 @@ again:
 #endif
 }
 
-static void
+void
 fwohci_poll(struct firewire_comm *fc, int quick, int count)
 {
        int s;
@@ -2055,7 +2111,7 @@ static void
 fwohci_tbuf_update(struct fwohci_softc *sc, int dmach)
 {
        struct firewire_comm *fc = &sc->fc;
-       volatile struct fwohcidb *db;
+       struct fwohcidb *db;
        struct fw_bulkxfer *chunk;
        struct fw_xferq *it;
        u_int32_t stat, count;
@@ -2065,11 +2121,14 @@ fwohci_tbuf_update(struct fwohci_softc *sc, int dmach)
        ldesc = sc->it[dmach].ndesc - 1;
        s = splfw(); /* unnecessary ? */
        fwdma_sync_multiseg_all(sc->it[dmach].am, BUS_DMASYNC_POSTREAD);
+       if (firewire_debug)
+               dump_db(sc, ITX_CH + dmach);
        while ((chunk = STAILQ_FIRST(&it->stdma)) != NULL) {
                db = ((struct fwohcidb_tr *)(chunk->end))->db;
                stat = FWOHCI_DMA_READ(db[ldesc].db.desc.res) 
                                >> OHCI_STATUS_SHIFT;
                db = ((struct fwohcidb_tr *)(chunk->start))->db;
+               /* timestamp */
                count = FWOHCI_DMA_READ(db[ldesc].db.desc.res)
                                & OHCI_COUNT_MASK;
                if (stat == 0)
@@ -2098,7 +2157,7 @@ static void
 fwohci_rbuf_update(struct fwohci_softc *sc, int dmach)
 {
        struct firewire_comm *fc = &sc->fc;
-       volatile struct fwohcidb_tr *db_tr;
+       struct fwohcidb_tr *db_tr;
        struct fw_bulkxfer *chunk;
        struct fw_xferq *ir;
        u_int32_t stat;
@@ -2203,7 +2262,7 @@ dump_db(struct fwohci_softc *sc, u_int32_t ch)
 {
        struct fwohci_dbch *dbch;
        struct fwohcidb_tr *cp = NULL, *pp, *np = NULL;
-       volatile struct fwohcidb *curr = NULL, *prev, *next = NULL;
+       struct fwohcidb *curr = NULL, *prev, *next = NULL;
        int idb, jdb;
        u_int32_t cmd, off;
        if(ch == 0){
@@ -2277,7 +2336,7 @@ outdb:
 }
 
 void
-print_db(struct fwohcidb_tr *db_tr, volatile struct fwohcidb *db,
+print_db(struct fwohcidb_tr *db_tr, struct fwohcidb *db,
                u_int32_t ch, u_int32_t max)
 {
        fwohcireg_t stat;
@@ -2394,9 +2453,9 @@ fwohci_txbufdb(struct fwohci_softc *sc, int dmach, struct fw_bulkxfer *bulkxfer)
 {
        struct fwohcidb_tr *db_tr, *fdb_tr;
        struct fwohci_dbch *dbch;
-       volatile struct fwohcidb *db;
+       struct fwohcidb *db;
        struct fw_pkt *fp;
-       volatile struct fwohci_txpkthdr *ohcifp;
+       struct fwohci_txpkthdr *ohcifp;
        unsigned short chtag;
        int idb;
 
@@ -2411,12 +2470,12 @@ device_printf(sc->fc.dev, "DB %08x %08x %08x\n", bulkxfer, db_tr->bus_addr, fdb_
        for (idb = 0; idb < dbch->xferq.bnpacket; idb ++) {
                db = db_tr->db;
                fp = (struct fw_pkt *)db_tr->buf;
-               ohcifp = (volatile struct fwohci_txpkthdr *) db[1].db.immed;
+               ohcifp = (struct fwohci_txpkthdr *) db[1].db.immed;
                ohcifp->mode.ld[0] = fp->mode.ld[0];
+               ohcifp->mode.common.spd = 0 & 0x7;
                ohcifp->mode.stream.len = fp->mode.stream.len;
                ohcifp->mode.stream.chtag = chtag;
                ohcifp->mode.stream.tcode = 0xa;
-               ohcifp->mode.stream.spd = 0;
 #if BYTE_ORDER == BIG_ENDIAN
                FWOHCI_DMA_WRITE(db[1].db.immed[0], db[1].db.immed[0]); 
                FWOHCI_DMA_WRITE(db[1].db.immed[1], db[1].db.immed[1]); 
@@ -2459,7 +2518,7 @@ static int
 fwohci_add_tx_buf(struct fwohci_dbch *dbch, struct fwohcidb_tr *db_tr,
                                                                int poffset)
 {
-       volatile struct fwohcidb *db = db_tr->db;
+       struct fwohcidb *db = db_tr->db;
        struct fw_xferq *it;
        int err = 0;
 
@@ -2473,6 +2532,8 @@ fwohci_add_tx_buf(struct fwohci_dbch *dbch, struct fwohcidb_tr *db_tr,
 
        FWOHCI_DMA_WRITE(db[0].db.desc.cmd,
                OHCI_OUTPUT_MORE | OHCI_KEY_ST2 | 8);
+       FWOHCI_DMA_WRITE(db[0].db.desc.addr, 0);
+       bzero((void *)&db[1].db.immed[0], sizeof(db[1].db.immed));
        FWOHCI_DMA_WRITE(db[2].db.desc.addr,
        fwdma_bus_addr(it->buf, poffset) + sizeof(u_int32_t));
 
@@ -2489,7 +2550,7 @@ int
 fwohci_add_rx_buf(struct fwohci_dbch *dbch, struct fwohcidb_tr *db_tr,
                int poffset, struct fwdma_alloc *dummy_dma)
 {
-       volatile struct fwohcidb *db = db_tr->db;
+       struct fwohcidb *db = db_tr->db;
        struct fw_xferq *ir;
        int i, ldesc;
        bus_addr_t dbuf[2];
@@ -2540,7 +2601,7 @@ fwohci_arcv_swap(struct fw_pkt *fp, int len)
 {
        struct fw_pkt *fp0;
        u_int32_t ld0;
-       int slen;
+       int slen, hlen;
 #if BYTE_ORDER == BIG_ENDIAN
        int i;
 #endif
@@ -2550,6 +2611,7 @@ fwohci_arcv_swap(struct fw_pkt *fp, int len)
        printf("ld0: x%08x\n", ld0);
 #endif
        fp0 = (struct fw_pkt *)&ld0;
+       /* determine length to swap */
        switch (fp0->mode.common.tcode) {
        case FWTCODE_RREQQ:
        case FWTCODE_WRES:
@@ -2569,75 +2631,47 @@ fwohci_arcv_swap(struct fw_pkt *fp, int len)
                printf("Unknown tcode %d\n", fp0->mode.common.tcode);
                return(0);
        }
-       if (slen > len) {
+       hlen = tinfo[fp0->mode.common.tcode].hdr_len;
+       if (hlen > len) {
                if (firewire_debug)
                        printf("splitted header\n");
-               return(-slen);
+               return(-hlen);
        }
 #if BYTE_ORDER == BIG_ENDIAN
        for(i = 0; i < slen/4; i ++)
                fp->mode.ld[i] = FWOHCI_DMA_READ(fp->mode.ld[i]);
 #endif
-       return(slen);
+       return(hlen);
 }
 
-#define PLEN(x)        roundup2(x, sizeof(u_int32_t))
 static int
 fwohci_get_plen(struct fwohci_softc *sc, struct fwohci_dbch *dbch, struct fw_pkt *fp)
 {
+       struct tcode_info *info;
        int r;
 
-       switch(fp->mode.common.tcode){
-       case FWTCODE_RREQQ:
-               r = sizeof(fp->mode.rreqq) + sizeof(u_int32_t);
-               break;
-       case FWTCODE_WRES:
-               r = sizeof(fp->mode.wres) + sizeof(u_int32_t);
-               break;
-       case FWTCODE_WREQQ:
-               r = sizeof(fp->mode.wreqq) + sizeof(u_int32_t);
-               break;
-       case FWTCODE_RREQB:
-               r = sizeof(fp->mode.rreqb) + sizeof(u_int32_t);
-               break;
-       case FWTCODE_RRESQ:
-               r = sizeof(fp->mode.rresq) + sizeof(u_int32_t);
-               break;
-       case FWTCODE_WREQB:
-               r = sizeof(struct fw_asyhdr) + PLEN(fp->mode.wreqb.len)
-                                               + sizeof(u_int32_t);
-               break;
-       case FWTCODE_LREQ:
-               r = sizeof(struct fw_asyhdr) + PLEN(fp->mode.lreq.len)
-                                               + sizeof(u_int32_t);
-               break;
-       case FWTCODE_RRESB:
-               r = sizeof(struct fw_asyhdr) + PLEN(fp->mode.rresb.len)
-                                               + sizeof(u_int32_t);
-               break;
-       case FWTCODE_LRES:
-               r = sizeof(struct fw_asyhdr) + PLEN(fp->mode.lres.len)
-                                               + sizeof(u_int32_t);
-               break;
-       case FWOHCITCODE_PHY:
-               r = 16;
-               break;
-       default:
+       info = &tinfo[fp->mode.common.tcode];
+       r = info->hdr_len + sizeof(u_int32_t);
+       if ((info->flag & FWTI_BLOCK_ASY) != 0)
+               r += roundup2(fp->mode.wreqb.len, sizeof(u_int32_t));
+
+       if (r == sizeof(u_int32_t))
+               /* XXX */
                device_printf(sc->fc.dev, "Unknown tcode %d\n",
                                                fp->mode.common.tcode);
-               r = 0;
-       }
+
        if (r > dbch->xferq.psize) {
                device_printf(sc->fc.dev, "Invalid packet length %d\n", r);
                /* panic ? */
        }
+
        return r;
 }
 
 static void
 fwohci_arcv_free_buf(struct fwohci_dbch *dbch, struct fwohcidb_tr *db_tr)
 {
-       volatile struct fwohcidb *db = &db_tr->db[0];
+       struct fwohcidb *db = &db_tr->db[0];
 
        FWOHCI_DMA_CLEAR(db->db.desc.depend, 0xf);
        FWOHCI_DMA_WRITE(db->db.desc.res, dbch->xferq.psize);
@@ -2747,7 +2781,9 @@ fwohci_arcv(struct fwohci_softc *sc, struct fwohci_dbch *dbch, int count)
                                        dbch->buf_offset = - dbch->buf_offset;
                                        /* sanity check */
                                        if (resCount != 0) 
-                                               printf("resCount != 0 !?\n");
+                                               printf("resCount = %d !?\n",
+                                                   resCount);
+                                       /* XXX clear pdb_tr */
                                        goto out;
                                }
                                offset = 0;
@@ -2757,7 +2793,9 @@ fwohci_arcv(struct fwohci_softc *sc, struct fwohci_dbch *dbch, int count)
                        if (plen < 0) {
                                /* minimum header size + trailer
                                = sizeof(fw_pkt) so this shouldn't happens */
-                               printf("plen is negative! offset=%d\n", offset);
+                               printf("plen(%d) is negative! offset=%d\n",
+                                   plen, offset);
+                               /* XXX clear pdb_tr */
                                goto out;
                        }
                        if (plen > 0) {
@@ -2768,7 +2806,9 @@ fwohci_arcv(struct fwohci_softc *sc, struct fwohci_dbch *dbch, int count)
                                                printf("splitted payload\n");
                                        /* sanity check */
                                        if (resCount != 0) 
-                                               printf("resCount != 0 !?\n");
+                                               printf("resCount = %d !?\n",
+                                                   resCount);
+                                       /* XXX clear pdb_tr */
                                        goto out;
                                }
                                vec[nvec].iov_base = ld;
@@ -2787,7 +2827,8 @@ fwohci_arcv(struct fwohci_softc *sc, struct fwohci_dbch *dbch, int count)
                        stat = ((struct fwohci_trailer *)(ld - sizeof(struct fwohci_trailer)))->stat;
 #endif
 #if 0
-                       printf("plen: %d, stat %x\n", plen ,stat);
+                       printf("plen: %d, stat %x\n",
+                           plen ,stat);
 #endif
                        spd = (stat >> 5) & 0x3;
                        stat &= 0x1f;
@@ -2798,11 +2839,19 @@ fwohci_arcv(struct fwohci_softc *sc, struct fwohci_dbch *dbch, int count)
 #endif
                                /* fall through */
                        case FWOHCIEV_ACKCOMPL:
+                       {
+                               struct fw_rcv_buf rb;
+
                                if ((vec[nvec-1].iov_len -=
                                        sizeof(struct fwohci_trailer)) == 0)
                                        nvec--; 
-                               fw_rcv(&sc->fc, vec, nvec, 0, spd);
-                                       break;
+                               rb.fc = &sc->fc;
+                               rb.vec = vec;
+                               rb.nvec = nvec;
+                               rb.spd = spd;
+                               fw_rcv(&rb);
+                               break;
+                       }
                        case FWOHCIEV_BUSRST:
                                if (sc->fc.status != FWBUSRESET) 
                                        printf("got BUSRST packet!?\n");
index 643efc6..16a8096 100644 (file)
@@ -31,8 +31,8 @@
  * 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.3.2.11 2003/04/28 03:29:18 simokawa Exp $
- * $DragonFly: src/sys/bus/firewire/fwohci_pci.c,v 1.3 2003/08/07 21:16:45 dillon Exp $
+ * $FreeBSD: src/sys/dev/firewire/fwohci_pci.c,v 1.38 2004/01/23 17:37:09 simokawa Exp $
+ * $DragonFly: src/sys/bus/firewire/fwohci_pci.c,v 1.4 2004/02/05 13:32:08 joerg Exp $
  */
 
 #define BOUNCE_BUFFER_TEST     0
 #include <sys/systm.h>
 #include <sys/kernel.h>
 #include <sys/module.h>
+#include <sys/conf.h>
 #include <sys/bus.h>
 #include <sys/queue.h>
 #include <machine/bus.h>
 #include <sys/rman.h>
 #include <sys/malloc.h>
+#if __FreeBSD_version >= 501102
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#endif
 #include <machine/resource.h>
 
+#if __FreeBSD_version < 500000
+#include <machine/clock.h>             /* for DELAY() */
+#endif
+
+#ifdef __DragonFly__
 #include <bus/pci/pcivar.h>
 #include <bus/pci/pcireg.h>
 
 #include "fwdma.h"
 #include "fwohcireg.h"
 #include "fwohcivar.h"
+#else
+#if __FreeBSD_version < 500000
+#include <pci/pcivar.h>
+#include <pci/pcireg.h>
+#else
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#endif
+
+#include <dev/firewire/firewire.h>
+#include <dev/firewire/firewirereg.h>
+
+#include <dev/firewire/fwdma.h>
+#include <dev/firewire/fwohcireg.h>
+#include <dev/firewire/fwohcivar.h>
+#endif
 
 static int fwohci_pci_attach(device_t self);
 static int fwohci_pci_detach(device_t self);
@@ -111,6 +137,10 @@ fwohci_pci_probe( device_t dev )
                device_set_desc(dev, "Texas Instruments TSB43AB23");
                return 0;
        }
+       if (id == (FW_VENDORID_TI | FW_DEVICE_TITSB82AA2)) {
+               device_set_desc(dev, "Texas Instruments TSB82AA2");
+               return 0;
+       }
        if (id == (FW_VENDORID_TI | FW_DEVICE_TIPCI4450)) {
                device_set_desc(dev, "Texas Instruments PCI4450");
                return 0;
@@ -215,7 +245,7 @@ fwohci_pci_attach(device_t self)
 {
        fwohci_softc_t *sc = device_get_softc(self);
        int err;
-       int rid, s;
+       int rid;
 #if __FreeBSD_version < 500000
        int intr;
        /* For the moment, put in a message stating what is wrong */
@@ -253,13 +283,6 @@ fwohci_pci_attach(device_t self)
                return ENXIO;
        }
 
-       sc->fc.bdev = device_add_child(self, "firewire", -1);
-       if (!sc->fc.bdev) {
-               device_printf(self, "Could not add firewire device\n");
-               fwohci_pci_detach(self);
-               return ENOMEM;
-       }
-       device_set_ivars(sc->fc.bdev, sc);
 
        err = bus_setup_intr(self, sc->irq_res,
 #if FWOHCI_TASKQUEUE
@@ -272,6 +295,9 @@ fwohci_pci_attach(device_t self)
        /* XXX splcam() should mask this irq for sbp.c*/
        err = bus_setup_intr(self, sc->irq_res, INTR_TYPE_CAM,
                     (driver_intr_t *) fwohci_dummy_intr, sc, &sc->ih_cam);
+       /* XXX splbio() should mask this irq for physio()/fwmem_strategy() */
+       err = bus_setup_intr(self, sc->irq_res, INTR_TYPE_BIO,
+                    (driver_intr_t *) fwohci_dummy_intr, sc, &sc->ih_bio);
 #endif
        if (err) {
                device_printf(self, "Could not setup irq, %d\n", err);
@@ -292,6 +318,10 @@ fwohci_pci_attach(device_t self)
                                /*nsegments*/0x20,
                                /*maxsegsz*/0x8000,
                                /*flags*/BUS_DMA_ALLOCNOW,
+#if __FreeBSD_version >= 501102
+                               /*lockfunc*/busdma_lock_mutex,
+                               /*lockarg*/&Giant,
+#endif
                                &sc->fc.dmat);
        if (err != 0) {
                printf("fwohci_pci_attach: Could not allocate DMA tag "
@@ -301,22 +331,15 @@ fwohci_pci_attach(device_t self)
 
        err = fwohci_init(sc, self);
 
-       if (!err)
-               err = device_probe_and_attach(sc->fc.bdev);
-
        if (err) {
-               device_printf(self, "FireWire init failed\n");
+               device_printf(self, "fwohci_init failed with err=%d\n", err);
                fwohci_pci_detach(self);
                return EIO;
        }
 
-       /* XXX
-        * Clear the bus reset event flag to start transactions even when
-        * interrupt is disabled during the boot process.
-        */
-       s = splfw();
-       fwohci_intr((void *)sc);
-       splx(s);
+       /* probe and attach a child device(firewire) */
+       bus_generic_probe(self);
+       bus_generic_attach(self);
 
        return 0;
 }
@@ -330,8 +353,14 @@ fwohci_pci_detach(device_t self)
 
        s = splfw();
 
-       fwohci_stop(sc, self);
+       if (sc->bsr)
+               fwohci_stop(sc, self);
+
        bus_generic_detach(self);
+       if (sc->fc.bdev) {
+               device_delete_child(self, sc->fc.bdev);
+               sc->fc.bdev = NULL;
+       }
 
        /* disable interrupts that might have been switched on */
        if (sc->bst && sc->bsh)
@@ -345,16 +374,12 @@ fwohci_pci_detach(device_t self)
                        device_printf(self, "Could not tear down irq, %d\n",
                                      err);
 #if __FreeBSD_version < 500000
-               err = bus_teardown_intr(self, sc->irq_res, sc->ih_cam);
+               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->fc.bdev) {
-               device_delete_child(self, sc->fc.bdev);
-               sc->fc.bdev = NULL;
-       }
-
        if (sc->irq_res) {
                bus_release_resource(self, SYS_RES_IRQ, 0, sc->irq_res);
                sc->irq_res = NULL;
@@ -376,13 +401,14 @@ fwohci_pci_detach(device_t self)
 static int
 fwohci_pci_suspend(device_t dev)
 {
+       fwohci_softc_t *sc = device_get_softc(dev);
        int err;
 
        device_printf(dev, "fwohci_pci_suspend\n");
        err = bus_generic_suspend(dev);
        if (err)
                return err;
-       /* fwohci_stop(dev); */
+       fwohci_stop(sc, dev);
        return 0;
 }
 
@@ -391,8 +417,11 @@ fwohci_pci_resume(device_t dev)
 {
        fwohci_softc_t *sc = device_get_softc(dev);
 
+#ifndef BURN_BRIDGES
        device_printf(dev, "fwohci_pci_resume: power_state = 0x%08x\n",
                                        pci_get_powerstate(dev));
+       pci_set_powerstate(dev, PCI_POWERSTATE_D0);
+#endif
        fwohci_pci_init(dev);
        fwohci_resume(sc, dev);
        return 0;
@@ -408,6 +437,42 @@ fwohci_pci_shutdown(device_t dev)
        return 0;
 }
 
+static device_t
+fwohci_pci_add_child(device_t dev, int order, const char *name, int unit)
+{
+       struct fwohci_softc *sc;
+       device_t child;
+       int s, err = 0;
+
+       sc = (struct fwohci_softc *)device_get_softc(dev);
+       child = device_add_child(dev, name, unit);
+       if (child == NULL)
+               return (child);
+
+       sc->fc.bdev = child;
+       device_set_ivars(child, (void *)&sc->fc);
+
+       err = device_probe_and_attach(child);
+       if (err) {
+               device_printf(dev, "probe_and_attach failed with err=%d\n",
+                   err);
+               fwohci_pci_detach(dev);
+               device_delete_child(dev, child);
+               return NULL;
+       }
+
+       /* XXX
+        * 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);
+
+       return (child);
+}
+
 static device_method_t fwohci_methods[] = {
        /* Device interface */
        DEVMETHOD(device_probe,         fwohci_pci_probe),
@@ -418,6 +483,7 @@ static device_method_t fwohci_methods[] = {
        DEVMETHOD(device_shutdown,      fwohci_pci_shutdown),
 
        /* Bus interface */
+       DEVMETHOD(bus_add_child,        fwohci_pci_add_child),
        DEVMETHOD(bus_print_child,      bus_generic_print_child),
 
        { 0, 0 }
@@ -431,5 +497,8 @@ static driver_t fwohci_driver = {
 
 static devclass_t fwohci_devclass;
 
+#ifdef FWOHCI_MODULE
+MODULE_DEPEND(fwohci, firewire, 1, 1, 1);
+#endif
 DRIVER_MODULE(fwohci, pci, fwohci_driver, fwohci_devclass, 0, 0);
 DRIVER_MODULE(fwohci, cardbus, fwohci_driver, fwohci_devclass, 0, 0);
index 1fed943..33f1cd0 100644 (file)
@@ -31,8 +31,8 @@
  * 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.2.2.6 2003/04/28 03:29:18 simokawa Exp $
- * $DragonFly: src/sys/bus/firewire/fwohcireg.h,v 1.3 2003/11/15 21:05:33 dillon Exp $
+ * $FreeBSD: src/sys/dev/firewire/fwohcireg.h,v 1.15 2004/01/06 14:24:01 simokawa Exp $
+ * $DragonFly: src/sys/bus/firewire/fwohcireg.h,v 1.4 2004/02/05 13:32:08 joerg Exp $
  *
  */
 #define                PCI_CBMEM               0x10
@@ -55,6 +55,7 @@
 #define                FW_DEVICE_TITSB43       (0x8021 << 16)
 #define                FW_DEVICE_TITSB43A      (0x8023 << 16)
 #define                FW_DEVICE_TITSB43AB23   (0x8024 << 16)
+#define                FW_DEVICE_TITSB82AA2    (0x8025 << 16)
 #define                FW_DEVICE_TIPCI4410A    (0x8017 << 16)
 #define                FW_DEVICE_TIPCI4450     (0x8011 << 16)
 #define                FW_DEVICE_TIPCI4451     (0x8027 << 16)
@@ -76,7 +77,7 @@
 #define                OHCI_MAX_DMA_CH         (0x4 + OHCI_DMA_ITCH + OHCI_DMA_IRCH)
 
 
-typedef volatile u_int32_t     fwohcireg_t;
+typedef u_int32_t      fwohcireg_t;
 
 /* for PCI */
 #if BYTE_ORDER == BIG_ENDIAN
@@ -94,12 +95,12 @@ typedef volatile u_int32_t  fwohcireg_t;
 struct fwohcidb {
        union {
                struct {
-                       volatile u_int32_t cmd;
-                       volatile u_int32_t addr;
-                       volatile u_int32_t depend;
-                       volatile u_int32_t res;
+                       u_int32_t cmd;
+                       u_int32_t addr;
+                       u_int32_t depend;
+                       u_int32_t res;
                } desc;
-               volatile u_int32_t immed[4];
+               u_int32_t immed[4];
        } db;
 #define OHCI_STATUS_SHIFT      16
 #define OHCI_COUNT_MASK                0xffff
@@ -312,14 +313,13 @@ struct ohci_registers {
 
        /*       0x400, 0x404, 0x408, 0x40c */
        /*       0x410, 0x404, 0x408, 0x40c */
-
        struct ohci_dma dma_irch[0x20];
 };
 
 struct fwohcidb_tr{
        STAILQ_ENTRY(fwohcidb_tr) link;
        struct fw_xfer *xfer;
-       volatile struct fwohcidb *db;
+       struct fwohcidb *db;
        bus_dmamap_t dma_map;
        caddr_t buf;
        bus_addr_t bus_addr;
@@ -334,8 +334,7 @@ struct fwohci_txpkthdr{
                u_int32_t ld[4];
                struct {
 #if BYTE_ORDER == BIG_ENDIAN
-                       u_int32_t :13,
-                                 spd:3,
+                       u_int32_t spd:16, /* XXX include reserved field */
                                  :8,
                                  tcode:4,
                                  :4;
@@ -343,8 +342,7 @@ struct fwohci_txpkthdr{
                        u_int32_t :4,
                                  tcode:4,
                                  :8,
-                                 spd:3,
-                                 :13;
+                                 spd:16; /* XXX include reserved fields */
 #endif
                }common;
                struct {
index bea9a25..6a6eaae 100644 (file)
@@ -31,8 +31,8 @@
  * 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.1.2.6 2003/04/28 03:29:18 simokawa Exp $
- * $DragonFly: src/sys/bus/firewire/fwohcivar.h,v 1.3 2003/08/27 11:42:34 rob Exp $
+ * $FreeBSD: src/sys/dev/firewire/fwohcivar.h,v 1.11 2004/01/06 14:30:47 simokawa Exp $
+ * $DragonFly: src/sys/bus/firewire/fwohcivar.h,v 1.4 2004/02/05 13:32:08 joerg Exp $
  *
  */
 
@@ -52,6 +52,7 @@ typedef struct fwohci_softc {
        void *ih;
 #if __FreeBSD_version < 500000
        void *ih_cam;
+       void *ih_bio;
 #endif
        struct resource *bsr;
        struct resource *irq_res;
@@ -85,6 +86,7 @@ typedef struct fwohci_softc {
 
 void fwohci_intr (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);
 int fwohci_detach (struct fwohci_softc *, device_t);
 int fwohci_resume (struct fwohci_softc *, device_t);
index 90e2f58..90553e9 100644 (file)
@@ -31,9 +31,8 @@
  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  * 
- * $FreeBSD: src/sys/dev/firewire/iec13213.h,v 1.1.2.4 2003/05/01 06:24:37 simokawa Exp $
- * $DragonFly: src/sys/bus/firewire/iec13213.h,v 1.2 2003/06/17 04:28:26 dillon Exp $
- *
+ * $FreeBSD: src/sys/dev/firewire/iec13213.h,v 1.10 2003/06/16 08:29:24 simokawa Exp $
+ * $DragonFly: src/sys/bus/firewire/iec13213.h,v 1.3 2004/02/05 13:32:08 joerg Exp $
  */
 
 #define        STATE_CLEAR     0x0000
 #define CSRTYPE_L      (2 << CSRTYPE_SHIFT) /* Leaf */
 #define CSRTYPE_D      (3 << CSRTYPE_SHIFT) /* Directory */
 
+/*
+ * CSR keys
+ * 00 - 2F: defined by CSR architecture standards.
+ * 30 - 37: defined by BUS starndards
+ * 38 - 3F: defined by Vendor/Specifier
+ */
 #define CSRKEY_MASK    0x3f
 #define CSRKEY_DESC    0x01 /* Descriptor */
 #define CSRKEY_BDINFO  0x02 /* Bus_Dependent_Info */
 #define CROM_LUN       (CSRTYPE_I | CSRKEY_DINFO) /* 0x14 Logical unit num. */
 #define CROM_MGM       (CSRTYPE_C | CSRKEY_DINFO) /* 0x54 Management agent */
 
+#define CSRVAL_VENDOR_PRIVATE  0xacde48
 #define CSRVAL_1394TA  0x00a02d
 #define CSRVAL_ANSIT10 0x00609e
 #define CSRVAL_IETF    0x00005e
@@ -156,12 +162,24 @@ struct csrtext {
 struct bus_info {
 #define        CSR_BUS_NAME_IEEE1394   0x31333934
        u_int32_t bus_name;     
+#if BYTE_ORDER == BIG_ENDIAN
+       u_int32_t irmc:1,               /* iso. resource manager capable */
+                 cmc:1,                /* cycle master capable */
+                 isc:1,                /* iso. operation support */
+                 bmc:1,                /* bus manager capable */
+                 pmc:1,                /* power manager capable */
+                 :3,
+                 cyc_clk_acc:8,        /* 0 <= ppm <= 100 */
+                 max_rec:4,            /* (2 << max_rec) bytes */
+                 :2,
+                 max_rom:2,
+                 generation:4,
+                 :1,
+                 link_spd:3;
+#else
        u_int32_t link_spd:3,
                  :1,
                  generation:4,
-#define MAXROM_4       0
-#define MAXROM_64      1
-#define MAXROM_1024    2
                  max_rom:2,
                  :2,
                  max_rec:4,            /* (2 << max_rec) bytes */
@@ -172,8 +190,13 @@ struct bus_info {
                  isc:1,                /* iso. operation support */
                  cmc:1,                /* cycle master capable */
                  irmc:1;               /* iso. resource manager capable */
+#endif
        struct fw_eui64 eui64;
 };
+/* max_rom */
+#define MAXROM_4       0
+#define MAXROM_64      1
+#define MAXROM_1024    2
 
 #define CROM_MAX_DEPTH 10
 struct crom_ptr {
@@ -213,9 +236,8 @@ struct crom_chunk {
        int ref_index; 
        int offset;
        struct {
-                       u_int32_t crc:16,
-                                 crc_len:16;
-                       u_int32_t buf[CROM_MAX_CHUNK_LEN]; 
+               BIT16x2(crc_len, crc);
+               u_int32_t buf[CROM_MAX_CHUNK_LEN]; 
        } data;
 };
 
index 4d5b5a9..7b2af22 100644 (file)
@@ -31,8 +31,8 @@
  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  * 
- * $FreeBSD: src/sys/dev/firewire/iec68113.h,v 1.1.2.5 2003/05/01 06:24:37 simokawa Exp $
- * $DragonFly: src/sys/bus/firewire/iec68113.h,v 1.2 2003/06/17 04:28:26 dillon Exp $
+ * $FreeBSD: src/sys/dev/firewire/iec68113.h,v 1.7 2003/04/29 13:27:13 simokawa Exp $
+ * $DragonFly: src/sys/bus/firewire/iec68113.h,v 1.3 2004/02/05 13:32:08 joerg Exp $
  *
  */
 
index 9de2d03..f6ef3aa 100644 (file)
@@ -1,5 +1,5 @@
 # $FreeBSD: src/sys/modules/firewire/sbp/Makefile,v 1.2.2.1 2002/11/03 10:58:21 simokawa Exp $
-# $DragonFly: src/sys/dev/disk/sbp/Makefile,v 1.3 2003/08/15 08:32:29 dillon Exp $
+# $DragonFly: src/sys/dev/disk/sbp/Makefile,v 1.4 2004/02/05 13:32:08 joerg Exp $
 
 # Makefile for the SBP-II (Serial Bus Protocol 2/SCSI over IEEE1394)
 
@@ -8,7 +8,7 @@
 KMOD   = sbp
 SRCS   = bus_if.h device_if.h \
          opt_cam.h opt_scsi.h \
-         sbp.c \
+         sbp.c sbp.h\
          firewire.h firewirereg.h \
          iec13213.h
 
index 13d39cb..ff1a15a 100644 (file)
@@ -1,6 +1,6 @@
 /*
- * Copyright (c) 2003 Hidetosh Shimokawa
- * Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetosh Shimokawa
+ * Copyright (c) 2003 Hidetoshi Shimokawa
+ * Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * 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.5.2.19 2003/05/12 04:16:30 simokawa Exp $
- * $DragonFly: src/sys/dev/disk/sbp/sbp.c,v 1.7 2004/01/14 07:13:27 joerg Exp $
+ * $FreeBSD: src/sys/dev/firewire/sbp.c,v 1.74 2004/01/08 14:58:09 simokawa Exp $
+ * $DragonFly: src/sys/dev/disk/sbp/sbp.c,v 1.8 2004/02/05 13:32:08 joerg Exp $
  *
  */
 
 #include <sys/param.h>
 #include <sys/systm.h>
+#include <sys/conf.h>
 #include <sys/module.h>
 #include <sys/bus.h>
-#include <sys/mbuf.h>
+#include <sys/kernel.h>
 #include <sys/sysctl.h>
 #include <machine/bus.h>
 #include <sys/malloc.h>
+#if __FreeBSD_version >= 501102
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#endif
 
 #if __FreeBSD_version < 500106
 #include <sys/devicestat.h>    /* for struct devstat */
 #endif
 
+#ifdef __DragonFly__
 #include <bus/cam/cam.h>
 #include <bus/cam/cam_ccb.h>
 #include <bus/cam/cam_sim.h>
 #include <bus/cam/cam_xpt_sim.h>
 #include <bus/cam/cam_debug.h>
 #include <bus/cam/cam_periph.h>
-
 #include <bus/cam/scsi/scsi_all.h>
-#include <bus/cam/scsi/scsi_message.h>
-#include <bus/cam/scsi/scsi_da.h>
-
-#include <sys/kernel.h>
 
 #include <bus/firewire/firewire.h>
 #include <bus/firewire/firewirereg.h>
 #include <bus/firewire/fwdma.h>
 #include <bus/firewire/iec13213.h>
+#include "sbp.h"
+#else
+#include <cam/cam.h>
+#include <cam/cam_ccb.h>
+#include <cam/cam_sim.h>
+#include <cam/cam_xpt_sim.h>
+#include <cam/cam_debug.h>
+#include <cam/cam_periph.h>
+#include <cam/scsi/scsi_all.h>
+#endif
 
 #define ccb_sdev_ptr   spriv_ptr0
 #define ccb_sbp_ptr    spriv_ptr1
 
 #define SBP_NUM_TARGETS 8 /* MAX 64 */
-#define SBP_NUM_LUNS 8 /* limited by CAM_SCSI2_MAXLUN in cam_xpt.c */
+/*
+ * Scan_bus doesn't work for more than 8 LUNs
+ * because of CAM_SCSI2_MAXLUN in cam_xpt.c
+ */
+#define SBP_NUM_LUNS 64
 #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))
 #define SBP_NUM_OCB (SBP_QUEUE_LEN * SBP_NUM_TARGETS)
 
-#define SBP_INITIATOR 7
-
-#define LOGIN_DELAY 2
-
 /* 
  * STATUS FIFO addressing
  *   bit
  *  0- 1( 2): 0 (alingment)
  *  2- 7( 6): target
  *  8-15( 8): lun
- * 16-23( 8): unit
- * 24-31( 8): reserved
+ * 16-31( 8): reserved
  * 32-47(16): SBP_BIND_HI 
  * 48-64(16): bus_id, node_id 
  */
 #define SBP_BIND_HI 0x1
-#define SBP_DEV2ADDR(u, t, l) \
-       ((((u) & 0xff) << 16) | (((l) & 0xff) << 8) | (((t) & 0x3f) << 2))
+#define SBP_DEV2ADDR(t, l) \
+       (((u_int64_t)SBP_BIND_HI << 32) \
+       | (((l) & 0xff) << 8) \
+       | (((t) & 0x3f) << 2))
 #define SBP_ADDR2TRG(a)        (((a) >> 2) & 0x3f)
 #define SBP_ADDR2LUN(a)        (((a) >> 8) & 0xff)
-
-#define ORB_NOTIFY     (1 << 31)
-#define        ORB_FMT_STD     (0 << 29)
-#define        ORB_FMT_VED     (2 << 29)
-#define        ORB_FMT_NOP     (3 << 29)
-#define        ORB_FMT_MSK     (3 << 29)
-#define        ORB_EXV         (1 << 28)
-/* */
-#define        ORB_CMD_IN      (1 << 27)
-/* */
-#define        ORB_CMD_SPD(x)  ((x) << 24)
-#define        ORB_CMD_MAXP(x) ((x) << 20)
-#define        ORB_RCN_TMO(x)  ((x) << 20)
-#define        ORB_CMD_PTBL    (1 << 19)
-#define        ORB_CMD_PSZ(x)  ((x) << 16)
-
-#define        ORB_FUN_LGI     (0 << 16)
-#define        ORB_FUN_QLG     (1 << 16)
-#define        ORB_FUN_RCN     (3 << 16)
-#define        ORB_FUN_LGO     (7 << 16)
-#define        ORB_FUN_ATA     (0xb << 16)
-#define        ORB_FUN_ATS     (0xc << 16)
-#define        ORB_FUN_LUR     (0xe << 16)
-#define        ORB_FUN_RST     (0xf << 16)
-#define        ORB_FUN_MSK     (0xf << 16)
-#define        ORB_FUN_RUNQUEUE 0xffff
+#define SBP_INITIATOR 7
 
 static char *orb_fun_name[] = {
-       /* 0 */ "LOGIN",
-       /* 1 */ "QUERY LOGINS",
-       /* 2 */ "Reserved",
-       /* 3 */ "RECONNECT",
-       /* 4 */ "SET PASSWORD",
-       /* 5 */ "Reserved",
-       /* 6 */ "Reserved",
-       /* 7 */ "LOGOUT",
-       /* 8 */ "Reserved",
-       /* 9 */ "Reserved",
-       /* A */ "Reserved",
-       /* B */ "ABORT TASK",
-       /* C */ "ABORT TASK SET",
-       /* D */ "Reserved",
-       /* E */ "LOGICAL UNIT RESET",
-       /* F */ "TARGET RESET"
+       ORB_FUN_NAMES
 };
 
-#define ORB_RES_CMPL 0
-#define ORB_RES_FAIL 1
-#define ORB_RES_ILLE 2
-#define ORB_RES_VEND 3
-
 static int debug = 0;
 static int auto_login = 1;
-static int max_speed = 2;
+static int max_speed = -1;
 static int sbp_cold = 1;
+static int ex_login = 1;
+static int login_delay = 1000; /* msec */
+static int scan_delay = 500;   /* msec */
 static int sbp_tags = 0;
 
 SYSCTL_DECL(_hw_firewire);
@@ -163,18 +133,24 @@ SYSCTL_INT(_hw_firewire_sbp, OID_AUTO, auto_login, CTLFLAG_RW, &auto_login, 0,
        "SBP perform login automatically");
 SYSCTL_INT(_hw_firewire_sbp, OID_AUTO, max_speed, CTLFLAG_RW, &max_speed, 0,
        "SBP transfer max speed");
-TUNABLE_INT("hw.firewire.sbp.tags", &sbp_tags);
+SYSCTL_INT(_hw_firewire_sbp, OID_AUTO, exclusive_login, CTLFLAG_RW,
+       &ex_login, 0, "SBP transfer max speed");
+SYSCTL_INT(_hw_firewire_sbp, OID_AUTO, login_delay, CTLFLAG_RW,
+       &login_delay, 0, "SBP login delay in msec");
+SYSCTL_INT(_hw_firewire_sbp, OID_AUTO, scan_delay, CTLFLAG_RW,
+       &scan_delay, 0, "SBP scan delay in msec");
 SYSCTL_INT(_hw_firewire_sbp, OID_AUTO, tags, CTLFLAG_RW, &sbp_tags, 0,
        "SBP tagged queuing support");
 
-#define SBP_DEBUG(x)   if (debug > x) {
-#define END_DEBUG      }
+TUNABLE_INT("hw.firewire.sbp.auto_login", &auto_login);
+TUNABLE_INT("hw.firewire.sbp.max_speed", &max_speed);
+TUNABLE_INT("hw.firewire.sbp.exclusive_login", &ex_login);
+TUNABLE_INT("hw.firewire.sbp.login_delay", &login_delay);
+TUNABLE_INT("hw.firewire.sbp.scan_delay", &scan_delay);
+TUNABLE_INT("hw.firewire.sbp.tags", &sbp_tags);
 
 #define NEED_RESPONSE 0
 
-struct ind_ptr {
-       u_int32_t hi,lo;
-};
 #define SBP_SEG_MAX rounddown(0xffff, PAGE_SIZE)
 #ifdef __sparc64__ /* iommu */
 #define SBP_IND_MAX howmany(MAXPHYS, SBP_SEG_MAX)
@@ -185,9 +161,9 @@ struct sbp_ocb {
        STAILQ_ENTRY(sbp_ocb)   ocb;
        union ccb       *ccb;
        bus_addr_t      bus_addr;
-       volatile u_int32_t      orb[8];
+       u_int32_t       orb[8];
 #define IND_PTR_OFFSET (8*sizeof(u_int32_t))
-       volatile struct ind_ptr  ind_ptr[SBP_IND_MAX];
+       struct ind_ptr  ind_ptr[SBP_IND_MAX];
        struct sbp_dev  *sdev;
        int             flags; /* XXX should be removed */
        bus_dmamap_t    dmamap;
@@ -197,70 +173,6 @@ struct sbp_ocb {
 #define OCB_ACT_CMD 1
 #define OCB_MATCH(o,s) ((o)->bus_addr == ntohl((s)->orb_lo))
 
-#define SBP_RECV_LEN (16 + 32) /* header + payload */
-
-struct sbp_login_res{
-       u_int16_t       len;
-       u_int16_t       id;
-       u_int16_t       res0;
-       u_int16_t       cmd_hi;
-       u_int32_t       cmd_lo;
-       u_int16_t       res1;
-       u_int16_t       recon_hold;
-};
-struct sbp_status{
-#if BYTE_ORDER == BIG_ENDIAN
-       u_int8_t        src:2,
-                       resp:2,
-                       dead:1,
-                       len:3;
-#else
-       u_int8_t        len:3,
-                       dead:1,
-                       resp:2,
-                       src:2;
-#endif
-       u_int8_t        status;
-       u_int16_t       orb_hi;
-       u_int32_t       orb_lo;
-       u_int32_t       data[6];
-};
-struct sbp_cmd_status{
-#define SBP_SFMT_CURR 0
-#define SBP_SFMT_DEFER 1
-#if BYTE_ORDER == BIG_ENDIAN
-       u_int8_t        sfmt:2,
-                       status:6;
-       u_int8_t        valid:1,
-                       mark:1,
-                       eom:1,
-                       ill_len:1,
-                       s_key:4;
-#else
-       u_int8_t        status:6,
-                       sfmt:2;
-       u_int8_t        s_key:4,
-                       ill_len:1,
-                       eom:1,
-                       mark:1,
-                       valid:1;
-#endif
-       u_int8_t        s_code;
-       u_int8_t        s_qlfr;
-       u_int32_t       info;
-       u_int32_t       cdb;
-
-#if BYTE_ORDER == BIG_ENDIAN
-       u_int32_t       s_keydep:24,
-                       fru:8;
-#else
-       u_int32_t       fru:8,
-                       s_keydep:24;
-#endif
-       u_int32_t       vend[2];
-
-};
-
 struct sbp_dev{
 #define SBP_DEV_RESET          0       /* accept login */
 #define SBP_DEV_LOGIN          1       /* to login */
@@ -276,7 +188,12 @@ struct sbp_dev{
                 timeout:4;
        u_int8_t type;
        u_int16_t lun_id;
-       int freeze;
+       u_int16_t freeze;
+#define        ORB_LINK_DEAD           (1 << 0)
+#define        VALID_LUN               (1 << 1)
+#define        ORB_POINTER_ACTIVE      (1 << 2)
+#define        ORB_POINTER_NEED        (1 << 3)
+       u_int16_t flags;
        struct cam_path *path;
        struct sbp_target *target;
        struct fwdma_alloc dma;
@@ -293,14 +210,13 @@ struct sbp_dev{
 struct sbp_target {
        int target_id;
        int num_lun;
-       struct sbp_dev  *luns;
+       struct sbp_dev  **luns;
        struct sbp_softc *sbp;
        struct fw_device *fwdev;
        u_int32_t mgm_hi, mgm_lo;
        struct sbp_ocb *mgm_ocb_cur;
        STAILQ_HEAD(, sbp_ocb) mgm_ocb_queue;
        struct callout mgm_ocb_timeout;
-#define SCAN_DELAY 2
        struct callout scan_callout;
        STAILQ_HEAD(, fw_xfer) xferlist;
        int n_xfer;
@@ -313,13 +229,17 @@ struct sbp_softc {
        struct sbp_target targets[SBP_NUM_TARGETS];
        struct fw_bind fwb;
        bus_dma_tag_t   dmat;
-#define SBP_RESOURCE_SHORTAGE 0x10
-       unsigned char flags;
+       struct timeval last_busreset;
+#define SIMQ_FREEZED 1
+       int flags;
 };
+
 static void sbp_post_explore (void *);
 static void sbp_recv (struct fw_xfer *);
 static void sbp_mgm_callback (struct fw_xfer *);
+#if 0
 static void sbp_cmd_callback (struct fw_xfer *);
+#endif
 static void sbp_orb_pointer (struct sbp_dev *, struct sbp_ocb *);
 static void sbp_execute_ocb (void *,  bus_dma_segment_t *, int, int);
 static void sbp_free_ocb (struct sbp_dev *, struct sbp_ocb *);
@@ -329,13 +249,13 @@ 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 *);
 static struct sbp_ocb * sbp_dequeue_ocb (struct sbp_dev *, struct sbp_status *);
+static void sbp_cam_detach_sdev(struct sbp_dev *);
+static void sbp_free_sdev(struct sbp_dev *);
 static void sbp_cam_detach_target (struct sbp_target *);
+static void sbp_free_target (struct sbp_target *);
 static void sbp_mgm_timeout (void *arg);
 static void sbp_timeout (void *arg);
 static void sbp_mgm_orb (struct sbp_dev *, int, struct sbp_ocb *);
-#define sbp_login(sdev) \
-       callout_reset(&(sdev)->login_callout, LOGIN_DELAY * hz, \
-                       sbp_login_callout, (void *)(sdev));
 
 MALLOC_DEFINE(M_SBP, "sbp", "SBP-II/FireWire");
 
@@ -417,7 +337,7 @@ END_DEBUG
                return(ENXIO);
        }
 
-       device_set_desc(dev, "SBP2/SCSI over firewire");
+       device_set_desc(dev, "SBP-2/SCSI over FireWire");
 
        if (bootverbose)
                debug = bootverbose;
@@ -508,50 +428,16 @@ sbp_new_target(struct sbp_softc *sbp, struct fw_device *fwdev)
        return target;
 }
 
-static struct sbp_target *
-sbp_alloc_target(struct sbp_softc *sbp, struct fw_device *fwdev)
+static void
+sbp_alloc_lun(struct sbp_target *target)
 {
-       int i, maxlun, lun;
-       struct sbp_target *target;
-       struct sbp_dev *sdev;
        struct crom_context cc;
        struct csrreg *reg;
+       struct sbp_dev *sdev, **newluns;
+       struct sbp_softc *sbp;
+       int maxlun, lun, i;
 
-SBP_DEBUG(1)
-       printf("sbp_alloc_target\n");
-END_DEBUG
-       i = sbp_new_target(sbp, fwdev);
-       if (i < 0) {
-               device_printf(sbp->fd.dev, "increase SBP_NUM_TARGETS!\n");
-               return NULL;
-       }
-       /* new target */
-       target = &sbp->targets[i];
-       target->sbp = sbp;
-       target->fwdev = fwdev;
-       target->target_id = i;
-       /* XXX we may want to reload mgm port after each bus reset */
-       /* XXX there might be multiple management agents */
-       crom_init_context(&cc, target->fwdev->csrrom);
-       reg = crom_search_key(&cc, CROM_MGM);
-       if (reg == NULL || reg->val == 0) {
-               printf("NULL management address\n");
-               target->fwdev = NULL;
-               return NULL;
-       }
-       target->mgm_hi = 0xffff;
-       target->mgm_lo = 0xf0000000 | (reg->val << 2);
-       target->mgm_ocb_cur = NULL;
-SBP_DEBUG(1)
-       printf("target:%d mgm_port: %x\n", i, target->mgm_lo);
-END_DEBUG
-       STAILQ_INIT(&target->xferlist);
-       target->n_xfer = 0;
-       STAILQ_INIT(&target->mgm_ocb_queue);
-       CALLOUT_INIT(&target->mgm_ocb_timeout);
-       CALLOUT_INIT(&target->scan_callout);
-
-       /* XXX num_lun may be changed. realloc luns? */
+       sbp = target->sbp;
        crom_init_context(&cc, target->fwdev->csrrom);
        /* XXX shoud parse appropriate unit directories only */
        maxlun = -1;
@@ -568,34 +454,86 @@ END_DEBUG
                crom_next(&cc);
        }
        if (maxlun < 0)
-               printf("no lun found!\n");
+               printf("%s:%d no LUN found\n",
+                   device_get_nameunit(target->sbp->fd.dev),
+                   target->target_id);
+
+       maxlun ++;
        if (maxlun >= SBP_NUM_LUNS)
                maxlun = SBP_NUM_LUNS;
-       target->num_lun = maxlun + 1;
-       target->luns = (struct sbp_dev *) malloc(
-                               sizeof(struct sbp_dev) * target->num_lun, 
-                               M_SBP, M_NOWAIT | M_ZERO);
-       for (i = 0; i < target->num_lun; i++) {
-               sdev = &target->luns[i];
-               sdev->lun_id = i;
-               sdev->target = target;
-               STAILQ_INIT(&sdev->ocbs);
-               CALLOUT_INIT(&sdev->login_callout);
-               sdev->status = SBP_DEV_DEAD;
+
+       /* Invalidiate stale devices */
+       for (lun = 0; lun < target->num_lun; lun ++) {
+               sdev = target->luns[lun];
+               if (sdev == NULL)
+                       continue;
+               sdev->flags &= ~VALID_LUN;
+               if (lun >= maxlun) {
+                       /* lost device */
+                       sbp_cam_detach_sdev(sdev);
+                       sbp_free_sdev(sdev);
+               }
        }
+
+       /* Reallocate */
+       if (maxlun != target->num_lun) {
+               newluns = (struct sbp_dev **) realloc(target->luns,
+                   sizeof(struct sbp_dev *) * maxlun,
+                   M_SBP, M_NOWAIT | M_ZERO);
+               
+               if (newluns == NULL) {
+                       printf("%s: realloc failed\n", __FUNCTION__);
+                       newluns = target->luns;
+                       maxlun = target->num_lun;
+               }
+
+               /*
+                * We must zero the extended region for the case
+                * realloc() doesn't allocate new buffer.
+                */
+               if (maxlun > target->num_lun)
+                       bzero(&newluns[target->num_lun],
+                           sizeof(struct sbp_dev *) *
+                           (maxlun - target->num_lun));
+
+               target->luns = newluns;
+               target->num_lun = maxlun;
+       }
+
        crom_init_context(&cc, target->fwdev->csrrom);
        while (cc.depth >= 0) {
+               int new = 0;
+
                reg = crom_search_key(&cc, CROM_LUN);
                if (reg == NULL)
                        break;
                lun = reg->val & 0xffff;
                if (lun >= SBP_NUM_LUNS) {
                        printf("too large lun %d\n", lun);
-                       continue;
+                       goto next;
                }
-               sdev = &target->luns[lun];
-               sdev->status = SBP_DEV_RESET;
-               sdev->type = (reg->val & 0xf0000) >> 16;
+
+               sdev = target->luns[lun];
+               if (sdev == NULL) {
+                       sdev = malloc(sizeof(struct sbp_dev),
+                           M_SBP, M_NOWAIT | M_ZERO);
+                       if (sdev == NULL) {
+                               printf("%s: malloc failed\n", __FUNCTION__);
+                               goto next;
+                       }
+                       target->luns[lun] = sdev;
+                       sdev->lun_id = lun;
+                       sdev->target = target;
+                       STAILQ_INIT(&sdev->ocbs);
+                       CALLOUT_INIT(&sdev->login_callout);
+                       sdev->status = SBP_DEV_RESET;
+                       new = 1;
+               }
+               sdev->flags |= VALID_LUN;
+               sdev->type = (reg->val & 0xff0000) >> 16;
+
+               if (new == 0)
+                       goto next;
 
                fwdma_malloc(sbp->fd.fc, 
                        /* alignment */ sizeof(u_int32_t),
@@ -603,7 +541,9 @@ END_DEBUG
                if (sdev->dma.v_addr == NULL) {
                        printf("%s: dma space allocation failed\n",
                                                        __FUNCTION__);
-                       return (NULL);
+                       free(sdev, M_SBP);
+                       target->luns[lun] = NULL;
+                       goto next;
                }
                sdev->login = (struct sbp_login_res *) sdev->dma.v_addr;
                sdev->ocb = (struct sbp_ocb *)
@@ -621,12 +561,69 @@ END_DEBUG
                                + offsetof(struct sbp_ocb, orb[0]);
                        if (bus_dmamap_create(sbp->dmat, 0, &ocb->dmamap)) {
                                printf("sbp_attach: cannot create dmamap\n");
-                               return (NULL);
+                               /* XXX */
+                               goto next;
                        }
                        sbp_free_ocb(sdev, ocb);
                }
+next:
                crom_next(&cc);
        }
+
+       for (lun = 0; lun < target->num_lun; lun ++) {
+               sdev = target->luns[lun];
+               if (sdev != NULL && (sdev->flags & VALID_LUN) == 0) {
+                       sbp_cam_detach_sdev(sdev);
+                       sbp_free_sdev(sdev);
+                       target->luns[lun] = NULL;
+               }
+       }
+}
+
+static struct sbp_target *
+sbp_alloc_target(struct sbp_softc *sbp, struct fw_device *fwdev)
+{
+       int i;
+       struct sbp_target *target;
+       struct crom_context cc;
+       struct csrreg *reg;
+
+SBP_DEBUG(1)
+       printf("sbp_alloc_target\n");
+END_DEBUG
+       i = sbp_new_target(sbp, fwdev);
+       if (i < 0) {
+               device_printf(sbp->fd.dev, "increase SBP_NUM_TARGETS!\n");
+               return NULL;
+       }
+       /* new target */
+       target = &sbp->targets[i];
+       target->sbp = sbp;
+       target->fwdev = fwdev;
+       target->target_id = i;
+       /* XXX we may want to reload mgm port after each bus reset */
+       /* XXX there might be multiple management agents */
+       crom_init_context(&cc, target->fwdev->csrrom);
+       reg = crom_search_key(&cc, CROM_MGM);
+       if (reg == NULL || reg->val == 0) {
+               printf("NULL management address\n");
+               target->fwdev = NULL;
+               return NULL;
+       }
+       target->mgm_hi = 0xffff;
+       target->mgm_lo = 0xf0000000 | (reg->val << 2);
+       target->mgm_ocb_cur = NULL;
+SBP_DEBUG(1)
+       printf("target:%d mgm_port: %x\n", i, target->mgm_lo);
+END_DEBUG
+       STAILQ_INIT(&target->xferlist);
+       target->n_xfer = 0;
+       STAILQ_INIT(&target->mgm_ocb_queue);
+       CALLOUT_INIT(&target->mgm_ocb_timeout);
+       CALLOUT_INIT(&target->scan_callout);
+
+       target->luns = NULL;
+       target->num_lun = 0;
        return target;
 }
 
@@ -670,6 +667,28 @@ sbp_login_callout(void *arg)
        sbp_mgm_orb(sdev, ORB_FUN_LGI, NULL);
 }
 
+static void
+sbp_login(struct sbp_dev *sdev)
+{
+       struct timeval delta;
+       struct timeval t;
+       int ticks = 0;
+
+       microtime(&delta);
+       timevalsub(&delta, &sdev->target->sbp->last_busreset);
+       t.tv_sec = login_delay / 1000;
+       t.tv_usec = (login_delay % 1000) * 1000;
+       timevalsub(&t, &delta);
+       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", __FUNCTION__,
+           t.tv_sec, t.tv_usec, ticks);
+END_DEBUG
+       callout_reset(&sdev->login_callout, ticks,
+                       sbp_login_callout, (void *)(sdev));
+}
+
 #define SBP_FWDEV_ALIVE(fwdev) (((fwdev)->status == FWDEVATTACHED) \
        && crom_has_specver((fwdev)->csrrom, CSRVAL_ANSIT10, CSRVAL_T10SBP2))
 
@@ -691,9 +710,13 @@ END_DEBUG
 
        sbp = target->sbp;
        fc = target->sbp->fd.fc;
+       sbp_alloc_lun(target);
+
        /* XXX untimeout mgm_ocb and dequeue */
        for (i=0; i < target->num_lun; i++) {
-               sdev = &target->luns[i];
+               sdev = target->luns[i];
+               if (sdev == NULL)
+                       continue;
                if (alive && (sdev->status != SBP_DEV_DEAD)) {
                        if (sdev->path != NULL) {
                                xpt_freeze_devq(sdev->path, 1);
@@ -757,6 +780,11 @@ sbp_post_busreset(void *arg)
 SBP_DEBUG(0)
        printf("sbp_post_busreset\n");
 END_DEBUG
+       if ((sbp->sim->flags & SIMQ_FREEZED) == 0) {
+               xpt_freeze_simq(sbp->sim, /*count*/1);
+               sbp->sim->flags |= SIMQ_FREEZED;
+       }
+       microtime(&sbp->last_busreset);
 }
 
 static void
@@ -770,14 +798,16 @@ sbp_post_explore(void *arg)
 SBP_DEBUG(0)
        printf("sbp_post_explore (sbp_cold=%d)\n", sbp_cold);
 END_DEBUG
-#if 0  /*
-        * XXX don't let CAM the bus rest. CAM tries to do something with
-        * freezed (DEV_RETRY) devices 
+       if (sbp_cold > 0)
+               sbp_cold --;
+
+#if 0
+       /*
+        * XXX don't let CAM the bus rest.
+        * CAM tries to do something with freezed (DEV_RETRY) devices.
         */
        xpt_async(AC_BUS_RESET, sbp->path, /*arg*/ NULL);
 #endif
-       if (sbp_cold > 0)
-               sbp_cold --;
 
        /* Gabage Collection */
        for(i = 0 ; i < SBP_NUM_TARGETS ; i ++){
@@ -785,14 +815,10 @@ END_DEBUG
                STAILQ_FOREACH(fwdev, &sbp->fd.fc->devices, link)
                        if (target->fwdev == NULL || target->fwdev == fwdev)
                                break;
-               if(fwdev == NULL){
+               if (fwdev == NULL) {
                        /* device has removed in lower driver */
                        sbp_cam_detach_target(target);
-                       if (target->luns != NULL)
-                               free(target->luns, M_SBP);
-                       target->num_lun = 0;;
-                       target->luns = NULL;
-                       target->fwdev = NULL;
+                       sbp_free_target(target);
                }
        }
        /* traverse device list */
@@ -824,7 +850,11 @@ END_DEBUG
                        }
                }
                sbp_probe_target((void *)target);
+               if (target->num_lun == 0)
+                       sbp_free_target(target);
        }
+       xpt_release_simq(sbp->sim, /*run queue*/TRUE);
+       sbp->sim->flags &= ~SIMQ_FREEZED;
 }
 
 #if NEED_RESPONSE
@@ -871,9 +901,9 @@ sbp_reset_start_callback(struct fw_xfer *xfer)
        }
 
        for (i = 0; i < target->num_lun; i++) {
-               tsdev = &target->luns[i];
-               if (tsdev->status == SBP_DEV_LOGIN)
-                       sbp_login(sdev);
+               tsdev = target->luns[i];
+               if (tsdev != NULL && tsdev->status == SBP_DEV_LOGIN)
+                       sbp_login(tsdev);
        }
 }
 
@@ -890,7 +920,7 @@ END_DEBUG
 
        xfer = sbp_write_cmd(sdev, FWTCODE_WREQQ, 0);
        xfer->act.hand = sbp_reset_start_callback;
-       fp = (struct fw_pkt *)xfer->send.buf;
+       fp = &xfer->send.hdr;
        fp->mode.wreqq.dest_hi = 0xffff;
        fp->mode.wreqq.dest_lo = 0xf0000000 | RESET_START;
        fp->mode.wreqq.data = htonl(0xf);
@@ -921,33 +951,17 @@ END_DEBUG
        return;
 }
 
-static void
-sbp_cmd_callback(struct fw_xfer *xfer)
-{
-SBP_DEBUG(2)
-       struct sbp_dev *sdev;
-       sdev = (struct sbp_dev *)xfer->sc;
-       sbp_show_sdev_info(sdev, 2);
-       printf("sbp_cmd_callback\n");
-END_DEBUG
-       sbp_xfer_free(xfer);
-       return;
-}
-
 static struct sbp_dev *
 sbp_next_dev(struct sbp_target *target, int lun)
 {
-       struct sbp_dev *sdev;
+       struct sbp_dev **sdevp;
        int i;
 
-       for (i = lun, sdev = &target->luns[lun];
-                       i < target->num_lun; i++, sdev++) {
-               if (sdev->status == SBP_DEV_PROBE)
-                       break;
-       }
-       if (i >= target->num_lun)
-               return(NULL);
-       return(sdev);
+       for (i = lun, sdevp = &target->luns[lun]; i < target->num_lun;
+           i++, sdevp++)
+               if (*sdevp != NULL && (*sdevp)->status == SBP_DEV_PROBE)
+                       return(*sdevp);
+       return(NULL);
 }
 
 #define SCAN_PRI 1
@@ -1021,7 +1035,7 @@ static __inline void
 sbp_scan_dev(struct sbp_dev *sdev)
 {
        sdev->status = SBP_DEV_PROBE;
-       callout_reset(&sdev->target->scan_callout, SCAN_DELAY * hz,
+       callout_reset(&sdev->target->scan_callout, scan_delay * hz / 1000,
                        sbp_cam_scan_target, (void *)sdev->target);
 }
 
@@ -1068,11 +1082,11 @@ sbp_agent_reset_callback(struct fw_xfer *xfer)
        sdev = (struct sbp_dev *)xfer->sc;
 SBP_DEBUG(1)
        sbp_show_sdev_info(sdev, 2);
-       printf("sbp_cmd_callback\n");
+       printf("%s\n", __FUNCTION__);
 END_DEBUG
        if (xfer->resp != 0) {
                sbp_show_sdev_info(sdev, 2);
-               printf("sbp_cmd_callback resp=%d\n", xfer->resp);
+               printf("%s: resp=%d\n", __FUNCTION__, xfer->resp);
        }
 
        sbp_xfer_free(xfer);
@@ -1095,11 +1109,11 @@ END_DEBUG
        xfer = sbp_write_cmd(sdev, FWTCODE_WREQQ, 0x04);
        if (xfer == NULL)
                return;
-       if (sdev->status == SBP_DEV_ATTACHED)
+       if (sdev->status == SBP_DEV_ATTACHED || sdev->status == SBP_DEV_PROBE)
                xfer->act.hand = sbp_agent_reset_callback;
        else
                xfer->act.hand = sbp_do_attach;
-       fp = (struct fw_pkt *)xfer->send.buf;
+       fp = &xfer->send.hdr;
        fp->mode.wreqq.data = htonl(0xf);
        fw_asyreq(xfer->fc, -1, xfer);
        sbp_abort_all_ocbs(sdev, CAM_BDR_SENT);
@@ -1131,34 +1145,71 @@ END_DEBUG
        xfer = sbp_write_cmd(sdev, FWTCODE_WREQQ, 0);
 
        xfer->act.hand = sbp_busy_timeout_callback;
-       fp = (struct fw_pkt *)xfer->send.buf;
+       fp = &xfer->send.hdr;
        fp->mode.wreqq.dest_hi = 0xffff;
        fp->mode.wreqq.dest_lo = 0xf0000000 | BUSY_TIMEOUT;
        fp->mode.wreqq.data = htonl((1 << (13+12)) | 0xf);
        fw_asyreq(xfer->fc, -1, xfer);
 }
 
+static void
+sbp_orb_pointer_callback(struct fw_xfer *xfer)
+{
+       struct sbp_dev *sdev;
+       sdev = (struct sbp_dev *)xfer->sc;
+
+SBP_DEBUG(1)
+       sbp_show_sdev_info(sdev, 2);
+       printf("%s\n", __FUNCTION__);
+END_DEBUG
+       if (xfer->resp != 0) {
+               /* XXX */
+               printf("%s: xfer->resp = %d\n", __FUNCTION__, xfer->resp);
+       }
+       sbp_xfer_free(xfer);
+       sdev->flags &= ~ORB_POINTER_ACTIVE;
+
+       if ((sdev->flags & ORB_POINTER_NEED) != 0) {
+               struct sbp_ocb *ocb;
+
+               sdev->flags &= ~ORB_POINTER_NEED;
+               ocb = STAILQ_FIRST(&sdev->ocbs);
+               if (ocb != NULL)
+                       sbp_orb_pointer(sdev, ocb);
+       }
+       return;
+}
+
 static void
 sbp_orb_pointer(struct sbp_dev *sdev, struct sbp_ocb *ocb)
 {
        struct fw_xfer *xfer;
        struct fw_pkt *fp;
-SBP_DEBUG(2)
+SBP_DEBUG(1)
        sbp_show_sdev_info(sdev, 2);
-       printf("sbp_orb_pointer\n");
+       printf("%s: 0x%08x\n", __FUNCTION__, (u_int32_t)ocb->bus_addr);
 END_DEBUG
 
+       if ((sdev->flags & ORB_POINTER_ACTIVE) != 0) {
+SBP_DEBUG(0)
+               printf("%s: orb pointer active\n", __FUNCTION__);
+END_DEBUG
+               sdev->flags |= ORB_POINTER_NEED;
+               return;
+       }
+
+       sdev->flags |= ORB_POINTER_ACTIVE;
        xfer = sbp_write_cmd(sdev, FWTCODE_WREQB, 0x08);
        if (xfer == NULL)
                return;
-       xfer->act.hand = sbp_cmd_callback;
+       xfer->act.hand = sbp_orb_pointer_callback;
 
-       fp = (struct fw_pkt *)xfer->send.buf;
+       fp = &xfer->send.hdr;
        fp->mode.wreqb.len = 8;
        fp->mode.wreqb.extcode = 0;
-       fp->mode.wreqb.payload[0] = 
+       xfer->send.payload[0] = 
                htonl(((sdev->target->sbp->fd.fc->nodeid | FWLOCALBUS )<< 16));
-       fp->mode.wreqb.payload[1] = htonl(ocb->bus_addr);
+       xfer->send.payload[1] = htonl((u_int32_t)ocb->bus_addr);
 
        if(fw_asyreq(xfer->fc, -1, xfer) != 0){
                        sbp_xfer_free(xfer);
@@ -1168,6 +1219,23 @@ END_DEBUG
 }
 
 #if 0
+static void
+sbp_cmd_callback(struct fw_xfer *xfer)
+{
+SBP_DEBUG(1)
+       struct sbp_dev *sdev;
+       sdev = (struct sbp_dev *)xfer->sc;
+       sbp_show_sdev_info(sdev, 2);
+       printf("sbp_cmd_callback\n");
+END_DEBUG
+       if (xfer->resp != 0) {
+               /* XXX */
+               printf("%s: xfer->resp = %d\n", __FUNCTION__, xfer->resp);
+       }
+       sbp_xfer_free(xfer);
+       return;
+}
+
 static void
 sbp_doorbell(struct sbp_dev *sdev)
 {
@@ -1205,7 +1273,7 @@ sbp_write_cmd(struct sbp_dev *sdev, int tcode, int offset)
                        splx(s);
                        return(NULL);
                }
-               xfer = fw_xfer_alloc_buf(M_SBP, 24, 12);
+               xfer = fw_xfer_alloc_buf(M_SBP, 8, 0);
                if(xfer == NULL){
                        printf("sbp: fw_xfer_alloc_buf failed\n");
                        splx(s);
@@ -1222,26 +1290,26 @@ sbp_write_cmd(struct sbp_dev *sdev, int tcode, int offset)
 
        microtime(&xfer->tv);
 
-       if (tcode == FWTCODE_WREQQ)
-               xfer->send.len = 16;
-       else
-               xfer->send.len = 24;
-       xfer->recv.len = 12;
-
        if (new) {
-               xfer->spd = min(sdev->target->fwdev->speed, max_speed);
+               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)
+               xfer->send.pay_len = 8;
+       else
+               xfer->send.pay_len = 0;
+
        xfer->sc = (caddr_t)sdev;
-       fp = (struct fw_pkt *)xfer->send.buf;
+       fp = &xfer->send.hdr;
        fp->mode.wreqq.dest_hi = sdev->login->cmd_hi;
        fp->mode.wreqq.dest_lo = sdev->login->cmd_lo + offset;
        fp->mode.wreqq.tlrt = 0;
        fp->mode.wreqq.tcode = tcode;
        fp->mode.wreqq.pri = 0;
-       xfer->dst = FWLOCALBUS | sdev->target->fwdev->dst;
-       fp->mode.wreqq.dst = xfer->dst;
+       fp->mode.wreqq.dst = FWLOCALBUS | sdev->target->fwdev->dst;
 
        return xfer;
 
@@ -1271,17 +1339,15 @@ sbp_mgm_orb(struct sbp_dev *sdev, int func, struct sbp_ocb *aocb)
        }
        if ((ocb = sbp_get_ocb(sdev)) == NULL) {
                splx(s);
+               /* XXX */
                return;
        }
        ocb->flags = OCB_ACT_MGM;
        ocb->sdev = sdev;
 
-       bzero((void *)(uintptr_t)(volatile void *)ocb->orb, sizeof(ocb->orb));
+       bzero((void *)ocb->orb, sizeof(ocb->orb));
        ocb->orb[6] = htonl((nid << 16) | SBP_BIND_HI);
-       ocb->orb[7] = htonl(SBP_DEV2ADDR(
-               device_get_unit(target->sbp->fd.dev),
-               target->target_id,
-               sdev->lun_id));
+       ocb->orb[7] = htonl(SBP_DEV2ADDR(target->target_id, sdev->lun_id));
 
 SBP_DEBUG(0)
        sbp_show_sdev_info(sdev, 2);
@@ -1289,9 +1355,12 @@ SBP_DEBUG(0)
 END_DEBUG
        switch (func) {
        case ORB_FUN_LGI:
+               ocb->orb[0] = ocb->orb[1] = 0; /* password */
                ocb->orb[2] = htonl(nid << 16);
                ocb->orb[3] = htonl(sdev->dma.bus_addr);
-               ocb->orb[4] = htonl(ORB_NOTIFY | ORB_EXV | sdev->lun_id);
+               ocb->orb[4] = htonl(ORB_NOTIFY | sdev->lun_id);
+               if (ex_login)
+                       ocb->orb[4] |= htonl(ORB_EXV);
                ocb->orb[5] = htonl(SBP_LOGIN_SIZE);
                fwdma_sync(&sdev->dma, BUS_DMASYNC_PREREAD);
                break;
@@ -1326,13 +1395,17 @@ start:
        }
        xfer->act.hand = sbp_mgm_callback;
 
-       fp = (struct fw_pkt *)xfer->send.buf;
+       fp = &xfer->send.hdr;
        fp->mode.wreqb.dest_hi = sdev->target->mgm_hi;
        fp->mode.wreqb.dest_lo = sdev->target->mgm_lo;
        fp->mode.wreqb.len = 8;
        fp->mode.wreqb.extcode = 0;
-       fp->mode.wreqb.payload[0] = htonl(nid << 16);
-       fp->mode.wreqb.payload[1] = htonl(ocb->bus_addr);
+       xfer->send.payload[0] = htonl(nid << 16);
+       xfer->send.payload[1] = htonl(ocb->bus_addr & 0xffffffff);
+SBP_DEBUG(0)
+       sbp_show_sdev_info(sdev, 2);
+       printf("mgm orb: %08x\n", (u_int32_t)ocb->bus_addr);
+END_DEBUG
 
        fw_asyreq(xfer->fc, -1, xfer);
 }
@@ -1406,10 +1479,9 @@ END_DEBUG
                        sense->flags |= SSD_EOM;
                if(sbp_cmd_status->ill_len)
                        sense->flags |= SSD_ILI;
-               sense->info[0] = ntohl(sbp_cmd_status->info) & 0xff;
-               sense->info[1] =(ntohl(sbp_cmd_status->info) >> 8) & 0xff;
-               sense->info[2] =(ntohl(sbp_cmd_status->info) >> 16) & 0xff;
-               sense->info[3] =(ntohl(sbp_cmd_status->info) >> 24) & 0xff;
+
+               bcopy(&sbp_cmd_status->info, &sense->info[0], 4);
+
                if (sbp_status->len <= 1)
                        /* XXX not scsi status. shouldn't be happened */ 
                        sense->extra_len = 0;
@@ -1419,16 +1491,15 @@ END_DEBUG
                else
                        /* fru, sense_key_spec */
                        sense->extra_len = 10;
-               sense->cmd_spec_info[0] = ntohl(sbp_cmd_status->cdb) & 0xff;
-               sense->cmd_spec_info[1] = (ntohl(sbp_cmd_status->cdb) >> 8) & 0xff;
-               sense->cmd_spec_info[2] = (ntohl(sbp_cmd_status->cdb) >> 16) & 0xff;
-               sense->cmd_spec_info[3] = (ntohl(sbp_cmd_status->cdb) >> 24) & 0xff;
+
+               bcopy(&sbp_cmd_status->cdb, &sense->cmd_spec_info[0], 4);
+
                sense->add_sense_code = sbp_cmd_status->s_code;
                sense->add_sense_code_qual = sbp_cmd_status->s_qlfr;
                sense->fru = sbp_cmd_status->fru;
-               sense->sense_key_spec[0] = ntohl(sbp_cmd_status->s_keydep) & 0xff;
-               sense->sense_key_spec[1] = (ntohl(sbp_cmd_status->s_keydep) >>8) & 0xff;
-               sense->sense_key_spec[2] = (ntohl(sbp_cmd_status->s_keydep) >>16) & 0xff;
+
+               bcopy(&sbp_cmd_status->s_keydep[0],
+                   &sense->sense_key_spec[0], 3);
 
                ocb->ccb->csio.scsi_status = sbp_cmd_status->status;;
                ocb->ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR
@@ -1472,17 +1543,17 @@ END_DEBUG
        inq = (struct scsi_inquiry_data *) ccb->csio.data_ptr;
        switch (SID_TYPE(inq)) {
        case T_DIRECT:
+#if 0
                /* 
                 * XXX Convert Direct Access device to RBC.
                 * I've never seen FireWire DA devices which support READ_6.
                 */
-#if 1
                if (SID_TYPE(inq) == T_DIRECT)
                        inq->device |= T_RBC; /*  T_DIRECT == 0 */
 #endif
                /* fall through */
        case T_RBC:
-               /* enable tag queuing */
+               /* enable tagged queuing */
                if (sbp_tags)
                        inq->flags |= SID_CmdQue;
                else
@@ -1523,23 +1594,21 @@ printf("sbp %x %d %d %08x %08x %08x %08x\n",
 printf("sbp %08x %08x %08x %08x\n", ntohl(ld[4]), ntohl(ld[5]), ntohl(ld[6]), ntohl(ld[7]));
 printf("sbp %08x %08x %08x %08x\n", ntohl(ld[8]), ntohl(ld[9]), ntohl(ld[10]), ntohl(ld[11]));
 */
-
        sbp = (struct sbp_softc *)xfer->sc;
-       if(xfer->resp != 0){
-               printf("sbp_recv: xfer->resp != 0\n");
+       if (xfer->resp != 0){
+               printf("sbp_recv: xfer->resp = %d\n", xfer->resp);
                goto done0;
        }
-       if(xfer->recv.buf == NULL){
-               printf("sbp_recv: xfer->recv.buf == NULL\n");
+       if (xfer->recv.payload == NULL){
+               printf("sbp_recv: xfer->recv.payload == NULL\n");
                goto done0;
        }
-       sbp = (struct sbp_softc *)xfer->sc;
-       rfp = (struct fw_pkt *)xfer->recv.buf;
+       rfp = &xfer->recv.hdr;
        if(rfp->mode.wreqb.tcode != FWTCODE_WREQB){
                printf("sbp_recv: tcode = %d\n", rfp->mode.wreqb.tcode);
                goto done0;
        }
-       sbp_status = (struct sbp_status *)rfp->mode.wreqb.payload;
+       sbp_status = (struct sbp_status *)xfer->recv.payload;
        addr = rfp->mode.wreqb.dest_lo;
 SBP_DEBUG(2)
        printf("received address 0x%x\n", addr);
@@ -1552,12 +1621,12 @@ END_DEBUG
        }
        target = &sbp->targets[t];
        l = SBP_ADDR2LUN(addr);
-       if (l >= target->num_lun) {
+       if (l >= target->num_lun || target->luns[l] == NULL) {
                device_printf(sbp->fd.dev,
                        "sbp_recv1: invalid lun %d (target=%d)\n", l, t);
                goto done0;
        }
-       sdev = &target->luns[l];
+       sdev = target->luns[l];
 
        ocb = NULL;
        switch (sbp_status->src) {
@@ -1598,7 +1667,7 @@ END_DEBUG
                        && sbp_status->dead == 0);
        status_valid = (status_valid0 && sbp_status->status == 0);
 
-       if (!status_valid0 || debug > 1){
+       if (!status_valid0 || debug > 2){
                int status;
 SBP_DEBUG(0)
                sbp_show_sdev_info(sdev, 2);
@@ -1658,6 +1727,7 @@ END_DEBUG
                switch(ocb->flags) {
                case OCB_ACT_MGM:
                        orb_fun = ntohl(ocb->orb[4]) & ORB_FUN_MSK;
+                       reset_agent = 0;
                        switch(orb_fun) {
                        case ORB_FUN_LGI:
                                fwdma_sync(&sdev->dma, BUS_DMASYNC_POSTREAD);
@@ -1762,6 +1832,7 @@ done:
                sbp_agent_reset(sdev);
 
 done0:
+       xfer->recv.pay_len = SBP_RECV_LEN;
 /* The received packet is usually small enough to be stored within
  * the buffer. In that case, the controller return ack_complete and
  * no respose is necessary.
@@ -1786,7 +1857,6 @@ done0:
        fw_asyreq(xfer->fc, -1, xfer);
 #else
        /* recycle */
-       xfer->recv.len = SBP_RECV_LEN;
        STAILQ_INSERT_TAIL(&sbp->fwb.xferlist, xfer, link);
 #endif
 
@@ -1824,6 +1894,10 @@ END_DEBUG
        bzero(sbp, sizeof(struct sbp_softc));
        sbp->fd.dev = dev;
        sbp->fd.fc = device_get_ivars(dev);
+
+       if (max_speed < 0)
+               max_speed = sbp->fd.fc->speed;
+
        error = bus_dma_tag_create(/*parent*/sbp->fd.fc->dmat,
                                /* XXX shoud be 4 for sane backend? */
                                /*alignment*/1,
@@ -1834,6 +1908,10 @@ END_DEBUG
                                /*maxsize*/0x100000, /*nsegments*/SBP_IND_MAX,
                                /*maxsegsz*/SBP_SEG_MAX,
                                /*flags*/BUS_DMA_ALLOCNOW,
+#if __FreeBSD_version >= 501102
+                               /*lockfunc*/busdma_lock_mutex,
+                               /*lockarg*/&Giant,
+#endif
                                &sbp->dmat);
        if (error != 0) {
                printf("sbp_attach: Could not allocate DMA tag "
@@ -1853,7 +1931,7 @@ END_DEBUG
        sbp->sim = cam_sim_alloc(sbp_action, sbp_poll, "sbp", sbp,
                                 device_get_unit(dev),
                                 /*untagged*/ 1,
-                                /*tagged*/ SBP_QUEUE_LEN,
+                                /*tagged*/ SBP_QUEUE_LEN - 1,
                                 devq);
 
        if (sbp->sim == NULL) {
@@ -1866,23 +1944,20 @@ END_DEBUG
                goto fail;
 
        if (xpt_create_path(&sbp->path, xpt_periph, cam_sim_path(sbp->sim),
-                       CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP)
+           CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
+               xpt_bus_deregister(cam_sim_path(sbp->sim));
                goto fail;
+       }
 
-       sbp->fwb.start_hi = SBP_BIND_HI;
-       sbp->fwb.start_lo = SBP_DEV2ADDR(device_get_unit(sbp->fd.dev), 0, 0);
        /* We reserve 16 bit space (4 bytes X 64 targets X 256 luns) */
-       sbp->fwb.addrlen = 0xffff;
+       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,
-#if NEED_RESPONSE
-                       /* send */12,
-#else
                        /* send */0,
-#endif
                        /* recv */SBP_RECV_LEN);
                xfer->act.hand = sbp_recv;
 #if NEED_RESPONSE
@@ -1898,9 +1973,11 @@ END_DEBUG
 
        if (sbp->fd.fc->status != -1) {
                s = splfw();
+               sbp_post_busreset((void *)sbp);
                sbp_post_explore((void *)sbp);
                splx(s);
        }
+       xpt_async(AC_BUS_RESET, sbp->path, /*arg*/ NULL);
 
        return (0);
 fail:
@@ -1923,7 +2000,9 @@ END_DEBUG
                if (target->luns == NULL)
                        continue;
                for (j = 0; j < target->num_lun; j++) {
-                       sdev = &target->luns[j];
+                       sdev = target->luns[j];
+                       if (sdev == NULL)
+                               continue;
                        callout_stop(&sdev->login_callout);
                        if (sdev->status >= SBP_DEV_TOATTACH &&
                                        sdev->status <= SBP_DEV_ATTACHED)
@@ -1943,15 +2022,53 @@ sbp_shutdown(device_t dev)
        return (0);
 }
 
+static void
+sbp_free_sdev(struct sbp_dev *sdev)
+{
+       int i;
+
+       if (sdev == NULL)
+               return;
+       for (i = 0; i < SBP_QUEUE_LEN; i++)
+               bus_dmamap_destroy(sdev->target->sbp->dmat,
+                   sdev->ocb[i].dmamap);
+       fwdma_free(sdev->target->sbp->fd.fc, &sdev->dma);
+       free(sdev, M_SBP);
+}
+
+static void
+sbp_free_target(struct sbp_target *target)
+{
+       struct sbp_softc *sbp;
+       struct fw_xfer *xfer, *next;
+       int i;
+
+       if (target->luns == NULL)
+               return;
+       callout_stop(&target->mgm_ocb_timeout);
+       sbp = target->sbp;
+       for (i = 0; i < target->num_lun; i++)
+               sbp_free_sdev(target->luns[i]);
+
+       for (xfer = STAILQ_FIRST(&target->xferlist);
+                       xfer != NULL; xfer = next) {
+               next = STAILQ_NEXT(xfer, link);
+               fw_xfer_free_buf(xfer);
+       }
+       STAILQ_INIT(&target->xferlist);
+       free(target->luns, M_SBP);
+       target->num_lun = 0;;
+       target->luns = NULL;
+       target->fwdev = NULL;
+}
+
 static int
 sbp_detach(device_t dev)
 {
        struct sbp_softc *sbp = ((struct sbp_softc *)device_get_softc(dev));
        struct firewire_comm *fc = sbp->fd.fc;
-       struct sbp_target *target;
-       struct sbp_dev *sdev;
        struct fw_xfer *xfer, *next;
-       int i, j;
+       int i;
 
 SBP_DEBUG(0)
        printf("sbp_detach\n");
@@ -1959,40 +2076,23 @@ END_DEBUG
 
        for (i = 0; i < SBP_NUM_TARGETS; i ++) 
                sbp_cam_detach_target(&sbp->targets[i]);
+       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),
 
        sbp_logout_all(sbp);
 
        /* XXX wait for logout completion */
        tsleep(&i, FWPRI, "sbpdtc", hz/2);
 
-       for (i = 0 ; i < SBP_NUM_TARGETS ; i ++) {
-               target = &sbp->targets[i];
-               if (target->luns == NULL)
-                       continue;
-               callout_stop(&target->mgm_ocb_timeout);
-               for (j = 0; j < target->num_lun; j++) {
-                       sdev = &target->luns[j];
-                       if (sdev->status != SBP_DEV_DEAD) {
-                               for (i = 0; i < SBP_QUEUE_LEN; i++)
-                                       bus_dmamap_destroy(sbp->dmat,
-                                               sdev->ocb[i].dmamap);
-                               fwdma_free(sbp->fd.fc, &sdev->dma);
-                       }
-               }
-               for (xfer = STAILQ_FIRST(&target->xferlist);
-                               xfer != NULL; xfer = next) {
-                       next = STAILQ_NEXT(xfer, link);
-                       fw_xfer_free(xfer);
-               }
-               free(target->luns, M_SBP);
-       }
+       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(xfer);
+               fw_xfer_free_buf(xfer);
        }
        STAILQ_INIT(&sbp->fwb.xferlist);
        fw_bindremove(fc, &sbp->fwb);
@@ -2002,10 +2102,29 @@ END_DEBUG
        return (0);
 }
 
+static void
+sbp_cam_detach_sdev(struct sbp_dev *sdev)
+{
+       if (sdev == NULL)
+               return;
+       if (sdev->status == SBP_DEV_DEAD)
+               return;
+       if (sdev->status == SBP_DEV_RESET)
+               return;
+       if (sdev->path) {
+               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_abort_all_ocbs(sdev, CAM_DEV_NOT_THERE);
+}
+
 static void
 sbp_cam_detach_target(struct sbp_target *target)
 {
-       struct sbp_dev *sdev;
        int i;
 
        if (target->luns != NULL) {
@@ -2013,22 +2132,8 @@ SBP_DEBUG(0)
                printf("sbp_detach_target %d\n", target->target_id);
 END_DEBUG
                callout_stop(&target->scan_callout);
-               for (i = 0; i < target->num_lun; i++) {
-                       sdev = &target->luns[i];
-                       if (sdev->status == SBP_DEV_DEAD)
-                               continue;
-                       if (sdev->status == SBP_DEV_RESET)
-                               continue;
-                       if (sdev->path) {
-                               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_abort_all_ocbs(sdev, CAM_DEV_NOT_THERE);
-               }
+               for (i = 0; i < target->num_lun; i++)
+                       sbp_cam_detach_sdev(target->luns[i]);
        }
 }
 
@@ -2040,7 +2145,9 @@ sbp_target_reset(struct sbp_dev *sdev, int method)
        struct sbp_dev *tsdev;
 
        for (i = 0; i < target->num_lun; i++) {
-               tsdev = &target->luns[i];
+               tsdev = target->luns[i];
+               if (tsdev == NULL)
+                       continue;
                if (tsdev->status == SBP_DEV_DEAD)
                        continue;
                if (tsdev->status == SBP_DEV_RESET)
@@ -2072,14 +2179,17 @@ sbp_mgm_timeout(void *arg)
        struct sbp_target *target = sdev->target;
 
        sbp_show_sdev_info(sdev, 2);
-       printf("management ORB timeout\n");
+       printf("request timeout(mgm orb:0x%08x) ... ",
+           (u_int32_t)ocb->bus_addr);
        target->mgm_ocb_cur = NULL;
        sbp_free_ocb(sdev, ocb);
 #if 0
        /* XXX */
+       printf("run next request\n");
        sbp_mgm_orb(sdev, ORB_FUN_RUNQUEUE, NULL);
 #endif
-#if 0
+#if 1
+       printf("reset start\n");
        sbp_reset_start(sdev);
 #endif
 }
@@ -2091,7 +2201,8 @@ sbp_timeout(void *arg)
        struct sbp_dev *sdev = ocb->sdev;
 
        sbp_show_sdev_info(sdev, 2);
-       printf("request timeout ... ");
+       printf("request timeout(cmd orb:0x%08x) ... ",
+           (u_int32_t)ocb->bus_addr);
 
        sdev->timeout ++;
        switch(sdev->timeout) {
@@ -2135,8 +2246,8 @@ sbp_action1(struct cam_sim *sim, union ccb *ccb)
                if (target->fwdev != NULL
                                && ccb->ccb_h.target_lun != CAM_LUN_WILDCARD
                                && ccb->ccb_h.target_lun < target->num_lun) {
-                       sdev = &target->luns[ccb->ccb_h.target_lun];
-                       if (sdev->status != SBP_DEV_ATTACHED &&
+                       sdev = target->luns[ccb->ccb_h.target_lun];
+                       if (sdev != NULL && sdev->status != SBP_DEV_ATTACHED &&
                                sdev->status != SBP_DEV_PROBE)
                                sdev = NULL;
                }
@@ -2203,7 +2314,7 @@ END_DEBUG
 
                csio = &ccb->csio;
 
-SBP_DEBUG(1)
+SBP_DEBUG(2)
                printf("%s:%d:%d XPT_SCSI_IO: "
                        "cmd: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x"
                        ", flags: 0x%02x, "
@@ -2242,8 +2353,11 @@ END_DEBUG
                        }
                }
 #endif
-               if ((ocb = sbp_get_ocb(sdev)) == NULL)
+               if ((ocb = sbp_get_ocb(sdev)) == NULL) {
+                       ccb->ccb_h.status = CAM_REQUEUE_REQ;
+                       xpt_done(ccb);
                        return;
+               }
 
                ocb->flags = OCB_ACT_CMD;
                ocb->sdev = sdev;
@@ -2269,9 +2383,7 @@ END_DEBUG
                        cdb = (void *)csio->cdb_io.cdb_ptr;
                else
                        cdb = (void *)&csio->cdb_io.cdb_bytes;
-               bcopy(cdb,
-                       (void *)(uintptr_t)(volatile void *)&ocb->orb[5],
-                               csio->cdb_len);
+               bcopy(cdb, (void *)&ocb->orb[5], csio->cdb_len);
 /*
 printf("ORB %08x %08x %08x %08x\n", ntohl(ocb->orb[0]), ntohl(ocb->orb[1]), ntohl(ocb->orb[2]), ntohl(ocb->orb[3]));
 printf("ORB %08x %08x %08x %08x\n", ntohl(ocb->orb[4]), ntohl(ocb->orb[5]), ntohl(ocb->orb[6]), ntohl(ocb->orb[7]));
@@ -2297,11 +2409,13 @@ printf("ORB %08x %08x %08x %08x\n", ntohl(ocb->orb[4]), ntohl(ocb->orb[5]), ntoh
        case XPT_CALC_GEOMETRY:
        {
                struct ccb_calc_geometry *ccg;
+#if __FreeBSD_version < 501100
                u_int32_t size_mb;
                u_int32_t secs_per_cylinder;
                int extended = 1;
-               ccg = &ccb->ccg;
+#endif
 
+               ccg = &ccb->ccg;
                if (ccg->block_size == 0) {
                        printf("sbp_action1: block_size is 0.\n");
                        ccb->ccb_h.status = CAM_REQ_INVALID;
@@ -2324,10 +2438,11 @@ SBP_DEBUG(1)
                                ccg->volume_size);
 END_DEBUG
 
+#if __FreeBSD_version < 501100
                size_mb = ccg->volume_size
                        / ((1024L * 1024L) / ccg->block_size);
 
-               if (size_mb >= 1024 && extended) {
+               if (size_mb > 1024 && extended) {
                        ccg->heads = 255;
                        ccg->secs_per_track = 63;
                } else {
@@ -2337,6 +2452,9 @@ END_DEBUG
                secs_per_cylinder = ccg->heads * ccg->secs_per_track;
                ccg->cylinders = ccg->volume_size / secs_per_cylinder;
                ccb->ccb_h.status = CAM_REQ_CMP;
+#else
+               cam_calc_geometry(ccg, /*extended*/1);
+#endif
                xpt_done(ccb);
                break;
        }
@@ -2364,7 +2482,7 @@ END_DEBUG
                cpi->version_num = 1; /* XXX??? */
                cpi->hba_inquiry = PI_TAG_ABLE;
                cpi->target_sprt = 0;
-               cpi->hba_misc = PIM_NOBUSRESET;
+               cpi->hba_misc = PIM_NOBUSRESET | PIM_NO_6_BYTE;
                cpi->hba_eng_cnt = 0;
                cpi->max_target = SBP_NUM_TARGETS - 1;
                cpi->max_lun = SBP_NUM_LUNS - 1;
@@ -2433,7 +2551,7 @@ sbp_execute_ocb(void *arg,  bus_dma_segment_t *segments, int seg, int error)
 
        ocb = (struct sbp_ocb *)arg;
 
-SBP_DEBUG(1)
+SBP_DEBUG(2)
        printf("sbp_execute_ocb: seg %d", seg);
        for (i = 0; i < seg; i++)
 #if __FreeBSD_version >= 500000
@@ -2481,16 +2599,26 @@ END_DEBUG
                        BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
        prev = sbp_enqueue_ocb(ocb->sdev, ocb);
        fwdma_sync(&ocb->sdev->dma, BUS_DMASYNC_PREWRITE);
-       if (prev == NULL)
+       if (prev == NULL || (ocb->sdev->flags & ORB_LINK_DEAD) != 0) {
+               ocb->sdev->flags &= ~ORB_LINK_DEAD;
                sbp_orb_pointer(ocb->sdev, ocb); 
+       }
 }
 
 static void
 sbp_poll(struct cam_sim *sim)
 {       
-       /* should call fwohci_intr? */
+       struct sbp_softc *sbp;
+       struct firewire_comm *fc;
+
+       sbp = (struct sbp_softc *)sim->softc;
+       fc = sbp->fd.fc;
+
+       fc->poll(fc, 0, -1);
+
        return;
 }
+
 static struct sbp_ocb *
 sbp_dequeue_ocb(struct sbp_dev *sdev, struct sbp_status *sbp_status)
 {
@@ -2499,20 +2627,18 @@ sbp_dequeue_ocb(struct sbp_dev *sdev, struct sbp_status *sbp_status)
        int s = splfw(), order = 0;
        int flags;
 
-       for (ocb = STAILQ_FIRST(&sdev->ocbs); ocb != NULL; ocb = next) {
-               next = STAILQ_NEXT(ocb, ocb);
-               flags = ocb->flags;
 SBP_DEBUG(1)
-               sbp_show_sdev_info(sdev, 2);
+       sbp_show_sdev_info(sdev, 2);
 #if __FreeBSD_version >= 500000
-               printf("orb: 0x%jx next: 0x%x, flags %x\n",
-                       (uintmax_t)ocb->bus_addr,
+       printf("%s: 0x%08x src %d\n",
 #else
-               printf("orb: 0x%x next: 0x%lx, flags %x\n",
-                       ocb->bus_addr,
+       printf("%s: 0x%08lx src %d\n",
 #endif
-                       ntohl(ocb->orb[1]), flags);
+           __FUNCTION__, ntohl(sbp_status->orb_lo), sbp_status->src);
 END_DEBUG
+       for (ocb = STAILQ_FIRST(&sdev->ocbs); ocb != NULL; ocb = next) {
+               next = STAILQ_NEXT(ocb, ocb);
+               flags = ocb->flags;
                if (OCB_MATCH(ocb, sbp_status)) {
                        /* found */
                        STAILQ_REMOVE(&sdev->ocbs, ocb, sbp_ocb, ocb);
@@ -2528,8 +2654,18 @@ END_DEBUG
                                bus_dmamap_unload(sdev->target->sbp->dmat,
                                        ocb->dmamap);
                        }
-                       if (next != NULL && sbp_status->src == 1)
-                               sbp_orb_pointer(sdev, next); 
+                       if (sbp_status->src == SRC_NO_NEXT) {
+                               if (next != NULL)
+                                       sbp_orb_pointer(sdev, next); 
+                               else if (order > 0) {
+                                       /*
+                                        * Unordered execution
+                                        * We need to send pointer for
+                                        * next ORB
+                                        */
+                                       sdev->flags |= ORB_LINK_DEAD;
+                               }
+                       }
                        break;
                } else
                        order ++;
@@ -2550,13 +2686,12 @@ sbp_enqueue_ocb(struct sbp_dev *sdev, struct sbp_ocb *ocb)
        int s = splfw();
        struct sbp_ocb *prev;
 
-SBP_DEBUG(2)
+SBP_DEBUG(1)
        sbp_show_sdev_info(sdev, 2);
 #if __FreeBSD_version >= 500000
-       printf("sbp_enqueue_ocb orb=0x%jx in physical memory\n", 
-               (uintmax_t)ocb->bus_addr);
+       printf("%s: 0x%08jx\n", __FUNCTION__, (uintmax_t)ocb->bus_addr);
 #else
-       printf("sbp_enqueue_ocb orb=0x%x in physical memory\n", ocb->bus_addr);
+       printf("%s: 0x%08x\n", __FUNCTION__, ocb->bus_addr);
 #endif
 END_DEBUG
        prev = STAILQ_LAST(&sdev->ocbs, sbp_ocb, ocb);
@@ -2566,13 +2701,14 @@ END_DEBUG
                ocb->ccb->ccb_h.timeout_ch = timeout(sbp_timeout, (caddr_t)ocb,
                                        (ocb->ccb->ccb_h.timeout * hz) / 1000);
 
-       if (prev != NULL ) {
-SBP_DEBUG(1)
+       if (prev != NULL) {
+SBP_DEBUG(2)
 #if __FreeBSD_version >= 500000
-       printf("linking chain 0x%jx -> 0x%jx\n",
-               (uintmax_t)prev->bus_addr, (uintmax_t)ocb->bus_addr);
+               printf("linking chain 0x%jx -> 0x%jx\n",
+                   (uintmax_t)prev->bus_addr, (uintmax_t)ocb->bus_addr);
 #else
-       printf("linking chain 0x%x -> 0x%x\n", prev->bus_addr, ocb->bus_addr);
+               printf("linking chain 0x%x -> 0x%x\n",
+                   prev->bus_addr, ocb->bus_addr);
 #endif
 END_DEBUG
                prev->orb[1] = htonl(ocb->bus_addr);
index 556924e..892799a 100644 (file)
@@ -31,8 +31,8 @@
  * 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.1.2.11 2003/04/28 03:29:18 simokawa Exp $
- * $DragonFly: src/sys/dev/netif/fwe/if_fwe.c,v 1.6 2004/01/06 01:40:47 dillon Exp $
+ * $FreeBSD: src/sys/dev/firewire/if_fwe.c,v 1.27 2004/01/08 14:58:09 simokawa Exp $
+ * $DragonFly: src/sys/dev/netif/fwe/if_fwe.c,v 1.7 2004/02/05 13:32:08 joerg Exp $
  */
 
 #include "opt_inet.h"
 #include <net/ethernet.h>
 #include <net/if.h>
 #include <net/if_arp.h>
+#ifdef __DragonFly__
 #include <net/vlan/if_vlan_var.h>
-#include <net/route.h>
-
-#include <netinet/in.h>
-
 #include <bus/firewire/firewire.h>
 #include <bus/firewire/firewirereg.h>
 #include "if_fwevar.h"
+#else
+#include <net/if_vlan_var.h>
+
+#include <dev/firewire/firewire.h>
+#include <dev/firewire/firewirereg.h>
+#include <dev/firewire/if_fwevar.h>
+#endif
 
-#define FWEDEBUG       if (fwedebug) printf
+#define FWEDEBUG       if (fwedebug) if_printf
 #define TX_MAX_QUEUE   (FWMAXQUEUE - 1)
-#define RX_MAX_QUEUE   FWMAXQUEUE
 
 /* network interface */
 static void fwe_start (struct ifnet *);
@@ -78,14 +81,24 @@ static void fwe_as_input (struct fw_xferq *);
 
 static int fwedebug = 0;
 static int stream_ch = 1;
+static int tx_speed = 2;
+static int rx_queue_len = FWMAXQUEUE;
 
 MALLOC_DEFINE(M_FWE, "if_fwe", "Ethernet over FireWire interface");
 SYSCTL_INT(_debug, OID_AUTO, if_fwe_debug, CTLFLAG_RW, &fwedebug, 0, "");
 SYSCTL_DECL(_hw_firewire);
 SYSCTL_NODE(_hw_firewire, OID_AUTO, fwe, CTLFLAG_RD, 0,
-       "Ethernet Emulation Subsystem");
+       "Ethernet emulation subsystem");
 SYSCTL_INT(_hw_firewire_fwe, OID_AUTO, stream_ch, CTLFLAG_RW, &stream_ch, 0,
        "Stream channel to use");
+SYSCTL_INT(_hw_firewire_fwe, OID_AUTO, tx_speed, CTLFLAG_RW, &tx_speed, 0,
+       "Transmission speed");
+SYSCTL_INT(_hw_firewire_fwe, OID_AUTO, rx_queue_len, CTLFLAG_RW, &rx_queue_len,
+       0, "Length of the receive queue");
+
+TUNABLE_INT("hw.firewire.fwe.stream_ch", &stream_ch);
+TUNABLE_INT("hw.firewire.fwe.tx_speed", &tx_speed);
+TUNABLE_INT("hw.firewire.fwe.rx_queue_len", &rx_queue_len);
 
 #ifdef DEVICE_POLLING
 #define FWE_POLL_REGISTER(func, fwe, ifp)                      \
@@ -125,7 +138,7 @@ fwe_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
 static void
 fwe_identify(driver_t *driver, device_t parent)
 {
-       BUS_ADD_CHILD(parent, 0, "if_fwe", device_get_unit(parent));
+       BUS_ADD_CHILD(parent, 0, "fwe", device_get_unit(parent));
 }
 
 static int
@@ -160,6 +173,9 @@ fwe_attach(device_t dev)
        fwe->dma_ch = -1;
 
        fwe->fd.fc = device_get_ivars(dev);
+       if (tx_speed < 0)
+               tx_speed = fwe->fd.fc->speed;
+
        fwe->fd.dev = dev;
        fwe->fd.post_explore = NULL;
        fwe->eth_softc.fwe = fwe;
@@ -188,7 +204,12 @@ fwe_attach(device_t dev)
        ifp = &fwe->fwe_if;
        ifp->if_softc = &fwe->eth_softc;
 
-       if_initname(ifp, "fwe", unit);
+#if __FreeBSD_version >= 501113 || defined(__DragonFly__)
+       if_initname(ifp, device_get_name(dev), unit);
+#else
+       ifp->if_unit = unit;
+       ifp->if_name = "fwe";
+#endif
        ifp->if_init = fwe_init;
        ifp->if_output = ether_output;
        ifp->if_start = fwe_start;
@@ -212,7 +233,7 @@ fwe_attach(device_t dev)
 #endif
 
 
-       FWEDEBUG("interface %s created.\n", ifp->if_xname);
+       FWEDEBUG(ifp, "interface created\n");
        return 0;
 }
 
@@ -288,7 +309,7 @@ fwe_init(void *arg)
        struct mbuf *m;
        int i;
 
-       FWEDEBUG("initializing %s\n", ifp->if_xname);
+       FWEDEBUG(ifp, "initializing\n");
 
        /* XXX keep promiscoud mode */
        ifp->if_flags |= IFF_PROMISC;
@@ -296,17 +317,14 @@ fwe_init(void *arg)
        fc = fwe->fd.fc;
 #define START 0
        if (fwe->dma_ch < 0) {
-               xferq = NULL;
                for (i = START; i < fc->nisodma; i ++) {
                        xferq = fc->ir[i];
                        if ((xferq->flag & FWXFERQ_OPEN) == 0)
-                               break;
-               }
-
-               if (xferq == NULL) {
-                       printf("no free dma channel\n");
-                       return;
+                               goto found;
                }
+               printf("no free dma channel\n");
+               return;
+found:
                fwe->dma_ch = i;
                fwe->stream_ch = stream_ch;
                fwe->pkt_hdr.mode.stream.chtag = fwe->stream_ch;
@@ -318,7 +336,7 @@ fwe_init(void *arg)
                /* register fwe_input handler */
                xferq->sc = (caddr_t) fwe;
                xferq->hand = fwe_as_input;
-               xferq->bnchunk = RX_MAX_QUEUE;
+               xferq->bnchunk = rx_queue_len;
                xferq->bnpacket = 1;
                xferq->psize = MCLBYTES;
                xferq->queued = 0;
@@ -354,7 +372,7 @@ fwe_init(void *arg)
                        xfer = fw_xfer_alloc(M_FWE);
                        if (xfer == NULL)
                                break;
-                       xfer->spd = 2;
+                       xfer->send.spd = tx_speed;
                        xfer->fc = fwe->fd.fc;
                        xfer->retry_req = fw_asybusy;
                        xfer->sc = (caddr_t)fwe;
@@ -446,12 +464,11 @@ fwe_output_callback(struct fw_xfer *xfer)
        fwe = (struct fwe_softc *)xfer->sc;
        ifp = &fwe->fwe_if;
        /* XXX error check */
-       FWEDEBUG("resp = %d\n", xfer->resp);
+       FWEDEBUG(ifp, "resp = %d\n", xfer->resp);
        if (xfer->resp != 0)
                ifp->if_oerrors ++;
                
        m_freem(xfer->mbuf);
-       xfer->send.buf = NULL;
        fw_xfer_unload(xfer);
 
        s = splimp();
@@ -469,12 +486,12 @@ fwe_start(struct ifnet *ifp)
        struct fwe_softc *fwe = ((struct fwe_eth_softc *)ifp->if_softc)->fwe;
        int s;
 
-       FWEDEBUG("%s starting\n", ifp->if_xname);
+       FWEDEBUG(ifp, "starting\n");
 
        if (fwe->dma_ch < 0) {
                struct mbuf     *m = NULL;
 
-               FWEDEBUG("%s not ready.\n", ifp->if_xname);
+               FWEDEBUG(ifp, "not ready\n");
 
                s = splimp();
                do {
@@ -533,12 +550,11 @@ fwe_as_output(struct fwe_softc *fwe, struct ifnet *ifp)
 
                /* keep ip packet alignment for alpha */
                M_PREPEND(m, ETHER_ALIGN, M_DONTWAIT);
-               fp = (struct fw_pkt *)&xfer->dst; /* XXX */
-               xfer->dst = *((int32_t *)&fwe->pkt_hdr);
+               fp = &xfer->send.hdr;
+               *(u_int32_t *)&xfer->send.hdr = *(int32_t *)&fwe->pkt_hdr;
                fp->mode.stream.len = m->m_pkthdr.len;
-               xfer->send.buf = (caddr_t) fp;
                xfer->mbuf = m;
-               xfer->send.len = m->m_pkthdr.len + HDR_LEN;
+               xfer->send.pay_len = m->m_pkthdr.len;
 
                if (fw_asyreq(fwe->fd.fc, -1, xfer) != 0) {
                        /* error */
@@ -579,15 +595,12 @@ fwe_as_input(struct fw_xferq *xferq)
 #endif
        while ((sxfer = STAILQ_FIRST(&xferq->stvalid)) != NULL) {
                STAILQ_REMOVE_HEAD(&xferq->stvalid, link);
-               if (sxfer->resp != 0)
-                       ifp->if_ierrors ++;
                fp = mtod(sxfer->mbuf, struct fw_pkt *);
-               /* XXX */
                if (fwe->fd.fc->irx_post != NULL)
                        fwe->fd.fc->irx_post(fwe->fd.fc, fp->mode.ld);
                m = sxfer->mbuf;
 
-               /* insert rbuf */
+               /* insert new rbuf */
                sxfer->mbuf = m0 = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
                if (m0 != NULL) {
                        m0->m_len = m0->m_pkthdr.len = m0->m_ext.ext_size;
@@ -595,6 +608,13 @@ fwe_as_input(struct fw_xferq *xferq)
                } else
                        printf("fwe_as_input: m_getcl failed\n");
 
+               if (sxfer->resp != 0 || fp->mode.stream.len <
+                   ETHER_ALIGN + sizeof(struct ether_header)) {
+                       m_freem(m);
+                       ifp->if_ierrors ++;
+                       continue;
+               }
+
                m->m_data += HDR_LEN + ETHER_ALIGN;
                c = mtod(m, char *);
 #if __FreeBSD_version < 500000
@@ -605,7 +625,7 @@ fwe_as_input(struct fw_xferq *xferq)
                                fp->mode.stream.len - ETHER_ALIGN;
                m->m_pkthdr.rcvif = ifp;
 #if 0
-               FWEDEBUG("%02x %02x %02x %02x %02x %02x\n"
+               FWEDEBUG(ifp, "%02x %02x %02x %02x %02x %02x\n"
                         "%02x %02x %02x %02x %02x %02x\n"
                         "%02x %02x %02x %02x\n"
                         "%02x %02x %02x %02x\n"
@@ -643,13 +663,13 @@ static device_method_t fwe_methods[] = {
 };
 
 static driver_t fwe_driver = {
-        "if_fwe",
+        "fwe",
        fwe_methods,
        sizeof(struct fwe_softc),
 };
 
 
-DECLARE_DUMMY_MODULE(if_fwe);
-DRIVER_MODULE(if_fwe, firewire, fwe_driver, fwe_devclass, 0, 0);
-MODULE_VERSION(if_fwe, 1);
-MODULE_DEPEND(if_fwe, firewire, 1, 1, 1);
+DECLARE_DUMMY_MODULE(fwe);
+DRIVER_MODULE(fwe, firewire, fwe_driver, fwe_devclass, 0, 0);
+MODULE_VERSION(fwe, 1);
+MODULE_DEPEND(fwe, firewire, 1, 1, 1);