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 _ISCSIT_H_
26 #define _ISCSIT_H_
27
28 #pragma ident "@(#)iscsit.h 1.15 08/03/28 SMI"
29
30 #include "iscsit_authclient.h"
31
32 /*
33 * For some reason iscsi_protocol.h lists the max version as "0x02" and the
34 * min version as "0x00". RFC3720 clearly states that the current version
35 * number is 0x00 so that is what we will use.
36 */
37 #define ISCSIT_MIN_VERSION 0x00
38 #define ISCSIT_MAX_VERSION 0x00
39 #define ISCSIT_MAX_CONNECTIONS 1 /* No MC/S support */
40 #define ISCSIT_MAX_RECV_DATA_SEGMENT_LENGTH (32*1024)
41 #define ISCSIT_MAX_BURST_LENGTH (512*1024)
42 #define ISCSIT_MAX_FIRST_BURST_LENGTH ISCSI_DEFAULT_FIRST_BURST_LENGTH
43 #define ISCSIT_MAX_TIME2WAIT ISCSI_DEFAULT_TIME_TO_WAIT
44 #define ISCSIT_MAX_TIME2RETAIN ISCSI_DEFAULT_TIME_TO_RETAIN
45 /* XXX We want to increase max outstanding R2T at some point for performance */
46 #define ISCSIT_MAX_OUTSTANDING_R2T ISCSI_DEFAULT_MAX_OUT_R2T
47 #define ISCSIT_MAX_ERROR_RECOVERY_LEVEL 0
48
49 #define ISCSIT_DEFAULT_TPG "iscsit-default-tpg"
50 #define ISCSIT_DEFAULT_TPGT 1
51
52 #define ISCSI_MAX_TSIH 0xffff
53 #define ISCSI_UNSPEC_TSIH 0
54
55 #define ISCSIT_GLOBAL_LOCK() mutex_enter(&iscsit_global.global_mutex)
56 #define ISCSIT_GLOBAL_UNLOCK() mutex_exit(&iscsit_global.global_mutex)
57
58 typedef struct {
59 char *tpg_name;
60 kmutex_t tpg_mutex;
61 int tpg_online;
62 avl_tree_t tpg_portal_list;
63 avl_node_t tpg_global_ln;
64 } iscsit_tpg_t;
65
66 typedef struct {
67 iscsit_tpg_t *tpgt_tpg;
68 avl_node_t tpgt_tgt_ln;
69 uint16_t tpgt_tag;
70 } iscsit_tpgt_t;
71
72 typedef struct {
73 struct sockaddr_storage portal_addr;
74 uint16_t portal_port;
75 int portal_online;
76 avl_node_t portal_tpg_ln;
77 iscsit_tpg_t *portal_tpg;
78 idm_svc_t *portal_svc;
79 } iscsit_portal_t;
80
81
82 #define ISCSIT_TEMP_TARGET_NAME "eui.abcd001122334455"
83
84 typedef struct {
85 char *target_name;
86 kmutex_t target_mutex;
87 avl_tree_t target_tpgt_list;
88 avl_tree_t target_sess_list;
89 avl_node_t target_global_ln;
90 /* STMF lport == iSCSI target */
91 scsi_devid_desc_t *target_devid;
92 stmf_local_port_t *target_stmf_lport;
93 uint8_t target_stmf_state;
94 uint8_t target_stmf_state_not_acked;
95 } iscsit_tgt_t;
96
97 /*
98 * iSCSI Auth Information
99 */
100 typedef struct sess_auth {
101 /* Initiator's authentication information. */
102 char username[iscsiAuthStringMaxLength];
103 uint8_t password[iscsiAuthStringMaxLength];
104 int password_length;
105
106 /* Target's authentication information. */
107 char username_in[iscsiAuthStringMaxLength];
108 uint8_t password_in[iscsiAuthStringMaxLength];
109 int password_length_in;
110
111 /* authentication method list */
112 int authMethodValidList[iscsiAuthMethodMaxCount];
113 } sess_auth_t;
114
115 /*
116 * We have three state machines (so far) between the IDM connection state
117 * machine, the session state machine, and the login state machine. All
118 * of these states have some concept of "full feature mode". It's going
119 * to be obnoxious if we use a mixture of these "ffp" representations
120 * since it will be difficult to ensure the three state machines
121 * transition at exactly the same time. We should drive decisions that
122 * depend on FFP from the IDM state machine which is actually snooping
123 * the iSCSI PDU's and will always transition at the correct time.
124 *
125 * A consequence of this approach is that there is a window just after
126 * login completes where we may get a SCSI request but the session
127 * or login state machine has not quite transitioned to "FFP". Whether
128 * this is a problem depends on how we use those state machines. This
129 * is what we should use them for:
130 *
131 * IDM Connection state machine - Decisions related to command processing
132 * including whether a connection is in FFP
133 *
134 * Session state machine - Summarize the state of all available connections
135 * for the purposes of ERL1, ERL2 and MC/S. A session in LOGGED_IN state
136 * should always have at least one FFP connection but there may be a brief
137 * window where a session in ACTIVE might have one or more FFP connections
138 * even though ACTIVE is not strictly an FFP state according to the RFC.
139 *
140 * Login state machine -- drive the login process, collect negotiated
141 * parameters. Another side effect of this approach is that we may get
142 * the "notify ffp" callback from the IDM connection state machine before
143 * the login state machine has actually transitioned to FFP state.
144 */
145
146 struct iscsit_conn_s;
147
148 /* Update iscsit_ss_name table whenever session states are modified */
149 typedef enum {
150 SS_UNDEFINED = 0,
151 SS_Q1_FREE,
152 SS_Q2_ACTIVE,
153 SS_Q3_LOGGED_IN,
154 SS_Q4_FAILED,
155 SS_Q5_CONTINUE,
156 SS_Q6_DONE,
157 SS_Q7_ERROR,
158 SS_MAX_STATE
159 } iscsit_session_state_t;
160
161 /* Update iscsit_se_name table whenever session events are modified */
162 typedef enum {
163 SE_UNDEFINED = 0,
164 SE_CONN_IN_LOGIN, /* From login state machine */
165 SE_CONN_LOGGED_IN, /* FFP enabled client notification */
166 SE_CONN_FFP_FAIL, /* FFP disabled client notification */
167 SE_CONN_FAIL, /* Conn destroy client notification */
168 SE_SESSION_CLOSE, /* From Logout PDU handler */
169 SE_SESSION_REINSTATE, /* From login state machine */
170 SE_SESSION_TIMEOUT, /* Internal? */
171 SE_SESSION_CONTINUE, /* From login state machine */
172 SE_SESSION_CONTINUE_FAIL, /* From login state machine? */
173 SE_MAX_EVENT
174 } iscsit_session_event_t;
175
176 typedef struct {
177 stmf_scsi_session_t *ist_stmf_sess;
178 stmf_local_port_t *ist_lport;
179 iscsit_tgt_t *ist_tgt;
180 kmem_cache_t *ist_task_cache;
181 kmutex_t ist_mutex;
182 kcondvar_t ist_cv;
183 iscsit_session_state_t ist_state;
184 iscsit_session_state_t ist_last_state;
185 boolean_t ist_sm_busy;
186 boolean_t ist_sm_complete;
187 list_t ist_events;
188 int ist_conn_count;
189 int ist_ffp_conn_count;
190 struct iscsit_conn_s *ist_failed_conn;
191 timeout_id_t ist_state_timeout;
192 /* Track ffp connections separately? Might be handy... XXX */
193 list_t ist_conn_list;
194 avl_node_t ist_tgt_ln;
195 char *ist_initiator_name;
196 char *ist_initiator_alias;
197 char *ist_target_name;
198 char *ist_target_alias;
199 uint8_t ist_isid[ISCSI_ISID_LEN];
200 uint16_t ist_tsih;
201 uint32_t ist_expcmdsn;
202 uint32_t ist_maxcmdsn;
203 sess_auth_t ist_auth;
204 } iscsit_sess_t;
205
206 /* Update iscsit_ils_name table whenever login states are modified */
207 typedef enum {
208 ILS_UNDEFINED = 0,
209 ILS_LOGIN_INIT,
210 ILS_LOGIN_WAITING, /* Waiting for more login PDU's */
211 ILS_LOGIN_PROCESSING, /* Processing login request */
212 ILS_LOGIN_RESPONDING, /* Sending login response */
213 ILS_LOGIN_RESPONDED, /* Sent login response (no trans. to FFP) */
214 ILS_LOGIN_FFP, /* Sending last login PDU for final response */
215 ILS_LOGIN_DONE, /* Last login PDU sent (so we can free it) */
216 ILS_LOGIN_ERROR, /* Login error, login failed */
217 ILS_MAX_STATE
218 } iscsit_login_state_t;
219
220 /* Update iscsit_ile_name table whenever login events are modified */
221 typedef enum {
222 ILE_UNDEFINED = 0,
223 ILE_LOGIN_RCV,
224 ILE_LOGIN_RESP_READY,
225 ILE_LOGIN_FFP,
226 ILE_LOGIN_RESP_COMPLETE,
227 ILE_LOGIN_ERROR,
228 ILE_LOGIN_CONN_ERROR,
229 ILE_MAX_EVENT
230 } iscsit_login_event_t;
231
232 typedef struct {
233 uint32_t op_initial_params_set:1,
234 op_discovery_session:1,
235 op_initial_r2t:1,
236 op_immed_data:1,
237 op_data_pdu_in_order:1,
238 op_data_sequence_in_order:1;
239 uint64_t op_max_connections;
240 uint64_t op_max_recv_data_segment_length;
241 uint64_t op_max_burst_length;
242 uint64_t op_first_burst_length;
243 uint64_t op_default_time_2_wait;
244 uint64_t op_default_time_2_retain;
245 uint64_t op_max_outstanding_r2t;
246 uint64_t op_error_recovery_level;
247 } iscsit_op_params_t;
248
249 typedef struct {
250 iscsit_login_state_t icl_login_state;
251 iscsit_login_state_t icl_login_last_state;
252 boolean_t icl_busy;
253 boolean_t icl_login_complete;
254 kmutex_t icl_mutex;
255 uint32_t icl_login_itt;
256 uint8_t icl_login_csg;
257 uint8_t icl_login_nsg;
258 boolean_t icl_login_transit;
259 iscsit_auth_client_t icl_auth_client;
260 int icl_auth_pass;
261 list_t icl_login_events;
262 list_t icl_pdu_list;
263 uint16_t icl_tsih;
264 uint8_t icl_isid[ISCSI_ISID_LEN];
265 uint32_t icl_cmdsn;
266 char *icl_target_name;
267 char *icl_initiator_name;
268 char *icl_login_resp_buf;
269 int icl_login_resp_len; /* For kmem_free */
270 int icl_login_resp_valid_len;
271 uint8_t icl_login_resp_err_class;
272 uint8_t icl_login_resp_err_detail;
273 idm_pdu_t *icl_login_rej_resp;
274 idm_pdu_t *icl_login_resp;
275 nvlist_t *icl_request_nvlist;
276 nvlist_t *icl_response_nvlist;
277 nvlist_t *icl_negotiated_values;
278 } iscsit_conn_login_t;
279
280 #define SET_LOGIN_ERROR(SLE_ICT, SLE_CLASS, SLE_DETAIL) \
281 (SLE_ICT)->ict_login_sm.icl_login_resp_err_class = (SLE_CLASS); \
282 (SLE_ICT)->ict_login_sm.icl_login_resp_err_detail = (SLE_DETAIL);
283
284 typedef struct iscsit_conn_s {
285 idm_conn_t *ict_ic;
286 iscsit_sess_t *ict_sess;
287 list_node_t ict_sess_ln;
288 iscsit_conn_login_t ict_login_sm;
289 iscsit_op_params_t ict_op;
290 uint16_t ict_cid;
291 uint32_t ict_statsn;
292 struct iscsit_conn_s *ict_reinstate_conn;
293 uint32_t ict_reinstating:1;
294 } iscsit_conn_t;
295
296 #define ICT_FLAGS_DISCOVERY 0x00000001
297
298 typedef struct {
299 scsi_task_t *it_stmf_task;
300 idm_task_t *it_idm_task;
301 iscsit_conn_t *it_ict;
302 uint32_t it_cmdsn;
303 uint32_t it_itt;
304 uint32_t it_ttt;
305 } iscsit_task_t;
306
307
308 typedef struct {
309 dev_info_t *global_dip;
310 stmf_port_provider_t *global_pp;
311 stmf_dbuf_store_t *global_dbuf_store;
312 taskq_t *global_dispatch_taskq;
313 int global_drv_opencount;
314 avl_tree_t global_discovery_sessions;
315 avl_tree_t global_target_list;
316 avl_tree_t global_tpg_list;
317 iscsit_tpg_t *global_default_tpg;
318 vmem_t *global_tsih_pool;
319 kmutex_t global_mutex;
320 } iscsit_global_t;
321
322 extern iscsit_global_t iscsit_global;
323
324
325 idm_status_t
326 iscsit_login_sm_init(iscsit_conn_t *ict);
327
328 void
329 iscsit_login_sm_fini(iscsit_conn_t *ict);
330
331 void
332 iscsit_login_sm_event(iscsit_conn_t *ic, iscsit_login_event_t event,
333 idm_pdu_t *pdu);
334
335 void
336 iscsit_login_sm_event_locked(iscsit_conn_t *ic, iscsit_login_event_t event,
337 idm_pdu_t *pdu);
338
339 void
340 iscsit_send_async_event(iscsit_conn_t *ict, uint8_t async_event);
341
342 void
343 iscsit_pdu_tx(idm_pdu_t *pdu);
344
345 /*
346 * IDM conn ops
347 */
348
349 idm_rx_pdu_cb_t iscsit_op_scsi_cmd;
350 idm_rx_pdu_cb_t iscsit_rx_pdu;
351 idm_rx_pdu_error_cb_t iscsit_rx_pdu_error;
352 idm_client_notify_cb_t iscsit_client_notify;
353 idm_build_hdr_cb_t iscsit_build_hdr;
354
355 /*
356 * lport entry points
357 */
358 stmf_status_t
359 iscsit_xfer_scsi_data(scsi_task_t *task, stmf_data_buf_t *dbuf,
360 uint32_t ioflags);
361
362 stmf_status_t
363 iscsit_send_scsi_status(scsi_task_t *task, uint32_t ioflags);
364
365 void
366 iscsit_lport_task_free(scsi_task_t *task);
367
368 stmf_status_t
369 iscsit_abort(stmf_local_port_t *lport, int abort_cmd, void *arg,
370 uint32_t flags);
371
372 void
373 iscsit_ctl(stmf_local_port_t *lport, int cmd, void *arg);
374
375 /*
376 * Connection functions
377 */
378 idm_status_t
379 iscsit_conn_reinstate(iscsit_conn_t *existing_ict, iscsit_conn_t *ict);
380
381 void
382 iscsit_conn_destroy_done(iscsit_conn_t *ict);
383
384 /*
385 * Session functions
386 */
387 int
388 iscsit_sess_avl_compare(const void *void_sess1, const void *void_sess2);
389
390 iscsit_sess_t *
391 iscsit_sess_create(iscsit_tgt_t *tgt, iscsit_conn_t *ict,
392 uint32_t cmdsn, uint8_t *isid, char *initiator_name, char *target_name,
393 uint8_t *error_class, uint8_t *error_detail);
394
395 void
396 iscsit_sess_destroy(iscsit_sess_t *ist);
397
398 iscsit_conn_t *
399 iscsit_sess_lookup_conn(iscsit_sess_t *ist, uint16_t cid);
400
401 void
402 iscsit_sess_bind_conn(iscsit_sess_t *ist, iscsit_conn_t *ict);
403
404 void
405 iscsit_sess_unbind_conn(iscsit_sess_t *ist, iscsit_conn_t *ict);
406
407 void
408 iscsit_sess_set_auth(iscsit_sess_t *ist);
409
410 iscsit_sess_t *
411 iscsit_sess_reinstate(iscsit_sess_t *ist, iscsit_conn_t *ict,
412 uint8_t *error_class, uint8_t *error_detail);
413
414 void
415 iscsit_sess_sm_event(iscsit_sess_t *ist, iscsit_session_event_t event,
416 iscsit_conn_t *ict);
417
418 /*
419 * Target, TPGT, TPGT and portal functions
420 */
421 iscsit_tgt_t *
422 iscsit_tgt_lookup(char *target_name);
423
424 iscsit_tgt_t *
425 iscsit_tgt_create(char *target_name);
426
427 void
428 iscsit_tgt_destroy(iscsit_tgt_t *tgt);
429
430 int
431 iscsit_tgt_avl_compare(const void *void_tgt1, const void *void_tgt2);
432
433 iscsit_tpgt_t *
434 iscsit_tgt_lookup_tpgt(iscsit_tgt_t *tgt, uint16_t tag);
435
436 iscsit_portal_t *
437 iscsit_tgt_lookup_portal(iscsit_tgt_t *tgt, struct sockaddr_storage *sa,
438 uint16_t port);
439
440 iscsit_sess_t *
441 iscsit_tgt_lookup_sess(iscsit_tgt_t *tgt, char *initiator_name,
442 uint8_t *isid, uint16_t tsih);
443
444 void
445 iscsit_tgt_bind_sess(iscsit_tgt_t *tgt, iscsit_sess_t *sess);
446
447 void
448 iscsit_tgt_unbind_sess(iscsit_tgt_t *tgt, iscsit_sess_t *sess);
449
450 idm_status_t
451 iscsit_tgt_bind_tpgt(iscsit_tgt_t *tgt, iscsit_tpg_t *tpg, uint16_t tag);
452
453 void
454 iscsit_tgt_unbind_tpgt(iscsit_tgt_t *tgt, iscsit_tpgt_t *tpgt);
455
456 idm_status_t
457 iscsit_tgt_online(iscsit_tgt_t *tgt);
458
459 void
460 iscsit_tgt_offline(iscsit_tgt_t *tgt);
461
462 iscsit_tpg_t *
463 iscsit_tpg_lookup(char *tpg_name);
464
465 iscsit_tpg_t *
466 iscsit_tpg_create(char *tpg_name);
467
468 void
469 iscsit_tpg_destroy(iscsit_tpg_t *tpg);
470
471 int
472 iscsit_tpg_avl_compare(const void *void_tpg1, const void *void_tpg2);
473
474 iscsit_tpg_t *
475 iscsit_tpg_createdefault();
476
477 idm_status_t
478 iscsit_tpg_online(iscsit_tpg_t *tpg);
479
480 void
481 iscsit_tpg_offline(iscsit_tpg_t *tpg);
482
483 iscsit_portal_t *
484 iscsit_portal_lookup(iscsit_tpg_t *tpg, struct sockaddr_storage *sa,
485 uint16_t port);
486
487 iscsit_portal_t *
488 iscsit_portal_create(iscsit_tpg_t *tpg, struct sockaddr_storage *sa,
489 uint16_t port);
490
491 void
492 iscsit_portal_destroy(iscsit_portal_t *portal);
493
494 int
495 iscsit_portal_avl_compare(const void *void_portal1, const void *void_portal2);
496
497 idm_status_t
498 iscsit_portal_online(iscsit_portal_t *portal);
499
500 void
501 iscsit_portal_offline(iscsit_portal_t *portal);
502
503
504
505 #endif /* _ISCSIT_H_ */