MFp4: MPSAFE firewire stack.
- lock its own locks and drop Giant. - create its own taskqueue thread. - split interrupt routine - use interrupt filter as a fast interrupt. - run watchdog timer in taskqueue so that it should be serialized with the bottom half. - add extra sanity check for transaction labels. disable ad-hoc workaround for unknown tlabels. - add sleep/wakeup synchronization primitives - don't reset OHCI in fwohci_stop()
This commit is contained in:
parent
e9bf9fb67c
commit
9950b741e9
@ -46,6 +46,8 @@
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/kthread.h>
|
||||
|
||||
#include <sys/kdb.h>
|
||||
|
||||
#if defined(__DragonFly__) || __FreeBSD_version < 500000
|
||||
#include <machine/clock.h> /* 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 @@ fw_bindremove(struct firewire_comm *fc, struct fw_bind *fwb)
|
||||
}
|
||||
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)
|
||||
{
|
||||
|
@ -47,6 +47,8 @@ typedef struct proc fw_proc;
|
||||
#endif
|
||||
|
||||
#include <sys/uio.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/taskqueue.h>
|
||||
|
||||
#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
|
||||
|
@ -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 @@ fw_read_async(struct fw_drv1 *d, struct uio *uio, int ioflag)
|
||||
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 @@ fw_read (struct cdev *dev, struct uio *uio, int ioflag)
|
||||
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 @@ fw_read (struct cdev *dev, struct uio *uio, int ioflag)
|
||||
}
|
||||
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 @@ fw_write (struct cdev *dev, struct uio *uio, int ioflag)
|
||||
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 @@ fw_write (struct cdev *dev, struct uio *uio, int ioflag)
|
||||
}
|
||||
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 @@ fw_ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
|
||||
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;
|
||||
|
@ -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");
|
||||
|
@ -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",
|
||||
|
@ -52,6 +52,7 @@
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/endian.h>
|
||||
#include <sys/kdb.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
|
||||
@ -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 @@ fwohci_start(struct fwohci_softc *sc, struct fwohci_dbch *dbch)
|
||||
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 @@ fwohci_start(struct fwohci_softc *sc, struct fwohci_dbch *dbch)
|
||||
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 @@ fwohci_txd(struct fwohci_softc *sc, struct fwohci_dbch *dbch)
|
||||
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 @@ fwohci_intr_body(struct fwohci_softc *sc, uint32_t stat, int count)
|
||||
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 @@ fwohci_intr_body(struct fwohci_softc *sc, uint32_t stat, int count)
|
||||
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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -35,13 +35,12 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined(__DragonFly__) || __FreeBSD_version < 500000
|
||||
#define FWOHCI_TASKQUEUE 0
|
||||
#else
|
||||
#define FWOHCI_TASKQUEUE 1
|
||||
#endif
|
||||
#if FWOHCI_TASKQUEUE
|
||||
#include <sys/taskqueue.h>
|
||||
|
||||
#if defined(__DragonFly__) || __FreeBSD_version < 700043
|
||||
#define FWOHCI_INTFILT 0
|
||||
#else
|
||||
#define FWOHCI_INTFILT 1
|
||||
#endif
|
||||
|
||||
typedef struct fwohci_softc {
|
||||
@ -77,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);
|
||||
|
@ -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 @@ fwe_init(void *arg)
|
||||
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);
|
||||
|
@ -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_ */
|
||||
|
@ -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;
|
||||
|
@ -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_ */
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user