/* * 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 src/sun_nws/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 src/sun_nws/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 _IDM_IMPL_H_ #define _IDM_IMPL_H_ #pragma ident "@(#)idm_impl.h 1.18 08/03/26 SMI" #ifdef __cplusplus extern "C" { #endif #include typedef struct { kmutex_t idm_global_mutex; taskq_t *idm_global_taskq; list_t idm_tgt_svc_list; list_t idm_ini_conn_list; } idm_global_t; #define CF_LOGIN_READY 0x00000001 #define CF_INITIAL_LOGIN 0x00000002 #define CF_ERROR 0x80000000 typedef enum { CONN_TYPE_INI = 1, CONN_TYPE_TGT } idm_conn_type_t; typedef union idm_sockaddr { struct sockaddr sin; struct sockaddr_in sin4; struct sockaddr_in6 sin6; } idm_sockaddr_t; /* * connection parameters - These parameters would be populated at * connection create, or during key-value negotiation at login */ typedef struct idm_conn_params_s { uint32_t max_dataseglen; } idm_conn_param_t; typedef struct idm_svc_s { list_node_t is_list_node; kmutex_t is_mutex; kcondvar_t is_cv; kmutex_t is_count_mutex; kcondvar_t is_count_cv; /* transport-specific service components */ void *is_so_svc; /* JBDB - iser_svc_t will go here */ idm_conn_ops_t is_conn_ops; list_t is_conn_list; /* Locked by is_mutex */ int is_conn_count; /* Locked by is_count_mutex */ uint16_t is_port; } idm_svc_t; typedef struct idm_conn_s { list_node_t ic_list_node; void *ic_handle; struct idm_svc_s *ic_svc_binding; /* Target conn. only */ idm_sockaddr_t ic_ini_dst_addr; idm_conn_state_t ic_state; idm_conn_state_t ic_last_state; kmutex_t ic_state_mutex; kcondvar_t ic_state_cv; uint32_t ic_state_flags; timeout_id_t ic_state_timeout; struct idm_conn_s *ic_reinstate_conn; /* For conn reinst. */ struct idm_conn_s *ic_logout_conn; /* For other conn logout */ taskq_t *ic_state_taskq; int ic_pdu_events; boolean_t ic_login_info_valid; uint16_t ic_login_cid; kmutex_t ic_mutex; kcondvar_t ic_cv; idm_status_t ic_conn_sm_status; boolean_t ic_ffm; uint32_t ic_internal_cid; unsigned int ic_client_refcount; unsigned int ic_task_refcount; unsigned int ic_buf_refcount; uint32_t ic_conn_flags; idm_conn_type_t ic_conn_type; idm_conn_ops_t ic_conn_ops; idm_transport_ops_t *ic_transport_ops; idm_transport_type_t ic_transport_type; void *ic_transport_private; idm_conn_param_t ic_conn_params; avl_tree_t ic_task_tree; } idm_conn_t; #define IDM_CONN_HEADER_DIGEST 0x00000001 #define IDM_CONN_DATA_DIGEST 0x00000002 #define IDM_CONN_ISINI(ICI_IC) ((ICI_IC)->ic_conn_type == CONN_TYPE_INI) #define IDM_CONN_ISTGT(ICI_IC) ((ICI_IC)->ic_conn_type == CONN_TYPE_TGT) /* * An IDM target task can transfer data using multiple buffers. The task * will maintain a list of buffers, and each buffer will contain the relative * offset of the transfer and a pointer to the next buffer in the list. * * An initiator will require only one buffer per task, the offset will be 0. */ typedef struct idm_task_s { avl_node_t idt_avl_link; /* node on the avl_tree */ idm_conn_t *idt_ic; /* Associated connection */ /* connection type is in idt_ic->ic_conn_type */ boolean_t idt_active; /* task state */ kmutex_t idt_mutex; void *idt_private; /* Client private data */ uint32_t idt_tt; /* Task tag */ /* * Statistics */ int idt_tx_to_ini_start; int idt_tx_to_ini_done; int idt_rx_from_ini_start; int idt_rx_from_ini_done; /* * For bi-directional commands, R2T and Data-In PDUs share the input * PDU numbering sequence */ uint32_t idt_exp_sn; /* shared by rttsn and datasn */ list_t idt_inbufv; /* chunks of IN buffers */ list_t idt_outbufv; /* chunks of OUT buffers */ } idm_task_t; int idm_task_constructor(void *task_void, void *arg, int flags); void idm_task_destructor(void *task_void, void *arg); #define IDM_TASKIDS_MAX USHRT_MAX /* 64k tasks */ typedef struct idm_buf_s { list_node_t idb_buflink; /* link in a multi-buffer data xfer */ idm_conn_t *idb_ic; /* Associated connection */ void *idb_buf; /* data */ uint64_t idb_buflen; /* length of buffer */ size_t idb_bufoffset; /* offset in a multi-buffer xfer */ /* * DataPDUInOrder=Yes, so to track that the PDUs in a sequence are sent * in continuously increasing address order, check that offsets for a * single buffer xfer are in order. */ uint32_t idb_exp_offset; size_t idb_xfer_len; /* Current requested xfer len */ void *idb_mr_handle; /* iSER - Memory region handle */ idm_buf_cb_t *idb_buf_cb; /* Data Completion Notify, tgt only */ void *idb_cb_arg; /* Client private data */ idm_task_t *idb_task_binding; idm_status_t idb_status; } idm_buf_t; #define PDU_MAX_IOVLEN 12 typedef struct idm_pdu_s { idm_conn_t *isp_ic; /* Must be set */ iscsi_hdr_t *isp_hdr; uint_t isp_hdrlen; uint8_t *isp_data; uint_t isp_datalen; /* * isp_data is used for sending SCSI status, NOP, text, scsi and * non-scsi data. Data is received using isp_iov and isp_iovlen * to support data over multiple buffers. */ void *isp_private; idm_pdu_cb_t *isp_callback; idm_status_t isp_status; /* Internal */ list_node_t isp_client_lnd; /* * The following four elements are only used in * idm_sorecv_scsidata() currently. */ struct iovec isp_iov[PDU_MAX_IOVLEN]; int isp_iovlen; idm_task_t *isp_sorx_task; idm_buf_t *isp_sorx_buf; /* Implementation data for idm_pdu_alloc and sorx PDU cache */ uint32_t isp_flags; uint_t isp_hdrbuflen; uint_t isp_databuflen; } idm_pdu_t; #define IDM_PDU_OPCODE(PDU) \ ((PDU)->isp_hdr->opcode & ISCSI_OPCODE_MASK) #define IDM_PDU_ALLOC 0x00000001 #define IDM_PDU_ADDL_HDR 0x00000002 #define IDM_PDU_ADDL_DATA 0x00000004 #define OSD_EXT_CDB_AHSLEN (200 - 15) #define BIDI_AHS_LENGTH 5 #define IDM_SORX_CACHE_AHSLEN \ (((OSD_EXT_CDB_AHSLEN + 3) + \ (BIDI_AHS_LENGTH + 3)) / sizeof (uint32_t)) #define IDM_SORX_CACHE_HDRLEN (sizeof (iscsi_hdr_t) + IDM_SORX_CACHE_AHSLEN) /* * ID pool */ #define IDM_IDPOOL_MAGIC 0x4944504C /* IDPL */ #define IDM_IDPOOL_MIN_SIZE 64 /* Number of IDs to begin with */ #define IDM_IDPOOL_MAX_SIZE 64 * 1024 typedef struct idm_idpool { uint32_t id_magic; kmutex_t id_mutex; uint8_t *id_pool; uint32_t id_size; uint8_t id_bit; uint8_t id_bit_idx; uint32_t id_idx; uint32_t id_idx_msk; uint32_t id_free_counter; uint32_t id_max_free_counter; } idm_idpool_t; int idm_idpool_create(idm_idpool_t *pool); void idm_idpool_destroy(idm_idpool_t *pool); int idm_idpool_alloc(idm_idpool_t *pool, uint16_t *id); void idm_idpool_free(idm_idpool_t *pool, uint16_t id); void idm_pdu_rx(idm_conn_t *ic, idm_pdu_t *pdu); void idm_pdu_tx_forward(idm_conn_t *ic, idm_pdu_t *pdu); boolean_t idm_pdu_rx_forward_ffm(idm_conn_t *ic, idm_pdu_t *pdu); void idm_pdu_rx_forward(idm_conn_t *ic, idm_pdu_t *pdu); void idm_parse_login_rsp(idm_conn_t *ic, idm_pdu_t *logout_req_pdu, boolean_t rx); void idm_parse_logout_req(idm_conn_t *ic, idm_pdu_t *logout_req_pdu, boolean_t rx); void idm_parse_logout_rsp(idm_conn_t *ic, idm_pdu_t *login_rsp_pdu, boolean_t rx); idm_status_t idm_svc_conn_create(idm_svc_t *is, idm_conn_t **ic_result); void idm_svc_conn_destroy(idm_conn_t *ic); idm_status_t idm_ini_conn_finish(idm_conn_t *ic); idm_status_t idm_tgt_conn_finish(idm_conn_t *ic); void idm_conn_close(idm_conn_t *ic); void idm_conn_hold_impl(idm_conn_t *ic, unsigned int *counter); void idm_conn_rele_impl(idm_conn_t *ic, unsigned int *counter); void idm_conn_wait_ref(idm_conn_t *ic); uint32_t idm_cid_alloc(void); void idm_cid_free(uint32_t cid); uint32_t idm_crc32c(void *address, unsigned long length); uint32_t idm_crc32c_continued(void *address, unsigned long length, uint32_t crc); void idm_listbuf_insert(list_t *lst, idm_buf_t *buf, uint32_t offset); int idm_task_compare(const void *v1, const void *v2); idm_conn_t *idm_lookup_conn(uint8_t *isid, uint16_t tsih, uint16_t cid); #ifdef __cplusplus } #endif #endif /* _IDM_IMPL_H_ */