/* * Send status from completed task management request. */ void ft_queue_tm_resp(struct se_cmd *se_cmd) { struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd); struct se_tmr_req *tmr = se_cmd->se_tmr_req; enum fcp_resp_rsp_codes code; if (cmd->aborted) return; switch (tmr->response) { case TMR_FUNCTION_COMPLETE: code = FCP_TMF_CMPL; break; case TMR_LUN_DOES_NOT_EXIST: code = FCP_TMF_INVALID_LUN; break; case TMR_FUNCTION_REJECTED: code = FCP_TMF_REJECTED; break; case TMR_TASK_DOES_NOT_EXIST: case TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED: default: code = FCP_TMF_FAILED; break; } pr_debug("tmr fn %d resp %d fcp code %d\n", tmr->function, tmr->response, code); ft_send_resp_code(cmd, code); }
/* * Send status from completed task management request. */ int ft_queue_tm_resp(struct se_cmd *se_cmd) { struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd); struct se_tmr_req *tmr = se_cmd->se_tmr_req; enum fcp_resp_rsp_codes code; switch (tmr->response) { case TMR_FUNCTION_COMPLETE: code = FCP_TMF_CMPL; break; case TMR_LUN_DOES_NOT_EXIST: code = FCP_TMF_INVALID_LUN; break; case TMR_FUNCTION_REJECTED: code = FCP_TMF_REJECTED; break; case TMR_TASK_DOES_NOT_EXIST: case TMR_TASK_STILL_ALLEGIANT: case TMR_TASK_FAILOVER_NOT_SUPPORTED: case TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED: case TMR_FUNCTION_AUTHORIZATION_FAILED: default: code = FCP_TMF_FAILED; break; } FT_TM_DBG("tmr fn %d resp %d fcp code %d\n", tmr->function, tmr->response, code); ft_send_resp_code(cmd, code); return 0; }
/* * Send status from completed task management request. */ void ft_queue_tm_resp(struct se_cmd *se_cmd) { struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd); struct se_tmr_req *tmr = se_cmd->se_tmr_req; enum fcp_resp_rsp_codes code; if (cmd->aborted) return; switch (tmr->response) { case TMR_FUNCTION_COMPLETE: code = FCP_TMF_CMPL; break; case TMR_LUN_DOES_NOT_EXIST: code = FCP_TMF_INVALID_LUN; break; case TMR_FUNCTION_REJECTED: code = FCP_TMF_REJECTED; break; case TMR_TASK_DOES_NOT_EXIST: case TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED: default: code = FCP_TMF_FAILED; break; } pr_debug("tmr fn %d resp %d fcp code %d\n", tmr->function, tmr->response, code); ft_send_resp_code(cmd, code); /* * Drop the extra ACK_KREF reference taken by target_submit_tmr() * ahead of ft_check_stop_free() -> transport_generic_free_cmd() * final se_cmd->cmd_kref put. */ target_put_sess_cmd(&cmd->se_cmd); }
/* * Send error or task management response. * Always frees the cmd and associated state. */ static void ft_send_resp_code_and_free(struct ft_cmd *cmd, enum fcp_resp_rsp_codes code) { ft_send_resp_code(cmd, code); ft_free_cmd(cmd); }
/* * Send new command to target. */ static void ft_send_cmd(struct ft_cmd *cmd) { struct fc_frame_header *fh = fc_frame_header_get(cmd->req_frame); struct se_cmd *se_cmd; struct fcp_cmnd *fcp; int data_dir; u32 data_len; int task_attr; int ret; fcp = fc_frame_payload_get(cmd->req_frame, sizeof(*fcp)); if (!fcp) goto err; if (fcp->fc_flags & FCP_CFL_LEN_MASK) goto err; /* not handling longer CDBs yet */ if (fcp->fc_tm_flags) { task_attr = FCP_PTA_SIMPLE; data_dir = DMA_NONE; data_len = 0; } else { switch (fcp->fc_flags & (FCP_CFL_RDDATA | FCP_CFL_WRDATA)) { case 0: data_dir = DMA_NONE; break; case FCP_CFL_RDDATA: data_dir = DMA_FROM_DEVICE; break; case FCP_CFL_WRDATA: data_dir = DMA_TO_DEVICE; break; case FCP_CFL_WRDATA | FCP_CFL_RDDATA: goto err; /* TBD not supported by tcm_fc yet */ } /* * Locate the SAM Task Attr from fc_pri_ta */ switch (fcp->fc_pri_ta & FCP_PTA_MASK) { case FCP_PTA_HEADQ: task_attr = MSG_HEAD_TAG; break; case FCP_PTA_ORDERED: task_attr = MSG_ORDERED_TAG; break; case FCP_PTA_ACA: task_attr = MSG_ACA_TAG; break; case FCP_PTA_SIMPLE: /* Fallthrough */ default: task_attr = MSG_SIMPLE_TAG; } task_attr = fcp->fc_pri_ta & FCP_PTA_MASK; data_len = ntohl(fcp->fc_dl); cmd->cdb = fcp->fc_cdb; } se_cmd = &cmd->se_cmd; /* * Initialize struct se_cmd descriptor from target_core_mod * infrastructure */ transport_init_se_cmd(se_cmd, &ft_configfs->tf_ops, cmd->sess->se_sess, data_len, data_dir, task_attr, &cmd->ft_sense_buffer[0]); /* * Check for FCP task management flags */ if (fcp->fc_tm_flags) { ft_send_tm(cmd); return; } fc_seq_exch(cmd->seq)->lp->tt.seq_set_resp(cmd->seq, ft_recv_seq, cmd); cmd->lun = scsilun_to_int((struct scsi_lun *)fcp->fc_lun); ret = transport_get_lun_for_cmd(&cmd->se_cmd, NULL, cmd->lun); if (ret < 0) { ft_dump_cmd(cmd, __func__); transport_send_check_condition_and_sense(&cmd->se_cmd, cmd->se_cmd.scsi_sense_reason, 0); return; } ret = transport_generic_allocate_tasks(se_cmd, cmd->cdb); FT_IO_DBG("r_ctl %x alloc task ret %d\n", fh->fh_r_ctl, ret); ft_dump_cmd(cmd, __func__); if (ret == -1) { transport_send_check_condition_and_sense(se_cmd, TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0); transport_generic_free_cmd(se_cmd, 0, 1, 0); return; } if (ret == -2) { if (se_cmd->se_cmd_flags & SCF_SCSI_RESERVATION_CONFLICT) ft_queue_status(se_cmd); else transport_send_check_condition_and_sense(se_cmd, se_cmd->scsi_sense_reason, 0); transport_generic_free_cmd(se_cmd, 0, 1, 0); return; } transport_generic_handle_cdb(se_cmd); return; err: ft_send_resp_code(cmd, FCP_CMND_FIELDS_INVALID); return; }
/* * Handle Task Management Request. */ static void ft_send_tm(struct ft_cmd *cmd) { struct se_tmr_req *tmr; struct fcp_cmnd *fcp; struct ft_sess *sess; u8 tm_func; fcp = fc_frame_payload_get(cmd->req_frame, sizeof(*fcp)); switch (fcp->fc_tm_flags) { case FCP_TMF_LUN_RESET: tm_func = TMR_LUN_RESET; break; case FCP_TMF_TGT_RESET: tm_func = TMR_TARGET_WARM_RESET; break; case FCP_TMF_CLR_TASK_SET: tm_func = TMR_CLEAR_TASK_SET; break; case FCP_TMF_ABT_TASK_SET: tm_func = TMR_ABORT_TASK_SET; break; case FCP_TMF_CLR_ACA: tm_func = TMR_CLEAR_ACA; break; default: /* * FCP4r01 indicates having a combination of * tm_flags set is invalid. */ FT_TM_DBG("invalid FCP tm_flags %x\n", fcp->fc_tm_flags); ft_send_resp_code(cmd, FCP_CMND_FIELDS_INVALID); return; } FT_TM_DBG("alloc tm cmd fn %d\n", tm_func); tmr = core_tmr_alloc_req(&cmd->se_cmd, cmd, tm_func); if (!tmr) { FT_TM_DBG("alloc failed\n"); ft_send_resp_code(cmd, FCP_TMF_FAILED); return; } cmd->se_cmd.se_tmr_req = tmr; switch (fcp->fc_tm_flags) { case FCP_TMF_LUN_RESET: cmd->lun = scsilun_to_int((struct scsi_lun *)fcp->fc_lun); if (transport_get_lun_for_tmr(&cmd->se_cmd, cmd->lun) < 0) { /* * Make sure to clean up newly allocated TMR request * since "unable to handle TMR request because failed * to get to LUN" */ FT_TM_DBG("Failed to get LUN for TMR func %d, " "se_cmd %p, unpacked_lun %d\n", tm_func, &cmd->se_cmd, cmd->lun); ft_dump_cmd(cmd, __func__); sess = cmd->sess; transport_send_check_condition_and_sense(&cmd->se_cmd, cmd->se_cmd.scsi_sense_reason, 0); transport_generic_free_cmd(&cmd->se_cmd, 0, 1, 0); ft_sess_put(sess); return; } break; case FCP_TMF_TGT_RESET: case FCP_TMF_CLR_TASK_SET: case FCP_TMF_ABT_TASK_SET: case FCP_TMF_CLR_ACA: break; default: return; } transport_generic_handle_tmr(&cmd->se_cmd); }