if (!cmd) return;
sess = cmd->sess;
fp = cmd->req_frame; if (fr_seq(fp))
fc_seq_release(fr_seq(fp));
fc_frame_free(fp);
target_free_tag(sess->se_sess, &cmd->se_cmd);
ft_sess_put(sess); /* undo get from lookup at recv */
}
len = se_cmd->scsi_sense_length; if (len) {
fcp->resp.fr_flags |= FCP_SNS_LEN_VAL;
fcp->ext.fr_sns_len = htonl(len);
memcpy((fcp + 1), se_cmd->sense_buffer, len);
}
/* * Test underflow and overflow with one mask. Usually both are off. * Bidirectional commands are not handled yet.
*/ if (se_cmd->se_cmd_flags & (SCF_OVERFLOW_BIT | SCF_UNDERFLOW_BIT)) { if (se_cmd->se_cmd_flags & SCF_OVERFLOW_BIT)
fcp->resp.fr_flags |= FCP_RESID_OVER; else
fcp->resp.fr_flags |= FCP_RESID_UNDER;
fcp->ext.fr_resid = cpu_to_be32(se_cmd->residual_count);
}
rc = fc_seq_send(lport, cmd->seq, fp); if (rc) {
pr_info_ratelimited("%s: Failed to send response frame %p, " "xid <0x%x>\n", __func__, fp, ep->xid); /* * Generate a TASK_SET_FULL status to notify the initiator * to reduce it's queue_depth after the se_cmd response has * been re-queued by target-core.
*/
se_cmd->scsi_status = SAM_STAT_TASK_SET_FULL; return -ENOMEM;
}
fc_exch_done(cmd->seq); /* * Drop the extra ACK_KREF reference taken by target_submit_cmd() * ahead of ft_check_stop_free() -> transport_generic_free_cmd() * final se_cmd->cmd_kref put.
*/
target_put_sess_cmd(&cmd->se_cmd); return 0;
}
if (IS_ERR(fp)) { /* XXX need to find cmd if queued */
cmd->seq = NULL;
cmd->aborted = true; return;
}
fh = fc_frame_header_get(fp);
switch (fh->fh_r_ctl) { case FC_RCTL_DD_SOL_DATA: /* write data */
ft_recv_write_data(cmd, fp); break; case FC_RCTL_DD_UNSOL_CTL: /* command */ case FC_RCTL_DD_SOL_CTL: /* transfer ready */ case FC_RCTL_DD_DATA_DESC: /* transfer ready */ default:
pr_debug("%s: unhandled frame r_ctl %x\n",
__func__, fh->fh_r_ctl);
ft_invl_hw_context(cmd);
fc_frame_free(fp);
transport_generic_free_cmd(&cmd->se_cmd, 0); break;
}
}
/* * Send a FCP response including SCSI status and optional FCP rsp_code. * status is SAM_STAT_GOOD (zero) iff code is valid. * This is used in error cases, such as allocation failures.
*/ staticvoid ft_send_resp_status(struct fc_lport *lport, conststruct fc_frame *rx_fp,
u32 status, enum fcp_resp_rsp_codes code)
{ struct fc_frame *fp; struct fc_seq *sp; conststruct fc_frame_header *fh;
size_t len; struct fcp_resp_with_ext *fcp; struct fcp_resp_rsp_info *info;
fh = fc_frame_header_get(rx_fp);
pr_debug("FCP error response: did %x oxid %x status %x code %x\n",
ntoh24(fh->fh_s_id), ntohs(fh->fh_ox_id), status, code);
len = sizeof(*fcp); if (status == SAM_STAT_GOOD)
len += sizeof(*info);
fp = fc_frame_alloc(lport, len); if (!fp) return;
fcp = fc_frame_payload_get(fp, len);
memset(fcp, 0, len);
fcp->resp.fr_status = status; if (status == SAM_STAT_GOOD) {
fcp->ext.fr_rsp_len = htonl(sizeof(*info));
fcp->resp.fr_flags |= FCP_RSP_LEN_VAL;
info = (struct fcp_resp_rsp_info *)(fcp + 1);
info->rsp_code = code;
}
/* * Use a single se_cmd->cmd_kref as we expect to release se_cmd * directly from ft_check_stop_free callback in response path.
*/ if (target_init_cmd(&cmd->se_cmd, cmd->sess->se_sess,
&cmd->ft_sense_buffer[0],
scsilun_to_int(&fcp->fc_lun), ntohl(fcp->fc_dl),
task_attr, data_dir, TARGET_SCF_ACK_KREF)) goto err;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.