/*-
* Copyright (c) 2004,2005,2006,2011 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Wasabi Systems, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _ISCSI_GLOBALS_H
#define _ISCSI_GLOBALS_H
/*
NOTE: CCBS_PER_SESSION must not exceed 256 due to the way the ITT
is constructed (it has the CCB index in its lower 8 bits). If it should ever
be necessary to increase the number beyond that (which isn't expected),
the corresponding ITT generation and extraction code must be rewritten.
*/
#define CCBS_PER_SESSION 32 /* ToDo: Reasonable number?? */
/*
NOTE: CCBS_FOR_SCSPI limits the number of outstanding commands for
SCSI commands, leaving some CCBs for keepalive and logout attempts,
which are needed for each connection.
*/
#define CCBS_FOR_SCSIPI 16 /* ToDo: Reasonable number?? */
/*
NOTE: PDUS_PER_CONNECTION is a number that could potentially impact
performance if set too low, as a single command may use up a lot of PDUs for
high values of First/MaxBurstLength and small values of
MaxRecvDataSegmentLength of the target.
*/
#define PDUS_PER_CONNECTION 64 /* ToDo: Reasonable number?? */
/* max outstanding serial nums before we give up on the connection */
#define SERNUM_BUFFER_LENGTH (CCBS_PER_SESSION / 2) /* ToDo: Reasonable?? */
/* The RecvDataSegmentLength for Target->Initiator */
#define DEFAULT_MaxRecvDataSegmentLength (64*1024)
/* Command timeout (reset on received PDU associated with the command's CCB) */
#define COMMAND_TIMEOUT (60 * hz) /* ToDo: Reasonable? (60 seconds) */
#define MAX_CCB_TIMEOUTS 3 /* Max number of tries to resend or SNACK */
#define MAX_CCB_TRIES 9 /* Max number of total tries to recover */
/* Connectionn timeout (reset on every valid received PDU) */
#define CONNECTION_TIMEOUT (2 * hz) /* ToDo: Reasonable? (2 seconds) */
#define CONNECTION_IDLE_TIMEOUT (30 * hz) /* Adjusted to Time2Retain/2 later */
#define MAX_CONN_TIMEOUTS 4 /* Max number of tries to ping a target */
/* Maximum attempts to recover connection */
#define MAX_RECOVERY_ATTEMPTS 2 /* If two attempts don't work, something */
/* probably is seriously broken */
/* PDU flags */
#define PDUF_BUSY 0x01 /* PDU is being sent, don't re-send */
#define PDUF_INQUEUE 0x02 /* PDU is in send queue */
#define PDUF_PRIORITY 0x04 /* Insert PDU at head of queue */
#define PDUF_NOUPDATE 0x10 /* Do not update PDU header/digest (test mode) */
/* CCB Flags */
#define CCBF_COMPLETE 0x0001 /* received status */
#define CCBF_RESENT 0x0002 /* ccb was resent */
#define CCBF_SENDTARGET 0x0004 /* SendTargets text request, not negotiation */
#define CCBF_GOT_RSP 0x0010 /* Got at least one response to this request */
#define CCBF_REASSIGN 0x0020 /* Command can be reassigned */
#define CCBF_OTHERCONN 0x0040 /* a logout for a different connection */
#define CCBF_WAITQUEUE 0x0080 /* CCB is on waiting queue */
/* --------------------------- Global Types ------------------------------- */
/* Connection state */
typedef enum {
ST_SEC_NEG = 0, /* security negotiation phase */
ST_SEC_FIN = 1, /* switch from SEC after mutual CHAP */
ST_OP_NEG = 2, /* operational negotiation phase */
ST_FULL_FEATURE = 3, /* full feature phase */
ST_WINDING_DOWN = 4, /* connection termination initiated, logging out */
ST_LOGOUT_SENT = 5, /* logout has been sent */
ST_SETTLING = 6, /* waiting for things to settle down */
ST_IDLE = 7 /* connection is idle (ready to delete) */
} conn_state_t;
/* Logout state */
typedef enum {
NOT_LOGGED_OUT, /* Not logged out */
LOGOUT_SENT, /* Logout was sent */
LOGOUT_SUCCESS, /* Logout succeeded */
LOGOUT_FAILED /* Logout failed */
} logout_state_t;
/* CCB Disposition */
typedef enum {
CCBDISP_UNUSED, /* 0 = In free pool */
CCBDISP_BUSY, /* This CCB is busy, don't allow rx ops */
CCBDISP_NOWAIT, /* Not waiting for anything */
CCBDISP_FREE, /* Free this CCB when done */
CCBDISP_WAIT, /* Calling thread is waiting for completion */
CCBDISP_SCSIPI, /* Call scsipi_done when operation completes */
CCBDISP_DEFER /* Defer waiting until all PDUs have been queued */
} ccb_disp_t;
/* PDU Disposition */
typedef enum {
PDUDISP_UNUSED, /* 0 = In free pool */
PDUDISP_FREE, /* Free this PDU when done */
PDUDISP_WAIT /* Waiting for acknowledge */
} pdu_disp_t;
/* Timeout state */
typedef enum {
TOUT_NONE, /* Initial */
TOUT_ARMED, /* callout is scheduled */
TOUT_QUEUED, /* put into timeout queue */
TOUT_BUSY /* cleanup thread working */
} tout_state_t;
/* the serial number management structure (a circular buffer) */
typedef struct {
uint32_t ExpSN; /* ExpxxSN (Data or Stat) sent to the target */
uint32_t next_sn; /* next_sn (== ExpSN if no ack is pending) */
int top; /* top of buffer (newest element) */
int bottom; /* bottom of buffer (oldest element) */
uint32_t sernum[SERNUM_BUFFER_LENGTH]; /* the serial numbers */
bool ack[SERNUM_BUFFER_LENGTH]; /* acknowledged? */
} sernum_buffer_t;
/*
The per-PDU data structure.
*/
struct pdu_s {
TAILQ_ENTRY(pdu_s) pdu_chain; /* freelist or wait list (or no list) */
TAILQ_ENTRY(pdu_s) pdu_send_chain;
/* chaining PDUs waiting to be sent */
pdu_disp_t pdu_disp; /* what to do with this pdu */
uint32_t pdu_flags; /* various processing flags */
pdu_header_t pdu_hdr; /* Buffer for PDU associated with cmd */
void *pdu_temp_data; /* (free after use) */
uint32_t pdu_temp_data_len; /* size of temp data */
struct uio pdu_save_uio;
/* UIO structure save for retransmits */
struct iovec pdu_save_iovec[4];
/* Header + data + data-digest + padding */
uint32_t pdu_data_digest;
/* holds data digest if enabled */
ccb_t *pdu_owner;
/* the ccb this PDU belongs to (if any) */
connection_t *pdu_connection;
/* the connection this PDU belongs to */
};
/*
The per-command data structure. Calling it ccb in correspondence
to other HA drivers.
*/
struct ccb_s {
TAILQ_ENTRY(ccb_s) ccb_chain;
/* either freelist or waiting list (or no list) */
uint32_t ccb_status; /* Status gets entered here */
ccb_disp_t ccb_disp; /* what to do with this ccb */
struct callout ccb_timeout; /* To make sure it isn't lost */
TAILQ_ENTRY(ccb_s) ccb_tchain;
tout_state_t ccb_timedout;
int ccb_num_timeouts;
/* How often we've sent out SNACK without answer */
int ccb_total_tries;
/* How often we've tried to recover */
uint32_t ccb_ITT;
/* task tag: ITT counter + sess id + CCB index */
sernum_buffer_t ccb_DataSN_buf;
/* Received Data Seq nums (read ops only) */
void *ccb_par;
/* misc. parameter for this request */
struct scsipi_xfer *ccb_xs;
/* the scsipi_xfer for this cmd */
void *ccb_temp_data;
/* to hold state (mainly during negotiation) */
void *ccb_text_data;
/* holds accumulated text for continued PDUs */
uint32_t ccb_text_len;
/* length of text data so far */
uint64_t ccb_lun; /* LUN */
uint32_t ccb_tag; /* Command tag */
uint8_t *ccb_cmd; /* SCSI command block */
uint16_t ccb_cmdlen; /* SCSI command block length */
bool ccb_data_in; /* if this is a read request */
uint8_t *ccb_data_ptr; /* data pointer for read/write */
uint32_t ccb_data_len; /* total data length */
uint32_t ccb_xfer_len; /* data transferred on read */
uint32_t ccb_residual; /* residual data size */
void *ccb_sense_ptr; /* sense data pointer */
int ccb_sense_len_req; /* requested sense data length */
int ccb_sense_len_got; /* actual sense data length */
pdu_t *ccb_pdu_waiting; /* PDU waiting to be ack'ed */
volatile uint32_t ccb_CmdSN; /* CmdSN associated with waiting PDU */
int ccb_flags;
connection_t *ccb_connection; /* connection for CCB */
session_t *ccb_session; /* session for CCB */
};
uint32_t c_terminating;
/* if closing down: status */
int c_recover; /* recovery count */
/* (reset on first successful data transfer) */
volatile unsigned c_usecount; /* number of active CCBs */
unsigned c_pducount; /* number of active PDUs */
bool c_destroy; /* conn will be destroyed */
bool c_in_session;
/* if it's linked into the session list */
logout_state_t c_loggedout;
/* status of logout (for recovery) */
struct callout c_timeout;
/* Timeout for checking if connection is dead */
TAILQ_ENTRY(connection_s) c_tchain;
tout_state_t c_timedout;
int c_num_timeouts;
/* How often we've sent out a NOP without answer */
uint32_t c_idle_timeout_val;
/* Connection timeout value when idle */
iscsi_login_parameters_t *c_login_par;
/* only valid during login */
struct session_s {
/* Interface to child drivers.
NOTE: sc_adapter MUST be the first field in this structure so we can
easily get from adapter to session.
*/
struct scsipi_adapter s_sc_adapter;
struct scsipi_channel s_sc_channel;
device_t s_child_dev;
/* the child we're associated with - (NULL if not mapped) */
int s_refcount; /* session in use by scsipi */
/* local stuff */
TAILQ_ENTRY(session_s) s_sessions; /* the list of sessions */
iscsi_login_session_type_t s_login_type; /* session type */
/* for send_targets requests */
uint8_t *s_target_list;
uint32_t s_target_list_len;
uint32_t s_conn_id; /* connection ID counter */
uint32_t s_terminating; /* if closing down: status */
uint32_t s_active_connections;
/* currently active connections */
uint32_t s_total_connections;
/* connections associated with this session (active or winding down) */
connection_list_t s_conn_list; /* the list of connections */
connection_t *s_mru_connection;
/* the most recently used connection */
ccb_t s_ccb[CCBS_PER_SESSION]; /* CCBs */
char s_tgtname[ISCSI_STRING_LENGTH + 1];
/* iSCSI target name */
};
/* /dev/iscsi0 state */
struct iscsifd {
TAILQ_ENTRY(iscsifd) fd_link;
device_t fd_dev;
int fd_unit;
};
/* ------------------------- Global Variables ----------------------------- */
/* In iscsi_main.c */
extern struct cfattach iscsi_ca; /* the device attach structure */
extern session_list_t iscsi_sessions; /* the list of sessions */
extern bool iscsi_detaching; /* signal to cleanup thread it should exit */
extern uint32_t iscsi_num_send_threads; /* the number of active send threads */