iscsi.h revision 49311b3511690f5b23558b0fba067bc8067c7a87
/*
* 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
* 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 2000 by Cisco Systems, Inc. All rights reserved.
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _ISCSI_H
#define _ISCSI_H
/*
* Block comment which describes the contents of this file.
*/
#ifdef __cplusplus
extern "C" {
#endif
#include <sys/mdi_impldefs.h>
#include <sys/iscsi_protocol.h>
#include <iscsiAuthClient.h>
#include <iscsi_stats.h>
#include <iscsi_thread.h>
#include <nvfile.h>
#ifndef MIN
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#endif
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
extern boolean_t iscsi_conn_logging;
extern boolean_t iscsi_io_logging;
extern boolean_t iscsi_login_logging;
extern boolean_t iscsi_logging;
extern boolean_t iscsi_sess_logging;
/*
* Name Format of the different Task Queues
*/
#define ISCSI_SESS_IOTH_NAME_FORMAT "io_thrd_%d.%d"
#define ISCSI_SESS_WD_NAME_FORMAT "wd_thrd_%d.%d"
#define ISCSI_SESS_LOGIN_TASKQ_NAME_FORMAT "login_taskq_%d.%d"
#define ISCSI_CONN_CN_TASKQ_NAME_FORMAT "conn_cn_taskq_%d.%d.%d"
#define ISCSI_CONN_RXTH_NAME_FORMAT "rx_thrd_%d.%d.%d"
#define ISCSI_CONN_TXTH_NAME_FORMAT "tx_thrd_%d.%d.%d"
/*
* than the value defined here. Asserts have been include in the code
* to check.
*/
#define ISCSI_MAX_IOVEC 5
#define ISCSI_DEFAULT_MAX_STORM_DELAY 32
/*
* The SNDBUF and RCVBUF size parameters for the sockets are just a
* guess for the time being (I think it is the values used by CISCO
* or UNH). Testing will have to be done to figure * out the impact
* of these values on performance.
*/
#define ISCSI_TCP_NODELAY_DEFAULT 0
#define ISCSI_TCP_CNOTIFY_THRESHOLD_DEFAULT 2000
#define ISCSI_TCP_CABORT_THRESHOLD_DEFAULT 10000
/* Default values for tunable parameters */
#define ISCSI_DEFAULT_RX_TIMEOUT_VALUE 60
#define ISCSI_DEFAULT_CONN_DEFAULT_LOGIN_MAX 180
#define ISCSI_DEFAULT_LOGIN_POLLING_DELAY 60
/*
* Convenient short hand defines
*/
#define TARGET_PROP "target"
#define LUN_PROP "lun"
#define MDI_GUID "wwn"
#define NDI_GUID "client-guid"
#define ISCSI_SIG_CMD 0x11111111
#define ISCSI_SIG_LUN 0x22222222
#define ISCSI_SIG_CONN 0x33333333
#define ISCSI_SIG_SESS 0x44444444
#define ISCSI_SIG_HBA 0x55555555
#define SENDTARGETS_DISCOVERY "SENDTARGETS_DISCOVERY"
#define ISCSI_LUN_MASK_MSB 0x00003f00
#define ISCSI_LUN_MASK_LSB 0x000000ff
/*
* Not defined by iSCSI, but used in the login code to
* determine when to send the initial Login PDU
*/
#define ISCSI_INITIAL_LOGIN_STAGE -1
typedef enum iscsi_status {
/* Success */
ISCSI_STATUS_SUCCESS = 0,
/* Driver / Kernel / Code error */
/* ITT table is already full, unable to reserve slot */
/* Login on connection failed */
/* No connections are in the LOGGED_IN state */
/* TCP Transfer Error */
/* TCP Receive Error */
/* iSCSI packet RCV timeout */
/* iSCSI Header Digest CRC error */
/* iSCSI Data Digest CRC error */
/* kmem_alloc failure */
/* cmd (tran_abort/reset) failed */
/* iSCSI protocol error */
/* iSCSI protocol version mismatch */
/* iSCSI login negotiation failed */
/* iSCSI login authentication failed */
/* iSCSI login redirection failed */
/* iSCSI uscsi status failure */
/* data received would have overflowed given buffer */
/* session/connection needs to shutdown */
/* logical unit in use */
/* Login on connection failed, retries exceeded */
/* SNA32 check value used on increment of CmdSn values */
/*
* This is the maximum number of commands that can be outstanding
* on a iSCSI session at anyone point in time.
*/
#define ISCSI_CMD_TABLE_SIZE 1024
/* Used on connections thread create of receiver thread */
extern pri_t minclsyspri;
/*
* Callers of iscsid_config_one/all must hold this
* semaphore across the calls. Otherwise a ndi_devi_enter()
* deadlock in the DDI layer may occur.
*/
extern ksema_t iscsid_config_semaphore;
extern kmutex_t iscsi_oid_mutex;
extern void *iscsi_state;
/*
* NOP delay is used to send a iSCSI NOP (ie. ping) across the
* wire to see if the target is still alive. NOPs are only
* sent when the RX thread hasn't received anything for the
* below amount of time.
*/
extern int iscsi_nop_delay;
/*
* If we haven't received anything in a specified period of time
* we will stop accepting IO via tran start. This will enable
* upper level drivers to see we might be having a problem and
* in the case of scsi_vhci will start to route IO down a better
* path.
*/
extern int iscsi_rx_window;
/*
* If we haven't received anything in a specified period of time
* we will stop accepting IO via tran start. This the max limit
* when encountered we will start returning a fatal error.
*/
extern int iscsi_rx_max_window;
/*
* During iscsi boot, if the boot session has been created, the
* initiator hasn't changed the boot lun to be online, we will wait
* 180s here for lun online by default.
*/
/*
* +--------------------------------------------------------------------+
* | iSCSI Driver Structures |
* +--------------------------------------------------------------------+
*/
/*
* iSCSI Auth Information
*/
typedef struct iscsi_auth {
int num_auth_buffers;
/*
* To indicate if bi-directional authentication is enabled.
* 0 means uni-directional authentication.
* 1 means bi-directional authentication.
*/
int bidirectional_auth;
/* Initiator's authentication information. */
char username[iscsiAuthStringMaxLength];
int password_length;
/* Target's authentication information. */
int password_length_in;
} iscsi_auth_t;
/*
* iSCSI Task
*/
typedef struct iscsi_task {
void *t_arg;
} iscsi_task_t;
/*
* These are all the iscsi_cmd types that we use to track our
* commands between queues and actions.
*/
typedef enum iscsi_cmd_type {
ISCSI_CMD_TYPE_NOP, /* nop / ping */
ISCSI_CMD_TYPE_ABORT, /* abort */
ISCSI_CMD_TYPE_RESET, /* reset */
ISCSI_CMD_TYPE_LOGOUT, /* logout */
ISCSI_CMD_TYPE_LOGIN, /* login */
ISCSI_CMD_TYPE_TEXT /* text */
/*
* iscsi_cmd_state - (reference iscsi_cmd.c for state diagram)
*/
typedef enum iscsi_cmd_state {
ISCSI_CMD_STATE_FREE = 0,
#ifdef ISCSI_CMD_SM_STRINGS
"ISCSI_CMD_STATE_FREE",
"ISCSI_CMD_STATE_PENDING",
"ISCSI_CMD_STATE_ACTIVE",
"ISCSI_CMD_STATE_ABORTING",
"ISCSI_CMD_STATE_IDM_ABORTING",
"ISCSI_CMD_STATE_COMPLETED",
"ISCSI_CMD_STATE_MAX"
};
#endif
/*
* iscsi command events
*/
typedef enum iscsi_cmd_event {
ISCSI_CMD_EVENT_E1 = 0,
#ifdef ISCSI_CMD_SM_STRINGS
"ISCSI_CMD_EVENT_E1",
"ISCSI_CMD_EVENT_E2",
"ISCSI_CMD_EVENT_E3",
"ISCSI_CMD_EVENT_E4",
"ISCSI_CMD_EVENT_E6",
"ISCSI_CMD_EVENT_E7",
"ISCSI_CMD_EVENT_E8",
"ISCSI_CMD_EVENT_E9",
"ISCSI_CMD_EVENT_E10",
"ISCSI_CMD_EVENT_MAX"
};
#endif
/*
* iscsi text command stages - these stages are used by iSCSI text
* processing to manage long resonses.
*/
typedef enum iscsi_cmd_text_stage {
/*
* iscsi cmd misc flags - bitwise applicable
*/
#define ISCSI_CMD_MISCFLAG_INTERNAL 0x1
#define ISCSI_CMD_MISCFLAG_FREE 0x2
#define ISCSI_CMD_MISCFLAG_STUCK 0x4
#define ISCSI_CMD_MISCFLAG_XARQ 0x8
#define ISCSI_CMD_MISCFLAG_SENT 0x10
#define ISCSI_CMD_MISCFLAG_FLUSH 0x20
/*
* 1/2 of a 32 bit number, used for checking CmdSN
* wrapped.
*/
#define ISCSI_CMD_SN_WRAP 0x80000000
#define ISCSI_CMD_PKT_STAT_INIT 0
/*
*/
typedef struct iscsi_cmd {
struct iscsi_conn *cmd_conn;
union {
/* ISCSI_CMD_TYPE_SCSI */
struct {
int cmdlen;
int statuslen;
/*
* If SCSI_CMD_TYPE is in ABORTING_STATE
* then the abort_icmdp field will be a pointer
* to the abort command chasing this one.
*/
struct iscsi_cmd *abort_icmdp;
/*
* pointer to the r2t associated with this
* command (if any)
*/
/*
* It will be true if this command has
* another R2T to handle.
*/
/*
* It is used to record pkt_statistics temporarily.
*/
} scsi;
/* ISCSI_CMD_TYPE_ABORT */
struct {
/* pointer to original iscsi_cmd, for abort */
} abort;
/* ISCSI_CMD_TYPE_RESET */
struct {
int level;
} reset;
/* ISCSI_CMD_TYPE_NOP */
struct {
int rsvd;
} nop;
/* ISCSI_CMD_TYPE_R2T */
struct {
} r2t;
/* ISCSI_CMD_TYPE_LOGIN */
struct {
int rvsd;
} login;
/* ISCSI_CMD_TYPE_LOGOUT */
struct {
int rsvd;
} logout;
/* ISCSI_CMD_TYPE_TEXT */
struct {
char *buf;
int buf_len;
} text;
} cmd_un;
/*
* If a data digest error is seem on a data pdu. This flag
* will get set. We don't abort the cmd immediately because
* we want to read in all the data to get it out of the
* stream. Once the completion for the cmd is received we
* we will abort the cmd and state no sense data was available.
*/
/*
* Used to block and wake up caller until action is completed.
* This is for ABORT, RESET, and PASSTHRU cmds.
*/
int cmd_result;
int cmd_completed;
} iscsi_cmd_t;
/*
* iSCSI LUN Structure
*/
typedef struct iscsi_lun {
int lun_state;
char *lun_guid; /* GUID */
int lun_guid_size; /* GUID allocation size */
char *lun_addr; /* sess,lun */
} iscsi_lun_t;
#define ISCSI_LUN_STATE_CLEAR 0 /* used to clear all states */
#define ISCSI_LUN_STATE_OFFLINE 1
#define ISCSI_LUN_STATE_ONLINE 2
#define ISCSI_LUN_CAP_RESET 0x01
#define ISCSI_SCSI_RESET_SENSE_CODE 0x29
/*
*
*
*/
typedef struct iscsi_queue {
int count;
#define ISCSI_CONN_DEFAULT_LOGIN_MIN 0
#define ISCSI_CONN_DEFAULT_LOGIN_REDIRECT 10
/* iSCSI tunable Parameters */
typedef struct iscsi_tunable_params {
int recv_login_rsp_timeout; /* range: 0 - 60*60 */
int conn_login_max; /* range: 0 - 60*60 */
int polling_login_delay; /* range: 0 - 60*60 */
typedef union iscsi_sockaddr {
struct sockaddr_in sin4;
struct sockaddr_in6 sin6;
sizeof (struct sockaddr_in) : sizeof (struct sockaddr_in6))
typedef enum {
#ifdef ISCSI_LOGIN_STATE_NAMES
"LOGIN_START",
"LOGIN_READY",
"LOGIN_TX",
"LOGIN_RX",
"LOGIN_ERROR",
"LOGIN_DONE",
"LOGIN_FFP",
"LOGIN_MAX"
};
#endif
/*
* iscsi_conn_state
*/
typedef enum iscsi_conn_state {
#ifdef ISCSI_ICS_NAMES
"ISCSI_CONN_STATE_UNDEFINED",
"ISCSI_CONN_STATE_FREE",
"ISCSI_CONN_STATE_IN_LOGIN",
"ISCSI_CONN_STATE_LOGGED_IN",
"ISCSI_CONN_STATE_IN_LOGOUT",
"ISCSI_CONN_STATE_FAILED",
"ISCSI_CONN_STATE_POLLING",
"ISCSI_CONN_STATE_MAX"
};
#endif
#define ISCSI_CONN_STATE_FULL_FEATURE(state) \
((state == ISCSI_CONN_STATE_LOGGED_IN) || \
/*
* iSCSI Connection Structure
*/
typedef struct iscsi_conn {
/* protects the session state and synchronizes the state machine */
/* base connection information, may have been redirected */
/* current connection information, may have been redirected */
int conn_current_stage; /* iSCSI login stage */
int conn_next_stage; /* iSCSI login stage */
/*
* The active queue contains iscsi_cmds that have already
* been sent on this connection. Any future responses to
* these cmds require alligence to this connection. If there
* are issues with these cmds the command may need aborted
* depending on the command type, and must be put back into
* the session's pending queue or aborted.
*/
/* lbolt from the last receive, used for nop processing */
/*
* The expstatsn is the command status sn that is expected
* next from the target. Command status is carried on a number
* of iSCSI PDUs (ex. SCSI Cmd Response, SCSI Data IN with
* S-Bit set, ...), not all PDUs. If our expstatsn is different
* than the received statsn. Something got out of sync we need to
* recover.
*/
/* active login parameters */
/* Statistics */
struct {
} stats;
/*
* These fields are used to coordinate the asynchronous IDM
* PDU operations with the synchronous login code.
*/
char *conn_login_data;
int conn_login_datalen;
/*
* login min and max identify the amount of time
* in lbolt that iscsi_start_login() should attempt
* to log into a target portal. The login will
* delay until the min lbolt has been reached and
* will end once max time has been reached. These
* values are normally set to the default but can
* are also altered by async commands received from
* the targetlogin.
*/
/* active tunable parameters */
} iscsi_conn_t;
/*
* iscsi_sess_state - (reference iscsi_sess.c for state diagram)
*/
typedef enum iscsi_sess_state {
#ifdef ISCSI_SESS_SM_STRINGS
"ISCSI_SESS_STATE_FREE",
"ISCSI_SESS_STATE_LOGGED_IN",
"ISCSI_SESS_STATE_FAILED",
"ISCSI_SESS_STATE_IN_FLUSH",
"ISCSI_SESS_STATE_FLUSHED",
"ISCSI_SESS_STATE_MAX"
};
#endif
#define ISCSI_SESS_STATE_FULL_FEATURE(state) \
((state == ISCSI_SESS_STATE_LOGGED_IN) || \
typedef enum iscsi_sess_event {
ISCSI_SESS_EVENT_N1 = 0,
#ifdef ISCSI_SESS_SM_STRINGS
"ISCSI_SESS_EVENT_N1",
"ISCSI_SESS_EVENT_N3",
"ISCSI_SESS_EVENT_N5",
"ISCSI_SESS_EVENT_N6",
"ISCSI_SESS_EVENT_N7",
"ISCSI_SESS_EVENT_MAX"
};
#endif
typedef enum iscsi_sess_type {
#define SESS_ABORT_TASK_MAX_THREADS 1
/* Sun's initiator session ID */
/*
* defines 4-5 are the reserved values. These reserved values
* are used as the ISID for an initiator-port in MP-API and used
* for the send targets discovery sessions. Byte 5 is overridden
* for full feature sessions. The default values of byte 5 for a
* full feature session is 0. When MS/T is enabled with more than
* one session this byte 5 will increment > 0 up to
* ISCSI_MAX_CONFIG_SESSIONS.
*/
#define ISCSI_SUN_ISID_4 0x00
#define ISCSI_SUN_ISID_5 0xFF
#define ISCSI_DEFAULT_SESS_BOUND B_FALSE
#define ISCSI_DEFAULT_SESS_NUM 1
/*
* iSCSI Session(Target) Structure
*/
typedef struct iscsi_sess {
/* protects the session state and synchronizes the state machine */
/*
* Associated target OID.
*/
/*
* Session OID. Used by IMA, interfaces and exported as
* TARGET_PROP which is checked by the NDI. In addition
* this is used in our tran_lun_init function.
*/
struct iscsi_sess *sess_next;
/* list of all luns relating to session */
struct iscsi_lun *sess_lun_list;
/* list of all connections relating to session */
struct iscsi_conn *sess_conn_list;
struct iscsi_conn *sess_conn_list_last_ptr;
/* pointer to active connection in session */
struct iscsi_conn *sess_conn_act;
/* Connection ID for next connection to be added to session */
/*
* last time any connection on this session received
* data from the target.
*/
int sess_storm_delay;
/*
* Cmdsn isn't that big of a problem yet since we only have
* one connection but in the future we will need to ensure
* this locking is working so keep the sequence numbers in
* sync on the wire.
*
* We also use this lock to protect the ITT table and it's
* values. We need to make sure someone doesn't assign
* a duplicate ITT value or cell to a command. Also we
* need to make sure when someone is looking up an ITT
* that the command is still in that correct queue location.
*/
/*
* iSCSI command sequencing / windowing. The next
* command to be sent via the pending queue will
* get the sess_cmdsn. If the maxcmdsn is less
* than the next cmdsn then the iSCSI window is
* closed and this command cannot be sent yet.
* Most iscsi cmd responses from the target carry
* a new maxcmdsn. If this new maxcmdsn is greater
* than the sess_maxcmdsn we will update it's value
* and set a timer to fire in one tick and reprocess
* the pending queue.
*
* The expcmdsn. Is the value the target expects
* to be sent for my next cmdsn. If the expcmdsn
* and the cmdsn get out of sync this could denote
* a communication problem.
*/
/* Next Initiator Task Tag (ITT) to use */
/*
* The session iscsi_cmd table is used to a fast performance
* lookup of an ITT to a iscsi_cmd when we receive an iSCSI
* PDU from the wire. To reserve a location in the sess_cmd_table
* we try the sess_itt % ISCSI_CMD_TABLE_SIZE if this cmd table
* cell is already full. Then increament the sess_itt and
* try to get the cell position again, repeat until an empty
* cell is found. Once an empty cell is found place your
* scsi_cmd point into the cell to reserve the location. This
* selection process should be done while holding the session's
* mutex.
*/
int sess_cmd_table_count;
/*
* The pending queue contains all iscsi_cmds that require an
* open MaxCmdSn window to be put on the wire and haven't
* been placed on the wire. Once placed on the wire they
* will be moved to a connections specific active queue.
*/
/* configured login parameters */
int sess_name_length;
char sess_alias[ISCSI_MAX_NAME_LEN];
int sess_alias_length;
/*
* If the target portal group tag(TPGT) is equal to ISCSI_DEFAULT_TPGT
* then the initiator will accept a successful login with any TPGT
* specified by the target. If a none default TPGT is configured
* then we will only successfully accept a login with that matching
* TPGT value.
*/
int sess_tpgt_conf;
/* This field records the negotiated TPGT value, preserved for dtrace */
int sess_tpgt_nego;
/*
* Authentication information.
*
* DCW: Again IMA seems to take a session view at this
* information.
*/
/* Statistics */
struct {
} stats;
} iscsi_sess_t;
/*
* This structure will be used to store sessions to be online
* during normal login operation.
*/
typedef struct iscsi_sess_list {
struct iscsi_sess_list *next;
/*
* iSCSI client notify task context for deferred IDM notifications processing
*/
typedef struct iscsi_cn_task {
/*
* iscsi_network
*/
typedef struct iscsi_network {
int (*listen)(void *, int);
int (*getsockopt)(void *, int, int, void *, int *, int);
int (*setsockopt)(void *, int, int, void *, int);
int (*shutdown)(void *, int);
void (*close)(void *);
int, int, int);
struct {
int sndbuf;
int rcvbuf;
int nodelay;
int conn_abort_threshold;
int abort_threshold;
} tweaks;
#define ISCSI_NET_HEADER_DIGEST 0x00000001
#define ISCSI_NET_DATA_DIGEST 0x00000002
extern iscsi_network_t *iscsi_net;
/*
* If we get bus_config requests in less than 5 seconds
* apart skip the name services re-discovery and just
* complete the requested logins. This protects against
* bus_config storms from stale /dev links.
*/
#define ISCSI_CONFIG_STORM_DELAY_DEFAULT 5
/*
* iSCSI HBA Structure
*/
typedef struct iscsi_hba {
/* lbolt of the last time we received a config request */
/* current number of seconds to protect against bus config storms */
int hba_name_length;
int hba_alias_length;
/* Default SessionID for HBA */
/* Default HBA wide settings */
/*
* There's only one HBA and it's set to ISCSI_INITIATOR_OID
* (value of 1) at the beginning of time.
*/
/*
* Keep track of which events have been sent. User daemons request
* this information so they don't wait for events which they won't
* see.
*/
/* if the persistent store is loaded */
/*
* Ensures only one SendTargets operation occurs at a time
*/
/*
* Statistics
*/
struct {
} stats;
/*
*
* service- service online ensures the operational of cli
* - so obviously offline means the unusable of cli
* - , disabling of all discovery methods and to offline
* - all discovered devices
*
* client - here the client actually means 'exclusive client'
* - for operations these clients take may conflict
* - with the changing of service status and therefore
* - need to be exclusive
*
* The service has three status:
* ISCSI_SERVICE_ENABLED - client is permitted to
* - request service
*
* ISCSI_SERVICE_DISABLED - client is not permitted to
* - request service
*
* ISCSI_SERVICE_TRANSITION - client must wait for
* - one of above two statuses
*
* The hba_service_client_count tracks the number of
* current clients, it increases with new clients and decreases
* with leaving clients. It stops to increase once the
* ISCSI_SERVICE_TRANSITION is set, and causes later clients be
* blocked there.
*
* The status of the service can only be changed when the number
* of current clients reaches zero.
*
* Clients include:
* iscsi_ioctl
* iscsi_tran_bus_config
* iscsi_tran_bus_unconfig
* isns_scn_callback
*/
/* Default HBA tunable settings */
} iscsi_hba_t;
/*
* +--------------------------------------------------------------------+
* | iSCSI prototypes |
* +--------------------------------------------------------------------+
*/
/* IDM client callback entry points */
/* iscsi_io.c */
void iscsi_handle_abort(void *arg);
iscsi_lun_t *ilp);
/* iscsi_crc.c */
/* iscsi_queue.c */
iscsi_cmd_t *);
/* iscsi_login.c */
/* iscsi_stats.c */
/* iscsi_net.c */
void iscsi_net_init();
void iscsi_net_fini();
/* iscsi_sess.c */
void iscsi_sess_online(void *arg);
iscsi_sess_t **ispp);
/* iscsi_conn.c */
iscsi_conn_t **icpp);
/* iscsi_lun.c */
iscsi_lun_t *ilp);
iscsi_lun_t *ilp);
/* iscsi_cmd.c */
/* iscsi_ioctl.c */
/* ioctls prototypes */
/* iscsid.c */
void iscsid_fini();
void isns_scn_callback(void *arg);
/*
* Here we need a contract for inet_ntop() and inet_pton()
* in uts/common/inet/ip/inet_ntop.c
*/
#ifdef __cplusplus
}
#endif
#endif /* _ISCSI_H */