diff --git a/sys/dev/firewire/firewire.c b/sys/dev/firewire/firewire.c index c8e8a53d5f03..e1ee133523b9 100644 --- a/sys/dev/firewire/firewire.c +++ b/sys/dev/firewire/firewire.c @@ -46,6 +46,8 @@ #include #include +#include + #if defined(__DragonFly__) || __FreeBSD_version < 500000 #include /* for DELAY() */ #endif @@ -95,6 +97,7 @@ static int firewire_probe (device_t); static int firewire_attach (device_t); static int firewire_detach (device_t); static int firewire_resume (device_t); +static void firewire_xfer_timeout(void *, int); #if 0 static int firewire_shutdown (device_t); #endif @@ -110,6 +113,7 @@ static void fw_bus_probe_thread(void *); static void fw_vmaccess (struct fw_xfer *); #endif static int fw_bmr (struct firewire_comm *); +static void fw_dump_hdr(struct fw_pkt *, char *); static device_method_t firewire_methods[] = { /* Device interface */ @@ -178,9 +182,11 @@ fw_noderesolve_eui64(struct firewire_comm *fc, struct fw_eui64 *eui) int s; s = splfw(); + FW_GLOCK(fc); STAILQ_FOREACH(fwdev, &fc->devices, link) if (FW_EUI64_EQUAL(fwdev->eui, *eui)) break; + FW_GUNLOCK(fc); splx(s); if(fwdev == NULL) return NULL; @@ -196,7 +202,7 @@ fw_asyreq(struct firewire_comm *fc, int sub, struct fw_xfer *xfer) { int err = 0; struct fw_xferq *xferq; - int tl = -1, len; + int len; struct fw_pkt *fp; int tcode; struct tcode_info *info; @@ -242,16 +248,15 @@ fw_asyreq(struct firewire_comm *fc, int sub, struct fw_xfer *xfer) if(!(xferq->queued < xferq->maxq)){ device_printf(fc->bdev, "Discard a packet (queued=%d)\n", xferq->queued); - return EINVAL; + return EAGAIN; } + xfer->tl = -1; if (info->flag & FWTI_TLABEL) { - if ((tl = fw_get_tlabel(fc, xfer)) == -1) + if (fw_get_tlabel(fc, xfer) < 0) return EAGAIN; - fp->mode.hdr.tlrt = tl << 2; } - xfer->tl = tl; xfer->resp = 0; xfer->fc = fc; xfer->q = xferq; @@ -263,11 +268,32 @@ fw_asyreq(struct firewire_comm *fc, int sub, struct fw_xfer *xfer) * Wakeup blocked process. */ void -fw_asy_callback(struct fw_xfer *xfer){ +fw_xferwake(struct fw_xfer *xfer) +{ + struct mtx *lock = &xfer->fc->wait_lock; + + mtx_lock(lock); + xfer->flag |= FWXF_WAKE; + mtx_unlock(lock); + wakeup(xfer); return; } +int +fw_xferwait(struct fw_xfer *xfer) +{ + struct mtx *lock = &xfer->fc->wait_lock; + int err = 0; + + mtx_lock(lock); + if ((xfer->flag & FWXF_WAKE) == 0) + err = msleep((void *)xfer, lock, PWAIT|PCATCH, "fw_xferwait", 0); + mtx_unlock(lock); + + return (err); +} + /* * Async. request with given xfer structure. */ @@ -279,17 +305,22 @@ fw_asystart(struct fw_xfer *xfer) #if 0 /* XXX allow bus explore packets only after bus rest */ if (fc->status < FWBUSEXPLORE) { xfer->resp = EAGAIN; - xfer->state = FWXF_BUSY; + xfer->flag = FWXF_BUSY; if (xfer->hand != NULL) xfer->hand(xfer); return; } #endif - microtime(&xfer->tv); s = splfw(); - xfer->state = FWXF_INQ; + /* Protect from interrupt/timeout */ + FW_GLOCK(fc); + microtime(&xfer->tv); + xfer->flag = FWXF_INQ; STAILQ_INSERT_TAIL(&xfer->q->q, xfer, link); +#if 0 xfer->q->queued ++; +#endif + FW_GUNLOCK(fc); splx(s); /* XXX just queue for mbuf */ if (xfer->mbuf == NULL) @@ -311,11 +342,13 @@ firewire_probe(device_t dev) } static void -firewire_xfer_timeout(struct firewire_comm *fc) +firewire_xfer_timeout(void *arg, int pending) { - struct fw_xfer *xfer; + struct firewire_comm *fc = (struct firewire_comm *)arg; + struct fw_xfer *xfer, *txfer; struct timeval tv; struct timeval split_timeout; + STAILQ_HEAD(, fw_xfer) xfer_timeout; int i, s; split_timeout.tv_sec = 0; @@ -323,32 +356,41 @@ firewire_xfer_timeout(struct firewire_comm *fc) microtime(&tv); timevalsub(&tv, &split_timeout); + STAILQ_INIT(&xfer_timeout); s = splfw(); + FW_GLOCK(fc); for (i = 0; i < 0x40; i ++) { while ((xfer = STAILQ_FIRST(&fc->tlabels[i])) != NULL) { if (timevalcmp(&xfer->tv, &tv, >)) /* the rests are newer than this */ break; - if (xfer->state == FWXF_START) + if ((xfer->flag & FWXF_SENT) == 0) /* not sent yet */ break; device_printf(fc->bdev, - "split transaction timeout dst=0x%x tl=0x%x state=%d\n", - xfer->send.hdr.mode.hdr.dst, i, xfer->state); + "split transaction timeout: " + "tl=0x%x flag=0x%02x\n", i, xfer->flag); + fw_dump_hdr(&xfer->send.hdr, "send"); xfer->resp = ETIMEDOUT; - fw_xfer_done(xfer); + STAILQ_REMOVE_HEAD(&fc->tlabels[i], tlabel); + STAILQ_INSERT_TAIL(&xfer_timeout, xfer, tlabel); } } + FW_GUNLOCK(fc); splx(s); + fc->timeout(fc); + + STAILQ_FOREACH_SAFE(xfer, &xfer_timeout, tlabel, txfer) + xfer->hand(xfer); } -#define WATCHDOC_HZ 10 +#define WATCHDOG_HZ 10 static void firewire_watchdog(void *arg) { struct firewire_comm *fc; - static int watchdoc_clock = 0; + static int watchdog_clock = 0; fc = (struct firewire_comm *)arg; @@ -357,13 +399,12 @@ firewire_watchdog(void *arg) * We encounter a timeout easily. To avoid this, * ignore clock interrupt for a while. */ - if (watchdoc_clock > WATCHDOC_HZ * 15) { - firewire_xfer_timeout(fc); - fc->timeout(fc); - } else - watchdoc_clock ++; + if (watchdog_clock > WATCHDOG_HZ * 15) + taskqueue_enqueue(fc->taskqueue, &fc->task_timeout); + else + watchdog_clock ++; - callout_reset(&fc->timeout_callout, hz / WATCHDOC_HZ, + callout_reset(&fc->timeout_callout, hz / WATCHDOG_HZ, (void *)firewire_watchdog, (void *)fc); } @@ -377,7 +418,6 @@ firewire_attach(device_t dev) struct firewire_softc *sc = device_get_softc(dev); device_t pa = device_get_parent(dev); struct firewire_comm *fc; - struct proc *p; fc = (struct firewire_comm *)device_get_softc(pa); sc->fc = fc; @@ -388,15 +428,17 @@ firewire_attach(device_t dev) fwdev_makedev(sc); - CALLOUT_INIT(&sc->fc->timeout_callout); - CALLOUT_INIT(&sc->fc->bmr_callout); - CALLOUT_INIT(&sc->fc->busprobe_callout); + mtx_init(&fc->wait_lock, "fwwait", NULL, MTX_DEF); + CALLOUT_INIT(&fc->timeout_callout); + CALLOUT_INIT(&fc->bmr_callout); + CALLOUT_INIT(&fc->busprobe_callout); + TASK_INIT(&fc->task_timeout, 0, firewire_xfer_timeout, (void *)fc); callout_reset(&sc->fc->timeout_callout, hz, (void *)firewire_watchdog, (void *)sc->fc); /* create thread */ - kthread_create(fw_bus_probe_thread, (void *)fc, &p, + kthread_create(fw_bus_probe_thread, (void *)fc, &fc->probe_thread, 0, 0, "fw%d_probe", unit); /* Locate our children */ @@ -457,7 +499,12 @@ firewire_detach(device_t dev) sc = (struct firewire_softc *)device_get_softc(dev); fc = sc->fc; + mtx_lock(&fc->wait_lock); fc->status = FWBUSDETACH; + wakeup(fc); + if (msleep(fc->probe_thread, &fc->wait_lock, PWAIT, "fwthr", hz * 60)) + printf("firewire probe thread didn't die\n"); + mtx_unlock(&fc->wait_lock); if ((err = fwdev_destroydev(sc)) != 0) return err; @@ -479,10 +526,7 @@ firewire_detach(device_t dev) free(fc->speed_map, M_FW); free(fc->crom_src_buf, M_FW); - wakeup(fc); - if (tsleep(fc, PWAIT, "fwthr", hz * 60)) - printf("firewire task thread didn't die\n"); - + mtx_destroy(&fc->wait_lock); return(0); } #if 0 @@ -501,9 +545,11 @@ fw_xferq_drain(struct fw_xferq *xferq) while ((xfer = STAILQ_FIRST(&xferq->q)) != NULL) { STAILQ_REMOVE_HEAD(&xferq->q, link); +#if 0 xferq->queued --; +#endif xfer->resp = EAGAIN; - xfer->state = FWXF_SENTERR; + xfer->flag = FWXF_SENTERR; fw_xfer_done(xfer); } } @@ -511,12 +557,30 @@ fw_xferq_drain(struct fw_xferq *xferq) void fw_drain_txq(struct firewire_comm *fc) { + struct fw_xfer *xfer, *txfer; + STAILQ_HEAD(, fw_xfer) xfer_drain; int i; + STAILQ_INIT(&xfer_drain); + + FW_GLOCK(fc); fw_xferq_drain(fc->atq); fw_xferq_drain(fc->ats); for(i = 0; i < fc->nisodma; i++) fw_xferq_drain(fc->it[i]); + + for (i = 0; i < 0x40; i ++) + while ((xfer = STAILQ_FIRST(&fc->tlabels[i])) != NULL) { + if (firewire_debug) + printf("tl=%d flag=%d\n", i, xfer->flag); + xfer->resp = EAGAIN; + STAILQ_REMOVE_HEAD(&fc->tlabels[i], tlabel); + STAILQ_INSERT_TAIL(&xfer_drain, xfer, tlabel); + } + FW_GUNLOCK(fc); + + STAILQ_FOREACH_SAFE(xfer, &xfer_drain, tlabel, txfer) + xfer->hand(xfer); } static void @@ -802,13 +866,17 @@ struct fw_bind * fw_bindlookup(struct firewire_comm *fc, uint16_t dest_hi, uint32_t dest_lo) { u_int64_t addr; - struct fw_bind *tfw; + struct fw_bind *tfw, *r = NULL; addr = ((u_int64_t)dest_hi << 32) | dest_lo; + FW_GLOCK(fc); STAILQ_FOREACH(tfw, &fc->binds, fclist) - if (BIND_CMP(addr, tfw) == 0) - return(tfw); - return(NULL); + if (BIND_CMP(addr, tfw) == 0) { + r = tfw; + break; + } + FW_GUNLOCK(fc); + return(r); } /* @@ -818,28 +886,29 @@ int fw_bindadd(struct firewire_comm *fc, struct fw_bind *fwb) { struct fw_bind *tfw, *prev = NULL; + int r = 0; if (fwb->start > fwb->end) { printf("%s: invalid range\n", __func__); return EINVAL; } + FW_GLOCK(fc); STAILQ_FOREACH(tfw, &fc->binds, fclist) { if (fwb->end < tfw->start) break; prev = tfw; } - if (prev == NULL) { + if (prev == NULL) STAILQ_INSERT_HEAD(&fc->binds, fwb, fclist); - return (0); - } - if (prev->end < fwb->start) { + else if (prev->end < fwb->start) STAILQ_INSERT_AFTER(&fc->binds, prev, fwb, fclist); - return (0); + else { + printf("%s: bind failed\n", __func__); + r = EBUSY; } - - printf("%s: bind failed\n", __func__); - return (EBUSY); + FW_GUNLOCK(fc); + return (r); } /* @@ -855,6 +924,7 @@ fw_bindremove(struct firewire_comm *fc, struct fw_bind *fwb) int s; s = splfw(); + FW_GLOCK(fc); STAILQ_FOREACH(tfw, &fc->binds, fclist) if (tfw == fwb) { STAILQ_REMOVE(&fc->binds, fwb, fw_bind, fclist); @@ -862,6 +932,7 @@ fw_bindremove(struct firewire_comm *fc, struct fw_bind *fwb) } printf("%s: no such binding\n", __func__); + FW_GUNLOCK(fc); splx(s); return (1); found: @@ -873,6 +944,7 @@ found: } STAILQ_INIT(&fwb->xferlist); #endif + FW_GUNLOCK(fc); splx(s); return 0; @@ -911,6 +983,19 @@ fw_xferlist_remove(struct fw_xferlist *q) } STAILQ_INIT(q); } +/* + * dump packet header + */ +static void +fw_dump_hdr(struct fw_pkt *fp, char *prefix) +{ + printf("%s: dst=0x%02x tl=0x%02x rt=%d tcode=0x%x pri=0x%x " + "src=0x%03x\n", prefix, + fp->mode.hdr.dst & 0x3f, + fp->mode.hdr.tlrt >> 2, fp->mode.hdr.tlrt & 3, + fp->mode.hdr.tcode, fp->mode.hdr.pri, + fp->mode.hdr.src); +} /* * To free transaction label. @@ -925,19 +1010,26 @@ fw_tl_free(struct firewire_comm *fc, struct fw_xfer *xfer) return; s = splfw(); + FW_GLOCK(fc); #if 1 /* make sure the label is allocated */ STAILQ_FOREACH(txfer, &fc->tlabels[xfer->tl], tlabel) if(txfer == xfer) break; if (txfer == NULL) { - printf("%s: the xfer is not in the tlabel(%d)\n", - __FUNCTION__, xfer->tl); + printf("%s: the xfer is not in the queue " + "(tlabel=%d, flag=0x%x)\n", + __FUNCTION__, xfer->tl, xfer->flag); + fw_dump_hdr(&xfer->send.hdr, "send"); + fw_dump_hdr(&xfer->recv.hdr, "recv"); + kdb_backtrace(); + FW_GUNLOCK(fc); splx(s); return; } #endif STAILQ_REMOVE(&fc->tlabels[xfer->tl], xfer, fw_xfer, tlabel); + FW_GUNLOCK(fc); splx(s); return; } @@ -946,18 +1038,33 @@ fw_tl_free(struct firewire_comm *fc, struct fw_xfer *xfer) * To obtain XFER structure by transaction label. */ static struct fw_xfer * -fw_tl2xfer(struct firewire_comm *fc, int node, int tlabel) +fw_tl2xfer(struct firewire_comm *fc, int node, int tlabel, int tcode) { struct fw_xfer *xfer; int s = splfw(); + int req; + FW_GLOCK(fc); STAILQ_FOREACH(xfer, &fc->tlabels[tlabel], tlabel) if(xfer->send.hdr.mode.hdr.dst == node) { + FW_GUNLOCK(fc); splx(s); + KASSERT(xfer->tl == tlabel, + ("xfer->tl 0x%x != 0x%x", xfer->tl, tlabel)); + /* extra sanity check */ + req = xfer->send.hdr.mode.hdr.tcode; + if (xfer->fc->tcode[req].valid_res != tcode) { + printf("%s: invalid response tcode " + "(0x%x for 0x%x)\n", __FUNCTION__, + tcode, req); + return(NULL); + } + if (firewire_debug > 2) printf("fw_tl2xfer: found tl=%d\n", tlabel); return(xfer); } + FW_GUNLOCK(fc); if (firewire_debug > 1) printf("fw_tl2xfer: not found tl=%d\n", tlabel); splx(s); @@ -1034,16 +1141,20 @@ fw_xfer_unload(struct fw_xfer* xfer) int s; if(xfer == NULL ) return; - if(xfer->state == FWXF_INQ){ + if(xfer->flag & FWXF_INQ){ printf("fw_xfer_free FWXF_INQ\n"); s = splfw(); + FW_GLOCK(xfer->fc); STAILQ_REMOVE(&xfer->q->q, xfer, fw_xfer, link); +#if 0 xfer->q->queued --; +#endif + FW_GUNLOCK(xfer->fc); splx(s); } if (xfer->fc != NULL) { #if 1 - if(xfer->state == FWXF_START) + if(xfer->flag & FWXF_START) /* * This could happen if: * 1. We call fwohci_arcv() before fwohci_txd(). @@ -1052,7 +1163,7 @@ fw_xfer_unload(struct fw_xfer* xfer) printf("fw_xfer_free FWXF_START\n"); #endif } - xfer->state = FWXF_INIT; + xfer->flag = FWXF_INIT; xfer->resp = 0; } /* @@ -1090,8 +1201,8 @@ void fw_asy_callback_free(struct fw_xfer *xfer) { #if 0 - printf("asyreq done state=%d resp=%d\n", - xfer->state, xfer->resp); + printf("asyreq done flag=0x%02x resp=%d\n", + xfer->flag, xfer->resp); #endif fw_xfer_free(xfer); } @@ -1297,10 +1408,10 @@ fw_explore_read_quads(struct fw_device *fwdev, int offset, for (i = 0; i < n; i ++, offset += sizeof(uint32_t)) { xfer = fwmem_read_quad(fwdev, NULL, -1, 0xffff, 0xf0000000 | offset, (void *)&tmp, - fw_asy_callback); + fw_xferwake); if (xfer == NULL) return (-1); - tsleep((void *)xfer, PWAIT|PCATCH, "rquad", 0); + fw_xferwait(xfer); if (xfer->resp == 0) quad[i] = ntohl(tmp); @@ -1532,20 +1643,20 @@ fw_bus_probe_thread(void *arg) fc = (struct firewire_comm *)arg; - mtx_lock(&Giant); - while (1) { + mtx_lock(&fc->wait_lock); + while (fc->status != FWBUSDETACH) { if (fc->status == FWBUSEXPLORE) { + mtx_unlock(&fc->wait_lock); fw_explore(fc); fc->status = FWBUSEXPDONE; if (firewire_debug) printf("bus_explore done\n"); fw_attach_dev(fc); - } else if (fc->status == FWBUSDETACH) - break; - tsleep((void *)fc, PWAIT|PCATCH, "-", 0); + mtx_lock(&fc->wait_lock); + } + msleep((void *)fc, &fc->wait_lock, PWAIT|PCATCH, "-", 0); } - mtx_unlock(&Giant); - wakeup(fc); + mtx_unlock(&fc->wait_lock); kthread_exit(0); } @@ -1606,6 +1717,7 @@ fw_get_tlabel(struct firewire_comm *fc, struct fw_xfer *xfer) static uint32_t label = 0; s = splfw(); + FW_GLOCK(fc); for( i = 0 ; i < 0x40 ; i ++){ label = (label + 1) & 0x3f; STAILQ_FOREACH(txfer, &fc->tlabels[label], tlabel) @@ -1613,14 +1725,19 @@ fw_get_tlabel(struct firewire_comm *fc, struct fw_xfer *xfer) xfer->send.hdr.mode.hdr.dst) break; if(txfer == NULL) { + xfer->tl = label; + xfer->send.hdr.mode.hdr.tlrt = label << 2; STAILQ_INSERT_TAIL(&fc->tlabels[label], xfer, tlabel); + FW_GUNLOCK(fc); splx(s); if (firewire_debug > 1) printf("fw_get_tlabel: dst=%d tl=%d\n", xfer->send.hdr.mode.hdr.dst, label); - return(label); + /* note: label may be incremanted after unlock */ + return(xfer->tl); } } + FW_GUNLOCK(fc); splx(s); if (firewire_debug > 1) @@ -1713,7 +1830,7 @@ fw_rcv(struct fw_rcv_buf *rb) case FWTCODE_RRESB: case FWTCODE_LRES: rb->xfer = fw_tl2xfer(rb->fc, fp->mode.hdr.src, - fp->mode.hdr.tlrt >> 2); + fp->mode.hdr.tlrt >> 2, fp->mode.hdr.tcode); if(rb->xfer == NULL) { printf("fw_rcv: unknown response " "%s(%x) src=0x%x tl=0x%x rt=%d data=0x%x\n", @@ -1722,7 +1839,7 @@ fw_rcv(struct fw_rcv_buf *rb) fp->mode.hdr.tlrt >> 2, fp->mode.hdr.tlrt & 3, fp->mode.rresq.data); -#if 1 +#if 0 printf("try ad-hoc work around!!\n"); rb->xfer = fw_tl2xfer(rb->fc, fp->mode.hdr.src, (fp->mode.hdr.tlrt >> 2)^3); @@ -1740,8 +1857,8 @@ fw_rcv(struct fw_rcv_buf *rb) else rb->xfer->resp = 0; /* make sure the packet is drained in AT queue */ - oldstate = rb->xfer->state; - rb->xfer->state = FWXF_RCVD; + oldstate = rb->xfer->flag; + rb->xfer->flag = FWXF_RCVD; switch (oldstate) { case FWXF_SENT: fw_xfer_done(rb->xfer); @@ -1753,7 +1870,7 @@ fw_rcv(struct fw_rcv_buf *rb) #endif break; default: - printf("unexpected state %d\n", rb->xfer->state); + printf("unexpected flag 0x%02x\n", rb->xfer->flag); } return; case FWTCODE_WREQQ: @@ -1806,7 +1923,7 @@ fw_rcv(struct fw_rcv_buf *rb) resfp->mode.rresb.extcode = 0; resfp->mode.rresb.len = 0; /* - rb->xfer->hand = fw_asy_callback; + rb->xfer->hand = fw_xferwake; */ rb->xfer->hand = fw_xfer_free; if(fw_asyreq(rb->fc, -1, rb->xfer)){ @@ -2099,6 +2216,34 @@ fw_bmr(struct firewire_comm *fc) return 0; } +int +fw_open_isodma(struct firewire_comm *fc, int tx) +{ + struct fw_xferq **xferqa; + struct fw_xferq *xferq; + int i; + + if (tx) + xferqa = &fc->it[0]; + else + xferqa = &fc->ir[0]; + + FW_GLOCK(fc); + for (i = 0; i < fc->nisodma; i ++) { + xferq = xferqa[i]; + if ((xferq->flag & FWXFERQ_OPEN) == 0) { + xferq->flag |= FWXFERQ_OPEN; + break; + } + } + if (i == fc->nisodma) { + printf("no free dma channel (tx=%d)\n", tx); + i = -1; + } + FW_GUNLOCK(fc); + return (i); +} + static int fw_modevent(module_t mode, int type, void *data) { diff --git a/sys/dev/firewire/firewirereg.h b/sys/dev/firewire/firewirereg.h index 05280f1aca08..50388681375d 100644 --- a/sys/dev/firewire/firewirereg.h +++ b/sys/dev/firewire/firewirereg.h @@ -47,6 +47,8 @@ typedef struct proc fw_proc; #endif #include +#include +#include #define splfw splimp @@ -98,6 +100,7 @@ struct tcode_info { #define FWTI_TLABEL (1 << 2) #define FWTI_BLOCK_STR (1 << 3) #define FWTI_BLOCK_ASY (1 << 4) + u_char valid_res; }; struct firewire_comm{ @@ -145,6 +148,7 @@ struct firewire_comm{ struct callout busprobe_callout; struct callout bmr_callout; struct callout timeout_callout; + struct task task_timeout; uint32_t (*cyctimer) (struct firewire_comm *); void (*ibr) (struct firewire_comm *); uint32_t (*set_bmr) (struct firewire_comm *, uint32_t); @@ -160,9 +164,18 @@ struct firewire_comm{ void (*itx_post) (struct firewire_comm *, uint32_t *); struct tcode_info *tcode; bus_dma_tag_t dmat; + struct mtx mtx; + struct mtx wait_lock; + struct taskqueue *taskqueue; + struct proc *probe_thread; }; #define CSRARC(sc, offset) ((sc)->csr_arc[(offset)/4]) +#define FW_GMTX(fc) (&(fc)->mtx) +#define FW_GLOCK(fc) mtx_lock(FW_GMTX(fc)) +#define FW_GUNLOCK(fc) mtx_unlock(FW_GMTX(fc)) +#define FW_GLOCK_ASSERT(fc) mtx_assert(FW_GMTX(fc), MA_OWNED) + struct fw_xferq { int flag; #define FWXFERQ_CHTAGMASK 0xff @@ -220,14 +233,16 @@ struct fw_xfer{ struct fw_xferq *q; struct timeval tv; int8_t resp; -#define FWXF_INIT 0 -#define FWXF_INQ 1 -#define FWXF_START 2 -#define FWXF_SENT 3 -#define FWXF_SENTERR 4 -#define FWXF_BUSY 8 -#define FWXF_RCVD 10 - uint8_t state; +#define FWXF_INIT 0x00 +#define FWXF_INQ 0x01 +#define FWXF_START 0x02 +#define FWXF_SENT 0x04 +#define FWXF_SENTERR 0x08 +#define FWXF_BUSY 0x10 +#define FWXF_RCVD 0x20 + +#define FWXF_WAKE 0x80 + uint8_t flag; int8_t tl; void (*hand) (struct fw_xfer *); struct { @@ -270,7 +285,8 @@ void fw_busreset (struct firewire_comm *, uint32_t); uint16_t fw_crc16 (uint32_t *, uint32_t); void fw_xfer_timeout (void *); void fw_xfer_done (struct fw_xfer *); -void fw_asy_callback (struct fw_xfer *); +void fw_xferwake (struct fw_xfer *); +int fw_xferwait (struct fw_xfer *); void fw_asy_callback_free (struct fw_xfer *); struct fw_device *fw_noderesolve_nodeid (struct firewire_comm *, int); struct fw_device *fw_noderesolve_eui64 (struct firewire_comm *, struct fw_eui64 *); @@ -279,6 +295,7 @@ void fw_drain_txq (struct firewire_comm *); int fwdev_makedev (struct firewire_softc *); int fwdev_destroydev (struct firewire_softc *); void fwdev_clone (void *, struct ucred *, char *, int, struct cdev **); +int fw_open_isodma(struct firewire_comm *, int); extern int firewire_debug; extern devclass_t firewire_devclass; @@ -292,7 +309,7 @@ extern devclass_t firewire_devclass; #if defined(__DragonFly__) || __FreeBSD_version < 500000 #define CALLOUT_INIT(x) callout_init(x) #else -#define CALLOUT_INIT(x) callout_init(x, 0 /* mpsafe */) +#define CALLOUT_INIT(x) callout_init(x, 1 /* mpsafe */) #endif #if defined(__DragonFly__) || __FreeBSD_version < 500000 diff --git a/sys/dev/firewire/fwdev.c b/sys/dev/firewire/fwdev.c index 2d91df4699b1..9e6602d068ce 100644 --- a/sys/dev/firewire/fwdev.c +++ b/sys/dev/firewire/fwdev.c @@ -98,7 +98,7 @@ struct cdevsw firewire_cdevsw = { .d_mmap = fw_mmap, .d_strategy = fw_strategy, .d_name = "fw", - .d_flags = D_MEM | D_NEEDGIANT + .d_flags = D_MEM #else #define CDEV_MAJOR 127 fw_open, fw_close, fw_read, fw_write, fw_ioctl, @@ -191,8 +191,22 @@ fw_open (struct cdev *dev, int flags, int fmt, fw_proc *td) if (DEV_FWMEM(dev)) return fwmem_open(dev, flags, fmt, td); - if (dev->si_drv1 != NULL) + sc = devclass_get_softc(firewire_devclass, unit); + if (sc == NULL) + return (ENXIO); + + FW_GLOCK(sc->fc); + if (dev->si_drv1 != NULL) { + FW_GUNLOCK(sc->fc); return (EBUSY); + } + /* set dummy value for allocation */ + dev->si_drv1 = (void *)-1; + FW_GUNLOCK(sc->fc); + + dev->si_drv1 = malloc(sizeof(struct fw_drv1), M_FW, M_WAITOK | M_ZERO); + if (dev->si_drv1 == NULL) + return (ENOMEM); #if defined(__FreeBSD__) && __FreeBSD_version >= 500000 if ((dev->si_flags & SI_NAMED) == 0) { @@ -204,13 +218,7 @@ fw_open (struct cdev *dev, int flags, int fmt, fw_proc *td) "fw%d.%d", unit, sub); } #endif - - dev->si_drv1 = malloc(sizeof(struct fw_drv1), M_FW, M_WAITOK | M_ZERO); - if (dev->si_drv1 == NULL) - return (ENOMEM); - d = (struct fw_drv1 *)dev->si_drv1; - sc = devclass_get_softc(firewire_devclass, unit); d->fc = sc->fc; STAILQ_INIT(&d->binds); STAILQ_INIT(&d->rq); @@ -296,14 +304,18 @@ fw_read_async(struct fw_drv1 *d, struct uio *uio, int ioflag) struct fw_pkt *fp; struct tcode_info *tinfo; + FW_GLOCK(d->fc); while ((xfer = STAILQ_FIRST(&d->rq)) == NULL && err == 0) - err = tsleep(&d->rq, FWPRI, "fwra", 0); + err = msleep(&d->rq, FW_GMTX(d->fc), FWPRI, "fwra", 0); - if (err != 0) + if (err != 0) { + FW_GUNLOCK(d->fc); return (err); + } s = splfw(); STAILQ_REMOVE_HEAD(&d->rq, link); + FW_GUNLOCK(xfer->fc); splx(s); fp = &xfer->recv.hdr; #if 0 /* for GASP ?? */ @@ -321,7 +333,9 @@ out: fwb = (struct fw_bind *)xfer->sc; fw_xfer_unload(xfer); xfer->recv.pay_len = PAGE_SIZE; + FW_GLOCK(xfer->fc); STAILQ_INSERT_TAIL(&fwb->xferlist, xfer, link); + FW_GUNLOCK(xfer->fc); return (err); } @@ -338,8 +352,7 @@ fw_read (struct cdev *dev, struct uio *uio, int ioflag) struct fw_pkt *fp; if (DEV_FWMEM(dev)) - return physio(dev, uio, ioflag); - + return (physio(dev, uio, ioflag)); d = (struct fw_drv1 *)dev->si_drv1; fc = d->fc; @@ -351,6 +364,7 @@ fw_read (struct cdev *dev, struct uio *uio, int ioflag) if (ir->buf == NULL) return (EIO); + FW_GLOCK(fc); readloop: if (ir->stproc == NULL) { /* iso bulkxfer */ @@ -367,15 +381,17 @@ readloop: if (slept == 0) { slept = 1; ir->flag |= FWXFERQ_WAKEUP; - err = tsleep(ir, FWPRI, "fw_read", hz); + err = msleep(ir, FW_GMTX(fc), FWPRI, "fw_read", hz); ir->flag &= ~FWXFERQ_WAKEUP; if (err == 0) goto readloop; } else if (slept == 1) err = EIO; + FW_GUNLOCK(fc); return err; } else if(ir->stproc != NULL) { /* iso bulkxfer */ + FW_GUNLOCK(fc); fp = (struct fw_pkt *)fwdma_v_addr(ir->buf, ir->stproc->poffset + ir->queued); if(fc->irx_post != NULL) @@ -396,6 +412,7 @@ readloop: } if (uio->uio_resid >= ir->psize) { slept = -1; + FW_GLOCK(fc); goto readloop; } } @@ -432,13 +449,13 @@ fw_write_async(struct fw_drv1 *d, struct uio *uio, int ioflag) xfer->fc = d->fc; xfer->sc = NULL; - xfer->hand = fw_asy_callback; + xfer->hand = fw_xferwake; xfer->send.spd = 2 /* XXX */; if ((err = fw_asyreq(xfer->fc, -1, xfer))) goto out; - if ((err = tsleep(xfer, FWPRI, "fwwa", 0))) + if ((err = fw_xferwait(xfer))) goto out; if (xfer->resp != 0) { @@ -446,8 +463,10 @@ fw_write_async(struct fw_drv1 *d, struct uio *uio, int ioflag) goto out; } - if (xfer->state == FWXF_RCVD) { + if (xfer->flag & FWXF_RCVD) { + FW_GLOCK(xfer->fc); STAILQ_INSERT_TAIL(&d->rq, xfer, link); + FW_GUNLOCK(xfer->fc); return (0); } @@ -467,7 +486,7 @@ fw_write (struct cdev *dev, struct uio *uio, int ioflag) struct fw_xferq *it; if (DEV_FWMEM(dev)) - return physio(dev, uio, ioflag); + return (physio(dev, uio, ioflag)); d = (struct fw_drv1 *)dev->si_drv1; fc = d->fc; @@ -478,6 +497,8 @@ fw_write (struct cdev *dev, struct uio *uio, int ioflag) if (it->buf == NULL) return (EIO); + + FW_GLOCK(fc); isoloop: if (it->stproc == NULL) { it->stproc = STAILQ_FIRST(&it->stfree); @@ -488,18 +509,21 @@ isoloop: it->queued = 0; } else if (slept == 0) { slept = 1; +#if 0 /* XXX to avoid lock recursion */ err = fc->itx_enable(fc, it->dmach); if (err) - return err; - err = tsleep(it, FWPRI, "fw_write", hz); + goto out; +#endif + err = msleep(it, FW_GMTX(fc), FWPRI, "fw_write", hz); if (err) - return err; + goto out; goto isoloop; } else { err = EIO; - return err; + goto out; } } + FW_GUNLOCK(fc); fp = (struct fw_pkt *)fwdma_v_addr(it->buf, it->stproc->poffset + it->queued); err = uiomove((caddr_t)fp, sizeof(struct fw_isohdr), uio); @@ -515,9 +539,14 @@ isoloop: } if (uio->uio_resid >= sizeof(struct fw_isohdr)) { slept = 0; + FW_GLOCK(fc); goto isoloop; } return err; + +out: + FW_GUNLOCK(fc); + return err; } static void @@ -528,7 +557,9 @@ fw_hand(struct fw_xfer *xfer) fwb = (struct fw_bind *)xfer->sc; d = (struct fw_drv1 *)fwb->sc; + FW_GLOCK(xfer->fc); STAILQ_INSERT_TAIL(&d->rq, xfer, link); + FW_GUNLOCK(xfer->fc); wakeup(&d->rq); } @@ -570,19 +601,17 @@ fw_ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, fw_proc *td) switch (cmd) { case FW_STSTREAM: if (it == NULL) { - for (i = 0; i < fc->nisodma; i ++) { - it = fc->it[i]; - if ((it->flag & FWXFERQ_OPEN) == 0) - break; - } - if (i >= fc->nisodma) { + i = fw_open_isodma(fc, /* tx */1); + if (i < 0) { err = EBUSY; break; } + it = fc->it[i]; err = fwdev_allocbuf(fc, it, &d->bufreq.tx); - if (err) + if (err) { + it->flag &= ~FWXFERQ_OPEN; break; - it->flag |= FWXFERQ_OPEN; + } } it->flag &= ~0xff; it->flag |= (0x3f & ichreq->ch); @@ -598,19 +627,17 @@ fw_ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, fw_proc *td) break; case FW_SRSTREAM: if (ir == NULL) { - for (i = 0; i < fc->nisodma; i ++) { - ir = fc->ir[i]; - if ((ir->flag & FWXFERQ_OPEN) == 0) - break; - } - if (i >= fc->nisodma) { + i = fw_open_isodma(fc, /* tx */0); + if (i < 0) { err = EBUSY; break; } + ir = fc->ir[i]; err = fwdev_allocbuf(fc, ir, &d->bufreq.rx); - if (err) + if (err) { + ir->flag &= ~FWXFERQ_OPEN; break; - ir->flag |= FWXFERQ_OPEN; + } } ir->flag &= ~0xff; ir->flag |= (0x3f & ichreq->ch); @@ -684,11 +711,11 @@ fw_ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, fw_proc *td) bcopy((char *)fp + tinfo->hdr_len, (void *)xfer->send.payload, pay_len); xfer->send.spd = asyreq->req.sped; - xfer->hand = fw_asy_callback; + xfer->hand = fw_xferwake; if ((err = fw_asyreq(fc, -1, xfer)) != 0) goto out; - if ((err = tsleep(xfer, FWPRI, "asyreq", hz)) != 0) + if ((err = fw_xferwait(xfer)) != 0) goto out; if (xfer->resp != 0) { err = EIO; @@ -742,7 +769,7 @@ out: err = EINVAL; break; } - fwb = (struct fw_bind *)malloc(sizeof (struct fw_bind), M_FW, M_NOWAIT); + fwb = (struct fw_bind *)malloc(sizeof (struct fw_bind), M_FW, M_WAITOK); if(fwb == NULL){ err = ENOMEM; break; diff --git a/sys/dev/firewire/fwdma.c b/sys/dev/firewire/fwdma.c index 2c84ebc0b31b..bf3bb6f5fcf6 100644 --- a/sys/dev/firewire/fwdma.c +++ b/sys/dev/firewire/fwdma.c @@ -92,7 +92,7 @@ fwdma_malloc(struct firewire_comm *fc, int alignment, bus_size_t size, /*flags*/ BUS_DMA_ALLOCNOW, #if defined(__FreeBSD__) && __FreeBSD_version >= 501102 /*lockfunc*/busdma_lock_mutex, - /*lockarg*/&Giant, + /*lockarg*/FW_GMTX(fc), #endif &dma->dma_tag); if (err) { @@ -190,7 +190,7 @@ fwdma_malloc_multiseg(struct firewire_comm *fc, int alignment, /*flags*/ BUS_DMA_ALLOCNOW, #if defined(__FreeBSD__) && __FreeBSD_version >= 501102 /*lockfunc*/busdma_lock_mutex, - /*lockarg*/&Giant, + /*lockarg*/FW_GMTX(fc), #endif &am->dma_tag)) { printf("fwdma_malloc_multiseg: tag_create failed\n"); diff --git a/sys/dev/firewire/fwmem.c b/sys/dev/firewire/fwmem.c index b6e7f70997ce..f0aa7ae33cd6 100644 --- a/sys/dev/firewire/fwmem.c +++ b/sys/dev/firewire/fwmem.c @@ -90,6 +90,7 @@ MALLOC_DEFINE(M_FWMEM, "fwmem", "fwmem/FireWire"); struct fwmem_softc { struct fw_eui64 eui; + struct firewire_softc *sc; int refcount; }; @@ -276,20 +277,33 @@ int fwmem_open (struct cdev *dev, int flags, int fmt, fw_proc *td) { struct fwmem_softc *fms; + struct firewire_softc *sc; + int unit = DEV2UNIT(dev); + sc = devclass_get_softc(firewire_devclass, unit); + if (sc == NULL) + return (ENXIO); + + FW_GLOCK(sc->fc); if (dev->si_drv1 != NULL) { - if ((flags & FWRITE) != 0) - return (EBUSY); + if ((flags & FWRITE) != 0) { + FW_GUNLOCK(sc->fc); + return(EBUSY); + } + FW_GUNLOCK(sc->fc); fms = (struct fwmem_softc *)dev->si_drv1; fms->refcount ++; } else { - fms = (struct fwmem_softc *)malloc(sizeof(struct fwmem_softc), - M_FWMEM, M_WAITOK); - if (fms == NULL) - return ENOMEM; - bcopy(&fwmem_eui64, &fms->eui, sizeof(struct fw_eui64)); - dev->si_drv1 = (void *)fms; + dev->si_drv1 = (void *)-1; + FW_GUNLOCK(sc->fc); + dev->si_drv1 = malloc(sizeof(struct fwmem_softc), + M_FWMEM, M_WAITOK); + if (dev->si_drv1 == NULL) + return(ENOMEM); dev->si_iosize_max = DFLTPHYS; + fms = (struct fwmem_softc *)dev->si_drv1; + bcopy(&fwmem_eui64, &fms->eui, sizeof(struct fw_eui64)); + fms->sc = sc; fms->refcount = 1; } if (fwmem_debug) @@ -304,7 +318,10 @@ fwmem_close (struct cdev *dev, int flags, int fmt, fw_proc *td) struct fwmem_softc *fms; fms = (struct fwmem_softc *)dev->si_drv1; + + FW_GLOCK(fms->sc->fc); fms->refcount --; + FW_GUNLOCK(fms->sc->fc); if (fwmem_debug) printf("%s: refcount=%d\n", __func__, fms->refcount); if (fms->refcount < 1) { @@ -338,22 +355,18 @@ fwmem_biodone(struct fw_xfer *xfer) void fwmem_strategy(struct bio *bp) { - struct firewire_softc *sc; struct fwmem_softc *fms; struct fw_device *fwdev; struct fw_xfer *xfer; struct cdev *dev; - int unit, err=0, s, iolen; + int err=0, s, iolen; dev = bp->bio_dev; /* XXX check request length */ - unit = DEV2UNIT(dev); - sc = devclass_get_softc(firewire_devclass, unit); - s = splfw(); fms = (struct fwmem_softc *)dev->si_drv1; - fwdev = fw_noderesolve_eui64(sc->fc, &fms->eui); + fwdev = fw_noderesolve_eui64(fms->sc->fc, &fms->eui); if (fwdev == NULL) { if (fwmem_debug) printf("fwmem: no such device ID:%08x%08x\n", diff --git a/sys/dev/firewire/fwohci.c b/sys/dev/firewire/fwohci.c index 4e7c36626be4..06bdc014a7ea 100644 --- a/sys/dev/firewire/fwohci.c +++ b/sys/dev/firewire/fwohci.c @@ -52,6 +52,7 @@ #include #include #include +#include #include @@ -90,7 +91,7 @@ static char dbkey[8][0x10]={"ST0", "ST1","ST2","ST3", static char dbcond[4][0x10]={"NEV","C=1", "C=0", "ALL"}; char fwohcicode[32][0x20]={ "No stat","Undef","long","miss Ack err", - "underrun","overrun","desc err", "data read err", + "FIFO underrun","FIFO overrun","desc err", "data read err", "data write err","bus reset","timeout","tcode err", "Undef","Undef","unknown event","flushed", "Undef","ack complete","ack pend","Undef", @@ -103,23 +104,23 @@ extern char *linkspeed[]; uint32_t tagbit[4] = { 1 << 28, 1 << 29, 1 << 30, 1 << 31}; static struct tcode_info tinfo[] = { -/* hdr_len block flag*/ -/* 0 WREQQ */ {16, FWTI_REQ | FWTI_TLABEL}, -/* 1 WREQB */ {16, FWTI_REQ | FWTI_TLABEL | FWTI_BLOCK_ASY}, -/* 2 WRES */ {12, FWTI_RES}, -/* 3 XXX */ { 0, 0}, -/* 4 RREQQ */ {12, FWTI_REQ | FWTI_TLABEL}, -/* 5 RREQB */ {16, FWTI_REQ | FWTI_TLABEL}, -/* 6 RRESQ */ {16, FWTI_RES}, -/* 7 RRESB */ {16, FWTI_RES | FWTI_BLOCK_ASY}, -/* 8 CYCS */ { 0, 0}, -/* 9 LREQ */ {16, FWTI_REQ | FWTI_TLABEL | FWTI_BLOCK_ASY}, -/* a STREAM */ { 4, FWTI_REQ | FWTI_BLOCK_STR}, -/* b LRES */ {16, FWTI_RES | FWTI_BLOCK_ASY}, -/* c XXX */ { 0, 0}, -/* d XXX */ { 0, 0}, -/* e PHY */ {12, FWTI_REQ}, -/* f XXX */ { 0, 0} +/* hdr_len block flag valid_response */ +/* 0 WREQQ */ {16, FWTI_REQ | FWTI_TLABEL, FWTCODE_WRES}, +/* 1 WREQB */ {16, FWTI_REQ | FWTI_TLABEL | FWTI_BLOCK_ASY, FWTCODE_WRES}, +/* 2 WRES */ {12, FWTI_RES, 0xff}, +/* 3 XXX */ { 0, 0, 0xff}, +/* 4 RREQQ */ {12, FWTI_REQ | FWTI_TLABEL, FWTCODE_RRESQ}, +/* 5 RREQB */ {16, FWTI_REQ | FWTI_TLABEL, FWTCODE_RRESB}, +/* 6 RRESQ */ {16, FWTI_RES, 0xff}, +/* 7 RRESB */ {16, FWTI_RES | FWTI_BLOCK_ASY, 0xff}, +/* 8 CYCS */ { 0, 0, 0xff}, +/* 9 LREQ */ {16, FWTI_REQ | FWTI_TLABEL | FWTI_BLOCK_ASY, FWTCODE_LRES}, +/* a STREAM */ { 4, FWTI_REQ | FWTI_BLOCK_STR, 0xff}, +/* b LRES */ {16, FWTI_RES | FWTI_BLOCK_ASY, 0xff}, +/* c XXX */ { 0, 0, 0xff}, +/* d XXX */ { 0, 0, 0xff}, +/* e PHY */ {12, FWTI_REQ, 0xff}, +/* f XXX */ { 0, 0, 0xff} }; #define OHCI_WRITE_SIGMASK 0xffff0000 @@ -159,9 +160,9 @@ static uint32_t fwohci_cyctimer (struct firewire_comm *); static void fwohci_rbuf_update (struct fwohci_softc *, int); static void fwohci_tbuf_update (struct fwohci_softc *, int); void fwohci_txbufdb (struct fwohci_softc *, int , struct fw_bulkxfer *); -#if FWOHCI_TASKQUEUE -static void fwohci_complete(void *, int); -#endif +static void fwohci_task_busreset(void *, int); +static void fwohci_task_sid(void *, int); +static void fwohci_task_dma(void *, int); /* * memory allocated for DMA programs @@ -264,6 +265,7 @@ d_ioctl_t fwohci_ioctl; /* * Communication with PHY device */ +/* XXX need lock for phy access */ static uint32_t fwphy_wrdata( struct fwohci_softc *sc, uint32_t addr, uint32_t data) { @@ -589,11 +591,13 @@ fwohci_reset(struct fwohci_softc *sc, device_t dev) /* Enable interrupts */ - OWRITE(sc, FWOHCI_INTMASK, - OHCI_INT_ERR | OHCI_INT_PHY_SID + sc->intmask = (OHCI_INT_ERR | OHCI_INT_PHY_SID | OHCI_INT_DMA_ATRQ | OHCI_INT_DMA_ATRS | OHCI_INT_DMA_PRRQ | OHCI_INT_DMA_PRRS | OHCI_INT_PHY_BUS_R | OHCI_INT_PW_ERR); + sc->intmask |= OHCI_INT_DMA_IR | OHCI_INT_DMA_IT; + sc->intmask |= OHCI_INT_CYC_LOST | OHCI_INT_PHY_INT; + OWRITE(sc, FWOHCI_INTMASK, sc->intmask); fwohci_set_intr(&sc->fc, 1); } @@ -605,10 +609,6 @@ fwohci_init(struct fwohci_softc *sc, device_t dev) uint32_t reg; uint8_t ui[8]; -#if FWOHCI_TASKQUEUE - TASK_INIT(&sc->fwohci_task_complete, 0, fwohci_complete, sc); -#endif - /* OHCI version */ reg = OREAD(sc, OHCI_VERSION); mver = (reg >> 16) & 0xff; @@ -761,6 +761,15 @@ fwohci_init(struct fwohci_softc *sc, device_t dev) sc->intmask = sc->irstat = sc->itstat = 0; + /* Init task queue */ + sc->fc.taskqueue = taskqueue_create_fast("fw_taskq", M_WAITOK, + taskqueue_thread_enqueue, &sc->fc.taskqueue); + taskqueue_start_threads(&sc->fc.taskqueue, 1, PI_NET, "fw%d_taskq", + device_get_unit(dev)); + TASK_INIT(&sc->fwohci_task_busreset, 2, fwohci_task_busreset, sc); + TASK_INIT(&sc->fwohci_task_sid, 1, fwohci_task_sid, sc); + TASK_INIT(&sc->fwohci_task_dma, 0, fwohci_task_dma, sc); + fw_init(&sc->fc); fwohci_reset(sc, dev); @@ -802,6 +811,14 @@ fwohci_detach(struct fwohci_softc *sc, device_t dev) fwohci_db_free(&sc->it[i]); fwohci_db_free(&sc->ir[i]); } + if (sc->fc.taskqueue != NULL) { + taskqueue_drain(sc->fc.taskqueue, &sc->fwohci_task_busreset); + taskqueue_drain(sc->fc.taskqueue, &sc->fwohci_task_sid); + taskqueue_drain(sc->fc.taskqueue, &sc->fwohci_task_dma); + taskqueue_drain(sc->fc.taskqueue, &sc->fc.task_timeout); + taskqueue_free(sc->fc.taskqueue); + sc->fc.taskqueue = NULL; + } return 0; } @@ -860,6 +877,8 @@ fwohci_start(struct fwohci_softc *sc, struct fwohci_dbch *dbch) struct tcode_info *info; static int maxdesc=0; + FW_GLOCK_ASSERT(&sc->fc); + if(&sc->atrq == dbch){ off = OHCI_ATQOFF; }else if(&sc->atrs == dbch){ @@ -878,12 +897,14 @@ txloop: if(xfer == NULL){ goto kick; } +#if 0 if(dbch->xferq.queued == 0 ){ device_printf(sc->fc.dev, "TX queue empty\n"); } +#endif STAILQ_REMOVE_HEAD(&dbch->xferq.q, link); db_tr->xfer = xfer; - xfer->state = FWXF_START; + xfer->flag = FWXF_START; fp = &xfer->send.hdr; tcode = fp->mode.common.tcode; @@ -993,6 +1014,7 @@ again: LAST_DB(dbch->pdb_tr, db); FWOHCI_DMA_SET(db->db.desc.depend, db_tr->dbcnt); } + dbch->xferq.queued ++; dbch->pdb_tr = db_tr; db_tr = STAILQ_NEXT(db_tr, link); if(db_tr != dbch->bottom){ @@ -1026,7 +1048,9 @@ static void fwohci_start_atq(struct firewire_comm *fc) { struct fwohci_softc *sc = (struct fwohci_softc *)fc; + FW_GLOCK(&sc->fc); fwohci_start( sc, &(sc->atrq)); + FW_GUNLOCK(&sc->fc); return; } @@ -1034,7 +1058,9 @@ static void fwohci_start_ats(struct firewire_comm *fc) { struct fwohci_softc *sc = (struct fwohci_softc *)fc; + FW_GLOCK(&sc->fc); fwohci_start( sc, &(sc->atrs)); + FW_GUNLOCK(&sc->fc); return; } @@ -1122,22 +1148,22 @@ fwohci_txd(struct fwohci_softc *sc, struct fwohci_dbch *dbch) } if (tr->xfer != NULL) { xfer = tr->xfer; - if (xfer->state == FWXF_RCVD) { + if (xfer->flag & FWXF_RCVD) { #if 0 if (firewire_debug) printf("already rcvd\n"); #endif fw_xfer_done(xfer); } else { - xfer->state = FWXF_SENT; + xfer->flag = FWXF_SENT; if (err == EBUSY && fc->status != FWBUSRESET) { - xfer->state = FWXF_BUSY; + xfer->flag = FWXF_BUSY; xfer->resp = err; xfer->recv.pay_len = 0; fw_xfer_done(xfer); } else if (stat != FWOHCIEV_ACKPEND) { if (stat != FWOHCIEV_ACKCOMPL) - xfer->state = FWXF_SENTERR; + xfer->flag = FWXF_SENTERR; xfer->resp = err; xfer->recv.pay_len = 0; fw_xfer_done(xfer); @@ -1150,7 +1176,9 @@ fwohci_txd(struct fwohci_softc *sc, struct fwohci_dbch *dbch) } else { printf("this shouldn't happen\n"); } + FW_GLOCK(fc); dbch->xferq.queued --; + FW_GUNLOCK(fc); tr->xfer = NULL; packets ++; @@ -1167,7 +1195,9 @@ out: if ((dbch->flags & FWOHCI_DBCH_FULL) && packets > 0) { printf("make free slot\n"); dbch->flags &= ~FWOHCI_DBCH_FULL; + FW_GLOCK(fc); fwohci_start(sc, dbch); + FW_GUNLOCK(fc); } splx(s); } @@ -1221,7 +1251,7 @@ fwohci_db_init(struct fwohci_softc *sc, struct fwohci_dbch *dbch) /*flags*/ 0, #if defined(__FreeBSD__) && __FreeBSD_version >= 501102 /*lockfunc*/busdma_lock_mutex, - /*lockarg*/&Giant, + /*lockarg*/FW_GMTX(&sc->fc), #endif &dbch->dmat)) return; @@ -1508,6 +1538,7 @@ fwohci_itxbuf_enable(struct firewire_comm *fc, int dmach) fwohci_db_init(sc, dbch); if ((dbch->flags & FWOHCI_DBCH_INIT) == 0) return ENOMEM; + err = fwohci_tx_enable(sc, dbch); } if(err) @@ -1515,6 +1546,7 @@ fwohci_itxbuf_enable(struct firewire_comm *fc, int dmach) ldesc = dbch->ndesc - 1; s = splfw(); + FW_GLOCK(fc); prev = STAILQ_LAST(&it->stdma, fw_bulkxfer, link); while ((chunk = STAILQ_FIRST(&it->stvalid)) != NULL) { struct fwohcidb *db; @@ -1541,6 +1573,7 @@ fwohci_itxbuf_enable(struct firewire_comm *fc, int dmach) STAILQ_INSERT_TAIL(&it->stdma, chunk, link); prev = chunk; } + FW_GUNLOCK(fc); fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREWRITE); fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREREAD); splx(s); @@ -1642,6 +1675,8 @@ fwohci_irx_enable(struct firewire_comm *fc, int dmach) ldesc = dbch->ndesc - 1; s = splfw(); + if ((ir->flag & FWXFERQ_HANDLER) == 0) + FW_GLOCK(fc); prev = STAILQ_LAST(&ir->stdma, fw_bulkxfer, link); while ((chunk = STAILQ_FIRST(&ir->stfree)) != NULL) { struct fwohcidb *db; @@ -1669,6 +1704,8 @@ fwohci_irx_enable(struct firewire_comm *fc, int dmach) STAILQ_INSERT_TAIL(&ir->stdma, chunk, link); prev = chunk; } + if ((ir->flag & FWXFERQ_HANDLER) == 0) + FW_GUNLOCK(fc); fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREWRITE); fwdma_sync_multiseg_all(dbch->am, BUS_DMASYNC_PREREAD); splx(s); @@ -1714,9 +1751,10 @@ fwohci_stop(struct fwohci_softc *sc, device_t dev) OWRITE(sc, OHCI_ITCTLCLR(i), OHCI_CNTL_DMA_RUN); } -/* FLUSH FIFO and reset Transmitter/Reciever */ - OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_RESET); + if (sc->fc.arq !=0 && sc->fc.arq->maxq > 0) + fw_drain_txq(&sc->fc); +#if 0 /* Let dcons(4) be accessed */ /* Stop interrupt */ OWRITE(sc, FWOHCI_INTMASKCLR, OHCI_INT_EN | OHCI_INT_ERR | OHCI_INT_PHY_SID @@ -1726,8 +1764,9 @@ fwohci_stop(struct fwohci_softc *sc, device_t dev) | OHCI_INT_DMA_ARRQ | OHCI_INT_DMA_ARRS | OHCI_INT_PHY_BUS_R); - if (sc->fc.arq !=0 && sc->fc.arq->maxq > 0) - fw_drain_txq(&sc->fc); +/* FLUSH FIFO and reset Transmitter/Reciever */ + OWRITE(sc, OHCI_HCCCTL, OHCI_HCC_RESET); +#endif /* XXX Link down? Bus reset? */ return 0; @@ -1762,15 +1801,10 @@ fwohci_resume(struct fwohci_softc *sc, device_t dev) return 0; } -#define ACK_ALL -static void -fwohci_intr_body(struct fwohci_softc *sc, uint32_t stat, int count) -{ - uint32_t irstat, itstat; - u_int i; - struct firewire_comm *fc = (struct firewire_comm *)sc; - #ifdef OHCI_DEBUG +static void +fwohci_dump_intr(struct fwohci_softc *sc, uint32_t stat) +{ 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 ":"", @@ -1796,11 +1830,16 @@ fwohci_intr_body(struct fwohci_softc *sc, uint32_t stat, int count) stat & OHCI_INT_DMA_ATRQ ? "DMA_ATRQ " :"", stat, OREAD(sc, FWOHCI_INTMASK) ); +} #endif -/* Bus reset */ - if(stat & OHCI_INT_PHY_BUS_R ){ - if (fc->status == FWBUSRESET) - goto busresetout; +static void +fwohci_intr_core(struct fwohci_softc *sc, uint32_t stat, int count) +{ + struct firewire_comm *fc = (struct firewire_comm *)sc; + uint32_t node_id, plen; + + if ((stat & OHCI_INT_PHY_BUS_R) && (fc->status != FWBUSRESET)) { + fc->status = FWBUSRESET; /* Disable bus reset interrupt until sid recv. */ OWRITE(sc, FWOHCI_INTMASKCLR, OHCI_INT_PHY_BUS_R); @@ -1813,96 +1852,14 @@ fwohci_intr_body(struct fwohci_softc *sc, uint32_t stat, int count) 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, FWBUSRESET); - OWRITE(sc, OHCI_CROMHDR, ntohl(sc->fc.config_rom[0])); - OWRITE(sc, OHCI_BUS_OPT, ntohl(sc->fc.config_rom[2])); + if (!kdb_active) + taskqueue_enqueue(sc->fc.taskqueue, &sc->fwohci_task_busreset); } -busresetout: - if((stat & OHCI_INT_DMA_IR )){ -#ifndef ACK_ALL - OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_DMA_IR); -#endif -#if defined(__DragonFly__) || __FreeBSD_version < 500000 - irstat = sc->irstat; - sc->irstat = 0; -#else - irstat = atomic_readandclear_int(&sc->irstat); -#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; - } - fwohci_rbuf_update(sc, i); - } - } - } - if((stat & OHCI_INT_DMA_IT )){ -#ifndef ACK_ALL - OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_DMA_IT); -#endif -#if defined(__DragonFly__) || __FreeBSD_version < 500000 - itstat = sc->itstat; - sc->itstat = 0; -#else - itstat = atomic_readandclear_int(&sc->itstat); -#endif - for(i = 0; i < fc->nisodma ; i++){ - if((itstat & (1 << i)) != 0){ - fwohci_tbuf_update(sc, i); - } - } - } - if((stat & OHCI_INT_DMA_PRRS )){ -#ifndef ACK_ALL - OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_DMA_PRRS); -#endif -#if 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_CYC_LOST) { - if (sc->cycle_lost >= 0) - sc->cycle_lost ++; - if (sc->cycle_lost > 10) { - sc->cycle_lost = -1; -#if 0 - OWRITE(sc, OHCI_LNKCTLCLR, OHCI_CNTL_CYCTIMER); -#endif - OWRITE(sc, FWOHCI_INTMASKCLR, OHCI_INT_CYC_LOST); - device_printf(fc->dev, "too many cycle lost, " - "no cycle master presents?\n"); - } - } - if(stat & OHCI_INT_PHY_SID){ - uint32_t *buf, node_id; - int plen; - -#ifndef ACK_ALL - OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_PHY_SID); -#endif + if (stat & OHCI_INT_PHY_SID) { /* Enable bus reset interrupt */ - OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_PHY_BUS_R); + OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_PHY_BUS_R); + OWRITE(sc, FWOHCI_INTMASK, OHCI_INT_PHY_BUS_R); + /* Allow async. request to us */ OWRITE(sc, OHCI_AREQHI, 1 << 31); /* XXX insecure ?? */ @@ -1913,13 +1870,15 @@ busresetout: 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. -*/ + + /* + * Checking whether the node is root or not. If root, turn on + * cycle master. + */ node_id = OREAD(sc, FWOHCI_NODEID); plen = OREAD(sc, OHCI_SID_CNT); + fc->nodeid = node_id & 0x3f; device_printf(fc->dev, "node_id=0x%08x, gen=%d, ", node_id, (plen >> 16) & 0xff); if (!(node_id & OHCI_NODE_VALID)) { @@ -1940,74 +1899,145 @@ busresetout: OWRITE(sc, OHCI_LNKCTL, OHCI_CNTL_CYCTIMER); } - fc->nodeid = node_id & 0x3f; + fc->status = FWBUSINIT; - if (plen & OHCI_SID_ERR) { - device_printf(fc->dev, "SID Error\n"); - goto sidout; - } - plen &= OHCI_SID_CNT_MASK; - if (plen < 4 || plen > OHCI_SIDSIZE) { - device_printf(fc->dev, "invalid SID len = %d\n", plen); - goto sidout; - } - plen -= 4; /* chop control info */ - buf = (uint32_t *)malloc(OHCI_SIDSIZE, M_FW, M_NOWAIT); - if (buf == NULL) { - device_printf(fc->dev, "malloc failed\n"); - goto sidout; - } - for (i = 0; i < plen / 4; i ++) - buf[i] = FWOHCI_DMA_READ(sc->sid_buf[i+1]); -#if 1 /* XXX needed?? */ - /* pending all pre-bus_reset packets */ - fwohci_txd(sc, &sc->atrq); - fwohci_txd(sc, &sc->atrs); - fwohci_arcv(sc, &sc->arrs, -1); - fwohci_arcv(sc, &sc->arrq, -1); - fw_drain_txq(fc); -#endif - fw_sidrcv(fc, buf, plen); - free(buf, M_FW); + if (!kdb_active) + taskqueue_enqueue(sc->fc.taskqueue, &sc->fwohci_task_sid); } sidout: - if((stat & OHCI_INT_DMA_ATRQ )){ -#ifndef ACK_ALL - OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_DMA_ATRQ); + if ((stat & ~(OHCI_INT_PHY_BUS_R | OHCI_INT_PHY_SID)) && (!kdb_active)) + taskqueue_enqueue(sc->fc.taskqueue, &sc->fwohci_task_dma); +} + +static void +fwohci_intr_dma(struct fwohci_softc *sc, uint32_t stat, int count) +{ + uint32_t irstat, itstat; + u_int i; + struct firewire_comm *fc = (struct firewire_comm *)sc; + + if (stat & OHCI_INT_DMA_IR) { + irstat = atomic_readandclear_int(&sc->irstat); + 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; + } + fwohci_rbuf_update(sc, i); + } + } + } + if (stat & OHCI_INT_DMA_IT) { + itstat = atomic_readandclear_int(&sc->itstat); + for(i = 0; i < fc->nisodma ; i++){ + if((itstat & (1 << i)) != 0){ + fwohci_tbuf_update(sc, i); + } + } + } + if (stat & OHCI_INT_DMA_PRRS) { +#if 0 + dump_dma(sc, ARRS_CH); + dump_db(sc, ARRS_CH); #endif + fwohci_arcv(sc, &sc->arrs, count); + } + if (stat & OHCI_INT_DMA_PRRQ) { +#if 0 + dump_dma(sc, ARRQ_CH); + dump_db(sc, ARRQ_CH); +#endif + fwohci_arcv(sc, &sc->arrq, count); + } + if (stat & OHCI_INT_CYC_LOST) { + if (sc->cycle_lost >= 0) + sc->cycle_lost ++; + if (sc->cycle_lost > 10) { + sc->cycle_lost = -1; +#if 0 + OWRITE(sc, OHCI_LNKCTLCLR, OHCI_CNTL_CYCTIMER); +#endif + OWRITE(sc, FWOHCI_INTMASKCLR, OHCI_INT_CYC_LOST); + device_printf(fc->dev, "too many cycle lost, " + "no cycle master presents?\n"); + } + } + if (stat & OHCI_INT_DMA_ATRQ) { fwohci_txd(sc, &(sc->atrq)); } - if((stat & OHCI_INT_DMA_ATRS )){ -#ifndef ACK_ALL - OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_DMA_ATRS); -#endif + if (stat & OHCI_INT_DMA_ATRS) { fwohci_txd(sc, &(sc->atrs)); } - if((stat & OHCI_INT_PW_ERR )){ -#ifndef ACK_ALL - OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_PW_ERR); -#endif + if (stat & OHCI_INT_PW_ERR) { device_printf(fc->dev, "posted write error\n"); } - if((stat & OHCI_INT_ERR )){ -#ifndef ACK_ALL - OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_ERR); -#endif + if (stat & OHCI_INT_ERR) { device_printf(fc->dev, "unrecoverable error\n"); } - if((stat & OHCI_INT_PHY_INT)) { -#ifndef ACK_ALL - OWRITE(sc, FWOHCI_INTSTATCLR, OHCI_INT_PHY_INT); -#endif + if (stat & OHCI_INT_PHY_INT) { device_printf(fc->dev, "phy int\n"); } return; } -#if FWOHCI_TASKQUEUE static void -fwohci_complete(void *arg, int pending) +fwohci_task_busreset(void *arg, int pending) +{ + struct fwohci_softc *sc = (struct fwohci_softc *)arg; + + fw_busreset(&sc->fc, FWBUSRESET); + OWRITE(sc, OHCI_CROMHDR, ntohl(sc->fc.config_rom[0])); + OWRITE(sc, OHCI_BUS_OPT, ntohl(sc->fc.config_rom[2])); +} + +static void +fwohci_task_sid(void *arg, int pending) +{ + struct fwohci_softc *sc = (struct fwohci_softc *)arg; + struct firewire_comm *fc = &sc->fc; + uint32_t *buf; + int i, plen; + + + plen = OREAD(sc, OHCI_SID_CNT); + + if (plen & OHCI_SID_ERR) { + device_printf(fc->dev, "SID Error\n"); + return; + } + plen &= OHCI_SID_CNT_MASK; + if (plen < 4 || plen > OHCI_SIDSIZE) { + device_printf(fc->dev, "invalid SID len = %d\n", plen); + return; + } + plen -= 4; /* chop control info */ + buf = (uint32_t *)malloc(OHCI_SIDSIZE, M_FW, M_NOWAIT); + if (buf == NULL) { + device_printf(fc->dev, "malloc failed\n"); + return; + } + for (i = 0; i < plen / 4; i ++) + buf[i] = FWOHCI_DMA_READ(sc->sid_buf[i+1]); +#if 1 /* XXX needed?? */ + /* pending all pre-bus_reset packets */ + fwohci_txd(sc, &sc->atrq); + fwohci_txd(sc, &sc->atrs); + fwohci_arcv(sc, &sc->arrs, -1); + fwohci_arcv(sc, &sc->arrq, -1); + fw_drain_txq(fc); +#endif + fw_sidrcv(fc, buf, plen); + free(buf, M_FW); +} + +static void +fwohci_task_dma(void *arg, int pending) { struct fwohci_softc *sc = (struct fwohci_softc *)arg; uint32_t stat; @@ -2015,15 +2045,14 @@ fwohci_complete(void *arg, int pending) again: stat = atomic_readandclear_int(&sc->intstat); if (stat) - fwohci_intr_body(sc, stat, -1); + fwohci_intr_dma(sc, stat, -1); else return; goto again; } -#endif -static uint32_t -fwochi_check_stat(struct fwohci_softc *sc) +static int +fwohci_check_stat(struct fwohci_softc *sc) { uint32_t stat, irstat, itstat; @@ -2031,12 +2060,16 @@ fwochi_check_stat(struct fwohci_softc *sc) if (stat == 0xffffffff) { device_printf(sc->fc.dev, "device physically ejected?\n"); - return(stat); + return (FILTER_STRAY); } -#ifdef ACK_ALL if (stat) - OWRITE(sc, FWOHCI_INTSTATCLR, stat); -#endif + OWRITE(sc, FWOHCI_INTSTATCLR, stat & ~OHCI_INT_PHY_BUS_R); + + stat &= sc->intmask; + if (stat == 0) + return (FILTER_STRAY); + + atomic_set_int(&sc->intstat, stat); if (stat & OHCI_INT_DMA_IR) { irstat = OREAD(sc, OHCI_IR_STAT); OWRITE(sc, OHCI_IR_STATCLR, irstat); @@ -2047,68 +2080,34 @@ fwochi_check_stat(struct fwohci_softc *sc) OWRITE(sc, OHCI_IT_STATCLR, itstat); atomic_set_int(&sc->itstat, itstat); } - return(stat); + + fwohci_intr_core(sc, stat, -1); + return (FILTER_HANDLED); +} + +int +fwohci_filt(void *arg) +{ + struct fwohci_softc *sc = (struct fwohci_softc *)arg; + + if (!(sc->intmask & OHCI_INT_EN)) { + /* polling mode */ + return (FILTER_STRAY); + } + return (fwohci_check_stat(sc)); } void fwohci_intr(void *arg) { - struct fwohci_softc *sc = (struct fwohci_softc *)arg; - uint32_t stat; -#if !FWOHCI_TASKQUEUE - uint32_t bus_reset = 0; -#endif - - if (!(sc->intmask & OHCI_INT_EN)) { - /* polling mode */ - return; - } - -#if !FWOHCI_TASKQUEUE -again: -#endif - stat = fwochi_check_stat(sc); - if (stat == 0 || stat == 0xffffffff) - return; -#if FWOHCI_TASKQUEUE - atomic_set_int(&sc->intstat, stat); - /* XXX mask bus reset intr. during bus reset phase */ - if (stat) - taskqueue_enqueue(taskqueue_swi_giant, &sc->fwohci_task_complete); -#else - /* We cannot clear bus reset event during bus reset phase */ - if ((stat & ~bus_reset) == 0) - return; - bus_reset = stat & OHCI_INT_PHY_BUS_R; - fwohci_intr_body(sc, stat, -1); - goto again; -#endif + fwohci_filt(arg); } void fwohci_poll(struct firewire_comm *fc, int quick, int count) { - int s; - uint32_t stat; - struct fwohci_softc *sc; - - - sc = (struct fwohci_softc *)fc; - stat = OHCI_INT_DMA_IR | OHCI_INT_DMA_IT | - OHCI_INT_DMA_PRRS | OHCI_INT_DMA_PRRQ | - OHCI_INT_DMA_ATRQ | OHCI_INT_DMA_ATRS; -#if 0 - if (!quick) { -#else - if (1) { -#endif - stat = fwochi_check_stat(sc); - if (stat == 0 || stat == 0xffffffff) - return; - } - s = splfw(); - fwohci_intr_body(sc, stat, count); - splx(s); + struct fwohci_softc *sc = (struct fwohci_softc *)fc; + fwohci_check_stat(sc); } static void @@ -2141,6 +2140,7 @@ fwohci_tbuf_update(struct fwohci_softc *sc, int dmach) it = fc->it[dmach]; ldesc = sc->it[dmach].ndesc - 1; s = splfw(); /* unnecessary ? */ + FW_GLOCK(fc); fwdma_sync_multiseg_all(sc->it[dmach].am, BUS_DMASYNC_POSTREAD); if (firewire_debug) dump_db(sc, ITX_CH + dmach); @@ -2169,6 +2169,7 @@ fwohci_tbuf_update(struct fwohci_softc *sc, int dmach) STAILQ_INSERT_TAIL(&it->stfree, chunk, link); w++; } + FW_GUNLOCK(fc); splx(s); if (w) wakeup(it); @@ -2182,14 +2183,17 @@ fwohci_rbuf_update(struct fwohci_softc *sc, int dmach) struct fw_bulkxfer *chunk; struct fw_xferq *ir; uint32_t stat; - int s, w=0, ldesc; + int s, w = 0, ldesc; ir = fc->ir[dmach]; ldesc = sc->ir[dmach].ndesc - 1; + #if 0 dump_db(sc, dmach); #endif s = splfw(); + if ((ir->flag & FWXFERQ_HANDLER) == 0) + FW_GLOCK(fc); fwdma_sync_multiseg_all(sc->ir[dmach].am, BUS_DMASYNC_POSTREAD); while ((chunk = STAILQ_FIRST(&ir->stdma)) != NULL) { db_tr = (struct fwohcidb_tr *)chunk->end; @@ -2224,13 +2228,16 @@ fwohci_rbuf_update(struct fwohci_softc *sc, int dmach) } w++; } + if ((ir->flag & FWXFERQ_HANDLER) == 0) + FW_GUNLOCK(fc); splx(s); - if (w) { - if (ir->flag & FWXFERQ_HANDLER) - ir->hand(ir); - else - wakeup(ir); - } + if (w == 0) + return; + + if (ir->flag & FWXFERQ_HANDLER) + ir->hand(ir); + else + wakeup(ir); } void @@ -2487,6 +2494,8 @@ fwohci_txbufdb(struct fwohci_softc *sc, int dmach, struct fw_bulkxfer *bulkxfer) unsigned short chtag; int idb; + FW_GLOCK_ASSERT(&sc->fc); + dbch = &sc->it[dmach]; chtag = sc->it[dmach].xferq.flag & 0xff; diff --git a/sys/dev/firewire/fwohci_pci.c b/sys/dev/firewire/fwohci_pci.c index ddc4f480fd1f..b21bb28afb30 100644 --- a/sys/dev/firewire/fwohci_pci.c +++ b/sys/dev/firewire/fwohci_pci.c @@ -302,6 +302,7 @@ fwohci_pci_attach(device_t self) firewire_debug = bootverbose; #endif + mtx_init(FW_GMTX(&sc->fc), "firewire", NULL, MTX_DEF); fwohci_pci_init(self); rid = PCI_CBMEM; @@ -335,12 +336,12 @@ fwohci_pci_attach(device_t self) err = bus_setup_intr(self, sc->irq_res, -#if FWOHCI_TASKQUEUE INTR_TYPE_NET | INTR_MPSAFE, +#if FWOHCI_INTFILT + fwohci_filt, NULL, sc, &sc->ih); #else - INTR_TYPE_NET, -#endif NULL, (driver_intr_t *) fwohci_intr, sc, &sc->ih); +#endif #if defined(__DragonFly__) || __FreeBSD_version < 500000 /* XXX splcam() should mask this irq for sbp.c*/ err = bus_setup_intr(self, sc->irq_res, INTR_TYPE_CAM, @@ -376,7 +377,7 @@ fwohci_pci_attach(device_t self) /*flags*/BUS_DMA_ALLOCNOW, #if defined(__FreeBSD__) && __FreeBSD_version >= 501102 /*lockfunc*/busdma_lock_mutex, - /*lockarg*/&Giant, + /*lockarg*/FW_GMTX(&sc->fc), #endif &sc->fc.dmat); if (err != 0) { @@ -448,6 +449,7 @@ fwohci_pci_detach(device_t self) } fwohci_detach(sc, self); + mtx_destroy(FW_GMTX(&sc->fc)); splx(s); return 0; @@ -492,7 +494,7 @@ fwohci_pci_add_child(device_t dev, int order, const char *name, int unit) { struct fwohci_softc *sc; device_t child; - int s, err = 0; + int err = 0; sc = (struct fwohci_softc *)device_get_softc(dev); child = device_add_child(dev, name, unit); @@ -516,6 +518,7 @@ fwohci_pci_add_child(device_t dev, int order, const char *name, int unit) * interrupt is disabled during the boot process. */ if (cold) { + int s; DELAY(250); /* 2 cycles */ s = splfw(); fwohci_poll((void *)sc, 0, -1); diff --git a/sys/dev/firewire/fwohcivar.h b/sys/dev/firewire/fwohcivar.h index 8435c5d3b1b1..d0ee9f65ecaa 100644 --- a/sys/dev/firewire/fwohcivar.h +++ b/sys/dev/firewire/fwohcivar.h @@ -35,13 +35,12 @@ * */ -#if defined(__DragonFly__) || __FreeBSD_version < 500000 -#define FWOHCI_TASKQUEUE 0 -#else -#define FWOHCI_TASKQUEUE 1 -#endif -#if FWOHCI_TASKQUEUE #include + +#if defined(__DragonFly__) || __FreeBSD_version < 700043 +#define FWOHCI_INTFILT 0 +#else +#define FWOHCI_INTFILT 1 #endif typedef struct fwohci_softc { @@ -77,14 +76,15 @@ typedef struct fwohci_softc { struct fwdma_alloc crom_dma; struct fwdma_alloc dummy_dma; uint32_t intmask, irstat, itstat; -#if FWOHCI_TASKQUEUE uint32_t intstat; - struct task fwohci_task_complete; -#endif + struct task fwohci_task_busreset; + struct task fwohci_task_sid; + struct task fwohci_task_dma; int cycle_lost; } fwohci_softc_t; void fwohci_intr (void *arg); +int fwohci_filt (void *arg); int fwohci_init (struct fwohci_softc *, device_t); void fwohci_poll (struct firewire_comm *, int, int); void fwohci_reset (struct fwohci_softc *, device_t); diff --git a/sys/dev/firewire/if_fwe.c b/sys/dev/firewire/if_fwe.c index b56c5cde9fcd..438838d404cd 100644 --- a/sys/dev/firewire/if_fwe.c +++ b/sys/dev/firewire/if_fwe.c @@ -157,6 +157,7 @@ fwe_attach(device_t dev) unit = device_get_unit(dev); bzero(fwe, sizeof(struct fwe_softc)); + mtx_init(&fwe->mtx, "fwe", NULL, MTX_DEF); /* XXX */ fwe->stream_ch = stream_ch; fwe->dma_ch = -1; @@ -213,8 +214,7 @@ fwe_attach(device_t dev) ifp->if_start = fwe_start; ifp->if_ioctl = fwe_ioctl; ifp->if_mtu = ETHERMTU; - ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST| - IFF_NEEDSGIANT); + ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST); ifp->if_snd.ifq_maxlen = TX_MAX_QUEUE; s = splimp(); @@ -305,6 +305,7 @@ fwe_detach(device_t dev) #endif splx(s); + mtx_destroy(&fwe->mtx); return 0; } @@ -325,22 +326,15 @@ fwe_init(void *arg) ifp->if_flags |= IFF_PROMISC; fc = fwe->fd.fc; -#define START 0 if (fwe->dma_ch < 0) { - for (i = START; i < fc->nisodma; i ++) { - xferq = fc->ir[i]; - if ((xferq->flag & FWXFERQ_OPEN) == 0) - goto found; - } - printf("no free dma channel\n"); - return; -found: - fwe->dma_ch = i; + fwe->dma_ch = fw_open_isodma(fc, /* tx */0); + if (fwe->dma_ch < 0) + return; + xferq = fc->ir[fwe->dma_ch]; + xferq->flag |= FWXFERQ_EXTBUF | + FWXFERQ_HANDLER | FWXFERQ_STREAM; fwe->stream_ch = stream_ch; fwe->pkt_hdr.mode.stream.chtag = fwe->stream_ch; - /* allocate DMA channel and init packet mode */ - xferq->flag |= FWXFERQ_OPEN | FWXFERQ_EXTBUF | - FWXFERQ_HANDLER | FWXFERQ_STREAM; xferq->flag &= ~0xff; xferq->flag |= fwe->stream_ch & 0xff; /* register fwe_input handler */ @@ -375,7 +369,7 @@ found: STAILQ_INSERT_TAIL(&xferq->stfree, &xferq->bulkxfer[i], link); } else - printf("fwe_as_input: m_getcl failed\n"); + printf("%s: m_getcl failed\n", __FUNCTION__); } STAILQ_INIT(&fwe->xferlist); for (i = 0; i < TX_MAX_QUEUE; i++) { @@ -520,7 +514,9 @@ fwe_output_callback(struct fw_xfer *xfer) fw_xfer_unload(xfer); s = splimp(); + FWE_LOCK(fwe); STAILQ_INSERT_TAIL(&fwe->xferlist, xfer, link); + FWE_UNLOCK(fwe); splx(s); /* for queue full */ @@ -534,8 +530,6 @@ fwe_start(struct ifnet *ifp) struct fwe_softc *fwe = ((struct fwe_eth_softc *)ifp->if_softc)->fwe; int s; - GIANT_REQUIRED; - FWEDEBUG(ifp, "starting\n"); if (fwe->dma_ch < 0) { @@ -589,16 +583,27 @@ fwe_as_output(struct fwe_softc *fwe, struct ifnet *ifp) xfer = NULL; xferq = fwe->fd.fc->atq; - while (xferq->queued < xferq->maxq - 1) { + while ((xferq->queued < xferq->maxq - 1) && + (ifp->if_snd.ifq_head != NULL)) { + FWE_LOCK(fwe); xfer = STAILQ_FIRST(&fwe->xferlist); if (xfer == NULL) { +#if 0 printf("if_fwe: lack of xfer\n"); - return; - } - IF_DEQUEUE(&ifp->if_snd, m); - if (m == NULL) +#endif + FWE_UNLOCK(fwe); break; + } STAILQ_REMOVE_HEAD(&fwe->xferlist, link); + FWE_UNLOCK(fwe); + + IF_DEQUEUE(&ifp->if_snd, m); + if (m == NULL) { + FWE_LOCK(fwe); + STAILQ_INSERT_HEAD(&fwe->xferlist, xfer, link); + FWE_UNLOCK(fwe); + break; + } #if defined(__DragonFly__) || __FreeBSD_version < 500000 if (ifp->if_bpf != NULL) bpf_mtap(ifp, m); @@ -649,6 +654,7 @@ fwe_as_input(struct fw_xferq *xferq) fwe = (struct fwe_softc *)xferq->sc; ifp = fwe->eth_softc.ifp; + /* We do not need a lock here because the bottom half is serialized */ while ((sxfer = STAILQ_FIRST(&xferq->stvalid)) != NULL) { STAILQ_REMOVE_HEAD(&xferq->stvalid, link); fp = mtod(sxfer->mbuf, struct fw_pkt *); @@ -662,7 +668,7 @@ fwe_as_input(struct fw_xferq *xferq) m0->m_len = m0->m_pkthdr.len = m0->m_ext.ext_size; STAILQ_INSERT_TAIL(&xferq->stfree, sxfer, link); } else - printf("fwe_as_input: m_getcl failed\n"); + printf("%s: m_getcl failed\n", __FUNCTION__); if (sxfer->resp != 0 || fp->mode.stream.len < ETHER_ALIGN + sizeof(struct ether_header)) { @@ -672,7 +678,7 @@ fwe_as_input(struct fw_xferq *xferq) } m->m_data += HDR_LEN + ETHER_ALIGN; - c = mtod(m, char *); + c = mtod(m, u_char *); #if defined(__DragonFly__) || __FreeBSD_version < 500000 eh = (struct ether_header *)c; m->m_data += sizeof(struct ether_header); diff --git a/sys/dev/firewire/if_fwevar.h b/sys/dev/firewire/if_fwevar.h index 73fcb3df285c..4b8eb76d0605 100644 --- a/sys/dev/firewire/if_fwevar.h +++ b/sys/dev/firewire/if_fwevar.h @@ -38,7 +38,7 @@ #define _NET_IF_FWEVAR_H_ struct fwe_softc { - /* XXX this must be first for fd.post_explore() */ + /* XXX this must be the first for fd.post_explore() */ struct firewire_dev_comm fd; short stream_ch; short dma_ch; @@ -48,5 +48,8 @@ struct fwe_softc { struct ifnet *ifp; struct fwe_softc *fwe; } eth_softc; + struct mtx mtx; }; +#define FWE_LOCK(fwe) mtx_lock(&(fwe)->mtx) +#define FWE_UNLOCK(fwe) mtx_unlock(&(fwe)->mtx) #endif /* !_NET_IF_FWEVAR_H_ */ diff --git a/sys/dev/firewire/if_fwip.c b/sys/dev/firewire/if_fwip.c index d7b2c315073f..a9d1f38faf02 100644 --- a/sys/dev/firewire/if_fwip.c +++ b/sys/dev/firewire/if_fwip.c @@ -161,6 +161,7 @@ fwip_attach(device_t dev) if (ifp == NULL) return (ENOSPC); + mtx_init(&fwip->mtx, "fwip", NULL, MTX_DEF); /* XXX */ fwip->dma_ch = -1; @@ -197,8 +198,7 @@ fwip_attach(device_t dev) ifp->if_init = fwip_init; ifp->if_start = fwip_start; ifp->if_ioctl = fwip_ioctl; - ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST| - IFF_NEEDSGIANT); + ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST); ifp->if_snd.ifq_maxlen = TX_MAX_QUEUE; #ifdef DEVICE_POLLING ifp->if_capabilities |= IFCAP_POLLING; @@ -282,6 +282,7 @@ fwip_detach(device_t dev) fwip_stop(fwip); firewire_ifdetach(ifp); if_free(ifp); + mtx_destroy(&fwip->mtx); splx(s); return 0; @@ -303,17 +304,11 @@ fwip_init(void *arg) fc = fwip->fd.fc; #define START 0 if (fwip->dma_ch < 0) { - for (i = START; i < fc->nisodma; i ++) { - xferq = fc->ir[i]; - if ((xferq->flag & FWXFERQ_OPEN) == 0) - goto found; - } - printf("no free dma channel\n"); - return; -found: - fwip->dma_ch = i; - /* allocate DMA channel and init packet mode */ - xferq->flag |= FWXFERQ_OPEN | FWXFERQ_EXTBUF | + fwip->dma_ch = fw_open_isodma(fc, /* tx */0); + if (fwip->dma_ch < 0) + return; + xferq = fc->ir[fwip->dma_ch]; + xferq->flag |= FWXFERQ_EXTBUF | FWXFERQ_HANDLER | FWXFERQ_STREAM; xferq->flag &= ~0xff; xferq->flag |= broadcast_channel & 0xff; @@ -522,8 +517,6 @@ fwip_output_callback(struct fw_xfer *xfer) struct ifnet *ifp; int s; - GIANT_REQUIRED; - fwip = (struct fwip_softc *)xfer->sc; ifp = fwip->fw_softc.fwip_ifp; /* XXX error check */ @@ -535,12 +528,15 @@ fwip_output_callback(struct fw_xfer *xfer) fw_xfer_unload(xfer); s = splimp(); + FWIP_LOCK(fwip); STAILQ_INSERT_TAIL(&fwip->xferlist, xfer, link); + FWIP_UNLOCK(fwip); splx(s); /* for queue full */ - if (ifp->if_snd.ifq_head != NULL) + if (ifp->if_snd.ifq_head != NULL) { fwip_start(ifp); + } } static void @@ -549,8 +545,6 @@ fwip_start(struct ifnet *ifp) struct fwip_softc *fwip = ((struct fwip_eth_softc *)ifp->if_softc)->fwip; int s; - GIANT_REQUIRED; - FWIPDEBUG(ifp, "starting\n"); if (fwip->dma_ch < 0) { @@ -603,19 +597,29 @@ fwip_async_output(struct fwip_softc *fwip, struct ifnet *ifp) int error; int i = 0; - GIANT_REQUIRED; - xfer = NULL; - xferq = fwip->fd.fc->atq; - while (xferq->queued < xferq->maxq - 1) { + xferq = fc->atq; + while ((xferq->queued < xferq->maxq - 1) && + (ifp->if_snd.ifq_head != NULL)) { + FWIP_LOCK(fwip); xfer = STAILQ_FIRST(&fwip->xferlist); if (xfer == NULL) { + FWIP_UNLOCK(fwip); +#if 0 printf("if_fwip: lack of xfer\n"); - return; - } - IF_DEQUEUE(&ifp->if_snd, m); - if (m == NULL) +#endif break; + } + STAILQ_REMOVE_HEAD(&fwip->xferlist, link); + FWIP_UNLOCK(fwip); + + IF_DEQUEUE(&ifp->if_snd, m); + if (m == NULL) { + FWIP_LOCK(fwip); + STAILQ_INSERT_HEAD(&fwip->xferlist, xfer, link); + FWIP_UNLOCK(fwip); + break; + } /* * Dig out the link-level address which @@ -629,7 +633,6 @@ fwip_async_output(struct fwip_softc *fwip, struct ifnet *ifp) else destfw = (struct fw_hwaddr *) (mtag + 1); - STAILQ_REMOVE_HEAD(&fwip->xferlist, link); /* * We don't do any bpf stuff here - the generic code @@ -722,7 +725,9 @@ fwip_async_output(struct fwip_softc *fwip, struct ifnet *ifp) * for later transmission. */ xfer->mbuf = 0; + FWIP_LOCK(fwip); STAILQ_INSERT_TAIL(&fwip->xferlist, xfer, link); + FWIP_UNLOCK(fwip); IF_PREPEND(&ifp->if_snd, m); break; } @@ -741,13 +746,8 @@ fwip_async_output(struct fwip_softc *fwip, struct ifnet *ifp) if (i > 1) printf("%d queued\n", i); #endif - if (i > 0) { -#if 1 + if (i > 0) xferq->start(fc); -#else - taskqueue_enqueue(taskqueue_swi_giant, &fwip->start_send); -#endif - } } static void @@ -755,7 +755,6 @@ fwip_start_send (void *arg, int count) { struct fwip_softc *fwip = arg; - GIANT_REQUIRED; fwip->fd.fc->atq->start(fwip->fd.fc); } @@ -772,7 +771,6 @@ fwip_stream_input(struct fw_xferq *xferq) uint16_t src; uint32_t *p; - GIANT_REQUIRED; fwip = (struct fwip_softc *)xferq->sc; ifp = fwip->fw_softc.fwip_ifp; @@ -874,8 +872,6 @@ fwip_unicast_input_recycle(struct fwip_softc *fwip, struct fw_xfer *xfer) { struct mbuf *m; - GIANT_REQUIRED; - /* * We have finished with a unicast xfer. Allocate a new * cluster and stick it on the back of the input queue. @@ -900,8 +896,6 @@ fwip_unicast_input(struct fw_xfer *xfer) //struct fw_pkt *sfp; int rtcode; - GIANT_REQUIRED; - fwip = (struct fwip_softc *)xfer->sc; ifp = fwip->fw_softc.fwip_ifp; m = xfer->mbuf; diff --git a/sys/dev/firewire/if_fwipvar.h b/sys/dev/firewire/if_fwipvar.h index 153ce949865d..57e7904b5f81 100644 --- a/sys/dev/firewire/if_fwipvar.h +++ b/sys/dev/firewire/if_fwipvar.h @@ -58,5 +58,8 @@ struct fwip_softc { struct ifnet *fwip_ifp; struct fwip_softc *fwip; } fw_softc; + struct mtx mtx; }; +#define FWIP_LOCK(fwip) mtx_lock(&(fwip)->mtx) +#define FWIP_UNLOCK(fwip) mtx_unlock(&(fwip)->mtx) #endif /* !_NET_IF_FWIPVAR_H_ */ diff --git a/sys/dev/firewire/sbp.c b/sys/dev/firewire/sbp.c index 1971e38bb6a8..a004f956308a 100644 --- a/sys/dev/firewire/sbp.c +++ b/sys/dev/firewire/sbp.c @@ -245,7 +245,10 @@ struct sbp_softc { struct timeval last_busreset; #define SIMQ_FREEZED 1 int flags; + struct mtx mtx; }; +#define SBP_LOCK(sbp) mtx_lock(&(sbp)->mtx) +#define SBP_UNLOCK(sbp) mtx_unlock(&(sbp)->mtx) static void sbp_post_explore (void *); static void sbp_recv (struct fw_xfer *); @@ -736,8 +739,10 @@ END_DEBUG continue; if (alive && (sdev->status != SBP_DEV_DEAD)) { if (sdev->path != NULL) { + SBP_LOCK(sbp); xpt_freeze_devq(sdev->path, 1); sdev->freeze ++; + SBP_UNLOCK(sbp); } sbp_probe_lun(sdev); SBP_DEBUG(0) @@ -769,8 +774,10 @@ SBP_DEBUG(0) printf("lost target\n"); END_DEBUG if (sdev->path) { + SBP_LOCK(sbp); xpt_freeze_devq(sdev->path, 1); sdev->freeze ++; + SBP_UNLOCK(sbp); } sdev->status = SBP_DEV_RETRY; sbp_abort_all_ocbs(sdev, CAM_SCSI_BUS_RESET); @@ -798,8 +805,10 @@ SBP_DEBUG(0) printf("sbp_post_busreset\n"); END_DEBUG if ((sbp->sim->flags & SIMQ_FREEZED) == 0) { + SBP_LOCK(sbp); xpt_freeze_simq(sbp->sim, /*count*/1); sbp->sim->flags |= SIMQ_FREEZED; + SBP_UNLOCK(sbp); } microtime(&sbp->last_busreset); } @@ -870,8 +879,10 @@ END_DEBUG if (target->num_lun == 0) sbp_free_target(target); } + SBP_LOCK(sbp); xpt_release_simq(sbp->sim, /*run queue*/TRUE); sbp->sim->flags &= ~SIMQ_FREEZED; + SBP_UNLOCK(sbp); } #if NEED_RESPONSE @@ -901,7 +912,9 @@ sbp_xfer_free(struct fw_xfer *xfer) sdev = (struct sbp_dev *)xfer->sc; fw_xfer_unload(xfer); s = splfw(); + SBP_LOCK(sdev->target->sbp); STAILQ_INSERT_TAIL(&sdev->target->xferlist, xfer, link); + SBP_UNLOCK(sdev->target->sbp); splx(s); } @@ -1043,9 +1056,11 @@ END_DEBUG ccb->ccb_h.ccb_sdev_ptr = sdev; /* The scan is in progress now. */ + SBP_LOCK(target->sbp); xpt_action(ccb); xpt_release_devq(sdev->path, sdev->freeze, TRUE); sdev->freeze = 1; + SBP_UNLOCK(target->sbp); } static __inline void @@ -1108,8 +1123,10 @@ END_DEBUG sbp_xfer_free(xfer); if (sdev->path) { + SBP_LOCK(sdev->target->sbp); xpt_release_devq(sdev->path, sdev->freeze, TRUE); sdev->freeze = 0; + SBP_UNLOCK(sdev->target->sbp); } } @@ -1353,20 +1370,25 @@ sbp_mgm_orb(struct sbp_dev *sdev, int func, struct sbp_ocb *aocb) nid = target->sbp->fd.fc->nodeid | FWLOCALBUS; s = splfw(); + SBP_LOCK(target->sbp); if (func == ORB_FUN_RUNQUEUE) { ocb = STAILQ_FIRST(&target->mgm_ocb_queue); if (target->mgm_ocb_cur != NULL || ocb == NULL) { + SBP_UNLOCK(target->sbp); splx(s); return; } STAILQ_REMOVE_HEAD(&target->mgm_ocb_queue, ocb); + SBP_UNLOCK(target->sbp); goto start; } if ((ocb = sbp_get_ocb(sdev)) == NULL) { + SBP_UNLOCK(target->sbp); splx(s); /* XXX */ return; } + SBP_UNLOCK(target->sbp); ocb->flags = OCB_ACT_MGM; ocb->sdev = sdev; @@ -1404,7 +1426,9 @@ END_DEBUG if (target->mgm_ocb_cur != NULL) { /* there is a standing ORB */ + SBP_LOCK(target->sbp); STAILQ_INSERT_TAIL(&sdev->target->mgm_ocb_queue, ocb, ocb); + SBP_UNLOCK(target->sbp); splx(s); return; } @@ -1738,8 +1762,10 @@ END_DEBUG /* we have to reset the fetch agent if it's dead */ if (sbp_status->dead) { if (sdev->path) { + SBP_LOCK(sbp); xpt_freeze_devq(sdev->path, 1); sdev->freeze ++; + SBP_UNLOCK(sbp); } reset_agent = 1; } @@ -1847,7 +1873,9 @@ printf("len %d\n", sbp_status->len); /* fix up inq data */ if (ccb->csio.cdb_io.cdb_bytes[0] == INQUIRY) sbp_fix_inq_data(ocb); + SBP_LOCK(sbp); xpt_done(ccb); + SBP_UNLOCK(sbp); } break; default: @@ -1910,6 +1938,7 @@ sbp_attach(device_t dev) { struct sbp_softc *sbp; struct cam_devq *devq; + struct firewire_comm *fc; int i, s, error; if (DFLTPHYS > SBP_MAXPHYS) @@ -1926,12 +1955,13 @@ END_DEBUG sbp = ((struct sbp_softc *)device_get_softc(dev)); bzero(sbp, sizeof(struct sbp_softc)); sbp->fd.dev = dev; - sbp->fd.fc = device_get_ivars(dev); + sbp->fd.fc = fc = device_get_ivars(dev); + mtx_init(&sbp->mtx, "sbp", NULL, MTX_DEF); if (max_speed < 0) - max_speed = sbp->fd.fc->speed; + max_speed = fc->speed; - error = bus_dma_tag_create(/*parent*/sbp->fd.fc->dmat, + error = bus_dma_tag_create(/*parent*/fc->dmat, /* XXX shoud be 4 for sane backend? */ /*alignment*/1, /*boundary*/0, @@ -1943,7 +1973,7 @@ END_DEBUG /*flags*/BUS_DMA_ALLOCNOW, #if defined(__FreeBSD__) && __FreeBSD_version >= 501102 /*lockfunc*/busdma_lock_mutex, - /*lockarg*/&Giant, + /*lockarg*/&sbp->mtx, #endif &sbp->dmat); if (error != 0) { @@ -1963,7 +1993,7 @@ END_DEBUG sbp->sim = cam_sim_alloc(sbp_action, sbp_poll, "sbp", sbp, device_get_unit(dev), - &Giant, + &sbp->mtx, /*untagged*/ 1, /*tagged*/ SBP_QUEUE_LEN - 1, devq); @@ -1973,7 +2003,7 @@ END_DEBUG return (ENXIO); } - + SBP_LOCK(sbp); if (xpt_bus_register(sbp->sim, /*bus*/0) != CAM_SUCCESS) goto fail; @@ -1982,6 +2012,7 @@ END_DEBUG xpt_bus_deregister(cam_sim_path(sbp->sim)); goto fail; } + SBP_UNLOCK(sbp); /* We reserve 16 bit space (4 bytes X 64 targets X 256 luns) */ sbp->fwb.start = ((u_int64_t)SBP_BIND_HI << 32) | SBP_DEV2ADDR(0, 0); @@ -1990,22 +2021,26 @@ END_DEBUG STAILQ_INIT(&sbp->fwb.xferlist); fw_xferlist_add(&sbp->fwb.xferlist, M_SBP, /*send*/ 0, /*recv*/ SBP_RECV_LEN, SBP_NUM_OCB/2, - sbp->fd.fc, (void *)sbp, sbp_recv); - fw_bindadd(sbp->fd.fc, &sbp->fwb); + fc, (void *)sbp, sbp_recv); + + fw_bindadd(fc, &sbp->fwb); sbp->fd.post_busreset = sbp_post_busreset; sbp->fd.post_explore = sbp_post_explore; - if (sbp->fd.fc->status != -1) { + if (fc->status != -1) { s = splfw(); sbp_post_busreset((void *)sbp); sbp_post_explore((void *)sbp); splx(s); } + SBP_LOCK(sbp); xpt_async(AC_BUS_RESET, sbp->path, /*arg*/ NULL); + SBP_UNLOCK(sbp); return (0); fail: + SBP_UNLOCK(sbp); cam_sim_free(sbp->sim, /*free_devq*/TRUE); return (ENXIO); } @@ -2100,10 +2135,13 @@ END_DEBUG for (i = 0; i < SBP_NUM_TARGETS; i ++) sbp_cam_detach_target(&sbp->targets[i]); + + SBP_LOCK(sbp); xpt_async(AC_LOST_DEVICE, sbp->path, NULL); xpt_free_path(sbp->path); xpt_bus_deregister(cam_sim_path(sbp->sim)); cam_sim_free(sbp->sim, /*free_devq*/ TRUE), + SBP_UNLOCK(sbp); sbp_logout_all(sbp); @@ -2117,6 +2155,7 @@ END_DEBUG fw_xferlist_remove(&sbp->fwb.xferlist); bus_dma_tag_destroy(sbp->dmat); + mtx_destroy(&sbp->mtx); return (0); } @@ -2130,15 +2169,17 @@ sbp_cam_detach_sdev(struct sbp_dev *sdev) return; if (sdev->status == SBP_DEV_RESET) return; + sbp_abort_all_ocbs(sdev, CAM_DEV_NOT_THERE); if (sdev->path) { + SBP_LOCK(sdev->target->sbp); xpt_release_devq(sdev->path, sdev->freeze, TRUE); sdev->freeze = 0; xpt_async(AC_LOST_DEVICE, sdev->path, NULL); xpt_free_path(sdev->path); sdev->path = NULL; + SBP_UNLOCK(sdev->target->sbp); } - sbp_abort_all_ocbs(sdev, CAM_DEV_NOT_THERE); } static void @@ -2171,8 +2212,10 @@ sbp_target_reset(struct sbp_dev *sdev, int method) continue; if (tsdev->status == SBP_DEV_RESET) continue; + SBP_LOCK(target->sbp); xpt_freeze_devq(tsdev->path, 1); tsdev->freeze ++; + SBP_UNLOCK(target->sbp); sbp_abort_all_ocbs(tsdev, CAM_CMD_TIMEOUT); if (method == 2) tsdev->status = SBP_DEV_LOGIN; @@ -2227,8 +2270,10 @@ sbp_timeout(void *arg) switch(sdev->timeout) { case 1: printf("agent reset\n"); + SBP_LOCK(sdev->target->sbp); xpt_freeze_devq(sdev->path, 1); sdev->freeze ++; + SBP_UNLOCK(sdev->target->sbp); sbp_abort_all_ocbs(sdev, CAM_CMD_TIMEOUT); sbp_agent_reset(sdev); break; @@ -2332,6 +2377,7 @@ END_DEBUG void *cdb; csio = &ccb->csio; + mtx_assert(sim->mtx, MA_OWNED); SBP_DEBUG(2) printf("%s:%d:%d XPT_SCSI_IO: " @@ -2375,8 +2421,10 @@ END_DEBUG if ((ocb = sbp_get_ocb(sdev)) == NULL) { ccb->ccb_h.status = CAM_REQUEUE_REQ; if (sdev->freeze == 0) { + SBP_LOCK(sdev->target->sbp); xpt_freeze_devq(sdev->path, 1); sdev->freeze ++; + SBP_UNLOCK(sdev->target->sbp); } xpt_done(ccb); return; @@ -2681,6 +2729,7 @@ SBP_DEBUG(1) #endif __func__, ntohl(sbp_status->orb_lo), sbp_status->src); END_DEBUG + SBP_LOCK(sdev->target->sbp); for (ocb = STAILQ_FIRST(&sdev->ocbs); ocb != NULL; ocb = next) { next = STAILQ_NEXT(ocb, ocb); flags = ocb->flags; @@ -2728,6 +2777,7 @@ END_DEBUG } else order ++; } + SBP_UNLOCK(sdev->target->sbp); splx(s); SBP_DEBUG(0) if (ocb && order > 0) { @@ -2785,6 +2835,8 @@ sbp_get_ocb(struct sbp_dev *sdev) { struct sbp_ocb *ocb; int s = splfw(); + + mtx_assert(&sdev->target->sbp->mtx, MA_OWNED); ocb = STAILQ_FIRST(&sdev->free_ocbs); if (ocb == NULL) { sdev->flags |= ORB_SHORTAGE; @@ -2803,6 +2855,8 @@ sbp_free_ocb(struct sbp_dev *sdev, struct sbp_ocb *ocb) { ocb->flags = 0; ocb->ccb = NULL; + + SBP_LOCK(sdev->target->sbp); STAILQ_INSERT_TAIL(&sdev->free_ocbs, ocb, ocb); if ((sdev->flags & ORB_SHORTAGE) != 0) { int count; @@ -2812,6 +2866,7 @@ sbp_free_ocb(struct sbp_dev *sdev, struct sbp_ocb *ocb) sdev->freeze = 0; xpt_release_devq(sdev->path, count, TRUE); } + SBP_UNLOCK(sdev->target->sbp); } static void @@ -2842,7 +2897,9 @@ END_DEBUG untimeout(sbp_timeout, (caddr_t)ocb, ocb->ccb->ccb_h.timeout_ch); ocb->ccb->ccb_h.status = status; + SBP_LOCK(sdev->target->sbp); xpt_done(ocb->ccb); + SBP_UNLOCK(sdev->target->sbp); } sbp_free_ocb(sdev, ocb); } diff --git a/sys/dev/firewire/sbp_targ.c b/sys/dev/firewire/sbp_targ.c index ef14efca1c9b..911460d1c74a 100644 --- a/sys/dev/firewire/sbp_targ.c +++ b/sys/dev/firewire/sbp_targ.c @@ -140,7 +140,10 @@ struct sbp_targ_softc { struct sbp_targ_lstate *lstate[MAX_LUN]; struct sbp_targ_lstate *black_hole; struct sbp_targ_login *logins[MAX_LOGINS]; + struct mtx mtx; }; +#define SBP_LOCK(sc) mtx_lock(&(sc)->mtx) +#define SBP_UNLOCK(sc) mtx_unlock(&(sc)->mtx) struct corb4 { #if BYTE_ORDER == BIG_ENDIAN @@ -215,6 +218,7 @@ static char *orb_fun_name[] = { static void sbp_targ_recv(struct fw_xfer *); static void sbp_targ_fetch_orb(struct sbp_targ_softc *, struct fw_device *, uint16_t, uint32_t, struct sbp_targ_login *, int); +static void sbp_targ_abort(struct sbp_targ_softc *, struct orb_info *); static void sbp_targ_identify(driver_t *driver, device_t parent) @@ -289,8 +293,10 @@ sbp_targ_post_busreset(void *arg) unit = &sc->unit; if ((sc->flags & F_FREEZED) == 0) { + SBP_LOCK(sc); sc->flags |= F_FREEZED; xpt_freeze_simq(sc->sim, /*count*/1); + SBP_UNLOCK(sc); } else { printf("%s: already freezed\n", __func__); } @@ -321,6 +327,7 @@ sbp_targ_post_busreset(void *arg) login = sc->logins[i]; if (login == NULL) continue; + sbp_targ_abort(sc, STAILQ_FIRST(&login->orbs)); if (login->flags & F_LOGIN) { login->flags |= F_HOLD; callout_reset(&login->hold_callout, @@ -336,8 +343,10 @@ sbp_targ_post_explore(void *arg) struct sbp_targ_softc *sc; sc = (struct sbp_targ_softc *)arg; + SBP_LOCK(sc); sc->flags &= ~F_FREEZED; xpt_release_simq(sc->sim, /*run queue*/TRUE); + SBP_UNLOCK(sc); return; } @@ -484,10 +493,19 @@ sbp_targ_send_lstate_events(struct sbp_targ_softc *sc, #endif } + +static __inline void +sbp_targ_remove_orb_info_locked(struct sbp_targ_login *login, struct orb_info *orbi) +{ + STAILQ_REMOVE(&login->orbs, orbi, orb_info, link); +} + static __inline void sbp_targ_remove_orb_info(struct sbp_targ_login *login, struct orb_info *orbi) { + SBP_LOCK(orbi->sc); STAILQ_REMOVE(&login->orbs, orbi, orb_info, link); + SBP_UNLOCK(orbi->sc); } /* @@ -518,19 +536,21 @@ sbp_targ_get_orb_info(struct sbp_targ_lstate *lstate, STAILQ_FOREACH(orbi, &login->orbs, link) if (orbi->orb_lo == tag_id) goto found; - printf("%s: orb not found tag_id=0x%08x\n", __func__, tag_id); + printf("%s: orb not found tag_id=0x%08x init_id=%d\n", + __func__, tag_id, init_id); return (NULL); found: return (orbi); } static void -sbp_targ_abort(struct orb_info *orbi) +sbp_targ_abort(struct sbp_targ_softc *sc, struct orb_info *orbi) { struct orb_info *norbi; + SBP_LOCK(sc); for (; orbi != NULL; orbi = norbi) { - printf("%s: status=%d\n", __func__, orbi->state); + printf("%s: status=%d ccb=%p\n", __func__, orbi->state, orbi->ccb); norbi = STAILQ_NEXT(orbi, link); if (orbi->state != ORBI_STATUS_ABORTED) { if (orbi->ccb != NULL) { @@ -538,13 +558,16 @@ sbp_targ_abort(struct orb_info *orbi) xpt_done(orbi->ccb); orbi->ccb = NULL; } +#if 0 if (orbi->state <= ORBI_STATUS_ATIO) { - sbp_targ_remove_orb_info(orbi->login, orbi); + sbp_targ_remove_orb_info_locked(orbi->login, orbi); free(orbi, M_SBP_TARG); } else +#endif orbi->state = ORBI_STATUS_ABORTED; } } + SBP_UNLOCK(sc); } static void @@ -585,6 +608,7 @@ static void sbp_targ_send_status(struct orb_info *orbi, union ccb *ccb) { struct sbp_status *sbp_status; + struct orb_info *norbi; sbp_status = &orbi->status; @@ -614,7 +638,24 @@ sbp_targ_send_status(struct orb_info *orbi, union ccb *ccb) sbp_cmd_status->status = ccb->csio.scsi_status; sense = &ccb->csio.sense_data; - sbp_targ_abort(STAILQ_NEXT(orbi, link)); +#if 0 /* XXX What we should do? */ +#if 0 + sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link)); +#else + norbi = STAILQ_NEXT(orbi, link); + while (norbi) { + printf("%s: status=%d\n", __func__, norbi->state); + if (norbi->ccb != NULL) { + norbi->ccb->ccb_h.status = CAM_REQ_ABORTED; + xpt_done(norbi->ccb); + norbi->ccb = NULL; + } + sbp_targ_remove_orb_info_locked(orbi->login, norbi); + norbi = STAILQ_NEXT(norbi, link); + free(norbi, M_SBP_TARG); + } +#endif +#endif if ((sense->error_code & SSD_ERRCODE) == SSD_CURRENT_ERROR) sbp_cmd_status->sfmt = SBP_SFMT_CURR; @@ -653,11 +694,11 @@ sbp_targ_send_status(struct orb_info *orbi, union ccb *ccb) sbp_status->status); } - sbp_targ_status_FIFO(orbi, - orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/1); - if (orbi->page_table != NULL) free(orbi->page_table, M_SBP_TARG); + + sbp_targ_status_FIFO(orbi, + orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/1); } static void @@ -677,13 +718,14 @@ sbp_targ_cam_done(struct fw_xfer *xfer) orbi->status.resp = SBP_TRANS_FAIL; orbi->status.status = OBJ_DATA | SBE_TIMEOUT/*XXX*/; orbi->status.dead = 1; - sbp_targ_abort(STAILQ_NEXT(orbi, link)); + sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link)); } orbi->refcount --; ccb = orbi->ccb; if (orbi->refcount == 0) { + orbi->ccb = NULL; if (orbi->state == ORBI_STATUS_ABORTED) { if (debug) printf("%s: orbi aborted\n", __func__); @@ -695,14 +737,18 @@ sbp_targ_cam_done(struct fw_xfer *xfer) if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) sbp_targ_send_status(orbi, ccb); ccb->ccb_h.status = CAM_REQ_CMP; + SBP_LOCK(orbi->sc); xpt_done(ccb); + SBP_UNLOCK(orbi->sc); } else { orbi->status.len = 1; sbp_targ_status_FIFO(orbi, orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/1); ccb->ccb_h.status = CAM_REQ_ABORTED; + SBP_LOCK(orbi->sc); xpt_done(ccb); + SBP_UNLOCK(orbi->sc); } } @@ -823,7 +869,7 @@ sbp_targ_pt_done(struct fw_xfer *xfer) orbi->status.status = OBJ_PT | SBE_TIMEOUT/*XXX*/; orbi->status.dead = 1; orbi->status.len = 1; - sbp_targ_abort(STAILQ_NEXT(orbi, link)); + sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link)); sbp_targ_status_FIFO(orbi, orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/1); @@ -901,7 +947,8 @@ sbp_targ_action1(struct cam_sim *sim, union ccb *ccb) struct orb_info *orbi; if (debug) - printf("%s: XPT_CONT_TARGET_IO\n", __func__); + printf("%s: XPT_CONT_TARGET_IO (0x%08x)\n", + __func__, ccb->csio.tag_id); if (status != CAM_REQ_CMP) { ccb->ccb_h.status = status; @@ -919,8 +966,10 @@ sbp_targ_action1(struct cam_sim *sim, union ccb *ccb) if (orbi->state == ORBI_STATUS_ABORTED) { if (debug) printf("%s: ctio aborted\n", __func__); - sbp_targ_remove_orb_info(orbi->login, orbi); + sbp_targ_remove_orb_info_locked(orbi->login, orbi); free(orbi, M_SBP_TARG); + ccb->ccb_h.status = CAM_REQ_ABORTED; + xpt_done(ccb); break; } orbi->state = ORBI_STATUS_CTIO; @@ -966,8 +1015,12 @@ sbp_targ_action1(struct cam_sim *sim, union ccb *ccb) sbp_targ_cam_done); if (ccb_dir == CAM_DIR_NONE) { - if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) + if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) { + /* XXX */ + SBP_UNLOCK(sc); sbp_targ_send_status(orbi, ccb); + SBP_LOCK(sc); + } ccb->ccb_h.status = CAM_REQ_CMP; xpt_done(ccb); } @@ -1106,7 +1159,7 @@ sbp_targ_cmd_handler(struct fw_xfer *xfer) orbi->status.status = OBJ_ORB | SBE_TIMEOUT/*XXX*/; orbi->status.dead = 1; orbi->status.len = 1; - sbp_targ_abort(STAILQ_NEXT(orbi, link)); + sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link)); sbp_targ_status_FIFO(orbi, orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/1); @@ -1115,10 +1168,16 @@ sbp_targ_cmd_handler(struct fw_xfer *xfer) } fp = &xfer->recv.hdr; + atio = orbi->atio; + if (orbi->state == ORBI_STATUS_ABORTED) { printf("%s: aborted\n", __func__); sbp_targ_remove_orb_info(orbi->login, orbi); free(orbi, M_SBP_TARG); + atio->ccb_h.status = CAM_REQ_ABORTED; + SBP_LOCK(orbi->sc); + xpt_done((union ccb*)atio); + SBP_UNLOCK(orbi->sc); goto done0; } orbi->state = ORBI_STATUS_ATIO; @@ -1134,7 +1193,6 @@ sbp_targ_cmd_handler(struct fw_xfer *xfer) printf("%s: rq_fmt(%d) != 0\n", __func__, orb4->rq_fmt); } - atio = orbi->atio; atio->ccb_h.target_id = 0; /* XXX */ atio->ccb_h.target_lun = orbi->login->lstate->lun; atio->sense_len = 0; @@ -1143,10 +1201,10 @@ sbp_targ_cmd_handler(struct fw_xfer *xfer) atio->init_id = orbi->login->id; atio->ccb_h.flags = CAM_TAG_ACTION_VALID; - bytes = (char *)&orb[5]; + bytes = (u_char *)&orb[5]; if (debug) - printf("%s: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", - __func__, + printf("%s: %p %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", + __func__, (void *)atio, bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7], bytes[8], bytes[9]); switch (bytes[0] >> 5) { @@ -1191,7 +1249,9 @@ sbp_targ_cmd_handler(struct fw_xfer *xfer) orbi->data_lo = orb[3]; orbi->orb4 = *orb4; + SBP_LOCK(orbi->sc); xpt_done((union ccb*)atio); + SBP_UNLOCK(orbi->sc); done0: fw_xfer_free(xfer); return; @@ -1256,7 +1316,7 @@ sbp_targ_mgm_handler(struct fw_xfer *xfer) orbi->status.status = OBJ_ORB | SBE_TIMEOUT/*XXX*/; orbi->status.dead = 1; orbi->status.len = 1; - sbp_targ_abort(STAILQ_NEXT(orbi, link)); + sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link)); sbp_targ_status_FIFO(orbi, orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/0); @@ -1309,6 +1369,7 @@ sbp_targ_mgm_handler(struct fw_xfer *xfer) orbi->status.len = 1; break; } + printf("%s: login id=%d\n", __func__, login->id); login->fifo_hi = orb[6]; login->fifo_lo = orb[7]; @@ -1318,10 +1379,10 @@ sbp_targ_mgm_handler(struct fw_xfer *xfer) login->loginres.cmd_lo = htonl(SBP_TARG_BIND_LO(login->id)); login->loginres.recon_hold = htons(login->hold_sec); + STAILQ_INSERT_TAIL(&lstate->logins, login, link); fwmem_write_block(orbi->fwdev, NULL, /*spd*/2, orb[2], orb[3], sizeof(struct sbp_login_res), (void *)&login->loginres, fw_asy_callback_free); - STAILQ_INSERT_TAIL(&lstate->logins, login, link); /* XXX return status after loginres is successfully written */ break; } @@ -1418,9 +1479,11 @@ sbp_targ_fetch_orb(struct sbp_targ_softc *sc, struct fw_device *fwdev, login->last_lo = orb_lo; login->flags |= F_LINK_ACTIVE; /* dequeue */ + SBP_LOCK(sc); orbi->atio = (struct ccb_accept_tio *) SLIST_FIRST(&login->lstate->accept_tios); if (orbi->atio == NULL) { + SBP_UNLOCK(sc); printf("%s: no free atio\n", __func__); login->lstate->flags |= F_ATIO_STARVED; login->flags |= F_ATIO_STARVED; @@ -1431,10 +1494,11 @@ sbp_targ_fetch_orb(struct sbp_targ_softc *sc, struct fw_device *fwdev, break; } SLIST_REMOVE_HEAD(&login->lstate->accept_tios, sim_links.sle); + STAILQ_INSERT_TAIL(&login->orbs, orbi, link); + SBP_UNLOCK(sc); fwmem_read_block(fwdev, (void *)orbi, /*spd*/2, orb_hi, orb_lo, sizeof(uint32_t) * 8, &orbi->orb[0], sbp_targ_cmd_handler); - STAILQ_INSERT_TAIL(&login->orbs, orbi, link); break; case FETCH_POINTER: orbi->state = ORBI_STATUS_POINTER; @@ -1489,7 +1553,7 @@ sbp_targ_cmd(struct fw_xfer *xfer, struct fw_device *fwdev, int login_id, switch (reg) { case 0x08: /* ORB_POINTER */ if (debug) - printf("%s: ORB_POINTER\n", __func__); + printf("%s: ORB_POINTER(%d)\n", __func__, login_id); if ((login->flags & F_LINK_ACTIVE) != 0) { if (debug) printf("link active (ORB_POINTER)\n"); @@ -1502,14 +1566,14 @@ sbp_targ_cmd(struct fw_xfer *xfer, struct fw_device *fwdev, int login_id, break; case 0x04: /* AGENT_RESET */ if (debug) - printf("%s: AGENT RESET\n", __func__); + printf("%s: AGENT RESET(%d)\n", __func__, login_id); login->last_hi = 0xffff; login->last_lo = 0xffffffff; - sbp_targ_abort(STAILQ_FIRST(&login->orbs)); + sbp_targ_abort(sc, STAILQ_FIRST(&login->orbs)); break; case 0x10: /* DOORBELL */ if (debug) - printf("%s: DOORBELL\n", __func__); + printf("%s: DOORBELL(%d)\n", __func__, login_id); if (login->last_hi == 0xffff && login->last_lo == 0xffffffff) { printf("%s: no previous pointer(DOORBELL)\n", @@ -1526,13 +1590,15 @@ sbp_targ_cmd(struct fw_xfer *xfer, struct fw_device *fwdev, int login_id, login, FETCH_POINTER); break; case 0x00: /* AGENT_STATE */ - printf("%s: AGENT_STATE (ignore)\n", __func__); + printf("%s: AGENT_STATE (%d:ignore)\n", __func__, login_id); break; case 0x14: /* UNSOLICITED_STATE_ENABLE */ - printf("%s: UNSOLICITED_STATE_ENABLE (ignore)\n", __func__); + printf("%s: UNSOLICITED_STATE_ENABLE (%d:ignore)\n", + __func__, login_id); break; default: - printf("%s: invalid register %d\n", __func__, reg); + printf("%s: invalid register %d(%d)\n", + __func__, reg, login_id); rtcode = RESP_ADDRESS_ERROR; } @@ -1561,7 +1627,6 @@ sbp_targ_mgm(struct fw_xfer *xfer, struct fw_device *fwdev) return(0); } - static void sbp_targ_recv(struct fw_xfer *xfer) { @@ -1582,6 +1647,7 @@ sbp_targ_recv(struct fw_xfer *xfer) goto done; } lo = fp->mode.wreqb.dest_lo; + if (lo == SBP_TARG_BIND_LO(-1)) rtcode = sbp_targ_mgm(xfer, fwdev); else if (lo >= SBP_TARG_BIND_LO(0)) @@ -1611,11 +1677,13 @@ sbp_targ_attach(device_t dev) { struct sbp_targ_softc *sc; struct cam_devq *devq; + struct firewire_comm *fc; sc = (struct sbp_targ_softc *) device_get_softc(dev); bzero((void *)sc, sizeof(struct sbp_targ_softc)); - sc->fd.fc = device_get_ivars(dev); + mtx_init(&sc->mtx, "sbp_targ", NULL, MTX_DEF); + sc->fd.fc = fc = device_get_ivars(dev); sc->fd.dev = dev; sc->fd.post_explore = (void *) sbp_targ_post_explore; sc->fd.post_busreset = (void *) sbp_targ_post_busreset; @@ -1625,13 +1693,14 @@ sbp_targ_attach(device_t dev) return (ENXIO); sc->sim = cam_sim_alloc(sbp_targ_action, sbp_targ_poll, - "sbp_targ", sc, device_get_unit(dev), &Giant, + "sbp_targ", sc, device_get_unit(dev), &sc->mtx, /*untagged*/ 1, /*tagged*/ 1, devq); if (sc->sim == NULL) { cam_simq_free(devq); return (ENXIO); } + SBP_LOCK(sc); if (xpt_bus_register(sc->sim, /*bus*/0) != CAM_SUCCESS) goto fail; @@ -1640,6 +1709,7 @@ sbp_targ_attach(device_t dev) xpt_bus_deregister(cam_sim_path(sc->sim)); goto fail; } + SBP_UNLOCK(sc); sc->fwb.start = SBP_TARG_BIND_START; sc->fwb.end = SBP_TARG_BIND_END; @@ -1648,11 +1718,12 @@ sbp_targ_attach(device_t dev) STAILQ_INIT(&sc->fwb.xferlist); fw_xferlist_add(&sc->fwb.xferlist, M_SBP_TARG, /*send*/ 0, /*recv*/ SBP_TARG_RECV_LEN, MAX_LUN /* XXX */, - sc->fd.fc, (void *)sc, sbp_targ_recv); - fw_bindadd(sc->fd.fc, &sc->fwb); + fc, (void *)sc, sbp_targ_recv); + fw_bindadd(fc, &sc->fwb); return 0; fail: + SBP_UNLOCK(sc); cam_sim_free(sc->sim, /*free_devq*/TRUE); return (ENXIO); } @@ -1667,8 +1738,10 @@ sbp_targ_detach(device_t dev) sc = (struct sbp_targ_softc *)device_get_softc(dev); sc->fd.post_busreset = NULL; + SBP_LOCK(sc); xpt_free_path(sc->path); xpt_bus_deregister(cam_sim_path(sc->sim)); + SBP_UNLOCK(sc); cam_sim_free(sc->sim, /*free_devq*/TRUE); for (i = 0; i < MAX_LUN; i ++) { @@ -1686,6 +1759,8 @@ sbp_targ_detach(device_t dev) fw_bindremove(sc->fd.fc, &sc->fwb); fw_xferlist_remove(&sc->fwb.xferlist); + mtx_destroy(&sc->mtx); + return 0; }