Emulex Logo
OneCoreā„¢ Storage SDK Release 11.2
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ocs_session.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2011-2015, Emulex
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions and the following disclaimer in the documentation
13  * and/or other materials provided with the distribution.
14  *
15  * 3. Neither the name of the copyright holder nor the names of its contributors
16  * may be used to endorse or promote products derived from this software
17  * without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  *
31  */
32 
33 /**
34  * @file
35  * OCS iSCSI session managment functions.
36  */
37 /*!
38 @defgroup sess_mgnt iSCSI session management
39 */
40 
41 #include "ocs.h"
42 #include "ocs_iscsi.h"
43 #include "ocs_iscsi_spec.h"
44 #include "ocs_common.h"
45 #include "ocs_hal.h"
46 #include "ocs_iscsi_api.h"
47 #include "ocs_cxn.h"
48 #include "ocs_login.h"
49 #include "ocs_session.h"
50 
51 #define CMD_Q_TIMER_MS 30 /* 30 milliseconds */
52 
53 /* declare local functions */
54 static void ocs_session_check_queued_commands(ocs_session_t *session);
55 static void ocs_session_cmd_q_timeout(void *arg);
56 
57 
58 /**
59  * @ingroup sess_mgnt
60  * @brief Initialize the session management by allocating objects for sessions.
61  *
62  * @param iscsi Pointer to the iSCSI structure that represents this device.
63  *
64  * @return Returns 0 on success.
65  */
66 int32_t
68 {
69  uint32_t i,j;
70 
71  ocs_lock_init(iscsi->os, &iscsi->sess_queue_lock, "session_mem_lock[%d]", ocs_instance(iscsi->os));
72 
73  /* Allocate the session objects and put them on the free list. */
74  ocs_list_init(&iscsi->sess_free, ocs_session_t, link);
75  ocs_list_init(&iscsi->sess_busy, ocs_session_t, link);
76 
77  iscsi->sess_mem = ocs_malloc(iscsi->os, sizeof(ocs_session_t) *
78  iscsi->num_cxns,
79  OCS_M_ZERO | OCS_M_NOWAIT);
80  if (iscsi->sess_mem == NULL) {
81  ocs_log_err(iscsi->os, "Failed to allocate sessions, num_cxns is %d\n",
82  iscsi->num_cxns);
83  ocs_log_err(iscsi->os, "sizeof(ocs_session_t) is %ld, total alloc is %ld\n", sizeof(ocs_session_t), sizeof(ocs_session_t) * iscsi->num_cxns);
84  return -ENOMEM;
85  }
86 
87  for (i = 0; i < iscsi->num_cxns; i++) {
88  ocs_session_t *session = &iscsi->sess_mem[i];
89 
90  /* Allocate memory for the command queue */
91  session->cmd_q = ocs_malloc(iscsi->os, sizeof(ocs_session_q_unsol_t) *
93  OCS_M_ZERO | OCS_M_NOWAIT);
94 
95  if (session->cmd_q == NULL) {
96  ocs_log_err(iscsi->os, "Failed to allocate memory for cmd queue\n");
97  return -ENOMEM;
98  }
99 
100  ocs_lock_init(iscsi->os, &session->cmd_q_lock, "cmd_q lock[%d]", i);
101  ocs_list_init(&session->cxn_list, ocs_cxn_t, sess_link);
102  session->ocs = iscsi->os;
103  session->iscsi = iscsi;
104  session->instance_index = i;
105  ocs_list_init(&session->cmd_q_waiting, ocs_session_q_unsol_t, link);
106  ocs_list_init(&session->cmd_q_free, ocs_session_q_unsol_t, link);
107  for (j = 0; j < OCS_ISCSI_MAX_QUEUED_CMDSN; j++) {
108  ocs_list_add_tail(&session->cmd_q_free, &session->cmd_q[j]);
109  }
110  ocs_list_add_tail(&iscsi->sess_free, session);
111  }
112 
113  return 0;
114 }
115 
116 /**
117  * @ingroup sess_mgnt
118  * @brief Releases the session objects used within the login module.
119  *
120  * @param iscsi Pointer to the iSCSI object.
121  */
122 void
124 {
125  ocs_session_t *session;
126  uint32_t i;
127 
128  /* Empty the lists */
129  ocs_lock(&iscsi->sess_queue_lock);
130  session = ocs_list_get_head(&iscsi->sess_free);
131  while (NULL != session) {
133  session = ocs_list_get_head(&iscsi->sess_free);
134  }
135 
136  session = ocs_list_get_head(&iscsi->sess_busy);
137  while (NULL != session) {
139 
140  /* Need to release this lock prior to calling ocs_session_close() */
141  ocs_unlock(&iscsi->sess_queue_lock);
142  ocs_session_close(session, TRUE);
143  ocs_lock(&iscsi->sess_queue_lock);
144 
145  session = ocs_list_get_head(&iscsi->sess_busy);
146  }
147  ocs_unlock(&iscsi->sess_queue_lock);
148 
149  if (iscsi->sess_mem != NULL) {
150  for (i = 0; i < iscsi->num_cxns; i++) {
151  ocs_session_t *session = &iscsi->sess_mem[i];
152 
153  if (session->cmd_q != NULL) {
154  ocs_free(iscsi->os, session->cmd_q,
155  sizeof(ocs_session_q_unsol_t) *
157  session->cmd_q = NULL;
158  }
159  ocs_lock_free(&session->cmd_q_lock);
160  }
161  ocs_free(iscsi->os, iscsi->sess_mem, sizeof(ocs_session_t) * iscsi->num_cxns);
162  iscsi->sess_mem = NULL;
163  }
164 
165  ocs_lock_free(&iscsi->sess_queue_lock);
166 }
167 
168 /**
169  * @ingroup sess_mgnt
170  * @brief Find an existing session or create a new one based on the login parameters.
171  *
172  * @param cxn Pointer to the connection object.
173  * @param tgt_name Pointer to the target name.
174  * @param ini_name Pointer to the initiator name.
175  * @param isid The iSCSI initiator session ID from the login PDU.
176  * @param tsih The iSCSI target session handle from the login PDU.
177  * @param cid The iSCSI connection ID from the login PDU.
178  * @param cmd_sn The iSCSI command SN from the login PDU.
179  *
180  * @return
181  * - 0 - success.
182  * - 1 - session does not exist.
183  * - 2 - exceeds Max Cxn.
184  * - 3 - no resources.
185  */
186 int32_t
187 ocs_session_cxn_new(ocs_cxn_t *cxn,
188  char *tgt_name,
189  char *ini_name,
190  uint64_t isid,
191  uint16_t tsih,
192  uint16_t cid,
193  uint32_t cmd_sn)
194 {
195  ocs_t *ocs = cxn->ocs;
196  ocs_iscsi_t *iscsi = cxn->iscsi;
197  ocs_session_t *session;
198  ocs_cxn_t *cxn_tmp;
199  uint8_t isid_found = FALSE;
200  uint8_t cxn_found = FALSE;
201  uint8_t create_new_session = FALSE;
202  uint8_t add_cxn = FALSE;
203  uint32_t cxn_cnt = 0;
204  int32_t rc = 0;
205 
206  /*
207  * See section 3.5.1 of the iSCSI spec, either find the session,
208  * create a new one or reject the login.
209  */
210 
211  /* Find the iSID in the existing sessions */
212  ocs_lock(&iscsi->sess_queue_lock);
213  ocs_list_foreach(&iscsi->sess_busy, session) {
214  if (isid == session->isid &&
215  !session->is_removed &&
216  ocs_strcmp(tgt_name, session->tgt_name) == 0 &&
217  ocs_strcmp(ini_name, session->ini_name) == 0) {
218  isid_found = TRUE;
219  break;
220  }
221  }
222  ocs_unlock(&iscsi->sess_queue_lock);
223 
224  if (isid_found) {
225  /* Find the connection and also count the connections*/
226  ocs_lock(&iscsi->sess_queue_lock);
227  ocs_list_foreach(&session->cxn_list, cxn_tmp) {
228  cxn_cnt++;
229  if (cid == cxn_tmp->cid) {
230  cxn_found = TRUE;
231  }
232  }
233  ocs_unlock(&iscsi->sess_queue_lock);
234 
235  if (tsih == 0) {
236  /* Perform session reinstatement */
237  ocs_log_debug(ocs, "Session reinstatement for isid 0x%" PRIx64 ", tsih = 0x%x\n",
238  session->isid, session->tsih);
239  ocs_session_close(session, TRUE);
240  create_new_session = TRUE;
241  cxn_cnt = 0;
242  } else if (tsih != session->tsih) {
243  /* Session does not exist */
244  rc = 1;
245  } else {
246  if (cxn_found) {
247  /* Perform connection reinstatement */
248  (void)ocs_cxn_close(cxn_tmp, TRUE);
249  add_cxn = TRUE;
250  } else {
251  /* Make sure we have not exceeded max connections */
252  if (cxn_cnt >= session->login_options.max_connections) {
253  rc = 2;
254  } else {
255  add_cxn = TRUE;
256  }
257  }
258  }
259  } else {
260  /* no session found */
261  if (tsih == 0) {
262  /* Create a new session */
263  create_new_session = TRUE;
264  } else {
265  /* Fail the login - session does not exist */
266  rc = 1;
267  }
268  }
269 
270  if (rc == 0 && create_new_session) {
271  /* Allocate one from the free list */
272  ocs_lock(&iscsi->sess_queue_lock);
273  session = ocs_list_get_head(&iscsi->sess_free);
274  if (NULL != session) {
276  ocs_list_add_tail(&iscsi->sess_busy, session);
277 
278  session->isid = isid;
279  /* tsih cannot be 0 */
280  if (ocs_strlen(tgt_name) < OCS_MAX_ISCSI_NAME) {
281  ocs_strcpy(session->tgt_name, tgt_name);
282  } else {
283  ocs_strncpy(session->tgt_name, tgt_name, OCS_MAX_ISCSI_NAME);
284  ocs_log_test(ocs, "Tgt name of len %d exceeds max of %d chars\n",
285  (int)ocs_strlen(tgt_name), OCS_MAX_ISCSI_NAME);
286  }
287  if (ocs_strlen(ini_name) < OCS_MAX_ISCSI_NAME) {
288  ocs_strcpy(session->ini_name, ini_name);
289  } else {
290  ocs_strncpy(session->ini_name, ini_name, OCS_MAX_ISCSI_NAME);
291  ocs_log_test(ocs, "Ini name of len %d exceeds max of %d chars\n",
292  (int)ocs_strlen(ini_name), OCS_MAX_ISCSI_NAME);
293  }
294  session->tsih = session->instance_index + 1;
295  session->login_options.initial_r2t = 1;
296  session->login_options.immediate_data = (ocs->enable_immediate_data ? 1 : 0);;
297  session->login_options.data_pdu_in_order = 1;
298  session->login_options.data_sequence_in_order = 1;
299  session->login_options.error_recovery_level = 0;
300  session->login_options.first_burst = OCS_HAL_RQ_SIZE_DATA;
301  session->login_options.max_burst = OCS_ISCSI_LOGIN_MAX_BURST_LEN;
302  session->login_options.max_connections = ocs_iscsi_get_max_cxns(ocs, tgt_name, ini_name);
303  session->login_options.max_r2t = 1;
304  session->login_options.def_time_to_wait = OCS_ISCSI_LOGIN_DEFAULT_TIME_2_WAIT;
305  session->login_options.def_time_to_retain = OCS_ISCSI_LOGIN_DEFAULT_TIME_2_RETAIN;
306 
307  session->cmd_sn = cmd_sn;
308  session->is_discovery_session = FALSE;
309  session->is_removed = FALSE;
310  session->cmd_q_num_queued = 0;
311  add_cxn = TRUE;
312 
313  ocs_log_debug(ocs, "Session created for isid 0x%" PRIx64 ", tsih = 0x%x\n",
314  session->isid, session->tsih);
315  } else {
316  rc = 3;
317  }
318  ocs_unlock(&iscsi->sess_queue_lock);
319  }
320 
321  if (rc == 0 && add_cxn) {
322  ocs_lock(&iscsi->sess_queue_lock);
323  ocs_list_add_tail(&session->cxn_list, cxn);
324  ocs_unlock(&iscsi->sess_queue_lock);
325 
326  cxn->session = session;
327  cxn->is_leading_login = (cxn_cnt == 0);
328  ocs_log_debug(ocs, "Added connection 0x%x to isid 0x%" PRIx64 ", tsih = 0x%x, is leading login = %d\n",
329  cxn->cid, session->isid, session->tsih,
330  cxn->is_leading_login);
331  }
332 
333  return rc;
334 }
335 
336 /**
337  * @ingroup sess_mgnt
338  * @brief Removes a connection from its session.
339  *
340  * @param cxn Pointer to the connection object.
341  */
342 int32_t
343 ocs_session_cxn_del(ocs_cxn_t *cxn)
344 {
345  ocs_iscsi_t *iscsi = cxn->iscsi;
346  ocs_session_t *session = cxn->session;
347 
348  if (session) {
349  ocs_lock(&iscsi->sess_queue_lock);
350  ocs_list_remove(&session->cxn_list, cxn);
351  cxn->session = NULL;
352 
353  ocs_log_debug(iscsi->os, "removed connection 0x%x to isid 0x%" PRIx64 ", tsih = 0x%x\n",
354  cxn->cid, session->isid, session->tsih);
355 
356  /* If all the connections are removed, then free the session */
357  cxn = ocs_list_get_head(&session->cxn_list);
358  if (cxn == NULL) {
359  ocs_list_remove(&iscsi->sess_busy, session);
360  ocs_list_add_tail(&iscsi->sess_free, session);
361 
362  ocs_log_debug(iscsi->os, "Session deleted for isid 0x%" PRIx64 " , tsih = 0x%x\n",
363  session->isid, session->tsih);
364  }
365  ocs_unlock(&iscsi->sess_queue_lock);
366  }
367  return 0;
368 }
369 
370 /**
371  * @ingroup sess_mgnt
372  * @brief Locate a connection within a session based on the cid.
373  *
374  * @param session Pointer to the session object.
375  * @param cid The iSCSI connection ID to find.
376  *
377  * @return Pointer to the connection, or NULL if not found.
378  */
379 ocs_cxn_t *ocs_session_cxn_find(ocs_session_t *session,
380  uint16_t cid)
381 {
382  ocs_iscsi_t *iscsi = session->iscsi;
383  ocs_cxn_t *cxn;
384  ocs_cxn_t *rc = NULL;
385 
386  ocs_lock(&iscsi->sess_queue_lock);
387  ocs_list_foreach(&session->cxn_list, cxn) {
388  if (cxn->cid == cid) {
389  rc = cxn;
390  break;
391  }
392  }
393  ocs_unlock(&iscsi->sess_queue_lock);
394  return rc;
395 }
396 
397 /**
398  * @ingroup sess_mgnt
399  * @brief Closes all connections on a session.
400  *
401  * @param session Pointer to the session object.
402  * @param reset A non-zero value causes a connection reset to be issued.
403  */
404 void
405 ocs_session_close(ocs_session_t *session, uint8_t reset)
406 {
407  ocs_iscsi_t *iscsi = session->iscsi;
408  ocs_cxn_t *cxn;
410 
411  session->is_removed = TRUE;
412  /* release any buffers held by queued commands */
413  ocs_lock(&session->cmd_q_lock);
414  cmd = ocs_list_get_head(&session->cmd_q_waiting);
415  if (NULL != cmd) {
416  ocs_list_remove_head(&session->cmd_q_waiting);
417  /* Don't post the buffers if the queues are not setup */
418  if (iscsi->is_hal_initialized == TRUE) {
419  ocs_iscsi_rx_buffers_free(iscsi, cmd->hdr, cmd->data);
420  }
421  ocs_list_add_tail(&session->cmd_q_free, cmd);
422  session->cmd_q_num_queued--;
423 
424  cmd = ocs_list_get_head(&session->cmd_q_waiting);
425  }
426  ocs_unlock(&session->cmd_q_lock);
427 
428  /* Kill the cmd_q timer if it is active */
429  if (ocs_timer_pending(&session->cmd_q_timer)) {
430  ocs_del_timer(&session->cmd_q_timer);
431  }
432 
433  ocs_lock(&iscsi->sess_queue_lock);
434  ocs_list_foreach(&session->cxn_list, cxn) {
435  cxn->cxn_state = CONN_STATE_LOGOUT_REQUESTED;
436  (void)ocs_cxn_close(cxn, reset);
437  }
438  ocs_unlock(&iscsi->sess_queue_lock);
439 }
440 
441 
442 /**
443  * @ingroup sess_mgnt
444  * @brief Updates the max_cmd_sn based on the number IOs available.
445  *
446  * @param session Pointer to the session object.
447  */
448 void
449 ocs_session_max_cmd_sn_upd(ocs_session_t *session)
450 {
451  uint32_t window_size;
452  uint32_t max_cmd_sn;
453 
454  window_size = OCS_ISCSI_MAX_QUEUED_CMDSN - session->cmd_q_num_queued;
455 
456  /*
457  * Subtract 2 commands to allow for a single immediate command and a
458  * task management command.
459  */
460  if (window_size > 2) {
461  window_size -=2;
462  }
463 
464  /*
465  * One last trick, the max_cmd_sn cannot move backwards or it will be
466  * discarded by the initiator. We also want to allow the max_cmd_sn to
467  * be equal to 1 less than the exp_cmd_sn (closed window) to prevent more
468  * commands from comming.
469  */
470  max_cmd_sn = (session->exp_cmd_sn + window_size) - 1;
471  if (GT_WRAPPED(max_cmd_sn, session->max_cmd_sn)) {
472  /* New number wrapped and therefore it is bigger => update */
473  session->max_cmd_sn = max_cmd_sn;
474  } else if (max_cmd_sn > session->max_cmd_sn) {
475  /* not wrapped, but bigger => update */
476  session->max_cmd_sn = max_cmd_sn;
477  }
478 
479 }
480 
481 /**
482  * @brief This function is called to process commands on a session command queue.
483  *
484  * @param arg Pointer to the session object.
485  */
486 static void
488 {
489  ocs_session_t *session = arg;
490 
492 }
493 
494 /**
495  * @ingroup sess_mgnt
496  * @brief Checks the queued command to see if any can start.
497  *
498  * @param session Pointer to the session object.
499  */
500 static void
501 ocs_session_check_queued_commands(ocs_session_t *session)
502 {
503  ocs_iscsi_t *iscsi = session->iscsi;
504  ocs_t *ocs = session->ocs;
505  ocs_session_q_unsol_t *cmd_q;
506  ocs_session_q_unsol_t *cmd_q_next;
507  uint8_t cmd_processed = TRUE;
508  uint8_t set_timer = FALSE;
509  uint8_t release_entry;
510  uint8_t free_rx_buffer;
511  uint8_t decr_cmd_sn;
512  ocs_pdu_process_rtn_e pdu_status;
513  uint8_t reject_reason;
514  int32_t rc;
515 
516  ocs_lock(&session->cmd_q_lock);
517  while (cmd_processed) {
518  cmd_processed = FALSE;
519 
520  ocs_list_foreach_safe(&session->cmd_q_waiting, cmd_q, cmd_q_next) {
521  iscsi_login_cmd_hdr_t *bhs = cmd_q->hdr->dma.virt;
522 
523  release_entry = FALSE;
524  free_rx_buffer = FALSE;
525  decr_cmd_sn = FALSE;
526  if (unlikely(before(cmd_q->cmd_sn, session->exp_cmd_sn))) {
527  /* Discard */
528  release_entry = TRUE;
529  free_rx_buffer = TRUE;
530  ocs_log_test(ocs, "Dropping cmd_sn 0x%x, exp_cmd_sn 0x%x for session instance %d\n",
531  cmd_q->cmd_sn,
532  session->exp_cmd_sn,
533  session->instance_index);
534  } else if (cmd_q->cmd_sn == session->exp_cmd_sn) {
535  if (cmd_q->aborted) {
536  ocs_iscsi_rx_buffers_free(iscsi, cmd_q->hdr, cmd_q->data);
537  pdu_status = OCS_PDU_RTN_PROCESSED;
538  } else {
539  /*
540  * Increment the cmdSN so that any
541  * response will carry the new values,
542  * in the case of a reject, then we will
543  * have to back it back out.
544  */
545  if (bhs->immediate == 0) {
546  session->exp_cmd_sn++;
547  }
548  pdu_status = ocs_iscsi_tgt_process_cmd_sn
549  (iscsi,
550  cmd_q->cxn,
551  cmd_q->hdr,
552  cmd_q->hdr_len,
553  cmd_q->data,
554  cmd_q->data_len,
555  cmd_q->code,
556  &reject_reason);
557  }
558 
559  switch(pdu_status) {
561  release_entry = TRUE;
562  free_rx_buffer = TRUE;
563  cmd_processed = TRUE;
564  break;
566  release_entry = TRUE;
567  break;
568 
570  decr_cmd_sn = TRUE;
571  /* Leave in queue, set timer */
572  set_timer = TRUE;
573  break;
575  ocs_log_test(ocs, "PDU handler returned reject\n");
576 
577  /* Do not increment cmdSN on reject */
578  decr_cmd_sn = TRUE;
579  rc = ocs_iscsi_send_reject(cmd_q->cxn,
580  cmd_q->hdr->dma.virt,
581  cmd_q->hdr_len,
582  reject_reason);
583  if (rc == 0 ||
584  rc == OCS_LOGIN_REQUEST_QUEUED) {
585  release_entry = TRUE;
586  free_rx_buffer = TRUE;
587  } else {
588  /* Leave in queue, set timer */
589  set_timer = TRUE;
590  }
591  break;
592 
594  ocs_log_test(ocs, "general error on cmdsn %d", cmd_q->cmd_sn);
595  decr_cmd_sn = TRUE;
596  release_entry = TRUE;
597  free_rx_buffer = TRUE;
598  cmd_processed = TRUE;
599  break;
600  }
601  }
602  if (release_entry) {
603  ocs_list_remove(&session->cmd_q_waiting, cmd_q);
604  if (free_rx_buffer) {
605  ocs_iscsi_rx_buffers_free(iscsi, cmd_q->hdr, cmd_q->data);
606  }
607  ocs_list_add_tail(&session->cmd_q_free, cmd_q);
608  session->cmd_q_num_queued--;
609  }
610  if (decr_cmd_sn && bhs->immediate == 0) {
611  session->exp_cmd_sn--;
612  }
613  }
614  }
615  ocs_unlock(&session->cmd_q_lock);
616 
617  if (set_timer) {
618  if (!ocs_timer_pending(&session->cmd_q_timer)) {
619  ocs_setup_timer(ocs, &session->cmd_q_timer,
621  session,
622  CMD_Q_TIMER_MS, false);
623  }
624  }
625 }
626 
627 /**
628  * @ingroup sess_mgnt
629  * @brief Adds a command to the command queue.
630  *
631  * @param cxn Pointer to the connection object.
632  * @param hdr DMA memory information for the header.
633  * @param hdr_len Length of the header received.
634  * @param data DMA memory information for the data.
635  * @param data_len Length of the data received.
636  * @param code Type of callback received from the chip
637  * (i.e. SLI_STATUS_UNSOL_DATA_DIGEST_ERROR).
638  * @param cmd_sn The iSCSI command sequence number.
639  *
640  * @return Returns 0 on success.
641  */
642 static int32_t
644  ocs_hal_rq_buffer_t *hdr,
645  uint32_t hdr_len,
646  ocs_hal_rq_buffer_t *data,
647  uint32_t data_len,
648  uint8_t code,
649  uint32_t cmd_sn)
650 {
651  ocs_iscsi_t *iscsi = cxn->iscsi;
652  ocs_session_t *session = cxn->session;
653  ocs_session_q_unsol_t *cmd_q;
654  int32_t rc = 0;
655 
656  /* make sure the session is not null */
657  if (session == NULL) {
658  rc = -1;
659  } else {
660  ocs_lock(&session->cmd_q_lock);
661  cmd_q = ocs_list_get_head(&session->cmd_q_free);
662  if (NULL != cmd_q) {
663  ocs_list_remove_head(&session->cmd_q_free);
664  cmd_q->cxn = cxn;
665  cmd_q->cmd_sn = cmd_sn;
666  cmd_q->hdr = hdr;
667  cmd_q->hdr_len = hdr_len;
668  cmd_q->data = data;
669  cmd_q->data_len = data_len;
670  cmd_q->code = code;
671  cmd_q->aborted = FALSE;
672  ocs_list_add_tail(&session->cmd_q_waiting, cmd_q);
673  session->cmd_q_num_queued++;
674  } else {
675  ocs_log_test(iscsi->os, "no room on command queue");
676  rc = -1;
677  }
678  ocs_unlock(&session->cmd_q_lock);
679  }
680  return rc;
681 }
682 
683 
684 /**
685  * @ingroup sess_mgnt
686  * @brief Function to handle unsolicited PDUs on a target.
687  *
688  * @param cxn Pointer to the connection object.
689  * @param hdr DMA memory information for the header.
690  * @param hdr_len Length of the header received.
691  * @param data DMA memory information for the data.
692  * @param data_len Length of the data received.
693  * @param code Type of callback received from the chip
694  * (i.e. SLI_STATUS_UNSOL_DATA_DIGEST_ERROR)
695  *
696  * @return Returns 0 on success.
697  */
698 int32_t
700  ocs_hal_rq_buffer_t *hdr,
701  uint32_t hdr_len,
702  ocs_hal_rq_buffer_t *data,
703  uint32_t data_len,
704  uint8_t code)
705 {
706  ocs_iscsi_t *iscsi = cxn->iscsi;
707  ocs_session_t *session = cxn->session;
708  iscsi_login_cmd_hdr_t *bhs = hdr->dma.virt;
709  uint32_t cmd_sn = ocs_be32toh(bhs->cmd_sn);
710  ocs_pdu_process_rtn_e pdu_status;
711  uint8_t decr_cmd_sn = FALSE;
712  uint8_t reject_reason;
713  int32_t rc = 0;
714 
715  /*
716  * If the header length is zero, then this is a frame freed as part of
717  * a connection cleanup, just free the buffer.
718  */
719  if (hdr_len == 0 ||
720  (session != NULL && session->is_removed)) {
721  return -1;
722  }
723 
724  /*
725  * A target receiving any PDU except a Login request before the Login
726  * phase is started MUST immediately terminate the connection on which
727  * the PDU was received.
728  */
729  if (cxn->cxn_state == CONN_STATE_NEW_CONN &&
730  bhs->opcode != ISCSI_CMD_LOGIN) {
731  /*
732  * It's possible to get an unsolicited PDU before we've associated
733  * the connection with an iscsi structure.
734  */
735  if (iscsi) {
736  ocs_log_test(iscsi->os, "startup connection rcvd opcode 0x%x instead of logi PDU",
737  bhs->opcode);
738  }
739  ocs_cxn_close(cxn, TRUE);
740  return -1;
741  /*
742  * Once the Login phase has started, if the target receives any PDU
743  * except a Login request, it MUST send a Login reject (with Status
744  * "invalid during login") and then disconnect. If the initiator
745  * receives any PDU except a Login response, it MUST immediately
746  * terminate the connection.
747  */
748  } else if (cxn->cxn_state == CONN_STATE_LOGIN_PROGRESS &&
749  bhs->opcode != ISCSI_CMD_LOGIN) {
750  ocs_log_test(iscsi->os, "connection rcvd opcode 0x%x during login",
751  bhs->opcode);
753  (cxn, ocs_be32toh(bhs->itt));
754  if (rc != 0 &&
755  rc != OCS_LOGIN_REQUEST_QUEUED) {
756  ocs_log_test(iscsi->os, "Failed sending Invalid login response");
757  }
758  ocs_cxn_close(cxn, FALSE);
759  return 0;
760  } else if (cxn->cxn_state == CONN_STATE_LOGOUT_REQUESTED &&
761  bhs->opcode != ISCSI_CMD_LOGOUT) {
762  /* Reject any PDUs received after requesting logout */
763  ocs_log_test(iscsi->os, "%s Non-logout PDU after logout request - reject\n",
764  cxn->display_name);
765  return ocs_iscsi_send_reject(cxn, hdr->dma.virt, hdr_len,
767  } else if (cxn->cxn_state == CONN_STATE_FULL_FEATURE &&
768  bhs->opcode == ISCSI_CMD_LOGIN) {
769  /* Reject any PDUs received after requesting logout */
770  ocs_log_test(iscsi->os, "%s Login PDU after login complete - reject\n",
771  cxn->display_name);
772  return ocs_iscsi_send_reject(cxn, hdr->dma.virt, hdr_len,
774  } else if (cxn->cxn_state == CONN_STATE_FULL_FEATURE &&
775  session != NULL &&
776  session->is_discovery_session) {
777  uint8_t reason = ((iscsi_logout_cmd_hdr_t*)bhs)->reason_code;
778 
779  /*
780  * For discovery sessions, The target MUST ONLY accept text
781  * requests with the SendTargets key and a logout request with
782  * the reason "close the session". All other requests MUST be
783  * rejected.
784  */
785  if (bhs->opcode != ISCSI_CMD_TEXT &&
786  bhs->opcode != ISCSI_CMD_LOGOUT) {
787  ocs_log_test(iscsi->os, "%s Only Text and logout allowed on discovery sessions\n",
788  cxn->display_name);
789  ocs_cxn_close(cxn, FALSE);
790  return 0;
791  } else if (bhs->opcode == ISCSI_CMD_LOGOUT &&
793  reason != LOGOUT_REASON_CLOSE_SESS) {
794  ocs_log_test(iscsi->os, "%s Discovery logout with bad reason %d\n",
795  cxn->display_name, reason);
796  ocs_cxn_close(cxn, FALSE);
797  return 0;
798  }
799  }
800 
801  /* Clear the idle count */
802  cxn->idle_count = 0;
803 
804  /*
805  * If we get a data digest error on the PDU, then we reject it here and
806  * no acknowledge the cmd_sn as it will have to be re-transmitted.
807  */
809  ocs_log_test(iscsi->os, "Received data digest error");
810  if (ocs_iscsi_send_reject(cxn, hdr->dma.virt, hdr_len,
812  ocs_log_test(iscsi->os, "error sending reject for data digest error");
813  ocs_cxn_close(cxn, FALSE);
814  }
815  return 0;
816  }
817 
818  /*
819  * Verify the cmdSN and then update the expected/max cmdSN fields.
820  *
821  * Immediate commands may be outside the command window (No checks)
822  * Non-immediate commands must be within the range.
823  * Multiple connections are not currently supported, so everything should be
824  * in order.
825  */
826  if (bhs->immediate ||
827  (session != NULL && cmd_sn == session->exp_cmd_sn)) {
828  /*
829  * Increment the cmdSN so that any response will carry the new
830  * values, in the case of a reject, then we will have to back
831  * it back out.
832  */
833  if (session != NULL &&
834  bhs->immediate == 0) {
835  session->exp_cmd_sn++;
836  }
837 
838  pdu_status = ocs_iscsi_tgt_process_cmd_sn(iscsi,
839  cxn,
840  hdr,
841  hdr_len,
842  data,
843  data_len,
844  code,
845  &reject_reason);
846  switch(pdu_status) {
848  break;
851  break;
853  decr_cmd_sn = TRUE;
854  rc = ocs_session_queue_command(cxn,
855  hdr,
856  hdr_len,
857  data,
858  data_len,
859  code,
860  cmd_sn);
861  break;
863  ocs_log_test(iscsi->os, "%s PDU handler returned reject\n",
864  cxn->display_name);
865  /* Do not increment cmdSN on reject */
866  decr_cmd_sn = TRUE;
867  rc = ocs_iscsi_send_reject(cxn, hdr->dma.virt, hdr_len,
868  reject_reason);
869  if (rc != 0 &&
870  rc != OCS_LOGIN_REQUEST_QUEUED) {
871  rc = ocs_session_queue_command(cxn,
872  hdr,
873  hdr_len,
874  data,
875  data_len,
876  code,
877  cmd_sn);
878  }
879  break;
881  decr_cmd_sn = TRUE;
882  ocs_log_test(iscsi->os, "%s general error on cmdsn %d",
883  cxn->display_name, cmd_sn);
884  rc = -1;
885  break;
886  }
887 
888  /* Backup the cmdSN if required */
889  if (decr_cmd_sn &&
890  session != NULL &&
891  bhs->immediate == 0) {
892  session->exp_cmd_sn--;
893  }
894 
895  if (session != NULL && session->cmd_q_num_queued > 0) {
897  }
898 
899  if (session != NULL) {
901  }
902  } else if (session != NULL && after(cmd_sn, session->exp_cmd_sn)) {
903  rc = ocs_session_queue_command(cxn,
904  hdr,
905  hdr_len,
906  data,
907  data_len,
908  code,
909  cmd_sn);
910  } else {
911  /*
912  * An old command SN was received, this may be due to an
913  * attempt to plug a perceived cmdsn hole. Silently discard
914  * the PDU.
915  */
916  rc = 0;
917  }
918 
919  return rc;
920 }
921 
922 
923 /**
924  * @brief Abort a specific IO based on the ITT.
925  *
926  * @param session Pointer to the session object.
927  * @param itt Initiator task tag to abort.
928  *
929  * @return Returns 0 if the IO was found.
930  */
931 int32_t
932 ocs_session_abort_itt(ocs_session_t *session,
933  uint32_t itt)
934 {
935  ocs_t *ocs = session->ocs;
936  ocs_session_q_unsol_t *cmd_q;
937  int32_t rc = -1;
938 
939  ocs_lock(&session->cmd_q_lock);
940  ocs_list_foreach(&session->cmd_q_waiting, cmd_q) {
941  iscsi_login_cmd_hdr_t *bhs = cmd_q->hdr->dma.virt;
942  uint32_t cmd_itt = ocs_be32toh(bhs->itt);
943  if (cmd_itt == itt) {
944  cmd_q->aborted = TRUE;
945  rc = 0;
946  }
947  }
948  ocs_unlock(&session->cmd_q_lock);
949 
950  ocs_log_debug(ocs, "ITT 0x%x aborted = %s for session instance %d\n",
951  itt,
952  (rc == 0 ? "Yes" : "No"),
953  session->instance_index);
954  return rc;
955 }
956 
957 
958 /**
959  * @brief Abort a specific IO based on the cmdSN of the abort request
960  *
961  * @param session Pointer to the session object.
962  * @param cmdsn Any commands preceding this cmdSN are aborted.
963  */
964 void
965 ocs_session_abort_cmdsn(ocs_session_t *session,
966  uint32_t cmdsn)
967 {
968  ocs_t *ocs = session->ocs;
969  ocs_session_q_unsol_t *cmd_q;
970  int32_t rc = -1;
971 
972  ocs_lock(&session->cmd_q_lock);
973  ocs_list_foreach(&session->cmd_q_waiting, cmd_q) {
974  if (cmd_q->cmd_sn <= cmdsn) {
975  cmd_q->aborted = TRUE;
976  rc = 0;
977  }
978  }
979  ocs_unlock(&session->cmd_q_lock);
980 
981  ocs_log_debug(ocs, "cmd_sn 0x%x aborted = %s for session instance %d\n",
982  cmdsn,
983  (rc == 0 ? "Yes" : "No"),
984  session->instance_index);
985 }
986 
987 /**
988  * @brief Abort a specific IO based on the cmdSN of the abort request.
989  *
990  * @param iscsi Pointer to the iSCSI object.
991  * @param cmdsn Any commands preceding this cmdSN are aborted.
992  */
993 void
995  uint32_t cmdsn)
996 {
997  ocs_session_t *session;
998 
999  ocs_lock(&iscsi->sess_queue_lock);
1000  ocs_list_foreach(&iscsi->sess_busy, session) {
1001  ocs_session_abort_cmdsn(session, cmdsn);
1002  }
1003  ocs_unlock(&iscsi->sess_queue_lock);
1004 }
1005 
1006 
1007 /**
1008  * @brief Generate node ddump data.
1009  *
1010  * @par Description
1011  * Generates the node ddump data.
1012  *
1013  * @param textbuf Pointer to text buffer.
1014  * @param cmd_q This queue contains the out-of-order commands for a session.
1015  *
1016  * @return None.
1017  */
1018 static void
1020 {
1021  ocs_ddump_section(textbuf, "cmd_q", 0);
1022 
1023  ocs_ddump_value(textbuf, "cmd_sn", "0x%x", cmd_q->cmd_sn);
1024  ocs_ddump_value(textbuf, "code", "0x%x", cmd_q->code);
1025  ocs_ddump_value(textbuf, "aborted", "%d", cmd_q->aborted);
1026 
1027  ocs_ddump_endsection(textbuf, "cmd_q", 0);
1028 }
1029 
1030 /**
1031  * @brief Generate node ddump data.
1032  *
1033  * @par Description
1034  * Generates the node ddump data.
1035  *
1036  * @param textbuf Pointer to text buffer.
1037  * @param session Pointer to session.
1038  *
1039  * @return None.
1040  */
1041 static void
1042 ocs_ddump_session(ocs_textbuf_t *textbuf, ocs_session_t *session)
1043 {
1044  ocs_session_q_unsol_t *cmd_q;
1045 
1046  ocs_ddump_section(textbuf, "session", session->instance_index);
1047 
1048  ocs_ddump_value(textbuf, "tgt_name", "%s", session->tgt_name);
1049  ocs_ddump_value(textbuf, "ini_name", "%s", session->ini_name);
1050  ocs_ddump_value(textbuf, "isid", "0x%" PRIx64 , session->isid);
1051  ocs_ddump_value(textbuf, "tsih", "0x%x", session->tsih);
1052  ocs_ddump_value(textbuf, "cmd_sn", "0x%x", session->cmd_sn);
1053  ocs_ddump_value(textbuf, "cmd_window", "0x%x", session->cmd_window);
1054  ocs_ddump_value(textbuf, "exp_cmd_sn", "0x%x", session->exp_cmd_sn);
1055  ocs_ddump_value(textbuf, "max_cmd_sn", "0x%x", session->max_cmd_sn);
1056  ocs_ddump_value(textbuf, "is_discovery_session", "%d", session->is_discovery_session);
1057  ocs_ddump_value(textbuf, "is_removed", "%d", session->is_removed);
1058 
1059  /* Session options */
1060  ocs_ddump_value(textbuf, "initial_r2t", "%d", session->login_options.initial_r2t);
1061  ocs_ddump_value(textbuf, "immediate_data", "%d", session->login_options.immediate_data);
1062  ocs_ddump_value(textbuf, "data_pdu_in_order", "%d", session->login_options.data_pdu_in_order);
1063  ocs_ddump_value(textbuf, "data_sequence_in_order", "%d", session->login_options.data_sequence_in_order);
1064  ocs_ddump_value(textbuf, "error_recovery_level", "%d", session->login_options.error_recovery_level);
1065  ocs_ddump_value(textbuf, "first_burst", "%d", session->login_options.first_burst);
1066  ocs_ddump_value(textbuf, "max_burst", "%d", session->login_options.max_burst);
1067  ocs_ddump_value(textbuf, "max_connections", "%d", session->login_options.max_connections);
1068  ocs_ddump_value(textbuf, "max_r2t", "%d", session->login_options.max_r2t);
1069  ocs_ddump_value(textbuf, "def_time_to_wait", "%d", session->login_options.def_time_to_wait);
1070  ocs_ddump_value(textbuf, "def_time_to_retain", "%d", session->login_options.def_time_to_retain);
1071 
1072  /* Print any queued commands */
1073  ocs_lock(&session->cmd_q_lock);
1074  ocs_ddump_value(textbuf, "cmd_q_num_queued", "%d", session->cmd_q_num_queued);
1075  ocs_list_foreach(&session->cmd_q_waiting, cmd_q) {
1076  ocs_ddump_cmd_q(textbuf, cmd_q);
1077  }
1078  ocs_unlock(&session->cmd_q_lock);
1079 
1080  ocs_ddump_endsection(textbuf, "session", session->instance_index);
1081 }
1082 
1083 /**
1084  * @brief Generate node ddump data.
1085  *
1086  * @par Description
1087  * Generates the node ddump data.
1088  *
1089  * @param textbuf Pointer to text buffer.
1090  * @param iscsi Pointer to the iscsi object.
1091  *
1092  * @return None.
1093  */
1094 void
1096 {
1097  ocs_session_t *session;
1098 
1099  ocs_ddump_section(textbuf, "active_sessions", 0);
1100 
1101  ocs_lock(&iscsi->sess_queue_lock);
1102  ocs_list_foreach(&iscsi->sess_busy, session) {
1103  ocs_ddump_session(textbuf, session);
1104  }
1105  ocs_unlock(&iscsi->sess_queue_lock);
1106 
1107  ocs_ddump_endsection(textbuf, "active_sessions", 0);
1108 }
#define OCS_ISCSI_LOGIN_DEFAULT_TIME_2_WAIT
static void ocs_ddump_cmd_q(ocs_textbuf_t *textbuf, ocs_session_q_unsol_t *cmd_q)
Generate node ddump data.
Definition: ocs_session.c:1019
#define OCS_ISCSI_LOGIN_MAX_BURST_LEN
ocs_list_t sess_free
Definition: ocs_iscsi.h:316
ocs_pdu_process_rtn_e
iSCSI PDU processing return codes
Definition: ocs_iscsi.h:99
static void ocs_session_cmd_q_timeout(void *arg)
This function is called to process commands on a session command queue.
Definition: ocs_session.c:487
static void * ocs_list_get_head(ocs_list_t *list)
Return the first item in the list.
Definition: ocs_list.h:292
static int32_t ocs_session_queue_command(ocs_cxn_t *cxn, ocs_hal_rq_buffer_t *hdr, uint32_t hdr_len, ocs_hal_rq_buffer_t *data, uint32_t data_len, uint8_t code, uint32_t cmd_sn)
Adds a command to the command queue.
Definition: ocs_session.c:643
void ocs_session_max_cmd_sn_upd(ocs_session_t *session)
Updates the max_cmd_sn based on the number IOs available.
Definition: ocs_session.c:449
#define ISCSI_REJECT_REASON_WAITING_FOR_LOGOUT
#define OCS_HAL_RQ_SIZE_DATA
ocs_pdu_process_rtn_e ocs_iscsi_tgt_process_cmd_sn(ocs_iscsi_t *iscsi, ocs_cxn_t *cxn, ocs_hal_rq_buffer_t *hdr, uint32_t hdr_len, ocs_hal_rq_buffer_t *data, uint32_t data_len, uint8_t code, uint8_t *reject_reason)
Function to process unsolicited PDUs for a target.
Definition: ocs_iscsi.c:4042
#define CONN_STATE_LOGIN_PROGRESS
ocs_session_t * sess_mem
Definition: ocs_iscsi.h:318
Defines the iSCSI logout PDU header.
void ocs_ddump_section(ocs_textbuf_t *textbuf, const char *name, uint32_t instance)
Generate driver dump section start data.
Definition: ocs_ddumplib.c:90
#define CONN_STATE_NEW_CONN
#define ISCSI_CMD_TEXT
int32_t ocs_iscsi_send_reject(ocs_cxn_t *cxn, void *hdr, uint32_t hdr_len, uint8_t reason)
Sends a reject PDU for the supplied PDU header.
Definition: ocs_login.c:4652
int32_t ocs_session_initialize(ocs_iscsi_t *iscsi)
Initialize the session management by allocating objects for sessions.
Definition: ocs_session.c:67
static void * ocs_list_remove(ocs_list_t *list, void *item)
Remove an item from the list.
Definition: ocs_list.h:385
struct ocs_hal_rq_buffer_s * hdr
Definition: ocs_common.h:231
int32_t ocs_session_cxn_del(ocs_cxn_t *cxn)
Removes a connection from its session.
Definition: ocs_session.c:343
#define ocs_list_init(head, type, link)
Definition: ocs_list.h:113
#define ISCSI_CMD_LOGOUT
void ocs_ddump_sessions(ocs_textbuf_t *textbuf, ocs_iscsi_t *iscsi)
Generate node ddump data.
Definition: ocs_session.c:1095
#define ocs_list_foreach_safe(list, item, nxt)
Iterate a linked list safely.
Definition: ocs_list.h:446
Defines the parameters passed to the target unsolicted PDU handler.
Definition: ocs_common.h:228
int32_t ocs_session_tgt_unsol_pdu_recv(ocs_cxn_t *cxn, ocs_hal_rq_buffer_t *hdr, uint32_t hdr_len, ocs_hal_rq_buffer_t *data, uint32_t data_len, uint8_t code)
Function to handle unsolicited PDUs on a target.
Definition: ocs_session.c:699
ocs_list_t sess_busy
Definition: ocs_iscsi.h:317
#define CONN_STATE_LOGOUT_REQUESTED
iSCSI object
Definition: ocs_iscsi.h:293
uint32_t num_cxns
Definition: ocs_iscsi.h:299
Defines a wrapper for the RQ payload buffers so that we can place it back on the proper queue...
Definition: ocs_hal.h:694
ocs_os_handle_t os
Definition: ocs_iscsi.h:294
#define LOGOUT_REASON_CLOSE_CONN_FOR_RECOVERY
void ocs_session_close(ocs_session_t *session, uint8_t reset)
Closes all connections on a session.
Definition: ocs_session.c:405
uint32_t ocs_instance(void *os)
Return the instance index of an opaque ocs structure.
Definition: ocs_driver.c:160
#define ISCSI_REJECT_REASON_PROTOCOL_ERR
void ocs_ddump_endsection(ocs_textbuf_t *textbuf, const char *name, uint32_t instance)
Generate driver dump section end data.
Definition: ocs_ddumplib.c:108
void ocs_iscsi_rx_buffers_free(ocs_iscsi_t *iscsi, ocs_hal_rq_buffer_t *header, ocs_hal_rq_buffer_t *payload)
Add a receive buffer pair to the Receive Queue, if an error is received, then queue the buffer...
Definition: ocs_iscsi.c:4447
static void ocs_session_check_queued_commands(ocs_session_t *session)
Checks the queued command to see if any can start.
Definition: ocs_session.c:501
int32_t ocs_iscsi_send_login_rsp_invalid_during_login(ocs_cxn_t *cxn, uint32_t itt)
Function to send an login Response PDU (invalid during login).
Definition: ocs_login.c:2815
#define OCS_ISCSI_MAX_QUEUED_CMDSN
void ocs_session_all_abort_cmdsn(ocs_iscsi_t *iscsi, uint32_t cmdsn)
Abort a specific IO based on the cmdSN of the abort request.
Definition: ocs_session.c:994
static void ocs_list_add_tail(ocs_list_t *list, void *item)
Add an item to the tail of the list.
Definition: ocs_list.h:263
static void ocs_ddump_session(ocs_textbuf_t *textbuf, ocs_session_t *session)
Generate node ddump data.
Definition: ocs_session.c:1042
#define ocs_list_remove_head(list)
Remove and return an item from the head of the list.
Definition: ocs_list.h:374
#define CMD_Q_TIMER_MS
Definition: ocs_session.c:51
bool is_hal_initialized
Definition: ocs_iscsi.h:306
struct ocs_hal_rq_buffer_s * data
Definition: ocs_common.h:232
#define LOGOUT_REASON_CLOSE_SESS
struct ocs_cxn_s * cxn
Definition: ocs_common.h:230
ocs_dma_t dma
Definition: ocs_hal.h:696
#define ISCSI_REJECT_REASON_DATA_DIGEST_ERR
ocs_lock_t sess_queue_lock
Definition: ocs_iscsi.h:315
int32_t ocs_session_cxn_new(ocs_cxn_t *cxn, char *tgt_name, char *ini_name, uint64_t isid, uint16_t tsih, uint16_t cid, uint32_t cmd_sn)
Find an existing session or create a new one based on the login parameters.
Definition: ocs_session.c:187
static bool before(uint32_t seq1, uint32_t seq2)
Definition: ocs.h:68
#define OCS_MAX_ISCSI_NAME
Definition: ocs_common.h:240
#define ISCSI_CMD_LOGIN
#define CONN_STATE_FULL_FEATURE
void ocs_session_teardown(ocs_iscsi_t *iscsi)
Releases the session objects used within the login module.
Definition: ocs_session.c:123
#define OCS_LOGIN_REQUEST_QUEUED
Definition: ocs_login.h:134
uint32_t ocs_iscsi_get_max_cxns(ocs_t *ocs, char *tgt_name, char *ini_name)
Returns the maximum number of connections allowed per session.
#define ocs_list_foreach(list, item)
Iterate a linked list.
Definition: ocs_list.h:428
#define after(seq2, seq1)
Definition: ocs.h:72
#define OCS_ISCSI_LOGIN_DEFAULT_TIME_2_RETAIN
#define GT_WRAPPED(a_cmd_sn, b_cmd_sn)
Definition: ocs_iscsi.h:73
int32_t ocs_cxn_close(ocs_cxn_t *cxn, uint8_t sendRst)
Issues a request to the HAL to close the connection.
Definition: ocs_cxn.c:1648
int32_t ocs_session_abort_itt(ocs_session_t *session, uint32_t itt)
Abort a specific IO based on the ITT.
Definition: ocs_session.c:932
ocs_cxn_t * ocs_session_cxn_find(ocs_session_t *session, uint16_t cid)
Locate a connection within a session based on the cid.
Definition: ocs_session.c:379
void ocs_ddump_value(ocs_textbuf_t *textbuf, const char *name, const char *fmt,...)
Generate driver dump data for a given value.
Definition: ocs_ddumplib.c:126
void ocs_session_abort_cmdsn(ocs_session_t *session, uint32_t cmdsn)
Abort a specific IO based on the cmdSN of the abort request.
Definition: ocs_session.c:965
Defines the iSCSI login PDU header.