From 2e96d8ac2695a13edf71976bd099003dda52056d Mon Sep 17 00:00:00 2001
From: Mike Christie <michaelc@cs.wisc.edu>
Date: Wed, 29 Jul 2015 04:23:49 -0500
Subject: [PATCH] target: compare and write backend driver sense handling
References: fate#318836
Patch-mainline: Not yet, SES2 clustered LIO/RBD
Currently, backend drivers seem to only fail IO with
SAM_STAT_CHECK_CONDITION which gets us
TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE.
For compare and write support we will want to be able to fail with
TCM_MISCOMPARE_VERIFY. This patch adds a new helper that allows backend
drivers to fail with specific sense codes.
It also allows the backend driver to set the miscompare offset.
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
Acked-by: David Disseldorp <ddiss@suse.de>
[ddiss@suse.de rebase against ab78fef4d5 and 9ec1e1ce3a]
---
drivers/target/target_core_transport.c | 35 ++++++++++++++++++++++++++++++---
include/target/target_core_backend.h | 1
include/target/target_core_base.h | 5 +++-
3 files changed, 37 insertions(+), 4 deletions(-)
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -677,8 +677,7 @@ static void target_complete_failure_work
{
struct se_cmd *cmd = container_of(work, struct se_cmd, work);
- transport_generic_request_failure(cmd,
- TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE);
+ transport_generic_request_failure(cmd, cmd->sense_reason);
}
/*
@@ -722,13 +721,15 @@ void transport_copy_sense_to_cmd(struct
}
EXPORT_SYMBOL(transport_copy_sense_to_cmd);
-void target_complete_cmd(struct se_cmd *cmd, u8 scsi_status)
+static void __target_complete_cmd(struct se_cmd *cmd, u8 scsi_status,
+ sense_reason_t sense_reason)
{
struct se_device *dev = cmd->se_dev;
int success;
unsigned long flags;
cmd->scsi_status = scsi_status;
+ cmd->sense_reason = sense_reason;
spin_lock_irqsave(&cmd->t_state_lock, flags);
switch (cmd->scsi_status) {
@@ -776,8 +777,22 @@ void target_complete_cmd(struct se_cmd *
else
queue_work(target_completion_wq, &cmd->work);
}
+
+void target_complete_cmd(struct se_cmd *cmd, u8 scsi_status)
+{
+ __target_complete_cmd(cmd, scsi_status, scsi_status ?
+ TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE :
+ TCM_NO_SENSE);
+}
EXPORT_SYMBOL(target_complete_cmd);
+void target_complete_cmd_with_sense(struct se_cmd *cmd,
+ sense_reason_t sense_reason)
+{
+ __target_complete_cmd(cmd, SAM_STAT_CHECK_CONDITION, sense_reason);
+}
+EXPORT_SYMBOL(target_complete_cmd_with_sense);
+
void target_complete_cmd_with_length(struct se_cmd *cmd, u8 scsi_status, int length)
{
if (scsi_status == SAM_STAT_GOOD && length < cmd->data_length) {
@@ -1770,6 +1785,7 @@ void transport_generic_request_failure(s
case TCM_UNSUPPORTED_TARGET_DESC_TYPE_CODE:
case TCM_TOO_MANY_SEGMENT_DESCS:
case TCM_UNSUPPORTED_SEGMENT_DESC_TYPE_CODE:
+ case TCM_MISCOMPARE_VERIFY:
break;
case TCM_OUT_OF_RESOURCES:
cmd->scsi_status = SAM_STAT_TASK_SET_FULL;
@@ -2975,11 +2991,13 @@ bool transport_wait_for_tasks(struct se_
}
EXPORT_SYMBOL(transport_wait_for_tasks);
+
struct sense_info {
u8 key;
u8 asc;
u8 ascq;
bool add_sector_info;
+ bool add_sense_info;
};
static const struct sense_info sense_info_table[] = {
@@ -3077,6 +3095,7 @@ static const struct sense_info sense_inf
.key = MISCOMPARE,
.asc = 0x1d, /* MISCOMPARE DURING VERIFY OPERATION */
.ascq = 0x00,
+ .add_sense_info = true,
},
[TCM_LOGICAL_BLOCK_GUARD_CHECK_FAILED] = {
.key = ABORTED_COMMAND,
@@ -3114,6 +3133,13 @@ static const struct sense_info sense_inf
},
};
+static void transport_err_sense_info(unsigned char *buffer, u32 info)
+{
+ buffer[SPC_INFO_VALIDITY_OFFSET] |= 0x80;
+ /* Sense Information */
+ put_unaligned_be32(info, &buffer[3]);
+}
+
static int translate_sense_reason(struct se_cmd *cmd, sense_reason_t reason)
{
const struct sense_info *si;
@@ -3146,6 +3172,9 @@ static int translate_sense_reason(struct
cmd->scsi_sense_length,
cmd->bad_sector);
+ if (si->add_sense_info)
+ transport_err_sense_info(buffer, cmd->sense_info);
+
return 0;
}
--- a/include/target/target_core_backend.h
+++ b/include/target/target_core_backend.h
@@ -69,6 +69,7 @@ int transport_backend_register(const str
void target_backend_unregister(const struct target_backend_ops *);
void target_complete_cmd(struct se_cmd *, u8);
+void target_complete_cmd_with_sense(struct se_cmd *, sense_reason_t);
void target_complete_cmd_with_length(struct se_cmd *, u8, int);
void transport_copy_sense_to_cmd(struct se_cmd *, unsigned char *);
--- a/include/target/target_core_base.h
+++ b/include/target/target_core_base.h
@@ -21,11 +21,12 @@
*/
#define TRANSPORT_SENSE_BUFFER 96
/* Used by transport_send_check_condition_and_sense() */
+#define SPC_INFO_VALIDITY_OFFSET 0
#define SPC_SENSE_KEY_OFFSET 2
#define SPC_ADD_SENSE_LEN_OFFSET 7
#define SPC_DESC_TYPE_OFFSET 8
#define SPC_ADDITIONAL_DESC_LEN_OFFSET 9
-#define SPC_VALIDITY_OFFSET 10
+#define SPC_CMD_INFO_VALIDITY_OFFSET 10
#define SPC_ASC_KEY_OFFSET 12
#define SPC_ASCQ_KEY_OFFSET 13
#define TRANSPORT_IQN_LEN 224
@@ -437,6 +438,8 @@ enum target_core_dif_check {
#define TCM_ACA_TAG 0x24
struct se_cmd {
+ sense_reason_t sense_reason;
+ u32 sense_info;
/* SAM response code being sent to initiator */
u8 scsi_status;
u8 scsi_asc;