162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2021 Broadcom. All Rights Reserved. The term 462306a36Sopenharmony_ci * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include "efct_driver.h" 862306a36Sopenharmony_ci#include "efct_unsol.h" 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#define frame_printf(efct, hdr, fmt, ...) \ 1162306a36Sopenharmony_ci do { \ 1262306a36Sopenharmony_ci char s_id_text[16]; \ 1362306a36Sopenharmony_ci efc_node_fcid_display(ntoh24((hdr)->fh_s_id), \ 1462306a36Sopenharmony_ci s_id_text, sizeof(s_id_text)); \ 1562306a36Sopenharmony_ci efc_log_debug(efct, "[%06x.%s] %02x/%04x/%04x: " fmt, \ 1662306a36Sopenharmony_ci ntoh24((hdr)->fh_d_id), s_id_text, \ 1762306a36Sopenharmony_ci (hdr)->fh_r_ctl, be16_to_cpu((hdr)->fh_ox_id), \ 1862306a36Sopenharmony_ci be16_to_cpu((hdr)->fh_rx_id), ##__VA_ARGS__); \ 1962306a36Sopenharmony_ci } while (0) 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic struct efct_node * 2262306a36Sopenharmony_ciefct_node_find(struct efct *efct, u32 port_id, u32 node_id) 2362306a36Sopenharmony_ci{ 2462306a36Sopenharmony_ci struct efct_node *node; 2562306a36Sopenharmony_ci u64 id = (u64)port_id << 32 | node_id; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci /* 2862306a36Sopenharmony_ci * During node shutdown, Lookup will be removed first, 2962306a36Sopenharmony_ci * before announcing to backend. So, no new IOs will be allowed 3062306a36Sopenharmony_ci */ 3162306a36Sopenharmony_ci /* Find a target node, given s_id and d_id */ 3262306a36Sopenharmony_ci node = xa_load(&efct->lookup, id); 3362306a36Sopenharmony_ci if (node) 3462306a36Sopenharmony_ci kref_get(&node->ref); 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci return node; 3762306a36Sopenharmony_ci} 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistatic int 4062306a36Sopenharmony_ciefct_dispatch_frame(struct efct *efct, struct efc_hw_sequence *seq) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci struct efct_node *node; 4362306a36Sopenharmony_ci struct fc_frame_header *hdr; 4462306a36Sopenharmony_ci u32 s_id, d_id; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci hdr = seq->header->dma.virt; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci /* extract the s_id and d_id */ 4962306a36Sopenharmony_ci s_id = ntoh24(hdr->fh_s_id); 5062306a36Sopenharmony_ci d_id = ntoh24(hdr->fh_d_id); 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci if (!(hdr->fh_type == FC_TYPE_FCP || hdr->fh_type == FC_TYPE_BLS)) 5362306a36Sopenharmony_ci return -EIO; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci if (hdr->fh_type == FC_TYPE_FCP) { 5662306a36Sopenharmony_ci node = efct_node_find(efct, d_id, s_id); 5762306a36Sopenharmony_ci if (!node) { 5862306a36Sopenharmony_ci efc_log_err(efct, 5962306a36Sopenharmony_ci "Node not found, drop cmd d_id:%x s_id:%x\n", 6062306a36Sopenharmony_ci d_id, s_id); 6162306a36Sopenharmony_ci efct_hw_sequence_free(&efct->hw, seq); 6262306a36Sopenharmony_ci return 0; 6362306a36Sopenharmony_ci } 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci efct_dispatch_fcp_cmd(node, seq); 6662306a36Sopenharmony_ci } else { 6762306a36Sopenharmony_ci node = efct_node_find(efct, d_id, s_id); 6862306a36Sopenharmony_ci if (!node) { 6962306a36Sopenharmony_ci efc_log_err(efct, "ABTS: Node not found, d_id:%x s_id:%x\n", 7062306a36Sopenharmony_ci d_id, s_id); 7162306a36Sopenharmony_ci return -EIO; 7262306a36Sopenharmony_ci } 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci efc_log_err(efct, "Received ABTS for Node:%p\n", node); 7562306a36Sopenharmony_ci efct_node_recv_abts_frame(node, seq); 7662306a36Sopenharmony_ci } 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci kref_put(&node->ref, node->release); 7962306a36Sopenharmony_ci efct_hw_sequence_free(&efct->hw, seq); 8062306a36Sopenharmony_ci return 0; 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ciint 8462306a36Sopenharmony_ciefct_unsolicited_cb(void *arg, struct efc_hw_sequence *seq) 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci struct efct *efct = arg; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci /* Process FCP command */ 8962306a36Sopenharmony_ci if (!efct_dispatch_frame(efct, seq)) 9062306a36Sopenharmony_ci return 0; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci /* Forward frame to discovery lib */ 9362306a36Sopenharmony_ci efc_dispatch_frame(efct->efcport, seq); 9462306a36Sopenharmony_ci return 0; 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistatic int 9862306a36Sopenharmony_ciefct_fc_tmf_rejected_cb(struct efct_io *io, 9962306a36Sopenharmony_ci enum efct_scsi_io_status scsi_status, 10062306a36Sopenharmony_ci u32 flags, void *arg) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci efct_scsi_io_free(io); 10362306a36Sopenharmony_ci return 0; 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic void 10762306a36Sopenharmony_ciefct_dispatch_unsol_tmf(struct efct_io *io, u8 tm_flags, u32 lun) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci u32 i; 11062306a36Sopenharmony_ci struct { 11162306a36Sopenharmony_ci u32 mask; 11262306a36Sopenharmony_ci enum efct_scsi_tmf_cmd cmd; 11362306a36Sopenharmony_ci } tmflist[] = { 11462306a36Sopenharmony_ci {FCP_TMF_ABT_TASK_SET, EFCT_SCSI_TMF_ABORT_TASK_SET}, 11562306a36Sopenharmony_ci {FCP_TMF_CLR_TASK_SET, EFCT_SCSI_TMF_CLEAR_TASK_SET}, 11662306a36Sopenharmony_ci {FCP_TMF_LUN_RESET, EFCT_SCSI_TMF_LOGICAL_UNIT_RESET}, 11762306a36Sopenharmony_ci {FCP_TMF_TGT_RESET, EFCT_SCSI_TMF_TARGET_RESET}, 11862306a36Sopenharmony_ci {FCP_TMF_CLR_ACA, EFCT_SCSI_TMF_CLEAR_ACA} }; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci io->exp_xfer_len = 0; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(tmflist); i++) { 12362306a36Sopenharmony_ci if (tmflist[i].mask & tm_flags) { 12462306a36Sopenharmony_ci io->tmf_cmd = tmflist[i].cmd; 12562306a36Sopenharmony_ci efct_scsi_recv_tmf(io, lun, tmflist[i].cmd, NULL, 0); 12662306a36Sopenharmony_ci break; 12762306a36Sopenharmony_ci } 12862306a36Sopenharmony_ci } 12962306a36Sopenharmony_ci if (i == ARRAY_SIZE(tmflist)) { 13062306a36Sopenharmony_ci /* Not handled */ 13162306a36Sopenharmony_ci efc_log_err(io->node->efct, "TMF x%x rejected\n", tm_flags); 13262306a36Sopenharmony_ci efct_scsi_send_tmf_resp(io, EFCT_SCSI_TMF_FUNCTION_REJECTED, 13362306a36Sopenharmony_ci NULL, efct_fc_tmf_rejected_cb, NULL); 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci} 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistatic int 13862306a36Sopenharmony_ciefct_validate_fcp_cmd(struct efct *efct, struct efc_hw_sequence *seq) 13962306a36Sopenharmony_ci{ 14062306a36Sopenharmony_ci /* 14162306a36Sopenharmony_ci * If we received less than FCP_CMND_IU bytes, assume that the frame is 14262306a36Sopenharmony_ci * corrupted in some way and drop it. 14362306a36Sopenharmony_ci * This was seen when jamming the FCTL 14462306a36Sopenharmony_ci * fill bytes field. 14562306a36Sopenharmony_ci */ 14662306a36Sopenharmony_ci if (seq->payload->dma.len < sizeof(struct fcp_cmnd)) { 14762306a36Sopenharmony_ci struct fc_frame_header *fchdr = seq->header->dma.virt; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci efc_log_debug(efct, 15062306a36Sopenharmony_ci "drop ox_id %04x payload (%zd) less than (%zd)\n", 15162306a36Sopenharmony_ci be16_to_cpu(fchdr->fh_ox_id), 15262306a36Sopenharmony_ci seq->payload->dma.len, sizeof(struct fcp_cmnd)); 15362306a36Sopenharmony_ci return -EIO; 15462306a36Sopenharmony_ci } 15562306a36Sopenharmony_ci return 0; 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistatic void 15962306a36Sopenharmony_ciefct_populate_io_fcp_cmd(struct efct_io *io, struct fcp_cmnd *cmnd, 16062306a36Sopenharmony_ci struct fc_frame_header *fchdr, bool sit) 16162306a36Sopenharmony_ci{ 16262306a36Sopenharmony_ci io->init_task_tag = be16_to_cpu(fchdr->fh_ox_id); 16362306a36Sopenharmony_ci /* note, tgt_task_tag, hw_tag set when HW io is allocated */ 16462306a36Sopenharmony_ci io->exp_xfer_len = be32_to_cpu(cmnd->fc_dl); 16562306a36Sopenharmony_ci io->transferred = 0; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci /* The upper 7 bits of CS_CTL is the frame priority thru the SAN. 16862306a36Sopenharmony_ci * Our assertion here is, the priority given to a frame containing 16962306a36Sopenharmony_ci * the FCP cmd should be the priority given to ALL frames contained 17062306a36Sopenharmony_ci * in that IO. Thus we need to save the incoming CS_CTL here. 17162306a36Sopenharmony_ci */ 17262306a36Sopenharmony_ci if (ntoh24(fchdr->fh_f_ctl) & FC_FC_RES_B17) 17362306a36Sopenharmony_ci io->cs_ctl = fchdr->fh_cs_ctl; 17462306a36Sopenharmony_ci else 17562306a36Sopenharmony_ci io->cs_ctl = 0; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci io->seq_init = sit; 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_cistatic u32 18162306a36Sopenharmony_ciefct_get_flags_fcp_cmd(struct fcp_cmnd *cmnd) 18262306a36Sopenharmony_ci{ 18362306a36Sopenharmony_ci u32 flags = 0; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci switch (cmnd->fc_pri_ta & FCP_PTA_MASK) { 18662306a36Sopenharmony_ci case FCP_PTA_SIMPLE: 18762306a36Sopenharmony_ci flags |= EFCT_SCSI_CMD_SIMPLE; 18862306a36Sopenharmony_ci break; 18962306a36Sopenharmony_ci case FCP_PTA_HEADQ: 19062306a36Sopenharmony_ci flags |= EFCT_SCSI_CMD_HEAD_OF_QUEUE; 19162306a36Sopenharmony_ci break; 19262306a36Sopenharmony_ci case FCP_PTA_ORDERED: 19362306a36Sopenharmony_ci flags |= EFCT_SCSI_CMD_ORDERED; 19462306a36Sopenharmony_ci break; 19562306a36Sopenharmony_ci case FCP_PTA_ACA: 19662306a36Sopenharmony_ci flags |= EFCT_SCSI_CMD_ACA; 19762306a36Sopenharmony_ci break; 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci if (cmnd->fc_flags & FCP_CFL_WRDATA) 20062306a36Sopenharmony_ci flags |= EFCT_SCSI_CMD_DIR_IN; 20162306a36Sopenharmony_ci if (cmnd->fc_flags & FCP_CFL_RDDATA) 20262306a36Sopenharmony_ci flags |= EFCT_SCSI_CMD_DIR_OUT; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci return flags; 20562306a36Sopenharmony_ci} 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_cistatic void 20862306a36Sopenharmony_ciefct_sframe_common_send_cb(void *arg, u8 *cqe, int status) 20962306a36Sopenharmony_ci{ 21062306a36Sopenharmony_ci struct efct_hw_send_frame_context *ctx = arg; 21162306a36Sopenharmony_ci struct efct_hw *hw = ctx->hw; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci /* Free WQ completion callback */ 21462306a36Sopenharmony_ci efct_hw_reqtag_free(hw, ctx->wqcb); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci /* Free sequence */ 21762306a36Sopenharmony_ci efct_hw_sequence_free(hw, ctx->seq); 21862306a36Sopenharmony_ci} 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_cistatic int 22162306a36Sopenharmony_ciefct_sframe_common_send(struct efct_node *node, 22262306a36Sopenharmony_ci struct efc_hw_sequence *seq, 22362306a36Sopenharmony_ci enum fc_rctl r_ctl, u32 f_ctl, 22462306a36Sopenharmony_ci u8 type, void *payload, u32 payload_len) 22562306a36Sopenharmony_ci{ 22662306a36Sopenharmony_ci struct efct *efct = node->efct; 22762306a36Sopenharmony_ci struct efct_hw *hw = &efct->hw; 22862306a36Sopenharmony_ci int rc = 0; 22962306a36Sopenharmony_ci struct fc_frame_header *req_hdr = seq->header->dma.virt; 23062306a36Sopenharmony_ci struct fc_frame_header hdr; 23162306a36Sopenharmony_ci struct efct_hw_send_frame_context *ctx; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci u32 heap_size = seq->payload->dma.size; 23462306a36Sopenharmony_ci uintptr_t heap_phys_base = seq->payload->dma.phys; 23562306a36Sopenharmony_ci u8 *heap_virt_base = seq->payload->dma.virt; 23662306a36Sopenharmony_ci u32 heap_offset = 0; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci /* Build the FC header reusing the RQ header DMA buffer */ 23962306a36Sopenharmony_ci memset(&hdr, 0, sizeof(hdr)); 24062306a36Sopenharmony_ci hdr.fh_r_ctl = r_ctl; 24162306a36Sopenharmony_ci /* send it back to whomever sent it to us */ 24262306a36Sopenharmony_ci memcpy(hdr.fh_d_id, req_hdr->fh_s_id, sizeof(hdr.fh_d_id)); 24362306a36Sopenharmony_ci memcpy(hdr.fh_s_id, req_hdr->fh_d_id, sizeof(hdr.fh_s_id)); 24462306a36Sopenharmony_ci hdr.fh_type = type; 24562306a36Sopenharmony_ci hton24(hdr.fh_f_ctl, f_ctl); 24662306a36Sopenharmony_ci hdr.fh_ox_id = req_hdr->fh_ox_id; 24762306a36Sopenharmony_ci hdr.fh_rx_id = req_hdr->fh_rx_id; 24862306a36Sopenharmony_ci hdr.fh_cs_ctl = 0; 24962306a36Sopenharmony_ci hdr.fh_df_ctl = 0; 25062306a36Sopenharmony_ci hdr.fh_seq_cnt = 0; 25162306a36Sopenharmony_ci hdr.fh_parm_offset = 0; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci /* 25462306a36Sopenharmony_ci * send_frame_seq_id is an atomic, we just let it increment, 25562306a36Sopenharmony_ci * while storing only the low 8 bits to hdr->seq_id 25662306a36Sopenharmony_ci */ 25762306a36Sopenharmony_ci hdr.fh_seq_id = (u8)atomic_add_return(1, &hw->send_frame_seq_id); 25862306a36Sopenharmony_ci hdr.fh_seq_id--; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci /* Allocate and fill in the send frame request context */ 26162306a36Sopenharmony_ci ctx = (void *)(heap_virt_base + heap_offset); 26262306a36Sopenharmony_ci heap_offset += sizeof(*ctx); 26362306a36Sopenharmony_ci if (heap_offset > heap_size) { 26462306a36Sopenharmony_ci efc_log_err(efct, "Fill send frame failed offset %d size %d\n", 26562306a36Sopenharmony_ci heap_offset, heap_size); 26662306a36Sopenharmony_ci return -EIO; 26762306a36Sopenharmony_ci } 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci memset(ctx, 0, sizeof(*ctx)); 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci /* Save sequence */ 27262306a36Sopenharmony_ci ctx->seq = seq; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci /* Allocate a response payload DMA buffer from the heap */ 27562306a36Sopenharmony_ci ctx->payload.phys = heap_phys_base + heap_offset; 27662306a36Sopenharmony_ci ctx->payload.virt = heap_virt_base + heap_offset; 27762306a36Sopenharmony_ci ctx->payload.size = payload_len; 27862306a36Sopenharmony_ci ctx->payload.len = payload_len; 27962306a36Sopenharmony_ci heap_offset += payload_len; 28062306a36Sopenharmony_ci if (heap_offset > heap_size) { 28162306a36Sopenharmony_ci efc_log_err(efct, "Fill send frame failed offset %d size %d\n", 28262306a36Sopenharmony_ci heap_offset, heap_size); 28362306a36Sopenharmony_ci return -EIO; 28462306a36Sopenharmony_ci } 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci /* Copy the payload in */ 28762306a36Sopenharmony_ci memcpy(ctx->payload.virt, payload, payload_len); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci /* Send */ 29062306a36Sopenharmony_ci rc = efct_hw_send_frame(&efct->hw, (void *)&hdr, FC_SOF_N3, 29162306a36Sopenharmony_ci FC_EOF_T, &ctx->payload, ctx, 29262306a36Sopenharmony_ci efct_sframe_common_send_cb, ctx); 29362306a36Sopenharmony_ci if (rc) 29462306a36Sopenharmony_ci efc_log_debug(efct, "efct_hw_send_frame failed: %d\n", rc); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci return rc; 29762306a36Sopenharmony_ci} 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_cistatic int 30062306a36Sopenharmony_ciefct_sframe_send_fcp_rsp(struct efct_node *node, struct efc_hw_sequence *seq, 30162306a36Sopenharmony_ci void *rsp, u32 rsp_len) 30262306a36Sopenharmony_ci{ 30362306a36Sopenharmony_ci return efct_sframe_common_send(node, seq, FC_RCTL_DD_CMD_STATUS, 30462306a36Sopenharmony_ci FC_FC_EX_CTX | 30562306a36Sopenharmony_ci FC_FC_LAST_SEQ | 30662306a36Sopenharmony_ci FC_FC_END_SEQ | 30762306a36Sopenharmony_ci FC_FC_SEQ_INIT, 30862306a36Sopenharmony_ci FC_TYPE_FCP, 30962306a36Sopenharmony_ci rsp, rsp_len); 31062306a36Sopenharmony_ci} 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_cistatic int 31362306a36Sopenharmony_ciefct_sframe_send_task_set_full_or_busy(struct efct_node *node, 31462306a36Sopenharmony_ci struct efc_hw_sequence *seq) 31562306a36Sopenharmony_ci{ 31662306a36Sopenharmony_ci struct fcp_resp_with_ext fcprsp; 31762306a36Sopenharmony_ci struct fcp_cmnd *fcpcmd = seq->payload->dma.virt; 31862306a36Sopenharmony_ci int rc = 0; 31962306a36Sopenharmony_ci unsigned long flags = 0; 32062306a36Sopenharmony_ci struct efct *efct = node->efct; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci /* construct task set full or busy response */ 32362306a36Sopenharmony_ci memset(&fcprsp, 0, sizeof(fcprsp)); 32462306a36Sopenharmony_ci spin_lock_irqsave(&node->active_ios_lock, flags); 32562306a36Sopenharmony_ci fcprsp.resp.fr_status = list_empty(&node->active_ios) ? 32662306a36Sopenharmony_ci SAM_STAT_BUSY : SAM_STAT_TASK_SET_FULL; 32762306a36Sopenharmony_ci spin_unlock_irqrestore(&node->active_ios_lock, flags); 32862306a36Sopenharmony_ci *((u32 *)&fcprsp.ext.fr_resid) = be32_to_cpu(fcpcmd->fc_dl); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci /* send it using send_frame */ 33162306a36Sopenharmony_ci rc = efct_sframe_send_fcp_rsp(node, seq, &fcprsp, sizeof(fcprsp)); 33262306a36Sopenharmony_ci if (rc) 33362306a36Sopenharmony_ci efc_log_debug(efct, "efct_sframe_send_fcp_rsp failed %d\n", rc); 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci return rc; 33662306a36Sopenharmony_ci} 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ciint 33962306a36Sopenharmony_ciefct_dispatch_fcp_cmd(struct efct_node *node, struct efc_hw_sequence *seq) 34062306a36Sopenharmony_ci{ 34162306a36Sopenharmony_ci struct efct *efct = node->efct; 34262306a36Sopenharmony_ci struct fc_frame_header *fchdr = seq->header->dma.virt; 34362306a36Sopenharmony_ci struct fcp_cmnd *cmnd = NULL; 34462306a36Sopenharmony_ci struct efct_io *io = NULL; 34562306a36Sopenharmony_ci u32 lun; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci if (!seq->payload) { 34862306a36Sopenharmony_ci efc_log_err(efct, "Sequence payload is NULL.\n"); 34962306a36Sopenharmony_ci return -EIO; 35062306a36Sopenharmony_ci } 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci cmnd = seq->payload->dma.virt; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci /* perform FCP_CMND validation check(s) */ 35562306a36Sopenharmony_ci if (efct_validate_fcp_cmd(efct, seq)) 35662306a36Sopenharmony_ci return -EIO; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci lun = scsilun_to_int(&cmnd->fc_lun); 35962306a36Sopenharmony_ci if (lun == U32_MAX) 36062306a36Sopenharmony_ci return -EIO; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci io = efct_scsi_io_alloc(node); 36362306a36Sopenharmony_ci if (!io) { 36462306a36Sopenharmony_ci int rc; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci /* Use SEND_FRAME to send task set full or busy */ 36762306a36Sopenharmony_ci rc = efct_sframe_send_task_set_full_or_busy(node, seq); 36862306a36Sopenharmony_ci if (rc) 36962306a36Sopenharmony_ci efc_log_err(efct, "Failed to send busy task: %d\n", rc); 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci return rc; 37262306a36Sopenharmony_ci } 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci io->hw_priv = seq->hw_priv; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci io->app_id = 0; 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci /* RQ pair, if we got here, SIT=1 */ 37962306a36Sopenharmony_ci efct_populate_io_fcp_cmd(io, cmnd, fchdr, true); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci if (cmnd->fc_tm_flags) { 38262306a36Sopenharmony_ci efct_dispatch_unsol_tmf(io, cmnd->fc_tm_flags, lun); 38362306a36Sopenharmony_ci } else { 38462306a36Sopenharmony_ci u32 flags = efct_get_flags_fcp_cmd(cmnd); 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci if (cmnd->fc_flags & FCP_CFL_LEN_MASK) { 38762306a36Sopenharmony_ci efc_log_err(efct, "Additional CDB not supported\n"); 38862306a36Sopenharmony_ci return -EIO; 38962306a36Sopenharmony_ci } 39062306a36Sopenharmony_ci /* 39162306a36Sopenharmony_ci * Can return failure for things like task set full and UAs, 39262306a36Sopenharmony_ci * no need to treat as a dropped frame if rc != 0 39362306a36Sopenharmony_ci */ 39462306a36Sopenharmony_ci efct_scsi_recv_cmd(io, lun, cmnd->fc_cdb, 39562306a36Sopenharmony_ci sizeof(cmnd->fc_cdb), flags); 39662306a36Sopenharmony_ci } 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci return 0; 39962306a36Sopenharmony_ci} 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_cistatic int 40262306a36Sopenharmony_ciefct_process_abts(struct efct_io *io, struct fc_frame_header *hdr) 40362306a36Sopenharmony_ci{ 40462306a36Sopenharmony_ci struct efct_node *node = io->node; 40562306a36Sopenharmony_ci struct efct *efct = io->efct; 40662306a36Sopenharmony_ci u16 ox_id = be16_to_cpu(hdr->fh_ox_id); 40762306a36Sopenharmony_ci u16 rx_id = be16_to_cpu(hdr->fh_rx_id); 40862306a36Sopenharmony_ci struct efct_io *abortio; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci /* Find IO and attempt to take a reference on it */ 41162306a36Sopenharmony_ci abortio = efct_io_find_tgt_io(efct, node, ox_id, rx_id); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci if (abortio) { 41462306a36Sopenharmony_ci /* Got a reference on the IO. Hold it until backend 41562306a36Sopenharmony_ci * is notified below 41662306a36Sopenharmony_ci */ 41762306a36Sopenharmony_ci efc_log_info(node->efct, "Abort ox_id [%04x] rx_id [%04x]\n", 41862306a36Sopenharmony_ci ox_id, rx_id); 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci /* 42162306a36Sopenharmony_ci * Save the ox_id for the ABTS as the init_task_tag in our 42262306a36Sopenharmony_ci * manufactured 42362306a36Sopenharmony_ci * TMF IO object 42462306a36Sopenharmony_ci */ 42562306a36Sopenharmony_ci io->display_name = "abts"; 42662306a36Sopenharmony_ci io->init_task_tag = ox_id; 42762306a36Sopenharmony_ci /* don't set tgt_task_tag, don't want to confuse with XRI */ 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci /* 43062306a36Sopenharmony_ci * Save the rx_id from the ABTS as it is 43162306a36Sopenharmony_ci * needed for the BLS response, 43262306a36Sopenharmony_ci * regardless of the IO context's rx_id 43362306a36Sopenharmony_ci */ 43462306a36Sopenharmony_ci io->abort_rx_id = rx_id; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci /* Call target server command abort */ 43762306a36Sopenharmony_ci io->tmf_cmd = EFCT_SCSI_TMF_ABORT_TASK; 43862306a36Sopenharmony_ci efct_scsi_recv_tmf(io, abortio->tgt_io.lun, 43962306a36Sopenharmony_ci EFCT_SCSI_TMF_ABORT_TASK, abortio, 0); 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci /* 44262306a36Sopenharmony_ci * Backend will have taken an additional 44362306a36Sopenharmony_ci * reference on the IO if needed; 44462306a36Sopenharmony_ci * done with current reference. 44562306a36Sopenharmony_ci */ 44662306a36Sopenharmony_ci kref_put(&abortio->ref, abortio->release); 44762306a36Sopenharmony_ci } else { 44862306a36Sopenharmony_ci /* 44962306a36Sopenharmony_ci * Either IO was not found or it has been 45062306a36Sopenharmony_ci * freed between finding it 45162306a36Sopenharmony_ci * and attempting to get the reference, 45262306a36Sopenharmony_ci */ 45362306a36Sopenharmony_ci efc_log_info(node->efct, "Abort: ox_id [%04x], IO not found\n", 45462306a36Sopenharmony_ci ox_id); 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci /* Send a BA_RJT */ 45762306a36Sopenharmony_ci efct_bls_send_rjt(io, hdr); 45862306a36Sopenharmony_ci } 45962306a36Sopenharmony_ci return 0; 46062306a36Sopenharmony_ci} 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ciint 46362306a36Sopenharmony_ciefct_node_recv_abts_frame(struct efct_node *node, struct efc_hw_sequence *seq) 46462306a36Sopenharmony_ci{ 46562306a36Sopenharmony_ci struct efct *efct = node->efct; 46662306a36Sopenharmony_ci struct fc_frame_header *hdr = seq->header->dma.virt; 46762306a36Sopenharmony_ci struct efct_io *io = NULL; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci node->abort_cnt++; 47062306a36Sopenharmony_ci io = efct_scsi_io_alloc(node); 47162306a36Sopenharmony_ci if (io) { 47262306a36Sopenharmony_ci io->hw_priv = seq->hw_priv; 47362306a36Sopenharmony_ci /* If we got this far, SIT=1 */ 47462306a36Sopenharmony_ci io->seq_init = 1; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci /* fill out generic fields */ 47762306a36Sopenharmony_ci io->efct = efct; 47862306a36Sopenharmony_ci io->node = node; 47962306a36Sopenharmony_ci io->cmd_tgt = true; 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci efct_process_abts(io, seq->header->dma.virt); 48262306a36Sopenharmony_ci } else { 48362306a36Sopenharmony_ci efc_log_err(efct, 48462306a36Sopenharmony_ci "SCSI IO allocation failed for ABTS received "); 48562306a36Sopenharmony_ci efc_log_err(efct, "s_id %06x d_id %06x ox_id %04x rx_id %04x\n", 48662306a36Sopenharmony_ci ntoh24(hdr->fh_s_id), ntoh24(hdr->fh_d_id), 48762306a36Sopenharmony_ci be16_to_cpu(hdr->fh_ox_id), 48862306a36Sopenharmony_ci be16_to_cpu(hdr->fh_rx_id)); 48962306a36Sopenharmony_ci } 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci return 0; 49262306a36Sopenharmony_ci} 493