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_ */