diff options
Diffstat (limited to 'drivers/target/target_core_pr.c')
| -rw-r--r-- | drivers/target/target_core_pr.c | 118 |
1 files changed, 100 insertions, 18 deletions
diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index 1493b1d01194..83e172c92238 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -19,7 +19,7 @@ #include <linux/fcntl.h> #include <linux/fs.h> #include <scsi/scsi_proto.h> -#include <asm/unaligned.h> +#include <linux/unaligned.h> #include <target/target_core_base.h> #include <target/target_core_backend.h> @@ -91,7 +91,7 @@ target_scsi2_reservation_check(struct se_cmd *cmd) switch (cmd->t_task_cdb[0]) { case INQUIRY: - case RELEASE: + case RELEASE_6: case RELEASE_10: return 0; default: @@ -418,12 +418,12 @@ static int core_scsi3_pr_seq_non_holder(struct se_cmd *cmd, u32 pr_reg_type, return -EINVAL; } break; - case RELEASE: + case RELEASE_6: case RELEASE_10: /* Handled by CRH=1 in target_scsi2_reservation_release() */ ret = 0; break; - case RESERVE: + case RESERVE_6: case RESERVE_10: /* Handled by CRH=1 in target_scsi2_reservation_reserve() */ ret = 0; @@ -470,6 +470,7 @@ static int core_scsi3_pr_seq_non_holder(struct se_cmd *cmd, u32 pr_reg_type, case INQUIRY: case LOG_SENSE: case SERVICE_ACTION_IN_12: + case READ_CAPACITY: case REPORT_LUNS: case REQUEST_SENSE: case PERSISTENT_RESERVE_IN: @@ -663,7 +664,7 @@ static struct t10_pr_registration *__core_scsi3_do_alloc_registration( } pr_reg->pr_res_mapped_lun = mapped_lun; pr_reg->pr_aptpl_target_lun = lun->unpacked_lun; - pr_reg->tg_pt_sep_rtpi = lun->lun_rtpi; + pr_reg->tg_pt_sep_rtpi = lun->lun_tpg->tpg_rtpi; pr_reg->pr_res_key = sa_res_key; pr_reg->pr_reg_all_tg_pt = all_tg_pt; pr_reg->pr_reg_aptpl = aptpl; @@ -967,7 +968,7 @@ static int __core_scsi3_check_aptpl_registration( rcu_read_unlock(); pr_reg->pr_reg_nacl = nacl; - pr_reg->tg_pt_sep_rtpi = lun->lun_rtpi; + pr_reg->tg_pt_sep_rtpi = lun->lun_tpg->tpg_rtpi; list_del(&pr_reg->pr_reg_aptpl_list); spin_unlock(&pr_tmpl->aptpl_reg_lock); /* @@ -1477,11 +1478,12 @@ core_scsi3_decode_spec_i_port( LIST_HEAD(tid_dest_list); struct pr_transport_id_holder *tidh_new, *tidh, *tidh_tmp; unsigned char *buf, *ptr, proto_ident; - const unsigned char *i_str = NULL; + unsigned char i_str[TRANSPORT_IQN_LEN]; char *iport_ptr = NULL, i_buf[PR_REG_ISID_ID_LEN]; sense_reason_t ret; u32 tpdl, tid_len = 0; u32 dest_rtpi = 0; + bool tid_found; /* * Allocate a struct pr_transport_id_holder and setup the @@ -1567,12 +1569,12 @@ core_scsi3_decode_spec_i_port( */ if (tmp_tpg->proto_id != proto_ident) continue; - dest_rtpi = tmp_lun->lun_rtpi; + dest_rtpi = tmp_lun->lun_tpg->tpg_rtpi; iport_ptr = NULL; - i_str = target_parse_pr_out_transport_id(tmp_tpg, - ptr, &tid_len, &iport_ptr); - if (!i_str) + tid_found = target_parse_pr_out_transport_id(tmp_tpg, + ptr, &tid_len, &iport_ptr, i_str); + if (!tid_found) continue; /* * Determine if this SCSI device server requires that @@ -1841,7 +1843,9 @@ out: } kmem_cache_free(t10_pr_reg_cache, dest_pr_reg); - core_scsi3_lunacl_undepend_item(dest_se_deve); + + if (dest_se_deve) + core_scsi3_lunacl_undepend_item(dest_se_deve); if (is_local) continue; @@ -3150,13 +3154,14 @@ core_scsi3_emulate_pro_register_and_move(struct se_cmd *cmd, u64 res_key, struct t10_pr_registration *pr_reg, *pr_res_holder, *dest_pr_reg; struct t10_reservation *pr_tmpl = &dev->t10_pr; unsigned char *buf; - const unsigned char *initiator_str; + unsigned char initiator_str[TRANSPORT_IQN_LEN]; char *iport_ptr = NULL, i_buf[PR_REG_ISID_ID_LEN] = { }; u32 tid_len, tmp_tid_len; int new_reg = 0, type, scope, matching_iname; sense_reason_t ret; unsigned short rtpi; unsigned char proto_ident; + bool tid_found; if (!se_sess || !se_lun) { pr_err("SPC-3 PR: se_sess || struct se_lun is NULL!\n"); @@ -3225,7 +3230,7 @@ core_scsi3_emulate_pro_register_and_move(struct se_cmd *cmd, u64 res_key, spin_lock(&dev->se_port_lock); list_for_each_entry(tmp_lun, &dev->dev_sep_list, lun_dev_link) { - if (tmp_lun->lun_rtpi != rtpi) + if (tmp_lun->lun_tpg->tpg_rtpi != rtpi) continue; dest_se_tpg = tmp_lun->lun_tpg; dest_tf_ops = dest_se_tpg->se_tpg_tfo; @@ -3275,9 +3280,9 @@ core_scsi3_emulate_pro_register_and_move(struct se_cmd *cmd, u64 res_key, ret = TCM_INVALID_PARAMETER_LIST; goto out; } - initiator_str = target_parse_pr_out_transport_id(dest_se_tpg, - &buf[24], &tmp_tid_len, &iport_ptr); - if (!initiator_str) { + tid_found = target_parse_pr_out_transport_id(dest_se_tpg, + &buf[24], &tmp_tid_len, &iport_ptr, initiator_str); + if (!tid_found) { pr_err("SPC-3 PR REGISTER_AND_MOVE: Unable to locate" " initiator_str from Transport ID\n"); ret = TCM_INVALID_PARAMETER_LIST; @@ -3538,6 +3543,37 @@ out_put_pr_reg: return ret; } +static sense_reason_t +target_try_pr_out_pt(struct se_cmd *cmd, u8 sa, u64 res_key, u64 sa_res_key, + u8 type, bool aptpl, bool all_tg_pt, bool spec_i_pt) +{ + struct exec_cmd_ops *ops = cmd->protocol_data; + + if (!cmd->se_sess || !cmd->se_lun) { + pr_err("SPC-3 PR: se_sess || struct se_lun is NULL!\n"); + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + } + + if (!ops->execute_pr_out) { + pr_err("SPC-3 PR: Device has been configured for PR passthrough but it's not supported by the backend.\n"); + return TCM_UNSUPPORTED_SCSI_OPCODE; + } + + switch (sa) { + case PRO_REGISTER_AND_MOVE: + case PRO_REPLACE_LOST_RESERVATION: + pr_err("SPC-3 PR: PRO_REGISTER_AND_MOVE and PRO_REPLACE_LOST_RESERVATION are not supported by PR passthrough.\n"); + return TCM_UNSUPPORTED_SCSI_OPCODE; + } + + if (spec_i_pt || all_tg_pt) { + pr_err("SPC-3 PR: SPEC_I_PT and ALL_TG_PT are not supported by PR passthrough.\n"); + return TCM_UNSUPPORTED_SCSI_OPCODE; + } + + return ops->execute_pr_out(cmd, sa, res_key, sa_res_key, type, aptpl); +} + /* * See spc4r17 section 6.14 Table 170 */ @@ -3641,6 +3677,12 @@ target_scsi3_emulate_pr_out(struct se_cmd *cmd) return TCM_PARAMETER_LIST_LENGTH_ERROR; } + if (dev->transport_flags & TRANSPORT_FLAG_PASSTHROUGH_PGR) { + ret = target_try_pr_out_pt(cmd, sa, res_key, sa_res_key, type, + aptpl, all_tg_pt, spec_i_pt); + goto done; + } + /* * (core_scsi3_emulate_pro_* function parameters * are defined by spc4r17 Table 174: @@ -3682,6 +3724,7 @@ target_scsi3_emulate_pr_out(struct se_cmd *cmd) return TCM_INVALID_CDB_FIELD; } +done: if (!ret) target_complete_cmd(cmd, SAM_STAT_GOOD); return ret; @@ -4039,9 +4082,42 @@ core_scsi3_pri_read_full_status(struct se_cmd *cmd) return 0; } +static sense_reason_t target_try_pr_in_pt(struct se_cmd *cmd, u8 sa) +{ + struct exec_cmd_ops *ops = cmd->protocol_data; + unsigned char *buf; + sense_reason_t ret; + + if (cmd->data_length < 8) { + pr_err("PRIN SA SCSI Data Length: %u too small\n", + cmd->data_length); + return TCM_INVALID_CDB_FIELD; + } + + if (!ops->execute_pr_in) { + pr_err("SPC-3 PR: Device has been configured for PR passthrough but it's not supported by the backend.\n"); + return TCM_UNSUPPORTED_SCSI_OPCODE; + } + + if (sa == PRI_READ_FULL_STATUS) { + pr_err("SPC-3 PR: PRI_READ_FULL_STATUS is not supported by PR passthrough.\n"); + return TCM_UNSUPPORTED_SCSI_OPCODE; + } + + buf = transport_kmap_data_sg(cmd); + if (!buf) + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + + ret = ops->execute_pr_in(cmd, sa, buf); + + transport_kunmap_data_sg(cmd); + return ret; +} + sense_reason_t target_scsi3_emulate_pr_in(struct se_cmd *cmd) { + u8 sa = cmd->t_task_cdb[1] & 0x1f; sense_reason_t ret; /* @@ -4060,7 +4136,12 @@ target_scsi3_emulate_pr_in(struct se_cmd *cmd) return TCM_RESERVATION_CONFLICT; } - switch (cmd->t_task_cdb[1] & 0x1f) { + if (cmd->se_dev->transport_flags & TRANSPORT_FLAG_PASSTHROUGH_PGR) { + ret = target_try_pr_in_pt(cmd, sa); + goto done; + } + + switch (sa) { case PRI_READ_KEYS: ret = core_scsi3_pri_read_keys(cmd); break; @@ -4079,6 +4160,7 @@ target_scsi3_emulate_pr_in(struct se_cmd *cmd) return TCM_INVALID_CDB_FIELD; } +done: if (!ret) target_complete_cmd(cmd, SAM_STAT_GOOD); return ret; |
