summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormjacob <mjacob@FreeBSD.org>2002-05-01 21:58:36 +0000
committermjacob <mjacob@FreeBSD.org>2002-05-01 21:58:36 +0000
commitccea943059f8c59175d6a86b9d1b6b4163b7efa4 (patch)
tree28051503d0bcf143c9feba7bf232a177d7d568da
parent5b777bef205c14e29efa71f1ccc9446c6f3ed756 (diff)
downloadFreeBSD-src-ccea943059f8c59175d6a86b9d1b6b4163b7efa4.zip
FreeBSD-src-ccea943059f8c59175d6a86b9d1b6b4163b7efa4.tar.gz
If we get a DATA UNDERRUN error from QLogic FC cards, but the RQCS_RU bit
is not set in the scsi completion status, or if the residual is clearly nonsense, then this was a command that suffered the loss of one or more FC frames in the middle of the exchange. Set HBA_BOTCH and hope it will get retried. It's the only thing we can do. MFC after: 1 day
-rw-r--r--sys/dev/isp/isp.c29
1 files changed, 23 insertions, 6 deletions
diff --git a/sys/dev/isp/isp.c b/sys/dev/isp/isp.c
index 2070df7..6bdacd8 100644
--- a/sys/dev/isp/isp.c
+++ b/sys/dev/isp/isp.c
@@ -107,6 +107,8 @@ static const char sc1[] =
static const char sc2[] = "%s CHAN %d TGT %d FLAGS 0x%x 0x%x/0x%x";
static const char sc3[] = "Generated";
static const char sc4[] = "NVRAM";
+static const char bun[] =
+ "bad underrun for %d.%d (count %d, resid %d, status %s)";
/*
* Local function prototypes.
@@ -4397,11 +4399,25 @@ isp_parse_status(struct ispsoftc *isp, ispstatusreq_t *sp, XS_T *xs)
break;
case RQCS_DATA_UNDERRUN:
+ {
+ if (IS_FC(isp)) {
+ int ru_marked = (sp->req_scsi_status & RQCS_RU) != 0;
+ if (!ru_marked || sp->req_resid > XS_XFRLEN(xs)) {
+ isp_prt(isp, ISP_LOGWARN, bun, XS_TGT(xs),
+ XS_LUN(xs), XS_XFRLEN(xs), sp->req_resid,
+ (ru_marked)? "marked" : "not marked");
+ if (XS_NOERR(xs)) {
+ XS_SETERR(xs, HBA_BOTCH);
+ }
+ return;
+ }
+ }
XS_RESID(xs) = sp->req_resid;
if (XS_NOERR(xs)) {
XS_SETERR(xs, HBA_NOERROR);
}
return;
+ }
case RQCS_XACT_ERR1:
isp_prt(isp, ISP_LOGERR, xact1, XS_CHANNEL(xs),
@@ -4424,8 +4440,8 @@ isp_parse_status(struct ispsoftc *isp, ispstatusreq_t *sp, XS_T *xs)
case RQCS_QUEUE_FULL:
isp_prt(isp, ISP_LOGDEBUG0,
- "internal queues full for %d.%d.%d status 0x%x", XS_TGT(xs),
- XS_LUN(xs), XS_CHANNEL(xs), *XS_STSP(xs));
+ "internal queues full for %d.%d.%d status 0x%x",
+ XS_CHANNEL(xs), XS_TGT(xs), XS_LUN(xs), *XS_STSP(xs));
/*
* If QFULL or some other status byte is set, then this
@@ -4507,13 +4523,14 @@ isp_parse_status(struct ispsoftc *isp, ispstatusreq_t *sp, XS_T *xs)
*/
if ((sp->req_completion_status & 0xff) == RQCS_PORT_UNAVAILABLE)
isp_prt(isp, ISP_LOGINFO,
- "Port Unavailable for target %d", XS_TGT(xs));
+ "port unavailable for target %d", XS_TGT(xs));
else
isp_prt(isp, ISP_LOGINFO,
"port logout for target %d", XS_TGT(xs));
/*
* If we're on a local loop, force a LIP (which is overkill)
- * to force a re-login of this unit.
+ * to force a re-login of this unit. If we're on fabric,
+ * then we'll have to relogin as a matter of course.
*/
if (FCPARAM(isp)->isp_topo == TOPO_NL_PORT ||
FCPARAM(isp)->isp_topo == TOPO_FL_PORT) {
@@ -4933,8 +4950,8 @@ static u_int16_t mbpfc[] = {
ISPOPMAP(0x00, 0x00), /* 0x58: */
ISPOPMAP(0x00, 0x00), /* 0x59: */
ISPOPMAP(0x00, 0x00), /* 0x5a: */
- ISPOPMAP(0x00, 0x00), /* 0x5b: */
- ISPOPMAP(0x00, 0x00), /* 0x5c: */
+ ISPOPMAP(0x03, 0x01), /* 0x5b: MBOX_DRIVER_HEARTBEAT */
+ ISPOPMAP(0xcf, 0x01), /* 0x5c: MBOX_FW_HEARTBEAT */
ISPOPMAP(0x07, 0x03), /* 0x5d: MBOX_GET_SET_DATA_RATE */
ISPOPMAP(0x00, 0x00), /* 0x5e: */
ISPOPMAP(0x00, 0x00), /* 0x5f: */
OpenPOWER on IntegriCloud