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