// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2021 Broadcom. All Rights Reserved. The term * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
*/
/* * During node shutdown, Lookup will be removed first, * before announcing to backend. So, no new IOs will be allowed
*/ /* Find a target node, given s_id and d_id */
node = xa_load(&efct->lookup, id); if (node)
kref_get(&node->ref);
for (i = 0; i < ARRAY_SIZE(tmflist); i++) { if (tmflist[i].mask & tm_flags) {
io->tmf_cmd = tmflist[i].cmd;
efct_scsi_recv_tmf(io, lun, tmflist[i].cmd, NULL, 0); break;
}
} if (i == ARRAY_SIZE(tmflist)) { /* Not handled */
efc_log_err(io->node->efct, "TMF x%x rejected\n", tm_flags);
efct_scsi_send_tmf_resp(io, EFCT_SCSI_TMF_FUNCTION_REJECTED,
NULL, efct_fc_tmf_rejected_cb, NULL);
}
}
staticint
efct_validate_fcp_cmd(struct efct *efct, struct efc_hw_sequence *seq)
{ /* * If we received less than FCP_CMND_IU bytes, assume that the frame is * corrupted in some way and drop it. * This was seen when jamming the FCTL * fill bytes field.
*/ if (seq->payload->dma.len < sizeof(struct fcp_cmnd)) { struct fc_frame_header *fchdr = seq->header->dma.virt;
efc_log_debug(efct, "drop ox_id %04x payload (%zd) less than (%zd)\n",
be16_to_cpu(fchdr->fh_ox_id),
seq->payload->dma.len, sizeof(struct fcp_cmnd)); return -EIO;
} return 0;
}
staticvoid
efct_populate_io_fcp_cmd(struct efct_io *io, struct fcp_cmnd *cmnd, struct fc_frame_header *fchdr, bool sit)
{
io->init_task_tag = be16_to_cpu(fchdr->fh_ox_id); /* note, tgt_task_tag, hw_tag set when HW io is allocated */
io->exp_xfer_len = be32_to_cpu(cmnd->fc_dl);
io->transferred = 0;
/* The upper 7 bits of CS_CTL is the frame priority thru the SAN. * Our assertion here is, the priority given to a frame containing * the FCP cmd should be the priority given to ALL frames contained * in that IO. Thus we need to save the incoming CS_CTL here.
*/ if (ntoh24(fchdr->fh_f_ctl) & FC_FC_RES_B17)
io->cs_ctl = fchdr->fh_cs_ctl; else
io->cs_ctl = 0;
/* Build the FC header reusing the RQ header DMA buffer */
memset(&hdr, 0, sizeof(hdr));
hdr.fh_r_ctl = r_ctl; /* send it back to whomever sent it to us */
memcpy(hdr.fh_d_id, req_hdr->fh_s_id, sizeof(hdr.fh_d_id));
memcpy(hdr.fh_s_id, req_hdr->fh_d_id, sizeof(hdr.fh_s_id));
hdr.fh_type = type;
hton24(hdr.fh_f_ctl, f_ctl);
hdr.fh_ox_id = req_hdr->fh_ox_id;
hdr.fh_rx_id = req_hdr->fh_rx_id;
hdr.fh_cs_ctl = 0;
hdr.fh_df_ctl = 0;
hdr.fh_seq_cnt = 0;
hdr.fh_parm_offset = 0;
/* * send_frame_seq_id is an atomic, we just let it increment, * while storing only the low 8 bits to hdr->seq_id
*/
hdr.fh_seq_id = (u8)atomic_add_return(1, &hw->send_frame_seq_id);
hdr.fh_seq_id--;
/* Allocate and fill in the send frame request context */
ctx = (void *)(heap_virt_base + heap_offset);
heap_offset += sizeof(*ctx); if (heap_offset > heap_size) {
efc_log_err(efct, "Fill send frame failed offset %d size %d\n",
heap_offset, heap_size); return -EIO;
}
lun = scsilun_to_int(&cmnd->fc_lun); if (lun == U32_MAX) return -EIO;
io = efct_scsi_io_alloc(node); if (!io) { int rc;
/* Use SEND_FRAME to send task set full or busy */
rc = efct_sframe_send_task_set_full_or_busy(node, seq); if (rc)
efc_log_err(efct, "Failed to send busy task: %d\n", rc);
return rc;
}
io->hw_priv = seq->hw_priv;
io->app_id = 0;
/* RQ pair, if we got here, SIT=1 */
efct_populate_io_fcp_cmd(io, cmnd, fchdr, true);
if (cmnd->fc_flags & FCP_CFL_LEN_MASK) {
efc_log_err(efct, "Additional CDB not supported\n"); return -EIO;
} /* * Can return failure for things like task set full and UAs, * no need to treat as a dropped frame if rc != 0
*/
efct_scsi_recv_cmd(io, lun, cmnd->fc_cdb, sizeof(cmnd->fc_cdb), flags);
}
/* Find IO and attempt to take a reference on it */
abortio = efct_io_find_tgt_io(efct, node, ox_id, rx_id);
if (abortio) { /* Got a reference on the IO. Hold it until backend * is notified below
*/
efc_log_info(node->efct, "Abort ox_id [%04x] rx_id [%04x]\n",
ox_id, rx_id);
/* * Save the ox_id for the ABTS as the init_task_tag in our * manufactured * TMF IO object
*/
io->display_name = "abts";
io->init_task_tag = ox_id; /* don't set tgt_task_tag, don't want to confuse with XRI */
/* * Save the rx_id from the ABTS as it is * needed for the BLS response, * regardless of the IO context's rx_id
*/
io->abort_rx_id = rx_id;
/* * Backend will have taken an additional * reference on the IO if needed; * done with current reference.
*/
kref_put(&abortio->ref, abortio->release);
} else { /* * Either IO was not found or it has been * freed between finding it * and attempting to get the reference,
*/
efc_log_info(node->efct, "Abort: ox_id [%04x], IO not found\n",
ox_id);
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.