iPXE
fcels.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2010 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301, USA.
18  *
19  * You can also choose to distribute this program under the terms of
20  * the Unmodified Binary Distribution Licence (as given in the file
21  * COPYING.UBDL), provided that you have satisfied its requirements.
22  */
23 
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25 
26 #include <stdint.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <errno.h>
30 #include <assert.h>
31 #include <byteswap.h>
32 #include <ipxe/interface.h>
33 #include <ipxe/xfer.h>
34 #include <ipxe/iobuf.h>
35 #include <ipxe/process.h>
36 #include <ipxe/fc.h>
37 #include <ipxe/fcels.h>
38 
39 /** @file
40  *
41  * Fibre Channel Extended Link Services
42  *
43  */
44 
45 /** Fibre Channel ELS transaction debug message format */
46 #define FCELS_FMT "FCELS %s %s %s %s"
47 
48 /** Fibre Channel ELS transaction debug message arguments */
49 #define FCELS_ARGS( els ) \
50  (els)->port->name, \
51  ( (els)->handler ? (els)->handler->name : "unknown ELS" ), \
52  ( fc_els_is_request ( els ) ? "to" : "from" ), \
53  fc_id_ntoa ( &(els)->peer_port_id )
54 
55 struct fc_els_handler fc_els_unknown_handler __fc_els_handler;
56 
57 /**
58  * Free Fibre Channel ELS transaction
59  *
60  * @v refcnt Reference count
61  */
62 static void fc_els_free ( struct refcnt *refcnt ) {
63  struct fc_els *els = container_of ( refcnt, struct fc_els, refcnt );
64 
65  assert ( ! process_running ( &els->process ) );
66  fc_port_put ( els->port );
67  free ( els );
68 }
69 
70 /**
71  * Close Fibre Channel ELS transaction
72  *
73  * @v els Fibre Channel ELS transaction
74  * @v rc Reason for close
75  */
76 static void fc_els_close ( struct fc_els *els, int rc ) {
77 
78  if ( rc != 0 ) {
79  DBGC ( els, FCELS_FMT " complete (%s)\n",
80  FCELS_ARGS ( els ), strerror ( rc ) );
81  }
82 
83  /* Stop process */
84  process_del ( &els->process );
85 
86  /* Shut down interfaces */
87  intf_shutdown ( &els->xchg, rc );
88  intf_shutdown ( &els->job, rc );
89 }
90 
91 /**
92  * Detect Fibre Channel ELS frame handler
93  *
94  * @v els Fibre Channel ELS transaction
95  * @v command ELS command code
96  * @ret handler ELS handler, or NULL
97  */
98 static struct fc_els_handler * fc_els_detect ( struct fc_els *els,
99  const void *data,
100  size_t len ) {
101  const struct fc_els_frame_common *frame = data;
102  struct fc_els_handler *handler;
103  int rc;
104 
105  /* Sanity check */
106  if ( len < sizeof ( *frame ) )
107  return NULL;
108 
109  /* Try each handler in turn */
111  if ( ( rc = handler->detect ( els, data, len ) ) == 0 )
112  return handler;
113  }
114 
115  return NULL;
116 }
117 
118 /**
119  * Transmit Fibre Channel ELS frame
120  *
121  * @v els Fibre Channel ELS transaction
122  * @v data Data to transmit
123  * @v len Length of data
124  * @ret rc Return status code
125  */
126 int fc_els_tx ( struct fc_els *els, const void *data, size_t len ) {
127  struct xfer_metadata meta;
128  struct sockaddr_fc dest;
129  int rc;
130 
131  DBGC2 ( els, FCELS_FMT " transmitting:\n", FCELS_ARGS ( els ) );
132  DBGC2_HDA ( els, 0, data, len );
133 
134  /* Construct metadata */
135  memset ( &meta, 0, sizeof ( meta ) );
136  meta.flags = ( fc_els_is_request ( els ) ?
138  meta.dest = fc_fill_sockaddr ( &dest, &els->peer_port_id );
139 
140  /* Transmit frame */
141  if ( ( rc = xfer_deliver_raw_meta ( &els->xchg, data, len,
142  &meta ) ) != 0 ) {
143  DBGC ( els, FCELS_FMT " could not deliver frame: %s\n",
144  FCELS_ARGS ( els ), strerror ( rc ) );
145  return rc;
146  }
147 
148  return 0;
149 }
150 
151 /**
152  * Receive Fibre Channel ELS frame
153  *
154  * @v els Fibre Channel ELS transaction
155  * @v iobuf I/O buffer
156  * @v meta Data transfer metadata
157  * @ret rc Return status code
158  */
159 static int fc_els_rx ( struct fc_els *els,
160  struct io_buffer *iobuf,
161  struct xfer_metadata *meta ) {
162  struct fc_els_frame_common *frame = iobuf->data;
163  struct sockaddr_fc *src = ( ( struct sockaddr_fc * ) meta->src );
164  struct sockaddr_fc *dest = ( ( struct sockaddr_fc * ) meta->dest );
165  size_t len = iob_len ( iobuf );
166  int rc;
167 
168  /* Sanity check */
169  if ( len < sizeof ( *frame ) ) {
170  DBGC ( els, FCELS_FMT " received underlength frame:\n",
171  FCELS_ARGS ( els ) );
172  DBGC_HDA ( els, 0, frame, len );
173  rc = -EINVAL;
174  goto done;
175  }
176  if ( ! src ) {
177  DBGC ( els, FCELS_FMT " received frame missing source "
178  "address:\n", FCELS_ARGS ( els ) );
179  rc = -EINVAL;
180  goto done;
181  }
182  if ( ! dest ) {
183  DBGC ( els, FCELS_FMT " received frame missing destination "
184  "address:\n", FCELS_ARGS ( els ) );
185  rc = -EINVAL;
186  goto done;
187  }
188 
189  /* Check for rejection responses */
190  if ( fc_els_is_request ( els ) &&
191  ( frame->command != FC_ELS_LS_ACC ) ) {
192  DBGC ( els, FCELS_FMT " rejected:\n", FCELS_ARGS ( els ) );
193  DBGC_HDA ( els, 0, frame, len );
194  rc = -EACCES;
195  goto done;
196  }
197 
198  /* Update port IDs */
199  memcpy ( &els->port_id, &dest->sfc_port_id, sizeof ( els->port_id ) );
200  memcpy ( &els->peer_port_id, &src->sfc_port_id,
201  sizeof ( els->peer_port_id ) );
202 
203  /* Determine handler, if necessary */
204  if ( ! els->handler )
205  els->handler = fc_els_detect ( els, frame, len );
206  if ( ! els->handler )
207  els->handler = &fc_els_unknown_handler;
208 
209  DBGC2 ( els, FCELS_FMT " received:\n", FCELS_ARGS ( els ) );
210  DBGC2_HDA ( els, 0, frame, len );
211 
212  /* Handle received frame */
213  if ( ( rc = els->handler->rx ( els, frame, len ) ) != 0 ) {
214  DBGC ( els, FCELS_FMT " could not handle received frame: "
215  "%s\n", FCELS_ARGS ( els ), strerror ( rc ) );
216  DBGC_HDA ( els, 0, frame, len );
217  goto done;
218  }
219 
220  done:
221  /* Free I/O buffer */
222  free_iob ( iobuf );
223 
224  /* Close transaction */
225  fc_els_close ( els, rc );
226 
227  return rc;
228 }
229 
230 /** Fibre Channel ELS exchange interface operations */
232  INTF_OP ( xfer_deliver, struct fc_els *, fc_els_rx ),
233  INTF_OP ( intf_close, struct fc_els *, fc_els_close ),
234 };
235 
236 /** Fibre Channel ELS exchange interface descriptor */
238  INTF_DESC ( struct fc_els, xchg, fc_els_xchg_op );
239 
240 /** Fibre Channel ELS job control interface operations */
242  INTF_OP ( intf_close, struct fc_els *, fc_els_close ),
243 };
244 
245 /** Fibre Channel ELS job control interface descriptor */
247  INTF_DESC ( struct fc_els, job, fc_els_job_op );
248 
249 /**
250  * Fibre Channel ELS process
251  *
252  * @v els Fibre Channel ELS transaction
253  */
254 static void fc_els_step ( struct fc_els *els ) {
255  int xchg_id;
256  int rc;
257 
258  /* Sanity check */
259  assert ( fc_els_is_request ( els ) );
260 
261  /* Create exchange */
262  if ( ( xchg_id = fc_xchg_originate ( &els->xchg, els->port,
263  &els->peer_port_id,
264  FC_TYPE_ELS ) ) < 0 ) {
265  rc = xchg_id;
266  DBGC ( els, FCELS_FMT " could not create exchange: %s\n",
267  FCELS_ARGS ( els ), strerror ( rc ) );
268  fc_els_close ( els, rc );
269  return;
270  }
271 
272  /* Transmit request */
273  if ( ( rc = els->handler->tx ( els ) ) != 0 ) {
274  DBGC ( els, FCELS_FMT " could not transmit request: %s\n",
275  FCELS_ARGS ( els ), strerror ( rc ) );
276  fc_els_close ( els, rc );
277  return;
278  }
279 }
280 
281 /** Fibre Channel ELS process descriptor */
284 
285 /**
286  * Create ELS transaction
287  *
288  * @v port Fibre Channel port
289  * @v port_id Local port ID
290  * @v peer_port_id Peer port ID
291  * @ret els Fibre Channel ELS transaction, or NULL
292  */
293 static struct fc_els * fc_els_create ( struct fc_port *port,
294  struct fc_port_id *port_id,
295  struct fc_port_id *peer_port_id ) {
296  struct fc_els *els;
297 
298  /* Allocate and initialise structure */
299  els = zalloc ( sizeof ( *els ) );
300  if ( ! els )
301  return NULL;
302  ref_init ( &els->refcnt, fc_els_free );
303  intf_init ( &els->job, &fc_els_job_desc, &els->refcnt );
304  intf_init ( &els->xchg, &fc_els_xchg_desc, &els->refcnt );
306  &els->refcnt );
307  els->port = fc_port_get ( port );
308  memcpy ( &els->port_id, port_id, sizeof ( els->port_id ) );
310  sizeof ( els->peer_port_id ) );
311  return els;
312 }
313 
314 /**
315  * Create ELS request
316  *
317  * @v job Parent job-control interface
318  * @v port Fibre Channel port
319  * @v peer_port_id Peer port ID
320  * @v handler ELS handler
321  * @ret rc Return status code
322  */
323 int fc_els_request ( struct interface *job, struct fc_port *port,
324  struct fc_port_id *peer_port_id,
325  struct fc_els_handler *handler ) {
326  struct fc_els *els;
327 
328  /* Allocate and initialise structure */
329  els = fc_els_create ( port, &port->port_id, peer_port_id );
330  if ( ! els )
331  return -ENOMEM;
332  els->handler = handler;
333  els->flags = FC_ELS_REQUEST;
334  process_add ( &els->process );
335 
336  /* Attach to parent job interface, mortalise self, and return */
337  intf_plug_plug ( &els->job, job );
338  ref_put ( &els->refcnt );
339  return 0;
340 }
341 
342 /**
343  * Create ELS response
344  *
345  * @v xchg Exchange interface
346  * @v port Fibre Channel port
347  * @v port_id Local port ID
348  * @v peer_port_id Peer port ID
349  * @ret rc Return status code
350  */
351 static int fc_els_respond ( struct interface *xchg, struct fc_port *port,
352  struct fc_port_id *port_id,
353  struct fc_port_id *peer_port_id ) {
354  struct fc_els *els;
355 
356  /* Allocate and initialise structure */
358  if ( ! els )
359  return -ENOMEM;
360 
361  /* Attach to exchange interface, mortalise self, and return */
362  intf_plug_plug ( &els->xchg, xchg );
363  ref_put ( &els->refcnt );
364  return 0;
365 }
366 
367 /** Fibre Channel ELS responder */
368 struct fc_responder fc_els_responder __fc_responder = {
369  .type = FC_TYPE_ELS,
370  .respond = fc_els_respond,
371 };
372 
373 /******************************************************************************
374  *
375  * Unknown ELS handler
376  *
377  ******************************************************************************
378  */
379 
380 /**
381  * Transmit unknown ELS request
382  *
383  * @v els Fibre Channel ELS transaction
384  * @ret rc Return status code
385  */
386 static int fc_els_unknown_tx ( struct fc_els *els __unused ) {
387  return -ENOTSUP;
388 }
389 
390 /**
391  * Transmit unknown ELS response
392  *
393  * @v els Fibre Channel ELS transaction
394  * @ret rc Return status code
395  */
396 static int fc_els_unknown_tx_response ( struct fc_els *els ) {
397  struct fc_ls_rjt_frame ls_rjt;
398 
399  /* Construct LS_RJT */
400  memset ( &ls_rjt, 0, sizeof ( ls_rjt ) );
401  ls_rjt.command = FC_ELS_LS_RJT;
403 
404  /* Transmit LS_RJT */
405  return fc_els_tx ( els, &ls_rjt, sizeof ( ls_rjt ) );
406 }
407 
408 /**
409  * Receive unknown ELS
410  *
411  * @v els Fibre Channel ELS transaction
412  * @v data ELS frame
413  * @v len Length of ELS frame
414  * @ret rc Return status code
415  */
416 static int fc_els_unknown_rx ( struct fc_els *els, void *data, size_t len ) {
417  int rc;
418 
419  DBGC ( els, FCELS_FMT ":\n", FCELS_ARGS ( els ) );
420  DBGC_HDA ( els, 0, data, len );
421 
422  /* Transmit response, if applicable */
423  if ( ! fc_els_is_request ( els ) ) {
424  if ( ( rc = fc_els_unknown_tx_response ( els ) ) != 0 )
425  return rc;
426  }
427 
428  return 0;
429 }
430 
431 /**
432  * Detect unknown ELS
433  *
434  * @v els Fibre Channel ELS transaction
435  * @v data ELS frame
436  * @v len Length of ELS frame
437  * @ret rc Return status code
438  */
439 static int fc_els_unknown_detect ( struct fc_els *els __unused,
440  const void *data __unused,
441  size_t len __unused ) {
442  return -ENOTSUP;
443 }
444 
445 /** Unknown ELS handler */
446 struct fc_els_handler fc_els_unknown_handler __fc_els_handler = {
447  .name = "UNKNOWN",
448  .tx = fc_els_unknown_tx,
449  .rx = fc_els_unknown_rx,
450  .detect = fc_els_unknown_detect,
451 };
452 
453 /******************************************************************************
454  *
455  * FLOGI
456  *
457  ******************************************************************************
458  */
459 
460 /**
461  * Transmit FLOGI
462  *
463  * @v els Fibre Channel ELS transaction
464  * @ret rc Return status code
465  */
466 static int fc_els_flogi_tx ( struct fc_els *els ) {
467  struct fc_login_frame flogi;
468 
469  /* Construct FLOGI */
470  memset ( &flogi, 0, sizeof ( flogi ) );
471  flogi.command = fc_els_tx_command ( els, FC_ELS_FLOGI );
472  flogi.common.version = htons ( FC_LOGIN_VERSION );
475  flogi.common.mtu = htons ( FC_LOGIN_DEFAULT_MTU );
476  memcpy ( &flogi.port_wwn, &els->port->port_wwn,
477  sizeof ( flogi.port_wwn ) );
478  memcpy ( &flogi.node_wwn, &els->port->node_wwn,
479  sizeof ( flogi.node_wwn ) );
482 
483  /* Transmit FLOGI */
484  return fc_els_tx ( els, &flogi, sizeof ( flogi ) );
485 }
486 
487 /**
488  * Receive FLOGI
489  *
490  * @v els Fibre Channel ELS transaction
491  * @v data ELS frame
492  * @v len Length of ELS frame
493  * @ret rc Return status code
494  */
495 static int fc_els_flogi_rx ( struct fc_els *els, void *data, size_t len ) {
496  struct fc_login_frame *flogi = data;
497  int has_fabric;
498  int rc;
499 
500  /* Sanity check */
501  if ( len < sizeof ( *flogi ) ) {
502  DBGC ( els, FCELS_FMT " received underlength frame:\n",
503  FCELS_ARGS ( els ) );
504  DBGC_HDA ( els, 0, data, len );
505  return -EINVAL;
506  }
507 
508  /* Extract parameters */
509  has_fabric = ( flogi->common.flags & htons ( FC_LOGIN_F_PORT ) );
510  DBGC ( els, FCELS_FMT " has node %s\n", FCELS_ARGS ( els ),
511  fc_ntoa ( &flogi->node_wwn ) );
512  DBGC ( els, FCELS_FMT " has port %s\n", FCELS_ARGS ( els ),
513  fc_ntoa ( &flogi->port_wwn ) );
514  if ( has_fabric ) {
515  DBGC ( els, FCELS_FMT " has fabric with", FCELS_ARGS ( els ) );
516  DBGC ( els, " local ID %s\n", fc_id_ntoa ( &els->port_id ) );
517  } else {
518  DBGC ( els, FCELS_FMT " has point-to-point link\n",
519  FCELS_ARGS ( els ) );
520  }
521 
522  /* Log in port */
523  if ( ( rc = fc_port_login ( els->port, &els->port_id, &flogi->node_wwn,
524  &flogi->port_wwn, has_fabric ) ) != 0 ) {
525  DBGC ( els, FCELS_FMT " could not log in port: %s\n",
526  FCELS_ARGS ( els ), strerror ( rc ) );
527  return rc;
528  }
529 
530  /* Send any responses to the newly-assigned peer port ID, if
531  * applicable.
532  */
533  if ( ! has_fabric ) {
534  memcpy ( &els->peer_port_id, &els->port->ptp_link_port_id,
535  sizeof ( els->peer_port_id ) );
536  }
537 
538  /* Transmit response, if applicable */
539  if ( ! fc_els_is_request ( els ) ) {
540  if ( ( rc = fc_els_flogi_tx ( els ) ) != 0 )
541  return rc;
542  }
543 
544  return 0;
545 }
546 
547 /**
548  * Detect FLOGI
549  *
550  * @v els Fibre Channel ELS transaction
551  * @v data ELS frame
552  * @v len Length of ELS frame
553  * @ret rc Return status code
554  */
555 static int fc_els_flogi_detect ( struct fc_els *els __unused, const void *data,
556  size_t len __unused ) {
557  const struct fc_login_frame *flogi = data;
558 
559  /* Check for FLOGI */
560  if ( flogi->command != FC_ELS_FLOGI )
561  return -EINVAL;
562 
563  return 0;
564 }
565 
566 /** FLOGI ELS handler */
567 struct fc_els_handler fc_els_flogi_handler __fc_els_handler = {
568  .name = "FLOGI",
569  .tx = fc_els_flogi_tx,
570  .rx = fc_els_flogi_rx,
571  .detect = fc_els_flogi_detect,
572 };
573 
574 /**
575  * Create FLOGI request
576  *
577  * @v parent Parent interface
578  * @v port Fibre Channel port
579  * @ret rc Return status code
580  */
581 int fc_els_flogi ( struct interface *parent, struct fc_port *port ) {
582 
583  return fc_els_request ( parent, port, &fc_f_port_id,
584  &fc_els_flogi_handler );
585 }
586 
587 /******************************************************************************
588  *
589  * PLOGI
590  *
591  ******************************************************************************
592  */
593 
594 /**
595  * Transmit PLOGI
596  *
597  * @v els Fibre Channel ELS transaction
598  * @ret rc Return status code
599  */
600 static int fc_els_plogi_tx ( struct fc_els *els ) {
601  struct fc_login_frame plogi;
602 
603  /* Construct PLOGI */
604  memset ( &plogi, 0, sizeof ( plogi ) );
605  plogi.command = fc_els_tx_command ( els, FC_ELS_PLOGI );
606  plogi.common.version = htons ( FC_LOGIN_VERSION );
609  plogi.common.mtu = htons ( FC_LOGIN_DEFAULT_MTU );
610  plogi.common.u.plogi.max_seq = htons ( FC_LOGIN_DEFAULT_MAX_SEQ );
611  plogi.common.u.plogi.rel_offs = htons ( FC_LOGIN_DEFAULT_REL_OFFS );
613  memcpy ( &plogi.port_wwn, &els->port->port_wwn,
614  sizeof ( plogi.port_wwn ) );
615  memcpy ( &plogi.node_wwn, &els->port->node_wwn,
616  sizeof ( plogi.node_wwn ) );
619  plogi.class3.mtu = htons ( FC_LOGIN_DEFAULT_MTU );
621  plogi.class3.max_seq_per_xchg = 1;
622 
623  /* Transmit PLOGI */
624  return fc_els_tx ( els, &plogi, sizeof ( plogi ) );
625 }
626 
627 /**
628  * Receive PLOGI
629  *
630  * @v els Fibre Channel ELS transaction
631  * @v data ELS frame
632  * @v len Length of ELS frame
633  * @ret rc Return status code
634  */
635 static int fc_els_plogi_rx ( struct fc_els *els, void *data, size_t len ) {
636  struct fc_login_frame *plogi = data;
637  struct fc_peer *peer;
638  int rc;
639 
640  /* Sanity checks */
641  if ( len < sizeof ( *plogi ) ) {
642  DBGC ( els, FCELS_FMT " received underlength frame:\n",
643  FCELS_ARGS ( els ) );
644  DBGC_HDA ( els, 0, data, len );
645  rc = -EINVAL;
646  goto err_sanity;
647  }
648  if ( ! fc_link_ok ( &els->port->link ) ) {
649  DBGC ( els, FCELS_FMT " received while port link is down\n",
650  FCELS_ARGS ( els ) );
651  rc = -EINVAL;
652  goto err_sanity;
653  }
654 
655  /* Extract parameters */
656  DBGC ( els, FCELS_FMT " has node %s\n", FCELS_ARGS ( els ),
657  fc_ntoa ( &plogi->node_wwn ) );
658  DBGC ( els, FCELS_FMT " has port %s as %s\n",
659  FCELS_ARGS ( els ), fc_ntoa ( &plogi->port_wwn ),
660  fc_id_ntoa ( &els->peer_port_id ) );
661 
662  /* Get peer */
663  peer = fc_peer_get_wwn ( &plogi->port_wwn );
664  if ( ! peer ) {
665  DBGC ( els, FCELS_FMT " could not create peer\n",
666  FCELS_ARGS ( els ) );
667  rc = -ENOMEM;
668  goto err_peer_get_wwn;
669  }
670 
671  /* Record login */
672  if ( ( rc = fc_peer_login ( peer, els->port,
673  &els->peer_port_id ) ) != 0 ) {
674  DBGC ( els, FCELS_FMT " could not log in peer: %s\n",
675  FCELS_ARGS ( els ), strerror ( rc ) );
676  goto err_login;
677  }
678 
679  /* Transmit response, if applicable */
680  if ( ! fc_els_is_request ( els ) ) {
681  if ( ( rc = fc_els_plogi_tx ( els ) ) != 0 )
682  goto err_plogi_tx;
683  }
684 
685  /* Drop temporary reference to peer */
686  fc_peer_put ( peer );
687 
688  return 0;
689 
690  err_plogi_tx:
691  err_login:
692  fc_peer_put ( peer );
693  err_peer_get_wwn:
694  err_sanity:
695  return rc;
696 }
697 
698 /**
699  * Detect PLOGI
700  *
701  * @v els Fibre Channel ELS transaction
702  * @v data ELS frame
703  * @v len Length of ELS frame
704  * @ret rc Return status code
705  */
706 static int fc_els_plogi_detect ( struct fc_els *els __unused, const void *data,
707  size_t len __unused ) {
708  const struct fc_login_frame *plogi = data;
709 
710  /* Check for PLOGI */
711  if ( plogi->command != FC_ELS_PLOGI )
712  return -EINVAL;
713 
714  return 0;
715 }
716 
717 /** PLOGI ELS handler */
718 struct fc_els_handler fc_els_plogi_handler __fc_els_handler = {
719  .name = "PLOGI",
720  .tx = fc_els_plogi_tx,
721  .rx = fc_els_plogi_rx,
722  .detect = fc_els_plogi_detect,
723 };
724 
725 /**
726  * Create PLOGI request
727  *
728  * @v parent Parent interface
729  * @v port Fibre Channel port
730  * @v peer_port_id Peer port ID
731  * @ret rc Return status code
732  */
733 int fc_els_plogi ( struct interface *parent, struct fc_port *port,
734  struct fc_port_id *peer_port_id ) {
735 
736  return fc_els_request ( parent, port, peer_port_id,
737  &fc_els_plogi_handler );
738 }
739 
740 /******************************************************************************
741  *
742  * LOGO
743  *
744  ******************************************************************************
745  */
746 
747 /**
748  * Transmit LOGO request
749  *
750  * @v els Fibre Channel ELS transaction
751  * @ret rc Return status code
752  */
753 static int fc_els_logo_tx ( struct fc_els *els ) {
754  struct fc_logout_request_frame logo;
755 
756  /* Construct LOGO */
757  memset ( &logo, 0, sizeof ( logo ) );
758  logo.command = FC_ELS_LOGO;
759  memcpy ( &logo.port_id, &els->port->port_id, sizeof ( logo.port_id ) );
760  memcpy ( &logo.port_wwn, &els->port->port_wwn,
761  sizeof ( logo.port_wwn ) );
762 
763  /* Transmit LOGO */
764  return fc_els_tx ( els, &logo, sizeof ( logo ) );
765 }
766 
767 /**
768  * Transmit LOGO response
769  *
770  * @v els Fibre Channel ELS transaction
771  * @ret rc Return status code
772  */
773 static int fc_els_logo_tx_response ( struct fc_els *els ) {
774  struct fc_logout_response_frame logo;
775 
776  /* Construct LOGO */
777  memset ( &logo, 0, sizeof ( logo ) );
778  logo.command = FC_ELS_LS_ACC;
779 
780  /* Transmit LOGO */
781  return fc_els_tx ( els, &logo, sizeof ( logo ) );
782 }
783 
784 /**
785  * Log out individual peer or whole port as applicable
786  *
787  * @v els Fibre Channel ELS transaction
788  * @v port_id Peer port ID
789  */
790 static void fc_els_logo_logout ( struct fc_els *els,
791  struct fc_port_id *peer_port_id ) {
792  struct fc_peer *peer;
793 
794  if ( ( memcmp ( peer_port_id, &fc_f_port_id,
795  sizeof ( *peer_port_id ) ) == 0 ) ||
796  ( memcmp ( peer_port_id, &els->port->port_id,
797  sizeof ( *peer_port_id ) ) == 0 ) ) {
798  fc_port_logout ( els->port, 0 );
799  } else {
800  peer = fc_peer_get_port_id ( els->port, peer_port_id );
801  if ( peer ) {
802  fc_peer_logout ( peer, 0 );
803  fc_peer_put ( peer );
804  }
805  }
806 }
807 
808 /**
809  * Receive LOGO request
810  *
811  * @v els Fibre Channel ELS transaction
812  * @v data ELS frame
813  * @v len Length of ELS frame
814  * @ret rc Return status code
815  */
816 static int fc_els_logo_rx_request ( struct fc_els *els, void *data,
817  size_t len ) {
818  struct fc_logout_request_frame *logo = data;
819  int rc;
820 
821  /* Sanity check */
822  if ( len < sizeof ( *logo ) ) {
823  DBGC ( els, FCELS_FMT " received underlength frame:\n",
824  FCELS_ARGS ( els ) );
825  DBGC_HDA ( els, 0, data, len );
826  return -EINVAL;
827  }
828 
829  DBGC ( els, FCELS_FMT " has port %s as %s\n", FCELS_ARGS ( els ),
830  fc_ntoa ( &logo->port_wwn ), fc_id_ntoa ( &logo->port_id ) );
831 
832  /* Log out individual peer or whole port as applicable */
833  fc_els_logo_logout ( els, &logo->port_id );
834 
835  /* Transmit repsonse */
836  if ( ( rc = fc_els_logo_tx_response ( els ) ) != 0 )
837  return rc;
838 
839  return 0;
840 }
841 
842 /**
843  * Receive LOGO response
844  *
845  * @v els Fibre Channel ELS transaction
846  * @v data ELS frame
847  * @v len Length of ELS frame
848  * @ret rc Return status code
849  */
850 static int fc_els_logo_rx_response ( struct fc_els *els, void *data __unused,
851  size_t len __unused ) {
852 
853  /* Log out individual peer or whole port as applicable */
854  fc_els_logo_logout ( els, &els->peer_port_id );
855 
856  return 0;
857 }
858 
859 /**
860  * Receive LOGO
861  *
862  * @v els Fibre Channel ELS transaction
863  * @v data ELS frame
864  * @v len Length of ELS frame
865  * @ret rc Return status code
866  */
867 static int fc_els_logo_rx ( struct fc_els *els, void *data, size_t len ) {
868 
869  if ( fc_els_is_request ( els ) ) {
870  return fc_els_logo_rx_response ( els, data, len );
871  } else {
872  return fc_els_logo_rx_request ( els, data, len );
873  }
874 }
875 
876 /**
877  * Detect LOGO
878  *
879  * @v els Fibre Channel ELS transaction
880  * @v data ELS frame
881  * @v len Length of ELS frame
882  * @ret rc Return status code
883  */
884 static int fc_els_logo_detect ( struct fc_els *els __unused, const void *data,
885  size_t len __unused ) {
886  const struct fc_logout_request_frame *logo = data;
887 
888  /* Check for LOGO */
889  if ( logo->command != FC_ELS_LOGO )
890  return -EINVAL;
891 
892  return 0;
893 }
894 
895 /** LOGO ELS handler */
896 struct fc_els_handler fc_els_logo_handler __fc_els_handler = {
897  .name = "LOGO",
898  .tx = fc_els_logo_tx,
899  .rx = fc_els_logo_rx,
900  .detect = fc_els_logo_detect,
901 };
902 
903 /**
904  * Create LOGO request
905  *
906  * @v parent Parent interface
907  * @v port Fibre Channel port
908  * @v peer_port_id Peer port ID
909  * @ret rc Return status code
910  */
911 int fc_els_logo ( struct interface *parent, struct fc_port *port,
912  struct fc_port_id *peer_port_id ) {
913 
914  return fc_els_request ( parent, port, peer_port_id,
915  &fc_els_logo_handler );
916 }
917 
918 /******************************************************************************
919  *
920  * PRLI
921  *
922  ******************************************************************************
923  */
924 
925 /**
926  * Find PRLI descriptor
927  *
928  * @v type Upper-layer protocol type
929  * @ret descriptor PRLI descriptor, or NULL
930  */
931 static struct fc_els_prli_descriptor *
932 fc_els_prli_descriptor ( unsigned int type ) {
933  struct fc_els_prli_descriptor *descriptor;
934 
936  if ( descriptor->type == type )
937  return descriptor;
938  }
939  return NULL;
940 }
941 
942 /**
943  * Transmit PRLI
944  *
945  * @v els Fibre Channel ELS transaction
946  * @v descriptor ELS PRLI descriptor
947  * @v param Service parameters
948  * @ret rc Return status code
949  */
950 int fc_els_prli_tx ( struct fc_els *els,
951  struct fc_els_prli_descriptor *descriptor, void *param ) {
952  struct {
953  struct fc_prli_frame frame;
954  uint8_t param[descriptor->param_len];
955  } __attribute__ (( packed )) prli;
956  struct fc_ulp *ulp;
957  int rc;
958 
959  /* Get ULP */
960  ulp = fc_ulp_get_port_id_type ( els->port, &els->peer_port_id,
961  descriptor->type );
962  if ( ! ulp ) {
963  rc = -ENOMEM;
964  goto err_get_port_id_type;
965  }
966 
967  /* Build frame for transmission */
968  memset ( &prli, 0, sizeof ( prli ) );
969  prli.frame.command = fc_els_tx_command ( els, FC_ELS_PRLI );
970  prli.frame.page_len =
971  ( sizeof ( prli.frame.page ) + sizeof ( prli.param ) );
972  prli.frame.len = htons ( sizeof ( prli ) );
973  prli.frame.page.type = descriptor->type;
974  if ( fc_els_is_request ( els ) ) {
975  prli.frame.page.flags |= htons ( FC_PRLI_ESTABLISH );
976  } else if ( fc_link_ok ( &ulp->link ) ) {
977  prli.frame.page.flags |= htons ( FC_PRLI_ESTABLISH |
979  }
980  memcpy ( &prli.param, param, sizeof ( prli.param ) );
981 
982  /* Transmit frame */
983  if ( ( rc = fc_els_tx ( els, &prli, sizeof ( prli ) ) ) != 0 )
984  goto err_tx;
985 
986  /* Drop temporary reference to ULP */
987  fc_ulp_put ( ulp );
988 
989  return 0;
990 
991  err_tx:
992  fc_ulp_put ( ulp );
993  err_get_port_id_type:
994  return rc;
995 }
996 
997 /**
998  * Receive PRLI
999  *
1000  * @v els Fibre Channel ELS transaction
1001  * @v descriptor ELS PRLI descriptor
1002  * @v frame ELS frame
1003  * @v len Length of ELS frame
1004  * @ret rc Return status code
1005  */
1006 int fc_els_prli_rx ( struct fc_els *els,
1007  struct fc_els_prli_descriptor *descriptor,
1008  void *data, size_t len ) {
1009  struct {
1010  struct fc_prli_frame frame;
1011  uint8_t param[descriptor->param_len];
1012  } __attribute__ (( packed )) *prli = data;
1013  struct fc_ulp *ulp;
1014  int rc;
1015 
1016  /* Sanity check */
1017  if ( len < sizeof ( *prli ) ) {
1018  DBGC ( els, FCELS_FMT " received underlength frame:\n",
1019  FCELS_ARGS ( els ) );
1020  DBGC_HDA ( els, 0, data, len );
1021  rc = -EINVAL;
1022  goto err_sanity;
1023  }
1024 
1025  DBGC ( els, FCELS_FMT " has parameters:\n", FCELS_ARGS ( els ) );
1026  DBGC_HDA ( els, 0, prli->param, sizeof ( prli->param ) );
1027 
1028  /* Get ULP */
1029  ulp = fc_ulp_get_port_id_type ( els->port, &els->peer_port_id,
1030  descriptor->type );
1031  if ( ! ulp ) {
1032  rc = -ENOMEM;
1033  goto err_get_port_id_type;
1034  }
1035 
1036  /* Sanity check */
1037  if ( ! fc_link_ok ( &ulp->peer->link ) ) {
1038  DBGC ( els, FCELS_FMT " received while peer link is down\n",
1039  FCELS_ARGS ( els ) );
1040  rc = -EINVAL;
1041  goto err_link;
1042  }
1043 
1044  /* Log in ULP, if applicable */
1045  if ( prli->frame.page.flags & htons ( FC_PRLI_ESTABLISH ) ) {
1046  if ( ( rc = fc_ulp_login ( ulp, prli->param,
1047  sizeof ( prli->param ),
1048  fc_els_is_request ( els ) ) ) != 0 ){
1049  DBGC ( els, FCELS_FMT " could not log in ULP: %s\n",
1050  FCELS_ARGS ( els ), strerror ( rc ) );
1051  goto err_login;
1052  }
1053  } else {
1054  if ( fc_els_is_request ( els ) ) {
1055  fc_ulp_logout ( ulp, -EACCES );
1056  } else {
1057  /* This is just an information-gathering PRLI; do not
1058  * log in or out
1059  */
1060  }
1061  }
1062 
1063  /* Transmit response, if applicable */
1064  if ( ! fc_els_is_request ( els ) ) {
1065  if ( ( rc = els->handler->tx ( els ) ) != 0 )
1066  goto err_tx;
1067  }
1068 
1069  /* Drop temporary reference to ULP */
1070  fc_ulp_put ( ulp );
1071 
1072  return 0;
1073 
1074  err_tx:
1075  err_login:
1076  err_link:
1077  fc_ulp_put ( ulp );
1078  err_get_port_id_type:
1079  err_sanity:
1080  return rc;
1081 }
1082 
1083 /**
1084  * Detect PRLI
1085  *
1086  * @v els Fibre Channel ELS transaction
1087  * @v descriptor ELS PRLI descriptor
1088  * @v data ELS frame
1089  * @v len Length of ELS frame
1090  * @ret rc Return status code
1091  */
1093  struct fc_els_prli_descriptor *descriptor,
1094  const void *data, size_t len ) {
1095  const struct {
1096  struct fc_prli_frame frame;
1097  uint8_t param[descriptor->param_len];
1098  } __attribute__ (( packed )) *prli = data;
1099 
1100  /* Check for PRLI */
1101  if ( prli->frame.command != FC_ELS_PRLI )
1102  return -EINVAL;
1103 
1104  /* Check for sufficient length to contain service parameter page */
1105  if ( len < sizeof ( *prli ) )
1106  return -EINVAL;
1107 
1108  /* Check for upper-layer protocol type */
1109  if ( prli->frame.page.type != descriptor->type )
1110  return -EINVAL;
1111 
1112  return 0;
1113 }
1114 
1115 /**
1116  * Create PRLI request
1117  *
1118  * @v parent Parent interface
1119  * @v port Fibre Channel port
1120  * @v peer_port_id Peer port ID
1121  * @v type Upper-layer protocol type
1122  * @ret rc Return status code
1123  */
1124 int fc_els_prli ( struct interface *parent, struct fc_port *port,
1125  struct fc_port_id *peer_port_id, unsigned int type ) {
1126  struct fc_els_prli_descriptor *descriptor;
1127 
1128  /* Find a PRLI descriptor */
1129  descriptor = fc_els_prli_descriptor ( type );
1130  if ( ! descriptor )
1131  return -ENOTSUP;
1132 
1133  return fc_els_request ( parent, port, peer_port_id,
1134  descriptor->handler );
1135 }
1136 
1137 /******************************************************************************
1138  *
1139  * RTV
1140  *
1141  ******************************************************************************
1142  */
1143 
1144 /**
1145  * Transmit RTV response
1146  *
1147  * @v els Fibre Channel ELS transaction
1148  * @ret rc Return status code
1149  */
1150 static int fc_els_rtv_tx_response ( struct fc_els *els ) {
1151  struct fc_rtv_response_frame rtv;
1152 
1153  /* Construct RTV */
1154  memset ( &rtv, 0, sizeof ( rtv ) );
1155  rtv.command = FC_ELS_LS_ACC;
1157 
1158  /* Transmit RTV */
1159  return fc_els_tx ( els, &rtv, sizeof ( rtv ) );
1160 }
1161 
1162 /**
1163  * Receive RTV
1164  *
1165  * @v els Fibre Channel ELS transaction
1166  * @v data ELS frame
1167  * @v len Length of ELS frame
1168  * @ret rc Return status code
1169  */
1170 static int fc_els_rtv_rx ( struct fc_els *els, void *data __unused,
1171  size_t len __unused ) {
1172  int rc;
1173 
1174  DBGC ( els, FCELS_FMT "\n", FCELS_ARGS ( els ) );
1175 
1176  /* Transmit response */
1177  if ( ! fc_els_is_request ( els ) ) {
1178  if ( ( rc = fc_els_rtv_tx_response ( els ) ) != 0 )
1179  return rc;
1180  }
1181 
1182  return 0;
1183 }
1184 
1185 /**
1186  * Detect RTV
1187  *
1188  * @v els Fibre Channel ELS transaction
1189  * @v data ELS frame
1190  * @v len Length of ELS frame
1191  * @ret rc Return status code
1192  */
1193 static int fc_els_rtv_detect ( struct fc_els *els __unused, const void *data,
1194  size_t len __unused ) {
1195  const struct fc_rtv_request_frame *rtv = data;
1196 
1197  /* Check for RTV */
1198  if ( rtv->command != FC_ELS_RTV )
1199  return -EINVAL;
1200 
1201  return 0;
1202 }
1203 
1204 /** RTV ELS handler */
1205 struct fc_els_handler fc_els_rtv_handler __fc_els_handler = {
1206  .name = "RTV",
1207  .tx = fc_els_unknown_tx,
1208  .rx = fc_els_rtv_rx,
1209  .detect = fc_els_rtv_detect,
1210 };
1211 
1212 /******************************************************************************
1213  *
1214  * ECHO
1215  *
1216  ******************************************************************************
1217  */
1218 
1219 /** ECHO request data */
1221  /** ECHO frame header */
1223  /** Magic marker */
1225 } __attribute__ (( packed ));
1226 
1227 /** ECHO magic marker */
1228 #define FC_ECHO_MAGIC 0x69505845
1229 
1230 /**
1231  * Transmit ECHO
1232  *
1233  * @v els Fibre Channel ELS transaction
1234  * @ret rc Return status code
1235  */
1236 static int fc_els_echo_tx ( struct fc_els *els ) {
1237  struct fc_echo_request_frame echo;
1238 
1239  /* Construct ECHO */
1240  memset ( &echo, 0, sizeof ( echo ) );
1241  echo.echo.command = FC_ELS_ECHO;
1242  echo.magic = htonl ( FC_ECHO_MAGIC );
1243 
1244  /* Transmit ECHO */
1245  return fc_els_tx ( els, &echo, sizeof ( echo ) );
1246 }
1247 
1248 /**
1249  * Receive ECHO request
1250  *
1251  * @v els Fibre Channel ELS transaction
1252  * @v data ELS frame
1253  * @v len Length of ELS frame
1254  * @ret rc Return status code
1255  */
1256 static int fc_els_echo_rx_request ( struct fc_els *els, void *data,
1257  size_t len ) {
1258  struct {
1259  struct fc_echo_frame_header echo;
1260  char payload[ len - sizeof ( struct fc_echo_frame_header ) ];
1261  } *echo = data;
1262  int rc;
1263 
1264  DBGC ( els, FCELS_FMT "\n", FCELS_ARGS ( els ) );
1265 
1266  /* Transmit response */
1267  echo->echo.command = FC_ELS_LS_ACC;
1268  if ( ( rc = fc_els_tx ( els, echo, sizeof ( *echo ) ) ) != 0 )
1269  return rc;
1270 
1271  /* Nothing to do */
1272  return 0;
1273 }
1274 
1275 /**
1276  * Receive ECHO response
1277  *
1278  * @v els Fibre Channel ELS transaction
1279  * @v data ELS frame
1280  * @v len Length of ELS frame
1281  * @ret rc Return status code
1282  */
1283 static int fc_els_echo_rx_response ( struct fc_els *els, void *data,
1284  size_t len ) {
1285  struct fc_echo_request_frame *echo = data;
1286 
1287  DBGC ( els, FCELS_FMT "\n", FCELS_ARGS ( els ) );
1288 
1289  /* Check response is correct */
1290  if ( ( len != sizeof ( *echo ) ) ||
1291  ( echo->magic != htonl ( FC_ECHO_MAGIC ) ) ) {
1292  DBGC ( els, FCELS_FMT " received bad echo response\n",
1293  FCELS_ARGS ( els ) );
1294  DBGC_HDA ( els, 0, data, len );
1295  return -EIO;
1296  }
1297 
1298  return 0;
1299 }
1300 
1301 /**
1302  * Receive ECHO
1303  *
1304  * @v els Fibre Channel ELS transaction
1305  * @v data ELS frame
1306  * @v len Length of ELS frame
1307  * @ret rc Return status code
1308  */
1309 static int fc_els_echo_rx ( struct fc_els *els, void *data, size_t len ) {
1310 
1311  if ( fc_els_is_request ( els ) ) {
1312  return fc_els_echo_rx_response ( els, data, len );
1313  } else {
1314  return fc_els_echo_rx_request ( els, data, len );
1315  }
1316 }
1317 
1318 /**
1319  * Detect ECHO
1320  *
1321  * @v els Fibre Channel ELS transaction
1322  * @v data ELS frame
1323  * @v len Length of ELS frame
1324  * @ret rc Return status code
1325  */
1326 static int fc_els_echo_detect ( struct fc_els *els __unused, const void *data,
1327  size_t len __unused ) {
1328  const struct fc_echo_frame_header *echo = data;
1329 
1330  /* Check for ECHO */
1331  if ( echo->command != FC_ELS_ECHO )
1332  return -EINVAL;
1333 
1334  return 0;
1335 }
1336 
1337 /** ECHO ELS handler */
1338 struct fc_els_handler fc_els_echo_handler __fc_els_handler = {
1339  .name = "ECHO",
1340  .tx = fc_els_echo_tx,
1341  .rx = fc_els_echo_rx,
1342  .detect = fc_els_echo_detect,
1343 };
#define FC_LOGIN_DEFAULT_REL_OFFS
Default relative offset by info category.
Definition: fcels.h:174
A process.
Definition: process.h:17
#define __attribute__(x)
Definition: compiler.h:10
int fc_els_request(struct interface *job, struct fc_port *port, struct fc_port_id *peer_port_id, struct fc_els_handler *handler)
Create ELS request.
Definition: fcels.c:323
#define FC_LOGIN_DEFAULT_E_D_TOV
Default E_D timeout value.
Definition: fcels.h:177
#define EINVAL
Invalid argument.
Definition: errno.h:428
An object interface operation.
Definition: interface.h:17
#define FC_LOGIN_CONTINUOUS_OFFSET
Continuously increasing relative offset.
Definition: fcels.h:108
Fibre Channel ELS frame common parameters.
Definition: fcels.h:22
struct fc_name port_wwn
Port name.
Definition: fc.h:265
Echo.
Definition: fcels.h:37
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
void intf_close(struct interface *intf, int rc)
Close an object interface.
Definition: interface.c:249
static int fc_els_plogi_tx(struct fc_els *els)
Transmit PLOGI.
Definition: fcels.c:600
static int fc_els_echo_rx(struct fc_els *els, void *data, size_t len)
Receive ECHO.
Definition: fcels.c:1309
struct fc_login_common::@548::@549 plogi
uint16_t mtu
Receive size.
Definition: fcels.h:83
Data transfer metadata.
Definition: xfer.h:22
void intf_shutdown(struct interface *intf, int rc)
Shut down an object interface.
Definition: interface.c:278
int fc_xchg_originate(struct interface *parent, struct fc_port *port, struct fc_port_id *peer_port_id, unsigned int type)
Originate a new Fibre Channel exchange.
Definition: fc.c:728
static int fc_els_respond(struct interface *xchg, struct fc_port *port, struct fc_port_id *port_id, struct fc_port_id *peer_port_id)
Create ELS response.
Definition: fcels.c:351
uint16_t version
Login version.
Definition: fcels.h:77
static struct fc_els_prli_descriptor * fc_els_prli_descriptor(unsigned int type)
Find PRLI descriptor.
Definition: fcels.c:932
size_t param_len
Service parameter length.
Definition: fcels.h:390
struct fc_login_common common
Common service parameters.
Definition: fcels.h:214
struct fc_responder fc_els_responder __fc_responder
Fibre Channel ELS responder.
Definition: fcels.c:368
Logout.
Definition: fcels.h:35
static int fc_els_rtv_tx_response(struct fc_els *els)
Transmit RTV response.
Definition: fcels.c:1150
int(* tx)(struct fc_els *els)
Transmit ELS frame.
Definition: fcels.h:360
int xfer_deliver_raw_meta(struct interface *intf, const void *data, size_t len, struct xfer_metadata *meta)
Deliver datagram as raw data.
Definition: xfer.c:268
struct fc_port_id ptp_link_port_id
Link port ID (for point-to-point links only)
Definition: fc.h:280
Fabric Login.
Definition: fcels.h:34
A Fibre Channel ECHO frame.
Definition: fcels.h:315
const char * fc_id_ntoa(const struct fc_port_id *id)
Format Fibre Channel port ID.
Definition: fc.c:92
A Fibre Channel RTV response frame.
Definition: fcels.h:293
#define ref_init(refcnt, free)
Initialise a reference counter.
Definition: refcnt.h:64
Error codes.
Link Service Reject.
Definition: fcels.h:31
static int fc_els_logo_detect(struct fc_els *els __unused, const void *data, size_t len __unused)
Detect LOGO.
Definition: fcels.c:884
struct fc_echo_frame_header echo
ECHO frame header.
Definition: fcels.c:1222
A Fibre Channel RTV request frame.
Definition: fcels.h:285
A Fibre Channel extended link services handler.
Definition: fcels.h:352
I/O buffers.
unsigned int type
Type.
Definition: fc.h:224
void free_iob(struct io_buffer *iobuf)
Free I/O buffer.
Definition: iobuf.c:146
struct fc_peer * fc_peer_get_wwn(const struct fc_name *port_wwn)
Get Fibre Channel peer by node name.
Definition: fc.c:1516
static void const void * src
Definition: crypto.h:244
A Fibre Channel responder.
Definition: fc.h:222
struct fc_port_id fc_f_port_id
F_Port contoller port ID.
Definition: fc.c:68
uint16_t flags
Flags.
Definition: fcels.h:182
static int fc_els_logo_rx_request(struct fc_els *els, void *data, size_t len)
Receive LOGO request.
Definition: fcels.c:816
#define DBGC(...)
Definition: compiler.h:505
struct fc_name node_wwn
Node name.
Definition: fc.h:263
uint32_t e_d_tov
Error detection timeout value.
Definition: fcels.h:301
struct fc_els_handler * handler
ELS handler, if known.
Definition: fcels.h:340
A process descriptor.
Definition: process.h:31
static int fc_els_plogi_detect(struct fc_els *els __unused, const void *data, size_t len __unused)
Detect PLOGI.
Definition: fcels.c:706
int fc_port_login(struct fc_port *port, struct fc_port_id *port_id, const struct fc_name *link_node_wwn, const struct fc_name *link_port_wwn, int has_fabric)
Log in Fibre Channel port.
Definition: fc.c:941
static int fc_els_unknown_tx_response(struct fc_els *els)
Transmit unknown ELS response.
Definition: fcels.c:396
Fibre Channel socket address.
Definition: fc.h:47
void intf_plug_plug(struct interface *a, struct interface *b)
Plug two object interfaces together.
Definition: interface.c:107
#define FC_LOGIN_CLASS_SEQUENTIAL
Sequential delivery requested.
Definition: fcels.h:205
#define FC_ECHO_MAGIC
ECHO magic marker.
Definition: fcels.c:1228
static int fc_els_flogi_tx(struct fc_els *els)
Transmit FLOGI.
Definition: fcels.c:466
static void fc_port_put(struct fc_port *port)
Drop reference to Fibre Channel port.
Definition: fc.h:315
#define EACCES
Permission denied.
Definition: errno.h:298
#define FC_ELS_PRLI_DESCRIPTORS
Fibre Channel ELS PRLI descriptor table.
Definition: fcels.h:396
struct fc_els_handler * handler
Fibre Channel ELS handler.
Definition: fcels.h:392
const char * fc_ntoa(const struct fc_name *wwn)
Format Fibre Channel WWN.
Definition: fc.c:127
#define PROC_DESC_ONCE(object_type, process, _step)
Define a process descriptor for a process that runs only once.
Definition: process.h:97
uint8_t command
ELS command code.
Definition: fcels.h:246
int fc_els_plogi(struct interface *parent, struct fc_port *port, struct fc_port_id *peer_port_id)
Create PLOGI request.
Definition: fcels.c:733
union fc_login_common::@548 u
"Common"?!
#define FCELS_FMT
Fibre Channel ELS transaction debug message format.
Definition: fcels.c:46
struct fc_port_id peer_port_id
Peer port ID.
Definition: fcels.h:338
static struct interface_operation fc_els_xchg_op[]
Fibre Channel ELS exchange interface operations.
Definition: fcels.c:231
static int fc_els_unknown_rx(struct fc_els *els, void *data, size_t len)
Receive unknown ELS.
Definition: fcels.c:416
struct fc_peer * peer
Fibre Channel peer.
Definition: fc.h:417
A Fibre Channel port.
Definition: fc.h:252
void process_del(struct process *process)
Remove process from process list.
Definition: process.c:79
#define htonl(value)
Definition: byteswap.h:133
uint8_t reason
Reason code.
Definition: fcels.h:49
static void fc_els_close(struct fc_els *els, int rc)
Close Fibre Channel ELS transaction.
Definition: fcels.c:76
#define ENOTSUP
Operation not supported.
Definition: errno.h:589
static struct fc_els_handler * fc_els_detect(struct fc_els *els, const void *data, size_t len)
Detect Fibre Channel ELS frame handler.
Definition: fcels.c:98
static int fc_els_logo_rx(struct fc_els *els, void *data, size_t len)
Receive LOGO.
Definition: fcels.c:867
Data transfer interfaces.
A reference counter.
Definition: refcnt.h:26
struct fc_port_id port_id
Local port ID.
Definition: fc.h:267
static int fc_els_unknown_detect(struct fc_els *els __unused, const void *data __unused, size_t len __unused)
Detect unknown ELS.
Definition: fcels.c:439
Extended Link Service.
Definition: fc.h:192
int fc_els_tx(struct fc_els *els, const void *data, size_t len)
Transmit Fibre Channel ELS frame.
Definition: fcels.c:126
#define XFER_FL_RESPONSE
Data content is a response.
Definition: xfer.h:63
int fc_els_prli_detect(struct fc_els *els __unused, struct fc_els_prli_descriptor *descriptor, const void *data, size_t len)
Detect PRLI.
Definition: fcels.c:1092
unsigned long frame
Definition: xengrant.h:179
int fc_els_prli_tx(struct fc_els *els, struct fc_els_prli_descriptor *descriptor, void *param)
Transmit PRLI.
Definition: fcels.c:950
int fc_peer_login(struct fc_peer *peer, struct fc_port *port, struct fc_port_id *port_id)
Log in Fibre Channel peer.
Definition: fc.c:1300
ECHO request data.
Definition: fcels.c:1220
#define ENOMEM
Not enough space.
Definition: errno.h:534
int(* detect)(struct fc_els *els, const void *data, size_t len)
Detect ELS frame.
Definition: fcels.h:376
void * memcpy(void *dest, const void *src, size_t len) __nonnull
uint8_t command
ELS command code.
Definition: fcels.h:295
A Fibre Channel PRLI frame.
Definition: fcels.h:273
Read Timeout Value.
Definition: fcels.h:36
static int fc_els_echo_rx_request(struct fc_els *els, void *data, size_t len)
Receive ECHO request.
Definition: fcels.c:1256
u8 port
Port number.
Definition: CIB_PRM.h:31
int fc_els_flogi(struct interface *parent, struct fc_port *port)
Create FLOGI request.
Definition: fcels.c:581
const char * name
Name.
Definition: fcels.h:354
uint8_t command
ELS command code.
Definition: fcels.h:287
Assertions.
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
#define container_of(ptr, type, field)
Get containing structure.
Definition: stddef.h:35
An object interface.
Definition: interface.h:124
A Fibre Channel port identifier.
Definition: fc.h:37
struct interface xchg
Fibre Channel exchange.
Definition: fcels.h:329
#define FC_LOGIN_F_PORT
Forwarder port.
Definition: fcels.h:129
#define DBGC_HDA(...)
Definition: compiler.h:506
Object interfaces.
static int fc_link_ok(struct fc_link_state *link)
Check Fibre Channel link state.
Definition: fc.h:108
struct fc_link_state link
Link state monitor.
Definition: fc.h:350
Command not supported.
Definition: fcels.h:69
uint8_t max_seq_per_xchg
Maximum number of open sequences per exchange.
Definition: fcels.h:196
struct sockaddr * fc_fill_sockaddr(struct sockaddr_fc *sa_fc, struct fc_port_id *id)
Fill Fibre Channel socket address.
Definition: fc.c:165
ELS transaction is a request.
Definition: fcels.h:348
int fc_els_prli(struct interface *parent, struct fc_port *port, struct fc_port_id *peer_port_id, unsigned int type)
Create PRLI request.
Definition: fcels.c:1124
#define FC_PRLI_ESTABLISH
Establish image pair.
Definition: fcels.h:264
struct fc_port_id port_id
Port ID.
Definition: fcels.h:238
struct interface prli
PRLI interface.
Definition: fc.h:429
Link Service Accept.
Definition: fcels.h:32
struct refcnt refcnt
Reference count.
Definition: fcels.h:325
static void * dest
Definition: strings.h:176
struct fc_login_class class3
Class 3 service parameters.
Definition: fcels.h:224
uint8_t command
ELS command code.
Definition: fcels.h:210
void process_add(struct process *process)
Add process to process list.
Definition: process.c:59
int meta(WINDOW *, bool)
#define DBGC2_HDA(...)
Definition: compiler.h:523
An object interface descriptor.
Definition: interface.h:55
A Fibre Channel extended link services transaction.
Definition: fcels.h:323
static int fc_els_unknown_tx(struct fc_els *els __unused)
Transmit unknown ELS request.
Definition: fcels.c:386
char * strerror(int errno)
Retrieve string representation of error number.
Definition: strerror.c:78
struct fc_peer * fc_peer_get_port_id(struct fc_port *port, const struct fc_port_id *peer_port_id)
Get Fibre Channel peer by port ID.
Definition: fc.c:1541
static void(* free)(struct refcnt *refcnt))
Definition: refcnt.h:54
static void fc_peer_put(struct fc_peer *peer)
Drop reference to Fibre Channel peer.
Definition: fc.h:390
static int fc_els_flogi_detect(struct fc_els *els __unused, const void *data, size_t len __unused)
Detect FLOGI.
Definition: fcels.c:555
static struct process_descriptor fc_els_process_desc
Fibre Channel ELS process descriptor.
Definition: fcels.c:282
void * zalloc(size_t size)
Allocate cleared memory.
Definition: malloc.c:624
struct fc_name node_wwn
Node name.
Definition: fcels.h:218
struct fc_port * port
Fibre Channel port.
Definition: fcels.h:334
static int fc_els_plogi_rx(struct fc_els *els, void *data, size_t len)
Receive PLOGI.
Definition: fcels.c:635
struct fc_link_state link
Link state monitor.
Definition: fc.h:272
void * param
Service parameters, if any.
Definition: fc.h:431
static int fc_els_rtv_detect(struct fc_els *els __unused, const void *data, size_t len __unused)
Detect RTV.
Definition: fcels.c:1193
static unsigned int fc_els_tx_command(struct fc_els *els, unsigned int request_command)
Calculate ELS command to transmit.
Definition: fcels.h:419
static size_t iob_len(struct io_buffer *iobuf)
Calculate length of data in an I/O buffer.
Definition: iobuf.h:155
struct hv_monitor_parameter param[4][32]
Parameters.
Definition: hyperv.h:24
Process Login.
Definition: fcels.h:38
#define INTF_OP(op_type, object_type, op_func)
Define an object interface operation.
Definition: interface.h:32
struct fc_link_state link
Link state monitor.
Definition: fc.h:427
#define FC_LOGIN_DEFAULT_MTU
Fibre Channel default MTU.
Definition: fcels.h:168
void fc_peer_logout(struct fc_peer *peer, int rc)
Log out Fibre Channel peer.
Definition: fc.c:1347
#define for_each_table_entry(pointer, table)
Iterate through all entries within a linker table.
Definition: tables.h:385
uint32_t magic
Magic marker.
Definition: fcels.c:1224
int xfer_deliver(struct interface *intf, struct io_buffer *iobuf, struct xfer_metadata *meta)
Deliver datagram.
Definition: xfer.c:194
Processes.
int(* rx)(struct fc_els *els, void *data, size_t len)
Receive ELS frame.
Definition: fcels.h:368
unsigned char uint8_t
Definition: stdint.h:10
struct interface job
Job control interface.
Definition: fcels.h:327
uint16_t credit
Buffer-to-buffer credit.
Definition: fcels.h:79
static void fc_els_step(struct fc_els *els)
Fibre Channel ELS process.
Definition: fcels.c:254
static void process_init_stopped(struct process *process, struct process_descriptor *desc, struct refcnt *refcnt)
Initialise process without adding to process list.
Definition: process.h:145
Fibre Channel.
#define FCELS_ARGS(els)
Fibre Channel ELS transaction debug message arguments.
Definition: fcels.c:49
unsigned int uint32_t
Definition: stdint.h:12
#define FC_ELS_HANDLERS
Fibre Channel ELS handler table.
Definition: fcels.h:380
static int fc_els_echo_detect(struct fc_els *els __unused, const void *data, size_t len __unused)
Detect ECHO.
Definition: fcels.c:1326
A Fibre Channel LOGO response frame.
Definition: fcels.h:244
uint32_t e_d_tov
Error detection timeout value.
Definition: fcels.h:98
A Fibre Channel peer.
Definition: fc.h:340
static int fc_els_logo_rx_response(struct fc_els *els, void *data __unused, size_t len __unused)
Receive LOGO response.
Definition: fcels.c:850
static int process_running(struct process *process)
Check if process is running.
Definition: process.h:175
uint8_t command
ELS command code.
Definition: fcels.h:234
int fc_ulp_login(struct fc_ulp *ulp, const void *param, size_t param_len, int originated)
Log in Fibre Channel upper-layer protocol.
Definition: fc.c:1657
static int fc_els_logo_tx_response(struct fc_els *els)
Transmit LOGO response.
Definition: fcels.c:773
static int fc_els_flogi_rx(struct fc_els *els, void *data, size_t len)
Receive FLOGI.
Definition: fcels.c:495
static struct fc_port * fc_port_get(struct fc_port *port)
Get reference to Fibre Channel port.
Definition: fc.h:304
#define __unused
Declare a variable or data structure as unused.
Definition: compiler.h:573
#define FC_LOGIN_DEFAULT_B2B
Fibre Channel default buffer-to-buffer credit.
Definition: fcels.h:105
struct interface plogi
PLOGI interface.
Definition: fc.h:352
void fc_ulp_logout(struct fc_ulp *ulp, int rc)
Log out Fibre Channel upper-layer protocol.
Definition: fc.c:1727
static struct fc_els * fc_els_create(struct fc_port *port, struct fc_port_id *port_id, struct fc_port_id *peer_port_id)
Create ELS transaction.
Definition: fcels.c:293
#define INTF_DESC(object_type, intf, operations)
Define an object interface descriptor.
Definition: interface.h:80
static int fc_els_logo_tx(struct fc_els *els)
Transmit LOGO request.
Definition: fcels.c:753
static int fc_els_is_request(struct fc_els *els)
Check if Fibre Channel ELS transaction is a request.
Definition: fcels.h:408
static int fc_els_echo_rx_response(struct fc_els *els, void *data, size_t len)
Receive ECHO response.
Definition: fcels.c:1283
static struct interface_descriptor fc_els_job_desc
Fibre Channel ELS job control interface descriptor.
Definition: fcels.c:246
unsigned int flags
Flags.
Definition: fcels.h:342
uint32_t len
Length.
Definition: ena.h:14
uint32_t type
Operating system type.
Definition: ena.h:12
#define FC_LOGIN_DEFAULT_MAX_SEQ
Default maximum number of concurrent sequences.
Definition: fcels.h:171
#define DBGC2(...)
Definition: compiler.h:522
uint8_t command
ELS command code.
Definition: fcels.h:45
A Fibre Channel LS_RJT frame.
Definition: fcels.h:43
void * data
Start of data.
Definition: iobuf.h:48
#define EIO
Input/output error.
Definition: errno.h:433
uint16_t mtu
Receive data field size.
Definition: fcels.h:188
Port Login.
Definition: fcels.h:33
struct fc_els_handler fc_els_unknown_handler __fc_els_handler
Unknown ELS handler.
Definition: fcels.c:55
static void fc_ulp_put(struct fc_ulp *ulp)
Drop reference to Fibre Channel upper-layer protocol.
Definition: fc.h:485
uint8_t data[48]
Additional event data.
Definition: ena.h:22
#define FC_PRLI_RESPONSE_SUCCESS
Request was executed successfully.
Definition: fcels.h:270
static int fc_els_rx(struct fc_els *els, struct io_buffer *iobuf, struct xfer_metadata *meta)
Receive Fibre Channel ELS frame.
Definition: fcels.c:159
struct fc_ulp * fc_ulp_get_port_id_type(struct fc_port *port, const struct fc_port_id *peer_port_id, unsigned int type)
Get Fibre Channel upper-layer protocol by port ID and type.
Definition: fc.c:1915
struct fc_name port_wwn
Port name.
Definition: fcels.h:240
#define FC_LOGIN_CLASS_VALID
Class valid.
Definition: fcels.h:202
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
#define XFER_FL_OVER
Sender is relinquishing use of half-duplex channel.
Definition: xfer.h:50
struct mschapv2_challenge peer
Peer challenge.
Definition: mschapv2.h:12
void fc_port_logout(struct fc_port *port, int rc)
Log out Fibre Channel port.
Definition: fc.c:1039
#define FC_LOGIN_VERSION
Fibre Channel default login version.
Definition: fcels.h:102
static void fc_els_logo_logout(struct fc_els *els, struct fc_port_id *peer_port_id)
Log out individual peer or whole port as applicable.
Definition: fcels.c:790
int fc_els_prli_rx(struct fc_els *els, struct fc_els_prli_descriptor *descriptor, void *data, size_t len)
Receive PRLI.
Definition: fcels.c:1006
struct process process
Request sending process.
Definition: fcels.h:331
unsigned int type
Upper-layer protocol type.
Definition: fcels.h:388
static void intf_init(struct interface *intf, struct interface_descriptor *desc, struct refcnt *refcnt)
Initialise an object interface.
Definition: interface.h:203
int fc_els_logo(struct interface *parent, struct fc_port *port, struct fc_port_id *peer_port_id)
Create LOGO request.
Definition: fcels.c:911
A Fibre Channel ELS PRLI descriptor.
Definition: fcels.h:386
struct fc_name port_wwn
Port name.
Definition: fcels.h:216
#define XFER_FL_OUT
This is the final data transfer.
Definition: xfer.h:53
uint16_t max_seq
Maximum number of concurrent sequences.
Definition: fcels.h:190
int memcmp(const void *first, const void *second, size_t len)
Compare memory regions.
Definition: string.c:114
A Fibre Channel FLOGI/PLOGI frame.
Definition: fcels.h:208
#define NULL
NULL pointer (VOID *)
Definition: Base.h:321
static void fc_els_free(struct refcnt *refcnt)
Free Fibre Channel ELS transaction.
Definition: fcels.c:62
String functions.
static struct interface_operation fc_els_job_op[]
Fibre Channel ELS job control interface operations.
Definition: fcels.c:241
#define htons(value)
Definition: byteswap.h:135
A Fibre Channel LOGO request frame.
Definition: fcels.h:232
struct bofm_section_header done
Definition: bofm_test.c:46
struct fc_port_id port_id
Local port ID.
Definition: fcels.h:336
uint16_t flags
Flags.
Definition: fcels.h:81
static struct interface_descriptor fc_els_xchg_desc
Fibre Channel ELS exchange interface descriptor.
Definition: fcels.c:237
#define ref_put(refcnt)
Drop reference to object.
Definition: refcnt.h:106
A Fibre Channel upper-layer protocol.
Definition: fc.h:413
Fibre Channel Extended Link Services.
static int fc_els_rtv_rx(struct fc_els *els, void *data __unused, size_t len __unused)
Receive RTV.
Definition: fcels.c:1170
void * memset(void *dest, int character, size_t len) __nonnull
int echo(void)
Definition: kb.c:133
A persistent I/O buffer.
Definition: iobuf.h:33
static int fc_els_echo_tx(struct fc_els *els)
Transmit ECHO.
Definition: fcels.c:1236