From: Joerg Sonnenberger Date: Thu, 5 Feb 2004 13:32:08 +0000 (+0000) Subject: Sync DragonFly and FreeBSD-current's FireWire driver. X-Git-Tag: v2.0.1~12119 X-Git-Url: https://gitweb.dragonflybsd.org/dragonfly.git/commitdiff_plain/7874877152fec632be4dcd07e99f1e3db3186dee Sync DragonFly and FreeBSD-current's FireWire driver. Patch submitted by Hidetoshi Shimokawa Modified to leave the sbp hack inplace. --- diff --git a/sys/bus/firewire/firewire.c b/sys/bus/firewire/firewire.c index e36dc52fd6..f90b741c0c 100644 --- a/sys/bus/firewire/firewire.c +++ b/sys/bus/firewire/firewire.c @@ -31,53 +31,69 @@ * 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 #include #include -#include -#include -#include #include #include #include #include -#include /* for rdtsc proto for clock.h below */ -#include +#if __FreeBSD_version < 500000 +#include /* for DELAY() */ +#endif #include /* used by smbus and newbus */ #include +#ifdef __DragonFly__ #include "firewire.h" #include "firewirereg.h" #include "fwmem.h" #include "iec13213.h" #include "iec68113.h" +#else +#include +#include +#include +#include +#include +#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_free( xfer); + 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); diff --git a/sys/bus/firewire/firewire.h b/sys/bus/firewire/firewire.h index becf94b8bb..4e856f8c49 100644 --- a/sys/bus/firewire/firewire.h +++ b/sys/bus/firewire/firewire.h @@ -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) diff --git a/sys/bus/firewire/firewire_phy.h b/sys/bus/firewire/firewire_phy.h index 21307fbf40..fca3f713e3 100644 --- a/sys/bus/firewire/firewire_phy.h +++ b/sys/bus/firewire/firewire_phy.h @@ -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 $ * */ diff --git a/sys/bus/firewire/firewirereg.h b/sys/bus/firewire/firewirereg.h index bd1cc49edb..237f73d89d 100644 --- a/sys/bus/firewire/firewirereg.h +++ b/sys/bus/firewire/firewirereg.h @@ -31,19 +31,20 @@ * 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 #else -typedef struct thread fw_proc; -#include +typedef struct proc fw_proc; #endif +#include #include #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); diff --git a/sys/bus/firewire/fwcrom.c b/sys/bus/firewire/fwcrom.c index 72a501d4ae..6389517322 100644 --- a/sys/bus/firewire/fwcrom.c +++ b/sys/bus/firewire/fwcrom.c @@ -1,4 +1,4 @@ -/* +/*- * Copyright (c) 2002-2003 * Hidetoshi Shimokawa. All rights reserved. * @@ -31,10 +31,14 @@ * 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 +__FBSDID("$FreeBSD: src/sys/dev/firewire/fwcrom.c,v 1.9 2003/10/02 04:06:55 simokawa Exp $"); +#endif + #include #if defined(_KERNEL) || defined(TEST) #include @@ -50,8 +54,17 @@ #include #include #endif + +#ifdef __DragonFly__ #include "firewire.h" #include "iec13213.h" +#else +#include +#include +#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 ++) { diff --git a/sys/bus/firewire/fwdev.c b/sys/bus/firewire/fwdev.c index 658307c3e4..95cad9eef0 100644 --- a/sys/bus/firewire/fwdev.c +++ b/sys/bus/firewire/fwdev.c @@ -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 $ * */ @@ -40,23 +40,36 @@ #include #include #include +#if __FreeBSD_version < 500000 +#include +#else +#include +#endif #include #include #include -#include #include #include +#include #include #include +#ifdef __DragonFly__ #include "firewire.h" #include "firewirereg.h" #include "fwdma.h" #include "fwmem.h" #include "iec68113.h" +#else +#include +#include +#include +#include +#include +#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 diff --git a/sys/bus/firewire/fwdma.c b/sys/bus/firewire/fwdma.c index af61f35918..2512c6aac7 100644 --- a/sys/bus/firewire/fwdma.c +++ b/sys/bus/firewire/fwdma.c @@ -31,21 +31,37 @@ * 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 +__FBSDID("$FreeBSD: src/sys/dev/firewire/fwdma.c,v 1.5 2003/08/24 17:46:07 obrien Exp $"); +#endif + #include #include +#include #include #include #include +#if __FreeBSD_version >= 501102 +#include +#include +#endif #include #include -#include "firewire.h" -#include "firewirereg.h" -#include "fwdma.h" +#ifdef __DragonFly__ +#include +#include +#include +#else +#include +#include +#include +#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); diff --git a/sys/bus/firewire/fwdma.h b/sys/bus/firewire/fwdma.h index 563829f376..b8b2ec4d7d 100644 --- a/sys/bus/firewire/fwdma.h +++ b/sys/bus/firewire/fwdma.h @@ -31,14 +31,10 @@ * 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; diff --git a/sys/bus/firewire/fwmem.c b/sys/bus/firewire/fwmem.c index e2dcec26da..c95b35890e 100644 --- a/sys/bus/firewire/fwmem.c +++ b/sys/bus/firewire/fwmem.c @@ -31,10 +31,14 @@ * 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 +__FBSDID("$FreeBSD: src/sys/dev/firewire/fwmem.c,v 1.26 2004/01/05 14:21:18 simokawa Exp $"); +#endif + #include #include #include @@ -43,6 +47,11 @@ #include #include #include +#if __FreeBSD_version < 500000 +#include +#else +#include +#endif #include #include @@ -50,10 +59,17 @@ #include #include #include +#include +#ifdef __DragonFly__ #include "firewire.h" #include "firewirereg.h" #include "fwmem.h" +#else +#include +#include +#include +#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; diff --git a/sys/bus/firewire/fwmem.h b/sys/bus/firewire/fwmem.h index b305be2807..c26d3ba6cb 100644 --- a/sys/bus/firewire/fwmem.h +++ b/sys/bus/firewire/fwmem.h @@ -31,18 +31,18 @@ * 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; diff --git a/sys/bus/firewire/fwohci.c b/sys/bus/firewire/fwohci.c index 6705717bfb..4188577686 100644 --- a/sys/bus/firewire/fwohci.c +++ b/sys/bus/firewire/fwohci.c @@ -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 @@ -44,14 +44,8 @@ #define IRX_CH 0x24 #include -#include #include -#include #include -#include -#include -#include -#include #include #include #include @@ -60,22 +54,26 @@ #include #include -#include -#include -#include /* for rdtsc proto for clock.h below */ -#include -#include -#include +#if __FreeBSD_version < 500000 +#include /* 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 +#include +#include +#include +#include +#include +#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"); diff --git a/sys/bus/firewire/fwohci_pci.c b/sys/bus/firewire/fwohci_pci.c index 643efc6d10..16a8096001 100644 --- a/sys/bus/firewire/fwohci_pci.c +++ b/sys/bus/firewire/fwohci_pci.c @@ -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 @@ -41,13 +41,23 @@ #include #include #include +#include #include #include #include #include #include +#if __FreeBSD_version >= 501102 +#include +#include +#endif #include +#if __FreeBSD_version < 500000 +#include /* for DELAY() */ +#endif + +#ifdef __DragonFly__ #include #include @@ -57,6 +67,22 @@ #include "fwdma.h" #include "fwohcireg.h" #include "fwohcivar.h" +#else +#if __FreeBSD_version < 500000 +#include +#include +#else +#include +#include +#endif + +#include +#include + +#include +#include +#include +#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); diff --git a/sys/bus/firewire/fwohcireg.h b/sys/bus/firewire/fwohcireg.h index 1fed943b47..33f1cd0b1e 100644 --- a/sys/bus/firewire/fwohcireg.h +++ b/sys/bus/firewire/fwohcireg.h @@ -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 { diff --git a/sys/bus/firewire/fwohcivar.h b/sys/bus/firewire/fwohcivar.h index bea9a252b2..6a6eaae680 100644 --- a/sys/bus/firewire/fwohcivar.h +++ b/sys/bus/firewire/fwohcivar.h @@ -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); diff --git a/sys/bus/firewire/iec13213.h b/sys/bus/firewire/iec13213.h index 90e2f58d5a..90553e937c 100644 --- a/sys/bus/firewire/iec13213.h +++ b/sys/bus/firewire/iec13213.h @@ -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 @@ -64,6 +63,12 @@ #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 */ @@ -99,6 +104,7 @@ #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; }; diff --git a/sys/bus/firewire/iec68113.h b/sys/bus/firewire/iec68113.h index 4d5b5a9235..7b2af226cd 100644 --- a/sys/bus/firewire/iec68113.h +++ b/sys/bus/firewire/iec68113.h @@ -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 $ * */ diff --git a/sys/dev/disk/sbp/Makefile b/sys/dev/disk/sbp/Makefile index 9de2d03b4e..f6ef3aabdc 100644 --- a/sys/dev/disk/sbp/Makefile +++ b/sys/dev/disk/sbp/Makefile @@ -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 diff --git a/sys/dev/disk/sbp/sbp.c b/sys/dev/disk/sbp/sbp.c index 13d39cb1d8..ff1a15a48d 100644 --- a/sys/dev/disk/sbp/sbp.c +++ b/sys/dev/disk/sbp/sbp.c @@ -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 @@ -31,56 +31,67 @@ * 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 #include +#include #include #include -#include +#include #include #include #include +#if __FreeBSD_version >= 501102 +#include +#include +#endif #if __FreeBSD_version < 500106 #include /* for struct devstat */ #endif +#ifdef __DragonFly__ #include #include #include #include #include #include - #include -#include -#include - -#include #include #include #include #include +#include "sbp.h" +#else +#include +#include +#include +#include +#include +#include +#include +#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 @@ -88,71 +99,30 @@ * 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); diff --git a/sys/dev/netif/fwe/if_fwe.c b/sys/dev/netif/fwe/if_fwe.c index 556924e31f..892799a3ee 100644 --- a/sys/dev/netif/fwe/if_fwe.c +++ b/sys/dev/netif/fwe/if_fwe.c @@ -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" @@ -54,18 +54,21 @@ #include #include #include +#ifdef __DragonFly__ #include -#include - -#include - #include #include #include "if_fwevar.h" +#else +#include + +#include +#include +#include +#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);