OpenSolaris_b135/cmd/iscsi/iscsitgtd/t10.h

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */

/*
 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#ifndef _T10_H
#define	_T10_H

/*
 * This header file describes the service level between the transport
 * layer and the emulation portion. These procedure calls can be thought
 * of as part of the T10 SAM-3 specification.
 */

#ifdef __cplusplus
extern "C" {
#endif

/*
 * Here are the header files which are required to define references found
 * in this file. No other header files are to be included.
 */
#include <pthread.h>
#include <sys/avl.h>
#include <signal.h>
#include <sys/scsi/generic/sense.h>

#include "queue.h"

#ifdef lint
/*
 * lints sees aio_return64, but can't find it in the aio structure. To keep
 * lint happy this define is used.
 */
#define	aio_return64 aio_return
#endif

typedef void *transport_t;
typedef void *t10_targ_handle_t;

typedef void *t10_lun_handle_t;

typedef void *emul_handle_t;
typedef void *emul_cmd_t;

typedef	enum {
	ClearSet,
	ResetTarget,
	ResetLun,
	InventoryChange,
	CapacityChange,
	DeviceOnline,
	DeviceOffline
} TaskOp_t;

/*
 * For an explanation of the t10_cmd_state_t and t10_cmd_event_t
 * see t10_sam.c:t10_cmd_state_machine()
 */
typedef enum {
	T10_Cmd_S1_Free		= 1,
	T10_Cmd_S2_In,
	T10_Cmd_S3_Trans,
	T10_Cmd_S4_AIO,
	T10_Cmd_S5_Wait,
	T10_Cmd_S6_Freeing_In,
	T10_Cmd_S7_Freeing_AIO
} t10_cmd_state_t;

typedef enum {
	T10_Cmd_T1		= 1,
	T10_Cmd_T2,
	T10_Cmd_T3,
	T10_Cmd_T4,
	T10_Cmd_T5,
	T10_Cmd_T6,		/* cancel */
	T10_Cmd_T7,
	T10_Cmd_T8		/* shutdown */
} t10_cmd_event_t;

typedef enum {
	lu_online,
	lu_offline,
	lu_errored
} t10_lu_state_t;

/*
 * The t10_cmd_t structure bridges the gap between the transport and
 * emulation services. At certain times either the transport or emulation
 * service needs to access the data stored within this structure.
 * For now we'll just use macros which hide the reference, but in the
 * future when the transport and emulation services are loadable modules
 * these macros will become functions so that the structure can change
 * inside of the T10 space and not cause compatibility issues.
 */
#define	T10_MAX_OUT(cmd)	(cmd->c_lu->l_targ->s_maxout)
#define	T10_MMAP_AREA(cmd)	(cmd->c_lu->l_common->l_mmap)
#define	T10_PARAMS_AREA(cmd)	trans_params_area(cmd)
#define	T10_TRANS_ID(cmd)	(cmd->c_trans_id)
#define	T10_DATA(cmd)		(cmd->c_data)
#define	T10_DATA_LEN(cmd)	(cmd->c_data_len)
#define	T10_DATA_OFFSET(cmd)	(cmd->c_offset)
#define	T10_CMD_LAST(cmd)	(cmd->c_last)
#define	T10_CMD_STATUS(cmd)	(cmd->c_cmd_status)
#define	T10_CMD_RESID(cmd)	(cmd->c_resid)
#define	T10_SENSE_LEN(cmd)	(cmd->c_cmd_sense_len)
#define	T10_SENSE_DATA(cmd)	(cmd->c_cmd_sense)
#define	T10_PGR_TNAME(cmd)	(cmd->c_lu->l_targ->s_targ_base)
#define	T10_PGR_INAME(cmd)	(cmd->c_lu->l_targ->s_i_name)

#define	T10_DEFAULT_TPG	1

/*
 * []------------------------------------------------------------------[]
 * | SAM-3 revision 14, section 4.9 -- Logical Unit Numbers		|
 * | The specification allows for 64-bit LUNs, but at this point	|
 * | most OSes don't support that many. Section 4.9.7, table 9 gives	|
 * | the Flat Space Addressing Method which allows for 16,383 LUNs.	|
 * | This will be the imposed maximum even though the code can support	|
 * | more. Raise this number if needed.					|
 * []------------------------------------------------------------------[]
 */
#define	T10_MAX_LUNS	16383

/*
 * SPC-3 Revision 21c, Section 6.4.2 Table 85
 * Version Descriptor Values
 */
#define	T10_TRANS_ISCSI		0x960 /* iSCSI (no version claimed) */
#define	T10_TRANS_FC		0x8c0 /* FCP (no version claimed) */

typedef struct t10_aio {
	/*
	 * This must be the first member of the structure. aioread/aiowrite
	 * take as one of the arguments an pointer to a aio_result_t
	 * structure. When the operation is complete the aio_return and
	 * aio_errno of that structure are updated. When aiowait() is
	 * called the address of that aio_result_t is returned. By having
	 * this structure at the beginning we can pass in the data_ptr
	 * structure address. The ste_aio_process thread will get everything
	 * it needs from the aiowait to send a message to the correct
	 * STE thread. Clear as mud?
	 */
	aio_result_t	a_aio;

	void		(*a_aio_cmplt)(emul_cmd_t id);
	emul_cmd_t	a_id;
	struct t10_cmd	*a_cmd;
} t10_aio_t;

/*
 * Bidirectional structure used to track requests from the transport
 * and send reponse data from the emulation.
 *
 * The glue logic for t10_send_cmd will allocate this structure, fill in
 * in with the provided data and put it on the LUN queue. The LUN thread
 * will dequeue this request and call the appropriate LUN command interpreter.
 */
typedef struct t10_cmd {
	/*
	 * Transport specific tracking value. If this value is non-zero it
	 * means this command was part of a previous command that wasn't
	 * completed. Currently this is only used for DATA_OUT (SCSI write op)
	 * commands.
	 */
	transport_t		c_trans_id;

	t10_cmd_state_t		c_state;

	/*
	 * Emulation specific tracking value.
	 */
	emul_cmd_t		c_emul_id;

	/*
	 * Per I_T_L structure used to determine which command
	 * interpreter to call and which transport queue to send the response.
	 */
	struct t10_lu_impl	*c_lu;

	/*
	 * Pointer to command buffer. No interpretation of data is
	 * done by the glue logic. Interpretation is done by the LUN
	 * emulation code.
	 */
	uint8_t			*c_cdb;
	size_t			c_cdb_len;

	/*
	 * Optional offset into the command. If more than one response
	 * is required this value indicates where the data belongs.
	 */
	off_t			c_offset;

	/*
	 * Data for transfer.
	 */
	char			*c_data;
	size_t			c_data_len;
	size_t			c_resid;

	/*
	 * Indicates if this response is the last to be sent
	 * and will be followed closely by a complete message. Enables
	 * transports to phase collapse the final READ data PDU with
	 * completion PDU if possible.
	 */
	Boolean_t		c_last;

	/*
	 * When the transport is finished sending the data it will
	 * call t10_cmd_destroy() which will cause the SAM-3 layer to
	 * call the emulation function stored here with this command
	 * pointer. The emulation code is responsible for freeing any
	 * memory it allocated.
	 */
	void			(*c_emul_complete)(emul_handle_t id);

	/*
	 * During transitions from T10 layer to transport one of three
	 * messages are sent. The state machine needs access to these
	 * values to pass things along so we keep it here.
	 */
	msg_type_t		c_msg;

	/*
	 * SCSI sense information.
	 */
	int			c_cmd_status;
	char			*c_cmd_sense;
	size_t			c_cmd_sense_len;

	/*
	 * List of active commands at the ITL level.
	 */
	avl_tree_t		c_cmd_avl;

	struct t10_cmd		*c_cmd_next;
} t10_cmd_t;

/*
 * Each LU has a structure which contains common data for all I_T's who
 * access this LU.
 */
typedef struct t10_lu_common {
	/*
	 * Logic Unit Number
	 */
	int			l_num;

	/*
	 * state of device
	 */
	t10_lu_state_t		l_state;

	/*
	 * Internal ID which will be unique for all LUs. This will be
	 * used for log messages to help tracking details.
	 */
	int			l_internal_num;

	/*
	 * Thread ID which is running this logical unit. This is currently
	 * used for only one purpose which is to locate this structure
	 * in case of a SIGBUS. It's possible for the underlying file system
	 * to run out of space for an mmap'd LU. The only means of notification
	 * the OS has is to send a SIGBUS. The thread only receives the memory
	 * address, so we look for our thread ID amongst all of the LU
	 * available.
	 */
	pthread_t		l_thr_id;

	/*
	 * If we receive a SIGBUS the initiator needs to be notified that
	 * something bad has occurred. This means we need to know which
	 * command was being emulated so that we can find the appropriate
	 * transport.
	 * Special handling needs to be done if the thread is initializing
	 * the LU so we need a flag to indicate that fact.
	 */
	t10_cmd_t		*l_curr;
	Boolean_t		l_curr_provo;

	/*
	 * The implementation uses a 16 byte EUI value for the GUID.
	 * Not only is this value used for SCSI INQUIRY data, but it
	 * is used to distinquish this common LUN from other LUNs in
	 * the AVL tree.
	 */
	uint8_t			*l_guid;
	size_t			l_guid_len;

	/*
	 * Other common information which is needed for ever device
	 * type.
	 */
	int			l_dtype;
	char			*l_pid,
				*l_vid;

	/*
	 * Each dtype has different parameters that it uses. This
	 * is a place holder for storing a pointer to some structure which
	 * contains that information.
	 */
	void			*l_dtype_params;

	/*
	 * Parameter information in XML format.
	 */
	tgt_node_t		*l_root;
	Boolean_t		l_root_okay_to_free;

	/*
	 * File descriptor for the open file which is the backing store
	 * for this device. This can be a regular file or a character
	 * special device if we're acting as a bridge between transports.
	 */
	int			l_fd;

	void			*l_mmap;
	off64_t			l_size;

	Boolean_t		l_fast_write_ack;

	/*
	 * AVL tree containing all I_T_L nexus' which are actively using
	 * this LUN.
	 */
	avl_tree_t		l_all_open;

	/*
	 * Each I_T will place requests for command emulation on this
	 * queue. Common requests are msg_ste_cmd and msg_ste_shutdown
	 */
	target_queue_t		*l_from_transports;

	/*
	 * Mutex used to lock access to the AVL tree.
	 */
	pthread_mutex_t		l_common_mutex;

	/*
	 * When a target is looking to see if an existing LUN is opened
	 * a search of all LUNs needs to be done and will use this
	 * AVL node. This field is modified only by the AVL code.
	 */
	avl_node_t		l_all_luns;
} t10_lu_common_t;

/*
 * Each I_T_L has a LU structure associated with it.
 */
typedef struct t10_lu_impl {
	/*
	 * pointer to common area of LUN.
	 */
	t10_lu_common_t		*l_common;
	pthread_mutex_t		l_mutex;

	/*
	 * Mutex to protect access to active commands
	 */
	pthread_mutex_t		l_cmd_mutex;
	pthread_cond_t		l_cmd_cond;
	Boolean_t		l_wait_for_drain;

	avl_tree_t		l_cmds;

	/*
	 * Queue for sending command results and R2T results back
	 * to the transport.
	 */
	target_queue_t		*l_to_transport;

	/*
	 * Back pointer to target structure who created this LUN reference.
	 */
	struct t10_targ_impl	*l_targ;

	struct scsi_cmd_table	*l_cmd_table;

	/*
	 * Per LU methods for issuing commands and data to the
	 * DTYPE emulator.
	 */
	void			(*l_cmd)(t10_cmd_t *cmd, uint8_t *cdb,
	    size_t cdb_len);
	void			(*l_data)(t10_cmd_t *cmd, emul_handle_t e,
	    size_t offset, char *data, size_t data_len);

	/*
	 * AVL node information for all other I_T nexus' who are referencing
	 * this LUN. This is used by the AVL code and *not* modified by
	 * this daemon directly.
	 */
	avl_node_t		l_open_lu_node;

	/*
	 * AVL node information for all LUN's being access by this I_T nexus.
	 * This is used by the AVL code and *not* modified by this daemon
	 * directly.
	 */
	avl_node_t		l_open_targ_node;

	/*
	 * Logical Unit Number. This value is used as the comparision value
	 * for the AVL search at the per target level.
	 */
	int			l_targ_lun;

	Boolean_t		l_dsense_enabled;
	Boolean_t		l_pgr_read;

	/*
	 * Statistics on a per ITL basis
	 */
	uint64_t		l_cmds_read,
				l_cmds_write,
				l_sects_read,
				l_sects_write;

	/*
	 * Each time a command is run the value of l_status is checked.
	 * If non-zero the command isn't executed and instead a transport
	 * complete message is sent with these values. This is commonly
	 * used to send UNIT ATTENTION for things like power on.
	 * -- Do we need some sort of stack to push and pop these values?
	 */
	int			l_status,
				l_asc,
				l_ascq;
} t10_lu_impl_t;

typedef struct t10_targ_impl {
	char			*s_i_name;
	char			*s_targ_base;
	int			s_targ_num; /* used in log messages */
	avl_tree_t		s_open_lu;
	pthread_mutex_t		s_mutex;

	/*
	 * The transport layer will set the maximum output size
	 * it's able to deal with during a call to set_create_handle()
	 */
	size_t			s_maxout;

	/*
	 * Target Port Set
	 */
	int			s_tpgt;

	/*
	 * transport version number to use in standard inquiry data
	 */
	int			s_trans_vers;

	/*
	 * Transport response queue. This queue will be stored in each
	 * lun that gets created.
	 */
	target_queue_t		*s_to_transport;

	/*
	 * During a SCSI WRITE the emulation will call trans_rqst_datain.
	 * If the transport indicated data was available by using non-zero
	 * values for the optional data and length when t10_send_cmd was
	 * called this callback is used when the emulation requests data.
	 */
	void		(*s_dataout_cb)(t10_cmd_t *, char *data,
	    size_t *data_len);

} t10_targ_impl_t;

typedef struct t10_shutdown {
	t10_lu_impl_t	*t_lu;
	target_queue_t	*t_q;
} t10_shutdown_t;

typedef struct scsi_cmd_table {
	void	(*cmd_start)(struct t10_cmd *, uint8_t *, size_t);
	void	(*cmd_data)(struct t10_cmd *, emul_handle_t e,
			    size_t offset, char *data, size_t data_len);
	void	(*cmd_end)(emul_handle_t e);
	char	*cmd_name;
} scsi_cmd_table_t;

typedef struct sam_device_table {
	Boolean_t	(*t_common_init)(t10_lu_common_t *);
	void		(*t_common_fini)(t10_lu_common_t *);
	void		(*t_per_init)(t10_lu_impl_t *);
	void		(*t_per_fini)(t10_lu_impl_t *);
	void		(*t_task_mgmt)(t10_lu_common_t *, TaskOp_t);
	char		*t_type_name;
} sam_device_table_t;

typedef struct t10_conn_shutdown {
	target_queue_t *t10_to_conn_q;
	target_queue_t *conn_to_t10_q;
} t10_conn_shutdown_t;

/*
 * []----
 * | Interfaces
 * []----
 */

extern target_queue_t *mgmtq;
void t10_init(target_queue_t *q);
void lu_buserr_handler(int sig, siginfo_t *sip, void *v);

/*
 * []------------------------------------------------------------------[]
 * | Methods called by the transports					|
 * []------------------------------------------------------------------[]
 */
/*
 * t10_handle_create -- create target handle to be used by transports
 */
t10_targ_handle_t
t10_handle_create(char *targ, char *init, int trans_vers, int tpg, int max_out,
    target_queue_t *tq, void (*datain_cb)(t10_cmd_t *, char *, size_t *));

/*
 * t10_handle_disable -- drains commands from emulation queues
 */
void
t10_handle_disable(t10_targ_handle_t t);

/*
 * t10_handle_destroy -- free resources used by handle
 */
int
t10_handle_destroy(t10_targ_handle_t t, Boolean_t wait);

Boolean_t
t10_cmd_create(t10_targ_handle_t t, int lun_number, uint8_t *cdb,
    size_t cdb_len, transport_t trans_id, t10_cmd_t **);

/*
 * t10_send_cmd -- send a command block to an target/LUN for emulation
 */
Boolean_t
t10_cmd_send(t10_targ_handle_t t, t10_cmd_t *cmd,
    char *opt_data, size_t opt_data_len);

Boolean_t
t10_cmd_data(t10_targ_handle_t t, t10_cmd_t *cmd, size_t offset,
    char *data, size_t data_len);

void
t10_cmd_done(t10_cmd_t *cmd);

Boolean_t
t10_task_mgmt(t10_targ_handle_t t, TaskOp_t op, int opt_lun, void *tag);

/*
 * t10_cmd_shoot_event -- perform transition to the  state of a T10 command
 */
void t10_cmd_shoot_event(t10_cmd_t *c, t10_cmd_event_t e);

void t10_targ_stat(t10_targ_handle_t t, char **buf);

/*
 * t10_thick_provision -- management function used when creating a new lun
 */
Boolean_t t10_thick_provision(char *target, int lun, target_queue_t *q);

/*
 * []------------------------------------------------------------------[]
 * | Methods called by the emulation routines				|
 * []------------------------------------------------------------------[]
 */

t10_cmd_t *trans_cmd_dup(t10_cmd_t *cmd);

/*
 * trans_send_datain -- Emulation layer sending data to initiator
 */
Boolean_t trans_send_datain(t10_cmd_t *cmd, char *data, size_t data_len,
    size_t offset, void (*callback)(emul_handle_t t), Boolean_t last,
    emul_handle_t id);

/*
 * trans_rqst_dataout -- Emulation needs more data to complete request
 */
Boolean_t trans_rqst_dataout(t10_cmd_t *cmd, char *data, size_t data_len,
    size_t offset, emul_cmd_t emul_id, void (*callback)(emul_handle_t e));

/*
 * trans_send_complete -- Emulation has completed request w/ opt. sense data
 */
void trans_send_complete(t10_cmd_t *cmd, int t10_status);

/*
 * trans_aiowrite -- asynchronous write and kicks the aio wait thread
 */
void trans_aiowrite(t10_cmd_t *cmd, char *data, size_t data_len, off_t offset,
    t10_aio_t *taio);

/*
 * trans_aioread -- asynchronous read and kicks the aio wait thread
 */
void trans_aioread(t10_cmd_t *cmd, char *data, size_t data_len, off_t offset,
    t10_aio_t *taio);

/*
 * trans_params_area -- given a t10_cmd return the dtype params
 */
void *trans_params_area(t10_cmd_t *cmd);

/*
 * []------------------------------------------------------------------[]
 * | Declaration of emulation entry points				|
 * []------------------------------------------------------------------[]
 */
Boolean_t sbc_common_init(t10_lu_common_t *lu);
void sbc_common_fini(t10_lu_common_t *lu);
void sbc_task_mgmt(t10_lu_common_t *lu, TaskOp_t op);
void sbc_per_init(t10_lu_impl_t *itl);
void sbc_per_fini(t10_lu_impl_t *itl);
Boolean_t ssc_common_init(t10_lu_common_t *lu);
void ssc_common_fini(t10_lu_common_t *lu);
void ssc_task_mgmt(t10_lu_common_t *lu, TaskOp_t op);
void ssc_per_init(t10_lu_impl_t *itl);
void ssc_per_fini(t10_lu_impl_t *itl);
Boolean_t raw_common_init(t10_lu_common_t *lu);
void raw_common_fini(t10_lu_common_t *lu);
void raw_per_init(t10_lu_impl_t *itl);
void raw_per_fini(t10_lu_impl_t *itl);
void raw_task_mgmt(t10_lu_common_t *lu, TaskOp_t op);
Boolean_t osd_common_init(t10_lu_common_t *lu);
void osd_common_fini(t10_lu_common_t *lu);
void osd_per_init(t10_lu_impl_t *itl);
void osd_per_fini(t10_lu_impl_t *itl);
void osd_task_mgmt(t10_lu_common_t *lu, TaskOp_t op);

#ifdef __cplusplus
}
#endif

#endif /* _T10_H */