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