Emulex Logo
OneCoreā„¢ Storage SDK Release 11.2
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ocs_device.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  * Implement remote device state machine for target and initiator.
36  */
37 
38 /*!
39 @defgroup device_sm Node State Machine: Remote Device States
40 */
41 
42 #include "ocs.h"
43 #include "ocs_device.h"
44 #include "ocs_fabric.h"
45 #include "ocs_els.h"
46 #include "scsi_cmds.h"
47 
48 static void *__ocs_d_common(const char *funcname, ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
49 static void *__ocs_d_wait_del_node(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
50 static void *__ocs_d_wait_del_ini_tgt(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
51 static int32_t ocs_process_abts(ocs_io_t *io, fc_header_t *hdr);
52 
53 /**
54  * @ingroup device_sm
55  * @brief Send response to PRLI.
56  *
57  * <h3 class="desc">Description</h3>
58  * For device nodes, this function sends a PRLI response.
59  *
60  * @param io Pointer to a SCSI IO object.
61  * @param ox_id OX_ID of PRLI
62  *
63  * @return Returns None.
64  */
65 
66 void
67 ocs_d_send_prli_rsp(ocs_io_t *io, uint16_t ox_id, uint8_t fc_type)
68 {
69  ocs_t *ocs = io->ocs;
70  ocs_node_t *node = io->node;
71 
72  if (fc_type == FC_TYPE_NVME) {
73  if (!node->ocs->enable_nvme_tgt || ocs_nvme_process_prli(io, ox_id)) {
74  node_printf(node, "NVME: PRLI rejected by target-server\n");
76  FC_EXPL_NO_ADDITIONAL, 0, NULL, NULL);
77  }
78  return;
79  }
80 
81  /* If the back-end doesn't support the fc-type, we send an LS_RJT */
82  if (ocs->fc_type != node->fc_type) {
83  node_printf(node, "PRLI rejected by target-server, fc-type not supported\n");
85  FC_EXPL_REQUEST_NOT_SUPPORTED, 0, NULL, NULL);
86  node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT;
88  return;
89  }
90 
91  /* If the back-end doesn't want to talk to this initiator, we send an LS_RJT */
92  if (node->sport->enable_tgt && (ocs_scsi_validate_initiator(node) == 0)) {
93  node_printf(node, "PRLI rejected by target-server\n");
95  FC_EXPL_NO_ADDITIONAL, 0, NULL, NULL);
96  node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT;
98  } else {
99  //sm: / process PRLI payload, send PRLI acc
100  ocs_send_prli_acc(io, ox_id, ocs->fc_type, NULL, NULL);
101 
102  /* Immediately go to ready state to avoid window where we're
103  * waiting for the PRLI LS_ACC to complete while holding FCP_CMNDs
104  */
106  }
107 }
108 
109 /**
110  * @ingroup device_sm
111  * @brief Device node state machine: Initiate node shutdown
112  *
113  * @param ctx Remote node state machine context.
114  * @param evt Event to process.
115  * @param arg Per event optional argument.
116  *
117  * @return Returns NULL.
118  */
119 
120 void *
121 __ocs_d_initiate_shutdown(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
122 {
124 
125  node_sm_trace();
126 
127  switch(evt) {
128  case OCS_EVT_ENTER: {
129  int32_t rc = OCS_SCSI_CALL_COMPLETE; // assume no wait needed
130 
132 
133  /* make necessary delete upcall(s) */
134  if (ocs->enable_nvme_tgt && node->nvme_init) {
135  ocs_nvme_node_lost(node);
136  }
137 
138  if (node->init && !node->targ) {
139  ocs_log_info(node->ocs, "[%s] delete (initiator) WWPN %s WWNN %s\n", node->display_name,
140  node->wwpn, node->wwnn);
142  if (node->sport->enable_tgt) {
144  }
145  if (rc == OCS_SCSI_CALL_COMPLETE) {
147  }
148  } else if (node->targ && !node->init) {
149  ocs_log_info(node->ocs, "[%s] delete (target) WWPN %s WWNN %s\n", node->display_name,
150  node->wwpn, node->wwnn);
152  if (node->sport->enable_ini) {
154  }
155  if (rc == OCS_SCSI_CALL_COMPLETE) {
157  }
158  } else if (node->init && node->targ) {
159  ocs_log_info(node->ocs, "[%s] delete (initiator+target) WWPN %s WWNN %s\n",
160  node->display_name, node->wwpn, node->wwnn);
162  if (node->sport->enable_tgt) {
164  }
165  if (rc == OCS_SCSI_CALL_COMPLETE) {
167  }
168  rc = OCS_SCSI_CALL_COMPLETE; // assume no wait needed
169  if (node->sport->enable_ini) {
171  }
172  if (rc == OCS_SCSI_CALL_COMPLETE) {
174  }
175  }
176 
177  /* we've initiated the upcalls as needed, now kick off the node
178  * detach to precipitate the aborting of outstanding exchanges
179  * associated with said node
180  *
181  * Beware: if we've made upcall(s), we've already transitioned
182  * to a new state by the time we execute this.
183  * TODO: consider doing this before the upcalls...
184  */
185  if (node->attached) {
186  /* issue hal node free; don't care if succeeds right away
187  * or sometime later, will check node->attached later in
188  * shutdown process
189  */
190  rc = ocs_hal_node_detach(&ocs->hal, &node->rnode);
191  if (node->rnode.free_group) {
192  ocs_remote_node_group_free(node->node_group);
193  node->node_group = NULL;
194  node->rnode.free_group = FALSE;
195  }
196  if (rc != OCS_HAL_RTN_SUCCESS && rc != OCS_HAL_RTN_SUCCESS_SYNC) {
197  node_printf(node, "Failed freeing HAL node, rc=%d\n", rc);
198  }
199  }
200 
201  /* if neither initiator nor target, proceed to cleanup */
202  if (!node->init && !node->targ){
203  /*
204  * node has either been detached or is in the process of being detached,
205  * call common node's initiate cleanup function
206  */
208  }
209  break;
210  }
212  /* Ignore, this can happen if an ELS is aborted while in a delay/retry state */
213  break;
214  default:
215  __ocs_d_common(__func__, ctx, evt, arg);
216  return NULL;
217  }
218  return NULL;
219 }
220 
221 /**
222  * @ingroup device_sm
223  * @brief Device node state machine: Common device event handler.
224  *
225  * <h3 class="desc">Description</h3>
226  * For device nodes, this event handler manages default and common events.
227  *
228  * @param funcname Function name text.
229  * @param ctx Remote node state machine context.
230  * @param evt Event to process.
231  * @param arg Per event optional argument.
232  *
233  * @return Returns NULL.
234  */
235 
236 static void *
237 __ocs_d_common(const char *funcname, ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
238 {
239  ocs_node_t *node = NULL;
240  ocs_t *ocs = NULL;
241  ocs_assert(ctx, NULL);
242  node = ctx->app;
243  ocs_assert(node, NULL);
244  ocs = node->ocs;
245  ocs_assert(ocs, NULL);
246 
247  switch(evt) {
248 
249  /* Handle shutdown events */
250  case OCS_EVT_SHUTDOWN:
251  ocs_log_debug(ocs, "[%s] %-20s %-20s\n", node->display_name, funcname, ocs_sm_event_name(evt));
252  node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT;
254  break;
256  ocs_log_debug(ocs, "[%s] %-20s %-20s\n", node->display_name, funcname, ocs_sm_event_name(evt));
257  node->shutdown_reason = OCS_NODE_SHUTDOWN_EXPLICIT_LOGO;
259  break;
261  ocs_log_debug(ocs, "[%s] %-20s %-20s\n", node->display_name, funcname, ocs_sm_event_name(evt));
262  node->shutdown_reason = OCS_NODE_SHUTDOWN_IMPLICIT_LOGO;
264  break;
265 
266  default:
267  /* call default event handler common to all nodes */
268  __ocs_node_common(funcname, ctx, evt, arg);
269  break;
270  }
271  return NULL;
272 }
273 
274 /**
275  * @ingroup device_sm
276  * @brief Device node state machine: Wait for a domain-attach completion in loop topology.
277  *
278  * <h3 class="desc">Description</h3>
279  * State waits for a domain-attached completion while in loop topology.
280  *
281  * @param ctx Remote node state machine context.
282  * @param evt Event to process.
283  * @param arg Per event optional argument.
284  *
285  * @return Returns NULL.
286  */
287 
288 void *
289 __ocs_d_wait_loop(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
290 {
292 
293  node_sm_trace();
294 
295  switch(evt) {
296  case OCS_EVT_ENTER:
297  ocs_node_hold_frames(node);
298  break;
299 
300  case OCS_EVT_EXIT:
302  break;
303 
305  /* send PLOGI automatically if initiator */
306  ocs_node_init_device(node, TRUE);
307  break;
308  }
309  default:
310  __ocs_d_common(__func__, ctx, evt, arg);
311  return NULL;
312  }
313 
314  return NULL;
315 }
316 
317 
318 
319 
320 /**
321  * @ingroup device_sm
322  * @brief state: wait for node resume event
323  *
324  * State is entered when a node is in I+T mode and sends a delete initiator/target
325  * call to the target-server/initiator-client and needs to wait for that work to complete.
326  *
327  * @param ctx Remote node state machine context.
328  * @param evt Event to process.
329  * @param arg per event optional argument
330  *
331  * @return returns NULL
332  */
333 
334 void *
335 __ocs_d_wait_del_ini_tgt(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
336 {
338 
339  node_sm_trace();
340 
341  switch(evt) {
342  case OCS_EVT_ENTER:
343  ocs_node_hold_frames(node);
344  /* Fall through */
345 
348  /* These are expected events. */
349  break;
350 
354  break;
355 
356  case OCS_EVT_EXIT:
358  break;
359 
361  /* Can happen as ELS IO IO's complete */
362  ocs_assert(node->els_req_cnt, NULL);
363  node->els_req_cnt--;
364  break;
365 
366  /* ignore shutdown events as we're already in shutdown path */
367  case OCS_EVT_SHUTDOWN:
368  /* have default shutdown event take precedence */
369  node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT;
370  /* fall through */
373  node_printf(node, "%s received\n", ocs_sm_event_name(evt));
374  break;
376  /* don't care about domain_attach_ok */
377  break;
378  default:
379  __ocs_d_common(__func__, ctx, evt, arg);
380  return NULL;
381  }
382 
383  return NULL;
384 }
385 
386 
387 /**
388  * @ingroup device_sm
389  * @brief state: Wait for node resume event.
390  *
391  * State is entered when a node sends a delete initiator/target call to the
392  * target-server/initiator-client and needs to wait for that work to complete.
393  *
394  * @param ctx Remote node state machine context.
395  * @param evt Event to process.
396  * @param arg Per event optional argument.
397  *
398  * @return Returns NULL.
399  */
400 
401 void *
402 __ocs_d_wait_del_node(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
403 {
405 
406  node_sm_trace();
407 
408  switch(evt) {
409  case OCS_EVT_ENTER:
410  ocs_node_hold_frames(node);
411  /* Fall through */
412 
415  /* These are expected events. */
416  break;
417 
420  /*
421  * node has either been detached or is in the process of being detached,
422  * call common node's initiate cleanup function
423  */
425  break;
426 
427  case OCS_EVT_EXIT:
429  break;
430 
432  /* Can happen as ELS IO IO's complete */
433  ocs_assert(node->els_req_cnt, NULL);
434  node->els_req_cnt--;
435  break;
436 
437  /* ignore shutdown events as we're already in shutdown path */
438  case OCS_EVT_SHUTDOWN:
439  /* have default shutdown event take precedence */
440  node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT;
441  /* fall through */
444  node_printf(node, "%s received\n", ocs_sm_event_name(evt));
445  break;
447  /* don't care about domain_attach_ok */
448  break;
449  default:
450  __ocs_d_common(__func__, ctx, evt, arg);
451  return NULL;
452  }
453 
454  return NULL;
455 }
456 
457 
458 
459 /**
460  * @brief Save the OX_ID for sending LS_ACC sometime later.
461  *
462  * <h3 class="desc">Description</h3>
463  * When deferring the response to an ELS request, the OX_ID of the request
464  * is saved using this function.
465  *
466  * @param io Pointer to a SCSI IO object.
467  * @param hdr Pointer to the FC header.
468  * @param ls Defines the type of ELS to send: LS_ACC, LS_ACC for PLOGI;
469  * or LSS_ACC for PRLI.
470  *
471  * @return None.
472  */
473 
474 void
476 {
477  ocs_node_t *node = io->node;
478  uint16_t ox_id = ocs_be16toh(hdr->ox_id);
479 
480  ocs_assert(node->send_ls_acc == OCS_NODE_SEND_LS_ACC_NONE);
481 
482  node->ls_acc_oxid = ox_id;
483  node->send_ls_acc = ls;
484  node->ls_acc_io = io;
485  node->ls_acc_did = fc_be24toh(hdr->d_id);
486 }
487 
488 #if defined(OCS_ENABLE_FIRST_BURST)
489 /**
490  * @brief Determine if first_burst is enabled on this device
491  *
492  * @param ocs Pointer to the OCS object
493  *
494  * @return TRUE if first burst enabled, otherwise FALSE
495  */
496 int32_t ocs_first_burst_enabled(ocs_t *ocs)
497 {
498  ocs_hal_t *hal = &ocs->hal;
499 
500  return (hal->tow_enabled && (hal->config.tow_feature & OCS_TOW_FEATURE_TFB));
501 }
502 #endif
503 
504 /**
505  * @brief Process the PRLI payload.
506  *
507  * <h3 class="desc">Description</h3>
508  * The PRLI payload is processed; the initiator/target capabilities of the
509  * remote node are extracted and saved in the node object.
510  *
511  * @param node Pointer to the node object.
512  * @param prli Pointer to the PRLI payload.
513  *
514  * @return None.
515  */
516 
517 void
519 {
520  if (prli->type == FC_TYPE_NVME) {
521  node->nvme_tgt = (ocs_be16toh(prli->service_params) & FC_PRLI_TARGET_FUNCTION) != 0;
522  node->nvme_init = (ocs_be16toh(prli->service_params) & FC_PRLI_INITIATOR_FUNCTION) != 0;
523  node->nvme_prli_service_params = prli->service_params; /* BE format */
524  } else {
525  /*
526  * Determine node first_burst capability based on the support at both sides.
527  */
528  node->first_burst = (ocs_be16toh(prli->service_params) & FC_PRLI_WRITE_XRDY_DISABLED) != 0;
529  node->init = (ocs_be16toh(prli->service_params) & FC_PRLI_INITIATOR_FUNCTION) != 0;
530  node->targ = (ocs_be16toh(prli->service_params) & FC_PRLI_TARGET_FUNCTION) != 0;
531  node->fc_type = prli->type;
532  }
533 }
534 
535 /**
536  * @brief Process the ABTS.
537  *
538  * <h3 class="desc">Description</h3>
539  * Common code to process a received ABTS. If an active IO can be found
540  * that matches the OX_ID of the ABTS request, a call is made to the
541  * backend. Otherwise, a BA_ACC is returned to the initiator.
542  *
543  * @param io Pointer to a SCSI IO object.
544  * @param hdr Pointer to the FC header.
545  *
546  * @return Returns 0 on success, or a negative error value on failure.
547  */
548 
549 static int32_t
550 ocs_process_abts(ocs_io_t *io, fc_header_t *hdr)
551 {
552  ocs_node_t *node = io->node;
553  ocs_t *ocs = node->ocs;
554  uint16_t ox_id = ocs_be16toh(hdr->ox_id);
555  uint16_t rx_id = ocs_be16toh(hdr->rx_id);
556  ocs_io_t *abortio;
557 
558  abortio = ocs_io_find_tgt_io(ocs, node, ox_id, rx_id);
559 
560  /* If an IO was found, attempt to take a reference on it */
561  if (abortio != NULL && (ocs_ref_get_unless_zero(&abortio->ref) != 0)) {
562 
563  /* Got a reference on the IO. Hold it until backend is notified below */
564  node_printf(node, "Abort request: ox_id [%04x] rx_id [%04x]\n",
565  ox_id, rx_id);
566 
567  /*
568  * Save the ox_id for the ABTS as the init_task_tag in our manufactured
569  * TMF IO object
570  */
571  io->display_name = "abts";
572  io->init_task_tag = ox_id;
573  // don't set tgt_task_tag, don't want to confuse with XRI
574 
575  /*
576  * Save the rx_id from the ABTS as it is needed for the BLS response,
577  * regardless of the IO context's rx_id
578  */
579  io->abort_rx_id = rx_id;
580 
581  /* Call target server command abort */
582  io->tmf_cmd = OCS_SCSI_TMF_ABORT_TASK;
583  ocs_scsi_recv_tmf(io, abortio->tgt_io.lun, OCS_SCSI_TMF_ABORT_TASK, abortio, 0);
584 
585  /*
586  * Backend will have taken an additional reference on the IO if needed;
587  * done with current reference.
588  */
589  ocs_ref_put(&abortio->ref); /* ocs_ref_get(): same function */
590  } else {
591  /*
592  * Either IO was not found or it has been freed between finding it
593  * and attempting to get the reference,
594  */
595  node_printf(node, "Abort request: ox_id [%04x], IO not found (exists=%d)\n",
596  ox_id, (abortio != NULL));
597  if (ocs->enable_nvme_tgt) {
598  ocs_nvme_process_abts(ocs, ox_id, rx_id, node->rnode.indicator);
599  ocs_scsi_io_free(io);
600  } else {
601  /* Send a BA_RJT */
602  ocs_bls_send_rjt_hdr(io, hdr);
603  }
604  }
605  return 0;
606 }
607 
608 /**
609  * @ingroup device_sm
610  * @brief Device node state machine: Wait for the PLOGI accept to complete.
611  *
612  * @param ctx Remote node state machine context.
613  * @param evt Event to process.
614  * @param arg Per event optional argument.
615  *
616  * @return Returns NULL.
617  */
618 
619 void *
620 __ocs_d_wait_plogi_acc_cmpl(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
621 {
623 
624  node_sm_trace();
625 
626  switch(evt) {
627  case OCS_EVT_ENTER:
628  ocs_node_hold_frames(node);
629  break;
630 
631  case OCS_EVT_EXIT:
633  break;
634 
636  ocs_assert(node->els_cmpl_cnt, NULL);
637  node->els_cmpl_cnt--;
638  node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT;
640  break;
641 
642  case OCS_EVT_SRRS_ELS_CMPL_OK: /* PLOGI ACC completions */
643  ocs_assert(node->els_cmpl_cnt, NULL);
644  node->els_cmpl_cnt--;
646  break;
647 
648  default:
649  __ocs_d_common(__func__, ctx, evt, arg);
650  return NULL;
651  }
652 
653  return NULL;
654 }
655 
656 /**
657  * @ingroup device_sm
658  * @brief Device node state machine: Wait for the LOGO response.
659  *
660  * @param ctx Remote node state machine context.
661  * @param evt Event to process.
662  * @param arg Per event optional argument.
663  *
664  * @return Returns NULL.
665  */
666 
667 void *
668 __ocs_d_wait_logo_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
669 {
670  ocs_node_t *node = ctx->app;
671  ocs_t *ocs = node->ocs;
672  ocs_sport_t *sport = node->sport;
673 
675  node_sm_trace();
676 
677  switch(evt) {
678  case OCS_EVT_ENTER:
679  // TODO: may want to remove this; if we'll want to know about PLOGI
680  ocs_node_hold_frames(node);
681  break;
682 
683  case OCS_EVT_EXIT:
685  break;
686 
690  /* LOGO response received, sent shutdown */
691  if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_LOGO, __ocs_d_common, __func__))
692  return NULL;
693 
694  ocs_assert(node->els_req_cnt, NULL);
695  node->els_req_cnt--;
696  node_printf(node, "LOGO sent (evt=%s), shutdown node\n", ocs_sm_event_name(evt));
697 
698  /* Post explicit logout */
700 
701  /*
702  * For NPIV, now that the vport LOGO is done, issue unreg_rpi_all
703  * (on behalf of all nodes of the vport) if needed
704  */
705  if (sport->is_vport && node->rnode.fc_id == FC_ADDR_FABRIC) {
706  if (sport->unreg_rpi_all)
707  ocs_hal_unreg_rpi_all(&ocs->hal, sport);
708  }
709  break;
710 
711  // TODO: PLOGI: abort LOGO and process PLOGI? (SHUTDOWN_EXPLICIT/IMPLICIT_LOGO?)
712 
713  default:
714  __ocs_d_common(__func__, ctx, evt, arg);
715  break;
716  }
717 
718  return NULL;
719 }
720 
721 /**
722  * @ingroup device_sm
723  * @brief Device node state machine: Wait for the PRLO response.
724  *
725  * @param ctx Remote node state machine context.
726  * @param evt Event to process.
727  * @param arg Per event optional argument.
728  *
729  * @return Returns NULL.
730  */
731 
732 void *
733 __ocs_d_wait_prlo_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
734 {
736 
737  node_sm_trace();
738 
739  switch(evt) {
740  case OCS_EVT_ENTER:
741  ocs_node_hold_frames(node);
742  break;
743 
744  case OCS_EVT_EXIT:
746  break;
747 
751  if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_PRLO, __ocs_d_common, __func__)) {
752  return NULL;
753  }
754  ocs_assert(node->els_req_cnt, NULL);
755  node->els_req_cnt--;
756  node_printf(node, "PRLO sent (evt=%s)\n", ocs_sm_event_name(evt));
758  break;
759 
760  default:
761  __ocs_node_common(__func__, ctx, evt, arg);
762  return NULL;
763  }
764  return NULL;
765 }
766 
767 
768 /**
769  * @brief Initialize device node.
770  *
771  * Initialize device node. If a node is an initiator, then send a PLOGI and transition
772  * to __ocs_d_wait_plogi_rsp, otherwise transition to __ocs_d_init.
773  *
774  * @param node Pointer to the node object.
775  * @param send_plogi Boolean indicating to send PLOGI command or not.
776  *
777  * @return none
778  */
779 
780 void
781 ocs_node_init_device(ocs_node_t *node, int send_plogi)
782 {
783  node->send_plogi = send_plogi;
784  if ((node->ocs->nodedb_mask & OCS_NODEDB_PAUSE_NEW_NODES) && !FC_ADDR_IS_DOMAIN_CTRL(node->rnode.fc_id)) {
785  node->nodedb_state = __ocs_d_init;
787  } else {
788  ocs_node_transition(node, __ocs_d_init, NULL);
789  }
790 }
791 
792 /**
793  * @ingroup device_sm
794  * @brief Device node state machine: Initial node state for an initiator or a target.
795  *
796  * <h3 class="desc">Description</h3>
797  * This state is entered when a node is instantiated, either having been
798  * discovered from a name services query, or having received a PLOGI/FLOGI.
799  *
800  * @param ctx Remote node state machine context.
801  * @param evt Event to process.
802  * @param arg Per event optional argument.
803  * - OCS_EVT_ENTER: (uint8_t *) - 1 to send a PLOGI on
804  * entry (initiator-only); 0 indicates a PLOGI is
805  * not sent on entry (initiator-only). Not applicable for a target.
806  *
807  * @return Returns NULL.
808  */
809 
810 void *
811 __ocs_d_init(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
812 {
813  int32_t rc;
814  ocs_node_cb_t *cbdata = arg;
816 
817  node_sm_trace();
818 
819  switch(evt) {
820  case OCS_EVT_ENTER:
821  /* check if we need to send PLOGI */
822  if (node->send_plogi) {
823  /* only send if we have initiator capability, and domain is attached */
824  if (node->sport->enable_ini && node->sport->domain->attached) {
826  OCS_FC_ELS_DEFAULT_RETRIES, NULL, NULL);
828  } else {
829  node_printf(node, "not sending plogi sport.ini=%d, domain attached=%d\n",
830  node->sport->enable_ini, node->sport->domain->attached);
831  }
832  }
833  break;
834  case OCS_EVT_PLOGI_RCVD: {
835  /* T, or I+T */
836  fc_header_t *hdr = cbdata->header->dma.virt;
837  uint32_t d_id = fc_be24toh(hdr->d_id);
838 
839  ocs_node_save_sparms(node, cbdata->payload->dma.virt);
840  ocs_send_ls_acc_after_attach(cbdata->io, cbdata->header->dma.virt, OCS_NODE_SEND_LS_ACC_PLOGI);
841 
842  /* domain already attached */
843  if (node->sport->domain->attached) {
844  rc = ocs_node_attach(node);
846  if (rc == OCS_HAL_RTN_SUCCESS_SYNC) {
848  }
849  break;
850  }
851 
852  /* domain not attached; several possibilities: */
853  switch (node->sport->topology) {
855  /* we're not attached and sport is p2p, need to attach */
856  ocs_domain_attach(node->sport->domain, d_id);
858  break;
860  /* we're not attached and sport is fabric, domain attach should have
861  * already been requested as part of the fabric state machine, wait for it
862  */
864  break;
866  /* Two possibilities:
867  * 1. received a PLOGI before our FLOGI has completed (possible since
868  * completion comes in on another CQ), thus we don't know what we're
869  * connected to yet; transition to a state to wait for the fabric
870  * node to tell us;
871  * 2. PLOGI received before link went down and we haven't performed
872  * domain attach yet.
873  * Note: we cannot distinguish between 1. and 2. so have to assume PLOGI
874  * was received after link back up.
875  */
876  node_printf(node, "received PLOGI, with unknown topology did=0x%x\n", d_id);
878  break;
879  default:
880  node_printf(node, "received PLOGI, with unexpectd topology %d\n",
881  node->sport->topology);
882  ocs_assert(FALSE, NULL);
883  break;
884  }
885  break;
886  }
887 
888  case OCS_EVT_FDISC_RCVD: {
889 #if defined(ENABLE_FABRIC_EMULATION)
890  fc_header_t *hdr = cbdata->header->dma.virt;
891 
892  /* If this domain is do configured then call the Fabric Emulation FDISC handler */
893  if (node->sport->domain->femul_enable) {
894  ocs_femul_process_fdisc(cbdata->io, hdr, cbdata->payload->dma.virt, cbdata->payload->dma.len);
895  break;
896  }
897 #endif
898  __ocs_d_common(__func__, ctx, evt, arg);
899  break;
900  }
901 
902  case OCS_EVT_FLOGI_RCVD: {
903  fc_header_t *hdr = cbdata->header->dma.virt;
904 
905  /* this better be coming from an NPort */
906  ocs_assert(ocs_rnode_is_nport(cbdata->payload->dma.virt), NULL);
907 
908  //sm: / save sparams, send FLOGI acc
909  ocs_domain_save_sparms(node->sport->domain, cbdata->payload->dma.virt);
910 
911 #if defined(ENABLE_FABRIC_EMULATION)
912  if (node->sport->domain->femul_enable) {
913  /* Process FLOGI in Fabric Emulation mode, don't transition */
914  ocs_femul_process_flogi(cbdata->io, hdr, cbdata->payload->dma.virt, cbdata->payload->dma.len);
915  break;
916  }
917 #endif
918  /* send FC LS_ACC response, override s_id */
920  ocs_send_flogi_p2p_acc(cbdata->io, ocs_be16toh(hdr->ox_id), fc_be24toh(hdr->d_id), NULL, NULL);
921  if (ocs_p2p_setup(node->sport)) {
922  node_printf(node, "p2p setup failed, shutting down node\n");
924  } else {
926  }
927 
928  break;
929  }
930 
931  case OCS_EVT_LOGO_RCVD: {
932  fc_header_t *hdr = cbdata->header->dma.virt;
933 
934  if (!node->sport->domain->attached) {
935  /* most likely a frame left over from before a link down; drop and
936  * shut node down w/ "explicit logout" so pending frames are processed */
937  node_printf(node, "%s domain not attached, dropping\n", ocs_sm_event_name(evt));
939  break;
940  }
941  ocs_send_logo_acc(cbdata->io, ocs_be16toh(hdr->ox_id), NULL, NULL);
943  break;
944  }
945 
946  case OCS_EVT_PRLI_RCVD:
947  case OCS_EVT_PRLO_RCVD:
948  case OCS_EVT_PDISC_RCVD:
949  case OCS_EVT_ADISC_RCVD:
950  case OCS_EVT_RSCN_RCVD: {
951  fc_header_t *hdr = cbdata->header->dma.virt;
952  if (!node->sport->domain->attached) {
953  /* most likely a frame left over from before a link down; drop and
954  * shut node down w/ "explicit logout" so pending frames are processed */
955  node_printf(node, "%s domain not attached, dropping\n", ocs_sm_event_name(evt));
957  break;
958  }
959  node_printf(node, "%s received, sending reject\n", ocs_sm_event_name(evt));
960  ocs_send_ls_rjt(cbdata->io, ocs_be16toh(hdr->ox_id),
962  NULL, NULL);
963 
964  break;
965  }
966 
967  case OCS_EVT_FCP_CMD_RCVD: {
968 //note: problem, we're now expecting an ELS REQ completion from both the LOGO and PLOGI
969  if (!node->sport->domain->attached) {
970  /* most likely a frame left over from before a link down; drop and
971  * shut node down w/ "explicit logout" so pending frames are processed */
972  node_printf(node, "%s domain not attached, dropping\n", ocs_sm_event_name(evt));
974  break;
975  }
976 
977  ocs_log_info(node->ocs, "[%s] FCP_CMND received before port login, send LOGO\n",
978  node->display_name);
979  if (ocs_send_logo(node, OCS_FC_ELS_SEND_DEFAULT_TIMEOUT, 0, NULL, NULL) == NULL) {
980  /* Failed to send LOGO, go ahead and cleanup node anyways */
981  ocs_log_err(node->ocs, "[%s] Failed to send LOGO, cleanup node context\n",
982  node->display_name);
984  }
985 
986  break;
987  }
988 
990  /* don't care about domain_attach_ok */
991  break;
992 
993 #if defined(ENABLE_FABRIC_EMULATION)
994  case OCS_EVT_SCR_RCVD:
995  if (node->sport->domain->femul_enable) {
996  fc_header_t *hdr = cbdata->header->dma.virt;
997  void *payload = cbdata->payload->dma.virt;
998  uint32_t payload_len = cbdata->payload->dma.len;
999  rc = ocs_femul_process_scr(cbdata->io, hdr, payload, payload_len);
1000  if (rc == 0) {
1001  break;
1002  }
1003  }
1004  /* fall through */
1005 #endif
1006 
1007  default:
1008  __ocs_d_common(__func__, ctx, evt, arg);
1009  return NULL;
1010  }
1011 
1012  return NULL;
1013 }
1014 
1015 /**
1016  * @ingroup device_sm
1017  * @brief Device node state machine: Wait on a response for a sent PLOGI.
1018  *
1019  * <h3 class="desc">Description</h3>
1020  * State is entered when an initiator-capable node has sent
1021  * a PLOGI and is waiting for a response.
1022  *
1023  * @param ctx Remote node state machine context.
1024  * @param evt Event to process.
1025  * @param arg Per event optional argument.
1026  *
1027  * @return Returns NULL.
1028  */
1029 
1030 void *
1031 __ocs_d_wait_plogi_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1032 {
1033  int32_t rc;
1034  ocs_node_cb_t *cbdata = arg;
1036 
1037  node_sm_trace();
1038 
1039  switch(evt) {
1040  case OCS_EVT_PLOGI_RCVD: {
1041  /* T, or I+T */
1042  /* received PLOGI with svc parms, go ahead and attach node
1043  * when PLOGI that was sent ultimately completes, it'll be a no-op
1044  */
1045 
1046  // TODO: there is an outstanding PLOGI sent, can we set a flag
1047  // to indicate that we don't want to retry it if it times out?
1048  ocs_node_save_sparms(node, cbdata->payload->dma.virt);
1049  ocs_send_ls_acc_after_attach(cbdata->io, cbdata->header->dma.virt, OCS_NODE_SEND_LS_ACC_PLOGI);
1050  //sm: domain->attached / ocs_node_attach
1051  rc = ocs_node_attach(node);
1053  if (rc == OCS_HAL_RTN_SUCCESS_SYNC) {
1055  }
1056  break;
1057  }
1058 
1059  case OCS_EVT_PRLI_RCVD:
1060  /* I, or I+T */
1061  /* sent PLOGI and before completion was seen, received the
1062  * PRLI from the remote node (WCQEs and RCQEs come in on
1063  * different queues and order of processing cannot be assumed)
1064  * Save OXID so PRLI can be sent after the attach and continue
1065  * to wait for PLOGI response
1066  */
1067  ocs_process_prli_payload(node, cbdata->payload->dma.virt);
1068  if (ocs->fc_type == node->fc_type) {
1069  ocs_send_ls_acc_after_attach(cbdata->io, cbdata->header->dma.virt, OCS_NODE_SEND_LS_ACC_PRLI);
1071  } else {
1072  // TODO this need to be looked at. What do we do here ?
1073  }
1074  break;
1075 
1076  // TODO this need to be looked at. we could very well be logged in
1077  case OCS_EVT_LOGO_RCVD: // why don't we do a shutdown here??
1078  case OCS_EVT_PRLO_RCVD:
1079  case OCS_EVT_PDISC_RCVD:
1080  case OCS_EVT_FDISC_RCVD:
1081  case OCS_EVT_ADISC_RCVD:
1082  case OCS_EVT_RSCN_RCVD:
1083  case OCS_EVT_SCR_RCVD: {
1084  fc_header_t *hdr = cbdata->header->dma.virt;
1085  node_printf(node, "%s received, sending reject\n", ocs_sm_event_name(evt));
1086  ocs_send_ls_rjt(cbdata->io, ocs_be16toh(hdr->ox_id),
1088  NULL, NULL);
1089 
1090  break;
1091  }
1092 
1093  case OCS_EVT_SRRS_ELS_REQ_OK: /* PLOGI response received */
1094  /* Completion from PLOGI sent */
1095  if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_PLOGI, __ocs_d_common, __func__)) {
1096  return NULL;
1097  }
1098  ocs_assert(node->els_req_cnt, NULL);
1099  node->els_req_cnt--;
1100  //sm: / save sparams, ocs_node_attach
1101  ocs_node_save_sparms(node, cbdata->els->els_rsp.virt);
1102  ocs_display_sparams(node->display_name, "plogi rcvd resp", 0, NULL,
1103  ((uint8_t*)cbdata->els->els_rsp.virt) + 4);
1104  rc = ocs_node_attach(node);
1106  if (rc == OCS_HAL_RTN_SUCCESS_SYNC) {
1108  }
1109  break;
1110 
1111  case OCS_EVT_SRRS_ELS_REQ_FAIL: /* PLOGI response received */
1112  /* PLOGI failed, shutdown the node */
1113  if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_PLOGI, __ocs_d_common, __func__)) {
1114  return NULL;
1115  }
1116  ocs_assert(node->els_req_cnt, NULL);
1117  node->els_req_cnt--;
1119  break;
1120 
1121  case OCS_EVT_SRRS_ELS_REQ_RJT: /* Our PLOGI was rejected, this is ok in some cases */
1122  if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_PLOGI, __ocs_d_common, __func__)) {
1123  return NULL;
1124  }
1125  ocs_assert(node->els_req_cnt, NULL);
1126  node->els_req_cnt--;
1127  break;
1128 
1129  case OCS_EVT_FCP_CMD_RCVD: {
1130  /* not logged in yet and outstanding PLOGI so don't send LOGO,
1131  * just drop
1132  */
1133  node_printf(node, "FCP_CMND received, drop\n");
1134  break;
1135  }
1136 
1137  default:
1138  __ocs_d_common(__func__, ctx, evt, arg);
1139  return NULL;
1140  }
1141 
1142  return NULL;
1143 }
1144 
1145 /**
1146  * @ingroup device_sm
1147  * @brief Device node state machine: Waiting on a response for a
1148  * sent PLOGI.
1149  *
1150  * <h3 class="desc">Description</h3>
1151  * State is entered when an initiator-capable node has sent
1152  * a PLOGI and is waiting for a response. Before receiving the
1153  * response, a PRLI was received, implying that the PLOGI was
1154  * successful.
1155  *
1156  * @param ctx Remote node state machine context.
1157  * @param evt Event to process.
1158  * @param arg Per event optional argument.
1159  *
1160  * @return Returns NULL.
1161  */
1162 
1163 void *
1164 __ocs_d_wait_plogi_rsp_recvd_prli(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1165 {
1166  int32_t rc;
1167  ocs_node_cb_t *cbdata = arg;
1169 
1170  node_sm_trace();
1171 
1172  switch(evt) {
1173  case OCS_EVT_ENTER:
1174  /*
1175  * Since we've received a PRLI, we have a port login and will
1176  * just need to wait for the PLOGI response to do the node
1177  * attach and then we can send the LS_ACC for the PRLI. If,
1178  * during this time, we receive FCP_CMNDs (which is possible
1179  * since we've already sent a PRLI and our peer may have accepted).
1180  * At this time, we are not waiting on any other unsolicited
1181  * frames to continue with the login process. Thus, it will not
1182  * hurt to hold frames here.
1183  */
1184  ocs_node_hold_frames(node);
1185  break;
1186 
1187  case OCS_EVT_EXIT:
1188  ocs_node_accept_frames(node);
1189  break;
1190 
1191  case OCS_EVT_SRRS_ELS_REQ_OK: /* PLOGI response received */
1192  /* Completion from PLOGI sent */
1193  if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_PLOGI, __ocs_d_common, __func__)) {
1194  return NULL;
1195  }
1196  ocs_assert(node->els_req_cnt, NULL);
1197  node->els_req_cnt--;
1198  //sm: / save sparams, ocs_node_attach
1199  ocs_node_save_sparms(node, cbdata->els->els_rsp.virt);
1200  ocs_display_sparams(node->display_name, "plogi rcvd resp", 0, NULL,
1201  ((uint8_t*)cbdata->els->els_rsp.virt) + 4);
1202  rc = ocs_node_attach(node);
1204  if (rc == OCS_HAL_RTN_SUCCESS_SYNC) {
1206  }
1207  break;
1208 
1209  case OCS_EVT_SRRS_ELS_REQ_FAIL: /* PLOGI response received */
1211  /* PLOGI failed, shutdown the node */
1212  if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_PLOGI, __ocs_d_common, __func__)) {
1213  return NULL;
1214  }
1215  ocs_assert(node->els_req_cnt, NULL);
1216  node->els_req_cnt--;
1218  break;
1219 
1220  default:
1221  __ocs_d_common(__func__, ctx, evt, arg);
1222  return NULL;
1223  }
1224 
1225  return NULL;
1226 }
1227 
1228 /**
1229  * @ingroup device_sm
1230  * @brief Device node state machine: Wait for a domain attach.
1231  *
1232  * <h3 class="desc">Description</h3>
1233  * Waits for a domain-attach complete ok event.
1234  *
1235  * @param ctx Remote node state machine context.
1236  * @param evt Event to process.
1237  * @param arg Per event optional argument.
1238  *
1239  * @return Returns NULL.
1240  */
1241 
1242 void *
1243 __ocs_d_wait_domain_attach(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1244 {
1245  int32_t rc;
1247 
1248  node_sm_trace();
1249 
1250  switch(evt) {
1251  case OCS_EVT_ENTER:
1252  ocs_node_hold_frames(node);
1253  break;
1254 
1255  case OCS_EVT_EXIT:
1256  ocs_node_accept_frames(node);
1257  break;
1258 
1260  ocs_assert(node->sport->domain->attached, NULL);
1261  //sm: / ocs_node_attach
1262  rc = ocs_node_attach(node);
1264  if (rc == OCS_HAL_RTN_SUCCESS_SYNC) {
1266  }
1267  break;
1268 
1269  default:
1270  __ocs_d_common(__func__, ctx, evt, arg);
1271  return NULL;
1272  }
1273  return NULL;
1274 }
1275 
1276 /**
1277  * @ingroup device_sm
1278  * @brief Device node state machine: Wait for topology
1279  * notification
1280  *
1281  * <h3 class="desc">Description</h3>
1282  * Waits for topology notification from fabric node, then
1283  * attaches domain and node.
1284  *
1285  * @param ctx Remote node state machine context.
1286  * @param evt Event to process.
1287  * @param arg Per event optional argument.
1288  *
1289  * @return Returns NULL.
1290  */
1291 
1292 void *
1293 __ocs_d_wait_topology_notify(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1294 {
1295  int32_t rc;
1297 
1298  node_sm_trace();
1299 
1300  switch(evt) {
1301  case OCS_EVT_ENTER:
1302  ocs_node_hold_frames(node);
1303  break;
1304 
1305  case OCS_EVT_EXIT:
1306  ocs_node_accept_frames(node);
1307  break;
1308 
1311  ocs_assert(!node->sport->domain->attached, NULL);
1312  ocs_assert(node->send_ls_acc == OCS_NODE_SEND_LS_ACC_PLOGI, NULL);
1313  node_printf(node, "topology notification, topology=%d\n", topology);
1314 
1315  /* At the time the PLOGI was received, the topology was unknown,
1316  * so we didn't know which node would perform the domain attach:
1317  * 1. The node from which the PLOGI was sent (p2p) or
1318  * 2. The node to which the FLOGI was sent (fabric).
1319  */
1320  if (topology == OCS_SPORT_TOPOLOGY_P2P) {
1321  /* if this is p2p, need to attach to the domain using the
1322  * d_id from the PLOGI received
1323  */
1324  ocs_domain_attach(node->sport->domain, node->ls_acc_did);
1325  }
1326  /* else, if this is fabric, the domain attach should be performed
1327  * by the fabric node (node sending FLOGI); just wait for attach
1328  * to complete
1329  */
1330 
1332  break;
1333  }
1335  ocs_assert(node->sport->domain->attached, NULL);
1336  node_printf(node, "domain attach ok\n");
1337  //sm: / ocs_node_attach
1338  rc = ocs_node_attach(node);
1340  if (rc == OCS_HAL_RTN_SUCCESS_SYNC) {
1342  }
1343  break;
1344 
1345  default:
1346  __ocs_d_common(__func__, ctx, evt, arg);
1347  return NULL;
1348  }
1349  return NULL;
1350 }
1351 
1352 /**
1353  * @ingroup device_sm
1354  * @brief Device node state machine: Wait for a node attach when found by a remote node.
1355  *
1356  * @param ctx Remote node state machine context.
1357  * @param evt Event to process.
1358  * @param arg Per event optional argument.
1359  *
1360  * @return Returns NULL.
1361  */
1362 
1363 void *
1364 __ocs_d_wait_node_attach(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1365 {
1367 
1368  node_sm_trace();
1369 
1370  switch(evt) {
1371  case OCS_EVT_ENTER:
1372  ocs_node_hold_frames(node);
1373  break;
1374 
1375  case OCS_EVT_EXIT:
1376  ocs_node_accept_frames(node);
1377  break;
1378 
1380  node->attached = TRUE;
1381  switch (node->send_ls_acc) {
1383  //sm: send_plogi_acc is set / send PLOGI acc
1384  /* Normal case for T, or I+T */
1385  ocs_send_plogi_acc(node->ls_acc_io, node->ls_acc_oxid, NULL, NULL);
1387  node->send_ls_acc = OCS_NODE_SEND_LS_ACC_NONE;
1388  node->ls_acc_io = NULL;
1389  break;
1390  }
1392  ocs_d_send_prli_rsp(node->ls_acc_io, node->ls_acc_oxid, FC_TYPE_FCP); /*Initiator support only for SCSI*/
1393  node->send_ls_acc = OCS_NODE_SEND_LS_ACC_NONE;
1394  node->ls_acc_io = NULL;
1395  break;
1396  }
1398  default:
1399  /* Normal case for I */
1400  //sm: send_plogi_acc is not set / send PLOGI acc
1402  break;
1403  }
1404  break;
1405 
1407  /* node attach failed, shutdown the node */
1408  node->attached = FALSE;
1409  node_printf(node, "node attach failed\n");
1410  node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT;
1412  break;
1413 
1414  /* Handle shutdown events */
1415  case OCS_EVT_SHUTDOWN:
1416  node_printf(node, "%s received\n", ocs_sm_event_name(evt));
1417  node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT;
1419  break;
1421  node_printf(node, "%s received\n", ocs_sm_event_name(evt));
1422  node->shutdown_reason = OCS_NODE_SHUTDOWN_EXPLICIT_LOGO;
1424  break;
1426  node_printf(node, "%s received\n", ocs_sm_event_name(evt));
1427  node->shutdown_reason = OCS_NODE_SHUTDOWN_IMPLICIT_LOGO;
1429  break;
1430  default:
1431  __ocs_d_common(__func__, ctx, evt, arg);
1432  return NULL;
1433  }
1434 
1435  return NULL;
1436 }
1437 
1438 /**
1439  * @ingroup device_sm
1440  * @brief Device node state machine: Wait for a node/domain
1441  * attach then shutdown node.
1442  *
1443  * @param ctx Remote node state machine context.
1444  * @param evt Event to process.
1445  * @param arg Per event optional argument.
1446  *
1447  * @return Returns NULL.
1448  */
1449 
1450 void *
1451 __ocs_d_wait_attach_evt_shutdown(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1452 {
1454 
1455  node_sm_trace();
1456 
1457  switch(evt) {
1458  case OCS_EVT_ENTER:
1459  ocs_node_hold_frames(node);
1460  break;
1461 
1462  case OCS_EVT_EXIT:
1463  ocs_node_accept_frames(node);
1464  break;
1465 
1466  /* wait for any of these attach events and then shutdown */
1468  node->attached = TRUE;
1469  node_printf(node, "Attach evt=%s, proceed to shutdown\n", ocs_sm_event_name(evt));
1471  break;
1472 
1474  /* node attach failed, shutdown the node */
1475  node->attached = FALSE;
1476  node_printf(node, "Attach evt=%s, proceed to shutdown\n", ocs_sm_event_name(evt));
1478  break;
1479 
1480  /* ignore shutdown events as we're already in shutdown path */
1481  case OCS_EVT_SHUTDOWN:
1482  /* have default shutdown event take precedence */
1483  node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT;
1484  /* fall through */
1487  node_printf(node, "%s received\n", ocs_sm_event_name(evt));
1488  break;
1489 
1490  default:
1491  __ocs_d_common(__func__, ctx, evt, arg);
1492  return NULL;
1493  }
1494 
1495  return NULL;
1496 }
1497 
1498 /**
1499  * @ingroup device_sm
1500  * @brief Device node state machine: Port is logged in.
1501  *
1502  * <h3 class="desc">Description</h3>
1503  * This state is entered when a remote port has completed port login (PLOGI).
1504  *
1505  * @param ctx Remote node state machine context.
1506  * @param evt Event to process
1507  * @param arg Per event optional argument
1508  *
1509  * @return Returns NULL.
1510  */
1511 void *
1512 __ocs_d_port_logged_in(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1513 {
1514  ocs_node_cb_t *cbdata = arg;
1516 
1517  node_sm_trace();
1518 
1519  //TODO: I+T: what if PLOGI response not yet received ?
1520 
1521  switch(evt) {
1522  case OCS_EVT_ENTER:
1523  /* Normal case for I or I+T */
1524  if (node->sport->enable_ini && !FC_ADDR_IS_DOMAIN_CTRL(node->rnode.fc_id)
1525  && !node->sent_prli) {
1526  //sm: if enable_ini / send PRLI
1528  node->sent_prli = TRUE;
1529  /* can now expect ELS_REQ_OK/FAIL/RJT */
1530  }
1531  break;
1532 
1533  case OCS_EVT_FCP_CMD_RCVD: {
1534  /* For target functionality send PRLO and drop the CMD frame. */
1535  if (node->sport->enable_tgt) {
1537  OCS_FC_ELS_DEFAULT_RETRIES, NULL, NULL)) {
1539  }
1540  }
1541  break;
1542  }
1543 
1544  case OCS_EVT_PRLI_RCVD: {
1545  fc_header_t *hdr = cbdata->header->dma.virt;
1546  fc_prli_payload_t *prli = cbdata->payload->dma.virt;
1547 
1548  /* Normal for T or I+T */
1549 
1550  ocs_process_prli_payload(node, cbdata->payload->dma.virt);
1551  ocs_d_send_prli_rsp(cbdata->io, ocs_be16toh(hdr->ox_id), prli->type);
1552  break;
1553  }
1554 
1555  case OCS_EVT_SRRS_ELS_REQ_OK: { /* PRLI response */
1556  /* Normal case for I or I+T */
1557  if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_PRLI, __ocs_d_common, __func__)) {
1558  return NULL;
1559  }
1560  ocs_assert(node->els_req_cnt, NULL);
1561  node->els_req_cnt--;
1562  //sm: / process PRLI payload
1563  ocs_process_prli_payload(node, cbdata->els->els_rsp.virt);
1565  break;
1566  }
1567 
1568  case OCS_EVT_SRRS_ELS_REQ_FAIL: { /* PRLI response failed */
1569  /* I, I+T, assume some link failure, shutdown node */
1570  if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_PRLI, __ocs_d_common, __func__)) {
1571  return NULL;
1572  }
1573  ocs_assert(node->els_req_cnt, NULL);
1574  node->els_req_cnt--;
1576  break;
1577  }
1578 
1579  case OCS_EVT_SRRS_ELS_REQ_RJT: {/* PRLI rejected by remote */
1580  /* Normal for I, I+T (connected to an I) */
1581  /* Node doesn't want to be a target, stay here and wait for a PRLI from the remote node
1582  * if it really wants to connect to us as target */
1583  if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_PRLI, __ocs_d_common, __func__)) {
1584  return NULL;
1585  }
1586  ocs_assert(node->els_req_cnt, NULL);
1587  node->els_req_cnt--;
1588  break;
1589  }
1590 
1591  case OCS_EVT_SRRS_ELS_CMPL_OK: {
1592  /* Normal T, I+T, target-server rejected the process login */
1593  /* This would be received only in the case where we sent LS_RJT for the PRLI, so
1594  * do nothing. (note: as T only we could shutdown the node)
1595  */
1596  ocs_assert(node->els_cmpl_cnt, NULL);
1597  node->els_cmpl_cnt--;
1598  break;
1599  }
1600 
1601  case OCS_EVT_PLOGI_RCVD: {
1602  //sm: / save sparams, set send_plogi_acc, post implicit logout
1603  /* Save plogi parameters */
1604  ocs_node_save_sparms(node, cbdata->payload->dma.virt);
1605  ocs_send_ls_acc_after_attach(cbdata->io, cbdata->header->dma.virt, OCS_NODE_SEND_LS_ACC_PLOGI);
1606 
1607  /* Restart node attach with new service paramters, and send ACC */
1609  break;
1610  }
1611 
1612  case OCS_EVT_LOGO_RCVD: {
1613  /* I, T, I+T */
1614  fc_header_t *hdr = cbdata->header->dma.virt;
1615  node_printf(node, "%s received attached=%d\n", ocs_sm_event_name(evt), node->attached);
1616  //sm: / send LOGO acc
1617  ocs_send_logo_acc(cbdata->io, ocs_be16toh(hdr->ox_id), NULL, NULL);
1619  break;
1620  }
1621 
1622  case OCS_EVT_ABTS_RCVD: {
1623  ocs_process_abts(cbdata->io, cbdata->header->dma.virt);
1624  break;
1625  }
1626 
1627 #if defined(ENABLE_FABRIC_EMULATION)
1628  /*
1629  * FC_GS received for directory server when using fabric emulation
1630  */
1631  case OCS_EVT_RFT_ID_RCVD:
1632  case OCS_EVT_RFF_ID_RCVD:
1633  case OCS_EVT_GNN_ID_RCVD:
1634  case OCS_EVT_GPN_ID_RCVD:
1635  case OCS_EVT_GFPN_ID_RCVD:
1636  case OCS_EVT_GFF_ID_RCVD:
1637  case OCS_EVT_GID_FT_RCVD:
1638  case OCS_EVT_GID_PT_RCVD:
1639  case OCS_EVT_RPN_ID_RCVD:
1640  case OCS_EVT_RNN_ID_RCVD:
1641  case OCS_EVT_RCS_ID_RCVD:
1642  case OCS_EVT_RSNN_NN_RCVD:
1643  case OCS_EVT_RSPN_ID_RCVD:
1644  case OCS_EVT_RHBA_RCVD:
1645  case OCS_EVT_RPA_RCVD:
1646  if (node->sport->domain->femul_enable) {
1647  fc_header_t *hdr;
1648  void *payload;
1649  uint32_t payload_len;
1650 
1651  ocs_assert(cbdata != NULL, NULL);
1652  ocs_assert(cbdata->header != NULL, NULL);
1653  ocs_assert(cbdata->payload != NULL, NULL);
1654  hdr = cbdata->header->dma.virt;
1655  payload = cbdata->payload->dma.virt;
1656  payload_len = cbdata->payload->dma.len;
1657 
1658  ocs_femul_process_fc_gs(__func__, cbdata->io, evt, hdr, payload, payload_len);
1659  break;
1660  }
1661  /* fall through */
1662 #endif
1663  default:
1664  __ocs_d_common(__func__, ctx, evt, arg);
1665  return NULL;
1666  }
1667 
1668  return NULL;
1669 }
1670 
1671 /**
1672  * @ingroup device_sm
1673  * @brief Device node state machine: Wait for a LOGO accept.
1674  *
1675  * <h3 class="desc">Description</h3>
1676  * Waits for a LOGO accept completion.
1677  *
1678  * @param ctx Remote node state machine context.
1679  * @param evt Event to process
1680  * @param arg Per event optional argument
1681  *
1682  * @return Returns NULL.
1683  */
1684 
1685 void *
1686 __ocs_d_wait_logo_acc_cmpl(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1687 {
1689 
1690  node_sm_trace();
1691 
1692  switch(evt) {
1693  case OCS_EVT_ENTER:
1694  ocs_node_hold_frames(node);
1695  break;
1696 
1697  case OCS_EVT_EXIT:
1698  ocs_node_accept_frames(node);
1699  break;
1700 
1703  //sm: / post explicit logout
1704  ocs_assert(node->els_cmpl_cnt, NULL);
1705  node->els_cmpl_cnt--;
1707  break;
1708  default:
1709  __ocs_d_common(__func__, ctx, evt, arg);
1710  return NULL;
1711  }
1712 
1713  return NULL;
1714 }
1715 
1716 /**
1717  * @ingroup device_sm
1718  * @brief Device node state machine: Device is ready.
1719  *
1720  * @param ctx Remote node state machine context.
1721  * @param evt Event to process.
1722  * @param arg Per event optional argument.
1723  *
1724  * @return Returns NULL.
1725  */
1726 
1727 void *
1728 __ocs_d_device_ready(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1729 {
1730  ocs_node_cb_t *cbdata = arg;
1732 
1733  if (evt != OCS_EVT_FCP_CMD_RCVD) {
1734  node_sm_trace();
1735  }
1736 
1737  switch(evt) {
1738  case OCS_EVT_ENTER:
1739  node->fcp_enabled = TRUE;
1740  if (node->init) {
1741  ocs_log_info(ocs, "[%s] found (initiator) WWPN %s WWNN %s\n", node->display_name,
1742  node->wwpn, node->wwnn);
1743  if (node->sport->enable_tgt)
1744  ocs_scsi_new_initiator(node);
1745  }
1746  if (node->targ) {
1747  ocs_log_info(ocs, "[%s] found (target) WWPN %s WWNN %s\n", node->display_name,
1748  node->wwpn, node->wwnn);
1749  if (node->sport->enable_ini)
1750  ocs_scsi_new_target(node);
1751  }
1752  break;
1753 
1754  case OCS_EVT_EXIT:
1755  node->fcp_enabled = FALSE;
1756  break;
1757 
1758  case OCS_EVT_PLOGI_RCVD: {
1759  //sm: / save sparams, set send_plogi_acc, post implicit logout
1760  /* Save plogi parameters */
1761  ocs_node_save_sparms(node, cbdata->payload->dma.virt);
1762  ocs_send_ls_acc_after_attach(cbdata->io, cbdata->header->dma.virt, OCS_NODE_SEND_LS_ACC_PLOGI);
1763 
1764  /* Restart node attach with new service paramters, and send ACC */
1766  break;
1767  }
1768 
1769 
1770  case OCS_EVT_PDISC_RCVD: {
1771  fc_header_t *hdr = cbdata->header->dma.virt;
1772  ocs_send_plogi_acc(cbdata->io, ocs_be16toh(hdr->ox_id), NULL, NULL);
1773  break;
1774  }
1775 
1776  case OCS_EVT_PRLI_RCVD: {
1777  /* T, I+T: remote initiator is slow to get started */
1778  fc_header_t *hdr = cbdata->header->dma.virt;
1779  fc_prli_payload_t *prli = cbdata->payload->dma.virt;
1780 
1781  ocs_process_prli_payload(node, cbdata->payload->dma.virt);
1782 
1783  //sm: / send PRLI acc/reject
1784  if (node->ocs->enable_nvme_tgt && (prli->type == FC_TYPE_NVME)) {
1785  ocs_d_send_prli_rsp(cbdata->io, ocs_be16toh(hdr->ox_id), prli->type);
1786  } else if (ocs->fc_type == node->fc_type)
1787  ocs_send_prli_acc(cbdata->io, ocs_be16toh(hdr->ox_id), ocs->fc_type, NULL, NULL);
1788  else
1789  ocs_send_ls_rjt(cbdata->io, ocs_be16toh(hdr->ox_id), FC_REASON_UNABLE_TO_PERFORM,
1790  FC_EXPL_REQUEST_NOT_SUPPORTED, 0, NULL, NULL);
1791  break;
1792  }
1793 
1794  case OCS_EVT_PRLO_RCVD: {
1795  fc_header_t *hdr = cbdata->header->dma.virt;
1796  fc_prlo_payload_t *prlo = cbdata->payload->dma.virt;
1797 
1798  //sm: / send PRLO acc/reject
1799  if (node->ocs->enable_nvme_tgt && (prlo->type == FC_TYPE_NVME)) {
1800  ocs_nvme_process_prlo(cbdata->io, ocs_be16toh(hdr->ox_id));
1801  } else if (ocs->fc_type == prlo->type)
1802  ocs_send_prlo_acc(cbdata->io, ocs_be16toh(hdr->ox_id), ocs->fc_type, NULL, NULL);
1803  else
1804  ocs_send_ls_rjt(cbdata->io, ocs_be16toh(hdr->ox_id), FC_REASON_UNABLE_TO_PERFORM,
1805  FC_EXPL_REQUEST_NOT_SUPPORTED, 0, NULL, NULL);
1806  //TODO: need implicit logout
1807  break;
1808  }
1809 
1810  case OCS_EVT_LOGO_RCVD: {
1811  fc_header_t *hdr = cbdata->header->dma.virt;
1812  node_printf(node, "%s received attached=%d\n", ocs_sm_event_name(evt), node->attached);
1813  //sm: / send LOGO acc
1814  ocs_send_logo_acc(cbdata->io, ocs_be16toh(hdr->ox_id), NULL, NULL);
1816  break;
1817  }
1818 
1819  case OCS_EVT_ADISC_RCVD: {
1820  fc_header_t *hdr = cbdata->header->dma.virt;
1821  //sm: / send ADISC acc
1822  ocs_send_adisc_acc(cbdata->io, ocs_be16toh(hdr->ox_id), NULL, NULL);
1823  break;
1824  }
1825 
1826  case OCS_EVT_RRQ_RCVD: {
1827  fc_header_t *hdr = cbdata->header->dma.virt;
1828  /* Send LS_ACC */
1829  ocs_send_ls_acc(cbdata->io, ocs_be16toh(hdr->ox_id), NULL, NULL);
1830  break;
1831  }
1832 
1833  case OCS_EVT_ABTS_RCVD:
1834  //sm: / process ABTS
1835  ocs_process_abts(cbdata->io, cbdata->header->dma.virt);
1836  break;
1837 
1839  break;
1840 
1841  case OCS_EVT_NODE_REFOUND:
1842  break;
1843 
1844  case OCS_EVT_NODE_MISSING:
1845  if (node->sport->enable_rscn) {
1847  }
1848  break;
1849 
1851  /* T, or I+T, PRLI accept completed ok */
1852  ocs_assert(node->els_cmpl_cnt, NULL);
1853  node->els_cmpl_cnt--;
1854  break;
1855 
1857  /* T, or I+T, PRLI accept failed to complete */
1858  ocs_assert(node->els_cmpl_cnt, NULL);
1859  node->els_cmpl_cnt--;
1860  node_printf(node, "Failed to send PRLI LS_ACC\n");
1861  break;
1862 
1863  default:
1864  __ocs_d_common(__func__, ctx, evt, arg);
1865  return NULL;
1866  }
1867 
1868  return NULL;
1869 }
1870 
1871 /**
1872  * @ingroup device_sm
1873  * @brief Device node state machine: Node is gone (absent from GID_PT).
1874  *
1875  * <h3 class="desc">Description</h3>
1876  * State entered when a node is detected as being gone (absent from GID_PT).
1877  *
1878  * @param ctx Remote node state machine context.
1879  * @param evt Event to process
1880  * @param arg Per event optional argument
1881  *
1882  * @return Returns NULL.
1883  */
1884 
1885 void *
1886 __ocs_d_device_gone(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1887 {
1888  int32_t rc = OCS_SCSI_CALL_COMPLETE;
1889  int32_t rc_2 = OCS_SCSI_CALL_COMPLETE;
1890  ocs_node_cb_t *cbdata = arg;
1892 
1893  node_sm_trace();
1894 
1895  switch(evt) {
1896  case OCS_EVT_ENTER: {
1897  const char *labels[] = {"none", "initiator", "target", "initiator+target"};
1898 
1899  ocs_log_info(ocs, "[%s] missing (%s) WWPN %s WWNN %s\n", node->display_name,
1900  labels[(node->targ << 1) | (node->init)], node->wwpn, node->wwnn);
1901 
1902  switch(ocs_node_get_enable(node)) {
1907  break;
1908 
1913  break;
1914 
1917  break;
1918 
1921  break;
1922 
1926  break;
1927 
1928  default:
1930  break;
1931 
1932  }
1933 
1934  if ((rc == OCS_SCSI_CALL_COMPLETE) && (rc_2 == OCS_SCSI_CALL_COMPLETE)) {
1936  }
1937 
1938  break;
1939  }
1940  case OCS_EVT_NODE_REFOUND:
1941  /* two approaches, reauthenticate with PLOGI/PRLI, or ADISC */
1942 
1943  /* reauthenticate with PLOGI/PRLI */
1944  /* ocs_node_transition(node, __ocs_d_discovered, NULL); */
1945 
1946  /* reauthenticate with ADISC */
1947  //sm: / send ADISC
1950  break;
1951 
1952  case OCS_EVT_PLOGI_RCVD: {
1953  //sm: / save sparams, set send_plogi_acc, post implicit logout
1954  /* Save plogi parameters */
1955  ocs_node_save_sparms(node, cbdata->payload->dma.virt);
1956  ocs_send_ls_acc_after_attach(cbdata->io, cbdata->header->dma.virt, OCS_NODE_SEND_LS_ACC_PLOGI);
1957 
1958  /* Restart node attach with new service paramters, and send ACC */
1960  break;
1961  }
1962 
1963  case OCS_EVT_FCP_CMD_RCVD: {
1964  /* most likely a stale frame (received prior to link down), if attempt
1965  * to send LOGO, will probably timeout and eat up 20s; thus, drop FCP_CMND
1966  */
1967  node_printf(node, "FCP_CMND received, drop\n");
1968  break;
1969  }
1970  case OCS_EVT_LOGO_RCVD: {
1971  /* I, T, I+T */
1972  fc_header_t *hdr = cbdata->header->dma.virt;
1973  node_printf(node, "%s received attached=%d\n", ocs_sm_event_name(evt), node->attached);
1974  //sm: / send LOGO acc
1975  ocs_send_logo_acc(cbdata->io, ocs_be16toh(hdr->ox_id), NULL, NULL);
1977  break;
1978  }
1979  default:
1980  __ocs_d_common(__func__, ctx, evt, arg);
1981  return NULL;
1982  }
1983 
1984  return NULL;
1985 }
1986 
1987 /**
1988  * @ingroup device_sm
1989  * @brief Device node state machine: Wait for the ADISC response.
1990  *
1991  * <h3 class="desc">Description</h3>
1992  * Waits for the ADISC response from the remote node.
1993  *
1994  * @param ctx Remote node state machine context.
1995  * @param evt Event to process.
1996  * @param arg Per event optional argument.
1997  *
1998  * @return Returns NULL.
1999  */
2000 
2001 void *
2002 __ocs_d_wait_adisc_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
2003 {
2004  ocs_node_cb_t *cbdata = arg;
2006 
2007  node_sm_trace();
2008 
2009  switch(evt) {
2011  if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_ADISC, __ocs_d_common, __func__)) {
2012  return NULL;
2013  }
2014  ocs_assert(node->els_req_cnt, NULL);
2015  node->els_req_cnt--;
2017  break;
2018 
2020  /* received an LS_RJT, in this case, send shutdown (explicit logo)
2021  * event which will unregister the node, and start over with PLOGI
2022  */
2023  if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_ADISC, __ocs_d_common, __func__)) {
2024  return NULL;
2025  }
2026  ocs_assert(node->els_req_cnt, NULL);
2027  node->els_req_cnt--;
2028  //sm: / post explicit logout
2030  break;
2031 
2032  case OCS_EVT_LOGO_RCVD: {
2033  /* In this case, we have the equivalent of an LS_RJT for the ADISC,
2034  * so we need to abort the ADISC, and re-login with PLOGI
2035  */
2036  //sm: / request abort, send LOGO acc
2037  fc_header_t *hdr = cbdata->header->dma.virt;
2038  node_printf(node, "%s received attached=%d\n", ocs_sm_event_name(evt), node->attached);
2039  ocs_send_logo_acc(cbdata->io, ocs_be16toh(hdr->ox_id), NULL, NULL);
2041  break;
2042  }
2043  default:
2044  __ocs_d_common(__func__, ctx, evt, arg);
2045  return NULL;
2046  }
2047 
2048  return NULL;
2049 }
int ocs_nvme_process_prlo(ocs_io_t *io, uint16_t ox_id)
Definition: ocs_nvme_stub.c:56
#define OCS_TOW_FEATURE_TFB
Definition: ocs_hal.h:149
int32_t ocs_scsi_recv_tmf(ocs_io_t *tmfio, uint32_t lun, ocs_scsi_tmf_cmd_e cmd, ocs_io_t *abortio, uint32_t flags)
Receive a TMF command IO.
Definition: ocs_ramd.c:2682
#define OCS_NODEDB_PAUSE_NEW_NODES
Definition: ocs_node.h:73
uint32_t type
Definition: ocs_fcp.h:393
int32_t ocs_scsi_del_target(ocs_node_t *node, ocs_scsi_del_target_reason_e reason)
Delete a SCSI target node.
Definition: ocs_ini_stub.c:258
void * __ocs_node_paused(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
Paused node state.
Definition: ocs_node.c:2160
static int32_t ocs_process_abts(ocs_io_t *io, fc_header_t *hdr)
Process the ABTS.
Definition: ocs_device.c:550
void * __ocs_d_wait_prlo_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
Device node state machine: Wait for the PRLO response.
Definition: ocs_device.c:733
#define FC_PRLI_TARGET_FUNCTION
Definition: ocs_fcp.h:441
ocs_hal_rtn_e ocs_hal_unreg_rpi_all(ocs_hal_t *hal, ocs_sport_t *sport)
Free all remote node objects.
Definition: ocs_hal.c:3658
void ocs_remote_node_group_free(ocs_remote_node_group_t *node_group)
Free a remote node group object.
Definition: ocs_sport.c:1995
void ocs_node_post_event(ocs_node_t *node, ocs_sm_event_t evt, void *arg)
Post event to node state machine context.
Definition: ocs_node.c:1498
#define FC_TYPE_NVME
Definition: ocs_fcp.h:57
int32_t ocs_rnode_is_nport(fc_plogi_payload_t *remote_sparms)
Return TRUE if the remote node is an NPORT.
Definition: ocs_fabric.c:1557
ocs_io_t * ocs_send_plogi_acc(ocs_io_t *io, uint32_t ox_id, els_cb_t cb, void *cbarg)
Send a PLOGI accept response.
Definition: ocs_els.c:1403
static void ocs_node_accept_frames(ocs_node_t *node)
accept frames
Definition: ocs_node.h:120
ocs_io_t * ocs_send_prli(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries, els_cb_t cb, void *cbarg)
Send a PRLI ELS command.
Definition: ocs_els.c:909
uint32_t ox_id
Definition: ocs_fcp.h:168
void ocs_node_transition(ocs_node_t *node, ocs_sm_function_t state, void *data)
transition state of a node
Definition: ocs_node.c:1547
ocs_io_t * ocs_send_ls_rjt(ocs_io_t *io, uint32_t ox_id, uint32_t reason_code, uint32_t reason_code_expl, uint32_t vendor_unique, els_cb_t cb, void *cbarg)
Send an LS_RJT ELS response.
Definition: ocs_els.c:1353
#define FC_TYPE_FCP
Definition: ocs_fcp.h:56
ocs_io_t * ocs_send_prli_acc(ocs_io_t *io, uint32_t ox_id, uint8_t fc_type, els_cb_t cb, void *cbarg)
Send a PRLI accept response.
Definition: ocs_els.c:1686
void * __ocs_d_wait_plogi_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
Device node state machine: Wait on a response for a sent PLOGI.
Definition: ocs_device.c:1031
int32_t ocs_node_attach(ocs_node_t *node)
Perform HAL call to attach a remote node.
Definition: ocs_node.c:671
ocs_io_t * ocs_send_plogi(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries, void(*cb)(ocs_node_t *node, ocs_node_cb_t *cbdata, void *arg), void *cbarg)
Format and send a PLOGI ELS command.
Definition: ocs_els.c:696
ocs_io_t * ocs_bls_send_rjt_hdr(ocs_io_t *io, fc_header_t *hdr)
Send a BA_RJT given the request&#39;s FC heade.
Definition: ocs_els.c:2685
void ocs_display_sparams(const char *prelabel, const char *reqlabel, int dest, void *textbuf, void *sparams)
Display service parameters.
Definition: ocs_debug.c:495
void * __ocs_d_wait_logo_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
Device node state machine: Wait for the LOGO response.
Definition: ocs_device.c:668
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_scsi_io_free(ocs_io_t *io)
Free a SCSI IO context.
Definition: ocs_scsi.c:317
void * __ocs_d_wait_topology_notify(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
Device node state machine: Wait for topology notification.
Definition: ocs_device.c:1293
void * __ocs_d_wait_adisc_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
Device node state machine: Wait for the ADISC response.
Definition: ocs_device.c:2002
void ocs_node_init_device(ocs_node_t *node, int send_plogi)
Initialize device node.
Definition: ocs_device.c:781
#define FC_ELS_CMD_LOGO
Definition: ocs_fcp.h:45
#define FC_EXPL_NPORT_LOGIN_REQUIRED
Definition: ocs_fcp.h:273
static ocs_node_enable_e ocs_node_get_enable(ocs_node_t *node)
Definition: ocs_node.h:186
void ocs_scsi_io_alloc_disable(ocs_node_t *node)
Disable IO allocation.
Definition: ocs_scsi.c:144
const char * ocs_sm_event_name(ocs_sm_event_t evt)
Definition: ocs_sm.c:92
uint32_t type
Definition: ocs_fcp.h:365
int32_t ocs_scsi_new_target(ocs_node_t *node)
receive notification of a new SCSI target node
Definition: ocs_ini_stub.c:232
ocs_hal_rtn_e ocs_hal_node_detach(ocs_hal_t *hal, ocs_remote_node_t *rnode)
Free a remote node object.
Definition: ocs_hal.c:3562
uint32_t d_id
Definition: ocs_fcp.h:158
#define FC_ELS_CMD_ADISC
Definition: ocs_fcp.h:51
FC header in big-endian order.
Definition: ocs_fcp.h:157
#define FC_ADDR_IS_DOMAIN_CTRL(x)
Definition: ocs_fcp.h:63
int ocs_nvme_process_prli(ocs_io_t *io, uint16_t ox_id)
Definition: ocs_nvme_stub.c:42
void ocs_d_send_prli_rsp(ocs_io_t *io, uint16_t ox_id, uint8_t fc_type)
Send response to PRLI.
Definition: ocs_device.c:67
static void * __ocs_d_common(const char *funcname, ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
Device node state machine: Common device event handler.
Definition: ocs_device.c:237
#define FC_PRLI_WRITE_XRDY_DISABLED
Definition: ocs_fcp.h:443
void * __ocs_d_device_gone(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
Device node state machine: Node is gone (absent from GID_PT).
Definition: ocs_device.c:1886
#define FC_ELS_CMD_PLOGI
Definition: ocs_fcp.h:43
void * __ocs_d_wait_plogi_acc_cmpl(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
Device node state machine: Wait for the PLOGI accept to complete.
Definition: ocs_device.c:620
void ocs_node_initiate_cleanup(ocs_node_t *node)
Initiate node IO cleanup.
Definition: ocs_node.c:1025
int32_t ocs_scsi_new_initiator(ocs_node_t *node)
Receive notification of a new SCSI initiator node.
Definition: ocs_ramd.c:1027
int ocs_nvme_node_lost(ocs_node_t *node)
Definition: ocs_nvme_stub.c:63
void * __ocs_p2p_wait_flogi_acc_cmpl(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
Point-to-point node state machine: Wait for the FLOGI accept completion.
Definition: ocs_fabric.c:1764
#define FC_REASON_UNABLE_TO_PERFORM
Definition: ocs_fcp.h:252
void ocs_domain_attach(ocs_domain_t *domain, uint32_t s_id)
Initiator domain attach.
Definition: ocs_domain.c:1299
ocs_io_t * ocs_send_ls_acc(ocs_io_t *io, uint32_t ox_id, els_cb_t cb, void *cbarg)
Send a generic LS_ACC response without a payload.
Definition: ocs_els.c:1787
#define FC_EXPL_REQUEST_NOT_SUPPORTED
Definition: ocs_fcp.h:277
void * __ocs_d_wait_domain_attach(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
Device node state machine: Wait for a domain attach.
Definition: ocs_device.c:1243
#define node_sm_prologue()
Definition: ocs_node.h:52
ocs_node_send_ls_acc_e
Definition: ocs_common.h:323
void * __ocs_d_wait_logo_acc_cmpl(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
Device node state machine: Wait for a LOGO accept.
Definition: ocs_device.c:1686
void * __ocs_d_wait_loop(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
Device node state machine: Wait for a domain-attach completion in loop topology.
Definition: ocs_device.c:289
#define OCS_FC_ELS_DEFAULT_RETRIES
Definition: ocs_fc_config.h:85
#define FC_ELS_CMD_PRLO
Definition: ocs_fcp.h:48
void * __ocs_d_wait_attach_evt_shutdown(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
Device node state machine: Wait for a node/domain attach then shutdown node.
Definition: ocs_device.c:1451
ocs_sport_topology_e
Definition: ocs_common.h:116
void * __ocs_d_initiate_shutdown(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
Device node state machine: Initiate node shutdown.
Definition: ocs_device.c:121
ocs_io_t * ocs_send_adisc_acc(ocs_io_t *io, uint32_t ox_id, els_cb_t cb, void *cbarg)
Send an ADISC accept response.
Definition: ocs_els.c:1883
ocs_io_t * ocs_send_adisc(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries, els_cb_t cb, void *cbarg)
Send an ADISC ELS command.
Definition: ocs_els.c:1081
void * __ocs_node_common(const char *funcname, ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
state: common node event handler
Definition: ocs_node.c:1317
#define std_node_state_decl(...)
Definition: ocs_node.h:62
void * __ocs_d_port_logged_in(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
Device node state machine: Port is logged in.
Definition: ocs_device.c:1512
static void ocs_node_hold_frames(ocs_node_t *node)
hold frames in pending frame list
Definition: ocs_node.h:102
void ocs_fabric_set_topology(ocs_node_t *node, ocs_sport_topology_e topology)
Set sport topology.
Definition: ocs_fabric.c:140
ocs_io_t * ocs_send_prlo_acc(ocs_io_t *io, uint32_t ox_id, uint8_t fc_type, els_cb_t cb, void *cbarg)
Send a PRLO accept response.
Definition: ocs_els.c:1731
int ocs_nvme_process_abts(ocs_t *ocs, uint16_t oxid, uint16_t rxid, uint32_t rpi)
Definition: ocs_nvme_stub.c:49
uint32_t rx_id
Definition: ocs_fcp.h:168
#define node_sm_trace()
Definition: ocs_node.h:42
void * __ocs_d_device_ready(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
Device node state machine: Device is ready.
Definition: ocs_device.c:1728
int32_t ocs_scsi_validate_initiator(ocs_node_t *node)
Validate a new initiator.
Definition: ocs_ramd.c:1002
#define node_printf(node, fmt,...)
Definition: ocs_node.h:48
void * __ocs_d_init(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
Device node state machine: Initial node state for an initiator or a target.
Definition: ocs_device.c:811
void * __ocs_d_wait_node_attach(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
Device node state machine: Wait for a node attach when found by a remote node.
Definition: ocs_device.c:1364
void ocs_domain_save_sparms(ocs_domain_t *domain, void *payload)
Save the port&#39;s service parameters.
Definition: ocs_domain.c:1261
#define ocs_assert(cond,...)
Definition: ocs_debug.h:176
uint32_t service_params
Definition: ocs_fcp.h:370
ocs_io_t * ocs_send_prlo(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries, els_cb_t cb, void *cbarg)
Send a PRLO ELS command.
Definition: ocs_els.c:968
static uint32_t fc_be24toh(uint32_t x)
Definition: ocs_fcp.h:143
void * __ocs_d_wait_plogi_rsp_recvd_prli(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
Device node state machine: Waiting on a response for a sent PLOGI.
Definition: ocs_device.c:1164
ocs_sm_event_t
Definition: ocs_sm.h:60
ocs_io_t * ocs_send_logo(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries, els_cb_t cb, void *cbarg)
Send a LOGO ELS command.
Definition: ocs_els.c:1021
#define OCS_SCSI_CALL_COMPLETE
Definition: ocs_scsi.h:249
ocs_io_t * ocs_io_find_tgt_io(ocs_t *ocs, ocs_node_t *node, uint16_t ox_id, uint16_t rx_id)
Find an I/O given it&#39;s node and ox_id.
Definition: ocs_io.c:316
void ocs_process_prli_payload(ocs_node_t *node, fc_prli_payload_t *prli)
Process the PRLI payload.
Definition: ocs_device.c:518
int32_t node_check_els_req(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg, uint8_t cmd, ocs_node_common_func_t node_common_func, const char *funcname)
check ELS request completion
Definition: ocs_node.c:1738
#define FC_EXPL_NO_ADDITIONAL
Definition: ocs_fcp.h:258
#define FC_ELS_CMD_PRLI
Definition: ocs_fcp.h:47
ocs_io_t * ocs_send_flogi_p2p_acc(ocs_io_t *io, uint32_t ox_id, uint32_t s_id, els_cb_t cb, void *cbarg)
Send an FLOGI accept response for point-to-point negotiation.
Definition: ocs_els.c:1491
ocs_io_t * ocs_send_logo_acc(ocs_io_t *io, uint32_t ox_id, els_cb_t cb, void *cbarg)
Send a LOGO accept response.
Definition: ocs_els.c:1834
void ocs_node_save_sparms(ocs_node_t *node, void *payload)
save node service parameters
Definition: ocs_node.c:1467
#define FC_PRLI_INITIATOR_FUNCTION
Definition: ocs_fcp.h:440
static void * __ocs_d_wait_del_ini_tgt(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
state: wait for node resume event
Definition: ocs_device.c:335
static void * __ocs_d_wait_del_node(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
state: Wait for node resume event.
Definition: ocs_device.c:402
#define OCS_FC_ELS_SEND_DEFAULT_TIMEOUT
Definition: ocs_fc_config.h:77
int32_t ocs_p2p_setup(ocs_sport_t *sport)
Set up the domain point-to-point parameters.
Definition: ocs_fabric.c:2733
#define FC_ADDR_FABRIC
Definition: ocs_fcp.h:61
void ocs_send_ls_acc_after_attach(ocs_io_t *io, fc_header_t *hdr, ocs_node_send_ls_acc_e ls)
Save the OX_ID for sending LS_ACC sometime later.
Definition: ocs_device.c:475