diff --git a/fcst/fcst.h b/fcst/fcst.h index 5d3027514..50f25b4a5 100644 --- a/fcst/fcst.h +++ b/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__ */ diff --git a/fcst/ft_cmd.c b/fcst/ft_cmd.c index 9cc1e48c3..8c3509a78 100644 --- a/fcst/ft_cmd.c +++ b/fcst/ft_cmd.c @@ -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); diff --git a/fcst/ft_io.c b/fcst/ft_io.c index 07fbdf4a4..19be72e8b 100644 --- a/fcst/ft_io.c +++ b/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; }