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_ */