@@ -1424,6 +1424,13 @@ static struct target_opcode_descriptor tcm_opcode_xdwriteread32 = {
0xff, 0xff, 0xff, 0xff},
};
+static bool tcm_is_ws_enabled(struct se_cmd *cmd)
+{
+ struct se_device *dev = cmd->se_dev;
+
+ return dev->dev_attrib.emulate_tpws;
+}
+
static struct target_opcode_descriptor tcm_opcode_write_same32 = {
.support = SCSI_SUPPORT_FULL,
.serv_action_valid = 1,
@@ -1438,8 +1445,16 @@ static struct target_opcode_descriptor tcm_opcode_write_same32 = {
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff},
+ .enabled = tcm_is_ws_enabled,
};
+static bool tcm_is_caw_enabled(struct se_cmd *cmd)
+{
+ struct se_device *dev = cmd->se_dev;
+
+ return dev->dev_attrib.emulate_caw;
+}
+
static struct target_opcode_descriptor tcm_opcode_compare_write = {
.support = SCSI_SUPPORT_FULL,
.opcode = COMPARE_AND_WRITE,
@@ -1448,6 +1463,7 @@ static struct target_opcode_descriptor tcm_opcode_compare_write = {
0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x00, 0x00,
0x00, 0xff, SCSI_GROUP_NUMBER_MASK, SCSI_CONTROL_MASK},
+ .enabled = tcm_is_caw_enabled,
};
static struct target_opcode_descriptor tcm_opcode_read_capacity = {
@@ -1471,6 +1487,20 @@ static struct target_opcode_descriptor tcm_opcode_read_capacity16 = {
0xff, 0xff, 0x00, SCSI_CONTROL_MASK},
};
+static bool tcm_is_rep_ref_enabled(struct se_cmd *cmd)
+{
+ struct se_device *dev = cmd->se_dev;
+
+ spin_lock(&dev->t10_alua.lba_map_lock);
+ if (list_empty(&dev->t10_alua.lba_map_list)) {
+ spin_unlock(&dev->t10_alua.lba_map_lock);
+ return false;
+ }
+ spin_unlock(&dev->t10_alua.lba_map_lock);
+ return true;
+
+}
+
static struct target_opcode_descriptor tcm_opcode_read_report_refferals = {
.support = SCSI_SUPPORT_FULL,
.serv_action_valid = 1,
@@ -1481,6 +1511,7 @@ static struct target_opcode_descriptor tcm_opcode_read_report_refferals = {
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff,
0xff, 0xff, 0x00, SCSI_CONTROL_MASK},
+ .enabled = tcm_is_rep_ref_enabled,
};
static struct target_opcode_descriptor tcm_opcode_sync_cache = {
@@ -1502,6 +1533,14 @@ static struct target_opcode_descriptor tcm_opcode_sync_cache16 = {
0xff, 0xff, SCSI_GROUP_NUMBER_MASK, SCSI_CONTROL_MASK},
};
+static bool tcm_is_unmap_enabled(struct se_cmd *cmd)
+{
+ struct sbc_ops *ops = cmd->protocol_data;
+ struct se_device *dev = cmd->se_dev;
+
+ return ops->execute_unmap && dev->dev_attrib.emulate_tpu;
+}
+
static struct target_opcode_descriptor tcm_opcode_unmap = {
.support = SCSI_SUPPORT_FULL,
.opcode = UNMAP,
@@ -1509,6 +1548,7 @@ static struct target_opcode_descriptor tcm_opcode_unmap = {
.usage_bits = {UNMAP, 0x00, 0x00, 0x00,
0x00, 0x00, SCSI_GROUP_NUMBER_MASK, 0xff,
0xff, SCSI_CONTROL_MASK},
+ .enabled = tcm_is_unmap_enabled,
};
static struct target_opcode_descriptor tcm_opcode_write_same = {
@@ -1518,6 +1558,7 @@ static struct target_opcode_descriptor tcm_opcode_write_same = {
.usage_bits = {WRITE_SAME, 0xe8, 0xff, 0xff,
0xff, 0xff, SCSI_GROUP_NUMBER_MASK, 0xff,
0xff, SCSI_CONTROL_MASK},
+ .enabled = tcm_is_ws_enabled,
};
static struct target_opcode_descriptor tcm_opcode_write_same16 = {
@@ -1528,6 +1569,7 @@ static struct target_opcode_descriptor tcm_opcode_write_same16 = {
0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff,
0xff, 0xff, SCSI_GROUP_NUMBER_MASK, SCSI_CONTROL_MASK},
+ .enabled = tcm_is_ws_enabled,
};
static struct target_opcode_descriptor tcm_opcode_verify = {
@@ -1613,6 +1655,13 @@ static struct target_opcode_descriptor tcm_opcode_pri_read_resrv = {
0xff, SCSI_CONTROL_MASK},
};
+static bool tcm_is_pr_enabled(struct se_cmd *cmd)
+{
+ struct se_device *dev = cmd->se_dev;
+
+ return dev->dev_attrib.emulate_pr;
+}
+
static struct target_opcode_descriptor tcm_opcode_pri_read_caps = {
.support = SCSI_SUPPORT_FULL,
.serv_action_valid = 1,
@@ -1622,6 +1671,7 @@ static struct target_opcode_descriptor tcm_opcode_pri_read_caps = {
.usage_bits = {PERSISTENT_RESERVE_IN, PRI_REPORT_CAPABILITIES, 0x00, 0x00,
0x00, 0x00, 0x00, 0xff,
0xff, SCSI_CONTROL_MASK},
+ .enabled = tcm_is_pr_enabled,
};
static struct target_opcode_descriptor tcm_opcode_pri_read_full_status = {
@@ -1633,6 +1683,7 @@ static struct target_opcode_descriptor tcm_opcode_pri_read_full_status = {
.usage_bits = {PERSISTENT_RESERVE_IN, PRI_READ_FULL_STATUS, 0x00, 0x00,
0x00, 0x00, 0x00, 0xff,
0xff, SCSI_CONTROL_MASK},
+ .enabled = tcm_is_pr_enabled,
};
static struct target_opcode_descriptor tcm_opcode_pro_register = {
@@ -1644,6 +1695,7 @@ static struct target_opcode_descriptor tcm_opcode_pro_register = {
.usage_bits = {PERSISTENT_RESERVE_OUT, PRO_REGISTER, 0xff, 0x00,
0x00, 0xff, 0xff, 0xff,
0xff, SCSI_CONTROL_MASK},
+ .enabled = tcm_is_pr_enabled,
};
static struct target_opcode_descriptor tcm_opcode_pro_reserve = {
@@ -1655,6 +1707,7 @@ static struct target_opcode_descriptor tcm_opcode_pro_reserve = {
.usage_bits = {PERSISTENT_RESERVE_OUT, PRO_RESERVE, 0xff, 0x00,
0x00, 0xff, 0xff, 0xff,
0xff, SCSI_CONTROL_MASK},
+ .enabled = tcm_is_pr_enabled,
};
static struct target_opcode_descriptor tcm_opcode_pro_release = {
@@ -1666,6 +1719,7 @@ static struct target_opcode_descriptor tcm_opcode_pro_release = {
.usage_bits = {PERSISTENT_RESERVE_OUT, PRO_RELEASE, 0xff, 0x00,
0x00, 0xff, 0xff, 0xff,
0xff, SCSI_CONTROL_MASK},
+ .enabled = tcm_is_pr_enabled,
};
static struct target_opcode_descriptor tcm_opcode_pro_clear = {
@@ -1677,6 +1731,7 @@ static struct target_opcode_descriptor tcm_opcode_pro_clear = {
.usage_bits = {PERSISTENT_RESERVE_OUT, PRO_CLEAR, 0xff, 0x00,
0x00, 0xff, 0xff, 0xff,
0xff, SCSI_CONTROL_MASK},
+ .enabled = tcm_is_pr_enabled,
};
static struct target_opcode_descriptor tcm_opcode_pro_preempt = {
@@ -1688,6 +1743,7 @@ static struct target_opcode_descriptor tcm_opcode_pro_preempt = {
.usage_bits = {PERSISTENT_RESERVE_OUT, PRO_PREEMPT, 0xff, 0x00,
0x00, 0xff, 0xff, 0xff,
0xff, SCSI_CONTROL_MASK},
+ .enabled = tcm_is_pr_enabled,
};
static struct target_opcode_descriptor tcm_opcode_pro_preempt_abort = {
@@ -1699,6 +1755,7 @@ static struct target_opcode_descriptor tcm_opcode_pro_preempt_abort = {
.usage_bits = {PERSISTENT_RESERVE_OUT, PRO_PREEMPT_AND_ABORT, 0xff, 0x00,
0x00, 0xff, 0xff, 0xff,
0xff, SCSI_CONTROL_MASK},
+ .enabled = tcm_is_pr_enabled,
};
static struct target_opcode_descriptor tcm_opcode_pro_reg_ign_exist = {
@@ -1712,6 +1769,7 @@ static struct target_opcode_descriptor tcm_opcode_pro_reg_ign_exist = {
0xff, 0x00,
0x00, 0xff, 0xff, 0xff,
0xff, SCSI_CONTROL_MASK},
+ .enabled = tcm_is_pr_enabled,
};
static struct target_opcode_descriptor tcm_opcode_pro_register_move = {
@@ -1723,14 +1781,23 @@ static struct target_opcode_descriptor tcm_opcode_pro_register_move = {
.usage_bits = {PERSISTENT_RESERVE_OUT, PRO_REGISTER_AND_MOVE, 0xff, 0x00,
0x00, 0xff, 0xff, 0xff,
0xff, SCSI_CONTROL_MASK},
+ .enabled = tcm_is_pr_enabled,
};
+static bool tcm_is_scsi2_reservations_enabled(struct se_cmd *cmd)
+{
+ struct se_device *dev = cmd->se_dev;
+
+ return dev->dev_attrib.emulate_pr;
+}
+
static struct target_opcode_descriptor tcm_opcode_release = {
.support = SCSI_SUPPORT_FULL,
.opcode = RELEASE,
.cdb_size = 6,
.usage_bits = {RELEASE, 0x00, 0x00, 0x00,
0x00, SCSI_CONTROL_MASK},
+ .enabled = tcm_is_scsi2_reservations_enabled,
};
static struct target_opcode_descriptor tcm_opcode_release10 = {
@@ -1740,6 +1807,7 @@ static struct target_opcode_descriptor tcm_opcode_release10 = {
.usage_bits = {RELEASE_10, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xff,
0xff, SCSI_CONTROL_MASK},
+ .enabled = tcm_is_scsi2_reservations_enabled,
};
static struct target_opcode_descriptor tcm_opcode_reserve = {
@@ -1748,6 +1816,7 @@ static struct target_opcode_descriptor tcm_opcode_reserve = {
.cdb_size = 6,
.usage_bits = {RESERVE, 0x00, 0x00, 0x00,
0x00, SCSI_CONTROL_MASK},
+ .enabled = tcm_is_scsi2_reservations_enabled,
};
static struct target_opcode_descriptor tcm_opcode_reserve10 = {
@@ -1757,6 +1826,7 @@ static struct target_opcode_descriptor tcm_opcode_reserve10 = {
.usage_bits = {RESERVE_10, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xff,
0xff, SCSI_CONTROL_MASK},
+ .enabled = tcm_is_scsi2_reservations_enabled,
};
static struct target_opcode_descriptor tcm_opcode_request_sense = {
@@ -1775,6 +1845,13 @@ static struct target_opcode_descriptor tcm_opcode_inquiry = {
0xff, SCSI_CONTROL_MASK},
};
+static bool tcm_is_3pc_enabled(struct se_cmd *cmd)
+{
+ struct se_device *dev = cmd->se_dev;
+
+ return dev->dev_attrib.emulate_3pc;
+}
+
static struct target_opcode_descriptor tcm_opcode_extended_copy_lid1 = {
.support = SCSI_SUPPORT_FULL,
.serv_action_valid = 1,
@@ -1784,6 +1861,7 @@ static struct target_opcode_descriptor tcm_opcode_extended_copy_lid1 = {
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff,
0xff, 0xff, 0x00, SCSI_CONTROL_MASK},
+ .enabled = tcm_is_3pc_enabled,
};
static struct target_opcode_descriptor tcm_opcode_rcv_copy_res_op_params = {
@@ -1797,6 +1875,7 @@ static struct target_opcode_descriptor tcm_opcode_rcv_copy_res_op_params = {
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff,
0xff, 0xff, 0x00, SCSI_CONTROL_MASK},
+ .enabled = tcm_is_3pc_enabled,
};
static struct target_opcode_descriptor tcm_opcode_report_luns = {
@@ -1839,6 +1918,26 @@ static struct target_opcode_descriptor tcm_opcode_report_supp_opcodes = {
0xff, 0xff, 0x00, SCSI_CONTROL_MASK},
};
+static bool tcm_is_set_tpg_enabled(struct se_cmd *cmd)
+{
+ struct t10_alua_tg_pt_gp *l_tg_pt_gp;
+ struct se_lun *l_lun = cmd->se_lun;
+
+ spin_lock(&l_lun->lun_tg_pt_gp_lock);
+ l_tg_pt_gp = l_lun->lun_tg_pt_gp;
+ if (!l_tg_pt_gp) {
+ spin_unlock(&l_lun->lun_tg_pt_gp_lock);
+ return false;
+ }
+ if (!(l_tg_pt_gp->tg_pt_gp_alua_access_type & TPGS_EXPLICIT_ALUA)) {
+ spin_unlock(&l_lun->lun_tg_pt_gp_lock);
+ return false;
+ }
+ spin_unlock(&l_lun->lun_tg_pt_gp_lock);
+
+ return true;
+}
+
static struct target_opcode_descriptor tcm_opcode_set_tpg = {
.support = SCSI_SUPPORT_FULL,
.serv_action_valid = 1,
@@ -1848,6 +1947,7 @@ static struct target_opcode_descriptor tcm_opcode_set_tpg = {
.usage_bits = {MAINTENANCE_OUT, MO_SET_TARGET_PGS, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff,
0xff, 0xff, 0x00, SCSI_CONTROL_MASK},
+ .enabled = tcm_is_set_tpg_enabled,
};
static struct target_opcode_descriptor *tcm_supported_opcodes[] = {
@@ -2003,7 +2103,9 @@ spc_rsoc_get_descr(struct se_cmd *cmd, struct target_opcode_descriptor **opcode)
*/
if (descr->serv_action_valid)
return TCM_INVALID_CDB_FIELD;
- *opcode = descr;
+
+ if (!descr->enabled || descr->enabled(cmd))
+ *opcode = descr;
break;
case 0x2:
/*
@@ -2015,9 +2117,10 @@ spc_rsoc_get_descr(struct se_cmd *cmd, struct target_opcode_descriptor **opcode)
* and the additional sense code set to INVALID FIELD IN CDB.
*/
if (descr->serv_action_valid &&
- descr->service_action == requested_sa)
- *opcode = descr;
- else if (!descr->serv_action_valid)
+ descr->service_action == requested_sa) {
+ if (!descr->enabled || descr->enabled(cmd))
+ *opcode = descr;
+ } else if (!descr->serv_action_valid)
return TCM_INVALID_CDB_FIELD;
break;
case 0x3:
@@ -2028,10 +2131,12 @@ spc_rsoc_get_descr(struct se_cmd *cmd, struct target_opcode_descriptor **opcode)
* be returned in the one_command parameter data format.
*/
if (descr->service_action == requested_sa)
- *opcode = descr;
+ if (!descr->enabled || descr->enabled(cmd))
+ *opcode = descr;
break;
}
}
+
return 0;
}
@@ -2080,6 +2185,9 @@ spc_emulate_report_supp_op_codes(struct se_cmd *cmd)
for (i = 0; i < ARRAY_SIZE(tcm_supported_opcodes); i++) {
descr = tcm_supported_opcodes[i];
+ if (descr->enabled && !descr->enabled(cmd))
+ continue;
+
response_length += spc_rsoc_encode_command_descriptor(
&buf[response_length], rctd, descr);
}
@@ -876,6 +876,7 @@ struct target_opcode_descriptor {
u8 specific_timeout;
u16 nominal_timeout;
u16 recommended_timeout;
+ bool (*enabled)(struct se_cmd *cmd);
u8 usage_bits[];
};