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:
Hidetoshi Shimokawa 2007-06-06 14:31:36 +00:00
parent e9bf9fb67c
commit 9950b741e9
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=170374
14 changed files with 866 additions and 514 deletions

View file

@ -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)
{

View file

@ -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

View file

@ -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;

View file

@ -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");

View file

@ -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",

View file

@ -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;

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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_ */

View file

@ -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;

View file

@ -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_ */

View file

@ -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);
}

View file

@ -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;
}