[PATCH 3/17]: SCST public headers

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

 



This patch contains declarations of all externally visible SCST constants, 
types and functions prototypes.

Signed-off-by: Vladislav Bolkhovitin <vst@xxxxxxxx>
---
 scst.h       | 3562 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 scst_const.h |  370 ++++++
 2 files changed, 3932 insertions(+)

diff -uprN orig/linux-2.6.35/include/scst/scst_const.h linux-2.6.35/include/scst/scst_const.h
--- orig/linux-2.6.35/include/scst/scst_const.h
+++ linux-2.6.35/include/scst/scst_const.h
@@ -0,0 +1,370 @@
+/*
+ *  include/scst_const.h
+ *
+ *  Copyright (C) 2004 - 2010 Vladislav Bolkhovitin <vst@xxxxxxxx>
+ *  Copyright (C) 2007 - 2010 ID7 Ltd.
+ *
+ *  Contains common SCST constants.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation, version 2
+ *  of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ */
+
+#ifndef __SCST_CONST_H
+#define __SCST_CONST_H
+
+#include <scsi/scsi.h>
+
+#define SCST_CONST_VERSION "$Revision: 1864 $"
+
+/*** Shared constants between user and kernel spaces ***/
+
+/* Max size of CDB */
+#define SCST_MAX_CDB_SIZE            16
+
+/* Max size of various names */
+#define SCST_MAX_NAME		     50
+
+/* Max size of external names, like initiator name */
+#define SCST_MAX_EXTERNAL_NAME	     256
+
+/*
+ * Size of sense sufficient to carry standard sense data.
+ * Warning! It's allocated on stack!
+ */
+#define SCST_STANDARD_SENSE_LEN      18
+
+/* Max size of sense */
+#define SCST_SENSE_BUFFERSIZE        96
+
+/*************************************************************
+ ** Allowed delivery statuses for cmd's delivery_status
+ *************************************************************/
+
+#define SCST_CMD_DELIVERY_SUCCESS	0
+#define SCST_CMD_DELIVERY_FAILED	-1
+#define SCST_CMD_DELIVERY_ABORTED	-2
+
+/*************************************************************
+ ** Values for task management functions
+ *************************************************************/
+#define SCST_ABORT_TASK			0
+#define SCST_ABORT_TASK_SET		1
+#define SCST_CLEAR_ACA			2
+#define SCST_CLEAR_TASK_SET		3
+#define SCST_LUN_RESET			4
+#define SCST_TARGET_RESET		5
+
+/** SCST extensions **/
+
+/*
+ * Notifies about I_T nexus loss event in the corresponding session.
+ * Aborts all tasks there, resets the reservation, if any, and sets
+ * up the I_T Nexus loss UA.
+ */
+#define SCST_NEXUS_LOSS_SESS		6
+
+/* Aborts all tasks in the corresponding session */
+#define SCST_ABORT_ALL_TASKS_SESS	7
+
+/*
+ * Notifies about I_T nexus loss event. Aborts all tasks in all sessions
+ * of the tgt, resets the reservations, if any,  and sets up the I_T Nexus
+ * loss UA.
+ */
+#define SCST_NEXUS_LOSS			8
+
+/* Aborts all tasks in all sessions of the tgt */
+#define SCST_ABORT_ALL_TASKS		9
+
+/*
+ * Internal TM command issued by SCST in scst_unregister_session(). It is the
+ * same as SCST_NEXUS_LOSS_SESS, except:
+ *  - it doesn't call task_mgmt_affected_cmds_done()
+ *  - it doesn't call task_mgmt_fn_done()
+ *  - it doesn't queue NEXUS LOSS UA.
+ *
+ * Target drivers must NEVER use it!!
+ */
+#define SCST_UNREG_SESS_TM		10
+
+/*
+ * Internal TM command issued by SCST in scst_pr_abort_reg(). It aborts all
+ * tasks from mcmd->origin_pr_cmd->tgt_dev, except mcmd->origin_pr_cmd.
+ * Additionally:
+ *  - it signals pr_aborting_cmpl completion when all affected
+ *    commands marked as aborted.
+ *  - it doesn't call task_mgmt_affected_cmds_done()
+ *  - it doesn't call task_mgmt_fn_done()
+ *  - it calls mcmd->origin_pr_cmd->scst_cmd_done() when all affected
+ *    commands aborted.
+ *
+ * Target drivers must NEVER use it!!
+ */
+#define SCST_PR_ABORT_ALL		11
+
+/*************************************************************
+ ** Values for mgmt cmd's status field. Codes taken from iSCSI
+ *************************************************************/
+#define SCST_MGMT_STATUS_SUCCESS		0
+#define SCST_MGMT_STATUS_TASK_NOT_EXIST		-1
+#define SCST_MGMT_STATUS_LUN_NOT_EXIST		-2
+#define SCST_MGMT_STATUS_FN_NOT_SUPPORTED	-5
+#define SCST_MGMT_STATUS_REJECTED		-255
+#define SCST_MGMT_STATUS_FAILED			-129
+
+/*************************************************************
+ ** SCSI task attribute queue types
+ *************************************************************/
+enum scst_cmd_queue_type {
+	SCST_CMD_QUEUE_UNTAGGED = 0,
+	SCST_CMD_QUEUE_SIMPLE,
+	SCST_CMD_QUEUE_ORDERED,
+	SCST_CMD_QUEUE_HEAD_OF_QUEUE,
+	SCST_CMD_QUEUE_ACA
+};
+
+/*************************************************************
+ ** CDB flags
+ *************************************************************/
+enum scst_cdb_flags {
+	SCST_TRANSFER_LEN_TYPE_FIXED =		0x0001,
+	SCST_SMALL_TIMEOUT =			0x0002,
+	SCST_LONG_TIMEOUT =			0x0004,
+	SCST_UNKNOWN_LENGTH =			0x0008,
+	SCST_INFO_VALID =			0x0010, /* must be single bit */
+	SCST_VERIFY_BYTCHK_MISMATCH_ALLOWED =	0x0020,
+	SCST_IMPLICIT_HQ =			0x0040,
+	SCST_SKIP_UA =				0x0080,
+	SCST_WRITE_MEDIUM =			0x0100,
+	SCST_LOCAL_CMD =			0x0200,
+	SCST_FULLY_LOCAL_CMD =			0x0400,
+	SCST_REG_RESERVE_ALLOWED =		0x0800,
+	SCST_WRITE_EXCL_ALLOWED =		0x1000,
+	SCST_EXCL_ACCESS_ALLOWED =		0x2000,
+#ifdef CONFIG_SCST_TEST_IO_IN_SIRQ
+	SCST_TEST_IO_IN_SIRQ_ALLOWED =		0x8000,
+#endif
+};
+
+/*************************************************************
+ ** Data direction aliases. Changing it don't forget to change
+ ** scst_to_tgt_dma_dir as well!!
+ *************************************************************/
+#define SCST_DATA_UNKNOWN		0
+#define SCST_DATA_WRITE			1
+#define SCST_DATA_READ			2
+#define SCST_DATA_BIDI			(SCST_DATA_WRITE | SCST_DATA_READ)
+#define SCST_DATA_NONE			4
+
+/*************************************************************
+ ** Default suffix for targets with NULL names
+ *************************************************************/
+#define SCST_DEFAULT_TGT_NAME_SUFFIX		"_target_"
+
+/*************************************************************
+ ** Sense manipulation and examination
+ *************************************************************/
+#define SCST_LOAD_SENSE(key_asc_ascq) key_asc_ascq
+
+#define SCST_SENSE_VALID(sense)  ((sense != NULL) && \
+				  ((((const uint8_t *)(sense))[0] & 0x70) == 0x70))
+
+#define SCST_NO_SENSE(sense)     ((sense != NULL) && \
+				  (((const uint8_t *)(sense))[2] == 0))
+
+/*************************************************************
+ ** Sense data for the appropriate errors. Can be used with
+ ** scst_set_cmd_error()
+ *************************************************************/
+#define scst_sense_no_sense			NO_SENSE,        0x00, 0
+#define scst_sense_hardw_error			HARDWARE_ERROR,  0x44, 0
+#define scst_sense_aborted_command		ABORTED_COMMAND, 0x00, 0
+#define scst_sense_invalid_opcode		ILLEGAL_REQUEST, 0x20, 0
+#define scst_sense_invalid_field_in_cdb		ILLEGAL_REQUEST, 0x24, 0
+#define scst_sense_invalid_field_in_parm_list	ILLEGAL_REQUEST, 0x26, 0
+#define scst_sense_parameter_value_invalid	ILLEGAL_REQUEST, 0x26, 2
+#define scst_sense_invalid_release		ILLEGAL_REQUEST, 0x26, 4
+#define scst_sense_parameter_list_length_invalid \
+						ILLEGAL_REQUEST, 0x1A, 0
+#define scst_sense_reset_UA			UNIT_ATTENTION,  0x29, 0
+#define scst_sense_nexus_loss_UA		UNIT_ATTENTION,  0x29, 0x7
+#define scst_sense_saving_params_unsup		ILLEGAL_REQUEST, 0x39, 0
+#define scst_sense_lun_not_supported		ILLEGAL_REQUEST, 0x25, 0
+#define scst_sense_data_protect			DATA_PROTECT,    0x00, 0
+#define scst_sense_miscompare_error		MISCOMPARE,      0x1D, 0
+#define scst_sense_block_out_range_error	ILLEGAL_REQUEST, 0x21, 0
+#define scst_sense_medium_changed_UA		UNIT_ATTENTION,  0x28, 0
+#define scst_sense_read_error			MEDIUM_ERROR,    0x11, 0
+#define scst_sense_write_error			MEDIUM_ERROR,    0x03, 0
+#define scst_sense_not_ready			NOT_READY,       0x04, 0x10
+#define scst_sense_invalid_message		ILLEGAL_REQUEST, 0x49, 0
+#define scst_sense_cleared_by_another_ini_UA	UNIT_ATTENTION,  0x2F, 0
+#define scst_sense_capacity_data_changed	UNIT_ATTENTION,  0x2A, 0x9
+#define scst_sense_reservation_preempted	UNIT_ATTENTION,  0x2A, 0x03
+#define scst_sense_reservation_released		UNIT_ATTENTION,  0x2A, 0x04
+#define scst_sense_registrations_preempted	UNIT_ATTENTION,  0x2A, 0x05
+#define scst_sense_reported_luns_data_changed	UNIT_ATTENTION,  0x3F, 0xE
+#define scst_sense_inquery_data_changed		UNIT_ATTENTION,  0x3F, 0x3
+
+/*************************************************************
+ * SCSI opcodes not listed anywhere else
+ *************************************************************/
+#define REPORT_DEVICE_IDENTIFIER    0xA3
+#define INIT_ELEMENT_STATUS         0x07
+#define INIT_ELEMENT_STATUS_RANGE   0x37
+#define PREVENT_ALLOW_MEDIUM        0x1E
+#define READ_ATTRIBUTE              0x8C
+#define REQUEST_VOLUME_ADDRESS      0xB5
+#define WRITE_ATTRIBUTE             0x8D
+#define WRITE_VERIFY_16             0x8E
+#define VERIFY_6                    0x13
+#ifndef VERIFY_12
+#define VERIFY_12                   0xAF
+#endif
+
+/*************************************************************
+ **  SCSI Architecture Model (SAM) Status codes. Taken from SAM-3 draft
+ **  T10/1561-D Revision 4 Draft dated 7th November 2002.
+ *************************************************************/
+#define SAM_STAT_GOOD            0x00
+#define SAM_STAT_CHECK_CONDITION 0x02
+#define SAM_STAT_CONDITION_MET   0x04
+#define SAM_STAT_BUSY            0x08
+#define SAM_STAT_INTERMEDIATE    0x10
+#define SAM_STAT_INTERMEDIATE_CONDITION_MET 0x14
+#define SAM_STAT_RESERVATION_CONFLICT 0x18
+#define SAM_STAT_COMMAND_TERMINATED 0x22	/* obsolete in SAM-3 */
+#define SAM_STAT_TASK_SET_FULL   0x28
+#define SAM_STAT_ACA_ACTIVE      0x30
+#define SAM_STAT_TASK_ABORTED    0x40
+
+/*************************************************************
+ ** Control byte field in CDB
+ *************************************************************/
+#define CONTROL_BYTE_LINK_BIT       0x01
+#define CONTROL_BYTE_NACA_BIT       0x04
+
+/*************************************************************
+ ** Byte 1 in INQUIRY CDB
+ *************************************************************/
+#define SCST_INQ_EVPD                0x01
+
+/*************************************************************
+ ** Byte 3 in Standard INQUIRY data
+ *************************************************************/
+#define SCST_INQ_BYTE3               3
+
+#define SCST_INQ_NORMACA_BIT         0x20
+
+/*************************************************************
+ ** Byte 2 in RESERVE_10 CDB
+ *************************************************************/
+#define SCST_RES_3RDPTY              0x10
+#define SCST_RES_LONGID              0x02
+
+/*************************************************************
+ ** Values for the control mode page TST field
+ *************************************************************/
+#define SCST_CONTR_MODE_ONE_TASK_SET  0
+#define SCST_CONTR_MODE_SEP_TASK_SETS 1
+
+/*******************************************************************
+ ** Values for the control mode page QUEUE ALGORITHM MODIFIER field
+ *******************************************************************/
+#define SCST_CONTR_MODE_QUEUE_ALG_RESTRICTED_REORDER   0
+#define SCST_CONTR_MODE_QUEUE_ALG_UNRESTRICTED_REORDER 1
+
+/*************************************************************
+ ** Values for the control mode page D_SENSE field
+ *************************************************************/
+#define SCST_CONTR_MODE_FIXED_SENSE  0
+#define SCST_CONTR_MODE_DESCR_SENSE 1
+
+/*************************************************************
+ ** TransportID protocol identifiers
+ *************************************************************/
+
+#define SCSI_TRANSPORTID_PROTOCOLID_FCP2	0
+#define SCSI_TRANSPORTID_PROTOCOLID_SPI5	1
+#define SCSI_TRANSPORTID_PROTOCOLID_SRP		4
+#define SCSI_TRANSPORTID_PROTOCOLID_ISCSI	5
+#define SCSI_TRANSPORTID_PROTOCOLID_SAS		6
+
+/*************************************************************
+ ** Misc SCSI constants
+ *************************************************************/
+#define SCST_SENSE_ASC_UA_RESET      0x29
+#define BYTCHK			     0x02
+#define POSITION_LEN_SHORT           20
+#define POSITION_LEN_LONG            32
+
+/*************************************************************
+ ** Various timeouts
+ *************************************************************/
+#define SCST_DEFAULT_TIMEOUT			(60 * HZ)
+
+#define SCST_GENERIC_CHANGER_TIMEOUT		(3 * HZ)
+#define SCST_GENERIC_CHANGER_LONG_TIMEOUT	(14000 * HZ)
+
+#define SCST_GENERIC_PROCESSOR_TIMEOUT		(3 * HZ)
+#define SCST_GENERIC_PROCESSOR_LONG_TIMEOUT	(14000 * HZ)
+
+#define SCST_GENERIC_TAPE_SMALL_TIMEOUT		(3 * HZ)
+#define SCST_GENERIC_TAPE_REG_TIMEOUT		(900 * HZ)
+#define SCST_GENERIC_TAPE_LONG_TIMEOUT		(14000 * HZ)
+
+#define SCST_GENERIC_MODISK_SMALL_TIMEOUT	(3 * HZ)
+#define SCST_GENERIC_MODISK_REG_TIMEOUT		(900 * HZ)
+#define SCST_GENERIC_MODISK_LONG_TIMEOUT	(14000 * HZ)
+
+#define SCST_GENERIC_DISK_SMALL_TIMEOUT		(3 * HZ)
+#define SCST_GENERIC_DISK_REG_TIMEOUT		(60 * HZ)
+#define SCST_GENERIC_DISK_LONG_TIMEOUT		(3600 * HZ)
+
+#define SCST_GENERIC_RAID_TIMEOUT		(3 * HZ)
+#define SCST_GENERIC_RAID_LONG_TIMEOUT		(14000 * HZ)
+
+#define SCST_GENERIC_CDROM_SMALL_TIMEOUT	(3 * HZ)
+#define SCST_GENERIC_CDROM_REG_TIMEOUT		(900 * HZ)
+#define SCST_GENERIC_CDROM_LONG_TIMEOUT		(14000 * HZ)
+
+#define SCST_MAX_OTHER_TIMEOUT			(14000 * HZ)
+
+/*************************************************************
+ ** I/O grouping attribute string values. Must match constants
+ ** w/o '_STR' suffix!
+ *************************************************************/
+#define SCST_IO_GROUPING_AUTO_STR		"auto"
+#define SCST_IO_GROUPING_THIS_GROUP_ONLY_STR	"this_group_only"
+#define SCST_IO_GROUPING_NEVER_STR		"never"
+
+/*************************************************************
+ ** Threads pool type attribute string values.
+ ** Must match scst_dev_type_threads_pool_type!
+ *************************************************************/
+#define SCST_THREADS_POOL_PER_INITIATOR_STR	"per_initiator"
+#define SCST_THREADS_POOL_SHARED_STR		"shared"
+
+/*************************************************************
+ ** Misc constants
+ *************************************************************/
+#define SCST_SYSFS_BLOCK_SIZE			PAGE_SIZE
+
+#define SCST_PR_DIR				"/var/lib/scst/pr"
+
+#define TID_COMMON_SIZE				24
+
+#define SCST_SYSFS_KEY_MARK			"[key]"
+
+#define SCST_MIN_REL_TGT_ID			1
+#define SCST_MAX_REL_TGT_ID			65535
+
+#endif /* __SCST_CONST_H */
diff -uprN orig/linux-2.6.35/include/scst/scst.h linux-2.6.35/include/scst/scst.h
--- orig/linux-2.6.35/include/scst/scst.h
+++ linux-2.6.35/include/scst/scst.h
@@ -0,0 +1,3562 @@
+/*
+ *  include/scst.h
+ *
+ *  Copyright (C) 2004 - 2010 Vladislav Bolkhovitin <vst@xxxxxxxx>
+ *  Copyright (C) 2004 - 2005 Leonid Stoljar
+ *  Copyright (C) 2007 - 2010 ID7 Ltd.
+ *
+ *  Main SCSI target mid-level include file.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation, version 2
+ *  of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ */
+
+#ifndef __SCST_H
+#define __SCST_H
+
+#include <linux/types.h>
+#include <linux/version.h>
+#include <linux/blkdev.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+
+
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_eh.h>
+#include <scsi/scsi.h>
+
+#include <scst/scst_const.h>
+
+#include <scst/scst_sgv.h>
+
+/*
+ * Version numbers, the same as for the kernel.
+ *
+ * Changing it don't forget to change SCST_FIO_REV in scst_vdisk.c
+ * and FIO_REV in usr/fileio/common.h as well.
+ */
+#define SCST_VERSION(a, b, c, d)    (((a) << 24) + ((b) << 16) + ((c) << 8) + d)
+#define SCST_VERSION_CODE	    SCST_VERSION(2, 0, 0, 0)
+#define SCST_VERSION_STRING_SUFFIX
+#define SCST_VERSION_STRING	    "2.1.0-pre1" SCST_VERSION_STRING_SUFFIX
+#define SCST_INTERFACE_VERSION	    \
+		SCST_VERSION_STRING "$Revision: 2115 $" SCST_CONST_VERSION
+
+#define SCST_LOCAL_NAME			"scst_local"
+
+/*************************************************************
+ ** States of command processing state machine. At first,
+ ** "active" states, then - "passive" ones. This is to have
+ ** more efficient generated code of the corresponding
+ ** "switch" statements.
+ *************************************************************/
+
+/* Internal parsing */
+#define SCST_CMD_STATE_PRE_PARSE     0
+
+/* Dev handler's parse() is going to be called */
+#define SCST_CMD_STATE_DEV_PARSE     1
+
+/* Allocation of the cmd's data buffer */
+#define SCST_CMD_STATE_PREPARE_SPACE 2
+
+/* Calling preprocessing_done() */
+#define SCST_CMD_STATE_PREPROCESSING_DONE 3
+
+/* Target driver's rdy_to_xfer() is going to be called */
+#define SCST_CMD_STATE_RDY_TO_XFER   4
+
+/* Target driver's pre_exec() is going to be called */
+#define SCST_CMD_STATE_TGT_PRE_EXEC  5
+
+/* Cmd is going to be sent for execution */
+#define SCST_CMD_STATE_SEND_FOR_EXEC 6
+
+/* Cmd is being checked if it should be executed locally */
+#define SCST_CMD_STATE_LOCAL_EXEC    7
+
+/* Cmd is ready for execution */
+#define SCST_CMD_STATE_REAL_EXEC     8
+
+/* Internal post-exec checks */
+#define SCST_CMD_STATE_PRE_DEV_DONE  9
+
+/* Internal MODE SELECT pages related checks */
+#define SCST_CMD_STATE_MODE_SELECT_CHECKS 10
+
+/* Dev handler's dev_done() is going to be called */
+#define SCST_CMD_STATE_DEV_DONE      11
+
+/* Target driver's xmit_response() is going to be called */
+#define SCST_CMD_STATE_PRE_XMIT_RESP 12
+
+/* Target driver's xmit_response() is going to be called */
+#define SCST_CMD_STATE_XMIT_RESP     13
+
+/* Cmd finished */
+#define SCST_CMD_STATE_FINISHED      14
+
+/* Internal cmd finished */
+#define SCST_CMD_STATE_FINISHED_INTERNAL 15
+
+#define SCST_CMD_STATE_LAST_ACTIVE   (SCST_CMD_STATE_FINISHED_INTERNAL+100)
+
+/* A cmd is created, but scst_cmd_init_done() not called */
+#define SCST_CMD_STATE_INIT_WAIT     (SCST_CMD_STATE_LAST_ACTIVE+1)
+
+/* LUN translation (cmd->tgt_dev assignment) */
+#define SCST_CMD_STATE_INIT          (SCST_CMD_STATE_LAST_ACTIVE+2)
+
+/* Waiting for scst_restart_cmd() */
+#define SCST_CMD_STATE_PREPROCESSING_DONE_CALLED (SCST_CMD_STATE_LAST_ACTIVE+3)
+
+/* Waiting for data from the initiator (until scst_rx_data() called) */
+#define SCST_CMD_STATE_DATA_WAIT     (SCST_CMD_STATE_LAST_ACTIVE+4)
+
+/* Waiting for CDB's execution finish */
+#define SCST_CMD_STATE_REAL_EXECUTING (SCST_CMD_STATE_LAST_ACTIVE+5)
+
+/* Waiting for response's transmission finish */
+#define SCST_CMD_STATE_XMIT_WAIT     (SCST_CMD_STATE_LAST_ACTIVE+6)
+
+/*************************************************************
+ * Can be retuned instead of cmd's state by dev handlers'
+ * functions, if the command's state should be set by default
+ *************************************************************/
+#define SCST_CMD_STATE_DEFAULT        500
+
+/*************************************************************
+ * Can be retuned instead of cmd's state by dev handlers'
+ * functions, if it is impossible to complete requested
+ * task in atomic context. The cmd will be restarted in thread
+ * context.
+ *************************************************************/
+#define SCST_CMD_STATE_NEED_THREAD_CTX 1000
+
+/*************************************************************
+ * Can be retuned instead of cmd's state by dev handlers'
+ * parse function, if the cmd processing should be stopped
+ * for now. The cmd will be restarted by dev handlers itself.
+ *************************************************************/
+#define SCST_CMD_STATE_STOP           1001
+
+/*************************************************************
+ ** States of mgmt command processing state machine
+ *************************************************************/
+
+/* LUN translation (mcmd->tgt_dev assignment) */
+#define SCST_MCMD_STATE_INIT				0
+
+/* Mgmt cmd is being processed */
+#define SCST_MCMD_STATE_EXEC				1
+
+/* Waiting for affected commands done */
+#define SCST_MCMD_STATE_WAITING_AFFECTED_CMDS_DONE	2
+
+/* Post actions when affected commands done */
+#define SCST_MCMD_STATE_AFFECTED_CMDS_DONE		3
+
+/* Waiting for affected local commands finished */
+#define SCST_MCMD_STATE_WAITING_AFFECTED_CMDS_FINISHED	4
+
+/* Target driver's task_mgmt_fn_done() is going to be called */
+#define SCST_MCMD_STATE_DONE				5
+
+/* The mcmd finished */
+#define SCST_MCMD_STATE_FINISHED			6
+
+/*************************************************************
+ ** Constants for "atomic" parameter of SCST's functions
+ *************************************************************/
+#define SCST_NON_ATOMIC              0
+#define SCST_ATOMIC                  1
+
+/*************************************************************
+ ** Values for pref_context parameter of scst_cmd_init_done(),
+ ** scst_rx_data(), scst_restart_cmd(), scst_tgt_cmd_done()
+ ** and scst_cmd_done()
+ *************************************************************/
+
+enum scst_exec_context {
+	/*
+	 * Direct cmd's processing (i.e. regular function calls in the current
+	 * context) sleeping is not allowed
+	 */
+	SCST_CONTEXT_DIRECT_ATOMIC,
+
+	/*
+	 * Direct cmd's processing (i.e. regular function calls in the current
+	 * context), sleeping is allowed, no restrictions
+	 */
+	SCST_CONTEXT_DIRECT,
+
+	/* Tasklet or thread context required for cmd's processing */
+	SCST_CONTEXT_TASKLET,
+
+	/* Thread context required for cmd's processing */
+	SCST_CONTEXT_THREAD,
+
+	/*
+	 * Context is the same as it was in previous call of the corresponding
+	 * callback. For example, if dev handler's exec() does sync. data
+	 * reading this value should be used for scst_cmd_done(). The same is
+	 * true if scst_tgt_cmd_done() called directly from target driver's
+	 * xmit_response(). Not allowed in scst_cmd_init_done() and
+	 * scst_cmd_init_stage1_done().
+	 */
+	SCST_CONTEXT_SAME
+};
+
+/*************************************************************
+ ** Values for status parameter of scst_rx_data()
+ *************************************************************/
+
+/* Success */
+#define SCST_RX_STATUS_SUCCESS       0
+
+/*
+ * Data receiving finished with error, so set the sense and
+ * finish the command, including xmit_response() call
+ */
+#define SCST_RX_STATUS_ERROR         1
+
+/*
+ * Data receiving finished with error and the sense is set,
+ * so finish the command, including xmit_response() call
+ */
+#define SCST_RX_STATUS_ERROR_SENSE_SET 2
+
+/*
+ * Data receiving finished with fatal error, so finish the command,
+ * but don't call xmit_response()
+ */
+#define SCST_RX_STATUS_ERROR_FATAL   3
+
+/*************************************************************
+ ** Values for status parameter of scst_restart_cmd()
+ *************************************************************/
+
+/* Success */
+#define SCST_PREPROCESS_STATUS_SUCCESS       0
+
+/*
+ * Command's processing finished with error, so set the sense and
+ * finish the command, including xmit_response() call
+ */
+#define SCST_PREPROCESS_STATUS_ERROR         1
+
+/*
+ * Command's processing finished with error and the sense is set,
+ * so finish the command, including xmit_response() call
+ */
+#define SCST_PREPROCESS_STATUS_ERROR_SENSE_SET 2
+
+/*
+ * Command's processing finished with fatal error, so finish the command,
+ * but don't call xmit_response()
+ */
+#define SCST_PREPROCESS_STATUS_ERROR_FATAL   3
+
+/*************************************************************
+ ** Values for AEN functions
+ *************************************************************/
+
+/*
+ * SCSI Asynchronous Event. Parameter contains SCSI sense
+ * (Unit Attention). AENs generated only for 2 the following UAs:
+ * CAPACITY DATA HAS CHANGED and REPORTED LUNS DATA HAS CHANGED.
+ * Other UAs reported regularly as CHECK CONDITION status,
+ * because it doesn't look safe to report them using AENs, since
+ * reporting using AENs opens delivery race windows even in case of
+ * untagged commands.
+ */
+#define SCST_AEN_SCSI                0
+
+/*************************************************************
+ ** Allowed return/status codes for report_aen() callback and
+ ** scst_set_aen_delivery_status() function
+ *************************************************************/
+
+/* Success */
+#define SCST_AEN_RES_SUCCESS         0
+
+/* Not supported */
+#define SCST_AEN_RES_NOT_SUPPORTED  -1
+
+/* Failure */
+#define SCST_AEN_RES_FAILED         -2
+
+/*************************************************************
+ ** Allowed return codes for xmit_response(), rdy_to_xfer()
+ *************************************************************/
+
+/* Success */
+#define SCST_TGT_RES_SUCCESS         0
+
+/* Internal device queue is full, retry again later */
+#define SCST_TGT_RES_QUEUE_FULL      -1
+
+/*
+ * It is impossible to complete requested task in atomic context.
+ * The cmd will be restarted in thread  context.
+ */
+#define SCST_TGT_RES_NEED_THREAD_CTX -2
+
+/*
+ * Fatal error, if returned by xmit_response() the cmd will
+ * be destroyed, if by any other function, xmit_response()
+ * will be called with HARDWARE ERROR sense data
+ */
+#define SCST_TGT_RES_FATAL_ERROR     -3
+
+/*************************************************************
+ ** Allowed return codes for dev handler's exec()
+ *************************************************************/
+
+/* The cmd is done, go to other ones */
+#define SCST_EXEC_COMPLETED          0
+
+/* The cmd should be sent to SCSI mid-level */
+#define SCST_EXEC_NOT_COMPLETED      1
+
+/*
+ * Set if cmd is finished and there is status/sense to be sent.
+ * The status should be not sent (i.e. the flag not set) if the
+ * possibility to perform a command in "chunks" (i.e. with multiple
+ * xmit_response()/rdy_to_xfer()) is used (not implemented yet).
+ * Obsolete, use scst_cmd_get_is_send_status() instead.
+ */
+#define SCST_TSC_FLAG_STATUS         0x2
+
+/*************************************************************
+ ** Additional return code for dev handler's task_mgmt_fn()
+ *************************************************************/
+
+/* Regular standard actions for the command should be done */
+#define SCST_DEV_TM_NOT_COMPLETED     1
+
+/*************************************************************
+ ** Session initialization phases
+ *************************************************************/
+
+/* Set if session is being initialized */
+#define SCST_SESS_IPH_INITING        0
+
+/* Set if the session is successfully initialized */
+#define SCST_SESS_IPH_SUCCESS        1
+
+/* Set if the session initialization failed */
+#define SCST_SESS_IPH_FAILED         2
+
+/* Set if session is initialized and ready */
+#define SCST_SESS_IPH_READY          3
+
+/*************************************************************
+ ** Session shutdown phases
+ *************************************************************/
+
+/* Set if session is initialized and ready */
+#define SCST_SESS_SPH_READY          0
+
+/* Set if session is shutting down */
+#define SCST_SESS_SPH_SHUTDOWN       1
+
+/* Set if session is shutting down */
+#define SCST_SESS_SPH_UNREG_DONE_CALLING 2
+
+/*************************************************************
+ ** Session's async (atomic) flags
+ *************************************************************/
+
+/* Set if the sess's hw pending work is scheduled */
+#define SCST_SESS_HW_PENDING_WORK_SCHEDULED	0
+
+/*************************************************************
+ ** Cmd's async (atomic) flags
+ *************************************************************/
+
+/* Set if the cmd is aborted and ABORTED sense will be sent as the result */
+#define SCST_CMD_ABORTED		0
+
+/* Set if the cmd is aborted by other initiator */
+#define SCST_CMD_ABORTED_OTHER		1
+
+/* Set if no response should be sent to the target about this cmd */
+#define SCST_CMD_NO_RESP		2
+
+/* Set if the cmd is dead and can be destroyed at any time */
+#define SCST_CMD_CAN_BE_DESTROYED	3
+
+/*
+ * Set if the cmd's device has TAS flag set. Used only when aborted by
+ * other initiator.
+ */
+#define SCST_CMD_DEVICE_TAS		4
+
+/*************************************************************
+ ** Tgt_dev's async. flags (tgt_dev_flags)
+ *************************************************************/
+
+/* Set if tgt_dev has Unit Attention sense */
+#define SCST_TGT_DEV_UA_PENDING		0
+
+/* Set if tgt_dev is RESERVED by another session */
+#define SCST_TGT_DEV_RESERVED		1
+
+/* Set if the corresponding context is atomic */
+#define SCST_TGT_DEV_AFTER_INIT_WR_ATOMIC	5
+#define SCST_TGT_DEV_AFTER_EXEC_ATOMIC		6
+
+#define SCST_TGT_DEV_CLUST_POOL			11
+
+/*************************************************************
+ ** I/O groupping types. Changing them don't forget to change
+ ** the corresponding *_STR values in scst_const.h!
+ *************************************************************/
+
+/*
+ * All initiators with the same name connected to this group will have
+ * shared IO context, for each name own context. All initiators with
+ * different names will have own IO context.
+ */
+#define SCST_IO_GROUPING_AUTO			0
+
+/* All initiators connected to this group will have shared IO context */
+#define SCST_IO_GROUPING_THIS_GROUP_ONLY	-1
+
+/* Each initiator connected to this group will have own IO context */
+#define SCST_IO_GROUPING_NEVER			-2
+
+/*************************************************************
+ ** Kernel cache creation helper
+ *************************************************************/
+#ifndef KMEM_CACHE
+#define KMEM_CACHE(__struct, __flags) kmem_cache_create(#__struct,\
+	sizeof(struct __struct), __alignof__(struct __struct),\
+	(__flags), NULL, NULL)
+#endif
+
+/*************************************************************
+ ** Vlaid_mask constants for scst_analyze_sense()
+ *************************************************************/
+
+#define SCST_SENSE_KEY_VALID		1
+#define SCST_SENSE_ASC_VALID		2
+#define SCST_SENSE_ASCQ_VALID		4
+
+#define SCST_SENSE_ASCx_VALID		(SCST_SENSE_ASC_VALID | \
+					 SCST_SENSE_ASCQ_VALID)
+
+#define SCST_SENSE_ALL_VALID		(SCST_SENSE_KEY_VALID | \
+					 SCST_SENSE_ASC_VALID | \
+					 SCST_SENSE_ASCQ_VALID)
+
+/*************************************************************
+ *                     TYPES
+ *************************************************************/
+
+struct scst_tgt;
+struct scst_session;
+struct scst_cmd;
+struct scst_mgmt_cmd;
+struct scst_device;
+struct scst_tgt_dev;
+struct scst_dev_type;
+struct scst_acg;
+struct scst_acg_dev;
+struct scst_acn;
+struct scst_aen;
+
+/*
+ * SCST uses 64-bit numbers to represent LUN's internally. The value
+ * NO_SUCH_LUN is guaranteed to be different of every valid LUN.
+ */
+#define NO_SUCH_LUN ((uint64_t)-1)
+
+typedef enum dma_data_direction scst_data_direction;
+
+/*
+ * SCST target template: defines target driver's parameters and callback
+ * functions.
+ *
+ * MUST HAVEs define functions that are expected to be defined in order to
+ * work. OPTIONAL says that there is a choice.
+ */
+struct scst_tgt_template {
+	/* public: */
+
+	/*
+	 * SG tablesize allows to check whether scatter/gather can be used
+	 * or not.
+	 */
+	int sg_tablesize;
+
+	/*
+	 * True, if this target adapter uses unchecked DMA onto an ISA bus.
+	 */
+	unsigned unchecked_isa_dma:1;
+
+	/*
+	 * True, if this target adapter can benefit from using SG-vector
+	 * clustering (i.e. smaller number of segments).
+	 */
+	unsigned use_clustering:1;
+
+	/*
+	 * True, if this target adapter doesn't support SG-vector clustering
+	 */
+	unsigned no_clustering:1;
+
+	/*
+	 * True, if corresponding function supports execution in
+	 * the atomic (non-sleeping) context
+	 */
+	unsigned xmit_response_atomic:1;
+	unsigned rdy_to_xfer_atomic:1;
+
+	/* True, if this target doesn't need "enabled" attribute */
+	unsigned enabled_attr_not_needed:1;
+
+	/*
+	 * The maximum time in seconds cmd can stay inside the target
+	 * hardware, i.e. after rdy_to_xfer() and xmit_response(), before
+	 * on_hw_pending_cmd_timeout() will be called, if defined.
+	 *
+	 * In the current implementation a cmd will be aborted in time t
+	 * max_hw_pending_time <= t < 2*max_hw_pending_time.
+	 */
+	int max_hw_pending_time;
+
+	/*
+	 * This function is equivalent to the SCSI
+	 * queuecommand. The target should transmit the response
+	 * buffer and the status in the scst_cmd struct.
+	 * The expectation is that this executing this command is NON-BLOCKING.
+	 * If it is blocking, consider to set threads_num to some none 0 number.
+	 *
+	 * After the response is actually transmitted, the target
+	 * should call the scst_tgt_cmd_done() function of the
+	 * mid-level, which will allow it to free up the command.
+	 * Returns one of the SCST_TGT_RES_* constants.
+	 *
+	 * Pay attention to "atomic" attribute of the cmd, which can be get
+	 * by scst_cmd_atomic(): it is true if the function called in the
+	 * atomic (non-sleeping) context.
+	 *
+	 * MUST HAVE
+	 */
+	int (*xmit_response) (struct scst_cmd *cmd);
+
+	/*
+	 * This function informs the driver that data
+	 * buffer corresponding to the said command have now been
+	 * allocated and it is OK to receive data for this command.
+	 * This function is necessary because a SCSI target does not
+	 * have any control over the commands it receives. Most lower
+	 * level protocols have a corresponding function which informs
+	 * the initiator that buffers have been allocated e.g., XFER_
+	 * RDY in Fibre Channel. After the data is actually received
+	 * the low-level driver needs to call scst_rx_data() in order to
+	 * continue processing this command.
+	 * Returns one of the SCST_TGT_RES_* constants.
+	 *
+	 * This command is expected to be NON-BLOCKING.
+	 * If it is blocking, consider to set threads_num to some none 0 number.
+	 *
+	 * Pay attention to "atomic" attribute of the cmd, which can be get
+	 * by scst_cmd_atomic(): it is true if the function called in the
+	 * atomic (non-sleeping) context.
+	 *
+	 * OPTIONAL
+	 */
+	int (*rdy_to_xfer) (struct scst_cmd *cmd);
+
+	/*
+	 * Called if cmd stays inside the target hardware, i.e. after
+	 * rdy_to_xfer() and xmit_response(), more than max_hw_pending_time
+	 * time. The target driver supposed to cleanup this command and
+	 * resume cmd's processing.
+	 *
+	 * OPTIONAL
+	 */
+	void (*on_hw_pending_cmd_timeout) (struct scst_cmd *cmd);
+
+	/*
+	 * Called to notify the driver that the command is about to be freed.
+	 * Necessary, because for aborted commands xmit_response() could not
+	 * be called. Could be called on IRQ context.
+	 *
+	 * OPTIONAL
+	 */
+	void (*on_free_cmd) (struct scst_cmd *cmd);
+
+	/*
+	 * This function allows target driver to handle data buffer
+	 * allocations on its own.
+	 *
+	 * Target driver doesn't have to always allocate buffer in this
+	 * function, but if it decide to do it, it must check that
+	 * scst_cmd_get_data_buff_alloced() returns 0, otherwise to avoid
+	 * double buffer allocation and memory leaks alloc_data_buf() shall
+	 * fail.
+	 *
+	 * Shall return 0 in case of success or < 0 (preferrably -ENOMEM)
+	 * in case of error, or > 0 if the regular SCST allocation should be
+	 * done. In case of returning successfully,
+	 * scst_cmd->tgt_data_buf_alloced will be set by SCST.
+	 *
+	 * It is possible that both target driver and dev handler request own
+	 * memory allocation. In this case, data will be memcpy() between
+	 * buffers, where necessary.
+	 *
+	 * If allocation in atomic context - cf. scst_cmd_atomic() - is not
+	 * desired or fails and consequently < 0 is returned, this function
+	 * will be re-called in thread context.
+	 *
+	 * Please note that the driver will have to handle itself all relevant
+	 * details such as scatterlist setup, highmem, freeing the allocated
+	 * memory, etc.
+	 *
+	 * OPTIONAL.
+	 */
+	int (*alloc_data_buf) (struct scst_cmd *cmd);
+
+	/*
+	 * This function informs the driver that data
+	 * buffer corresponding to the said command have now been
+	 * allocated and other preprocessing tasks have been done.
+	 * A target driver could need to do some actions at this stage.
+	 * After the target driver done the needed actions, it shall call
+	 * scst_restart_cmd() in order to continue processing this command.
+	 * In case of preliminary the command completion, this function will
+	 * also be called before xmit_response().
+	 *
+	 * Called only if the cmd is queued using scst_cmd_init_stage1_done()
+	 * instead of scst_cmd_init_done().
+	 *
+	 * Returns void, the result is expected to be returned using
+	 * scst_restart_cmd().
+	 *
+	 * This command is expected to be NON-BLOCKING.
+	 * If it is blocking, consider to set threads_num to some none 0 number.
+	 *
+	 * Pay attention to "atomic" attribute of the cmd, which can be get
+	 * by scst_cmd_atomic(): it is true if the function called in the
+	 * atomic (non-sleeping) context.
+	 *
+	 * OPTIONAL.
+	 */
+	void (*preprocessing_done) (struct scst_cmd *cmd);
+
+	/*
+	 * This function informs the driver that the said command is about
+	 * to be executed.
+	 *
+	 * Returns one of the SCST_PREPROCESS_* constants.
+	 *
+	 * This command is expected to be NON-BLOCKING.
+	 * If it is blocking, consider to set threads_num to some none 0 number.
+	 *
+	 * OPTIONAL
+	 */
+	int (*pre_exec) (struct scst_cmd *cmd);
+
+	/*
+	 * This function informs the driver that all affected by the
+	 * corresponding task management function commands have beed completed.
+	 * No return value expected.
+	 *
+	 * This function is expected to be NON-BLOCKING.
+	 *
+	 * Called without any locks held from a thread context.
+	 *
+	 * OPTIONAL
+	 */
+	void (*task_mgmt_affected_cmds_done) (struct scst_mgmt_cmd *mgmt_cmd);
+
+	/*
+	 * This function informs the driver that the corresponding task
+	 * management function has been completed, i.e. all the corresponding
+	 * commands completed and freed. No return value expected.
+	 *
+	 * This function is expected to be NON-BLOCKING.
+	 *
+	 * Called without any locks held from a thread context.
+	 *
+	 * MUST HAVE if the target supports task management.
+	 */
+	void (*task_mgmt_fn_done) (struct scst_mgmt_cmd *mgmt_cmd);
+
+	/*
+	 * This function should detect the target adapters that
+	 * are present in the system. The function should return a value
+	 * >= 0 to signify the number of detected target adapters.
+	 * A negative value should be returned whenever there is
+	 * an error.
+	 *
+	 * MUST HAVE
+	 */
+	int (*detect) (struct scst_tgt_template *tgt_template);
+
+	/*
+	 * This function should free up the resources allocated to the device.
+	 * The function should return 0 to indicate successful release
+	 * or a negative value if there are some issues with the release.
+	 * In the current version the return value is ignored.
+	 *
+	 * MUST HAVE
+	 */
+	int (*release) (struct scst_tgt *tgt);
+
+	/*
+	 * This function is used for Asynchronous Event Notifications.
+	 *
+	 * Returns one of the SCST_AEN_RES_* constants.
+	 * After AEN is sent, target driver must call scst_aen_done() and,
+	 * optionally, scst_set_aen_delivery_status().
+	 *
+	 * This function is expected to be NON-BLOCKING, but can sleep.
+	 *
+	 * This function must be prepared to handle AENs between calls for the
+	 * corresponding session of scst_unregister_session() and
+	 * unreg_done_fn() callback called or before scst_unregister_session()
+	 * returned, if its called in the blocking mode. AENs for such sessions
+	 * should be ignored.
+	 *
+	 * MUST HAVE, if low-level protocol supports AENs.
+	 */
+	int (*report_aen) (struct scst_aen *aen);
+
+	/*
+	 * This function returns in tr_id the corresponding to sess initiator
+	 * port TransporID in the form as it's used by PR commands, see
+	 * "Transport Identifiers" in SPC. Space for the initiator port
+	 * TransporID must be allocated via kmalloc(). Caller supposed to
+	 * kfree() it, when it isn't needed anymore.
+	 *
+	 * If sess is NULL, this function must return TransportID PROTOCOL
+	 * IDENTIFIER of this transport.
+	 *
+	 * Returns 0 on success or negative error code otherwise.
+	 *
+	 * SHOULD HAVE, because it's required for Persistent Reservations.
+	 */
+	int (*get_initiator_port_transport_id) (struct scst_session *sess,
+		uint8_t **transport_id);
+
+	/*
+	 * This function allows to enable or disable particular target.
+	 * A disabled target doesn't receive and process any SCSI commands.
+	 *
+	 * SHOULD HAVE to avoid race when there are connected initiators,
+	 * while target not yet completed the initial configuration. In this
+	 * case the too early connected initiators would see not those devices,
+	 * which they intended to see.
+	 *
+	 * If you are sure your target driver doesn't need enabling target,
+	 * you should set enabled_attr_not_needed in 1.
+	 */
+	int (*enable_target) (struct scst_tgt *tgt, bool enable);
+
+	/*
+	 * This function shows if particular target is enabled or not.
+	 *
+	 * SHOULD HAVE, see above why.
+	 */
+	bool (*is_target_enabled) (struct scst_tgt *tgt);
+
+	/*
+	 * This function adds a virtual target.
+	 *
+	 * If both add_target and del_target callbacks defined, then this
+	 * target driver supposed to support virtual targets. In this case
+	 * an "mgmt" entry will be created in the sysfs root for this driver.
+	 * The "mgmt" entry will support 2 commands: "add_target" and
+	 * "del_target", for which the corresponding callbacks will be called.
+	 * Also target driver can define own commands for the "mgmt" entry, see
+	 * mgmt_cmd and mgmt_cmd_help below.
+	 *
+	 * This approach allows uniform targets management to simplify external
+	 * management tools like scstadmin. See README for more details.
+	 *
+	 * Either both add_target and del_target must be defined, or none.
+	 *
+	 * MUST HAVE if virtual targets are supported.
+	 */
+	ssize_t (*add_target) (const char *target_name, char *params);
+
+	/*
+	 * This function deletes a virtual target. See comment for add_target
+	 * above.
+	 *
+	 * MUST HAVE if virtual targets are supported.
+	 */
+	ssize_t (*del_target) (const char *target_name);
+
+	/*
+	 * This function called if not "add_target" or "del_target" command is
+	 * sent to the mgmt entry (see comment for add_target above). In this
+	 * case the command passed to this function as is in a string form.
+	 *
+	 * OPTIONAL.
+	 */
+	ssize_t (*mgmt_cmd) (char *cmd);
+
+	/*
+	 * Should return physical transport version. Used in the corresponding
+	 * INQUIRY version descriptor. See SPC for the list of available codes.
+	 *
+	 * OPTIONAL
+	 */
+	uint16_t (*get_phys_transport_version) (struct scst_tgt *tgt);
+
+	/*
+	 * Should return SCSI transport version. Used in the corresponding
+	 * INQUIRY version descriptor. See SPC for the list of available codes.
+	 *
+	 * OPTIONAL
+	 */
+	uint16_t (*get_scsi_transport_version) (struct scst_tgt *tgt);
+
+	/*
+	 * Name of the template. Must be unique to identify
+	 * the template. MUST HAVE
+	 */
+	const char name[SCST_MAX_NAME];
+
+	/*
+	 * Number of additional threads to the pool of dedicated threads.
+	 * Used if xmit_response() or rdy_to_xfer() is blocking.
+	 * It is the target driver's duty to ensure that not more, than that
+	 * number of threads, are blocked in those functions at any time.
+	 */
+	int threads_num;
+
+	/* Optional default log flags */
+	const unsigned long default_trace_flags;
+
+	/* Optional pointer to trace flags */
+	unsigned long *trace_flags;
+
+	/* Optional local trace table */
+	struct scst_trace_log *trace_tbl;
+
+	/* Optional local trace table help string */
+	const char *trace_tbl_help;
+
+	/* sysfs attributes, if any */
+	const struct attribute **tgtt_attrs;
+
+	/* sysfs target attributes, if any */
+	const struct attribute **tgt_attrs;
+
+	/* sysfs session attributes, if any */
+	const struct attribute **sess_attrs;
+
+	/* Optional help string for mgmt_cmd commands */
+	const char *mgmt_cmd_help;
+
+	/* List of parameters for add_target command, if any */
+	const char *add_target_parameters;
+
+	/*
+	 * List of optional, i.e. which could be added by add_attribute command
+	 * and deleted by del_attribute command, sysfs attributes, if any.
+	 * Helpful for scstadmin to work correctly.
+	 */
+	const char *tgtt_optional_attributes;
+
+	/*
+	 * List of optional, i.e. which could be added by add_target_attribute
+	 * command and deleted by del_target_attribute command, sysfs
+	 * attributes, if any. Helpful for scstadmin to work correctly.
+	 */
+	const char *tgt_optional_attributes;
+
+	/** Private, must be inited to 0 by memset() **/
+
+	/* List of targets per template, protected by scst_mutex */
+	struct list_head tgt_list;
+
+	/* List entry of global templates list */
+	struct list_head scst_template_list_entry;
+
+	struct kobject tgtt_kobj; /* kobject for this struct */
+
+	/* Number of currently active sysfs mgmt works (scst_sysfs_work_item) */
+	int tgtt_active_sysfs_works_count;
+
+	/* sysfs release completion */
+	struct completion tgtt_kobj_release_cmpl;
+
+};
+
+/*
+ * Threads pool types. Changing them don't forget to change
+ * the corresponding *_STR values in scst_const.h!
+ */
+enum scst_dev_type_threads_pool_type {
+	/* Each initiator will have dedicated threads pool. */
+	SCST_THREADS_POOL_PER_INITIATOR = 0,
+
+	/* All connected initiators will use shared threads pool */
+	SCST_THREADS_POOL_SHARED,
+
+	/* Invalid value for scst_parse_threads_pool_type() */
+	SCST_THREADS_POOL_TYPE_INVALID,
+};
+
+/*
+ * SCST dev handler template: defines dev handler's parameters and callback
+ * functions.
+ *
+ * MUST HAVEs define functions that are expected to be defined in order to
+ * work. OPTIONAL says that there is a choice.
+ */
+struct scst_dev_type {
+	/* SCSI type of the supported device. MUST HAVE */
+	int type;
+
+	/*
+	 * True, if corresponding function supports execution in
+	 * the atomic (non-sleeping) context
+	 */
+	unsigned parse_atomic:1;
+	unsigned alloc_data_buf_atomic:1;
+	unsigned dev_done_atomic:1;
+
+	/*
+	 * Should be true, if exec() is synchronous. This is a hint to SCST core
+	 * to optimize commands order management.
+	 */
+	unsigned exec_sync:1;
+
+	/*
+	 * Should be set if the device wants to receive notification of
+	 * Persistent Reservation commands (PR OUT only)
+	 * Note: The notification will not be send if the command failed
+	 */
+	unsigned pr_cmds_notifications:1;
+
+	/*
+	 * Called to parse CDB from the cmd and initialize
+	 * cmd->bufflen and cmd->data_direction (both - REQUIRED).
+	 *
+	 * Returns the command's next state or SCST_CMD_STATE_DEFAULT,
+	 * if the next default state should be used, or
+	 * SCST_CMD_STATE_NEED_THREAD_CTX if the function called in atomic
+	 * context, but requires sleeping, or SCST_CMD_STATE_STOP if the
+	 * command should not be further processed for now. In the
+	 * SCST_CMD_STATE_NEED_THREAD_CTX case the function
+	 * will be recalled in the thread context, where sleeping is allowed.
+	 *
+	 * Pay attention to "atomic" attribute of the cmd, which can be get
+	 * by scst_cmd_atomic(): it is true if the function called in the
+	 * atomic (non-sleeping) context.
+	 *
+	 * MUST HAVE
+	 */
+	int (*parse) (struct scst_cmd *cmd);
+
+	/*
+	 * This function allows dev handler to handle data buffer
+	 * allocations on its own.
+	 *
+	 * Returns the command's next state or SCST_CMD_STATE_DEFAULT,
+	 * if the next default state should be used, or
+	 * SCST_CMD_STATE_NEED_THREAD_CTX if the function called in atomic
+	 * context, but requires sleeping, or SCST_CMD_STATE_STOP if the
+	 * command should not be further processed for now. In the
+	 * SCST_CMD_STATE_NEED_THREAD_CTX case the function
+	 * will be recalled in the thread context, where sleeping is allowed.
+	 *
+	 * Pay attention to "atomic" attribute of the cmd, which can be get
+	 * by scst_cmd_atomic(): it is true if the function called in the
+	 * atomic (non-sleeping) context.
+	 *
+	 * OPTIONAL
+	 */
+	int (*alloc_data_buf) (struct scst_cmd *cmd);
+
+	/*
+	 * Called to execute CDB. Useful, for instance, to implement
+	 * data caching. The result of CDB execution is reported via
+	 * cmd->scst_cmd_done() callback.
+	 * Returns:
+	 *  - SCST_EXEC_COMPLETED - the cmd is done, go to other ones
+	 *  - SCST_EXEC_NOT_COMPLETED - the cmd should be sent to SCSI
+	 *	mid-level.
+	 *
+	 * If this function provides sync execution, you should set
+	 * exec_sync flag and consider to setup dedicated threads by
+	 * setting threads_num > 0.
+	 *
+	 * !! If this function is implemented, scst_check_local_events() !!
+	 * !! shall be called inside it just before the actual command's !!
+	 * !! execution.                                                 !!
+	 *
+	 * OPTIONAL, if not set, the commands will be sent directly to SCSI
+	 * device.
+	 */
+	int (*exec) (struct scst_cmd *cmd);
+
+	/*
+	 * Called to notify dev handler about the result of cmd execution
+	 * and perform some post processing. Cmd's fields is_send_status and
+	 * resp_data_len should be set by this function, but SCST offers good
+	 * defaults.
+	 * Returns the command's next state or SCST_CMD_STATE_DEFAULT,
+	 * if the next default state should be used, or
+	 * SCST_CMD_STATE_NEED_THREAD_CTX if the function called in atomic
+	 * context, but requires sleeping. In the last case, the function
+	 * will be recalled in the thread context, where sleeping is allowed.
+	 *
+	 * Pay attention to "atomic" attribute of the cmd, which can be get
+	 * by scst_cmd_atomic(): it is true if the function called in the
+	 * atomic (non-sleeping) context.
+	 *
+	 * OPTIONAL
+	 */
+	int (*dev_done) (struct scst_cmd *cmd);
+
+	/*
+	 * Called to notify dev hander that the command is about to be freed.
+	 *
+	 * Could be called on IRQ context.
+	 *
+	 * OPTIONAL
+	 */
+	void (*on_free_cmd) (struct scst_cmd *cmd);
+
+	/*
+	 * Called to execute a task management command.
+	 * Returns:
+	 *  - SCST_MGMT_STATUS_SUCCESS - the command is done with success,
+	 *	no firther actions required
+	 *  - The SCST_MGMT_STATUS_* error code if the command is failed and
+	 *	no further actions required
+	 *  - SCST_DEV_TM_NOT_COMPLETED - regular standard actions for the
+	 *      command should be done
+	 *
+	 * Called without any locks held from a thread context.
+	 *
+	 * OPTIONAL
+	 */
+	int (*task_mgmt_fn) (struct scst_mgmt_cmd *mgmt_cmd,
+		struct scst_tgt_dev *tgt_dev);
+
+	/*
+	 * Called to notify dev handler that its sg_tablesize is too low to
+	 * satisfy this command's data transfer requirements. Should return
+	 * true if exec() callback will split this command's CDB on smaller
+	 * transfers, false otherwise.
+	 *
+	 * Could be called on SIRQ context.
+	 *
+	 * MUST HAVE, if dev handler supports CDB splitting.
+	 */
+	bool (*on_sg_tablesize_low) (struct scst_cmd *cmd);
+
+	/*
+	 * Called when new device is attaching to the dev handler
+	 * Returns 0 on success, error code otherwise.
+	 *
+	 * OPTIONAL
+	 */
+	int (*attach) (struct scst_device *dev);
+
+	/*
+	 * Called when a device is detaching from the dev handler.
+	 *
+	 * OPTIONAL
+	 */
+	void (*detach) (struct scst_device *dev);
+
+	/*
+	 * Called when new tgt_dev (session) is attaching to the dev handler.
+	 * Returns 0 on success, error code otherwise.
+	 *
+	 * OPTIONAL
+	 */
+	int (*attach_tgt) (struct scst_tgt_dev *tgt_dev);
+
+	/*
+	 * Called when tgt_dev (session) is detaching from the dev handler.
+	 *
+	 * OPTIONAL
+	 */
+	void (*detach_tgt) (struct scst_tgt_dev *tgt_dev);
+
+	/*
+	 * This function adds a virtual device.
+	 *
+	 * If both add_device and del_device callbacks defined, then this
+	 * dev handler supposed to support adding/deleting virtual devices.
+	 * In this case an "mgmt" entry will be created in the sysfs root for
+	 * this handler. The "mgmt" entry will support 2 commands: "add_device"
+	 * and "del_device", for which the corresponding callbacks will be called.
+	 * Also dev handler can define own commands for the "mgmt" entry, see
+	 * mgmt_cmd and mgmt_cmd_help below.
+	 *
+	 * This approach allows uniform devices management to simplify external
+	 * management tools like scstadmin. See README for more details.
+	 *
+	 * Either both add_device and del_device must be defined, or none.
+	 *
+	 * MUST HAVE if virtual devices are supported.
+	 */
+	ssize_t (*add_device) (const char *device_name, char *params);
+
+	/*
+	 * This function deletes a virtual device. See comment for add_device
+	 * above.
+	 *
+	 * MUST HAVE if virtual devices are supported.
+	 */
+	ssize_t (*del_device) (const char *device_name);
+
+	/*
+	 * This function called if not "add_device" or "del_device" command is
+	 * sent to the mgmt entry (see comment for add_device above). In this
+	 * case the command passed to this function as is in a string form.
+	 *
+	 * OPTIONAL.
+	 */
+	ssize_t (*mgmt_cmd) (char *cmd);
+
+	/*
+	 * Name of the dev handler. Must be unique. MUST HAVE.
+	 *
+	 * It's SCST_MAX_NAME + few more bytes to match scst_user expectations.
+	 */
+	char name[SCST_MAX_NAME + 10];
+
+	/*
+	 * Number of threads in this handler's devices' threads pools.
+	 * If 0 - no threads will be created, if <0 - creation of the threads
+	 * pools is prohibited. Also pay attention to threads_pool_type below.
+	 */
+	int threads_num;
+
+	/* Threads pool type. Valid only if threads_num > 0. */
+	enum scst_dev_type_threads_pool_type threads_pool_type;
+
+	/* Optional default log flags */
+	const unsigned long default_trace_flags;
+
+	/* Optional pointer to trace flags */
+	unsigned long *trace_flags;
+
+	/* Optional local trace table */
+	struct scst_trace_log *trace_tbl;
+
+	/* Optional local trace table help string */
+	const char *trace_tbl_help;
+
+	/* Optional help string for mgmt_cmd commands */
+	const char *mgmt_cmd_help;
+
+	/* List of parameters for add_device command, if any */
+	const char *add_device_parameters;
+
+	/*
+	 * List of optional, i.e. which could be added by add_attribute command
+	 * and deleted by del_attribute command, sysfs attributes, if any.
+	 * Helpful for scstadmin to work correctly.
+	 */
+	const char *devt_optional_attributes;
+
+	/*
+	 * List of optional, i.e. which could be added by add_device_attribute
+	 * command and deleted by del_device_attribute command, sysfs
+	 * attributes, if any. Helpful for scstadmin to work correctly.
+	 */
+	const char *dev_optional_attributes;
+
+	/* sysfs attributes, if any */
+	const struct attribute **devt_attrs;
+
+	/* sysfs device attributes, if any */
+	const struct attribute **dev_attrs;
+
+	/* Pointer to dev handler's private data */
+	void *devt_priv;
+
+	/* Pointer to parent dev type in the sysfs hierarchy */
+	struct scst_dev_type *parent;
+
+	struct module *module;
+
+	/** Private, must be inited to 0 by memset() **/
+
+	/* list entry in scst_(virtual_)dev_type_list */
+	struct list_head dev_type_list_entry;
+
+	struct kobject devt_kobj; /* main handlers/driver */
+
+	/* Number of currently active sysfs mgmt works (scst_sysfs_work_item) */
+	int devt_active_sysfs_works_count;
+
+	/* To wait until devt_kobj released */
+	struct completion devt_kobj_release_compl;
+};
+
+/*
+ * An SCST target, analog of SCSI target port.
+ */
+struct scst_tgt {
+	/* List of remote sessions per target, protected by scst_mutex */
+	struct list_head sess_list;
+
+	/* List entry of targets per template (tgts_list) */
+	struct list_head tgt_list_entry;
+
+	struct scst_tgt_template *tgtt;	/* corresponding target template */
+
+	struct scst_acg *default_acg; /* default acg for this target */
+
+	struct list_head tgt_acg_list; /* target ACG groups */
+
+	/*
+	 * Maximum SG table size. Needed here, since different cards on the
+	 * same target template can have different SG table limitations.
+	 */
+	int sg_tablesize;
+
+	/* Used for storage of target driver private stuff */
+	void *tgt_priv;
+
+	/*
+	 * The following fields used to store and retry cmds if target's
+	 * internal queue is full, so the target is unable to accept
+	 * the cmd returning QUEUE FULL.
+	 * They protected by tgt_lock, where necessary.
+	 */
+	bool retry_timer_active;
+	struct timer_list retry_timer;
+	atomic_t finished_cmds;
+	int retry_cmds;
+	spinlock_t tgt_lock;
+	struct list_head retry_cmd_list;
+
+	/* Used to wait until session finished to unregister */
+	wait_queue_head_t unreg_waitQ;
+
+	/* Name of the target */
+	char *tgt_name;
+
+	uint16_t rel_tgt_id;
+
+	/* sysfs release completion */
+	struct completion tgt_kobj_release_cmpl;
+
+	struct kobject tgt_kobj; /* main targets/target kobject */
+	struct kobject *tgt_sess_kobj; /* target/sessions/ */
+	struct kobject *tgt_luns_kobj; /* target/luns/ */
+	struct kobject *tgt_ini_grp_kobj; /* target/ini_groups/ */
+};
+
+/* Hash size and hash fn for hash based lun translation */
+#define	TGT_DEV_HASH_SHIFT	5
+#define	TGT_DEV_HASH_SIZE	(1 << TGT_DEV_HASH_SHIFT)
+#define	HASH_VAL(_val)		(_val & (TGT_DEV_HASH_SIZE - 1))
+
+#ifdef CONFIG_SCST_MEASURE_LATENCY
+
+/* Defines extended latency statistics */
+struct scst_ext_latency_stat {
+	uint64_t scst_time_rd, tgt_time_rd, dev_time_rd;
+	unsigned int processed_cmds_rd;
+	uint64_t min_scst_time_rd, min_tgt_time_rd, min_dev_time_rd;
+	uint64_t max_scst_time_rd, max_tgt_time_rd, max_dev_time_rd;
+
+	uint64_t scst_time_wr, tgt_time_wr, dev_time_wr;
+	unsigned int processed_cmds_wr;
+	uint64_t min_scst_time_wr, min_tgt_time_wr, min_dev_time_wr;
+	uint64_t max_scst_time_wr, max_tgt_time_wr, max_dev_time_wr;
+};
+
+#define SCST_IO_SIZE_THRESHOLD_SMALL		(8*1024)
+#define SCST_IO_SIZE_THRESHOLD_MEDIUM		(32*1024)
+#define SCST_IO_SIZE_THRESHOLD_LARGE		(128*1024)
+#define SCST_IO_SIZE_THRESHOLD_VERY_LARGE	(512*1024)
+
+#define SCST_LATENCY_STAT_INDEX_SMALL		0
+#define SCST_LATENCY_STAT_INDEX_MEDIUM		1
+#define SCST_LATENCY_STAT_INDEX_LARGE		2
+#define SCST_LATENCY_STAT_INDEX_VERY_LARGE	3
+#define SCST_LATENCY_STAT_INDEX_OTHER		4
+#define SCST_LATENCY_STATS_NUM		(SCST_LATENCY_STAT_INDEX_OTHER + 1)
+
+#endif /* CONFIG_SCST_MEASURE_LATENCY */
+
+/*
+ * SCST session, analog of SCSI I_T nexus
+ */
+struct scst_session {
+	/*
+	 * Initialization phase, one of SCST_SESS_IPH_* constants, protected by
+	 * sess_list_lock
+	 */
+	int init_phase;
+
+	struct scst_tgt *tgt;	/* corresponding target */
+
+	/* Used for storage of target driver private stuff */
+	void *tgt_priv;
+
+	/* session's async flags */
+	unsigned long sess_aflags;
+
+	/*
+	 * Hash list of tgt_dev's for this session, protected by scst_mutex
+	 * and suspended activity
+	 */
+	struct list_head sess_tgt_dev_list_hash[TGT_DEV_HASH_SIZE];
+
+	/*
+	 * List of cmds in this session. Protected by sess_list_lock.
+	 *
+	 * We must always keep commands in the sess list from the
+	 * very beginning, because otherwise they can be missed during
+	 * TM processing.
+	 */
+	struct list_head sess_cmd_list;
+
+	spinlock_t sess_list_lock; /* protects sess_cmd_list, etc */
+
+	atomic_t refcnt;		/* get/put counter */
+
+	/*
+	 * Alive commands for this session. ToDo: make it part of the common
+	 * IO flow control.
+	 */
+	atomic_t sess_cmd_count;
+
+	/* Access control for this session and list entry there */
+	struct scst_acg *acg;
+
+	/* Initiator port transport id */
+	uint8_t *transport_id;
+
+	/* List entry for the sessions list inside ACG */
+	struct list_head acg_sess_list_entry;
+
+	struct delayed_work hw_pending_work;
+
+	/* Name of attached initiator */
+	const char *initiator_name;
+
+	/* List entry of sessions per target */
+	struct list_head sess_list_entry;
+
+	/* List entry for the list that keeps session, waiting for the init */
+	struct list_head sess_init_list_entry;
+
+	/*
+	 * List entry for the list that keeps session, waiting for the shutdown
+	 */
+	struct list_head sess_shut_list_entry;
+
+	/*
+	 * Lists of deferred during session initialization commands.
+	 * Protected by sess_list_lock.
+	 */
+	struct list_head init_deferred_cmd_list;
+	struct list_head init_deferred_mcmd_list;
+
+	/*
+	 * Shutdown phase, one of SCST_SESS_SPH_* constants, unprotected.
+	 * Async. relating to init_phase, must be a separate variable, because
+	 * session could be unregistered before async. registration is finished.
+	 */
+	unsigned long shut_phase;
+
+	/* Used if scst_unregister_session() called in wait mode */
+	struct completion *shutdown_compl;
+
+	/* sysfs release completion */
+	struct completion sess_kobj_release_cmpl;
+
+	unsigned int sess_kobj_ready:1;
+
+	struct kobject sess_kobj; /* kobject for this struct */
+
+	/*
+	 * Functions and data for user callbacks from scst_register_session()
+	 * and scst_unregister_session()
+	 */
+	void *reg_sess_data;
+	void (*init_result_fn) (struct scst_session *sess, void *data,
+				int result);
+	void (*unreg_done_fn) (struct scst_session *sess);
+
+#ifdef CONFIG_SCST_MEASURE_LATENCY
+	/*
+	 * Must be the last to allow to work with drivers who don't know
+	 * about this config time option.
+	 */
+	spinlock_t lat_lock;
+	uint64_t scst_time, tgt_time, dev_time;
+	unsigned int processed_cmds;
+	uint64_t min_scst_time, min_tgt_time, min_dev_time;
+	uint64_t max_scst_time, max_tgt_time, max_dev_time;
+	struct scst_ext_latency_stat sess_latency_stat[SCST_LATENCY_STATS_NUM];
+#endif
+};
+
+/*
+ * SCST_PR_ABORT_ALL TM function helper structure
+ */
+struct scst_pr_abort_all_pending_mgmt_cmds_counter {
+	/*
+	 * How many there are pending for this cmd SCST_PR_ABORT_ALL TM
+	 * commands.
+	 */
+	atomic_t pr_abort_pending_cnt;
+
+	/* Saved completition routine */
+	void (*saved_cmd_done) (struct scst_cmd *cmd, int next_state,
+		enum scst_exec_context pref_context);
+
+	/*
+	 * How many there are pending for this cmd SCST_PR_ABORT_ALL TM
+	 * commands, which not yet aborted all affected commands and
+	 * a completion to signal, when it's done.
+	 */
+	atomic_t pr_aborting_cnt;
+	struct completion pr_aborting_cmpl;
+};
+
+/*
+ * Structure to control commands' queuing and threads pool processing the queue
+ */
+struct scst_cmd_threads {
+	spinlock_t cmd_list_lock;
+	struct list_head active_cmd_list; /* commands queue */
+	wait_queue_head_t cmd_list_waitQ;
+
+	struct io_context *io_context; /* IO context of the threads pool */
+
+	bool io_context_ready;
+
+	int nr_threads; /* number of processing threads */
+	struct list_head threads_list; /* processing threads */
+
+	struct list_head lists_list_entry;
+};
+
+/*
+ * SCST command, analog of I_T_L_Q nexus or task
+ */
+struct scst_cmd {
+	/* List entry for below *_cmd_threads */
+	struct list_head cmd_list_entry;
+
+	/* Pointer to lists of commands with the lock */
+	struct scst_cmd_threads *cmd_threads;
+
+	atomic_t cmd_ref;
+
+	struct scst_session *sess;	/* corresponding session */
+
+	/* Cmd state, one of SCST_CMD_STATE_* constants */
+	int state;
+
+	/*************************************************************
+	 ** Cmd's flags
+	 *************************************************************/
+
+	/*
+	 * Set if expected_sn should be incremented, i.e. cmd was sent
+	 * for execution
+	 */
+	unsigned int sent_for_exec:1;
+
+	/* Set if the cmd's action is completed */
+	unsigned int completed:1;
+
+	/* Set if we should ignore Unit Attention in scst_check_sense() */
+	unsigned int ua_ignore:1;
+
+	/* Set if cmd is being processed in atomic context */
+	unsigned int atomic:1;
+
+	/* Set if this command was sent in double UA possible state */
+	unsigned int double_ua_possible:1;
+
+	/* Set if this command contains status */
+	unsigned int is_send_status:1;
+
+	/* Set if cmd is being retried */
+	unsigned int retry:1;
+
+	/* Set if cmd is internally generated */
+	unsigned int internal:1;
+
+	/* Set if the device was blocked by scst_inc_on_dev_cmd() (for debug) */
+	unsigned int inc_blocking:1;
+
+	/* Set if the device should be unblocked after cmd's finish */
+	unsigned int needs_unblocking:1;
+
+	/* Set if scst_dec_on_dev_cmd() call is needed on the cmd's finish */
+	unsigned int dec_on_dev_needed:1;
+
+	/* Set if cmd is queued as hw pending */
+	unsigned int cmd_hw_pending:1;
+
+	/*
+	 * Set if the target driver wants to alloc data buffers on its own.
+	 * In this case alloc_data_buf() must be provided in the target driver
+	 * template.
+	 */
+	unsigned int tgt_need_alloc_data_buf:1;
+
+	/*
+	 * Set by SCST if the custom data buffer allocation by the target driver
+	 * succeeded.
+	 */
+	unsigned int tgt_data_buf_alloced:1;
+
+	/* Set if custom data buffer allocated by dev handler */
+	unsigned int dh_data_buf_alloced:1;
+
+	/* Set if the target driver called scst_set_expected() */
+	unsigned int expected_values_set:1;
+
+	/*
+	 * Set if the SG buffer was modified by scst_adjust_sg()
+	 */
+	unsigned int sg_buff_modified:1;
+
+	/*
+	 * Set if cmd buffer was vmallocated and copied from more
+	 * then one sg chunk
+	 */
+	unsigned int sg_buff_vmallocated:1;
+
+	/*
+	 * Set if scst_cmd_init_stage1_done() called and the target
+	 * want that preprocessing_done() will be called
+	 */
+	unsigned int preprocessing_only:1;
+
+	/* Set if cmd's SN was set */
+	unsigned int sn_set:1;
+
+	/* Set if hq_cmd_count was incremented */
+	unsigned int hq_cmd_inced:1;
+
+	/*
+	 * Set if scst_cmd_init_stage1_done() called and the target wants
+	 * that the SN for the cmd won't be assigned until scst_restart_cmd()
+	 */
+	unsigned int set_sn_on_restart_cmd:1;
+
+	/* Set if the cmd's must not use sgv cache for data buffer */
+	unsigned int no_sgv:1;
+
+	/*
+	 * Set if target driver may need to call dma_sync_sg() or similar
+	 * function before transferring cmd' data to the target device
+	 * via DMA.
+	 */
+	unsigned int may_need_dma_sync:1;
+
+	/* Set if the cmd was done or aborted out of its SN */
+	unsigned int out_of_sn:1;
+
+	/* Set if increment expected_sn in cmd->scst_cmd_done() */
+	unsigned int inc_expected_sn_on_done:1;
+
+	/* Set if tgt_sn field is valid */
+	unsigned int tgt_sn_set:1;
+
+	/* Set if any direction residual is possible */
+	unsigned int resid_possible:1;
+
+	/* Set if cmd is done */
+	unsigned int done:1;
+
+	/* Set if cmd is finished */
+	unsigned int finished:1;
+
+#ifdef CONFIG_SCST_DEBUG_TM
+	/* Set if the cmd was delayed by task management debugging code */
+	unsigned int tm_dbg_delayed:1;
+
+	/* Set if the cmd must be ignored by task management debugging code */
+	unsigned int tm_dbg_immut:1;
+#endif
+
+	/**************************************************************/
+
+	/* cmd's async flags */
+	unsigned long cmd_flags;
+
+	/* Keeps status of cmd's status/data delivery to remote initiator */
+	int delivery_status;
+
+	struct scst_tgt_template *tgtt;	/* to save extra dereferences */
+	struct scst_tgt *tgt;		/* to save extra dereferences */
+	struct scst_device *dev;	/* to save extra dereferences */
+
+	struct scst_tgt_dev *tgt_dev;	/* corresponding device for this cmd */
+
+	uint64_t lun;			/* LUN for this cmd */
+
+	unsigned long start_time;
+
+	/* List entry for tgt_dev's SN related lists */
+	struct list_head sn_cmd_list_entry;
+
+	/* Cmd's serial number, used to execute cmd's in order of arrival */
+	unsigned int sn;
+
+	/* The corresponding sn_slot in tgt_dev->sn_slots */
+	atomic_t *sn_slot;
+
+	/* List entry for sess's sess_cmd_list */
+	struct list_head sess_cmd_list_entry;
+
+	/*
+	 * Used to found the cmd by scst_find_cmd_by_tag(). Set by the
+	 * target driver on the cmd's initialization time
+	 */
+	uint64_t tag;
+
+	uint32_t tgt_sn; /* SN set by target driver (for TM purposes) */
+
+	/* CDB and its len */
+	uint8_t cdb[SCST_MAX_CDB_SIZE];
+	unsigned short cdb_len;
+	unsigned short ext_cdb_len;
+	uint8_t *ext_cdb;
+
+	enum scst_cdb_flags op_flags;
+	const char *op_name;
+
+	enum scst_cmd_queue_type queue_type;
+
+	int timeout; /* CDB execution timeout in seconds */
+	int retries; /* Amount of retries that will be done by SCSI mid-level */
+
+	/* SCSI data direction, one of SCST_DATA_* constants */
+	scst_data_direction data_direction;
+
+	/* Remote initiator supplied values, if any */
+	scst_data_direction expected_data_direction;
+	int expected_transfer_len;
+	int expected_out_transfer_len; /* for bidi writes */
+
+	/*
+	 * Cmd data length. Could be different from bufflen for commands like
+	 * VERIFY, which transfer different amount of data (if any), than
+	 * processed.
+	 */
+	int data_len;
+
+	/* Completition routine */
+	void (*scst_cmd_done) (struct scst_cmd *cmd, int next_state,
+		enum scst_exec_context pref_context);
+
+	struct sgv_pool_obj *sgv;	/* sgv object */
+	int bufflen;			/* cmd buffer length */
+	struct scatterlist *sg;		/* cmd data buffer SG vector */
+	int sg_cnt;			/* SG segments count */
+
+	/*
+	 * Response data length in data buffer. Must not be set
+	 * directly, use scst_set_resp_data_len() for that.
+	 */
+	int resp_data_len;
+
+	/*
+	 * Response data length adjusted on residual, i.e.
+	 * min(expected_len, resp_len), if expected len set.
+	 */
+	int adjusted_resp_data_len;
+
+	/*
+	 * Data length to write, i.e. transfer from the initiator. Might be
+	 * different from (out_)bufflen, if the initiator asked too big or too
+	 * small expected(_out_)transfer_len.
+	 */
+	int write_len;
+
+	/*
+	 * Write sg and sg_cnt to point out either on sg/sg_cnt, or on
+	 * out_sg/out_sg_cnt.
+	 */
+	struct scatterlist **write_sg;
+	int *write_sg_cnt;
+
+	/* scst_get_sg_buf_[first,next]() support */
+	struct scatterlist *get_sg_buf_cur_sg_entry;
+	int get_sg_buf_entry_num;
+
+	/* Bidirectional transfers support */
+	int out_bufflen;			/* WRITE buffer length */
+	struct sgv_pool_obj *out_sgv;	/* WRITE sgv object */
+	struct scatterlist *out_sg;	/* WRITE data buffer SG vector */
+	int out_sg_cnt;			/* WRITE SG segments count */
+
+	/*
+	 * Used if both target driver and dev handler request own memory
+	 * allocation. In other cases, both are equal to sg and sg_cnt
+	 * correspondingly.
+	 *
+	 * If target driver requests own memory allocations, it MUST use
+	 * functions scst_cmd_get_tgt_sg*() to get sg and sg_cnt! Otherwise,
+	 * it may use functions scst_cmd_get_sg*().
+	 */
+	struct scatterlist *tgt_sg;
+	int tgt_sg_cnt;
+	struct scatterlist *tgt_out_sg;	/* bidirectional */
+	int tgt_out_sg_cnt;		/* bidirectional */
+
+	/*
+	 * The status fields in case of errors must be set using
+	 * scst_set_cmd_error_status()!
+	 */
+	uint8_t status;		/* status byte from target device */
+	uint8_t msg_status;	/* return status from host adapter itself */
+	uint8_t host_status;	/* set by low-level driver to indicate status */
+	uint8_t driver_status;	/* set by mid-level */
+
+	uint8_t *sense;		/* pointer to sense buffer */
+	unsigned short sense_valid_len; /* length of valid sense data */
+	unsigned short sense_buflen; /* length of the sense buffer, if any */
+
+	/* Start time when cmd was sent to rdy_to_xfer() or xmit_response() */
+	unsigned long hw_pending_start;
+
+	/* Used for storage of target driver private stuff */
+	void *tgt_priv;
+
+	/* Used for storage of dev handler private stuff */
+	void *dh_priv;
+
+	/* Used to restore sg if it was modified by scst_adjust_sg() */
+	struct scatterlist *orig_sg;
+	int *p_orig_sg_cnt;
+	int orig_sg_cnt, orig_sg_entry, orig_entry_len;
+
+	/* Used to retry commands in case of double UA */
+	int dbl_ua_orig_resp_data_len, dbl_ua_orig_data_direction;
+
+	/*
+	 * List of the corresponding mgmt cmds, if any. Protected by
+	 * sess_list_lock.
+	 */
+	struct list_head mgmt_cmd_list;
+
+	/* List entry for dev's blocked_cmd_list */
+	struct list_head blocked_cmd_list_entry;
+
+	/* Counter of the corresponding SCST_PR_ABORT_ALL TM commands */
+	struct scst_pr_abort_all_pending_mgmt_cmds_counter *pr_abort_counter;
+
+	struct scst_cmd *orig_cmd; /* Used to issue REQUEST SENSE */
+
+#ifdef CONFIG_SCST_MEASURE_LATENCY
+	/*
+	 * Must be the last to allow to work with drivers who don't know
+	 * about this config time option.
+	 */
+	uint64_t start, curr_start, parse_time, alloc_buf_time;
+	uint64_t restart_waiting_time, rdy_to_xfer_time;
+	uint64_t pre_exec_time, exec_time, dev_done_time;
+	uint64_t xmit_time, tgt_on_free_time, dev_on_free_time;
+#endif
+};
+
+/*
+ * Parameters for SCST management commands
+ */
+struct scst_rx_mgmt_params {
+	int fn;
+	uint64_t tag;
+	const uint8_t *lun;
+	int lun_len;
+	uint32_t cmd_sn;
+	int atomic;
+	void *tgt_priv;
+	unsigned char tag_set;
+	unsigned char lun_set;
+	unsigned char cmd_sn_set;
+};
+
+/*
+ * A stub structure to link an management command and affected regular commands
+ */
+struct scst_mgmt_cmd_stub {
+	struct scst_mgmt_cmd *mcmd;
+
+	/* List entry in cmd->mgmt_cmd_list */
+	struct list_head cmd_mgmt_cmd_list_entry;
+
+	/* Set if the cmd was counted in  mcmd->cmd_done_wait_count */
+	unsigned int done_counted:1;
+
+	/* Set if the cmd was counted in  mcmd->cmd_finish_wait_count */
+	unsigned int finish_counted:1;
+};
+
+/*
+ * SCST task management structure
+ */
+struct scst_mgmt_cmd {
+	/* List entry for *_mgmt_cmd_list */
+	struct list_head mgmt_cmd_list_entry;
+
+	struct scst_session *sess;
+
+	/* Mgmt cmd state, one of SCST_MCMD_STATE_* constants */
+	int state;
+
+	int fn; /* task management function */
+
+	/* Set if device(s) should be unblocked after mcmd's finish */
+	unsigned int needs_unblocking:1;
+	unsigned int lun_set:1;		/* set, if lun field is valid */
+	unsigned int cmd_sn_set:1;	/* set, if cmd_sn field is valid */
+
+	/*
+	 * Number of commands to finish before sending response,
+	 * protected by scst_mcmd_lock
+	 */
+	int cmd_finish_wait_count;
+
+	/*
+	 * Number of commands to complete (done) before resetting reservation,
+	 * protected by scst_mcmd_lock
+	 */
+	int cmd_done_wait_count;
+
+	/* Number of completed commands, protected by scst_mcmd_lock */
+	int completed_cmd_count;
+
+	uint64_t lun;	/* LUN for this mgmt cmd */
+	/* or (and for iSCSI) */
+	uint64_t tag;	/* tag of the corresponding cmd */
+
+	uint32_t cmd_sn; /* affected command's highest SN */
+
+	/* corresponding cmd (to be aborted, found by tag) */
+	struct scst_cmd *cmd_to_abort;
+
+	/* corresponding device for this mgmt cmd (found by lun) */
+	struct scst_tgt_dev *mcmd_tgt_dev;
+
+	/* completition status, one of the SCST_MGMT_STATUS_* constants */
+	int status;
+
+	/* Used for storage of target driver private stuff or origin PR cmd */
+	union {
+		void *tgt_priv;
+		struct scst_cmd *origin_pr_cmd;
+	};
+};
+
+/*
+ * Persistent reservations registrant
+ */
+struct scst_dev_registrant {
+	uint8_t *transport_id;
+	uint16_t rel_tgt_id;
+	__be64 key;
+
+	/* tgt_dev (I_T nexus) for this registrant, if any */
+	struct scst_tgt_dev *tgt_dev;
+
+	/* List entry for dev_registrants_list */
+	struct list_head dev_registrants_list_entry;
+
+	/* 2 auxiliary fields used to rollback changes for errors, etc. */
+	struct list_head aux_list_entry;
+	__be64 rollback_key;
+};
+
+/*
+ * SCST device
+ */
+struct scst_device {
+	unsigned short type;	/* SCSI type of the device */
+
+	/*************************************************************
+	 ** Dev's flags. Updates serialized by dev_lock or suspended
+	 ** activity
+	 *************************************************************/
+
+	/* Set if dev is RESERVED */
+	unsigned short dev_reserved:1;
+
+	/* Set if double reset UA is possible */
+	unsigned short dev_double_ua_possible:1;
+
+	/* If set, dev is read only */
+	unsigned short rd_only:1;
+
+	/**************************************************************/
+
+	/*************************************************************
+	 ** Dev's control mode page related values. Updates serialized
+	 ** by scst_block_dev(). Modified independently to the above and
+	 ** below fields, hence the alignment.
+	 *************************************************************/
+
+	unsigned int queue_alg:4  __attribute__((aligned(sizeof(long))));
+	unsigned int tst:3;
+	unsigned int tas:1;
+	unsigned int swp:1;
+	unsigned int d_sense:1;
+
+	/*
+	 * Set if device implements own ordered commands management. If not set
+	 * and queue_alg is SCST_CONTR_MODE_QUEUE_ALG_RESTRICTED_REORDER,
+	 * expected_sn will be incremented only after commands finished.
+	 */
+	unsigned int has_own_order_mgmt:1;
+
+	/**************************************************************/
+
+	/*
+	 * Set if dev is persistently reserved. Protected by dev_pr_mutex.
+	 * Modified independently to the above field, hence the alignment.
+	 */
+	unsigned int pr_is_set:1 __attribute__((aligned(sizeof(long))));
+
+	/*
+	 * Set if there is a thread changing or going to change PR state(s).
+	 * Protected by dev_pr_mutex.
+	 */
+	unsigned int pr_writer_active:1;
+
+	/*
+	 * How many threads are checking commands for PR allowance. Used to
+	 * implement lockless read-only fast path.
+	 */
+	atomic_t pr_readers_count;
+
+	struct scst_dev_type *handler;	/* corresponding dev handler */
+
+	/* Used for storage of dev handler private stuff */
+	void *dh_priv;
+
+	/* Corresponding real SCSI device, could be NULL for virtual devices */
+	struct scsi_device *scsi_dev;
+
+	/* List of commands with lock, if dedicated threads are used */
+	struct scst_cmd_threads dev_cmd_threads;
+
+	/* Memory limits for this device */
+	struct scst_mem_lim dev_mem_lim;
+
+	/* How many cmds alive on this dev */
+	atomic_t dev_cmd_count;
+
+	/*
+	 * How many there are "on_dev" commands, i.e. ones those are being
+	 * executed by the underlying SCSI/virtual device.
+	 */
+	atomic_t on_dev_count;
+
+	/*
+	 * How many times device was blocked for new cmds execution.
+	 * Protected by dev_lock
+	 */
+	int block_count;
+
+	/* How many write cmds alive on this dev. Temporary, ToDo */
+	atomic_t write_cmd_count;
+
+	/*************************************************************
+	 ** Persistent reservation fields. Protected by dev_pr_mutex.
+	 *************************************************************/
+
+	/*
+	 * True if persist through power loss is activated. Modified
+	 * independently to the above field, hence the alignment.
+	 */
+	unsigned short pr_aptpl:1 __attribute__((aligned(sizeof(long))));
+
+	/* Persistent reservation type */
+	uint8_t pr_type;
+
+	/* Persistent reservation scope */
+	uint8_t pr_scope;
+
+	/* Mutex to protect PR operations */
+	struct mutex dev_pr_mutex;
+
+	/* Persistent reservation generation value */
+	uint32_t pr_generation;
+
+	/* Reference to registrant - persistent reservation holder */
+	struct scst_dev_registrant *pr_holder;
+
+	/* List of dev's registrants */
+	struct list_head dev_registrants_list;
+
+	/*
+	 * Count of connected tgt_devs from transports, which don't support
+	 * PRs, i.e. don't have get_initiator_port_transport_id(). Protected
+	 * by scst_mutex.
+	 */
+	int not_pr_supporting_tgt_devs_num;
+
+	/* Persist through power loss files */
+	char *pr_file_name;
+	char *pr_file_name1;
+
+	/**************************************************************/
+
+	spinlock_t dev_lock;		/* device lock */
+
+	struct list_head blocked_cmd_list; /* protected by dev_lock */
+
+	/* Used to wait for requested amount of "on_dev" commands */
+	wait_queue_head_t on_dev_waitQ;
+
+	/* A list entry used during TM, protected by scst_mutex */
+	struct list_head tm_dev_list_entry;
+
+	/* Virtual device internal ID */
+	int virt_id;
+
+	/* Pointer to virtual device name, for convenience only */
+	char *virt_name;
+
+	/* List entry in global devices list */
+	struct list_head dev_list_entry;
+
+	/*
+	 * List of tgt_dev's, one per session, protected by scst_mutex or
+	 * dev_lock for reads and both for writes
+	 */
+	struct list_head dev_tgt_dev_list;
+
+	/* List of acg_dev's, one per acg, protected by scst_mutex */
+	struct list_head dev_acg_dev_list;
+
+	/* Number of threads in the device's threads pools */
+	int threads_num;
+
+	/* Threads pool type of the device. Valid only if threads_num > 0. */
+	enum scst_dev_type_threads_pool_type threads_pool_type;
+
+	/* sysfs release completion */
+	struct completion dev_kobj_release_cmpl;
+
+	struct kobject dev_kobj; /* kobject for this struct */
+	struct kobject *dev_exp_kobj; /* exported groups */
+
+	/* Export number in the dev's sysfs list. Protected by scst_mutex */
+	int dev_exported_lun_num;
+};
+
+/*
+ * Used to store threads local tgt_dev specific data
+ */
+struct scst_thr_data_hdr {
+	/* List entry in tgt_dev->thr_data_list */
+	struct list_head thr_data_list_entry;
+	struct task_struct *owner_thr; /* the owner thread */
+	atomic_t ref;
+	/* Function that will be called on the tgt_dev destruction */
+	void (*free_fn) (struct scst_thr_data_hdr *data);
+};
+
+/*
+ * Used to clearly dispose async io_context
+ */
+struct scst_async_io_context_keeper {
+	struct kref aic_keeper_kref;
+	bool aic_ready;
+	struct io_context *aic;
+	struct task_struct *aic_keeper_thr;
+	wait_queue_head_t aic_keeper_waitQ;
+};
+
+/*
+ * Used to store per-session specific device information, analog of
+ * SCSI I_T_L nexus.
+ */
+struct scst_tgt_dev {
+	/* List entry in sess->sess_tgt_dev_list_hash */
+	struct list_head sess_tgt_dev_list_entry;
+
+	struct scst_device *dev; /* to save extra dereferences */
+	uint64_t lun;		 /* to save extra dereferences */
+
+	gfp_t gfp_mask;
+	struct sgv_pool *pool;
+	int max_sg_cnt;
+
+	/*
+	 * Tgt_dev's async flags. Modified independently to the neighbour
+	 * fields.
+	 */
+	unsigned long tgt_dev_flags;
+
+	/* Used for storage of dev handler private stuff */
+	void *dh_priv;
+
+	/* How many cmds alive on this dev in this session */
+	atomic_t tgt_dev_cmd_count;
+
+	/*
+	 * Used to execute cmd's in order of arrival, honoring SCSI task
+	 * attributes.
+	 *
+	 * Protected by sn_lock, except expected_sn, which is protected by
+	 * itself. Curr_sn must have the same size as expected_sn to
+	 * overflow simultaneously.
+	 */
+	int def_cmd_count;
+	spinlock_t sn_lock;
+	unsigned int expected_sn;
+	unsigned int curr_sn;
+	int hq_cmd_count;
+	struct list_head deferred_cmd_list;
+	struct list_head skipped_sn_list;
+
+	/*
+	 * Set if the prev cmd was ORDERED. Size and, hence, alignment must
+	 * allow unprotected modifications independently to the neighbour fields.
+	 */
+	unsigned long prev_cmd_ordered;
+
+	int num_free_sn_slots; /* if it's <0, then all slots are busy */
+	atomic_t *cur_sn_slot;
+	atomic_t sn_slots[15];
+
+	/* List of scst_thr_data_hdr and lock */
+	spinlock_t thr_data_lock;
+	struct list_head thr_data_list;
+
+	/* Pointer to lists of commands with the lock */
+	struct scst_cmd_threads *active_cmd_threads;
+
+	/* Union to save some CPU cache footprint */
+	union {
+		struct {
+			/* Copy to save fast path dereference */
+			struct io_context *async_io_context;
+
+			struct scst_async_io_context_keeper *aic_keeper;
+		};
+
+		/* Lists of commands with lock, if dedicated threads are used */
+		struct scst_cmd_threads tgt_dev_cmd_threads;
+	};
+
+	spinlock_t tgt_dev_lock;	/* per-session device lock */
+
+	/* List of UA's for this device, protected by tgt_dev_lock */
+	struct list_head UA_list;
+
+	struct scst_session *sess;	/* corresponding session */
+	struct scst_acg_dev *acg_dev;	/* corresponding acg_dev */
+
+	/* Reference to registrant to find quicker */
+	struct scst_dev_registrant *registrant;
+
+	/* List entry in dev->dev_tgt_dev_list */
+	struct list_head dev_tgt_dev_list_entry;
+
+	/* Internal tmp list entry */
+	struct list_head extra_tgt_dev_list_entry;
+
+	/* Set if INQUIRY DATA HAS CHANGED UA is needed */
+	unsigned int inq_changed_ua_needed:1;
+
+	/*
+	 * Stored Unit Attention sense and its length for possible
+	 * subsequent REQUEST SENSE. Both protected by tgt_dev_lock.
+	 */
+	unsigned short tgt_dev_valid_sense_len;
+	uint8_t tgt_dev_sense[SCST_SENSE_BUFFERSIZE];
+
+	/* sysfs release completion */
+	struct completion tgt_dev_kobj_release_cmpl;
+
+	struct kobject tgt_dev_kobj; /* kobject for this struct */
+
+#ifdef CONFIG_SCST_MEASURE_LATENCY
+	/*
+	 * Must be the last to allow to work with drivers who don't know
+	 * about this config time option.
+	 *
+	 * Protected by sess->lat_lock.
+	 */
+	uint64_t scst_time, tgt_time, dev_time;
+	unsigned int processed_cmds;
+	struct scst_ext_latency_stat dev_latency_stat[SCST_LATENCY_STATS_NUM];
+#endif
+};
+
+/*
+ * Used to store ACG-specific device information, like LUN
+ */
+struct scst_acg_dev {
+	struct scst_device *dev; /* corresponding device */
+
+	uint64_t lun; /* device's LUN in this acg */
+
+	/* If set, the corresponding LU is read only */
+	unsigned int rd_only:1;
+
+	struct scst_acg *acg; /* parent acg */
+
+	/* List entry in dev->dev_acg_dev_list */
+	struct list_head dev_acg_dev_list_entry;
+
+	/* List entry in acg->acg_dev_list */
+	struct list_head acg_dev_list_entry;
+
+	/* kobject for this structure */
+	struct kobject acg_dev_kobj;
+
+	/* sysfs release completion */
+	struct completion acg_dev_kobj_release_cmpl;
+
+	/* Name of the link to the corresponding LUN */
+	char acg_dev_link_name[20];
+};
+
+/*
+ * ACG - access control group. Used to store group related
+ * control information.
+ */
+struct scst_acg {
+	/* Owner target */
+	struct scst_tgt *tgt;
+
+	/* List of acg_dev's in this acg, protected by scst_mutex */
+	struct list_head acg_dev_list;
+
+	/* List of attached sessions, protected by scst_mutex */
+	struct list_head acg_sess_list;
+
+	/* List of attached acn's, protected by scst_mutex */
+	struct list_head acn_list;
+
+	/* List entry in acg_lists */
+	struct list_head acg_list_entry;
+
+	/* Name of this acg */
+	const char *acg_name;
+
+	/* Type of I/O initiators groupping */
+	int acg_io_grouping_type;
+
+	unsigned int tgt_acg:1;
+
+	/* sysfs release completion */
+	struct completion acg_kobj_release_cmpl;
+
+	/* kobject for this structure */
+	struct kobject acg_kobj;
+
+	struct kobject *luns_kobj;
+	struct kobject *initiators_kobj;
+
+	unsigned int addr_method;
+};
+
+/*
+ * ACN - access control name. Used to store names, by which
+ * incoming sessions will be assigned to appropriate ACG.
+ */
+struct scst_acn {
+	struct scst_acg *acg; /* owner ACG */
+
+	const char *name; /* initiator's name */
+
+	/* List entry in acg->acn_list */
+	struct list_head acn_list_entry;
+
+	/* sysfs file attributes */
+	struct kobj_attribute *acn_attr;
+};
+
+/*
+ * Used to store per-session UNIT ATTENTIONs
+ */
+struct scst_tgt_dev_UA {
+	/* List entry in tgt_dev->UA_list */
+	struct list_head UA_list_entry;
+
+	/* Set if UA is global for session */
+	unsigned short global_UA:1;
+
+	/* Unit Attention valid sense len */
+	unsigned short UA_valid_sense_len;
+	/* Unit Attention sense buf */
+	uint8_t UA_sense_buffer[SCST_SENSE_BUFFERSIZE];
+};
+
+/* Used to deliver AENs */
+struct scst_aen {
+	int event_fn; /* AEN fn */
+
+	struct scst_session *sess;	/* corresponding session */
+	__be64 lun;			/* corresponding LUN in SCSI form */
+
+	union {
+		/* SCSI AEN data */
+		struct {
+			int aen_sense_len;
+			uint8_t aen_sense[SCST_STANDARD_SENSE_LEN];
+		};
+	};
+
+	/* Keeps status of AEN's delivery to remote initiator */
+	int delivery_status;
+};
+
+#ifndef smp_mb__after_set_bit
+/* There is no smp_mb__after_set_bit() in the kernel */
+#define smp_mb__after_set_bit()                 smp_mb()
+#endif
+
+/*
+ * Registers target template.
+ * Returns 0 on success or appropriate error code otherwise.
+ */
+int __scst_register_target_template(struct scst_tgt_template *vtt,
+	const char *version);
+static inline int scst_register_target_template(struct scst_tgt_template *vtt)
+{
+	return __scst_register_target_template(vtt, SCST_INTERFACE_VERSION);
+}
+
+/*
+ * Registers target template, non-GPL version.
+ * Returns 0 on success or appropriate error code otherwise.
+ *
+ * Note: *vtt must be static!
+ */
+int __scst_register_target_template_non_gpl(struct scst_tgt_template *vtt,
+	const char *version);
+static inline int scst_register_target_template_non_gpl(
+	struct scst_tgt_template *vtt)
+{
+	return __scst_register_target_template_non_gpl(vtt,
+		SCST_INTERFACE_VERSION);
+}
+
+void scst_unregister_target_template(struct scst_tgt_template *vtt);
+
+struct scst_tgt *scst_register_target(struct scst_tgt_template *vtt,
+	const char *target_name);
+void scst_unregister_target(struct scst_tgt *tgt);
+
+struct scst_session *scst_register_session(struct scst_tgt *tgt, int atomic,
+	const char *initiator_name, void *tgt_priv, void *result_fn_data,
+	void (*result_fn) (struct scst_session *sess, void *data, int result));
+struct scst_session *scst_register_session_non_gpl(struct scst_tgt *tgt,
+	const char *initiator_name, void *tgt_priv);
+void scst_unregister_session(struct scst_session *sess, int wait,
+	void (*unreg_done_fn) (struct scst_session *sess));
+void scst_unregister_session_non_gpl(struct scst_session *sess);
+
+int __scst_register_dev_driver(struct scst_dev_type *dev_type,
+	const char *version);
+static inline int scst_register_dev_driver(struct scst_dev_type *dev_type)
+{
+	return __scst_register_dev_driver(dev_type, SCST_INTERFACE_VERSION);
+}
+void scst_unregister_dev_driver(struct scst_dev_type *dev_type);
+
+int __scst_register_virtual_dev_driver(struct scst_dev_type *dev_type,
+	const char *version);
+/*
+ * Registers dev handler driver for virtual devices (eg VDISK).
+ * Returns 0 on success or appropriate error code otherwise.
+ */
+static inline int scst_register_virtual_dev_driver(
+	struct scst_dev_type *dev_type)
+{
+	return __scst_register_virtual_dev_driver(dev_type,
+		SCST_INTERFACE_VERSION);
+}
+
+void scst_unregister_virtual_dev_driver(struct scst_dev_type *dev_type);
+
+bool scst_initiator_has_luns(struct scst_tgt *tgt, const char *initiator_name);
+
+struct scst_cmd *scst_rx_cmd(struct scst_session *sess,
+	const uint8_t *lun, int lun_len, const uint8_t *cdb,
+	unsigned int cdb_len, int atomic);
+void scst_cmd_init_done(struct scst_cmd *cmd,
+	enum scst_exec_context pref_context);
+
+/*
+ * Notifies SCST that the driver finished the first stage of the command
+ * initialization, and the command is ready for execution, but after
+ * SCST done the command's preprocessing preprocessing_done() function
+ * should be called. The second argument sets preferred command execition
+ * context. See SCST_CONTEXT_* constants for details.
+ *
+ * See comment for scst_cmd_init_done() for the serialization requirements.
+ */
+static inline void scst_cmd_init_stage1_done(struct scst_cmd *cmd,
+	enum scst_exec_context pref_context, int set_sn)
+{
+	cmd->preprocessing_only = 1;
+	cmd->set_sn_on_restart_cmd = !set_sn;
+	scst_cmd_init_done(cmd, pref_context);
+}
+
+void scst_restart_cmd(struct scst_cmd *cmd, int status,
+	enum scst_exec_context pref_context);
+
+void scst_rx_data(struct scst_cmd *cmd, int status,
+	enum scst_exec_context pref_context);
+
+void scst_tgt_cmd_done(struct scst_cmd *cmd,
+	enum scst_exec_context pref_context);
+
+int scst_rx_mgmt_fn(struct scst_session *sess,
+	const struct scst_rx_mgmt_params *params);
+
+/*
+ * Creates new management command using tag and sends it for execution.
+ * Can be used for SCST_ABORT_TASK only.
+ * Must not be called in parallel with scst_unregister_session() for the
+ * same sess. Returns 0 for success, error code otherwise.
+ *
+ * Obsolete in favor of scst_rx_mgmt_fn()
+ */
+static inline int scst_rx_mgmt_fn_tag(struct scst_session *sess, int fn,
+	uint64_t tag, int atomic, void *tgt_priv)
+{
+	struct scst_rx_mgmt_params params;
+
+	BUG_ON(fn != SCST_ABORT_TASK);
+
+	memset(&params, 0, sizeof(params));
+	params.fn = fn;
+	params.tag = tag;
+	params.tag_set = 1;
+	params.atomic = atomic;
+	params.tgt_priv = tgt_priv;
+	return scst_rx_mgmt_fn(sess, &params);
+}
+
+/*
+ * Creates new management command using LUN and sends it for execution.
+ * Currently can be used for any fn, except SCST_ABORT_TASK.
+ * Must not be called in parallel with scst_unregister_session() for the
+ * same sess. Returns 0 for success, error code otherwise.
+ *
+ * Obsolete in favor of scst_rx_mgmt_fn()
+ */
+static inline int scst_rx_mgmt_fn_lun(struct scst_session *sess, int fn,
+	const uint8_t *lun, int lun_len, int atomic, void *tgt_priv)
+{
+	struct scst_rx_mgmt_params params;
+
+	BUG_ON(fn == SCST_ABORT_TASK);
+
+	memset(&params, 0, sizeof(params));
+	params.fn = fn;
+	params.lun = lun;
+	params.lun_len = lun_len;
+	params.lun_set = 1;
+	params.atomic = atomic;
+	params.tgt_priv = tgt_priv;
+	return scst_rx_mgmt_fn(sess, &params);
+}
+
+int scst_get_cdb_info(struct scst_cmd *cmd);
+
+int scst_set_cmd_error_status(struct scst_cmd *cmd, int status);
+int scst_set_cmd_error(struct scst_cmd *cmd, int key, int asc, int ascq);
+void scst_set_busy(struct scst_cmd *cmd);
+
+void scst_check_convert_sense(struct scst_cmd *cmd);
+
+void scst_set_initial_UA(struct scst_session *sess, int key, int asc, int ascq);
+
+void scst_capacity_data_changed(struct scst_device *dev);
+
+struct scst_cmd *scst_find_cmd_by_tag(struct scst_session *sess, uint64_t tag);
+struct scst_cmd *scst_find_cmd(struct scst_session *sess, void *data,
+			       int (*cmp_fn) (struct scst_cmd *cmd,
+					      void *data));
+
+enum dma_data_direction scst_to_dma_dir(int scst_dir);
+enum dma_data_direction scst_to_tgt_dma_dir(int scst_dir);
+
+/*
+ * Returns true, if cmd's CDB is fully locally handled by SCST and false
+ * otherwise. Dev handlers parse() and dev_done() not called for such commands.
+ */
+static inline bool scst_is_cmd_fully_local(struct scst_cmd *cmd)
+{
+	return (cmd->op_flags & SCST_FULLY_LOCAL_CMD) != 0;
+}
+
+/*
+ * Returns true, if cmd's CDB is locally handled by SCST and
+ * false otherwise.
+ */
+static inline bool scst_is_cmd_local(struct scst_cmd *cmd)
+{
+	return (cmd->op_flags & SCST_LOCAL_CMD) != 0;
+}
+
+/* Returns true, if cmd can deliver UA */
+static inline bool scst_is_ua_command(struct scst_cmd *cmd)
+{
+	return (cmd->op_flags & SCST_SKIP_UA) == 0;
+}
+
+int scst_register_virtual_device(struct scst_dev_type *dev_handler,
+	const char *dev_name);
+void scst_unregister_virtual_device(int id);
+
+/*
+ * Get/Set functions for tgt's sg_tablesize
+ */
+static inline int scst_tgt_get_sg_tablesize(struct scst_tgt *tgt)
+{
+	return tgt->sg_tablesize;
+}
+
+static inline void scst_tgt_set_sg_tablesize(struct scst_tgt *tgt, int val)
+{
+	tgt->sg_tablesize = val;
+}
+
+/*
+ * Get/Set functions for tgt's target private data
+ */
+static inline void *scst_tgt_get_tgt_priv(struct scst_tgt *tgt)
+{
+	return tgt->tgt_priv;
+}
+
+static inline void scst_tgt_set_tgt_priv(struct scst_tgt *tgt, void *val)
+{
+	tgt->tgt_priv = val;
+}
+
+void scst_update_hw_pending_start(struct scst_cmd *cmd);
+
+/*
+ * Get/Set functions for session's target private data
+ */
+static inline void *scst_sess_get_tgt_priv(struct scst_session *sess)
+{
+	return sess->tgt_priv;
+}
+
+static inline void scst_sess_set_tgt_priv(struct scst_session *sess,
+					      void *val)
+{
+	sess->tgt_priv = val;
+}
+
+/**
+ * Returns TRUE if cmd is being executed in atomic context.
+ *
+ * Note: checkpatch will complain on the use of in_atomic() below. You can
+ * safely ignore this warning since in_atomic() is used here only for debugging
+ * purposes.
+ */
+static inline bool scst_cmd_atomic(struct scst_cmd *cmd)
+{
+	int res = cmd->atomic;
+#ifdef CONFIG_SCST_EXTRACHECKS
+	if (unlikely((in_atomic() || in_interrupt() || irqs_disabled()) &&
+		     !res)) {
+		printk(KERN_ERR "ERROR: atomic context and non-atomic cmd\n");
+		dump_stack();
+		cmd->atomic = 1;
+		res = 1;
+	}
+#endif
+	return res;
+}
+
+/*
+ * Returns TRUE if cmd has been preliminary completed, i.e. completed or
+ * aborted.
+ */
+static inline bool scst_cmd_prelim_completed(struct scst_cmd *cmd)
+{
+	return cmd->completed || test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags);
+}
+
+static inline enum scst_exec_context __scst_estimate_context(bool direct)
+{
+	if (in_irq())
+		return SCST_CONTEXT_TASKLET;
+	else if (irqs_disabled())
+		return SCST_CONTEXT_THREAD;
+	else
+		return direct ? SCST_CONTEXT_DIRECT :
+				SCST_CONTEXT_DIRECT_ATOMIC;
+}
+
+static inline enum scst_exec_context scst_estimate_context(void)
+{
+	return __scst_estimate_context(0);
+}
+
+static inline enum scst_exec_context scst_estimate_context_direct(void)
+{
+	return __scst_estimate_context(1);
+}
+
+/* Returns cmd's CDB */
+static inline const uint8_t *scst_cmd_get_cdb(struct scst_cmd *cmd)
+{
+	return cmd->cdb;
+}
+
+/* Returns cmd's CDB length */
+static inline unsigned int scst_cmd_get_cdb_len(struct scst_cmd *cmd)
+{
+	return cmd->cdb_len;
+}
+
+/* Returns cmd's extended CDB */
+static inline const uint8_t *scst_cmd_get_ext_cdb(struct scst_cmd *cmd)
+{
+	return cmd->ext_cdb;
+}
+
+/* Returns cmd's extended CDB length */
+static inline unsigned int scst_cmd_get_ext_cdb_len(struct scst_cmd *cmd)
+{
+	return cmd->ext_cdb_len;
+}
+
+/* Sets cmd's extended CDB and its length */
+static inline void scst_cmd_set_ext_cdb(struct scst_cmd *cmd,
+	uint8_t *ext_cdb, unsigned int ext_cdb_len)
+{
+	cmd->ext_cdb = ext_cdb;
+	cmd->ext_cdb_len = ext_cdb_len;
+}
+
+/* Returns cmd's session */
+static inline struct scst_session *scst_cmd_get_session(struct scst_cmd *cmd)
+{
+	return cmd->sess;
+}
+
+/* Returns cmd's response data length */
+static inline int scst_cmd_get_resp_data_len(struct scst_cmd *cmd)
+{
+	return cmd->resp_data_len;
+}
+
+/* Returns cmd's adjusted response data length */
+static inline int scst_cmd_get_adjusted_resp_data_len(struct scst_cmd *cmd)
+{
+	return cmd->adjusted_resp_data_len;
+}
+
+/* Returns if status should be sent for cmd */
+static inline int scst_cmd_get_is_send_status(struct scst_cmd *cmd)
+{
+	return cmd->is_send_status;
+}
+
+/*
+ * Returns pointer to cmd's SG data buffer.
+ *
+ * Usage of this function is not recommended, use scst_get_buf_*()
+ * family of functions instead.
+ */
+static inline struct scatterlist *scst_cmd_get_sg(struct scst_cmd *cmd)
+{
+	return cmd->sg;
+}
+
+/*
+ * Returns cmd's sg_cnt.
+ *
+ * Usage of this function is not recommended, use scst_get_buf_*()
+ * family of functions instead.
+ */
+static inline int scst_cmd_get_sg_cnt(struct scst_cmd *cmd)
+{
+	return cmd->sg_cnt;
+}
+
+/*
+ * Returns cmd's data buffer length.
+ *
+ * In case if you need to iterate over data in the buffer, usage of
+ * this function is not recommended, use scst_get_buf_*()
+ * family of functions instead.
+ */
+static inline unsigned int scst_cmd_get_bufflen(struct scst_cmd *cmd)
+{
+	return cmd->bufflen;
+}
+
+/*
+ * Returns pointer to cmd's bidirectional in (WRITE) SG data buffer.
+ *
+ * Usage of this function is not recommended, use scst_get_out_buf_*()
+ * family of functions instead.
+ */
+static inline struct scatterlist *scst_cmd_get_out_sg(struct scst_cmd *cmd)
+{
+	return cmd->out_sg;
+}
+
+/*
+ * Returns cmd's bidirectional in (WRITE) sg_cnt.
+ *
+ * Usage of this function is not recommended, use scst_get_out_buf_*()
+ * family of functions instead.
+ */
+static inline int scst_cmd_get_out_sg_cnt(struct scst_cmd *cmd)
+{
+	return cmd->out_sg_cnt;
+}
+
+void scst_restore_sg_buff(struct scst_cmd *cmd);
+
+/* Restores modified sg buffer in the original state, if necessary */
+static inline void scst_check_restore_sg_buff(struct scst_cmd *cmd)
+{
+	if (unlikely(cmd->sg_buff_modified))
+		scst_restore_sg_buff(cmd);
+}
+
+/*
+ * Returns cmd's bidirectional in (WRITE) data buffer length.
+ *
+ * In case if you need to iterate over data in the buffer, usage of
+ * this function is not recommended, use scst_get_out_buf_*()
+ * family of functions instead.
+ */
+static inline unsigned int scst_cmd_get_out_bufflen(struct scst_cmd *cmd)
+{
+	return cmd->out_bufflen;
+}
+
+/* Returns pointer to cmd's target's SG data buffer */
+static inline struct scatterlist *scst_cmd_get_tgt_sg(struct scst_cmd *cmd)
+{
+	return cmd->tgt_sg;
+}
+
+/* Returns cmd's target's sg_cnt */
+static inline int scst_cmd_get_tgt_sg_cnt(struct scst_cmd *cmd)
+{
+	return cmd->tgt_sg_cnt;
+}
+
+/* Sets cmd's target's SG data buffer */
+static inline void scst_cmd_set_tgt_sg(struct scst_cmd *cmd,
+	struct scatterlist *sg, int sg_cnt)
+{
+	cmd->tgt_sg = sg;
+	cmd->tgt_sg_cnt = sg_cnt;
+	cmd->tgt_data_buf_alloced = 1;
+}
+
+/* Returns pointer to cmd's target's OUT SG data buffer */
+static inline struct scatterlist *scst_cmd_get_out_tgt_sg(struct scst_cmd *cmd)
+{
+	return cmd->tgt_out_sg;
+}
+
+/* Returns cmd's target's OUT sg_cnt */
+static inline int scst_cmd_get_tgt_out_sg_cnt(struct scst_cmd *cmd)
+{
+	return cmd->tgt_out_sg_cnt;
+}
+
+/* Sets cmd's target's OUT SG data buffer */
+static inline void scst_cmd_set_tgt_out_sg(struct scst_cmd *cmd,
+	struct scatterlist *sg, int sg_cnt)
+{
+	WARN_ON(!cmd->tgt_data_buf_alloced);
+
+	cmd->tgt_out_sg = sg;
+	cmd->tgt_out_sg_cnt = sg_cnt;
+}
+
+/* Returns cmd's data direction */
+static inline scst_data_direction scst_cmd_get_data_direction(
+	struct scst_cmd *cmd)
+{
+	return cmd->data_direction;
+}
+
+/* Returns cmd's write len as well as write SG and sg_cnt */
+static inline int scst_cmd_get_write_fields(struct scst_cmd *cmd,
+	struct scatterlist **sg, int *sg_cnt)
+{
+	*sg = *cmd->write_sg;
+	*sg_cnt = *cmd->write_sg_cnt;
+	return cmd->write_len;
+}
+
+void scst_cmd_set_write_not_received_data_len(struct scst_cmd *cmd,
+	int not_received);
+
+bool __scst_get_resid(struct scst_cmd *cmd, int *resid, int *bidi_out_resid);
+
+/*
+ * Returns true if cmd has residual(s) and returns them in the corresponding
+ * parameters(s).
+ */
+static inline bool scst_get_resid(struct scst_cmd *cmd,
+	int *resid, int *bidi_out_resid)
+{
+	if (likely(!cmd->resid_possible))
+		return false;
+	return __scst_get_resid(cmd, resid, bidi_out_resid);
+}
+
+/* Returns cmd's status byte from host device */
+static inline uint8_t scst_cmd_get_status(struct scst_cmd *cmd)
+{
+	return cmd->status;
+}
+
+/* Returns cmd's status from host adapter itself */
+static inline uint8_t scst_cmd_get_msg_status(struct scst_cmd *cmd)
+{
+	return cmd->msg_status;
+}
+
+/* Returns cmd's status set by low-level driver to indicate its status */
+static inline uint8_t scst_cmd_get_host_status(struct scst_cmd *cmd)
+{
+	return cmd->host_status;
+}
+
+/* Returns cmd's status set by SCSI mid-level */
+static inline uint8_t scst_cmd_get_driver_status(struct scst_cmd *cmd)
+{
+	return cmd->driver_status;
+}
+
+/* Returns pointer to cmd's sense buffer */
+static inline uint8_t *scst_cmd_get_sense_buffer(struct scst_cmd *cmd)
+{
+	return cmd->sense;
+}
+
+/* Returns cmd's valid sense length */
+static inline int scst_cmd_get_sense_buffer_len(struct scst_cmd *cmd)
+{
+	return cmd->sense_valid_len;
+}
+
+/*
+ * Get/Set functions for cmd's queue_type
+ */
+static inline enum scst_cmd_queue_type scst_cmd_get_queue_type(
+	struct scst_cmd *cmd)
+{
+	return cmd->queue_type;
+}
+
+static inline void scst_cmd_set_queue_type(struct scst_cmd *cmd,
+	enum scst_cmd_queue_type queue_type)
+{
+	cmd->queue_type = queue_type;
+}
+
+/*
+ * Get/Set functions for cmd's target SN
+ */
+static inline uint64_t scst_cmd_get_tag(struct scst_cmd *cmd)
+{
+	return cmd->tag;
+}
+
+static inline void scst_cmd_set_tag(struct scst_cmd *cmd, uint64_t tag)
+{
+	cmd->tag = tag;
+}
+
+/*
+ * Get/Set functions for cmd's target private data.
+ * Variant with *_lock must be used if target driver uses
+ * scst_find_cmd() to avoid race with it, except inside scst_find_cmd()'s
+ * callback, where lock is already taken.
+ */
+static inline void *scst_cmd_get_tgt_priv(struct scst_cmd *cmd)
+{
+	return cmd->tgt_priv;
+}
+
+static inline void scst_cmd_set_tgt_priv(struct scst_cmd *cmd, void *val)
+{
+	cmd->tgt_priv = val;
+}
+
+/*
+ * Get/Set functions for tgt_need_alloc_data_buf flag
+ */
+static inline int scst_cmd_get_tgt_need_alloc_data_buf(struct scst_cmd *cmd)
+{
+	return cmd->tgt_need_alloc_data_buf;
+}
+
+static inline void scst_cmd_set_tgt_need_alloc_data_buf(struct scst_cmd *cmd)
+{
+	cmd->tgt_need_alloc_data_buf = 1;
+}
+
+/*
+ * Get/Set functions for tgt_data_buf_alloced flag
+ */
+static inline int scst_cmd_get_tgt_data_buff_alloced(struct scst_cmd *cmd)
+{
+	return cmd->tgt_data_buf_alloced;
+}
+
+static inline void scst_cmd_set_tgt_data_buff_alloced(struct scst_cmd *cmd)
+{
+	cmd->tgt_data_buf_alloced = 1;
+}
+
+/*
+ * Get/Set functions for dh_data_buf_alloced flag
+ */
+static inline int scst_cmd_get_dh_data_buff_alloced(struct scst_cmd *cmd)
+{
+	return cmd->dh_data_buf_alloced;
+}
+
+static inline void scst_cmd_set_dh_data_buff_alloced(struct scst_cmd *cmd)
+{
+	cmd->dh_data_buf_alloced = 1;
+}
+
+/*
+ * Get/Set functions for no_sgv flag
+ */
+static inline int scst_cmd_get_no_sgv(struct scst_cmd *cmd)
+{
+	return cmd->no_sgv;
+}
+
+static inline void scst_cmd_set_no_sgv(struct scst_cmd *cmd)
+{
+	cmd->no_sgv = 1;
+}
+
+/*
+ * Get/Set functions for tgt_sn
+ */
+static inline int scst_cmd_get_tgt_sn(struct scst_cmd *cmd)
+{
+	BUG_ON(!cmd->tgt_sn_set);
+	return cmd->tgt_sn;
+}
+
+static inline void scst_cmd_set_tgt_sn(struct scst_cmd *cmd, uint32_t tgt_sn)
+{
+	cmd->tgt_sn_set = 1;
+	cmd->tgt_sn = tgt_sn;
+}
+
+/*
+ * Returns 1 if the cmd was aborted, so its status is invalid and no
+ * reply shall be sent to the remote initiator. A target driver should
+ * only clear internal resources, associated with cmd.
+ */
+static inline int scst_cmd_aborted(struct scst_cmd *cmd)
+{
+	return test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags) &&
+		!test_bit(SCST_CMD_ABORTED_OTHER, &cmd->cmd_flags);
+}
+
+/* Returns sense data format for cmd's dev */
+static inline bool scst_get_cmd_dev_d_sense(struct scst_cmd *cmd)
+{
+	return (cmd->dev != NULL) ? cmd->dev->d_sense : 0;
+}
+
+/*
+ * Get/Set functions for expected data direction, transfer length
+ * and its validity flag
+ */
+static inline int scst_cmd_is_expected_set(struct scst_cmd *cmd)
+{
+	return cmd->expected_values_set;
+}
+
+static inline scst_data_direction scst_cmd_get_expected_data_direction(
+	struct scst_cmd *cmd)
+{
+	return cmd->expected_data_direction;
+}
+
+static inline int scst_cmd_get_expected_transfer_len(
+	struct scst_cmd *cmd)
+{
+	return cmd->expected_transfer_len;
+}
+
+static inline int scst_cmd_get_expected_out_transfer_len(
+	struct scst_cmd *cmd)
+{
+	return cmd->expected_out_transfer_len;
+}
+
+static inline void scst_cmd_set_expected(struct scst_cmd *cmd,
+	scst_data_direction expected_data_direction,
+	int expected_transfer_len)
+{
+	cmd->expected_data_direction = expected_data_direction;
+	cmd->expected_transfer_len = expected_transfer_len;
+	cmd->expected_values_set = 1;
+}
+
+static inline void scst_cmd_set_expected_out_transfer_len(struct scst_cmd *cmd,
+	int expected_out_transfer_len)
+{
+	WARN_ON(!cmd->expected_values_set);
+	cmd->expected_out_transfer_len = expected_out_transfer_len;
+}
+
+/*
+ * Get/clear functions for cmd's may_need_dma_sync
+ */
+static inline int scst_get_may_need_dma_sync(struct scst_cmd *cmd)
+{
+	return cmd->may_need_dma_sync;
+}
+
+static inline void scst_clear_may_need_dma_sync(struct scst_cmd *cmd)
+{
+	cmd->may_need_dma_sync = 0;
+}
+
+/*
+ * Get/set functions for cmd's delivery_status. It is one of
+ * SCST_CMD_DELIVERY_* constants. It specifies the status of the
+ * command's delivery to initiator.
+ */
+static inline int scst_get_delivery_status(struct scst_cmd *cmd)
+{
+	return cmd->delivery_status;
+}
+
+static inline void scst_set_delivery_status(struct scst_cmd *cmd,
+	int delivery_status)
+{
+	cmd->delivery_status = delivery_status;
+}
+
+static inline unsigned int scst_get_active_cmd_count(struct scst_cmd *cmd)
+{
+	if (likely(cmd->tgt_dev != NULL))
+		return atomic_read(&cmd->tgt_dev->tgt_dev_cmd_count);
+	else
+		return (unsigned int)-1;
+}
+
+/*
+ * Get/Set function for mgmt cmd's target private data
+ */
+static inline void *scst_mgmt_cmd_get_tgt_priv(struct scst_mgmt_cmd *mcmd)
+{
+	return mcmd->tgt_priv;
+}
+
+static inline void scst_mgmt_cmd_set_tgt_priv(struct scst_mgmt_cmd *mcmd,
+	void *val)
+{
+	mcmd->tgt_priv = val;
+}
+
+/* Returns mgmt cmd's completition status (SCST_MGMT_STATUS_* constants) */
+static inline int scst_mgmt_cmd_get_status(struct scst_mgmt_cmd *mcmd)
+{
+	return mcmd->status;
+}
+
+/* Returns mgmt cmd's TM fn */
+static inline int scst_mgmt_cmd_get_fn(struct scst_mgmt_cmd *mcmd)
+{
+	return mcmd->fn;
+}
+
+/*
+ * Called by dev handler's task_mgmt_fn() to notify SCST core that mcmd
+ * is going to complete asynchronously.
+ */
+void scst_prepare_async_mcmd(struct scst_mgmt_cmd *mcmd);
+
+/*
+ * Called by dev handler to notify SCST core that async. mcmd is completed
+ * with status "status".
+ */
+void scst_async_mcmd_completed(struct scst_mgmt_cmd *mcmd, int status);
+
+/* Returns AEN's fn */
+static inline int scst_aen_get_event_fn(struct scst_aen *aen)
+{
+	return aen->event_fn;
+}
+
+/* Returns AEN's session */
+static inline struct scst_session *scst_aen_get_sess(struct scst_aen *aen)
+{
+	return aen->sess;
+}
+
+/* Returns AEN's LUN */
+static inline __be64 scst_aen_get_lun(struct scst_aen *aen)
+{
+	return aen->lun;
+}
+
+/* Returns SCSI AEN's sense */
+static inline const uint8_t *scst_aen_get_sense(struct scst_aen *aen)
+{
+	return aen->aen_sense;
+}
+
+/* Returns SCSI AEN's sense length */
+static inline int scst_aen_get_sense_len(struct scst_aen *aen)
+{
+	return aen->aen_sense_len;
+}
+
+/*
+ * Get/set functions for AEN's delivery_status. It is one of
+ * SCST_AEN_RES_* constants. It specifies the status of the
+ * command's delivery to initiator.
+ */
+static inline int scst_get_aen_delivery_status(struct scst_aen *aen)
+{
+	return aen->delivery_status;
+}
+
+static inline void scst_set_aen_delivery_status(struct scst_aen *aen,
+	int status)
+{
+	aen->delivery_status = status;
+}
+
+void scst_aen_done(struct scst_aen *aen);
+
+static inline void sg_clear(struct scatterlist *sg)
+{
+	memset(sg, 0, sizeof(*sg));
+#ifdef CONFIG_DEBUG_SG
+	sg->sg_magic = SG_MAGIC;
+#endif
+}
+
+enum scst_sg_copy_dir {
+	SCST_SG_COPY_FROM_TARGET,
+	SCST_SG_COPY_TO_TARGET
+};
+
+void scst_copy_sg(struct scst_cmd *cmd, enum scst_sg_copy_dir copy_dir);
+
+/*
+ * Functions for access to the commands data (SG) buffer. Should be used
+ * instead of direct access. Returns the buffer length for success, 0 for EOD,
+ * negative error code otherwise.
+ *
+ * "Buf" argument returns the mapped buffer
+ *
+ * The "put" function unmaps the buffer.
+ */
+static inline int __scst_get_buf(struct scst_cmd *cmd, int sg_cnt,
+	uint8_t **buf)
+{
+	int res = 0;
+	struct scatterlist *sg = cmd->get_sg_buf_cur_sg_entry;
+
+	*buf = NULL;
+
+	if (cmd->get_sg_buf_entry_num >= sg_cnt)
+		goto out;
+
+	if (unlikely(sg_is_chain(sg)))
+		sg = sg_chain_ptr(sg);
+
+	*buf = page_address(sg_page(sg));
+	*buf += sg->offset;
+
+	res = sg->length;
+
+	cmd->get_sg_buf_entry_num++;
+	cmd->get_sg_buf_cur_sg_entry = ++sg;
+
+out:
+	return res;
+}
+
+static inline int scst_get_buf_first(struct scst_cmd *cmd, uint8_t **buf)
+{
+	if (unlikely(cmd->sg == NULL))
+		return 0;
+	cmd->get_sg_buf_entry_num = 0;
+	cmd->get_sg_buf_cur_sg_entry = cmd->sg;
+	cmd->may_need_dma_sync = 1;
+	return __scst_get_buf(cmd, cmd->sg_cnt, buf);
+}
+
+static inline int scst_get_buf_next(struct scst_cmd *cmd, uint8_t **buf)
+{
+	return __scst_get_buf(cmd, cmd->sg_cnt, buf);
+}
+
+static inline void scst_put_buf(struct scst_cmd *cmd, void *buf)
+{
+	/* Nothing to do */
+}
+
+static inline int scst_get_out_buf_first(struct scst_cmd *cmd, uint8_t **buf)
+{
+	if (unlikely(cmd->out_sg == NULL))
+		return 0;
+	cmd->get_sg_buf_entry_num = 0;
+	cmd->get_sg_buf_cur_sg_entry = cmd->out_sg;
+	cmd->may_need_dma_sync = 1;
+	return __scst_get_buf(cmd, cmd->out_sg_cnt, buf);
+}
+
+static inline int scst_get_out_buf_next(struct scst_cmd *cmd, uint8_t **buf)
+{
+	return __scst_get_buf(cmd, cmd->out_sg_cnt, buf);
+}
+
+static inline void scst_put_out_buf(struct scst_cmd *cmd, void *buf)
+{
+	/* Nothing to do */
+}
+
+static inline int scst_get_sg_buf_first(struct scst_cmd *cmd, uint8_t **buf,
+	struct scatterlist *sg, int sg_cnt)
+{
+	if (unlikely(sg == NULL))
+		return 0;
+	cmd->get_sg_buf_entry_num = 0;
+	cmd->get_sg_buf_cur_sg_entry = cmd->sg;
+	cmd->may_need_dma_sync = 1;
+	return __scst_get_buf(cmd, sg_cnt, buf);
+}
+
+static inline int scst_get_sg_buf_next(struct scst_cmd *cmd, uint8_t **buf,
+	struct scatterlist *sg, int sg_cnt)
+{
+	return __scst_get_buf(cmd, sg_cnt, buf);
+}
+
+static inline void scst_put_sg_buf(struct scst_cmd *cmd, void *buf,
+	struct scatterlist *sg, int sg_cnt)
+{
+	/* Nothing to do */
+}
+
+/*
+ * Returns approximate higher rounded buffers count that
+ * scst_get_buf_[first|next]() return.
+ */
+static inline int scst_get_buf_count(struct scst_cmd *cmd)
+{
+	return (cmd->sg_cnt == 0) ? 1 : cmd->sg_cnt;
+}
+
+/*
+ * Returns approximate higher rounded buffers count that
+ * scst_get_out_buf_[first|next]() return.
+ */
+static inline int scst_get_out_buf_count(struct scst_cmd *cmd)
+{
+	return (cmd->out_sg_cnt == 0) ? 1 : cmd->out_sg_cnt;
+}
+
+int scst_suspend_activity(bool interruptible);
+void scst_resume_activity(void);
+
+void scst_process_active_cmd(struct scst_cmd *cmd, bool atomic);
+
+void scst_post_parse(struct scst_cmd *cmd);
+void scst_post_alloc_data_buf(struct scst_cmd *cmd);
+
+int scst_check_local_events(struct scst_cmd *cmd);
+
+int scst_set_cmd_abnormal_done_state(struct scst_cmd *cmd);
+
+struct scst_trace_log {
+	unsigned int val;
+	const char *token;
+};
+
+extern struct mutex scst_mutex;
+
+const struct sysfs_ops *scst_sysfs_get_sysfs_ops(void);
+
+/*
+ * Returns target driver's root sysfs kobject.
+ * The driver can create own files/directories/links here.
+ */
+static inline struct kobject *scst_sysfs_get_tgtt_kobj(
+	struct scst_tgt_template *tgtt)
+{
+	return &tgtt->tgtt_kobj;
+}
+
+/*
+ * Returns target's root sysfs kobject.
+ * The driver can create own files/directories/links here.
+ */
+static inline struct kobject *scst_sysfs_get_tgt_kobj(
+	struct scst_tgt *tgt)
+{
+	return &tgt->tgt_kobj;
+}
+
+/*
+ * Returns device handler's root sysfs kobject.
+ * The driver can create own files/directories/links here.
+ */
+static inline struct kobject *scst_sysfs_get_devt_kobj(
+	struct scst_dev_type *devt)
+{
+	return &devt->devt_kobj;
+}
+
+/*
+ * Returns device's root sysfs kobject.
+ * The driver can create own files/directories/links here.
+ */
+static inline struct kobject *scst_sysfs_get_dev_kobj(
+	struct scst_device *dev)
+{
+	return &dev->dev_kobj;
+}
+
+/*
+ * Returns session's root sysfs kobject.
+ * The driver can create own files/directories/links here.
+ */
+static inline struct kobject *scst_sysfs_get_sess_kobj(
+	struct scst_session *sess)
+{
+	return &sess->sess_kobj;
+}
+
+/* Returns target name */
+static inline const char *scst_get_tgt_name(const struct scst_tgt *tgt)
+{
+	return tgt->tgt_name;
+}
+
+int scst_alloc_sense(struct scst_cmd *cmd, int atomic);
+int scst_alloc_set_sense(struct scst_cmd *cmd, int atomic,
+	const uint8_t *sense, unsigned int len);
+
+int scst_set_sense(uint8_t *buffer, int len, bool d_sense,
+	int key, int asc, int ascq);
+
+bool scst_is_ua_sense(const uint8_t *sense, int len);
+
+bool scst_analyze_sense(const uint8_t *sense, int len,
+	unsigned int valid_mask, int key, int asc, int ascq);
+
+unsigned long scst_random(void);
+
+void scst_set_resp_data_len(struct scst_cmd *cmd, int resp_data_len);
+
+void scst_get(void);
+void scst_put(void);
+
+void scst_cmd_get(struct scst_cmd *cmd);
+void scst_cmd_put(struct scst_cmd *cmd);
+
+struct scatterlist *scst_alloc(int size, gfp_t gfp_mask, int *count);
+void scst_free(struct scatterlist *sg, int count);
+
+void scst_add_thr_data(struct scst_tgt_dev *tgt_dev,
+	struct scst_thr_data_hdr *data,
+	void (*free_fn) (struct scst_thr_data_hdr *data));
+void scst_del_all_thr_data(struct scst_tgt_dev *tgt_dev);
+void scst_dev_del_all_thr_data(struct scst_device *dev);
+struct scst_thr_data_hdr *__scst_find_thr_data(struct scst_tgt_dev *tgt_dev,
+	struct task_struct *tsk);
+
+/* Finds local to the current thread data. Returns NULL, if they not found. */
+static inline struct scst_thr_data_hdr *scst_find_thr_data(
+	struct scst_tgt_dev *tgt_dev)
+{
+	return __scst_find_thr_data(tgt_dev, current);
+}
+
+/* Increase ref counter for the thread data */
+static inline void scst_thr_data_get(struct scst_thr_data_hdr *data)
+{
+	atomic_inc(&data->ref);
+}
+
+/* Decrease ref counter for the thread data */
+static inline void scst_thr_data_put(struct scst_thr_data_hdr *data)
+{
+	if (atomic_dec_and_test(&data->ref))
+		data->free_fn(data);
+}
+
+int scst_calc_block_shift(int sector_size);
+int scst_sbc_generic_parse(struct scst_cmd *cmd,
+	int (*get_block_shift)(struct scst_cmd *cmd));
+int scst_cdrom_generic_parse(struct scst_cmd *cmd,
+	int (*get_block_shift)(struct scst_cmd *cmd));
+int scst_modisk_generic_parse(struct scst_cmd *cmd,
+	int (*get_block_shift)(struct scst_cmd *cmd));
+int scst_tape_generic_parse(struct scst_cmd *cmd,
+	int (*get_block_size)(struct scst_cmd *cmd));
+int scst_changer_generic_parse(struct scst_cmd *cmd,
+	int (*nothing)(struct scst_cmd *cmd));
+int scst_processor_generic_parse(struct scst_cmd *cmd,
+	int (*nothing)(struct scst_cmd *cmd));
+int scst_raid_generic_parse(struct scst_cmd *cmd,
+	int (*nothing)(struct scst_cmd *cmd));
+
+int scst_block_generic_dev_done(struct scst_cmd *cmd,
+	void (*set_block_shift)(struct scst_cmd *cmd, int block_shift));
+int scst_tape_generic_dev_done(struct scst_cmd *cmd,
+	void (*set_block_size)(struct scst_cmd *cmd, int block_size));
+
+int scst_obtain_device_parameters(struct scst_device *dev);
+
+void scst_reassign_persistent_sess_states(struct scst_session *new_sess,
+	struct scst_session *old_sess);
+
+int scst_get_max_lun_commands(struct scst_session *sess, uint64_t lun);
+
+/*
+ * Has to be put here open coded, because Linux doesn't have equivalent, which
+ * allows exclusive wake ups of threads in LIFO order. We need it to let (yet)
+ * unneeded threads sleep and not pollute CPU cache by their stacks.
+ */
+static inline void add_wait_queue_exclusive_head(wait_queue_head_t *q,
+	wait_queue_t *wait)
+{
+	unsigned long flags;
+
+	wait->flags |= WQ_FLAG_EXCLUSIVE;
+	spin_lock_irqsave(&q->lock, flags);
+	__add_wait_queue(q, wait);
+	spin_unlock_irqrestore(&q->lock, flags);
+}
+
+/*
+ * Structure to match events to user space and replies on them
+ */
+struct scst_sysfs_user_info {
+	/* Unique cookie to identify request */
+	uint32_t info_cookie;
+
+	/* Entry in the global list */
+	struct list_head info_list_entry;
+
+	/* Set if reply from the user space is being executed */
+	unsigned int info_being_executed:1;
+
+	/* Set if this info is in the info_list */
+	unsigned int info_in_list:1;
+
+	/* Completion to wait on for the request completion */
+	struct completion info_completion;
+
+	/* Request completion status and optional data */
+	int info_status;
+	void *data;
+};
+
+int scst_sysfs_user_add_info(struct scst_sysfs_user_info **out_info);
+void scst_sysfs_user_del_info(struct scst_sysfs_user_info *info);
+struct scst_sysfs_user_info *scst_sysfs_user_get_info(uint32_t cookie);
+int scst_wait_info_completion(struct scst_sysfs_user_info *info,
+	unsigned long timeout);
+
+unsigned int scst_get_setup_id(void);
+
+/*
+ * Needed to avoid potential circular locking dependency between scst_mutex
+ * and internal sysfs locking (s_active). It could be since most sysfs entries
+ * are created and deleted under scst_mutex AND scst_mutex is taken inside
+ * sysfs functions. So, we push from the sysfs functions all the processing
+ * taking scst_mutex. To avoid deadlock, we return from them with EAGAIN
+ * if processing is taking too long. User space then should poll
+ * last_sysfs_mgmt_res until it returns the result of the processing
+ * (something other than EAGAIN).
+ */
+struct scst_sysfs_work_item {
+	struct list_head sysfs_work_list_entry;
+	struct kref sysfs_work_kref;
+	int (*sysfs_work_fn)(struct scst_sysfs_work_item *work);
+	struct completion sysfs_work_done;
+	char *buf;
+	union {
+		struct scst_dev_type *devt;
+		struct scst_tgt_template *tgtt;
+		struct {
+			struct scst_tgt *tgt;
+			struct scst_acg *acg;
+			union {
+				bool is_tgt_kobj;
+				int io_grouping_type;
+				bool enable;
+			};
+		};
+		struct {
+			struct scst_device *dev;
+			int new_threads_num;
+			enum scst_dev_type_threads_pool_type new_threads_pool_type;
+		};
+		struct scst_session *sess;
+		struct {
+			struct scst_tgt *tgt;
+			unsigned long l;
+		};
+	};
+	int work_res;
+	char *res_buf;
+};
+
+int scst_alloc_sysfs_work(int (*sysfs_work_fn)(struct scst_sysfs_work_item *),
+	struct scst_sysfs_work_item **res_work);
+int scst_sysfs_queue_wait_work(struct scst_sysfs_work_item *work);
+void scst_sysfs_work_get(struct scst_sysfs_work_item *work);
+void scst_sysfs_work_put(struct scst_sysfs_work_item *work);
+
+char *scst_get_next_lexem(char **token_str);
+void scst_restore_token_str(char *prev_lexem, char *token_str);
+char *scst_get_next_token_str(char **input_str);
+
+void scst_init_threads(struct scst_cmd_threads *cmd_threads);
+void scst_deinit_threads(struct scst_cmd_threads *cmd_threads);
+
+void scst_pass_through_cmd_done(void *data, char *sense, int result, int resid);
+int scst_scsi_exec_async(struct scst_cmd *cmd, void *data,
+	void (*done)(void *data, char *sense, int result, int resid));
+
+#endif /* __SCST_H */

--
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