iPXE
fc.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 <stddef.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <stdio.h>
30 #include <errno.h>
31 #include <assert.h>
32 #include <byteswap.h>
33 #include <ipxe/refcnt.h>
34 #include <ipxe/list.h>
35 #include <ipxe/tables.h>
36 #include <ipxe/timer.h>
37 #include <ipxe/retry.h>
38 #include <ipxe/interface.h>
39 #include <ipxe/xfer.h>
40 #include <ipxe/iobuf.h>
41 #include <ipxe/fc.h>
42 #include <ipxe/fcels.h>
43 #include <ipxe/fcns.h>
44 
45 /** @file
46  *
47  * Fibre Channel
48  *
49  */
50 
51 /** List of Fibre Channel ports */
53 
54 /** List of Fibre Channel peers */
56 
57 /******************************************************************************
58  *
59  * Well-known addresses
60  *
61  ******************************************************************************
62  */
63 
64 /** Unassigned port ID */
65 struct fc_port_id fc_empty_port_id = { .bytes = { 0x00, 0x00, 0x00 } };
66 
67 /** F_Port contoller port ID */
68 struct fc_port_id fc_f_port_id = { .bytes = { 0xff, 0xff, 0xfe } };
69 
70 /** Generic services port ID */
71 struct fc_port_id fc_gs_port_id = { .bytes = { 0xff, 0xff, 0xfc } };
72 
73 /** Point-to-point low port ID */
74 struct fc_port_id fc_ptp_low_port_id = { .bytes = { 0x01, 0x01, 0x01 } };
75 
76 /** Point-to-point high port ID */
77 struct fc_port_id fc_ptp_high_port_id = { .bytes = { 0x01, 0x01, 0x02 } };
78 
79 /******************************************************************************
80  *
81  * Utility functions
82  *
83  ******************************************************************************
84  */
85 
86 /**
87  * Format Fibre Channel port ID
88  *
89  * @v id Fibre Channel port ID
90  * @ret id_text Port ID text
91  */
92 const char * fc_id_ntoa ( const struct fc_port_id *id ) {
93  static char id_text[ FC_PORT_ID_STRLEN + 1 /* NUL */ ];
94 
95  snprintf ( id_text, sizeof ( id_text ), "%02x.%02x.%02x",
96  id->bytes[0], id->bytes[1], id->bytes[2] );
97  return id_text;
98 }
99 
100 /**
101  * Parse Fibre Channel port ID
102  *
103  * @v id_text Port ID text
104  * @ret id Fibre Channel port ID
105  * @ret rc Return status code
106  */
107 int fc_id_aton ( const char *id_text, struct fc_port_id *id ) {
108  char *ptr = ( ( char * ) id_text );
109  unsigned int i = 0;
110 
111  while ( 1 ) {
112  id->bytes[i++] = strtoul ( ptr, &ptr, 16 );
113  if ( i == sizeof ( id->bytes ) )
114  return ( ( *ptr == '\0' ) ? 0 : -EINVAL );
115  if ( *ptr != '.' )
116  return -EINVAL;
117  ptr++;
118  }
119 }
120 
121 /**
122  * Format Fibre Channel WWN
123  *
124  * @v wwn Fibre Channel WWN
125  * @ret wwn_text WWN text
126  */
127 const char * fc_ntoa ( const struct fc_name *wwn ) {
128  static char wwn_text[ FC_NAME_STRLEN + 1 /* NUL */ ];
129 
130  snprintf ( wwn_text, sizeof ( wwn_text ),
131  "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
132  wwn->bytes[0], wwn->bytes[1], wwn->bytes[2], wwn->bytes[3],
133  wwn->bytes[4], wwn->bytes[5], wwn->bytes[6], wwn->bytes[7] );
134  return wwn_text;
135 }
136 
137 /**
138  * Parse Fibre Channel WWN
139  *
140  * @v wwn_text WWN text
141  * @ret wwn Fibre Channel WWN
142  * @ret rc Return status code
143  */
144 int fc_aton ( const char *wwn_text, struct fc_name *wwn ) {
145  char *ptr = ( ( char * ) wwn_text );
146  unsigned int i = 0;
147 
148  while ( 1 ) {
149  wwn->bytes[i++] = strtoul ( ptr, &ptr, 16 );
150  if ( i == sizeof ( wwn->bytes ) )
151  return ( ( *ptr == '\0' ) ? 0 : -EINVAL );
152  if ( *ptr != ':' )
153  return -EINVAL;
154  ptr++;
155  }
156 }
157 
158 /**
159  * Fill Fibre Channel socket address
160  *
161  * @v sa_fc Fibre Channel socket address to fill in
162  * @v id Fibre Channel port ID
163  * @ret sa Socket address
164  */
165 struct sockaddr * fc_fill_sockaddr ( struct sockaddr_fc *sa_fc,
166  struct fc_port_id *id ) {
167  union {
168  struct sockaddr sa;
169  struct sockaddr_fc fc;
170  } *u = container_of ( sa_fc, typeof ( *u ), fc );
171 
172  memset ( sa_fc, 0, sizeof ( *sa_fc ) );
173  sa_fc->sfc_family = AF_FC;
174  memcpy ( &sa_fc->sfc_port_id, id, sizeof ( sa_fc->sfc_port_id ) );
175  return &u->sa;
176 }
177 
178 /******************************************************************************
179  *
180  * Fibre Channel link state
181  *
182  ******************************************************************************
183  */
184 
185 /** Default link status code */
186 #define EUNKNOWN_LINK_STATUS __einfo_error ( EINFO_EUNKNOWN_LINK_STATUS )
187 #define EINFO_EUNKNOWN_LINK_STATUS \
188  __einfo_uniqify ( EINFO_EINPROGRESS, 0x01, "Unknown" )
189 
190 /**
191  * Mark Fibre Channel link as up
192  *
193  * @v link Fibre Channel link state monitor
194  */
195 static void fc_link_up ( struct fc_link_state *link ) {
196 
197  /* Stop retry timer */
198  stop_timer ( &link->timer );
199 
200  /* Record link state */
201  link->rc = 0;
202 }
203 
204 /**
205  * Mark Fibre Channel link as down
206  *
207  * @v link Fibre Channel link state monitor
208  * @v rc Link state
209  */
210 static void fc_link_err ( struct fc_link_state *link, int rc ) {
211 
212  /* Record link state */
213  if ( rc == 0 )
215  link->rc = rc;
216 
217  /* Schedule another link examination */
219 }
220 
221 /**
222  * Examine Fibre Channel link state
223  *
224  * @v link Fibre Channel link state monitor
225  */
226 static void fc_link_examine ( struct fc_link_state *link ) {
227 
228  link->examine ( link );
229 }
230 
231 /**
232  * Handle Fibre Channel link retry timer expiry
233  */
234 static void fc_link_expired ( struct retry_timer *timer, int over __unused ) {
235  struct fc_link_state *link =
236  container_of ( timer, struct fc_link_state, timer );
237 
238  /* Schedule another link examination */
240 
241  /* Examine link */
242  fc_link_examine ( link );
243 }
244 
245 /**
246  * Initialise Fibre Channel link state monitor
247  *
248  * @v link Fibre Channel link state monitor
249  * @v examine Examine link state method
250  * @v refcnt Reference counter
251  */
252 static void fc_link_init ( struct fc_link_state *link,
253  void ( * examine ) ( struct fc_link_state *link ),
254  struct refcnt *refcnt ) {
255 
256  link->rc = -EUNKNOWN_LINK_STATUS;
257  timer_init ( &link->timer, fc_link_expired, refcnt );
258  link->examine = examine;
259 }
260 
261 /**
262  * Start monitoring Fibre Channel link state
263  *
264  * @v link Fibre Channel link state monitor
265  */
266 static void fc_link_start ( struct fc_link_state *link ) {
267  start_timer_nodelay ( &link->timer );
268 }
269 
270 /**
271  * Stop monitoring Fibre Channel link state
272  *
273  * @v link Fibre Channel link state monitor
274  */
275 static void fc_link_stop ( struct fc_link_state *link ) {
276  stop_timer ( &link->timer );
277 }
278 
279 /******************************************************************************
280  *
281  * Fibre Channel exchanges
282  *
283  ******************************************************************************
284  */
285 
286 /** A Fibre Channel exchange */
287 struct fc_exchange {
288  /** Reference count */
289  struct refcnt refcnt;
290  /** Fibre Channel port */
291  struct fc_port *port;
292  /** List of active exchanges within this port */
293  struct list_head list;
294 
295  /** Peer port ID */
297  /** Data structure type */
298  unsigned int type;
299  /** Flags */
300  unsigned int flags;
301  /** Local exchange ID */
303  /** Peer exchange ID */
305  /** Active sequence ID */
307  /** Active sequence count */
309 
310  /** Timeout timer */
312 
313  /** Upper-layer protocol interface */
314  struct interface ulp;
315 };
316 
317 /** Fibre Channel exchange flags */
319  /** We are the exchange originator */
321  /** We have the sequence initiative */
323  /** This is the first sequence of the exchange */
325 };
326 
327 /** Fibre Channel timeout */
328 #define FC_TIMEOUT ( 1 * TICKS_PER_SEC )
329 
330 /**
331  * Create local Fibre Channel exchange identifier
332  *
333  * @ret xchg_id Local exchange ID
334  */
335 static unsigned int fc_new_xchg_id ( void ) {
336  static uint16_t next_id = 0x0000;
337 
338  /* We must avoid using FC_RX_ID_UNKNOWN (0xffff) */
339  next_id += 2;
340  return next_id;
341 }
342 
343 /**
344  * Create local Fibre Channel sequence identifier
345  *
346  * @ret seq_id Local sequence identifier
347  */
348 static unsigned int fc_new_seq_id ( void ) {
349  static uint8_t seq_id = 0x00;
350 
351  return (++seq_id);
352 }
353 
354 /**
355  * Free Fibre Channel exchange
356  *
357  * @v refcnt Reference count
358  */
359 static void fc_xchg_free ( struct refcnt *refcnt ) {
360  struct fc_exchange *xchg =
361  container_of ( refcnt, struct fc_exchange, refcnt );
362 
363  assert ( ! timer_running ( &xchg->timer ) );
364  assert ( list_empty ( &xchg->list ) );
365 
366  fc_port_put ( xchg->port );
367  free ( xchg );
368 }
369 
370 /**
371  * Close Fibre Channel exchange
372  *
373  * @v xchg Fibre Channel exchange
374  * @v rc Reason for close
375  */
376 static void fc_xchg_close ( struct fc_exchange *xchg, int rc ) {
377  struct fc_port *port = xchg->port;
378 
379  if ( rc != 0 ) {
380  DBGC2 ( port, "FCXCHG %s/%04x closed: %s\n",
381  port->name, xchg->xchg_id, strerror ( rc ) );
382  }
383 
384  /* Stop timer */
385  stop_timer ( &xchg->timer );
386 
387  /* If list still holds a reference, remove from list of open
388  * exchanges and drop list's reference.
389  */
390  if ( ! list_empty ( &xchg->list ) ) {
391  list_del ( &xchg->list );
392  INIT_LIST_HEAD ( &xchg->list );
393  ref_put ( &xchg->refcnt );
394  }
395 
396  /* Shutdown interfaces */
397  intf_shutdown ( &xchg->ulp, rc );
398 }
399 
400 /**
401  * Handle exchange timeout
402  *
403  * @v timer Timeout timer
404  * @v over Failure indicator
405  */
406 static void fc_xchg_expired ( struct retry_timer *timer, int over __unused ) {
407  struct fc_exchange *xchg =
408  container_of ( timer, struct fc_exchange, timer );
409  struct fc_port *port = xchg->port;
410 
411  DBGC ( port, "FCXCHG %s/%04x timed out\n", port->name, xchg->xchg_id );
412 
413  /* Terminate the exchange */
414  fc_xchg_close ( xchg, -ETIMEDOUT );
415 }
416 
417 /**
418  * Check Fibre Channel exchange window
419  *
420  * @v xchg Fibre Channel exchange
421  * @ret len Length opf window
422  */
423 static size_t fc_xchg_window ( struct fc_exchange *xchg __unused ) {
424 
425  /* We don't currently store the path MTU */
426  return FC_LOGIN_DEFAULT_MTU;
427 }
428 
429 /**
430  * Allocate Fibre Channel I/O buffer
431  *
432  * @v xchg Fibre Channel exchange
433  * @v len Payload length
434  * @ret iobuf I/O buffer, or NULL
435  */
436 static struct io_buffer * fc_xchg_alloc_iob ( struct fc_exchange *xchg,
437  size_t len ) {
438  struct fc_port *port = xchg->port;
439  struct io_buffer *iobuf;
440 
441  iobuf = xfer_alloc_iob ( &port->transport,
442  ( sizeof ( struct fc_frame_header ) + len ) );
443  if ( iobuf ) {
444  iob_reserve ( iobuf, sizeof ( struct fc_frame_header ) );
445  }
446  return iobuf;
447 }
448 
449 /**
450  * Transmit data as part of a Fibre Channel exchange
451  *
452  * @v xchg Fibre Channel exchange
453  * @v iobuf I/O buffer
454  * @v meta Data transfer metadata
455  * @ret rc Return status code
456  */
457 static int fc_xchg_tx ( struct fc_exchange *xchg, struct io_buffer *iobuf,
458  struct xfer_metadata *meta ) {
459  struct fc_port *port = xchg->port;
460  struct sockaddr_fc *dest = ( ( struct sockaddr_fc * ) meta->dest );
461  struct fc_frame_header *fchdr;
462  unsigned int r_ctl;
463  unsigned int f_ctl_es;
464  int rc;
465 
466  /* Sanity checks */
467  if ( ! ( xchg->flags & FC_XCHG_SEQ_INITIATIVE ) ) {
468  DBGC ( port, "FCXCHG %s/%04x cannot transmit while not "
469  "holding sequence initiative\n",
470  port->name, xchg->xchg_id );
471  rc = -EBUSY;
472  goto done;
473  }
474 
475  /* Calculate routing control */
476  switch ( xchg->type ) {
477  case FC_TYPE_ELS:
479  if ( meta->flags & XFER_FL_RESPONSE ) {
481  } else {
483  }
484  break;
485  case FC_TYPE_CT:
487  if ( meta->flags & XFER_FL_RESPONSE ) {
489  } else {
491  }
492  break;
493  default:
495  switch ( meta->flags &
499  break;
500  case ( XFER_FL_CMD_STAT ):
502  break;
503  case ( XFER_FL_RESPONSE ):
505  break;
506  default:
508  break;
509  }
510  break;
511  }
512 
513  /* Calculate exchange and sequence control */
514  f_ctl_es = 0;
515  if ( ! ( xchg->flags & FC_XCHG_ORIGINATOR ) )
517  if ( xchg->flags & FC_XCHG_SEQ_FIRST )
519  if ( meta->flags & XFER_FL_OUT )
521  if ( meta->flags & XFER_FL_OVER )
523 
524  /* Create frame header */
525  fchdr = iob_push ( iobuf, sizeof ( *fchdr ) );
526  memset ( fchdr, 0, sizeof ( *fchdr ) );
527  fchdr->r_ctl = r_ctl;
528  memcpy ( &fchdr->d_id,
529  ( dest ? &dest->sfc_port_id : &xchg->peer_port_id ),
530  sizeof ( fchdr->d_id ) );
531  memcpy ( &fchdr->s_id, &port->port_id, sizeof ( fchdr->s_id ) );
532  fchdr->type = xchg->type;
533  fchdr->f_ctl_es = f_ctl_es;
534  fchdr->seq_id = xchg->seq_id;
535  fchdr->seq_cnt = htons ( xchg->seq_cnt++ );
536  fchdr->ox_id = htons ( ( xchg->flags & FC_XCHG_ORIGINATOR ) ?
537  xchg->xchg_id : xchg->peer_xchg_id );
538  fchdr->rx_id = htons ( ( xchg->flags & FC_XCHG_ORIGINATOR ) ?
539  xchg->peer_xchg_id : xchg->xchg_id );
540  if ( meta->flags & XFER_FL_ABS_OFFSET ) {
542  fchdr->parameter = htonl ( meta->offset );
543  }
544 
545  /* Relinquish sequence initiative if applicable */
546  if ( meta->flags & XFER_FL_OVER ) {
548  xchg->seq_cnt = 0;
549  }
550 
551  /* Reset timeout */
552  start_timer_fixed ( &xchg->timer, FC_TIMEOUT );
553 
554  /* Deliver frame */
555  if ( ( rc = xfer_deliver_iob ( &port->transport,
556  iob_disown ( iobuf ) ) ) != 0 ) {
557  DBGC ( port, "FCXCHG %s/%04x cannot transmit: %s\n",
558  port->name, xchg->xchg_id, strerror ( rc ) );
559  goto done;
560  }
561 
562  done:
563  free_iob ( iobuf );
564  return rc;
565 }
566 
567 /** Mapping from Fibre Channel routing control information to xfer metadata */
569  [FC_R_CTL_UNCAT] = ( 0 ),
573  [FC_R_CTL_UNSOL_DATA] = ( 0 ),
577 };
578 
579 /**
580  * Receive data as part of a Fibre Channel exchange
581  *
582  * @v xchg Fibre Channel exchange
583  * @v iobuf I/O buffer
584  * @v meta Data transfer metadata
585  * @ret rc Return status code
586  */
587 static int fc_xchg_rx ( struct fc_exchange *xchg, struct io_buffer *iobuf,
588  struct xfer_metadata *meta __unused ) {
589  struct fc_port *port = xchg->port;
590  struct fc_frame_header *fchdr = iobuf->data;
591  struct xfer_metadata fc_meta;
592  struct sockaddr_fc src;
593  struct sockaddr_fc dest;
594  int rc;
595 
596  /* Record peer exchange ID */
597  xchg->peer_xchg_id =
598  ntohs ( ( fchdr->f_ctl_es & FC_F_CTL_ES_RESPONDER ) ?
599  fchdr->rx_id : fchdr->ox_id );
600 
601  /* Sequence checks */
602  if ( xchg->flags & FC_XCHG_SEQ_INITIATIVE ) {
603  DBGC ( port, "FCXCHG %s/%04x received frame while holding "
604  "sequence initiative\n", port->name, xchg->xchg_id );
605  rc = -EBUSY;
606  goto done;
607  }
608  if ( ntohs ( fchdr->seq_cnt ) != xchg->seq_cnt ) {
609  DBGC ( port, "FCXCHG %s/%04x received out-of-order frame %d "
610  "(expected %d)\n", port->name, xchg->xchg_id,
611  ntohs ( fchdr->seq_cnt ), xchg->seq_cnt );
612  rc = -EPIPE;
613  goto done;
614  }
615  if ( xchg->seq_cnt == 0 )
616  xchg->seq_id = fchdr->seq_id;
617  xchg->seq_cnt++;
618  if ( fchdr->seq_id != xchg->seq_id ) {
619  DBGC ( port, "FCXCHG %s/%04x received frame for incorrect "
620  "sequence %02x (expected %02x)\n", port->name,
621  xchg->xchg_id, fchdr->seq_id, xchg->seq_id );
622  rc = -EPIPE;
623  goto done;
624  }
625 
626  /* Check for end of sequence and transfer of sequence initiative */
627  if ( fchdr->f_ctl_es & FC_F_CTL_ES_END ) {
628  xchg->seq_cnt = 0;
629  if ( fchdr->f_ctl_es & FC_F_CTL_ES_TRANSFER ) {
630  xchg->flags |= FC_XCHG_SEQ_INITIATIVE;
631  xchg->seq_id = fc_new_seq_id();
632  }
633  }
634 
635  /* Construct metadata */
636  memset ( &fc_meta, 0, sizeof ( fc_meta ) );
637  fc_meta.flags =
639  if ( fchdr->f_ctl_es & FC_F_CTL_ES_TRANSFER ) {
640  fc_meta.flags |= XFER_FL_OVER;
641  }
642  if ( ( fchdr->f_ctl_es & FC_F_CTL_ES_LAST ) &&
643  ( fchdr->f_ctl_es & FC_F_CTL_ES_END ) ) {
644  fc_meta.flags |= XFER_FL_OUT;
645  }
646  if ( fchdr->f_ctl_misc & FC_F_CTL_MISC_REL_OFF ) {
647  fc_meta.flags |= XFER_FL_ABS_OFFSET;
648  fc_meta.offset = ntohl ( fchdr->parameter );
649  }
650  fc_meta.src = fc_fill_sockaddr ( &src, &fchdr->s_id );
651  fc_meta.dest = fc_fill_sockaddr ( &dest, &fchdr->d_id );
652 
653  /* Reset timeout */
654  start_timer_fixed ( &xchg->timer, FC_TIMEOUT );
655 
656  /* Deliver via exchange's ULP interface */
657  iob_pull ( iobuf, sizeof ( *fchdr ) );
658  if ( ( rc = xfer_deliver ( &xchg->ulp, iob_disown ( iobuf ),
659  &fc_meta ) ) != 0 ) {
660  DBGC ( port, "FCXCHG %s/%04x cannot deliver frame: %s\n",
661  port->name, xchg->xchg_id, strerror ( rc ) );
662  goto done;
663  }
664 
665  /* Close exchange if applicable */
666  if ( ( fchdr->f_ctl_es & FC_F_CTL_ES_LAST ) &&
667  ( fchdr->f_ctl_es & FC_F_CTL_ES_END ) ) {
668  fc_xchg_close ( xchg, 0 );
669  }
670 
671  done:
672  free_iob ( iobuf );
673  return rc;
674 }
675 
676 /** Fibre Channel exchange ULP interface operations */
682 };
683 
684 /** Fibre Channel exchange ULP interface descriptor */
686  INTF_DESC ( struct fc_exchange, ulp, fc_xchg_ulp_op );
687 
688 /**
689  * Create new Fibre Channel exchange
690  *
691  * @v port Fibre Channel port
692  * @v peer_port_id Peer port ID
693  * @ret xchg Exchange, or NULL
694  */
695 static struct fc_exchange * fc_xchg_create ( struct fc_port *port,
696  struct fc_port_id *peer_port_id,
697  unsigned int type ) {
698  struct fc_exchange *xchg;
699 
700  /* Allocate and initialise structure */
701  xchg = zalloc ( sizeof ( *xchg ) );
702  if ( ! xchg )
703  return NULL;
704  ref_init ( &xchg->refcnt, fc_xchg_free );
705  intf_init ( &xchg->ulp, &fc_xchg_ulp_desc, &xchg->refcnt );
706  timer_init ( &xchg->timer, fc_xchg_expired, &xchg->refcnt );
707  xchg->port = fc_port_get ( port );
708  memcpy ( &xchg->peer_port_id, peer_port_id,
709  sizeof ( xchg->peer_port_id ) );
710  xchg->type = type;
711  xchg->xchg_id = fc_new_xchg_id();
713  xchg->seq_id = fc_new_seq_id();
714 
715  /* Transfer reference to list of exchanges and return */
716  list_add ( &xchg->list, &port->xchgs );
717  return xchg;
718 }
719 
720 /**
721  * Originate a new Fibre Channel exchange
722  *
723  * @v parent Interface to which to attach
724  * @v port Fibre Channel port
725  * @v peer_port_id Peer port ID
726  * @ret xchg_id Exchange ID, or negative error
727  */
728 int fc_xchg_originate ( struct interface *parent, struct fc_port *port,
729  struct fc_port_id *peer_port_id, unsigned int type ) {
730  struct fc_exchange *xchg;
731 
732  /* Allocate and initialise structure */
733  xchg = fc_xchg_create ( port, peer_port_id, type );
734  if ( ! xchg )
735  return -ENOMEM;
738 
739  DBGC2 ( port, "FCXCHG %s/%04x originating to %s (type %02x)\n",
740  port->name, xchg->xchg_id, fc_id_ntoa ( &xchg->peer_port_id ),
741  xchg->type );
742 
743  /* Attach to parent interface and return */
744  intf_plug_plug ( &xchg->ulp, parent );
745  return xchg->xchg_id;
746 }
747 
748 /**
749  * Open a new responder Fibre Channel exchange
750  *
751  * @v port Fibre Channel port
752  * @v fchdr Fibre Channel frame header
753  * @ret xchg Fibre Channel exchange, or NULL
754  */
755 static struct fc_exchange * fc_xchg_respond ( struct fc_port *port,
756  struct fc_frame_header *fchdr ) {
757  struct fc_exchange *xchg;
758  struct fc_responder *responder;
759  unsigned int type = fchdr->type;
760  int rc;
761 
762  /* Allocate and initialise structure */
763  xchg = fc_xchg_create ( port, &fchdr->s_id, type );
764  if ( ! xchg )
765  return NULL;
766  xchg->seq_id = fchdr->seq_id;
767 
768  DBGC2 ( port, "FCXCHG %s/%04x responding to %s xchg %04x (type "
769  "%02x)\n", port->name, xchg->xchg_id,
770  fc_id_ntoa ( &xchg->peer_port_id ),
771  ntohs ( fchdr->ox_id ), xchg->type );
772 
773  /* Find a responder, if any */
774  for_each_table_entry ( responder, FC_RESPONDERS ) {
775  if ( responder->type == type ) {
776  if ( ( rc = responder->respond ( &xchg->ulp, port,
777  &fchdr->d_id,
778  &fchdr->s_id ) ) !=0 ){
779  DBGC ( port, "FCXCHG %s/%04x could not "
780  "respond: %s\n", port->name,
781  xchg->xchg_id, strerror ( rc ) );
782  }
783  }
784  break;
785  }
786 
787  /* We may or may not have a ULP attached at this point, but
788  * the exchange does exist.
789  */
790  return xchg;
791 }
792 
793 /******************************************************************************
794  *
795  * Fibre Channel ports
796  *
797  ******************************************************************************
798  */
799 
800 /**
801  * Close Fibre Channel port
802  *
803  * @v port Fibre Channel port
804  * @v rc Reason for close
805  */
806 static void fc_port_close ( struct fc_port *port, int rc ) {
807  struct fc_exchange *xchg;
808  struct fc_exchange *tmp;
809 
810  DBGC ( port, "FCPORT %s closed\n", port->name );
811 
812  /* Log out port, if necessary */
813  if ( fc_link_ok ( &port->link ) )
814  fc_port_logout ( port, rc );
815 
816  /* Stop link monitor */
817  fc_link_stop ( &port->link );
818 
819  /* Shut down interfaces */
820  intf_shutdown ( &port->transport, rc );
821  intf_shutdown ( &port->flogi, rc );
822  intf_shutdown ( &port->ns_plogi, rc );
823 
824  /* Shut down any remaining exchanges */
825  list_for_each_entry_safe ( xchg, tmp, &port->xchgs, list )
826  fc_xchg_close ( xchg, rc );
827 
828  /* Remove from list of ports */
829  list_del ( &port->list );
830  INIT_LIST_HEAD ( &port->list );
831 }
832 
833 /**
834  * Identify Fibre Channel exchange by local exchange ID
835  *
836  * @v port Fibre Channel port
837  * @v xchg_id Local exchange ID
838  * @ret xchg Fibre Channel exchange, or NULL
839  */
840 static struct fc_exchange * fc_port_demux ( struct fc_port *port,
841  unsigned int xchg_id ) {
842  struct fc_exchange *xchg;
843 
844  list_for_each_entry ( xchg, &port->xchgs, list ) {
845  if ( xchg->xchg_id == xchg_id )
846  return xchg;
847  }
848  return NULL;
849 }
850 
851 /**
852  * Handle received frame from Fibre Channel port
853  *
854  * @v port Fibre Channel port
855  * @v iobuf I/O buffer
856  * @v meta Data transfer metadata
857  * @ret rc Return status code
858  */
859 static int fc_port_deliver ( struct fc_port *port, struct io_buffer *iobuf,
860  struct xfer_metadata *meta ) {
861  struct fc_frame_header *fchdr = iobuf->data;
862  unsigned int xchg_id;
863  struct fc_exchange *xchg;
864  int rc;
865 
866  /* Sanity check */
867  if ( iob_len ( iobuf ) < sizeof ( *fchdr ) ) {
868  DBGC ( port, "FCPORT %s received underlength frame (%zd "
869  "bytes)\n", port->name, iob_len ( iobuf ) );
870  rc = -EINVAL;
871  goto err_sanity;
872  }
873 
874  /* Verify local port ID */
875  if ( ( memcmp ( &fchdr->d_id, &port->port_id,
876  sizeof ( fchdr->d_id ) ) != 0 ) &&
877  ( memcmp ( &fchdr->d_id, &fc_f_port_id,
878  sizeof ( fchdr->d_id ) ) != 0 ) &&
879  ( memcmp ( &port->port_id, &fc_empty_port_id,
880  sizeof ( port->port_id ) ) != 0 ) ) {
881  DBGC ( port, "FCPORT %s received frame for incorrect port ID "
882  "%s\n", port->name, fc_id_ntoa ( &fchdr->d_id ) );
883  rc = -ENOTCONN;
884  goto err_port_id;
885  }
886 
887  /* Demultiplex amongst active exchanges */
888  xchg_id = ntohs ( ( fchdr->f_ctl_es & FC_F_CTL_ES_RESPONDER ) ?
889  fchdr->ox_id : fchdr->rx_id );
890  xchg = fc_port_demux ( port, xchg_id );
891 
892  /* If we have no active exchange and this frame starts a new
893  * exchange, try to create a new responder exchange
894  */
895  if ( ( fchdr->f_ctl_es & FC_F_CTL_ES_FIRST ) &&
896  ( fchdr->seq_cnt == 0 ) ) {
897 
898  /* Create new exchange */
899  xchg = fc_xchg_respond ( port, fchdr );
900  if ( ! xchg ) {
901  DBGC ( port, "FCPORT %s cannot create new exchange\n",
902  port->name );
903  rc = -ENOMEM;
904  goto err_respond;
905  }
906  }
907 
908  /* Fail if no exchange exists */
909  if ( ! xchg ) {
910  DBGC ( port, "FCPORT %s xchg %04x unknown\n",
911  port->name, xchg_id );
912  rc = -ENOTCONN;
913  goto err_no_xchg;
914  }
915 
916  /* Pass received frame to exchange */
917  ref_get ( &xchg->refcnt );
918  if ( ( rc = fc_xchg_rx ( xchg, iob_disown ( iobuf ), meta ) ) != 0 )
919  goto err_xchg_rx;
920 
921  err_xchg_rx:
922  ref_put ( &xchg->refcnt );
923  err_no_xchg:
924  err_respond:
925  err_port_id:
926  err_sanity:
927  free_iob ( iobuf );
928  return rc;
929 }
930 
931 /**
932  * Log in Fibre Channel port
933  *
934  * @v port Fibre Channel port
935  * @v port_id Local port ID
936  * @v link_node_wwn Link node name
937  * @v link_port_wwn Link port name
938  * @v has_fabric Link is to a fabric
939  * @ret rc Return status code
940  */
941 int fc_port_login ( struct fc_port *port, struct fc_port_id *port_id,
942  const struct fc_name *link_node_wwn,
943  const struct fc_name *link_port_wwn, int has_fabric ) {
944  struct fc_peer *peer;
945  struct fc_peer *tmp;
946  int rc;
947 
948  /* Perform implicit logout if logged in and details differ */
949  if ( fc_link_ok ( &port->link ) &&
950  ( ( ( !! ( port->flags & FC_PORT_HAS_FABRIC ) ) !=
951  ( !! has_fabric ) ) ||
952  ( memcmp ( &port->link_node_wwn, link_node_wwn,
953  sizeof ( port->link_node_wwn ) ) != 0 ) ||
954  ( memcmp ( &port->link_port_wwn, link_port_wwn,
955  sizeof ( port->link_port_wwn ) ) != 0 ) ||
956  ( has_fabric &&
957  ( memcmp ( &port->port_id, port_id,
958  sizeof ( port->port_id ) ) != 0 ) ) ) ) {
959  fc_port_logout ( port, 0 );
960  }
961 
962  /* Log in, if applicable */
963  if ( ! fc_link_ok ( &port->link ) ) {
964 
965  /* Record link port name */
966  memcpy ( &port->link_node_wwn, link_node_wwn,
967  sizeof ( port->link_node_wwn ) );
968  memcpy ( &port->link_port_wwn, link_port_wwn,
969  sizeof ( port->link_port_wwn ) );
970  DBGC ( port, "FCPORT %s logged in to %s",
971  port->name, fc_ntoa ( &port->link_node_wwn ) );
972  DBGC ( port, " port %s\n", fc_ntoa ( &port->link_port_wwn ) );
973 
974  /* Calculate local (and possibly remote) port IDs */
975  if ( has_fabric ) {
976  port->flags |= FC_PORT_HAS_FABRIC;
977  memcpy ( &port->port_id, port_id,
978  sizeof ( port->port_id ) );
979  } else {
980  port->flags &= ~FC_PORT_HAS_FABRIC;
981  if ( memcmp ( &port->port_wwn, link_port_wwn,
982  sizeof ( port->port_wwn ) ) > 0 ) {
983  memcpy ( &port->port_id, &fc_ptp_high_port_id,
984  sizeof ( port->port_id ) );
985  memcpy ( &port->ptp_link_port_id,
987  sizeof ( port->ptp_link_port_id ) );
988  } else {
989  memcpy ( &port->port_id, &fc_ptp_low_port_id,
990  sizeof ( port->port_id ) );
991  memcpy ( &port->ptp_link_port_id,
993  sizeof ( port->ptp_link_port_id ) );
994  }
995  }
996  DBGC ( port, "FCPORT %s logged in via a %s, with local ID "
997  "%s\n", port->name,
998  ( ( port->flags & FC_PORT_HAS_FABRIC ) ?
999  "fabric" : "point-to-point link" ),
1000  fc_id_ntoa ( &port->port_id ) );
1001  }
1002 
1003  /* Log in to name server, if attached to a fabric */
1004  if ( has_fabric && ! ( port->flags & FC_PORT_HAS_NS ) ) {
1005 
1006  DBGC ( port, "FCPORT %s attempting login to name server\n",
1007  port->name );
1008 
1009  intf_restart ( &port->ns_plogi, -ECANCELED );
1010  if ( ( rc = fc_els_plogi ( &port->ns_plogi, port,
1011  &fc_gs_port_id ) ) != 0 ) {
1012  DBGC ( port, "FCPORT %s could not initiate name "
1013  "server PLOGI: %s\n",
1014  port->name, strerror ( rc ) );
1015  fc_port_logout ( port, rc );
1016  return rc;
1017  }
1018  }
1019 
1020  /* Record login */
1021  fc_link_up ( &port->link );
1022 
1023  /* Notify peers of link state change */
1024  list_for_each_entry_safe ( peer, tmp, &fc_peers, list ) {
1025  fc_peer_get ( peer );
1026  fc_link_examine ( &peer->link );
1027  fc_peer_put ( peer );
1028  }
1029 
1030  return 0;
1031 }
1032 
1033 /**
1034  * Log out Fibre Channel port
1035  *
1036  * @v port Fibre Channel port
1037  * @v rc Reason for logout
1038  */
1039 void fc_port_logout ( struct fc_port *port, int rc ) {
1040  struct fc_peer *peer;
1041  struct fc_peer *tmp;
1042 
1043  DBGC ( port, "FCPORT %s logged out: %s\n",
1044  port->name, strerror ( rc ) );
1045 
1046  /* Erase port details */
1047  memset ( &port->port_id, 0, sizeof ( port->port_id ) );
1048  port->flags = 0;
1049 
1050  /* Record logout */
1051  fc_link_err ( &port->link, rc );
1052 
1053  /* Notify peers of link state change */
1054  list_for_each_entry_safe ( peer, tmp, &fc_peers, list ) {
1055  fc_peer_get ( peer );
1056  fc_link_examine ( &peer->link );
1057  fc_peer_put ( peer );
1058  }
1059 }
1060 
1061 /**
1062  * Handle FLOGI completion
1063  *
1064  * @v port Fibre Channel port
1065  * @v rc Reason for completion
1066  */
1067 static void fc_port_flogi_done ( struct fc_port *port, int rc ) {
1068 
1069  intf_restart ( &port->flogi, rc );
1070 
1071  if ( rc != 0 )
1072  fc_port_logout ( port, rc );
1073 }
1074 
1075 /**
1076  * Handle name server PLOGI completion
1077  *
1078  * @v port Fibre Channel port
1079  * @v rc Reason for completion
1080  */
1081 static void fc_port_ns_plogi_done ( struct fc_port *port, int rc ) {
1082 
1083  intf_restart ( &port->ns_plogi, rc );
1084 
1085  if ( rc == 0 ) {
1086  port->flags |= FC_PORT_HAS_NS;
1087  DBGC ( port, "FCPORT %s logged in to name server\n",
1088  port->name );
1089  } else {
1090  DBGC ( port, "FCPORT %s could not log in to name server: %s\n",
1091  port->name, strerror ( rc ) );
1092  /* Absence of a name server is not a fatal error */
1093  }
1094 }
1095 
1096 /**
1097  * Examine Fibre Channel port link state
1098  *
1099  * @ link Fibre Channel link state monitor
1100  */
1101 static void fc_port_examine ( struct fc_link_state *link ) {
1102  struct fc_port *port = container_of ( link, struct fc_port, link );
1103  int rc;
1104 
1105  /* Do nothing if already logged in */
1106  if ( fc_link_ok ( &port->link ) )
1107  return;
1108 
1109  DBGC ( port, "FCPORT %s attempting login\n", port->name );
1110 
1111  /* Try to create FLOGI ELS */
1112  intf_restart ( &port->flogi, -ECANCELED );
1113  if ( ( rc = fc_els_flogi ( &port->flogi, port ) ) != 0 ) {
1114  DBGC ( port, "FCPORT %s could not initiate FLOGI: %s\n",
1115  port->name, strerror ( rc ) );
1116  fc_port_logout ( port, rc );
1117  return;
1118  }
1119 }
1120 
1121 /**
1122  * Handle change of flow control window
1123  *
1124  * @v port Fibre Channel port
1125  */
1126 static void fc_port_window_changed ( struct fc_port *port ) {
1127  size_t window;
1128 
1129  /* Check if transport layer is ready */
1130  window = xfer_window ( &port->transport );
1131  if ( window > 0 ) {
1132 
1133  /* Transport layer is ready. Start login if the link
1134  * is not already up.
1135  */
1136  if ( ! fc_link_ok ( &port->link ) )
1137  fc_link_start ( &port->link );
1138 
1139  } else {
1140 
1141  /* Transport layer is not ready. Log out port and
1142  * wait for transport layer before attempting log in
1143  * again.
1144  */
1146  fc_link_stop ( &port->link );
1147  }
1148 }
1149 
1150 /** Fibre Channel port transport interface operations */
1153  INTF_OP ( xfer_window_changed, struct fc_port *,
1155  INTF_OP ( intf_close, struct fc_port *, fc_port_close ),
1156 };
1157 
1158 /** Fibre Channel port transport interface descriptor */
1160  INTF_DESC ( struct fc_port, transport, fc_port_transport_op );
1161 
1162 /** Fibre Channel port FLOGI interface operations */
1165 };
1166 
1167 /** Fibre Channel port FLOGI interface descriptor */
1169  INTF_DESC ( struct fc_port, flogi, fc_port_flogi_op );
1170 
1171 /** Fibre Channel port name server PLOGI interface operations */
1174 };
1175 
1176 /** Fibre Channel port name server PLOGI interface descriptor */
1178  INTF_DESC ( struct fc_port, ns_plogi, fc_port_ns_plogi_op );
1179 
1180 /**
1181  * Create Fibre Channel port
1182  *
1183  * @v transport Transport interface
1184  * @v node Fibre Channel node name
1185  * @v port Fibre Channel port name
1186  * @v name Symbolic port name
1187  * @ret rc Return status code
1188  */
1189 int fc_port_open ( struct interface *transport, const struct fc_name *node_wwn,
1190  const struct fc_name *port_wwn, const char *name ) {
1191  struct fc_port *port;
1192 
1193  /* Allocate and initialise structure */
1194  port = zalloc ( sizeof ( *port ) );
1195  if ( ! port )
1196  return -ENOMEM;
1197  ref_init ( &port->refcnt, NULL );
1198  intf_init ( &port->transport, &fc_port_transport_desc, &port->refcnt );
1199  fc_link_init ( &port->link, fc_port_examine, &port->refcnt );
1200  intf_init ( &port->flogi, &fc_port_flogi_desc, &port->refcnt );
1201  intf_init ( &port->ns_plogi, &fc_port_ns_plogi_desc, &port->refcnt );
1202  list_add_tail ( &port->list, &fc_ports );
1203  INIT_LIST_HEAD ( &port->xchgs );
1204  memcpy ( &port->node_wwn, node_wwn, sizeof ( port->node_wwn ) );
1205  memcpy ( &port->port_wwn, port_wwn, sizeof ( port->port_wwn ) );
1206  snprintf ( port->name, sizeof ( port->name ), "%s", name );
1207 
1208  DBGC ( port, "FCPORT %s opened as %s",
1209  port->name, fc_ntoa ( &port->node_wwn ) );
1210  DBGC ( port, " port %s\n", fc_ntoa ( &port->port_wwn ) );
1211 
1212  /* Attach to transport layer, mortalise self, and return */
1213  intf_plug_plug ( &port->transport, transport );
1214  ref_put ( &port->refcnt );
1215  return 0;
1216 }
1217 
1218 /**
1219  * Find Fibre Channel port by name
1220  *
1221  * @v name Fibre Channel port name
1222  * @ret port Fibre Channel port, or NULL
1223  */
1224 struct fc_port * fc_port_find ( const char *name ) {
1225  struct fc_port *port;
1226 
1228  if ( strcmp ( name, port->name ) == 0 )
1229  return port;
1230  }
1231  return NULL;
1232 }
1233 
1234 /******************************************************************************
1235  *
1236  * Fibre Channel peers
1237  *
1238  ******************************************************************************
1239  */
1240 
1241 /**
1242  * Close Fibre Channel peer
1243  *
1244  * @v peer Fibre Channel peer
1245  * @v rc Reason for close
1246  */
1247 static void fc_peer_close ( struct fc_peer *peer, int rc ) {
1248 
1249  DBGC ( peer, "FCPEER %s closed: %s\n",
1250  fc_ntoa ( &peer->port_wwn ) , strerror ( rc ) );
1251 
1252  /* Sanity check */
1253  assert ( list_empty ( &peer->ulps ) );
1254 
1255  /* Stop link timer */
1256  fc_link_stop ( &peer->link );
1257 
1258  /* Shut down interfaces */
1259  intf_shutdown ( &peer->plogi, rc );
1260 
1261  /* Remove from list of peers */
1262  list_del ( &peer->list );
1263  INIT_LIST_HEAD ( &peer->list );
1264 }
1265 
1266 /**
1267  * Increment Fibre Channel peer active usage count
1268  *
1269  * @v peer Fibre Channel peer
1270  */
1271 static void fc_peer_increment ( struct fc_peer *peer ) {
1272 
1273  /* Increment our usage count */
1274  peer->usage++;
1275 }
1276 
1277 /**
1278  * Decrement Fibre Channel peer active usage count
1279  *
1280  * @v peer Fibre Channel peer
1281  */
1282 static void fc_peer_decrement ( struct fc_peer *peer ) {
1283 
1284  /* Sanity check */
1285  assert ( peer->usage > 0 );
1286 
1287  /* Decrement our usage count and log out if we reach zero */
1288  if ( --(peer->usage) == 0 )
1289  fc_peer_logout ( peer, 0 );
1290 }
1291 
1292 /**
1293  * Log in Fibre Channel peer
1294  *
1295  * @v peer Fibre Channel peer
1296  * @v port Fibre Channel port
1297  * @v port_id Port ID
1298  * @ret rc Return status code
1299  */
1300 int fc_peer_login ( struct fc_peer *peer, struct fc_port *port,
1301  struct fc_port_id *port_id ) {
1302  struct fc_ulp *ulp;
1303  struct fc_ulp *tmp;
1304 
1305  /* Perform implicit logout if logged in and details differ */
1306  if ( fc_link_ok ( &peer->link ) &&
1307  ( ( peer->port != port ) ||
1308  ( memcmp ( &peer->port_id, port_id,
1309  sizeof ( peer->port_id ) ) !=0 ) ) ) {
1310  fc_peer_logout ( peer, 0 );
1311  }
1312 
1313  /* Log in, if applicable */
1314  if ( ! fc_link_ok ( &peer->link ) ) {
1315 
1316  /* Record peer details */
1317  assert ( peer->port == NULL );
1318  peer->port = fc_port_get ( port );
1319  memcpy ( &peer->port_id, port_id, sizeof ( peer->port_id ) );
1320  DBGC ( peer, "FCPEER %s logged in via %s as %s\n",
1321  fc_ntoa ( &peer->port_wwn ), peer->port->name,
1322  fc_id_ntoa ( &peer->port_id ) );
1323 
1324  /* Add login reference */
1325  fc_peer_get ( peer );
1326  }
1327 
1328  /* Record login */
1329  fc_link_up ( &peer->link );
1330 
1331  /* Notify ULPs of link state change */
1332  list_for_each_entry_safe ( ulp, tmp, &peer->ulps, list ) {
1333  fc_ulp_get ( ulp );
1334  fc_link_examine ( &ulp->link );
1335  fc_ulp_put ( ulp );
1336  }
1337 
1338  return 0;
1339 }
1340 
1341 /**
1342  * Log out Fibre Channel peer
1343  *
1344  * @v peer Fibre Channel peer
1345  * @v rc Reason for logout
1346  */
1347 void fc_peer_logout ( struct fc_peer *peer, int rc ) {
1348  struct fc_ulp *ulp;
1349  struct fc_ulp *tmp;
1350 
1351  DBGC ( peer, "FCPEER %s logged out: %s\n",
1352  fc_ntoa ( &peer->port_wwn ), strerror ( rc ) );
1353 
1354  /* Drop login reference, if applicable */
1355  if ( fc_link_ok ( &peer->link ) )
1356  fc_peer_put ( peer );
1357 
1358  /* Erase peer details */
1359  fc_port_put ( peer->port );
1360  peer->port = NULL;
1361 
1362  /* Record logout */
1363  fc_link_err ( &peer->link, rc );
1364 
1365  /* Notify ULPs of link state change */
1366  list_for_each_entry_safe ( ulp, tmp, &peer->ulps, list ) {
1367  fc_ulp_get ( ulp );
1368  fc_link_examine ( &ulp->link );
1369  fc_ulp_put ( ulp );
1370  }
1371 
1372  /* Close peer if there are no active users */
1373  if ( peer->usage == 0 )
1374  fc_peer_close ( peer, rc );
1375 }
1376 
1377 /**
1378  * Handle PLOGI completion
1379  *
1380  * @v peer Fibre Channel peer
1381  * @v rc Reason for completion
1382  */
1383 static void fc_peer_plogi_done ( struct fc_peer *peer, int rc ) {
1384 
1385  intf_restart ( &peer->plogi, rc );
1386 
1387  if ( rc != 0 )
1388  fc_peer_logout ( peer, rc );
1389 }
1390 
1391 /**
1392  * Initiate PLOGI
1393  *
1394  * @v peer Fibre Channel peer
1395  * @v port Fibre Channel port
1396  * @v peer_port_id Peer port ID
1397  * @ret rc Return status code
1398  */
1399 static int fc_peer_plogi ( struct fc_peer *peer, struct fc_port *port,
1400  struct fc_port_id *peer_port_id ) {
1401  int rc;
1402 
1403  /* Try to create PLOGI ELS */
1404  intf_restart ( &peer->plogi, -ECANCELED );
1405  if ( ( rc = fc_els_plogi ( &peer->plogi, port, peer_port_id ) ) != 0 ) {
1406  DBGC ( peer, "FCPEER %s could not initiate PLOGI: %s\n",
1407  fc_ntoa ( &peer->port_wwn ), strerror ( rc ) );
1408  fc_peer_logout ( peer, rc );
1409  return rc;
1410  }
1411 
1412  return 0;
1413 }
1414 
1415 /**
1416  * Examine Fibre Channel peer link state
1417  *
1418  * @ link Fibre Channel link state monitor
1419  */
1420 static void fc_peer_examine ( struct fc_link_state *link ) {
1421  struct fc_peer *peer = container_of ( link, struct fc_peer, link );
1422  struct fc_port *port;
1423  int rc;
1424 
1425  /* Check to see if underlying port link has gone down */
1426  if ( peer->port && ( ! fc_link_ok ( &peer->port->link ) ) ) {
1427  fc_peer_logout ( peer, -ENOTCONN );
1428  return;
1429  }
1430 
1431  /* Do nothing if already logged in */
1432  if ( fc_link_ok ( &peer->link ) )
1433  return;
1434 
1435  DBGC ( peer, "FCPEER %s attempting login\n",
1436  fc_ntoa ( &peer->port_wwn ) );
1437 
1438  /* Sanity check */
1439  assert ( peer->port == NULL );
1440 
1441  /* First, look for a port with the peer attached via a
1442  * point-to-point link.
1443  */
1445  if ( fc_link_ok ( &port->link ) &&
1446  ( ! ( port->flags & FC_PORT_HAS_FABRIC ) ) &&
1447  ( memcmp ( &peer->port_wwn, &port->link_port_wwn,
1448  sizeof ( peer->port_wwn ) ) == 0 ) ) {
1449  /* Use this peer port ID, and stop looking */
1450  fc_peer_plogi ( peer, port, &port->ptp_link_port_id );
1451  return;
1452  }
1453  }
1454 
1455  /* If the peer is not directly attached, try initiating a name
1456  * server lookup on any suitable ports.
1457  */
1459  if ( fc_link_ok ( &port->link ) &&
1460  ( port->flags & FC_PORT_HAS_FABRIC ) &&
1461  ( port->flags & FC_PORT_HAS_NS ) ) {
1462  if ( ( rc = fc_ns_query ( peer, port,
1463  fc_peer_plogi ) ) != 0 ) {
1464  DBGC ( peer, "FCPEER %s could not attempt "
1465  "name server lookup on %s: %s\n",
1466  fc_ntoa ( &peer->port_wwn ), port->name,
1467  strerror ( rc ) );
1468  /* Non-fatal */
1469  }
1470  }
1471  }
1472 }
1473 
1474 /** Fibre Channel peer PLOGI interface operations */
1477 };
1478 
1479 /** Fibre Channel peer PLOGI interface descriptor */
1481  INTF_DESC ( struct fc_peer, plogi, fc_peer_plogi_op );
1482 
1483 /**
1484  * Create Fibre Channel peer
1485  *
1486  * @v port_wwn Node name
1487  * @ret peer Fibre Channel peer, or NULL
1488  */
1489 static struct fc_peer * fc_peer_create ( const struct fc_name *port_wwn ) {
1490  struct fc_peer *peer;
1491 
1492  /* Allocate and initialise structure */
1493  peer = zalloc ( sizeof ( *peer ) );
1494  if ( ! peer )
1495  return NULL;
1496  ref_init ( &peer->refcnt, NULL );
1497  fc_link_init ( &peer->link, fc_peer_examine, &peer->refcnt );
1498  intf_init ( &peer->plogi, &fc_peer_plogi_desc, &peer->refcnt );
1499  list_add_tail ( &peer->list, &fc_peers );
1500  memcpy ( &peer->port_wwn, port_wwn, sizeof ( peer->port_wwn ) );
1501  INIT_LIST_HEAD ( &peer->ulps );
1502 
1503  /* Start link monitor */
1504  fc_link_start ( &peer->link );
1505 
1506  DBGC ( peer, "FCPEER %s created\n", fc_ntoa ( &peer->port_wwn ) );
1507  return peer;
1508 }
1509 
1510 /**
1511  * Get Fibre Channel peer by node name
1512  *
1513  * @v port_wwn Node name
1514  * @ret peer Fibre Channel peer, or NULL
1515  */
1516 struct fc_peer * fc_peer_get_wwn ( const struct fc_name *port_wwn ) {
1517  struct fc_peer *peer;
1518 
1519  /* Look for an existing peer */
1520  list_for_each_entry ( peer, &fc_peers, list ) {
1521  if ( memcmp ( &peer->port_wwn, port_wwn,
1522  sizeof ( peer->port_wwn ) ) == 0 )
1523  return fc_peer_get ( peer );
1524  }
1525 
1526  /* Create a new peer */
1527  peer = fc_peer_create ( port_wwn );
1528  if ( ! peer )
1529  return NULL;
1530 
1531  return peer;
1532 }
1533 
1534 /**
1535  * Get Fibre Channel peer by port ID
1536  *
1537  * @v port Fibre Channel port
1538  * @v peer_port_id Peer port ID
1539  * @ret peer Fibre Channel peer, or NULL
1540  */
1542  const struct fc_port_id *peer_port_id ){
1543  struct fc_peer *peer;
1544 
1545  /* Look for an existing peer */
1546  list_for_each_entry ( peer, &fc_peers, list ) {
1547  if ( ( peer->port == port ) &&
1548  ( memcmp ( &peer->port_id, peer_port_id,
1549  sizeof ( peer->port_id ) ) == 0 ) )
1550  return fc_peer_get ( peer );
1551  }
1552 
1553  /* Cannot create a new peer, since we have no port name to use */
1554  return NULL;
1555 }
1556 
1557 /******************************************************************************
1558  *
1559  * Fibre Channel upper-layer protocols
1560  *
1561  ******************************************************************************
1562  */
1563 
1564 /**
1565  * Free Fibre Channel upper-layer protocol
1566  *
1567  * @v refcnt Reference count
1568  */
1569 static void fc_ulp_free ( struct refcnt *refcnt ) {
1570  struct fc_ulp *ulp = container_of ( refcnt, struct fc_ulp, refcnt );
1571 
1572  fc_peer_put ( ulp->peer );
1573  free ( ulp );
1574 }
1575 
1576 /**
1577  * Close Fibre Channel upper-layer protocol
1578  *
1579  * @v ulp Fibre Channel upper-layer protocol
1580  * @v rc Reason for close
1581  */
1582 static void fc_ulp_close ( struct fc_ulp *ulp, int rc ) {
1583 
1584  DBGC ( ulp, "FCULP %s/%02x closed: %s\n",
1585  fc_ntoa ( &ulp->peer->port_wwn ), ulp->type, strerror ( rc ) );
1586 
1587  /* Sanity check */
1588  assert ( list_empty ( &ulp->users ) );
1589 
1590  /* Stop link monitor */
1591  fc_link_stop ( &ulp->link );
1592 
1593  /* Shut down interfaces */
1594  intf_shutdown ( &ulp->prli, rc );
1595 
1596  /* Remove from list of ULPs */
1597  list_del ( &ulp->list );
1598  INIT_LIST_HEAD ( &ulp->list );
1599 }
1600 
1601 /**
1602  * Attach Fibre Channel upper-layer protocol user
1603  *
1604  * @v ulp Fibre Channel upper-layer protocol
1605  * @v user Fibre Channel upper-layer protocol user
1606  */
1607 void fc_ulp_attach ( struct fc_ulp *ulp, struct fc_ulp_user *user ) {
1608 
1609  /* Sanity check */
1610  assert ( user->ulp == NULL );
1611 
1612  /* Increment peer's usage count */
1613  fc_peer_increment ( ulp->peer );
1614 
1615  /* Attach user */
1616  user->ulp = fc_ulp_get ( ulp );
1617  list_add ( &user->list, &ulp->users );
1618 }
1619 
1620 /**
1621  * Detach Fibre Channel upper-layer protocol user
1622  *
1623  * @v user Fibre Channel upper-layer protocol user
1624  */
1625 void fc_ulp_detach ( struct fc_ulp_user *user ) {
1626  struct fc_ulp *ulp = user->ulp;
1627 
1628  /* Do nothing if not attached */
1629  if ( ! ulp )
1630  return;
1631 
1632  /* Sanity checks */
1634 
1635  /* Detach user and log out if no users remain */
1636  list_del ( &user->list );
1637  if ( list_empty ( &ulp->users ) )
1638  fc_ulp_logout ( ulp, 0 );
1639 
1640  /* Decrement our peer's usage count */
1641  fc_peer_decrement ( ulp->peer );
1642 
1643  /* Drop reference */
1644  user->ulp = NULL;
1645  fc_ulp_put ( ulp );
1646 }
1647 
1648 /**
1649  * Log in Fibre Channel upper-layer protocol
1650  *
1651  * @v ulp Fibre Channel upper-layer protocol
1652  * @v param Service parameters
1653  * @v param_len Length of service parameters
1654  * @v originated Login was originated by us
1655  * @ret rc Return status code
1656  */
1657 int fc_ulp_login ( struct fc_ulp *ulp, const void *param, size_t param_len,
1658  int originated ) {
1659  struct fc_ulp_user *user;
1660  struct fc_ulp_user *tmp;
1661 
1662  /* Perform implicit logout if logged in and service parameters differ */
1663  if ( fc_link_ok ( &ulp->link ) &&
1664  ( ( ulp->param_len != param_len ) ||
1665  ( memcmp ( ulp->param, param, ulp->param_len ) != 0 ) ) ) {
1666  fc_ulp_logout ( ulp, 0 );
1667  }
1668 
1669  /* Work around a bug in some versions of the Linux Fibre
1670  * Channel stack, which fail to fully initialise image pairs
1671  * established via a PRLI originated by the Linux stack
1672  * itself.
1673  */
1674  if ( originated )
1676  if ( ! ( ulp->flags & FC_ULP_ORIGINATED_LOGIN_OK ) ) {
1677  DBGC ( ulp, "FCULP %s/%02x sending extra PRLI to work around "
1678  "Linux bug\n",
1679  fc_ntoa ( &ulp->peer->port_wwn ), ulp->type );
1680  fc_link_stop ( &ulp->link );
1681  fc_link_start ( &ulp->link );
1682  return 0;
1683  }
1684 
1685  /* Log in, if applicable */
1686  if ( ! fc_link_ok ( &ulp->link ) ) {
1687 
1688  /* Record service parameters */
1689  assert ( ulp->param == NULL );
1690  assert ( ulp->param_len == 0 );
1691  ulp->param = malloc ( param_len );
1692  if ( ! ulp->param ) {
1693  DBGC ( ulp, "FCULP %s/%02x could not record "
1694  "parameters\n",
1695  fc_ntoa ( &ulp->peer->port_wwn ), ulp->type );
1696  return -ENOMEM;
1697  }
1698  memcpy ( ulp->param, param, param_len );
1699  ulp->param_len = param_len;
1700  DBGC ( ulp, "FCULP %s/%02x logged in with parameters:\n",
1701  fc_ntoa ( &ulp->peer->port_wwn ), ulp->type );
1702  DBGC_HDA ( ulp, 0, ulp->param, ulp->param_len );
1703 
1704  /* Add login reference */
1705  fc_ulp_get ( ulp );
1706  }
1707 
1708  /* Record login */
1709  fc_link_up ( &ulp->link );
1710 
1711  /* Notify users of link state change */
1713  fc_ulp_user_get ( user );
1714  user->examine ( user );
1715  fc_ulp_user_put ( user );
1716  }
1717 
1718  return 0;
1719 }
1720 
1721 /**
1722  * Log out Fibre Channel upper-layer protocol
1723  *
1724  * @v ulp Fibre Channel upper-layer protocol
1725  * @v rc Reason for logout
1726  */
1727 void fc_ulp_logout ( struct fc_ulp *ulp, int rc ) {
1728  struct fc_ulp_user *user;
1729  struct fc_ulp_user *tmp;
1730 
1731  DBGC ( ulp, "FCULP %s/%02x logged out: %s\n",
1732  fc_ntoa ( &ulp->peer->port_wwn ), ulp->type, strerror ( rc ) );
1733 
1734  /* Drop login reference, if applicable */
1735  if ( fc_link_ok ( &ulp->link ) )
1736  fc_ulp_put ( ulp );
1737 
1738  /* Discard service parameters */
1739  free ( ulp->param );
1740  ulp->param = NULL;
1741  ulp->param_len = 0;
1742  ulp->flags = 0;
1743 
1744  /* Record logout */
1745  fc_link_err ( &ulp->link, rc );
1746 
1747  /* Notify users of link state change */
1749  fc_ulp_user_get ( user );
1750  user->examine ( user );
1751  fc_ulp_user_put ( user );
1752  }
1753 
1754  /* Close ULP if there are no clients attached */
1755  if ( list_empty ( &ulp->users ) )
1756  fc_ulp_close ( ulp, rc );
1757 }
1758 
1759 /**
1760  * Handle PRLI completion
1761  *
1762  * @v ulp Fibre Channel upper-layer protocol
1763  * @v rc Reason for completion
1764  */
1765 static void fc_ulp_prli_done ( struct fc_ulp *ulp, int rc ) {
1766 
1767  intf_restart ( &ulp->prli, rc );
1768 
1769  if ( rc != 0 )
1770  fc_ulp_logout ( ulp, rc );
1771 }
1772 
1773 /**
1774  * Examine Fibre Channel upper-layer protocol link state
1775  *
1776  * @ link Fibre Channel link state monitor
1777  */
1778 static void fc_ulp_examine ( struct fc_link_state *link ) {
1779  struct fc_ulp *ulp = container_of ( link, struct fc_ulp, link );
1780  int rc;
1781 
1782  /* Check to see if underlying peer link has gone down */
1783  if ( ! fc_link_ok ( &ulp->peer->link ) ) {
1784  fc_ulp_logout ( ulp, -ENOTCONN );
1785  return;
1786  }
1787 
1788  /* Do nothing if already logged in */
1789  if ( fc_link_ok ( &ulp->link ) &&
1790  ( ulp->flags & FC_ULP_ORIGINATED_LOGIN_OK ) )
1791  return;
1792 
1793  DBGC ( ulp, "FCULP %s/%02x attempting login\n",
1794  fc_ntoa ( &ulp->peer->port_wwn ), ulp->type );
1795 
1796  /* Try to create PRLI ELS */
1797  intf_restart ( &ulp->prli, -ECANCELED );
1798  if ( ( rc = fc_els_prli ( &ulp->prli, ulp->peer->port,
1799  &ulp->peer->port_id, ulp->type ) ) != 0 ) {
1800  DBGC ( ulp, "FCULP %s/%02x could not initiate PRLI: %s\n",
1801  fc_ntoa ( &ulp->peer->port_wwn ), ulp->type,
1802  strerror ( rc ) );
1803  fc_ulp_logout ( ulp, rc );
1804  return;
1805  }
1806 }
1807 
1808 /** Fibre Channel upper-layer protocol PRLI interface operations */
1810  INTF_OP ( intf_close, struct fc_ulp *, fc_ulp_prli_done ),
1811 };
1812 
1813 /** Fibre Channel upper-layer protocol PRLI interface descriptor */
1815  INTF_DESC ( struct fc_ulp, prli, fc_ulp_prli_op );
1816 
1817 /**
1818  * Create Fibre Channel upper-layer protocl
1819  *
1820  * @v peer Fibre Channel peer
1821  * @v type Type
1822  * @ret ulp Fibre Channel upper-layer protocol, or NULL
1823  */
1824 static struct fc_ulp * fc_ulp_create ( struct fc_peer *peer,
1825  unsigned int type ) {
1826  struct fc_ulp *ulp;
1827 
1828  /* Allocate and initialise structure */
1829  ulp = zalloc ( sizeof ( *ulp ) );
1830  if ( ! ulp )
1831  return NULL;
1832  ref_init ( &ulp->refcnt, fc_ulp_free );
1833  fc_link_init ( &ulp->link, fc_ulp_examine, &ulp->refcnt );
1834  intf_init ( &ulp->prli, &fc_ulp_prli_desc, &ulp->refcnt );
1835  ulp->peer = fc_peer_get ( peer );
1836  list_add_tail ( &ulp->list, &peer->ulps );
1837  ulp->type = type;
1838  INIT_LIST_HEAD ( &ulp->users );
1839 
1840  /* Start link state monitor */
1841  fc_link_start ( &ulp->link );
1842 
1843  DBGC ( ulp, "FCULP %s/%02x created\n",
1844  fc_ntoa ( &ulp->peer->port_wwn ), ulp->type );
1845  return ulp;
1846 }
1847 
1848 /**
1849  * Get Fibre Channel upper-layer protocol by peer and type
1850  *
1851  * @v peer Fibre Channel peer
1852  * @v type Type
1853  * @ret ulp Fibre Channel upper-layer protocol, or NULL
1854  */
1855 static struct fc_ulp * fc_ulp_get_type ( struct fc_peer *peer,
1856  unsigned int type ) {
1857  struct fc_ulp *ulp;
1858 
1859  /* Look for an existing ULP */
1860  list_for_each_entry ( ulp, &peer->ulps, list ) {
1861  if ( ulp->type == type )
1862  return fc_ulp_get ( ulp );
1863  }
1864 
1865  /* Create a new ULP */
1866  ulp = fc_ulp_create ( peer, type );
1867  if ( ! ulp )
1868  return NULL;
1869 
1870  return ulp;
1871 }
1872 
1873 /**
1874  * Get Fibre Channel upper-layer protocol by port name and type
1875  *
1876  * @v port_wwn Port name
1877  * @v type Type
1878  * @ret ulp Fibre Channel upper-layer protocol, or NULL
1879  */
1880 struct fc_ulp * fc_ulp_get_wwn_type ( const struct fc_name *port_wwn,
1881  unsigned int type ) {
1882  struct fc_ulp *ulp;
1883  struct fc_peer *peer;
1884 
1885  /* Get peer */
1886  peer = fc_peer_get_wwn ( port_wwn );
1887  if ( ! peer )
1888  goto err_peer_get_wwn;
1889 
1890  /* Get ULP */
1891  ulp = fc_ulp_get_type ( peer, type );
1892  if ( ! ulp )
1893  goto err_ulp_get_type;
1894 
1895  /* Drop temporary reference to peer */
1896  fc_peer_put ( peer );
1897 
1898  return ulp;
1899 
1900  fc_ulp_put ( ulp );
1901  err_ulp_get_type:
1902  fc_peer_put ( peer );
1903  err_peer_get_wwn:
1904  return NULL;
1905 }
1906 
1907 /**
1908  * Get Fibre Channel upper-layer protocol by port ID and type
1909  *
1910  * @v port Fibre Channel port
1911  * @v peer_port_id Peer port ID
1912  * @v type Type
1913  * @ret ulp Fibre Channel upper-layer protocol, or NULL
1914  */
1916  const struct fc_port_id *peer_port_id,
1917  unsigned int type ) {
1918  struct fc_ulp *ulp;
1919  struct fc_peer *peer;
1920 
1921  /* Get peer */
1922  peer = fc_peer_get_port_id ( port, peer_port_id );
1923  if ( ! peer )
1924  goto err_peer_get_wwn;
1925 
1926  /* Get ULP */
1927  ulp = fc_ulp_get_type ( peer, type );
1928  if ( ! ulp )
1929  goto err_ulp_get_type;
1930 
1931  /* Drop temporary reference to peer */
1932  fc_peer_put ( peer );
1933 
1934  return ulp;
1935 
1936  fc_ulp_put ( ulp );
1937  err_ulp_get_type:
1938  fc_peer_put ( peer );
1939  err_peer_get_wwn:
1940  return NULL;
1941 }
1942 
1943 /* Drag in objects via fc_ports */
1945 
1946 /* Drag in Fibre Channel configuration */
1947 REQUIRE_OBJECT ( config_fc );
#define iob_pull(iobuf, len)
Definition: iobuf.h:98
void fc_ulp_detach(struct fc_ulp_user *user)
Detach Fibre Channel upper-layer protocol user.
Definition: fc.c:1625
struct interface ulp
Upper-layer protocol interface.
Definition: fc.c:314
#define EINVAL
Invalid argument.
Definition: errno.h:428
An object interface operation.
Definition: interface.h:17
unsigned int flags
Flags.
Definition: fc.c:300
Solicited Data.
Definition: fc.h:177
char name[8]
Name of this port.
Definition: fc.h:258
struct fc_name port_wwn
Port name.
Definition: fc.h:265
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
static void fc_port_examine(struct fc_link_state *link)
Examine Fibre Channel port link state.
Definition: fc.c:1101
const char * name
Definition: ath9k_hw.c:1984
void xfer_window_changed(struct interface *intf)
Report change of flow control window.
Definition: xfer.c:145
unsigned short uint16_t
Definition: stdint.h:11
void intf_close(struct interface *intf, int rc)
Close an object interface.
Definition: interface.c:244
static struct interface_descriptor fc_xchg_ulp_desc
Fibre Channel exchange ULP interface descriptor.
Definition: fc.c:685
static void fc_ulp_free(struct refcnt *refcnt)
Free Fibre Channel upper-layer protocol.
Definition: fc.c:1569
void intf_restart(struct interface *intf, int rc)
Shut down and restart an object interface.
Definition: interface.c:337
struct fc_port_id fc_ptp_high_port_id
Point-to-point high port ID.
Definition: fc.c:77
static struct fc_ulp * fc_ulp_get_type(struct fc_peer *peer, unsigned int type)
Get Fibre Channel upper-layer protocol by peer and type.
Definition: fc.c:1855
Data transfer metadata.
Definition: xfer.h:22
void intf_shutdown(struct interface *intf, int rc)
Shut down an object interface.
Definition: interface.c:273
struct list_head fc_peers
struct fc_ulp * ulp
Fibre Channel upper layer protocol.
Definition: fc.h:455
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
struct list_head list
List of all ports.
Definition: fc.h:256
int xfer_deliver_iob(struct interface *intf, struct io_buffer *iobuf)
Deliver datagram as I/O buffer without metadata.
Definition: xfer.c:254
#define FC_LINK_RETRY_DELAY
Delay between failed link-up attempts.
Definition: fc.h:86
#define EBUSY
Device or resource busy.
Definition: errno.h:338
static void start_timer_nodelay(struct retry_timer *timer)
Start timer with no delay.
Definition: retry.h:99
unsigned long strtoul(const char *string, char **endp, int base)
Convert string to numeric value.
Definition: string.c:441
Last Sequence of Exchange.
Definition: fc.h:202
struct sockaddr sa
Definition: dns.c:68
static void fc_port_flogi_done(struct fc_port *port, int rc)
Handle FLOGI completion.
Definition: fc.c:1067
int fc_aton(const char *wwn_text, struct fc_name *wwn)
Parse Fibre Channel WWN.
Definition: fc.c:144
uint8_t seq_id
Active sequence ID.
Definition: fc.c:306
static unsigned int fc_new_xchg_id(void)
Create local Fibre Channel exchange identifier.
Definition: fc.c:335
#define list_add(new, head)
Add a new entry to the head of a list.
Definition: list.h:69
A Fibre Channel name server query.
Definition: fcns.c:45
const char * fc_id_ntoa(const struct fc_port_id *id)
Format Fibre Channel port ID.
Definition: fc.c:92
uint16_t seq_cnt
Sequence count.
Definition: fc.h:146
#define XFER_FL_ABS_OFFSET
Offset is absolute.
Definition: xfer.h:47
#define ref_init(refcnt, free)
Initialise a reference counter.
Definition: refcnt.h:64
Error codes.
static void fc_peer_decrement(struct fc_peer *peer)
Decrement Fibre Channel peer active usage count.
Definition: fc.c:1282
#define iob_push(iobuf, len)
Definition: iobuf.h:80
static struct interface_operation fc_ulp_prli_op[]
Fibre Channel upper-layer protocol PRLI interface operations.
Definition: fc.c:1809
uint8_t seq_id
Sequence ID.
Definition: fc.h:142
u16 fc
802.11 Frame Control field
Definition: ieee80211.h:14
I/O buffers.
unsigned int type
Data structure type.
Definition: fc.c:298
unsigned int type
Type.
Definition: fc.h:224
void free_iob(struct io_buffer *iobuf)
Free I/O buffer.
Definition: iobuf.c:145
static void fc_link_examine(struct fc_link_state *link)
Examine Fibre Channel link state.
Definition: fc.c:226
struct refcnt refcnt
Reference count.
Definition: fc.c:289
uint8_t type
Type.
Definition: ena.h:16
#define EPIPE
Broken pipe.
Definition: errno.h:619
Retry timers.
struct fc_peer * fc_peer_get_wwn(const struct fc_name *port_wwn)
Get Fibre Channel peer by node name.
Definition: fc.c:1516
uint16_t seq_cnt
Active sequence count.
Definition: fc.c:308
static void fc_link_init(struct fc_link_state *link, void(*examine)(struct fc_link_state *link), struct refcnt *refcnt)
Initialise Fibre Channel link state monitor.
Definition: fc.c:252
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
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
struct fc_port_id fc_ptp_low_port_id
Point-to-point low port ID.
Definition: fc.c:74
#define DBGC(...)
Definition: compiler.h:505
struct fc_name node_wwn
Node name.
Definition: fc.h:263
static struct interface_operation fc_port_transport_op[]
Fibre Channel port transport interface operations.
Definition: fc.c:1151
#define EUNKNOWN_LINK_STATUS
Default link status code.
Definition: fc.c:186
static void fc_peer_increment(struct fc_peer *peer)
Increment Fibre Channel peer active usage count.
Definition: fc.c:1271
A retry timer.
Definition: retry.h:21
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
struct refcnt refcnt
Reference count.
Definition: fc.h:342
static struct interface_descriptor fc_ulp_prli_desc
Fibre Channel upper-layer protocol PRLI interface descriptor.
Definition: fc.c:1814
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:102
We have the sequence initiative.
Definition: fc.c:322
struct list_head list
List of upper-layer protocols.
Definition: fc.h:419
#define ntohl(value)
Definition: byteswap.h:134
struct io_buffer * xfer_alloc_iob(struct interface *intf, size_t len)
Allocate I/O buffer.
Definition: xfer.c:157
uint16_t xchg_id
Local exchange ID.
Definition: fc.c:302
struct fc_port_id sfc_port_id
Port ID.
Definition: fc.h:54
Extended Link Services.
Definition: fc.h:162
static void fc_port_put(struct fc_port *port)
Drop reference to Fibre Channel port.
Definition: fc.h:315
iPXE timers
#define ntohs(value)
Definition: byteswap.h:136
const char * fc_ntoa(const struct fc_name *wwn)
Format Fibre Channel WWN.
Definition: fc.c:127
uint8_t f_ctl_misc
Frame control - miscellaneous.
Definition: fc.h:140
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
static struct interface_operation fc_xchg_ulp_op[]
Fibre Channel exchange ULP interface operations.
Definition: fc.c:677
sa_family_t sfc_family
Socket address family (part of struct sockaddr)
Definition: fc.h:52
static void fc_link_err(struct fc_link_state *link, int rc)
Mark Fibre Channel link as down.
Definition: fc.c:210
#define FC_PORT_ID_STRLEN
Length of Fibre Channel port identifier next.
Definition: fc.h:42
struct list_head fc_ports
Last Data Frame of Sequence.
Definition: fc.h:203
Unsolicited Control.
Definition: fc.h:178
struct fc_peer * peer
Fibre Channel peer.
Definition: fc.h:417
We are the exchange originator.
Definition: fc.c:320
A Fibre Channel port.
Definition: fc.h:252
struct fc_port_id s_id
Source ID.
Definition: fc.h:132
#define htonl(value)
Definition: byteswap.h:133
#define AF_FC
Fibre Channel addresses.
Definition: socket.h:65
size_t xfer_window(struct interface *intf)
Check flow control window.
Definition: xfer.c:115
#define ECANCELED
Operation canceled.
Definition: errno.h:343
static struct interface_operation fc_port_ns_plogi_op[]
Fibre Channel port name server PLOGI interface operations.
Definition: fc.c:1172
struct list_head users
Active users of this upper-layer protocol.
Definition: fc.h:443
A doubly-linked list entry (or list head)
Definition: list.h:18
Data transfer interfaces.
A reference counter.
Definition: refcnt.h:26
struct fc_port_id port_id
Local port ID.
Definition: fc.h:267
#define FC_RESPONDERS
Fibre Channel responder table.
Definition: fc.h:239
REQUIRING_SYMBOL(fc_ports)
A timer.
Definition: timer.h:28
Unsolicited Command.
Definition: fc.h:182
struct list_head list
List of users.
Definition: fc.h:457
uint8_t bytes[3]
Definition: fc.h:38
static void fc_peer_examine(struct fc_link_state *link)
Examine Fibre Channel peer link state.
Definition: fc.c:1420
Extended Link Service.
Definition: fc.h:192
#define list_empty(list)
Test whether a list is empty.
Definition: list.h:136
struct fc_port * port
Fibre Channel port, if known.
Definition: fc.h:354
static struct fc_ulp_user * fc_ulp_user_get(struct fc_ulp_user *user)
Get reference to Fibre Channel upper-layer protocol user.
Definition: fc.h:496
#define XFER_FL_RESPONSE
Data content is a response.
Definition: xfer.h:63
static struct interface_descriptor fc_peer_plogi_desc
Fibre Channel peer PLOGI interface descriptor.
Definition: fc.c:1480
#define list_del(list)
Delete an entry from a list.
Definition: list.h:119
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
static struct interface_operation fc_port_flogi_op[]
Fibre Channel port FLOGI interface operations.
Definition: fc.c:1163
#define ENOMEM
Not enough space.
Definition: errno.h:534
#define iob_disown(iobuf)
Disown an I/O buffer.
Definition: iobuf.h:208
void * memcpy(void *dest, const void *src, size_t len) __nonnull
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
Fibre Channel name server lookups.
Port is attached to a fabric.
Definition: fc.h:292
Assertions.
static struct interface_descriptor fc_port_flogi_desc
Fibre Channel port FLOGI interface descriptor.
Definition: fc.c:1168
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
#define container_of(ptr, type, field)
Get containing structure.
Definition: stddef.h:35
static void fc_peer_plogi_done(struct fc_peer *peer, int rc)
Handle PLOGI completion.
Definition: fc.c:1383
An object interface.
Definition: interface.h:109
struct list_head ulps
List of upper-layer protocols.
Definition: fc.h:359
void fc_ulp_attach(struct fc_ulp *ulp, struct fc_ulp_user *user)
Attach Fibre Channel upper-layer protocol user.
Definition: fc.c:1607
A Fibre Channel port identifier.
Definition: fc.h:37
static void fc_port_close(struct fc_port *port, int rc)
Close Fibre Channel port.
Definition: fc.c:806
struct fc_port_id peer_port_id
Peer port ID.
Definition: fc.c:296
struct ntlm_data user
User name.
Definition: ntlm.h:20
Command Status.
Definition: fc.h:183
static void fc_xchg_free(struct refcnt *refcnt)
Free Fibre Channel exchange.
Definition: fc.c:359
#define list_for_each_entry(pos, head, member)
Iterate over entries in a list.
Definition: list.h:420
size_t param_len
Service parameter length.
Definition: fc.h:433
#define DBGC_HDA(...)
Definition: compiler.h:506
Object interfaces.
#define list_add_tail(new, head)
Add a new entry to the tail of a list.
Definition: list.h:93
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
static int fc_xchg_tx(struct fc_exchange *xchg, struct io_buffer *iobuf, struct xfer_metadata *meta)
Transmit data as part of a Fibre Channel exchange.
Definition: fc.c:457
A login originated by us has succeeded.
Definition: fc.h:449
uint8_t type
Data structure type.
Definition: fc.h:134
A Fibre Channel exchange.
Definition: fc.c:287
struct sockaddr * fc_fill_sockaddr(struct sockaddr_fc *sa_fc, struct fc_port_id *id)
Fill Fibre Channel socket address.
Definition: fc.c:165
Transfer Sequence Initiative.
Definition: fc.h:204
u32 link
Link to next descriptor.
Definition: ar9003_mac.h:68
struct list_head list
List of all peers.
Definition: fc.h:344
static struct interface_descriptor fc_port_ns_plogi_desc
Fibre Channel port name server PLOGI interface descriptor.
Definition: fc.c:1177
Unsolicited Data.
Definition: fc.h:180
This is the first sequence of the exchange.
Definition: fc.c:324
#define FC_TIMEOUT
Fibre Channel timeout.
Definition: fc.c:328
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
struct interface prli
PRLI interface.
Definition: fc.h:429
unsigned int usage
Active usage count.
Definition: fc.h:369
Solicited Control.
Definition: fc.h:179
static void * dest
Definition: strings.h:176
#define list_for_each_entry_safe(pos, tmp, head, member)
Iterate over entries in a list, safe against deletion of the current entry.
Definition: list.h:447
unsigned int type
Type.
Definition: fc.h:422
uint8_t id
Request identifier.
Definition: ena.h:12
static __always_inline void off_t userptr_t src
Definition: efi_uaccess.h:66
static struct interface_operation fc_peer_plogi_op[]
Fibre Channel peer PLOGI interface operations.
Definition: fc.c:1475
int meta(WINDOW *, bool)
struct fc_port_id fc_empty_port_id
Unassigned port ID.
Definition: fc.c:65
#define ENOTCONN
The socket is not connected.
Definition: errno.h:569
Linked lists.
Generalized socket address structure.
Definition: socket.h:96
An object interface descriptor.
Definition: interface.h:40
static int fc_peer_plogi(struct fc_peer *peer, struct fc_port *port, struct fc_port_id *peer_port_id)
Initiate PLOGI.
Definition: fc.c:1399
Common Transport.
Definition: fc.h:194
int(* respond)(struct interface *xchg, struct fc_port *port, struct fc_port_id *port_id, struct fc_port_id *peer_port_id)
Respond to exchange.
Definition: fc.h:233
static struct fc_exchange * fc_xchg_respond(struct fc_port *port, struct fc_frame_header *fchdr)
Open a new responder Fibre Channel exchange.
Definition: fc.c:755
struct fc_port_id port_id
Peer port ID, if known.
Definition: fc.h:356
char * strerror(int errno)
Retrieve string representation of error number.
Definition: strerror.c:78
off_t offset
Offset of data within stream.
Definition: xfer.h:37
struct fc_port * port
Fibre Channel port.
Definition: fc.c:291
#define FC_R_CTL_INFO_MASK
Fibre Channel Routing Control Information mask.
Definition: fc.h:187
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 struct io_buffer * fc_xchg_alloc_iob(struct fc_exchange *xchg, size_t len)
Allocate Fibre Channel I/O buffer.
Definition: fc.c:436
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
void * zalloc(size_t size)
Allocate cleared memory.
Definition: malloc.c:624
struct fc_link_state link
Link state monitor.
Definition: fc.h:272
static size_t fc_xchg_window(struct fc_exchange *xchg __unused)
Check Fibre Channel exchange window.
Definition: fc.c:423
void * param
Service parameters, if any.
Definition: fc.h:431
#define ref_get(refcnt)
Get additional reference to object.
Definition: refcnt.h:92
Port is logged in to a name server.
Definition: fc.h:294
static struct fc_ulp * fc_ulp_get(struct fc_ulp *ulp)
Get reference to Fibre Channel upper-layer protocol.
Definition: fc.h:474
static struct fc_peer * fc_peer_create(const struct fc_name *port_wwn)
Create Fibre Channel peer.
Definition: fc.c:1489
uint8_t r_ctl
Routing control.
Definition: fc.h:126
static size_t iob_len(struct io_buffer *iobuf)
Calculate length of data in an I/O buffer.
Definition: iobuf.h:151
struct hv_monitor_parameter param[4][32]
Parameters.
Definition: hyperv.h:24
uint8_t * tmp
Definition: entropy.h:156
#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
static void fc_xchg_close(struct fc_exchange *xchg, int rc)
Close Fibre Channel exchange.
Definition: fc.c:376
#define for_each_table_entry(pointer, table)
Iterate through all entries within a linker table.
Definition: tables.h:358
static void fc_ulp_prli_done(struct fc_ulp *ulp, int rc)
Handle PRLI completion.
Definition: fc.c:1765
uint16_t peer_xchg_id
Peer exchange ID.
Definition: fc.c:304
#define XFER_FL_CMD_STAT
Data content represents a command or status message.
Definition: xfer.h:60
int fc_port_open(struct interface *transport, const struct fc_name *node_wwn, const struct fc_name *port_wwn, const char *name)
Create Fibre Channel port.
Definition: fc.c:1189
int xfer_deliver(struct interface *intf, struct io_buffer *iobuf, struct xfer_metadata *meta)
Deliver datagram.
Definition: xfer.c:193
Responder of Exchange.
Definition: fc.h:199
struct fc_name port_wwn
Port name.
Definition: fc.h:347
unsigned char uint8_t
Definition: stdint.h:10
static void fc_ulp_user_put(struct fc_ulp_user *user)
Drop reference to Fibre Channel upper-layer protocol user.
Definition: fc.h:507
A Fibre Channel upper-layer protocol user.
Definition: fc.h:453
Fibre Channel.
static void fc_ulp_examine(struct fc_link_state *link)
Examine Fibre Channel upper-layer protocol link state.
Definition: fc.c:1778
static int fc_xchg_rx(struct fc_exchange *xchg, struct io_buffer *iobuf, struct xfer_metadata *meta __unused)
Receive data as part of a Fibre Channel exchange.
Definition: fc.c:587
static struct fc_peer * fc_peer_get(struct fc_peer *peer)
Get reference to Fibre Channel peer.
Definition: fc.h:379
REQUIRE_OBJECT(config_fc)
unsigned int flags
Flags.
Definition: xfer.h:28
void * malloc(size_t size)
Allocate memory.
Definition: malloc.c:583
Data Descriptor.
Definition: fc.h:181
static void fc_link_stop(struct fc_link_state *link)
Stop monitoring Fibre Channel link state.
Definition: fc.c:275
A Fibre Channel peer.
Definition: fc.h:340
struct sockaddr * src
Source socket address, or NULL.
Definition: xfer.h:39
static unsigned int fc_new_seq_id(void)
Create local Fibre Channel sequence identifier.
Definition: fc.c:348
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 void fc_peer_close(struct fc_peer *peer, int rc)
Close Fibre Channel peer.
Definition: fc.c:1247
A Fibre Channel name.
Definition: fc.h:29
struct refcnt refcnt
Reference count.
Definition: fc.h:415
void start_timer_fixed(struct retry_timer *timer, unsigned long timeout)
Start timer with a specified timeout.
Definition: retry.c:64
uint8_t f_ctl_es
Frame control - exchange and sequence.
Definition: fc.h:136
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
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
#define FC_RX_ID_UNKNOWN
Responder exchange identifier used before first response.
Definition: fc.h:213
#define iob_reserve(iobuf, len)
Definition: iobuf.h:63
#define INIT_LIST_HEAD(list)
Initialise a list head.
Definition: list.h:45
#define INTF_DESC(object_type, intf, operations)
Define an object interface descriptor.
Definition: interface.h:65
void stop_timer(struct retry_timer *timer)
Stop timer.
Definition: retry.c:117
static struct fc_exchange * fc_port_demux(struct fc_port *port, unsigned int xchg_id)
Identify Fibre Channel exchange by local exchange ID.
Definition: fc.c:840
Device Data.
Definition: fc.h:161
static void fc_link_up(struct fc_link_state *link)
Mark Fibre Channel link as up.
Definition: fc.c:195
uint32_t len
Length.
Definition: ena.h:14
#define DBGC2(...)
Definition: compiler.h:522
int strcmp(const char *first, const char *second)
Compare strings.
Definition: string.c:157
static void fc_port_ns_plogi_done(struct fc_port *port, int rc)
Handle name server PLOGI completion.
Definition: fc.c:1081
struct sockaddr * dest
Destination socket address, or NULL.
Definition: xfer.h:41
static struct fc_ulp * fc_ulp_create(struct fc_peer *peer, unsigned int type)
Create Fibre Channel upper-layer protocl.
Definition: fc.c:1824
void * data
Start of data.
Definition: iobuf.h:44
struct interface transport
Transport interface.
Definition: fc.h:261
static void fc_ulp_put(struct fc_ulp *ulp)
Drop reference to Fibre Channel upper-layer protocol.
Definition: fc.h:485
Reference counting.
struct fc_port * fc_port_find(const char *name)
Find Fibre Channel port by name.
Definition: fc.c:1224
struct retry_timer timer
Timeout timer.
Definition: fc.c:311
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
Linker tables.
struct fc_port_id d_id
Destination ID.
Definition: fc.h:128
static void fc_link_expired(struct retry_timer *timer, int over __unused)
Handle Fibre Channel link retry timer expiry.
Definition: fc.c:234
int snprintf(char *buf, size_t size, const char *fmt,...)
Write a formatted string to a buffer.
Definition: vsprintf.c:382
#define XFER_FL_OVER
Sender is relinquishing use of half-duplex channel.
Definition: xfer.h:50
void fc_port_logout(struct fc_port *port, int rc)
Log out Fibre Channel port.
Definition: fc.c:1039
LIST_HEAD(fc_ports)
List of Fibre Channel ports.
static struct fc_exchange * fc_xchg_create(struct fc_port *port, struct fc_port_id *peer_port_id, unsigned int type)
Create new Fibre Channel exchange.
Definition: fc.c:695
Uncategorized.
Definition: fc.h:176
uint16_t ox_id
Originator exchange ID.
Definition: fc.h:148
fc_exchange_flags
Fibre Channel exchange flags.
Definition: fc.c:318
struct list_head list
List of active exchanges within this port.
Definition: fc.c:293
static void fc_ulp_close(struct fc_ulp *ulp, int rc)
Close Fibre Channel upper-layer protocol.
Definition: fc.c:1582
Relative Offset Present.
Definition: fc.h:209
union @16 u
static void intf_init(struct interface *intf, struct interface_descriptor *desc, struct refcnt *refcnt)
Initialise an object interface.
Definition: interface.h:173
#define FC_NAME_STRLEN
Length of Fibre Channel name text.
Definition: fc.h:34
struct fc_port_id fc_gs_port_id
Generic services port ID.
Definition: fc.c:71
struct fc_ulp * fc_ulp_get_wwn_type(const struct fc_name *port_wwn, unsigned int type)
Get Fibre Channel upper-layer protocol by port name and type.
Definition: fc.c:1880
#define list_check_contains_entry(entry, head, member)
Check list contains a specified entry.
Definition: list.h:522
#define XFER_FL_OUT
This is the final data transfer.
Definition: xfer.h:53
First Sequence of Exchange.
Definition: fc.h:201
int memcmp(const void *first, const void *second, size_t len)
Compare memory regions.
Definition: string.c:98
#define NULL
NULL pointer (VOID *)
Definition: Base.h:362
unsigned int flags
Flags.
Definition: fc.h:424
#define ETIMEDOUT
Connection timed out.
Definition: errno.h:669
String functions.
static const uint8_t fc_r_ctl_info_meta_flags[FC_R_CTL_INFO_MASK+1]
Mapping from Fibre Channel routing control information to xfer metadata.
Definition: fc.c:568
#define htons(value)
Definition: byteswap.h:135
struct bofm_section_header done
Definition: bofm_test.c:46
uint16_t rx_id
Responder exchange ID.
Definition: fc.h:150
static void fc_xchg_expired(struct retry_timer *timer, int over __unused)
Handle exchange timeout.
Definition: fc.c:406
static struct interface_descriptor fc_port_transport_desc
Fibre Channel port transport interface descriptor.
Definition: fc.c:1159
uint32_t parameter
Parameter.
Definition: fc.h:156
#define ref_put(refcnt)
Drop reference to object.
Definition: refcnt.h:106
A Fibre Channel upper-layer protocol.
Definition: fc.h:413
static void fc_port_window_changed(struct fc_port *port)
Handle change of flow control window.
Definition: fc.c:1126
Fibre Channel Extended Link Services.
int fc_id_aton(const char *id_text, struct fc_port_id *id)
Parse Fibre Channel port ID.
Definition: fc.c:107
A Fibre Channel Frame Header.
Definition: fc.h:120
void * memset(void *dest, int character, size_t len) __nonnull
uint64_t wwn
WWN.
Definition: edd.h:30
static void fc_link_start(struct fc_link_state *link)
Start monitoring Fibre Channel link state.
Definition: fc.c:266
A persistent I/O buffer.
Definition: iobuf.h:32
static int fc_port_deliver(struct fc_port *port, struct io_buffer *iobuf, struct xfer_metadata *meta)
Handle received frame from Fibre Channel port.
Definition: fc.c:859