t10.h revision 36c5fee33fa8b822175d410202aebcf592c8d342
/*
* 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 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _T10_H
#define _T10_H
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* 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;
typedef enum {
T10_Cmd_Free = 1,
T10_Cmd_Alloc,
T10_Cmd_DataIn,
T10_Cmd_DataOut,
T10_Cmd_DataOut_Sent,
T10_Cmd_Complete,
T10_Cmd_Canceled,
T10_Cmd_Errored
} t10_cmd_state_t;
typedef enum {
T10_Cmd_Event_DataOut_Sent,
T10_Cmd_Event_DataIn_Recv,
T10_Cmd_Event_Release,
T10_Cmd_Event_Canceled
} 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_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;
} 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);
/*
* 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;
} 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.
*/
xml_node_t *l_root;
/*
* 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_Q 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_Q 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;
/*
* 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_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_tp_grp;
/*
* 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;
/*
* []----
* | 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_name, int trans_version, int tpg, int max_out,
target_queue_t *transq, 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
*/
void
t10_handle_destroy(t10_targ_handle_t t);
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);
Boolean_t
t10_task_mgmt(t10_targ_handle_t t, TaskOp_t op, int opt_lun, void *tag);
/*
* t10_cmd_state -- issue an event to change the state of a T10 layer command
*/
void t10_cmd_state(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 |
* []------------------------------------------------------------------[]
*/
/*
* 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);
/*
* 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,
aio_result_t *aiop);
/*
* 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,
aio_result_t *aiop);
/*
* 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_init_common(t10_lu_common_t *lu);
void sbc_fini_common(t10_lu_common_t *lu);
void sbc_task_mgmt(t10_lu_common_t *lu, TaskOp_t op);
void sbc_init_per(t10_lu_impl_t *itl);
void sbc_fini_per(t10_lu_impl_t *itl);
Boolean_t ssc_init_common(t10_lu_common_t *lu);
void ssc_fini_common(t10_lu_common_t *lu);
void ssc_task_mgmt(t10_lu_common_t *lu, TaskOp_t op);
void ssc_init_per(t10_lu_impl_t *itl);
void ssc_fini_per(t10_lu_impl_t *itl);
Boolean_t raw_init_common(t10_lu_common_t *lu);
void raw_fini_common(t10_lu_common_t *lu);
void raw_init_per(t10_lu_impl_t *itl);
void raw_fini_per(t10_lu_impl_t *itl);
Boolean_t osd_init_common(t10_lu_common_t *lu);
void osd_fini_common(t10_lu_common_t *lu);
void osd_init_per(t10_lu_impl_t *itl);
void osd_fini_per(t10_lu_impl_t *itl);
#ifdef __cplusplus
}
#endif
#endif /* _T10_H */