[SCSI] libfc: incorrect scsi host byte codes returned to scsi-ml

The fcp packet recovery handler fc_fcp_recover() is called
when errors occurr in a fcp session. Currently it is
generically setting the status code to FC_CMD_RECOVERY for
all error types. This results in DID_BUS_BUSY errors
being returned to the scsi-ml.

DID_BUS_BUSY errors indicate "BUS stayed busy through time
out period" according to scsi.h. Many of the error reported
by fc_rcp_recovery() are pkt errors. Here we update
fc_fcp_recovery to use better host byte codes.

With certain FAST FAIL flags set DID_BUS_BUSY and DID_ERROR
will have different behaviors this was causing dm multipath
to fail quickly in some cases where a retry would be a
better action.

Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
Signed-off-by: Robert Love <robert.w.love@intel.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
This commit is contained in:
john fastabend 2010-11-30 16:18:39 -08:00 committed by James Bottomley
parent e90ff5ef0a
commit ac17ea8d7d
1 changed files with 41 additions and 20 deletions

View File

@ -96,7 +96,7 @@ static void fc_fcp_resp(struct fc_fcp_pkt *, struct fc_frame *);
static void fc_fcp_complete_locked(struct fc_fcp_pkt *); static void fc_fcp_complete_locked(struct fc_fcp_pkt *);
static void fc_tm_done(struct fc_seq *, struct fc_frame *, void *); static void fc_tm_done(struct fc_seq *, struct fc_frame *, void *);
static void fc_fcp_error(struct fc_fcp_pkt *, struct fc_frame *); static void fc_fcp_error(struct fc_fcp_pkt *, struct fc_frame *);
static void fc_fcp_recovery(struct fc_fcp_pkt *); static void fc_fcp_recovery(struct fc_fcp_pkt *, u8 code);
static void fc_fcp_timeout(unsigned long); static void fc_fcp_timeout(unsigned long);
static void fc_fcp_rec(struct fc_fcp_pkt *); static void fc_fcp_rec(struct fc_fcp_pkt *);
static void fc_fcp_rec_error(struct fc_fcp_pkt *, struct fc_frame *); static void fc_fcp_rec_error(struct fc_fcp_pkt *, struct fc_frame *);
@ -120,7 +120,8 @@ static void fc_fcp_srr_error(struct fc_fcp_pkt *, struct fc_frame *);
#define FC_DATA_UNDRUN 7 #define FC_DATA_UNDRUN 7
#define FC_ERROR 8 #define FC_ERROR 8
#define FC_HRD_ERROR 9 #define FC_HRD_ERROR 9
#define FC_CMD_RECOVERY 10 #define FC_CRC_ERROR 10
#define FC_TIMED_OUT 11
/* /*
* Error recovery timeout values. * Error recovery timeout values.
@ -438,6 +439,7 @@ static void fc_fcp_recv_data(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
void *buf; void *buf;
struct scatterlist *sg; struct scatterlist *sg;
u32 nents; u32 nents;
u8 host_bcode = FC_COMPLETE;
fh = fc_frame_header_get(fp); fh = fc_frame_header_get(fp);
offset = ntohl(fh->fh_parm_offset); offset = ntohl(fh->fh_parm_offset);
@ -446,13 +448,16 @@ static void fc_fcp_recv_data(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
buf = fc_frame_payload_get(fp, 0); buf = fc_frame_payload_get(fp, 0);
/* /*
* if this I/O is ddped then clear it * if this I/O is ddped then clear it and initiate recovery since data
* and initiate recovery since data * frames are expected to be placed directly in that case.
* frames are expected to be placed *
* directly in that case. * Indicate error to scsi-ml because something went wrong with the
* ddp handling to get us here.
*/ */
if (fsp->xfer_ddp != FC_XID_UNKNOWN) { if (fsp->xfer_ddp != FC_XID_UNKNOWN) {
fc_fcp_ddp_done(fsp); fc_fcp_ddp_done(fsp);
FC_FCP_DBG(fsp, "DDP I/O in fc_fcp_recv_data set ERROR\n");
host_bcode = FC_ERROR;
goto err; goto err;
} }
if (offset + len > fsp->data_len) { if (offset + len > fsp->data_len) {
@ -462,6 +467,9 @@ static void fc_fcp_recv_data(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
goto crc_err; goto crc_err;
FC_FCP_DBG(fsp, "data received past end. len %zx offset %zx " FC_FCP_DBG(fsp, "data received past end. len %zx offset %zx "
"data_len %x\n", len, offset, fsp->data_len); "data_len %x\n", len, offset, fsp->data_len);
/* Data is corrupted indicate scsi-ml should retry */
host_bcode = FC_DATA_OVRRUN;
goto err; goto err;
} }
if (offset != fsp->xfer_len) if (offset != fsp->xfer_len)
@ -498,8 +506,10 @@ crc_err:
* If so, we need to retry the entire operation. * If so, we need to retry the entire operation.
* Otherwise, ignore it. * Otherwise, ignore it.
*/ */
if (fsp->state & FC_SRB_DISCONTIG) if (fsp->state & FC_SRB_DISCONTIG) {
host_bcode = FC_CRC_ERROR;
goto err; goto err;
}
return; return;
} }
} }
@ -517,7 +527,7 @@ crc_err:
fc_fcp_complete_locked(fsp); fc_fcp_complete_locked(fsp);
return; return;
err: err:
fc_fcp_recovery(fsp); fc_fcp_recovery(fsp, host_bcode);
} }
/** /**
@ -1347,7 +1357,7 @@ static void fc_fcp_timeout(unsigned long data)
else if (fsp->state & FC_SRB_RCV_STATUS) else if (fsp->state & FC_SRB_RCV_STATUS)
fc_fcp_complete_locked(fsp); fc_fcp_complete_locked(fsp);
else else
fc_fcp_recovery(fsp); fc_fcp_recovery(fsp, FC_TIMED_OUT);
fsp->state &= ~FC_SRB_FCP_PROCESSING_TMO; fsp->state &= ~FC_SRB_FCP_PROCESSING_TMO;
unlock: unlock:
fc_fcp_unlock_pkt(fsp); fc_fcp_unlock_pkt(fsp);
@ -1391,7 +1401,7 @@ retry:
if (fsp->recov_retry++ < FC_MAX_RECOV_RETRY) if (fsp->recov_retry++ < FC_MAX_RECOV_RETRY)
fc_fcp_timer_set(fsp, FC_SCSI_REC_TOV); fc_fcp_timer_set(fsp, FC_SCSI_REC_TOV);
else else
fc_fcp_recovery(fsp); fc_fcp_recovery(fsp, FC_TIMED_OUT);
} }
/** /**
@ -1460,7 +1470,7 @@ static void fc_fcp_rec_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg)
fc_fcp_retry_cmd(fsp); fc_fcp_retry_cmd(fsp);
break; break;
} }
fc_fcp_recovery(fsp); fc_fcp_recovery(fsp, FC_ERROR);
break; break;
} }
} else if (opcode == ELS_LS_ACC) { } else if (opcode == ELS_LS_ACC) {
@ -1575,7 +1585,7 @@ static void fc_fcp_rec_error(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
if (fsp->recov_retry++ < FC_MAX_RECOV_RETRY) if (fsp->recov_retry++ < FC_MAX_RECOV_RETRY)
fc_fcp_rec(fsp); fc_fcp_rec(fsp);
else else
fc_fcp_recovery(fsp); fc_fcp_recovery(fsp, FC_ERROR);
break; break;
} }
fc_fcp_unlock_pkt(fsp); fc_fcp_unlock_pkt(fsp);
@ -1587,9 +1597,9 @@ out:
* fc_fcp_recovery() - Handler for fcp_pkt recovery * fc_fcp_recovery() - Handler for fcp_pkt recovery
* @fsp: The FCP pkt that needs to be aborted * @fsp: The FCP pkt that needs to be aborted
*/ */
static void fc_fcp_recovery(struct fc_fcp_pkt *fsp) static void fc_fcp_recovery(struct fc_fcp_pkt *fsp, u8 code)
{ {
fsp->status_code = FC_CMD_RECOVERY; fsp->status_code = code;
fsp->cdb_status = 0; fsp->cdb_status = 0;
fsp->io_status = 0; fsp->io_status = 0;
/* /*
@ -1695,7 +1705,7 @@ static void fc_fcp_srr_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg)
break; break;
case ELS_LS_RJT: case ELS_LS_RJT:
default: default:
fc_fcp_recovery(fsp); fc_fcp_recovery(fsp, FC_ERROR);
break; break;
} }
fc_fcp_unlock_pkt(fsp); fc_fcp_unlock_pkt(fsp);
@ -1721,7 +1731,7 @@ static void fc_fcp_srr_error(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
if (fsp->recov_retry++ < FC_MAX_RECOV_RETRY) if (fsp->recov_retry++ < FC_MAX_RECOV_RETRY)
fc_fcp_rec(fsp); fc_fcp_rec(fsp);
else else
fc_fcp_recovery(fsp); fc_fcp_recovery(fsp, FC_TIMED_OUT);
break; break;
case -FC_EX_CLOSED: /* e.g., link failure */ case -FC_EX_CLOSED: /* e.g., link failure */
/* fall through */ /* fall through */
@ -1946,18 +1956,29 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp)
break; break;
case FC_CMD_ABORTED: case FC_CMD_ABORTED:
FC_FCP_DBG(fsp, "Returning DID_ERROR to scsi-ml " FC_FCP_DBG(fsp, "Returning DID_ERROR to scsi-ml "
"due to FC_CMD_ABORTED\n"); "due to FC_CMD_ABORTED\n");
sc_cmd->result = (DID_ERROR << 16) | fsp->io_status; sc_cmd->result = (DID_ERROR << 16) | fsp->io_status;
break; break;
case FC_CMD_RECOVERY:
sc_cmd->result = (DID_BUS_BUSY << 16) | fsp->io_status;
break;
case FC_CMD_RESET: case FC_CMD_RESET:
FC_FCP_DBG(fsp, "Returning DID_RESET to scsi-ml "
"due to FC_CMD_RESET\n");
sc_cmd->result = (DID_RESET << 16); sc_cmd->result = (DID_RESET << 16);
break; break;
case FC_HRD_ERROR: case FC_HRD_ERROR:
FC_FCP_DBG(fsp, "Returning DID_NO_CONNECT to scsi-ml "
"due to FC_HRD_ERROR\n");
sc_cmd->result = (DID_NO_CONNECT << 16); sc_cmd->result = (DID_NO_CONNECT << 16);
break; break;
case FC_CRC_ERROR:
FC_FCP_DBG(fsp, "Returning DID_PARITY to scsi-ml "
"due to FC_CRC_ERROR\n");
sc_cmd->result = (DID_PARITY << 16);
break;
case FC_TIMED_OUT:
FC_FCP_DBG(fsp, "Returning DID_BUS_BUSY to scsi-ml "
"due to FC_TIMED_OUT\n");
sc_cmd->result = (DID_BUS_BUSY << 16) | fsp->io_status;
break;
default: default:
FC_FCP_DBG(fsp, "Returning DID_ERROR to scsi-ml " FC_FCP_DBG(fsp, "Returning DID_ERROR to scsi-ml "
"due to unknown error\n"); "due to unknown error\n");