Index: head/sys/dev/firewire/firewire.c =================================================================== --- head/sys/dev/firewire/firewire.c (revision 113583) +++ head/sys/dev/firewire/firewire.c (revision 113584) @@ -1,2152 +1,2149 @@ /* + * 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 * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the acknowledgement as bellow: * * This product includes software developed by K. Kobayashi and H. Shimokawa * * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ * */ #include #include #include #include #include #include #include #include #include -#include #include #include /* for rdtsc proto for clock.h below */ #include #include /* used by smbus and newbus */ +#include #include #include #include #include #include int firewire_debug=0, try_bmr=1; 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"); MALLOC_DEFINE(M_FW, "firewire", "FireWire"); MALLOC_DEFINE(M_FWXFER, "fw_xfer", "XFER/FireWire"); #define FW_MAXASYRTY 4 #define FW_MAXDEVRCNT 4 -#define XFER_TIMEOUT 0 - devclass_t firewire_devclass; static int firewire_match __P((device_t)); static int firewire_attach __P((device_t)); static int firewire_detach __P((device_t)); #if 0 static int firewire_shutdown __P((device_t)); #endif static device_t firewire_add_child __P((device_t, int, const char *, int)); static void fw_try_bmr __P((void *)); static void fw_try_bmr_callback __P((struct fw_xfer *)); static void fw_asystart __P((struct fw_xfer *)); static int fw_get_tlabel __P((struct firewire_comm *, struct fw_xfer *)); static void fw_bus_probe __P((struct firewire_comm *)); static void fw_bus_explore __P((struct firewire_comm *)); static void fw_bus_explore_callback __P((struct fw_xfer *)); static void fw_attach_dev __P((struct firewire_comm *)); #ifdef FW_VMACCESS static void fw_vmaccess __P((struct fw_xfer *)); #endif struct fw_xfer *asyreqq __P((struct firewire_comm *, u_int8_t, u_int8_t, u_int8_t, u_int32_t, u_int32_t, void (*)__P((struct fw_xfer *)))); static int fw_bmr __P((struct firewire_comm *)); static device_method_t firewire_methods[] = { /* Device interface */ DEVMETHOD(device_probe, firewire_match), DEVMETHOD(device_attach, firewire_attach), DEVMETHOD(device_detach, firewire_detach), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), DEVMETHOD(device_shutdown, bus_generic_shutdown), /* Bus interface */ DEVMETHOD(bus_add_child, firewire_add_child), DEVMETHOD(bus_print_child, bus_generic_print_child), { 0, 0 } }; char linkspeed[7][0x10]={"S100","S200","S400","S800","S1600","S3200","Unknown"}; #define MAX_GAPHOP 16 u_int gap_cnt[] = {1, 1, 4, 6, 9, 12, 14, 17, 20, 23, 25, 28, 31, 33, 36, 39, 42}; extern struct cdevsw firewire_cdevsw; static driver_t firewire_driver = { "firewire", firewire_methods, sizeof(struct firewire_softc), }; /* * Lookup fwdev by node id. */ struct fw_device * fw_noderesolve_nodeid(struct firewire_comm *fc, int dst) { struct fw_device *fwdev; int s; s = splfw(); STAILQ_FOREACH(fwdev, &fc->devices, link) if (fwdev->dst == dst) break; splx(s); if(fwdev == NULL) return NULL; if(fwdev->status == FWDEVINVAL) return NULL; return fwdev; } /* * Lookup fwdev by EUI64. */ struct fw_device * fw_noderesolve_eui64(struct firewire_comm *fc, struct fw_eui64 *eui) { struct fw_device *fwdev; int s; s = splfw(); STAILQ_FOREACH(fwdev, &fc->devices, link) if (FW_EUI64_EQUAL(fwdev->eui, *eui)) break; splx(s); if(fwdev == NULL) return NULL; if(fwdev->status == FWDEVINVAL) return NULL; return fwdev; } /* * Async. request procedure for userland application. */ int fw_asyreq(struct firewire_comm *fc, int sub, struct fw_xfer *xfer) { int err = 0; struct fw_xferq *xferq; int tl = 0, len; struct fw_pkt *fp; int tcode; 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; tcode = fp->mode.common.tcode & 0xf; info = &fc->tcode[tcode]; if (info->flag == 0) { printf("invalid tcode=%d\n", tcode); return EINVAL; } if (info->flag & FWTI_REQ) xferq = fc->atq; else xferq = fc->ats; len = info->hdr_len; if (info->flag & FWTI_BLOCK_STR) - len += ntohs(fp->mode.stream.len); + len += fp->mode.stream.len; else if (info->flag & FWTI_BLOCK_ASY) - len += ntohs(fp->mode.rresb.len); + len += fp->mode.rresb.len; if( len > xfer->send.len ){ printf("len(%d) > send.len(%d) (tcode=%d)\n", len, xfer->send.len, tcode); return EINVAL; } xfer->send.len = len; if(xferq->start == NULL){ printf("xferq->start == NULL\n"); return EINVAL; } if(!(xferq->queued < xferq->maxq)){ device_printf(fc->bdev, "Discard a packet (queued=%d)\n", xferq->queued); return EINVAL; } if (info->flag & FWTI_TLABEL) { if((tl = fw_get_tlabel(fc, xfer)) == -1 ) return EIO; fp->mode.hdr.tlrt = tl << 2; } xfer->tl = tl; - xfer->tcode = tcode; xfer->resp = 0; xfer->fc = fc; xfer->q = xferq; - xfer->act_type = FWACT_XFER; xfer->retry_req = fw_asybusy; fw_asystart(xfer); return err; } /* * Wakeup blocked process. */ void fw_asy_callback(struct fw_xfer *xfer){ wakeup(xfer); return; } /* * Postpone to later retry. */ void fw_asybusy(struct fw_xfer *xfer){ -#if 1 printf("fw_asybusy\n"); -#endif -#if XFER_TIMEOUT - untimeout(fw_xfer_timeout, (void *)xfer, xfer->ch); -#endif /* xfer->ch = timeout((timeout_t *)fw_asystart, (void *)xfer, 20000); */ DELAY(20000); fw_asystart(xfer); return; } -#if XFER_TIMEOUT -/* - * Post timeout for async. request. - */ -void -fw_xfer_timeout(void *arg) -{ - int s; - struct fw_xfer *xfer; - xfer = (struct fw_xfer *)arg; - printf("fw_xfer_timeout status=%d resp=%d\n", xfer->state, xfer->resp); - /* XXX set error code */ - s = splfw(); - xfer->act.hand(xfer); - splx(s); -} -#endif /* * Async. request with given xfer structure. */ static void fw_asystart(struct fw_xfer *xfer) { struct firewire_comm *fc = xfer->fc; int s; if(xfer->retry++ >= fc->max_asyretry){ + device_printf(fc->bdev, "max_asyretry exceeded\n"); xfer->resp = EBUSY; xfer->state = FWXF_BUSY; xfer->act.hand(xfer); return; } #if 0 /* XXX allow bus explore packets only after bus rest */ if (fc->status < FWBUSEXPLORE) { xfer->resp = EAGAIN; xfer->state = FWXF_BUSY; if (xfer->act.hand != NULL) xfer->act.hand(xfer); return; } #endif s = splfw(); xfer->state = FWXF_INQ; STAILQ_INSERT_TAIL(&xfer->q->q, xfer, link); xfer->q->queued ++; splx(s); /* XXX just queue for mbuf */ if (xfer->mbuf == NULL) xfer->q->start(fc); -#if XFER_TIMEOUT - if (xfer->act.hand != NULL) - xfer->ch = timeout(fw_xfer_timeout, (void *)xfer, hz); -#endif return; } static int firewire_match( device_t dev ) { device_set_desc(dev, "IEEE1394(FireWire) bus"); return -140; } static void firewire_xfer_timeout(struct firewire_comm *fc) { struct fw_xfer *xfer; struct tlabel *tl; struct timeval tv; struct timeval split_timeout; int i, s; split_timeout.tv_sec = 6; split_timeout.tv_usec = 0; microtime(&tv); timevalsub(&tv, &split_timeout); s = splfw(); for (i = 0; i < 0x40; i ++) { while ((tl = STAILQ_FIRST(&fc->tlabels[i])) != NULL) { xfer = tl->xfer; if (timevalcmp(&xfer->tv, &tv, >)) /* the rests are newer than this */ break; device_printf(fc->bdev, "split transaction timeout dst=0x%x tl=0x%x\n", xfer->dst, i); xfer->resp = ETIMEDOUT; STAILQ_REMOVE_HEAD(&fc->tlabels[i], link); - switch (xfer->act_type) { - case FWACT_XFER: - fw_xfer_done(xfer); - break; - default: - /* ??? */ - fw_xfer_free(xfer); - break; - } + fw_xfer_done(xfer); } } splx(s); } static void firewire_watchdog(void *arg) { struct firewire_comm *fc; fc = (struct firewire_comm *)arg; firewire_xfer_timeout(fc); fc->timeout(fc); callout_reset(&fc->timeout_callout, hz, (void *)firewire_watchdog, (void *)fc); } /* * The attach routine. */ static int firewire_attach( device_t dev ) { int i, unitmask, mn; 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)); 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 CALLOUT_INIT(&sc->fc->timeout_callout); CALLOUT_INIT(&sc->fc->bmr_callout); CALLOUT_INIT(&sc->fc->retry_probe_callout); CALLOUT_INIT(&sc->fc->busprobe_callout); callout_reset(&sc->fc->timeout_callout, hz, (void *)firewire_watchdog, (void *)sc->fc); /* Locate our children */ bus_generic_probe(dev); /* launch attachement of the added children */ bus_generic_attach(dev); -#if 1 /* bus_reset */ fc->ibr(fc); -#endif return 0; } /* * Attach it as child. */ static device_t firewire_add_child(device_t dev, int order, const char *name, int unit) { device_t child; struct firewire_softc *sc; sc = (struct firewire_softc *)device_get_softc(dev); child = device_add_child(dev, name, unit); if (child) { device_set_ivars(child, sc->fc); device_probe_and_attach(child); } return child; } /* * Dettach it. */ static int firewire_detach( device_t dev ) { struct firewire_softc *sc; struct csrdir *csrd, *next; struct fw_device *fwdev, *fwdev_next; sc = (struct firewire_softc *)device_get_softc(dev); bus_generic_detach(dev); 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) { fwdev_next = STAILQ_NEXT(fwdev, link); free(fwdev, M_FW); } for (csrd = SLIST_FIRST(&sc->fc->csrfree); csrd != NULL; csrd = next) { next = SLIST_NEXT(csrd, link); free(csrd, M_FW); } free(sc->fc->topology_map, M_FW); free(sc->fc->speed_map, M_FW); return(0); } #if 0 static int firewire_shutdown( device_t dev ) { return 0; } #endif static void fw_xferq_drain(struct fw_xferq *xferq) { struct fw_xfer *xfer; while ((xfer = STAILQ_FIRST(&xferq->q)) != NULL) { STAILQ_REMOVE_HEAD(&xferq->q, link); xferq->queued --; xfer->resp = EAGAIN; - switch (xfer->act_type) { - case FWACT_XFER: - fw_xfer_done(xfer); - break; - default: - /* ??? */ - fw_xfer_free(xfer); - break; - } + fw_xfer_done(xfer); } } void fw_drain_txq(struct firewire_comm *fc) { int i; fw_xferq_drain(fc->atq); fw_xferq_drain(fc->ats); for(i = 0; i < fc->nisodma; i++) fw_xferq_drain(fc->it[i]); } /* * Called after bus reset. */ void fw_busreset(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); CSRARC(fc, NODE_IDS) = 0x3f; CSRARC(fc, TOPO_MAP + 8) = 0; fc->irm = -1; fc->max_node = -1; for(i = 2; i < 0x100/4 - 2 ; i++){ CSRARC(fc, SPED_MAP + i * 4) = 0; } CSRARC(fc, STATE_CLEAR) = 1 << 23 | 0 << 17 | 1 << 16 | 1 << 15 | 1 << 14 ; CSRARC(fc, STATE_SET) = CSRARC(fc, STATE_CLEAR); CSRARC(fc, RESET_START) = 0; CSRARC(fc, SPLIT_TIMEOUT_HI) = 0; CSRARC(fc, SPLIT_TIMEOUT_LO) = 800 << 19; CSRARC(fc, CYCLE_TIME) = 0x0; CSRARC(fc, BUS_TIME) = 0x0; CSRARC(fc, BUS_MGR_ID) = 0x3f; CSRARC(fc, BANDWIDTH_AV) = 4915; CSRARC(fc, CHANNELS_AV_HI) = 0xffffffff; CSRARC(fc, CHANNELS_AV_LO) = 0xffffffff; CSRARC(fc, IP_CHANNELS) = (1 << 31); CSRARC(fc, CONF_ROM) = 0x04 << 24; CSRARC(fc, CONF_ROM + 4) = 0x31333934; /* means strings 1394 */ CSRARC(fc, CONF_ROM + 8) = 1 << 31 | 1 << 30 | 1 << 29 | 1 << 28 | 0xff << 16 | 0x09 << 8; CSRARC(fc, CONF_ROM + 0xc) = 0; /* DV depend CSRs see blue book */ CSRARC(fc, oPCR) &= ~DV_BROADCAST_ON; CSRARC(fc, iPCR) &= ~DV_BROADCAST_ON; CSRARC(fc, STATE_CLEAR) &= ~(1 << 23 | 1 << 15 | 1 << 14 ); CSRARC(fc, STATE_SET) = CSRARC(fc, STATE_CLEAR); + + if (device_get_children(fc->bdev, &devlistp, &devcnt) == 0) { + for( i = 0 ; i < devcnt ; i++) + if (device_get_state(devlistp[i]) >= DS_ATTACHED) { + fdc = device_get_softc(devlistp[i]); + if (fdc->post_busreset != NULL) + fdc->post_busreset(fdc); + } + free(devlistp, M_TEMP); + } } /* Call once after reboot */ void fw_init(struct firewire_comm *fc) { int i; struct csrdir *csrd; #ifdef FW_VMACCESS struct fw_xfer *xfer; struct fw_bind *fwb; #endif fc->max_asyretry = FW_MAXASYRTY; fc->arq->queued = 0; fc->ars->queued = 0; fc->atq->queued = 0; fc->ats->queued = 0; - fc->arq->psize = PAGE_SIZE; - fc->ars->psize = PAGE_SIZE; - fc->atq->psize = 0; - fc->ats->psize = 0; - - fc->arq->buf = NULL; fc->ars->buf = NULL; fc->atq->buf = NULL; fc->ats->buf = NULL; - fc->arq->flag = FWXFERQ_PACKET; - fc->ars->flag = FWXFERQ_PACKET; - fc->atq->flag = FWXFERQ_PACKET; - fc->ats->flag = FWXFERQ_PACKET; + fc->arq->flag = 0; + fc->ars->flag = 0; + fc->atq->flag = 0; + fc->ats->flag = 0; STAILQ_INIT(&fc->atq->q); STAILQ_INIT(&fc->ats->q); for( i = 0 ; i < fc->nisodma ; i ++ ){ fc->it[i]->queued = 0; fc->ir[i]->queued = 0; fc->it[i]->start = NULL; fc->ir[i]->start = NULL; fc->it[i]->buf = NULL; fc->ir[i]->buf = NULL; fc->it[i]->flag = FWXFERQ_STREAM; fc->ir[i]->flag = FWXFERQ_STREAM; STAILQ_INIT(&fc->it[i]->q); STAILQ_INIT(&fc->ir[i]->q); STAILQ_INIT(&fc->it[i]->binds); STAILQ_INIT(&fc->ir[i]->binds); } fc->arq->maxq = FWMAXQUEUE; fc->ars->maxq = FWMAXQUEUE; fc->atq->maxq = FWMAXQUEUE; fc->ats->maxq = FWMAXQUEUE; for( i = 0 ; i < fc->nisodma ; i++){ fc->ir[i]->maxq = FWMAXQUEUE; fc->it[i]->maxq = FWMAXQUEUE; } /* Initialize csr registers */ fc->topology_map = (struct fw_topology_map *)malloc( sizeof(struct fw_topology_map), M_FW, M_NOWAIT | M_ZERO); fc->speed_map = (struct fw_speed_map *)malloc( sizeof(struct fw_speed_map), M_FW, M_NOWAIT | M_ZERO); CSRARC(fc, TOPO_MAP) = 0x3f1 << 16; CSRARC(fc, TOPO_MAP + 4) = 1; CSRARC(fc, SPED_MAP) = 0x3f1 << 16; CSRARC(fc, SPED_MAP + 4) = 1; STAILQ_INIT(&fc->devices); STAILQ_INIT(&fc->pending); /* Initialize csr ROM work space */ SLIST_INIT(&fc->ongocsr); SLIST_INIT(&fc->csrfree); for( i = 0 ; i < FWMAXCSRDIR ; i++){ csrd = (struct csrdir *) malloc(sizeof(struct csrdir), M_FW,M_NOWAIT); if(csrd == NULL) break; SLIST_INSERT_HEAD(&fc->csrfree, csrd, link); } /* Initialize Async handlers */ STAILQ_INIT(&fc->binds); for( i = 0 ; i < 0x40 ; i++){ STAILQ_INIT(&fc->tlabels[i]); } /* DV depend CSRs see blue book */ #if 0 CSRARC(fc, oMPR) = 0x3fff0001; /* # output channel = 1 */ CSRARC(fc, oPCR) = 0x8000007a; for(i = 4 ; i < 0x7c/4 ; i+=4){ CSRARC(fc, i + oPCR) = 0x8000007a; } CSRARC(fc, iMPR) = 0x00ff0001; /* # input channel = 1 */ CSRARC(fc, iPCR) = 0x803f0000; for(i = 4 ; i < 0x7c/4 ; i+=4){ CSRARC(fc, i + iPCR) = 0x0; } #endif #ifdef FW_VMACCESS xfer = fw_xfer_alloc(); if(xfer == NULL) return; fwb = (struct fw_bind *)malloc(sizeof (struct fw_bind), M_FW, M_NOWAIT); if(fwb == NULL){ fw_xfer_free(xfer); } xfer->act.hand = fw_vmaccess; - xfer->act_type = FWACT_XFER; xfer->fc = fc; xfer->sc = NULL; fwb->start_hi = 0x2; fwb->start_lo = 0; fwb->addrlen = 0xffffffff; fwb->xfer = xfer; fw_bindadd(fc, fwb); #endif } /* * 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) { struct fw_bind *tfw; for(tfw = STAILQ_FIRST(&fc->binds) ; tfw != NULL ; tfw = STAILQ_NEXT(tfw, fclist)){ - if(tfw->xfer->act_type != FWACT_NULL && + if (tfw->act_type != FWACT_NULL && tfw->start_hi == dest_hi && tfw->start_lo <= dest_lo && (tfw->start_lo + tfw->addrlen) > dest_lo){ return(tfw); } } return(NULL); } /* * To bind IEEE1394 address block to process. */ 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; } if((tfw->start_hi > fwb->start_hi) || (tfw->start_hi == fwb->start_hi && (tfw->start_lo > (fwb->start_lo + fwb->addrlen)))){ 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); } out: - if(!err && fwb->xfer->act_type == FWACT_CH){ - STAILQ_INSERT_HEAD(&fc->ir[fwb->xfer->sub]->binds, fwb, chlist); - } + if (!err && fwb->act_type == FWACT_CH) + STAILQ_INSERT_HEAD(&fc->ir[fwb->sub]->binds, fwb, chlist); return err; } /* * To free IEEE1394 address block. */ int fw_bindremove(struct firewire_comm *fc, struct fw_bind *fwb) { int s; + struct fw_xfer *xfer, *next; s = splfw(); /* shall we check the existance? */ STAILQ_REMOVE(&fc->binds, fwb, fw_bind, fclist); - splx(s); - if (fwb->xfer) - fw_xfer_free(fwb->xfer); + /* 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); + splx(s); return 0; } /* * To free transaction label. */ static void fw_tl_free(struct firewire_comm *fc, struct fw_xfer *xfer) { struct tlabel *tl; int s = splfw(); for( tl = STAILQ_FIRST(&fc->tlabels[xfer->tl]); tl != NULL; tl = STAILQ_NEXT(tl, link)){ if(tl->xfer == xfer){ STAILQ_REMOVE(&fc->tlabels[xfer->tl], tl, tlabel, link); free(tl, M_FW); splx(s); return; } } splx(s); return; } /* * To obtain XFER structure by transaction label. */ static struct fw_xfer * fw_tl2xfer(struct firewire_comm *fc, int node, int tlabel) { struct fw_xfer *xfer; struct tlabel *tl; int s = splfw(); for( tl = STAILQ_FIRST(&fc->tlabels[tlabel]); tl != NULL; tl = STAILQ_NEXT(tl, link)){ if(tl->xfer->dst == node){ xfer = tl->xfer; splx(s); if (firewire_debug > 2) printf("fw_tl2xfer: found tl=%d\n", tlabel); return(xfer); } } if (firewire_debug > 1) printf("fw_tl2xfer: not found tl=%d\n", tlabel); splx(s); return(NULL); } /* * To allocate IEEE1394 XFER structure. */ struct fw_xfer * fw_xfer_alloc(struct malloc_type *type) { struct fw_xfer *xfer; xfer = malloc(sizeof(struct fw_xfer), type, M_NOWAIT | M_ZERO); if (xfer == NULL) return xfer; microtime(&xfer->tv); - xfer->sub = -1; xfer->malloc = type; return xfer; } +struct fw_xfer * +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; + if (xfer == NULL) + return(NULL); + if (send_len) { + xfer->send.buf = malloc(send_len, type, M_NOWAIT | M_ZERO); + if (xfer->send.buf == 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); + fw_xfer_free(xfer); + return(NULL); + } + } + return(xfer); +} + /* * IEEE1394 XFER post process. */ void fw_xfer_done(struct fw_xfer *xfer) { if (xfer->act.hand == NULL) return; -#if XFER_TIMEOUT - untimeout(fw_xfer_timeout, (void *)xfer, xfer->ch); -#endif - 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?"); } } -/* - * To free IEEE1394 XFER structure. - */ void -fw_xfer_free( struct fw_xfer* xfer) +fw_xfer_unload(struct fw_xfer* xfer) { int s; + if(xfer == NULL ) return; if(xfer->state == FWXF_INQ){ printf("fw_xfer_free FWXF_INQ\n"); s = splfw(); STAILQ_REMOVE(&xfer->q->q, xfer, fw_xfer, link); xfer->q->queued --; splx(s); } - if(xfer->fc != NULL){ - if(xfer->state == FWXF_START){ -#if 0 /* this could happen if we call fwohci_arcv() before fwohci_txd() */ - printf("fw_xfer_free FWXF_START\n"); + if (xfer->fc != NULL) { +#if 1 /* this could happen if we call fwohci_arcv() before fwohci_txd() */ + if(xfer->state == FWXF_START) + panic("fw_xfer_free FWXF_START\n"); #endif - s = splfw(); - xfer->q->drain(xfer->fc, xfer); - splx(s); - } + fw_tl_free(xfer->fc, xfer); } + xfer->state = FWXF_INIT; + xfer->resp = 0; + xfer->retry = 0; +} +/* + * To free IEEE1394 XFER structure. + */ +void +fw_xfer_free( struct fw_xfer* xfer) +{ + if(xfer == NULL ) return; + fw_xfer_unload(xfer); if(xfer->send.buf != NULL){ - free(xfer->send.buf, M_FW); + free(xfer->send.buf, xfer->malloc); } if(xfer->recv.buf != NULL){ - free(xfer->recv.buf, M_FW); + free(xfer->recv.buf, xfer->malloc); } - if(xfer->fc != NULL){ - fw_tl_free(xfer->fc, xfer); - } free(xfer, xfer->malloc); } static void fw_asy_callback_free(struct fw_xfer *xfer) { #if 0 printf("asyreq done state=%d resp=%d\n", xfer->state, xfer->resp); #endif fw_xfer_free(xfer); } /* * To configure PHY. */ static void fw_phy_config(struct firewire_comm *fc, int root_node, int gap_count) { struct fw_xfer *xfer; struct fw_pkt *fp; fc->status = FWBUSPHYCONF; -#if 0 - DELAY(100000); -#endif - xfer = fw_xfer_alloc(M_FWXFER); - xfer->send.len = 12; - xfer->send.off = 0; + xfer = fw_xfer_alloc_buf(M_FWXFER, 12, 0); + if (xfer == NULL) + return; xfer->fc = fc; xfer->retry_req = fw_asybusy; xfer->act.hand = fw_asy_callback_free; - xfer->send.buf = malloc(sizeof(u_int32_t), - M_FW, M_NOWAIT | M_ZERO); fp = (struct fw_pkt *)xfer->send.buf; fp->mode.ld[1] = 0; if (root_node >= 0) - fp->mode.ld[1] |= htonl((root_node & 0x3f) << 24 | 1 << 23); + fp->mode.ld[1] |= (root_node & 0x3f) << 24 | 1 << 23; if (gap_count >= 0) - fp->mode.ld[1] |= htonl(1 << 22 | (gap_count & 0x3f) << 16); + fp->mode.ld[1] |= 1 << 22 | (gap_count & 0x3f) << 16; fp->mode.ld[2] = ~fp->mode.ld[1]; /* XXX Dangerous, how to pass PHY packet to device driver */ fp->mode.common.tcode |= FWTCODE_PHY; if (firewire_debug) printf("send phy_config root_node=%d gap_count=%d\n", root_node, gap_count); fw_asyreq(fc, -1, xfer); } #if 0 /* * Dump self ID. */ static void fw_print_sid(u_int32_t sid) { union fw_self_id *s; s = (union fw_self_id *) &sid; printf("node:%d link:%d gap:%d spd:%d del:%d con:%d pwr:%d" " p0:%d p1:%d p2:%d i:%d m:%d\n", s->p0.phy_id, s->p0.link_active, s->p0.gap_count, s->p0.phy_speed, s->p0.phy_delay, s->p0.contender, s->p0.power_class, s->p0.port0, s->p0.port1, s->p0.port2, s->p0.initiated_reset, s->p0.more_packets); } #endif /* * To receive self ID. */ -void fw_sidrcv(struct firewire_comm* fc, caddr_t buf, u_int len, u_int off) +void fw_sidrcv(struct firewire_comm* fc, u_int32_t *sid, u_int len) { - u_int32_t *p, *sid = (u_int32_t *)(buf + off); + u_int32_t *p; union fw_self_id *self_id; u_int i, j, node, c_port = 0, i_branch = 0; fc->sid_cnt = len /(sizeof(u_int32_t) * 2); fc->status = FWBUSINIT; fc->max_node = fc->nodeid & 0x3f; CSRARC(fc, NODE_IDS) = ((u_int32_t)fc->nodeid) << 16; fc->status = FWBUSCYMELECT; fc->topology_map->crc_len = 2; fc->topology_map->generation ++; fc->topology_map->self_id_count = 0; fc->topology_map->node_count = 0; fc->speed_map->generation ++; fc->speed_map->crc_len = 1 + (64*64 + 3) / 4; self_id = &fc->topology_map->self_id[0]; for(i = 0; i < fc->sid_cnt; i ++){ if (sid[1] != ~sid[0]) { printf("fw_sidrcv: invalid self-id packet\n"); sid += 2; continue; } *self_id = *((union fw_self_id *)sid); fc->topology_map->crc_len++; if(self_id->p0.sequel == 0){ fc->topology_map->node_count ++; c_port = 0; #if 0 fw_print_sid(sid[0]); #endif node = self_id->p0.phy_id; if(fc->max_node < node){ fc->max_node = self_id->p0.phy_id; } /* XXX I'm not sure this is the right speed_map */ fc->speed_map->speed[node][node] = self_id->p0.phy_speed; for (j = 0; j < node; j ++) { fc->speed_map->speed[j][node] = fc->speed_map->speed[node][j] = min(fc->speed_map->speed[j][j], self_id->p0.phy_speed); } if ((fc->irm == -1 || self_id->p0.phy_id > fc->irm) && (self_id->p0.link_active && self_id->p0.contender)) { fc->irm = self_id->p0.phy_id; } if(self_id->p0.port0 >= 0x2){ c_port++; } if(self_id->p0.port1 >= 0x2){ c_port++; } if(self_id->p0.port2 >= 0x2){ c_port++; } } if(c_port > 2){ i_branch += (c_port - 2); } sid += 2; self_id++; fc->topology_map->self_id_count ++; } device_printf(fc->bdev, "%d nodes", fc->max_node + 1); /* CRC */ fc->topology_map->crc = fw_crc16( (u_int32_t *)&fc->topology_map->generation, fc->topology_map->crc_len * 4); fc->speed_map->crc = fw_crc16( (u_int32_t *)&fc->speed_map->generation, fc->speed_map->crc_len * 4); /* byteswap and copy to CSR */ p = (u_int32_t *)fc->topology_map; for (i = 0; i <= fc->topology_map->crc_len; i++) CSRARC(fc, TOPO_MAP + i * 4) = htonl(*p++); p = (u_int32_t *)fc->speed_map; CSRARC(fc, SPED_MAP) = htonl(*p++); CSRARC(fc, SPED_MAP + 4) = htonl(*p++); /* don't byte-swap u_int8_t array */ bcopy(p, &CSRARC(fc, SPED_MAP + 8), (fc->speed_map->crc_len - 1)*4); fc->max_hop = fc->max_node - i_branch; -#if 1 printf(", maxhop <= %d", fc->max_hop); -#endif if(fc->irm == -1 ){ printf(", Not found IRM capable node"); }else{ printf(", cable IRM = %d", fc->irm); if (fc->irm == fc->nodeid) printf(" (me)"); } printf("\n"); if (try_bmr && (fc->irm != -1) && (CSRARC(fc, BUS_MGR_ID) == 0x3f)) { if (fc->irm == ((CSRARC(fc, NODE_IDS) >> 16 ) & 0x3f)) { fc->status = FWBUSMGRDONE; CSRARC(fc, BUS_MGR_ID) = fc->set_bmr(fc, fc->irm); } else { fc->status = FWBUSMGRELECT; callout_reset(&fc->bmr_callout, hz/8, (void *)fw_try_bmr, (void *)fc); } } else { fc->status = FWBUSMGRDONE; #if 0 device_printf(fc->bdev, "BMR = %x\n", CSRARC(fc, BUS_MGR_ID)); #endif } - free(buf, M_FW); if(fc->irm == ((CSRARC(fc, NODE_IDS) >> 16 ) & 0x3f)){ /* I am BMGR */ fw_bmr(fc); } callout_reset(&fc->busprobe_callout, hz/4, (void *)fw_bus_probe, (void *)fc); } /* * To probe devices on the IEEE1394 bus. */ static void fw_bus_probe(struct firewire_comm *fc) { int s; struct fw_device *fwdev, *next; 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); 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; fc->ongoeui.hi = 0xffffffff; fc->ongoeui.lo = 0xffffffff; fw_bus_explore(fc); splx(s); } /* * To collect device informations on the IEEE1394 bus. */ static void fw_bus_explore(struct firewire_comm *fc ) { int err = 0; struct fw_device *fwdev, *pfwdev, *tfwdev; u_int32_t addr; struct fw_xfer *xfer; struct fw_pkt *fp; if(fc->status != FWBUSEXPLORE) return; loop: if(fc->ongonode == fc->nodeid) fc->ongonode++; if(fc->ongonode > fc->max_node) goto done; if(fc->ongonode >= 0x3f) goto done; /* check link */ /* XXX we need to check phy_id first */ if (!fc->topology_map->self_id[fc->ongonode].p0.link_active) { if (firewire_debug) printf("node%d: link down\n", fc->ongonode); fc->ongonode++; goto loop; } if(fc->ongoaddr <= CSRROMOFF && fc->ongoeui.hi == 0xffffffff && fc->ongoeui.lo == 0xffffffff ){ fc->ongoaddr = CSRROMOFF; addr = 0xf0000000 | fc->ongoaddr; }else if(fc->ongoeui.hi == 0xffffffff ){ fc->ongoaddr = CSRROMOFF + 0xc; addr = 0xf0000000 | fc->ongoaddr; }else if(fc->ongoeui.lo == 0xffffffff ){ fc->ongoaddr = CSRROMOFF + 0x10; addr = 0xf0000000 | fc->ongoaddr; }else if(fc->ongodev == NULL){ STAILQ_FOREACH(fwdev, &fc->devices, link) if (FW_EUI64_EQUAL(fwdev->eui, fc->ongoeui)) break; if(fwdev != NULL){ fwdev->dst = fc->ongonode; fwdev->status = FWDEVATTACHED; fc->ongonode++; fc->ongoaddr = CSRROMOFF; fc->ongodev = NULL; fc->ongoeui.hi = 0xffffffff; fc->ongoeui.lo = 0xffffffff; goto loop; } fwdev = malloc(sizeof(struct fw_device), M_FW, M_NOWAIT); if(fwdev == NULL) return; fwdev->fc = fc; fwdev->rommax = 0; fwdev->dst = fc->ongonode; fwdev->eui.hi = fc->ongoeui.hi; fwdev->eui.lo = fc->ongoeui.lo; fwdev->status = FWDEVINIT; -#if 0 - fwdev->speed = CSRARC(fc, SPED_MAP + 8 + fc->ongonode / 4) - >> ((3 - (fc->ongonode % 4)) * 8); -#else fwdev->speed = fc->speed_map->speed[fc->nodeid][fc->ongonode]; -#endif pfwdev = NULL; STAILQ_FOREACH(tfwdev, &fc->devices, link) { if (tfwdev->eui.hi > fwdev->eui.hi || (tfwdev->eui.hi == fwdev->eui.hi && tfwdev->eui.lo > fwdev->eui.lo)) break; pfwdev = tfwdev; } if (pfwdev == NULL) STAILQ_INSERT_HEAD(&fc->devices, fwdev, link); else STAILQ_INSERT_AFTER(&fc->devices, pfwdev, fwdev, link); device_printf(fc->bdev, "New %s device ID:%08x%08x\n", linkspeed[fwdev->speed], fc->ongoeui.hi, fc->ongoeui.lo); fc->ongodev = fwdev; fc->ongoaddr = CSRROMOFF; addr = 0xf0000000 | fc->ongoaddr; }else{ addr = 0xf0000000 | fc->ongoaddr; } #if 0 xfer = asyreqq(fc, FWSPD_S100, 0, 0, ((FWLOCALBUS | fc->ongonode) << 16) | 0xffff , addr, fw_bus_explore_callback); if(xfer == NULL) goto done; #else - xfer = fw_xfer_alloc(M_FWXFER); + xfer = fw_xfer_alloc_buf(M_FWXFER, 16, 16); if(xfer == NULL){ goto done; } - xfer->send.len = 16; xfer->spd = 0; - xfer->send.buf = malloc(16, M_FW, M_NOWAIT); - if(xfer->send.buf == NULL){ - fw_xfer_free( xfer); - return; - } - - xfer->send.off = 0; fp = (struct fw_pkt *)xfer->send.buf; - fp->mode.rreqq.dest_hi = htons(0xffff); + 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 = htons(xfer->dst); - fp->mode.rreqq.dest_lo = htonl(addr); + fp->mode.rreqq.dst = xfer->dst; + fp->mode.rreqq.dest_lo = addr; xfer->act.hand = fw_bus_explore_callback; if (firewire_debug) printf("node%d: explore addr=0x%x\n", fc->ongonode, fc->ongoaddr); err = fw_asyreq(fc, -1, xfer); if(err){ fw_xfer_free( xfer); return; } #endif return; done: /* fw_attach_devs */ fc->status = FWBUSEXPDONE; if (firewire_debug) printf("bus_explore done\n"); fw_attach_dev(fc); return; } /* Portable Async. request read quad */ struct fw_xfer * asyreqq(struct firewire_comm *fc, u_int8_t spd, u_int8_t tl, u_int8_t rt, u_int32_t addr_hi, u_int32_t addr_lo, void (*hand) __P((struct fw_xfer*))) { struct fw_xfer *xfer; struct fw_pkt *fp; int err; - xfer = fw_xfer_alloc(M_FWXFER); - if(xfer == NULL){ + xfer = fw_xfer_alloc_buf(M_FWXFER, 16, 16); + if (xfer == NULL) return NULL; - } - xfer->send.len = 16; - xfer->spd = spd; /* XXX:min(spd, fc->spd) */ - xfer->send.buf = malloc(16, M_FW, M_NOWAIT); - if(xfer->send.buf == NULL){ - fw_xfer_free( xfer); - return NULL; - } - xfer->send.off = 0; + xfer->spd = spd; /* XXX:min(spd, fc->spd) */ fp = (struct fw_pkt *)xfer->send.buf; - fp->mode.rreqq.dest_hi = htons(addr_hi & 0xffff); + fp->mode.rreqq.dest_hi = addr_hi & 0xffff; if(tl & FWP_TL_VALID){ fp->mode.rreqq.tlrt = (tl & 0x3f) << 2; }else{ fp->mode.rreqq.tlrt = 0; } fp->mode.rreqq.tlrt |= rt & 0x3; 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 = htons(xfer->dst); - fp->mode.rreqq.dest_lo = htonl(addr_lo); + fp->mode.rreqq.dst = xfer->dst; + fp->mode.rreqq.dest_lo = addr_lo; xfer->act.hand = hand; err = fw_asyreq(fc, -1, xfer); if(err){ fw_xfer_free( xfer); return NULL; } return xfer; } /* * Callback for the IEEE1394 bus information collection. */ static void fw_bus_explore_callback(struct fw_xfer *xfer) { struct firewire_comm *fc; struct fw_pkt *sfp,*rfp; struct csrhdr *chdr; struct csrdir *csrd; struct csrreg *csrreg; u_int32_t offset; if(xfer == NULL) { printf("xfer == NULL\n"); return; } fc = xfer->fc; if (firewire_debug) printf("node%d: callback addr=0x%x\n", fc->ongonode, fc->ongoaddr); if(xfer->resp != 0){ printf("node%d: resp=%d addr=0x%x\n", fc->ongonode, xfer->resp, fc->ongoaddr); fc->retry_count++; goto nextnode; } if(xfer->send.buf == NULL){ printf("node%d: send.buf=NULL addr=0x%x\n", fc->ongonode, fc->ongoaddr); fc->retry_count++; goto nextnode; } 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); fc->retry_count++; goto nextnode; } rfp = (struct fw_pkt *)xfer->recv.buf; #if 0 { u_int32_t *qld; int i; qld = (u_int32_t *)xfer->recv.buf; printf("len:%d\n", xfer->recv.len); for( i = 0 ; i <= xfer->recv.len && i < 32; i+= 4){ - printf("0x%08x ", ntohl(rfp->mode.ld[i/4])); + printf("0x%08x ", rfp->mode.ld[i/4]); if((i % 16) == 15) printf("\n"); } if((i % 16) != 15) printf("\n"); } #endif if(fc->ongodev == NULL){ - if(sfp->mode.rreqq.dest_lo == htonl((0xf0000000 | CSRROMOFF))){ + if(sfp->mode.rreqq.dest_lo == (0xf0000000 | CSRROMOFF)){ rfp->mode.rresq.data = ntohl(rfp->mode.rresq.data); chdr = (struct csrhdr *)(&rfp->mode.rresq.data); /* If CSR is minimal confinguration, more investgation is not needed. */ if(chdr->info_len == 1){ if (firewire_debug) printf("node%d: minimal config\n", fc->ongonode); goto nextnode; }else{ fc->ongoaddr = CSRROMOFF + 0xc; } - }else if(sfp->mode.rreqq.dest_lo == htonl((0xf0000000 |(CSRROMOFF + 0xc)))){ + }else if(sfp->mode.rreqq.dest_lo == (0xf0000000 |(CSRROMOFF + 0xc))){ fc->ongoeui.hi = ntohl(rfp->mode.rresq.data); fc->ongoaddr = CSRROMOFF + 0x10; - }else if(sfp->mode.rreqq.dest_lo == htonl((0xf0000000 |(CSRROMOFF + 0x10)))){ + }else if(sfp->mode.rreqq.dest_lo == (0xf0000000 |(CSRROMOFF + 0x10))){ fc->ongoeui.lo = ntohl(rfp->mode.rresq.data); if (fc->ongoeui.hi == 0 && fc->ongoeui.lo == 0) { if (firewire_debug) printf("node%d: eui64 is zero.\n", fc->ongonode); goto nextnode; } fc->ongoaddr = CSRROMOFF; } }else{ fc->ongodev->csrrom[(fc->ongoaddr - CSRROMOFF)/4] = ntohl(rfp->mode.rresq.data); if(fc->ongoaddr > fc->ongodev->rommax){ fc->ongodev->rommax = fc->ongoaddr; } csrd = SLIST_FIRST(&fc->ongocsr); if((csrd = SLIST_FIRST(&fc->ongocsr)) == NULL){ chdr = (struct csrhdr *)(fc->ongodev->csrrom); offset = CSRROMOFF; }else{ chdr = (struct csrhdr *)&fc->ongodev->csrrom[(csrd->off - CSRROMOFF)/4]; offset = csrd->off; } if(fc->ongoaddr > (CSRROMOFF + 0x14) && fc->ongoaddr != offset){ csrreg = (struct csrreg *)&fc->ongodev->csrrom[(fc->ongoaddr - CSRROMOFF)/4]; if( csrreg->key == 0x81 || csrreg->key == 0xd1){ csrd = SLIST_FIRST(&fc->csrfree); if(csrd == NULL){ goto nextnode; }else{ csrd->ongoaddr = fc->ongoaddr; fc->ongoaddr += csrreg->val * 4; csrd->off = fc->ongoaddr; SLIST_REMOVE_HEAD(&fc->csrfree, link); SLIST_INSERT_HEAD(&fc->ongocsr, csrd, link); goto nextaddr; } } } fc->ongoaddr += 4; if(((fc->ongoaddr - offset)/4 > chdr->crc_len) && (fc->ongodev->rommax < 0x414)){ if(fc->ongodev->rommax <= 0x414){ csrd = SLIST_FIRST(&fc->csrfree); if(csrd == NULL) goto nextnode; csrd->off = fc->ongoaddr; csrd->ongoaddr = fc->ongoaddr; SLIST_REMOVE_HEAD(&fc->csrfree, link); SLIST_INSERT_HEAD(&fc->ongocsr, csrd, link); } goto nextaddr; } while(((fc->ongoaddr - offset)/4 > chdr->crc_len)){ if(csrd == NULL){ goto nextnode; }; fc->ongoaddr = csrd->ongoaddr + 4; SLIST_REMOVE_HEAD(&fc->ongocsr, link); SLIST_INSERT_HEAD(&fc->csrfree, csrd, link); csrd = SLIST_FIRST(&fc->ongocsr); if((csrd = SLIST_FIRST(&fc->ongocsr)) == NULL){ chdr = (struct csrhdr *)(fc->ongodev->csrrom); offset = CSRROMOFF; }else{ chdr = (struct csrhdr *)&(fc->ongodev->csrrom[(csrd->off - CSRROMOFF)/4]); offset = csrd->off; } } if((fc->ongoaddr - CSRROMOFF) > CSRROMSIZE){ goto nextnode; } } nextaddr: fw_xfer_free( xfer); fw_bus_explore(fc); return; nextnode: fw_xfer_free( xfer); fc->ongonode++; /* housekeeping work space */ fc->ongoaddr = CSRROMOFF; fc->ongodev = NULL; fc->ongoeui.hi = 0xffffffff; fc->ongoeui.lo = 0xffffffff; while((csrd = SLIST_FIRST(&fc->ongocsr)) != NULL){ SLIST_REMOVE_HEAD(&fc->ongocsr, link); SLIST_INSERT_HEAD(&fc->csrfree, csrd, link); } fw_bus_explore(fc); return; } /* * To obtain CSR register values. */ u_int32_t getcsrdata(struct fw_device *fwdev, u_int8_t key) { int i; struct csrhdr *chdr; struct csrreg *creg; chdr = (struct csrhdr *)&fwdev->csrrom[0]; for( i = chdr->info_len + 4; i <= fwdev->rommax - CSRROMOFF; i+=4){ creg = (struct csrreg *)&fwdev->csrrom[i/4]; if(creg->key == key){ return (u_int32_t)creg->val; } } return 0; } /* * To attach sub-devices layer onto IEEE1394 bus. */ static void fw_attach_dev(struct firewire_comm *fc) { struct fw_device *fwdev; struct fw_xfer *xfer; int i, err; device_t *devlistp; int devcnt; struct firewire_dev_comm *fdc; u_int32_t spec, ver; STAILQ_FOREACH(fwdev, &fc->devices, link) { if(fwdev->status == FWDEVINIT){ spec = getcsrdata(fwdev, CSRKEY_SPEC); if(spec == 0) continue; ver = getcsrdata(fwdev, CSRKEY_VER); if(ver == 0) continue; fwdev->maxrec = (fwdev->csrrom[2] >> 12) & 0xf; device_printf(fc->bdev, "Device "); switch(spec){ case CSRVAL_ANSIT10: switch(ver){ case CSRVAL_T10SBP2: printf("SBP-II"); break; default: break; } break; case CSRVAL_1394TA: switch(ver){ case CSR_PROTAVC: printf("AV/C"); break; case CSR_PROTCAL: printf("CAL"); break; case CSR_PROTEHS: printf("EHS"); break; case CSR_PROTHAVI: printf("HAVi"); break; case CSR_PROTCAM104: printf("1394 Cam 1.04"); break; case CSR_PROTCAM120: printf("1394 Cam 1.20"); break; case CSR_PROTCAM130: printf("1394 Cam 1.30"); break; case CSR_PROTDPP: printf("1394 Direct print"); break; case CSR_PROTIICP: printf("Industrial & Instrument"); break; default: printf("unknown 1394TA"); break; } break; default: printf("unknown spec"); break; } fwdev->status = FWDEVATTACHED; printf("\n"); } } err = device_get_children(fc->bdev, &devlistp, &devcnt); if( err != 0 ) return; for( i = 0 ; i < devcnt ; i++){ if (device_get_state(devlistp[i]) >= DS_ATTACHED) { fdc = device_get_softc(devlistp[i]); if (fdc->post_explore != NULL) fdc->post_explore(fdc); } } 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 callout_reset(&fc->retry_probe_callout, hz*2, (void *)fc->ibr, (void *)fc); #endif } return; } /* * To allocate uniq transaction label. */ static int fw_get_tlabel(struct firewire_comm *fc, struct fw_xfer *xfer) { u_int i; struct tlabel *tl, *tmptl; int s; static u_int32_t label = 0; s = splfw(); for( i = 0 ; i < 0x40 ; i ++){ label = (label + 1) & 0x3f; for(tmptl = STAILQ_FIRST(&fc->tlabels[label]); tmptl != NULL; tmptl = STAILQ_NEXT(tmptl, link)){ if(tmptl->xfer->dst == xfer->dst) break; } if(tmptl == NULL) { tl = malloc(sizeof(struct tlabel),M_FW,M_NOWAIT); if (tl == NULL) { splx(s); return (-1); } tl->xfer = xfer; STAILQ_INSERT_TAIL(&fc->tlabels[label], tl, link); splx(s); if (firewire_debug > 1) printf("fw_get_tlabel: dst=%d tl=%d\n", xfer->dst, label); return(label); } } splx(s); printf("fw_get_tlabel: no free tlabel\n"); return(-1); } +static void +fw_rcv_copy(struct fw_xfer *xfer, struct iovec *vec, int nvec) +{ + char *p; + int res, i, len; + + p = xfer->recv.buf; + res = xfer->recv.len; + for (i = 0; i < nvec; i++, vec++) { + len = vec->iov_len; + if (res < len) { + printf("rcv buffer(%d) is %d bytes short.\n", + xfer->recv.len, len - res); + len = res; + } + bcopy(vec->iov_base, p, len); + p += len; + res -= len; + if (res <= 0) + break; + } + xfer->recv.len -= res; +} + /* * Generic packet receving process. */ void -fw_rcv(struct firewire_comm* fc, caddr_t buf, u_int len, u_int sub, u_int off, u_int spd) +fw_rcv(struct firewire_comm *fc, struct iovec *vec, int nvec, u_int sub, u_int spd) { struct fw_pkt *fp, *resfp; struct fw_xfer *xfer; struct fw_bind *bind; struct firewire_softc *sc; - int s; + int tcode, s; + int i, len, oldstate; #if 0 { u_int32_t *qld; int i; qld = (u_int32_t *)buf; printf("spd %d len:%d\n", spd, len); for( i = 0 ; i <= len && i < 32; i+= 4){ printf("0x%08x ", ntohl(qld[i/4])); if((i % 16) == 15) printf("\n"); } if((i % 16) != 15) printf("\n"); } #endif - fp = (struct fw_pkt *)(buf + off); - switch(fp->mode.common.tcode){ + fp = (struct fw_pkt *)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, ntohs(fp->mode.hdr.src), + xfer = fw_tl2xfer(fc, fp->mode.hdr.src, fp->mode.hdr.tlrt >> 2); if(xfer == NULL) { printf("fw_rcv: unknown response " "tcode=%d src=0x%x tl=0x%x rt=%d data=0x%x\n", - fp->mode.common.tcode, - ntohs(fp->mode.hdr.src), + 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, ntohs(fp->mode.hdr.src), + xfer = fw_tl2xfer(fc, fp->mode.hdr.src, (fp->mode.hdr.tlrt >> 2)^3); if (xfer == NULL) { printf("no use...\n"); goto err; } #else goto err; #endif } - switch(xfer->act_type){ - case FWACT_XFER: - if((xfer->sub >= 0) && - ((fc->ir[xfer->sub]->flag & FWXFERQ_MODEMASK ) == 0)){ - xfer->resp = EINVAL; - fw_xfer_done(xfer); - goto err; - } - xfer->recv.len = len; - xfer->recv.off = off; - xfer->recv.buf = buf; - xfer->resp = 0; + fw_rcv_copy(xfer, vec, nvec); + xfer->resp = 0; + /* make sure the packet is drained in AT queue */ + oldstate = xfer->state; + xfer->state = FWXF_RCVD; + switch (oldstate) { + case FWXF_SENT: fw_xfer_done(xfer); - return; break; - case FWACT_CH: - default: - goto err; + case FWXF_START: + if (firewire_debug) + printf("not sent yet\n"); break; + default: + printf("unexpected state %d\n", xfer->state); } - break; + return; case FWTCODE_WREQQ: case FWTCODE_WREQB: case FWTCODE_RREQQ: case FWTCODE_RREQB: case FWTCODE_LREQ: - bind = fw_bindlookup(fc, ntohs(fp->mode.rreqq.dest_hi), - ntohl(fp->mode.rreqq.dest_lo)); + bind = fw_bindlookup(fc, fp->mode.rreqq.dest_hi, + fp->mode.rreqq.dest_lo); if(bind == NULL){ -#if __FreeBSD_version >= 500000 - printf("Unknown service addr 0x%08x:0x%08x tcode=%x\n src=0x%x", -#else - printf("Unknown service addr 0x%08x:0x%08lx tcode=%x src=0x%x\n", -#endif - ntohs(fp->mode.rreqq.dest_hi), - ntohl(fp->mode.rreqq.dest_lo), - fp->mode.common.tcode, - fp->mode.hdr.src); + printf("Unknown service addr 0x%08x:0x%08x tcode=%x src=0x%x data=%x\n", + fp->mode.wreqq.dest_hi, + fp->mode.wreqq.dest_lo, + tcode, + fp->mode.hdr.src, + ntohl(fp->mode.wreqq.data)); if (fc->status == FWBUSRESET) { printf("fw_rcv: cannot respond(bus reset)!\n"); goto err; } - xfer = fw_xfer_alloc(M_FWXFER); + xfer = fw_xfer_alloc_buf(M_FWXFER, 16, 0); if(xfer == NULL){ return; } xfer->spd = spd; - xfer->send.buf = malloc(16, M_FW, M_NOWAIT); resfp = (struct fw_pkt *)xfer->send.buf; - switch(fp->mode.common.tcode){ + 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.extcode = 0; resfp->mode.rresb.len = 0; /* xfer->act.hand = fw_asy_callback; */ xfer->act.hand = fw_xfer_free; if(fw_asyreq(fc, -1, xfer)){ fw_xfer_free( xfer); return; } goto err; } - switch(bind->xfer->act_type){ + len = 0; + for (i = 0; i < nvec; i ++) + len += vec[i].iov_len; + switch(bind->act_type){ case FWACT_XFER: - xfer = fw_xfer_alloc(M_FWXFER); - if(xfer == NULL) goto err; - xfer->fc = bind->xfer->fc; - xfer->sc = bind->xfer->sc; - xfer->recv.buf = buf; - xfer->recv.len = len; - xfer->recv.off = off; + /* splfw()?? */ + xfer = STAILQ_FIRST(&bind->xferlist); + if (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; - xfer->act.hand = bind->xfer->act.hand; if (fc->status != FWBUSRESET) xfer->act.hand(xfer); else STAILQ_INSERT_TAIL(&fc->pending, xfer, link); return; break; case FWACT_CH: - if(fc->ir[bind->xfer->sub]->queued >= - fc->ir[bind->xfer->sub]->maxq){ + if(fc->ir[bind->sub]->queued >= + fc->ir[bind->sub]->maxq){ device_printf(fc->bdev, "Discard a packet %x %d\n", - bind->xfer->sub, - fc->ir[bind->xfer->sub]->queued); + bind->sub, + fc->ir[bind->sub]->queued); goto err; } - xfer = fw_xfer_alloc(M_FWXFER); - if(xfer == NULL) goto err; - xfer->recv.buf = buf; - xfer->recv.len = len; - xfer->recv.off = off; + xfer = STAILQ_FIRST(&bind->xferlist); + if (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; s = splfw(); - fc->ir[bind->xfer->sub]->queued++; - STAILQ_INSERT_TAIL(&fc->ir[bind->xfer->sub]->q, xfer, link); + fc->ir[bind->sub]->queued++; + STAILQ_INSERT_TAIL(&fc->ir[bind->sub]->q, xfer, link); splx(s); - wakeup((caddr_t)fc->ir[bind->xfer->sub]); + wakeup((caddr_t)fc->ir[bind->sub]); return; break; default: goto err; break; } break; case FWTCODE_STREAM: { struct fw_xferq *xferq; xferq = fc->ir[sub]; #if 0 printf("stream rcv dma %d len %d off %d spd %d\n", sub, len, off, spd); #endif if(xferq->queued >= xferq->maxq) { printf("receive queue is full\n"); goto err; } - xfer = fw_xfer_alloc(M_FWXFER); + /* XXX get xfer from xfer queue, we don't need copy for + per packet mode */ + xfer = fw_xfer_alloc_buf(M_FWXFER, 0, /* XXX */ + vec[0].iov_len); if(xfer == NULL) goto err; - xfer->recv.buf = buf; - xfer->recv.len = len; - xfer->recv.off = off; + fw_rcv_copy(xfer, vec, nvec); xfer->spd = spd; s = splfw(); xferq->queued++; STAILQ_INSERT_TAIL(&xferq->q, xfer, link); splx(s); sc = device_get_softc(fc->bdev); #if __FreeBSD_version >= 500000 if (SEL_WAITING(&xferq->rsel)) #else if (&xferq->rsel.si_pid != 0) #endif selwakeup(&xferq->rsel); if (xferq->flag & FWXFERQ_WAKEUP) { xferq->flag &= ~FWXFERQ_WAKEUP; wakeup((caddr_t)xferq); } if (xferq->flag & FWXFERQ_HANDLER) { xferq->hand(xferq); } return; break; } default: - printf("fw_rcv: unknow tcode\n"); + printf("fw_rcv: unknow tcode %d\n", tcode); break; } err: - free(buf, M_FW); + return; } /* * Post process for Bus Manager election process. */ static void fw_try_bmr_callback(struct fw_xfer *xfer) { struct fw_pkt *rfp; struct firewire_comm *fc; int bmr; if (xfer == NULL) return; fc = xfer->fc; if (xfer->resp != 0) goto error; if (xfer->send.buf == NULL) goto error; if (xfer->recv.buf == NULL) goto error; rfp = (struct fw_pkt *)xfer->recv.buf; if (rfp->mode.lres.rtcode != FWRCODE_COMPLETE) goto error; bmr = ntohl(rfp->mode.lres.payload[0]); if (bmr == 0x3f) bmr = fc->nodeid; CSRARC(fc, BUS_MGR_ID) = fc->set_bmr(fc, bmr & 0x3f); device_printf(fc->bdev, "new bus manager %d ", CSRARC(fc, BUS_MGR_ID)); if(bmr == fc->nodeid){ printf("(me)\n"); fw_bmr(fc); }else{ printf("\n"); } error: fw_xfer_free(xfer); } + /* * To candidate Bus Manager election process. */ static void fw_try_bmr(void *arg) { struct fw_xfer *xfer; struct firewire_comm *fc = (struct firewire_comm *)arg; struct fw_pkt *fp; int err = 0; - xfer = fw_xfer_alloc(M_FWXFER); + xfer = fw_xfer_alloc_buf(M_FWXFER, 24, 20); if(xfer == NULL){ return; } - xfer->send.len = 24; xfer->spd = 0; - xfer->send.buf = malloc(24, M_FW, M_NOWAIT); - if(xfer->send.buf == NULL){ - fw_xfer_free( xfer); - return; - } - fc->status = FWBUSMGRELECT; - xfer->send.off = 0; fp = (struct fw_pkt *)xfer->send.buf; - fp->mode.lreq.dest_hi = htons(0xffff); + 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 = htons(8); - fp->mode.lreq.extcode = htons(FW_LREQ_CMPSWAP); + fp->mode.lreq.len = 8; + fp->mode.lreq.extcode = FW_LREQ_CMPSWAP; xfer->dst = FWLOCALBUS | fc->irm; - fp->mode.lreq.dst = htons(xfer->dst); - fp->mode.lreq.dest_lo = htonl(0xf0000000 | BUS_MGR_ID); + fp->mode.lreq.dst = xfer->dst; + 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->act_type = FWACT_XFER; xfer->act.hand = fw_try_bmr_callback; err = fw_asyreq(fc, -1, xfer); if(err){ fw_xfer_free( xfer); return; } return; } #ifdef FW_VMACCESS /* * Software implementation for physical memory block access. * XXX:Too slow, usef for debug purpose only. */ static void fw_vmaccess(struct fw_xfer *xfer){ struct fw_pkt *rfp, *sfp = NULL; - u_int32_t *ld = (u_int32_t *)(xfer->recv.buf + xfer->recv.off); + u_int32_t *ld = (u_int32_t *)xfer->recv.buf; - printf("vmaccess spd:%2x len:%03x %d data:%08x %08x %08x %08x\n", - xfer->spd, xfer->recv.len, xfer->recv.off, ntohl(ld[0]), ntohl(ld[1]), ntohl(ld[2]), ntohl(ld[3])); + printf("vmaccess spd:%2x len:%03x data:%08x %08x %08x %08x\n", + xfer->spd, xfer->recv.len, ntohl(ld[0]), ntohl(ld[1]), ntohl(ld[2]), ntohl(ld[3])); printf("vmaccess data:%08x %08x %08x %08x\n", ntohl(ld[4]), ntohl(ld[5]), ntohl(ld[6]), ntohl(ld[7])); if(xfer->resp != 0){ fw_xfer_free( xfer); return; } if(xfer->recv.buf == NULL){ fw_xfer_free( xfer); return; } rfp = (struct fw_pkt *)xfer->recv.buf; switch(rfp->mode.hdr.tcode){ /* XXX need fix for 64bit arch */ case FWTCODE_WREQB: xfer->send.buf = malloc(12, M_FW, M_NOWAIT); xfer->send.len = 12; sfp = (struct fw_pkt *)xfer->send.buf; bcopy(rfp->mode.wreqb.payload, (caddr_t)ntohl(rfp->mode.wreqb.dest_lo), ntohs(rfp->mode.wreqb.len)); sfp->mode.wres.tcode = FWTCODE_WRES; sfp->mode.wres.rtcode = 0; break; case FWTCODE_WREQQ: xfer->send.buf = malloc(12, M_FW, M_NOWAIT); xfer->send.len = 12; sfp->mode.wres.tcode = FWTCODE_WRES; *((u_int32_t *)(ntohl(rfp->mode.wreqb.dest_lo))) = rfp->mode.wreqq.data; sfp->mode.wres.rtcode = 0; break; case FWTCODE_RREQB: xfer->send.buf = malloc(16 + rfp->mode.rreqb.len, M_FW, M_NOWAIT); xfer->send.len = 16 + ntohs(rfp->mode.rreqb.len); sfp = (struct fw_pkt *)xfer->send.buf; bcopy((caddr_t)ntohl(rfp->mode.rreqb.dest_lo), sfp->mode.rresb.payload, (u_int16_t)ntohs(rfp->mode.rreqb.len)); sfp->mode.rresb.tcode = FWTCODE_RRESB; sfp->mode.rresb.len = rfp->mode.rreqb.len; sfp->mode.rresb.rtcode = 0; sfp->mode.rresb.extcode = 0; break; case FWTCODE_RREQQ: xfer->send.buf = malloc(16, M_FW, M_NOWAIT); xfer->send.len = 16; sfp = (struct fw_pkt *)xfer->send.buf; sfp->mode.rresq.data = *(u_int32_t *)(ntohl(rfp->mode.rreqq.dest_lo)); sfp->mode.wres.tcode = FWTCODE_RRESQ; sfp->mode.rresb.rtcode = 0; break; default: fw_xfer_free( xfer); return; } - xfer->send.off = 0; sfp->mode.hdr.dst = rfp->mode.hdr.src; xfer->dst = ntohs(rfp->mode.hdr.src); xfer->act.hand = fw_xfer_free; xfer->retry_req = fw_asybusy; sfp->mode.hdr.tlrt = rfp->mode.hdr.tlrt; sfp->mode.hdr.pri = 0; fw_asyreq(xfer->fc, -1, xfer); /**/ return; } #endif /* * CRC16 check-sum for IEEE1394 register blocks. */ u_int16_t fw_crc16(u_int32_t *ptr, u_int32_t len){ u_int32_t i, sum, crc = 0; int shift; len = (len + 3) & ~3; for(i = 0 ; i < len ; i+= 4){ for( shift = 28 ; shift >= 0 ; shift -= 4){ sum = ((crc >> 12) ^ (ptr[i/4] >> shift)) & 0xf; crc = (crc << 4) ^ ( sum << 12 ) ^ ( sum << 5) ^ sum; } crc &= 0xffff; } return((u_int16_t) crc); } static int fw_bmr(struct firewire_comm *fc) { struct fw_device fwdev; + union fw_self_id *self_id; int cmstr; - /* XXX Assume that the current root node is cycle master capable */ - cmstr = fc->max_node; + /* Check to see if the current root node is cycle master capable */ + self_id = &fc->topology_map->self_id[fc->max_node]; + if (fc->max_node > 0) { + if (self_id->p0.contender) + cmstr = fc->max_node; + else + /* XXX shall we be cycle master? */ + cmstr = fc->nodeid; + /* XXX bus reset? */ + } else + cmstr = -1; /* If I am the bus manager, optimize gapcount */ - if(fc->max_hop <= MAX_GAPHOP ){ - fw_phy_config(fc, (fc->max_node > 0)?cmstr:-1, - gap_cnt[fc->max_hop]); - } + if(fc->max_hop <= MAX_GAPHOP ) + fw_phy_config(fc, cmstr, gap_cnt[fc->max_hop]); /* If we are the cycle master, nothing to do */ - if (cmstr == fc->nodeid) + if (cmstr == fc->nodeid || cmstr == -1) return 0; /* Bus probe has not finished, make dummy fwdev for cmstr */ bzero(&fwdev, sizeof(fwdev)); fwdev.fc = fc; fwdev.dst = cmstr; fwdev.speed = 0; fwdev.maxrec = 8; /* 512 */ fwdev.status = FWDEVINIT; /* Set cmstr bit on the cycle master */ fwmem_write_quad(&fwdev, NULL, 0/*spd*/, 0xffff, 0xf0000000 | STATE_SET, htonl(1 << 16), fw_asy_callback_free); return 0; } DRIVER_MODULE(firewire,fwohci,firewire_driver,firewire_devclass,0,0); MODULE_VERSION(firewire, 1); Index: head/sys/dev/firewire/firewire.h =================================================================== --- head/sys/dev/firewire/firewire.h (revision 113583) +++ head/sys/dev/firewire/firewire.h (revision 113584) @@ -1,498 +1,403 @@ /* + * 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 * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the acknowledgement as bellow: * * This product includes software developed by K. Kobayashi and H. Shimokawa * * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ * */ #ifndef _FIREWIRE_H #define _FIREWIRE_H 1 #define DEV_DEF 0 #define DEV_DV 2 -#if 0 -struct dv_data{ - u_int32_t n_write; - u_int32_t a_write; - u_int32_t k_write; - u_int32_t write_done; - u_int32_t write_len[16]; - u_int32_t write_off[16]; - u_int32_t n_read; - u_int32_t a_read; - u_int32_t k_read; - u_int32_t read_done; - u_int32_t read_len[16]; - u_int32_t read_off[16]; -}; - -struct dv_data_req_t { - unsigned long index; - unsigned long len; - unsigned long off; -}; -#endif - struct fw_isochreq { unsigned char ch:6, tag:2; }; struct fw_isobufreq { struct { unsigned int nchunk; unsigned int npacket; unsigned int psize; } tx, rx; }; struct fw_addr { unsigned long hi; unsigned long lo; }; struct fw_asybindreq { struct fw_addr start; unsigned long len; }; struct fw_reg_req_t { unsigned long addr; unsigned long data; }; #define MAXREC(x) (2 << (x)) #define FWPMAX_S400 (2048 + 20) /* MAXREC plus space for control data */ -#define FWMAXQUEUE 256 +#define FWMAXQUEUE 64 #define FWLOCALBUS 0xffc0 #define FWTCODE_WREQQ 0 #define FWTCODE_WREQB 1 #define FWTCODE_WRES 2 #define FWTCODE_RREQQ 4 #define FWTCODE_RREQB 5 #define FWTCODE_RRESQ 6 #define FWTCODE_RRESB 7 #define FWTCODE_CYCS 8 #define FWTCODE_LREQ 9 #define FWTCODE_STREAM 0xa #define FWTCODE_LRES 0xb #define FWTCODE_PHY 0xe #define FWRETRY_1 0 #define FWRETRY_X 1 #define FWRETRY_A 2 #define FWRETRY_B 3 #define FWRCODE_COMPLETE 0 #define FWRCODE_ER_CONFL 4 #define FWRCODE_ER_DATA 5 #define FWRCODE_ER_TYPE 6 #define FWRCODE_ER_ADDR 7 #define FWSPD_S100 0 #define FWSPD_S200 1 #define FWSPD_S400 2 #define FWP_TL_VALID (1 << 7) struct fw_isohdr { u_int32_t hdr[1]; }; struct fw_asyhdr { u_int32_t hdr[4]; }; -#if 0 -#define FWPHYSIDSUBS(SID) (((SID) >> 23) & 1) -#define FWPHYSIDNODE(SID) (((SID) >> 24) & 0x3f) -#define FWPHYSIDLINK(SID) (((SID) >> 22) & 1) -#define FWPHYSIDGAP(SID) (((SID) >> 16) & 0x3f) -#define FWPHYSIDSPD(SID) (((SID) >> 14) & 0x3) -#define FWPHYSIDDEL(SID) (((SID) >> 12) & 0x3) -#define FWPHYSIDCON(SID) (((SID) >> 11) & 1) -#define FWPHYSIDPWR(SID) (((SID) >> 8) & 0x7) -#define FWPHYSIDP0(SID) (((SID) >> 6) & 0x3) -#define FWPHYSIDP1(SID) (((SID) >> 4) & 0x3) -#define FWPHYSIDP2(SID) (((SID) >> 2) & 0x3) -#define FWPHYSIDIR(SID) (((SID) >> 1) & 1) -#define FWPHYSIDMORE(SID) ((SID) & 1) -#define FWPHYSIDSEQ(SID) (((SID) >> 20) & 0x7) -#define FWPHYSIDPA(SID) (((SID) >> 16) & 0x3) -#define FWPHYSIDPB(SID) (((SID) >> 14) & 0x3) -#define FWPHYSIDPC(SID) (((SID) >> 12) & 0x3) -#define FWPHYSIDPD(SID) (((SID) >> 10) & 0x3) -#define FWPHYSIDPE(SID) (((SID) >> 8) & 0x3) -#define FWPHYSIDPF(SID) (((SID) >> 6) & 0x3) -#define FWPHYSIDPG(SID) (((SID) >> 4) & 0x3) -#define FWPHYSIDPH(SID) (((SID) >> 2) & 0x3) +#if BYTE_ORDER == BIG_ENDIAN +#define BIT4x2(x,y) u_int8_t x:4, y:4 +#define BIT16x2(x,y) u_int32_t x:16, y:16 +#else +#define BIT4x2(x,y) u_int8_t y:4, x:4 +#define BIT16x2(x,y) u_int32_t y:16, x:16 #endif + +#if BYTE_ORDER == BIG_ENDIAN +#define COMMON_HDR(a,b,c,d) u_int32_t a:16,b:8,c:4,d:4 +#define COMMON_RES(a,b,c,d) u_int32_t a:16,b:4,c:4,d:8 +#else +#define COMMON_HDR(a,b,c,d) u_int32_t d:4,c:4,b:8,a:16 +#define COMMON_RES(a,b,c,d) u_int32_t d:8,c:4,b:4,a:16 +#endif + struct fw_pkt { union { u_int32_t ld[0]; struct { - u_int16_t :16; - u_int8_t :8; - u_int8_t :4, - tcode:4; + COMMON_HDR(, , tcode, ); } common; struct { - u_int16_t len; - u_int8_t chtag; - u_int8_t sy:4, - tcode:4; + COMMON_HDR(len, chtag, tcode, sy); u_int32_t payload[0]; } stream; struct { - u_int16_t dst; - u_int8_t tlrt; - u_int8_t pri:4, - tcode:4; - u_int16_t src; + COMMON_HDR(dst, tlrt, tcode, pri); + BIT16x2(src, ); } hdr; struct { - u_int16_t dst; - u_int8_t tlrt; - u_int8_t pri:4, - tcode:4; - u_int16_t src; - u_int16_t dest_hi; + COMMON_HDR(dst, tlrt, tcode, pri); + BIT16x2(src, dest_hi); u_int32_t dest_lo; } rreqq; struct { - u_int16_t dst; - u_int8_t tlrt; - u_int8_t pri:4, - tcode:4; - u_int16_t src; - u_int8_t :4, - rtcode:4; - u_int8_t :8; + COMMON_HDR(dst, tlrt, tcode, pri); + COMMON_RES(src, rtcode, , ); u_int32_t :32; } wres; struct { - u_int16_t dst; - u_int8_t tlrt; - u_int8_t pri:4, - tcode:4; - u_int16_t src; - u_int16_t dest_hi; + COMMON_HDR(dst, tlrt, tcode, pri); + BIT16x2(src, dest_hi); u_int32_t dest_lo; - u_int16_t len; - u_int16_t extcode:16; + BIT16x2(len, extcode); } rreqb; struct { - u_int16_t dst; - u_int8_t tlrt; - u_int8_t pri:4, - tcode:4; - u_int16_t src; - u_int16_t dest_hi; + COMMON_HDR(dst, tlrt, tcode, pri); + BIT16x2(src, dest_hi); u_int32_t dest_lo; u_int32_t data; } wreqq; struct { - u_int16_t dst; - u_int8_t tlrt; - u_int8_t pri:4, - tcode:4; - u_int16_t src; - u_int16_t dest_hi; + COMMON_HDR(dst, tlrt, tcode, pri); + BIT16x2(src, dest_hi); u_int32_t dest_lo; u_int32_t data; } cyc; struct { - u_int16_t dst; - u_int8_t tlrt; - u_int8_t pri:4, - tcode:4; - u_int16_t src; - u_int8_t :4, - rtcode:4; - u_int8_t :8; + COMMON_HDR(dst, tlrt, tcode, pri); + COMMON_RES(src, rtcode, , ); u_int32_t :32; u_int32_t data; } rresq; struct { - u_int16_t dst; - u_int8_t tlrt; - u_int8_t pri:4, - tcode:4; - u_int16_t src; - u_int16_t dest_hi; + COMMON_HDR(dst, tlrt, tcode, pri); + BIT16x2(src, dest_hi); u_int32_t dest_lo; - u_int16_t len; - u_int16_t extcode; + BIT16x2(len, extcode); u_int32_t payload[0]; } wreqb; struct { - u_int16_t dst; - u_int8_t tlrt; - u_int8_t pri:4, - tcode:4; - u_int16_t src; - u_int16_t dest_hi; + COMMON_HDR(dst, tlrt, tcode, pri); + BIT16x2(src, dest_hi); u_int32_t dest_lo; - u_int16_t len; - u_int16_t extcode; + 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 { - u_int16_t dst; - u_int8_t tlrt; - u_int8_t pri:4, - tcode:4; - u_int16_t src; - u_int8_t :4, - rtcode:4; - u_int8_t :8; + COMMON_HDR(dst, tlrt, tcode, pri); + COMMON_RES(src, rtcode, , ); u_int32_t :32; - u_int16_t len; - u_int16_t extcode; + BIT16x2(len, extcode); u_int32_t payload[0]; } rresb; struct { - u_int16_t dst; - u_int8_t tlrt; - u_int8_t pri:4, - tcode:4; - u_int16_t src; - u_int8_t :4, - rtcode:4; - u_int8_t :8; + COMMON_HDR(dst, tlrt, tcode, pri); + COMMON_RES(src, rtcode, , ); u_int32_t :32; - u_int16_t len; - u_int16_t extcode; + BIT16x2(len, extcode); u_int32_t payload[0]; } lres; } mode; }; struct fw_eui64 { u_int32_t hi, lo; }; #define FW_EUI64_BYTE(eui, x) \ ((((x)<4)? \ ((eui)->hi >> (8*(3-(x)))): \ ((eui)->lo >> (8*(7-(x)))) \ ) & 0xff) #define FW_EUI64_EQUAL(x, y) \ ((x).hi == (y).hi && (x).lo == (y).lo) struct fw_asyreq { struct fw_asyreq_t{ unsigned char sped; unsigned int type; #define FWASREQNODE 0 #define FWASREQEUI 1 #define FWASRESTL 2 #define FWASREQSTREAM 3 unsigned short len; union { struct fw_eui64 eui; }dst; }req; struct fw_pkt pkt; u_int32_t data[512]; }; struct fw_devinfo { struct fw_eui64 eui; u_int16_t dst; u_int16_t status; }; #define FW_MAX_DEVLST 70 struct fw_devlstreq { u_int16_t n; u_int16_t info_len; struct fw_devinfo dev[FW_MAX_DEVLST]; }; #define FW_SELF_ID_PORT_CONNECTED_TO_CHILD 3 #define FW_SELF_ID_PORT_CONNECTED_TO_PARENT 2 #define FW_SELF_ID_PORT_NOT_CONNECTED 1 #define FW_SELF_ID_PORT_NOT_EXISTS 0 -#if 0 +#if BYTE_ORDER == BIG_ENDIAN union fw_self_id { struct { + u_int32_t id:2, + phy_id:6, + sequel:1, + link_active:1, + gap_count:6, + phy_speed:2, + phy_delay:2, + contender:1, + power_class:3, + port0:2, + port1:2, + port2:2, + initiated_reset:1, + more_packets:1; + } p0; + struct { + u_int32_t + id:2, + phy_id:6, + sequel:1, + sequence_num:3, + :2, + porta:2, + portb:2, + portc:2, + portd:2, + porte:2, + portf:2, + portg:2, + porth:2, + :1, + more_packets:1; + } p1; +}; +#else +union fw_self_id { + struct { u_int32_t more_packets:1, initiated_reset:1, port2:2, port1:2, port0:2, power_class:3, contender:1, phy_delay:2, phy_speed:2, gap_count:6, link_active:1, sequel:1, phy_id:6, id:2; } p0; struct { u_int32_t more_packets:1, reserved1:1, porth:2, portg:2, portf:2, porte:2, portd:2, portc:2, portb:2, porta:2, reserved2:2, sequence_num:3, sequel:1, phy_id:6, id:2; } p1; }; -#else -union fw_self_id { - struct { - u_int8_t more_packets:1, - initiated_reset:1, - port2:2, - port1:2, - port0:2; - u_int8_t power_class:3, - contender:1, - phy_delay:2, - phy_speed:2; - u_int8_t gap_count:6, - link_active:1, - sequel:1; - u_int8_t phy_id:6, - id:2; - } p0; - struct { - u_int8_t more_packets:1, - reserved1:1, - porth:2, - portg:2, - portf:2; - u_int8_t porte:2, - portd:2, - portc:2, - portb:2; - u_int8_t porta:2, - reserved2:2, - sequence_num:3, - sequel:1; - u_int8_t phy_id:6, - id:2; - } p1; -}; #endif struct fw_topology_map { u_int32_t crc:16, crc_len:16; u_int32_t generation; u_int32_t self_id_count:16, node_count:16; union fw_self_id self_id[4*64]; }; struct fw_speed_map { u_int32_t crc:16, crc_len:16; u_int32_t generation; u_int8_t speed[64][64]; }; struct fw_crom_buf { struct fw_eui64 eui; int len; void *ptr; }; -#define FWSTMAXCHUNK 16 /* * FireWire specific system requests. */ -#if 0 -#define FW_SSTDV _IOWR('S', 85, unsigned int) -#endif #define FW_SSTBUF _IOWR('S', 86, struct fw_isobufreq) #define FW_GSTBUF _IOWR('S', 87, struct fw_isobufreq) #define FW_SRSTREAM _IOWR('S', 88, struct fw_isochreq) #define FW_GRSTREAM _IOWR('S', 89, struct fw_isochreq) #define FW_STSTREAM _IOWR('S', 90, struct fw_isochreq) #define FW_GTSTREAM _IOWR('S', 91, struct fw_isochreq) #define FW_ASYREQ _IOWR('S', 92, struct fw_asyreq) #define FW_IBUSRST _IOR('S', 1, unsigned int) #define FW_GDEVLST _IOWR('S', 2, struct fw_devlstreq) #define FW_SBINDADDR _IOWR('S', 3, struct fw_asybindreq) #define FW_CBINDADDR _IOWR('S', 4, struct fw_asybindreq) #define FW_GTPMAP _IOR('S', 5, struct fw_topology_map) #define FW_GCROM _IOWR('S', 7, struct fw_crom_buf) #define FW_SDEUI64 _IOW('S', 20, struct fw_eui64) #define FW_GDEUI64 _IOR('S', 21, struct fw_eui64) #define FWOHCI_RDREG _IOWR('S', 80, struct fw_reg_req_t) #define FWOHCI_WRREG _IOWR('S', 81, struct fw_reg_req_t) #define DUMPDMA _IOWR('S', 82, u_int32_t) #ifdef _KERNEL #define FWMAXNDMA 0x100 /* 8 bits DMA channel id. in device No. */ #if __FreeBSD_version < 500000 #define dev2unit(x) ((minor(x) & 0xff) | (minor(x) >> 8)) #define unit2minor(x) (((x) & 0xff) | (((x) << 8) & ~0xffff)) #endif #define UNIT2MIN(x) (((x) & 0xff) << 8) #define DEV2UNIT(x) ((dev2unit(x) & 0xff00) >> 8) #define DEV2DMACH(x) (dev2unit(x) & 0xff) #define FWMEM_FLAG 0x10000 #define DEV_FWMEM(x) (dev2unit(x) & FWMEM_FLAG) #endif #endif Index: head/sys/dev/firewire/firewire_phy.h =================================================================== --- head/sys/dev/firewire/firewire_phy.h (revision 113583) +++ head/sys/dev/firewire/firewire_phy.h (revision 113584) @@ -1,87 +1,85 @@ /* * Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the acknowledgement as bellow: * * This product includes software developed by K. Kobayashi and H. Shimokawa * * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ * */ #define FW_PHY_PHYSID_REG 0x00 #define FW_PHY_PHYSID (63<<2) #define FW_PHY_ROOT_REG 0x00 #define FW_PHY_ROOT (1<<1) #define FW_PHY_CPS_REG 0x00 #define FW_PHY_CPS (1<<0) #define FW_PHY_RHB_REG 0x01 #define FW_PHY_RHB (1<<7) #define FW_PHY_IBR_REG 0x01 #define FW_PHY_IBR (1<<6) #define FW_PHY_ISBR_REG 0x05 #define FW_PHY_ISBR (1<<6) #define FW_PHY_GC_REG 0x01 #define FW_PHY_SPD_REG 0x02 #define FW_PHY_SPD (3<<6) #define FW_PHY_REV_REG 0x02 #define FW_PHY_REV (3<<4) #define FW_PHY_NP_REG 0x02 #define FW_PHY_NP (15<<0) #define FW_PHY_P1_REG 0x03 #define FW_PHY_P2_REG 0x04 #define FW_PHY_P3_REG 0x05 #define FW_PHY_P_ASTAT (3<<6) #define FW_PHY_P_BSTAT (3<<4) #define FW_PHY_P_CH (1<<3) #define FW_PHY_P_CON (1<<2) #define FW_PHY_LOOPINT_REG 0x06 #define FW_PHY_LOOPINT (1<<7) #define FW_PHY_CPSINT_REG 0x06 #define FW_PHY_CPSNT (1<<6) /* #define FW_PHY_CPS_REG 0x06 #define FW_PHY_CPS (1<<5) */ #define FW_PHY_IR_REG 0x06 #define FW_PHY_IR (1<<4) #define FW_PHY_C_REG 0x06 #define FW_PHY_C (1<<0) #define FW_PHY_ESPD_REG 0x03 #define FW_PHY_ESPD (7<<5) #define FW_PHY_EDEL_REG 0x03 #define FW_PHY_EDEL 15<<0 - - Index: head/sys/dev/firewire/firewirereg.h =================================================================== --- head/sys/dev/firewire/firewirereg.h (revision 113583) +++ head/sys/dev/firewire/firewirereg.h (revision 113584) @@ -1,380 +1,332 @@ /* + * 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 * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the acknowledgement as bellow: * * This product includes software developed by K. Kobayashi and H. Shimokawa * * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ * */ #if __FreeBSD_version >= 500000 typedef struct thread fw_proc; #include #else typedef struct proc fw_proc; #include #endif +#include + #define splfw splimp struct fw_device{ u_int16_t dst; struct fw_eui64 eui; -#if 0 - u_int32_t spec; - u_int32_t ver; -#endif u_int8_t speed; u_int8_t maxrec; u_int8_t nport; u_int8_t power; #define CSRROMOFF 0x400 #define CSRROMSIZE 0x400 int rommax; /* offset from 0xffff f000 0000 */ u_int32_t csrrom[CSRROMSIZE/4]; int rcnt; struct firewire_comm *fc; u_int32_t status; #define FWDEVINIT 1 #define FWDEVATTACHED 2 #define FWDEVINVAL 3 STAILQ_ENTRY(fw_device) link; -#if 0 - LIST_HEAD(, fw_xfer) txqueue; - LIST_HEAD(, fw_xfer) rxqueue; -#endif }; struct firewire_softc { #if __FreeBSD_version >= 500000 dev_t dev; #else dev_t dev[FWMAXNDMA+1]; #endif struct firewire_comm *fc; }; #define FW_MAX_DMACH 0x20 #define FW_MAX_DEVCH FW_MAX_DMACH #define FW_XFERTIMEOUT 1 struct firewire_dev_comm { device_t dev; struct firewire_comm *fc; + void (*post_busreset) __P((void *)); void (*post_explore) __P((void *)); }; struct tcode_info { u_char hdr_len; /* IEEE1394 header length */ u_char flag; #define FWTI_REQ (1 << 0) #define FWTI_RES (1 << 1) #define FWTI_TLABEL (1 << 2) #define FWTI_BLOCK_STR (1 << 3) #define FWTI_BLOCK_ASY (1 << 4) }; struct firewire_comm{ device_t dev; device_t bdev; u_int16_t busid:10, nodeid:6; u_int mode; u_int nport; u_int speed; u_int maxrec; u_int irm; u_int max_node; u_int max_hop; u_int max_asyretry; #define FWPHYASYST (1 << 0) u_int retry_count; u_int32_t ongobus:10, ongonode:6, ongoaddr:16; struct fw_device *ongodev; struct fw_eui64 ongoeui; #define FWMAXCSRDIR 16 SLIST_HEAD(, csrdir) ongocsr; SLIST_HEAD(, csrdir) csrfree; u_int32_t status; #define FWBUSRESET 0 #define FWBUSINIT 1 #define FWBUSCYMELECT 2 #define FWBUSMGRELECT 3 #define FWBUSMGRDONE 4 #define FWBUSEXPLORE 5 #define FWBUSPHYCONF 6 #define FWBUSEXPDONE 7 #define FWBUSCOMPLETION 10 int nisodma; struct fw_eui64 eui; - STAILQ_HEAD(fw_queue, fw_xfer); struct fw_xferq *arq, *atq, *ars, *ats, *it[FW_MAX_DMACH],*ir[FW_MAX_DMACH]; STAILQ_HEAD(, tlabel) tlabels[0x40]; STAILQ_HEAD(, fw_bind) binds; STAILQ_HEAD(, fw_device) devices; STAILQ_HEAD(, fw_xfer) pending; - volatile u_int32_t *sid_buf; u_int sid_cnt; #define CSRSIZE 0x4000 u_int32_t csr_arc[CSRSIZE/4]; #define CROMSIZE 0x400 u_int32_t *config_rom; struct fw_topology_map *topology_map; struct fw_speed_map *speed_map; struct callout busprobe_callout; struct callout bmr_callout; struct callout timeout_callout; struct callout retry_probe_callout; u_int32_t (*cyctimer) __P((struct firewire_comm *)); void (*ibr) __P((struct firewire_comm *)); u_int32_t (*set_bmr) __P((struct firewire_comm *, u_int32_t)); int (*ioctl) __P((dev_t, u_long, caddr_t, int, fw_proc *)); int (*irx_enable) __P((struct firewire_comm *, int)); int (*irx_disable) __P((struct firewire_comm *, int)); int (*itx_enable) __P((struct firewire_comm *, int)); int (*itx_disable) __P((struct firewire_comm *, int)); void (*timeout) __P((void *)); void (*poll) __P((struct firewire_comm *, int, int)); void (*set_intr) __P((struct firewire_comm *, int)); void (*irx_post) __P((struct firewire_comm *, u_int32_t *)); void (*itx_post) __P((struct firewire_comm *, u_int32_t *)); struct tcode_info *tcode; + bus_dma_tag_t dmat; }; #define CSRARC(sc, offset) ((sc)->csr_arc[(offset)/4]) struct csrdir{ u_int32_t ongoaddr; u_int32_t off; SLIST_ENTRY(csrdir) link; }; struct fw_xferq { int flag; #define FWXFERQ_CHTAGMASK 0xff #define FWXFERQ_RUNNING (1 << 8) #define FWXFERQ_STREAM (1 << 9) -#define FWXFERQ_PACKET (1 << 10) #define FWXFERQ_BULK (1 << 11) -#if 0 /* BROKEN */ -#define FWXFERQ_DV (1 << 12) -#endif #define FWXFERQ_MODEMASK (7 << 10) #define FWXFERQ_EXTBUF (1 << 13) #define FWXFERQ_OPEN (1 << 14) #define FWXFERQ_HANDLER (1 << 16) #define FWXFERQ_WAKEUP (1 << 17) void (*start) __P((struct firewire_comm*)); - void (*drain) __P((struct firewire_comm*, struct fw_xfer*)); - struct fw_queue q; + STAILQ_HEAD(, fw_xfer) q; u_int queued; u_int maxq; u_int psize; - u_int packets; STAILQ_HEAD(, fw_bind) binds; - caddr_t buf; + struct fwdma_alloc_multi *buf; u_int bnchunk; u_int bnpacket; struct fw_bulkxfer *bulkxfer; STAILQ_HEAD(, fw_bulkxfer) stvalid; STAILQ_HEAD(, fw_bulkxfer) stfree; STAILQ_HEAD(, fw_bulkxfer) stdma; struct fw_bulkxfer *stproc; -#ifdef FWXFERQ_DV - int dvdbc, dvdiff, dvsync, dvoffset; - struct fw_dvbuf *dvbuf; - STAILQ_HEAD(, fw_dvbuf) dvvalid; - STAILQ_HEAD(, fw_dvbuf) dvfree; - struct fw_dvbuf *dvdma; - struct fw_dvbuf *dvproc; - u_int dvptr; - u_int dvpacket; -#endif struct selinfo rsel; caddr_t sc; void (*hand) __P((struct fw_xferq *)); }; struct fw_bulkxfer{ - caddr_t buf; + int poffset; struct mbuf *mbuf; STAILQ_ENTRY(fw_bulkxfer) link; caddr_t start; caddr_t end; - u_int npacket; int resp; }; -struct fw_dvbuf{ - caddr_t buf; - STAILQ_ENTRY(fw_dvbuf) link; -}; - struct tlabel{ struct fw_xfer *xfer; STAILQ_ENTRY(tlabel) link; }; struct fw_bind{ u_int32_t start_hi, start_lo, addrlen; - struct fw_xfer* xfer; + STAILQ_HEAD(, fw_xfer) xferlist; STAILQ_ENTRY(fw_bind) fclist; STAILQ_ENTRY(fw_bind) chlist; +#define FWACT_NULL 0 +#define FWACT_XFER 2 +#define FWACT_CH 3 + u_int8_t act_type; + u_int8_t sub; }; struct fw_xfer{ caddr_t sc; struct firewire_comm *fc; struct fw_xferq *q; -#ifdef XFER_TIMEOUT - struct callout_handle ch; -#endif struct timeval tv; - struct fw_tlabel *tlabel; + /* XXX should be removed */ + u_int32_t dst; /* XXX for if_fwe */ u_int8_t spd; - u_int8_t tcode; - int resp; + int8_t resp; #define FWXF_INIT 0 #define FWXF_INQ 1 #define FWXF_START 2 #define FWXF_SENT 3 #define FWXF_SENTERR 4 #define FWXF_BUSY 8 #define FWXF_RCVD 10 - int state; + u_int8_t state; u_int8_t retry; u_int8_t tl; - int sub; - int32_t dst; - u_int8_t act_type; -#define FWACT_NULL 0 -#define FWACT_XFER 2 -#define FWACT_CH 3 void (*retry_req) __P((struct fw_xfer *)); union{ void (*hand) __P((struct fw_xfer *)); } act; -#if 0 - union{ - struct { - struct fw_device *device; - } req; - struct { - struct stch *channel; - } stream; - } mode; -#endif struct { - u_int16_t len, off; + int len; caddr_t buf; } send, recv; struct mbuf *mbuf; STAILQ_ENTRY(fw_xfer) link; struct malloc_type *malloc; }; -void fw_sidrcv __P((struct firewire_comm *, caddr_t, u_int, u_int)); -void fw_rcv __P((struct firewire_comm *, caddr_t, u_int, u_int, u_int, u_int)); +void fw_sidrcv __P((struct firewire_comm *, u_int32_t *, u_int)); +void fw_rcv __P((struct firewire_comm *, struct iovec *, int, u_int, u_int)); +void fw_xfer_unload __P(( struct fw_xfer*)); void fw_xfer_free __P(( struct fw_xfer*)); struct fw_xfer *fw_xfer_alloc __P((struct malloc_type *)); +struct fw_xfer *fw_xfer_alloc_buf __P((struct malloc_type *, int, int)); void fw_init __P((struct firewire_comm *)); int fw_tbuf_update __P((struct firewire_comm *, int, int)); int fw_rbuf_update __P((struct firewire_comm *, int, int)); -int fw_readreqq __P((struct firewire_comm *, u_int32_t, u_int32_t, u_int32_t *)); -int fw_writereqb __P((struct firewire_comm *, u_int32_t, u_int32_t, u_int32_t, u_int32_t *)); -int fw_readresb __P((struct firewire_comm *, u_int32_t, u_int32_t, u_int32_t, u_int32_t*)); -int fw_writeres __P((struct firewire_comm *, u_int32_t, u_int32_t)); u_int32_t getcsrdata __P((struct fw_device *, u_int8_t)); void fw_asybusy __P((struct fw_xfer *)); int fw_bindadd __P((struct firewire_comm *, struct fw_bind *)); int fw_bindremove __P((struct firewire_comm *, struct fw_bind *)); int fw_asyreq __P((struct firewire_comm *, int, struct fw_xfer*)); void fw_busreset __P((struct firewire_comm *)); u_int16_t fw_crc16 __P((u_int32_t *, u_int32_t)); void fw_xfer_timeout __P((void *)); void fw_xfer_done __P((struct fw_xfer *)); void fw_asy_callback __P((struct fw_xfer *)); struct fw_device *fw_noderesolve_nodeid __P((struct firewire_comm *, int)); struct fw_device *fw_noderesolve_eui64 __P((struct firewire_comm *, struct fw_eui64 *)); struct fw_bind *fw_bindlookup __P((struct firewire_comm *, u_int32_t, u_int32_t)); void fw_drain_txq __P((struct firewire_comm *)); extern int firewire_debug; extern devclass_t firewire_devclass; #define DV_BROADCAST_ON (1<<30) #define IP_CHANNELS 0x0234 #define STATE_CLEAR 0x0000 #define STATE_SET 0x0004 #define NODE_IDS 0x0008 #define RESET_START 0x000c #define SPLIT_TIMEOUT_HI 0x0018 #define SPLIT_TIMEOUT_LO 0x001c #define CYCLE_TIME 0x0200 #define BUS_TIME 0x0204 #define BUSY_TIMEOUT 0x0210 #define BUS_MGR_ID 0x021c #define BANDWIDTH_AV 0x0220 #define CHANNELS_AV_HI 0x0224 #define CHANNELS_AV_LO 0x0228 #define CONF_ROM 0x0400 #define TOPO_MAP 0x1000 #define SPED_MAP 0x2000 #define oMPR 0x900 #define oPCR 0x904 #define iMPR 0x980 #define iPCR 0x984 #define FWPRI ((PZERO+8)|PCATCH) - -#ifdef __alpha__ -#undef vtophys -#define vtophys(va) alpha_XXX_dmamap((vm_offset_t)(va)) -#endif /* __alpha__ */ #if __FreeBSD_version >= 500000 #define CALLOUT_INIT(x) callout_init(x, 0 /* mpsafe */) #else #define CALLOUT_INIT(x) callout_init(x) #endif MALLOC_DECLARE(M_FW); MALLOC_DECLARE(M_FWXFER); Index: head/sys/dev/firewire/fwcrom.c =================================================================== --- head/sys/dev/firewire/fwcrom.c (revision 113583) +++ head/sys/dev/firewire/fwcrom.c (revision 113584) @@ -1,255 +1,506 @@ /* - * Copyright (C) 2002 + * Copyright (c) 2002-2003 * Hidetoshi Shimokawa. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * * This product includes software developed by Hidetoshi Shimokawa. * * 4. Neither the name of the author nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include -#include -#include +#if defined(_KERNEL) || defined(TEST) +#include +#endif #ifdef _KERNEL #include #include #else #include #include #include #include #include #include #endif +#include +#include void crom_init_context(struct crom_context *cc, u_int32_t *p) { struct csrhdr *hdr; hdr = (struct csrhdr *)p; if (hdr->info_len == 1) { /* minimum ROM */ cc->depth = -1; } p += 1 + hdr->info_len; cc->depth = 0; cc->stack[0].dir = (struct csrdirectory *)p; cc->stack[0].index = 0; } struct csrreg * crom_get(struct crom_context *cc) { struct crom_ptr *ptr; ptr = &cc->stack[cc->depth]; return (&ptr->dir->entry[ptr->index]); } void crom_next(struct crom_context *cc) { struct crom_ptr *ptr; struct csrreg *reg; if (cc->depth < 0) return; reg = crom_get(cc); if ((reg->key & CSRTYPE_MASK) == CSRTYPE_D) { cc->depth ++; if (cc->depth > CROM_MAX_DEPTH) { printf("crom_next: too deep\n"); cc->depth --; goto again; } ptr = &cc->stack[cc->depth]; ptr->dir = (struct csrdirectory *) (reg + reg->val); ptr->index = 0; goto check; } again: ptr = &cc->stack[cc->depth]; ptr->index ++; check: if (ptr->index < ptr->dir->crc_len) return; if (cc->depth > 0) { cc->depth--; goto again; } /* no more data */ cc->depth = -1; } struct csrreg * crom_search_key(struct crom_context *cc, u_int8_t key) { struct csrreg *reg; while(cc->depth >= 0) { reg = crom_get(cc); if (reg->key == key) return reg; crom_next(cc); } return NULL; } void crom_parse_text(struct crom_context *cc, char *buf, int len) { struct csrreg *reg; struct csrtext *textleaf; u_int32_t *bp; int i, qlen; static char *nullstr = "(null)"; reg = crom_get(cc); if (reg->key != CROM_TEXTLEAF) { strncpy(buf, nullstr, len); return; } textleaf = (struct csrtext *)(reg + reg->val); /* XXX should check spec and type */ bp = (u_int32_t *)&buf[0]; qlen = textleaf->crc_len - 2; if (len < qlen * 4) qlen = len/4; for (i = 0; i < qlen; i ++) *bp++ = ntohl(textleaf->text[i]); /* make sure to terminate the string */ if (len <= qlen * 4) buf[len - 1] = 0; else buf[qlen * 4] = 0; } u_int16_t crom_crc(u_int32_t *ptr, int len) { int i, shift; u_int32_t data, sum, crc = 0; for (i = 0; i < len; i++) { data = ptr[i]; for (shift = 28; shift >= 0; shift -= 4) { sum = ((crc >> 12) ^ (data >> shift)) & 0xf; crc = (crc << 4) ^ (sum << 12) ^ (sum << 5) ^ sum; } crc &= 0xffff; } return((u_int16_t) crc); } #ifndef _KERNEL char * crom_desc(struct crom_context *cc, char *buf, int len) { struct csrreg *reg; struct csrdirectory *dir; char *desc; + u_int16_t crc; reg = crom_get(cc); switch (reg->key & CSRTYPE_MASK) { case CSRTYPE_I: snprintf(buf, len, "%d", reg->val); break; - case CSRTYPE_L: case CSRTYPE_C: snprintf(buf, len, "offset=0x%04x(%d)", reg->val, reg->val); break; + case CSRTYPE_L: + /* XXX fall through */ case CSRTYPE_D: dir = (struct csrdirectory *) (reg + reg->val); - snprintf(buf, len, "len=0x%04x(%d) crc=0x%04x", - dir->crc_len, dir->crc_len, dir->crc); + crc = crom_crc((u_int32_t *)&dir->entry[0], dir->crc_len); + len -= snprintf(buf, len, "len=%d crc=0x%04x", + dir->crc_len, dir->crc); + if (crc == dir->crc) + strncat(buf, "(OK) ", len); + else + strncat(buf, "(NG) ", len); + len -= 5; } switch (reg->key) { case 0x03: desc = "module_vendor_ID"; break; case 0x04: desc = "hardware_version"; break; case 0x0c: desc = "node_capabilities"; break; case 0x12: desc = "unit_spec_ID"; break; case 0x13: desc = "unit_sw_version"; break; case 0x14: desc = "logical_unit_number"; break; case 0x17: desc = "model_ID"; break; case 0x38: desc = "command_set_spec_ID"; break; case 0x39: desc = "command_set"; break; case 0x3a: desc = "unit_characteristics"; break; case 0x3b: desc = "command_set_revision"; break; case 0x3c: desc = "firmware_revision"; break; case 0x3d: desc = "reconnect_timeout"; break; case 0x54: desc = "management_agent"; break; case 0x81: desc = "text_leaf"; - crom_parse_text(cc, buf, len); + crom_parse_text(cc, buf + strlen(buf), len); break; case 0xd1: desc = "unit_directory"; break; case 0xd4: desc = "logical_unit_directory"; break; default: desc = "unknown"; } return desc; +} +#endif + +#if defined(_KERNEL) || defined(TEST) + +int +crom_add_quad(struct crom_chunk *chunk, u_int32_t entry) +{ + int index; + + index = chunk->data.crc_len; + if (index >= CROM_MAX_CHUNK_LEN - 1) { + printf("too large chunk %d\n", index); + return(-1); + } + chunk->data.buf[index] = entry; + chunk->data.crc_len++; + return(index); +} + +int +crom_add_entry(struct crom_chunk *chunk, int key, int val) +{ + struct csrreg *reg; + u_int32_t i; + + reg = (struct csrreg *)&i; + reg->key = key; + reg->val = val; + return(crom_add_quad(chunk, (u_int32_t) i)); +} + +int +crom_add_chunk(struct crom_src *src, struct crom_chunk *parent, + struct crom_chunk *child, int key) +{ + int index; + + if (parent == NULL) { + STAILQ_INSERT_TAIL(&src->chunk_list, child, link); + return(0); + } + + index = crom_add_entry(parent, key, 0); + if (index < 0) { + return(-1); + } + child->ref_chunk = parent; + child->ref_index = index; + STAILQ_INSERT_TAIL(&src->chunk_list, child, link); + return(index); +} + +int +crom_add_simple_text(struct crom_src *src, struct crom_chunk *parent, + struct crom_chunk *chunk, char *buf) +{ + struct csrtext *tl; + u_int32_t *p; + int len, i; + + 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); +#else + printf("text(%d) trancated to %td.\n", len, MAX_TEXT); +#endif + len = MAX_TEXT; + } + + tl = (struct csrtext *) &chunk->data; + tl->crc_len = howmany(sizeof(struct csrtext) + len, sizeof(u_int32_t)); + 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 ++) + tl->text[i] = ntohl(*p++); + return (crom_add_chunk(src, parent, chunk, CROM_TEXTLEAF)); +} + +static int +crom_copy(u_int32_t *src, u_int32_t *dst, int *offset, int len, int maxlen) +{ + if (*offset + len > maxlen) { + printf("Config. ROM is too large for the buffer\n"); + return(-1); + } + bcopy(src, (char *)(dst + *offset), len * sizeof(u_int32_t)); + *offset += len; + return(0); +} + +int +crom_load(struct crom_src *src, u_int32_t *buf, int maxlen) +{ + struct crom_chunk *chunk, *parent; + struct csrhdr *hdr; +#if 0 + u_int32_t *ptr; +#endif + int count, offset; + int len; + + offset = 0; + /* Determine offset */ + STAILQ_FOREACH(chunk, &src->chunk_list, link) { + chunk->offset = offset; + /* Assume the offset of the parent is already known */ + parent = chunk->ref_chunk; + if (parent != NULL) { + struct csrreg *reg; + reg = (struct csrreg *) + &parent->data.buf[chunk->ref_index]; + reg->val = offset - + (parent->offset + 1 + chunk->ref_index); + } + offset += 1 + chunk->data.crc_len; + } + + /* Calculate CRC and dump to the buffer */ + len = 1 + src->hdr.info_len; + count = 0; + if (crom_copy((u_int32_t *)&src->hdr, buf, &count, len, maxlen) < 0) + return(-1); + STAILQ_FOREACH(chunk, &src->chunk_list, link) { + chunk->data.crc = + crom_crc(&chunk->data.buf[0], chunk->data.crc_len); + + len = 1 + chunk->data.crc_len; + if (crom_copy((u_int32_t *)&chunk->data, buf, + &count, len, maxlen) < 0) + return(-1); + } + hdr = (struct csrhdr *)buf; + hdr->crc_len = count - 1; + hdr->crc = crom_crc(buf + 1, hdr->crc_len); + +#if 0 + /* byte swap */ + ptr = buf; + for (i = 0; i < count; i ++) { + *ptr = htonl(*ptr); + ptr++; + } +#endif + + return(count); +} +#endif + +#ifdef TEST +int +main () { + struct crom_src src; + struct crom_chunk root,unit1,unit2,unit3; + struct crom_chunk text1,text2,text3,text4,text5,text6,text7; + u_int32_t buf[256], *p; + int i; + + bzero(&src, sizeof(src)); + bzero(&root, sizeof(root)); + bzero(&unit1, sizeof(unit1)); + bzero(&unit2, sizeof(unit2)); + bzero(&unit3, sizeof(unit3)); + bzero(&text1, sizeof(text1)); + bzero(&text2, sizeof(text2)); + bzero(&text3, sizeof(text3)); + bzero(&text3, sizeof(text4)); + bzero(&text3, sizeof(text5)); + bzero(&text3, sizeof(text6)); + bzero(&text3, sizeof(text7)); + bzero(buf, sizeof(buf)); + + /* BUS info sample */ + src.hdr.info_len = 4; + src.businfo.bus_name = CSR_BUS_NAME_IEEE1394; + src.businfo.eui64.hi = 0x11223344; + src.businfo.eui64.lo = 0x55667788; + src.businfo.link_spd = FWSPD_S400; + src.businfo.generation = 0; + src.businfo.max_rom = MAXROM_4; + src.businfo.max_rec = 10; + src.businfo.cyc_clk_acc = 100; + src.businfo.pmc = 0; + src.businfo.bmc = 1; + src.businfo.isc = 1; + src.businfo.cmc = 1; + src.businfo.irmc = 1; + STAILQ_INIT(&src.chunk_list); + + /* Root directory */ + crom_add_chunk(&src, NULL, &root, 0); + crom_add_entry(&root, CSRKEY_NCAP, 0x123456); + /* private company_id */ + crom_add_entry(&root, CSRKEY_VENDOR, 0xacde48); + + crom_add_simple_text(&src, &root, &text1, "FreeBSD"); + crom_add_entry(&root, CSRKEY_HW, __FreeBSD_version); + crom_add_simple_text(&src, &root, &text2, "FreeBSD-5"); + + /* SBP unit directory */ + crom_add_chunk(&src, &root, &unit1, CROM_UDIR); + crom_add_entry(&unit1, CSRKEY_SPEC, CSRVAL_ANSIT10); + crom_add_entry(&unit1, CSRKEY_VER, CSRVAL_T10SBP2); + crom_add_entry(&unit1, CSRKEY_COM_SPEC, CSRVAL_ANSIT10); + crom_add_entry(&unit1, CSRKEY_COM_SET, CSRVAL_SCSI); + /* management_agent */ + crom_add_entry(&unit1, CROM_MGM, 0x1000); + crom_add_entry(&unit1, CSRKEY_UNIT_CH, (10<<8) | 8); + /* Device type and LUN */ + crom_add_entry(&unit1, CROM_LUN, 0); + crom_add_entry(&unit1, CSRKEY_MODEL, 1); + crom_add_simple_text(&src, &unit1, &text3, "scsi_target"); + + /* RFC2734 IPv4 over IEEE1394 */ + crom_add_chunk(&src, &root, &unit2, CROM_UDIR); + crom_add_entry(&unit2, CSRKEY_SPEC, CSRVAL_IETF); + crom_add_simple_text(&src, &unit2, &text4, "IANA"); + crom_add_entry(&unit2, CSRKEY_VER, 1); + crom_add_simple_text(&src, &unit2, &text5, "IPv4"); + + /* RFC3146 IPv6 over IEEE1394 */ + crom_add_chunk(&src, &root, &unit3, CROM_UDIR); + crom_add_entry(&unit3, CSRKEY_SPEC, CSRVAL_IETF); + crom_add_simple_text(&src, &unit3, &text6, "IANA"); + crom_add_entry(&unit3, CSRKEY_VER, 2); + crom_add_simple_text(&src, &unit3, &text7, "IPv6"); + + crom_load(&src, buf, 256); + p = buf; +#define DUMP_FORMAT "%08x %08x %08x %08x %08x %08x %08x %08x\n" + for (i = 0; i < 256/8; i ++) { + printf(DUMP_FORMAT, + p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); + p += 8; + } + return(0); } #endif Index: head/sys/dev/firewire/fwdev.c =================================================================== --- head/sys/dev/firewire/fwdev.c (revision 113583) +++ head/sys/dev/firewire/fwdev.c (revision 113584) @@ -1,952 +1,741 @@ /* + * 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 * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the acknowledgement as bellow: * * This product includes software developed by K. Kobayashi and H. Shimokawa * * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ * */ #include #include #include #include #include #include #include -#include #include #include +#include #include #include #include +#include #include #include #define CDEV_MAJOR 127 #define FWNODE_INVAL 0xffff static d_open_t fw_open; static d_close_t fw_close; static d_ioctl_t fw_ioctl; 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; struct cdevsw firewire_cdevsw = { #if __FreeBSD_version >= 500104 .d_open = fw_open, .d_close = fw_close, .d_read = fw_read, .d_write = fw_write, .d_ioctl = fw_ioctl, .d_poll = fw_poll, .d_mmap = fw_mmap, .d_name = "fw", .d_maj = CDEV_MAJOR, .d_flags = D_MEM #else fw_open, fw_close, fw_read, fw_write, fw_ioctl, fw_poll, fw_mmap, nostrategy, "fw", CDEV_MAJOR, nodump, nopsize, D_MEM #endif }; static int fw_open (dev_t dev, int flags, int fmt, fw_proc *td) { struct firewire_softc *sc; int unit = DEV2UNIT(dev); int sub = DEV2DMACH(dev); 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; } /* Default is per packet mode */ sc->fc->ir[sub]->flag |= FWXFERQ_OPEN; sc->fc->it[sub]->flag |= FWXFERQ_OPEN; - sc->fc->ir[sub]->flag |= FWXFERQ_PACKET; return err; } static int fw_close (dev_t dev, int flags, int fmt, fw_proc *td) { struct firewire_softc *sc; int unit = DEV2UNIT(dev); int sub = DEV2DMACH(dev); struct fw_xfer *xfer; struct fw_bind *fwb; int err = 0; if (DEV_FWMEM(dev)) 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; 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); } -#ifdef FWXFERQ_DV - if(sc->fc->it[sub]->flag & FWXFERQ_DV){ - struct fw_dvbuf *dvbuf; - - if((dvbuf = sc->fc->it[sub]->dvproc) != NULL){ - free(dvbuf->buf, M_FW); - sc->fc->it[sub]->dvproc = NULL; - } - if((dvbuf = sc->fc->it[sub]->dvdma) != NULL){ - free(dvbuf->buf, M_FW); - sc->fc->it[sub]->dvdma = NULL; - } - while((dvbuf = STAILQ_FIRST(&sc->fc->it[sub]->dvvalid)) != NULL){ - STAILQ_REMOVE_HEAD(&sc->fc->it[sub]->dvvalid, link); - free(dvbuf->buf, M_FW); - } - while((dvbuf = STAILQ_FIRST(&sc->fc->it[sub]->dvfree)) != NULL){ - STAILQ_REMOVE_HEAD(&sc->fc->it[sub]->dvfree, link); - free(dvbuf->buf, M_FW); - } - free(sc->fc->it[sub]->dvbuf, M_FW); - sc->fc->it[sub]->dvbuf = NULL; - } -#endif if(sc->fc->ir[sub]->flag & FWXFERQ_EXTBUF){ - free(sc->fc->ir[sub]->buf, M_FW); + 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){ - free(sc->fc->it[sub]->buf, M_FW); + 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; -#ifdef FWXFERQ_DV - sc->fc->it[sub]->dvbuf = NULL; -#endif 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); xfer->resp = 0; - switch(xfer->act_type){ - case FWACT_XFER: - fw_xfer_done(xfer); - break; - default: - break; - } - fw_xfer_free(xfer); + 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); } - sc->fc->ir[sub]->flag &= ~FWXFERQ_MODEMASK; - sc->fc->it[sub]->flag &= ~FWXFERQ_MODEMASK; + sc->fc->ir[sub]->flag &= ~(FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK); + sc->fc->it[sub]->flag &= ~(FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK); return err; } /* * read request. */ static int fw_read (dev_t dev, struct uio *uio, int ioflag) { struct firewire_softc *sc; struct fw_xferq *ir; 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); sc = devclass_get_softc(firewire_devclass, unit); ir = sc->fc->ir[sub]; - if (ir->flag & FWXFERQ_PACKET) { - ir->stproc = NULL; - } readloop: xfer = STAILQ_FIRST(&ir->q); - if ((ir->flag & FWXFERQ_PACKET) == 0 && ir->stproc == NULL) { + if (ir->stproc == NULL) { /* iso bulkxfer */ ir->stproc = STAILQ_FIRST(&ir->stvalid); if (ir->stproc != NULL) { s = splfw(); STAILQ_REMOVE_HEAD(&ir->stvalid, link); splx(s); ir->queued = 0; } } if (xfer == NULL && ir->stproc == NULL) { /* no data avaliable */ if (slept == 0) { slept = 1; - if ((ir->flag & FWXFERQ_RUNNING) == 0 - && (ir->flag & FWXFERQ_PACKET)) { - err = sc->fc->irx_enable(sc->fc, sub); - if (err) - return err; - } ir->flag |= FWXFERQ_WAKEUP; err = tsleep(ir, FWPRI, "fw_read", hz); ir->flag &= ~FWXFERQ_WAKEUP; if (err == 0) goto readloop; } else if (slept == 1) err = EIO; return err; } else if(xfer != NULL) { - /* per packet mode */ + /* 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 + xfer->recv.off); + fp = (struct fw_pkt *)xfer->recv.buf; if(sc->fc->irx_post != NULL) sc->fc->irx_post(sc->fc, fp->mode.ld); - err = uiomove(xfer->recv.buf + xfer->recv.off, xfer->recv.len, uio); + err = uiomove(xfer->recv.buf, xfer->recv.len, uio); + /* XXX we should recycle this xfer */ fw_xfer_free( xfer); } else if(ir->stproc != NULL) { /* iso bulkxfer */ - fp = (struct fw_pkt *)(ir->stproc->buf + ir->queued * ir->psize); + fp = (struct fw_pkt *)fwdma_v_addr(ir->buf, + ir->stproc->poffset + ir->queued); if(sc->fc->irx_post != NULL) sc->fc->irx_post(sc->fc, fp->mode.ld); - if(ntohs(fp->mode.stream.len) == 0){ + if(fp->mode.stream.len == 0){ err = EIO; return err; } err = uiomove((caddr_t)fp, - ntohs(fp->mode.stream.len) + sizeof(u_int32_t), uio); -#if 0 - fp->mode.stream.len = 0; -#endif + fp->mode.stream.len + sizeof(u_int32_t), uio); ir->queued ++; if(ir->queued >= ir->bnpacket){ s = splfw(); STAILQ_INSERT_TAIL(&ir->stfree, ir->stproc, link); splx(s); sc->fc->irx_enable(sc->fc, sub); ir->stproc = NULL; } if (uio->uio_resid >= ir->psize) { slept = -1; goto readloop; } } return err; } static int 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 fw_xfer *xfer; struct fw_xferq *xferq; struct firewire_comm *fc; struct fw_xferq *it; if (DEV_FWMEM(dev)) return fwmem_write(dev, uio, ioflag); sc = devclass_get_softc(firewire_devclass, unit); fc = sc->fc; it = sc->fc->it[sub]; - fp = (struct fw_pkt *)uio->uio_iov->iov_base; - switch(fp->mode.common.tcode){ - case FWTCODE_RREQQ: - case FWTCODE_RREQB: - case FWTCODE_LREQ: - err = EINVAL; - return err; - case FWTCODE_WREQQ: - case FWTCODE_WREQB: - xferq = fc->atq; - break; - case FWTCODE_STREAM: - if(it->flag & FWXFERQ_PACKET){ - xferq = fc->atq; - }else{ - xferq = NULL; - } - break; - case FWTCODE_WRES: - case FWTCODE_RRESQ: - case FWTCODE_RRESB: - case FWTCODE_LRES: - xferq = fc->ats; - break; - default: - err = EINVAL; - return err; - } + xferq = NULL; /* Discard unsent buffered stream packet, when sending Asyrequrst */ if(xferq != NULL && it->stproc != NULL){ s = splfw(); STAILQ_INSERT_TAIL(&it->stfree, it->stproc, link); splx(s); it->stproc = NULL; } -#ifdef FWXFERQ_DV - if(xferq == NULL && !(it->flag & FWXFERQ_DV)){ -#else if (xferq == NULL) { -#endif isoloop: if (it->stproc == NULL) { it->stproc = STAILQ_FIRST(&it->stfree); if (it->stproc != NULL) { s = splfw(); STAILQ_REMOVE_HEAD(&it->stfree, link); splx(s); it->queued = 0; } else if (slept == 0) { slept = 1; err = sc->fc->itx_enable(sc->fc, sub); if (err) return err; err = tsleep(it, FWPRI, "fw_write", hz); if (err) return err; goto isoloop; } else { err = EIO; return err; } } - fp = (struct fw_pkt *) - (it->stproc->buf + it->queued * it->psize); + fp = (struct fw_pkt *)fwdma_v_addr(it->buf, + it->stproc->poffset + it->queued); err = uiomove((caddr_t)fp, sizeof(struct fw_isohdr), uio); err = uiomove((caddr_t)fp->mode.stream.payload, - ntohs(fp->mode.stream.len), uio); + fp->mode.stream.len, uio); it->queued ++; if (it->queued >= it->bnpacket) { s = splfw(); STAILQ_INSERT_TAIL(&it->stvalid, it->stproc, link); splx(s); it->stproc = NULL; err = sc->fc->itx_enable(sc->fc, sub); } if (uio->uio_resid >= sizeof(struct fw_isohdr)) { slept = 0; goto isoloop; } return err; } -#ifdef FWXFERQ_DV - if(xferq == NULL && it->flag & FWXFERQ_DV){ -dvloop: - if(it->dvproc == NULL){ - it->dvproc = STAILQ_FIRST(&it->dvfree); - if(it->dvproc != NULL){ - s = splfw(); - STAILQ_REMOVE_HEAD(&it->dvfree, link); - splx(s); - it->dvptr = 0; - }else if(slept == 0){ - slept = 1; - err = sc->fc->itx_enable(sc->fc, sub); - if(err){ - return err; - } - err = tsleep(it, FWPRI, "fw_write", hz); - if(err){ - return err; - } - goto dvloop; - }else{ - err = EIO; - return err; - } - } -#if 0 /* What's this for? (it->dvptr? overwritten by the following uiomove)*/ - fp = (struct fw_pkt *)(it->dvproc->buf + it->queued * it->psize); - fp->mode.stream.len = htons(uio->uio_resid - sizeof(u_int32_t)); -#endif - err = uiomove(it->dvproc->buf + it->dvptr, - uio->uio_resid, uio); - it->dvptr += it->psize; - if(err){ - return err; - } - if(it->dvptr >= it->psize * it->dvpacket){ - s = splfw(); - STAILQ_INSERT_TAIL(&it->dvvalid, it->dvproc, link); - splx(s); - it->dvproc = NULL; - err = fw_tbuf_update(sc->fc, sub, 0); - if(err){ - return err; - } - err = sc->fc->itx_enable(sc->fc, sub); - } - return err; - } -#endif - if(xferq != NULL){ - xfer = fw_xfer_alloc(M_FWXFER); + if (xferq != NULL) { + xfer = fw_xfer_alloc_buf(M_FWXFER, uio->uio_resid, 12); if(xfer == NULL){ err = ENOMEM; return err; } - xfer->send.buf = malloc(uio->uio_resid, M_FW, M_NOWAIT); - if(xfer->send.buf == NULL){ - fw_xfer_free( xfer); - err = ENOBUFS; - return err; - } - xfer->dst = ntohs(fp->mode.hdr.dst); -#if 0 - switch(fp->mode.common.tcode){ - case FWTCODE_WREQQ: - case FWTCODE_WREQB: - if((tl = fw_get_tlabel(fc, xfer)) == -1 ){ - fw_xfer_free( xfer); - err = EAGAIN; - return err; - } - fp->mode.hdr.tlrt = tl << 2; - default: - break; - } - - xfer->tl = fp->mode.hdr.tlrt >> 2; - xfer->tcode = fp->mode.common.tcode; - xfer->fc = fc; - xfer->q = xferq; - xfer->act_type = FWACT_XFER; - xfer->retry_req = fw_asybusy; -#endif + xfer->dst = fp->mode.hdr.dst; xfer->send.len = uio->uio_resid; - xfer->send.off = 0; xfer->spd = 0;/* XXX: how to setup it */ xfer->act.hand = fw_asy_callback; err = uiomove(xfer->send.buf, uio->uio_resid, uio); if(err){ fw_xfer_free( xfer); return err; } -#if 0 - fw_asystart(xfer); -#else fw_asyreq(fc, -1, xfer); -#endif err = tsleep(xfer, FWPRI, "fw_write", hz); if(xfer->resp == EBUSY) return EBUSY; fw_xfer_free( xfer); return err; } return EINVAL; } /* * ioctl support. */ int fw_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td) { struct firewire_softc *sc; int unit = DEV2UNIT(dev); int sub = DEV2DMACH(dev); - int i, len, err = 0; + int s, i, len, err = 0; struct fw_device *fwdev; struct fw_bind *fwb; struct fw_xferq *ir, *it; struct fw_xfer *xfer; struct fw_pkt *fp; struct fw_devinfo *devinfo; struct fw_devlstreq *fwdevlst = (struct fw_devlstreq *)data; struct fw_asyreq *asyreq = (struct fw_asyreq *)data; struct fw_isochreq *ichreq = (struct fw_isochreq *)data; struct fw_isobufreq *ibufreq = (struct fw_isobufreq *)data; struct fw_asybindreq *bindreq = (struct fw_asybindreq *)data; struct fw_crom_buf *crom_buf = (struct fw_crom_buf *)data; if (DEV_FWMEM(dev)) return fwmem_ioctl(dev, cmd, data, flag, td); sc = devclass_get_softc(firewire_devclass, unit); if (!data) return(EINVAL); 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; break; case FW_GTSTREAM: ichreq->ch = sc->fc->it[sub]->flag & 0x3f; ichreq->tag =(sc->fc->it[sub]->flag) >> 2 & 0x3; err = 0; 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); break; case FW_GRSTREAM: ichreq->ch = sc->fc->ir[sub]->flag & 0x3f; ichreq->tag =(sc->fc->ir[sub]->flag) >> 2 & 0x3; err = 0; break; -#ifdef FWXFERQ_DV - case FW_SSTDV: - ibufreq = (struct fw_isobufreq *) - malloc(sizeof(struct fw_isobufreq), M_FW, M_NOWAIT); - if(ibufreq == NULL){ - err = ENOMEM; - break; - } -#if DV_PAL -#define FWDVPACKET 300 -#else -#define FWDVPACKET 250 -#endif -#define FWDVPMAX 512 - ibufreq->rx.nchunk = 8; - ibufreq->rx.npacket = 50; - ibufreq->rx.psize = FWDVPMAX; - - ibufreq->tx.nchunk = 5; - ibufreq->tx.npacket = FWDVPACKET + 30; /* > 320 or 267 */ - ibufreq->tx.psize = FWDVPMAX; - - err = fw_ioctl(dev, FW_SSTBUF, (caddr_t)ibufreq, flag, td); - sc->fc->it[sub]->dvpacket = FWDVPACKET; - free(ibufreq, M_FW); -/* reserve a buffer space */ -#define NDVCHUNK 8 - sc->fc->it[sub]->dvproc = NULL; - sc->fc->it[sub]->dvdma = NULL; - sc->fc->it[sub]->flag |= FWXFERQ_DV; - /* XXX check malloc failure */ - sc->fc->it[sub]->dvbuf - = (struct fw_dvbuf *)malloc(sizeof(struct fw_dvbuf) * NDVCHUNK, M_FW, M_NOWAIT); - STAILQ_INIT(&sc->fc->it[sub]->dvvalid); - STAILQ_INIT(&sc->fc->it[sub]->dvfree); - for( i = 0 ; i < NDVCHUNK ; i++){ - /* XXX check malloc failure */ - sc->fc->it[sub]->dvbuf[i].buf - = malloc(FWDVPMAX * sc->fc->it[sub]->dvpacket, M_FW, M_NOWAIT); - STAILQ_INSERT_TAIL(&sc->fc->it[sub]->dvfree, - &sc->fc->it[sub]->dvbuf[i], link); - } - break; -#endif 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); } - if(ibufreq->rx.nchunk > FWSTMAXCHUNK || - ibufreq->tx.nchunk > FWSTMAXCHUNK){ - return(EINVAL); - } ir->bulkxfer - = (struct fw_bulkxfer *)malloc(sizeof(struct fw_bulkxfer) * ibufreq->rx.nchunk, M_FW, 0); + = (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, 0); + = (struct fw_bulkxfer *)malloc(sizeof(struct fw_bulkxfer) * ibufreq->tx.nchunk, M_FW, M_WAITOK); if(it->bulkxfer == NULL){ return(ENOMEM); } - ir->buf = malloc( - ibufreq->rx.nchunk * ibufreq->rx.npacket - /* XXX psize must be 2^n and less or - equal to PAGE_SIZE */ - * ((ibufreq->rx.psize + 3) &~3), - M_FW, 0); - 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); + 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); + } } - it->buf = malloc( - ibufreq->tx.nchunk * ibufreq->tx.npacket - /* XXX psize must be 2^n and less or - equal to PAGE_SIZE */ - * ((ibufreq->tx.psize + 3) &~3), - M_FW, 0); - if(it->buf == NULL){ - free(ir->bulkxfer, M_FW); - free(it->bulkxfer, M_FW); - free(ir->buf, M_FW); - ir->bulkxfer = NULL; - it->bulkxfer = NULL; - it->buf = NULL; - return(ENOMEM); + 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); + } } 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; -#ifdef FWXFERQ_DV - it->dvdbc = 0; - it->dvdiff = 0; - it->dvsync = 0; - it->dvoffset = 0; -#endif - STAILQ_INIT(&ir->stvalid); STAILQ_INIT(&ir->stfree); STAILQ_INIT(&ir->stdma); ir->stproc = NULL; STAILQ_INIT(&it->stvalid); STAILQ_INIT(&it->stfree); STAILQ_INIT(&it->stdma); it->stproc = NULL; for(i = 0 ; i < sc->fc->ir[sub]->bnchunk; i++){ - ir->bulkxfer[i].buf = - ir->buf + i * ir->bnpacket * ir->psize; + ir->bulkxfer[i].poffset = i * ir->bnpacket; + ir->bulkxfer[i].mbuf = NULL; STAILQ_INSERT_TAIL(&ir->stfree, &ir->bulkxfer[i], link); - ir->bulkxfer[i].npacket = ir->bnpacket; } for(i = 0 ; i < sc->fc->it[sub]->bnchunk; i++){ - it->bulkxfer[i].buf = - it->buf + i * it->bnpacket * it->psize; + it->bulkxfer[i].poffset = i * it->bnpacket; + it->bulkxfer[i].mbuf = NULL; STAILQ_INSERT_TAIL(&it->stfree, &it->bulkxfer[i], link); - it->bulkxfer[i].npacket = it->bnpacket; } 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; 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(M_FWXFER); + 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 = ntohs(fp->mode.hdr.dst); + xfer->dst = fp->mode.hdr.dst; break; case FWASREQEUI: fwdev = fw_noderesolve_eui64(sc->fc, &asyreq->req.dst.eui); if (fwdev == NULL) { device_printf(sc->fc->bdev, "cannot find node\n"); err = EINVAL; goto error; } xfer->dst = fwdev->dst; - fp->mode.hdr.dst = htons(FWLOCALBUS | xfer->dst); + fp->mode.hdr.dst = FWLOCALBUS | xfer->dst; break; case FWASRESTL: /* XXX what's this? */ break; case FWASREQSTREAM: /* nothing to do */ break; } xfer->spd = asyreq->req.sped; - xfer->send.len = asyreq->req.len; - xfer->send.buf = malloc(xfer->send.len, M_FW, M_NOWAIT); - if(xfer->send.buf == NULL){ - return ENOMEM; - } - xfer->send.off = 0; bcopy(fp, xfer->send.buf, xfer->send.len); 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 + xfer->recv.off, fp, asyreq->req.len); + bcopy(xfer->recv.buf, fp, asyreq->req.len); } error: fw_xfer_free( xfer); break; case FW_IBUSRST: sc->fc->ibr(sc->fc); break; case FW_CBINDADDR: fwb = fw_bindlookup(sc->fc, bindreq->start.hi, bindreq->start.lo); if(fwb == NULL){ err = EINVAL; break; } STAILQ_REMOVE(&sc->fc->binds, fwb, fw_bind, fclist); STAILQ_REMOVE(&sc->fc->ir[sub]->binds, fwb, fw_bind, chlist); free(fwb, M_FW); break; case FW_SBINDADDR: if(bindreq->len <= 0 ){ err = EINVAL; break; } if(bindreq->start.hi > 0xffff ){ err = EINVAL; break; } fwb = (struct fw_bind *)malloc(sizeof (struct fw_bind), M_FW, M_NOWAIT); if(fwb == NULL){ err = ENOMEM; break; } fwb->start_hi = bindreq->start.hi; fwb->start_lo = bindreq->start.lo; fwb->addrlen = bindreq->len; + fwb->sub = sub; + fwb->act_type = FWACT_CH; xfer = fw_xfer_alloc(M_FWXFER); if(xfer == NULL){ err = ENOMEM; return err; } - xfer->act_type = FWACT_CH; - xfer->sub = sub; xfer->fc = sc->fc; - fwb->xfer = xfer; + s = splfw(); + /* XXX broken. need multiple xfer */ + STAILQ_INIT(&fwb->xferlist); + STAILQ_INSERT_TAIL(&fwb->xferlist, xfer, link); + splx(s); err = fw_bindadd(sc->fc, fwb); break; case FW_GDEVLST: i = len = 1; /* myself */ devinfo = &fwdevlst->dev[0]; devinfo->dst = sc->fc->nodeid; devinfo->status = 0; /* XXX */ devinfo->eui.hi = sc->fc->eui.hi; devinfo->eui.lo = sc->fc->eui.lo; STAILQ_FOREACH(fwdev, &sc->fc->devices, link) { if(len < FW_MAX_DEVLST){ devinfo = &fwdevlst->dev[len++]; devinfo->dst = fwdev->dst; devinfo->status = (fwdev->status == FWDEVINVAL)?0:1; devinfo->eui.hi = fwdev->eui.hi; devinfo->eui.lo = fwdev->eui.lo; } i++; } fwdevlst->n = i; fwdevlst->info_len = len; break; case FW_GTPMAP: bcopy(sc->fc->topology_map, data, (sc->fc->topology_map->crc_len + 1) * 4); break; case FW_GCROM: STAILQ_FOREACH(fwdev, &sc->fc->devices, link) if (FW_EUI64_EQUAL(fwdev->eui, crom_buf->eui)) break; if (fwdev == NULL) { err = FWNODE_INVAL; break; } -#if 0 - if (fwdev->csrrom[0] >> 24 == 1) - len = 4; - else - len = (1 + ((fwdev->csrrom[0] >> 16) & 0xff)) * 4; -#else if (fwdev->rommax < CSRROMOFF) len = 0; else len = fwdev->rommax - CSRROMOFF + 4; -#endif if (crom_buf->len < len) len = crom_buf->len; else crom_buf->len = len; err = copyout(&fwdev->csrrom[0], crom_buf->ptr, len); break; default: sc->fc->ioctl (dev, cmd, data, flag, td); break; } return err; } int fw_poll(dev_t dev, int events, fw_proc *td) { 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); revents = 0; tmp = POLLIN | POLLRDNORM; if (events & tmp) { if (STAILQ_FIRST(&sc->fc->ir[sub]->q) != NULL) revents |= tmp; else selrecord(td, &sc->fc->ir[sub]->rsel); } tmp = POLLOUT | POLLWRNORM; if (events & tmp) { /* XXX should be fixed */ revents |= tmp; } return revents; } static int -#if __FreeBSD_version < 500000 +#if __FreeBSD_version < 500102 fw_mmap (dev_t dev, vm_offset_t offset, int nproto) #else -fw_mmap (dev_t dev, vm_offset_t offset, vm_offset_t *paddr, int nproto) +fw_mmap (dev_t dev, vm_offset_t offset, vm_paddr_t *paddr, int nproto) #endif { struct firewire_softc *fc; int unit = DEV2UNIT(dev); if (DEV_FWMEM(dev)) -#if __FreeBSD_version < 500000 +#if __FreeBSD_version < 500102 return fwmem_mmap(dev, offset, nproto); #else return fwmem_mmap(dev, offset, paddr, nproto); #endif fc = devclass_get_softc(firewire_devclass, unit); return EINVAL; } Index: head/sys/dev/firewire/fwdma.c =================================================================== --- head/sys/dev/firewire/fwdma.c (nonexistent) +++ head/sys/dev/firewire/fwdma.c (revision 113584) @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2003 + * Hidetoshi Shimokawa. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * + * This product includes software developed by Hidetoshi Shimokawa. + * + * 4. Neither the name of the author nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +static void +fwdma_map_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error) +{ + bus_addr_t *baddr; + + if (error) + printf("fwdma_map_cb: error=%d\n", error); + baddr = (bus_addr_t *)arg; + *baddr = segs->ds_addr; +} + +void * +fwdma_malloc(struct firewire_comm *fc, int alignment, bus_size_t size, + struct fwdma_alloc *dma, int flag) +{ + int err; + + dma->v_addr = NULL; + err = bus_dma_tag_create( + /*parent*/ fc->dmat, + /*alignment*/ alignment, + /*boundary*/ 0, + /*lowaddr*/ BUS_SPACE_MAXADDR_32BIT, + /*highaddr*/ BUS_SPACE_MAXADDR, + /*filter*/NULL, /*filterarg*/NULL, + /*maxsize*/ size, + /*nsegments*/ 1, + /*maxsegsz*/ BUS_SPACE_MAXSIZE_32BIT, + /*flags*/ BUS_DMA_ALLOCNOW, &dma->dma_tag); + if (err) { + printf("fwdma_malloc: failed(1)\n"); + return(NULL); + } + + err = bus_dmamem_alloc(dma->dma_tag, &dma->v_addr, + flag, &dma->dma_map); + if (err) { + printf("fwdma_malloc: failed(2)\n"); + /* XXX destory tag */ + return(NULL); + } + + bus_dmamap_load(dma->dma_tag, dma->dma_map, dma->v_addr, + size, fwdma_map_cb, &dma->bus_addr, /*flags*/0); + + return(dma->v_addr); +} + +void +fwdma_free(struct firewire_comm *fc, struct fwdma_alloc *dma) +{ + bus_dmamap_unload(dma->dma_tag, dma->dma_map); + bus_dmamem_free(dma->dma_tag, dma->v_addr, dma->dma_map); + bus_dma_tag_destroy(dma->dma_tag); +} + + +void * +fwdma_malloc_size(bus_dma_tag_t dmat, bus_dmamap_t *dmamap, + bus_size_t size, bus_addr_t *bus_addr, int flag) +{ + void *v_addr; + + if (bus_dmamem_alloc(dmat, &v_addr, flag, dmamap)) { + printf("fwdma_malloc_size: failed(1)\n"); + return(NULL); + } + bus_dmamap_load(dmat, *dmamap, v_addr, size, + fwdma_map_cb, bus_addr, /*flags*/0); + return(v_addr); +} + +void +fwdma_free_size(bus_dma_tag_t dmat, bus_dmamap_t dmamap, + void *vaddr, bus_size_t size) +{ + bus_dmamap_unload(dmat, dmamap); + bus_dmamem_free(dmat, vaddr, dmamap); +} + +/* + * Allocate multisegment dma buffers + * each segment size is eqaul to ssize except last segment. + */ +struct fwdma_alloc_multi * +fwdma_malloc_multiseg(struct firewire_comm *fc, int alignment, + int esize, int n, int flag) +{ + struct fwdma_alloc_multi *am; + struct fwdma_seg *seg; + bus_size_t ssize; + int nseg; + + if (esize > PAGE_SIZE) { + /* round up to PAGE_SIZE */ + esize = ssize = roundup2(esize, PAGE_SIZE); + nseg = n; + } else { + /* allocate PAGE_SIZE segment for small elements */ + ssize = rounddown(PAGE_SIZE, esize); + nseg = howmany(n, ssize / esize); + } + am = (struct fwdma_alloc_multi *)malloc(sizeof(struct fwdma_alloc_multi) + + sizeof(struct fwdma_seg)*nseg, M_FW, M_WAITOK); + if (am == NULL) { + printf("fwdma_malloc_multiseg: malloc failed\n"); + return(NULL); + } + am->ssize = ssize; + am->esize = esize; + am->nseg = 0; + if (bus_dma_tag_create( + /*parent*/ fc->dmat, + /*alignment*/ alignment, + /*boundary*/ 0, + /*lowaddr*/ BUS_SPACE_MAXADDR_32BIT, + /*highaddr*/ BUS_SPACE_MAXADDR, + /*filter*/NULL, /*filterarg*/NULL, + /*maxsize*/ ssize, + /*nsegments*/ 1, + /*maxsegsz*/ BUS_SPACE_MAXSIZE_32BIT, + /*flags*/ BUS_DMA_ALLOCNOW, &am->dma_tag)) { + printf("fwdma_malloc_multiseg: tag_create failed\n"); + free(am, M_FW); + return(NULL); + } + +#if 0 +#if __FreeBSD_version < 500000 + printf("malloc_multi: ssize=%d nseg=%d\n", ssize, nseg); +#else + printf("malloc_multi: ssize=%td nseg=%d\n", ssize, nseg); +#endif +#endif + for (seg = &am->seg[0]; nseg --; seg ++) { + seg->v_addr = fwdma_malloc_size(am->dma_tag, &seg->dma_map, + ssize, &seg->bus_addr, flag); + if (seg->v_addr == NULL) { + printf("fwdma_malloc_multi: malloc_size failed %d\n", + am->nseg); + fwdma_free_multiseg(am); + return(NULL); + } + am->nseg++; + } + return(am); +} + +void +fwdma_free_multiseg(struct fwdma_alloc_multi *am) +{ + struct fwdma_seg *seg; + + for (seg = &am->seg[0]; am->nseg --; seg ++) { + fwdma_free_size(am->dma_tag, seg->dma_map, + seg->v_addr, am->ssize); + } + bus_dma_tag_destroy(am->dma_tag); + free(am, M_FW); +} Property changes on: head/sys/dev/firewire/fwdma.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: head/sys/dev/firewire/fwdma.h =================================================================== --- head/sys/dev/firewire/fwdma.h (nonexistent) +++ head/sys/dev/firewire/fwdma.h (revision 113584) @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2003 + * Hidetoshi Shimokawa. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * + * This product includes software developed by Hidetoshi Shimokawa. + * + * 4. Neither the name of the author nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#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; + void * v_addr; + bus_addr_t bus_addr; +}; + +struct fwdma_seg { + bus_dmamap_t dma_map; + void * v_addr; + bus_addr_t bus_addr; +}; + +struct fwdma_alloc_multi { + bus_size_t ssize; + bus_size_t esize; + int nseg; + bus_dma_tag_t dma_tag; + struct fwdma_seg seg[0]; +}; + +static __inline void * +fwdma_v_addr(struct fwdma_alloc_multi *am, int index) +{ + bus_size_t ssize = am->ssize; + int offset = am->esize * index; + + return ((caddr_t)am->seg[offset / ssize].v_addr + (offset % ssize)); +} + +static __inline bus_addr_t +fwdma_bus_addr(struct fwdma_alloc_multi *am, int index) +{ + bus_size_t ssize = am->ssize; + int offset = am->esize * index; + + return (am->seg[offset / ssize].bus_addr + (offset % ssize)); +} + +static __inline void +fwdma_sync(struct fwdma_alloc *dma, bus_dmasync_op_t op) +{ + bus_dmamap_sync(dma->dma_tag, dma->dma_map, op); +} + +static __inline void +fwdma_sync_multiseg(struct fwdma_alloc_multi *am, + int start, int end, bus_dmasync_op_t op) +{ + struct fwdma_seg *seg, *eseg; + + seg = &am->seg[am->esize * start / am->ssize]; + eseg = &am->seg[am->esize * end / am->ssize]; + for (; seg <= eseg; seg ++) + bus_dmamap_sync(am->dma_tag, seg->dma_map, op); +} + +static __inline void +fwdma_sync_multiseg_all(struct fwdma_alloc_multi *am, bus_dmasync_op_t op) +{ + struct fwdma_seg *seg; + int i; + + seg = &am->seg[0]; + for (i = 0; i < am->nseg; i++, seg++) + bus_dmamap_sync(am->dma_tag, seg->dma_map, op); +} + +void *fwdma_malloc(struct firewire_comm *, int, bus_size_t, struct fwdma_alloc *, int); +void fwdma_free(struct firewire_comm *, struct fwdma_alloc *); +void *fwdma_malloc_size(bus_dma_tag_t, bus_dmamap_t *, bus_size_t, bus_addr_t *, int); +void fwdma_free_size(bus_dma_tag_t, bus_dmamap_t, void *, bus_size_t); +struct fwdma_alloc_multi *fwdma_malloc_multiseg(struct firewire_comm *, + int, int, int, int); +void fwdma_free_multiseg(struct fwdma_alloc_multi *); + Property changes on: head/sys/dev/firewire/fwdma.h ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: head/sys/dev/firewire/fwmem.c =================================================================== --- head/sys/dev/firewire/fwmem.c (revision 113583) +++ head/sys/dev/firewire/fwmem.c (revision 113584) @@ -1,431 +1,419 @@ /* - * Copyright (C) 2002 + * Copyright (c) 2002-2003 * Hidetoshi Shimokawa. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * * This product includes software developed by Hidetoshi Shimokawa. * * 4. Neither the name of the author nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #include #include #include #include #include -#include #include #include +#include #include #include #include #include #include #include static int fwmem_speed=2, fwmem_debug=0; static struct fw_eui64 fwmem_eui64; SYSCTL_DECL(_hw_firewire); SYSCTL_NODE(_hw_firewire, OID_AUTO, fwmem, CTLFLAG_RD, 0, "FireWire Memory Access"); SYSCTL_UINT(_hw_firewire_fwmem, OID_AUTO, eui64_hi, CTLFLAG_RW, &fwmem_eui64.hi, 0, "Fwmem target EUI64 high"); SYSCTL_UINT(_hw_firewire_fwmem, OID_AUTO, eui64_lo, CTLFLAG_RW, &fwmem_eui64.lo, 0, "Fwmem target EUI64 low"); SYSCTL_INT(_hw_firewire_fwmem, OID_AUTO, speed, CTLFLAG_RW, &fwmem_speed, 0, "Fwmem link speed"); SYSCTL_INT(_debug, OID_AUTO, fwmem_debug, CTLFLAG_RW, &fwmem_debug, 0, "Fwmem driver debug flag"); -static struct fw_xfer *fwmem_xfer_req(struct fw_device *, caddr_t, - int, int, void *); - static struct fw_xfer * fwmem_xfer_req( struct fw_device *fwdev, caddr_t sc, int spd, - int len, + int slen, + int rlen, void *hand) { struct fw_xfer *xfer; - xfer = fw_xfer_alloc(M_FWXFER); + xfer = fw_xfer_alloc_buf(M_FWXFER, slen, rlen); if (xfer == NULL) return NULL; xfer->fc = fwdev->fc; xfer->dst = FWLOCALBUS | fwdev->dst; if (spd < 0) xfer->spd = fwdev->speed; else xfer->spd = min(spd, fwdev->speed); - xfer->send.len = len; - xfer->send.buf = malloc(len, M_FW, M_NOWAIT | M_ZERO); - - if (xfer->send.buf == NULL) { - fw_xfer_free(xfer); - return NULL; - } - - xfer->send.off = 0; xfer->act.hand = hand; xfer->retry_req = fw_asybusy; xfer->sc = sc; return xfer; } struct fw_xfer * fwmem_read_quad( struct fw_device *fwdev, caddr_t sc, u_int8_t spd, u_int16_t dst_hi, u_int32_t dst_lo, void (*hand)(struct fw_xfer *)) { struct fw_xfer *xfer; struct fw_pkt *fp; - xfer = fwmem_xfer_req(fwdev, sc, spd, 12, hand); + xfer = fwmem_xfer_req(fwdev, sc, spd, 12, 16, hand); if (xfer == NULL) return NULL; fp = (struct fw_pkt *)xfer->send.buf; fp->mode.rreqq.tcode = FWTCODE_RREQQ; - fp->mode.rreqq.dst = htons(xfer->dst); - fp->mode.rreqq.dest_hi = htons(dst_hi); - fp->mode.rreqq.dest_lo = htonl(dst_lo); + fp->mode.rreqq.dst = xfer->dst; + fp->mode.rreqq.dest_hi = dst_hi; + fp->mode.rreqq.dest_lo = dst_lo; if (fwmem_debug) printf("fwmem_read_quad: %d %04x:%08x\n", fwdev->dst, dst_hi, dst_lo); if (fw_asyreq(xfer->fc, -1, xfer) == 0) return xfer; fw_xfer_free(xfer); return NULL; } struct fw_xfer * fwmem_write_quad( struct fw_device *fwdev, caddr_t sc, u_int8_t spd, u_int16_t dst_hi, u_int32_t dst_lo, u_int32_t data, void (*hand)(struct fw_xfer *)) { struct fw_xfer *xfer; struct fw_pkt *fp; - xfer = fwmem_xfer_req(fwdev, sc, spd, 16, hand); + xfer = fwmem_xfer_req(fwdev, sc, spd, 16, 12, hand); if (xfer == NULL) return NULL; fp = (struct fw_pkt *)xfer->send.buf; fp->mode.wreqq.tcode = FWTCODE_WREQQ; - fp->mode.wreqq.dst = htons(xfer->dst); - fp->mode.wreqq.dest_hi = htons(dst_hi); - fp->mode.wreqq.dest_lo = htonl(dst_lo); + fp->mode.wreqq.dst = xfer->dst; + fp->mode.wreqq.dest_hi = dst_hi; + fp->mode.wreqq.dest_lo = dst_lo; fp->mode.wreqq.data = data; if (fwmem_debug) printf("fwmem_write_quad: %d %04x:%08x %08x\n", fwdev->dst, dst_hi, dst_lo, data); if (fw_asyreq(xfer->fc, -1, xfer) == 0) return xfer; fw_xfer_free(xfer); return NULL; } struct fw_xfer * fwmem_read_block( struct fw_device *fwdev, caddr_t sc, u_int8_t spd, u_int16_t dst_hi, u_int32_t dst_lo, int len, void (*hand)(struct fw_xfer *)) { struct fw_xfer *xfer; struct fw_pkt *fp; - xfer = fwmem_xfer_req(fwdev, sc, spd, 16, hand); + xfer = fwmem_xfer_req(fwdev, sc, spd, 16, roundup2(16+len,4), hand); if (xfer == NULL) return NULL; fp = (struct fw_pkt *)xfer->send.buf; fp->mode.rreqb.tcode = FWTCODE_RREQB; - fp->mode.rreqb.dst = htons(xfer->dst); - fp->mode.rreqb.dest_hi = htons(dst_hi); - fp->mode.rreqb.dest_lo = htonl(dst_lo); - fp->mode.rreqb.len = htons(len); + 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; if (fwmem_debug) printf("fwmem_read_block: %d %04x:%08x %d\n", fwdev->dst, dst_hi, dst_lo, len); if (fw_asyreq(xfer->fc, -1, xfer) == 0) return xfer; fw_xfer_free(xfer); return NULL; } struct fw_xfer * fwmem_write_block( struct fw_device *fwdev, caddr_t sc, u_int8_t spd, u_int16_t dst_hi, u_int32_t dst_lo, int len, char *data, void (*hand)(struct fw_xfer *)) { struct fw_xfer *xfer; struct fw_pkt *fp; - xfer = fwmem_xfer_req(fwdev, sc, spd, 16 + roundup(len, 4), hand); + xfer = fwmem_xfer_req(fwdev, sc, spd, roundup(16+len, 4), 12, hand); if (xfer == NULL) return NULL; fp = (struct fw_pkt *)xfer->send.buf; fp->mode.wreqb.tcode = FWTCODE_WREQB; - fp->mode.wreqb.dst = htons(xfer->dst); - fp->mode.wreqb.dest_hi = htons(dst_hi); - fp->mode.wreqb.dest_lo = htonl(dst_lo); - fp->mode.wreqb.len = htons(len); + 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); if (fwmem_debug) printf("fwmem_write_block: %d %04x:%08x %d\n", fwdev->dst, dst_hi, dst_lo, len); if (fw_asyreq(xfer->fc, -1, xfer) == 0) return xfer; fw_xfer_free(xfer); return NULL; } 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, 0); + 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; return (0); } int fwmem_close (dev_t dev, int flags, int fmt, fw_proc *td) { free(dev->si_drv1, M_FW); return (0); } #define MAXLEN 2048 #define USE_QUAD 0 int fwmem_read (dev_t dev, struct uio *uio, int ioflag) { 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; sc = devclass_get_softc(firewire_devclass, unit); fwdev = fw_noderesolve_eui64(sc->fc, (struct fw_eui64 *)dev->si_drv1); if (fwdev == NULL) { if (fwmem_debug) printf("fwmem: no such device ID:%08x%08x\n", fwmem_eui64.hi, fwmem_eui64.lo); return EINVAL; } 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 - + xfer->recv.off + 4*3, 4, uio); + 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 - + xfer->recv.off + 4*4, len, uio); + err = uiomove(xfer->recv.buf + 4*4, len, uio); } fw_xfer_free(xfer); } return err; } int fwmem_write (dev_t dev, struct uio *uio, int ioflag) { 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, quad; char *data; off_t offset; int len; sc = devclass_get_softc(firewire_devclass, unit); fwdev = fw_noderesolve_eui64(sc->fc, (struct fw_eui64 *)dev->si_drv1); if (fwdev == NULL) { if (fwmem_debug) printf("fwmem: no such device ID:%08x%08x\n", fwmem_eui64.hi, fwmem_eui64.lo); return EINVAL; } - data = malloc(MAXLEN, M_FW, 0); + 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); } free(data, M_FW); return err; } int fwmem_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td) { int err = 0; switch (cmd) { case FW_SDEUI64: bcopy(data, dev->si_drv1, sizeof(struct fw_eui64)); break; case FW_GDEUI64: bcopy(dev->si_drv1, data, sizeof(struct fw_eui64)); break; default: err = EINVAL; } return(err); } int fwmem_poll (dev_t dev, int events, fw_proc *td) { return EINVAL; } int -#if __FreeBSD_version < 500000 +#if __FreeBSD_version < 500102 fwmem_mmap (dev_t dev, vm_offset_t offset, int nproto) #else -fwmem_mmap (dev_t dev, vm_offset_t offset, vm_offset_t *paddr, int nproto) +fwmem_mmap (dev_t dev, vm_offset_t offset, vm_paddr_t *paddr, int nproto) #endif { return EINVAL; } Index: head/sys/dev/firewire/fwmem.h =================================================================== --- head/sys/dev/firewire/fwmem.h (revision 113583) +++ head/sys/dev/firewire/fwmem.h (revision 113584) @@ -1,52 +1,52 @@ /* - * Copyright (C) 2002 + * Copyright (C) 2002-2003 * Hidetoshi Shimokawa. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * * This product includes software developed by Hidetoshi Shimokawa. * * 4. Neither the name of the author nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ struct fw_xfer *fwmem_read_quad(struct fw_device *, caddr_t, u_int8_t, u_int16_t, u_int32_t, 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 *)); 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 *)); 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 *)); d_open_t fwmem_open; d_close_t fwmem_close; d_ioctl_t fwmem_ioctl; d_read_t fwmem_read; d_write_t fwmem_write; d_poll_t fwmem_poll; d_mmap_t fwmem_mmap; Index: head/sys/dev/firewire/fwohci.c =================================================================== --- head/sys/dev/firewire/fwohci.c (revision 113583) +++ head/sys/dev/firewire/fwohci.c (revision 113584) @@ -1,2849 +1,2846 @@ /* + * 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 * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the acknowledgement as bellow: * * This product includes software developed by K. Kobayashi and H. Shimokawa * * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ * */ #define ATRQ_CH 0 #define ATRS_CH 1 #define ARRQ_CH 2 #define ARRS_CH 3 #define ITX_CH 4 #define IRX_CH 0x24 #include #include #include #include #include #include #include #include #include #include -#include #include #include #include #include +#include #include #include #include #include /* for rdtsc proto for clock.h below */ #include #include #include -#include -#include -#include /* for vtophys proto */ #include #include +#include #include #include #include #include #undef OHCI_DEBUG static char dbcode[16][0x10]={"OUTM", "OUTL","INPM","INPL", "STOR","LOAD","NOP ","STOP",}; + static char dbkey[8][0x10]={"ST0", "ST1","ST2","ST3", "UNDEF","REG","SYS","DEV"}; +static char dbcond[4][0x10]={"NEV","C=1", "C=0", "ALL"}; char fwohcicode[32][0x20]={ "No stat","Undef","long","miss Ack err", "underrun","overrun","desc err", "data read err", "data write err","bus reset","timeout","tcode err", "Undef","Undef","unknown event","flushed", "Undef","ack complete","ack pend","Undef", "ack busy_X","ack busy_A","ack busy_B","Undef", "Undef","Undef","Undef","ack tardy", "Undef","ack data_err","ack type_err",""}; + #define MAX_SPEED 2 extern char linkspeed[MAX_SPEED+1][0x10]; -static char dbcond[4][0x10]={"NEV","C=1", "C=0", "ALL"}; u_int32_t tagbit[4] = { 1 << 28, 1 << 29, 1 << 30, 1 << 31}; static struct tcode_info tinfo[] = { /* hdr_len block flag*/ /* 0 WREQQ */ {16, FWTI_REQ | FWTI_TLABEL}, /* 1 WREQB */ {16, FWTI_REQ | FWTI_TLABEL | FWTI_BLOCK_ASY}, /* 2 WRES */ {12, FWTI_RES}, /* 3 XXX */ { 0, 0}, /* 4 RREQQ */ {12, FWTI_REQ | FWTI_TLABEL}, /* 5 RREQB */ {16, FWTI_REQ | FWTI_TLABEL}, /* 6 RRESQ */ {16, FWTI_RES}, /* 7 RRESB */ {16, FWTI_RES | FWTI_BLOCK_ASY}, /* 8 CYCS */ { 0, 0}, /* 9 LREQ */ {16, FWTI_REQ | FWTI_TLABEL | FWTI_BLOCK_ASY}, /* a STREAM */ { 4, FWTI_REQ | FWTI_BLOCK_STR}, /* b LRES */ {16, FWTI_RES | FWTI_BLOCK_ASY}, /* c XXX */ { 0, 0}, /* d XXX */ { 0, 0}, /* e PHY */ {12, FWTI_REQ}, /* f XXX */ { 0, 0} }; #define OHCI_WRITE_SIGMASK 0xffff0000 #define OHCI_READ_SIGMASK 0xffff0000 #define OWRITE(sc, r, x) bus_space_write_4((sc)->bst, (sc)->bsh, (r), (x)) #define OREAD(sc, r) bus_space_read_4((sc)->bst, (sc)->bsh, (r)) static void fwohci_ibr __P((struct firewire_comm *)); -static void fwohci_db_init __P((struct fwohci_dbch *)); +static void fwohci_db_init __P((struct fwohci_softc *, struct fwohci_dbch *)); static void fwohci_db_free __P((struct fwohci_dbch *)); static void fwohci_arcv __P((struct fwohci_softc *, struct fwohci_dbch *, int)); -static void fwohci_ircv __P((struct fwohci_softc *, struct fwohci_dbch *, int)); static void fwohci_txd __P((struct fwohci_softc *, struct fwohci_dbch *)); static void fwohci_start_atq __P((struct firewire_comm *)); static void fwohci_start_ats __P((struct firewire_comm *)); static void fwohci_start __P((struct fwohci_softc *, struct fwohci_dbch *)); -static void fwohci_drain_atq __P((struct firewire_comm *, struct fw_xfer *)); -static void fwohci_drain_ats __P((struct firewire_comm *, struct fw_xfer *)); -static void fwohci_drain __P((struct firewire_comm *, struct fw_xfer *, struct fwohci_dbch *)); static u_int32_t fwphy_wrdata __P(( struct fwohci_softc *, u_int32_t, u_int32_t)); static u_int32_t fwphy_rddata __P(( struct fwohci_softc *, u_int32_t)); static int fwohci_rx_enable __P((struct fwohci_softc *, struct fwohci_dbch *)); static int fwohci_tx_enable __P((struct fwohci_softc *, struct fwohci_dbch *)); static int fwohci_irx_enable __P((struct firewire_comm *, int)); -static int fwohci_irxpp_enable __P((struct firewire_comm *, int)); -static int fwohci_irxbuf_enable __P((struct firewire_comm *, int)); static int fwohci_irx_disable __P((struct firewire_comm *, int)); +#if BYTE_ORDER == BIG_ENDIAN static void fwohci_irx_post __P((struct firewire_comm *, u_int32_t *)); +#endif static int fwohci_itxbuf_enable __P((struct firewire_comm *, int)); static int fwohci_itx_disable __P((struct firewire_comm *, int)); static void fwohci_timeout __P((void *)); static void fwohci_poll __P((struct firewire_comm *, int, int)); static void fwohci_set_intr __P((struct firewire_comm *, int)); -static int fwohci_add_rx_buf __P((struct fwohcidb_tr *, unsigned short, int, void *, void *)); -static int fwohci_add_tx_buf __P((struct fwohcidb_tr *, unsigned short, int, void *)); + +static int fwohci_add_rx_buf __P((struct fwohci_dbch *, struct fwohcidb_tr *, int, struct fwdma_alloc *)); +static int fwohci_add_tx_buf __P((struct fwohci_dbch *, struct fwohcidb_tr *, int)); static void dump_db __P((struct fwohci_softc *, u_int32_t)); -static void print_db __P((volatile struct fwohcidb *, u_int32_t , u_int32_t)); +static void print_db __P((struct fwohcidb_tr *, volatile struct fwohcidb *, u_int32_t , u_int32_t)); static void dump_dma __P((struct fwohci_softc *, u_int32_t)); static u_int32_t fwohci_cyctimer __P((struct firewire_comm *)); static void fwohci_rbuf_update __P((struct fwohci_softc *, int)); static void fwohci_tbuf_update __P((struct fwohci_softc *, int)); void fwohci_txbufdb __P((struct fwohci_softc *, int , struct fw_bulkxfer *)); +#if FWOHCI_TASKQUEUE +static void fwohci_complete(void *, int); +#endif /* * memory allocated for DMA programs */ #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 #define OHCI_CROMHDR 0x18 #define OHCI_BUS_OPT 0x20 #define OHCI_BUSIRMC (1 << 31) #define OHCI_BUSCMC (1 << 30) #define OHCI_BUSISC (1 << 29) #define OHCI_BUSBMC (1 << 28) #define OHCI_BUSPMC (1 << 27) #define OHCI_BUSFNC OHCI_BUSIRMC | OHCI_BUSCMC | OHCI_BUSISC |\ OHCI_BUSBMC | OHCI_BUSPMC #define OHCI_EUID_HI 0x24 #define OHCI_EUID_LO 0x28 #define OHCI_CROMPTR 0x34 #define OHCI_HCCCTL 0x50 #define OHCI_HCCCTLCLR 0x54 #define OHCI_AREQHI 0x100 #define OHCI_AREQHICLR 0x104 #define OHCI_AREQLO 0x108 #define OHCI_AREQLOCLR 0x10c #define OHCI_PREQHI 0x110 #define OHCI_PREQHICLR 0x114 #define OHCI_PREQLO 0x118 #define OHCI_PREQLOCLR 0x11c #define OHCI_PREQUPPER 0x120 #define OHCI_SID_BUF 0x64 #define OHCI_SID_CNT 0x68 +#define OHCI_SID_ERR (1 << 31) #define OHCI_SID_CNT_MASK 0xffc #define OHCI_IT_STAT 0x90 #define OHCI_IT_STATCLR 0x94 #define OHCI_IT_MASK 0x98 #define OHCI_IT_MASKCLR 0x9c #define OHCI_IR_STAT 0xa0 #define OHCI_IR_STATCLR 0xa4 #define OHCI_IR_MASK 0xa8 #define OHCI_IR_MASKCLR 0xac #define OHCI_LNKCTL 0xe0 #define OHCI_LNKCTLCLR 0xe4 #define OHCI_PHYACCESS 0xec #define OHCI_CYCLETIMER 0xf0 #define OHCI_DMACTL(off) (off) #define OHCI_DMACTLCLR(off) (off + 4) #define OHCI_DMACMD(off) (off + 0xc) #define OHCI_DMAMATCH(off) (off + 0x10) #define OHCI_ATQOFF 0x180 #define OHCI_ATQCTL OHCI_ATQOFF #define OHCI_ATQCTLCLR (OHCI_ATQOFF + 4) #define OHCI_ATQCMD (OHCI_ATQOFF + 0xc) #define OHCI_ATQMATCH (OHCI_ATQOFF + 0x10) #define OHCI_ATSOFF 0x1a0 #define OHCI_ATSCTL OHCI_ATSOFF #define OHCI_ATSCTLCLR (OHCI_ATSOFF + 4) #define OHCI_ATSCMD (OHCI_ATSOFF + 0xc) #define OHCI_ATSMATCH (OHCI_ATSOFF + 0x10) #define OHCI_ARQOFF 0x1c0 #define OHCI_ARQCTL OHCI_ARQOFF #define OHCI_ARQCTLCLR (OHCI_ARQOFF + 4) #define OHCI_ARQCMD (OHCI_ARQOFF + 0xc) #define OHCI_ARQMATCH (OHCI_ARQOFF + 0x10) #define OHCI_ARSOFF 0x1e0 #define OHCI_ARSCTL OHCI_ARSOFF #define OHCI_ARSCTLCLR (OHCI_ARSOFF + 4) #define OHCI_ARSCMD (OHCI_ARSOFF + 0xc) #define OHCI_ARSMATCH (OHCI_ARSOFF + 0x10) #define OHCI_ITOFF(CH) (0x200 + 0x10 * (CH)) #define OHCI_ITCTL(CH) (OHCI_ITOFF(CH)) #define OHCI_ITCTLCLR(CH) (OHCI_ITOFF(CH) + 4) #define OHCI_ITCMD(CH) (OHCI_ITOFF(CH) + 0xc) #define OHCI_IROFF(CH) (0x400 + 0x20 * (CH)) #define OHCI_IRCTL(CH) (OHCI_IROFF(CH)) #define OHCI_IRCTLCLR(CH) (OHCI_IROFF(CH) + 4) #define OHCI_IRCMD(CH) (OHCI_IROFF(CH) + 0xc) #define OHCI_IRMATCH(CH) (OHCI_IROFF(CH) + 0x10) d_ioctl_t fwohci_ioctl; /* * Communication with PHY device */ static u_int32_t fwphy_wrdata( struct fwohci_softc *sc, u_int32_t addr, u_int32_t data) { u_int32_t fun; addr &= 0xf; data &= 0xff; fun = (PHYDEV_WRCMD | (addr << PHYDEV_REGADDR) | (data << PHYDEV_WRDATA)); OWRITE(sc, OHCI_PHYACCESS, fun); DELAY(100); return(fwphy_rddata( sc, addr)); } static u_int32_t fwohci_set_bus_manager(struct firewire_comm *fc, u_int node) { struct fwohci_softc *sc = (struct fwohci_softc *)fc; int i; u_int32_t bm; #define OHCI_CSR_DATA 0x0c #define OHCI_CSR_COMP 0x10 #define OHCI_CSR_CONT 0x14 #define OHCI_BUS_MANAGER_ID 0 OWRITE(sc, OHCI_CSR_DATA, node); OWRITE(sc, OHCI_CSR_COMP, 0x3f); OWRITE(sc, OHCI_CSR_CONT, OHCI_BUS_MANAGER_ID); for (i = 0; !(OREAD(sc, OHCI_CSR_CONT) & (1<<31)) && (i < 1000); i++) DELAY(10); bm = OREAD(sc, OHCI_CSR_DATA); if((bm & 0x3f) == 0x3f) bm = node; if (bootverbose) device_printf(sc->fc.dev, "fw_set_bus_manager: %d->%d (loop=%d)\n", bm, node, i); return(bm); } static u_int32_t fwphy_rddata(struct fwohci_softc *sc, u_int addr) { u_int32_t fun, stat; u_int i, retry = 0; addr &= 0xf; #define MAX_RETRY 100 again: OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_REG_FAIL); fun = PHYDEV_RDCMD | (addr << PHYDEV_REGADDR); OWRITE(sc, OHCI_PHYACCESS, fun); for ( i = 0 ; i < MAX_RETRY ; i ++ ){ fun = OREAD(sc, OHCI_PHYACCESS); if ((fun & PHYDEV_RDCMD) == 0 && (fun & PHYDEV_RDDONE) != 0) break; DELAY(100); } if(i >= MAX_RETRY) { if (bootverbose) device_printf(sc->fc.dev, "phy read failed(1).\n"); if (++retry < MAX_RETRY) { DELAY(100); goto again; } } /* Make sure that SCLK is started */ stat = OREAD(sc, FWOHCI_INTSTAT); if ((stat & OHCI_INT_REG_FAIL) != 0 || ((fun >> PHYDEV_REGADDR) & 0xf) != addr) { if (bootverbose) device_printf(sc->fc.dev, "phy read failed(2).\n"); if (++retry < MAX_RETRY) { DELAY(100); goto again; } } if (bootverbose || retry >= MAX_RETRY) device_printf(sc->fc.dev, "fwphy_rddata: loop=%d, retry=%d\n", i, retry); #undef MAX_RETRY return((fun >> PHYDEV_RDDATA )& 0xff); } /* Device specific ioctl. */ int fwohci_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td) { struct firewire_softc *sc; struct fwohci_softc *fc; int unit = DEV2UNIT(dev); int err = 0; struct fw_reg_req_t *reg = (struct fw_reg_req_t *) data; u_int32_t *dmach = (u_int32_t *) data; sc = devclass_get_softc(firewire_devclass, unit); if(sc == NULL){ return(EINVAL); } fc = (struct fwohci_softc *)sc->fc; if (!data) return(EINVAL); switch (cmd) { case FWOHCI_WRREG: #define OHCI_MAX_REG 0x800 if(reg->addr <= OHCI_MAX_REG){ OWRITE(fc, reg->addr, reg->data); reg->data = OREAD(fc, reg->addr); }else{ err = EINVAL; } break; case FWOHCI_RDREG: if(reg->addr <= OHCI_MAX_REG){ reg->data = OREAD(fc, reg->addr); }else{ err = EINVAL; } break; /* Read DMA descriptors for debug */ case DUMPDMA: if(*dmach <= OHCI_MAX_DMA_CH ){ dump_dma(fc, *dmach); dump_db(fc, *dmach); }else{ err = EINVAL; } break; default: break; } return err; } static int fwohci_probe_phy(struct fwohci_softc *sc, device_t dev) { u_int32_t reg, reg2; int e1394a = 1; /* * probe PHY parameters * 0. to prove PHY version, whether compliance of 1394a. * 1. to probe maximum speed supported by the PHY and * number of port supported by core-logic. * It is not actually available port on your PC . */ OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_LPS); -#if 0 - /* XXX wait for SCLK. */ - DELAY(100000); -#endif reg = fwphy_rddata(sc, FW_PHY_SPD_REG); if((reg >> 5) != 7 ){ sc->fc.mode &= ~FWPHYASYST; sc->fc.nport = reg & FW_PHY_NP; sc->fc.speed = reg & FW_PHY_SPD >> 6; if (sc->fc.speed > MAX_SPEED) { device_printf(dev, "invalid speed %d (fixed to %d).\n", sc->fc.speed, MAX_SPEED); sc->fc.speed = MAX_SPEED; } device_printf(dev, "Phy 1394 only %s, %d ports.\n", linkspeed[sc->fc.speed], sc->fc.nport); }else{ reg2 = fwphy_rddata(sc, FW_PHY_ESPD_REG); sc->fc.mode |= FWPHYASYST; sc->fc.nport = reg & FW_PHY_NP; sc->fc.speed = (reg2 & FW_PHY_ESPD) >> 5; if (sc->fc.speed > MAX_SPEED) { device_printf(dev, "invalid speed %d (fixed to %d).\n", sc->fc.speed, MAX_SPEED); sc->fc.speed = MAX_SPEED; } device_printf(dev, "Phy 1394a available %s, %d ports.\n", linkspeed[sc->fc.speed], sc->fc.nport); /* check programPhyEnable */ reg2 = fwphy_rddata(sc, 5); #if 0 if (e1394a && (OREAD(sc, OHCI_HCCCTL) & OHCI_HCC_PRPHY)) { #else /* XXX force to enable 1394a */ if (e1394a) { #endif if (bootverbose) device_printf(dev, "Enable 1394a Enhancements\n"); /* enable EAA EMC */ reg2 |= 0x03; /* set aPhyEnhanceEnable */ OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_PHYEN); OWRITE(sc, OHCI_HCCCTLCLR, OHCI_HCC_PRPHY); } else { /* for safe */ reg2 &= ~0x83; } reg2 = fwphy_wrdata(sc, 5, reg2); } reg = fwphy_rddata(sc, FW_PHY_SPD_REG); if((reg >> 5) == 7 ){ reg = fwphy_rddata(sc, 4); reg |= 1 << 6; fwphy_wrdata(sc, 4, reg); reg = fwphy_rddata(sc, 4); } return 0; } void fwohci_reset(struct fwohci_softc *sc, device_t dev) { int i, max_rec, speed; u_int32_t reg, reg2; struct fwohcidb_tr *db_tr; /* Disable interrupt */ OWRITE(sc, FWOHCI_INTMASKCLR, ~0); /* Now stopping all DMA channel */ OWRITE(sc, OHCI_ARQCTLCLR, OHCI_CNTL_DMA_RUN); OWRITE(sc, OHCI_ARSCTLCLR, OHCI_CNTL_DMA_RUN); OWRITE(sc, OHCI_ATQCTLCLR, OHCI_CNTL_DMA_RUN); OWRITE(sc, OHCI_ATSCTLCLR, OHCI_CNTL_DMA_RUN); OWRITE(sc, OHCI_IR_MASKCLR, ~0); for( i = 0 ; i < sc->fc.nisodma ; i ++ ){ OWRITE(sc, OHCI_IRCTLCLR(i), OHCI_CNTL_DMA_RUN); OWRITE(sc, OHCI_ITCTLCLR(i), OHCI_CNTL_DMA_RUN); } /* FLUSH FIFO and reset Transmitter/Reciever */ OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_RESET); if (bootverbose) device_printf(dev, "resetting OHCI..."); i = 0; while(OREAD(sc, OHCI_HCCCTL) & OHCI_HCC_RESET) { if (i++ > 100) break; DELAY(1000); } if (bootverbose) printf("done (loop=%d)\n", i); /* Probe phy */ fwohci_probe_phy(sc, dev); /* Probe link */ reg = OREAD(sc, OHCI_BUS_OPT); reg2 = reg | OHCI_BUSFNC; max_rec = (reg & 0x0000f000) >> 12; speed = (reg & 0x00000007); device_printf(dev, "Link %s, max_rec %d bytes.\n", linkspeed[speed], MAXREC(max_rec)); /* XXX fix max_rec */ sc->fc.maxrec = sc->fc.speed + 8; if (max_rec != sc->fc.maxrec) { reg2 = (reg2 & 0xffff0fff) | (sc->fc.maxrec << 12); device_printf(dev, "max_rec %d -> %d\n", MAXREC(max_rec), MAXREC(sc->fc.maxrec)); } if (bootverbose) device_printf(dev, "BUS_OPT 0x%x -> 0x%x\n", reg, reg2); OWRITE(sc, OHCI_BUS_OPT, reg2); /* Initialize registers */ OWRITE(sc, OHCI_CROMHDR, sc->fc.config_rom[0]); - OWRITE(sc, OHCI_CROMPTR, vtophys(&sc->fc.config_rom[0])); + OWRITE(sc, OHCI_CROMPTR, sc->crom_dma.bus_addr); OWRITE(sc, OHCI_HCCCTLCLR, OHCI_HCC_BIGEND); OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_POSTWR); - OWRITE(sc, OHCI_SID_BUF, vtophys(sc->fc.sid_buf)); + 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); /* Force to start async RX DMA */ sc->arrq.xferq.flag &= ~FWXFERQ_RUNNING; sc->arrs.xferq.flag &= ~FWXFERQ_RUNNING; fwohci_rx_enable(sc, &sc->arrq); fwohci_rx_enable(sc, &sc->arrs); /* 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) ; for( i = 0, db_tr = sc->atrq.top; i < sc->atrq.ndb ; i ++, db_tr = STAILQ_NEXT(db_tr, link)){ db_tr->xfer = NULL; } for( i = 0, db_tr = sc->atrs.top; i < sc->atrs.ndb ; i ++, db_tr = STAILQ_NEXT(db_tr, link)){ db_tr->xfer = NULL; } /* Enable interrupt */ OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_ERR | OHCI_INT_PHY_SID | OHCI_INT_DMA_ATRQ | OHCI_INT_DMA_ATRS | OHCI_INT_DMA_PRRQ | OHCI_INT_DMA_PRRS | OHCI_INT_PHY_BUS_R | OHCI_INT_PW_ERR); fwohci_set_intr(&sc->fc, 1); } int fwohci_init(struct fwohci_softc *sc, device_t dev) { int i; u_int32_t reg; u_int8_t ui[8]; +#if FWOHCI_TASKQUEUE + TASK_INIT(&sc->fwohci_task_complete, 0, fwohci_complete, sc); +#endif + reg = OREAD(sc, OHCI_VERSION); device_printf(dev, "OHCI version %x.%x (ROM=%d)\n", (reg>>16) & 0xff, reg & 0xff, (reg>>24) & 1); /* Available Isochrounous DMA channel probe */ OWRITE(sc, OHCI_IT_MASK, 0xffffffff); OWRITE(sc, OHCI_IR_MASK, 0xffffffff); reg = OREAD(sc, OHCI_IT_MASK) & OREAD(sc, OHCI_IR_MASK); OWRITE(sc, OHCI_IT_MASKCLR, 0xffffffff); OWRITE(sc, OHCI_IR_MASKCLR, 0xffffffff); for (i = 0; i < 0x20; i++) if ((reg & (1 << i)) == 0) break; sc->fc.nisodma = i; device_printf(dev, "No. of Isochronous channel is %d.\n", i); sc->fc.arq = &sc->arrq.xferq; sc->fc.ars = &sc->arrs.xferq; sc->fc.atq = &sc->atrq.xferq; sc->fc.ats = &sc->atrs.xferq; + sc->arrq.xferq.psize = roundup2(FWPMAX_S400, PAGE_SIZE); + sc->arrs.xferq.psize = roundup2(FWPMAX_S400, PAGE_SIZE); + sc->atrq.xferq.psize = roundup2(FWPMAX_S400, PAGE_SIZE); + sc->atrs.xferq.psize = roundup2(FWPMAX_S400, PAGE_SIZE); + sc->arrq.xferq.start = NULL; sc->arrs.xferq.start = NULL; sc->atrq.xferq.start = fwohci_start_atq; sc->atrs.xferq.start = fwohci_start_ats; - sc->arrq.xferq.drain = NULL; - sc->arrs.xferq.drain = NULL; - sc->atrq.xferq.drain = fwohci_drain_atq; - sc->atrs.xferq.drain = fwohci_drain_ats; + sc->arrq.xferq.buf = NULL; + sc->arrs.xferq.buf = NULL; + sc->atrq.xferq.buf = NULL; + sc->atrs.xferq.buf = NULL; sc->arrq.ndesc = 1; sc->arrs.ndesc = 1; sc->atrq.ndesc = 8; /* equal to maximum of mbuf chains */ sc->atrs.ndesc = 2; sc->arrq.ndb = NDB; sc->arrs.ndb = NDB / 2; sc->atrq.ndb = NDB; sc->atrs.ndb = NDB / 2; - sc->arrq.dummy = NULL; - sc->arrs.dummy = NULL; - sc->atrq.dummy = NULL; - sc->atrs.dummy = NULL; 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].ndb = 0; sc->ir[i].ndb = 0; } sc->fc.tcode = tinfo; + sc->fc.dev = dev; - sc->cromptr = (u_int32_t *) malloc(CROMSIZE * 2, M_FW, M_NOWAIT); - - if(sc->cromptr == NULL){ - device_printf(dev, "cromptr alloc failed."); + sc->fc.config_rom = fwdma_malloc(&sc->fc, CROMSIZE, CROMSIZE, + &sc->crom_dma, BUS_DMA_WAITOK); + if(sc->fc.config_rom == NULL){ + device_printf(dev, "config_rom alloc failed."); return ENOMEM; } - sc->fc.dev = dev; - sc->fc.config_rom = &(sc->cromptr[CROMSIZE/4]); +#if 1 sc->fc.config_rom[1] = 0x31333934; sc->fc.config_rom[2] = 0xf000a002; sc->fc.config_rom[3] = OREAD(sc, OHCI_EUID_HI); sc->fc.config_rom[4] = OREAD(sc, OHCI_EUID_LO); sc->fc.config_rom[5] = 0; sc->fc.config_rom[0] = (4 << 24) | (5 << 16); sc->fc.config_rom[0] |= fw_crc16(&sc->fc.config_rom[1], 5*4); +#endif /* SID recieve buffer must allign 2^11 */ #define OHCI_SIDSIZE (1 << 11) - sc->fc.sid_buf = (u_int32_t *) malloc(OHCI_SIDSIZE, M_FW, M_NOWAIT); - if (sc->fc.sid_buf == NULL) { - device_printf(dev, "sid_buf alloc failed.\n"); + sc->sid_buf = fwdma_malloc(&sc->fc, OHCI_SIDSIZE, OHCI_SIDSIZE, + &sc->sid_dma, BUS_DMA_WAITOK); + if (sc->sid_buf == NULL) { + device_printf(dev, "sid_buf alloc failed."); return ENOMEM; } - if (((vm_offset_t) sc->fc.sid_buf & (OHCI_SIDSIZE - 1)) != 0) { - device_printf(dev, "sid_buf(%p) not aligned.\n", - sc->fc.sid_buf); + + fwdma_malloc(&sc->fc, sizeof(u_int32_t), sizeof(u_int32_t), + &sc->dummy_dma, BUS_DMA_WAITOK); + + if (sc->dummy_dma.v_addr == NULL) { + device_printf(dev, "dummy_dma alloc failed."); return ENOMEM; } - - fwohci_db_init(&sc->arrq); + + fwohci_db_init(sc, &sc->arrq); if ((sc->arrq.flags & FWOHCI_DBCH_INIT) == 0) return ENOMEM; - fwohci_db_init(&sc->arrs); + fwohci_db_init(sc, &sc->arrs); if ((sc->arrs.flags & FWOHCI_DBCH_INIT) == 0) return ENOMEM; - fwohci_db_init(&sc->atrq); + fwohci_db_init(sc, &sc->atrq); if ((sc->atrq.flags & FWOHCI_DBCH_INIT) == 0) return ENOMEM; - fwohci_db_init(&sc->atrs); + fwohci_db_init(sc, &sc->atrs); if ((sc->atrs.flags & FWOHCI_DBCH_INIT) == 0) return ENOMEM; sc->fc.eui.hi = OREAD(sc, FWOHCIGUID_H); sc->fc.eui.lo = OREAD(sc, FWOHCIGUID_L); for( i = 0 ; i < 8 ; i ++) ui[i] = FW_EUI64_BYTE(&sc->fc.eui,i); device_printf(dev, "EUI64 %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", ui[0], ui[1], ui[2], ui[3], ui[4], ui[5], ui[6], ui[7]); sc->fc.ioctl = fwohci_ioctl; sc->fc.cyctimer = fwohci_cyctimer; sc->fc.set_bmr = fwohci_set_bus_manager; sc->fc.ibr = fwohci_ibr; sc->fc.irx_enable = fwohci_irx_enable; sc->fc.irx_disable = fwohci_irx_disable; sc->fc.itx_enable = fwohci_itxbuf_enable; sc->fc.itx_disable = fwohci_itx_disable; +#if BYTE_ORDER == BIG_ENDIAN sc->fc.irx_post = fwohci_irx_post; +#else + sc->fc.irx_post = NULL; +#endif sc->fc.itx_post = NULL; sc->fc.timeout = fwohci_timeout; sc->fc.poll = fwohci_poll; sc->fc.set_intr = fwohci_set_intr; + sc->intmask = sc->irstat = sc->itstat = 0; + fw_init(&sc->fc); fwohci_reset(sc, dev); return 0; } void fwohci_timeout(void *arg) { struct fwohci_softc *sc; sc = (struct fwohci_softc *)arg; } u_int32_t fwohci_cyctimer(struct firewire_comm *fc) { struct fwohci_softc *sc = (struct fwohci_softc *)fc; return(OREAD(sc, OHCI_CYCLETIMER)); } int fwohci_detach(struct fwohci_softc *sc, device_t dev) { int i; - if (sc->fc.sid_buf != NULL) - free((void *)(uintptr_t)sc->fc.sid_buf, M_FW); - if (sc->cromptr != NULL) - free((void *)sc->cromptr, M_FW); + if (sc->sid_buf != NULL) + fwdma_free(&sc->fc, &sc->sid_dma); + if (sc->fc.config_rom != NULL) + fwdma_free(&sc->fc, &sc->crom_dma); fwohci_db_free(&sc->arrq); fwohci_db_free(&sc->arrs); fwohci_db_free(&sc->atrq); fwohci_db_free(&sc->atrs); for( i = 0 ; i < sc->fc.nisodma ; i ++ ){ fwohci_db_free(&sc->it[i]); fwohci_db_free(&sc->ir[i]); } return 0; } #define LAST_DB(dbtr, db) do { \ struct fwohcidb_tr *_dbtr = (dbtr); \ int _cnt = _dbtr->dbcnt; \ db = &_dbtr->db[ (_cnt > 2) ? (_cnt -1) : 0]; \ } while (0) 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; + bus_dma_segment_t *s; + int i; + + db_tr = (struct fwohcidb_tr *)arg; + db = &db_tr->db[db_tr->dbcnt]; + if (error) { + if (firewire_debug || error != EFBIG) + printf("fwohci_execute_db: error=%d\n", error); + return; + } + for (i = 0; i < nseg; i++) { + s = &segs[i]; + FWOHCI_DMA_WRITE(db->db.desc.addr, s->ds_addr); + FWOHCI_DMA_WRITE(db->db.desc.cmd, s->ds_len); + FWOHCI_DMA_WRITE(db->db.desc.res, 0); + db++; + db_tr->dbcnt++; + } +} + +static void +fwohci_execute_db2(void *arg, bus_dma_segment_t *segs, int nseg, + bus_size_t size, int error) +{ + fwohci_execute_db(arg, segs, nseg, error); +} + +static void fwohci_start(struct fwohci_softc *sc, struct fwohci_dbch *dbch) { int i, s; - int tcode, hdr_len, hdr_off, len; + int tcode, hdr_len, pl_off, pl_len; int fsegment = -1; u_int32_t off; struct fw_xfer *xfer; struct fw_pkt *fp; volatile struct fwohci_txpkthdr *ohcifp; struct fwohcidb_tr *db_tr; volatile struct fwohcidb *db; - struct mbuf *m; struct tcode_info *info; static int maxdesc=0; if(&sc->atrq == dbch){ off = OHCI_ATQOFF; }else if(&sc->atrs == dbch){ off = OHCI_ATSOFF; }else{ return; } if (dbch->flags & FWOHCI_DBCH_FULL) return; s = splfw(); db_tr = dbch->top; txloop: xfer = STAILQ_FIRST(&dbch->xferq.q); if(xfer == NULL){ goto kick; } if(dbch->xferq.queued == 0 ){ device_printf(sc->fc.dev, "TX queue empty\n"); } STAILQ_REMOVE_HEAD(&dbch->xferq.q, link); db_tr->xfer = xfer; xfer->state = FWXF_START; - dbch->xferq.packets++; - fp = (struct fw_pkt *)(xfer->send.buf + xfer->send.off); + fp = (struct fw_pkt *)xfer->send.buf; tcode = fp->mode.common.tcode; ohcifp = (volatile struct fwohci_txpkthdr *) db_tr->db[1].db.immed; info = &tinfo[tcode]; - hdr_len = hdr_off = info->hdr_len; - /* fw_asyreq must pass valid send.len */ - len = xfer->send.len; - for( i = 0 ; i < hdr_off ; i+= 4){ - ohcifp->mode.ld[i/4] = ntohl(fp->mode.ld[i/4]); + 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]; } - /* XXX payload must be network byte order */ - if (tcode == FWTCODE_WREQQ || tcode == FWTCODE_RRESQ) { - ohcifp->mode.ld[3] = htonl(ohcifp->mode.ld[3]); - } ohcifp->mode.common.spd = xfer->spd; if (tcode == FWTCODE_STREAM ){ hdr_len = 8; - ohcifp->mode.stream.len = ntohs(fp->mode.stream.len); + ohcifp->mode.stream.len = fp->mode.stream.len; } else if (tcode == FWTCODE_PHY) { hdr_len = 12; - ohcifp->mode.ld[1] = ntohl(fp->mode.ld[1]); - ohcifp->mode.ld[2] = ntohl(fp->mode.ld[2]); + ohcifp->mode.ld[1] = fp->mode.ld[1]; + ohcifp->mode.ld[2] = fp->mode.ld[2]; ohcifp->mode.common.spd = 0; ohcifp->mode.common.tcode = FWOHCITCODE_PHY; } else { - ohcifp->mode.asycomm.dst = ntohs(fp->mode.hdr.dst); + ohcifp->mode.asycomm.dst = fp->mode.hdr.dst; ohcifp->mode.asycomm.srcbus = OHCI_ASYSRCBUS; ohcifp->mode.asycomm.tlrt |= FWRETRY_X; } db = &db_tr->db[0]; - db->db.desc.control = OHCI_OUTPUT_MORE | OHCI_KEY_ST2; - db->db.desc.reqcount = hdr_len; - db->db.desc.status = 0; + FWOHCI_DMA_WRITE(db->db.desc.cmd, + OHCI_OUTPUT_MORE | OHCI_KEY_ST2 | hdr_len); + FWOHCI_DMA_WRITE(db->db.desc.res, 0); /* Specify bound timer of asy. responce */ if(&sc->atrs == dbch){ - db->db.desc.count - = (OREAD(sc, OHCI_CYCLETIMER) >> 12) + (1 << 13); + FWOHCI_DMA_WRITE(db->db.desc.res, + (OREAD(sc, OHCI_CYCLETIMER) >> 12) + (1 << 13)); } +#if BYTE_ORDER == BIG_ENDIAN + 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]); +#endif again: db_tr->dbcnt = 2; db = &db_tr->db[db_tr->dbcnt]; - if(len > hdr_off){ + pl_len = xfer->send.len - pl_off; + if (pl_len > 0) { + int err; + /* handle payload */ if (xfer->mbuf == NULL) { - db->db.desc.addr - = vtophys(xfer->send.buf + xfer->send.off) + hdr_off; - db->db.desc.control = OHCI_OUTPUT_MORE; - db->db.desc.reqcount = len - hdr_off; - db->db.desc.status = 0; + caddr_t pl_addr; - db_tr->dbcnt++; + pl_addr = xfer->send.buf + pl_off; + err = bus_dmamap_load(dbch->dmat, db_tr->dma_map, + pl_addr, pl_len, + fwohci_execute_db, db_tr, + /*flags*/0); } else { - int mchain=0; /* XXX we can handle only 6 (=8-2) mbuf chains */ - for (m = xfer->mbuf; m != NULL; m = m->m_next) { - if (m->m_len == 0) - /* unrecoverable error could occur. */ - continue; - mchain++; - if (db_tr->dbcnt >= dbch->ndesc) - continue; - db->db.desc.addr - = vtophys(mtod(m, caddr_t)); - db->db.desc.control = OHCI_OUTPUT_MORE; - db->db.desc.reqcount = m->m_len; - db->db.desc.status = 0; - db++; - db_tr->dbcnt++; - } - if (mchain > dbch->ndesc - 2) { - struct mbuf *m_new; - if (bootverbose) - device_printf(sc->fc.dev, - "too long mbuf chain(%d)\n", - mchain); - m_new = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); - if (m_new != NULL) { + err = bus_dmamap_load_mbuf(dbch->dmat, db_tr->dma_map, + xfer->mbuf, + fwohci_execute_db2, db_tr, + /* flags */0); + if (err == EFBIG) { + struct mbuf *m0; + + if (firewire_debug) + device_printf(sc->fc.dev, "EFBIG.\n"); + m0 = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); + if (m0 != NULL) { m_copydata(xfer->mbuf, 0, xfer->mbuf->m_pkthdr.len, - mtod(m_new, caddr_t)); - m_new->m_pkthdr.len = m_new->m_len = + mtod(m0, caddr_t)); + m0->m_len = m0->m_pkthdr.len = xfer->mbuf->m_pkthdr.len; m_freem(xfer->mbuf); - xfer->mbuf = m_new; + xfer->mbuf = m0; goto again; } device_printf(sc->fc.dev, "m_getcl failed.\n"); } } + if (err) + printf("dmamap_load: err=%d\n", err); + bus_dmamap_sync(dbch->dmat, db_tr->dma_map, + BUS_DMASYNC_PREWRITE); +#if 0 /* OHCI_OUTPUT_MODE == 0 */ + for (i = 2; i < db_tr->dbcnt; i++) + FWOHCI_DMA_SET(db_tr->db[i].db.desc.cmd, + OHCI_OUTPUT_MORE); +#endif } if (maxdesc < db_tr->dbcnt) { maxdesc = db_tr->dbcnt; if (bootverbose) device_printf(sc->fc.dev, "maxdesc: %d\n", maxdesc); } /* last db */ LAST_DB(db_tr, db); - db->db.desc.control |= OHCI_OUTPUT_LAST - | OHCI_INTERRUPT_ALWAYS - | OHCI_BRANCH_ALWAYS; - db->db.desc.depend = vtophys(STAILQ_NEXT(db_tr, link)->db); + FWOHCI_DMA_SET(db->db.desc.cmd, + OHCI_OUTPUT_LAST | OHCI_INTERRUPT_ALWAYS | OHCI_BRANCH_ALWAYS); + FWOHCI_DMA_WRITE(db->db.desc.depend, + STAILQ_NEXT(db_tr, link)->bus_addr); if(fsegment == -1 ) fsegment = db_tr->dbcnt; if (dbch->pdb_tr != NULL) { LAST_DB(dbch->pdb_tr, db); - db->db.desc.depend |= db_tr->dbcnt; + FWOHCI_DMA_SET(db->db.desc.depend, db_tr->dbcnt); } dbch->pdb_tr = db_tr; db_tr = STAILQ_NEXT(db_tr, link); if(db_tr != dbch->bottom){ goto txloop; } else { device_printf(sc->fc.dev, "fwohci_start: lack of db_trq\n"); dbch->flags |= FWOHCI_DBCH_FULL; } kick: /* kick asy q */ + fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREREAD); + fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREWRITE); if(dbch->xferq.flag & FWXFERQ_RUNNING) { OWRITE(sc, OHCI_DMACTL(off), OHCI_CNTL_DMA_WAKE); } else { if (bootverbose) device_printf(sc->fc.dev, "start AT DMA status=%x\n", OREAD(sc, OHCI_DMACTL(off))); - OWRITE(sc, OHCI_DMACMD(off), vtophys(dbch->top->db) | fsegment); + OWRITE(sc, OHCI_DMACMD(off), dbch->top->bus_addr | fsegment); OWRITE(sc, OHCI_DMACTL(off), OHCI_CNTL_DMA_RUN); dbch->xferq.flag |= FWXFERQ_RUNNING; } dbch->top = db_tr; splx(s); return; } static void -fwohci_drain_atq(struct firewire_comm *fc, struct fw_xfer *xfer) -{ - struct fwohci_softc *sc = (struct fwohci_softc *)fc; - fwohci_drain(&sc->fc, xfer, &(sc->atrq)); - return; -} - -static void -fwohci_drain_ats(struct firewire_comm *fc, struct fw_xfer *xfer) -{ - struct fwohci_softc *sc = (struct fwohci_softc *)fc; - fwohci_drain(&sc->fc, xfer, &(sc->atrs)); - return; -} - -static void fwohci_start_atq(struct firewire_comm *fc) { struct fwohci_softc *sc = (struct fwohci_softc *)fc; fwohci_start( sc, &(sc->atrq)); return; } static void fwohci_start_ats(struct firewire_comm *fc) { struct fwohci_softc *sc = (struct fwohci_softc *)fc; fwohci_start( sc, &(sc->atrs)); return; } void fwohci_txd(struct fwohci_softc *sc, struct fwohci_dbch *dbch) { - int s, err = 0; + int s, ch, err = 0; struct fwohcidb_tr *tr; volatile struct fwohcidb *db; struct fw_xfer *xfer; u_int32_t off; - u_int stat; + u_int stat, status; int packets; struct firewire_comm *fc = (struct firewire_comm *)sc; + if(&sc->atrq == dbch){ off = OHCI_ATQOFF; + ch = ATRQ_CH; }else if(&sc->atrs == dbch){ off = OHCI_ATSOFF; + ch = ATRS_CH; }else{ return; } s = splfw(); tr = dbch->bottom; packets = 0; + fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_POSTREAD); + fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_POSTWRITE); while(dbch->xferq.queued > 0){ LAST_DB(tr, db); - if(!(db->db.desc.status & OHCI_CNTL_DMA_ACTIVE)){ + status = FWOHCI_DMA_READ(db->db.desc.res) >> OHCI_STATUS_SHIFT; + if(!(status & OHCI_CNTL_DMA_ACTIVE)){ if (fc->status != FWBUSRESET) /* maybe out of order?? */ goto out; } - if(db->db.desc.status & OHCI_CNTL_DMA_DEAD) { -#ifdef OHCI_DEBUG - dump_dma(sc, ch); - dump_db(sc, ch); + 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); #endif -/* Stop DMA */ + if(status & OHCI_CNTL_DMA_DEAD) { + /* Stop DMA */ OWRITE(sc, OHCI_DMACTLCLR(off), OHCI_CNTL_DMA_RUN); device_printf(sc->fc.dev, "force reset AT FIFO\n"); OWRITE(sc, OHCI_HCCCTLCLR, OHCI_HCC_LINKEN); OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_LPS | OHCI_HCC_LINKEN); OWRITE(sc, OHCI_DMACTLCLR(off), OHCI_CNTL_DMA_RUN); } - stat = db->db.desc.status & FWOHCIEV_MASK; + stat = status & FWOHCIEV_MASK; switch(stat){ case FWOHCIEV_ACKPEND: case FWOHCIEV_ACKCOMPL: err = 0; break; case FWOHCIEV_ACKBSA: case FWOHCIEV_ACKBSB: case FWOHCIEV_ACKBSX: device_printf(sc->fc.dev, "txd err=%2x %s\n", stat, fwohcicode[stat]); err = EBUSY; break; case FWOHCIEV_FLUSHED: case FWOHCIEV_ACKTARD: device_printf(sc->fc.dev, "txd err=%2x %s\n", stat, fwohcicode[stat]); err = EAGAIN; break; case FWOHCIEV_MISSACK: case FWOHCIEV_UNDRRUN: case FWOHCIEV_OVRRUN: case FWOHCIEV_DESCERR: case FWOHCIEV_DTRDERR: case FWOHCIEV_TIMEOUT: case FWOHCIEV_TCODERR: case FWOHCIEV_UNKNOWN: case FWOHCIEV_ACKDERR: case FWOHCIEV_ACKTERR: default: device_printf(sc->fc.dev, "txd err=%2x %s\n", stat, fwohcicode[stat]); err = EINVAL; break; } if (tr->xfer != NULL) { xfer = tr->xfer; + if (xfer->state == FWXF_RCVD) { + if (firewire_debug) + printf("already rcvd\n"); + fw_xfer_done(xfer); + } else { xfer->state = FWXF_SENT; if (err == EBUSY && fc->status != FWBUSRESET) { xfer->state = FWXF_BUSY; - switch (xfer->act_type) { - case FWACT_XFER: - xfer->resp = err; - if (xfer->retry_req != NULL) - xfer->retry_req(xfer); - else - fw_xfer_done(xfer); - break; - default: - break; - } + xfer->resp = err; + if (xfer->retry_req != NULL) + xfer->retry_req(xfer); + else + fw_xfer_done(xfer); } else if (stat != FWOHCIEV_ACKPEND) { if (stat != FWOHCIEV_ACKCOMPL) xfer->state = FWXF_SENTERR; xfer->resp = err; - switch (xfer->act_type) { - case FWACT_XFER: - fw_xfer_done(xfer); - break; - default: - break; - } + fw_xfer_done(xfer); } + } /* * The watchdog timer takes care of split * transcation timeout for ACKPEND case. */ + } else { + printf("this shouldn't happen\n"); } dbch->xferq.queued --; tr->xfer = NULL; packets ++; tr = STAILQ_NEXT(tr, link); dbch->bottom = tr; if (dbch->bottom == dbch->top) { /* we reaches the end of context program */ if (firewire_debug && dbch->xferq.queued > 0) printf("queued > 0\n"); break; } } out: if ((dbch->flags & FWOHCI_DBCH_FULL) && packets > 0) { printf("make free slot\n"); dbch->flags &= ~FWOHCI_DBCH_FULL; fwohci_start(sc, dbch); } splx(s); } static void -fwohci_drain(struct firewire_comm *fc, struct fw_xfer *xfer, struct fwohci_dbch *dbch) -{ - int i, s, found=0; - struct fwohcidb_tr *tr; - - if(xfer->state != FWXF_START) return; - - s = splfw(); - tr = dbch->bottom; - for (i = 0; i < dbch->xferq.queued; i ++) { - if(tr->xfer == xfer){ - tr->xfer = NULL; -#if 0 - dbch->xferq.queued --; - /* XXX */ - if (tr == dbch->bottom) - dbch->bottom = STAILQ_NEXT(tr, link); - if (dbch->flags & FWOHCI_DBCH_FULL) { - printf("fwohci_drain: make slot\n"); - dbch->flags &= ~FWOHCI_DBCH_FULL; - fwohci_start((struct fwohci_softc *)fc, dbch); - } -#endif - found ++; - break; - } - tr = STAILQ_NEXT(tr, link); - } - splx(s); - if (!found) - device_printf(fc->dev, "fwochi_drain: xfer not found\n"); - return; -} - -static void fwohci_db_free(struct fwohci_dbch *dbch) { struct fwohcidb_tr *db_tr; - int idb, i; + int idb; if ((dbch->flags & FWOHCI_DBCH_INIT) == 0) return; - if(!(dbch->xferq.flag & FWXFERQ_EXTBUF)){ - for(db_tr = STAILQ_FIRST(&dbch->db_trq), idb = 0; - idb < dbch->ndb; + for(db_tr = STAILQ_FIRST(&dbch->db_trq), idb = 0; idb < dbch->ndb; db_tr = STAILQ_NEXT(db_tr, link), idb++){ - if (db_tr->buf != NULL) { - free(db_tr->buf, M_FW); - db_tr->buf = NULL; - } - } + if ((dbch->xferq.flag & FWXFERQ_EXTBUF) == 0 && + db_tr->buf != NULL) { + fwdma_free_size(dbch->dmat, db_tr->dma_map, + db_tr->buf, dbch->xferq.psize); + db_tr->buf = NULL; + } else if (db_tr->dma_map != NULL) + bus_dmamap_destroy(dbch->dmat, db_tr->dma_map); } dbch->ndb = 0; db_tr = STAILQ_FIRST(&dbch->db_trq); - for (i = 0; i < dbch->npages; i++) - free(dbch->pages[i], M_FW); + fwdma_free_multiseg(dbch->am); free(db_tr, M_FW); STAILQ_INIT(&dbch->db_trq); dbch->flags &= ~FWOHCI_DBCH_INIT; } static void -fwohci_db_init(struct fwohci_dbch *dbch) +fwohci_db_init(struct fwohci_softc *sc, struct fwohci_dbch *dbch) { int idb; struct fwohcidb_tr *db_tr; - int ndbpp, i, j; if ((dbch->flags & FWOHCI_DBCH_INIT) != 0) goto out; + /* create dma_tag for buffers */ +#define MAX_REQCOUNT 0xffff + if (bus_dma_tag_create(/*parent*/ sc->fc.dmat, + /*alignment*/ 1, /*boundary*/ 0, + /*lowaddr*/ BUS_SPACE_MAXADDR_32BIT, + /*highaddr*/ BUS_SPACE_MAXADDR, + /*filter*/NULL, /*filterarg*/NULL, + /*maxsize*/ dbch->xferq.psize, + /*nsegments*/ dbch->ndesc > 3 ? dbch->ndesc - 2 : 1, + /*maxsegsz*/ MAX_REQCOUNT, + /*flags*/ 0, &dbch->dmat)) + return; + /* allocate DB entries and attach one to each DMA channels */ /* DB entry must start at 16 bytes bounary. */ STAILQ_INIT(&dbch->db_trq); db_tr = (struct fwohcidb_tr *) malloc(sizeof(struct fwohcidb_tr) * dbch->ndb, - M_FW, M_ZERO); + M_FW, M_WAITOK | M_ZERO); if(db_tr == NULL){ printf("fwohci_db_init: malloc(1) failed\n"); return; } - ndbpp = PAGE_SIZE / (sizeof(struct fwohcidb) * dbch->ndesc); - dbch->npages = (dbch->ndb + ndbpp - 1)/ ndbpp; - if (firewire_debug) - printf("ndesc: %d, ndbpp: %d, ndb: %d, npages: %d\n", - dbch->ndesc, ndbpp, dbch->ndb, dbch->npages); - if (dbch->npages > FWOHCI_DBCH_MAX_PAGES) { - printf("npages(%d) > DBCH_MAX_PAGES(%d)\n", - dbch->npages, FWOHCI_DBCH_MAX_PAGES); +#define DB_SIZE(x) (sizeof(struct fwohcidb) * (x)->ndesc) + dbch->am = fwdma_malloc_multiseg(&sc->fc, DB_SIZE(dbch), + DB_SIZE(dbch), dbch->ndb, BUS_DMA_WAITOK); + if (dbch->am == NULL) { + printf("fwohci_db_init: fwdma_malloc_multiseg failed\n"); return; } - for (i = 0; i < dbch->npages; i++) { - dbch->pages[i] = malloc(PAGE_SIZE, M_FW, M_ZERO); - if (dbch->pages[i] == NULL) { - printf("fwohci_db_init: malloc(2) failed\n"); - for (j = 0; j < i; j ++) - free(dbch->pages[j], M_FW); - free(db_tr, M_FW); - return; - } - } /* Attach DB to DMA ch. */ for(idb = 0 ; idb < dbch->ndb ; idb++){ db_tr->dbcnt = 0; - db_tr->db = (struct fwohcidb *)dbch->pages[idb/ndbpp] - + dbch->ndesc * (idb % ndbpp); + db_tr->db = (struct fwohcidb *)fwdma_v_addr(dbch->am, idb); + db_tr->bus_addr = fwdma_bus_addr(dbch->am, idb); + /* create dmamap for buffers */ + /* XXX do we need 4bytes alignment tag? */ + /* XXX don't alloc dma_map for AR */ + if (bus_dmamap_create(dbch->dmat, 0, &db_tr->dma_map) != 0) { + printf("bus_dmamap_create failed\n"); + dbch->flags = FWOHCI_DBCH_INIT; /* XXX fake */ + fwohci_db_free(dbch); + return; + } STAILQ_INSERT_TAIL(&dbch->db_trq, db_tr, link); - if (!(dbch->xferq.flag & FWXFERQ_PACKET) && - dbch->xferq.bnpacket != 0) { + if (dbch->xferq.flag & FWXFERQ_EXTBUF) { if (idb % dbch->xferq.bnpacket == 0) dbch->xferq.bulkxfer[idb / dbch->xferq.bnpacket ].start = (caddr_t)db_tr; if ((idb + 1) % dbch->xferq.bnpacket == 0) dbch->xferq.bulkxfer[idb / dbch->xferq.bnpacket ].end = (caddr_t)db_tr; } db_tr++; } STAILQ_LAST(&dbch->db_trq, fwohcidb_tr,link)->link.stqe_next = STAILQ_FIRST(&dbch->db_trq); out: - dbch->frag.buf = NULL; - dbch->frag.len = 0; - dbch->frag.plen = 0; dbch->xferq.queued = 0; dbch->pdb_tr = NULL; dbch->top = STAILQ_FIRST(&dbch->db_trq); dbch->bottom = dbch->top; dbch->flags = FWOHCI_DBCH_INIT; } static int fwohci_itx_disable(struct firewire_comm *fc, int dmach) { struct fwohci_softc *sc = (struct fwohci_softc *)fc; - int dummy; + int sleepch; - OWRITE(sc, OHCI_ITCTLCLR(dmach), OHCI_CNTL_DMA_RUN); + OWRITE(sc, OHCI_ITCTLCLR(dmach), + OHCI_CNTL_DMA_RUN | OHCI_CNTL_CYCMATCH_S); OWRITE(sc, OHCI_IT_MASKCLR, 1 << dmach); OWRITE(sc, OHCI_IT_STATCLR, 1 << dmach); /* XXX we cannot free buffers until the DMA really stops */ - tsleep((void *)&dummy, FWPRI, "fwitxd", hz); + tsleep((void *)&sleepch, FWPRI, "fwitxd", hz); fwohci_db_free(&sc->it[dmach]); sc->it[dmach].xferq.flag &= ~FWXFERQ_RUNNING; return 0; } static int fwohci_irx_disable(struct firewire_comm *fc, int dmach) { struct fwohci_softc *sc = (struct fwohci_softc *)fc; - int dummy; + int sleepch; OWRITE(sc, OHCI_IRCTLCLR(dmach), OHCI_CNTL_DMA_RUN); OWRITE(sc, OHCI_IR_MASKCLR, 1 << dmach); OWRITE(sc, OHCI_IR_STATCLR, 1 << dmach); /* XXX we cannot free buffers until the DMA really stops */ - tsleep((void *)&dummy, FWPRI, "fwirxd", hz); - if(sc->ir[dmach].dummy != NULL){ - free(sc->ir[dmach].dummy, M_FW); - } - sc->ir[dmach].dummy = NULL; + tsleep((void *)&sleepch, FWPRI, "fwirxd", hz); fwohci_db_free(&sc->ir[dmach]); sc->ir[dmach].xferq.flag &= ~FWXFERQ_RUNNING; return 0; } +#if BYTE_ORDER == BIG_ENDIAN static void fwohci_irx_post (struct firewire_comm *fc , u_int32_t *qld) { - qld[0] = ntohl(qld[0]); + qld[0] = FWOHCI_DMA_READ(qld[0]); return; } - -static int -fwohci_irxpp_enable(struct firewire_comm *fc, int dmach) -{ - struct fwohci_softc *sc = (struct fwohci_softc *)fc; - int err = 0; - unsigned short tag, ich; - - tag = (sc->ir[dmach].xferq.flag >> 6) & 3; - ich = sc->ir[dmach].xferq.flag & 0x3f; - -#if 0 - if(STAILQ_FIRST(&fc->ir[dmach]->q) != NULL){ - wakeup(fc->ir[dmach]); - return err; - } #endif - OWRITE(sc, OHCI_IRMATCH(dmach), tagbit[tag] | ich); - if(!(sc->ir[dmach].xferq.flag & FWXFERQ_RUNNING)){ - sc->ir[dmach].xferq.queued = 0; - sc->ir[dmach].ndb = NDB; - sc->ir[dmach].xferq.psize = PAGE_SIZE; - sc->ir[dmach].ndesc = 1; - fwohci_db_init(&sc->ir[dmach]); - if ((sc->ir[dmach].flags & FWOHCI_DBCH_INIT) == 0) - return ENOMEM; - err = fwohci_rx_enable(sc, &sc->ir[dmach]); - } - if(err){ - device_printf(sc->fc.dev, "err in IRX setting\n"); - return err; - } - if(!(OREAD(sc, OHCI_IRCTL(dmach)) & OHCI_CNTL_DMA_ACTIVE)){ - OWRITE(sc, OHCI_IRCTLCLR(dmach), OHCI_CNTL_DMA_RUN); - OWRITE(sc, OHCI_IR_MASKCLR, 1 << dmach); - OWRITE(sc, OHCI_IR_STATCLR, 1 << dmach); - OWRITE(sc, OHCI_IR_MASK, 1 << dmach); - OWRITE(sc, OHCI_IRCTLCLR(dmach), 0xf8000000); - OWRITE(sc, OHCI_IRCTL(dmach), OHCI_CNTL_ISOHDR); - OWRITE(sc, OHCI_IRCMD(dmach), - vtophys(sc->ir[dmach].top->db) | 1); - OWRITE(sc, OHCI_IRCTL(dmach), OHCI_CNTL_DMA_RUN); - OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_DMA_IR); - } - return err; -} - static int fwohci_tx_enable(struct fwohci_softc *sc, struct fwohci_dbch *dbch) { int err = 0; - int idb, z, i, dmach = 0; + int idb, z, i, dmach = 0, ldesc; u_int32_t off = NULL; struct fwohcidb_tr *db_tr; volatile struct fwohcidb *db; if(!(dbch->xferq.flag & FWXFERQ_EXTBUF)){ err = EINVAL; return err; } z = dbch->ndesc; for(dmach = 0 ; dmach < sc->fc.nisodma ; dmach++){ if( &sc->it[dmach] == dbch){ off = OHCI_ITOFF(dmach); break; } } if(off == NULL){ err = EINVAL; return err; } if(dbch->xferq.flag & FWXFERQ_RUNNING) return err; dbch->xferq.flag |= FWXFERQ_RUNNING; for( i = 0, dbch->bottom = dbch->top; i < (dbch->ndb - 1); i++){ dbch->bottom = STAILQ_NEXT(dbch->bottom, link); } db_tr = dbch->top; - for( idb = 0 ; idb < dbch->ndb ; idb ++){ - fwohci_add_tx_buf(db_tr, - dbch->xferq.psize, dbch->xferq.flag, - dbch->xferq.buf + dbch->xferq.psize * idb); + for (idb = 0; idb < dbch->ndb; idb ++) { + fwohci_add_tx_buf(dbch, db_tr, idb); if(STAILQ_NEXT(db_tr, link) == NULL){ break; } db = db_tr->db; - db[0].db.desc.depend = db[db_tr->dbcnt - 1].db.desc.depend - = vtophys(STAILQ_NEXT(db_tr, link)->db) | z; + ldesc = db_tr->dbcnt - 1; + FWOHCI_DMA_WRITE(db[0].db.desc.depend, + STAILQ_NEXT(db_tr, link)->bus_addr | z); + db[ldesc].db.desc.depend = db[0].db.desc.depend; if(dbch->xferq.flag & FWXFERQ_EXTBUF){ if(((idb + 1 ) % dbch->xferq.bnpacket) == 0){ - db[db_tr->dbcnt - 1].db.desc.control - |= OHCI_INTERRUPT_ALWAYS; + FWOHCI_DMA_SET( + db[ldesc].db.desc.cmd, + OHCI_INTERRUPT_ALWAYS); /* OHCI 1.1 and above */ - db[0].db.desc.control |= OHCI_INTERRUPT_ALWAYS; -#if 0 - db[0].db.desc.depend &= ~0xf; - db[db_tr->dbcnt - 1].db.desc.depend &= ~0xf; -#endif + FWOHCI_DMA_SET( + db[0].db.desc.cmd, + OHCI_INTERRUPT_ALWAYS); } } db_tr = STAILQ_NEXT(db_tr, link); } - dbch->bottom->db[db_tr->dbcnt - 1].db.desc.depend &= 0xfffffff0; + FWOHCI_DMA_CLEAR( + dbch->bottom->db[dbch->bottom->dbcnt - 1].db.desc.depend, 0xf); return err; } static int 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; struct fwohcidb_tr *db_tr; volatile struct fwohcidb *db; z = dbch->ndesc; if(&sc->arrq == dbch){ off = OHCI_ARQOFF; }else if(&sc->arrs == dbch){ off = OHCI_ARSOFF; }else{ for(dmach = 0 ; dmach < sc->fc.nisodma ; dmach++){ if( &sc->ir[dmach] == dbch){ off = OHCI_IROFF(dmach); break; } } } if(off == NULL){ err = EINVAL; return err; } if(dbch->xferq.flag & FWXFERQ_STREAM){ if(dbch->xferq.flag & FWXFERQ_RUNNING) return err; }else{ if(dbch->xferq.flag & FWXFERQ_RUNNING){ err = EBUSY; return err; } } dbch->xferq.flag |= FWXFERQ_RUNNING; dbch->top = STAILQ_FIRST(&dbch->db_trq); for( i = 0, dbch->bottom = dbch->top; i < (dbch->ndb - 1); i++){ dbch->bottom = STAILQ_NEXT(dbch->bottom, link); } db_tr = dbch->top; - for( idb = 0 ; idb < dbch->ndb ; idb ++){ - if(!(dbch->xferq.flag & FWXFERQ_EXTBUF)){ - fwohci_add_rx_buf(db_tr, - dbch->xferq.psize, dbch->xferq.flag, 0, NULL); - }else{ - fwohci_add_rx_buf(db_tr, - dbch->xferq.psize, dbch->xferq.flag, - dbch->xferq.bulkxfer[idb - / dbch->xferq.bnpacket].buf - + dbch->xferq.psize * - (idb % dbch->xferq.bnpacket), - dbch->dummy + sizeof(u_int32_t) * idb); - } - if(STAILQ_NEXT(db_tr, link) == NULL){ + for (idb = 0; idb < dbch->ndb; idb ++) { + fwohci_add_rx_buf(dbch, db_tr, idb, &sc->dummy_dma); + if (STAILQ_NEXT(db_tr, link) == NULL) break; - } db = db_tr->db; ldesc = db_tr->dbcnt - 1; - db[ldesc].db.desc.depend - = vtophys(STAILQ_NEXT(db_tr, link)->db) | z; + FWOHCI_DMA_WRITE(db[ldesc].db.desc.depend, + STAILQ_NEXT(db_tr, link)->bus_addr | z); if(dbch->xferq.flag & FWXFERQ_EXTBUF){ if(((idb + 1 ) % dbch->xferq.bnpacket) == 0){ - db[ldesc].db.desc.control - |= OHCI_INTERRUPT_ALWAYS; - db[ldesc].db.desc.depend &= ~0xf; + FWOHCI_DMA_SET( + db[ldesc].db.desc.cmd, + OHCI_INTERRUPT_ALWAYS); + FWOHCI_DMA_CLEAR( + db[ldesc].db.desc.depend, + 0xf); } } db_tr = STAILQ_NEXT(db_tr, link); } - dbch->bottom->db[db_tr->dbcnt - 1].db.desc.depend &= 0xfffffff0; + FWOHCI_DMA_CLEAR( + dbch->bottom->db[db_tr->dbcnt - 1].db.desc.depend, 0xf); dbch->buf_offset = 0; + fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREREAD); + fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREWRITE); if(dbch->xferq.flag & FWXFERQ_STREAM){ return err; }else{ - OWRITE(sc, OHCI_DMACMD(off), vtophys(dbch->top->db) | z); + OWRITE(sc, OHCI_DMACMD(off), dbch->top->bus_addr | z); } OWRITE(sc, OHCI_DMACTL(off), OHCI_CNTL_DMA_RUN); return err; } static int -fwochi_next_cycle(struct firewire_comm *fc, int cycle_now) +fwohci_next_cycle(struct firewire_comm *fc, int cycle_now) { int sec, cycle, cycle_match; cycle = cycle_now & 0x1fff; sec = cycle_now >> 13; #define CYCLE_MOD 0x10 +#if 1 #define CYCLE_DELAY 8 /* min delay to start DMA */ +#else +#define CYCLE_DELAY 7000 /* min delay to start DMA */ +#endif cycle = cycle + CYCLE_DELAY; if (cycle >= 8000) { sec ++; cycle -= 8000; } - cycle = ((cycle + CYCLE_MOD - 1) / CYCLE_MOD) * CYCLE_MOD; + cycle = roundup2(cycle, CYCLE_MOD); if (cycle >= 8000) { sec ++; if (cycle == 8000) cycle = 0; else cycle = CYCLE_MOD; } cycle_match = ((sec << 13) | cycle) & 0x7ffff; return(cycle_match); } static int fwohci_itxbuf_enable(struct firewire_comm *fc, int dmach) { struct fwohci_softc *sc = (struct fwohci_softc *)fc; int err = 0; unsigned short tag, ich; struct fwohci_dbch *dbch; int cycle_match, cycle_now, s, ldesc; u_int32_t stat; struct fw_bulkxfer *first, *chunk, *prev; struct fw_xferq *it; dbch = &sc->it[dmach]; it = &dbch->xferq; tag = (it->flag >> 6) & 3; ich = it->flag & 0x3f; if ((dbch->flags & FWOHCI_DBCH_INIT) == 0) { dbch->ndb = it->bnpacket * it->bnchunk; dbch->ndesc = 3; - fwohci_db_init(dbch); + fwohci_db_init(sc, dbch); if ((dbch->flags & FWOHCI_DBCH_INIT) == 0) return ENOMEM; err = fwohci_tx_enable(sc, dbch); } if(err) return err; ldesc = dbch->ndesc - 1; s = splfw(); prev = STAILQ_LAST(&it->stdma, fw_bulkxfer, link); while ((chunk = STAILQ_FIRST(&it->stvalid)) != NULL) { volatile struct fwohcidb *db; + fwdma_sync_multiseg(it->buf, chunk->poffset, it->bnpacket, + BUS_DMASYNC_PREWRITE); fwohci_txbufdb(sc, dmach, chunk); -#if 0 - db = ((struct fwohcidb_tr *)(chunk->end))->db; - db[ldesc].db.desc.status = db[0].db.desc.status = 0; - db[ldesc].db.desc.count = db[0].db.desc.count = 0; - db[ldesc].db.desc.depend &= ~0xf; - db[0].db.desc.depend &= ~0xf; -#endif if (prev != NULL) { db = ((struct fwohcidb_tr *)(prev->end))->db; - db[ldesc].db.desc.control |= OHCI_BRANCH_ALWAYS; +#if 0 /* XXX necessary? */ + FWOHCI_DMA_SET(db[ldesc].db.desc.cmd, + OHCI_BRANCH_ALWAYS); +#endif #if 0 /* if bulkxfer->npacket changes */ db[ldesc].db.desc.depend = db[0].db.desc.depend = - vtophys(((struct fwohcidb_tr *) - (chunk->start))->db) | dbch->ndesc; + ((struct fwohcidb_tr *) + (chunk->start))->bus_addr | dbch->ndesc; #else - db[0].db.desc.depend |= dbch->ndesc; - db[ldesc].db.desc.depend |= dbch->ndesc; + FWOHCI_DMA_SET(db[0].db.desc.depend, dbch->ndesc); + FWOHCI_DMA_SET(db[ldesc].db.desc.depend, dbch->ndesc); #endif } STAILQ_REMOVE_HEAD(&it->stvalid, link); STAILQ_INSERT_TAIL(&it->stdma, chunk, link); prev = chunk; } + fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREWRITE); + fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREREAD); splx(s); stat = OREAD(sc, OHCI_ITCTL(dmach)); + if (firewire_debug && (stat & OHCI_CNTL_CYCMATCH_S)) + printf("stat 0x%x\n", stat); + if (stat & (OHCI_CNTL_DMA_ACTIVE | OHCI_CNTL_CYCMATCH_S)) return 0; +#if 0 OWRITE(sc, OHCI_ITCTLCLR(dmach), OHCI_CNTL_DMA_RUN); +#endif OWRITE(sc, OHCI_IT_MASKCLR, 1 << dmach); OWRITE(sc, OHCI_IT_STATCLR, 1 << dmach); OWRITE(sc, OHCI_IT_MASK, 1 << dmach); + OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_DMA_IT); first = STAILQ_FIRST(&it->stdma); - OWRITE(sc, OHCI_ITCMD(dmach), vtophys(((struct fwohcidb_tr *) - (first->start))->db) | dbch->ndesc); - if (firewire_debug) + OWRITE(sc, OHCI_ITCMD(dmach), + ((struct fwohcidb_tr *)(first->start))->bus_addr | dbch->ndesc); + if (firewire_debug) { printf("fwohci_itxbuf_enable: kick 0x%08x\n", stat); +#if 1 + dump_dma(sc, ITX_CH + dmach); +#endif + } if ((stat & OHCI_CNTL_DMA_RUN) == 0) { #if 1 /* Don't start until all chunks are buffered */ if (STAILQ_FIRST(&it->stfree) != NULL) goto out; #endif -#ifdef FWXFERQ_DV -#define CYCLE_OFFSET 1 - if(dbch->xferq.flag & FWXFERQ_DV){ - struct fw_pkt *fp; - struct fwohcidb_tr *db_tr; - - db_tr = (struct fwohcidb_tr *)dbch->xferq.stdma->start; - fp = (struct fw_pkt *)db_tr->buf; - dbch->xferq.dvoffset = CYCLE_OFFSET; - fp->mode.ld[2] |= htonl(dbch->xferq.dvoffset << 12); - } -#endif +#if 1 /* Clear cycle match counter bits */ OWRITE(sc, OHCI_ITCTLCLR(dmach), 0xffff0000); - OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_DMA_IT); /* 2bit second + 13bit cycle */ cycle_now = (fc->cyctimer(fc) >> 12) & 0x7fff; - cycle_match = fwochi_next_cycle(fc, cycle_now); + cycle_match = fwohci_next_cycle(fc, cycle_now); OWRITE(sc, OHCI_ITCTL(dmach), OHCI_CNTL_CYCMATCH_S | (cycle_match << 16) | OHCI_CNTL_DMA_RUN); - if (firewire_debug) +#else + OWRITE(sc, OHCI_ITCTL(dmach), OHCI_CNTL_DMA_RUN); +#endif + if (firewire_debug) { printf("cycle_match: 0x%04x->0x%04x\n", cycle_now, cycle_match); + dump_dma(sc, ITX_CH + dmach); + dump_db(sc, ITX_CH + dmach); + } } else if ((stat & OHCI_CNTL_CYCMATCH_S) == 0) { device_printf(sc->fc.dev, "IT DMA underrun (0x%08x)\n", stat); - OWRITE(sc, OHCI_ITCTL(dmach), OHCI_CNTL_DMA_RUN); + OWRITE(sc, OHCI_ITCTL(dmach), OHCI_CNTL_DMA_WAKE); } out: return err; } static int -fwohci_irxbuf_enable(struct firewire_comm *fc, int dmach) +fwohci_irx_enable(struct firewire_comm *fc, int dmach) { struct fwohci_softc *sc = (struct fwohci_softc *)fc; int err = 0, s, ldesc; unsigned short tag, ich; u_int32_t stat; struct fwohci_dbch *dbch; + struct fwohcidb_tr *db_tr; struct fw_bulkxfer *first, *prev, *chunk; struct fw_xferq *ir; dbch = &sc->ir[dmach]; ir = &dbch->xferq; if ((ir->flag & FWXFERQ_RUNNING) == 0) { tag = (ir->flag >> 6) & 3; ich = ir->flag & 0x3f; OWRITE(sc, OHCI_IRMATCH(dmach), tagbit[tag] | ich); ir->queued = 0; dbch->ndb = ir->bnpacket * ir->bnchunk; - dbch->dummy = malloc(sizeof(u_int32_t) * dbch->ndb, - M_FW, 0); - if (dbch->dummy == NULL) { - err = ENOMEM; - return err; - } dbch->ndesc = 2; - fwohci_db_init(dbch); + fwohci_db_init(sc, dbch); if ((dbch->flags & FWOHCI_DBCH_INIT) == 0) return ENOMEM; err = fwohci_rx_enable(sc, dbch); } if(err) return err; first = STAILQ_FIRST(&ir->stfree); if (first == NULL) { device_printf(fc->dev, "IR DMA no free chunk\n"); return 0; } ldesc = dbch->ndesc - 1; s = splfw(); prev = STAILQ_LAST(&ir->stdma, fw_bulkxfer, link); while ((chunk = STAILQ_FIRST(&ir->stfree)) != NULL) { volatile struct fwohcidb *db; #if 1 /* XXX for if_fwe */ - db = ((struct fwohcidb_tr *)(chunk->start))->db; - db[ldesc].db.desc.addr = vtophys(chunk->buf); + if (chunk->mbuf != NULL) { + db_tr = (struct fwohcidb_tr *)(chunk->start); + db_tr->dbcnt = 1; + err = bus_dmamap_load_mbuf(dbch->dmat, db_tr->dma_map, + chunk->mbuf, fwohci_execute_db2, db_tr, + /* flags */0); + FWOHCI_DMA_SET(db_tr->db[1].db.desc.cmd, + OHCI_UPDATE | OHCI_INPUT_LAST | + OHCI_INTERRUPT_ALWAYS | OHCI_BRANCH_ALWAYS); + } #endif db = ((struct fwohcidb_tr *)(chunk->end))->db; - db[ldesc].db.desc.status = db[ldesc].db.desc.count = 0; - db[ldesc].db.desc.depend &= ~0xf; + FWOHCI_DMA_WRITE(db[ldesc].db.desc.res, 0); + FWOHCI_DMA_CLEAR(db[ldesc].db.desc.depend, 0xf); if (prev != NULL) { db = ((struct fwohcidb_tr *)(prev->end))->db; -#if 0 - db[ldesc].db.desc.depend = - vtophys(((struct fwohcidb_tr *) - (chunk->start))->db) | dbch->ndesc; -#else - db[ldesc].db.desc.depend |= dbch->ndesc; -#endif + FWOHCI_DMA_SET(db[ldesc].db.desc.depend, dbch->ndesc); } STAILQ_REMOVE_HEAD(&ir->stfree, link); STAILQ_INSERT_TAIL(&ir->stdma, chunk, link); prev = chunk; } + fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREWRITE); + fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREREAD); splx(s); stat = OREAD(sc, OHCI_IRCTL(dmach)); if (stat & OHCI_CNTL_DMA_ACTIVE) return 0; if (stat & OHCI_CNTL_DMA_RUN) { OWRITE(sc, OHCI_IRCTLCLR(dmach), OHCI_CNTL_DMA_RUN); device_printf(sc->fc.dev, "IR DMA overrun (0x%08x)\n", stat); } + if (firewire_debug) + printf("start IR DMA 0x%x\n", stat); OWRITE(sc, OHCI_IR_MASKCLR, 1 << dmach); OWRITE(sc, OHCI_IR_STATCLR, 1 << dmach); OWRITE(sc, OHCI_IR_MASK, 1 << dmach); OWRITE(sc, OHCI_IRCTLCLR(dmach), 0xf0000000); OWRITE(sc, OHCI_IRCTL(dmach), OHCI_CNTL_ISOHDR); OWRITE(sc, OHCI_IRCMD(dmach), - vtophys(((struct fwohcidb_tr *)(first->start))->db) + ((struct fwohcidb_tr *)(first->start))->bus_addr | dbch->ndesc); OWRITE(sc, OHCI_IRCTL(dmach), OHCI_CNTL_DMA_RUN); OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_DMA_IR); +#if 0 + dump_db(sc, IRX_CH + dmach); +#endif return err; } -static int -fwohci_irx_enable(struct firewire_comm *fc, int dmach) -{ - struct fwohci_softc *sc = (struct fwohci_softc *)fc; - int err = 0; - - if(sc->ir[dmach].xferq.flag & FWXFERQ_PACKET){ - err = fwohci_irxpp_enable(fc, dmach); - return err; - }else{ - err = fwohci_irxbuf_enable(fc, dmach); - return err; - } -} - int fwohci_stop(struct fwohci_softc *sc, device_t dev) { u_int i; /* Now stopping all DMA channel */ OWRITE(sc, OHCI_ARQCTLCLR, OHCI_CNTL_DMA_RUN); OWRITE(sc, OHCI_ARSCTLCLR, OHCI_CNTL_DMA_RUN); OWRITE(sc, OHCI_ATQCTLCLR, OHCI_CNTL_DMA_RUN); OWRITE(sc, OHCI_ATSCTLCLR, OHCI_CNTL_DMA_RUN); for( i = 0 ; i < sc->fc.nisodma ; i ++ ){ OWRITE(sc, OHCI_IRCTLCLR(i), OHCI_CNTL_DMA_RUN); OWRITE(sc, OHCI_ITCTLCLR(i), OHCI_CNTL_DMA_RUN); } /* FLUSH FIFO and reset Transmitter/Reciever */ OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_RESET); /* Stop interrupt */ OWRITE(sc, FWOHCI_INTMASKCLR, OHCI_INT_EN | OHCI_INT_ERR | OHCI_INT_PHY_SID | OHCI_INT_PHY_INT | OHCI_INT_DMA_ATRQ | OHCI_INT_DMA_ATRS | OHCI_INT_DMA_PRRQ | OHCI_INT_DMA_PRRS | OHCI_INT_DMA_ARRQ | OHCI_INT_DMA_ARRS | OHCI_INT_PHY_BUS_R); /* XXX Link down? Bus reset? */ return 0; } int fwohci_resume(struct fwohci_softc *sc, device_t dev) { int i; 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) { device_printf(sc->fc.dev, "resume iso receive ch: %d\n", i); sc->ir[i].xferq.flag &= ~FWXFERQ_RUNNING; sc->fc.irx_enable(&sc->fc, i); } } bus_generic_resume(dev); sc->fc.ibr(&sc->fc); return 0; } #define ACK_ALL static void fwohci_intr_body(struct fwohci_softc *sc, u_int32_t stat, int count) { u_int32_t irstat, itstat; u_int i; struct firewire_comm *fc = (struct firewire_comm *)sc; #ifdef OHCI_DEBUG if(stat & OREAD(sc, FWOHCI_INTMASK)) device_printf(fc->dev, "INTERRUPT < %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s> 0x%08x, 0x%08x\n", stat & OHCI_INT_EN ? "DMA_EN ":"", stat & OHCI_INT_PHY_REG ? "PHY_REG ":"", stat & OHCI_INT_CYC_LONG ? "CYC_LONG ":"", stat & OHCI_INT_ERR ? "INT_ERR ":"", stat & OHCI_INT_CYC_ERR ? "CYC_ERR ":"", stat & OHCI_INT_CYC_LOST ? "CYC_LOST ":"", stat & OHCI_INT_CYC_64SECOND ? "CYC_64SECOND ":"", stat & OHCI_INT_CYC_START ? "CYC_START ":"", stat & OHCI_INT_PHY_INT ? "PHY_INT ":"", stat & OHCI_INT_PHY_BUS_R ? "BUS_RESET ":"", stat & OHCI_INT_PHY_SID ? "SID ":"", stat & OHCI_INT_LR_ERR ? "DMA_LR_ERR ":"", stat & OHCI_INT_PW_ERR ? "DMA_PW_ERR ":"", stat & OHCI_INT_DMA_IR ? "DMA_IR ":"", stat & OHCI_INT_DMA_IT ? "DMA_IT " :"", stat & OHCI_INT_DMA_PRRS ? "DMA_PRRS " :"", stat & OHCI_INT_DMA_PRRQ ? "DMA_PRRQ " :"", stat & OHCI_INT_DMA_ARRS ? "DMA_ARRS " :"", stat & OHCI_INT_DMA_ARRQ ? "DMA_ARRQ " :"", stat & OHCI_INT_DMA_ATRS ? "DMA_ATRS " :"", stat & OHCI_INT_DMA_ATRQ ? "DMA_ATRQ " :"", stat, OREAD(sc, FWOHCI_INTMASK) ); #endif /* Bus reset */ if(stat & OHCI_INT_PHY_BUS_R ){ if (fc->status == FWBUSRESET) goto busresetout; /* Disable bus reset interrupt until sid recv. */ OWRITE(sc, FWOHCI_INTMASKCLR, OHCI_INT_PHY_BUS_R); device_printf(fc->dev, "BUS reset\n"); OWRITE(sc, FWOHCI_INTMASKCLR, OHCI_INT_CYC_LOST); OWRITE(sc, OHCI_LNKCTLCLR, OHCI_CNTL_CYCSRC); OWRITE(sc, OHCI_ATQCTLCLR, OHCI_CNTL_DMA_RUN); sc->atrq.xferq.flag &= ~FWXFERQ_RUNNING; OWRITE(sc, OHCI_ATSCTLCLR, OHCI_CNTL_DMA_RUN); sc->atrs.xferq.flag &= ~FWXFERQ_RUNNING; #ifndef ACK_ALL OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_PHY_BUS_R); #endif fw_busreset(fc); } busresetout: if((stat & OHCI_INT_DMA_IR )){ #ifndef ACK_ALL OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_DMA_IR); #endif - irstat = OREAD(sc, OHCI_IR_STAT); - OWRITE(sc, OHCI_IR_STATCLR, irstat); +#if __FreeBSD_version >= 500000 + irstat = atomic_readandclear_int(&sc->irstat); +#else + irstat = sc->irstat; + sc->irstat = 0; +#endif for(i = 0; i < fc->nisodma ; i++){ struct fwohci_dbch *dbch; if((irstat & (1 << i)) != 0){ dbch = &sc->ir[i]; if ((dbch->xferq.flag & FWXFERQ_OPEN) == 0) { device_printf(sc->fc.dev, "dma(%d) not active\n", i); continue; } - if (dbch->xferq.flag & FWXFERQ_PACKET) { - fwohci_ircv(sc, dbch, count); - } else { - fwohci_rbuf_update(sc, i); - } + fwohci_rbuf_update(sc, i); } } } if((stat & OHCI_INT_DMA_IT )){ #ifndef ACK_ALL OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_DMA_IT); #endif - itstat = OREAD(sc, OHCI_IT_STAT); - OWRITE(sc, OHCI_IT_STATCLR, itstat); +#if __FreeBSD_version >= 500000 + itstat = atomic_readandclear_int(&sc->itstat); +#else + itstat = sc->itstat; + sc->itstat = 0; +#endif for(i = 0; i < fc->nisodma ; i++){ if((itstat & (1 << i)) != 0){ fwohci_tbuf_update(sc, i); } } } if((stat & OHCI_INT_DMA_PRRS )){ #ifndef ACK_ALL OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_DMA_PRRS); #endif #if 0 dump_dma(sc, ARRS_CH); dump_db(sc, ARRS_CH); #endif fwohci_arcv(sc, &sc->arrs, count); } if((stat & OHCI_INT_DMA_PRRQ )){ #ifndef ACK_ALL OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_DMA_PRRQ); #endif #if 0 dump_dma(sc, ARRQ_CH); dump_db(sc, ARRQ_CH); #endif fwohci_arcv(sc, &sc->arrq, count); } if(stat & OHCI_INT_PHY_SID){ - caddr_t buf; + u_int32_t *buf, node_id; int plen; #ifndef ACK_ALL OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_PHY_SID); #endif /* Enable bus reset interrupt */ OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_PHY_BUS_R); /* Allow async. request to us */ OWRITE(sc, OHCI_AREQHI, 1 << 31); /* XXX insecure ?? */ OWRITE(sc, OHCI_PREQHI, 0x7fffffff); OWRITE(sc, OHCI_PREQLO, 0xffffffff); OWRITE(sc, OHCI_PREQUPPER, 0x10000); /* Set ATRetries register */ OWRITE(sc, OHCI_ATRETRY, 1<<(13+16) | 0xfff); /* ** Checking whether the node is root or not. If root, turn on ** cycle master. */ - device_printf(fc->dev, "node_id = 0x%08x, ", OREAD(sc, FWOHCI_NODEID)); - if(!(OREAD(sc, FWOHCI_NODEID) & OHCI_NODE_VALID)){ + node_id = OREAD(sc, FWOHCI_NODEID); + plen = OREAD(sc, OHCI_SID_CNT); + + device_printf(fc->dev, "node_id=0x%08x, gen=%d, ", + node_id, (plen >> 16) & 0xff); + if (!(node_id & OHCI_NODE_VALID)) { printf("Bus reset failure\n"); goto sidout; } - if( OREAD(sc, FWOHCI_NODEID) & OHCI_NODE_ROOT ){ + if (node_id & OHCI_NODE_ROOT) { printf("CYCLEMASTER mode\n"); OWRITE(sc, OHCI_LNKCTL, OHCI_CNTL_CYCMTR | OHCI_CNTL_CYCTIMER); - }else{ + } else { printf("non CYCLEMASTER mode\n"); OWRITE(sc, OHCI_LNKCTLCLR, OHCI_CNTL_CYCMTR); OWRITE(sc, OHCI_LNKCTL, OHCI_CNTL_CYCTIMER); } - fc->nodeid = OREAD(sc, FWOHCI_NODEID) & 0x3f; + fc->nodeid = node_id & 0x3f; - plen = OREAD(sc, OHCI_SID_CNT) & OHCI_SID_CNT_MASK; + if (plen & OHCI_SID_ERR) { + device_printf(fc->dev, "SID Error\n"); + goto sidout; + } + plen &= OHCI_SID_CNT_MASK; if (plen < 4 || plen > OHCI_SIDSIZE) { device_printf(fc->dev, "invalid SID len = %d\n", plen); goto sidout; } plen -= 4; /* chop control info */ - buf = malloc(OHCI_SIDSIZE, M_FW, M_NOWAIT); - if(buf == NULL) goto sidout; - bcopy((void *)(uintptr_t)(volatile void *)(fc->sid_buf + 1), - buf, plen); + buf = (u_int32_t *)malloc(OHCI_SIDSIZE, M_FW, M_NOWAIT); + if (buf == NULL) { + device_printf(fc->dev, "malloc failed\n"); + goto sidout; + } + for (i = 0; i < plen / 4; i ++) + buf[i] = FWOHCI_DMA_READ(sc->sid_buf[i+1]); #if 1 /* pending all pre-bus_reset packets */ fwohci_txd(sc, &sc->atrq); fwohci_txd(sc, &sc->atrs); fwohci_arcv(sc, &sc->arrs, -1); fwohci_arcv(sc, &sc->arrq, -1); fw_drain_txq(fc); #endif - fw_sidrcv(fc, buf, plen, 0); + fw_sidrcv(fc, buf, plen); + free(buf, M_FW); } sidout: if((stat & OHCI_INT_DMA_ATRQ )){ #ifndef ACK_ALL OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_DMA_ATRQ); #endif fwohci_txd(sc, &(sc->atrq)); } if((stat & OHCI_INT_DMA_ATRS )){ #ifndef ACK_ALL OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_DMA_ATRS); #endif fwohci_txd(sc, &(sc->atrs)); } if((stat & OHCI_INT_PW_ERR )){ #ifndef ACK_ALL OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_PW_ERR); #endif device_printf(fc->dev, "posted write error\n"); } if((stat & OHCI_INT_ERR )){ #ifndef ACK_ALL OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_ERR); #endif device_printf(fc->dev, "unrecoverable error\n"); } if((stat & OHCI_INT_PHY_INT)) { #ifndef ACK_ALL OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_PHY_INT); #endif device_printf(fc->dev, "phy int\n"); } return; } +#if FWOHCI_TASKQUEUE +static void +fwohci_complete(void *arg, int pending) +{ + struct fwohci_softc *sc = (struct fwohci_softc *)arg; + u_int32_t stat; + +again: + stat = atomic_readandclear_int(&sc->intstat); + if (stat) + fwohci_intr_body(sc, stat, -1); + else + return; + goto again; +} +#endif + +static u_int32_t +fwochi_check_stat(struct fwohci_softc *sc) +{ + u_int32_t stat, irstat, itstat; + + stat = OREAD(sc, FWOHCI_INTSTAT); + if (stat == 0xffffffff) { + device_printf(sc->fc.dev, + "device physically ejected?\n"); + return(stat); + } +#ifdef ACK_ALL + if (stat) + OWRITE(sc, FWOHCI_INTSTATCLR, stat); +#endif + if (stat & OHCI_INT_DMA_IR) { + irstat = OREAD(sc, OHCI_IR_STAT); + OWRITE(sc, OHCI_IR_STATCLR, irstat); + atomic_set_int(&sc->irstat, irstat); + } + if (stat & OHCI_INT_DMA_IT) { + itstat = OREAD(sc, OHCI_IT_STAT); + OWRITE(sc, OHCI_IT_STATCLR, itstat); + atomic_set_int(&sc->itstat, itstat); + } + return(stat); +} + void fwohci_intr(void *arg) { struct fwohci_softc *sc = (struct fwohci_softc *)arg; - u_int32_t stat, bus_reset = 0; + u_int32_t stat; +#if !FWOHCI_TASKQUEUE + u_int32_t bus_reset = 0; +#endif if (!(sc->intmask & OHCI_INT_EN)) { /* polling mode */ return; } - while ((stat = OREAD(sc, FWOHCI_INTSTAT)) != 0) { - if (stat == 0xffffffff) { - device_printf(sc->fc.dev, - "device physically ejected?\n"); - return; - } -#ifdef ACK_ALL - OWRITE(sc, FWOHCI_INTSTATCLR, stat); +#if !FWOHCI_TASKQUEUE +again: #endif - /* We cannot clear bus reset event during bus reset phase */ - if ((stat & ~bus_reset) == 0) - return; - bus_reset = stat & OHCI_INT_PHY_BUS_R; - fwohci_intr_body(sc, stat, -1); - } + stat = fwochi_check_stat(sc); + if (stat == 0 || stat == 0xffffffff) + return; +#if FWOHCI_TASKQUEUE + atomic_set_int(&sc->intstat, stat); + /* XXX mask bus reset intr. during bus reset phase */ + if (stat) + taskqueue_enqueue(taskqueue_swi_giant, &sc->fwohci_task_complete); +#else + /* We cannot clear bus reset event during bus reset phase */ + if ((stat & ~bus_reset) == 0) + return; + bus_reset = stat & OHCI_INT_PHY_BUS_R; + fwohci_intr_body(sc, stat, -1); + goto again; +#endif } static void fwohci_poll(struct firewire_comm *fc, int quick, int count) { int s; u_int32_t stat; struct fwohci_softc *sc; sc = (struct fwohci_softc *)fc; stat = OHCI_INT_DMA_IR | OHCI_INT_DMA_IT | OHCI_INT_DMA_PRRS | OHCI_INT_DMA_PRRQ | OHCI_INT_DMA_ATRQ | OHCI_INT_DMA_ATRS; #if 0 if (!quick) { #else if (1) { #endif - stat = OREAD(sc, FWOHCI_INTSTAT); - if (stat == 0) + stat = fwochi_check_stat(sc); + if (stat == 0 || stat == 0xffffffff) return; - if (stat == 0xffffffff) { - device_printf(sc->fc.dev, - "device physically ejected?\n"); - return; - } -#ifdef ACK_ALL - OWRITE(sc, FWOHCI_INTSTATCLR, stat); -#endif } s = splfw(); fwohci_intr_body(sc, stat, count); splx(s); } static void fwohci_set_intr(struct firewire_comm *fc, int enable) { struct fwohci_softc *sc; sc = (struct fwohci_softc *)fc; if (bootverbose) device_printf(sc->fc.dev, "fwohci_set_intr: %d\n", enable); if (enable) { sc->intmask |= OHCI_INT_EN; OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_EN); } else { sc->intmask &= ~OHCI_INT_EN; OWRITE(sc, FWOHCI_INTMASKCLR, OHCI_INT_EN); } } static void fwohci_tbuf_update(struct fwohci_softc *sc, int dmach) { struct firewire_comm *fc = &sc->fc; volatile struct fwohcidb *db; struct fw_bulkxfer *chunk; struct fw_xferq *it; u_int32_t stat, count; - int s, w=0; + int s, w=0, ldesc; it = fc->it[dmach]; + ldesc = sc->it[dmach].ndesc - 1; s = splfw(); /* unnecessary ? */ + fwdma_sync_multiseg_all(sc->it[dmach].am, BUS_DMASYNC_POSTREAD); while ((chunk = STAILQ_FIRST(&it->stdma)) != NULL) { db = ((struct fwohcidb_tr *)(chunk->end))->db; - stat = db[sc->it[dmach].ndesc - 1].db.desc.status; + stat = FWOHCI_DMA_READ(db[ldesc].db.desc.res) + >> OHCI_STATUS_SHIFT; db = ((struct fwohcidb_tr *)(chunk->start))->db; - count = db[sc->it[dmach].ndesc - 1].db.desc.count; + count = FWOHCI_DMA_READ(db[ldesc].db.desc.res) + & OHCI_COUNT_MASK; if (stat == 0) break; STAILQ_REMOVE_HEAD(&it->stdma, link); switch (stat & FWOHCIEV_MASK){ case FWOHCIEV_ACKCOMPL: #if 0 device_printf(fc->dev, "0x%08x\n", count); #endif break; default: device_printf(fc->dev, - "Isochronous transmit err %02x\n", stat); + "Isochronous transmit err %02x(%s)\n", + stat, fwohcicode[stat & 0x1f]); } STAILQ_INSERT_TAIL(&it->stfree, chunk, link); w++; } splx(s); if (w) wakeup(it); } static void fwohci_rbuf_update(struct fwohci_softc *sc, int dmach) { struct firewire_comm *fc = &sc->fc; - volatile struct fwohcidb *db; + volatile struct fwohcidb_tr *db_tr; struct fw_bulkxfer *chunk; struct fw_xferq *ir; u_int32_t stat; - int s, w=0; + int s, w=0, ldesc; ir = fc->ir[dmach]; + ldesc = sc->ir[dmach].ndesc - 1; +#if 0 + dump_db(sc, dmach); +#endif s = splfw(); + fwdma_sync_multiseg_all(sc->ir[dmach].am, BUS_DMASYNC_POSTREAD); while ((chunk = STAILQ_FIRST(&ir->stdma)) != NULL) { - db = ((struct fwohcidb_tr *)(chunk->end))->db; - stat = db[sc->ir[dmach].ndesc - 1].db.desc.status; + db_tr = (struct fwohcidb_tr *)chunk->end; + stat = FWOHCI_DMA_READ(db_tr->db[ldesc].db.desc.res) + >> OHCI_STATUS_SHIFT; if (stat == 0) break; + + if (chunk->mbuf != NULL) { + bus_dmamap_sync(sc->ir[dmach].dmat, db_tr->dma_map, + BUS_DMASYNC_POSTREAD); + bus_dmamap_unload(sc->ir[dmach].dmat, db_tr->dma_map); + } else if (ir->buf != NULL) { + fwdma_sync_multiseg(ir->buf, chunk->poffset, + ir->bnpacket, BUS_DMASYNC_POSTREAD); + } else { + /* XXX */ + printf("fwohci_rbuf_update: this shouldn't happend\n"); + } + STAILQ_REMOVE_HEAD(&ir->stdma, link); STAILQ_INSERT_TAIL(&ir->stvalid, chunk, link); switch (stat & FWOHCIEV_MASK) { case FWOHCIEV_ACKCOMPL: chunk->resp = 0; break; default: chunk->resp = EINVAL; device_printf(fc->dev, - "Isochronous receive err %02x\n", stat); + "Isochronous receive err %02x(%s)\n", + stat, fwohcicode[stat & 0x1f]); } w++; } splx(s); if (w) { if (ir->flag & FWXFERQ_HANDLER) ir->hand(ir); else wakeup(ir); } } void dump_dma(struct fwohci_softc *sc, u_int32_t ch) { u_int32_t off, cntl, stat, cmd, match; if(ch == 0){ off = OHCI_ATQOFF; }else if(ch == 1){ off = OHCI_ATSOFF; }else if(ch == 2){ off = OHCI_ARQOFF; }else if(ch == 3){ off = OHCI_ARSOFF; }else if(ch < IRX_CH){ off = OHCI_ITCTL(ch - ITX_CH); }else{ off = OHCI_IRCTL(ch - IRX_CH); } cntl = stat = OREAD(sc, off); cmd = OREAD(sc, off + 0xc); match = OREAD(sc, off + 0x10); - device_printf(sc->fc.dev, "dma ch %1x:dma regs 0x%08x 0x%08x 0x%08x 0x%08x \n", + device_printf(sc->fc.dev, "ch %1x cntl:0x%08x cmd:0x%08x match:0x%08x\n", ch, cntl, - stat, cmd, match); stat &= 0xffff ; - if(stat & 0xff00){ + if (stat) { device_printf(sc->fc.dev, "dma %d ch:%s%s%s%s%s%s %s(%x)\n", ch, stat & OHCI_CNTL_DMA_RUN ? "RUN," : "", stat & OHCI_CNTL_DMA_WAKE ? "WAKE," : "", stat & OHCI_CNTL_DMA_DEAD ? "DEAD," : "", stat & OHCI_CNTL_DMA_ACTIVE ? "ACTIVE," : "", stat & OHCI_CNTL_DMA_BT ? "BRANCH," : "", stat & OHCI_CNTL_DMA_BAD ? "BADDMA," : "", fwohcicode[stat & 0x1f], stat & 0x1f ); }else{ device_printf(sc->fc.dev, "dma %d ch: Nostat\n", ch); } } void dump_db(struct fwohci_softc *sc, u_int32_t ch) { struct fwohci_dbch *dbch; - struct fwohcidb_tr *cp = NULL, *pp, *np; + struct fwohcidb_tr *cp = NULL, *pp, *np = NULL; volatile struct fwohcidb *curr = NULL, *prev, *next = NULL; int idb, jdb; u_int32_t cmd, off; if(ch == 0){ off = OHCI_ATQOFF; dbch = &sc->atrq; }else if(ch == 1){ off = OHCI_ATSOFF; dbch = &sc->atrs; }else if(ch == 2){ off = OHCI_ARQOFF; dbch = &sc->arrq; }else if(ch == 3){ off = OHCI_ARSOFF; dbch = &sc->arrs; }else if(ch < IRX_CH){ off = OHCI_ITCTL(ch - ITX_CH); dbch = &sc->it[ch - ITX_CH]; }else { off = OHCI_IRCTL(ch - IRX_CH); dbch = &sc->ir[ch - IRX_CH]; } cmd = OREAD(sc, off + 0xc); if( dbch->ndb == 0 ){ device_printf(sc->fc.dev, "No DB is attached ch=%d\n", ch); return; } pp = dbch->top; prev = pp->db; for(idb = 0 ; idb < dbch->ndb ; idb ++ ){ if(pp == NULL){ curr = NULL; goto outdb; } cp = STAILQ_NEXT(pp, link); if(cp == NULL){ curr = NULL; goto outdb; } np = STAILQ_NEXT(cp, link); - if(cp == NULL) break; for(jdb = 0 ; jdb < dbch->ndesc ; jdb ++ ){ - if((cmd & 0xfffffff0) - == vtophys(&(cp->db[jdb]))){ + if ((cmd & 0xfffffff0) == cp->bus_addr) { curr = cp->db; if(np != NULL){ next = np->db; }else{ next = NULL; } goto outdb; } } pp = STAILQ_NEXT(pp, link); prev = pp->db; } outdb: if( curr != NULL){ +#if 0 printf("Prev DB %d\n", ch); - print_db(prev, ch, dbch->ndesc); + print_db(pp, prev, ch, dbch->ndesc); +#endif printf("Current DB %d\n", ch); - print_db(curr, ch, dbch->ndesc); + print_db(cp, curr, ch, dbch->ndesc); +#if 0 printf("Next DB %d\n", ch); - print_db(next, ch, dbch->ndesc); + print_db(np, next, ch, dbch->ndesc); +#endif }else{ printf("dbdump err ch = %d cmd = 0x%08x\n", ch, cmd); } return; } void -print_db(volatile struct fwohcidb *db, u_int32_t ch, u_int32_t max) +print_db(struct fwohcidb_tr *db_tr, volatile struct fwohcidb *db, + u_int32_t ch, u_int32_t max) { fwohcireg_t stat; int i, key; + u_int32_t cmd, res; if(db == NULL){ printf("No Descriptor is found\n"); return; } printf("ch = %d\n%8s %s %s %s %s %4s %8s %8s %4s:%4s\n", ch, "Current", "OP ", "KEY", "INT", "BR ", "len", "Addr", "Depend", "Stat", "Cnt"); for( i = 0 ; i <= max ; i ++){ - key = db[i].db.desc.control & OHCI_KEY_MASK; + cmd = FWOHCI_DMA_READ(db[i].db.desc.cmd); + res = FWOHCI_DMA_READ(db[i].db.desc.res); + key = cmd & OHCI_KEY_MASK; + stat = res >> OHCI_STATUS_SHIFT; #if __FreeBSD_version >= 500000 printf("%08tx %s %s %s %s %5d %08x %08x %04x:%04x", #else printf("%08x %s %s %s %s %5d %08x %08x %04x:%04x", #endif - vtophys(&db[i]), - dbcode[(db[i].db.desc.control >> 12) & 0xf], - dbkey[(db[i].db.desc.control >> 8) & 0x7], - dbcond[(db[i].db.desc.control >> 4) & 0x3], - dbcond[(db[i].db.desc.control >> 2) & 0x3], - db[i].db.desc.reqcount, - db[i].db.desc.addr, - db[i].db.desc.depend, - db[i].db.desc.status, - db[i].db.desc.count); - stat = db[i].db.desc.status; + db_tr->bus_addr, + dbcode[(cmd >> 28) & 0xf], + dbkey[(cmd >> 24) & 0x7], + dbcond[(cmd >> 20) & 0x3], + dbcond[(cmd >> 18) & 0x3], + cmd & OHCI_COUNT_MASK, + FWOHCI_DMA_READ(db[i].db.desc.addr), + FWOHCI_DMA_READ(db[i].db.desc.depend), + stat, + res & OHCI_COUNT_MASK); if(stat & 0xff00){ printf(" %s%s%s%s%s%s %s(%x)\n", stat & OHCI_CNTL_DMA_RUN ? "RUN," : "", stat & OHCI_CNTL_DMA_WAKE ? "WAKE," : "", stat & OHCI_CNTL_DMA_DEAD ? "DEAD," : "", stat & OHCI_CNTL_DMA_ACTIVE ? "ACTIVE," : "", stat & OHCI_CNTL_DMA_BT ? "BRANCH," : "", stat & OHCI_CNTL_DMA_BAD ? "BADDMA," : "", fwohcicode[stat & 0x1f], stat & 0x1f ); }else{ printf(" Nostat\n"); } if(key == OHCI_KEY_ST2 ){ printf("0x%08x 0x%08x 0x%08x 0x%08x\n", - db[i+1].db.immed[0], - db[i+1].db.immed[1], - db[i+1].db.immed[2], - db[i+1].db.immed[3]); + FWOHCI_DMA_READ(db[i+1].db.immed[0]), + FWOHCI_DMA_READ(db[i+1].db.immed[1]), + FWOHCI_DMA_READ(db[i+1].db.immed[2]), + FWOHCI_DMA_READ(db[i+1].db.immed[3])); } if(key == OHCI_KEY_DEVICE){ return; } - if((db[i].db.desc.control & OHCI_BRANCH_MASK) + if((cmd & OHCI_BRANCH_MASK) == OHCI_BRANCH_ALWAYS){ return; } - if((db[i].db.desc.control & OHCI_CMD_MASK) + if((cmd & OHCI_CMD_MASK) == OHCI_OUTPUT_LAST){ return; } - if((db[i].db.desc.control & OHCI_CMD_MASK) + if((cmd & OHCI_CMD_MASK) == OHCI_INPUT_LAST){ return; } if(key == OHCI_KEY_ST2 ){ i++; } } return; } void fwohci_ibr(struct firewire_comm *fc) { struct fwohci_softc *sc; u_int32_t fun; device_printf(fc->dev, "Initiate bus reset\n"); sc = (struct fwohci_softc *)fc; /* * Set root hold-off bit so that non cyclemaster capable node * shouldn't became the root node. */ #if 1 fun = fwphy_rddata(sc, FW_PHY_IBR_REG); fun |= FW_PHY_IBR | FW_PHY_RHB; fun = fwphy_wrdata(sc, FW_PHY_IBR_REG, fun); #else /* Short bus reset */ fun = fwphy_rddata(sc, FW_PHY_ISBR_REG); fun |= FW_PHY_ISBR | FW_PHY_RHB; fun = fwphy_wrdata(sc, FW_PHY_ISBR_REG, fun); #endif } void 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 fw_pkt *fp; volatile struct fwohci_txpkthdr *ohcifp; unsigned short chtag; int idb; dbch = &sc->it[dmach]; chtag = sc->it[dmach].xferq.flag & 0xff; db_tr = (struct fwohcidb_tr *)(bulkxfer->start); fdb_tr = (struct fwohcidb_tr *)(bulkxfer->end); /* -device_printf(sc->fc.dev, "DB %08x %08x %08x\n", bulkxfer, vtophys(db_tr->db), vtophys(fdb_tr->db)); +device_printf(sc->fc.dev, "DB %08x %08x %08x\n", bulkxfer, db_tr->bus_addr, fdb_tr->bus_addr); */ - for( idb = 0 ; idb < bulkxfer->npacket ; idb ++){ + for (idb = 0; idb < dbch->xferq.bnpacket; idb ++) { db = db_tr->db; -#if 0 - db[0].db.desc.control - = OHCI_OUTPUT_MORE | OHCI_KEY_ST2; - db[0].db.desc.reqcount = 8; -#endif fp = (struct fw_pkt *)db_tr->buf; ohcifp = (volatile struct fwohci_txpkthdr *) db[1].db.immed; - ohcifp->mode.ld[0] = ntohl(fp->mode.ld[0]); - ohcifp->mode.stream.len = ntohs(fp->mode.stream.len); + ohcifp->mode.ld[0] = fp->mode.ld[0]; + 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]); +#endif - db[2].db.desc.reqcount = ntohs(fp->mode.stream.len); - db[2].db.desc.status = 0; - db[2].db.desc.count = 0; + FWOHCI_DMA_CLEAR(db[2].db.desc.cmd, OHCI_COUNT_MASK); + FWOHCI_DMA_SET(db[2].db.desc.cmd, fp->mode.stream.len); + FWOHCI_DMA_WRITE(db[2].db.desc.res, 0); #if 0 /* if bulkxfer->npackets changes */ - db[2].db.desc.control = OHCI_OUTPUT_LAST + db[2].db.desc.cmd = OHCI_OUTPUT_LAST | OHCI_UPDATE | OHCI_BRANCH_ALWAYS; db[0].db.desc.depend = = db[dbch->ndesc - 1].db.desc.depend - = vtophys(STAILQ_NEXT(db_tr, link)->db) | dbch->ndesc; + = STAILQ_NEXT(db_tr, link)->bus_addr | dbch->ndesc; #else - db[0].db.desc.depend |= dbch->ndesc; - db[dbch->ndesc - 1].db.desc.depend |= dbch->ndesc; + FWOHCI_DMA_SET(db[0].db.desc.depend, dbch->ndesc); + FWOHCI_DMA_SET(db[dbch->ndesc - 1].db.desc.depend, dbch->ndesc); #endif bulkxfer->end = (caddr_t)db_tr; db_tr = STAILQ_NEXT(db_tr, link); } db = ((struct fwohcidb_tr *)bulkxfer->end)->db; - db[0].db.desc.depend &= ~0xf; - db[dbch->ndesc - 1].db.desc.depend &= ~0xf; + FWOHCI_DMA_CLEAR(db[0].db.desc.depend, 0xf); + FWOHCI_DMA_CLEAR(db[dbch->ndesc - 1].db.desc.depend, 0xf); #if 0 /* if bulkxfer->npackets changes */ db[dbch->ndesc - 1].db.desc.control |= OHCI_INTERRUPT_ALWAYS; /* OHCI 1.1 and above */ db[0].db.desc.control |= OHCI_INTERRUPT_ALWAYS; #endif /* db_tr = (struct fwohcidb_tr *)bulkxfer->start; fdb_tr = (struct fwohcidb_tr *)bulkxfer->end; -device_printf(sc->fc.dev, "DB %08x %3d %08x %08x\n", bulkxfer, bulkxfer->npacket, vtophys(db_tr->db), vtophys(fdb_tr->db)); +device_printf(sc->fc.dev, "DB %08x %3d %08x %08x\n", bulkxfer, bulkxfer->npacket, db_tr->bus_addr, fdb_tr->bus_addr); */ return; } static int -fwohci_add_tx_buf(struct fwohcidb_tr *db_tr, unsigned short size, - int mode, void *buf) +fwohci_add_tx_buf(struct fwohci_dbch *dbch, struct fwohcidb_tr *db_tr, + int poffset) { volatile struct fwohcidb *db = db_tr->db; + struct fw_xferq *it; int err = 0; - if(buf == 0){ + + it = &dbch->xferq; + if(it->buf == 0){ err = EINVAL; return err; } - db_tr->buf = buf; + db_tr->buf = fwdma_v_addr(it->buf, poffset); db_tr->dbcnt = 3; - db_tr->dummy = NULL; - db[0].db.desc.control = OHCI_OUTPUT_MORE | OHCI_KEY_ST2; - db[0].db.desc.reqcount = 8; - db[2].db.desc.addr = vtophys(buf) + sizeof(u_int32_t); - db[2].db.desc.control = - OHCI_OUTPUT_LAST | OHCI_UPDATE | OHCI_BRANCH_ALWAYS; + FWOHCI_DMA_WRITE(db[0].db.desc.cmd, + OHCI_OUTPUT_MORE | OHCI_KEY_ST2 | 8); + FWOHCI_DMA_WRITE(db[2].db.desc.addr, + fwdma_bus_addr(it->buf, poffset) + sizeof(u_int32_t)); + + FWOHCI_DMA_WRITE(db[2].db.desc.cmd, + OHCI_OUTPUT_LAST | OHCI_UPDATE | OHCI_BRANCH_ALWAYS); #if 1 - db[0].db.desc.status = 0; - db[0].db.desc.count = 0; - db[2].db.desc.status = 0; - db[2].db.desc.count = 0; + FWOHCI_DMA_WRITE(db[0].db.desc.res, 0); + FWOHCI_DMA_WRITE(db[2].db.desc.res, 0); #endif - if( mode & FWXFERQ_STREAM ){ - if(mode & FWXFERQ_PACKET ){ - db[2].db.desc.control |= OHCI_INTERRUPT_ALWAYS; - } - } else { - printf("fwohci_add_tx_buf: who calls me?"); - } - return 1; + return 0; } int -fwohci_add_rx_buf(struct fwohcidb_tr *db_tr, unsigned short size, int mode, - void *buf, void *dummy) +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; - int i; - void *dbuf[2]; + struct fw_xferq *ir; + int i, ldesc; + bus_addr_t dbuf[2]; int dsiz[2]; - if(buf == 0){ - buf = malloc(size, M_FW, M_NOWAIT); - if(buf == NULL) return 0; - db_tr->buf = buf; + ir = &dbch->xferq; + if (ir->buf == NULL && (dbch->xferq.flag & FWXFERQ_EXTBUF) == 0) { + db_tr->buf = fwdma_malloc_size(dbch->dmat, &db_tr->dma_map, + ir->psize, &dbuf[0], BUS_DMA_NOWAIT); + if (db_tr->buf == NULL) + return(ENOMEM); db_tr->dbcnt = 1; - db_tr->dummy = NULL; - dsiz[0] = size; - dbuf[0] = buf; - }else if(dummy == NULL){ - db_tr->buf = buf; - db_tr->dbcnt = 1; - db_tr->dummy = NULL; - dsiz[0] = size; - dbuf[0] = buf; - }else{ - db_tr->buf = buf; - db_tr->dbcnt = 2; - db_tr->dummy = dummy; - dsiz[0] = sizeof(u_int32_t); - dsiz[1] = size; - dbuf[0] = dummy; - dbuf[1] = buf; + dsiz[0] = ir->psize; + bus_dmamap_sync(dbch->dmat, db_tr->dma_map, + BUS_DMASYNC_PREREAD); + } else { + db_tr->dbcnt = 0; + if (dummy_dma != NULL) { + dsiz[db_tr->dbcnt] = sizeof(u_int32_t); + dbuf[db_tr->dbcnt++] = dummy_dma->bus_addr; + } + dsiz[db_tr->dbcnt] = ir->psize; + if (ir->buf != NULL) { + db_tr->buf = fwdma_v_addr(ir->buf, poffset); + dbuf[db_tr->dbcnt] = fwdma_bus_addr( ir->buf, poffset); + } + db_tr->dbcnt++; } for(i = 0 ; i < db_tr->dbcnt ; i++){ - db[i].db.desc.addr = vtophys(dbuf[i]) ; - db[i].db.desc.control = OHCI_INPUT_MORE; - db[i].db.desc.reqcount = dsiz[i]; - if( mode & FWXFERQ_STREAM ){ - db[i].db.desc.control |= OHCI_UPDATE; + FWOHCI_DMA_WRITE(db[i].db.desc.addr, dbuf[i]); + FWOHCI_DMA_WRITE(db[i].db.desc.cmd, OHCI_INPUT_MORE | dsiz[i]); + if (ir->flag & FWXFERQ_STREAM) { + FWOHCI_DMA_SET(db[i].db.desc.cmd, OHCI_UPDATE); } - db[i].db.desc.status = 0; - db[i].db.desc.count = dsiz[i]; + FWOHCI_DMA_WRITE(db[i].db.desc.res, dsiz[i]); } - if( mode & FWXFERQ_STREAM ){ - db[db_tr->dbcnt - 1].db.desc.control |= OHCI_INPUT_LAST; - if(mode & FWXFERQ_PACKET ){ - db[db_tr->dbcnt - 1].db.desc.control - |= OHCI_INTERRUPT_ALWAYS; - } + ldesc = db_tr->dbcnt - 1; + if (ir->flag & FWXFERQ_STREAM) { + FWOHCI_DMA_SET(db[ldesc].db.desc.cmd, OHCI_INPUT_LAST); } - db[db_tr->dbcnt - 1].db.desc.control |= OHCI_BRANCH_ALWAYS; - return 1; + FWOHCI_DMA_SET(db[ldesc].db.desc.cmd, OHCI_BRANCH_ALWAYS); + return 0; } -static void -fwohci_ircv(struct fwohci_softc *sc, struct fwohci_dbch *dbch, int count) + +static int +fwohci_arcv_swap(struct fw_pkt *fp, int len) { - struct fwohcidb_tr *db_tr = dbch->top, *odb_tr; - struct firewire_comm *fc = (struct firewire_comm *)sc; - int z = 1; - struct fw_pkt *fp; - u_int8_t *ld; - u_int32_t off = NULL; - u_int32_t stat; - u_int32_t *qld; - u_int32_t reg; - u_int spd; - u_int dmach; - int len, i, plen; - caddr_t buf; + struct fw_pkt *fp0; + u_int32_t ld0; + int slen; +#if BYTE_ORDER == BIG_ENDIAN + int i; +#endif - for(dmach = 0 ; dmach < sc->fc.nisodma ; dmach++){ - if( &sc->ir[dmach] == dbch){ - off = OHCI_IROFF(dmach); - break; - } + ld0 = FWOHCI_DMA_READ(fp->mode.ld[0]); +#if 0 + printf("ld0: x%08x\n", ld0); +#endif + fp0 = (struct fw_pkt *)&ld0; + switch (fp0->mode.common.tcode) { + case FWTCODE_RREQQ: + case FWTCODE_WRES: + case FWTCODE_WREQQ: + case FWTCODE_RRESQ: + case FWOHCITCODE_PHY: + slen = 12; + break; + case FWTCODE_RREQB: + case FWTCODE_WREQB: + case FWTCODE_LREQ: + case FWTCODE_RRESB: + case FWTCODE_LRES: + slen = 16; + break; + default: + printf("Unknown tcode %d\n", fp0->mode.common.tcode); + return(0); } - if(off == NULL){ - return; + if (slen > len) { + if (firewire_debug) + printf("splitted header\n"); + return(-slen); } - if(!(dbch->xferq.flag & FWXFERQ_RUNNING)){ - fwohci_irx_disable(&sc->fc, dmach); - return; - } - - odb_tr = NULL; - db_tr = dbch->top; - i = 0; - while ((reg = db_tr->db[0].db.desc.status) & 0x1f) { - if (count >= 0 && count-- == 0) - break; - ld = (u_int8_t *)db_tr->buf; - if (dbch->xferq.flag & FWXFERQ_PACKET) { - /* skip timeStamp */ - ld += sizeof(struct fwohci_trailer); - } - qld = (u_int32_t *)ld; - len = dbch->xferq.psize - (db_tr->db[0].db.desc.count); -/* -{ -device_printf(sc->fc.dev, "%04x %2x 0x%08x 0x%08x 0x%08x 0x%08x\n", len, - db_tr->db[0].db.desc.status & 0x1f, qld[0],qld[1],qld[2],qld[3]); +#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); } -*/ - fp=(struct fw_pkt *)ld; - qld[0] = htonl(qld[0]); - plen = sizeof(struct fw_isohdr) - + ntohs(fp->mode.stream.len) + sizeof(u_int32_t); - ld += plen; - len -= plen; - buf = db_tr->buf; - db_tr->buf = NULL; - stat = reg & 0x1f; - spd = reg & 0x3; - switch(stat){ - case FWOHCIEV_ACKCOMPL: - case FWOHCIEV_ACKPEND: - fw_rcv(&sc->fc, buf, plen - sizeof(u_int32_t), dmach, sizeof(u_int32_t), spd); - break; - default: - free(buf, M_FW); - device_printf(sc->fc.dev, "Isochronous receive err %02x\n", stat); - break; - } - i++; - fwohci_add_rx_buf(db_tr, dbch->xferq.psize, - dbch->xferq.flag, 0, NULL); - db_tr->db[0].db.desc.depend &= ~0xf; - if(dbch->pdb_tr != NULL){ - dbch->pdb_tr->db[0].db.desc.depend |= z; - } else { - /* XXX should be rewritten in better way */ - dbch->bottom->db[0].db.desc.depend |= z; - } - dbch->pdb_tr = db_tr; - db_tr = STAILQ_NEXT(db_tr, link); - } - dbch->top = db_tr; - reg = OREAD(sc, OHCI_DMACTL(off)); - if (reg & OHCI_CNTL_DMA_ACTIVE) - return; - device_printf(sc->fc.dev, "IR DMA %d stopped at %x status=%x (%d)\n", - dmach, OREAD(sc, OHCI_DMACMD(off)), reg, i); - dbch->top = db_tr; - fwohci_irx_enable(fc, dmach); -} -#define PLEN(x) roundup2(ntohs(x), sizeof(u_int32_t)) +#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, int hlen) +fwohci_get_plen(struct fwohci_softc *sc, struct fwohci_dbch *dbch, struct fw_pkt *fp) { - int i, r; + int r; - for( i = 4; i < hlen ; i+=4){ - fp->mode.ld[i/4] = htonl(fp->mode.ld[i/4]); - } - 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: 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]; + + FWOHCI_DMA_CLEAR(db->db.desc.depend, 0xf); + FWOHCI_DMA_WRITE(db->db.desc.res, dbch->xferq.psize); + FWOHCI_DMA_SET(dbch->bottom->db[0].db.desc.depend, 1); + fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREWRITE); + dbch->bottom = db_tr; +} + +static void fwohci_arcv(struct fwohci_softc *sc, struct fwohci_dbch *dbch, int count) { struct fwohcidb_tr *db_tr; - int z = 1; + struct iovec vec[2]; + struct fw_pkt pktbuf; + int nvec; struct fw_pkt *fp; u_int8_t *ld; - u_int32_t stat, off; + u_int32_t stat, off, status; u_int spd; - int len, plen, hlen, pcnt, poff = 0, rlen; + int len, plen, hlen, pcnt, offset; int s; caddr_t buf; int resCount; if(&sc->arrq == dbch){ off = OHCI_ARQOFF; }else if(&sc->arrs == dbch){ off = OHCI_ARSOFF; }else{ return; } s = splfw(); db_tr = dbch->top; pcnt = 0; /* XXX we cannot handle a packet which lies in more than two buf */ - while (db_tr->db[0].db.desc.status & OHCI_CNTL_DMA_ACTIVE) { - ld = (u_int8_t *)db_tr->buf + dbch->buf_offset; - resCount = db_tr->db[0].db.desc.count; - len = dbch->xferq.psize - resCount - - dbch->buf_offset; + fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_POSTREAD); + fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_POSTWRITE); + status = FWOHCI_DMA_READ(db_tr->db[0].db.desc.res) >> OHCI_STATUS_SHIFT; + resCount = FWOHCI_DMA_READ(db_tr->db[0].db.desc.res) & OHCI_COUNT_MASK; +#if 0 + printf("status 0x%04x, resCount 0x%04x\n", status, resCount); +#endif + while (status & OHCI_CNTL_DMA_ACTIVE) { + len = dbch->xferq.psize - resCount; + ld = (u_int8_t *)db_tr->buf; + if (dbch->pdb_tr == NULL) { + len -= dbch->buf_offset; + ld += dbch->buf_offset; + } + if (len > 0) + bus_dmamap_sync(dbch->dmat, db_tr->dma_map, + BUS_DMASYNC_POSTREAD); while (len > 0 ) { if (count >= 0 && count-- == 0) goto out; - if(dbch->frag.buf != NULL){ - buf = dbch->frag.buf; - if (dbch->frag.plen < 0) { - /* incomplete header */ - int hlen; + if(dbch->pdb_tr != NULL){ + /* we have a fragment in previous buffer */ + int rlen; - hlen = - dbch->frag.plen; - rlen = hlen - dbch->frag.len; - bcopy(ld, dbch->frag.buf + dbch->frag.len, rlen); + offset = dbch->buf_offset; + if (offset < 0) + offset = - offset; + buf = dbch->pdb_tr->buf + offset; + rlen = dbch->xferq.psize - offset; + if (firewire_debug) + printf("rlen=%d, offset=%d\n", + rlen, dbch->buf_offset); + if (dbch->buf_offset < 0) { + /* splitted in header, pull up */ + char *p; + + p = (char *)&pktbuf; + bcopy(buf, p, rlen); + p += rlen; + /* this must be too long but harmless */ + rlen = sizeof(pktbuf) - rlen; + if (rlen < 0) + printf("why rlen < 0\n"); + bcopy(db_tr->buf, p, rlen); ld += rlen; len -= rlen; - dbch->frag.len += rlen; -#if 0 - printf("(1)frag.plen=%d frag.len=%d rlen=%d len=%d\n", dbch->frag.plen, dbch->frag.len, rlen, len); -#endif - fp=(struct fw_pkt *)dbch->frag.buf; - dbch->frag.plen - = fwohci_get_plen(sc, - dbch, fp, hlen); - if (dbch->frag.plen == 0) - goto out; + hlen = fwohci_arcv_swap(&pktbuf, sizeof(pktbuf)); + if (hlen < 0) { + printf("hlen < 0 shouldn't happen"); + } + offset = sizeof(pktbuf); + vec[0].iov_base = (char *)&pktbuf; + vec[0].iov_len = offset; + } else { + /* splitted in payload */ + offset = rlen; + vec[0].iov_base = buf; + vec[0].iov_len = rlen; } - rlen = dbch->frag.plen - dbch->frag.len; -#if 0 - printf("(2)frag.plen=%d frag.len=%d rlen=%d len=%d\n", dbch->frag.plen, dbch->frag.len, rlen, len); -#endif - bcopy(ld, dbch->frag.buf + dbch->frag.len, - rlen); - ld += rlen; - len -= rlen; - plen = dbch->frag.plen; - dbch->frag.buf = NULL; - dbch->frag.plen = 0; - dbch->frag.len = 0; - poff = 0; - }else{ + fp=(struct fw_pkt *)vec[0].iov_base; + nvec = 1; + } else { + /* no fragment in previous buffer */ fp=(struct fw_pkt *)ld; - fp->mode.ld[0] = htonl(fp->mode.ld[0]); - switch(fp->mode.common.tcode){ - case FWTCODE_RREQQ: - case FWTCODE_WRES: - case FWTCODE_WREQQ: - case FWTCODE_RRESQ: - case FWOHCITCODE_PHY: - hlen = 12; - break; - case FWTCODE_RREQB: - case FWTCODE_WREQB: - case FWTCODE_LREQ: - case FWTCODE_RRESB: - case FWTCODE_LRES: - hlen = 16; - break; - default: - device_printf(sc->fc.dev, "Unknown tcode %d\n", fp->mode.common.tcode); + hlen = fwohci_arcv_swap(fp, len); + if (hlen == 0) + /* XXX need reset */ goto out; + if (hlen < 0) { + dbch->pdb_tr = db_tr; + dbch->buf_offset = - dbch->buf_offset; + /* sanity check */ + if (resCount != 0) + printf("resCount != 0 !?\n"); + goto out; } - if (len >= hlen) { - plen = fwohci_get_plen(sc, - dbch, fp, hlen); - if (plen == 0) - goto out; - plen = (plen + 3) & ~3; - len -= plen; - } else { - plen = -hlen; - len -= hlen; + offset = 0; + nvec = 0; + } + plen = fwohci_get_plen(sc, dbch, fp) - offset; + if (plen < 0) { + /* minimum header size + trailer + = sizeof(fw_pkt) so this shouldn't happens */ + printf("plen is negative! offset=%d\n", offset); + goto out; + } + if (plen > 0) { + len -= plen; + if (len < 0) { + dbch->pdb_tr = db_tr; + if (firewire_debug) + printf("splitted payload\n"); + /* sanity check */ + if (resCount != 0) + printf("resCount != 0 !?\n"); + goto out; } - if(resCount > 0 || len > 0){ - buf = malloc(plen, M_FW, M_NOWAIT); - if(buf == NULL){ - printf("cannot malloc!\n"); - free(db_tr->buf, M_FW); - goto out; - } - bcopy(ld, buf, plen); - poff = 0; - dbch->frag.buf = NULL; - dbch->frag.plen = 0; - dbch->frag.len = 0; - }else if(len < 0){ - dbch->frag.buf = db_tr->buf; - if (plen < 0) { -#if 0 - printf("plen < 0:" - "hlen: %d len: %d\n", - hlen, len); -#endif - dbch->frag.len = hlen + len; - dbch->frag.plen = -hlen; - } else { - dbch->frag.len = plen + len; - dbch->frag.plen = plen; - } - bcopy(ld, db_tr->buf, dbch->frag.len); - buf = NULL; - }else{ - buf = db_tr->buf; - poff = ld - (u_int8_t *)buf; - dbch->frag.buf = NULL; - dbch->frag.plen = 0; - dbch->frag.len = 0; - } + vec[nvec].iov_base = ld; + vec[nvec].iov_len = plen; + nvec ++; ld += plen; } - if( buf != NULL){ + dbch->buf_offset = ld - (u_int8_t *)db_tr->buf; + if (nvec == 0) + printf("nvec == 0\n"); + /* DMA result-code will be written at the tail of packet */ - stat = ((struct fwohci_trailer *)(ld - sizeof(struct fwohci_trailer)))->stat; - spd = (stat >> 5) & 0x3; - stat &= 0x1f; - switch(stat){ - case FWOHCIEV_ACKPEND: +#if BYTE_ORDER == BIG_ENDIAN + stat = FWOHCI_DMA_READ(((struct fwohci_trailer *)(ld - sizeof(struct fwohci_trailer)))->stat) >> 16; +#else + stat = ((struct fwohci_trailer *)(ld - sizeof(struct fwohci_trailer)))->stat; +#endif #if 0 - printf("fwohci_arcv: ack pending tcode=0x%x..\n", fp->mode.common.tcode); + printf("plen: %d, stat %x\n", plen ,stat); #endif - /* fall through */ - case FWOHCIEV_ACKCOMPL: - if( poff != 0 ) - bcopy(buf+poff, buf, plen - 4); - fw_rcv(&sc->fc, buf, plen - sizeof(struct fwohci_trailer), 0, 0, spd); + spd = (stat >> 5) & 0x3; + stat &= 0x1f; + switch(stat){ + case FWOHCIEV_ACKPEND: +#if 0 + printf("fwohci_arcv: ack pending tcode=0x%x..\n", fp->mode.common.tcode); +#endif + /* fall through */ + case FWOHCIEV_ACKCOMPL: + if ((vec[nvec-1].iov_len -= + sizeof(struct fwohci_trailer)) == 0) + nvec--; + fw_rcv(&sc->fc, vec, nvec, 0, spd); break; - case FWOHCIEV_BUSRST: - free(buf, M_FW); - if (sc->fc.status != FWBUSRESET) - printf("got BUSRST packet!?\n"); - break; - default: - device_printf(sc->fc.dev, "Async DMA Receive error err = %02x %s\n", stat, fwohcicode[stat]); + case FWOHCIEV_BUSRST: + if (sc->fc.status != FWBUSRESET) + printf("got BUSRST packet!?\n"); + break; + default: + device_printf(sc->fc.dev, "Async DMA Receive error err = %02x %s\n", stat, fwohcicode[stat]); #if 0 /* XXX */ - goto out; + goto out; #endif - break; - } + break; } pcnt ++; - }; + if (dbch->pdb_tr != NULL) { + fwohci_arcv_free_buf(dbch, dbch->pdb_tr); + dbch->pdb_tr = NULL; + } + + } out: if (resCount == 0) { /* done on this buffer */ - fwohci_add_rx_buf(db_tr, dbch->xferq.psize, - dbch->xferq.flag, 0, NULL); - dbch->bottom->db[0].db.desc.depend |= z; - dbch->bottom = db_tr; + if (dbch->pdb_tr == NULL) { + fwohci_arcv_free_buf(dbch, db_tr); + dbch->buf_offset = 0; + } else + if (dbch->pdb_tr != db_tr) + printf("pdb_tr != db_tr\n"); db_tr = STAILQ_NEXT(db_tr, link); + status = FWOHCI_DMA_READ(db_tr->db[0].db.desc.res) + >> OHCI_STATUS_SHIFT; + resCount = FWOHCI_DMA_READ(db_tr->db[0].db.desc.res) + & OHCI_COUNT_MASK; + /* XXX check buffer overrun */ dbch->top = db_tr; - dbch->buf_offset = 0; } else { dbch->buf_offset = dbch->xferq.psize - resCount; break; } /* XXX make sure DMA is not dead */ } #if 0 if (pcnt < 1) printf("fwohci_arcv: no packets\n"); #endif splx(s); } Index: head/sys/dev/firewire/fwohci_pci.c =================================================================== --- head/sys/dev/firewire/fwohci_pci.c (revision 113583) +++ head/sys/dev/firewire/fwohci_pci.c (revision 113584) @@ -1,387 +1,414 @@ /* + * 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 * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the acknowledgement as bellow: * * This product includes software developed by K. Kobayashi and H. SHimokawa * * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ +#define BOUNCE_BUFFER_TEST 0 + #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#include #include #include static int fwohci_pci_attach(device_t self); static int fwohci_pci_detach(device_t self); /* * The probe routine. */ static int fwohci_pci_probe( device_t dev ) { #if 1 u_int32_t id; id = pci_get_devid(dev); if (id == (FW_VENDORID_NEC | FW_DEVICE_UPD861)) { device_set_desc(dev, "NEC uPD72861"); return 0; } if (id == (FW_VENDORID_NEC | FW_DEVICE_UPD871)) { device_set_desc(dev, "NEC uPD72871/2"); return 0; } if (id == (FW_VENDORID_TI | FW_DEVICE_TITSB22)) { device_set_desc(dev, "Texas Instruments TSB12LV22"); return 0; } if (id == (FW_VENDORID_TI | FW_DEVICE_TITSB23)) { device_set_desc(dev, "Texas Instruments TSB12LV23"); return 0; } if (id == (FW_VENDORID_TI | FW_DEVICE_TITSB26)) { device_set_desc(dev, "Texas Instruments TSB12LV26"); return 0; } if (id == (FW_VENDORID_TI | FW_DEVICE_TITSB43)) { device_set_desc(dev, "Texas Instruments TSB43AA22"); return 0; } if (id == (FW_VENDORID_TI | FW_DEVICE_TITSB43A)) { device_set_desc(dev, "Texas Instruments TSB43AB22/A"); return 0; } if (id == (FW_VENDORID_TI | FW_DEVICE_TIPCI4450)) { device_set_desc(dev, "Texas Instruments PCI4450"); return 0; } if (id == (FW_VENDORID_TI | FW_DEVICE_TIPCI4410A)) { device_set_desc(dev, "Texas Instruments PCI4410A"); return 0; } if (id == (FW_VENDORID_SONY | FW_DEVICE_CX3022)) { - device_set_desc(dev, "SONY CX3022"); + device_set_desc(dev, "Sony CX3022"); return 0; } if (id == (FW_VENDORID_VIA | FW_DEVICE_VT6306)) { device_set_desc(dev, "VIA VT6306"); return 0; } if (id == (FW_VENDORID_RICOH | FW_DEVICE_R5C552)) { device_set_desc(dev, "Ricoh R5C552"); return 0; } if (id == (FW_VENDORID_APPLE | FW_DEVICE_PANGEA)) { device_set_desc(dev, "Apple Pangea"); return 0; } if (id == (FW_VENDORID_APPLE | FW_DEVICE_UNINORTH)) { device_set_desc(dev, "Apple UniNorth"); return 0; } if (id == (FW_VENDORID_LUCENT | FW_DEVICE_FW322)) { device_set_desc(dev, "Lucent FW322/323"); return 0; } #endif if (pci_get_class(dev) == PCIC_SERIALBUS && pci_get_subclass(dev) == PCIS_SERIALBUS_FW && pci_get_progif(dev) == PCI_INTERFACE_OHCI) { device_printf(dev, "vendor=%x, dev=%x\n", pci_get_vendor(dev), pci_get_device(dev)); device_set_desc(dev, "1394 Open Host Controller Interface"); return 0; } return ENXIO; } #if __FreeBSD_version < 500000 static void fwohci_dummy_intr(void *arg) { /* XXX do nothing */ } #endif static int fwohci_pci_init(device_t self) { - int latency, cache_line; + int olatency, latency, ocache_line, cache_line; u_int16_t cmd; cmd = pci_read_config(self, PCIR_COMMAND, 2); cmd |= PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN | PCIM_CMD_MWRICEN | PCIM_CMD_SERRESPEN | PCIM_CMD_PERRESPEN; #if 1 cmd &= ~PCIM_CMD_MWRICEN; #endif pci_write_config(self, PCIR_COMMAND, cmd, 2); - latency = pci_read_config(self, PCIR_LATTIMER, 1); + latency = olatency = pci_read_config(self, PCIR_LATTIMER, 1); #define DEF_LATENCY 0x20 - if( latency < DEF_LATENCY ) { + if (olatency < DEF_LATENCY) { latency = DEF_LATENCY; - device_printf(self, "PCI bus latency was changing to"); - pci_write_config(self, PCIR_LATTIMER,latency, 1); - } else - { - device_printf(self, "PCI bus latency is"); + pci_write_config(self, PCIR_LATTIMER, latency, 1); } - printf(" %d.\n", (int) latency); - cache_line = pci_read_config(self, PCIR_CACHELNSZ, 1); -#if 0 -#define DEF_CACHE_LINE 0xc - cache_line = DEF_CACHE_LINE; - pci_write_config(self, PCIR_CACHELNSZ, cache_line, 1); -#endif - if (bootverbose) - device_printf(self, "cache size %d.\n", (int) cache_line); + cache_line = ocache_line = pci_read_config(self, PCIR_CACHELNSZ, 1); +#define DEF_CACHE_LINE 8 + if (ocache_line < DEF_CACHE_LINE) { + cache_line = DEF_CACHE_LINE; + pci_write_config(self, PCIR_CACHELNSZ, cache_line, 1); + } + + if (firewire_debug) { + device_printf(self, "latency timer %d -> %d.\n", + olatency, latency); + device_printf(self, "cache size %d -> %d.\n", + ocache_line, cache_line); + } + return 0; } static int fwohci_pci_attach(device_t self) { fwohci_softc_t *sc = device_get_softc(self); int err; int rid, s; #if __FreeBSD_version < 500000 int intr; /* For the moment, put in a message stating what is wrong */ intr = pci_read_config(self, PCIR_INTLINE, 1); if (intr == 0 || intr == 255) { device_printf(self, "Invalid irq %d\n", intr); #ifdef __i386__ device_printf(self, "Please switch PNP-OS to 'No' in BIOS\n"); #endif -#if 0 - return ENXIO; -#endif } #endif + if (bootverbose) + firewire_debug = bootverbose; + fwohci_pci_init(self); rid = PCI_CBMEM; sc->bsr = bus_alloc_resource(self, SYS_RES_MEMORY, &rid, 0, ~0, 1, RF_ACTIVE); if (!sc->bsr) { device_printf(self, "Could not map memory\n"); return ENXIO; } sc->bst = rman_get_bustag(sc->bsr); sc->bsh = rman_get_bushandle(sc->bsr); rid = 0; sc->irq_res = bus_alloc_resource(self, SYS_RES_IRQ, &rid, 0, ~0, 1, RF_SHAREABLE | RF_ACTIVE); if (sc->irq_res == NULL) { device_printf(self, "Could not allocate irq\n"); fwohci_pci_detach(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, INTR_TYPE_NET, + err = bus_setup_intr(self, sc->irq_res, +#if FWOHCI_TASKQUEUE + INTR_TYPE_NET | INTR_MPSAFE, +#else + INTR_TYPE_NET, +#endif (driver_intr_t *) fwohci_intr, sc, &sc->ih); #if __FreeBSD_version < 500000 /* 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); #endif if (err) { device_printf(self, "Could not setup irq, %d\n", err); fwohci_pci_detach(self); return ENXIO; } + err = bus_dma_tag_create(/*parent*/NULL, /*alignment*/1, + /*boundary*/0, +#if BOUNCE_BUFFER_TEST + /*lowaddr*/BUS_SPACE_MAXADDR_24BIT, +#else + /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, +#endif + /*highaddr*/BUS_SPACE_MAXADDR, + /*filter*/NULL, /*filterarg*/NULL, + /*maxsize*/0x100000, + /*nsegments*/0x20, + /*maxsegsz*/0x8000, + /*flags*/BUS_DMA_ALLOCNOW, + &sc->fc.dmat); + if (err != 0) { + printf("fwohci_pci_attach: Could not allocate DMA tag " + "- error %d\n", err); + return (ENOMEM); + } + err = fwohci_init(sc, self); if (!err) err = device_probe_and_attach(sc->fc.bdev); if (err) { device_printf(self, "FireWire init failed\n"); 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. */ -#if 0 - DELAY(100); -#endif s = splfw(); fwohci_intr((void *)sc); splx(s); return 0; } static int fwohci_pci_detach(device_t self) { fwohci_softc_t *sc = device_get_softc(self); int s; s = splfw(); fwohci_stop(sc, self); bus_generic_detach(self); /* disable interrupts that might have been switched on */ if (sc->bst && sc->bsh) bus_space_write_4(sc->bst, sc->bsh, FWOHCI_INTMASKCLR, OHCI_INT_EN); if (sc->irq_res) { int err = bus_teardown_intr(self, sc->irq_res, sc->ih); if (err) /* XXX or should we panic? */ device_printf(self, "Could not tear down irq, %d\n", err); #if __FreeBSD_version < 500000 err = bus_teardown_intr(self, sc->irq_res, sc->ih_cam); #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; } if (sc->bsr) { bus_release_resource(self, SYS_RES_MEMORY,PCI_CBMEM,sc->bsr); sc->bsr = NULL; sc->bst = 0; sc->bsh = 0; } fwohci_detach(sc, self); splx(s); return 0; } static int fwohci_pci_suspend(device_t dev) { int err; device_printf(dev, "fwohci_pci_suspend\n"); err = bus_generic_suspend(dev); if (err) return err; /* fwohci_stop(dev); */ return 0; } static int fwohci_pci_resume(device_t dev) { fwohci_softc_t *sc = device_get_softc(dev); device_printf(dev, "fwohci_pci_resume: power_state = 0x%08x\n", pci_get_powerstate(dev)); fwohci_pci_init(dev); fwohci_resume(sc, dev); return 0; } static int fwohci_pci_shutdown(device_t dev) { fwohci_softc_t *sc = device_get_softc(dev); bus_generic_shutdown(dev); fwohci_stop(sc, dev); return 0; } static device_method_t fwohci_methods[] = { /* Device interface */ DEVMETHOD(device_probe, fwohci_pci_probe), DEVMETHOD(device_attach, fwohci_pci_attach), DEVMETHOD(device_detach, fwohci_pci_detach), DEVMETHOD(device_suspend, fwohci_pci_suspend), DEVMETHOD(device_resume, fwohci_pci_resume), DEVMETHOD(device_shutdown, fwohci_pci_shutdown), /* Bus interface */ DEVMETHOD(bus_print_child, bus_generic_print_child), { 0, 0 } }; static driver_t fwohci_driver = { "fwohci", fwohci_methods, sizeof(fwohci_softc_t), }; static devclass_t fwohci_devclass; DRIVER_MODULE(fwohci, pci, fwohci_driver, fwohci_devclass, 0, 0); DRIVER_MODULE(fwohci, cardbus, fwohci_driver, fwohci_devclass, 0, 0); Index: head/sys/dev/firewire/fwohcireg.h =================================================================== --- head/sys/dev/firewire/fwohcireg.h (revision 113583) +++ head/sys/dev/firewire/fwohcireg.h (revision 113584) @@ -1,386 +1,425 @@ /* - * Copyright (c) 1998-2001 Katsushi Kobayashi and Hidetoshi 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 * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the acknowledgement as bellow: * * This product includes software developed by K. Kobayashi and H. Shimokawa * * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ * */ #define PCI_CBMEM 0x10 #define FW_VENDORID_NEC 0x1033 #define FW_VENDORID_TI 0x104c #define FW_VENDORID_SONY 0x104d #define FW_VENDORID_VIA 0x1106 #define FW_VENDORID_RICOH 0x1180 #define FW_VENDORID_APPLE 0x106b #define FW_VENDORID_LUCENT 0x11c1 #define FW_DEVICE_UPD861 (0x0063 << 16) #define FW_DEVICE_UPD871 (0x00ce << 16) #define FW_DEVICE_TITSB22 (0x8009 << 16) #define FW_DEVICE_TITSB23 (0x8019 << 16) #define FW_DEVICE_TITSB26 (0x8020 << 16) #define FW_DEVICE_TITSB43 (0x8021 << 16) #define FW_DEVICE_TITSB43A (0x8023 << 16) #define FW_DEVICE_TIPCI4450 (0x8011 << 16) #define FW_DEVICE_TIPCI4410A (0x8017 << 16) #define FW_DEVICE_CX3022 (0x8039 << 16) #define FW_DEVICE_VT6306 (0x3044 << 16) #define FW_DEVICE_R5C552 (0x0552 << 16) #define FW_DEVICE_PANGEA (0x0030 << 16) #define FW_DEVICE_UNINORTH (0x0031 << 16) #define FW_DEVICE_FW322 (0x5811 << 16) #define PCI_INTERFACE_OHCI 0x10 #define FW_OHCI_BASE_REG 0x10 #define OHCI_DMA_ITCH 0x20 #define OHCI_DMA_IRCH 0x20 #define OHCI_MAX_DMA_CH (0x4 + OHCI_DMA_ITCH + OHCI_DMA_IRCH) typedef volatile u_int32_t fwohcireg_t; +/* for PCI */ +#if BYTE_ORDER == BIG_ENDIAN +#define FWOHCI_DMA_WRITE(x, y) ((x) = htole32(y)) +#define FWOHCI_DMA_READ(x) le32toh(x) +#define FWOHCI_DMA_SET(x, y) ((x) |= htole32(y)) +#define FWOHCI_DMA_CLEAR(x, y) ((x) &= htole32(~(y))) +#else +#define FWOHCI_DMA_WRITE(x, y) ((x) = (y)) +#define FWOHCI_DMA_READ(x) (x) +#define FWOHCI_DMA_SET(x, y) ((x) |= (y)) +#define FWOHCI_DMA_CLEAR(x, y) ((x) &= ~(y)) +#endif + struct fwohcidb { union { struct { - volatile u_int32_t reqcount:16, - control:16; + volatile u_int32_t cmd; volatile u_int32_t addr; volatile u_int32_t depend; - volatile u_int32_t count:16, - status:16; + volatile u_int32_t res; } desc; volatile u_int32_t immed[4]; } db; -#define OHCI_OUTPUT_MORE (0 << 12) -#define OHCI_OUTPUT_LAST (1 << 12) -#define OHCI_INPUT_MORE (2 << 12) -#define OHCI_INPUT_LAST (3 << 12) -#define OHCI_STORE_QUAD (4 << 12) -#define OHCI_LOAD_QUAD (5 << 12) -#define OHCI_NOP (6 << 12) -#define OHCI_STOP (7 << 12) -#define OHCI_STORE (8 << 12) -#define OHCI_CMD_MASK (0xf << 12) +#define OHCI_STATUS_SHIFT 16 +#define OHCI_COUNT_MASK 0xffff +#define OHCI_OUTPUT_MORE (0 << 28) +#define OHCI_OUTPUT_LAST (1 << 28) +#define OHCI_INPUT_MORE (2 << 28) +#define OHCI_INPUT_LAST (3 << 28) +#define OHCI_STORE_QUAD (4 << 28) +#define OHCI_LOAD_QUAD (5 << 28) +#define OHCI_NOP (6 << 28) +#define OHCI_STOP (7 << 28) +#define OHCI_STORE (8 << 28) +#define OHCI_CMD_MASK (0xf << 28) -#define OHCI_UPDATE (1 << 11) +#define OHCI_UPDATE (1 << 27) -#define OHCI_KEY_ST0 (0 << 8) -#define OHCI_KEY_ST1 (1 << 8) -#define OHCI_KEY_ST2 (2 << 8) -#define OHCI_KEY_ST3 (3 << 8) -#define OHCI_KEY_REGS (5 << 8) -#define OHCI_KEY_SYS (6 << 8) -#define OHCI_KEY_DEVICE (7 << 8) -#define OHCI_KEY_MASK (7 << 8) +#define OHCI_KEY_ST0 (0 << 24) +#define OHCI_KEY_ST1 (1 << 24) +#define OHCI_KEY_ST2 (2 << 24) +#define OHCI_KEY_ST3 (3 << 24) +#define OHCI_KEY_REGS (5 << 24) +#define OHCI_KEY_SYS (6 << 24) +#define OHCI_KEY_DEVICE (7 << 24) +#define OHCI_KEY_MASK (7 << 24) -#define OHCI_INTERRUPT_NEVER (0 << 4) -#define OHCI_INTERRUPT_TRUE (1 << 4) -#define OHCI_INTERRUPT_FALSE (2 << 4) -#define OHCI_INTERRUPT_ALWAYS (3 << 4) +#define OHCI_INTERRUPT_NEVER (0 << 20) +#define OHCI_INTERRUPT_TRUE (1 << 20) +#define OHCI_INTERRUPT_FALSE (2 << 20) +#define OHCI_INTERRUPT_ALWAYS (3 << 20) -#define OHCI_BRANCH_NEVER (0 << 2) -#define OHCI_BRANCH_TRUE (1 << 2) -#define OHCI_BRANCH_FALSE (2 << 2) -#define OHCI_BRANCH_ALWAYS (3 << 2) -#define OHCI_BRANCH_MASK (3 << 2) +#define OHCI_BRANCH_NEVER (0 << 18) +#define OHCI_BRANCH_TRUE (1 << 18) +#define OHCI_BRANCH_FALSE (2 << 18) +#define OHCI_BRANCH_ALWAYS (3 << 18) +#define OHCI_BRANCH_MASK (3 << 18) -#define OHCI_WAIT_NEVER (0) -#define OHCI_WAIT_TRUE (1) -#define OHCI_WAIT_FALSE (2) -#define OHCI_WAIT_ALWAYS (3) +#define OHCI_WAIT_NEVER (0 << 16) +#define OHCI_WAIT_TRUE (1 << 16) +#define OHCI_WAIT_FALSE (2 << 16) +#define OHCI_WAIT_ALWAYS (3 << 16) }; #define OHCI_SPD_S100 0x4 #define OHCI_SPD_S200 0x1 #define OHCI_SPD_S400 0x2 #define FWOHCIEV_NOSTAT 0 #define FWOHCIEV_LONGP 2 #define FWOHCIEV_MISSACK 3 #define FWOHCIEV_UNDRRUN 4 #define FWOHCIEV_OVRRUN 5 #define FWOHCIEV_DESCERR 6 #define FWOHCIEV_DTRDERR 7 #define FWOHCIEV_DTWRERR 8 #define FWOHCIEV_BUSRST 9 #define FWOHCIEV_TIMEOUT 0xa #define FWOHCIEV_TCODERR 0xb #define FWOHCIEV_UNKNOWN 0xe #define FWOHCIEV_FLUSHED 0xf #define FWOHCIEV_ACKCOMPL 0x11 #define FWOHCIEV_ACKPEND 0x12 #define FWOHCIEV_ACKBSX 0x14 #define FWOHCIEV_ACKBSA 0x15 #define FWOHCIEV_ACKBSB 0x16 #define FWOHCIEV_ACKTARD 0x1b #define FWOHCIEV_ACKDERR 0x1d #define FWOHCIEV_ACKTERR 0x1e #define FWOHCIEV_MASK 0x1f struct ohci_registers { fwohcireg_t ver; /* Version No. 0x0 */ fwohcireg_t guid; /* GUID_ROM No. 0x4 */ fwohcireg_t retry; /* AT retries 0x8 */ #define FWOHCI_RETRY 0x8 fwohcireg_t csr_data; /* CSR data 0xc */ fwohcireg_t csr_cmp; /* CSR compare 0x10 */ fwohcireg_t csr_cntl; /* CSR compare 0x14 */ fwohcireg_t rom_hdr; /* config ROM ptr. 0x18 */ fwohcireg_t bus_id; /* BUS_ID 0x1c */ fwohcireg_t bus_opt; /* BUS option 0x20 */ #define FWOHCIGUID_H 0x24 #define FWOHCIGUID_L 0x28 fwohcireg_t guid_hi; /* GUID hi 0x24 */ fwohcireg_t guid_lo; /* GUID lo 0x28 */ fwohcireg_t dummy0[2]; /* dummy 0x2c-0x30 */ fwohcireg_t config_rom; /* config ROM map 0x34 */ fwohcireg_t post_wr_lo; /* post write addr lo 0x38 */ fwohcireg_t post_wr_hi; /* post write addr hi 0x3c */ fwohcireg_t vender; /* vender ID 0x40 */ fwohcireg_t dummy1[3]; /* dummy 0x44-0x4c */ fwohcireg_t hcc_cntl_set; /* HCC control set 0x50 */ fwohcireg_t hcc_cntl_clr; /* HCC control clr 0x54 */ #define OHCI_HCC_BIBIV (1 << 31) /* BIBimage Valid */ #define OHCI_HCC_BIGEND (1 << 30) /* noByteSwapData */ #define OHCI_HCC_PRPHY (1 << 23) /* programPhyEnable */ #define OHCI_HCC_PHYEN (1 << 22) /* aPhyEnhanceEnable */ #define OHCI_HCC_LPS (1 << 19) /* LPS */ #define OHCI_HCC_POSTWR (1 << 18) /* postedWriteEnable */ #define OHCI_HCC_LINKEN (1 << 17) /* linkEnable */ #define OHCI_HCC_RESET (1 << 16) /* softReset */ fwohcireg_t dummy2[2]; /* dummy 0x58-0x5c */ fwohcireg_t dummy3[1]; /* dummy 0x60 */ fwohcireg_t sid_buf; /* self id buffer 0x64 */ fwohcireg_t sid_cnt; /* self id count 0x68 */ fwohcireg_t dummy4[1]; /* dummy 0x6c */ fwohcireg_t ir_mask_hi_set; /* ir mask hi set 0x70 */ fwohcireg_t ir_mask_hi_clr; /* ir mask hi set 0x74 */ fwohcireg_t ir_mask_lo_set; /* ir mask hi set 0x78 */ fwohcireg_t ir_mask_lo_clr; /* ir mask hi set 0x7c */ #define FWOHCI_INTSTAT 0x80 #define FWOHCI_INTSTATCLR 0x84 #define FWOHCI_INTMASK 0x88 #define FWOHCI_INTMASKCLR 0x8c fwohcireg_t int_stat; /* 0x80 */ fwohcireg_t int_clear; /* 0x84 */ fwohcireg_t int_mask; /* 0x88 */ fwohcireg_t int_mask_clear; /* 0x8c */ fwohcireg_t it_int_stat; /* 0x90 */ fwohcireg_t it_int_clear; /* 0x94 */ fwohcireg_t it_int_mask; /* 0x98 */ fwohcireg_t it_mask_clear; /* 0x9c */ fwohcireg_t ir_int_stat; /* 0xa0 */ fwohcireg_t ir_int_clear; /* 0xa4 */ fwohcireg_t ir_int_mask; /* 0xa8 */ fwohcireg_t ir_mask_clear; /* 0xac */ fwohcireg_t dummy5[11]; /* dummy 0xb0-d8 */ fwohcireg_t fairness; /* fairness control 0xdc */ fwohcireg_t link_cntl; /* Chip control 0xe0*/ fwohcireg_t link_cntl_clr; /* Chip control clear 0xe4*/ #define FWOHCI_NODEID 0xe8 fwohcireg_t node; /* Node ID 0xe8 */ #define OHCI_NODE_VALID (1 << 31) #define OHCI_NODE_ROOT (1 << 30) #define OHCI_ASYSRCBUS 1 fwohcireg_t phy_access; /* PHY cntl 0xec */ #define PHYDEV_RDDONE (1<<31) #define PHYDEV_RDCMD (1<<15) #define PHYDEV_WRCMD (1<<14) #define PHYDEV_REGADDR 8 #define PHYDEV_WRDATA 0 #define PHYDEV_RDADDR 24 #define PHYDEV_RDDATA 16 fwohcireg_t cycle_timer; /* Cycle Timer 0xf0 */ fwohcireg_t dummy6[3]; /* dummy 0xf4-fc */ fwohcireg_t areq_hi; /* Async req. filter hi 0x100 */ fwohcireg_t areq_hi_clr; /* Async req. filter hi 0x104 */ fwohcireg_t areq_lo; /* Async req. filter lo 0x108 */ fwohcireg_t areq_lo_clr; /* Async req. filter lo 0x10c */ fwohcireg_t preq_hi; /* Async req. filter hi 0x110 */ fwohcireg_t preq_hi_clr; /* Async req. filter hi 0x114 */ fwohcireg_t preq_lo; /* Async req. filter lo 0x118 */ fwohcireg_t preq_lo_clr; /* Async req. filter lo 0x11c */ fwohcireg_t pys_upper; /* Physical Upper bound 0x120 */ fwohcireg_t dummy7[23]; /* dummy 0x124-0x17c */ struct ohci_dma{ fwohcireg_t cntl; #define OHCI_CNTL_CYCMATCH_S (0x1 << 31) #define OHCI_CNTL_BUFFIL (0x1 << 31) #define OHCI_CNTL_ISOHDR (0x1 << 30) #define OHCI_CNTL_CYCMATCH_R (0x1 << 29) #define OHCI_CNTL_MULTICH (0x1 << 28) #define OHCI_CNTL_DMA_RUN (0x1 << 15) #define OHCI_CNTL_DMA_WAKE (0x1 << 12) #define OHCI_CNTL_DMA_DEAD (0x1 << 11) #define OHCI_CNTL_DMA_ACTIVE (0x1 << 10) #define OHCI_CNTL_DMA_BT (0x1 << 8) #define OHCI_CNTL_DMA_BAD (0x1 << 7) #define OHCI_CNTL_DMA_STAT (0xff) fwohcireg_t cntl_clr; fwohcireg_t dummy0; fwohcireg_t cmd; fwohcireg_t match; fwohcireg_t dummy1; fwohcireg_t dummy2; fwohcireg_t dummy3; }; /* 0x180, 0x184, 0x188, 0x18c */ /* 0x190, 0x194, 0x198, 0x19c */ /* 0x1a0, 0x1a4, 0x1a8, 0x1ac */ /* 0x1b0, 0x1b4, 0x1b8, 0x1bc */ /* 0x1c0, 0x1c4, 0x1c8, 0x1cc */ /* 0x1d0, 0x1d4, 0x1d8, 0x1dc */ /* 0x1e0, 0x1e4, 0x1e8, 0x1ec */ /* 0x1f0, 0x1f4, 0x1f8, 0x1fc */ struct ohci_dma dma_ch[0x4]; /* 0x200, 0x204, 0x208, 0x20c */ /* 0x210, 0x204, 0x208, 0x20c */ struct ohci_itdma{ fwohcireg_t cntl; fwohcireg_t cntl_clr; fwohcireg_t dummy0; fwohcireg_t cmd; }; struct ohci_itdma dma_itch[0x20]; /* 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; + bus_dmamap_t dma_map; caddr_t buf; - caddr_t dummy; + bus_addr_t bus_addr; int dbcnt; }; /* * OHCI info structure. */ struct fwohci_txpkthdr{ union{ u_int32_t ld[4]; struct { - u_int32_t res3:4, +#if BYTE_ORDER == BIG_ENDIAN + u_int32_t :13, + spd:3, + :8, tcode:4, - res2:8, + :4; +#else + u_int32_t :4, + tcode:4, + :8, spd:3, - res1:13; + :13; +#endif }common; struct { - u_int32_t res3:4, - tcode:4, - tlrt:8, - spd:3, - res2:4, - srcbus:1, - res1:8; - u_int32_t res4:16, - dst:16; +#if BYTE_ORDER == BIG_ENDIAN + u_int32_t :8, + srcbus:1, + :4, + spd:3, + tlrt:8, + tcode:4, + :4; +#else + u_int32_t :4, + tcode:4, + tlrt:8, + spd:3, + :4, + srcbus:1, + :8; +#endif + BIT16x2(dst, ); }asycomm; struct { +#if BYTE_ORDER == BIG_ENDIAN + u_int32_t :13, + spd:3, + chtag:8, + tcode:4, + sy:4; +#else u_int32_t sy:4, tcode:4, chtag:8, spd:3, - res1:13; - u_int32_t res2:16, - len:16; + :13; +#endif + BIT16x2(len, ); }stream; }mode; }; struct fwohci_trailer{ u_int32_t time:16, stat:16; }; #define OHCI_CNTL_CYCSRC (0x1 << 22) #define OHCI_CNTL_CYCMTR (0x1 << 21) #define OHCI_CNTL_CYCTIMER (0x1 << 20) #define OHCI_CNTL_PHYPKT (0x1 << 10) #define OHCI_CNTL_SID (0x1 << 9) #define OHCI_INT_DMA_ATRQ (0x1 << 0) #define OHCI_INT_DMA_ATRS (0x1 << 1) #define OHCI_INT_DMA_ARRQ (0x1 << 2) #define OHCI_INT_DMA_ARRS (0x1 << 3) #define OHCI_INT_DMA_PRRQ (0x1 << 4) #define OHCI_INT_DMA_PRRS (0x1 << 5) #define OHCI_INT_DMA_IT (0x1 << 6) #define OHCI_INT_DMA_IR (0x1 << 7) #define OHCI_INT_PW_ERR (0x1 << 8) #define OHCI_INT_LR_ERR (0x1 << 9) #define OHCI_INT_PHY_SID (0x1 << 16) #define OHCI_INT_PHY_BUS_R (0x1 << 17) #define OHCI_INT_REG_FAIL (0x1 << 18) #define OHCI_INT_PHY_INT (0x1 << 19) #define OHCI_INT_CYC_START (0x1 << 20) #define OHCI_INT_CYC_64SECOND (0x1 << 21) #define OHCI_INT_CYC_LOST (0x1 << 22) #define OHCI_INT_CYC_ERR (0x1 << 23) #define OHCI_INT_ERR (0x1 << 24) #define OHCI_INT_CYC_LONG (0x1 << 25) #define OHCI_INT_PHY_REG (0x1 << 26) #define OHCI_INT_EN (0x1 << 31) #define IP_CHANNELS 0x0234 #define FWOHCI_MAXREC 2048 #define OHCI_ISORA 0x02 #define OHCI_ISORB 0x04 #define FWOHCITCODE_PHY 0xe Index: head/sys/dev/firewire/fwohcivar.h =================================================================== --- head/sys/dev/firewire/fwohcivar.h (revision 113583) +++ head/sys/dev/firewire/fwohcivar.h (revision 113584) @@ -1,77 +1,90 @@ /* + * 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 * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the acknowledgement as bellow: * * This product includes software developed by K. Kobayashi and H. Shimokawa * * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ * */ + +#if __FreeBSD_version >= 500000 +#define FWOHCI_TASKQUEUE 1 +#else +#define FWOHCI_TASKQUEUE 0 +#endif +#if FWOHCI_TASKQUEUE +#include +#endif + typedef struct fwohci_softc { struct firewire_comm fc; bus_space_tag_t bst; bus_space_handle_t bsh; void *ih; #if __FreeBSD_version < 500000 void *ih_cam; #endif - struct resource *bsr; struct resource *irq_res; struct fwohci_dbch{ u_int ndb; u_int ndesc; - caddr_t dummy; STAILQ_HEAD(, fwohcidb_tr) db_trq; struct fwohcidb_tr *top, *bottom, *pdb_tr; struct fw_xferq xferq; - struct { - int len; - int hlen; - int plen; - caddr_t buf; - } frag; int flags; #define FWOHCI_DBCH_INIT (1<<0) #define FWOHCI_DBCH_FULL (1<<1) - int buf_offset; + /* used only in receive context */ + int buf_offset; /* signed */ #define FWOHCI_DBCH_MAX_PAGES 32 - int npages; - void *pages[FWOHCI_DBCH_MAX_PAGES]; + /* Context programs buffer */ + struct fwdma_alloc_multi *am; + bus_dma_tag_t dmat; } arrq, arrs, atrq, atrs, it[OHCI_DMA_ITCH], ir[OHCI_DMA_IRCH]; u_int maxrec; - u_int32_t *cromptr; - u_int32_t intmask; + u_int32_t *sid_buf; + struct fwdma_alloc sid_dma; + struct fwdma_alloc crom_dma; + struct fwdma_alloc dummy_dma; + u_int32_t intmask, irstat, itstat; +#if FWOHCI_TASKQUEUE + u_int32_t intstat; + struct task fwohci_task_complete; +#endif } fwohci_softc_t; + void fwohci_intr __P((void *arg)); int fwohci_init __P((struct fwohci_softc *, device_t)); void fwohci_reset __P((struct fwohci_softc *, device_t)); int fwohci_detach __P((struct fwohci_softc *, device_t)); int fwohci_resume __P((struct fwohci_softc *, device_t)); int fwohci_stop __P((struct fwohci_softc *, device_t dev)); Index: head/sys/dev/firewire/iec13213.h =================================================================== --- head/sys/dev/firewire/iec13213.h (revision 113583) +++ head/sys/dev/firewire/iec13213.h (revision 113584) @@ -1,149 +1,205 @@ /* + * 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 * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the acknowledgement as bellow: * * This product includes software developed by K. Kobayashi and H. Shimokawa * * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ * */ #define CSRTYPE_SHIFT 6 #define CSRTYPE_MASK (3 << CSRTYPE_SHIFT) #define CSRTYPE_I (0 << CSRTYPE_SHIFT) /* Immediate */ #define CSRTYPE_C (1 << CSRTYPE_SHIFT) /* CSR offset */ #define CSRTYPE_L (2 << CSRTYPE_SHIFT) /* Leaf */ #define CSRTYPE_D (3 << CSRTYPE_SHIFT) /* Directory */ #define CSRKEY_MASK 0x3f #define CSRKEY_DESC 0x01 /* Descriptor */ #define CSRKEY_BDINFO 0x02 /* Bus_Dependent_Info */ #define CSRKEY_VENDOR 0x03 /* Vendor */ #define CSRKEY_HW 0x04 /* Hardware_Version */ #define CSRKEY_MODULE 0x07 /* Module */ #define CSRKEY_NCAP 0x0c /* Node_Capabilities */ #define CSRKEY_EUI64 0x0d /* EUI_64 */ #define CSRKEY_UNIT 0x11 /* Unit */ #define CSRKEY_SPEC 0x12 /* Specifier_ID */ #define CSRKEY_VER 0x13 /* Version */ #define CSRKEY_DINFO 0x14 /* Dependent_Info */ #define CSRKEY_ULOC 0x15 /* Unit_Location */ #define CSRKEY_MODEL 0x17 /* Model */ #define CSRKEY_INST 0x18 /* Instance */ #define CSRKEY_KEYW 0x19 /* Keyword */ #define CSRKEY_FEAT 0x1a /* Feature */ #define CSRKEY_EROM 0x1b /* Extended_ROM */ #define CSRKEY_EKSID 0x1c /* Extended_Key_Specifier_ID */ #define CSRKEY_EKEY 0x1d /* Extended_Key */ #define CSRKEY_EDATA 0x1e /* Extended_Data */ #define CSRKEY_MDESC 0x1f /* Modifiable_Descriptor */ #define CSRKEY_DID 0x20 /* Directory_ID */ #define CSRKEY_REV 0x21 /* Revision */ -#define CROM_TEXTLEAF (CSRTYPE_L | CSRKEY_DESC) /* 0x81 */ -#define CROM_LUN (CSRTYPE_I | CSRKEY_DINFO) /* 0x14 */ +#define CSRKEY_FIRM_VER 0x3c /* Firemware version */ +#define CSRKEY_UNIT_CH 0x3a /* Unit characteristics */ +#define CSRKEY_COM_SPEC 0x38 /* Command set revision */ +#define CSRKEY_COM_SET 0x39 /* Command set */ -/* ??? -#define CSRKEY_MVID 0x3 -#define CSRKEY_NUNQ 0x8d -#define CSRKEY_NPWR 0x30 -*/ +#define CROM_UDIR (CSRTYPE_D | CSRKEY_UNIT) /* 0x81 Unit directory */ +#define CROM_TEXTLEAF (CSRTYPE_L | CSRKEY_DESC) /* 0x81 Text leaf */ +#define CROM_LUN (CSRTYPE_I | CSRKEY_DINFO) /* 0x14 Logical unit num. */ +#define CROM_MGM (CSRTYPE_C | CSRKEY_DINFO) /* 0x54 Management agent */ -#define CSRVAL_1394TA 0x00a02d -#define CSRVAL_ANSIT10 0x00609e -#define CSR_PROTAVC 0x010001 -#define CSR_PROTCAL 0x010002 -#define CSR_PROTEHS 0x010004 -#define CSR_PROTHAVI 0x010008 -#define CSR_PROTCAM104 0x000100 -#define CSR_PROTCAM120 0x000101 -#define CSR_PROTCAM130 0x000102 -#define CSR_PROTDPP 0x0a6be2 -#define CSR_PROTIICP 0x4b661f +#define CSRVAL_1394TA 0x00a02d +#define CSRVAL_ANSIT10 0x00609e +#define CSRVAL_IETF 0x00005e -#define CSRVAL_T10SBP2 0x010483 +#define CSR_PROTAVC 0x010001 +#define CSR_PROTCAL 0x010002 +#define CSR_PROTEHS 0x010004 +#define CSR_PROTHAVI 0x010008 +#define CSR_PROTCAM104 0x000100 +#define CSR_PROTCAM120 0x000101 +#define CSR_PROTCAM130 0x000102 +#define CSR_PROTDPP 0x0a6be2 +#define CSR_PROTIICP 0x4b661f +#define CSRVAL_T10SBP2 0x010483 +#define CSRVAL_SCSI 0x0104d8 + struct csrreg { +#if BYTE_ORDER == BIG_ENDIAN + u_int32_t key:8, + val:24; +#else u_int32_t val:24, key:8; +#endif }; struct csrhdr { +#if BYTE_ORDER == BIG_ENDIAN + u_int32_t info_len:8, + crc_len:8, + crc:16; +#else u_int32_t crc:16, crc_len:8, info_len:8; +#endif }; struct csrdirectory { - u_int32_t crc:16, - crc_len:16; + BIT16x2(crc_len, crc); struct csrreg entry[0]; }; struct csrtext { - u_int32_t crc:16, - crc_len:16; + BIT16x2(crc_len, crc); +#if BYTE_ORDER == BIG_ENDIAN + u_int32_t spec_type:8, + spec_id:24; +#else u_int32_t spec_id:24, spec_type:8; +#endif u_int32_t lang_id; u_int32_t text[0]; }; -struct businfo { - u_int32_t crc:16, - crc_len:8, - :12, - max_rec:4, - clk_acc:8, - :4, - bmc:1, - isc:1, - cmc:1, - irmc:1; - u_int32_t c_id_hi:8, - v_id:24; - u_int32_t c_id_lo; + +struct bus_info { +#define CSR_BUS_NAME_IEEE1394 0x31333934 + u_int32_t bus_name; + 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 */ + cyc_clk_acc:8, /* 0 <= ppm <= 100 */ + :3, + pmc:1, /* power manager capable */ + bmc:1, /* bus manager capable */ + isc:1, /* iso. operation support */ + cmc:1, /* cycle master capable */ + irmc:1; /* iso. resource manager capable */ + struct fw_eui64 eui64; }; #define CROM_MAX_DEPTH 10 struct crom_ptr { struct csrdirectory *dir; int index; }; struct crom_context { int depth; struct crom_ptr stack[CROM_MAX_DEPTH]; }; void crom_init_context(struct crom_context *, u_int32_t *); struct csrreg *crom_get(struct crom_context *); void crom_next(struct crom_context *); void crom_parse_text(struct crom_context *, char *, int); u_int16_t crom_crc(u_int32_t *r, int); struct csrreg *crom_search_key(struct crom_context *, u_int8_t); #ifndef _KERNEL char *crom_desc(struct crom_context *, char *, int); +#endif + +/* For CROM build */ +#if defined(_KERNEL) || defined(TEST) +#define CROM_MAX_CHUNK_LEN 20 +struct crom_src { + struct csrhdr hdr; + struct bus_info businfo; + STAILQ_HEAD(, crom_chunk) chunk_list; +}; + +struct crom_chunk { + STAILQ_ENTRY(crom_chunk) link; + struct crom_chunk *ref_chunk; + int ref_index; + int offset; + struct { + u_int32_t crc:16, + crc_len:16; + u_int32_t buf[CROM_MAX_CHUNK_LEN]; + } data; +}; + +extern int crom_add_quad(struct crom_chunk *, u_int32_t); +extern int crom_add_entry(struct crom_chunk *, int, int); +extern int crom_add_chunk(struct crom_src *src, struct crom_chunk *, + struct crom_chunk *, int); +extern int crom_add_simple_text(struct crom_src *src, struct crom_chunk *, + struct crom_chunk *, char *); +extern int crom_load(struct crom_src *, u_int32_t *, int); #endif Index: head/sys/dev/firewire/iec68113.h =================================================================== --- head/sys/dev/firewire/iec68113.h (revision 113583) +++ head/sys/dev/firewire/iec68113.h (revision 113584) @@ -1,81 +1,120 @@ /* - * Copyright (c) 1998-2001 Katsushi Kobayashi and Hidetoshi 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 * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the acknowledgement as bellow: * * This product includes software developed by K. Kobayashi and H. Shimokawa * * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ * */ struct ciphdr { +#if BYTE_ORDER == BIG_ENDIAN + u_int8_t eoh0:1, /* 0 */ + form0:1, /* 0 */ + src:6; +#else u_int8_t src:6, form0:1, /* 0 */ eoh0:1; /* 0 */ +#endif u_int8_t len; +#if BYTE_ORDER == BIG_ENDIAN + u_int8_t fn:2, + qpc:3, + sph:1, + :2; +#else u_int8_t :2, sph:1, qpc:3, fn:2; +#endif u_int8_t dbc; +#if BYTE_ORDER == BIG_ENDIAN + u_int8_t eoh1:1, /* 1 */ + form1:1, /* 0 */ + fmt:6; +#else u_int8_t fmt:6, -#define CIP_FMT_DVCR 0 -#define CIP_FMT_MPEG (1<<5) form1:1, /* 0 */ eoh1:1; /* 1 */ +#endif +#define CIP_FMT_DVCR 0 +#define CIP_FMT_MPEG (1<<5) union { struct { - u_int8_t :2, - stype:5, +#if BYTE_ORDER == BIG_ENDIAN + u_int8_t fs:1, /* 50/60 field system + NTSC/PAL */ + stype:5, + :2; +#else + u_int8_t :2, + stype:5, + fs:1; /* 50/60 field system + NTSC/PAL */ +#endif #define CIP_STYPE_SD 0 #define CIP_STYPE_SDL 1 #define CIP_STYPE_HD 2 - fs:1; /* 50/60 field system - NTSC/PAL */ u_int16_t cyc:16; /* take care of byte order! */ } __attribute__ ((packed)) dv; u_int8_t bytes[3]; } fdf; }; struct dvdbc{ +#if BYTE_ORDER == BIG_ENDIAN + u_int8_t sct:3, /* Section type */ + :1, /* Reserved */ + arb:4; /* Arbitrary bit */ +#else u_int8_t arb:4, /* Arbitrary bit */ :1, /* Reserved */ sct:3; /* Section type */ +#endif #define DV_SCT_HEADER 0 #define DV_SCT_SUBCODE 1 #define DV_SCT_VAUX 2 #define DV_SCT_AUDIO 3 #define DV_SCT_VIDEO 4 +#if BYTE_ORDER == BIG_ENDIAN + u_int8_t dseq:4, /* DIF sequence number */ + fsc:1, /* ID of a DIF block in each channel */ + :3; +#else u_int8_t :3, fsc:1, /* ID of a DIF block in each channel */ dseq:4; /* DIF sequence number */ +#endif u_int8_t dbn; /* DIF block number */ u_int8_t payload[77]; #define DV_DSF_12 0x80 /* PAL: payload[0] in Header DIF */ }; Index: head/sys/dev/firewire/if_fwe.c =================================================================== --- head/sys/dev/firewire/if_fwe.c (revision 113583) +++ head/sys/dev/firewire/if_fwe.c (revision 113584) @@ -1,689 +1,654 @@ /* - * Copyright (C) 2002 + * Copyright (c) 2002-2003 * Hidetoshi Shimokawa. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * * This product includes software developed by Hidetoshi Shimokawa. * * 4. Neither the name of the author nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include "opt_inet.h" #include #include #include #include #include #include #include #include #include #include #include +#include #include #include #include #include #include #include #include #include #include #include #define FWEDEBUG if (fwedebug) printf #define TX_MAX_QUEUE (FWMAXQUEUE - 1) #define RX_MAX_QUEUE FWMAXQUEUE /* network interface */ static void fwe_start __P((struct ifnet *)); static int fwe_ioctl __P((struct ifnet *, u_long, caddr_t)); static void fwe_init __P((void *)); static void fwe_output_callback __P((struct fw_xfer *)); static void fwe_as_output __P((struct fwe_softc *, struct ifnet *)); static void fwe_as_input __P((struct fw_xferq *)); static int fwedebug = 0; static int stream_ch = 1; 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"); SYSCTL_INT(_hw_firewire_fwe, OID_AUTO, stream_ch, CTLFLAG_RW, &stream_ch, 0, "Stream channel to use"); #ifdef DEVICE_POLLING #define FWE_POLL_REGISTER(func, fwe, ifp) \ if (ether_poll_register(func, ifp)) { \ struct firewire_comm *fc = (fwe)->fd.fc; \ fc->set_intr(fc, 0); \ } #define FWE_POLL_DEREGISTER(fwe, ifp) \ do { \ struct firewire_comm *fc = (fwe)->fd.fc; \ ether_poll_deregister(ifp); \ fc->set_intr(fc, 1); \ } while(0) \ static poll_handler_t fwe_poll; static void fwe_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) { struct fwe_softc *fwe; struct firewire_comm *fc; fwe = ((struct fwe_eth_softc *)ifp->if_softc)->fwe; fc = fwe->fd.fc; if (cmd == POLL_DEREGISTER) { /* enable interrupts */ fc->set_intr(fc, 1); return; } fc->poll(fc, (cmd == POLL_AND_CHECK_STATUS)?0:1, count); } #else #define FWE_POLL_REGISTER(func, fwe, ifp) #define FWE_POLL_DEREGISTER(fwe, ifp) #endif static void fwe_identify(driver_t *driver, device_t parent) { BUS_ADD_CHILD(parent, 0, "if_fwe", device_get_unit(parent)); } static int fwe_probe(device_t dev) { device_t pa; pa = device_get_parent(dev); if(device_get_unit(dev) != device_get_unit(pa)){ return(ENXIO); } device_set_desc(dev, "Ethernet over FireWire"); return (0); } static int fwe_attach(device_t dev) { struct fwe_softc *fwe; struct ifnet *ifp; int unit, s; u_char *eaddr; struct fw_eui64 *eui; fwe = ((struct fwe_softc *)device_get_softc(dev)); unit = device_get_unit(dev); bzero(fwe, sizeof(struct fwe_softc)); /* XXX */ fwe->stream_ch = stream_ch; fwe->dma_ch = -1; fwe->fd.fc = device_get_ivars(dev); fwe->fd.dev = dev; fwe->fd.post_explore = NULL; fwe->eth_softc.fwe = fwe; fwe->pkt_hdr.mode.stream.tcode = FWTCODE_STREAM; fwe->pkt_hdr.mode.stream.sy = 0; fwe->pkt_hdr.mode.stream.chtag = fwe->stream_ch; /* generate fake MAC address: first and last 3bytes from eui64 */ #define LOCAL (0x02) #define GROUP (0x01) eaddr = &fwe->eth_softc.arpcom.ac_enaddr[0]; eui = &fwe->fd.fc->eui; eaddr[0] = (FW_EUI64_BYTE(eui, 0) | LOCAL) & ~GROUP; eaddr[1] = FW_EUI64_BYTE(eui, 1); eaddr[2] = FW_EUI64_BYTE(eui, 2); eaddr[3] = FW_EUI64_BYTE(eui, 5); eaddr[4] = FW_EUI64_BYTE(eui, 6); eaddr[5] = FW_EUI64_BYTE(eui, 7); printf("if_fwe%d: Fake Ethernet address: " "%02x:%02x:%02x:%02x:%02x:%02x\n", unit, eaddr[0], eaddr[1], eaddr[2], eaddr[3], eaddr[4], eaddr[5]); /* fill the rest and attach interface */ ifp = &fwe->fwe_if; ifp->if_softc = &fwe->eth_softc; ifp->if_unit = unit; ifp->if_name = "fwe"; ifp->if_init = fwe_init; ifp->if_output = ether_output; ifp->if_start = fwe_start; ifp->if_ioctl = fwe_ioctl; ifp->if_mtu = ETHERMTU; ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST); ifp->if_snd.ifq_maxlen = TX_MAX_QUEUE; s = splimp(); #if __FreeBSD_version >= 500000 ether_ifattach(ifp, eaddr); #else ether_ifattach(ifp, 1); #endif splx(s); /* Tell the upper layer(s) we support long frames. */ ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); #if __FreeBSD_version >= 500000 ifp->if_capabilities |= IFCAP_VLAN_MTU; #endif FWEDEBUG("interface %s%d created.\n", ifp->if_name, ifp->if_unit); return 0; } static void fwe_stop(struct fwe_softc *fwe) { struct firewire_comm *fc; struct fw_xferq *xferq; struct ifnet *ifp = &fwe->fwe_if; struct fw_xfer *xfer, *next; int i; fc = fwe->fd.fc; FWE_POLL_DEREGISTER(fwe, ifp); if (fwe->dma_ch >= 0) { xferq = fc->ir[fwe->dma_ch]; if (xferq->flag & FWXFERQ_RUNNING) fc->irx_disable(fc, fwe->dma_ch); xferq->flag &= - ~(FWXFERQ_MODEMASK | FWXFERQ_OPEN | - FWXFERQ_EXTBUF | FWXFERQ_HANDLER); + ~(FWXFERQ_MODEMASK | FWXFERQ_OPEN | FWXFERQ_STREAM | + FWXFERQ_EXTBUF | FWXFERQ_HANDLER | FWXFERQ_CHTAGMASK); xferq->hand = NULL; for (i = 0; i < xferq->bnchunk; i ++) m_freem(xferq->bulkxfer[i].mbuf); free(xferq->bulkxfer, M_FWE); for (xfer = STAILQ_FIRST(&fwe->xferlist); xfer != NULL; xfer = next) { next = STAILQ_NEXT(xfer, link); fw_xfer_free(xfer); } STAILQ_INIT(&fwe->xferlist); xferq->bulkxfer = NULL; fwe->dma_ch = -1; } ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); } static int fwe_detach(device_t dev) { struct fwe_softc *fwe; int s; fwe = (struct fwe_softc *)device_get_softc(dev); s = splimp(); fwe_stop(fwe); #if __FreeBSD_version >= 500000 ether_ifdetach(&fwe->fwe_if); #else ether_ifdetach(&fwe->fwe_if, 1); #endif splx(s); return 0; } static void fwe_init(void *arg) { struct fwe_softc *fwe = ((struct fwe_eth_softc *)arg)->fwe; struct firewire_comm *fc; struct ifnet *ifp = &fwe->fwe_if; struct fw_xferq *xferq; struct fw_xfer *xfer; + struct mbuf *m; int i; FWEDEBUG("initializing %s%d\n", ifp->if_name, ifp->if_unit); /* XXX keep promiscoud mode */ ifp->if_flags |= IFF_PROMISC; 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; } fwe->dma_ch = i; fwe->stream_ch = stream_ch; fwe->pkt_hdr.mode.stream.chtag = fwe->stream_ch; /* allocate DMA channel and init packet mode */ - xferq->flag |= FWXFERQ_OPEN | FWXFERQ_EXTBUF; + xferq->flag |= FWXFERQ_OPEN | FWXFERQ_EXTBUF | + FWXFERQ_HANDLER | FWXFERQ_STREAM; xferq->flag &= ~0xff; xferq->flag |= fwe->stream_ch & 0xff; /* register fwe_input handler */ xferq->sc = (caddr_t) fwe; xferq->hand = fwe_as_input; - xferq->flag |= FWXFERQ_HANDLER; xferq->bnchunk = RX_MAX_QUEUE; xferq->bnpacket = 1; xferq->psize = MCLBYTES; xferq->queued = 0; + xferq->buf = NULL; xferq->bulkxfer = (struct fw_bulkxfer *) malloc( - sizeof(struct fw_bulkxfer) * xferq->bnchunk, M_FWE, 0); + sizeof(struct fw_bulkxfer) * xferq->bnchunk, + M_FWE, M_WAITOK); if (xferq->bulkxfer == NULL) { printf("if_fwe: malloc failed\n"); return; } STAILQ_INIT(&xferq->stvalid); STAILQ_INIT(&xferq->stfree); STAILQ_INIT(&xferq->stdma); xferq->stproc = NULL; for (i = 0; i < xferq->bnchunk; i ++) { - xferq->bulkxfer[i].mbuf = + m = #if __FreeBSD_version >= 500000 m_getcl(M_TRYWAIT, MT_DATA, M_PKTHDR); #else m_getcl(M_WAIT, MT_DATA, M_PKTHDR); #endif - xferq->bulkxfer[i].buf = - mtod(xferq->bulkxfer[i].mbuf, char *); - STAILQ_INSERT_TAIL(&xferq->stfree, - &xferq->bulkxfer[i], link); + xferq->bulkxfer[i].mbuf = m; + if (m != NULL) { + m->m_len = m->m_pkthdr.len = m->m_ext.ext_size; + STAILQ_INSERT_TAIL(&xferq->stfree, + &xferq->bulkxfer[i], link); + } else + printf("fwe_as_input: m_getcl failed\n"); } STAILQ_INIT(&fwe->xferlist); for (i = 0; i < TX_MAX_QUEUE; i++) { xfer = fw_xfer_alloc(M_FWE); if (xfer == NULL) break; - xfer->send.off = 0; xfer->spd = 2; xfer->fc = fwe->fd.fc; xfer->retry_req = fw_asybusy; xfer->sc = (caddr_t)fwe; xfer->act.hand = fwe_output_callback; STAILQ_INSERT_TAIL(&fwe->xferlist, xfer, link); } } else xferq = fc->ir[fwe->dma_ch]; /* start dma */ if ((xferq->flag & FWXFERQ_RUNNING) == 0) fc->irx_enable(fc, fwe->dma_ch); ifp->if_flags |= IFF_RUNNING; ifp->if_flags &= ~IFF_OACTIVE; FWE_POLL_REGISTER(fwe_poll, fwe, ifp); #if 0 /* attempt to start output */ fwe_start(ifp); #endif } static int fwe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { struct fwe_softc *fwe = ((struct fwe_eth_softc *)ifp->if_softc)->fwe; struct ifstat *ifs = NULL; int s, error, len; switch (cmd) { case SIOCSIFFLAGS: s = splimp(); if (ifp->if_flags & IFF_UP) { if (!(ifp->if_flags & IFF_RUNNING)) fwe_init(&fwe->eth_softc); } else { if (ifp->if_flags & IFF_RUNNING) fwe_stop(fwe); } /* XXX keep promiscoud mode */ ifp->if_flags |= IFF_PROMISC; splx(s); break; case SIOCADDMULTI: case SIOCDELMULTI: break; case SIOCGIFSTATUS: s = splimp(); ifs = (struct ifstat *)data; len = strlen(ifs->ascii); if (len < sizeof(ifs->ascii)) snprintf(ifs->ascii + len, sizeof(ifs->ascii) - len, "\tch %d dma %d\n", fwe->stream_ch, fwe->dma_ch); splx(s); break; #if __FreeBSD_version >= 500000 default: #else case SIOCSIFADDR: case SIOCGIFADDR: case SIOCSIFMTU: #endif s = splimp(); error = ether_ioctl(ifp, cmd, data); splx(s); return (error); #if __FreeBSD_version < 500000 default: return (EINVAL); #endif } return (0); } static void fwe_output_callback(struct fw_xfer *xfer) { struct fwe_softc *fwe; struct ifnet *ifp; int s; fwe = (struct fwe_softc *)xfer->sc; ifp = &fwe->fwe_if; /* XXX error check */ FWEDEBUG("resp = %d\n", xfer->resp); if (xfer->resp != 0) ifp->if_oerrors ++; m_freem(xfer->mbuf); xfer->send.buf = NULL; -#if 0 fw_xfer_unload(xfer); -#else - xfer->state = FWXF_INIT; - xfer->resp = 0; - xfer->retry = 0; -#endif + s = splimp(); STAILQ_INSERT_TAIL(&fwe->xferlist, xfer, link); splx(s); -#if 1 - /* XXX for queue full */ + + /* for queue full */ if (ifp->if_snd.ifq_head != NULL) fwe_start(ifp); -#endif } static void fwe_start(struct ifnet *ifp) { struct fwe_softc *fwe = ((struct fwe_eth_softc *)ifp->if_softc)->fwe; int s; -#if 1 FWEDEBUG("%s%d starting\n", ifp->if_name, ifp->if_unit); if (fwe->dma_ch < 0) { struct mbuf *m = NULL; FWEDEBUG("%s%d not ready.\n", ifp->if_name, ifp->if_unit); s = splimp(); do { IF_DEQUEUE(&ifp->if_snd, m); if (m != NULL) m_freem(m); ifp->if_oerrors ++; } while (m != NULL); splx(s); return; } -#endif s = splimp(); ifp->if_flags |= IFF_OACTIVE; if (ifp->if_snd.ifq_len != 0) fwe_as_output(fwe, ifp); ifp->if_flags &= ~IFF_OACTIVE; splx(s); } #define HDR_LEN 4 #ifndef ETHER_ALIGN #define ETHER_ALIGN 2 #endif /* Async. stream output */ static void fwe_as_output(struct fwe_softc *fwe, struct ifnet *ifp) { struct mbuf *m; struct fw_xfer *xfer; struct fw_xferq *xferq; struct fw_pkt *fp; int i = 0; xfer = NULL; xferq = fwe->fd.fc->atq; while (xferq->queued < xferq->maxq - 1) { xfer = STAILQ_FIRST(&fwe->xferlist); if (xfer == NULL) { printf("if_fwe: lack of xfer\n"); return; } IF_DEQUEUE(&ifp->if_snd, m); if (m == NULL) break; STAILQ_REMOVE_HEAD(&fwe->xferlist, link); #if __FreeBSD_version >= 500000 BPF_MTAP(ifp, m); #else if (ifp->if_bpf != NULL) bpf_mtap(ifp, m); #endif /* 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->mode.stream.len = htons(m->m_pkthdr.len); + 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; if (fw_asyreq(fwe->fd.fc, -1, xfer) != 0) { /* error */ ifp->if_oerrors ++; /* XXX set error code */ fwe_output_callback(xfer); } else { ifp->if_opackets ++; i++; } } #if 0 if (i > 1) printf("%d queued\n", i); #endif if (i > 0) xferq->start(fwe->fd.fc); } -#if 0 -#if __FreeBSD_version >= 500000 -static void -fwe_free(void *buf, void *args) -{ - FWEDEBUG("fwe_free:\n"); - free(buf, M_FW); -} - -#else -static void -fwe_free(caddr_t buf, u_int size) -{ - int *p; - FWEDEBUG("fwe_free:\n"); - p = (int *)buf; - (*p) --; - if (*p < 1) - free(buf, M_FW); -} - -static void -fwe_ref(caddr_t buf, u_int size) -{ - int *p; - - FWEDEBUG("fwe_ref: called\n"); - p = (int *)buf; - (*p) ++; -} -#endif -#endif - /* Async. stream output */ static void fwe_as_input(struct fw_xferq *xferq) { - struct mbuf *m; + struct mbuf *m, *m0; struct ifnet *ifp; struct fwe_softc *fwe; struct fw_bulkxfer *sxfer; struct fw_pkt *fp; u_char *c; #if __FreeBSD_version < 500000 struct ether_header *eh; #endif fwe = (struct fwe_softc *)xferq->sc; ifp = &fwe->fwe_if; #if 0 FWE_POLL_REGISTER(fwe_poll, fwe, ifp); #endif while ((sxfer = STAILQ_FIRST(&xferq->stvalid)) != NULL) { STAILQ_REMOVE_HEAD(&xferq->stvalid, link); -#if 0 - xferq->queued --; -#endif if (sxfer->resp != 0) ifp->if_ierrors ++; - fp = (struct fw_pkt *)sxfer->buf; + 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 */ - sxfer->mbuf = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); - sxfer->buf = mtod(sxfer->mbuf, char *); - STAILQ_INSERT_TAIL(&xferq->stfree, sxfer, link); + 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; + STAILQ_INSERT_TAIL(&xferq->stfree, sxfer, link); + } else + printf("fwe_as_input: m_getcl failed\n"); m->m_data += HDR_LEN + ETHER_ALIGN; c = mtod(m, char *); #if __FreeBSD_version < 500000 eh = (struct ether_header *)c; m->m_data += sizeof(struct ether_header); #endif m->m_len = m->m_pkthdr.len = - ntohs(fp->mode.stream.len) - ETHER_ALIGN; + fp->mode.stream.len - ETHER_ALIGN; m->m_pkthdr.rcvif = ifp; #if 0 FWEDEBUG("%02x %02x %02x %02x %02x %02x\n" "%02x %02x %02x %02x %02x %02x\n" "%02x %02x %02x %02x\n" "%02x %02x %02x %02x\n" "%02x %02x %02x %02x\n" "%02x %02x %02x %02x\n", c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7], c[8], c[9], c[10], c[11], c[12], c[13], c[14], c[15], c[16], c[17], c[18], c[19], c[20], c[21], c[22], c[23], c[20], c[21], c[22], c[23] ); #endif #if __FreeBSD_version >= 500000 (*ifp->if_input)(ifp, m); #else ether_input(ifp, eh, m); #endif ifp->if_ipackets ++; } if (STAILQ_FIRST(&xferq->stfree) != NULL) fwe->fd.fc->irx_enable(fwe->fd.fc, fwe->dma_ch); } static devclass_t fwe_devclass; static device_method_t fwe_methods[] = { /* device interface */ DEVMETHOD(device_identify, fwe_identify), DEVMETHOD(device_probe, fwe_probe), DEVMETHOD(device_attach, fwe_attach), DEVMETHOD(device_detach, fwe_detach), { 0, 0 } }; static driver_t fwe_driver = { "if_fwe", fwe_methods, sizeof(struct fwe_softc), }; DRIVER_MODULE(fwe, firewire, fwe_driver, fwe_devclass, 0, 0); MODULE_VERSION(fwe, 1); MODULE_DEPEND(fwe, firewire, 1, 1, 1); Index: head/sys/dev/firewire/if_fwevar.h =================================================================== --- head/sys/dev/firewire/if_fwevar.h (revision 113583) +++ head/sys/dev/firewire/if_fwevar.h (revision 113584) @@ -1,54 +1,54 @@ /* - * Copyright (C) 2002 + * Copyright (c) 2002-2003 * Hidetoshi Shimokawa. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * * This product includes software developed by Hidetoshi Shimokawa. * * 4. Neither the name of the author nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _NET_IF_FWEVAR_H_ #define _NET_IF_FWEVAR_H_ struct fwe_softc { /* XXX this must be first for fd.post_explore() */ struct firewire_dev_comm fd; short stream_ch; short dma_ch; struct fw_pkt pkt_hdr; STAILQ_HEAD(, fw_xfer) xferlist; struct fwe_eth_softc { /* XXX this must be the first for if_ethersub.c */ struct arpcom arpcom; /* ethernet common data */ #define fwe_if eth_softc.arpcom.ac_if struct fwe_softc *fwe; } eth_softc; }; #endif /* !_NET_IF_FWEVAR_H_ */ Index: head/sys/dev/firewire/sbp.c =================================================================== --- head/sys/dev/firewire/sbp.c (revision 113583) +++ head/sys/dev/firewire/sbp.c (revision 113584) @@ -1,2600 +1,2598 @@ /* - * Copyright (c) 1998,1999,2000,2001 Katsushi Kobayashi and Hidetosh Shimokawa + * Copyright (c) 2003 Hidetosh Shimokawa + * Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetosh Shimokawa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the acknowledgement as bellow: * * This product includes software developed by K. Kobayashi and H. Shimokawa * * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ * */ #include #include #include #include #include #include #include #include #if __FreeBSD_version < 500106 #include /* for struct devstat */ #endif #include #include #include #include #include #include #include #include #include #include -#include -#include - #include #include +#include #include #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 */ -#define SBP_QUEUE_LEN 4 +#define SBP_DMA_SIZE PAGE_SIZE +#define SBP_LOGIN_SIZE sizeof(struct sbp_login_res) +#define SBP_QUEUE_LEN ((SBP_DMA_SIZE - SBP_LOGIN_SIZE) / sizeof(struct sbp_ocb)) #define SBP_NUM_OCB (SBP_QUEUE_LEN * SBP_NUM_TARGETS) + #define SBP_INITIATOR 7 #define LOGIN_DELAY 2 /* * STATUS FIFO addressing * bit * ----------------------- * 0- 1( 2): 0 (alingment) * 2- 7( 6): target * 8-15( 8): lun * 16-23( 8): unit * 24-31( 8): reserved * 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_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 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" }; #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 sbp_cold = 1; SYSCTL_DECL(_hw_firewire); SYSCTL_NODE(_hw_firewire, OID_AUTO, sbp, CTLFLAG_RD, 0, "SBP-II Subsystem"); SYSCTL_INT(_debug, OID_AUTO, sbp_debug, CTLFLAG_RW, &debug, 0, "SBP debug flag"); 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"); #define SBP_DEBUG(x) if (debug > x) { #define END_DEBUG } #define NEED_RESPONSE 0 struct ind_ptr { u_int32_t hi,lo; }; -#define SBP_IND_MAX 0x20 +#define SBP_SEG_MAX rounddown(0xffff, PAGE_SIZE) +#ifdef __sparc64__ /* iommu */ +#define SBP_IND_MAX howmany(MAXPHYS, SBP_SEG_MAX) +#else +#define SBP_IND_MAX howmany(MAXPHYS, PAGE_SIZE) +#endif struct sbp_ocb { STAILQ_ENTRY(sbp_ocb) ocb; union ccb *ccb; + bus_addr_t bus_addr; volatile u_int32_t orb[8]; +#define IND_PTR_OFFSET (8*sizeof(u_int32_t)) volatile struct ind_ptr ind_ptr[SBP_IND_MAX]; struct sbp_dev *sdev; - int flags; + int flags; /* XXX should be removed */ bus_dmamap_t dmamap; }; + #define OCB_ACT_MGM 0 #define OCB_ACT_CMD 1 -#define OCB_MATCH(o,s) (vtophys(&(o)->orb[0]) == ntohl((s)->orb_lo)) +#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; - u_int8_t status:8; +#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 */ #if 0 #define SBP_DEV_LOGIN 1 /* to login */ #define SBP_DEV_RECONN 2 /* to reconnect */ #endif #define SBP_DEV_TOATTACH 3 /* to attach */ #define SBP_DEV_PROBE 4 /* scan lun */ #define SBP_DEV_ATTACHED 5 /* in operation */ #define SBP_DEV_DEAD 6 /* unavailable unit */ #define SBP_DEV_RETRY 7 /* unavailable unit */ u_int8_t status:4, #define SBP_DEV_TIMEOUT 1 flags:4; u_int8_t type; u_int16_t lun_id; int freeze; struct cam_path *path; struct sbp_target *target; - struct sbp_login_res login; + struct fwdma_alloc dma; + struct sbp_login_res *login; struct callout login_callout; + struct sbp_ocb *ocb; STAILQ_HEAD(, sbp_ocb) ocbs; + STAILQ_HEAD(, sbp_ocb) free_ocbs; char vendor[32]; char product[32]; char revision[10]; }; struct sbp_target { int target_id; int num_lun; 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; }; struct sbp_softc { struct firewire_dev_comm fd; struct cam_sim *sim; struct cam_path *path; struct sbp_target targets[SBP_NUM_TARGETS]; struct fw_bind fwb; - STAILQ_HEAD(, sbp_ocb) free_ocbs; - struct sbp_ocb *ocb; bus_dma_tag_t dmat; #define SBP_RESOURCE_SHORTAGE 0x10 unsigned char flags; }; static void sbp_post_explore __P((void *)); static void sbp_recv __P((struct fw_xfer *)); static void sbp_login_callback __P((struct fw_xfer *)); static void sbp_cmd_callback __P((struct fw_xfer *)); static void sbp_orb_pointer __P((struct sbp_dev *, struct sbp_ocb *)); static void sbp_execute_ocb __P((void *, bus_dma_segment_t *, int, int)); -static void sbp_free_ocb __P((struct sbp_softc *, struct sbp_ocb *)); +static void sbp_free_ocb __P((struct sbp_dev *, struct sbp_ocb *)); static void sbp_abort_ocb __P((struct sbp_ocb *, int)); static void sbp_abort_all_ocbs __P((struct sbp_dev *, int)); static struct fw_xfer * sbp_write_cmd __P((struct sbp_dev *, int, int)); -static struct sbp_ocb * sbp_get_ocb __P((struct sbp_softc *)); +static struct sbp_ocb * sbp_get_ocb __P((struct sbp_dev *)); static struct sbp_ocb * sbp_enqueue_ocb __P((struct sbp_dev *, struct sbp_ocb *)); static struct sbp_ocb * sbp_dequeue_ocb __P((struct sbp_dev *, struct sbp_status *)); static void sbp_cam_detach_target __P((struct sbp_target *)); static void sbp_timeout __P((void *arg)); static void sbp_mgm_orb __P((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"); /* cam related functions */ static void sbp_action(struct cam_sim *sim, union ccb *ccb); static void sbp_poll(struct cam_sim *sim); static void sbp_cam_scan_lun(struct cam_periph *, union ccb *); static void sbp_cam_scan_target(void *arg); static char *orb_status0[] = { /* 0 */ "No additional information to report", /* 1 */ "Request type not supported", /* 2 */ "Speed not supported", /* 3 */ "Page size not supported", /* 4 */ "Access denied", /* 5 */ "Logical unit not supported", /* 6 */ "Maximum payload too small", /* 7 */ "Reserved for future standardization", /* 8 */ "Resources unavailable", /* 9 */ "Function rejected", /* A */ "Login ID not recognized", /* B */ "Dummy ORB completed", /* C */ "Request aborted", /* FF */ "Unspecified error" #define MAX_ORB_STATUS0 0xd }; static char *orb_status1_object[] = { /* 0 */ "Operation request block (ORB)", /* 1 */ "Data buffer", /* 2 */ "Page table", /* 3 */ "Unable to specify" }; static char *orb_status1_serial_bus_error[] = { /* 0 */ "Missing acknowledge", /* 1 */ "Reserved; not to be used", /* 2 */ "Time-out error", /* 3 */ "Reserved; not to be used", /* 4 */ "Busy retry limit exceeded(X)", /* 5 */ "Busy retry limit exceeded(A)", /* 6 */ "Busy retry limit exceeded(B)", /* 7 */ "Reserved for future standardization", /* 8 */ "Reserved for future standardization", /* 9 */ "Reserved for future standardization", /* A */ "Reserved for future standardization", /* B */ "Tardy retry limit exceeded", /* C */ "Conflict error", /* D */ "Data error", /* E */ "Type error", /* F */ "Address error" }; static void sbp_identify(driver_t *driver, device_t parent) { device_t child; SBP_DEBUG(0) printf("sbp_identify\n"); END_DEBUG child = BUS_ADD_CHILD(parent, 0, "sbp", device_get_unit(parent)); } /* * sbp_probe() */ static int sbp_probe(device_t dev) { device_t pa; SBP_DEBUG(0) printf("sbp_probe\n"); END_DEBUG pa = device_get_parent(dev); if(device_get_unit(dev) != device_get_unit(pa)){ return(ENXIO); } device_set_desc(dev, "SBP2/SCSI over firewire"); if (bootverbose) debug = bootverbose; return (0); } static void sbp_show_sdev_info(struct sbp_dev *sdev, int new) { struct fw_device *fwdev; printf("%s:%d:%d ", device_get_nameunit(sdev->target->sbp->fd.dev), sdev->target->target_id, sdev->lun_id ); if (new == 2) { return; } fwdev = sdev->target->fwdev; printf("ordered:%d type:%d EUI:%08x%08x node:%d " "speed:%d maxrec:%d", (sdev->type & 0x40) >> 6, (sdev->type & 0x1f), fwdev->eui.hi, fwdev->eui.lo, fwdev->dst, fwdev->speed, fwdev->maxrec ); if (new) printf(" new!\n"); else printf("\n"); sbp_show_sdev_info(sdev, 2); printf("'%s' '%s' '%s'\n", sdev->vendor, sdev->product, sdev->revision); } static struct { int bus; int target; struct fw_eui64 eui; } wired[] = { /* Bus Target EUI64 */ #if 0 {0, 2, {0x00018ea0, 0x01fd0154}}, /* Logitec HDD */ {0, 0, {0x00018ea6, 0x00100682}}, /* Logitec DVD */ {0, 1, {0x00d03200, 0xa412006a}}, /* Yano HDD */ #endif {-1, -1, {0,0}} }; static int sbp_new_target(struct sbp_softc *sbp, struct fw_device *fwdev) { int bus, i, target=-1; char w[SBP_NUM_TARGETS]; bzero(w, sizeof(w)); bus = device_get_unit(sbp->fd.dev); /* XXX wired-down configuration should be gotten from tunable or device hint */ for (i = 0; wired[i].bus >= 0; i ++) { if (wired[i].bus == bus) { w[wired[i].target] = 1; if (wired[i].eui.hi == fwdev->eui.hi && wired[i].eui.lo == fwdev->eui.lo) target = wired[i].target; } } if (target >= 0) { if(target < SBP_NUM_TARGETS && sbp->targets[target].fwdev == NULL) return(target); device_printf(sbp->fd.dev, "target %d is not free for %08x:%08x\n", target, fwdev->eui.hi, fwdev->eui.lo); target = -1; } /* non-wired target */ for (i = 0; i < SBP_NUM_TARGETS; i ++) if (sbp->targets[i].fwdev == NULL && w[i] == 0) { target = i; break; } return target; } static struct sbp_target * sbp_alloc_target(struct sbp_softc *sbp, struct fw_device *fwdev) { int i, maxlun, lun; struct sbp_target *target; struct sbp_dev *sdev; 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 */ if((target->mgm_lo = getcsrdata(fwdev, 0x54)) == 0 ){ /* bad target */ printf("NULL management address\n"); target->fwdev = NULL; return NULL; } target->mgm_hi = 0xffff; target->mgm_lo = 0xf0000000 | target->mgm_lo << 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? */ crom_init_context(&cc, target->fwdev->csrrom); /* XXX shoud parse appropriate unit directories only */ maxlun = -1; while (cc.depth >= 0) { reg = crom_search_key(&cc, CROM_LUN); if (reg == NULL) break; lun = reg->val & 0xffff; SBP_DEBUG(0) printf("target %d lun %d found\n", target->target_id, lun); END_DEBUG if (maxlun < lun) maxlun = lun; crom_next(&cc); } if (maxlun < 0) printf("no lun found!\n"); 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; } crom_init_context(&cc, target->fwdev->csrrom); while (cc.depth >= 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; } - target->luns[lun].status = SBP_DEV_RESET; - target->luns[lun].type = (reg->val & 0xf0000) >> 16; + sdev = &target->luns[lun]; + sdev->status = SBP_DEV_RESET; + sdev->type = (reg->val & 0xf0000) >> 16; + + fwdma_malloc(sbp->fd.fc, + /* alignment */ sizeof(u_int32_t), + SBP_DMA_SIZE, &sdev->dma, BUS_DMA_NOWAIT); + if (sdev->dma.v_addr == NULL) { + printf("%s: dma space allocation failed\n", + __FUNCTION__); + return (NULL); + } + sdev->login = (struct sbp_login_res *) sdev->dma.v_addr; + sdev->ocb = (struct sbp_ocb *) + ((char *)sdev->dma.v_addr + SBP_LOGIN_SIZE); + bzero((char *)sdev->ocb, + sizeof (struct sbp_ocb) * SBP_QUEUE_LEN); + + STAILQ_INIT(&sdev->free_ocbs); + for (i = 0; i < SBP_QUEUE_LEN; i++) { + struct sbp_ocb *ocb; + ocb = &sdev->ocb[i]; + ocb->bus_addr = sdev->dma.bus_addr + + SBP_LOGIN_SIZE + + sizeof(struct sbp_ocb) * i + + offsetof(struct sbp_ocb, orb[0]); + if (bus_dmamap_create(sbp->dmat, 0, &ocb->dmamap)) { + printf("sbp_attach: cannot create dmamap\n"); + return (NULL); + } + sbp_free_ocb(sdev, ocb); + } crom_next(&cc); } return target; } static void sbp_get_text_leaf(struct fw_device *fwdev, int key, char *buf, int len) { static char *nullstr = "(null)"; int i, clen, found=0; struct csrhdr *chdr; struct csrreg *creg; u_int32_t *src, *dst; chdr = (struct csrhdr *)&fwdev->csrrom[0]; /* skip crom header, bus info and root directory */ creg = (struct csrreg *)chdr + chdr->info_len + 2; /* search unitl the one before the last. */ for (i = chdr->info_len + 2; i < fwdev->rommax / 4; i++) { if((creg++)->key == key){ found = 1; break; } } if (!found || creg->key != CROM_TEXTLEAF) { strncpy(buf, nullstr, len); return; } src = (u_int32_t *) creg + creg->val; clen = ((*src >> 16) - 2) * 4; src += 3; dst = (u_int32_t *) buf; if (len < clen) clen = len; for (i = 0; i < clen/4; i++) *dst++ = htonl(*src++); buf[clen] = 0; } static void sbp_probe_lun(struct sbp_dev *sdev) { struct fw_device *fwdev; int rev; fwdev = sdev->target->fwdev; bzero(sdev->vendor, sizeof(sdev->vendor)); bzero(sdev->product, sizeof(sdev->product)); sbp_get_text_leaf(fwdev, 0x03, sdev->vendor, sizeof(sdev->vendor)); sbp_get_text_leaf(fwdev, 0x17, sdev->product, sizeof(sdev->product)); rev = getcsrdata(sdev->target->fwdev, 0x3c); snprintf(sdev->revision, sizeof(sdev->revision), "%06x", rev); } static void sbp_login_callout(void *arg) { struct sbp_dev *sdev = (struct sbp_dev *)arg; sbp_mgm_orb(sdev, ORB_FUN_LGI, NULL); } #define SBP_FWDEV_ALIVE(fwdev) \ ((fwdev->status == FWDEVATTACHED) \ && (getcsrdata(fwdev, CSRKEY_SPEC) == CSRVAL_ANSIT10) \ && (getcsrdata(fwdev, CSRKEY_VER) == CSRVAL_T10SBP2)) static void sbp_probe_target(void *arg) { struct sbp_target *target = (struct sbp_target *)arg; struct sbp_softc *sbp; struct sbp_dev *sdev; struct firewire_comm *fc; int i, alive; alive = SBP_FWDEV_ALIVE(target->fwdev); SBP_DEBUG(1) printf("sbp_probe_target %d\n", target->target_id); if (!alive) printf("not alive\n"); END_DEBUG sbp = target->sbp; fc = target->sbp->fd.fc; /* XXX untimeout mgm_ocb and dequeue */ for (i=0; i < target->num_lun; i++) { sdev = &target->luns[i]; if (alive && (sdev->status != SBP_DEV_DEAD)) { if (sdev->path != NULL) { xpt_freeze_devq(sdev->path, 1); sdev->freeze ++; } sbp_probe_lun(sdev); SBP_DEBUG(0) sbp_show_sdev_info(sdev, -#if 0 - (sdev->status == SBP_DEV_TOATTACH)); -#else (sdev->status == SBP_DEV_RESET)); -#endif END_DEBUG sbp_abort_all_ocbs(sdev, CAM_SCSI_BUS_RESET); switch (sdev->status) { case SBP_DEV_RESET: /* new or revived target */ - if (auto_login) { -#if 0 - sdev->status = SBP_DEV_TOATTACH; -#endif + if (auto_login) sbp_login(sdev); - } break; case SBP_DEV_TOATTACH: case SBP_DEV_PROBE: case SBP_DEV_ATTACHED: case SBP_DEV_RETRY: default: sbp_mgm_orb(sdev, ORB_FUN_RCN, NULL); break; } } else { switch (sdev->status) { case SBP_DEV_ATTACHED: SBP_DEBUG(0) /* the device has gone */ sbp_show_sdev_info(sdev, 2); printf("lost target\n"); END_DEBUG if (sdev->path) { xpt_freeze_devq(sdev->path, 1); sdev->freeze ++; } sdev->status = SBP_DEV_RETRY; sbp_abort_all_ocbs(sdev, CAM_SCSI_BUS_RESET); break; case SBP_DEV_PROBE: case SBP_DEV_TOATTACH: sdev->status = SBP_DEV_RESET; break; case SBP_DEV_RETRY: case SBP_DEV_RESET: case SBP_DEV_DEAD: break; } } } } static void +sbp_post_busreset(void *arg) +{ + struct sbp_softc *sbp; + + sbp = (struct sbp_softc *)arg; +SBP_DEBUG(0) + printf("sbp_post_busreset\n"); +END_DEBUG +} + +static void sbp_post_explore(void *arg) { struct sbp_softc *sbp = (struct sbp_softc *)arg; struct sbp_target *target; struct fw_device *fwdev; int i, alive; 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 */ 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 ++){ target = &sbp->targets[i]; STAILQ_FOREACH(fwdev, &sbp->fd.fc->devices, link) if (target->fwdev == NULL || target->fwdev == fwdev) break; 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; } } /* traverse device list */ STAILQ_FOREACH(fwdev, &sbp->fd.fc->devices, link) { SBP_DEBUG(0) printf("sbp_post_explore: EUI:%08x%08x ", fwdev->eui.hi, fwdev->eui.lo); if (fwdev->status == FWDEVATTACHED) { printf("spec=%d key=%d.\n", getcsrdata(fwdev, CSRKEY_SPEC) == CSRVAL_ANSIT10, getcsrdata(fwdev, CSRKEY_VER) == CSRVAL_T10SBP2); } else { printf("not attached, state=%d.\n", fwdev->status); } END_DEBUG alive = SBP_FWDEV_ALIVE(fwdev); for(i = 0 ; i < SBP_NUM_TARGETS ; i ++){ target = &sbp->targets[i]; if(target->fwdev == fwdev ) { /* known target */ break; } } if(i == SBP_NUM_TARGETS){ if (alive) { /* new target */ target = sbp_alloc_target(sbp, fwdev); if (target == NULL) continue; } else { continue; } } sbp_probe_target((void *)target); } -#if 0 - timeout(sbp_release_queue, (caddr_t)sbp, bus_reset_rest * hz / 1000); -#endif } #if NEED_RESPONSE static void sbp_loginres_callback(struct fw_xfer *xfer){ -SBP_DEBUG(1) + int s; struct sbp_dev *sdev; sdev = (struct sbp_dev *)xfer->sc; +SBP_DEBUG(1) sbp_show_sdev_info(sdev, 2); printf("sbp_loginres_callback\n"); END_DEBUG - fw_xfer_free(xfer); + /* recycle */ + s = splfw(); + STAILQ_INSERT_TAIL(&sdev->target->sbp->fwb.xferlist, xfer, link); + splx(s); return; } #endif +static __inline void +sbp_xfer_free(struct fw_xfer *xfer) +{ + struct sbp_dev *sdev; + int s; + + sdev = (struct sbp_dev *)xfer->sc; + fw_xfer_unload(xfer); + s = splfw(); + STAILQ_INSERT_TAIL(&sdev->target->xferlist, xfer, link); + splx(s); +} + static void sbp_login_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_login_callback\n"); END_DEBUG - fw_xfer_free(xfer); + sbp_xfer_free(xfer); 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 - fw_xfer_free(xfer); + sbp_xfer_free(xfer); return; } static struct sbp_dev * sbp_next_dev(struct sbp_target *target, int lun) { struct sbp_dev *sdev; 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); } #define SCAN_PRI 1 static void sbp_cam_scan_lun(struct cam_periph *periph, union ccb *ccb) { struct sbp_target *target; struct sbp_dev *sdev; sdev = (struct sbp_dev *) ccb->ccb_h.ccb_sdev_ptr; target = sdev->target; SBP_DEBUG(0) sbp_show_sdev_info(sdev, 2); printf("sbp_cam_scan_lun\n"); END_DEBUG if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { sdev->status = SBP_DEV_ATTACHED; } else { sbp_show_sdev_info(sdev, 2); printf("scan failed\n"); } sdev = sbp_next_dev(target, sdev->lun_id + 1); if (sdev == NULL) { free(ccb, M_SBP); return; } /* reuse ccb */ xpt_setup_ccb(&ccb->ccb_h, sdev->path, SCAN_PRI); ccb->ccb_h.ccb_sdev_ptr = sdev; xpt_action(ccb); xpt_release_devq(sdev->path, sdev->freeze, TRUE); sdev->freeze = 1; } static void sbp_cam_scan_target(void *arg) { struct sbp_target *target = (struct sbp_target *)arg; struct sbp_dev *sdev; union ccb *ccb; sdev = sbp_next_dev(target, 0); if (sdev == NULL) { printf("sbp_cam_scan_target: nothing to do for target%d\n", target->target_id); return; } SBP_DEBUG(0) sbp_show_sdev_info(sdev, 2); printf("sbp_cam_scan_target\n"); END_DEBUG ccb = malloc(sizeof(union ccb), M_SBP, M_NOWAIT | M_ZERO); if (ccb == NULL) { printf("sbp_cam_scan_target: malloc failed\n"); return; } xpt_setup_ccb(&ccb->ccb_h, sdev->path, SCAN_PRI); ccb->ccb_h.func_code = XPT_SCAN_LUN; ccb->ccb_h.cbfcnp = sbp_cam_scan_lun; ccb->ccb_h.flags |= CAM_DEV_QFREEZE; ccb->crcn.flags = CAM_FLAG_NONE; ccb->ccb_h.ccb_sdev_ptr = sdev; /* The scan is in progress now. */ xpt_action(ccb); xpt_release_devq(sdev->path, sdev->freeze, TRUE); sdev->freeze = 1; } - -#if 0 -static void -sbp_ping_unit_callback(struct cam_periph *periph, union ccb *ccb) -{ - struct sbp_dev *sdev; - sdev = (struct sbp_dev *) ccb->ccb_h.ccb_sdev_ptr; -SBP_DEBUG(0) - sbp_show_sdev_info(sdev, 2); - printf("sbp_ping_unit_callback\n"); -END_DEBUG - if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { - if (--ccb->ccb_h.retry_count == 0) { - sbp_show_sdev_info(sdev, 2); - printf("sbp_ping_unit_callback: " - "retry count exceeded\n"); - sdev->status = SBP_DEV_RETRY; - free(ccb, M_SBP); - } else { - /* requeue */ - xpt_action(ccb); - xpt_release_devq(sdev->path, sdev->freeze, TRUE); - sdev->freeze = 1; /* we will freeze */ - } - } else { - free(ccb->csio.data_ptr, M_SBP); - free(ccb, M_SBP); - sdev->status = SBP_DEV_ATTACHED; - xpt_release_devq(sdev->path, sdev->freeze, TRUE); - sdev->freeze = 0; - } -} - -/* - * XXX Some devices need to execute inquiry or read_capacity - * after bus_rest during busy transfer. - * Otherwise they return incorrect result for READ(and WRITE?) - * command without any SBP-II/SCSI error. - * - * e.g. Maxtor 3000XT, Yano A-dish. - */ -static void -sbp_ping_unit(struct sbp_dev *sdev) -{ - union ccb *ccb; - struct scsi_inquiry_data *inq_buf; - - - ccb = malloc(sizeof(union ccb), M_SBP, M_NOWAIT | M_ZERO); - if (ccb == NULL) { - printf("sbp_ping_unit: malloc failed\n"); - return; - } - - inq_buf = (struct scsi_inquiry_data *) - malloc(sizeof(*inq_buf), M_SBP, M_NOWAIT); - if (inq_buf == NULL) { - free(ccb, M_SBP); - printf("sbp_ping_unit: malloc failed\n"); - return; - } - -SBP_DEBUG(0) - sbp_show_sdev_info(sdev, 2); - printf("sbp_ping_unit\n"); -END_DEBUG - - /* - * We need to execute this command before any other queued command. - * Make priority 0 and freeze the queue after execution for retry. - * cam's scan_lun command doesn't provide this feature. - */ - xpt_setup_ccb(&ccb->ccb_h, sdev->path, 0/*priority (high)*/); - scsi_inquiry( - &ccb->csio, - /*retries*/ 5, - sbp_ping_unit_callback, - MSG_SIMPLE_Q_TAG, - (u_int8_t *)inq_buf, - SHORT_INQUIRY_LENGTH, - /*evpd*/FALSE, - /*page_code*/0, - SSD_MIN_SIZE, - /*timeout*/60000 - ); - ccb->ccb_h.flags |= CAM_DEV_QFREEZE; - ccb->ccb_h.ccb_sdev_ptr = sdev; - xpt_action(ccb); - if (sdev->status != SBP_DEV_ATTACHED) - sdev->status = SBP_DEV_PROBE; - xpt_release_devq(sdev->path, sdev->freeze, TRUE); - sdev->freeze = 1; /* We will freeze the queue */ -} -#endif - static __inline void sbp_scan_dev(struct sbp_dev *sdev) { sdev->status = SBP_DEV_PROBE; callout_reset(&sdev->target->scan_callout, SCAN_DELAY * hz, sbp_cam_scan_target, (void *)sdev->target); } static void sbp_do_attach(struct fw_xfer *xfer) { struct sbp_dev *sdev; struct sbp_target *target; struct sbp_softc *sbp; sdev = (struct sbp_dev *)xfer->sc; target = sdev->target; sbp = target->sbp; SBP_DEBUG(0) sbp_show_sdev_info(sdev, 2); printf("sbp_do_attach\n"); END_DEBUG - fw_xfer_free(xfer); + sbp_xfer_free(xfer); if (sdev->path == NULL) xpt_create_path(&sdev->path, xpt_periph, cam_sim_path(target->sbp->sim), target->target_id, sdev->lun_id); /* * Let CAM scan the bus if we are in the boot process. * XXX xpt_scan_bus cannot detect LUN larger than 0 * if LUN 0 doesn't exists. */ if (sbp_cold > 0) { sdev->status = SBP_DEV_ATTACHED; return; } sbp_scan_dev(sdev); return; } static void sbp_agent_reset_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("sbp_cmd_callback\n"); END_DEBUG - fw_xfer_free(xfer); + sbp_xfer_free(xfer); if (sdev->path) { xpt_release_devq(sdev->path, sdev->freeze, TRUE); sdev->freeze = 0; } } static void sbp_agent_reset(struct sbp_dev *sdev) { struct fw_xfer *xfer; struct fw_pkt *fp; SBP_DEBUG(0) sbp_show_sdev_info(sdev, 2); printf("sbp_agent_reset\n"); END_DEBUG xfer = sbp_write_cmd(sdev, FWTCODE_WREQQ, 0x04); if (xfer == NULL) return; if (sdev->status == SBP_DEV_ATTACHED) xfer->act.hand = sbp_agent_reset_callback; else xfer->act.hand = sbp_do_attach; fp = (struct fw_pkt *)xfer->send.buf; fp->mode.wreqq.data = htonl(0xf); fw_asyreq(xfer->fc, -1, xfer); sbp_abort_all_ocbs(sdev, CAM_BDR_SENT); } static void sbp_busy_timeout_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("sbp_busy_timeout_callback\n"); END_DEBUG - fw_xfer_free(xfer); + sbp_xfer_free(xfer); sbp_agent_reset(sdev); } static void sbp_busy_timeout(struct sbp_dev *sdev) { struct fw_pkt *fp; struct fw_xfer *xfer; SBP_DEBUG(0) sbp_show_sdev_info(sdev, 2); printf("sbp_busy_timeout\n"); 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->mode.wreqq.dest_hi = htons(0xffff); - fp->mode.wreqq.dest_lo = htonl(0xf0000000 | BUSY_TIMEOUT); + 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); } #if 0 static void sbp_reset_start(struct sbp_dev *sdev) { struct fw_xfer *xfer; struct fw_pkt *fp; SBP_DEBUG(0) sbp_show_sdev_info(sdev, 2); printf("sbp_reset_start\n"); END_DEBUG xfer = sbp_write_cmd(sdev, FWTCODE_WREQQ, 0); xfer->act.hand = sbp_busy_timeout; fp = (struct fw_pkt *)xfer->send.buf; - fp->mode.wreqq.dest_hi = htons(0xffff); - fp->mode.wreqq.dest_lo = htonl(0xf0000000 | RESET_START); + fp->mode.wreqq.dest_hi = 0xffff; + fp->mode.wreqq.dest_lo = 0xf0000000 | RESET_START; fp->mode.wreqq.data = htonl(0xf); fw_asyreq(xfer->fc, -1, xfer); } #endif 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_show_sdev_info(sdev, 2); printf("sbp_orb_pointer\n"); END_DEBUG xfer = sbp_write_cmd(sdev, FWTCODE_WREQB, 0x08); if (xfer == NULL) return; xfer->act.hand = sbp_cmd_callback; fp = (struct fw_pkt *)xfer->send.buf; - fp->mode.wreqb.len = htons(8); + fp->mode.wreqb.len = 8; fp->mode.wreqb.extcode = 0; fp->mode.wreqb.payload[0] = htonl(((sdev->target->sbp->fd.fc->nodeid | FWLOCALBUS )<< 16)); - fp->mode.wreqb.payload[1] = htonl(vtophys(&ocb->orb[0])); + fp->mode.wreqb.payload[1] = htonl(ocb->bus_addr); if(fw_asyreq(xfer->fc, -1, xfer) != 0){ - fw_xfer_free(xfer); + sbp_xfer_free(xfer); ocb->ccb->ccb_h.status = CAM_REQ_INVALID; xpt_done(ocb->ccb); } } #if 0 static void sbp_doorbell(struct sbp_dev *sdev) { struct fw_xfer *xfer; struct fw_pkt *fp; SBP_DEBUG(1) sbp_show_sdev_info(sdev, 2); printf("sbp_doorbell\n"); END_DEBUG xfer = sbp_write_cmd(sdev, FWTCODE_WREQQ, 0x10); if (xfer == NULL) return; xfer->act.hand = sbp_cmd_callback; fp = (struct fw_pkt *)xfer->send.buf; fp->mode.wreqq.data = htonl(0xf); fw_asyreq(xfer->fc, -1, xfer); } #endif static struct fw_xfer * sbp_write_cmd(struct sbp_dev *sdev, int tcode, int offset) { struct fw_xfer *xfer; struct fw_pkt *fp; + struct sbp_target *target; + int s, new = 0; - xfer = fw_xfer_alloc(M_SBP); - if(xfer == NULL){ - return NULL; + target = sdev->target; + s = splfw(); + xfer = STAILQ_FIRST(&target->xferlist); + if (xfer == NULL) { + if (target->n_xfer > 5 /* XXX */) { + printf("sbp: no more xfer for this target\n"); + splx(s); + return(NULL); + } + xfer = fw_xfer_alloc_buf(M_SBP, 24, 12); + if(xfer == NULL){ + printf("sbp: fw_xfer_alloc_buf failed\n"); + splx(s); + return NULL; + } + target->n_xfer ++; + if (debug) + printf("sbp: alloc %d xfer\n", target->n_xfer); + new = 1; + } else { + STAILQ_REMOVE_HEAD(&target->xferlist, link); } + splx(s); + + microtime(&xfer->tv); + if (tcode == FWTCODE_WREQQ) xfer->send.len = 16; else xfer->send.len = 24; + xfer->recv.len = 12; - xfer->send.buf = malloc(xfer->send.len, M_FW, M_NOWAIT); - if(xfer->send.buf == NULL){ - fw_xfer_free(xfer); - return NULL; + if (new) { + xfer->spd = min(sdev->target->fwdev->speed, max_speed); + xfer->fc = sdev->target->sbp->fd.fc; + xfer->retry_req = fw_asybusy; } - - xfer->send.off = 0; - xfer->spd = min(sdev->target->fwdev->speed, max_speed); xfer->sc = (caddr_t)sdev; - xfer->fc = sdev->target->sbp->fd.fc; - xfer->retry_req = fw_asybusy; - fp = (struct fw_pkt *)xfer->send.buf; - fp->mode.wreqq.dest_hi = htons(sdev->login.cmd_hi); - fp->mode.wreqq.dest_lo = htonl(sdev->login.cmd_lo + offset); + 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 = htons(xfer->dst); + fp->mode.wreqq.dst = xfer->dst; return xfer; } static void sbp_mgm_orb(struct sbp_dev *sdev, int func, struct sbp_ocb *aocb) { struct fw_xfer *xfer; struct fw_pkt *fp; struct sbp_ocb *ocb; struct sbp_target *target; int s, nid; target = sdev->target; nid = target->sbp->fd.fc->nodeid | FWLOCALBUS; s = splfw(); if (func == ORB_FUN_RUNQUEUE) { ocb = STAILQ_FIRST(&target->mgm_ocb_queue); if (target->mgm_ocb_cur != NULL || ocb == NULL) { splx(s); return; } STAILQ_REMOVE_HEAD(&target->mgm_ocb_queue, ocb); goto start; } - if ((ocb = sbp_get_ocb(target->sbp)) == NULL) { - target->sbp->flags |= SBP_RESOURCE_SHORTAGE; + if ((ocb = sbp_get_ocb(sdev)) == NULL) { splx(s); return; } ocb->flags = OCB_ACT_MGM; ocb->sdev = sdev; bzero((void *)(uintptr_t)(volatile 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)); SBP_DEBUG(0) sbp_show_sdev_info(sdev, 2); printf("%s\n", orb_fun_name[(func>>16)&0xf]); END_DEBUG switch (func) { case ORB_FUN_LGI: ocb->orb[2] = htonl(nid << 16); - ocb->orb[3] = htonl(vtophys(&sdev->login)); + ocb->orb[3] = htonl(sdev->dma.bus_addr); ocb->orb[4] = htonl(ORB_NOTIFY | ORB_EXV | sdev->lun_id); - ocb->orb[5] = htonl(sizeof(struct sbp_login_res)); + ocb->orb[5] = htonl(SBP_LOGIN_SIZE); + fwdma_sync(&sdev->dma, BUS_DMASYNC_PREREAD); break; case ORB_FUN_ATA: ocb->orb[0] = htonl((0 << 16) | 0); - ocb->orb[1] = htonl(vtophys(&aocb->orb[0])); + ocb->orb[1] = htonl(aocb->bus_addr & 0xffffffff); /* fall through */ case ORB_FUN_RCN: case ORB_FUN_LGO: case ORB_FUN_LUR: case ORB_FUN_RST: case ORB_FUN_ATS: - ocb->orb[4] = htonl(ORB_NOTIFY | func | sdev->login.id); + ocb->orb[4] = htonl(ORB_NOTIFY | func | sdev->login->id); break; } if (target->mgm_ocb_cur != NULL) { /* there is a standing ORB */ STAILQ_INSERT_TAIL(&sdev->target->mgm_ocb_queue, ocb, ocb); splx(s); return; } start: target->mgm_ocb_cur = ocb; splx(s); callout_reset(&target->mgm_ocb_timeout, 5*hz, sbp_timeout, (caddr_t)ocb); xfer = sbp_write_cmd(sdev, FWTCODE_WREQB, 0); if(xfer == NULL){ return; } xfer->act.hand = sbp_login_callback; fp = (struct fw_pkt *)xfer->send.buf; - fp->mode.wreqb.dest_hi = htons(sdev->target->mgm_hi); - fp->mode.wreqb.dest_lo = htonl(sdev->target->mgm_lo); - fp->mode.wreqb.len = htons(8); + 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(vtophys(&ocb->orb[0])); + fp->mode.wreqb.payload[1] = htonl(ocb->bus_addr); fw_asyreq(xfer->fc, -1, xfer); } static void sbp_print_scsi_cmd(struct sbp_ocb *ocb) { struct ccb_scsiio *csio; csio = &ocb->ccb->csio; printf("%s:%d:%d XPT_SCSI_IO: " "cmd: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x" ", flags: 0x%02x, " "%db cmd/%db data/%db sense\n", device_get_nameunit(ocb->sdev->target->sbp->fd.dev), ocb->ccb->ccb_h.target_id, ocb->ccb->ccb_h.target_lun, csio->cdb_io.cdb_bytes[0], csio->cdb_io.cdb_bytes[1], csio->cdb_io.cdb_bytes[2], csio->cdb_io.cdb_bytes[3], csio->cdb_io.cdb_bytes[4], csio->cdb_io.cdb_bytes[5], csio->cdb_io.cdb_bytes[6], csio->cdb_io.cdb_bytes[7], csio->cdb_io.cdb_bytes[8], csio->cdb_io.cdb_bytes[9], ocb->ccb->ccb_h.flags & CAM_DIR_MASK, csio->cdb_len, csio->dxfer_len, csio->sense_len); } static void sbp_scsi_status(struct sbp_status *sbp_status, struct sbp_ocb *ocb) { struct sbp_cmd_status *sbp_cmd_status; struct scsi_sense_data *sense; sbp_cmd_status = (struct sbp_cmd_status *)sbp_status->data; sense = &ocb->ccb->csio.sense_data; SBP_DEBUG(0) sbp_print_scsi_cmd(ocb); /* XXX need decode status */ sbp_show_sdev_info(ocb->sdev, 2); - printf("SCSI status %x sfmt %x valid %x key %x code %x qlfr %x len %d", + printf("SCSI status %x sfmt %x valid %x key %x code %x qlfr %x len %d\n", sbp_cmd_status->status, sbp_cmd_status->sfmt, sbp_cmd_status->valid, sbp_cmd_status->s_key, sbp_cmd_status->s_code, sbp_cmd_status->s_qlfr, sbp_status->len ); -#if 0 /* XXX */ - if (sbp_cmd_status->status == SCSI_STATUS_CHECK_COND) { - printf(" %s\n", scsi_sense_key_text[sbp_cmd_status->s_key]); - scsi_sense_desc( - sbp_cmd_status->s_code, - sbp_cmd_status->s_qlfr, - ocb->ccb->ccb_h.path->device->inq_data - ) - } else { - printf("\n"); - } -#else - printf("\n"); -#endif END_DEBUG switch (sbp_cmd_status->status) { case SCSI_STATUS_CHECK_COND: case SCSI_STATUS_BUSY: case SCSI_STATUS_CMD_TERMINATED: if(sbp_cmd_status->sfmt == SBP_SFMT_CURR){ sense->error_code = SSD_CURRENT_ERROR; }else{ sense->error_code = SSD_DEFERRED_ERROR; } if(sbp_cmd_status->valid) sense->error_code |= SSD_ERRCODE_VALID; sense->flags = sbp_cmd_status->s_key; if(sbp_cmd_status->mark) sense->flags |= SSD_FILEMARK; if(sbp_cmd_status->eom) 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; if (sbp_status->len <= 1) /* XXX not scsi status. shouldn't be happened */ sense->extra_len = 0; else if (sbp_status->len <= 4) /* add_sense_code(_qual), info, cmd_spec_info */ sense->extra_len = 6; 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; 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; ocb->ccb->csio.scsi_status = sbp_cmd_status->status;; ocb->ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR | CAM_AUTOSNS_VALID; /* { u_int8_t j, *tmp; tmp = sense; for( j = 0 ; j < 32 ; j+=8){ printf("sense %02x%02x %02x%02x %02x%02x %02x%02x\n", tmp[j], tmp[j+1], tmp[j+2], tmp[j+3], tmp[j+4], tmp[j+5], tmp[j+6], tmp[j+7]); } } */ break; default: sbp_show_sdev_info(ocb->sdev, 2); printf("sbp_scsi_status: unknown scsi status 0x%x\n", sbp_cmd_status->status); } } static void sbp_fix_inq_data(struct sbp_ocb *ocb) { union ccb *ccb; struct sbp_dev *sdev; struct scsi_inquiry_data *inq; ccb = ocb->ccb; sdev = ocb->sdev; if (ccb->csio.cdb_io.cdb_bytes[1] & SI_EVPD) return; SBP_DEBUG(1) sbp_show_sdev_info(sdev, 2); printf("sbp_fix_inq_data\n"); END_DEBUG inq = (struct scsi_inquiry_data *) ccb->csio.data_ptr; switch (SID_TYPE(inq)) { case T_DIRECT: /* * 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 */ #if 1 inq->flags |= SID_CmdQue; #endif /* * Override vendor/product/revision information. * Some devices sometimes return strange strings. */ #if 1 bcopy(sdev->vendor, inq->vendor, sizeof(inq->vendor)); bcopy(sdev->product, inq->product, sizeof(inq->product)); bcopy(sdev->revision+2, inq->revision, sizeof(inq->revision)); #endif break; } } static void -sbp_recv1(struct fw_xfer *xfer){ +sbp_recv1(struct fw_xfer *xfer) +{ struct fw_pkt *rfp; #if NEED_RESPONSE struct fw_pkt *sfp; #endif struct sbp_softc *sbp; struct sbp_dev *sdev; struct sbp_ocb *ocb; struct sbp_login_res *login_res = NULL; struct sbp_status *sbp_status; struct sbp_target *target; int orb_fun, status_valid0, status_valid, t, l, reset_agent = 0; u_int32_t addr; /* u_int32_t *ld; ld = xfer->recv.buf; printf("sbp %x %d %d %08x %08x %08x %08x\n", xfer->resp, xfer->recv.len, xfer->recv.off, ntohl(ld[0]), ntohl(ld[1]), ntohl(ld[2]), ntohl(ld[3])); 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"); - fw_xfer_free( xfer); - return; + goto done0; } if(xfer->recv.buf == NULL){ printf("sbp_recv: xfer->recv.buf == NULL\n"); - fw_xfer_free( xfer); - return; + goto done0; } sbp = (struct sbp_softc *)xfer->sc; rfp = (struct fw_pkt *)xfer->recv.buf; if(rfp->mode.wreqb.tcode != FWTCODE_WREQB){ printf("sbp_recv: tcode = %d\n", rfp->mode.wreqb.tcode); - fw_xfer_free( xfer); - return; + goto done0; } sbp_status = (struct sbp_status *)rfp->mode.wreqb.payload; - addr = ntohl(rfp->mode.wreqb.dest_lo); + addr = rfp->mode.wreqb.dest_lo; SBP_DEBUG(2) printf("received address 0x%x\n", addr); END_DEBUG t = SBP_ADDR2TRG(addr); if (t >= SBP_NUM_TARGETS) { device_printf(sbp->fd.dev, "sbp_recv1: invalid target %d\n", t); - fw_xfer_free(xfer); - return; + goto done0; } target = &sbp->targets[t]; l = SBP_ADDR2LUN(addr); if (l >= target->num_lun) { device_printf(sbp->fd.dev, "sbp_recv1: invalid lun %d (target=%d)\n", l, t); - fw_xfer_free(xfer); - return; + goto done0; } sdev = &target->luns[l]; ocb = NULL; switch (sbp_status->src) { case 0: case 1: /* check mgm_ocb_cur first */ ocb = target->mgm_ocb_cur; if (ocb != NULL) { if (OCB_MATCH(ocb, sbp_status)) { callout_stop(&target->mgm_ocb_timeout); target->mgm_ocb_cur = NULL; break; } } ocb = sbp_dequeue_ocb(sdev, sbp_status); if (ocb == NULL) { sbp_show_sdev_info(sdev, 2); #if __FreeBSD_version >= 500000 printf("No ocb(%x) on the queue\n", #else printf("No ocb(%lx) on the queue\n", #endif ntohl(sbp_status->orb_lo)); } break; case 2: /* unsolicit */ sbp_show_sdev_info(sdev, 2); printf("unsolicit status received\n"); break; default: sbp_show_sdev_info(sdev, 2); printf("unknown sbp_status->src\n"); } status_valid0 = (sbp_status->src < 2 && sbp_status->resp == ORB_RES_CMPL && sbp_status->dead == 0); status_valid = (status_valid0 && sbp_status->status == 0); if (!status_valid0 || debug > 1){ int status; SBP_DEBUG(0) sbp_show_sdev_info(sdev, 2); printf("ORB status src:%x resp:%x dead:%x" #if __FreeBSD_version >= 500000 " len:%x stat:%x orb:%x%08x\n", #else " len:%x stat:%x orb:%x%08lx\n", #endif sbp_status->src, sbp_status->resp, sbp_status->dead, sbp_status->len, sbp_status->status, ntohs(sbp_status->orb_hi), ntohl(sbp_status->orb_lo)); END_DEBUG sbp_show_sdev_info(sdev, 2); status = sbp_status->status; switch(sbp_status->resp) { case 0: if (status > MAX_ORB_STATUS0) printf("%s\n", orb_status0[MAX_ORB_STATUS0]); else printf("%s\n", orb_status0[status]); break; case 1: printf("Obj: %s, Error: %s\n", orb_status1_object[(status>>6) & 3], orb_status1_serial_bus_error[status & 0xf]); break; case 2: printf("Illegal request\n"); break; case 3: printf("Vendor dependent\n"); break; default: printf("unknown respose code %d\n", sbp_status->resp); } } /* we have to reset the fetch agent if it's dead */ if (sbp_status->dead) { if (sdev->path) { xpt_freeze_devq(sdev->path, 1); sdev->freeze ++; } reset_agent = 1; } if (ocb == NULL) goto done; sdev->flags &= ~SBP_DEV_TIMEOUT; switch(ntohl(ocb->orb[4]) & ORB_FMT_MSK){ case ORB_FMT_NOP: break; case ORB_FMT_VED: break; case ORB_FMT_STD: switch(ocb->flags) { case OCB_ACT_MGM: orb_fun = ntohl(ocb->orb[4]) & ORB_FUN_MSK; switch(orb_fun) { case ORB_FUN_LGI: - login_res = &sdev->login; + fwdma_sync(&sdev->dma, BUS_DMASYNC_POSTREAD); + login_res = sdev->login; login_res->len = ntohs(login_res->len); login_res->id = ntohs(login_res->id); login_res->cmd_hi = ntohs(login_res->cmd_hi); login_res->cmd_lo = ntohl(login_res->cmd_lo); if (status_valid) { SBP_DEBUG(0) sbp_show_sdev_info(sdev, 2); printf("login: len %d, ID %d, cmd %08x%08x, recon_hold %d\n", login_res->len, login_res->id, login_res->cmd_hi, login_res->cmd_lo, ntohs(login_res->recon_hold)); END_DEBUG -#if 0 - sdev->status = SBP_DEV_TOATTACH; -#endif -#if 1 sbp_busy_timeout(sdev); -#else - sbp_mgm_orb(sdev, ORB_FUN_ATS, NULL); -#endif } else { /* forgot logout? */ sbp_show_sdev_info(sdev, 2); printf("login failed\n"); sdev->status = SBP_DEV_RESET; } break; case ORB_FUN_RCN: - login_res = &sdev->login; + login_res = sdev->login; if (status_valid) { SBP_DEBUG(0) sbp_show_sdev_info(sdev, 2); printf("reconnect: len %d, ID %d, cmd %08x%08x\n", login_res->len, login_res->id, login_res->cmd_hi, login_res->cmd_lo); END_DEBUG #if 1 if (sdev->status == SBP_DEV_ATTACHED) sbp_scan_dev(sdev); else sbp_agent_reset(sdev); #else sdev->status = SBP_DEV_ATTACHED; sbp_mgm_orb(sdev, ORB_FUN_ATS, NULL); #endif } else { /* reconnection hold time exceed? */ SBP_DEBUG(0) sbp_show_sdev_info(sdev, 2); printf("reconnect failed\n"); END_DEBUG sbp_login(sdev); } break; case ORB_FUN_LGO: sdev->status = SBP_DEV_RESET; break; case ORB_FUN_RST: sbp_busy_timeout(sdev); break; case ORB_FUN_LUR: case ORB_FUN_ATA: case ORB_FUN_ATS: sbp_agent_reset(sdev); break; default: sbp_show_sdev_info(sdev, 2); printf("unknown function %d\n", orb_fun); break; } sbp_mgm_orb(sdev, ORB_FUN_RUNQUEUE, NULL); break; case OCB_ACT_CMD: if(ocb->ccb != NULL){ union ccb *ccb; /* u_int32_t *ld; ld = ocb->ccb->csio.data_ptr; if(ld != NULL && ocb->ccb->csio.dxfer_len != 0) printf("ptr %08x %08x %08x %08x\n", ld[0], ld[1], ld[2], ld[3]); else printf("ptr NULL\n"); printf("len %d\n", sbp_status->len); */ ccb = ocb->ccb; if(sbp_status->len > 1){ sbp_scsi_status(sbp_status, ocb); }else{ if(sbp_status->resp != ORB_RES_CMPL){ ccb->ccb_h.status = CAM_REQ_CMP_ERR; }else{ ccb->ccb_h.status = CAM_REQ_CMP; } } /* fix up inq data */ if (ccb->csio.cdb_io.cdb_bytes[0] == INQUIRY) sbp_fix_inq_data(ocb); xpt_done(ccb); } break; default: break; } } - sbp_free_ocb(sbp, ocb); + sbp_free_ocb(sdev, ocb); done: if (reset_agent) sbp_agent_reset(sdev); +done0: /* 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. * * XXX fwohci.c and firewire.c should inform event_code such as * ack_complete or ack_pending to upper driver. */ #if NEED_RESPONSE - xfer->send.buf = malloc(12, M_SBP, M_NOWAIT | M_ZERO); - xfer->send.len = 12; xfer->send.off = 0; sfp = (struct fw_pkt *)xfer->send.buf; sfp->mode.wres.dst = rfp->mode.wreqb.src; - xfer->dst = ntohs(sfp->mode.wres.dst); + xfer->dst = sfp->mode.wres.dst; xfer->spd = min(sdev->target->fwdev->speed, max_speed); xfer->act.hand = sbp_loginres_callback; xfer->retry_req = fw_asybusy; sfp->mode.wres.tlrt = rfp->mode.wreqb.tlrt; sfp->mode.wres.tcode = FWTCODE_WRES; sfp->mode.wres.rtcode = 0; sfp->mode.wres.pri = 0; fw_asyreq(xfer->fc, -1, xfer); #else - fw_xfer_free(xfer); + /* recycle */ + xfer->recv.len = SBP_RECV_LEN; + STAILQ_INSERT_TAIL(&sbp->fwb.xferlist, xfer, link); #endif return; } static void sbp_recv(struct fw_xfer *xfer) { int s; s = splcam(); sbp_recv1(xfer); splx(s); } /* * sbp_attach() */ static int sbp_attach(device_t dev) { struct sbp_softc *sbp; struct cam_devq *devq; struct fw_xfer *xfer; int i, s, error; SBP_DEBUG(0) printf("sbp_attach (cold=%d)\n", cold); END_DEBUG if (cold) sbp_cold ++; sbp = ((struct sbp_softc *)device_get_softc(dev)); bzero(sbp, sizeof(struct sbp_softc)); sbp->fd.dev = dev; sbp->fd.fc = device_get_ivars(dev); -#define SBP_SEG_MAX 0x8000 - error = bus_dma_tag_create(/*parent*/NULL, /*alignment*/1, + error = bus_dma_tag_create(/*parent*/sbp->fd.fc->dmat, + /* XXX shoud be 4 for sane backend? */ + /*alignment*/1, /*boundary*/0, /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, /*highaddr*/BUS_SPACE_MAXADDR, /*filter*/NULL, /*filterarg*/NULL, /*maxsize*/0x100000, /*nsegments*/SBP_IND_MAX, /*maxsegsz*/SBP_SEG_MAX, /*flags*/BUS_DMA_ALLOCNOW, &sbp->dmat); if (error != 0) { printf("sbp_attach: Could not allocate DMA tag " "- error %d\n", error); return (ENOMEM); } devq = cam_simq_alloc(/*maxopenings*/SBP_NUM_OCB); if (devq == NULL) return (ENXIO); for( i = 0 ; i < SBP_NUM_TARGETS ; i++){ sbp->targets[i].fwdev = NULL; sbp->targets[i].luns = NULL; } sbp->sim = cam_sim_alloc(sbp_action, sbp_poll, "sbp", sbp, device_get_unit(dev), /*untagged*/ 1, /*tagged*/ SBP_QUEUE_LEN, devq); if (sbp->sim == NULL) { cam_simq_free(devq); return (ENXIO); } - sbp->ocb = (struct sbp_ocb *) contigmalloc( - sizeof (struct sbp_ocb) * SBP_NUM_OCB, - M_SBP, M_NOWAIT, 0x10000, 0xffffffff, PAGE_SIZE, 0ul); - bzero(sbp->ocb, sizeof (struct sbp_ocb) * SBP_NUM_OCB); - if (sbp->ocb == NULL) { - printf("sbp0: ocb alloction failure\n"); - return (ENOMEM); - } - - STAILQ_INIT(&sbp->free_ocbs); - for (i = 0; i < SBP_NUM_OCB; i++) { - sbp_free_ocb(sbp, &sbp->ocb[i]); - } - if (xpt_bus_register(sbp->sim, /*bus*/0) != CAM_SUCCESS) goto fail; if (xpt_create_path(&sbp->path, xpt_periph, cam_sim_path(sbp->sim), CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) goto fail; - xfer = fw_xfer_alloc(M_SBP); - xfer->act.hand = sbp_recv; - xfer->act_type = FWACT_XFER; -#if NEED_RESPONSE - xfer->fc = sbp->fd.fc; -#endif - xfer->sc = (caddr_t)sbp; - 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.xfer = xfer; + 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 + xfer->fc = sbp->fd.fc; +#endif + xfer->sc = (caddr_t)sbp; + STAILQ_INSERT_TAIL(&sbp->fwb.xferlist, xfer, link); + } fw_bindadd(sbp->fd.fc, &sbp->fwb); + sbp->fd.post_busreset = sbp_post_busreset; sbp->fd.post_explore = sbp_post_explore; if (sbp->fd.fc->status != -1) { s = splfw(); sbp_post_explore((void *)sbp); splx(s); } return (0); fail: cam_sim_free(sbp->sim, /*free_devq*/TRUE); - contigfree(sbp->ocb, sizeof (struct sbp_ocb) * SBP_NUM_OCB, M_SBP); return (ENXIO); } static int sbp_logout_all(struct sbp_softc *sbp) { struct sbp_target *target; struct sbp_dev *sdev; int i, j; SBP_DEBUG(0) printf("sbp_logout_all\n"); END_DEBUG for (i = 0 ; i < SBP_NUM_TARGETS ; i ++) { target = &sbp->targets[i]; if (target->luns == NULL) continue; for (j = 0; j < target->num_lun; j++) { sdev = &target->luns[j]; + callout_stop(&sdev->login_callout); if (sdev->status >= SBP_DEV_TOATTACH && sdev->status <= SBP_DEV_ATTACHED) sbp_mgm_orb(sdev, ORB_FUN_LGO, NULL); } } + return 0; } static int sbp_shutdown(device_t dev) { struct sbp_softc *sbp = ((struct sbp_softc *)device_get_softc(dev)); sbp_logout_all(sbp); return (0); } 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; - int i; + struct sbp_target *target; + struct sbp_dev *sdev; + struct fw_xfer *xfer, *next; + int i, j; SBP_DEBUG(0) printf("sbp_detach\n"); END_DEBUG -#if 0 - /* bus reset for logout */ - sbp->fd.post_explore = NULL; - fc->ibr(fc); -#endif - + for (i = 0; i < SBP_NUM_TARGETS; i ++) sbp_cam_detach_target(&sbp->targets[i]); xpt_free_path(sbp->path); xpt_bus_deregister(cam_sim_path(sbp->sim)); 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 (xfer = STAILQ_FIRST(&sbp->fwb.xferlist); + xfer != NULL; xfer = next) { + next = STAILQ_NEXT(xfer, link); + fw_xfer_free(xfer); + } + STAILQ_INIT(&sbp->fwb.xferlist); fw_bindremove(fc, &sbp->fwb); - contigfree(sbp->ocb, sizeof (struct sbp_ocb) * SBP_NUM_OCB, M_SBP); + bus_dma_tag_destroy(sbp->dmat); - for (i = 0; i < SBP_NUM_TARGETS; i ++) - if (sbp->targets[i].luns != NULL) - free(sbp->targets[i].luns, M_SBP); - return (0); } static void sbp_cam_detach_target(struct sbp_target *target) { - int i; struct sbp_dev *sdev; + int i; if (target->luns != NULL) { SBP_DEBUG(0) printf("sbp_detach_target %d\n", target->target_id); END_DEBUG callout_stop(&target->scan_callout); - callout_stop(&target->mgm_ocb_timeout); for (i = 0; i < target->num_lun; i++) { sdev = &target->luns[i]; - callout_stop(&sdev->login_callout); - if (sdev->status == SBP_DEV_RESET || - sdev->status == SBP_DEV_DEAD) + if (sdev->status == SBP_DEV_DEAD) continue; + if (sdev->status == SBP_DEV_RESET) + continue; if (sdev->path) { 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_timeout(void *arg) { struct sbp_ocb *ocb = (struct sbp_ocb *)arg; struct sbp_dev *sdev = ocb->sdev; sbp_show_sdev_info(sdev, 2); printf("request timeout ... "); if (ocb->flags == OCB_ACT_MGM) { printf("management ORB\n"); /* XXX just ignore for now */ sdev->target->mgm_ocb_cur = NULL; - sbp_free_ocb(sdev->target->sbp, ocb); + sbp_free_ocb(sdev, ocb); sbp_mgm_orb(sdev, ORB_FUN_RUNQUEUE, NULL); return; } xpt_freeze_devq(sdev->path, 1); sdev->freeze ++; sbp_abort_all_ocbs(sdev, CAM_CMD_TIMEOUT); if (sdev->flags & SBP_DEV_TIMEOUT) { -#if 0 - struct firewire_comm *fc; - - printf("bus reset\n"); - fc = sdev->target->sbp->fd.fc; - fc->ibr(fc); - sdev->status == SBP_DEV_RETRY; -#else printf("target reset\n"); sbp_mgm_orb(sdev, ORB_FUN_RST, NULL); -#endif sdev->flags &= ~SBP_DEV_TIMEOUT; } else { printf("agent reset\n"); sdev->flags |= SBP_DEV_TIMEOUT; sbp_agent_reset(sdev); } return; } static void sbp_action1(struct cam_sim *sim, union ccb *ccb) { struct sbp_softc *sbp = (struct sbp_softc *)sim->softc; struct sbp_target *target = NULL; struct sbp_dev *sdev = NULL; /* target:lun -> sdev mapping */ if (sbp != NULL && ccb->ccb_h.target_id != CAM_TARGET_WILDCARD && ccb->ccb_h.target_id < SBP_NUM_TARGETS) { target = &sbp->targets[ccb->ccb_h.target_id]; 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->status != SBP_DEV_PROBE) sdev = NULL; } } SBP_DEBUG(1) if (sdev == NULL) printf("invalid target %d lun %d\n", ccb->ccb_h.target_id, ccb->ccb_h.target_lun); END_DEBUG switch (ccb->ccb_h.func_code) { case XPT_SCSI_IO: case XPT_RESET_DEV: case XPT_GET_TRAN_SETTINGS: case XPT_SET_TRAN_SETTINGS: case XPT_CALC_GEOMETRY: if (sdev == NULL) { SBP_DEBUG(1) printf("%s:%d:%d:func_code 0x%04x: " "Invalid target (target needed)\n", device_get_nameunit(sbp->fd.dev), ccb->ccb_h.target_id, ccb->ccb_h.target_lun, ccb->ccb_h.func_code); END_DEBUG ccb->ccb_h.status = CAM_DEV_NOT_THERE; xpt_done(ccb); return; } break; case XPT_PATH_INQ: case XPT_NOOP: /* The opcodes sometimes aimed at a target (sc is valid), * sometimes aimed at the SIM (sc is invalid and target is * CAM_TARGET_WILDCARD) */ if (sbp == NULL && ccb->ccb_h.target_id != CAM_TARGET_WILDCARD) { SBP_DEBUG(0) printf("%s:%d:%d func_code 0x%04x: " "Invalid target (no wildcard)\n", device_get_nameunit(sbp->fd.dev), ccb->ccb_h.target_id, ccb->ccb_h.target_lun, ccb->ccb_h.func_code); END_DEBUG ccb->ccb_h.status = CAM_DEV_NOT_THERE; xpt_done(ccb); return; } break; default: /* XXX Hm, we should check the input parameters */ break; } switch (ccb->ccb_h.func_code) { case XPT_SCSI_IO: { struct ccb_scsiio *csio; struct sbp_ocb *ocb; - int s, speed; + int speed; void *cdb; csio = &ccb->csio; SBP_DEBUG(1) printf("%s:%d:%d XPT_SCSI_IO: " "cmd: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x" ", flags: 0x%02x, " "%db cmd/%db data/%db sense\n", device_get_nameunit(sbp->fd.dev), ccb->ccb_h.target_id, ccb->ccb_h.target_lun, csio->cdb_io.cdb_bytes[0], csio->cdb_io.cdb_bytes[1], csio->cdb_io.cdb_bytes[2], csio->cdb_io.cdb_bytes[3], csio->cdb_io.cdb_bytes[4], csio->cdb_io.cdb_bytes[5], csio->cdb_io.cdb_bytes[6], csio->cdb_io.cdb_bytes[7], csio->cdb_io.cdb_bytes[8], csio->cdb_io.cdb_bytes[9], ccb->ccb_h.flags & CAM_DIR_MASK, csio->cdb_len, csio->dxfer_len, csio->sense_len); END_DEBUG if(sdev == NULL){ ccb->ccb_h.status = CAM_DEV_NOT_THERE; xpt_done(ccb); return; } #if 0 /* if we are in probe stage, pass only probe commands */ if (sdev->status == SBP_DEV_PROBE) { char *name; name = xpt_path_periph(ccb->ccb_h.path)->periph_name; printf("probe stage, periph name: %s\n", name); if (strcmp(name, "probe") != 0) { ccb->ccb_h.status = CAM_REQUEUE_REQ; xpt_done(ccb); return; } } #endif - if ((ocb = sbp_get_ocb(sbp)) == NULL) { - s = splfw(); - sbp->flags |= SBP_RESOURCE_SHORTAGE; - splx(s); + if ((ocb = sbp_get_ocb(sdev)) == NULL) return; - } + ocb->flags = OCB_ACT_CMD; ocb->sdev = sdev; ocb->ccb = ccb; ccb->ccb_h.ccb_sdev_ptr = sdev; ocb->orb[0] = htonl(1 << 31); ocb->orb[1] = 0; ocb->orb[2] = htonl(((sbp->fd.fc->nodeid | FWLOCALBUS )<< 16) ); - ocb->orb[3] = htonl(vtophys(ocb->ind_ptr)); + ocb->orb[3] = htonl(ocb->bus_addr + IND_PTR_OFFSET); speed = min(target->fwdev->speed, max_speed); ocb->orb[4] = htonl(ORB_NOTIFY | ORB_CMD_SPD(speed) | ORB_CMD_MAXP(speed + 7)); if((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN){ ocb->orb[4] |= htonl(ORB_CMD_IN); } if (csio->ccb_h.flags & CAM_SCATTER_VALID) printf("sbp: CAM_SCATTER_VALID\n"); if (csio->ccb_h.flags & CAM_DATA_PHYS) printf("sbp: CAM_DATA_PHYS\n"); if (csio->ccb_h.flags & CAM_CDB_POINTER) 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); /* 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])); */ if (ccb->csio.dxfer_len > 0) { - int s; + int s, error; - if (bus_dmamap_create(sbp->dmat, 0, &ocb->dmamap)) { - printf("sbp_action1: cannot create dmamap\n"); - break; - } - s = splsoftvm(); - bus_dmamap_load(/*dma tag*/sbp->dmat, + error = bus_dmamap_load(/*dma tag*/sbp->dmat, /*dma map*/ocb->dmamap, ccb->csio.data_ptr, ccb->csio.dxfer_len, sbp_execute_ocb, ocb, /*flags*/0); splx(s); + if (error) + printf("sbp: bus_dmamap_load error %d\n", error); } else sbp_execute_ocb(ocb, NULL, 0, 0); break; } case XPT_CALC_GEOMETRY: { struct ccb_calc_geometry *ccg; u_int32_t size_mb; u_int32_t secs_per_cylinder; int extended = 1; ccg = &ccb->ccg; if (ccg->block_size == 0) { printf("sbp_action1: block_size is 0.\n"); ccb->ccb_h.status = CAM_REQ_INVALID; xpt_done(ccb); break; } SBP_DEBUG(1) printf("%s:%d:%d:%d:XPT_CALC_GEOMETRY: " "Volume size = %d\n", device_get_nameunit(sbp->fd.dev), cam_sim_path(sbp->sim), ccb->ccb_h.target_id, ccb->ccb_h.target_lun, ccg->volume_size); END_DEBUG size_mb = ccg->volume_size / ((1024L * 1024L) / ccg->block_size); if (size_mb >= 1024 && extended) { ccg->heads = 255; ccg->secs_per_track = 63; } else { ccg->heads = 64; ccg->secs_per_track = 32; } secs_per_cylinder = ccg->heads * ccg->secs_per_track; ccg->cylinders = ccg->volume_size / secs_per_cylinder; ccb->ccb_h.status = CAM_REQ_CMP; xpt_done(ccb); break; } case XPT_RESET_BUS: /* Reset the specified SCSI bus */ { SBP_DEBUG(1) printf("%s:%d:XPT_RESET_BUS: \n", device_get_nameunit(sbp->fd.dev), cam_sim_path(sbp->sim)); END_DEBUG ccb->ccb_h.status = CAM_REQ_INVALID; xpt_done(ccb); break; } case XPT_PATH_INQ: /* Path routing inquiry */ { struct ccb_pathinq *cpi = &ccb->cpi; SBP_DEBUG(1) printf("%s:%d:%d XPT_PATH_INQ:.\n", device_get_nameunit(sbp->fd.dev), ccb->ccb_h.target_id, ccb->ccb_h.target_lun); END_DEBUG cpi->version_num = 1; /* XXX??? */ cpi->hba_inquiry = PI_TAG_ABLE; cpi->target_sprt = 0; cpi->hba_misc = PIM_NOBUSRESET; cpi->hba_eng_cnt = 0; cpi->max_target = SBP_NUM_TARGETS - 1; cpi->max_lun = SBP_NUM_LUNS - 1; cpi->initiator_id = SBP_INITIATOR; cpi->bus_id = sim->bus_id; cpi->base_transfer_speed = 400 * 1000 / 8; strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); strncpy(cpi->hba_vid, "SBP", HBA_IDLEN); strncpy(cpi->dev_name, sim->sim_name, DEV_IDLEN); cpi->unit_number = sim->unit_number; cpi->ccb_h.status = CAM_REQ_CMP; xpt_done(ccb); break; } case XPT_GET_TRAN_SETTINGS: { struct ccb_trans_settings *cts = &ccb->cts; SBP_DEBUG(1) printf("%s:%d:%d XPT_GET_TRAN_SETTINGS:.\n", device_get_nameunit(sbp->fd.dev), ccb->ccb_h.target_id, ccb->ccb_h.target_lun); END_DEBUG /* Enable disconnect and tagged queuing */ cts->valid = CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID; cts->flags = CCB_TRANS_DISC_ENB | CCB_TRANS_TAG_ENB; cts->ccb_h.status = CAM_REQ_CMP; xpt_done(ccb); break; } case XPT_ABORT: ccb->ccb_h.status = CAM_UA_ABORT; xpt_done(ccb); break; case XPT_SET_TRAN_SETTINGS: /* XXX */ default: ccb->ccb_h.status = CAM_REQ_INVALID; xpt_done(ccb); break; } return; } static void sbp_action(struct cam_sim *sim, union ccb *ccb) { int s; s = splfw(); sbp_action1(sim, ccb); splx(s); } static void sbp_execute_ocb(void *arg, bus_dma_segment_t *segments, int seg, int error) { int i; struct sbp_ocb *ocb; struct sbp_ocb *prev; - union ccb *ccb; bus_dma_segment_t *s; if (error) printf("sbp_execute_ocb: error=%d\n", error); ocb = (struct sbp_ocb *)arg; + +SBP_DEBUG(1) + printf("sbp_execute_ocb: seg %d", seg); + for (i = 0; i < seg; i++) +#if __FreeBSD_version >= 500000 + printf(", %tx:%zd", segments[i].ds_addr, +#else + printf(", %x:%d", segments[i].ds_addr, +#endif + segments[i].ds_len); + printf("\n"); +END_DEBUG + if (seg == 1) { /* direct pointer */ s = &segments[0]; if (s->ds_len > SBP_SEG_MAX) panic("ds_len > SBP_SEG_MAX, fix busdma code"); ocb->orb[3] = htonl(s->ds_addr); ocb->orb[4] |= htonl(s->ds_len); } else if(seg > 1) { /* page table */ -SBP_DEBUG(1) - printf("sbp_execute_ocb: seg %d", seg); - for (i = 0; i < seg; i++) -#if __FreeBSD_version >= 500000 - printf(", %tx:%zd", segments[i].ds_addr, -#else - printf(", %x:%d", segments[i].ds_addr, -#endif - segments[i].ds_len); - printf("\n"); -END_DEBUG for (i = 0; i < seg; i++) { s = &segments[i]; SBP_DEBUG(0) /* XXX LSI Logic "< 16 byte" bug might be hit */ if (s->ds_len < 16) printf("sbp_execute_ocb: warning, " #if __FreeBSD_version >= 500000 "segment length(%zd) is less than 16." #else "segment length(%d) is less than 16." #endif "(seg=%d/%d)\n", s->ds_len, i+1, seg); END_DEBUG if (s->ds_len > SBP_SEG_MAX) panic("ds_len > SBP_SEG_MAX, fix busdma code"); ocb->ind_ptr[i].hi = htonl(s->ds_len << 16); ocb->ind_ptr[i].lo = htonl(s->ds_addr); } ocb->orb[4] |= htonl(ORB_CMD_PTBL | seg); } - ccb = ocb->ccb; + if (seg > 0) + bus_dmamap_sync(ocb->sdev->target->sbp->dmat, ocb->dmamap, + (ntohl(ocb->orb[4]) & ORB_CMD_IN) ? + BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); prev = sbp_enqueue_ocb(ocb->sdev, ocb); + fwdma_sync(&ocb->sdev->dma, BUS_DMASYNC_PREWRITE); if (prev == NULL) sbp_orb_pointer(ocb->sdev, ocb); } static void sbp_poll(struct cam_sim *sim) { /* should call fwohci_intr? */ return; } static struct sbp_ocb * sbp_dequeue_ocb(struct sbp_dev *sdev, struct sbp_status *sbp_status) { struct sbp_ocb *ocb; struct sbp_ocb *next; 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); #if __FreeBSD_version >= 500000 printf("orb: 0x%tx next: 0x%x, flags %x\n", #else printf("orb: 0x%x next: 0x%lx, flags %x\n", #endif - vtophys(&ocb->orb[0]), ntohl(ocb->orb[1]), flags); + ocb->bus_addr, ntohl(ocb->orb[1]), flags); END_DEBUG if (OCB_MATCH(ocb, sbp_status)) { /* found */ STAILQ_REMOVE(&sdev->ocbs, ocb, sbp_ocb, ocb); if (ocb->ccb != NULL) untimeout(sbp_timeout, (caddr_t)ocb, ocb->ccb->ccb_h.timeout_ch); - if (ocb->dmamap != NULL) { - bus_dmamap_destroy(sdev->target->sbp->dmat, - ocb->dmamap); - ocb->dmamap = NULL; + if (ntohl(ocb->orb[4]) & 0xffff) { + bus_dmamap_sync(sdev->target->sbp->dmat, + ocb->dmamap, + (ntohl(ocb->orb[4]) & ORB_CMD_IN) ? + BUS_DMASYNC_POSTREAD : + BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(sdev->target->sbp->dmat, + ocb->dmamap); } if (next != NULL && sbp_status->src == 1) sbp_orb_pointer(sdev, next); break; } else order ++; } splx(s); SBP_DEBUG(0) if (ocb && order > 0) { sbp_show_sdev_info(sdev, 2); printf("unordered execution order:%d\n", order); } END_DEBUG return (ocb); } static struct sbp_ocb * sbp_enqueue_ocb(struct sbp_dev *sdev, struct sbp_ocb *ocb) { int s = splfw(); struct sbp_ocb *prev; SBP_DEBUG(2) sbp_show_sdev_info(sdev, 2); #if __FreeBSD_version >= 500000 - printf("sbp_enqueue_ocb orb=0x%tx in physical memory\n", vtophys(&ocb->orb[0])); + printf("sbp_enqueue_ocb orb=0x%tx in physical memory\n", ocb->bus_addr); #else - printf("sbp_enqueue_ocb orb=0x%x in physical memory\n", vtophys(&ocb->orb[0])); + printf("sbp_enqueue_ocb orb=0x%x in physical memory\n", ocb->bus_addr); #endif END_DEBUG prev = STAILQ_LAST(&sdev->ocbs, sbp_ocb, ocb); STAILQ_INSERT_TAIL(&sdev->ocbs, ocb, ocb); if (ocb->ccb != NULL) 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 __FreeBSD_version >= 500000 - printf("linking chain 0x%tx -> 0x%tx\n", vtophys(&prev->orb[0]), + printf("linking chain 0x%tx -> 0x%tx\n", prev->bus_addr, #else - printf("linking chain 0x%x -> 0x%x\n", vtophys(&prev->orb[0]), + printf("linking chain 0x%x -> 0x%x\n", prev->bus_addr, #endif - vtophys(&ocb->orb[0])); + ocb->bus_addr); END_DEBUG - prev->orb[1] = htonl(vtophys(&ocb->orb[0])); + prev->orb[1] = htonl(ocb->bus_addr); prev->orb[0] = 0; } splx(s); return prev; } static struct sbp_ocb * -sbp_get_ocb(struct sbp_softc *sbp) +sbp_get_ocb(struct sbp_dev *sdev) { struct sbp_ocb *ocb; int s = splfw(); - ocb = STAILQ_FIRST(&sbp->free_ocbs); + ocb = STAILQ_FIRST(&sdev->free_ocbs); if (ocb == NULL) { printf("ocb shortage!!!\n"); return NULL; } - STAILQ_REMOVE_HEAD(&sbp->free_ocbs, ocb); + STAILQ_REMOVE_HEAD(&sdev->free_ocbs, ocb); splx(s); ocb->ccb = NULL; return (ocb); } static void -sbp_free_ocb(struct sbp_softc *sbp, struct sbp_ocb *ocb) +sbp_free_ocb(struct sbp_dev *sdev, struct sbp_ocb *ocb) { -#if 0 /* XXX make sure that ocb has ccb */ - if ((sbp->flags & SBP_RESOURCE_SHORTAGE) != 0 && - (ocb->ccb->ccb_h.status & CAM_RELEASE_SIMQ) == 0) { - ocb->ccb->ccb_h.status |= CAM_RELEASE_SIMQ; - sbp->flags &= ~SBP_RESOURCE_SHORTAGE; - } -#else - if ((sbp->flags & SBP_RESOURCE_SHORTAGE) != 0) - sbp->flags &= ~SBP_RESOURCE_SHORTAGE; -#endif ocb->flags = 0; ocb->ccb = NULL; - STAILQ_INSERT_TAIL(&sbp->free_ocbs, ocb, ocb); + STAILQ_INSERT_TAIL(&sdev->free_ocbs, ocb, ocb); } static void sbp_abort_ocb(struct sbp_ocb *ocb, int status) { struct sbp_dev *sdev; sdev = ocb->sdev; -SBP_DEBUG(1) +SBP_DEBUG(0) sbp_show_sdev_info(sdev, 2); #if __FreeBSD_version >= 500000 printf("sbp_abort_ocb 0x%tx\n", #else printf("sbp_abort_ocb 0x%x\n", #endif - vtophys(&ocb->orb[0])); + ocb->bus_addr); +END_DEBUG +SBP_DEBUG(1) if (ocb->ccb != NULL) sbp_print_scsi_cmd(ocb); END_DEBUG + if (ntohl(ocb->orb[4]) & 0xffff) { + bus_dmamap_sync(sdev->target->sbp->dmat, ocb->dmamap, + (ntohl(ocb->orb[4]) & ORB_CMD_IN) ? + BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(sdev->target->sbp->dmat, ocb->dmamap); + } if (ocb->ccb != NULL) { untimeout(sbp_timeout, (caddr_t)ocb, ocb->ccb->ccb_h.timeout_ch); ocb->ccb->ccb_h.status = status; xpt_done(ocb->ccb); } - if (ocb->dmamap != NULL) { - bus_dmamap_destroy(sdev->target->sbp->dmat, ocb->dmamap); - ocb->dmamap = NULL; - } - sbp_free_ocb(sdev->target->sbp, ocb); + sbp_free_ocb(sdev, ocb); } static void sbp_abort_all_ocbs(struct sbp_dev *sdev, int status) { int s; struct sbp_ocb *ocb, *next; STAILQ_HEAD(, sbp_ocb) temp; s = splfw(); bcopy(&sdev->ocbs, &temp, sizeof(temp)); STAILQ_INIT(&sdev->ocbs); for (ocb = STAILQ_FIRST(&temp); ocb != NULL; ocb = next) { next = STAILQ_NEXT(ocb, ocb); sbp_abort_ocb(ocb, status); } splx(s); } static devclass_t sbp_devclass; static device_method_t sbp_methods[] = { /* device interface */ DEVMETHOD(device_identify, sbp_identify), DEVMETHOD(device_probe, sbp_probe), DEVMETHOD(device_attach, sbp_attach), DEVMETHOD(device_detach, sbp_detach), DEVMETHOD(device_shutdown, sbp_shutdown), { 0, 0 } }; static driver_t sbp_driver = { "sbp", sbp_methods, sizeof(struct sbp_softc), }; DRIVER_MODULE(sbp, firewire, sbp_driver, sbp_devclass, 0, 0); MODULE_VERSION(sbp, 1); MODULE_DEPEND(sbp, firewire, 1, 1, 1); MODULE_DEPEND(sbp, cam, 1, 1, 1); Index: head/sys/modules/firewire/Makefile.inc =================================================================== --- head/sys/modules/firewire/Makefile.inc (revision 113583) +++ head/sys/modules/firewire/Makefile.inc (revision 113584) @@ -1,3 +1,4 @@ # $FreeBSD$ +#CFLAGS+=-g .include "../Makefile.inc" Index: head/sys/modules/firewire/firewire/Makefile =================================================================== --- head/sys/modules/firewire/firewire/Makefile (revision 113583) +++ head/sys/modules/firewire/firewire/Makefile (revision 113584) @@ -1,15 +1,15 @@ # $FreeBSD$ # Makefile for the IEEE1394 OHCI chipset .PATH: ${.CURDIR}/../../../dev/firewire KMOD= firewire SRCS = bus_if.h device_if.h pci_if.h \ firewire.c firewire.h firewire_phy.h firewirereg.h \ fwohci.c fwohci_pci.c fwohcireg.h fwohcivar.h \ iec13213.h iec68113.h \ - fwcrom.c fwdev.c fwmem.c fwmem.h + fwcrom.c fwdev.c fwmem.c fwmem.h fwdma.c fwdma.h .include Index: head/sys/modules/firewire/fwe/Makefile =================================================================== --- head/sys/modules/firewire/fwe/Makefile (revision 113583) +++ head/sys/modules/firewire/fwe/Makefile (revision 113584) @@ -1,14 +1,15 @@ # $FreeBSD$ # Makefile for the fwe(4) module (Ethernet over IEEE1394) .PATH: ${.CURDIR}/../../../dev/firewire KMOD = if_fwe SRCS = bus_if.h device_if.h \ opt_inet.h \ if_fwe.c if_fwevar.h \ firewire.h firewirereg.h +#CFLAGS += -DDEVICE_POLLING .include Index: head/usr.sbin/fwcontrol/fwcontrol.c =================================================================== --- head/usr.sbin/fwcontrol/fwcontrol.c (revision 113583) +++ head/usr.sbin/fwcontrol/fwcontrol.c (revision 113584) @@ -1,425 +1,437 @@ /* * Copyright (C) 2002 * Hidetoshi Shimokawa. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * * This product includes software developed by Hidetoshi Shimokawa. * * 4. Neither the name of the author nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern int dvrecv(int, char *, char, int); extern int dvsend(int, char *, char, int); static void usage(void) { fprintf(stderr, "fwcontrol [-g gap_count] [-b pri_req] [-c node]" " [-r] [-t] [-d node] [-l file] [-R file] [-S file]\n"); fprintf(stderr, "\t-g: broadcast gap_count by phy_config packet\n"); fprintf(stderr, "\t-b: set PRIORITY_BUDGET register on all supported nodes\n"); fprintf(stderr, "\t-c: read configuration ROM\n"); fprintf(stderr, "\t-r: bus reset\n"); fprintf(stderr, "\t-t: read topology map\n"); fprintf(stderr, "\t-d: hex dump of configuration ROM\n"); fprintf(stderr, "\t-l: load and parse hex dump file of configuration ROM\n"); fprintf(stderr, "\t-R: Receive DV stream\n"); fprintf(stderr, "\t-S: Send DV stream\n"); exit(0); } static struct fw_devlstreq * get_dev(int fd) { struct fw_devlstreq *data; data = (struct fw_devlstreq *)malloc(sizeof(struct fw_devlstreq)); if (data == NULL) err(1, "malloc"); if( ioctl(fd, FW_GDEVLST, data) < 0) { err(1, "ioctl"); } return data; } static void list_dev(int fd) { struct fw_devlstreq *data; struct fw_devinfo *devinfo; int i; data = get_dev(fd); printf("%d devices (info_len=%d)\n", data->n, data->info_len); printf("node EUI64 status\n"); for (i = 0; i < data->info_len; i++) { devinfo = &data->dev[i]; printf("%4d %08x%08x %6d\n", (devinfo->status || i == 0) ? devinfo->dst : -1, devinfo->eui.hi, devinfo->eui.lo, devinfo->status ); } free((void *)data); } static u_int32_t read_write_quad(int fd, struct fw_eui64 eui, u_int32_t addr_lo, int read, u_int32_t data) { struct fw_asyreq *asyreq; u_int32_t *qld, res; asyreq = (struct fw_asyreq *)malloc(sizeof(struct fw_asyreq_t) + 16); asyreq->req.len = 16; asyreq->req.type = FWASREQEUI; asyreq->req.dst.eui = eui; #if 0 asyreq->pkt.mode.rreqq.dst = htons(FWLOCALBUS | node); #endif asyreq->pkt.mode.rreqq.tlrt = 0; if (read) asyreq->pkt.mode.rreqq.tcode = FWTCODE_RREQQ; else asyreq->pkt.mode.rreqq.tcode = FWTCODE_WREQQ; - asyreq->pkt.mode.rreqq.dest_hi = htons(0xffff); - asyreq->pkt.mode.rreqq.dest_lo = htonl(addr_lo); + asyreq->pkt.mode.rreqq.dest_hi = 0xffff; + asyreq->pkt.mode.rreqq.dest_lo = addr_lo; qld = (u_int32_t *)&asyreq->pkt; if (!read) asyreq->pkt.mode.wreqq.data = data; if (ioctl(fd, FW_ASYREQ, asyreq) < 0) { err(1, "ioctl"); } res = qld[3]; free(asyreq); if (read) return ntohl(res); else return 0; } static void send_phy_config(int fd, int root_node, int gap_count) { struct fw_asyreq *asyreq; asyreq = (struct fw_asyreq *)malloc(sizeof(struct fw_asyreq_t) + 12); asyreq->req.len = 12; asyreq->req.type = FWASREQNODE; asyreq->pkt.mode.ld[0] = 0; asyreq->pkt.mode.ld[1] = 0; asyreq->pkt.mode.common.tcode = FWTCODE_PHY; if (root_node >= 0) - asyreq->pkt.mode.ld[1] |= htonl((root_node & 0x3f) << 24 | 1 << 23); + asyreq->pkt.mode.ld[1] |= (root_node & 0x3f) << 24 | 1 << 23; if (gap_count >= 0) - asyreq->pkt.mode.ld[1] |= htonl(1 << 22 | (gap_count & 0x3f) << 16); + asyreq->pkt.mode.ld[1] |= 1 << 22 | (gap_count & 0x3f) << 16; asyreq->pkt.mode.ld[2] = ~asyreq->pkt.mode.ld[1]; printf("send phy_config root_node=%d gap_count=%d\n", root_node, gap_count); if (ioctl(fd, FW_ASYREQ, asyreq) < 0) { err(1, "ioctl"); } } static void set_pri_req(int fd, int pri_req) { struct fw_devlstreq *data; struct fw_devinfo *devinfo; u_int32_t max, reg, old; int i; data = get_dev(fd); #define BUGET_REG 0xf0000218 for (i = 0; i < data->info_len; i++) { devinfo = &data->dev[i]; if (!devinfo->status) continue; reg = read_write_quad(fd, devinfo->eui, BUGET_REG, 1, 0); printf("%d %08x:%08x, %08x", devinfo->dst, devinfo->eui.hi, devinfo->eui.lo, reg); if (reg > 0 && pri_req >= 0) { old = (reg & 0x3f); max = (reg & 0x3f00) >> 8; if (pri_req > max) pri_req = max; printf(" 0x%x -> 0x%x\n", old, pri_req); read_write_quad(fd, devinfo->eui, BUGET_REG, 0, pri_req); } else { printf("\n"); } } free((void *)data); } static void parse_bus_info_block(u_int32_t *p, int info_len) { int i; for (i = 0; i < info_len; i++) { printf("bus_info%d: 0x%08x\n", i, *p++); } } static int get_crom(int fd, int node, void *crom_buf, int len) { struct fw_crom_buf buf; int i, error; struct fw_devlstreq *data; data = get_dev(fd); for (i = 0; i < data->info_len; i++) { if (data->dev[i].dst == node && data->dev[i].eui.lo != 0) break; } if (i == data->info_len) errx(1, "no such node %d.", node); else if (i == 0) errx(1, "node %d is myself.", node); else buf.eui = data->dev[i].eui; free((void *)data); buf.len = len; buf.ptr = crom_buf; if ((error = ioctl(fd, FW_GCROM, &buf)) < 0) { err(1, "ioctl"); } return error; } static void show_crom(u_int32_t *crom_buf) { int i; struct crom_context cc; char *desc, info[256]; static char *key_types = "ICLD"; struct csrreg *reg; struct csrdirectory *dir; struct csrhdr *hdr; + u_int16_t crc; - printf("first quad: 0x%08x\n", *crom_buf); + printf("first quad: 0x%08x ", *crom_buf); hdr = (struct csrhdr *)crom_buf; if (hdr->info_len == 1) { /* minimum ROM */ struct csrreg *reg; reg = (struct csrreg *)hdr; printf("verndor ID: 0x%06x\n", reg->val); return; } - printf("len: %d\n", hdr->crc_len); + printf("info_len=%d crc_len=%d crc=0x%04x", + hdr->info_len, hdr->crc_len, hdr->crc); + crc = crom_crc(crom_buf+1, hdr->crc_len); + if (crc == hdr->crc) + printf("(OK)\n"); + else + printf("(NG)\n"); parse_bus_info_block(crom_buf+1, hdr->info_len); crom_init_context(&cc, crom_buf); dir = cc.stack[0].dir; - printf("root_directory: len=0x%04x(%d) crc=0x%04x\n", + printf("root_directory: len=0x%04x(%d) crc=0x%04x", dir->crc_len, dir->crc_len, dir->crc); + crc = crom_crc((u_int32_t *)&dir->entry[0], dir->crc_len); + if (crc == dir->crc) + printf("(OK)\n"); + else + printf("(NG)\n"); if (dir->crc_len < 1) return; while (cc.depth >= 0) { desc = crom_desc(&cc, info, sizeof(info)); reg = crom_get(&cc); for (i = 0; i < cc.depth; i++) printf("\t"); printf("%02x(%c:%02x) %06x %s: %s\n", reg->key, key_types[(reg->key & CSRTYPE_MASK)>>6], reg->key & CSRKEY_MASK, reg->val, desc, info); crom_next(&cc); } } #define DUMP_FORMAT "%08x %08x %08x %08x %08x %08x %08x %08x\n" static void dump_crom(u_int32_t *p) { int len=1024, i; for (i = 0; i < len/(4*8); i ++) { printf(DUMP_FORMAT, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); p += 8; } } static void load_crom(char *filename, u_int32_t *p) { FILE *file; int len=1024, i; if ((file = fopen(filename, "r")) == NULL) err(1, "load_crom"); for (i = 0; i < len/(4*8); i ++) { fscanf(file, DUMP_FORMAT, p, p+1, p+2, p+3, p+4, p+5, p+6, p+7); p += 8; } } static void show_topology_map(int fd) { struct fw_topology_map *tmap; union fw_self_id sid; int i; static char *port_status[] = {" ", "-", "P", "C"}; static char *pwr_class[] = {" 0W", "15W", "30W", "45W", "-1W", "-2W", "-5W", "-9W"}; static char *speed[] = {"S100", "S200", "S400", "S800"}; tmap = malloc(sizeof(struct fw_topology_map)); if (tmap == NULL) return; if (ioctl(fd, FW_GTPMAP, tmap) < 0) { err(1, "ioctl"); } printf("crc_len: %d generation:%d node_count:%d sid_count:%d\n", tmap->crc_len, tmap->generation, tmap->node_count, tmap->self_id_count); printf("id link gap_cnt speed delay cIRM power port0 port1 port2" " ini more\n"); for (i = 0; i < tmap->crc_len - 2; i++) { sid = tmap->self_id[i]; if (sid.p0.sequel) { printf("%02d sequel packet\n", sid.p0.phy_id); continue; } printf("%02d %2d %2d %4s %d %d %3s" " %s %s %s %d %d\n", sid.p0.phy_id, sid.p0.link_active, sid.p0.gap_count, speed[sid.p0.phy_speed], sid.p0.phy_delay, sid.p0.contender, pwr_class[sid.p0.power_class], port_status[sid.p0.port0], port_status[sid.p0.port1], port_status[sid.p0.port2], sid.p0.initiated_reset, sid.p0.more_packets ); } free(tmap); } int main(int argc, char **argv) { char devname[256]; u_int32_t crom_buf[1024/4]; int fd, i, tmp, ch, len=1024; for (i = 0; i < 4; i++) { snprintf(devname, sizeof(devname), "/dev/fw%d", i); if ((fd = open(devname, O_RDWR)) >= 0) break; } if (fd < 0) err(1, "open"); if (argc < 2) { list_dev(fd); } while ((ch = getopt(argc, argv, "g:b:rtc:d:l:R:S:")) != -1) switch(ch) { case 'g': /* gap count */ tmp = strtol(optarg, NULL, 0); send_phy_config(fd, -1, tmp); break; case 'b': tmp = strtol(optarg, NULL, 0); set_pri_req(fd, tmp); break; case 'r': if(ioctl(fd, FW_IBUSRST, &tmp) < 0) err(1, "ioctl"); break; case 't': show_topology_map(fd); break; case 'c': tmp = strtol(optarg, NULL, 0); get_crom(fd, tmp, crom_buf, len); show_crom(crom_buf); break; case 'd': tmp = strtol(optarg, NULL, 0); get_crom(fd, tmp, crom_buf, len); dump_crom(crom_buf); break; case 'l': load_crom(optarg, crom_buf); show_crom(crom_buf); break; #define TAG (1<<6) #define CHANNEL 63 case 'R': dvrecv(fd, optarg, TAG | CHANNEL, -1); break; case 'S': dvsend(fd, optarg, TAG | CHANNEL, -1); break; default: usage(); } return 0; } Index: head/usr.sbin/fwcontrol/fwcrom.c =================================================================== --- head/usr.sbin/fwcontrol/fwcrom.c (revision 113583) +++ head/usr.sbin/fwcontrol/fwcrom.c (revision 113584) @@ -1,255 +1,502 @@ /* * Copyright (C) 2002 * Hidetoshi Shimokawa. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * * This product includes software developed by Hidetoshi Shimokawa. * * 4. Neither the name of the author nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include -#include -#include +#if defined(_KERNEL) || defined(TEST) +#include +#endif #ifdef _KERNEL #include #include #else #include #include #include #include #include #include #endif +#include +#include void crom_init_context(struct crom_context *cc, u_int32_t *p) { struct csrhdr *hdr; hdr = (struct csrhdr *)p; if (hdr->info_len == 1) { /* minimum ROM */ cc->depth = -1; } p += 1 + hdr->info_len; cc->depth = 0; cc->stack[0].dir = (struct csrdirectory *)p; cc->stack[0].index = 0; } struct csrreg * crom_get(struct crom_context *cc) { struct crom_ptr *ptr; ptr = &cc->stack[cc->depth]; return (&ptr->dir->entry[ptr->index]); } void crom_next(struct crom_context *cc) { struct crom_ptr *ptr; struct csrreg *reg; if (cc->depth < 0) return; reg = crom_get(cc); if ((reg->key & CSRTYPE_MASK) == CSRTYPE_D) { cc->depth ++; if (cc->depth > CROM_MAX_DEPTH) { printf("crom_next: too deep\n"); cc->depth --; goto again; } ptr = &cc->stack[cc->depth]; ptr->dir = (struct csrdirectory *) (reg + reg->val); ptr->index = 0; goto check; } again: ptr = &cc->stack[cc->depth]; ptr->index ++; check: if (ptr->index < ptr->dir->crc_len) return; if (cc->depth > 0) { cc->depth--; goto again; } /* no more data */ cc->depth = -1; } struct csrreg * crom_search_key(struct crom_context *cc, u_int8_t key) { struct csrreg *reg; while(cc->depth >= 0) { reg = crom_get(cc); if (reg->key == key) return reg; crom_next(cc); } return NULL; } void crom_parse_text(struct crom_context *cc, char *buf, int len) { struct csrreg *reg; struct csrtext *textleaf; u_int32_t *bp; int i, qlen; static char *nullstr = "(null)"; reg = crom_get(cc); if (reg->key != CROM_TEXTLEAF) { strncpy(buf, nullstr, len); return; } textleaf = (struct csrtext *)(reg + reg->val); /* XXX should check spec and type */ bp = (u_int32_t *)&buf[0]; qlen = textleaf->crc_len - 2; if (len < qlen * 4) qlen = len/4; for (i = 0; i < qlen; i ++) *bp++ = ntohl(textleaf->text[i]); /* make sure to terminate the string */ if (len <= qlen * 4) buf[len - 1] = 0; else buf[qlen * 4] = 0; } u_int16_t crom_crc(u_int32_t *ptr, int len) { int i, shift; u_int32_t data, sum, crc = 0; for (i = 0; i < len; i++) { data = ptr[i]; for (shift = 28; shift >= 0; shift -= 4) { sum = ((crc >> 12) ^ (data >> shift)) & 0xf; crc = (crc << 4) ^ (sum << 12) ^ (sum << 5) ^ sum; } crc &= 0xffff; } return((u_int16_t) crc); } #ifndef _KERNEL char * crom_desc(struct crom_context *cc, char *buf, int len) { struct csrreg *reg; struct csrdirectory *dir; char *desc; + u_int16_t crc; reg = crom_get(cc); switch (reg->key & CSRTYPE_MASK) { case CSRTYPE_I: snprintf(buf, len, "%d", reg->val); break; - case CSRTYPE_L: case CSRTYPE_C: snprintf(buf, len, "offset=0x%04x(%d)", reg->val, reg->val); break; + case CSRTYPE_L: + /* XXX fall through */ case CSRTYPE_D: dir = (struct csrdirectory *) (reg + reg->val); - snprintf(buf, len, "len=0x%04x(%d) crc=0x%04x", - dir->crc_len, dir->crc_len, dir->crc); + crc = crom_crc((u_int32_t *)&dir->entry[0], dir->crc_len); + len -= snprintf(buf, len, "len=%d crc=0x%04x", + dir->crc_len, dir->crc); + if (crc == dir->crc) + strncat(buf, "(OK) ", len); + else + strncat(buf, "(NG) ", len); + len -= 5; } switch (reg->key) { case 0x03: desc = "module_vendor_ID"; break; case 0x04: desc = "hardware_version"; break; case 0x0c: desc = "node_capabilities"; break; case 0x12: desc = "unit_spec_ID"; break; case 0x13: desc = "unit_sw_version"; break; case 0x14: desc = "logical_unit_number"; break; case 0x17: desc = "model_ID"; break; case 0x38: desc = "command_set_spec_ID"; break; case 0x39: desc = "command_set"; break; case 0x3a: desc = "unit_characteristics"; break; case 0x3b: desc = "command_set_revision"; break; case 0x3c: desc = "firmware_revision"; break; case 0x3d: desc = "reconnect_timeout"; break; case 0x54: desc = "management_agent"; break; case 0x81: desc = "text_leaf"; - crom_parse_text(cc, buf, len); + crom_parse_text(cc, buf + strlen(buf), len); break; case 0xd1: desc = "unit_directory"; break; case 0xd4: desc = "logical_unit_directory"; break; default: desc = "unknown"; } return desc; +} +#endif + +#if defined(_KERNEL) || defined(TEST) + +int +crom_add_quad(struct crom_chunk *chunk, u_int32_t entry) +{ + int index; + + index = chunk->data.crc_len; + if (index >= CROM_MAX_CHUNK_LEN - 1) { + printf("too large chunk %d\n", index); + return(-1); + } + chunk->data.buf[index] = entry; + chunk->data.crc_len++; + return(index); +} + +int +crom_add_entry(struct crom_chunk *chunk, int key, int val) +{ + struct csrreg *reg; + u_int32_t i; + + reg = (struct csrreg *)&i; + reg->key = key; + reg->val = val; + return(crom_add_quad(chunk, (u_int32_t) i)); +} + +int +crom_add_chunk(struct crom_src *src, struct crom_chunk *parent, + struct crom_chunk *child, int key) +{ + int index; + + if (parent == NULL) { + STAILQ_INSERT_TAIL(&src->chunk_list, child, link); + return(0); + } + + index = crom_add_entry(parent, key, 0); + if (index < 0) { + return(-1); + } + child->ref_chunk = parent; + child->ref_index = index; + STAILQ_INSERT_TAIL(&src->chunk_list, child, link); + return(index); +} + +int +crom_add_simple_text(struct crom_src *src, struct crom_chunk *parent, + struct crom_chunk *chunk, char *buf) +{ + struct csrtext *tl; + u_int32_t *p; + int len, i; + + len = strlen(buf); +#define MAX_TEXT ((CROM_MAX_CHUNK_LEN + 1) * 4 - sizeof(struct csrtext)) + if (len > MAX_TEXT) { + printf("text(%d) trancated to %d.\n", len, MAX_TEXT); + len = MAX_TEXT; + } + + tl = (struct csrtext *) &chunk->data; + tl->crc_len = roundup2(sizeof(struct csrtext) + len, 4) / 4; + tl->spec_id = 0; + tl->spec_type = 0; + tl->lang_id = 0; + p = (u_int32_t *) buf; + for (i = 0; i < roundup2(len, 4) / 4; i ++) + tl->text[i] = ntohl(*p++); + return (crom_add_chunk(src, parent, chunk, CROM_TEXTLEAF)); +} + +static int +crom_copy(u_int32_t *src, u_int32_t *dst, int *offset, int len, int maxlen) +{ + if (*offset + len > maxlen) { + printf("Config. ROM is too large for the buffer\n"); + return(-1); + } + bcopy(src, (char *)(dst + *offset), len * sizeof(u_int32_t)); + *offset += len; + return(0); +} + +int +crom_load(struct crom_src *src, u_int32_t *buf, int maxlen) +{ + struct crom_chunk *chunk, *parent; + struct csrhdr *hdr; +#if 0 + u_int32_t *ptr; +#endif + int count, offset; + int len; + + offset = 0; + /* Determine offset */ + STAILQ_FOREACH(chunk, &src->chunk_list, link) { + chunk->offset = offset; + /* Assume the offset of the parent is already known */ + parent = chunk->ref_chunk; + if (parent != NULL) { + struct csrreg *reg; + reg = (struct csrreg *) + &parent->data.buf[chunk->ref_index]; + reg->val = offset - + (parent->offset + 1 + chunk->ref_index); + } + offset += 1 + chunk->data.crc_len; + } + + /* Calculate CRC and dump to the buffer */ + len = 1 + src->hdr.info_len; + count = 0; + if (crom_copy((u_int32_t *)&src->hdr, buf, &count, len, maxlen) < 0) + return(-1); + STAILQ_FOREACH(chunk, &src->chunk_list, link) { + chunk->data.crc = + crom_crc(&chunk->data.buf[0], chunk->data.crc_len); + + len = 1 + chunk->data.crc_len; + if (crom_copy((u_int32_t *)&chunk->data, buf, + &count, len, maxlen) < 0) + return(-1); + } + hdr = (struct csrhdr *)buf; + hdr->crc_len = count - 1; + hdr->crc = crom_crc(buf + 1, hdr->crc_len); + +#if 0 + /* byte swap */ + ptr = buf; + for (i = 0; i < count; i ++) { + *ptr = htonl(*ptr); + ptr++; + } +#endif + + return(count); +} +#endif + +#ifdef TEST +int +main () { + struct crom_src src; + struct crom_chunk root,unit1,unit2,unit3; + struct crom_chunk text1,text2,text3,text4,text5,text6,text7; + u_int32_t buf[256], *p; + int i; + + bzero(&src, sizeof(src)); + bzero(&root, sizeof(root)); + bzero(&unit1, sizeof(unit1)); + bzero(&unit2, sizeof(unit2)); + bzero(&unit3, sizeof(unit3)); + bzero(&text1, sizeof(text1)); + bzero(&text2, sizeof(text2)); + bzero(&text3, sizeof(text3)); + bzero(&text3, sizeof(text4)); + bzero(&text3, sizeof(text5)); + bzero(&text3, sizeof(text6)); + bzero(&text3, sizeof(text7)); + bzero(buf, sizeof(buf)); + + /* BUS info sample */ + src.hdr.info_len = 4; + src.businfo.bus_name = CSR_BUS_NAME_IEEE1394; + src.businfo.eui64.hi = 0x11223344; + src.businfo.eui64.lo = 0x55667788; + src.businfo.link_spd = FWSPD_S400; + src.businfo.generation = 0; + src.businfo.max_rom = MAXROM_4; + src.businfo.max_rec = 10; + src.businfo.cyc_clk_acc = 100; + src.businfo.pmc = 0; + src.businfo.bmc = 1; + src.businfo.isc = 1; + src.businfo.cmc = 1; + src.businfo.irmc = 1; + STAILQ_INIT(&src.chunk_list); + + /* Root directory */ + crom_add_chunk(&src, NULL, &root, 0); + crom_add_entry(&root, CSRKEY_NCAP, 0x123456); + /* private company_id */ + crom_add_entry(&root, CSRKEY_VENDOR, 0xacde48); + + crom_add_simple_text(&src, &root, &text1, "FreeBSD"); + crom_add_entry(&root, CSRKEY_HW, __FreeBSD_version); + crom_add_simple_text(&src, &root, &text2, "FreeBSD-5"); + + /* SBP unit directory */ + crom_add_chunk(&src, &root, &unit1, CROM_UDIR); + crom_add_entry(&unit1, CSRKEY_SPEC, CSRVAL_ANSIT10); + crom_add_entry(&unit1, CSRKEY_VER, CSRVAL_T10SBP2); + crom_add_entry(&unit1, CSRKEY_COM_SPEC, CSRVAL_ANSIT10); + crom_add_entry(&unit1, CSRKEY_COM_SET, CSRVAL_SCSI); + /* management_agent */ + crom_add_entry(&unit1, CROM_MGM, 0x1000); + crom_add_entry(&unit1, CSRKEY_UNIT_CH, (10<<8) | 8); + /* Device type and LUN */ + crom_add_entry(&unit1, CROM_LUN, 0); + crom_add_entry(&unit1, CSRKEY_MODEL, 1); + crom_add_simple_text(&src, &unit1, &text3, "scsi_target"); + + /* RFC2734 IPv4 over IEEE1394 */ + crom_add_chunk(&src, &root, &unit2, CROM_UDIR); + crom_add_entry(&unit2, CSRKEY_SPEC, CSRVAL_IETF); + crom_add_simple_text(&src, &unit2, &text4, "IANA"); + crom_add_entry(&unit2, CSRKEY_VER, 1); + crom_add_simple_text(&src, &unit2, &text5, "IPv4"); + + /* RFC3146 IPv6 over IEEE1394 */ + crom_add_chunk(&src, &root, &unit3, CROM_UDIR); + crom_add_entry(&unit3, CSRKEY_SPEC, CSRVAL_IETF); + crom_add_simple_text(&src, &unit3, &text6, "IANA"); + crom_add_entry(&unit3, CSRKEY_VER, 2); + crom_add_simple_text(&src, &unit3, &text7, "IPv6"); + + crom_load(&src, buf, 256); + p = buf; +#define DUMP_FORMAT "%08x %08x %08x %08x %08x %08x %08x %08x\n" + for (i = 0; i < 256/8; i ++) { + printf(DUMP_FORMAT, + p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); + p += 8; + } + return(0); } #endif Index: head/usr.sbin/fwcontrol/fwdv.c =================================================================== --- head/usr.sbin/fwcontrol/fwdv.c (revision 113583) +++ head/usr.sbin/fwcontrol/fwdv.c (revision 113584) @@ -1,410 +1,410 @@ /* * Copyright (C) 2003 * Hidetoshi Shimokawa. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * * This product includes software developed by Hidetoshi Shimokawa. * * 4. Neither the name of the author nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #include #include #include #include #if __FreeBSD_version >= 500000 #include #endif #include #include #include #include #include #include #include #include #include #define DEBUG 0 #define FIX_FRAME 1 struct frac { int n,d; }; struct frac frame_cycle[2] = { {8000*100, 2997}, /* NTSC 8000 cycle / 29.97 Hz */ {320, 1}, /* PAL 8000 cycle / 25 Hz */ }; int npackets[] = { 250 /* NTSC */, 300 /* PAL */ }; struct frac pad_rate[2] = { {203, 2997}, /* = (8000 - 29.97 * 250)/(29.97 * 250) */ {1, 15}, /* = (8000 - 25 * 300)/(25 * 300) */ }; char *system_name[] = {"NTSC", "PAL"}; int frame_rate[] = {30, 25}; #define PSIZE 512 #define DSIZE 480 #define NCHUNK 8 #define NPACKET_R 256 #define NPACKET_T 255 #define TNBUF 100 /* XXX too large value causes block noise */ #define NEMPTY 10 /* depends on TNBUF */ #define RBUFSIZE (PSIZE * NPACKET_R) #define MAXBLOCKS (300) #define CYCLE_FRAC 0xc00 int dvrecv(int d, char *filename, char ich, int count) { struct fw_isochreq isoreq; struct fw_isobufreq bufreq; struct dvdbc *dv; struct ciphdr *ciph; struct fw_pkt *pkt; char *pad, *buf; u_int32_t *ptr; int len, tlen, npad, fd, k, m, vec, system = -1, nb; int nblocks[] = {250 /* NTSC */, 300 /* PAL */}; struct iovec wbuf[NPACKET_R]; fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0660); buf = (char *)malloc(RBUFSIZE); pad = (char *)malloc(DSIZE*MAXBLOCKS); memset(pad, 0xff, DSIZE*MAXBLOCKS); bzero(wbuf, sizeof(wbuf)); bufreq.rx.nchunk = NCHUNK; bufreq.rx.npacket = NPACKET_R; bufreq.rx.psize = PSIZE; bufreq.tx.nchunk = 0; bufreq.tx.npacket = 0; bufreq.tx.psize = 0; if (ioctl(d, FW_SSTBUF, &bufreq) < 0) { err(1, "ioctl"); } isoreq.ch = ich & 0x3f; isoreq.tag = (ich >> 6) & 3; if( ioctl(d, FW_SRSTREAM, &isoreq) < 0) err(1, "ioctl"); k = m = 0; while (count <= 0 || k <= count) { #if 0 tlen = 0; while ((len = read(d, buf + tlen, PSIZE /* RBUFSIZE - tlen */)) > 0) { if (len < 0) { if (errno == EAGAIN) { fprintf(stderr, "(EAGAIN)\n"); fflush(stderr); if (len <= 0) continue; } else err(1, "read failed"); } tlen += len; if ((RBUFSIZE - tlen) < PSIZE) break; }; #else tlen = len = read(d, buf, RBUFSIZE); if (len < 0) { if (errno == EAGAIN) { fprintf(stderr, "(EAGAIN)\n"); fflush(stderr); if (len <= 0) continue; } else err(1, "read failed"); } #endif vec = 0; ptr = (u_int32_t *) buf; again: pkt = (struct fw_pkt *) ptr; #if DEBUG fprintf(stderr, "%08x %08x %08x %08x\n", htonl(ptr[0]), htonl(ptr[1]), htonl(ptr[2]), htonl(ptr[3])); #endif ciph = (struct ciphdr *)(ptr + 1); /* skip iso header */ if (ciph->fmt != CIP_FMT_DVCR) errx(1, "unknown format 0x%x", ciph->fmt); ptr = (u_int32_t *) (ciph + 1); /* skip cip header */ #if DEBUG if (ciph->fdf.dv.cyc != 0xffff && k == 0) { fprintf(stderr, "0x%04x\n", ntohs(ciph->fdf.dv.cyc)); } #endif - if (ntohs(pkt->mode.stream.len) <= sizeof(struct ciphdr)) + if (pkt->mode.stream.len <= sizeof(struct ciphdr)) /* no payload */ goto next; for (dv = (struct dvdbc *)ptr; (char *)dv < (char *)(ptr + ciph->len); dv+=6) { #if DEBUG fprintf(stderr, "(%d,%d) ", dv->sct, dv->dseq); #endif if (dv->sct == DV_SCT_HEADER && dv->dseq == 0) { if (system < 0) { system = ciph->fdf.dv.fs; printf("%s\n", system_name[system]); } /* Fix DSF bit */ if (system == 1 && (dv->payload[0] & DV_DSF_12) == 0) dv->payload[0] |= DV_DSF_12; nb = nblocks[system]; fprintf(stderr, "%d", k%10); #if FIX_FRAME if (m > 0 && m != nb) { /* padding bad frame */ npad = ((nb - m) % nb); if (npad < 0) npad += nb; fprintf(stderr, "(%d blocks padded)", npad); npad *= DSIZE; wbuf[vec].iov_base = pad; wbuf[vec++].iov_len = npad; if (vec >= NPACKET_R) { writev(fd, wbuf, vec); vec = 0; } } #endif k++; if (k % frame_rate[system] == 0) { /* every second */ fprintf(stderr, "\n"); } fflush(stderr); m = 0; } if (k == 0 || (count > 0 && k > count)) continue; m++; wbuf[vec].iov_base = (char *) dv; wbuf[vec++].iov_len = DSIZE; if (vec >= NPACKET_R) { writev(fd, wbuf, vec); vec = 0; } } ptr = (u_int32_t *)dv; next: if ((char *)ptr < buf + tlen) goto again; if (vec > 0) writev(fd, wbuf, vec); } close(fd); fprintf(stderr, "\n"); return 0; } int dvsend(int d, char *filename, char ich, int count) { struct fw_isochreq isoreq; struct fw_isobufreq bufreq; struct dvdbc *dv; struct fw_pkt *pkt; int len, tlen, header, fd, frames, packets, vec, offset, nhdr, i; int system=-1, pad_acc, cycle_acc, cycle, f_cycle, f_frac; struct iovec wbuf[TNBUF*2 + NEMPTY]; char *pbuf; u_int32_t iso_data, iso_empty, hdr[TNBUF + NEMPTY][3]; struct ciphdr *ciph; struct timeval start, end; double rtime; fd = open(filename, O_RDONLY); pbuf = (char *)malloc(DSIZE * TNBUF); bzero(wbuf, sizeof(wbuf)); bufreq.rx.nchunk = 0; bufreq.rx.npacket = 0; bufreq.rx.psize = 0; bufreq.tx.nchunk = NCHUNK; bufreq.tx.npacket = NPACKET_T; bufreq.tx.psize = PSIZE; if (ioctl(d, FW_SSTBUF, &bufreq) < 0) { err(1, "ioctl"); } isoreq.ch = ich & 0x3f; isoreq.tag = (ich >> 6) & 3; if( ioctl(d, FW_STSTREAM, &isoreq) < 0) err(1, "ioctl"); iso_data = 0; pkt = (struct fw_pkt *) &iso_data; - pkt->mode.stream.len = htons(DSIZE + sizeof(struct ciphdr)); + pkt->mode.stream.len = DSIZE + sizeof(struct ciphdr); pkt->mode.stream.sy = 0; pkt->mode.stream.tcode = FWTCODE_STREAM; pkt->mode.stream.chtag = ich; iso_empty = iso_data; pkt = (struct fw_pkt *) &iso_empty; - pkt->mode.stream.len = htons(sizeof(struct ciphdr)); + pkt->mode.stream.len = sizeof(struct ciphdr); bzero(hdr[0], sizeof(hdr[0])); hdr[0][0] = iso_data; ciph = (struct ciphdr *)&hdr[0][1]; ciph->src = 0; /* XXX */ ciph->len = 120; ciph->dbc = 0; ciph->eoh1 = 1; ciph->fdf.dv.cyc = 0xffff; for (i = 1; i < TNBUF; i++) { bcopy(hdr[0], hdr[i], sizeof(hdr[0])); } gettimeofday(&start, NULL); #if DEBUG fprintf(stderr, "%08x %08x %08x\n", htonl(hdr[0]), htonl(hdr[1]), htonl(hdr[2])); #endif frames = 0; packets = 0; pad_acc = 0; while (1) { tlen = 0; while (tlen < DSIZE * TNBUF) { len = read(fd, pbuf + tlen, DSIZE * TNBUF - tlen); if (len <= 0) { if (tlen > 0) break; if (len < 0) warn("read"); else printf("\nend of file\n"); goto send_end; } tlen += len; } vec = 0; offset = 0; nhdr = 0; next: dv = (struct dvdbc *)(pbuf + offset * DSIZE); #if 0 header = (dv->sct == 0 && dv->dseq == 0); #else header = (packets == 0 || packets % npackets[system] == 0); #endif ciph = (struct ciphdr *)&hdr[nhdr][1]; if (header) { if (system < 0) { system = ((dv->payload[0] & DV_DSF_12) != 0); printf("%s\n", system_name[system]); cycle = 1; cycle_acc = frame_cycle[system].d * cycle; } fprintf(stderr, "%d", frames % 10); frames ++; if (count > 0 && frames > count) break; if (frames % frame_rate[system] == 0) fprintf(stderr, "\n"); fflush(stderr); f_cycle = (cycle_acc / frame_cycle[system].d) & 0xf; f_frac = (cycle_acc % frame_cycle[system].d * CYCLE_FRAC) / frame_cycle[system].d; #if 0 ciph->fdf.dv.cyc = htons(f_cycle << 12 | f_frac); #else ciph->fdf.dv.cyc = htons(cycle << 12 | f_frac); #endif cycle_acc += frame_cycle[system].n; cycle_acc %= frame_cycle[system].d * 0x10; } else { ciph->fdf.dv.cyc = 0xffff; } ciph->dbc = packets++ % 256; pad_acc += pad_rate[system].n; if (pad_acc >= pad_rate[system].d) { pad_acc -= pad_rate[system].d; bcopy(hdr[nhdr], hdr[nhdr+1], sizeof(hdr[0])); hdr[nhdr][0] = iso_empty; wbuf[vec].iov_base = (char *)hdr[nhdr]; wbuf[vec++].iov_len = sizeof(hdr[0]); nhdr ++; cycle ++; } hdr[nhdr][0] = iso_data; wbuf[vec].iov_base = (char *)hdr[nhdr]; wbuf[vec++].iov_len = sizeof(hdr[0]); wbuf[vec].iov_base = (char *)dv; wbuf[vec++].iov_len = DSIZE; nhdr ++; cycle ++; offset ++; if (offset * DSIZE < tlen) goto next; again: len = writev(d, wbuf, vec); if (len < 0) { if (errno == EAGAIN) { fprintf(stderr, "(EAGAIN)\n"); fflush(stderr); goto again; } err(1, "write failed"); } } close(fd); fprintf(stderr, "\n"); send_end: gettimeofday(&end, NULL); rtime = end.tv_sec - start.tv_sec + (end.tv_usec - start.tv_usec) * 1e-6; fprintf(stderr, "%d frames, %.2f secs, %.2f frames/sec\n", frames, rtime, frames/rtime); return 0; }