xref: /illumos-gate/usr/src/uts/common/sys/idm/idm_impl.h (revision 179c3dac)
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 usr/src/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 usr/src/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 2009 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 #ifdef	__cplusplus
29 extern "C" {
30 #endif
31 
32 #include <sys/avl.h>
33 #include <sys/socket_impl.h>
34 
35 /*
36  * IDM lock order:
37  *
38  * idm_taskid_table_lock, idm_task_t.idt_mutex
39  */
40 
41 #define	CF_LOGIN_READY		0x00000001
42 #define	CF_INITIAL_LOGIN	0x00000002
43 #define	CF_ERROR		0x80000000
44 
45 typedef enum {
46 	CONN_TYPE_INI = 1,
47 	CONN_TYPE_TGT
48 } idm_conn_type_t;
49 
50 /*
51  * Watchdog interval in seconds
52  */
53 #define	IDM_WD_INTERVAL			5
54 
55 /*
56  * Timeout period before a TRANSPORT_FAIL event is generated in seconds
57  * if the connection is idle.
58  */
59 #define	IDM_TRANSPORT_FAIL_IDLE_TIMEOUT	30
60 
61 /*
62  * IDM reference count structure.  Audit code is shamelessly adapted
63  * from CIFS server.
64  */
65 
66 #define	REFCNT_AUDIT_STACK_DEPTH	16
67 #define	REFCNT_AUDIT_BUF_MAX_REC	16
68 
69 typedef struct {
70 	uint32_t		anr_refcnt;
71 	int			anr_depth;
72 	pc_t			anr_stack[REFCNT_AUDIT_STACK_DEPTH];
73 } refcnt_audit_record_t;
74 
75 typedef struct {
76 	int			anb_index;
77 	int			anb_max_index;
78 	refcnt_audit_record_t	anb_records[REFCNT_AUDIT_BUF_MAX_REC];
79 } refcnt_audit_buf_t;
80 
81 #define	REFCNT_AUDIT(_rf_) {				\
82 	refcnt_audit_record_t	*anr;			\
83 							\
84 	anr = (_rf_)->ir_audit_buf.anb_records;		\
85 	anr += (_rf_)->ir_audit_buf.anb_index;		\
86 	(_rf_)->ir_audit_buf.anb_index++;		\
87 	(_rf_)->ir_audit_buf.anb_index &=		\
88 	    (_rf_)->ir_audit_buf.anb_max_index;		\
89 	anr->anr_refcnt = (_rf_)->ir_refcnt;		\
90 	anr->anr_depth = getpcstack(anr->anr_stack,	\
91 	    REFCNT_AUDIT_STACK_DEPTH);			\
92 }
93 
94 struct idm_refcnt_s;
95 
96 typedef void (idm_refcnt_cb_t)(void *ref_obj);
97 
98 typedef enum {
99 	REF_NOWAIT,
100 	REF_WAIT_SYNC,
101 	REF_WAIT_ASYNC
102 } idm_refcnt_wait_t;
103 
104 typedef struct idm_refcnt_s {
105 	int			ir_refcnt;
106 	void			*ir_referenced_obj;
107 	idm_refcnt_wait_t	ir_waiting;
108 	kmutex_t		ir_mutex;
109 	kcondvar_t		ir_cv;
110 	idm_refcnt_cb_t		*ir_cb;
111 	refcnt_audit_buf_t	ir_audit_buf;
112 } idm_refcnt_t;
113 
114 /*
115  * connection parameters - These parameters would be populated at
116  * connection create, or during key-value negotiation at login
117  */
118 typedef struct idm_conn_params_s {
119 	uint32_t		max_dataseglen;
120 } idm_conn_param_t;
121 
122 typedef struct idm_svc_s {
123 	list_node_t		is_list_node;
124 	kmutex_t		is_mutex;
125 	kcondvar_t		is_cv;
126 	kmutex_t		is_count_mutex;
127 	kcondvar_t		is_count_cv;
128 	idm_refcnt_t		is_refcnt;
129 	int			is_online;
130 	/* transport-specific service components */
131 	void			*is_so_svc;
132 	void			*is_iser_svc;
133 	idm_svc_req_t		is_svc_req;
134 } idm_svc_t;
135 
136 typedef struct idm_conn_s {
137 	list_node_t		ic_list_node;
138 	void			*ic_handle;
139 	idm_refcnt_t		ic_refcnt;
140 	idm_svc_t		*ic_svc_binding; /* Target conn. only */
141 	idm_sockaddr_t 		ic_ini_dst_addr;
142 	struct sockaddr_storage	ic_laddr;	/* conn local address */
143 	struct sockaddr_storage	ic_raddr;	/* conn remote address */
144 	idm_conn_state_t	ic_state;
145 	idm_conn_state_t	ic_last_state;
146 	sm_audit_buf_t		ic_state_audit;
147 	kmutex_t		ic_state_mutex;
148 	kcondvar_t		ic_state_cv;
149 	uint32_t		ic_state_flags;
150 	timeout_id_t		ic_state_timeout;
151 	struct idm_conn_s	*ic_reinstate_conn; /* For conn reinst. */
152 	struct idm_conn_s	*ic_logout_conn; /* For other conn logout */
153 	taskq_t			*ic_state_taskq;
154 	int			ic_pdu_events;
155 	boolean_t		ic_login_info_valid;
156 	boolean_t		ic_rdma_extensions;
157 	uint16_t		ic_login_cid;
158 
159 	kmutex_t		ic_mutex;
160 	kcondvar_t		ic_cv;
161 	idm_status_t		ic_conn_sm_status;
162 
163 	boolean_t		ic_ffp;
164 	uint32_t		ic_internal_cid;
165 
166 	uint32_t		ic_conn_flags;
167 	idm_conn_type_t		ic_conn_type;
168 	idm_conn_ops_t		ic_conn_ops;
169 	idm_transport_ops_t	*ic_transport_ops;
170 	idm_transport_type_t	ic_transport_type;
171 	int			ic_transport_hdrlen;
172 	void			*ic_transport_private;
173 	idm_conn_param_t	ic_conn_params;
174 	/*
175 	 * Save client callback to interpose idm callback
176 	 */
177 	idm_pdu_cb_t		*ic_client_callback;
178 	clock_t			ic_timestamp;
179 } idm_conn_t;
180 
181 #define	IDM_CONN_HEADER_DIGEST	0x00000001
182 #define	IDM_CONN_DATA_DIGEST	0x00000002
183 #define	IDM_CONN_USE_SCOREBOARD	0x00000004
184 
185 #define	IDM_CONN_ISINI(ICI_IC)	((ICI_IC)->ic_conn_type == CONN_TYPE_INI)
186 #define	IDM_CONN_ISTGT(ICI_IC)	((ICI_IC)->ic_conn_type == CONN_TYPE_TGT)
187 
188 /*
189  * An IDM target task can transfer data using multiple buffers. The task
190  * will maintain a list of buffers, and each buffer will contain the relative
191  * offset of the transfer and a pointer to the next buffer in the list.
192  *
193  * Note on client private data:
194  * idt_private is intended to be a pointer to some sort of client-
195  * specific state.
196  *
197  * idt_client_handle is a more generic client-private piece of data that can
198  * be used by the client for the express purpose of task lookup.  The driving
199  * use case for this is for the client to store the initiator task tag for
200  * a given task so that it may be more easily retrieved for task management.
201  *
202  * The key take away here is that clients should never call
203  * idm_task_find_by_handle in the performance path.
204  *
205  * An initiator will require only one buffer per task, the offset will be 0.
206  */
207 
208 typedef struct idm_task_s {
209 	idm_conn_t		*idt_ic;	/* Associated connection */
210 	/* connection type is in idt_ic->ic_conn_type */
211 	kmutex_t		idt_mutex;
212 	void			*idt_private;	/* Client private data */
213 	uintptr_t		idt_client_handle;	/* Client private */
214 	uint32_t		idt_tt;		/* Task tag */
215 	uint32_t		idt_r2t_ttt;	/* R2T Target Task tag */
216 	idm_task_state_t	idt_state;
217 	idm_refcnt_t		idt_refcnt;
218 
219 	/*
220 	 * Statistics
221 	 */
222 	int			idt_tx_to_ini_start;
223 	int			idt_tx_to_ini_done;
224 	int			idt_rx_from_ini_start;
225 	int			idt_rx_from_ini_done;
226 	int			idt_tx_bytes;	/* IDM_CONN_USE_SCOREBOARD */
227 	int			idt_rx_bytes;	/* IDM_CONN_USE_SCOREBOARD */
228 
229 	uint32_t		idt_exp_datasn;	/* expected datasn */
230 	uint32_t		idt_exp_rttsn;	/* expected rttsn */
231 	list_t			idt_inbufv;	/* chunks of IN buffers */
232 	list_t			idt_outbufv;	/* chunks of OUT buffers */
233 
234 	/*
235 	 * Transport header, which describes this tasks remote tagged buffer
236 	 */
237 	int			idt_transport_hdrlen;
238 	void			*idt_transport_hdr;
239 } idm_task_t;
240 
241 int idm_task_constructor(void *task_void, void *arg, int flags);
242 void idm_task_destructor(void *task_void, void *arg);
243 
244 #define	IDM_TASKIDS_MAX		16384
245 #define	IDM_BUF_MAGIC		0x49425546	/* "IBUF" */
246 
247 /* Protect with task mutex */
248 typedef struct idm_buf_s {
249 	uint32_t	idb_magic;	/* "IBUF" */
250 
251 	/*
252 	 * Note: idm_tx_link *must* be the second element in the list for
253 	 * proper TX PDU ordering.
254 	 */
255 	list_node_t	idm_tx_link;	/* link in a list of TX objects */
256 
257 	list_node_t	idb_buflink;	/* link in a multi-buffer data xfer */
258 	idm_conn_t	*idb_ic;	/* Associated connection */
259 	void		*idb_buf;	/* data */
260 	uint64_t	idb_buflen;	/* length of buffer */
261 	size_t		idb_bufoffset;	/* offset in a multi-buffer xfer */
262 	boolean_t	idb_bufalloc;  /* true if alloc'd in idm_buf_alloc */
263 	/*
264 	 * DataPDUInOrder=Yes, so to track that the PDUs in a sequence are sent
265 	 * in continuously increasing address order, check that offsets for a
266 	 * single buffer xfer are in order.
267 	 */
268 	uint32_t	idb_exp_offset;
269 	size_t		idb_xfer_len;	/* Current requested xfer len */
270 	void		*idb_buf_private; /* transport-specific buf handle */
271 	void		*idb_reg_private; /* transport-specific reg handle */
272 	void		*idb_bufptr; /* transport-specific bcopy pointer */
273 	boolean_t	idb_bufbcopy;	/* true if bcopy required */
274 
275 	idm_buf_cb_t	*idb_buf_cb;	/* Data Completion Notify, tgt only */
276 	void		*idb_cb_arg;	/* Client private data */
277 	idm_task_t	*idb_task_binding;
278 	timespec_t	idb_xfer_start;
279 	timespec_t	idb_xfer_done;
280 	boolean_t	idb_in_transport;
281 	boolean_t	idb_tx_thread;		/* Sockets only */
282 	iscsi_hdr_t	idb_data_hdr_tmpl;	/* Sockets only */
283 	idm_status_t	idb_status;
284 } idm_buf_t;
285 
286 typedef enum {
287 	BP_CHECK_QUICK,
288 	BP_CHECK_THOROUGH,
289 	BP_CHECK_ASSERT
290 } idm_bufpat_check_type_t;
291 
292 #define	BUFPAT_MATCH(bc_bufpat, bc_idb) 		\
293 	((bufpat->bufpat_idb == bc_idb) &&		\
294 	    (bufpat->bufpat_bufmagic == IDM_BUF_MAGIC))
295 
296 typedef struct idm_bufpat_s {
297 	void		*bufpat_idb;
298 	uint32_t	bufpat_bufmagic;
299 	uint32_t	bufpat_offset;
300 } idm_bufpat_t;
301 
302 #define	PDU_MAX_IOVLEN	12
303 #define	IDM_PDU_MAGIC	0x49504455	/* "IPDU" */
304 
305 typedef struct idm_pdu_s {
306 	uint32_t	isp_magic;	/* "IPDU" */
307 
308 	/*
309 	 * Internal - Order is vital.  idm_tx_link *must* be the second
310 	 * element in this structure for proper TX PDU ordering.
311 	 */
312 	list_node_t	idm_tx_link;
313 
314 	list_node_t	isp_client_lnd;
315 
316 	idm_conn_t	*isp_ic;	/* Must be set */
317 	iscsi_hdr_t	*isp_hdr;
318 	uint_t		isp_hdrlen;
319 	uint8_t		*isp_data;
320 	uint_t		isp_datalen;
321 
322 	/* Transport header */
323 	void		*isp_transport_hdr;
324 	uint32_t	isp_transport_hdrlen;
325 	void		*isp_transport_private;
326 
327 	/*
328 	 * isp_data is used for sending SCSI status, NOP, text, scsi and
329 	 * non-scsi data. Data is received using isp_iov and isp_iovlen
330 	 * to support data over multiple buffers.
331 	 */
332 	void		*isp_private;
333 	idm_pdu_cb_t	*isp_callback;
334 	idm_status_t	isp_status;
335 
336 	/*
337 	 * The following four elements are only used in
338 	 * idm_sorecv_scsidata() currently.
339 	 */
340 	struct iovec	isp_iov[PDU_MAX_IOVLEN];
341 	int		isp_iovlen;
342 	idm_buf_t	*isp_sorx_buf;
343 
344 	/* Implementation data for idm_pdu_alloc and sorx PDU cache */
345 	uint32_t	isp_flags;
346 	uint_t		isp_hdrbuflen;
347 	uint_t		isp_databuflen;
348 } idm_pdu_t;
349 
350 /*
351  * This "generic" object is used when removing an item from the ic_tx_list
352  * in order to determine whether it's an idm_pdu_t or an idm_buf_t
353  */
354 
355 typedef struct {
356 	uint32_t	idm_tx_obj_magic;
357 	/*
358 	 * idm_tx_link *must* be the second element in this structure.
359 	 */
360 	list_node_t	idm_tx_link;
361 } idm_tx_obj_t;
362 
363 
364 #define	IDM_PDU_OPCODE(PDU) \
365 	((PDU)->isp_hdr->opcode & ISCSI_OPCODE_MASK)
366 
367 #define	IDM_PDU_ALLOC		0x00000001
368 #define	IDM_PDU_ADDL_HDR	0x00000002
369 #define	IDM_PDU_ADDL_DATA	0x00000004
370 #define	IDM_PDU_LOGIN_TX	0x00000008
371 
372 #define	OSD_EXT_CDB_AHSLEN	(200 - 15)
373 #define	BIDI_AHS_LENGTH		5
374 #define	IDM_SORX_CACHE_AHSLEN \
375 	(((OSD_EXT_CDB_AHSLEN + 3) + \
376 	    (BIDI_AHS_LENGTH + 3)) / sizeof (uint32_t))
377 #define	IDM_SORX_CACHE_HDRLEN	(sizeof (iscsi_hdr_t) + IDM_SORX_CACHE_AHSLEN)
378 
379 /*
380  * ID pool
381  */
382 
383 #define	IDM_IDPOOL_MAGIC	0x4944504C	/* IDPL */
384 #define	IDM_IDPOOL_MIN_SIZE	64	/* Number of IDs to begin with */
385 #define	IDM_IDPOOL_MAX_SIZE	64 * 1024
386 
387 typedef struct idm_idpool {
388 	uint32_t	id_magic;
389 	kmutex_t	id_mutex;
390 	uint8_t		*id_pool;
391 	uint32_t	id_size;
392 	uint8_t		id_bit;
393 	uint8_t		id_bit_idx;
394 	uint32_t	id_idx;
395 	uint32_t	id_idx_msk;
396 	uint32_t	id_free_counter;
397 	uint32_t	id_max_free_counter;
398 } idm_idpool_t;
399 
400 /*
401  * Global IDM state structure
402  */
403 typedef struct {
404 	kmutex_t	idm_global_mutex;
405 	taskq_t		*idm_global_taskq;
406 	kthread_t	*idm_wd_thread;
407 	kt_did_t	idm_wd_thread_did;
408 	boolean_t	idm_wd_thread_running;
409 	kcondvar_t	idm_wd_cv;
410 	list_t		idm_tgt_svc_list;
411 	kcondvar_t	idm_tgt_svc_cv;
412 	list_t		idm_tgt_conn_list;
413 	int		idm_tgt_conn_count;
414 	list_t		idm_ini_conn_list;
415 	kmem_cache_t	*idm_buf_cache;
416 	kmem_cache_t	*idm_task_cache;
417 	krwlock_t	idm_taskid_table_lock;
418 	idm_task_t	**idm_taskid_table;
419 	uint32_t	idm_taskid_next;
420 	uint32_t	idm_taskid_max;
421 	idm_idpool_t	idm_conn_id_pool;
422 	kmem_cache_t	*idm_sotx_pdu_cache;
423 	kmem_cache_t	*idm_sorx_pdu_cache;
424 	kmem_cache_t	*idm_so_128k_buf_cache;
425 } idm_global_t;
426 
427 idm_global_t	idm; /* Global state */
428 
429 int
430 idm_idpool_create(idm_idpool_t	*pool);
431 
432 void
433 idm_idpool_destroy(idm_idpool_t *pool);
434 
435 int
436 idm_idpool_alloc(idm_idpool_t *pool, uint16_t *id);
437 
438 void
439 idm_idpool_free(idm_idpool_t *pool, uint16_t id);
440 
441 void
442 idm_pdu_rx(idm_conn_t *ic, idm_pdu_t *pdu);
443 
444 void
445 idm_pdu_tx_forward(idm_conn_t *ic, idm_pdu_t *pdu);
446 
447 boolean_t
448 idm_pdu_rx_forward_ffp(idm_conn_t *ic, idm_pdu_t *pdu);
449 
450 void
451 idm_pdu_rx_forward(idm_conn_t *ic, idm_pdu_t *pdu);
452 
453 void
454 idm_pdu_tx_protocol_error(idm_conn_t *ic, idm_pdu_t *pdu);
455 
456 void
457 idm_pdu_rx_protocol_error(idm_conn_t *ic, idm_pdu_t *pdu);
458 
459 void idm_parse_login_rsp(idm_conn_t *ic, idm_pdu_t *logout_req_pdu,
460     boolean_t rx);
461 
462 void idm_parse_logout_req(idm_conn_t *ic, idm_pdu_t *logout_req_pdu,
463     boolean_t rx);
464 
465 void idm_parse_logout_rsp(idm_conn_t *ic, idm_pdu_t *login_rsp_pdu,
466     boolean_t rx);
467 
468 idm_status_t idm_svc_conn_create(idm_svc_t *is, idm_transport_type_t type,
469     idm_conn_t **ic_result);
470 
471 void idm_svc_conn_destroy(idm_conn_t *ic);
472 
473 idm_status_t idm_ini_conn_finish(idm_conn_t *ic);
474 
475 idm_status_t idm_tgt_conn_finish(idm_conn_t *ic);
476 
477 idm_conn_t *idm_conn_create_common(idm_conn_type_t conn_type,
478     idm_transport_type_t tt, idm_conn_ops_t *conn_ops);
479 
480 void idm_conn_destroy_common(idm_conn_t *ic);
481 
482 void idm_conn_close(idm_conn_t *ic);
483 
484 uint32_t idm_cid_alloc(void);
485 
486 void idm_cid_free(uint32_t cid);
487 
488 uint32_t idm_crc32c(void *address, unsigned long length);
489 
490 uint32_t idm_crc32c_continued(void *address, unsigned long length,
491     uint32_t crc);
492 
493 void idm_listbuf_insert(list_t *lst, idm_buf_t *buf);
494 
495 int idm_task_compare(const void *v1, const void *v2);
496 
497 idm_conn_t *idm_lookup_conn(uint8_t *isid, uint16_t tsih, uint16_t cid);
498 
499 #ifdef	__cplusplus
500 }
501 #endif
502 
503 #endif /* _IDM_IMPL_H_ */
504