- Detect split transcation timeout.

* implement watchdog timer.
	* check all standing transactions in firewire_xfer_timeout().
- Add firewire_xferq_drain() for fw_busreset().
- Add/improve some debug messages.
- Call fw_xfer_done() if retry handler is NULL.
This commit is contained in:
Hidetoshi Shimokawa 2003-02-09 07:16:01 +00:00
parent a4d1b9a3c6
commit 864d7e72b8
4 changed files with 139 additions and 65 deletions

@ -328,6 +328,57 @@ firewire_match( device_t dev )
return -140;
}
static void
firewire_xfer_timeout(struct firewire_comm *fc)
{
struct fw_xfer *xfer;
struct tlabel *tl;
struct timeval tv;
struct timeval split_timeout;
int i;
split_timeout.tv_sec = 2;
split_timeout.tv_usec = 0;
microtime(&tv);
timevalsub(&tv, &split_timeout);
for (i = 0; i < 0x40; i ++) {
while ((tl = STAILQ_FIRST(&fc->tlabels[i])) != NULL) {
xfer = tl->xfer;
if (timevalcmp(&xfer->tv, &tv, >))
/* the rests are newer than this */
break;
device_printf(fc->bdev,
"split transaction timeout dst=%d tl=%d\n",
xfer->dst, i);
xfer->resp = ETIMEDOUT;
STAILQ_REMOVE_HEAD(&fc->tlabels[i], link);
switch (xfer->act_type) {
case FWACT_XFER:
fw_xfer_done(xfer);
break;
default:
/* ??? */
fw_xfer_free(xfer);
break;
}
}
}
}
static void
firewire_watchdog(void *arg)
{
struct firewire_comm *fc;
fc = (struct firewire_comm *)arg;
firewire_xfer_timeout(fc);
fc->timeout(fc);
callout_reset(&fc->timeout_callout, hz,
(void *)firewire_watchdog, (void *)fc);
}
/*
* The attach routine.
*/
@ -379,8 +430,8 @@ firewire_attach( device_t dev )
CALLOUT_INIT(&sc->fc->retry_probe_callout);
CALLOUT_INIT(&sc->fc->busprobe_callout);
callout_reset(&sc->fc->timeout_callout, hz * 10,
(void *)sc->fc->timeout, (void *)sc->fc);
callout_reset(&sc->fc->timeout_callout, hz,
(void *)firewire_watchdog, (void *)sc->fc);
/* Locate our children */
bus_generic_probe(dev);
@ -388,8 +439,10 @@ firewire_attach( device_t dev )
/* launch attachement of the added children */
bus_generic_attach(dev);
#if 1
/* bus_reset */
fc->ibr(fc);
#endif
return 0;
}
@ -450,6 +503,27 @@ firewire_shutdown( device_t dev )
}
#endif
static void
firewire_xferq_drain(struct fw_xferq *xferq)
{
struct fw_xfer *xfer;
while ((xfer = STAILQ_FIRST(&xferq->q)) != NULL) {
STAILQ_REMOVE_HEAD(&xferq->q, link);
xfer->resp = EAGAIN;
switch (xfer->act_type) {
case FWACT_XFER:
fw_xfer_done(xfer);
break;
default:
/* ??? */
fw_xfer_free(xfer);
break;
}
}
}
/*
* Called after bus reset.
*/
@ -457,7 +531,6 @@ void
fw_busreset(struct firewire_comm *fc)
{
int i;
struct fw_xfer *xfer;
switch(fc->status){
case FWBUSMGRELECT:
@ -468,42 +541,10 @@ fw_busreset(struct firewire_comm *fc)
}
fc->status = FWBUSRESET;
/* XXX: discard all queued packet */
while((xfer = STAILQ_FIRST(&fc->atq->q)) != NULL){
STAILQ_REMOVE_HEAD(&fc->atq->q, link);
xfer->resp = EAGAIN;
switch(xfer->act_type){
case FWACT_XFER:
fw_xfer_done(xfer);
break;
default:
break;
}
fw_xfer_free( xfer);
}
while((xfer = STAILQ_FIRST(&fc->ats->q)) != NULL){
STAILQ_REMOVE_HEAD(&fc->ats->q, link);
xfer->resp = EAGAIN;
switch(xfer->act_type){
case FWACT_XFER:
fw_xfer_done(xfer);
default:
break;
}
fw_xfer_free( xfer);
}
firewire_xferq_drain(fc->atq);
firewire_xferq_drain(fc->ats);
for(i = 0; i < fc->nisodma; i++)
while((xfer = STAILQ_FIRST(&fc->it[i]->q)) != NULL){
STAILQ_REMOVE_HEAD(&fc->it[i]->q, link);
xfer->resp = 0;
switch(xfer->act_type){
case FWACT_XFER:
fw_xfer_done(xfer);
break;
default:
break;
}
fw_xfer_free( xfer);
}
firewire_xferq_drain(fc->it[i]);
CSRARC(fc, STATE_CLEAR)
= 1 << 23 | 0 << 17 | 1 << 16 | 1 << 15 | 1 << 14 ;
@ -799,9 +840,13 @@ fw_tl2xfer(struct firewire_comm *fc, int node, int tlabel)
if(tl->xfer->dst == node){
xfer = tl->xfer;
splx(s);
if (firewire_debug > 2)
printf("fw_tl2xfer: found tl=%d\n", tlabel);
return(xfer);
}
}
if (firewire_debug > 1)
printf("fw_tl2xfer: not found tl=%d\n", tlabel);
splx(s);
return(NULL);
}
@ -818,7 +863,7 @@ fw_xfer_alloc(struct malloc_type *type)
if (xfer == NULL)
return xfer;
xfer->time = time_second;
microtime(&xfer->tv);
xfer->sub = -1;
xfer->malloc = type;
@ -1140,7 +1185,8 @@ loop:
/* check link */
/* XXX we need to check phy_id first */
if (!fc->topology_map->self_id[fc->ongonode].p0.link_active) {
printf("fw_bus_explore: node %d link down\n", fc->ongonode);
if (firewire_debug)
printf("node%d: link down\n", fc->ongonode);
fc->ongonode++;
goto loop;
}
@ -1237,6 +1283,9 @@ loop:
fp->mode.rreqq.dest_lo = htonl(addr);
xfer->act.hand = fw_bus_explore_callback;
if (firewire_debug)
printf("node%d: explore addr=0x%x\n",
fc->ongonode, fc->ongoaddr);
err = fw_asyreq(fc, -1, xfer);
if(err){
fw_xfer_free( xfer);
@ -1315,26 +1364,33 @@ fw_bus_explore_callback(struct fw_xfer *xfer)
u_int32_t offset;
if(xfer == NULL) return;
if(xfer == NULL) {
printf("xfer == NULL\n");
return;
}
fc = xfer->fc;
if(xfer->resp != 0){
printf("resp != 0: node=%d addr=0x%x\n",
if (firewire_debug)
printf("node%d: callback addr=0x%x\n",
fc->ongonode, fc->ongoaddr);
if(xfer->resp != 0){
printf("node%d: resp=%d addr=0x%x\n",
fc->ongonode, xfer->resp, fc->ongoaddr);
fc->retry_count++;
goto nextnode;
}
if(xfer->send.buf == NULL){
printf("send.buf == NULL: node=%d addr=0x%x\n",
printf("node%d: send.buf=NULL addr=0x%x\n",
fc->ongonode, fc->ongoaddr);
printf("send.buf == NULL\n");
fc->retry_count++;
goto nextnode;
}
sfp = (struct fw_pkt *)xfer->send.buf;
if(xfer->recv.buf == NULL){
printf("recv.buf == NULL: node=%d addr=0x%x\n",
printf("node%d: recv.buf=NULL addr=0x%x\n",
fc->ongonode, fc->ongoaddr);
fc->retry_count++;
goto nextnode;
@ -1357,8 +1413,11 @@ fw_bus_explore_callback(struct fw_xfer *xfer)
if(sfp->mode.rreqq.dest_lo == htonl((0xf0000000 | CSRROMOFF))){
rfp->mode.rresq.data = ntohl(rfp->mode.rresq.data);
chdr = (struct csrhdr *)(&rfp->mode.rresq.data);
/* If CSR is minimul confinguration, more investgation is not needed. */
/* If CSR is minimal confinguration, more investgation is not needed. */
if(chdr->info_len == 1){
if (firewire_debug)
printf("node%d: minimal config\n",
fc->ongonode);
goto nextnode;
}else{
fc->ongoaddr = CSRROMOFF + 0xc;
@ -1368,8 +1427,12 @@ fw_bus_explore_callback(struct fw_xfer *xfer)
fc->ongoaddr = CSRROMOFF + 0x10;
}else if(sfp->mode.rreqq.dest_lo == htonl((0xf0000000 |(CSRROMOFF + 0x10)))){
fc->ongoeui.lo = ntohl(rfp->mode.rresq.data);
if (fc->ongoeui.hi == 0 && fc->ongoeui.lo == 0)
if (fc->ongoeui.hi == 0 && fc->ongoeui.lo == 0) {
if (firewire_debug)
printf("node%d: eui64 is zero.\n",
fc->ongonode);
goto nextnode;
}
fc->ongoaddr = CSRROMOFF;
}
}else{
@ -1607,6 +1670,9 @@ fw_get_tlabel(struct firewire_comm *fc, struct fw_xfer *xfer)
tl->xfer = xfer;
STAILQ_INSERT_TAIL(&fc->tlabels[label], tl, link);
splx(s);
if (firewire_debug > 1)
printf("fw_get_tlabel: dst=%d tl=%d\n",
xfer->dst, label);
return(label);
}
}

@ -257,8 +257,10 @@ struct fw_xfer{
caddr_t sc;
struct firewire_comm *fc;
struct fw_xferq *q;
#ifdef XFER_TIMEOUT
struct callout_handle ch;
time_t time;
#endif
struct timeval tv;
struct fw_tlabel *tlabel;
u_int8_t spd;
u_int8_t tcode;

@ -279,8 +279,9 @@ fwmem_read (dev_t dev, struct uio *uio, int ioflag)
sc = devclass_get_softc(firewire_devclass, unit);
fwdev = fw_noderesolve_eui64(sc->fc, fwmem_eui64);
if (fwdev == NULL) {
printf("fwmem: no such device ID:%08x%08x\n",
fwmem_eui64.hi, fwmem_eui64.lo);
if (fwmem_debug)
printf("fwmem: no such device ID:%08x%08x\n",
fwmem_eui64.hi, fwmem_eui64.lo);
return EINVAL;
}
@ -341,8 +342,9 @@ fwmem_write (dev_t dev, struct uio *uio, int ioflag)
sc = devclass_get_softc(firewire_devclass, unit);
fwdev = fw_noderesolve_eui64(sc->fc, fwmem_eui64);
if (fwdev == NULL) {
printf("fwmem: no such device ID:%08x%08x\n",
fwmem_eui64.hi, fwmem_eui64.lo);
if (fwmem_debug)
printf("fwmem: no such device ID:%08x%08x\n",
fwmem_eui64.hi, fwmem_eui64.lo);
return EINVAL;
}

@ -718,8 +718,6 @@ fwohci_timeout(void *arg)
struct fwohci_softc *sc;
sc = (struct fwohci_softc *)arg;
callout_reset(&sc->fc.timeout_callout, FW_XFERTIMEOUT * hz * 10,
(void *)fwohci_timeout, (void *)sc);
}
u_int32_t
@ -992,14 +990,14 @@ fwohci_txd(struct fwohci_softc *sc, struct fwohci_dbch *dbch)
}
stat = db->db.desc.status & FWOHCIEV_MASK;
switch(stat){
case FWOHCIEV_ACKCOMPL:
case FWOHCIEV_ACKPEND:
case FWOHCIEV_ACKCOMPL:
err = 0;
break;
case FWOHCIEV_ACKBSA:
case FWOHCIEV_ACKBSB:
device_printf(sc->fc.dev, "txd err=%2x %s\n", stat, fwohcicode[stat]);
case FWOHCIEV_ACKBSX:
device_printf(sc->fc.dev, "txd err=%2x %s\n", stat, fwohcicode[stat]);
err = EBUSY;
break;
case FWOHCIEV_FLUSHED:
@ -1023,26 +1021,27 @@ fwohci_txd(struct fwohci_softc *sc, struct fwohci_dbch *dbch)
err = EINVAL;
break;
}
if(tr->xfer != NULL){
if (tr->xfer != NULL) {
xfer = tr->xfer;
xfer->state = FWXF_SENT;
if(err == EBUSY && fc->status != FWBUSRESET){
if (err == EBUSY && fc->status != FWBUSRESET) {
xfer->state = FWXF_BUSY;
switch(xfer->act_type){
switch (xfer->act_type) {
case FWACT_XFER:
xfer->resp = err;
if(xfer->retry_req != NULL){
if (xfer->retry_req != NULL)
xfer->retry_req(xfer);
}
else
fw_xfer_done(xfer);
break;
default:
break;
}
} else if( stat != FWOHCIEV_ACKPEND){
} else if (stat != FWOHCIEV_ACKPEND) {
if (stat != FWOHCIEV_ACKCOMPL)
xfer->state = FWXF_SENTERR;
xfer->resp = err;
switch(xfer->act_type){
switch (xfer->act_type) {
case FWACT_XFER:
fw_xfer_done(xfer);
break;
@ -1050,6 +1049,10 @@ fwohci_txd(struct fwohci_softc *sc, struct fwohci_dbch *dbch)
break;
}
}
/*
* The watchdog timer takes care of split
* transcation timeout for ACKPEND case.
*/
}
dbch->xferq.queued --;
tr->xfer = NULL;
@ -2295,6 +2298,7 @@ fwohci_ibr(struct firewire_comm *fc)
struct fwohci_softc *sc;
u_int32_t fun;
device_printf(fc->dev, "Initiate bus reset\n");
sc = (struct fwohci_softc *)fc;
/*
@ -2745,7 +2749,7 @@ fwohci_arcv(struct fwohci_softc *sc, struct fwohci_dbch *dbch, int count)
stat &= 0x1f;
switch(stat){
case FWOHCIEV_ACKPEND:
#if 1
#if 0
printf("fwohci_arcv: ack pending..\n");
#endif
/* fall through */