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