[PATCH 1/5] [Target_Core_Mod]: Add emulated REQUEST_SENSE and Control mode page TAS bit

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



>From 09bbe19217c4a9dbd07562b1c220a878d1ed1e96 Mon Sep 17 00:00:00 2001
From: Nicholas Bellinger <nab@xxxxxxxxxxxxxxx>
Date: Mon, 23 Mar 2009 22:21:27 -0700
Subject: [PATCH 1/5] [Target_Core_Mod]: Add emulated REQUEST_SENSE and Control mode page TAS bit

This patch adds transport_generic_emulate_request_sense(), and updates
transport_modesense_control() to set the TASK_ABORTED Status (TAS) bit
based on DEV_ATTRIB(dev)->emulated_tas.

This patch also adds transport_cmd_finish_abort() and
transport_cmd_finish_abort_tmr() functions (used by new LUN_RESET code).
Also, transport_send_check_condition_and_sense() is updated to use
new SPC_ASC_KEY_OFFSET and SPC_ASCQ_KEY_OFFSET defines.

Signed-off-by: Nicholas A. Bellinger <nab@xxxxxxxxxxxxxxx>
---
 drivers/lio-core/target_core_base.h      |    7 +-
 drivers/lio-core/target_core_transport.c |  149 +++++++++++++++++++++++++-----
 drivers/lio-core/target_core_transport.h |   13 +++
 3 files changed, 145 insertions(+), 24 deletions(-)

diff --git a/drivers/lio-core/target_core_base.h b/drivers/lio-core/target_core_base.h
index 3341cb2..cab978f 100644
--- a/drivers/lio-core/target_core_base.h
+++ b/drivers/lio-core/target_core_base.h
@@ -55,7 +55,8 @@
 #define TRANSPORT_SENSE_BUFFER              SCSI_SENSE_BUFFERSIZE
 
 #define SPC_SENSE_KEY_OFFSET			2
-#define SPC_ASQ_KEY_OFFSET			12
+#define SPC_ASC_KEY_OFFSET			12
+#define SPC_ASCQ_KEY_OFFSET			13
 
 /* Currently same as ISCSI_IQN_LEN */
 #define TRANSPORT_IQN_LEN			224
@@ -195,6 +196,7 @@
 #define LOGICAL_UNIT_COMMUNICATION_FAILURE	0xa
 #define UNKNOWN_MODE_PAGE			0xb
 #define WRITE_PROTECTED				0xc
+#define CHECK_CONDITION_ABORT_CMD		0xd
 
 typedef struct se_obj_s {
 	atomic_t obj_access_count;
@@ -320,7 +322,7 @@ typedef struct se_queue_req_s {
 typedef struct se_queue_obj_s {
 	atomic_t		queue_cnt;
 	spinlock_t		cmd_queue_lock;
-	struct list_head	qobj_list;		
+	struct list_head	qobj_list;
 	wait_queue_head_t	thread_wq;
 	struct semaphore	thread_create_sem;
 	struct semaphore	thread_done_sem;
@@ -604,6 +606,7 @@ typedef struct se_dev_entry_s {
 typedef struct se_dev_attrib_s {
 	int		status_thread;
 	int		status_thread_tur;
+	int		emulate_tas;
 	int		emulate_reservations;
 	int		emulate_alua;
 	u32		hw_block_size;
diff --git a/drivers/lio-core/target_core_transport.c b/drivers/lio-core/target_core_transport.c
index 4597e1b..6fa358d 100644
--- a/drivers/lio-core/target_core_transport.c
+++ b/drivers/lio-core/target_core_transport.c
@@ -899,7 +899,36 @@ static void transport_lun_remove_cmd(se_cmd_t *cmd)
 	spin_unlock_irqrestore(&lun->lun_cmd_lock, flags);
 }
 
-extern int transport_add_cmd_to_queue(
+void transport_cmd_finish_abort(se_cmd_t *cmd, int remove)
+{
+	transport_remove_cmd_from_queue(cmd,
+		CMD_ORIG_OBJ_API(cmd)->get_queue_obj(
+			cmd->se_orig_obj_ptr));
+
+	transport_lun_remove_cmd(cmd);
+
+	if (!(transport_cmd_check_stop(cmd, 1, 0))) {
+		transport_passthrough_check_stop(cmd);
+		return;
+	}
+	if (remove)
+		transport_generic_remove(cmd, 0, 0);
+}
+
+void transport_cmd_finish_abort_tmr(se_cmd_t *cmd)
+{
+	transport_remove_cmd_from_queue(cmd,
+			CMD_ORIG_OBJ_API(cmd)->get_queue_obj(
+			cmd->se_orig_obj_ptr));
+
+	if (!(transport_cmd_check_stop(cmd, 1, 0))) {
+		transport_passthrough_check_stop(cmd);
+		return;
+	}
+	transport_generic_remove(cmd, 0, 0);
+}
+
+int transport_add_cmd_to_queue(
 	se_cmd_t *cmd,
 	se_queue_obj_t *qobj,
 	u8 t_state)
@@ -955,7 +984,7 @@ se_queue_req_t *__transport_get_qr_from_queue(se_queue_obj_t *qobj)
 
 	list_for_each_entry(qr, &qobj->qobj_list, qr_list)
 		break;
-	
+
 	if (qr->cmd) {
 		cmd = (se_cmd_t *)qr->cmd;
 		atomic_dec(&T_TASK(cmd)->t_transport_queue_active);
@@ -992,7 +1021,7 @@ se_queue_req_t *transport_get_qr_from_queue(se_queue_obj_t *qobj)
 	return qr;
 }
 
-static void transport_remove_cmd_from_queue(se_cmd_t *cmd, se_queue_obj_t *qobj)
+void transport_remove_cmd_from_queue(se_cmd_t *cmd, se_queue_obj_t *qobj)
 {
 	se_cmd_t *q_cmd;
 	se_queue_req_t *qr = NULL, *qr_p = NULL;
@@ -4467,11 +4496,36 @@ static int transport_modesense_rwrecovery(unsigned char *p)
 	return 12;
 }
 
-static int transport_modesense_control(unsigned char *p)
+static int transport_modesense_control(se_device_t *dev, unsigned char *p)
 {
 	p[0] = 0x0a;
 	p[1] = 0x0a;
 	p[2] = 2;
+	/*
+	 * From spc4r17, section 7.4.6 Control mode Page
+	 *
+	 * Unit Attention interlocks control (UN_INTLCK_CTRL) to code 00b
+	 *
+	 * 00b: The logical unit shall clear any unit attention condition
+	 * reported in the same I_T_L_Q nexus transaction as a CHECK CONDITION
+	 * status and shall not establish a unit attention condition when a com-
+	 * mand is completed with BUSY, TASK SET FULL, or RESERVATION CONFLICT
+	 * status.
+	 */
+	p[4] = 0x00;
+	/*
+	 * From spc4r17, section 7.4.6 Control mode Page
+	 *
+	 * Task Aborted Status (TAS) bit set to zero.
+	 *
+	 * A task aborted status (TAS) bit set to zero specifies that aborted
+	 * tasks shall be terminated by the device server without any response
+	 * to the application client. A TAS bit set to one specifies that tasks
+	 * aborted by the actions of an I_T nexus other than the I_T nexus on
+	 * which the command was received shall be completed with TASK ABORTED
+	 * status (see SAM-4).
+	 */
+	p[5] = (DEV_ATTRIB(dev)->emulate_tas) ? 0x40 : 0x00;
 	p[8] = 0xff;
 	p[9] = 0xff;
 	p[11] = 30;
@@ -4525,6 +4579,7 @@ int transport_generic_emulate_modesense(
 	int ten,
 	int type)
 {
+	se_device_t *dev = SE_DEV(cmd);
 	int offset = (ten) ? 8 : 4;
 	int length = 0;
 	unsigned char buf[SE_MODE_PAGE_BUF];
@@ -4539,7 +4594,7 @@ int transport_generic_emulate_modesense(
 		length = transport_modesense_caching(&buf[offset]);
 		break;
 	case 0x0a:
-		length = transport_modesense_control(&buf[offset]);
+		length = transport_modesense_control(dev, &buf[offset]);
 		break;
 #if 0
 	case 0x2a:
@@ -4549,7 +4604,7 @@ int transport_generic_emulate_modesense(
 	case 0x3f:
 		length = transport_modesense_rwrecovery(&buf[offset]);
 		length += transport_modesense_caching(&buf[offset+length]);
-		length += transport_modesense_control(&buf[offset+length]);
+		length += transport_modesense_control(dev, &buf[offset+length]);
 #if 0
 		length += transport_modesense_devicecaps(&buf[offset+length]);
 #endif
@@ -4591,6 +4646,38 @@ int transport_generic_emulate_modesense(
 	return 0;
 }
 
+int transport_generic_emulate_request_sense(
+	se_cmd_t *cmd,
+	unsigned char *cdb)
+{
+	unsigned char *buf = (unsigned char *) T_TASK(cmd)->t_task_buf;
+
+	if (cdb[1] & 0x01) {
+		printk(KERN_ERR "REQUEST_SENSE description emulation not"
+			" supported\n");
+		return PYX_TRANSPORT_INVALID_CDB_FIELD;
+	}
+	/*
+	 * CURRENT ERROR
+	 */
+	buf[0] = 0x70;
+	buf[SPC_SENSE_KEY_OFFSET] = NO_SENSE;
+	/*
+	 * Make sure request data length is enough for additional sense data.
+	 */
+	if (cmd->data_length <= 18) {
+		buf[7] = 0x00;
+		return 0;
+	}
+	/*
+	 * NO ADDITIONAL SENSE INFORMATION
+	 */
+	buf[SPC_ASC_KEY_OFFSET] = 0x00;
+	buf[7] = 0x0A;
+
+	return 0;
+}
+
 /*
  * Used to obtain Sense Data from underlying Linux/SCSI struct scsi_cmnd
  */
@@ -4692,7 +4779,8 @@ static int transport_generic_cmd_sequencer(
 	u32 sectors = 0, size = 0, pr_reg_type = 0;
 
 	if (T10_RES(su_dev)->t10_reservation_check(cmd, &pr_reg_type) != 0) {
-		if (T10_RES(su_dev)->t10_seq_non_holder(cmd, cdb, pr_reg_type) != 0) {
+		if (T10_RES(su_dev)->t10_seq_non_holder(
+					cmd, cdb, pr_reg_type) != 0) {
 			cmd->transport_wait_for_tasks =
 					&transport_nop_wait_for_tasks;
 			transport_get_maps(cmd);
@@ -7051,7 +7139,7 @@ int transport_send_check_condition_and_sense(
 		/* ILLEGAL REQUEST */
 		buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
 		/* INVALID COMMAND OPERATION CODE */
-		buffer[offset+SPC_ASQ_KEY_OFFSET] = 0x20;
+		buffer[offset+SPC_ASC_KEY_OFFSET] = 0x20;
 		break;
 	case UNKNOWN_MODE_PAGE:
 		/* CURRENT ERROR */
@@ -7059,7 +7147,16 @@ int transport_send_check_condition_and_sense(
 		/* ILLEGAL REQUEST */
 		buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
 		/* INVALID FIELD IN CDB */
-		buffer[offset+SPC_ASQ_KEY_OFFSET] = 0x24;
+		buffer[offset+SPC_ASC_KEY_OFFSET] = 0x24;
+		break;
+	case CHECK_CONDITION_ABORT_CMD:
+		/* CURRENT ERROR */
+		buffer[offset] = 0x70;
+		/* ABORTED COMMAND */
+		buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
+		/* BUS DEVICE RESET FUNCTION OCCURRED */
+		buffer[offset+SPC_ASC_KEY_OFFSET] = 0x29;
+		buffer[offset+SPC_ASCQ_KEY_OFFSET] = 0x03;
 		break;
 	case INCORRECT_AMOUNT_OF_DATA:
 		/* CURRENT ERROR */
@@ -7067,9 +7164,9 @@ int transport_send_check_condition_and_sense(
 		/* ABORTED COMMAND */
 		buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
 		/* WRITE ERROR */
-		buffer[offset+SPC_ASQ_KEY_OFFSET] = 0x0c;
+		buffer[offset+SPC_ASC_KEY_OFFSET] = 0x0c;
 		/* NOT ENOUGH UNSOLICITED DATA */
-		buffer[offset+SPC_ASQ_KEY_OFFSET+1] = 0x0d;
+		buffer[offset+SPC_ASCQ_KEY_OFFSET] = 0x0d;
 		break;
 	case INVALID_CDB_FIELD:
 		/* CURRENT ERROR */
@@ -7077,7 +7174,7 @@ int transport_send_check_condition_and_sense(
 		/* ABORTED COMMAND */
 		buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
 		/* INVALID FIELD IN CDB */
-		buffer[offset+SPC_ASQ_KEY_OFFSET] = 0x24;
+		buffer[offset+SPC_ASC_KEY_OFFSET] = 0x24;
 		break;
 	case INVALID_PARAMETER_LIST:
 		/* CURRENT ERROR */
@@ -7085,7 +7182,7 @@ int transport_send_check_condition_and_sense(
 		/* ABORTED COMMAND */
 		buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
 		/* INVALID FIELD IN PARAMETER LIST */
-		buffer[offset+SPC_ASQ_KEY_OFFSET] = 0x26;
+		buffer[offset+SPC_ASC_KEY_OFFSET] = 0x26;
 		break;
 	case UNEXPECTED_UNSOLICITED_DATA:
 		/* CURRENT ERROR */
@@ -7093,9 +7190,9 @@ int transport_send_check_condition_and_sense(
 		/* ABORTED COMMAND */
 		buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
 		/* WRITE ERROR */
-		buffer[offset+SPC_ASQ_KEY_OFFSET] = 0x0c;
+		buffer[offset+SPC_ASC_KEY_OFFSET] = 0x0c;
 		/* UNEXPECTED_UNSOLICITED_DATA */
-		buffer[offset+SPC_ASQ_KEY_OFFSET+1] = 0x0c;
+		buffer[offset+SPC_ASCQ_KEY_OFFSET] = 0x0c;
 		break;
 	case SERVICE_CRC_ERROR:
 		/* CURRENT ERROR */
@@ -7103,9 +7200,9 @@ int transport_send_check_condition_and_sense(
 		/* ABORTED COMMAND */
 		buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
 		/* PROTOCOL SERVICE CRC ERROR */
-		buffer[offset+SPC_ASQ_KEY_OFFSET] = 0x47;
+		buffer[offset+SPC_ASC_KEY_OFFSET] = 0x47;
 		/* N/A */
-		buffer[offset+SPC_ASQ_KEY_OFFSET+1] = 0x05;
+		buffer[offset+SPC_ASCQ_KEY_OFFSET] = 0x05;
 		break;
 	case SNACK_REJECTED:
 		/* CURRENT ERROR */
@@ -7113,9 +7210,9 @@ int transport_send_check_condition_and_sense(
 		/* ABORTED COMMAND */
 		buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
 		/* READ ERROR */
-		buffer[offset+SPC_ASQ_KEY_OFFSET] = 0x11;
+		buffer[offset+SPC_ASC_KEY_OFFSET] = 0x11;
 		/* FAILED RETRANSMISSION REQUEST */
-		buffer[offset+SPC_ASQ_KEY_OFFSET+1] = 0x13;
+		buffer[offset+SPC_ASCQ_KEY_OFFSET] = 0x13;
 		break;
 	case WRITE_PROTECTED:
 		/* CURRENT ERROR */
@@ -7123,7 +7220,7 @@ int transport_send_check_condition_and_sense(
 		/* DATA PROTECT */
 		buffer[offset+SPC_SENSE_KEY_OFFSET] = DATA_PROTECT;
 		/* WRITE PROTECTED */
-		buffer[offset+SPC_ASQ_KEY_OFFSET] = 0x27;
+		buffer[offset+SPC_ASC_KEY_OFFSET] = 0x27;
 		break;
 	case LOGICAL_UNIT_COMMUNICATION_FAILURE:
 	default:
@@ -7132,7 +7229,7 @@ int transport_send_check_condition_and_sense(
 		/* ILLEGAL REQUEST */
 		buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
 		/* LOGICAL UNIT COMMUNICATION FAILURE */
-		buffer[offset+SPC_ASQ_KEY_OFFSET] = 0x80;
+		buffer[offset+SPC_ASC_KEY_OFFSET] = 0x80;
 		break;
 	}
 	/*
@@ -7153,6 +7250,14 @@ after_reason:
 }
 EXPORT_SYMBOL(transport_send_check_condition_and_sense);
 
+void transport_send_task_abort(se_cmd_t *cmd)
+{
+	cmd->scsi_status = SAM_STAT_TASK_ABORTED;
+
+	if (!(cmd->se_cmd_flags & SCF_CMD_PASSTHROUGH))
+		CMD_TFO(cmd)->queue_status(cmd);
+}
+
 /*	transport_generic_do_tmr():
  *
  *
@@ -7388,7 +7493,7 @@ static int transport_status_thread_tur(
  *	Called with spin_lock_irq(&dev->execute_task_lock); held
  *
  */
-static se_task_t *transport_get_task_from_state_list(se_device_t *dev)
+se_task_t *transport_get_task_from_state_list(se_device_t *dev)
 {
 	se_task_t *task;
 
diff --git a/drivers/lio-core/target_core_transport.h b/drivers/lio-core/target_core_transport.h
index e8c3c3f..f3637ec 100644
--- a/drivers/lio-core/target_core_transport.h
+++ b/drivers/lio-core/target_core_transport.h
@@ -102,6 +102,8 @@
 #define DA_STATUS_THREAD			0
 /* Disabled by default */
 #define DA_STATUS_THREAD_TUR			0
+/* Emulation for TASK_ABORTED status (TAS) by default */
+#define DA_EMULATE_TAS				1
 /* No Emulation for PSCSI by default */
 #define DA_EMULATE_RESERVATIONS			0
 /* No Emulation for PSCSI by default */
@@ -139,8 +141,14 @@ extern void transport_deregister_session_configfs(struct se_session_s *);
 extern void transport_deregister_session(struct se_session_s *);
 extern void transport_task_dev_remove_state(struct se_task_s *,
 						struct se_device_s *);
+extern void transport_cmd_finish_abort(struct se_cmd_s *, int);
+extern void transport_cmd_finish_abort_tmr(struct se_cmd_s *);
 extern int transport_add_cmd_to_queue(struct se_cmd_s *,
 					struct se_queue_obj_s *, u8);
+extern struct se_queue_req_s *__transport_get_qr_from_queue(
+					struct se_queue_obj_s *);
+extern void transport_remove_cmd_from_queue(struct se_cmd_s *,
+					    struct se_queue_obj_s *);
 extern void transport_complete_cmd(se_cmd_t *, int);
 extern void transport_complete_task(struct se_task_s *, int);
 extern void transport_add_task_to_execute_queue(struct se_task_s *,
@@ -208,6 +216,8 @@ extern int transport_generic_emulate_readcapacity_16(struct se_cmd_s *,
 extern int transport_generic_emulate_modesense(struct se_cmd_s *,
 						unsigned char *,
 						unsigned char *, int, int);
+extern int transport_generic_emulate_request_sense(struct se_cmd_s *,
+						   unsigned char *);
 extern int transport_get_sense_data(struct se_cmd_s *);
 extern void transport_memcpy_read_contig(struct se_cmd_s *, unsigned char *);
 extern void transport_memcpy_read_sg(struct se_cmd_s *, struct scatterlist *);
@@ -232,6 +242,7 @@ extern int transport_generic_remove(se_cmd_t *, int, int);
 extern int transport_lun_wait_for_tasks(se_cmd_t *, se_lun_t *);
 extern void transport_clear_lun_from_sessions(se_lun_t *);
 extern int transport_send_check_condition_and_sense(se_cmd_t *, u8, int);
+extern void transport_send_task_abort(struct se_cmd_s *);
 extern void transport_release_cmd_to_pool(se_cmd_t *);
 extern void transport_generic_free_cmd(se_cmd_t *, int, int, int);
 extern void transport_generic_wait_for_cmds(se_cmd_t *, int);
@@ -267,6 +278,8 @@ extern void transport_generic_process_write(se_cmd_t *);
 extern int transport_generic_do_tmr(se_cmd_t *);
 extern void transport_start_status_timer(se_device_t *);
 extern void transport_stop_status_timer(se_device_t *);
+extern struct se_task_s *transport_get_task_from_state_list(
+					struct se_device_s *);
 extern void transport_status_thr_force_offline(se_device_t *,
 					struct se_obj_lun_type_s *,
 					void *);
-- 
1.5.4.1




--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]
  Powered by Linux