diff options
author | scottl <scottl@FreeBSD.org> | 2007-03-06 01:12:15 +0000 |
---|---|---|
committer | scottl <scottl@FreeBSD.org> | 2007-03-06 01:12:15 +0000 |
commit | 2af792b8915a6aab423f7f69284ebc8498a1fdda (patch) | |
tree | 35989b1717c9a78ad667671116c6f65440ae88d9 /sys | |
parent | de1068910187cc59c6ffea68b3b754da87651362 (diff) | |
download | FreeBSD-src-2af792b8915a6aab423f7f69284ebc8498a1fdda.zip FreeBSD-src-2af792b8915a6aab423f7f69284ebc8498a1fdda.tar.gz |
Better fix for the errors under high load. Returning CAM_SCSI_BUSY is almost
never correct as CAM has no real understanding of it, and will just immediately
retry the command. This leads to undesirable cycling of the camisr as well as
a high possibility for the command to exhaust its retries before the driver
can get around to servicing it.
The better fix, as demonstrated here, is to freeze the simq and mark the
command as needing to be tried. Then when driver can service the command,
the simq gets unfrozen. This is correct, and documented here to help reduce
the mystery. However, it also points out a shortcoming in CAM error handling
that makes writing drivers harder.
Submitted by: Erich Chen
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/arcmsr/arcmsr.c | 10 | ||||
-rw-r--r-- | sys/dev/arcmsr/arcmsr.h | 2 |
2 files changed, 10 insertions, 2 deletions
diff --git a/sys/dev/arcmsr/arcmsr.c b/sys/dev/arcmsr/arcmsr.c index 185e0da..5e2bb86 100644 --- a/sys/dev/arcmsr/arcmsr.c +++ b/sys/dev/arcmsr/arcmsr.c @@ -417,7 +417,12 @@ static void arcmsr_srb_complete(struct CommandControlBlock *srb, int stand_flag) } ARCMSR_LOCK_ACQUIRE(&acb->workingQ_done_lock); if(stand_flag==1) { - atomic_subtract_int(&acb->srboutstandingcount, 1); + atomic_subtract_int(&acb->srboutstandingcount, 1); + if((acb->acb_flags & ACB_F_CAM_DEV_QFRZN) && ( + acb->srboutstandingcount < ARCMSR_RELEASE_SIMQ_LEVEL)) { + acb->acb_flags &= ~ACB_F_CAM_DEV_QFRZN; + pccb->ccb_h.status |= CAM_RELEASE_SIMQ; + } } srb->startdone=ARCMSR_SRB_DONE; srb->srb_flags=0; @@ -1303,7 +1308,8 @@ static void arcmsr_executesrb(void *arg, bus_dma_segment_t *dm_segs, int nseg, i pccb->ccb_h.status |= CAM_SIM_QUEUED; if(acb->srboutstandingcount >= ARCMSR_MAX_OUTSTANDING_CMD) { pccb->ccb_h.status &= ~CAM_STATUS_MASK; - pccb->ccb_h.status |= CAM_REQUEUE_REQ; + pccb->ccb_h.status |= (CAM_REQUEUE_REQ|CAM_DEV_QFRZN); + acb->acb_flags |= ACB_F_CAM_DEV_QFRZN; arcmsr_srb_complete(srb, 0); return; } diff --git a/sys/dev/arcmsr/arcmsr.h b/sys/dev/arcmsr/arcmsr.h index 31cc728..8060707 100644 --- a/sys/dev/arcmsr/arcmsr.h +++ b/sys/dev/arcmsr/arcmsr.h @@ -51,6 +51,7 @@ #define ARCMSR_MAX_QBUFFER 4096 /* ioctl QBUFFER */ #define ARCMSR_MAX_SG_ENTRIES 38 /* max 38*/ #define ARCMSR_MAX_ADAPTER 4 +#define ARCMSR_RELEASE_SIMQ_LEVEL 230 /* ********************************************************************* */ @@ -509,6 +510,7 @@ struct AdapterControlBlock { #define ACB_F_BUS_RESET 0x0080 #define ACB_F_IOP_INITED 0x0100 /* iop init */ #define ACB_F_MAPFREESRB_FAILD 0x0200 /* arcmsr_map_freesrb faild */ +#define ACB_F_CAM_DEV_QFRZN 0x0400 struct CommandControlBlock * psrb_pool[ARCMSR_MAX_FREESRB_NUM]; /* serial srb pointer array */ struct CommandControlBlock * srbworkingQ[ARCMSR_MAX_FREESRB_NUM]; /* working srb pointer array */ |