Emulex Logo
OneCoreā„¢ Storage SDK Release 11.2
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ocs_femul.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  * Fabric Emulation
36  *
37  */
38 
39 #include "ocs.h"
40 #include "ocs_femul.h"
41 #include "ocs_fabric.h"
42 #include "ocs_els.h"
43 #include "ocs_scsi_fc.h"
44 #include "ocs_device.h"
45 
46 #if defined(ENABLE_FABRIC_EMULATION)
47 
48 /* Name Services Database API */
49 struct ocs_ns_record_s {
50  uint32_t active:1,
51  scr_requested:1;
52  uint32_t port_id;
53  uint32_t fc4_types;
54  uint8_t fc4_features;
55  uint8_t type_code;
56  uint64_t node_name;
57  uint64_t port_name;
58  char *sym_node_name;
59  uint32_t sym_node_name_len;
60  uint32_t class_of_srvc;
61  ocs_node_t *node;
62 };
63 
64 void *__ocs_sport_femul_fabric_idle(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
65 void *__ocs_node_femul_fabric_idle(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg);
66 
67 static int32_t ocs_femul_process_rft_id(ocs_io_t *io, fc_header_t *hdr, void *payload, uint32_t payload_len);
68 static int32_t ocs_femul_process_gnn_id(ocs_io_t *io, fc_header_t *hdr, void *payload, uint32_t payload_len);
69 static int32_t ocs_femul_process_gpn_id(ocs_io_t *io, fc_header_t *hdr, void *payload, uint32_t payload_len);
70 static int32_t ocs_femul_process_gfpn_id(ocs_io_t *io, fc_header_t *hdr, void *payload, uint32_t payload_len);
71 static int32_t ocs_femul_process_gff_id(ocs_io_t *io, fc_header_t *hdr, void *payload, uint32_t payload_len);
72 static int32_t ocs_femul_process_gid_ft(ocs_io_t *io, fc_header_t *hdr, void *payload, uint32_t payload_len);
73 static int32_t ocs_femul_process_gid_pt(ocs_io_t *io, fc_header_t *hdr, void *payload, uint32_t payload_len);
74 static int32_t ocs_femul_process_ga_nxt(ocs_io_t *io, fc_header_t *hdr, void *payload, uint32_t payload_len);
75 static int32_t ocs_femul_process_rff_id(ocs_io_t *io, fc_header_t *hdr, void *payload, uint32_t payload_len);
76 static int32_t ocs_femul_process_rpn_id(ocs_io_t *io, fc_header_t *hdr, void *payload, uint32_t payload_len);
77 static int32_t ocs_femul_process_rnn_id(ocs_io_t *io, fc_header_t *hdr, void *payload, uint32_t payload_len);
78 static int32_t ocs_femul_process_rcs_id(ocs_io_t *io, fc_header_t *hdr, void *payload, uint32_t payload_len);
79 static int32_t ocs_femul_process_rsnn_nn(ocs_io_t *io, fc_header_t *hdr, void *payload, uint32_t payload_len);
80 static int32_t ocs_femul_process_rspn_id(ocs_io_t *io, fc_header_t *hdr, void *payload, uint32_t payload_len);
81 static int32_t ocs_femul_process_rhba(ocs_io_t *io, fc_header_t *hdr, void *payload, uint32_t payload_len);
82 static int32_t ocs_femul_process_rpa(ocs_io_t *io, fc_header_t *hdr, void *payload, uint32_t payload_len);
83 
84 static int32_t ocs_ns_event_add(ocs_ns_t *ns, uint32_t port_id);
85 static void ocs_ns_event_clear(ocs_ns_t *ns);
86 
87 static void ocs_ns_rscn_timeout(void *arg);
88 
89 #define OCS_FEMUL_PORTID_BASE 0x20100
90 #define OCS_FEMUL_NUM_PORTID 256
91 
92 struct ocs_ns_s {
93  ocs_domain_t *domain;
94  uint32_t ns_record_count;
95  ocs_ns_record_t *ns_records;
96  ocs_lock_t ns_event_lock;
97  uint32_t *ns_event_list;
98  uint32_t ns_event_list_len;
99  uint32_t ns_event_list_count;
100  ocs_timer_t rscn_timer;
101 };
102 
103 
104 /**
105  * @brief Allocate a port ID from the port_id pool
106  *
107  * A port ID is allocated from the domain's port_id pool
108  *
109  * @param domain Pointer to the domain object
110  *
111  * @return returns positive port ID value, or negative value for an error
112  */
113 int32_t
114 ocs_femul_portid_alloc(ocs_domain_t *domain)
115 {
116  if (domain->portid_pool == NULL) {
117  return -1;
118  }
119 
120  return ocs_bitmap_find(domain->portid_pool, OCS_FEMUL_NUM_PORTID) + OCS_FEMUL_PORTID_BASE;
121 }
122 
123 /**
124  * @brief Free a port ID
125  *
126  * Free the previously allocated port ID
127  *
128  * @param domain Pointer to domain object
129  * @param portid Port ID to free
130  *
131  * @return none
132  */
133 void
134 ocs_femul_portid_free(ocs_domain_t *domain, int32_t portid)
135 {
136  int32_t bitnum = portid - OCS_FEMUL_PORTID_BASE;
137 
138  ocs_assert((bitnum >= 0) && (bitnum < OCS_FEMUL_NUM_PORTID));
139 
140  if (domain->portid_pool != NULL) {
141  ocs_bitmap_clear(domain->portid_pool, portid - OCS_FEMUL_PORTID_BASE);
142  }
143 }
144 
145 /**
146  * @brief Initialize Fabric Emulation subsystem
147  *
148  * The Fabric Emulation subsystem is initialized, which includes allocating of the
149  * port ID pool, as well as instantiating ports for the Fabric Port controller,
150  * the Fabric Controller, and the Name services controller,
151  *
152  * @param domain Pointer to domain object
153  *
154  * @return returns 0 for success, a negative error code value for failure.
155  */
156 int32_t
157 ocs_femul_init(ocs_domain_t *domain)
158 {
159  /* Initialize Port ID allocation pool */
160  domain->portid_pool = ocs_bitmap_alloc(OCS_FEMUL_NUM_PORTID);
161 
162  ocs_atomic_init(&domain->femul_count, 0);
163 
164  return 0;
165 }
166 
167 
168 /**
169  * @brief Shut down Fabric Emulation
170  *
171  * The Fabric Emulation is shut down. This includes freeing port ID allocation
172  * bitmap
173  *
174  * @param domain Pointer to domain object
175  *
176  * @return returns 0
177  */
178 int32_t
179 ocs_femul_shutdown(ocs_domain_t *domain)
180 {
181  ocs_bitmap_free(domain->portid_pool);
182  return 0;
183 }
184 
185 /**
186  * @brief Process FLOGI while in Fabric Emulation mode
187  *
188  * An inbound FLOGI request is processed while in Fabric Emulation mode. In this
189  * case a port ID is allocated and returned to the requestor, with service
190  * parameters indicating that this node is an F_port.
191  *
192  * @param io Pointer to an IO object
193  * @param hdr Pointer to the FC header
194  * @param payload Pointer to payload buffer (service parameters)
195  * @param payload_len Length of payload buffer in bytes
196  *
197  * @return returns 0 for success, a negative error code value for failure.
198  */
199 int32_t
200 ocs_femul_process_flogi(ocs_io_t *io, fc_header_t *hdr, void *payload, uint32_t payload_len)
201 {
202  ocs_t *ocs = io->ocs;
203  ocs_domain_t *domain = io->node->sport->domain;
204  fc_plogi_payload_t *flogi = payload;
205  uint64_t port_name = ocs_be64toh(((long)flogi->port_name_hi << 32 |
206  flogi->port_name_lo));
207  int32_t portid;
208  ocs_ns_record_t *nsrec;
209 
210  /*
211  * handle the case where we may receive another FLOGI. Check the name
212  * server DB for the port name (from the FLOGI). If it exists, then
213  * just send the FLOGI accept.
214  */
215  nsrec = ocs_ns_find_port_name(domain->ocs_ns, port_name);
216  if (nsrec != NULL) {
217  ocs_log_debug(ocs, "Found existing NS record, send FLOGI acc\n");
218  ocs_send_flogi_acc(io, ocs_be16toh(hdr->ox_id), TRUE, NULL, NULL);
219  return 0;
220  }
221 
222  /* Allocate the physical port id */
223  portid = ocs_femul_portid_alloc(domain);
224  if (portid < 0) {
225  ocs_log_err(ocs, "ocs_femul_portid_alloc() failed: %d\n", portid);
226  return -1;
227  }
228 
229  /* Save OX_ID for FLOGI accecpt */
230  domain->femul_oxid = ocs_be16toh(hdr->ox_id);
231 
232  /* Save port_name for NS database accecpt */
233  domain->femul_port_name = port_name;
234 
235  /*
236  * During cable pull events, we may get a second flogi request. So see if the
237  * fabric vports have been created, to prevent creating duplicates.
238  */
239  if (!domain->femul_vports_started) {
240  domain->femul_vports_started = TRUE;
241  /*
242  * Attach the domain with the local physical port
243  *
244  * Note: Use the fabric controller address for the physical port
245  * so that any traffic to the fabric controller is not discarded
246  * before the vport is registered.
247  */
248  __ocs_domain_attach_internal(domain, portid);
249 
250  /* Create F_Port controller, Fabric controller, and Directory server (name server) */
251  ocs_atomic_add_return(&domain->femul_count, 4);
252  ocs_sport_vport_new(domain, 0ll, 0ll, FC_ADDR_FABRIC, FALSE, FALSE, NULL, NULL, FALSE);
253  ocs_sport_vport_new(domain, 0ll, 0ll, FC_ADDR_NAMESERVER, FALSE, FALSE, NULL, NULL, FALSE);
254  ocs_sport_vport_new(domain, 0ll, 0ll, FC_ADDR_CONTROLLER, FALSE, FALSE, NULL, NULL, FALSE);
255  }
256 
257  /* Free the IO that was passed in */
258  ocs_els_io_free(io);
259 
260  return 0;
261 }
262 
263 /**
264  * @brief Process FDISC while in Fabric Emulation mode
265  *
266  * An inbound FDISC request is processed while in Fabric Emulation mode. In this
267  * case a port ID is allocated and returned to the requestor, with service
268  * parameters indicating that this node is an F_port.
269  *
270  * @param io Pointer to an IO object
271  * @param hdr Pointer to the FC header
272  * @param payload Pointer to payload buffer (service parameters)
273  * @param payload_len Length of payload buffer in bytes
274  *
275  * @return returns 0 for success, a negative error code value for failure.
276  */
277 int32_t
278 ocs_femul_process_fdisc(ocs_io_t *io, fc_header_t *hdr, void *payload, uint32_t payload_len)
279 {
280  ocs_t *ocs = io->ocs;
281  int32_t portid;
282  ocs_node_t *rspnode;
283  ocs_io_t *rspio;
284 
285  /* Allocate the physical port id */
286  portid = ocs_femul_portid_alloc(io->node->sport->domain);
287  if (portid < 0) {
288  ocs_log_err(ocs, "ocs_femul_portid_alloc() failed: %d\n", portid);
289  return -1;
290  }
291 
292  /* Allocate a node */
293  rspnode = ocs_node_alloc(io->node->sport, portid, FALSE, FALSE);
294  if (rspnode == NULL) {
295  ocs_log_err(ocs, "ocs_node_alloc failed\n");
296  return -1;
297  }
298  ocs_node_transition(rspnode, __ocs_d_init, NULL);
299 
300  /* Allocate an IO for the response */
302  if (rspio == NULL) {
303  ocs_log_err(ocs, "OCS_EVT_FDISC_RCVD: ocs_els_io_alloc failed\n");
304  ocs_node_free(rspnode);
305  return -1;
306  }
307 
308  /* Send response */
309  ocs_send_flogi_acc(rspio, ocs_be16toh(hdr->ox_id), TRUE, NULL, NULL);
310 
311  /* Free the IO that was passed in */
312  ocs_els_io_free(io);
313 
314  return 0;
315 }
316 
317 /**
318  * @brief Process sport attached event
319  *
320  * Called when a sport is attached. This function will create a name server
321  * entry for the sport.
322  *
323  * @param sport Pointer to the sport object
324  */
325 void
326 ocs_femul_sport_attach(ocs_sport_t *sport)
327 {
328  ocs_t *ocs = sport->ocs;
329  ocs_domain_t *domain = sport->domain;
330  ocs_ns_record_t *nsrec;
331 
332  if (sport->fc_id == FC_ADDR_FABRIC ||
333  sport->fc_id == FC_ADDR_NAMESERVER ||
334  sport->fc_id == FC_ADDR_CONTROLLER) {
335  return;
336  }
337 
338  nsrec = ocs_ns_alloc(domain->ocs_ns, sport->fc_id);
339  if (nsrec == NULL) {
340  ocs_log_err(ocs, "failed to allocate nsrec for fc_id 0x%x\n",
341  sport->fc_id);
342  return;
343  }
344  nsrec->fc4_types = (1 << FC_GS_TYPE_BIT(FC_TYPE_FCP));
345  nsrec->fc4_features = ((sport->enable_ini ? FC4_FEATURE_INITIATOR : 0) |
346  (sport->enable_tgt ? FC4_FEATURE_TARGET : 0));
347  nsrec->type_code = FC_TYPE_FCP;
348  nsrec->node_name = sport->wwnn;
349  nsrec->port_name = sport->wwpn;
350  nsrec->class_of_srvc = FCCT_CLASS_OF_SERVICE_2;
351 }
352 
353 /**
354  * @brief Process fabric emulation ports attached event
355  *
356  * Called with all of the well known port attaches have completed. At this point
357  * the FLOGI accept is sent to the direct connect port.
358  *
359  * @param domain Pointer to the domain object
360  *
361  * @return returns 0 for success, a negative error code value for failure.
362  */
363 int32_t ocs_femul_ports_attached(ocs_domain_t *domain)
364 {
365  ocs_t *ocs;
366  ocs_sport_t *fabric;
367  int32_t fc_id;
368  ocs_node_t *node;
369  ocs_io_t *rspio;
370  ocs_ns_record_t *nsrec;
371 
372  ocs_assert(domain != NULL, -1);
373 
374  ocs = domain->ocs;
375  ocs_assert(ocs != NULL, -1);
376  ocs_log_debug(ocs, "all sports attached\n");
377 
378  fabric = ocs_sport_find(domain, FC_ADDR_FABRIC);
379  if (fabric == NULL) {
380  ocs_log_warn(ocs, "ocs_sport_find(FC_ADD_FABRIC) failed\n");
381  return -1;
382  }
383 
384  /* Assign an FC_ID for the FLOGI node */
385  fc_id = ocs_femul_portid_alloc(domain);
386 
387  /* Allocate a node */
388  node = ocs_node_alloc(fabric, fc_id, 0, 0);
389  if (node == NULL) {
390  ocs_log_err(ocs, "ocs_node_alloc() failed\n");
391  ocs_femul_portid_free(domain, fc_id);
392  return -1;
393  }
394  ocs_node_transition(node, __ocs_d_init, NULL);
395 
396  /* Allocate an IO */
398  if (rspio == NULL) {
399  ocs_log_err(ocs, "ocs_els_io_alloc() failed\n");
400  ocs_node_free(node);
401  ocs_femul_portid_free(domain, fc_id);
402  return -1;
403  }
404 
405  /*
406  * Set the port name that was sent of the flogi in the name server db.
407  *
408  * Note: This must be done before sending the FLOGI accept in case the
409  * initiator sends another FLOGI. We need to find the name server
410  * entry so we can just send FLOGI-ACC and not create any more
411  * vports
412  */
413  nsrec = ocs_ns_alloc(domain->ocs_ns, fc_id);
414  if (nsrec != NULL) {
415  nsrec->port_name = domain->femul_port_name;
416  }
417 
418  /* send FLOGI response */
419  ocs_send_flogi_acc(rspio, domain->femul_oxid, TRUE, NULL, NULL);
420 
421  return 0;
422 }
423 
424 /**
425  * @brief Process and RFT_ID FCGS request
426  *
427  * An RFT_ID request is processed while in Fabric Emulation mode. In this case, the
428  * payload contains the Port ID and fc4_typess of the requester which is added
429  * to the directory services database.
430  *
431  * @param io Pointer to IO object
432  * @param hdr Pointer to FC header
433  * @param payload Address of payload
434  * @param payload_len Length of payload in bytes
435  *
436  * @return returns 0 for success, a negative error code value for failure.
437  */
438 int32_t
439 ocs_femul_process_rft_id(ocs_io_t *io, fc_header_t *hdr, void *payload, uint32_t payload_len)
440 {
441  fcgs_rft_id_t *rftid = payload;
442  ocs_ns_record_t *nsrec;
443  uint32_t port_id = ocs_be32toh(rftid->port_id);
444 
445  node_printf(io->node, "port_id x%x fc4_types x%x\n", ocs_be32toh(rftid->port_id), ocs_be32toh(rftid->fc4_types));
446 
447  /* Allocate a name services record */
448  nsrec = ocs_ns_alloc(io->node->sport->domain->ocs_ns, port_id);
449  if (nsrec == NULL) {
450  ocs_log_err(io->ocs, "ocs_ns_alloc failed\n");
451  return -1;
452  }
453 
454  /* Update the fc4_types */
455  nsrec->fc4_types = ocs_be32toh(rftid->fc4_types);
456 
457  return ocs_send_ct_rsp(io, hdr->ox_id, payload, FCCT_HDR_CMDRSP_ACCEPT, 0, 0);
458 }
459 
460 /**
461  * @brief Process RFF_ID request
462  *
463  * The RFF_ID request is processed.
464  *
465  * @param io Pointer to IO object
466  * @param hdr Pointer to FC header
467  * @param payload Address of payload
468  * @param payload_len Length of payload in bytes
469  *
470  * @return returns 0 for success, a negative error code value for failure.
471  */
472 static int32_t
473 ocs_femul_process_rff_id(ocs_io_t *io, fc_header_t *hdr, void *payload, uint32_t payload_len)
474 {
475  fcgs_rff_id_t *rffid = payload;
476  uint32_t port_id = ocs_be32toh(rffid->port_id);
477  ocs_ns_t *ns = io->node->sport->domain->ocs_ns;
478  ocs_ns_record_t *nsrec;
479 
480  nsrec = ocs_ns_alloc(ns, port_id);
481  if (nsrec == NULL) {
484  return -1;
485  }
486  /* Update fc4_features and type_code */
487  nsrec->fc4_features = rffid->fc4_features;
488  nsrec->type_code = rffid->type_code;
489 
490  return ocs_send_ct_rsp(io, hdr->ox_id, payload, FCCT_HDR_CMDRSP_ACCEPT, 0, 0);
491 }
492 
493 /**
494  * @brief Process RPN_ID request
495  *
496  * The RPN_ID request is processed.
497  *
498  * @param io Pointer to IO object
499  * @param hdr Pointer to FC header
500  * @param payload Address of payload
501  * @param payload_len Length of payload in bytes
502  *
503  * @return returns 0 for success, a negative error code value for failure.
504  */
505 static int32_t
506 ocs_femul_process_rpn_id(ocs_io_t *io, fc_header_t *hdr, void *payload, uint32_t payload_len)
507 {
508  fcgs_rpn_id_t *rpnid = payload;
509  uint32_t port_id = ocs_be32toh(rpnid->port_id);
510  ocs_ns_t *ns = io->node->sport->domain->ocs_ns;
511  ocs_ns_record_t *nsrec;
512 
513  nsrec = ocs_ns_alloc(ns, port_id);
514  if (nsrec == NULL) {
517  return -1;
518  }
519 
520  /* Update port name */
521  nsrec->port_name = ocs_be64toh(rpnid->port_name);
522 
523  return ocs_send_ct_rsp(io, hdr->ox_id, payload, FCCT_HDR_CMDRSP_ACCEPT, 0, 0);
524 }
525 
526 /**
527  * @brief Process RNN_ID request
528  *
529  * The RNN_ID request is processed.
530  *
531  * @param io Pointer to IO object
532  * @param hdr Pointer to FC header
533  * @param payload Address of payload
534  * @param payload_len Length of payload in bytes
535  *
536  * @return returns 0 for success, a negative error code value for failure.
537  */
538 static int32_t
539 ocs_femul_process_rnn_id(ocs_io_t *io, fc_header_t *hdr, void *payload, uint32_t payload_len)
540 {
541  fcgs_rnn_id_t *rnnid = payload;
542  uint32_t port_id = ocs_be32toh(rnnid->port_id);
543  ocs_ns_t *ns = io->node->sport->domain->ocs_ns;
544  ocs_ns_record_t *nsrec;
545 
546  nsrec = ocs_ns_alloc(ns, port_id);
547  if (nsrec == NULL) {
550  return -1;
551  }
552 
553  /* Update node name */
554  nsrec->node_name = ocs_be64toh(rnnid->node_name);
555 
556  return ocs_send_ct_rsp(io, hdr->ox_id, payload, FCCT_HDR_CMDRSP_ACCEPT, 0, 0);
557 }
558 
559 /**
560  * @brief Process RCS_ID request
561  *
562  * The RCS_ID request is processed.
563  *
564  * @param io Pointer to IO object
565  * @param hdr Pointer to FC header
566  * @param payload Address of payload
567  * @param payload_len Length of payload in bytes
568  *
569  * @return returns 0 for success, a negative error code value for failure.
570  */
571 static int32_t
572 ocs_femul_process_rcs_id(ocs_io_t *io, fc_header_t *hdr, void *payload, uint32_t payload_len)
573 {
574  fcgs_rcs_id_t *rcsid = payload;
575  uint32_t port_id = ocs_be32toh(rcsid->port_id);
576  ocs_ns_t *ns = io->node->sport->domain->ocs_ns;
577  ocs_ns_record_t *nsrec;
578 
579  nsrec = ocs_ns_alloc(ns, port_id);
580  if (nsrec == NULL) {
583  return -1;
584  }
585 
586  /* Update node name */
587  nsrec->class_of_srvc = ocs_be32toh(rcsid->class_of_srvc);
588 
589  return ocs_send_ct_rsp(io, hdr->ox_id, payload, FCCT_HDR_CMDRSP_ACCEPT, 0, 0);
590 }
591 
592 /**
593  * @brief Process RSNN_NN request
594  *
595  * The register symbolic node name (RSNN_NN) request is processed.
596  *
597  * @param io Pointer to IO object
598  * @param hdr Pointer to FC header
599  * @param payload Address of payload
600  * @param payload_len Length of payload in bytes
601  *
602  * @return returns 0 for success, a negative error code value for failure.
603  */
604 static int32_t
605 ocs_femul_process_rsnn_nn(ocs_io_t *io, fc_header_t *hdr, void *payload, uint32_t payload_len)
606 {
607  fcgs_rsnn_nn_t *rsnnnn = payload;
608  uint64_t node_name = ocs_be64toh(rsnnnn->node_name);
609  ocs_ns_t *ns = io->node->sport->domain->ocs_ns;
610  ocs_ns_record_t *nsrec;
611  ocs_t *ocs = io->ocs;
612 
613  for (nsrec = NULL; (nsrec = ocs_ns_enumerate(ns, nsrec)) != NULL; ) {
614  if (nsrec->node_name == node_name) {
615  break;
616  }
617  }
618 
619  if (nsrec == NULL) {
622  return -1;
623  }
624 
625  nsrec->sym_node_name = ocs_malloc(ocs, rsnnnn->name_len + 1, OCS_M_ZERO | OCS_M_NOWAIT);
626  if (nsrec->sym_node_name == NULL) {
627  ocs_log_err(io->ocs, "ocs_malloc sym_node_name failed\n");
630  return -1;
631  }
632  nsrec->sym_node_name_len = rsnnnn->name_len + 1;
633  ocs_memcpy(nsrec->sym_node_name, rsnnnn->sym_node_name, rsnnnn->name_len);
634 
635  /* Extract symbolic node name */
636 
637  return ocs_send_ct_rsp(io, hdr->ox_id, payload, FCCT_HDR_CMDRSP_ACCEPT, 0, 0);
638 }
639 
640 /**
641  * @brief Process RSPN_ID request
642  *
643  * The RSPN_ID request is processed.
644  *
645  * @param io Pointer to IO object
646  * @param hdr Pointer to FC header
647  * @param payload Address of payload
648  * @param payload_len Length of payload in bytes
649  *
650  * @return returns 0 for success, a negative error code value for failure.
651  */
652 static int32_t
653 ocs_femul_process_rspn_id(ocs_io_t *io, fc_header_t *hdr, void *payload, uint32_t payload_len)
654 {
655  return ocs_send_ct_rsp(io, hdr->ox_id, payload, FCCT_HDR_CMDRSP_ACCEPT, 0, 0);
656 }
657 
658 /**
659  * @brief Process RHBA request
660  *
661  * The RHBA request is processed.
662  *
663  * @param io Pointer to IO object
664  * @param hdr Pointer to FC header
665  * @param payload Address of payload
666  * @param payload_len Length of payload in bytes
667  *
668  * @return returns 0 for success, a negative error code value for failure.
669  */
670 static int32_t
671 ocs_femul_process_rhba(ocs_io_t *io, fc_header_t *hdr, void *payload, uint32_t payload_len)
672 {
673  /* Just send an accept - data is not stored */
674  return ocs_send_ct_rsp(io, hdr->ox_id, payload, FCCT_HDR_CMDRSP_ACCEPT, 0, 0);
675 }
676 
677 /**
678  * @brief Process RPA request
679  *
680  * The RPA request is processed.
681  *
682  * @param io Pointer to IO object
683  * @param hdr Pointer to FC header
684  * @param payload Address of payload
685  * @param payload_len Length of payload in bytes
686  *
687  * @return returns 0 for success, a negative error code value for failure.
688  */
689 static int32_t
690 ocs_femul_process_rpa(ocs_io_t *io, fc_header_t *hdr, void *payload, uint32_t payload_len)
691 {
692  /* Just send an accept - data is not stored */
693  return ocs_send_ct_rsp(io, hdr->ox_id, payload, FCCT_HDR_CMDRSP_ACCEPT, 0, 0);
694 }
695 
696 /**
697  * @brief Process GNN_ID command
698  *
699  * Process the GNN_ID request
700  *
701  * @param io Pointer to IO object
702  * @param hdr Pointer to FC header
703  * @param payload Address of payload
704  * @param payload_len Length of payload in bytes
705  *
706  * @return returns 0 for success, a negative error code value for failure.
707  */
708 static int32_t
709 ocs_femul_process_gnn_id(ocs_io_t *io, fc_header_t *hdr, void *payload, uint32_t payload_len)
710 {
711  fcct_gnnid_req_t *gnnid = payload;
712  uint32_t port_id = fc_be24toh(gnnid->port_id);
713  fcct_gnnid_acc_t *acc = io->els_rsp.virt;
714  ocs_ns_record_t *nsrec = NULL;
715  uint32_t cmd_rsp_code = FCCT_HDR_CMDRSP_ACCEPT;
716  uint32_t reason_code = 0;
717  uint32_t reason_code_explanation = 0;
718 
719  /* Find the record for the port */
720  nsrec = ocs_ns_find_port_id(io->node->sport->domain->ocs_ns, port_id);
721  if (nsrec != NULL) {
722  acc->node_name = ocs_htobe64(nsrec->node_name);
723  io->wire_len += sizeof(acc->node_name);
724  } else {
725  ocs_log_test(io->ocs, "port_id 0x%x not found\n", port_id);
726  cmd_rsp_code = FCCT_HDR_CMDRSP_REJECT;
727  reason_code = FCCT_UNABLE_TO_PERFORM;
728  reason_code_explanation = FCCT_DEVICES_NOT_IN_COMMON_ZONE;
729  }
730  return ocs_send_ct_rsp(io, hdr->ox_id, payload, cmd_rsp_code,
731  reason_code, reason_code_explanation);
732 }
733 
734 /**
735  * @brief Process GPN_ID command
736  *
737  * Process the GPN_ID request
738  *
739  * @param io Pointer to IO object
740  * @param hdr Pointer to FC header
741  * @param payload Address of payload
742  * @param payload_len Length of payload in bytes
743  *
744  * @return returns 0 for success, a negative error code value for failure.
745  */
746 static int32_t
747 ocs_femul_process_gpn_id(ocs_io_t *io, fc_header_t *hdr, void *payload, uint32_t payload_len)
748 {
749  fcct_gpnid_req_t *gpnid = payload;
750  uint32_t port_id = fc_be24toh(gpnid->port_id);
751  fcct_gpnid_acc_t *acc = io->els_rsp.virt;
752  ocs_ns_record_t *nsrec = NULL;
753  uint32_t cmd_rsp_code = FCCT_HDR_CMDRSP_ACCEPT;
754  uint32_t reason_code = 0;
755  uint32_t reason_code_explanation = 0;
756 
757  /* Find the record for the port */
758  nsrec = ocs_ns_find_port_id(io->node->sport->domain->ocs_ns, port_id);
759  if (nsrec != NULL) {
760  acc->port_name = ocs_htobe64(nsrec->port_name);
761  io->wire_len += sizeof(acc->port_name);
762  } else {
763  ocs_log_test(io->ocs, "port_id 0x%x not found\n", port_id);
764  cmd_rsp_code = FCCT_HDR_CMDRSP_REJECT;
765  reason_code = FCCT_UNABLE_TO_PERFORM;
766  reason_code_explanation = FCCT_DEVICES_NOT_IN_COMMON_ZONE;
767  }
768  return ocs_send_ct_rsp(io, hdr->ox_id, payload, cmd_rsp_code,
769  reason_code, reason_code_explanation);
770 }
771 
772 /**
773  * @brief Process GFPN_ID command
774  *
775  * Process the GFPN_ID request
776  *
777  * @param io Pointer to IO object
778  * @param hdr Pointer to FC header
779  * @param payload Address of payload
780  * @param payload_len Length of payload in bytes
781  *
782  * @return returns 0 for success, a negative error code value for failure.
783  */
784 static int32_t
785 ocs_femul_process_gfpn_id(ocs_io_t *io, fc_header_t *hdr, void *payload, uint32_t payload_len)
786 {
787  return ocs_send_ct_rsp(io, hdr->ox_id, payload, FCCT_HDR_CMDRSP_REJECT,
789 }
790 
791 /**
792  * @brief Process GFF_ID command
793  *
794  * Process the GFF_ID request
795  *
796  * @param io Pointer to IO object
797  * @param hdr Pointer to FC header
798  * @param payload Address of payload
799  * @param payload_len Length of payload in bytes
800  *
801  * @return returns 0 for success, a negative error code value for failure.
802  */
803 static int32_t
804 ocs_femul_process_gff_id(ocs_io_t *io, fc_header_t *hdr, void *payload, uint32_t payload_len)
805 {
806  fcct_gffid_req_t *gffid = payload;
807  uint32_t port_id = fc_be24toh(gffid->port_id);
808  fcct_gffid_acc_t *acc = io->els_rsp.virt;
809  ocs_ns_record_t *nsrec = NULL;
810  uint32_t cmd_rsp_code = FCCT_HDR_CMDRSP_ACCEPT;
811  uint32_t reason_code = 0;
812  uint32_t reason_code_explanation = 0;
813 
814  /* Find the record for the port */
815  nsrec = ocs_ns_find_port_id(io->node->sport->domain->ocs_ns, port_id);
816  if (nsrec != NULL) {
817  acc->fc4_feature_bits = nsrec->fc4_features;
818  io->wire_len += sizeof(acc->fc4_feature_bits);
819  } else {
820  ocs_log_test(io->ocs, "port_id 0x%x not found\n", port_id);
821  cmd_rsp_code = FCCT_HDR_CMDRSP_REJECT;
822  reason_code = FCCT_UNABLE_TO_PERFORM;
823  reason_code_explanation = FCCT_DEVICES_NOT_IN_COMMON_ZONE;
824  }
825  return ocs_send_ct_rsp(io, hdr->ox_id, payload, cmd_rsp_code,
826  reason_code, reason_code_explanation);
827 }
828 
829 /**
830  * @brief Process GID_FT command
831  *
832  * Process the GID_FT request
833  *
834  * @param io Pointer to IO object
835  * @param hdr Pointer to FC header
836  * @param payload Address of payload
837  * @param payload_len Length of payload in bytes
838  *
839  * @return returns 0 for success, a negative error code value for failure.
840  */
841 static int32_t
842 ocs_femul_process_gid_ft(ocs_io_t *io, fc_header_t *hdr, void *payload, uint32_t payload_len)
843 {
844  fcct_gidft_acc_t *gidft = io->els_rsp.virt;
845  uint32_t reqid = fc_be24toh(hdr->s_id);
846  uint32_t idx;
847  uint32_t max_entries;
848  ocs_ns_record_t *nsrec = NULL;
849 
850  /* Compute maximum entries, given the response payload size */
851  max_entries = (io->els_rsp.size - sizeof(gidft->hdr)) / sizeof(uint32_t);
852 
853  /* enumerate all nodes that are in the domain to which the requestor belongs */
854  idx = 0;
855  for (nsrec = ocs_ns_enumerate(io->node->sport->domain->ocs_ns, nsrec); nsrec != NULL;
856  nsrec = ocs_ns_enumerate(io->node->sport->domain->ocs_ns, nsrec)) {
857 
858  if (idx >= max_entries) {
859  ocs_log_test(io->ocs, "overflowed GID_FT response buffer\n");
860  break;
861  }
862  /* Skip this entry if it blocks to the requestor */
863  if (nsrec->port_id == reqid) {
864  continue;
865  }
866  gidft->port_list[idx].ctl = 0;
867  gidft->port_list[idx].port_id = fc_htobe24(nsrec->port_id);
868  io->wire_len += sizeof(uint32_t);
869  idx++;
870  }
871 
872  gidft->port_list[idx > 0 ? idx-1 : idx].ctl = 0x80;
873 
874  return ocs_send_ct_rsp(io, hdr->ox_id, payload, FCCT_HDR_CMDRSP_ACCEPT, 0, 0);
875 }
876 
877 /**
878  * @brief Process GID_PT command
879  *
880  * Process the GID_PT request
881  *
882  * @param io Pointer to IO object
883  * @param hdr Pointer to FC header
884  * @param payload Address of payload
885  * @param payload_len Length of payload in bytes
886  *
887  * @return returns 0 for success, a negative error code value for failure.
888  */
889 static int32_t
890 ocs_femul_process_gid_pt(ocs_io_t *io, fc_header_t *hdr, void *payload, uint32_t payload_len)
891 {
892  fcct_gidpt_acc_t *gidpt = io->els_rsp.virt;
893  uint32_t reqid = fc_be24toh(hdr->s_id);
894  uint32_t idx;
895  uint32_t max_entries;
896  ocs_ns_record_t *nsrec = NULL;
897 
898  /* Compute maximum entries, given the response payload size */
899  max_entries = (io->els_rsp.size - sizeof(gidpt->hdr)) / sizeof(uint32_t);
900 
901  /* enumerate all nodes that are in the domain to which the requestor belongs */
902  idx = 0;
903  for (nsrec = ocs_ns_enumerate(io->node->sport->domain->ocs_ns, nsrec); nsrec != NULL;
904  nsrec = ocs_ns_enumerate(io->node->sport->domain->ocs_ns, nsrec)) {
905 
906  if (idx >= max_entries) {
907  ocs_log_test(io->ocs, "overflowed GID_PT response buffer\n");
908  break;
909  }
910  /* Skip this entry if it blocks to the requestor */
911  if (nsrec->port_id == reqid) {
912  continue;
913  }
914  gidpt->port_list[idx].ctl = 0;
915  gidpt->port_list[idx].port_id = fc_htobe24(nsrec->port_id);
916  io->wire_len += sizeof(uint32_t);
917  idx++;
918  }
919 
920  gidpt->port_list[idx > 0 ? idx-1 : idx].ctl = 0x80;
921 
922  return ocs_send_ct_rsp(io, hdr->ox_id, payload, FCCT_HDR_CMDRSP_ACCEPT, 0, 0);
923 }
924 
925 /**
926  * @brief Process GA_NXT command
927  *
928  * Process the GA_NXT request
929  *
930  * @param io Pointer to IO object
931  * @param hdr Pointer to FC header
932  * @param payload Address of payload
933  * @param payload_len Length of payload in bytes
934  *
935  * @return returns 0 for success, a negative error code value for failure.
936  */
937 static int32_t
938 ocs_femul_process_ga_nxt(ocs_io_t *io, fc_header_t *hdr, void *payload, uint32_t payload_len)
939 {
940  fcct_ganxt_req_t *ganxt_req = payload;
941  fcct_ganxt_acc_t *ganxt_resp = io->els_rsp.virt;
942  uint32_t port_id = ganxt_req->port_id;
943  ocs_ns_record_t *nsrec = NULL, *tmp_nsrec = NULL;
944 
945  ocs_memset(io->els_rsp.virt, 0, sizeof(ganxt_resp));
946  while ((nsrec = ocs_ns_enumerate(io->node->sport->domain->ocs_ns, nsrec)) != NULL) {
947  if (nsrec->port_id > port_id) {
948  if (!tmp_nsrec || (tmp_nsrec->port_id > nsrec->port_id)) {
949  tmp_nsrec = nsrec;
950  }
951  }
952 
953  }
954 
955  if (tmp_nsrec) {
956  ganxt_resp->port_id = tmp_nsrec->port_id;
957  ganxt_resp->port_name = tmp_nsrec->port_name;
958  ganxt_resp->sym_node_name_len = tmp_nsrec->sym_node_name_len;
959  ocs_memcpy(ganxt_resp->sym_node_name, tmp_nsrec->sym_node_name, MIN(tmp_nsrec->sym_node_name_len, 255));
960  ganxt_resp->class_of_serv = tmp_nsrec->class_of_srvc;
961  ganxt_resp->node_name = tmp_nsrec->node_name;
962  return ocs_send_ct_rsp(io, hdr->ox_id, payload, FCCT_HDR_CMDRSP_ACCEPT, 0, 0);
963  }
964 
967  return -1;
968 }
969 
970 /**
971  * @brief Process SCR request
972  *
973  * Process the SCR request
974  *
975  * @param io Pointer to IO object
976  * @param hdr Pointer to FC header
977  * @param payload Address of payload
978  * @param payload_len Length of payload in bytes
979  *
980  * @return returns 0 for success, a negative error code value for failure.
981  */
982 int32_t
983 ocs_femul_process_scr(ocs_io_t *io, fc_header_t *hdr, void *payload, uint32_t payload_len)
984 {
985  ocs_ns_t *ns = io->node->sport->domain->ocs_ns;
986  uint32_t port_id = fc_be24toh(hdr->s_id);
987  ocs_ns_record_t *nsrec;
988 
989  nsrec = ocs_ns_alloc(io->node->sport->domain->ocs_ns, port_id);
990 
991  if (nsrec == NULL) {
992  ocs_log_test(io->ocs, "port_id %x not found\n", port_id);
993  /* caller will send failure response */
994  return -1;
995  }
996  nsrec->scr_requested = TRUE;
997  nsrec->node = io->node;
998  ocs_log_debug(io->ocs, "SCR accepted from %x\n", port_id);
999 
1000  /* Clear the ns_event_list */
1001  ocs_ns_event_clear(ns);
1002 
1003  ocs_send_ls_acc(io, ocs_htobe16(hdr->ox_id), NULL, NULL);
1004  return 0;
1005 }
1006 
1007 /**
1008  * @brief Process Fabric Emulation FCGS request
1009  *
1010  * The requested FCGS command is processed
1011  *
1012  * @param funcname Name of function
1013  * @param io Pointer to IO object
1014  * @param evt Event to process
1015  * @param hdr Pointer to FC header
1016  * @param payload Address of payload buffer
1017  * @param payload_len Length of payload buffer in bytes
1018  *
1019  * @return returns 0 for success, a negative error code value for failure.
1020  */
1021 
1022 int32_t
1023 ocs_femul_process_fc_gs(const char *funcname, ocs_io_t *io, ocs_sm_event_t evt, fc_header_t *hdr, void *payload, uint32_t payload_len)
1024 {
1025  int32_t rc = -1;
1026  ocs_node_t *node = io->node;
1027  ocs_t *ocs = io->ocs;
1028 
1029  /*
1030  * ocs_send_ct_rsp uses this to append the header size. Clear to 0
1031  * and the individual functions can add whatever they need to the
1032  * payload size.
1033  */
1034  io->wire_len = 0;
1035 
1036  switch(evt) {
1037  case OCS_EVT_RFF_ID_RCVD:
1038  rc = ocs_femul_process_rff_id(io, hdr, payload, payload_len);
1039  break;
1040  case OCS_EVT_GNN_ID_RCVD:
1041  rc = ocs_femul_process_gnn_id(io, hdr, payload, payload_len);
1042  break;
1043  case OCS_EVT_GPN_ID_RCVD:
1044  rc = ocs_femul_process_gpn_id(io, hdr, payload, payload_len);
1045  break;
1046  case OCS_EVT_GFPN_ID_RCVD:
1047  rc = ocs_femul_process_gfpn_id(io, hdr, payload, payload_len);
1048  break;
1049  case OCS_EVT_GFF_ID_RCVD:
1050  rc = ocs_femul_process_gff_id(io, hdr, payload, payload_len);
1051  break;
1052  case OCS_EVT_GID_FT_RCVD:
1053  rc = ocs_femul_process_gid_ft(io, hdr, payload, payload_len);
1054  break;
1055  case OCS_EVT_GID_PT_RCVD:
1056  rc = ocs_femul_process_gid_pt(io, hdr, payload, payload_len);
1057  break;
1058  case OCS_EVT_GA_NXT_RCVD:
1059  rc = ocs_femul_process_ga_nxt(io, hdr, payload, payload_len);
1060  break;
1061  case OCS_EVT_RPN_ID_RCVD:
1062  rc = ocs_femul_process_rpn_id(io, hdr, payload, payload_len);
1063  break;
1064  case OCS_EVT_RNN_ID_RCVD:
1065  rc = ocs_femul_process_rnn_id(io, hdr, payload, payload_len);
1066  break;
1067  case OCS_EVT_RCS_ID_RCVD:
1068  rc = ocs_femul_process_rcs_id(io, hdr, payload, payload_len);
1069  break;
1070  case OCS_EVT_RSNN_NN_RCVD:
1071  rc = ocs_femul_process_rsnn_nn(io, hdr, payload, payload_len);
1072  break;
1073  case OCS_EVT_RSPN_ID_RCVD:
1074  rc = ocs_femul_process_rspn_id(io, hdr, payload, payload_len);
1075  break;
1076  case OCS_EVT_RFT_ID_RCVD:
1077  rc = ocs_femul_process_rft_id(io, hdr, payload, payload_len);
1078  break;
1079  case OCS_EVT_RHBA_RCVD:
1080  rc = ocs_femul_process_rhba(io, hdr, payload, payload_len);
1081  break;
1082  case OCS_EVT_RPA_RCVD:
1083  rc = ocs_femul_process_rpa(io, hdr, payload, payload_len);
1084  break;
1085  default: {
1086  ocs_log_test(ocs, "[%s] (%s) %s sending CT_REJECT\n",
1087  node->display_name, funcname, ocs_sm_event_name(evt));
1089  break;
1090  }
1091  }
1092  return rc;
1093 
1094 }
1095 
1096 /**
1097  * @brief Attach the Name Services database
1098  *
1099  * Allocate the name services database
1100  *
1101  * @param domain Pointer to the domain object
1102  * @param max_ports Maximum number of ports to be supported by this name services database
1103  *
1104  * @return Pointer to name services datatbase object, or NULL if there is an error
1105  */
1106 ocs_ns_t *
1107 ocs_ns_attach(ocs_domain_t *domain, uint32_t max_ports)
1108 {
1109  ocs_ns_t *ns;
1110  ocs_t *ocs = domain->ocs;
1111 
1112  ns = ocs_malloc(ocs, sizeof(*ns), OCS_M_ZERO | OCS_M_NOWAIT);
1113  if (ns == NULL) {
1114  ocs_log_err(ocs, "ocs_malloc ns failed\n");
1115  return NULL;
1116  }
1117  ns->ns_records = ocs_malloc(ocs, sizeof(*ns->ns_records)*max_ports, OCS_M_ZERO | OCS_M_NOWAIT);
1118  ns->ns_record_count = max_ports;
1119  if (ns->ns_records == NULL) {
1120  ocs_log_err(ocs, "ocs_malloc ns records failed\n");
1121  ocs_free(ocs, ns, sizeof(*ns));
1122  return NULL;
1123  }
1124  ocs_lock_init(ocs, &ns->ns_event_lock, "ns_event_list lock[%d]", domain->instance_index);
1125  ns->ns_event_list_len = sizeof(*ns->ns_event_list)*max_ports;
1126  ns->ns_event_list = ocs_malloc(ocs, sizeof(*ns->ns_event_list)*max_ports, OCS_M_ZERO | OCS_M_NOWAIT);
1127  if (ns->ns_event_list == NULL) {
1128  ocs_log_err(ocs, "ocs_malloc ns_event_list failed\n");
1129  ocs_free(ocs, ns->ns_records, sizeof(*ns->ns_records)*max_ports);
1130  ocs_free(ocs, ns, sizeof(*ns));
1131  return NULL;
1132  }
1133  ns->ns_event_list_count = 0;
1134 
1135  ns->domain = domain;
1136 
1137  return ns;
1138 }
1139 
1140 /**
1141  * @brief Detach name services database
1142  *
1143  * The name services database is freed
1144  *
1145  * @param ns Pointer to name services database object
1146  *
1147  * @return none
1148  */
1149 void
1150 ocs_ns_detach(ocs_ns_t *ns)
1151 {
1152  ocs_t *ocs = ns->domain->ocs;
1153  ocs_ns_record_t *nsrec;
1154 
1155  if (ocs_timer_pending(&ns->rscn_timer)) {
1156  ocs_del_timer(&ns->rscn_timer);
1157  }
1158 
1159  if (ns != NULL) {
1160  for (nsrec = NULL; (nsrec = ocs_ns_enumerate(ns, nsrec)) != NULL; ) {
1161  if (nsrec->sym_node_name != NULL) {
1162  ocs_free(ocs, nsrec->sym_node_name, nsrec->sym_node_name_len);
1163  nsrec->sym_node_name = NULL;
1164  }
1165  }
1166 
1167  if (ns->ns_records != NULL) {
1168  ocs_free(ocs, ns->ns_records, sizeof(*ns->ns_records) * ns->ns_record_count);
1169  }
1170  if (ns->ns_event_list != NULL) {
1171  ocs_free(ocs, ns->ns_event_list, ns->ns_event_list_len);
1172  }
1173  ocs_lock_free(&ns->ns_event_lock);
1174  ocs_free(ocs, ns, sizeof(*ns));
1175  }
1176 }
1177 
1178 /**
1179  * @brief Find or allocate a port ID record
1180  *
1181  * A port ID record is found or allocated, and returned.
1182  *
1183  * @param ns Pointer to name services database
1184  * @param port_id Port ID to find/allocate
1185  *
1186  * @return Pointer to NS record, or NULL if failure
1187  */
1188 ocs_ns_record_t *
1189 ocs_ns_alloc(ocs_ns_t *ns, uint32_t port_id)
1190 {
1191  uint32_t i;
1192  ocs_ns_record_t *nsrec;
1193  ocs_t *ocs = ns->domain->ocs;
1194 
1195  /* Don't accept registratoin requests from the well known switch ports */
1196  switch(port_id) {
1197  case FC_ADDR_FABRIC:
1198  case FC_ADDR_NAMESERVER:
1199  case FC_ADDR_CONTROLLER:
1200  return NULL;
1201  }
1202 
1203  nsrec = ocs_ns_find_port_id(ns, port_id);
1204  if (nsrec != NULL) {
1205  return nsrec;
1206  }
1207 
1208  /* Find an empty slot */
1209  for (i = 0, nsrec = ns->ns_records; i < ns->ns_record_count; i++, nsrec++) {
1210  if (!nsrec->active) {
1211  nsrec->active = 1;
1212  nsrec->port_id = port_id;
1213  break;
1214  }
1215  }
1216 
1217  if (nsrec != NULL) {
1218  /* Add this port_id to the event list */
1219  ocs_ns_event_add(ns, nsrec->port_id);
1220 
1221  /* Start delay and then send rscn's */
1222  if (ocs_timer_pending(&ns->rscn_timer)) {
1223  ocs_del_timer(&ns->rscn_timer);
1224  }
1225  ocs_setup_timer(ocs, &ns->rscn_timer, ocs_ns_rscn_timeout, ns, 1000, false);
1226  }
1227  return nsrec;
1228 }
1229 
1230 /**
1231  * @brief Free name services database record
1232  *
1233  * A name services database record is freed
1234  *
1235  * @param ns Pointer to name services database object
1236  * @param port_id Port ID to free
1237  *
1238  * @return none
1239  */
1240 void
1241 ocs_ns_free(ocs_ns_t *ns, uint32_t port_id)
1242 {
1243  ocs_ns_record_t *nsrec;
1244 
1245  nsrec = ocs_ns_find_port_id(ns, port_id);
1246  if (nsrec != NULL) {
1247  ocs_memset(nsrec, 0, sizeof(*ns));
1248  }
1249 }
1250 
1251 /**
1252  * @brief Find port ID in name services database
1253  *
1254  * Find a name services record given a port ID
1255  *
1256  * @param ns Pointer to name services database
1257  * @param port_id Port ID to find
1258  *
1259  * @return Pointer to NS record, or NULL if not found
1260  */
1261 ocs_ns_record_t *
1262 ocs_ns_find_port_id(ocs_ns_t *ns, uint32_t port_id)
1263 {
1264  uint32_t i;
1265  ocs_ns_record_t *nsrec;
1266 
1267  for (i = 0, nsrec = ns->ns_records; i < ns->ns_record_count; i++, nsrec++) {
1268  if (nsrec->active && (nsrec->port_id == port_id)) {
1269  return nsrec;
1270  }
1271  }
1272  return NULL;
1273 }
1274 
1275 /**
1276  * @brief Find port name in name services database
1277  *
1278  * Find a name services record given a port name
1279  *
1280  * @param ns Pointer to name services database
1281  * @param port_name Port WWPN to find
1282  *
1283  * @return Pointer to NS record, or NULL if not found
1284  */
1285 ocs_ns_record_t *
1286 ocs_ns_find_port_name(ocs_ns_t *ns, uint64_t port_name)
1287 {
1288  uint32_t i;
1289  ocs_ns_record_t *nsrec;
1290 
1291  for (i = 0, nsrec = ns->ns_records; i < ns->ns_record_count; i++, nsrec++) {
1292  if (nsrec->active && (nsrec->port_name == port_name)) {
1293  return nsrec;
1294  }
1295  }
1296  return NULL;
1297 }
1298 
1299 /**
1300  * @brief Enumerate NS records
1301  *
1302  * Name services database records are enumerated. The pattern for using this function is:
1303  *
1304  * ocs_ns_record_t *nsrec = NULL;
1305  * while ((nsrec = ocs_ns_enumerate(ns, nsrec)) != NULL) {
1306  * action(nsrec);
1307  * }
1308  *
1309  * @param ns Pointer to name services database record
1310  * @param nsrec Pointer to NS record to iterate
1311  *
1312  * @return Pointer to next NS record or NULL
1313  */
1314 ocs_ns_record_t *
1315 ocs_ns_enumerate(ocs_ns_t *ns, ocs_ns_record_t *nsrec)
1316 {
1317  uint32_t idx;
1318 
1319  if (nsrec == NULL) {
1320  nsrec = ns->ns_records;
1321  } else {
1322  nsrec++;
1323  }
1324  idx = nsrec - ns->ns_records;
1325  while (idx < ns->ns_record_count) {
1326  if (nsrec->active) {
1327  return nsrec;
1328  }
1329  idx--;
1330  nsrec++;
1331  }
1332  return NULL;
1333 }
1334 
1335 
1336 /**
1337  * @brief Name services RSCN timeout handler
1338  *
1339  * When an RSCN event is detected (registering or removing a port ID), all remote nodes that
1340  * have registered for state change notifications (using SCR) will be notified. In order
1341  * to keep from thrashing with a blast of changes, the RSCN's are accumultated for a timeout period
1342  * then sent.
1343  *
1344  * @param arg Pointer to name services database
1345  *
1346  * @return none
1347  */
1348 static void
1349 ocs_ns_rscn_timeout(void *arg)
1350 {
1351  ocs_ns_t *ns = arg;
1352  ocs_t *ocs = ns->domain->ocs;
1353  ocs_ns_record_t *nsrec;
1354  uint32_t port_ids_buf_len;
1355  fc_rscn_affected_port_id_page_t *port_ids_buf;
1357  uint32_t i;
1358 
1359  ocs_del_timer(&ns->rscn_timer);
1360 
1361  /* If event list is empty, then don't send out any RSCN's */
1362  ocs_lock(&ns->ns_event_lock);
1363  if (ns->ns_event_list_count == 0) {
1364  ocs_unlock(&ns->ns_event_lock);
1365  return;
1366  }
1367 
1368  /* Build the payload */
1369  port_ids_buf_len = sizeof(*port_ids_buf) * ns->ns_event_list_count;
1370  port_ids_buf = ocs_malloc(ocs, port_ids_buf_len, OCS_M_ZERO | OCS_M_NOWAIT);
1371  if (port_ids_buf == NULL) {
1372  ocs_log_err(ocs, "ocs_malloc port_ids failed\n");
1373  ocs_unlock(&ns->ns_event_lock);
1374  return;
1375  }
1376  for (i = 0, pid = port_ids_buf; i < ns->ns_event_list_count; i++, pid++) {
1377  pid->port_id = fc_htobe24(ns->ns_event_list[i]);
1378  pid->address_format = 0;
1379  pid->rscn_event_qualifier = 0;
1380  }
1381  ocs_unlock(&ns->ns_event_lock);
1382 
1383  /* Find all of the registered ports, and send an RSCN to them */
1384  nsrec = NULL;
1385  while ((nsrec = ocs_ns_enumerate(ns, nsrec)) != NULL) {
1386  if (nsrec->scr_requested) {
1388  port_ids_buf, port_ids_buf_len / sizeof(*port_ids_buf), NULL, NULL);
1389  }
1390  }
1391 
1392  /* Clear the event list */
1393  ocs_ns_event_clear(ns);
1394 
1395  ocs_free(ocs, port_ids_buf, port_ids_buf_len);
1396 }
1397 
1398 /**
1399  * @brief Add a changed event
1400  *
1401  * Add a port ID to the changed event list
1402  *
1403  * @param ns Pointer to name services database
1404  * @param port_id Port ID to add to the event list
1405  *
1406  * @return returns 0
1407  */
1408 static int32_t
1409 ocs_ns_event_add(ocs_ns_t *ns, uint32_t port_id)
1410 {
1411  uint32_t i;
1412  ocs_t *ocs = ns->domain->ocs;
1413 
1414  ocs_lock(&ns->ns_event_lock);
1415  /* See if this event has already been posted */
1416  for (i = 0; i < ns->ns_event_list_count; i++) {
1417  if (ns->ns_event_list[i] == port_id) {
1418  ocs_unlock(&ns->ns_event_lock);
1419  return 0;
1420  }
1421  }
1422 
1423  if (ns->ns_event_list_count >= ns->ns_record_count) {
1424  ocs_log_test(ocs, "ns_event_list is full\n");
1425  ocs_unlock(&ns->ns_event_lock);
1426  return -1;
1427  }
1428 
1429  ns->ns_event_list[ns->ns_event_list_count++] = port_id;
1430  ocs_unlock(&ns->ns_event_lock);
1431 
1432  return 0;
1433 }
1434 
1435 /**
1436  * @brief Clear name services event list
1437  *
1438  * The name services changed event list is cleared
1439  *
1440  * @param ns Pointer to name services database
1441  *
1442  * @return none
1443  */
1444 static void
1445 ocs_ns_event_clear(ocs_ns_t *ns)
1446 {
1447  ocs_lock(&ns->ns_event_lock);
1448  ns->ns_event_list_count = 0;
1449  ocs_unlock(&ns->ns_event_lock);
1450 }
1451 
1452 /**
1453  * @brief Process driver dump request
1454  *
1455  * Process driver dump request by providing name services database information
1456  *
1457  * @param textbuf Pointer to text buffer
1458  * @param ns Pointer to name services database object
1459  *
1460  * @return returns 0
1461  */
1462 int32_t
1463 ocs_ddump_ns(ocs_textbuf_t *textbuf, ocs_ns_t *ns)
1464 {
1465  ocs_ns_record_t *nsrec = NULL;
1466 
1467  if (!textbuf)
1468  return 0;
1469 
1470  if (textbuf->ocs->domain && textbuf->ocs->domain->femul_enable) {
1471  ocs_ddump_section(textbuf, "nameserver", 0);
1472  ocs_lock(&ns->ns_event_lock);
1473  while ((nsrec = ocs_ns_enumerate(ns, nsrec)) != NULL) {
1474  ocs_ddump_value(textbuf, "portid", "%06x", nsrec->port_id);
1475  ocs_ddump_value(textbuf, "scr_requested", "%d", nsrec->scr_requested);
1476  ocs_ddump_value(textbuf, "fc4_types", "%08x", nsrec->fc4_types);
1477  ocs_ddump_value(textbuf, "fc4_featurces", "%02x", nsrec->fc4_features);
1478  ocs_ddump_value(textbuf, "port_name", "%" PRIx64 , nsrec->port_name);
1479  ocs_ddump_value(textbuf, "node_name", "%" PRIx64 , nsrec->node_name);
1480  ocs_ddump_value(textbuf, "sym_node_name", "%s", nsrec->sym_node_name);
1481  }
1482  ocs_unlock(&ns->ns_event_lock);
1483  ocs_ddump_endsection(textbuf, "nameserver", 0);
1484  }
1485  return 0;
1486 }
1487 #endif
uint32_t class_of_serv
Definition: ocs_fcp.h:826
uint32_t fc4_features
Definition: ocs_fcp.h:532
uint64_t node_name
Definition: ocs_fcp.h:584
uint64_t port_name
Definition: ocs_fcp.h:787
ocs_sport_t * ocs_sport_find(ocs_domain_t *domain, uint32_t d_id)
Find a SLI port object, given an FC_ID.
Definition: ocs_sport.c:365
uint64_t node_name
Definition: ocs_fcp.h:821
uint8_t fc4_feature_bits
Definition: ocs_fcp.h:792
char sym_node_name[1]
Definition: ocs_fcp.h:586
ocs_io_t * ocs_els_io_alloc(ocs_node_t *node, uint32_t reqlen, ocs_els_role_e role)
Allocate an IO structure for an ELS IO context.
Definition: ocs_els.c:197
#define FC_ADDR_CONTROLLER
Definition: ocs_fcp.h:62
uint32_t port_id
Definition: ocs_fcp.h:798
#define FC4_FEATURE_TARGET
Definition: ocs_fcp.h:637
uint32_t port_id
Definition: ocs_fcp.h:754
#define FCCT_HDR_CMDRSP_ACCEPT
Definition: ocs_fcp.h:594
uint32_t ctl
Definition: ocs_fcp.h:806
#define FCCT_COMMAND_NOT_SUPPORTED
Definition: ocs_fcp.h:503
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
uint32_t port_id
Definition: ocs_fcp.h:572
#define FCCT_UNABLE_TO_PERFORM
Definition: ocs_fcp.h:502
void __ocs_domain_attach_internal(ocs_domain_t *domain, uint32_t s_id)
Initiator domain attach. (internal call only)
Definition: ocs_domain.c:1280
#define FC4_FEATURE_INITIATOR
Definition: ocs_fcp.h:638
#define FC_TYPE_FCP
Definition: ocs_fcp.h:56
uint8_t name_len
Definition: ocs_fcp.h:585
uint8_t sym_node_name[255]
Definition: ocs_fcp.h:823
uint32_t port_id
Definition: ocs_fcp.h:521
static uint32_t fc_htobe24(uint32_t x)
Definition: ocs_fcp.h:147
uint8_t sym_node_name_len
Definition: ocs_fcp.h:822
uint64_t port_name
Definition: ocs_fcp.h:545
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
void ocs_els_io_free(ocs_io_t *els)
Free IO structure for an ELS IO context.
Definition: ocs_els.c:330
struct fcct_gidft_acc_t::@6 port_list[1]
uint32_t class_of_srvc
Definition: ocs_fcp.h:573
uint32_t port_id
Definition: ocs_fcp.h:806
const char * ocs_sm_event_name(ocs_sm_event_t evt)
Definition: ocs_sm.c:92
struct fcct_gidpt_acc_t::@7 port_list[1]
#define FCCT_DATA_BASE_FULL
Definition: ocs_fcp.h:512
FC header in big-endian order.
Definition: ocs_fcp.h:157
#define FCCT_DEVICES_NOT_IN_COMMON_ZONE
Definition: ocs_fcp.h:516
uint32_t port_id
Definition: ocs_fcp.h:748
int32_t ocs_node_free(ocs_node_t *node)
free a node structure
Definition: ocs_node.c:510
#define FCCT_FABRIC_PORT_NAME_NOT_REGISTERED
Definition: ocs_fcp.h:504
ocs_io_t * ocs_send_rscn(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries, void *port_ids, uint32_t port_ids_count, els_cb_t cb, void *cbarg)
Send an RSCN ELS command.
Definition: ocs_els.c:1295
int32_t ocs_sport_vport_new(ocs_domain_t *domain, uint64_t wwpn, uint64_t wwnn, uint32_t fc_id, uint8_t ini, uint8_t tgt, void *tgt_data, void *ini_data, uint8_t restore_vport)
Allocate a new virtual SLI port.
Definition: ocs_sport.c:1057
uint32_t port_name_lo
Definition: ocs_fcp.h:325
uint32_t fc4_types
Definition: ocs_fcp.h:522
#define FCCT_CLASS_OF_SERVICE_2
Definition: ocs_fcp.h:566
uint32_t port_id
Definition: ocs_fcp.h:544
uint32_t port_id
Definition: ocs_fcp.h:531
uint32_t port_name_hi
Definition: ocs_fcp.h:324
uint64_t port_name
Definition: ocs_fcp.h:818
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
ocs_node_t * ocs_node_alloc(ocs_sport_t *sport, uint32_t port_id, uint8_t init, uint8_t targ)
Allocate an fc node structure and add to node list.
Definition: ocs_node.c:415
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
int32_t ocs_send_ct_rsp(ocs_io_t *io, uint32_t ox_id, fcct_iu_header_t *ct_hdr, uint32_t cmd_rsp_code, uint32_t reason_code, uint32_t reason_code_explanation)
Send CT response.
Definition: ocs_els.c:3535
uint32_t type_code
Definition: ocs_fcp.h:532
fcct_iu_header_t hdr
Definition: ocs_fcp.h:804
uint32_t port_id
Definition: ocs_fcp.h:816
ocs_t * ocs
Definition: ocs_textbuf.h:49
uint64_t node_name
Definition: ocs_fcp.h:557
ocs_io_t * ocs_send_flogi_acc(ocs_io_t *io, uint32_t ox_id, uint32_t is_fport, els_cb_t cb, void *cbarg)
Definition: ocs_els.c:1534
#define FC_GS_TYPE_BIT(type)
Definition: ocs_fcp.h:80
fcct_iu_header_t hdr
Definition: ocs_fcp.h:796
#define OCS_FC_ELS_DEFAULT_RETRIES
Definition: ocs_fc_config.h:85
#define FCCT_HDR_CMDRSP_REJECT
Definition: ocs_fcp.h:595
uint32_t port_id
Definition: ocs_fcp.h:760
#define FC_ADDR_NAMESERVER
Definition: ocs_fcp.h:65
#define FCCT_NO_ADDITIONAL_EXPLANATION
Definition: ocs_fcp.h:509
uint32_t port_id
Definition: ocs_fcp.h:742
uint32_t ctl
Definition: ocs_fcp.h:798
#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
#define ocs_assert(cond,...)
Definition: ocs_debug.h:176
static uint32_t fc_be24toh(uint32_t x)
Definition: ocs_fcp.h:143
ocs_sm_event_t
Definition: ocs_sm.h:60
struct ocs_ns_s ocs_ns_t
Definition: ocs_common.h:64
uint32_t s_id
Definition: ocs_fcp.h:161
uint64_t node_name
Definition: ocs_fcp.h:782
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
uint32_t port_id
Definition: ocs_fcp.h:556
#define OCS_FC_ELS_SEND_DEFAULT_TIMEOUT
Definition: ocs_fc_config.h:77
#define FC_ADDR_FABRIC
Definition: ocs_fcp.h:61