1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at src/sun_nws/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at src/sun_nws/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 #ifndef _IDM_IMPL_H_
  26 #define _IDM_IMPL_H_
  27 
  28 #pragma ident   "@(#)idm_impl.h 1.18    08/03/26 SMI"
  29 
  30 #ifdef  __cplusplus
  31 extern "C" {
  32 #endif
  33 
  34 #include <sys/avl.h>
  35 
  36 typedef struct {
  37         kmutex_t        idm_global_mutex;
  38         taskq_t         *idm_global_taskq;
  39         list_t          idm_tgt_svc_list;
  40         list_t          idm_ini_conn_list;
  41 } idm_global_t;
  42 
  43 #define CF_LOGIN_READY          0x00000001
  44 #define CF_INITIAL_LOGIN        0x00000002
  45 #define CF_ERROR                0x80000000
  46 
  47 typedef enum {
  48         CONN_TYPE_INI = 1,
  49         CONN_TYPE_TGT
  50 } idm_conn_type_t;
  51 
  52 typedef union idm_sockaddr {
  53         struct sockaddr         sin;
  54         struct sockaddr_in      sin4;
  55         struct sockaddr_in6     sin6;
  56 } idm_sockaddr_t;
  57 
  58 /*
  59  * connection parameters - These parameters would be populated at
  60  * connection create, or during key-value negotiation at login
  61  */
  62 typedef struct idm_conn_params_s {
  63         uint32_t                max_dataseglen;
  64 } idm_conn_param_t;
  65 
  66 typedef struct idm_svc_s {
  67         list_node_t             is_list_node;
  68         kmutex_t                is_mutex;
  69         kcondvar_t              is_cv;
  70         kmutex_t                is_count_mutex;
  71         kcondvar_t              is_count_cv;
  72         /* transport-specific service components */
  73         void                    *is_so_svc;
  74         /* JBDB - iser_svc_t will go here */
  75         idm_conn_ops_t          is_conn_ops;
  76         list_t                  is_conn_list;   /* Locked by is_mutex */
  77         int                     is_conn_count;  /* Locked by is_count_mutex */
  78         uint16_t                is_port;
  79 } idm_svc_t;
  80 
  81 typedef struct idm_conn_s {
  82         list_node_t             ic_list_node;
  83         void                    *ic_handle;
  84         struct idm_svc_s        *ic_svc_binding; /* Target conn. only */
  85         idm_sockaddr_t          ic_ini_dst_addr;
  86         idm_conn_state_t        ic_state;
  87         idm_conn_state_t        ic_last_state;
  88         kmutex_t                ic_state_mutex;
  89         kcondvar_t              ic_state_cv;
  90         uint32_t                ic_state_flags;
  91         timeout_id_t            ic_state_timeout;
  92         struct idm_conn_s       *ic_reinstate_conn; /* For conn reinst. */
  93         struct idm_conn_s       *ic_logout_conn; /* For other conn logout */
  94         taskq_t                 *ic_state_taskq;
  95         int                     ic_pdu_events;
  96 
  97         boolean_t               ic_login_info_valid;
  98         uint16_t                ic_login_cid;
  99 
 100         kmutex_t                ic_mutex;
 101         kcondvar_t              ic_cv;
 102         idm_status_t            ic_conn_sm_status;
 103 
 104         boolean_t               ic_ffm;
 105         uint32_t                ic_internal_cid;
 106         unsigned int            ic_client_refcount;
 107         unsigned int            ic_task_refcount;
 108         unsigned int            ic_buf_refcount;
 109         uint32_t                ic_conn_flags;
 110         idm_conn_type_t         ic_conn_type;
 111         idm_conn_ops_t          ic_conn_ops;
 112         idm_transport_ops_t     *ic_transport_ops;
 113         idm_transport_type_t    ic_transport_type;
 114         void                    *ic_transport_private;
 115         idm_conn_param_t        ic_conn_params;
 116         avl_tree_t              ic_task_tree;
 117 } idm_conn_t;
 118 
 119 #define IDM_CONN_HEADER_DIGEST  0x00000001
 120 #define IDM_CONN_DATA_DIGEST    0x00000002
 121 
 122 #define IDM_CONN_ISINI(ICI_IC)  ((ICI_IC)->ic_conn_type == CONN_TYPE_INI)
 123 #define IDM_CONN_ISTGT(ICI_IC)  ((ICI_IC)->ic_conn_type == CONN_TYPE_TGT)
 124 
 125 /*
 126  * An IDM target task can transfer data using multiple buffers. The task
 127  * will maintain a list of buffers, and each buffer will contain the relative
 128  * offset of the transfer and a pointer to the next buffer in the list.
 129  *
 130  * An initiator will require only one buffer per task, the offset will be 0.
 131  */
 132 
 133 typedef struct idm_task_s {
 134         avl_node_t              idt_avl_link;   /* node on the avl_tree */
 135         idm_conn_t              *idt_ic;        /* Associated connection */
 136         /* connection type is in idt_ic->ic_conn_type */
 137         boolean_t               idt_active;     /* task state */
 138         kmutex_t                idt_mutex;
 139         void                    *idt_private;   /* Client private data */
 140         uint32_t                idt_tt;         /* Task tag */
 141         /*
 142          * Statistics
 143          */
 144         int                     idt_tx_to_ini_start;
 145         int                     idt_tx_to_ini_done;
 146         int                     idt_rx_from_ini_start;
 147         int                     idt_rx_from_ini_done;
 148 
 149         /*
 150          * For bi-directional commands, R2T and Data-In PDUs share the input
 151          * PDU numbering sequence
 152          */
 153         uint32_t                idt_exp_sn;     /* shared by rttsn and datasn */
 154         list_t                  idt_inbufv;     /* chunks of IN buffers */
 155         list_t                  idt_outbufv;    /* chunks of OUT buffers */
 156 } idm_task_t;
 157 
 158 int idm_task_constructor(void *task_void, void *arg, int flags);
 159 void idm_task_destructor(void *task_void, void *arg);
 160 
 161 #define IDM_TASKIDS_MAX         USHRT_MAX       /* 64k tasks */
 162 
 163 typedef struct idm_buf_s {
 164         list_node_t     idb_buflink;    /* link in a multi-buffer data xfer */
 165         idm_conn_t      *idb_ic;        /* Associated connection */
 166         void            *idb_buf;       /* data */
 167         uint64_t        idb_buflen;     /* length of buffer */
 168         size_t          idb_bufoffset;  /* offset in a multi-buffer xfer */
 169         /*
 170          * DataPDUInOrder=Yes, so to track that the PDUs in a sequence are sent
 171          * in continuously increasing address order, check that offsets for a
 172          * single buffer xfer are in order.
 173          */
 174         uint32_t        idb_exp_offset;
 175         size_t          idb_xfer_len;   /* Current requested xfer len */
 176         void            *idb_mr_handle; /* iSER - Memory region handle */
 177         idm_buf_cb_t    *idb_buf_cb;    /* Data Completion Notify, tgt only */
 178         void            *idb_cb_arg;    /* Client private data */
 179         idm_task_t      *idb_task_binding;
 180         idm_status_t    idb_status;
 181 } idm_buf_t;
 182 
 183 
 184 #define PDU_MAX_IOVLEN  12
 185 
 186 typedef struct idm_pdu_s {
 187         idm_conn_t      *isp_ic;        /* Must be set */
 188         iscsi_hdr_t     *isp_hdr;
 189         uint_t          isp_hdrlen;
 190         uint8_t         *isp_data;
 191         uint_t          isp_datalen;
 192 
 193         /*
 194          * isp_data is used for sending SCSI status, NOP, text, scsi and
 195          * non-scsi data. Data is received using isp_iov and isp_iovlen
 196          * to support data over multiple buffers.
 197          */
 198         void            *isp_private;
 199         idm_pdu_cb_t    *isp_callback;
 200         idm_status_t    isp_status;
 201 
 202         /* Internal */
 203         list_node_t     isp_client_lnd;
 204 
 205         /*
 206          * The following four elements are only used in
 207          * idm_sorecv_scsidata() currently.
 208          */
 209         struct iovec    isp_iov[PDU_MAX_IOVLEN];
 210         int             isp_iovlen;
 211         idm_task_t      *isp_sorx_task;
 212         idm_buf_t       *isp_sorx_buf;
 213 
 214         /* Implementation data for idm_pdu_alloc and sorx PDU cache */
 215         uint32_t        isp_flags;
 216         uint_t          isp_hdrbuflen;
 217         uint_t          isp_databuflen;
 218 
 219 } idm_pdu_t;
 220 
 221 #define IDM_PDU_OPCODE(PDU) \
 222         ((PDU)->isp_hdr->opcode & ISCSI_OPCODE_MASK)
 223 
 224 #define IDM_PDU_ALLOC           0x00000001
 225 #define IDM_PDU_ADDL_HDR        0x00000002
 226 #define IDM_PDU_ADDL_DATA       0x00000004
 227 
 228 #define OSD_EXT_CDB_AHSLEN      (200 - 15)
 229 #define BIDI_AHS_LENGTH         5
 230 #define IDM_SORX_CACHE_AHSLEN \
 231         (((OSD_EXT_CDB_AHSLEN + 3) + \
 232             (BIDI_AHS_LENGTH + 3)) / sizeof (uint32_t))
 233 #define IDM_SORX_CACHE_HDRLEN   (sizeof (iscsi_hdr_t) + IDM_SORX_CACHE_AHSLEN)
 234 
 235 /*
 236  * ID pool
 237  */
 238 
 239 #define IDM_IDPOOL_MAGIC        0x4944504C      /* IDPL */
 240 #define IDM_IDPOOL_MIN_SIZE     64      /* Number of IDs to begin with */
 241 #define IDM_IDPOOL_MAX_SIZE     64 * 1024
 242 
 243 typedef struct idm_idpool {
 244         uint32_t        id_magic;
 245         kmutex_t        id_mutex;
 246         uint8_t         *id_pool;
 247         uint32_t        id_size;
 248         uint8_t         id_bit;
 249         uint8_t         id_bit_idx;
 250         uint32_t        id_idx;
 251         uint32_t        id_idx_msk;
 252         uint32_t        id_free_counter;
 253         uint32_t        id_max_free_counter;
 254 } idm_idpool_t;
 255 
 256 int
 257 idm_idpool_create(idm_idpool_t  *pool);
 258 
 259 void
 260 idm_idpool_destroy(idm_idpool_t *pool);
 261 
 262 int
 263 idm_idpool_alloc(idm_idpool_t *pool, uint16_t *id);
 264 
 265 void
 266 idm_idpool_free(idm_idpool_t *pool, uint16_t id);
 267 
 268 void
 269 idm_pdu_rx(idm_conn_t *ic, idm_pdu_t *pdu);
 270 
 271 void
 272 idm_pdu_tx_forward(idm_conn_t *ic, idm_pdu_t *pdu);
 273 
 274 boolean_t
 275 idm_pdu_rx_forward_ffm(idm_conn_t *ic, idm_pdu_t *pdu);
 276 
 277 void
 278 idm_pdu_rx_forward(idm_conn_t *ic, idm_pdu_t *pdu);
 279 
 280 void idm_parse_login_rsp(idm_conn_t *ic, idm_pdu_t *logout_req_pdu,
 281     boolean_t rx);
 282 
 283 void idm_parse_logout_req(idm_conn_t *ic, idm_pdu_t *logout_req_pdu,
 284     boolean_t rx);
 285 
 286 void idm_parse_logout_rsp(idm_conn_t *ic, idm_pdu_t *login_rsp_pdu,
 287     boolean_t rx);
 288 
 289 idm_status_t idm_svc_conn_create(idm_svc_t *is, idm_conn_t **ic_result);
 290 
 291 void idm_svc_conn_destroy(idm_conn_t *ic);
 292 
 293 idm_status_t idm_ini_conn_finish(idm_conn_t *ic);
 294 
 295 idm_status_t idm_tgt_conn_finish(idm_conn_t *ic);
 296 
 297 void idm_conn_close(idm_conn_t *ic);
 298 
 299 void idm_conn_hold_impl(idm_conn_t *ic, unsigned int *counter);
 300 
 301 void idm_conn_rele_impl(idm_conn_t *ic, unsigned int *counter);
 302 
 303 void idm_conn_wait_ref(idm_conn_t *ic);
 304 
 305 uint32_t idm_cid_alloc(void);
 306 
 307 void idm_cid_free(uint32_t cid);
 308 
 309 uint32_t idm_crc32c(void *address, unsigned long length);
 310 
 311 uint32_t idm_crc32c_continued(void *address, unsigned long length,
 312     uint32_t crc);
 313 
 314 void idm_listbuf_insert(list_t *lst, idm_buf_t *buf, uint32_t offset);
 315 
 316 int idm_task_compare(const void *v1, const void *v2);
 317 
 318 idm_conn_t *idm_lookup_conn(uint8_t *isid, uint16_t tsih, uint16_t cid);
 319 
 320 
 321 #ifdef  __cplusplus
 322 }
 323 #endif
 324 
 325 #endif /* _IDM_IMPL_H_ */