Emulex Logo
OneCoreā„¢ Storage SDK Release 11.2
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ocs_cxn.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 connection management functions.
36  */
37 
38 /**
39  * @defgroup cxn_mgnt iSCSI Connection Management
40  * @defgroup cxn_sm Connection State Machine: Connection States
41 */
42 
43 #include "ocs.h"
44 #include "ocs_iscsi.h"
45 #include "ocs_iscsi_spec.h"
46 #include "ocs_common.h"
47 #include "ocs_hal.h"
48 #include "ocs_iscsi_api.h"
49 #include "ocs_login.h"
50 #include "ocs_session.h"
51 #include "ocs_cxn.h"
52 
53 #define std_cxn_state_decl(...) \
54  ocs_cxn_t *cxn = NULL; \
55  ocs_iscsi_t *iscsi = NULL; \
56  ocs_t *ocs = NULL; \
57  \
58  ocs_assert(ctx, NULL); \
59  cxn = ctx->app; \
60  ocs_assert(cxn, NULL); \
61  iscsi = cxn->iscsi; \
62  ocs_assert(iscsi, NULL); \
63  ocs = cxn->ocs; \
64  ocs_assert(ocs, NULL); \
65 
66 #define cxn_sm_trace() \
67  do { \
68  if (ocs_debug_is_enabled(OCS_DEBUG_ENABLE_SM_TRACE)) \
69  ocs_log_info(cxn->ocs, "[%s] %-20s %-20s\n", cxn->display_name, __func__, ocs_sm_event_name(evt)); \
70  } while (0)
71 
72 void ocs_mgmt_node_list(ocs_textbuf_t *textbuf, void *node);
73 void ocs_mgmt_node_get_all(ocs_textbuf_t *textbuf, void *node);
74 int ocs_mgmt_node_get(ocs_textbuf_t *textbuf, char *parent, char *name, void *node);
75 int ocs_mgmt_node_set(char *parent, char *name, char *value, void *node);
76 int ocs_mgmt_node_exec(char *parent, char *action, void *arg_in, uint32_t arg_in_length,
77  void *arg_out, uint32_t arg_out_length, void *node);
80  .get_handler = ocs_mgmt_node_get,
81  .get_all_handler = ocs_mgmt_node_get_all,
82  .set_handler = ocs_mgmt_node_set,
83  .exec_handler = ocs_mgmt_node_exec,
84 };
85 
86 /* declare local functions */
87 static void * __ocs_cxn_connect(ocs_sm_ctx_t *, ocs_sm_event_t, void *);
88 static void * __ocs_cxn_connect_wait(ocs_sm_ctx_t *, ocs_sm_event_t, void *);
89 static void * __ocs_cxn_connect_delay(ocs_sm_ctx_t *, ocs_sm_event_t, void *);
90 static void * __ocs_cxn_get_info(ocs_sm_ctx_t *, ocs_sm_event_t, void *);
91 static void * __ocs_cxn_get_info_wait(ocs_sm_ctx_t *, ocs_sm_event_t, void *);
92 static void * __ocs_cxn_offload(ocs_sm_ctx_t *, ocs_sm_event_t, void *);
93 static void * __ocs_cxn_offload_wait(ocs_sm_ctx_t *, ocs_sm_event_t, void *);
94 static void * __ocs_cxn_reject(ocs_sm_ctx_t *, ocs_sm_event_t, void *);
95 static void * __ocs_cxn_reject_wait(ocs_sm_ctx_t *, ocs_sm_event_t, void *);
96 static void * __ocs_cxn_connected(ocs_sm_ctx_t *, ocs_sm_event_t, void *);
97 static void * __ocs_cxn_close_abort_io(ocs_sm_ctx_t *, ocs_sm_event_t, void *);
98 static void * __ocs_cxn_abort_wait(ocs_sm_ctx_t *, ocs_sm_event_t, void *);
99 static void * __ocs_cxn_close_abort_login(ocs_sm_ctx_t *, ocs_sm_event_t, void *);
100 static void * __ocs_cxn_close(ocs_sm_ctx_t *, ocs_sm_event_t, void *);
101 static void * __ocs_cxn_close_wait(ocs_sm_ctx_t *, ocs_sm_event_t, void *);
102 static void * __ocs_cxn_upload(ocs_sm_ctx_t *, ocs_sm_event_t, void *);
103 static void * __ocs_cxn_upload_wait(ocs_sm_ctx_t *, ocs_sm_event_t, void *);
104 static void * __ocs_cxn_error(ocs_sm_ctx_t *, ocs_sm_event_t, void *);
105 
106 static void ocs_cxn_connect_cb(void *, int32_t, uint32_t, void *);
107 static void ocs_cxn_close_cb(void *, int32_t, uint32_t, void*);
108 static void ocs_cxn_upload_cb(void *, int32_t, uint32_t, void*);
109 static void ocs_cxn_get_info_cb(void *, int32_t, uint32_t, void*);
110 static void ocs_cxn_offload_cb(void *, int32_t, uint32_t, void*);
111 static void ocs_cxn_reject_cb(void *, int32_t, uint32_t, void*);
112 
113 
114 /**
115  * @brief Initialize the iSCSI connection objects.
116  *
117  * @param iscsi Pointer to the iSCSI object.
118  *
119  * @return Returns 0 on success, or a non-zero value otherwise.
120  */
122 {
124  if (ocs_iscsi_tracker_alloc(iscsi,
125  &iscsi->cxn_login_hdr,
126  FALSE,
127  64,
129  iscsi->num_cxns)) {
130  ocs_log_err(iscsi->os, "Failed to allocate login hdr buffers\n");
131  return -ENOMEM;
132  }
133 
135  if (ocs_iscsi_tracker_alloc(iscsi,
136  &iscsi->cxn_login_data,
137  FALSE,
140  iscsi->num_cxns)) {
141  ocs_log_err(iscsi->os, "Failed to allocate login data buffers\n");
142  return -ENOMEM;
143  }
144 
145  return 0;
146 }
147 
148 /**
149  * @brief Free the iSCSI connection objects.
150  *
151  * @param iscsi Pointer to the iSCSI object.
152  *
153  * @return Returns 0 on success, or a non-zero value otherwise.
154  */
156 {
157  ocs_iscsi_tracker_free(iscsi, &iscsi->cxn_login_hdr);
158  ocs_iscsi_tracker_free(iscsi, &iscsi->cxn_login_data);
159 }
160 
161 /**
162  * @brief Free memory resources of a node object.
163  *
164  * @par Description
165  * The node object's child objects are freed after which the
166  * node object is freed.
167  *
168  * @param cxn Pointer to connection.
169  *
170  * @return None.
171  */
172 
173 void
174 ocs_cxn_force_free(ocs_cxn_t *cxn)
175 {
176  ocs_t *ocs = cxn->ocs;
177  ocs_io_t *io;
178  ocs_io_t *next;
179 
180  /* shutdown sm processing */
181  ocs_sm_disable(&cxn->sm);
182 
183  ocs_scsi_notify_node_force_free((ocs_node_t *)cxn);
184 
185  ocs_device_lock(ocs);
186  ocs_lock(&cxn->active_ios_lock);
187  ocs_list_foreach_safe(&cxn->active_ios, io, next) {
188  ocs_list_remove(&cxn->active_ios, io);
189 
190  /* clear from the pending list */
191  if (ocs_list_on_list(&io->io_pending_link)) {
192  ocs_list_remove(&ocs->io_pending_list, io);
193  }
194  ocs_io_free(cxn->ocs, io);
195  }
196  ocs_list_foreach_safe(&cxn->aborted_ios, io, next) {
197  ocs_list_remove(&cxn->aborted_ios, io);
198  /* clear from the pending list */
199  if (ocs_list_on_list(&io->io_pending_link)) {
200  ocs_list_remove(&ocs->io_pending_list, io);
201  }
202  ocs_io_free(cxn->ocs, io);
203  }
204  ocs_unlock(&cxn->active_ios_lock);
205  ocs_device_unlock(ocs);
206 
207  /* manually purge pending frames (if any) */
208  (void)ocs_iscsi_login_cxn_cleanup(cxn);
209 }
210 
211 
212 /**
213  * @brief Transition state of a node.
214  *
215  * @par Description
216  * The connection's state is transitioned to the requested state. Entry/Exit
217  * events are posted as needed.
218  *
219  * @param cxn Pointer to connection.
220  * @param state State to transition to.
221  * @param data Transition data.
222  *
223  * @return None.
224  */
225 
226 static void
227 ocs_cxn_transition(ocs_cxn_t *cxn, ocs_sm_function_t state, void *data)
228 {
229  ocs_sm_ctx_t *ctx = &cxn->sm;
230 
231  if (ctx->current_state == state) {
233  } else {
234  ocs_sm_post_event(ctx, OCS_EVT_EXIT, data);
235  ctx->current_state = state;
236  ocs_sm_post_event(ctx, OCS_EVT_ENTER, data);
237  }
238 }
239 
240 
241 /**
242  * @brief This function is called on timer expiration and sends an event to the
243  * the state machine.
244  *
245  * @param arg Pointer to the cxn object.
246  */
247 static void ocs_cxn_retry_timeout(void *arg)
248 {
249  ocs_cxn_t *cxn = arg;
251 }
252 
253 
254 /**
255  * @brief Set the SM timer to retry a command at a later time.
256  *
257  * @param cxn Pointer to the connection object.
258  * @param timeout Timeout value in milliseconds.
259  */
260 static void
261 ocs_cxn_set_sm_retry_timer(ocs_cxn_t *cxn, uint32_t timeout)
262 {
263  if (ocs_timer_pending(&cxn->sm_retry_timer)) {
264  ocs_del_timer(&cxn->sm_retry_timer);
265  }
266 
267  ocs_setup_timer(cxn->ocs, &cxn->sm_retry_timer,
269  cxn,
270  timeout, false);
271 }
272 
273 /**
274  * @ingroup cxn_sm
275  * @brief State: Common device event handler.
276  *
277  * @par Description
278  * For connection nodes, this handles default/common events.
279  *
280  * @param funcname Higher level function name.
281  * @param ctx Remote node sm context.
282  * @param evt Event to process.
283  * @param arg Per event optional argument.
284  *
285  * @return Returns NULL.
286  */
287 static void *
288 __ocs_cxn_common(const char *funcname, ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
289 {
291 
292  switch(evt) {
293  case OCS_EVT_ENTER:
294  case OCS_EVT_REENTER:
295  case OCS_EVT_EXIT:
296  case OCS_EVT_SHUTDOWN:
297  break;
298 
299  default:
300  ocs_log_test(ocs, "[%s] %-20s %-20s not handled\n", cxn->display_name, funcname, ocs_sm_event_name(evt));
301  break;
302  }
303  return NULL;
304 }
305 
306 /**
307  * @ingroup cxn_sm
308  * @brief State: Initial state.
309  *
310  * @par Description
311  * For connection nodes, this handles connect/connection received events.
312  *
313  * @param ctx Remote node sm context.
314  * @param evt Event to process.
315  * @param arg Per event optional argument.
316  *
317  * @return Returns NULL.
318  */
319 static void *
320 __ocs_cxn_initial(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
321 {
323 
324  cxn_sm_trace();
325 
326  switch(evt) {
327  case OCS_EVT_ENTER:
328  /* Kill the test negotiation timer if it is active */
329  if (ocs_timer_pending(&cxn->ffp_timer)) {
330  ocs_del_timer(&cxn->ffp_timer);
331  }
332 
333  /* Cleanup any cbit buffers */
335  break;
336 
337  case OCS_EVT_CXN_CONNECT:
339  break;
340 
343  break;
344 
348  case OCS_EVT_IO_CMPL:
349  /* Ignore */
350  break;
351 
352  default:
353  __ocs_cxn_common(__func__, ctx, evt, arg);
354  return NULL;
355  }
356 
357  return NULL;
358 }
359 
360 /**
361  * @ingroup cxn_sm
362  * @brief State: Connect to a remote node
363  *
364  * @par Description
365  * For connection nodes, this handles connecting to a remote node.
366  *
367  * @param ctx Remote node sm context.
368  * @param evt Event to process.
369  * @param arg Per event optional argument.
370  *
371  * @return Returns NULL.
372  */
373 static void *
374 __ocs_cxn_connect(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
375 {
376  ocs_hal_ip_address_t remote_ip;
377  int32_t rc;
379 
380  cxn_sm_trace();
381 
382  switch(evt) {
383  case OCS_EVT_ENTER:
385  remote_ip.ip_type = cxn->dest_ip_type;
386  ocs_memcpy(remote_ip.ip_address, cxn->dest_ip, 16);
387 
388  rc = ocs_hal_cxn_connect(iscsi->hal,
389  cxn,
390  &remote_ip,
391  cxn->dest_port,
392  ocs->tcp_window_size,
393  ocs->tcp_window_scale,
395  cxn);
396  if (rc == OCS_HAL_RTN_NO_RESOURCES) {
398  } else if (rc) {
400  (void)ocs_session_cxn_del(cxn);
401  ocs_hal_cxn_free(iscsi->hal, cxn);
402  } else {
404  }
405  break;
406 
407  default:
408  __ocs_cxn_common(__func__, ctx, evt, arg);
409  return NULL;
410  }
411 
412  return NULL;
413 }
414 
415 
416 /**
417  * @ingroup cxn_sm
418  * @brief State: Waiting for the connection to complete.
419  *
420  * @param ctx Remote node sm context.
421  * @param evt Event to process.
422  * @param arg Per event optional argument.
423  *
424  * @return Returns NULL.
425  */
426 static void *
427 __ocs_cxn_connect_wait(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
428 {
429  int32_t rc;
431 
432  cxn_sm_trace();
433 
434  switch(evt) {
435  case OCS_EVT_ENTER:
436  break;
437 
439  // TODO: transition first then do stuff?
440  // "connected" before LOGIN PDU completes?
442 
443  rc = ocs_iscsi_send_login(cxn, FALSE, cxn->session->tgt_name);
444  if (rc) {
445  ocs_log_err(iscsi->os, "failing building login (rc=%d)\n", rc);
446  ocs_cxn_close(cxn, FALSE);
447  }
448  break;
449 
452  cxn->sendRst = (evt == OCS_EVT_CXN_SW_REQ_CLOSE_WITH_RST);
454  break;
455 
456  case OCS_EVT_ERROR:
458  break;
459 
460  default:
461  __ocs_cxn_common(__func__, ctx, evt, arg);
462  return NULL;
463  }
464 
465  return NULL;
466 }
467 
468 
469 /**
470  * @ingroup cxn_sm
471  * @brief State: Connection to target failed, delay before retrying.
472  *
473  * @param ctx Remote node sm context.
474  * @param evt Event to process.
475  * @param arg Per event optional argument.
476  *
477  * @return Returns NULL.
478  */
479 static void *
480 __ocs_cxn_connect_delay(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
481 {
483 
484  cxn_sm_trace();
485 
486  switch(evt) {
487  case OCS_EVT_ENTER:
489  break;
490 
493  break;
494 
495  case OCS_EVT_ERROR:
497  break;
498 
499  default:
500  __ocs_cxn_common(__func__, ctx, evt, arg);
501  return NULL;
502  }
503 
504  return NULL;
505 }
506 
507 
508 /**
509  * @ingroup cxn_sm
510  * @brief State: Connected, waiting for the teardown request.
511  *
512  * @param ctx Remote node sm context.
513  * @param evt Event to process.
514  * @param arg Per event optional argument.
515  *
516  * @return Returns NULL.
517  */
518 static void *
519 __ocs_cxn_connected(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
520 {
522 
523  cxn_sm_trace();
524 
525  switch(evt) {
526  case OCS_EVT_ENTER:
528  break;
529 
532  cxn->sendRst = (evt == OCS_EVT_CXN_SW_REQ_CLOSE_WITH_RST);
534  break;
535 
536  default:
537  __ocs_cxn_common(__func__, ctx, evt, arg);
538  return NULL;
539  }
540 
541  return NULL;
542 }
543 
544 /**
545  * @ingroup cxn_sm
546  * @brief Aborts active IO objects on a connection.
547  *
548  * @param ctx Remote node sm context.
549  * @param evt Event to process.
550  * @param arg Per event optional argument.
551  *
552  * @return Returns NULL.
553  */
554 static void *
555 __ocs_cxn_close_abort_io(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
556 {
557  int32_t rc;
558  ocs_io_t *io, *abort_io = NULL;
560 
561  cxn_sm_trace();
562 
563  switch(evt) {
564  case OCS_EVT_ENTER:
566  /* Purge any IOs for this connection off the pending list */
568 
569  /* try to find one with a HAL IO allocated. */
570  ocs_node_lock(cxn);
571  ocs_list_foreach(&cxn->active_ios, io) {
572  if (io->hio != NULL) {
573  abort_io = io;
574  break;
575  }
576  }
577  ocs_node_unlock(cxn);
578  if (abort_io == NULL) {
580  } else {
581  rc = ocs_hal_io_abort(iscsi->hal,
582  abort_io->hio,
585 
586  if (rc == OCS_HAL_RTN_NO_RESOURCES ||
587  rc == OCS_HAL_RTN_NO_MEMORY) {
588  // TODO - no Memory may require a big hammer reset
590  } else if (rc) {
592  } else {
593  ocs_log_debug(iscsi->os, "cxn, hdl=0x%x abort ICD %d\n",
594  cxn->conn_hdl,
595  (abort_io->hio != NULL) ? abort_io->hio->icd : -1);
597  }
598  }
599  break;
600 
602  /* Reset during offload - just ignore */
603  break;
604 
605  default:
606  __ocs_cxn_common(__func__, ctx, evt, arg);
607  return NULL;
608  }
609 
610  return NULL;
611 }
612 
613 /**
614  * @ingroup cxn_sm
615  * @brief Aborts any login transactions on a connection.
616  *
617  * @param ctx Remote node sm context.
618  * @param evt Event to process.
619  * @param arg Per event optional argument.
620  *
621  * @return Returns NULL.
622  */
623 static void *
624 __ocs_cxn_close_abort_login(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
625 {
626  int32_t rc;
628 
629  cxn_sm_trace();
630 
631  switch(evt) {
632  case OCS_EVT_ENTER:
634  rc = ocs_iscsi_login_cxn_cleanup(cxn);
635 
636  if (rc == OCS_HAL_RTN_NO_RESOURCES) {
638  } else if (rc) {
640  } else {
642  }
643  break;
644 
646  /* Reset during offload - just ignore */
647  break;
648 
649  default:
650  __ocs_cxn_common(__func__, ctx, evt, arg);
651  return NULL;
652  }
653 
654  return NULL;
655 }
656 
657 
658 /**
659  * @ingroup cxn_sm
660  * @brief State: Waiting for the IO aborts to complete.
661  *
662  * @param ctx Remote node sm context.
663  * @param evt Event to process.
664  * @param arg Per event optional argument.
665  *
666  * @return Returns NULL.
667  */
668 static void *
669 __ocs_cxn_abort_wait(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
670 {
671  int32_t rc;
672  uint8_t is_io_empty;
673  uint8_t are_login_reqs;
675 
676  cxn_sm_trace();
677 
678  switch(evt) {
679  case OCS_EVT_ENTER:
680  case OCS_EVT_IO_CMPL:
681  /* Check to see if all the IOs are completed */
682  ocs_node_lock(cxn);
683  is_io_empty = ocs_list_empty(&cxn->active_ios);
684  ocs_node_unlock(cxn);
685  are_login_reqs = ocs_iscsi_are_login_reqs_outstanding(cxn);
686 
687  if (is_io_empty && !are_login_reqs) {
688  if (cxn->send_logout_rsp) {
689  rc = ocs_iscsi_send_logout_rsp(cxn,
690  cxn->logout_rsp,
691  cxn->logout_itt);
692 
693  if (rc == 0) {
694  cxn->send_logout_rsp = FALSE;
696  } else if (rc == OCS_HAL_RTN_NO_RESOURCES) {
698  } else {
700  }
701  } else {
703  }
704  }
705  break;
706 
708  /* Ignore */
709  break;
711  /* We are already closing */
712  break;
714  cxn->sendRst = TRUE;
716  break;
717 
718  case OCS_EVT_ERROR:
720  break;
721 
722  default:
723  __ocs_cxn_common(__func__, ctx, evt, arg);
724  return NULL;
725  }
726 
727  return NULL;
728 }
729 
730 /**
731  * @ingroup cxn_sm
732  * @brief Closes a TCP connection.
733  *
734  * @param ctx Remote node sm context.
735  * @param evt Event to process.
736  * @param arg Per event optional argument.
737  *
738  * @return Returns NULL.
739  */
740 static void *
741 __ocs_cxn_close(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
742 {
743  int32_t rc;
745 
746  cxn_sm_trace();
747 
748  switch(evt) {
749  case OCS_EVT_ENTER:
750  if (cxn->cxn_state != CONN_STATE_LOGOUT_REQUESTED) {
751  cxn->cxn_state = CONN_STATE_CLEANUP;
752  }
753  rc = ocs_hal_cxn_close(iscsi->hal,
754  cxn,
755  cxn->sendRst,
757  cxn);
758 
759  if (rc == OCS_HAL_RTN_NO_RESOURCES) {
761  } else if (rc) {
763  } else {
764  // TODO: should we wait to clean up until connection closed?
765  ocs_log_debug(iscsi->os, "sent request to close cxn, hdl=0x%x\n",
766  cxn->conn_hdl);
767  if (cxn->is_ini_cxn) {
769  } else {
771  }
773  }
774  break;
775 
778  /* Reset during offload - just ignore */
779  break;
780 
781  default:
782  __ocs_cxn_common(__func__, ctx, evt, arg);
783  return NULL;
784  }
785 
786  return NULL;
787 }
788 
789 
790 /**
791  * @ingroup cxn_sm
792  * @brief State: Closing, waiting for the close callback.
793  *
794  * @param ctx Remote node sm context.
795  * @param evt Event to process.
796  * @param arg Per event optional argument.
797  *
798  * @return Returns NULL.
799  */
800 static void *
801 __ocs_cxn_close_wait(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
802 {
804 
805  cxn_sm_trace();
806 
807  switch(evt) {
808  case OCS_EVT_ENTER:
810  break;
811 
814  /* ignore since we are already closing */
815  break;
816 
818  /* Reset during offload - just ignore */
819  break;
820 
823  break;
824 
825  case OCS_EVT_ERROR:
827  break;
828 
829  default:
830  __ocs_cxn_common(__func__, ctx, evt, arg);
831  return NULL;
832  }
833 
834  return NULL;
835 }
836 
837 
838 /**
839  * @ingroup cxn_sm
840  * @brief State: Closing, waiting for the close callback.
841  *
842  * @param ctx Remote node sm context.
843  * @param evt Event to process.
844  * @param arg Per event optional argument.
845  *
846  * @return Returns NULL.
847  */
848 static void *
849 __ocs_cxn_upload(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
850 {
851  int32_t rc;
853 
854  cxn_sm_trace();
855 
856  switch(evt) {
857  case OCS_EVT_ENTER:
859  rc = ocs_hal_cxn_upload(iscsi->hal,
860  cxn,
861  !cxn->sendRst,
863  cxn);
864  if (rc == OCS_HAL_RTN_NO_RESOURCES) {
866  } else if (rc) {
868  } else {
870  }
871  break;
872 
875  /* ignore since we are already closing */
876  break;
877 
878  default:
879  __ocs_cxn_common(__func__, ctx, evt, arg);
880  return NULL;
881  }
882 
883  return NULL;
884 }
885 
886 
887 /**
888  * @ingroup cxn_sm
889  * @brief State: Waiting for connection upload to complete.
890  *
891  * @param ctx Remote node sm context.
892  * @param evt Event to process.
893  * @param arg Per event optional argument.
894  *
895  * @return Returns NULL.
896  */
897 static void *
898 __ocs_cxn_upload_wait(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
899 {
900  ocs_hal_ip_address_t remote_ip;
901  uint16_t tcp_port = 0;
902  uint8_t is_ini_cxn;
903  char tgt_name[OCS_MAX_ISCSI_NAME];
905 
906  cxn_sm_trace();
907 
908  switch(evt) {
909  case OCS_EVT_ENTER:
911  break;
912 
915  /* ignore since we are already closing */
916  break;
917 
919  ocs_log_debug(iscsi->os, "Upload completed on connection\n");
920  /*
921  * Attempt to re-establish initiator connections. Free
922  * connections on the target
923  */
924  is_ini_cxn = cxn->is_ini_cxn;
925  if (is_ini_cxn &&
926  !iscsi->shutting_down) {
927  remote_ip.ip_type = cxn->dest_ip_type;
928  ocs_memcpy(remote_ip.ip_address, cxn->dest_ip, 16);
929  if (cxn->session != NULL) {
930  ocs_strcpy(tgt_name, cxn->session->tgt_name);
931  } else {
932  ocs_log_test(iscsi->os, "INI session with no session - cannot retry connection %s\n",
933  cxn->display_name);
934  is_ini_cxn = FALSE;
935  }
936  tcp_port = cxn->dest_port;
937  }
938 
940  (void)ocs_session_cxn_del(cxn);
941 
942  /* Free any IOs on the aborted IO list */
943  ocs_cxn_force_free(cxn);
944 
945  if (ocs_hal_cxn_free(iscsi->hal, cxn)) {
946  ocs_log_test(iscsi->os, "Failed to free connection %s\n", cxn->display_name);
947  }
948 
949  if (is_ini_cxn &&
950  !iscsi->shutting_down) {
951  if (ocs_cxn_connect(iscsi, &remote_ip, tcp_port, tgt_name)) {
952  ocs_log_test(iscsi->os, "failed Starting connection to target\n");
953  }
954  }
955  break;
956 
957  case OCS_EVT_ERROR:
959  break;
960 
961 
962  default:
963  __ocs_cxn_common(__func__, ctx, evt, arg);
964  return NULL;
965  }
966 
967  return NULL;
968 }
969 
970 
971 
972 /**
973  * @ingroup cxn_sm
974  * @brief Get information on the connection.
975  *
976  * @param ctx Remote node sm context.
977  * @param evt Event to process.
978  * @param arg Per event optional argument.
979  *
980  * @return Returns NULL.
981  */
982 static void *
983 __ocs_cxn_get_info(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
984 {
985  int32_t rc;
987 
988  cxn_sm_trace();
989 
990  switch(evt) {
991  case OCS_EVT_ENTER:
993  /*
994  * Get the connection information including the TCP MSS
995  */
996  rc = ocs_hal_cxn_get_info(iscsi->hal, cxn,
997  ocs_cxn_get_info_cb, cxn);
998  if (rc == OCS_HAL_RTN_NO_RESOURCES) {
1000  } else if (rc) {
1002  } else {
1004  }
1005  break;
1006 
1010  break;
1011 
1012  default:
1013  __ocs_cxn_common(__func__, ctx, evt, arg);
1014  return NULL;
1015  }
1016 
1017  return NULL;
1018 }
1019 
1020 
1021 /**
1022  * @ingroup cxn_sm
1023  * @brief State: Waiting for connection information request to complete.
1024  *
1025  * @param ctx Remote node sm context.
1026  * @param evt Event to process.
1027  * @param arg Per event optional argument.
1028  *
1029  * @return Returns NULL.
1030  */
1031 static void *
1032 __ocs_cxn_get_info_wait(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1033 {
1035 
1036  cxn_sm_trace();
1037 
1038  switch(evt) {
1039  case OCS_EVT_ENTER:
1041  break;
1042 
1045  case OCS_EVT_ERROR:
1047  break;
1048 
1051  break;
1052 
1053  default:
1054  __ocs_cxn_common(__func__, ctx, evt, arg);
1055  return NULL;
1056  }
1057 
1058  return NULL;
1059 }
1060 
1061 
1062 /**
1063  * @ingroup cxn_sm
1064  * @brief Offload the connection to the chip.
1065  *
1066  * @param ctx Remote node sm context.
1067  * @param evt Event to process.
1068  * @param arg Per event optional argument.
1069  *
1070  * @return Returns NULL.
1071  */
1072 static void *
1073 __ocs_cxn_offload(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1074 {
1075  int32_t rc;
1077 
1078  cxn_sm_trace();
1079 
1080  switch(evt) {
1081  case OCS_EVT_ENTER:
1083 
1084  rc = ocs_hal_cxn_offload(iscsi->hal,
1085  cxn,
1086  ocs->tcp_window_size,
1087  0, /* data_digest */
1088  0, /* hdr_digest */
1091  cxn);
1092  if (rc == OCS_HAL_RTN_NO_RESOURCES) {
1094  } else if (rc) {
1096  } else {
1098  }
1099  break;
1100 
1104  break;
1105 
1106  default:
1107  __ocs_cxn_common(__func__, ctx, evt, arg);
1108  return NULL;
1109  }
1110 
1111  return NULL;
1112 }
1113 
1114 
1115 /**
1116  * @ingroup cxn_sm
1117  * @brief State: Waiting for connection offload request to complete.
1118  *
1119  * @param ctx Remote node sm context.
1120  * @param evt Event to process.
1121  * @param arg Per event optional argument.
1122  *
1123  * @return Returns NULL.
1124  */
1125 static void *
1126 __ocs_cxn_offload_wait(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1127 {
1129 
1130  cxn_sm_trace();
1131 
1132  switch(evt) {
1133  case OCS_EVT_ENTER:
1134  ocs_log_debug(iscsi->os, "conn_hdl 0x%x Offloading new connection from %s, MSS %d\n",
1135  cxn->conn_hdl,
1136  cxn->display_name,
1137  cxn->tcp_mss);
1138  break;
1139 
1142  case OCS_EVT_ERROR:
1144  break;
1145 
1148  break;
1149 
1151  break;
1152 
1153  default:
1154  __ocs_cxn_common(__func__, ctx, evt, arg);
1155  return NULL;
1156  }
1157 
1158  return NULL;
1159 }
1160 
1161 
1162 /**
1163  * @ingroup cxn_sm
1164  * @brief Reject a connection after some connection protocol started.
1165  *
1166  * @param ctx Remote node sm context.
1167  * @param evt Event to process.
1168  * @param arg Per event optional argument.
1169  *
1170  * @return Returns NULL.
1171  */
1172 static void *
1173 __ocs_cxn_reject(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1174 {
1175  int32_t rc;
1177 
1178  cxn_sm_trace();
1179 
1180  switch(evt) {
1181  case OCS_EVT_ENTER:
1183  rc = ocs_hal_cxn_reject(iscsi->hal, cxn->conn_hdl, ocs_cxn_reject_cb, cxn);
1184  if (rc == OCS_HAL_RTN_NO_RESOURCES) {
1186  } else if (rc) {
1187  ocs_log_test(iscsi->os, "connection from %s failed to reject\n", cxn->display_name);
1188 
1189  /* At least free up the cxn object */
1191  (void)ocs_session_cxn_del(cxn);
1192  ocs_hal_cxn_free(iscsi->hal, cxn);
1193  } else {
1195  }
1196  break;
1197 
1200  /* we are rejecting already, so we have it covered */
1201  break;
1202 
1204  /*
1205  * Since the connection can be closed during these operations,
1206  * there may be libgering events pending, just ignore them
1207  * as we are rejecting the connection.
1208  */
1209  break;
1210 
1211  default:
1212  __ocs_cxn_common(__func__, ctx, evt, arg);
1213  return NULL;
1214  }
1215 
1216  return NULL;
1217 }
1218 
1219 
1220 /**
1221  * @ingroup cxn_sm
1222  * @brief State: Waiting for connection reject request to complete.
1223  *
1224  * @param ctx Remote node sm context.
1225  * @param evt Event to process.
1226  * @param arg Per event optional argument.
1227  *
1228  * @return Returns NULL.
1229  */
1230 static void *
1231 __ocs_cxn_reject_wait(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1232 {
1234 
1235  cxn_sm_trace();
1236 
1237  switch(evt) {
1238  case OCS_EVT_ENTER:
1240  break;
1241 
1244  case OCS_EVT_ERROR:
1245  /* Already rejected */
1246  break;
1247 
1250  (void)ocs_session_cxn_del(cxn);
1251  ocs_hal_cxn_free(iscsi->hal, cxn);
1252  break;
1253 
1254  default:
1255  __ocs_cxn_common(__func__, ctx, evt, arg);
1256  return NULL;
1257  }
1258 
1259  return NULL;
1260 }
1261 
1262 /**
1263  * @ingroup cxn_sm
1264  * @brief An error was received, something unexpected occurred.
1265  *
1266  * @param ctx Remote node sm context.
1267  * @param evt Event to process.
1268  * @param arg Per event optional argument.
1269  *
1270  * @return Returns NULL.
1271  */
1272 static void *
1273 __ocs_cxn_error(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1274 {
1276 
1277  cxn_sm_trace();
1278 
1279  switch(evt) {
1280  case OCS_EVT_ENTER:
1281  ocs_log_test(iscsi->os, "connection from %s is in the error state\n",
1282  cxn->display_name);
1283  break;
1284 
1293  /* jusr stay here as something we don;t expect happened */
1294  break;
1295 
1296  default:
1297  __ocs_cxn_common(__func__, ctx, evt, arg);
1298  return NULL;
1299  }
1300 
1301  return NULL;
1302 }
1303 
1304 
1305 /**
1306  * @brief Function to receive the notification that the connection reject is
1307  * complete.
1308  *
1309  * @param ul_arg Pointer to the cxn structure.
1310  * @param status Status of the command.
1311  * @param ext_status Extended status of the command.
1312  * @param params NULL for this call.
1313  */
1314 void
1315 ocs_cxn_reject_cb(void *ul_arg,
1316  int32_t status,
1317  uint32_t ext_status,
1318  void * params)
1319 {
1320  ocs_cxn_t *cxn = ul_arg;
1321  ocs_iscsi_t *iscsi = cxn->iscsi;
1322 
1323  if (status) {
1324  ocs_log_test(iscsi->os, "Failed rejecting connection from %s\n", cxn->display_name);
1325  ocs_sm_post_event(&cxn->sm, OCS_EVT_ERROR, NULL);
1326  } else {
1327  ocs_log_debug(iscsi->os, "cxn rejected from %s\n", cxn->display_name);
1328  ocs_sm_post_event(&cxn->sm, OCS_EVT_CXN_REJECT_CMPL, NULL);
1329  }
1330 }
1331 
1332 
1333 /**
1334  * @brief Function to receive the notification that the connection info is
1335  * available.
1336  *
1337  * @param ul_arg Pointer to the cxn structure.
1338  * @param status Status of the command.
1339  * @param ext_status Extended status of the command.
1340  * @param params NULL for this call.
1341  *
1342  * @return Returns 0 on success.
1343  */
1344 void
1345 ocs_cxn_offload_cb(void *ul_arg,
1346  int32_t status,
1347  uint32_t ext_status,
1348  void * params)
1349 {
1350  ocs_cxn_t *cxn = ul_arg;
1351  ocs_iscsi_t *iscsi = cxn->iscsi;
1352 
1353  if (status) {
1354  ocs_log_test(iscsi->os, "Failed offloading connection from %s\n",
1355  cxn->display_name);
1356  ocs_sm_post_event(&cxn->sm, OCS_EVT_ERROR, NULL);
1357  } else {
1358  ocs_log_debug(iscsi->os, "cxn Offloaded from %s, window scale %d\n",
1359  cxn->display_name,
1360  cxn->tcp_wscale);
1362  }
1363 }
1364 
1365 /**
1366  * @brief Function to receive the notification that the connection info is
1367  * available.
1368  *
1369  * @param ul_arg Pointer to the cxn structure.
1370  * @param status Status of the command.
1371  * @param ext_status Extended status of the command.
1372  * @param params NULL for this call.
1373  *
1374  * @return Returns 0 on success.
1375  */
1376 void
1377 ocs_cxn_get_info_cb(void *ul_arg,
1378  int32_t status,
1379  uint32_t ext_status,
1380  void * params)
1381 {
1382  ocs_cxn_t *cxn = ul_arg;
1383  ocs_iscsi_t *iscsi = cxn->iscsi;
1384  char ip_str[40];
1385 
1386  if (status) {
1387  ocs_log_test(iscsi->os, "Failed offloading connection from %s\n",
1388  cxn->display_name);
1389  ocs_sm_post_event(&cxn->sm, OCS_EVT_ERROR, NULL);
1390  } else {
1391  format_ip_address(ocs_iscsi_convert_to_ip_type(cxn->source_ip_type),
1392  cxn->source_ip,
1393  ip_str, sizeof(ip_str));
1394 
1395  ocs_snprintf(cxn->display_name,
1396  sizeof(cxn->display_name),
1397  "%s(%d) cid %x",
1398  ip_str,
1399  cxn->source_port,
1400  cxn->conn_hdl);
1402  }
1403 }
1404 
1405 /**
1406  * @brief This function is the callback for connecting to a target.
1407  *
1408  * @param ul_arg Pointer to the iSCSI object.
1409  * @param status Status of the command.
1410  * @param ext_status Extended status of the command.
1411  * @param params Pointer to ocs_hal_ip_address_subnet_t.
1412  */
1413 static void ocs_cxn_connect_cb(void *ul_arg,
1414  int32_t status,
1415  uint32_t ext_status,
1416  void * params)
1417 {
1418  ocs_cxn_t *cxn = ul_arg;
1419  ocs_iscsi_t *iscsi = cxn->iscsi;
1420 
1421  if (status == 0) {
1422  ocs_log_debug(iscsi->os, "Connect success\n");
1424  } else {
1425  ocs_log_test(iscsi->os, "TCP connect failed with status %d, ext_status %d\n",
1426  status, ext_status);
1427  ocs_sm_post_event(&cxn->sm, OCS_EVT_ERROR, NULL);
1428  }
1429 }
1430 
1431 /**
1432  * @brief This function is the callback for uploading a connection
1433  *
1434  * @param ul_arg Pointer to the iSCSI object.
1435  * @param status Status of the command.
1436  * @param ext_status Extended status of the command.
1437  * @param params Points to NULL.
1438  */
1439 static void ocs_cxn_upload_cb(void *ul_arg,
1440  int32_t status,
1441  uint32_t ext_status,
1442  void *params)
1443 {
1444  ocs_cxn_t *cxn = ul_arg;
1445  ocs_iscsi_t *iscsi = cxn->iscsi;
1446 
1447  if (status) {
1448  ocs_log_test(iscsi->os, "Failed to upload connection %s\n",
1449  cxn->display_name);
1450  ocs_sm_post_event(&cxn->sm, OCS_EVT_ERROR, NULL);
1451  } else {
1452  ocs_log_debug(iscsi->os, "connection uploaded %s\n",
1453  cxn->display_name);
1454  ocs_sm_post_event(&cxn->sm, OCS_EVT_CXN_UPLOAD_CMPL, NULL);
1455  }
1456 }
1457 
1458 
1459 /**
1460  * @brief This function is the callback for closing a connection
1461  *
1462  * @param ul_arg Pointer to the iSCSI object.
1463  * @param status Status of the command.
1464  * @param ext_status Extended status of the command.
1465  * @param params Points to NULL.
1466  */
1467 static void ocs_cxn_close_cb(void *ul_arg,
1468  int32_t status,
1469  uint32_t ext_status,
1470  void * params)
1471 {
1472  ocs_cxn_t *cxn = ul_arg;
1473  ocs_iscsi_t *iscsi = cxn->iscsi;
1474 
1475  if (status) {
1476  ocs_log_test(iscsi->os, "Failed to close connection %s\n",
1477  cxn->display_name);
1478  ocs_sm_post_event(&cxn->sm, OCS_EVT_ERROR, NULL);
1479  } else {
1480  ocs_log_debug(iscsi->os, "closed connection %s\n",
1481  cxn->display_name);
1482  ocs_sm_post_event(&cxn->sm, OCS_EVT_CXN_CLOSE_CMPL, NULL);
1483  }
1484 }
1485 
1486 /**
1487  * @ingroup cxn_mgnt
1488  * @brief Log an initiator into the specified target address
1489  *
1490  * @param iscsi Pointer to the iSCSI structure that represents this device.
1491  * @param remote_ip Remote IP address to connect to.
1492  * @param tcp_port Remote TCP port to connect to.
1493  * @param tgt_name The iSCSI target name.
1494  *
1495  * @return Returns 0 on success.
1496  */
1497 int32_t
1499  ocs_hal_ip_address_t *remote_ip,
1500  uint16_t tcp_port,
1501  char *tgt_name)
1502 {
1503  ocs_cxn_t *cxn;
1504  int32_t rc = -1;
1505  char ip_str[40];
1506 
1507  if (ocs_strlen(tgt_name) > OCS_MAX_ISCSI_NAME) {
1508  ocs_log_test(iscsi->os, "target name exceeds maximum length\n");
1509  return -1;
1510  }
1511 
1512  cxn = ocs_cxn_alloc(iscsi, 0);
1513  if (cxn != NULL) {
1514  int64_t isid;
1515 
1516  /* Use the Emulex OUI 0000c9 */
1517  isid = 0x0000c9000000l | cxn->instance_index;
1518  rc = ocs_session_cxn_new(cxn,
1519  tgt_name,
1520  ocs_iscsi_ini_get_name(cxn->ocs),
1521  isid,
1522  0, /* tsih */
1523  cxn->instance_index, /* cid */
1524  1); /* cmd_sn */
1525 
1526  /* This should not fail since there are as many sessions as cxn */
1527  if (rc) {
1528  ocs_log_test(iscsi->os, "failed, ocs_session_cxn_new() return %d\n",
1529  rc);
1530  ocs_hal_cxn_free(iscsi->hal, cxn);
1531  return rc;
1532  }
1533 
1534  /* save the remote IP address for retries */
1535  cxn->dest_ip_type = remote_ip->ip_type;
1536  ocs_memcpy(cxn->dest_ip, remote_ip->ip_address, 16);
1537  cxn->dest_port = tcp_port;
1539  remote_ip->ip_address,
1540  ip_str, sizeof(ip_str));
1541  ocs_snprintf(cxn->display_name,
1542  sizeof(cxn->display_name),
1543  "%s(%d)",
1544  ip_str,
1545  tcp_port);
1546  ocs_log_debug(iscsi->os, "attempt to connect to IP address %s\n",
1547  ip_str);
1548  ocs_sm_post_event(&cxn->sm, OCS_EVT_CXN_CONNECT, NULL);
1549  } else {
1550  ocs_log_err(iscsi->os, "Failed allocating an initiator connection\n");
1551  }
1552  return rc;
1553 }
1554 
1555 /**
1556  * @ingroup cxn_mgnt
1557  * @brief Function to receive new TCP connections.
1558  *
1559  * @param iscsi Pointer to the iSCSI structure that represents this device.
1560  * @param conn_hdl Connection handle from the firmware.
1561  *
1562  * @return Returns 0 on success.
1563  */
1565  uint32_t conn_hdl)
1566 {
1567  ocs_t *ocs = iscsi->os;
1568  ocs_cxn_t *cxn = NULL;
1569  int32_t rc = -1;
1570 
1571  ocs_log_debug(iscsi->os, "cxn event received conn_hdl 0x%x\n", conn_hdl);
1572 
1573  cxn = ocs_cxn_alloc(iscsi, conn_hdl);
1574  if (cxn == NULL) {
1575  rc = ocs_hal_cxn_reject(iscsi->hal, conn_hdl, NULL, NULL);
1576  } else {
1577  if (ocs_is_target_enabled()) {
1578  /*
1579  * Use validate initiator here to allow the target to reject
1580  * initiators. Will call ocs_scsi_new_initiator during login, when
1581  * the initiator name is known.
1582  */
1583  if ((ocs_scsi_validate_initiator((ocs_node_t *) cxn) == FALSE) ) {
1584  ocs_log_test(iscsi->os, "conn_hdl %u failed adding initiator to target server\n",
1585  conn_hdl);
1586  (void)ocs_session_cxn_del(cxn);
1587  ocs_hal_cxn_free(iscsi->hal, cxn);
1588  ocs_hal_cxn_reject(iscsi->hal, conn_hdl, NULL, NULL);
1589  return -1;
1590  }
1591  }
1593  }
1594 
1595  return rc;
1596 }
1597 
1598 static void ocs_tgt_cxn_invalidate_cb(void *ul_arg,
1599  int32_t status,
1600  uint32_t ext_status,
1601  void *params)
1602 {
1603  ocs_cxn_t *cxn = ul_arg;
1604  ocs_iscsi_t *iscsi = cxn->iscsi;
1605 
1606  if (status) {
1607  ocs_log_test(iscsi->os, "Failed to close connection %s\n",
1608  cxn->display_name);
1609  ocs_sm_post_event(&cxn->sm, OCS_EVT_ERROR, NULL);
1610  } else {
1611  ocs_log_debug(iscsi->os, "Invalidated cxn %s success\n",
1612  cxn->display_name);
1613  ocs_sm_post_event(&cxn->sm, OCS_EVT_CXN_CLOSE_CMPL, NULL);
1614  }
1615 }
1616 
1617 void ocs_tgt_cxn_invalidate(ocs_cxn_t *cxn)
1618 {
1619  ocs_iscsi_t *iscsi;
1620  int32_t rc;
1621 
1622  iscsi = cxn->iscsi;
1623 
1624  rc = ocs_hal_cxn_close(iscsi->hal, cxn, cxn->sendRst,
1626  cxn);
1627  if (rc) {
1628  ocs_cxn_transition(cxn, __ocs_cxn_error, NULL);
1629  } else {
1630  ocs_log_debug(iscsi->os, "sent request to close cxn, hdl=0x%x\n",
1631  cxn->conn_hdl);
1633 
1635  }
1636 }
1637 
1638 /**
1639  * @ingroup cxn_mgnt
1640  * @brief Issues a request to the HAL to close the connection.
1641  *
1642  * @param cxn Pointer to the connection object.
1643  * @param sendRst Non-zero sends a TCP reset on the connection.
1644  *
1645  * @return Returns 0 on success.
1646  */
1647 int32_t
1648 ocs_cxn_close(ocs_cxn_t *cxn,
1649  uint8_t sendRst)
1650 {
1651  ocs_sm_post_event(&cxn->sm,
1653  NULL);
1654  return 0;
1655 }
1656 
1657 /**
1658  * @brief Allocates a connection and initializes the fields as required.
1659  *
1660  * @param iscsi Pointer to the iSCSI structure that represents this device.
1661  * @param conn_hdl Connection handle from the firmware.
1662  *
1663  * @return Returns 0 on success.
1664  */
1665 ocs_cxn_t*
1667  uint32_t conn_hdl)
1668 {
1669  ocs_t *ocs = iscsi->os;
1670  ocs_cxn_t *cxn;
1671 
1672  cxn = ocs_hal_cxn_alloc(iscsi->hal, conn_hdl);
1673  if (cxn != NULL) {
1674  /*
1675  * Set the login parameters to the desired values and then let the
1676  * login change them as required.
1677  */
1678  cxn->data_digest = (ocs->enable_data_digest ? 1 : 0);
1679  cxn->hdr_digest = (ocs->enable_hdr_digest ? 1 : 0);
1680  cxn->use_chap = 0;
1681  cxn->max_rcv_dsl = 8192;
1682  cxn->max_xmit_dsl = 8192;
1683  cxn->chap_state = 0;
1684  cxn->chap_ident_recv = 0;
1685  cxn->chap_challenge_recv = NULL;
1686  cxn->chap_response = NULL;
1687  cxn->chap_name_recv = NULL;
1688  cxn->chap_name_send = NULL;
1689 
1690  cxn->ocs = iscsi->os;
1691  cxn->iscsi = iscsi;
1692  cxn->session = NULL;
1693  cxn->cxn_state = CONN_STATE_NEW_CONN;
1694  cxn->is_leading_login = TRUE;
1695  cxn->is_first_login_rsp = 1;
1696  cxn->send_logout_rsp = 0;
1697  cxn->logout_rsp = 0;
1698  cxn->idle_count = 0;
1699  cxn->lgn_parms_sent = 0;
1700  cxn->lgn_parms_recv = 0;
1701  cxn->stat_sn = 0;
1702  cxn->no_idle_timer = FALSE;
1703  cxn->sm.app = cxn;
1704  cxn->ffp_is_neg_active = FALSE;
1705  ocs_list_init(&cxn->cbit_list, ocs_cxn_q_cbit_t, link);
1706  cxn->cbit_rsp = NULL;
1707  cxn->cbit_rsp_len = 0;
1708  cxn->cbit_rsp_offset = 0;
1709  cxn->data_digest_error = FALSE;
1710  cxn->login_hdr_mem =
1711  *ocs_iscsi_tracker_calc(&iscsi->cxn_login_hdr, cxn->instance_index);
1712  cxn->login_data_mem =
1713  *ocs_iscsi_tracker_calc(&iscsi->cxn_login_data, cxn->instance_index);
1714  cxn->mgmt_functions = &node_mgmt_functions;
1715  ocs_atomic_init(&cxn->login_mem_in_use, 0);
1716  ocs_list_init(&cxn->aborted_ios, ocs_io_t, link);
1717  ocs_atomic_init(&cxn->nop_abort_counter, 0);
1718 
1719 
1721  }
1722  return cxn;
1723 }
1724 
1725 /**
1726  * @brief Generate node ddump data.
1727  *
1728  * @par Description
1729  * Generates the node ddump data.
1730  *
1731  * @param textbuf Pointer to text buffer.
1732  * @param node Pointer to node context.
1733  *
1734  * @return Returns 0 on success, or a negative value on failure.
1735  */
1736 
1737 int
1738 ocs_ddump_node(ocs_textbuf_t *textbuf, ocs_node_t *node)
1739 {
1740  ocs_io_t *io;
1741  char ip_str[40];
1742  int retval = 0;
1743 
1744  ocs_ddump_section(textbuf, "node", node->instance_index);
1745  ocs_ddump_value(textbuf, "display_name", "%s", node->display_name);
1746 
1747  ocs_ddump_value(textbuf, "conn_hdl", "0x%x", node->conn_hdl);
1748  ocs_ddump_value(textbuf, "wq_id", "%d", node->wq_id);
1749  ocs_ddump_value(textbuf, "wq_index", "%d", node->wq_index);
1750  ocs_ddump_value(textbuf, "source_ip_type", "%d", node->source_ip_type);
1751 
1752  format_ip_address(ocs_iscsi_convert_to_ip_type(node->source_ip_type),
1753  node->source_ip, ip_str, sizeof(ip_str));
1754  ocs_ddump_value(textbuf, "source_ip", "%s", ip_str);
1755  ocs_ddump_value(textbuf, "source_port", "%d", node->source_port);
1756  ocs_ddump_value(textbuf, "dest_ip_type", "%d", node->dest_ip_type);
1757 
1758  format_ip_address(ocs_iscsi_convert_to_ip_type(node->dest_ip_type),
1759  node->dest_ip, ip_str, sizeof(ip_str));
1760  ocs_ddump_value(textbuf, "dest_ip", "%s", ip_str);
1761  ocs_ddump_value(textbuf, "dest_port", "%d", node->dest_port);
1762  ocs_ddump_value(textbuf, "tcp_mss", "%d", node->tcp_mss);
1763  ocs_ddump_value(textbuf, "max_wr_xfer_size", "%d", node->max_wr_xfer_size);
1764 
1765  // ocs_scsi_ini_ddump(textbuf, OCS_SCSI_DDUMP_NODE, node);
1766  ocs_scsi_tgt_ddump(textbuf, OCS_SCSI_DDUMP_NODE, node);
1767 
1768  if (ocs_node_lock_try(node) != TRUE) {
1769  /* Didn't get the lock */
1770  return -1;
1771  }
1772  ocs_list_foreach(&node->active_ios, io) {
1773  ocs_ddump_io(textbuf, io);
1774  }
1775  ocs_node_unlock(node);
1776 
1777  ocs_ddump_endsection(textbuf, "node", node->instance_index);
1778 
1779  return retval;
1780 }
1781 
1782 void
1783 ocs_mgmt_node_list(ocs_textbuf_t *textbuf, void *object)
1784 {
1785  ocs_io_t *io;
1786  ocs_node_t *node = (ocs_node_t *)object;
1787 
1788  ocs_mgmt_start_section(textbuf, "node", node->instance_index);
1789 
1790  /* Readonly values */
1791 
1792  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "cid");
1793  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "source_ip_type");
1794  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "source_ip");
1795  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "source_port");
1796  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "dest_ip_type");
1797  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "dest_ip");
1798  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "dest_port");
1799  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "tcp_mss");
1800  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "is_ini_cxn");
1801  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "max_wr_xfer_size");
1802  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "display_name");
1803  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "cxn_state");
1804  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "is_discovery_session");
1805  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "is_leading_login");
1806  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "sendRst");
1807  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "idle_count");
1808  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "lgn_parms_sent");
1809  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "lgn_parms_recv");
1810  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "cmd_sn");
1811  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "cmd_window");
1812  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "exp_cmd_sn");
1813  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "max_cmd_sn");
1814  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "stat_sn");
1815  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "sess_id");
1816 
1817 
1818  if (ocs_node_lock_try(node) == TRUE) {
1819 
1820  /* Here the node lock is held */
1821  ocs_list_foreach(&node->active_ios, io) {
1822  if ((io->mgmt_functions) && (io->mgmt_functions->get_list_handler)) {
1823  io->mgmt_functions->get_list_handler(textbuf, io);
1824  }
1825  }
1826  ocs_node_unlock(node);
1827  }
1828 
1829  ocs_mgmt_end_section(textbuf, "node", node->instance_index);
1830 }
1831 
1832 int
1833 ocs_mgmt_node_get(ocs_textbuf_t *textbuf, char *parent, char *name, void *object)
1834 {
1835  ocs_io_t *io;
1836  ocs_node_t *node = (ocs_node_t *)object;
1837  char qualifier[80];
1838  char ip_str[40];
1839  int retval = -1;
1840 
1841  ocs_mgmt_start_section(textbuf, "node", node->instance_index);
1842  ocs_snprintf(qualifier, sizeof(qualifier), "%s.node%d", parent, node->instance_index);
1843 
1844  /* If it doesn't start with my qualifier I don't know what to do with it */
1845  if (ocs_strncmp(name, qualifier, strlen(qualifier)) == 0) {
1846  char *unqualified_name = name + strlen(qualifier) +1;
1847 
1848  /* See if it's a value I can supply */
1849  if (ocs_strcmp(unqualified_name, "cid") == 0) {
1850  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "cid", "0x%x", node->cid);
1851  retval = 0;
1852  } else if (ocs_strcmp(unqualified_name, "source_ip_type") == 0) {
1853  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "source_ip_type", "0x%x", node->source_ip_type);
1854  retval = 0;
1855  } else if (ocs_strcmp(unqualified_name, "source_ip") == 0) {
1856  format_ip_address(ocs_iscsi_convert_to_ip_type(node->source_ip_type),
1857  node->source_ip, ip_str, sizeof(ip_str));
1858  ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "source_ip", ip_str);
1859  retval = 0;
1860  } else if (ocs_strcmp(unqualified_name, "source_port") == 0) {
1861  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "source_port", "%d", node->source_port);
1862  retval = 0;
1863  } else if (ocs_strcmp(unqualified_name, "dest_ip_type") == 0) {
1864  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "dest_ip_type", "0x%x", node->dest_ip_type);
1865  retval = 0;
1866  } else if (ocs_strcmp(unqualified_name, "dest_ip") == 0) {
1867  format_ip_address(ocs_iscsi_convert_to_ip_type(node->dest_ip_type),
1868  node->dest_ip, ip_str, sizeof(ip_str));
1869  ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "dest_ip", ip_str);
1870  retval = 0;
1871  } else if (ocs_strcmp(unqualified_name, "dest_port") == 0) {
1872  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "dest_port", "%d", node->dest_port);
1873  retval = 0;
1874  } else if (ocs_strcmp(unqualified_name, "tcp_mss") == 0) {
1875  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "tcp_mss", "%d", node->tcp_mss);
1876  retval = 0;
1877  } else if (ocs_strcmp(unqualified_name, "is_ini_cxn") == 0) {
1878  ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "is_ini_cxn", node->is_ini_cxn);
1879  retval = 0;
1880  } else if (ocs_strcmp(unqualified_name, "max_wr_xfer_size") == 0) {
1881  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "max_wr_xfer_size", "%d", node->max_wr_xfer_size);
1882  retval = 0;
1883  } else if (ocs_strcmp(unqualified_name, "display_name") == 0) {
1884  ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "display_name", node->display_name);
1885  retval = 0;
1886  } else if (ocs_strcmp(unqualified_name, "cxn_state") == 0) {
1887  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "cxn_state", "0x%x", node->cxn_state);
1888  retval = 0;
1889  } else if (ocs_strcmp(unqualified_name, "is_leading_login") == 0) {
1890  ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "is_leading_login", node->is_leading_login);
1891  retval = 0;
1892  } else if (ocs_strcmp(unqualified_name, "sendRst") == 0) {
1893  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "sendRst", "0x%x", node->sendRst);
1894  retval = 0;
1895  } else if (ocs_strcmp(unqualified_name, "idle_count") == 0) {
1896  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "idle_count", "%d", node->idle_count);
1897  retval = 0;
1898  } else if (ocs_strcmp(unqualified_name, "lgn_parms_sent") == 0) {
1899  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "lgn_parms_sent", "0x%" PRIx64 , node->lgn_parms_sent);
1900  retval = 0;
1901  } else if (ocs_strcmp(unqualified_name, "lgn_parms_recv") == 0) {
1902  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "lgn_parms_recv", "0x%" PRIx64 , node->lgn_parms_recv);
1903  retval = 0;
1904  } else if (ocs_strcmp(unqualified_name, "stat_sn") == 0) {
1905  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "stat_sn", "0x%x", node->stat_sn);
1906  retval = 0;
1907  } else {
1908  /* If I didn't know the value of this status pass the request to each of my children */
1909  ocs_node_lock(node);
1910  ocs_list_foreach(&node->active_ios, io) {
1911  if ((io->mgmt_functions) && (io->mgmt_functions->get_handler)) {
1912  retval = io->mgmt_functions->get_handler(textbuf, qualifier, name, io);
1913  }
1914 
1915  if (retval == 0) {
1916  break;
1917  }
1918  }
1919  ocs_node_unlock(node);
1920  }
1921  }
1922 
1923  ocs_mgmt_end_section(textbuf, "node", node->instance_index);
1924 
1925  return retval;
1926 }
1927 
1928 void
1929 ocs_mgmt_node_get_all(ocs_textbuf_t *textbuf, void *object)
1930 {
1931  ocs_io_t *io;
1932  ocs_node_t *node = (ocs_node_t *)object;
1933  char ip_str[40];
1934 
1935  ocs_mgmt_start_section(textbuf, "node", node->instance_index);
1936 
1937  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "cid", "0x%x", node->cid);
1938  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "source_ip_type", "0x%x", node->source_ip_type);
1939  format_ip_address(ocs_iscsi_convert_to_ip_type(node->source_ip_type),
1940  node->source_ip, ip_str, sizeof(ip_str));
1941  ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "source_ip", ip_str);
1942  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "source_port", "%d", node->source_port);
1943  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "dest_ip_type", "0x%x", node->dest_ip_type);
1944  format_ip_address(ocs_iscsi_convert_to_ip_type(node->dest_ip_type),
1945  node->dest_ip, ip_str, sizeof(ip_str));
1946  ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "dest_ip", ip_str);
1947  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "dest_port", "%d", node->dest_port);
1948  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "tcp_mss", "%d", node->tcp_mss);
1949  ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "is_ini_cxn", node->is_ini_cxn);
1950  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "max_wr_xfer_size", "%d", node->max_wr_xfer_size);
1951  ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "display_name", node->display_name);
1952  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "cxn_state", "0x%x", node->cxn_state);
1953  ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "is_leading_login", node->is_leading_login);
1954  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "sendRst", "0x%x", node->sendRst);
1955  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "idle_count", "%d", node->idle_count);
1956  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "lgn_parms_sent", "0x%" PRIx64 , node->lgn_parms_sent);
1957  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "lgn_parms_recv", "0x%" PRIx64 , node->lgn_parms_recv);
1958  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "stat_sn", "0x%x", node->stat_sn);
1959 
1960  ocs_node_lock(node);
1961  ocs_list_foreach(&node->active_ios, io) {
1962  if ((io->mgmt_functions) && (io->mgmt_functions->get_all_handler)) {
1963  io->mgmt_functions->get_all_handler(textbuf, io);
1964  }
1965 
1966  }
1967  ocs_node_unlock(node);
1968 
1969  ocs_mgmt_end_section(textbuf, "node", node->instance_index);
1970 }
1971 
1972 int
1973 ocs_mgmt_node_set(char *parent, char *name, char *value, void *object)
1974 {
1975  ocs_io_t *io;
1976  ocs_node_t *node = (ocs_node_t *)object;
1977  char qualifier[80];
1978  int retval = -1;
1979 
1980  ocs_snprintf(qualifier, sizeof(qualifier), "%s/node[%d]", parent, node->instance_index);
1981 
1982  /* If it doesn't start with my qualifier I don't know what to do with it */
1983  if (ocs_strncmp(name, qualifier, strlen(qualifier)) == 0) {
1984 
1985  /* If I didn't know the value of this status pass the request to each of my children */
1986  ocs_node_lock(node);
1987  ocs_list_foreach(&node->active_ios, io) {
1988  if ((io->mgmt_functions) && (io->mgmt_functions->set_handler)) {
1989  retval = io->mgmt_functions->set_handler(qualifier, name, value, io);
1990  }
1991 
1992  if (retval == 0) {
1993  break;
1994  }
1995  }
1996  ocs_node_unlock(node);
1997  }
1998 
1999  return retval;
2000 }
2001 
2002 int
2003 ocs_mgmt_node_exec(char *parent, char *action, void *arg_in, uint32_t arg_in_length,
2004  void *arg_out, uint32_t arg_out_length, void *object)
2005 {
2006  ocs_io_t *io;
2007  ocs_node_t *node = (ocs_node_t *)object;
2008  char qualifier[80];
2009  int retval = -1;
2010 
2011  ocs_snprintf(qualifier, sizeof(qualifier), "%s.node%d", parent, node->instance_index);
2012 
2013  /* If it doesn't start with my qualifier I don't know what to do with it */
2014  if (ocs_strncmp(action, qualifier, strlen(qualifier)) == 0) {
2015 
2016  /* If I didn't know how to do this action pass the request to each of my children */
2017  ocs_node_lock(node);
2018  ocs_list_foreach(&node->active_ios, io) {
2019  if ((io->mgmt_functions) && (io->mgmt_functions->exec_handler)) {
2020  retval = io->mgmt_functions->exec_handler(qualifier, action, arg_in, arg_in_length,
2021  arg_out, arg_out_length, io);
2022  }
2023 
2024  if (retval == 0) {
2025  break;
2026  }
2027  }
2028  ocs_node_unlock(node);
2029  }
2030 
2031  return retval;
2032 }
static int32_t ocs_list_on_list(ocs_list_link_t *link)
Test if object is on a list.
Definition: ocs_list.h:460
void ocs_iscsi_cbit_cleanup(ocs_cxn_t *cxn)
Sends the login parameters to the firmware.
Definition: ocs_login.c:2410
ocs_hal_rtn_e ocs_hal_cxn_connect(ocs_hal_t *hal, ocs_cxn_t *cxn, ocs_hal_ip_address_t *ipaddr, uint32_t tcp_port, uint16_t window_size, uint8_t window_scale, cxn_cb_t cxn_cb, void *ul_arg)
Establish a TCP connection from an initiator to a target.
Definition: ocs_hal.c:4551
static void ocs_cxn_set_sm_retry_timer(ocs_cxn_t *cxn, uint32_t timeout)
Set the SM timer to retry a command at a later time.
Definition: ocs_cxn.c:261
static void * __ocs_cxn_connect_delay(ocs_sm_ctx_t *, ocs_sm_event_t, void *)
State: Connection to target failed, delay before retrying.
Definition: ocs_cxn.c:480
static void ocs_cxn_connect_cb(void *, int32_t, uint32_t, void *)
This function is the callback for connecting to a target.
Definition: ocs_cxn.c:1413
ocs_hal_rtn_e ocs_hal_cxn_close(ocs_hal_t *hal, ocs_cxn_t *cxn, uint8_t sendRst, cxn_cb_t cxn_cb, void *ul_arg)
Invalidates a connection and optionally sends a TCP Reset.
Definition: ocs_hal.c:5038
ocs_iscsi_mem_tracker_t cxn_login_data
Definition: ocs_iscsi.h:312
int32_t ocs_iscsi_are_login_reqs_outstanding(ocs_cxn_t *cxn)
Checks to see if there are any retry or login IOs active on a connection.
Definition: ocs_login.c:245
ocs_hal_t * hal
Definition: ocs_iscsi.h:295
static void * __ocs_cxn_upload_wait(ocs_sm_ctx_t *, ocs_sm_event_t, void *)
State: Waiting for connection upload to complete.
Definition: ocs_cxn.c:898
int ocs_mgmt_node_set(char *parent, char *name, char *value, void *node)
Definition: ocs_cxn.c:1973
void ocs_scsi_pending_cleanup(ocs_node_t *node)
Clean up any IOs on the pending list when a connection goes down.
Definition: ocs_scsi.c:598
static void * __ocs_cxn_connect_wait(ocs_sm_ctx_t *, ocs_sm_event_t, void *)
State: Waiting for the connection to complete.
Definition: ocs_cxn.c:427
static void ocs_cxn_get_info_cb(void *, int32_t, uint32_t, void *)
Function to receive the notification that the connection info is available.
Definition: ocs_cxn.c:1377
static int32_t ocs_list_empty(ocs_list_t *list)
Test if a list is empty.
Definition: ocs_list.h:125
uint8_t ip_address[16]
Definition: ocs_hal.h:261
static void * __ocs_cxn_initial(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
State: Initial state.
Definition: ocs_cxn.c:320
void ocs_mgmt_emit_int(ocs_textbuf_t *textbuf, int mode, const char *name, const char *fmt,...)
Generate a property with an integer value in a management XML document.
static void ocs_cxn_retry_timeout(void *arg)
This function is called on timer expiration and sends an event to the the state machine.
Definition: ocs_cxn.c:247
#define cxn_sm_trace()
Definition: ocs_cxn.c:66
static void * __ocs_cxn_reject_wait(ocs_sm_ctx_t *, ocs_sm_event_t, void *)
State: Waiting for connection reject request to complete.
Definition: ocs_cxn.c:1231
static ocs_mgmt_functions_t node_mgmt_functions
Definition: ocs_cxn.c:78
ocs_cxn_t * ocs_hal_cxn_alloc(ocs_hal_t *hal, uint32_t conn_hdl)
Gets a free connection structure.
Definition: ocs_hal.c:4468
static void * __ocs_cxn_upload(ocs_sm_ctx_t *, ocs_sm_event_t, void *)
State: Closing, waiting for the close callback.
Definition: ocs_cxn.c:849
ocs_cxn_t * ocs_cxn_alloc(ocs_iscsi_t *iscsi, uint32_t conn_hdl)
Allocates a connection and initializes the fields as required.
Definition: ocs_cxn.c:1666
int32_t ocs_iscsi_send_login(ocs_cxn_t *cxn, bool is_discovery, char *tgt_name)
Function to send an initial login PDU.
Definition: ocs_login.c:3182
int32_t ocs_cxn_initialize(ocs_iscsi_t *iscsi)
Initialize the iSCSI connection objects.
Definition: ocs_cxn.c:121
static void * __ocs_cxn_close(ocs_sm_ctx_t *, ocs_sm_event_t, void *)
Closes a TCP connection.
Definition: ocs_cxn.c:741
#define OCS_ISCSI_CXN_RETRY_TIMER_CONNECT_MS
int ocs_ddump_node(ocs_textbuf_t *textbuf, ocs_node_t *node)
Generate node ddump data.
Definition: ocs_cxn.c:1738
ocs_hal_rtn_e ocs_hal_cxn_reject(ocs_hal_t *hal, uint32_t conn_hdl, cxn_cb_t cxn_cb, void *ul_arg)
Rejects an incoming connection on a target.
Definition: ocs_hal.c:4685
void ocs_mgmt_node_get_all(ocs_textbuf_t *textbuf, void *node)
Definition: ocs_cxn.c:1929
int ocs_mgmt_node_get(ocs_textbuf_t *textbuf, char *parent, char *name, void *node)
Definition: ocs_cxn.c:1833
ocs_iscsi_mem_tracker_t cxn_login_hdr
Definition: ocs_iscsi.h:311
static void ocs_cxn_transition(ocs_cxn_t *cxn, ocs_sm_function_t state, void *data)
Transition state of a node.
Definition: ocs_cxn.c:227
#define OCS_ISCSI_LOGIN_PAYLOAD_SIZE
void ocs_cxn_force_free(ocs_cxn_t *cxn)
Free memory resources of a node object.
Definition: ocs_cxn.c:174
static void ocs_device_lock(ocs_t *ocs)
Definition: ocs_drv_fc.h:218
char * ocs_iscsi_ini_get_name(ocs_t *ocs)
Return this initiator's name.
const char * name
Definition: ocs_ddump.h:54
int32_t ocs_scsi_del_initiator(ocs_node_t *node, ocs_scsi_del_initiator_reason_e reason)
Delete a SCSI initiator node.
Definition: ocs_ramd.c:1092
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
void ocs_mgmt_start_section(ocs_textbuf_t *textbuf, const char *name, int index)
Generate the beginning of a numbered section in a management XML document.
int const char const char void ocs_mgmt_emit_boolean(ocs_textbuf_t *textbuf, int access, const char *name, const int value)
Generate a property with a boolean value in a management XML document.
#define std_cxn_state_decl(...)
Definition: ocs_cxn.c:53
static void * ocs_list_remove(ocs_list_t *list, void *item)
Remove an item from the list.
Definition: ocs_list.h:385
void ocs_cxn_teardown(ocs_iscsi_t *iscsi)
Free the iSCSI connection objects.
Definition: ocs_cxn.c:155
const char * ocs_sm_event_name(ocs_sm_event_t evt)
Definition: ocs_sm.c:93
int32_t ocs_session_cxn_del(ocs_cxn_t *cxn)
Removes a connection from its session.
Definition: ocs_session.c:343
#define OCS_ISCSI_CACHE_LINE_SIZE
#define ocs_list_init(head, type, link)
Definition: ocs_list.h:113
static void * __ocs_cxn_close_abort_io(ocs_sm_ctx_t *, ocs_sm_event_t, void *)
Aborts active IO objects on a connection.
Definition: ocs_cxn.c:555
ocs_ip_type_e ocs_iscsi_convert_to_ip_type(ocs_hal_ip_type_e ip_type)
Convert an HAL IP type to the iSCSI API value.
Definition: ocs_iscsi.c:327
ocs_hal_rtn_e ocs_hal_io_abort(ocs_hal_t *hal, ocs_hal_io_t *io, ocs_hal_abort_scope_e abort_scope, ocs_hal_abort_type_e abort_type)
Abort a currently running IO.
Definition: ocs_hal.c:6148
int ocs_mgmt_node_exec(char *parent, char *action, void *arg_in, uint32_t arg_in_length, void *arg_out, uint32_t arg_out_length, void *node)
Definition: ocs_cxn.c:2003
void *(* ocs_sm_function_t)(ocs_sm_ctx_t *, ocs_sm_event_t, void *)
Definition: ocs_sm.h:107
#define ocs_list_foreach_safe(list, item, nxt)
Iterate a linked list safely.
Definition: ocs_list.h:446
static void ocs_device_unlock(ocs_t *ocs)
Definition: ocs_drv_fc.h:223
static void ocs_tgt_cxn_invalidate_cb(void *ul_arg, int32_t status, uint32_t ext_status, void *params)
Definition: ocs_cxn.c:1598
static void * __ocs_cxn_offload_wait(ocs_sm_ctx_t *, ocs_sm_event_t, void *)
State: Waiting for connection offload request to complete.
Definition: ocs_cxn.c:1126
#define CONN_STATE_LOGOUT_REQUESTED
static void * __ocs_cxn_connect(ocs_sm_ctx_t *, ocs_sm_event_t, void *)
State: Connect to a remote node.
Definition: ocs_cxn.c:374
void ocs_iscsi_tracker_init(ocs_iscsi_mem_tracker_t *tracker)
Initialize the memory tracker.
Definition: ocs_iscsi.c:4275
iSCSI object
Definition: ocs_iscsi.h:293
void ocs_mgmt_end_section(ocs_textbuf_t *textbuf, const char *name, int index)
Generate the indexed end of a section in a management XML document.
uint32_t num_cxns
Definition: ocs_iscsi.h:299
static void * __ocs_cxn_close_abort_login(ocs_sm_ctx_t *, ocs_sm_event_t, void *)
Aborts any login transactions on a connection.
Definition: ocs_cxn.c:624
ocs_hal_ip_type_e ip_type
Definition: ocs_hal.h:260
static void * __ocs_cxn_offload(ocs_sm_ctx_t *, ocs_sm_event_t, void *)
Offload the connection to the chip.
Definition: ocs_cxn.c:1073
ocs_os_handle_t os
Definition: ocs_iscsi.h:294
static void * __ocs_cxn_close_wait(ocs_sm_ctx_t *, ocs_sm_event_t, void *)
State: Closing, waiting for the close callback.
Definition: ocs_cxn.c:801
ocs_hal_rtn_e ocs_hal_cxn_offload(ocs_hal_t *hal, ocs_cxn_t *cxn, uint32_t tcp_window_size, uint8_t data_digest, uint8_t hdr_digest, uint32_t max_rcv_dsl, cxn_cb_t cxn_cb, void *ul_arg)
Offloads an incoming connection on a target.
Definition: ocs_hal.c:4919
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
static int32_t ocs_node_lock_try(ocs_node_t *node)
Definition: ocs_common.h:427
static void * __ocs_cxn_abort_wait(ocs_sm_ctx_t *, ocs_sm_event_t, void *)
State: Waiting for the IO aborts to complete.
Definition: ocs_cxn.c:669
ocs_mgmt_get_list_handler get_list_handler
Definition: ocs_mgmt.h:83
static void * __ocs_cxn_get_info(ocs_sm_ctx_t *, ocs_sm_event_t, void *)
Get information on the connection.
Definition: ocs_cxn.c:983
ocs_hal_rtn_e ocs_hal_cxn_free(ocs_hal_t *hal, ocs_cxn_t *cxn)
Frees a connection object for re-use.
Definition: ocs_hal.c:5141
static void ocs_cxn_close_cb(void *, int32_t, uint32_t, void *)
This function is the callback for closing a connection.
Definition: ocs_cxn.c:1467
#define MGMT_MODE_RD
Definition: ocs_mgmt.h:47
int ocs_sm_post_event(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
Post an event to a context.
Definition: ocs_sm.c:59
static void ocs_cxn_upload_cb(void *, int32_t, uint32_t, void *)
This function is the callback for uploading a connection.
Definition: ocs_cxn.c:1439
ocs_dma_t * ocs_iscsi_tracker_calc(ocs_iscsi_mem_tracker_t *tracker, uint32_t obj_offset)
Helper to return the pointers for a specific object in the group.
Definition: ocs_iscsi.c:4429
#define OCS_ISCSI_LOGIN_MAX_RECV_DATA_SEG_LEN
void ocs_scsi_tgt_ddump(ocs_textbuf_t *textbuf, ocs_scsi_ddump_type_e type, void *obj)
Definition: ocs_ramd.c:6580
static void * __ocs_cxn_reject(ocs_sm_ctx_t *, ocs_sm_event_t, void *)
Reject a connection after some connection protocol started.
Definition: ocs_cxn.c:1173
static void ocs_cxn_offload_cb(void *, int32_t, uint32_t, void *)
Function to receive the notification that the connection info is available.
Definition: ocs_cxn.c:1345
void format_ip_address(ocs_ip_type_e ip_type, uint8_t *address, char *buffer, int size)
Format an IP address into a string.
Definition: ocs_iscsi.c:460
structure wrapping an IP address together with it's type.
Definition: ocs_hal.h:259
static void ocs_node_lock(ocs_node_t *node)
Definition: ocs_common.h:432
static void * __ocs_cxn_common(const char *funcname, ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
State: Common device event handler.
Definition: ocs_cxn.c:288
int32_t ocs_cxn_connect(ocs_iscsi_t *iscsi, ocs_hal_ip_address_t *remote_ip, uint16_t tcp_port, char *tgt_name)
Log an initiator into the specified target address.
Definition: ocs_cxn.c:1498
int32_t ocs_iscsi_send_logout_rsp(ocs_cxn_t *cxn, uint8_t response, uint32_t itt)
Function to send a logout response PDU.
Definition: ocs_login.c:4095
ocs_hal_rtn_e ocs_hal_cxn_get_info(ocs_hal_t *hal, ocs_cxn_t *cxn, cxn_cb_t cxn_cb, void *ul_arg)
Retrieves information about an incoming context.
Definition: ocs_hal.c:4795
#define ocs_is_target_enabled()
void ocs_ddump_io(ocs_textbuf_t *textbuf, ocs_io_t *io)
generate IO context ddump data
Definition: ocs_io.c:330
static void * __ocs_cxn_get_info_wait(ocs_sm_ctx_t *, ocs_sm_event_t, void *)
State: Waiting for connection information request to complete.
Definition: ocs_cxn.c:1032
static void ocs_node_unlock(ocs_node_t *node)
Definition: ocs_common.h:437
int32_t ocs_scsi_del_target(ocs_node_t *node, ocs_scsi_del_target_reason_e reason)
Delete a SCSI target node.
int32_t ocs_scsi_validate_initiator(ocs_node_t *node)
Validate a new initiator.
Definition: ocs_ramd.c:1002
static void ocs_cxn_reject_cb(void *, int32_t, uint32_t, void *)
Function to receive the notification that the connection reject is complete.
Definition: ocs_cxn.c:1315
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
void ocs_mgmt_node_list(ocs_textbuf_t *textbuf, void *node)
Definition: ocs_cxn.c:1783
#define OCS_MAX_ISCSI_NAME
Definition: ocs_common.h:240
static void ocs_io_free(ocs_t *ocs, ocs_io_t *io)
Definition: ocs_drv_fc.h:238
static void * __ocs_cxn_connected(ocs_sm_ctx_t *, ocs_sm_event_t, void *)
State: Connected, waiting for the teardown request.
Definition: ocs_cxn.c:519
static void ocs_scsi_notify_node_force_free(ocs_node_t *node)
Notification from base driver that node is in force-free path.
ocs_sm_event_t
State Machine Events.
Definition: ocs_sm.h:59
void ocs_mgmt_emit_string(ocs_textbuf_t *textbuf, int access, const char *name, const char *value)
Generate a property with a string value in a management XML document.
#define ocs_list_foreach(list, item)
Iterate a linked list.
Definition: ocs_list.h:428
#define OCS_ISCSI_CXN_RETRY_TIMER_NO_RESOURCES_MS
int32_t ocs_cxn_new_tgt_connection(ocs_iscsi_t *iscsi, uint32_t conn_hdl)
Function to receive new TCP connections.
Definition: ocs_cxn.c:1564
void ocs_sm_disable(ocs_sm_ctx_t *ctx)
Disable further state machine processing.
Definition: ocs_sm.c:88
int32_t ocs_iscsi_tracker_alloc(ocs_iscsi_t *iscsi, ocs_iscsi_mem_tracker_t *tracker, uint8_t zero, uint32_t object_size, uint32_t alignment, uint32_t num_objects)
Allocate a group of objects uses pages to minimize waste.
Definition: ocs_iscsi.c:4331
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
static void * __ocs_cxn_error(ocs_sm_ctx_t *, ocs_sm_event_t, void *)
An error was received, something unexpected occurred.
Definition: ocs_cxn.c:1273
void ocs_mgmt_emit_property_name(ocs_textbuf_t *textbuf, int access, const char *name)
Generate a property, with no value, in a management XML document.
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
#define CONN_STATE_CLEANUP
void ocs_iscsi_tracker_free(ocs_iscsi_t *iscsi, ocs_iscsi_mem_tracker_t *tracker)
Free the memory associated with a memory tracker.
Definition: ocs_iscsi.c:4293
ocs_hal_rtn_e ocs_iscsi_login_cxn_cleanup(ocs_cxn_t *cxn)
Frees any retry objects for the connection.
Definition: ocs_login.c:277
ocs_hal_rtn_e ocs_hal_cxn_upload(ocs_hal_t *hal, ocs_cxn_t *cxn, uint8_t graceful, cxn_cb_t cxn_cb, void *ul_arg)
uploads an incoming connection on a target.
Definition: ocs_hal.c:5096
void ocs_tgt_cxn_invalidate(ocs_cxn_t *cxn)
Definition: ocs_cxn.c:1617