mirror of
https://github.com/SCST-project/scst.git
synced 2026-05-14 09:11:27 +00:00
fcst: Handle frame send failures properly
Retry sending XFER_RDY, data and response frames if the network driver reports that sending failed (-ENOMEM) instead of reporting a kernel warning (WARN_ON(1)). If sending XFER_RDY or data frames failed for another reason, report this to the initiator as a write error (ASC = 03; ASCQ = 00 which stands for PERIPHERAL DEVICE WRITE FAULT). If sending a response frame failed with another error code than -ENOMEM, do not send a response. git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@5607 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
22
fcst/fcst.h
22
fcst/fcst.h
@@ -174,4 +174,26 @@ struct ft_tpg *ft_lport_find_tpg(struct fc_lport *);
|
||||
struct ft_node_acl *ft_acl_get(struct ft_tpg *, struct fc_rport_priv *);
|
||||
void ft_cmd_dump(struct scst_cmd *, const char *);
|
||||
|
||||
/* #define FCST_INJECT_SEND_ERRORS 2 */
|
||||
|
||||
#ifdef FCST_INJECT_SEND_ERRORS
|
||||
#define FCST_INJ_SEND_ERR(e) \
|
||||
({ \
|
||||
int _error = 0; \
|
||||
\
|
||||
if (scst_random() % 62929 == 0) \
|
||||
_error = -ENOMEM; \
|
||||
if (FCST_INJECT_SEND_ERRORS >= 2 && scst_random() % 69491 == 0) \
|
||||
_error = -ENXIO; \
|
||||
if (_error) \
|
||||
pr_warn("%s: injected seq_send() error %d\n", __func__, \
|
||||
_error); \
|
||||
else \
|
||||
_error = (e); \
|
||||
_error; \
|
||||
})
|
||||
#else
|
||||
#define FCST_INJ_SEND_ERR(e) (e)
|
||||
#endif
|
||||
|
||||
#endif /* __SCSI_FCST_H__ */
|
||||
|
||||
@@ -291,6 +291,7 @@ int ft_send_response(struct scst_cmd *cmd)
|
||||
struct fc_exch *ep;
|
||||
unsigned int slen;
|
||||
size_t len;
|
||||
enum ft_cmd_state prev_state;
|
||||
int resid = 0;
|
||||
int bi_resid = 0;
|
||||
int error;
|
||||
@@ -303,7 +304,7 @@ int ft_send_response(struct scst_cmd *cmd)
|
||||
lport = ep->lp;
|
||||
|
||||
WARN_ON(fcmd->state != FT_STATE_NEW && fcmd->state != FT_STATE_DATA_IN);
|
||||
ft_set_cmd_state(fcmd, FT_STATE_CMD_RSP_SENT);
|
||||
prev_state = ft_set_cmd_state(fcmd, FT_STATE_CMD_RSP_SENT);
|
||||
|
||||
if (scst_cmd_aborted_on_xmit(cmd)) {
|
||||
FT_IO_DBG("cmd aborted did %x oxid %x\n", ep->did, ep->oxid);
|
||||
@@ -313,7 +314,8 @@ int ft_send_response(struct scst_cmd *cmd)
|
||||
|
||||
if (!scst_cmd_get_is_send_status(cmd)) {
|
||||
FT_IO_DBG("send status not set. feature not implemented\n");
|
||||
return SCST_TGT_RES_FATAL_ERROR;
|
||||
error = SCST_TGT_RES_FATAL_ERROR;
|
||||
goto err;
|
||||
}
|
||||
|
||||
status = scst_cmd_get_status(cmd);
|
||||
@@ -333,7 +335,7 @@ int ft_send_response(struct scst_cmd *cmd)
|
||||
error = ft_send_read_data(cmd);
|
||||
if (error) {
|
||||
FT_ERR("ft_send_read_data returned %d\n", error);
|
||||
return error;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (dir == SCST_DATA_BIDI) {
|
||||
@@ -347,8 +349,10 @@ int ft_send_response(struct scst_cmd *cmd)
|
||||
}
|
||||
|
||||
fp = fc_frame_alloc(lport, len);
|
||||
if (!fp)
|
||||
return SCST_TGT_RES_QUEUE_FULL;
|
||||
if (!fp) {
|
||||
error = SCST_TGT_RES_QUEUE_FULL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
fcp = fc_frame_payload_get(fp, len);
|
||||
memset(fcp, 0, sizeof(*fcp));
|
||||
@@ -384,13 +388,26 @@ int ft_send_response(struct scst_cmd *cmd)
|
||||
fc_fill_fc_hdr(fp, FC_RCTL_DD_CMD_STATUS, ep->did, ep->sid, FC_TYPE_FCP,
|
||||
FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ, 0);
|
||||
|
||||
error = lport->tt.seq_send(lport, fcmd->seq, fp);
|
||||
if (error < 0)
|
||||
error = FCST_INJ_SEND_ERR(lport->tt.seq_send(lport, fcmd->seq, fp));
|
||||
if (error < 0) {
|
||||
pr_err("Sending response for exchange with OX_ID %#x and RX_ID"
|
||||
" %#x failed: %d\n", ep->oxid, ep->rxid, error);
|
||||
error = error == -ENOMEM ? SCST_TGT_RES_QUEUE_FULL :
|
||||
SCST_TGT_RES_FATAL_ERROR;
|
||||
goto err;
|
||||
}
|
||||
done:
|
||||
scst_tgt_cmd_done(cmd, SCST_CONTEXT_SAME);
|
||||
return SCST_TGT_RES_SUCCESS;
|
||||
|
||||
err:
|
||||
ft_set_cmd_state(fcmd, prev_state);
|
||||
WARN_ONCE(error != SCST_TGT_RES_QUEUE_FULL &&
|
||||
error != SCST_TGT_RES_FATAL_ERROR,
|
||||
"%s: invalid error code %d\n",
|
||||
__func__, error);
|
||||
return error;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -451,6 +468,7 @@ int ft_send_xfer_rdy(struct scst_cmd *cmd)
|
||||
struct fcp_txrdy *txrdy;
|
||||
struct fc_lport *lport;
|
||||
struct fc_exch *ep;
|
||||
int error;
|
||||
|
||||
fcmd = scst_cmd_get_tgt_priv(cmd);
|
||||
|
||||
@@ -471,8 +489,17 @@ int ft_send_xfer_rdy(struct scst_cmd *cmd)
|
||||
fcmd->seq = lport->tt.seq_start_next(fcmd->seq);
|
||||
fc_fill_fc_hdr(fp, FC_RCTL_DD_DATA_DESC, ep->did, ep->sid, FC_TYPE_FCP,
|
||||
FC_FC_EX_CTX | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
|
||||
lport->tt.seq_send(lport, fcmd->seq, fp);
|
||||
return SCST_TGT_RES_SUCCESS;
|
||||
error = FCST_INJ_SEND_ERR(lport->tt.seq_send(lport, fcmd->seq, fp));
|
||||
switch (error) {
|
||||
case 0:
|
||||
return SCST_TGT_RES_SUCCESS;
|
||||
case -ENOMEM:
|
||||
ft_set_cmd_state(fcmd, FT_STATE_NEW);
|
||||
return SCST_TGT_RES_QUEUE_FULL;
|
||||
default:
|
||||
ft_set_cmd_state(fcmd, FT_STATE_NEW);
|
||||
return SCST_TGT_RES_FATAL_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -708,13 +735,6 @@ static void ft_recv_cmd(struct ft_sess *sess, struct fc_frame *fp)
|
||||
scst_cmd_set_tgt_priv(cmd, fcmd);
|
||||
cmd->state = FT_STATE_NEW;
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
|
||||
sp = fr_seq(fp);
|
||||
#else
|
||||
sp = lport->tt.seq_assign(lport, fp);
|
||||
if (!sp)
|
||||
goto busy;
|
||||
#endif
|
||||
fcmd->seq = sp;
|
||||
lport->tt.seq_set_resp(sp, ft_recv_seq, cmd);
|
||||
|
||||
|
||||
13
fcst/ft_io.c
13
fcst/ft_io.c
@@ -175,10 +175,17 @@ int ft_send_read_data(struct scst_cmd *cmd)
|
||||
remaining ? (FC_FC_EX_CTX | FC_FC_REL_OFF) :
|
||||
(FC_FC_EX_CTX | FC_FC_REL_OFF | FC_FC_END_SEQ),
|
||||
fh_off);
|
||||
error = lport->tt.seq_send(lport, fcmd->seq, fp);
|
||||
error = FCST_INJ_SEND_ERR(lport->tt.seq_send(lport, fcmd->seq,
|
||||
fp));
|
||||
if (error) {
|
||||
WARN_ON(1);
|
||||
/* XXX For now, initiator will retry */
|
||||
pr_warn("Sending frame with oid %#x oxid %#x resp_len"
|
||||
" %d failed at frame_off %u / remaining %zu"
|
||||
" with error code %d - %s", ep->oid, ep->oxid,
|
||||
scst_cmd_get_resp_data_len(cmd), frame_off,
|
||||
remaining, error, error == -ENOMEM ?
|
||||
"retrying" : "giving up");
|
||||
return error == -ENOMEM ? SCST_TGT_RES_QUEUE_FULL :
|
||||
SCST_TGT_RES_FATAL_ERROR;
|
||||
} else
|
||||
fcmd->read_data_len = frame_off;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user