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
24FILE_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 */
65struct fc_port_id fc_empty_port_id = { .bytes = { 0x00, 0x00, 0x00 } };
66
67/** F_Port contoller port ID */
68struct fc_port_id fc_f_port_id = { .bytes = { 0xff, 0xff, 0xfe } };
69
70/** Generic services port ID */
71struct fc_port_id fc_gs_port_id = { .bytes = { 0xff, 0xff, 0xfc } };
72
73/** Point-to-point low port ID */
74struct fc_port_id fc_ptp_low_port_id = { .bytes = { 0x01, 0x01, 0x01 } };
75
76/** Point-to-point high port ID */
77struct 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 */
92const 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 */
107int 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 */
127const 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 */
144int 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 */
165struct 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 */
195static 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 */
210static 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 */
226static 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 */
234static void fc_link_expired ( struct retry_timer *timer, int over __unused ) {
235 struct fc_link_state *link =
237
238 /* Schedule another link examination */
240
241 /* 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 */
252static void fc_link_init ( struct fc_link_state *link,
253 void ( * examine ) ( struct fc_link_state *link ),
254 struct refcnt *refcnt ) {
255
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 */
266static 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 */
275static 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 */
288 /** Reference count */
290 /** Fibre Channel port */
291 struct fc_port *port;
292 /** List of active exchanges within this port */
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 */
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 */
335static 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 */
348static 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 */
359static void fc_xchg_free ( struct refcnt *refcnt ) {
360 struct fc_exchange *xchg =
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 */
376static 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 */
406static 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 */
423static size_t fc_xchg_window ( struct fc_exchange *xchg __unused ) {
424
425 /* We don't currently store the path 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 */
436static 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 */
457static 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 */
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 */
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 */
587static 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 ) {
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 */
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 */
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 */
695static 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 );
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 */
728int 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 */
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 */
755static 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 */
806static 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 ) )
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 */
840static 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 */
859static int fc_port_deliver ( struct fc_port *port, struct io_buffer *iobuf,
860 struct xfer_metadata *meta ) {
861 struct fc_frame_header *fchdr;
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 fchdr = iobuf->data;
874
875 /* Verify local port ID */
876 if ( ( memcmp ( &fchdr->d_id, &port->port_id,
877 sizeof ( fchdr->d_id ) ) != 0 ) &&
878 ( memcmp ( &fchdr->d_id, &fc_f_port_id,
879 sizeof ( fchdr->d_id ) ) != 0 ) &&
880 ( memcmp ( &port->port_id, &fc_empty_port_id,
881 sizeof ( port->port_id ) ) != 0 ) ) {
882 DBGC ( port, "FCPORT %s received frame for incorrect port ID "
883 "%s\n", port->name, fc_id_ntoa ( &fchdr->d_id ) );
884 rc = -ENOTCONN;
885 goto err_port_id;
886 }
887
888 /* Demultiplex amongst active exchanges */
890 fchdr->ox_id : fchdr->rx_id );
891 xchg = fc_port_demux ( port, xchg_id );
892
893 /* If we have no active exchange and this frame starts a new
894 * exchange, try to create a new responder exchange
895 */
896 if ( ( fchdr->f_ctl_es & FC_F_CTL_ES_FIRST ) &&
897 ( fchdr->seq_cnt == 0 ) ) {
898
899 /* Create new exchange */
900 xchg = fc_xchg_respond ( port, fchdr );
901 if ( ! xchg ) {
902 DBGC ( port, "FCPORT %s cannot create new exchange\n",
903 port->name );
904 rc = -ENOMEM;
905 goto err_respond;
906 }
907 }
908
909 /* Fail if no exchange exists */
910 if ( ! xchg ) {
911 DBGC ( port, "FCPORT %s xchg %04x unknown\n",
912 port->name, xchg_id );
913 rc = -ENOTCONN;
914 goto err_no_xchg;
915 }
916
917 /* Pass received frame to exchange */
918 ref_get ( &xchg->refcnt );
919 if ( ( rc = fc_xchg_rx ( xchg, iob_disown ( iobuf ), meta ) ) != 0 )
920 goto err_xchg_rx;
921
922 err_xchg_rx:
923 ref_put ( &xchg->refcnt );
924 err_no_xchg:
925 err_respond:
926 err_port_id:
927 err_sanity:
928 free_iob ( iobuf );
929 return rc;
930}
931
932/**
933 * Log in Fibre Channel port
934 *
935 * @v port Fibre Channel port
936 * @v port_id Local port ID
937 * @v link_node_wwn Link node name
938 * @v link_port_wwn Link port name
939 * @v has_fabric Link is to a fabric
940 * @ret rc Return status code
941 */
942int fc_port_login ( struct fc_port *port, struct fc_port_id *port_id,
943 const struct fc_name *link_node_wwn,
944 const struct fc_name *link_port_wwn, int has_fabric ) {
945 struct fc_peer *peer;
946 struct fc_peer *tmp;
947 int rc;
948
949 /* Perform implicit logout if logged in and details differ */
950 if ( fc_link_ok ( &port->link ) &&
951 ( ( ( !! ( port->flags & FC_PORT_HAS_FABRIC ) ) !=
952 ( !! has_fabric ) ) ||
953 ( memcmp ( &port->link_node_wwn, link_node_wwn,
954 sizeof ( port->link_node_wwn ) ) != 0 ) ||
955 ( memcmp ( &port->link_port_wwn, link_port_wwn,
956 sizeof ( port->link_port_wwn ) ) != 0 ) ||
957 ( has_fabric &&
958 ( memcmp ( &port->port_id, port_id,
959 sizeof ( port->port_id ) ) != 0 ) ) ) ) {
960 fc_port_logout ( port, 0 );
961 }
962
963 /* Log in, if applicable */
964 if ( ! fc_link_ok ( &port->link ) ) {
965
966 /* Record link port name */
967 memcpy ( &port->link_node_wwn, link_node_wwn,
968 sizeof ( port->link_node_wwn ) );
969 memcpy ( &port->link_port_wwn, link_port_wwn,
970 sizeof ( port->link_port_wwn ) );
971 DBGC ( port, "FCPORT %s logged in to %s",
972 port->name, fc_ntoa ( &port->link_node_wwn ) );
973 DBGC ( port, " port %s\n", fc_ntoa ( &port->link_port_wwn ) );
974
975 /* Calculate local (and possibly remote) port IDs */
976 if ( has_fabric ) {
977 port->flags |= FC_PORT_HAS_FABRIC;
978 memcpy ( &port->port_id, port_id,
979 sizeof ( port->port_id ) );
980 } else {
981 port->flags &= ~FC_PORT_HAS_FABRIC;
982 if ( memcmp ( &port->port_wwn, link_port_wwn,
983 sizeof ( port->port_wwn ) ) > 0 ) {
984 memcpy ( &port->port_id, &fc_ptp_high_port_id,
985 sizeof ( port->port_id ) );
986 memcpy ( &port->ptp_link_port_id,
988 sizeof ( port->ptp_link_port_id ) );
989 } else {
990 memcpy ( &port->port_id, &fc_ptp_low_port_id,
991 sizeof ( port->port_id ) );
992 memcpy ( &port->ptp_link_port_id,
994 sizeof ( port->ptp_link_port_id ) );
995 }
996 }
997 DBGC ( port, "FCPORT %s logged in via a %s, with local ID "
998 "%s\n", port->name,
999 ( ( port->flags & FC_PORT_HAS_FABRIC ) ?
1000 "fabric" : "point-to-point link" ),
1001 fc_id_ntoa ( &port->port_id ) );
1002 }
1003
1004 /* Log in to name server, if attached to a fabric */
1005 if ( has_fabric && ! ( port->flags & FC_PORT_HAS_NS ) ) {
1006
1007 DBGC ( port, "FCPORT %s attempting login to name server\n",
1008 port->name );
1009
1010 intf_restart ( &port->ns_plogi, -ECANCELED );
1011 if ( ( rc = fc_els_plogi ( &port->ns_plogi, port,
1012 &fc_gs_port_id ) ) != 0 ) {
1013 DBGC ( port, "FCPORT %s could not initiate name "
1014 "server PLOGI: %s\n",
1015 port->name, strerror ( rc ) );
1016 fc_port_logout ( port, rc );
1017 return rc;
1018 }
1019 }
1020
1021 /* Record login */
1022 fc_link_up ( &port->link );
1023
1024 /* Notify peers of link state change */
1026 fc_peer_get ( peer );
1027 fc_link_examine ( &peer->link );
1028 fc_peer_put ( peer );
1029 }
1030
1031 return 0;
1032}
1033
1034/**
1035 * Log out Fibre Channel port
1036 *
1037 * @v port Fibre Channel port
1038 * @v rc Reason for logout
1039 */
1040void fc_port_logout ( struct fc_port *port, int rc ) {
1041 struct fc_peer *peer;
1042 struct fc_peer *tmp;
1043
1044 DBGC ( port, "FCPORT %s logged out: %s\n",
1045 port->name, strerror ( rc ) );
1046
1047 /* Erase port details */
1048 memset ( &port->port_id, 0, sizeof ( port->port_id ) );
1049 port->flags = 0;
1050
1051 /* Record logout */
1052 fc_link_err ( &port->link, rc );
1053
1054 /* Notify peers of link state change */
1056 fc_peer_get ( peer );
1057 fc_link_examine ( &peer->link );
1058 fc_peer_put ( peer );
1059 }
1060}
1061
1062/**
1063 * Handle FLOGI completion
1064 *
1065 * @v port Fibre Channel port
1066 * @v rc Reason for completion
1067 */
1068static void fc_port_flogi_done ( struct fc_port *port, int rc ) {
1069
1070 intf_restart ( &port->flogi, rc );
1071
1072 if ( rc != 0 )
1073 fc_port_logout ( port, rc );
1074}
1075
1076/**
1077 * Handle name server PLOGI completion
1078 *
1079 * @v port Fibre Channel port
1080 * @v rc Reason for completion
1081 */
1082static void fc_port_ns_plogi_done ( struct fc_port *port, int rc ) {
1083
1084 intf_restart ( &port->ns_plogi, rc );
1085
1086 if ( rc == 0 ) {
1087 port->flags |= FC_PORT_HAS_NS;
1088 DBGC ( port, "FCPORT %s logged in to name server\n",
1089 port->name );
1090 } else {
1091 DBGC ( port, "FCPORT %s could not log in to name server: %s\n",
1092 port->name, strerror ( rc ) );
1093 /* Absence of a name server is not a fatal error */
1094 }
1095}
1096
1097/**
1098 * Examine Fibre Channel port link state
1099 *
1100 * @ link Fibre Channel link state monitor
1101 */
1102static void fc_port_examine ( struct fc_link_state *link ) {
1103 struct fc_port *port = container_of ( link, struct fc_port, link );
1104 int rc;
1105
1106 /* Do nothing if already logged in */
1107 if ( fc_link_ok ( &port->link ) )
1108 return;
1109
1110 DBGC ( port, "FCPORT %s attempting login\n", port->name );
1111
1112 /* Try to create FLOGI ELS */
1113 intf_restart ( &port->flogi, -ECANCELED );
1114 if ( ( rc = fc_els_flogi ( &port->flogi, port ) ) != 0 ) {
1115 DBGC ( port, "FCPORT %s could not initiate FLOGI: %s\n",
1116 port->name, strerror ( rc ) );
1117 fc_port_logout ( port, rc );
1118 return;
1119 }
1120}
1121
1122/**
1123 * Handle change of flow control window
1124 *
1125 * @v port Fibre Channel port
1126 */
1127static void fc_port_window_changed ( struct fc_port *port ) {
1128 size_t window;
1129
1130 /* Check if transport layer is ready */
1131 window = xfer_window ( &port->transport );
1132 if ( window > 0 ) {
1133
1134 /* Transport layer is ready. Start login if the link
1135 * is not already up.
1136 */
1137 if ( ! fc_link_ok ( &port->link ) )
1138 fc_link_start ( &port->link );
1139
1140 } else {
1141
1142 /* Transport layer is not ready. Log out port and
1143 * wait for transport layer before attempting log in
1144 * again.
1145 */
1147 fc_link_stop ( &port->link );
1148 }
1149}
1150
1151/** Fibre Channel port transport interface operations */
1158
1159/** Fibre Channel port transport interface descriptor */
1161 INTF_DESC ( struct fc_port, transport, fc_port_transport_op );
1162
1163/** Fibre Channel port FLOGI interface operations */
1167
1168/** Fibre Channel port FLOGI interface descriptor */
1170 INTF_DESC ( struct fc_port, flogi, fc_port_flogi_op );
1171
1172/** Fibre Channel port name server PLOGI interface operations */
1176
1177/** Fibre Channel port name server PLOGI interface descriptor */
1179 INTF_DESC ( struct fc_port, ns_plogi, fc_port_ns_plogi_op );
1180
1181/**
1182 * Create Fibre Channel port
1183 *
1184 * @v transport Transport interface
1185 * @v node Fibre Channel node name
1186 * @v port Fibre Channel port name
1187 * @v name Symbolic port name
1188 * @ret rc Return status code
1189 */
1190int fc_port_open ( struct interface *transport, const struct fc_name *node_wwn,
1191 const struct fc_name *port_wwn, const char *name ) {
1192 struct fc_port *port;
1193
1194 /* Allocate and initialise structure */
1195 port = zalloc ( sizeof ( *port ) );
1196 if ( ! port )
1197 return -ENOMEM;
1198 ref_init ( &port->refcnt, NULL );
1199 intf_init ( &port->transport, &fc_port_transport_desc, &port->refcnt );
1200 fc_link_init ( &port->link, fc_port_examine, &port->refcnt );
1201 intf_init ( &port->flogi, &fc_port_flogi_desc, &port->refcnt );
1202 intf_init ( &port->ns_plogi, &fc_port_ns_plogi_desc, &port->refcnt );
1203 list_add_tail ( &port->list, &fc_ports );
1204 INIT_LIST_HEAD ( &port->xchgs );
1205 memcpy ( &port->node_wwn, node_wwn, sizeof ( port->node_wwn ) );
1206 memcpy ( &port->port_wwn, port_wwn, sizeof ( port->port_wwn ) );
1207 snprintf ( port->name, sizeof ( port->name ), "%s", name );
1208
1209 DBGC ( port, "FCPORT %s opened as %s",
1210 port->name, fc_ntoa ( &port->node_wwn ) );
1211 DBGC ( port, " port %s\n", fc_ntoa ( &port->port_wwn ) );
1212
1213 /* Attach to transport layer, mortalise self, and return */
1214 intf_plug_plug ( &port->transport, transport );
1215 ref_put ( &port->refcnt );
1216 return 0;
1217}
1218
1219/**
1220 * Find Fibre Channel port by name
1221 *
1222 * @v name Fibre Channel port name
1223 * @ret port Fibre Channel port, or NULL
1224 */
1225struct fc_port * fc_port_find ( const char *name ) {
1226 struct fc_port *port;
1227
1229 if ( strcmp ( name, port->name ) == 0 )
1230 return port;
1231 }
1232 return NULL;
1233}
1234
1235/******************************************************************************
1236 *
1237 * Fibre Channel peers
1238 *
1239 ******************************************************************************
1240 */
1241
1242/**
1243 * Close Fibre Channel peer
1244 *
1245 * @v peer Fibre Channel peer
1246 * @v rc Reason for close
1247 */
1248static void fc_peer_close ( struct fc_peer *peer, int rc ) {
1249
1250 DBGC ( peer, "FCPEER %s closed: %s\n",
1251 fc_ntoa ( &peer->port_wwn ) , strerror ( rc ) );
1252
1253 /* Sanity check */
1254 assert ( list_empty ( &peer->ulps ) );
1255
1256 /* Stop link timer */
1257 fc_link_stop ( &peer->link );
1258
1259 /* Shut down interfaces */
1260 intf_shutdown ( &peer->plogi, rc );
1261
1262 /* Remove from list of peers */
1263 list_del ( &peer->list );
1264 INIT_LIST_HEAD ( &peer->list );
1265}
1266
1267/**
1268 * Increment Fibre Channel peer active usage count
1269 *
1270 * @v peer Fibre Channel peer
1271 */
1272static void fc_peer_increment ( struct fc_peer *peer ) {
1273
1274 /* Increment our usage count */
1275 peer->usage++;
1276}
1277
1278/**
1279 * Decrement Fibre Channel peer active usage count
1280 *
1281 * @v peer Fibre Channel peer
1282 */
1283static void fc_peer_decrement ( struct fc_peer *peer ) {
1284
1285 /* Sanity check */
1286 assert ( peer->usage > 0 );
1287
1288 /* Decrement our usage count and log out if we reach zero */
1289 if ( --(peer->usage) == 0 )
1290 fc_peer_logout ( peer, 0 );
1291}
1292
1293/**
1294 * Log in Fibre Channel peer
1295 *
1296 * @v peer Fibre Channel peer
1297 * @v port Fibre Channel port
1298 * @v port_id Port ID
1299 * @ret rc Return status code
1300 */
1301int fc_peer_login ( struct fc_peer *peer, struct fc_port *port,
1302 struct fc_port_id *port_id ) {
1303 struct fc_ulp *ulp;
1304 struct fc_ulp *tmp;
1305
1306 /* Perform implicit logout if logged in and details differ */
1307 if ( fc_link_ok ( &peer->link ) &&
1308 ( ( peer->port != port ) ||
1309 ( memcmp ( &peer->port_id, port_id,
1310 sizeof ( peer->port_id ) ) !=0 ) ) ) {
1311 fc_peer_logout ( peer, 0 );
1312 }
1313
1314 /* Log in, if applicable */
1315 if ( ! fc_link_ok ( &peer->link ) ) {
1316
1317 /* Record peer details */
1318 assert ( peer->port == NULL );
1319 peer->port = fc_port_get ( port );
1320 memcpy ( &peer->port_id, port_id, sizeof ( peer->port_id ) );
1321 DBGC ( peer, "FCPEER %s logged in via %s as %s\n",
1322 fc_ntoa ( &peer->port_wwn ), peer->port->name,
1323 fc_id_ntoa ( &peer->port_id ) );
1324
1325 /* Add login reference */
1326 fc_peer_get ( peer );
1327 }
1328
1329 /* Record login */
1330 fc_link_up ( &peer->link );
1331
1332 /* Notify ULPs of link state change */
1333 list_for_each_entry_safe ( ulp, tmp, &peer->ulps, list ) {
1334 fc_ulp_get ( ulp );
1335 fc_link_examine ( &ulp->link );
1336 fc_ulp_put ( ulp );
1337 }
1338
1339 return 0;
1340}
1341
1342/**
1343 * Log out Fibre Channel peer
1344 *
1345 * @v peer Fibre Channel peer
1346 * @v rc Reason for logout
1347 */
1348void fc_peer_logout ( struct fc_peer *peer, int rc ) {
1349 struct fc_ulp *ulp;
1350 struct fc_ulp *tmp;
1351
1352 DBGC ( peer, "FCPEER %s logged out: %s\n",
1353 fc_ntoa ( &peer->port_wwn ), strerror ( rc ) );
1354
1355 /* Drop login reference, if applicable */
1356 if ( fc_link_ok ( &peer->link ) )
1357 fc_peer_put ( peer );
1358
1359 /* Erase peer details */
1360 fc_port_put ( peer->port );
1361 peer->port = NULL;
1362
1363 /* Record logout */
1364 fc_link_err ( &peer->link, rc );
1365
1366 /* Notify ULPs of link state change */
1367 list_for_each_entry_safe ( ulp, tmp, &peer->ulps, list ) {
1368 fc_ulp_get ( ulp );
1369 fc_link_examine ( &ulp->link );
1370 fc_ulp_put ( ulp );
1371 }
1372
1373 /* Close peer if there are no active users */
1374 if ( peer->usage == 0 )
1375 fc_peer_close ( peer, rc );
1376}
1377
1378/**
1379 * Handle PLOGI completion
1380 *
1381 * @v peer Fibre Channel peer
1382 * @v rc Reason for completion
1383 */
1384static void fc_peer_plogi_done ( struct fc_peer *peer, int rc ) {
1385
1386 intf_restart ( &peer->plogi, rc );
1387
1388 if ( rc != 0 )
1389 fc_peer_logout ( peer, rc );
1390}
1391
1392/**
1393 * Initiate PLOGI
1394 *
1395 * @v peer Fibre Channel peer
1396 * @v port Fibre Channel port
1397 * @v peer_port_id Peer port ID
1398 * @ret rc Return status code
1399 */
1400static int fc_peer_plogi ( struct fc_peer *peer, struct fc_port *port,
1401 struct fc_port_id *peer_port_id ) {
1402 int rc;
1403
1404 /* Try to create PLOGI ELS */
1405 intf_restart ( &peer->plogi, -ECANCELED );
1406 if ( ( rc = fc_els_plogi ( &peer->plogi, port, peer_port_id ) ) != 0 ) {
1407 DBGC ( peer, "FCPEER %s could not initiate PLOGI: %s\n",
1408 fc_ntoa ( &peer->port_wwn ), strerror ( rc ) );
1409 fc_peer_logout ( peer, rc );
1410 return rc;
1411 }
1412
1413 return 0;
1414}
1415
1416/**
1417 * Examine Fibre Channel peer link state
1418 *
1419 * @ link Fibre Channel link state monitor
1420 */
1421static void fc_peer_examine ( struct fc_link_state *link ) {
1422 struct fc_peer *peer = container_of ( link, struct fc_peer, link );
1423 struct fc_port *port;
1424 int rc;
1425
1426 /* Check to see if underlying port link has gone down */
1427 if ( peer->port && ( ! fc_link_ok ( &peer->port->link ) ) ) {
1429 return;
1430 }
1431
1432 /* Do nothing if already logged in */
1433 if ( fc_link_ok ( &peer->link ) )
1434 return;
1435
1436 DBGC ( peer, "FCPEER %s attempting login\n",
1437 fc_ntoa ( &peer->port_wwn ) );
1438
1439 /* Sanity check */
1440 assert ( peer->port == NULL );
1441
1442 /* First, look for a port with the peer attached via a
1443 * point-to-point link.
1444 */
1446 if ( fc_link_ok ( &port->link ) &&
1447 ( ! ( port->flags & FC_PORT_HAS_FABRIC ) ) &&
1448 ( memcmp ( &peer->port_wwn, &port->link_port_wwn,
1449 sizeof ( peer->port_wwn ) ) == 0 ) ) {
1450 /* Use this peer port ID, and stop looking */
1451 fc_peer_plogi ( peer, port, &port->ptp_link_port_id );
1452 return;
1453 }
1454 }
1455
1456 /* If the peer is not directly attached, try initiating a name
1457 * server lookup on any suitable ports.
1458 */
1460 if ( fc_link_ok ( &port->link ) &&
1461 ( port->flags & FC_PORT_HAS_FABRIC ) &&
1462 ( port->flags & FC_PORT_HAS_NS ) ) {
1463 if ( ( rc = fc_ns_query ( peer, port,
1464 fc_peer_plogi ) ) != 0 ) {
1465 DBGC ( peer, "FCPEER %s could not attempt "
1466 "name server lookup on %s: %s\n",
1467 fc_ntoa ( &peer->port_wwn ), port->name,
1468 strerror ( rc ) );
1469 /* Non-fatal */
1470 }
1471 }
1472 }
1473}
1474
1475/** Fibre Channel peer PLOGI interface operations */
1479
1480/** Fibre Channel peer PLOGI interface descriptor */
1482 INTF_DESC ( struct fc_peer, plogi, fc_peer_plogi_op );
1483
1484/**
1485 * Create Fibre Channel peer
1486 *
1487 * @v port_wwn Node name
1488 * @ret peer Fibre Channel peer, or NULL
1489 */
1490static struct fc_peer * fc_peer_create ( const struct fc_name *port_wwn ) {
1491 struct fc_peer *peer;
1492
1493 /* Allocate and initialise structure */
1494 peer = zalloc ( sizeof ( *peer ) );
1495 if ( ! peer )
1496 return NULL;
1497 ref_init ( &peer->refcnt, NULL );
1498 fc_link_init ( &peer->link, fc_peer_examine, &peer->refcnt );
1499 intf_init ( &peer->plogi, &fc_peer_plogi_desc, &peer->refcnt );
1500 list_add_tail ( &peer->list, &fc_peers );
1501 memcpy ( &peer->port_wwn, port_wwn, sizeof ( peer->port_wwn ) );
1502 INIT_LIST_HEAD ( &peer->ulps );
1503
1504 /* Start link monitor */
1505 fc_link_start ( &peer->link );
1506
1507 DBGC ( peer, "FCPEER %s created\n", fc_ntoa ( &peer->port_wwn ) );
1508 return peer;
1509}
1510
1511/**
1512 * Get Fibre Channel peer by node name
1513 *
1514 * @v port_wwn Node name
1515 * @ret peer Fibre Channel peer, or NULL
1516 */
1517struct fc_peer * fc_peer_get_wwn ( const struct fc_name *port_wwn ) {
1518 struct fc_peer *peer;
1519
1520 /* Look for an existing peer */
1522 if ( memcmp ( &peer->port_wwn, port_wwn,
1523 sizeof ( peer->port_wwn ) ) == 0 )
1524 return fc_peer_get ( peer );
1525 }
1526
1527 /* Create a new peer */
1529 if ( ! peer )
1530 return NULL;
1531
1532 return peer;
1533}
1534
1535/**
1536 * Get Fibre Channel peer by port ID
1537 *
1538 * @v port Fibre Channel port
1539 * @v peer_port_id Peer port ID
1540 * @ret peer Fibre Channel peer, or NULL
1541 */
1543 const struct fc_port_id *peer_port_id ){
1544 struct fc_peer *peer;
1545
1546 /* Look for an existing peer */
1548 if ( ( peer->port == port ) &&
1549 ( memcmp ( &peer->port_id, peer_port_id,
1550 sizeof ( peer->port_id ) ) == 0 ) )
1551 return fc_peer_get ( peer );
1552 }
1553
1554 /* Cannot create a new peer, since we have no port name to use */
1555 return NULL;
1556}
1557
1558/******************************************************************************
1559 *
1560 * Fibre Channel upper-layer protocols
1561 *
1562 ******************************************************************************
1563 */
1564
1565/**
1566 * Free Fibre Channel upper-layer protocol
1567 *
1568 * @v refcnt Reference count
1569 */
1570static void fc_ulp_free ( struct refcnt *refcnt ) {
1571 struct fc_ulp *ulp = container_of ( refcnt, struct fc_ulp, refcnt );
1572
1573 fc_peer_put ( ulp->peer );
1574 free ( ulp );
1575}
1576
1577/**
1578 * Close Fibre Channel upper-layer protocol
1579 *
1580 * @v ulp Fibre Channel upper-layer protocol
1581 * @v rc Reason for close
1582 */
1583static void fc_ulp_close ( struct fc_ulp *ulp, int rc ) {
1584
1585 DBGC ( ulp, "FCULP %s/%02x closed: %s\n",
1586 fc_ntoa ( &ulp->peer->port_wwn ), ulp->type, strerror ( rc ) );
1587
1588 /* Sanity check */
1589 assert ( list_empty ( &ulp->users ) );
1590
1591 /* Stop link monitor */
1592 fc_link_stop ( &ulp->link );
1593
1594 /* Shut down interfaces */
1595 intf_shutdown ( &ulp->prli, rc );
1596
1597 /* Remove from list of ULPs */
1598 list_del ( &ulp->list );
1599 INIT_LIST_HEAD ( &ulp->list );
1600}
1601
1602/**
1603 * Attach Fibre Channel upper-layer protocol user
1604 *
1605 * @v ulp Fibre Channel upper-layer protocol
1606 * @v user Fibre Channel upper-layer protocol user
1607 */
1608void fc_ulp_attach ( struct fc_ulp *ulp, struct fc_ulp_user *user ) {
1609
1610 /* Sanity check */
1611 assert ( user->ulp == NULL );
1612
1613 /* Increment peer's usage count */
1614 fc_peer_increment ( ulp->peer );
1615
1616 /* Attach user */
1617 user->ulp = fc_ulp_get ( ulp );
1618 list_add ( &user->list, &ulp->users );
1619}
1620
1621/**
1622 * Detach Fibre Channel upper-layer protocol user
1623 *
1624 * @v user Fibre Channel upper-layer protocol user
1625 */
1626void fc_ulp_detach ( struct fc_ulp_user *user ) {
1627 struct fc_ulp *ulp = user->ulp;
1628
1629 /* Do nothing if not attached */
1630 if ( ! ulp )
1631 return;
1632
1633 /* Sanity checks */
1634 list_check_contains_entry ( user, &ulp->users, list );
1635
1636 /* Detach user and log out if no users remain */
1637 list_del ( &user->list );
1638 if ( list_empty ( &ulp->users ) )
1639 fc_ulp_logout ( ulp, 0 );
1640
1641 /* Decrement our peer's usage count */
1642 fc_peer_decrement ( ulp->peer );
1643
1644 /* Drop reference */
1645 user->ulp = NULL;
1646 fc_ulp_put ( ulp );
1647}
1648
1649/**
1650 * Log in Fibre Channel upper-layer protocol
1651 *
1652 * @v ulp Fibre Channel upper-layer protocol
1653 * @v param Service parameters
1654 * @v param_len Length of service parameters
1655 * @v originated Login was originated by us
1656 * @ret rc Return status code
1657 */
1658int fc_ulp_login ( struct fc_ulp *ulp, const void *param, size_t param_len,
1659 int originated ) {
1660 struct fc_ulp_user *user;
1661 struct fc_ulp_user *tmp;
1662
1663 /* Perform implicit logout if logged in and service parameters differ */
1664 if ( fc_link_ok ( &ulp->link ) &&
1665 ( ( ulp->param_len != param_len ) ||
1666 ( memcmp ( ulp->param, param, ulp->param_len ) != 0 ) ) ) {
1667 fc_ulp_logout ( ulp, 0 );
1668 }
1669
1670 /* Work around a bug in some versions of the Linux Fibre
1671 * Channel stack, which fail to fully initialise image pairs
1672 * established via a PRLI originated by the Linux stack
1673 * itself.
1674 */
1675 if ( originated )
1677 if ( ! ( ulp->flags & FC_ULP_ORIGINATED_LOGIN_OK ) ) {
1678 DBGC ( ulp, "FCULP %s/%02x sending extra PRLI to work around "
1679 "Linux bug\n",
1680 fc_ntoa ( &ulp->peer->port_wwn ), ulp->type );
1681 fc_link_stop ( &ulp->link );
1682 fc_link_start ( &ulp->link );
1683 return 0;
1684 }
1685
1686 /* Log in, if applicable */
1687 if ( ! fc_link_ok ( &ulp->link ) ) {
1688
1689 /* Record service parameters */
1690 assert ( ulp->param == NULL );
1691 assert ( ulp->param_len == 0 );
1692 ulp->param = malloc ( param_len );
1693 if ( ! ulp->param ) {
1694 DBGC ( ulp, "FCULP %s/%02x could not record "
1695 "parameters\n",
1696 fc_ntoa ( &ulp->peer->port_wwn ), ulp->type );
1697 return -ENOMEM;
1698 }
1699 memcpy ( ulp->param, param, param_len );
1700 ulp->param_len = param_len;
1701 DBGC ( ulp, "FCULP %s/%02x logged in with parameters:\n",
1702 fc_ntoa ( &ulp->peer->port_wwn ), ulp->type );
1703 DBGC_HDA ( ulp, 0, ulp->param, ulp->param_len );
1704
1705 /* Add login reference */
1706 fc_ulp_get ( ulp );
1707 }
1708
1709 /* Record login */
1710 fc_link_up ( &ulp->link );
1711
1712 /* Notify users of link state change */
1713 list_for_each_entry_safe ( user, tmp, &ulp->users, list ) {
1714 fc_ulp_user_get ( user );
1715 user->examine ( user );
1716 fc_ulp_user_put ( user );
1717 }
1718
1719 return 0;
1720}
1721
1722/**
1723 * Log out Fibre Channel upper-layer protocol
1724 *
1725 * @v ulp Fibre Channel upper-layer protocol
1726 * @v rc Reason for logout
1727 */
1728void fc_ulp_logout ( struct fc_ulp *ulp, int rc ) {
1729 struct fc_ulp_user *user;
1730 struct fc_ulp_user *tmp;
1731
1732 DBGC ( ulp, "FCULP %s/%02x logged out: %s\n",
1733 fc_ntoa ( &ulp->peer->port_wwn ), ulp->type, strerror ( rc ) );
1734
1735 /* Drop login reference, if applicable */
1736 if ( fc_link_ok ( &ulp->link ) )
1737 fc_ulp_put ( ulp );
1738
1739 /* Discard service parameters */
1740 free ( ulp->param );
1741 ulp->param = NULL;
1742 ulp->param_len = 0;
1743 ulp->flags = 0;
1744
1745 /* Record logout */
1746 fc_link_err ( &ulp->link, rc );
1747
1748 /* Notify users of link state change */
1749 list_for_each_entry_safe ( user, tmp, &ulp->users, list ) {
1750 fc_ulp_user_get ( user );
1751 user->examine ( user );
1752 fc_ulp_user_put ( user );
1753 }
1754
1755 /* Close ULP if there are no clients attached */
1756 if ( list_empty ( &ulp->users ) )
1757 fc_ulp_close ( ulp, rc );
1758}
1759
1760/**
1761 * Handle PRLI completion
1762 *
1763 * @v ulp Fibre Channel upper-layer protocol
1764 * @v rc Reason for completion
1765 */
1766static void fc_ulp_prli_done ( struct fc_ulp *ulp, int rc ) {
1767
1768 intf_restart ( &ulp->prli, rc );
1769
1770 if ( rc != 0 )
1771 fc_ulp_logout ( ulp, rc );
1772}
1773
1774/**
1775 * Examine Fibre Channel upper-layer protocol link state
1776 *
1777 * @ link Fibre Channel link state monitor
1778 */
1779static void fc_ulp_examine ( struct fc_link_state *link ) {
1780 struct fc_ulp *ulp = container_of ( link, struct fc_ulp, link );
1781 int rc;
1782
1783 /* Check to see if underlying peer link has gone down */
1784 if ( ! fc_link_ok ( &ulp->peer->link ) ) {
1785 fc_ulp_logout ( ulp, -ENOTCONN );
1786 return;
1787 }
1788
1789 /* Do nothing if already logged in */
1790 if ( fc_link_ok ( &ulp->link ) &&
1792 return;
1793
1794 DBGC ( ulp, "FCULP %s/%02x attempting login\n",
1795 fc_ntoa ( &ulp->peer->port_wwn ), ulp->type );
1796
1797 /* Try to create PRLI ELS */
1798 intf_restart ( &ulp->prli, -ECANCELED );
1799 if ( ( rc = fc_els_prli ( &ulp->prli, ulp->peer->port,
1800 &ulp->peer->port_id, ulp->type ) ) != 0 ) {
1801 DBGC ( ulp, "FCULP %s/%02x could not initiate PRLI: %s\n",
1802 fc_ntoa ( &ulp->peer->port_wwn ), ulp->type,
1803 strerror ( rc ) );
1804 fc_ulp_logout ( ulp, rc );
1805 return;
1806 }
1807}
1808
1809/** Fibre Channel upper-layer protocol PRLI interface operations */
1812};
1813
1814/** Fibre Channel upper-layer protocol PRLI interface descriptor */
1816 INTF_DESC ( struct fc_ulp, prli, fc_ulp_prli_op );
1817
1818/**
1819 * Create Fibre Channel upper-layer protocl
1820 *
1821 * @v peer Fibre Channel peer
1822 * @v type Type
1823 * @ret ulp Fibre Channel upper-layer protocol, or NULL
1824 */
1825static struct fc_ulp * fc_ulp_create ( struct fc_peer *peer,
1826 unsigned int type ) {
1827 struct fc_ulp *ulp;
1828
1829 /* Allocate and initialise structure */
1830 ulp = zalloc ( sizeof ( *ulp ) );
1831 if ( ! ulp )
1832 return NULL;
1833 ref_init ( &ulp->refcnt, fc_ulp_free );
1834 fc_link_init ( &ulp->link, fc_ulp_examine, &ulp->refcnt );
1835 intf_init ( &ulp->prli, &fc_ulp_prli_desc, &ulp->refcnt );
1836 ulp->peer = fc_peer_get ( peer );
1837 list_add_tail ( &ulp->list, &peer->ulps );
1838 ulp->type = type;
1839 INIT_LIST_HEAD ( &ulp->users );
1840
1841 /* Start link state monitor */
1842 fc_link_start ( &ulp->link );
1843
1844 DBGC ( ulp, "FCULP %s/%02x created\n",
1845 fc_ntoa ( &ulp->peer->port_wwn ), ulp->type );
1846 return ulp;
1847}
1848
1849/**
1850 * Get Fibre Channel upper-layer protocol by peer and type
1851 *
1852 * @v peer Fibre Channel peer
1853 * @v type Type
1854 * @ret ulp Fibre Channel upper-layer protocol, or NULL
1855 */
1856static struct fc_ulp * fc_ulp_get_type ( struct fc_peer *peer,
1857 unsigned int type ) {
1858 struct fc_ulp *ulp;
1859
1860 /* Look for an existing ULP */
1861 list_for_each_entry ( ulp, &peer->ulps, list ) {
1862 if ( ulp->type == type )
1863 return fc_ulp_get ( ulp );
1864 }
1865
1866 /* Create a new ULP */
1867 ulp = fc_ulp_create ( peer, type );
1868 if ( ! ulp )
1869 return NULL;
1870
1871 return ulp;
1872}
1873
1874/**
1875 * Get Fibre Channel upper-layer protocol by port name and type
1876 *
1877 * @v port_wwn Port name
1878 * @v type Type
1879 * @ret ulp Fibre Channel upper-layer protocol, or NULL
1880 */
1881struct fc_ulp * fc_ulp_get_wwn_type ( const struct fc_name *port_wwn,
1882 unsigned int type ) {
1883 struct fc_ulp *ulp;
1884 struct fc_peer *peer;
1885
1886 /* Get peer */
1888 if ( ! peer )
1889 goto err_peer_get_wwn;
1890
1891 /* Get ULP */
1892 ulp = fc_ulp_get_type ( peer, type );
1893 if ( ! ulp )
1894 goto err_ulp_get_type;
1895
1896 /* Drop temporary reference to peer */
1897 fc_peer_put ( peer );
1898
1899 return ulp;
1900
1901 fc_ulp_put ( ulp );
1902 err_ulp_get_type:
1903 fc_peer_put ( peer );
1904 err_peer_get_wwn:
1905 return NULL;
1906}
1907
1908/**
1909 * Get Fibre Channel upper-layer protocol by port ID and type
1910 *
1911 * @v port Fibre Channel port
1912 * @v peer_port_id Peer port ID
1913 * @v type Type
1914 * @ret ulp Fibre Channel upper-layer protocol, or NULL
1915 */
1917 const struct fc_port_id *peer_port_id,
1918 unsigned int type ) {
1919 struct fc_ulp *ulp;
1920 struct fc_peer *peer;
1921
1922 /* Get peer */
1923 peer = fc_peer_get_port_id ( port, peer_port_id );
1924 if ( ! peer )
1925 goto err_peer_get_wwn;
1926
1927 /* Get ULP */
1928 ulp = fc_ulp_get_type ( peer, type );
1929 if ( ! ulp )
1930 goto err_ulp_get_type;
1931
1932 /* Drop temporary reference to peer */
1933 fc_peer_put ( peer );
1934
1935 return ulp;
1936
1937 fc_ulp_put ( ulp );
1938 err_ulp_get_type:
1939 fc_peer_put ( peer );
1940 err_peer_get_wwn:
1941 return NULL;
1942}
1943
1944/* Drag in objects via fc_ports */
1946
1947/* Drag in Fibre Channel configuration */
1948REQUIRE_OBJECT ( config_fc );
#define NULL
NULL pointer (VOID *).
Definition Base.h:321
u8 port
Port number.
Definition CIB_PRM.h:3
typeof(acpi_finder=acpi_find)
ACPI table finder.
Definition acpi.c:48
u32 link
Link to next descriptor.
Definition ar9003_mac.h:1
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
unsigned short uint16_t
Definition stdint.h:11
unsigned char uint8_t
Definition stdint.h:10
if(len >=6 *4) __asm__ __volatile__("movsl" if(len >=5 *4) __asm__ __volatile__("movsl" if(len >=4 *4) __asm__ __volatile__("movsl" if(len >=3 *4) __asm__ __volatile__("movsl" if(len >=2 *4) __asm__ __volatile__("movsl" if(len >=1 *4) __asm__ __volatile__("movsl" if((len % 4) >=2) __asm__ __volatile__("movsw" if((len % 2) >=1) __asm__ __volatile__("movsb" retur dest)
Definition string.h:151
static const void * src
Definition string.h:48
Assertions.
#define assert(condition)
Assert a condition at run-time.
Definition assert.h:61
const char * name
Definition ath9k_hw.c:1986
struct bofm_section_header done
Definition bofm_test.c:46
union @104331263140136355135267063077374276003064103115 u
ring len
Length.
Definition dwmac.h:226
uint64_t wwn
WWN.
Definition edd.h:1
uint8_t id
Request identifier.
Definition ena.h:1
uint32_t type
Operating system type.
Definition ena.h:1
uint8_t meta
Metadata flags.
Definition ena.h:3
Error codes.
static void fc_port_flogi_done(struct fc_port *port, int rc)
Handle FLOGI completion.
Definition fc.c:1068
static void fc_port_examine(struct fc_link_state *link)
Examine Fibre Channel port link state.
Definition fc.c:1102
static void fc_peer_close(struct fc_peer *peer, int rc)
Close Fibre Channel peer.
Definition fc.c:1248
static void fc_port_ns_plogi_done(struct fc_port *port, int rc)
Handle name server PLOGI completion.
Definition fc.c:1082
int fc_aton(const char *wwn_text, struct fc_name *wwn)
Parse Fibre Channel WWN.
Definition fc.c:144
struct sockaddr * fc_fill_sockaddr(struct sockaddr_fc *sa_fc, struct fc_port_id *id)
Fill Fibre Channel socket address.
Definition fc.c:165
struct fc_peer * fc_peer_get_wwn(const struct fc_name *port_wwn)
Get Fibre Channel peer by node name.
Definition fc.c:1517
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
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:1542
static struct interface_descriptor fc_port_flogi_desc
Fibre Channel port FLOGI interface descriptor.
Definition fc.c:1169
static void fc_xchg_free(struct refcnt *refcnt)
Free Fibre Channel exchange.
Definition fc.c:359
static struct interface_descriptor fc_ulp_prli_desc
Fibre Channel upper-layer protocol PRLI interface descriptor.
Definition fc.c:1815
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
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
static struct interface_descriptor fc_peer_plogi_desc
Fibre Channel peer PLOGI interface descriptor.
Definition fc.c:1481
struct fc_port_id fc_ptp_high_port_id
Point-to-point high port ID.
Definition fc.c:77
void fc_ulp_detach(struct fc_ulp_user *user)
Detach Fibre Channel upper-layer protocol user.
Definition fc.c:1626
static void fc_xchg_close(struct fc_exchange *xchg, int rc)
Close Fibre Channel exchange.
Definition fc.c:376
static void fc_link_up(struct fc_link_state *link)
Mark Fibre Channel link as up.
Definition fc.c:195
static size_t fc_xchg_window(struct fc_exchange *xchg __unused)
Check Fibre Channel exchange window.
Definition fc.c:423
void fc_ulp_attach(struct fc_ulp *ulp, struct fc_ulp_user *user)
Attach Fibre Channel upper-layer protocol user.
Definition fc.c:1608
static struct interface_descriptor fc_port_transport_desc
Fibre Channel port transport interface descriptor.
Definition fc.c:1160
static struct interface_operation fc_xchg_ulp_op[]
Fibre Channel exchange ULP interface operations.
Definition fc.c:677
struct fc_port_id fc_f_port_id
F_Port contoller port ID.
Definition fc.c:68
static void fc_link_start(struct fc_link_state *link)
Start monitoring Fibre Channel link state.
Definition fc.c:266
static struct interface_operation fc_port_flogi_op[]
Fibre Channel port FLOGI interface operations.
Definition fc.c:1164
static struct fc_peer * fc_peer_create(const struct fc_name *port_wwn)
Create Fibre Channel peer.
Definition fc.c:1490
static struct interface_operation fc_port_ns_plogi_op[]
Fibre Channel port name server PLOGI interface operations.
Definition fc.c:1173
static struct interface_operation fc_peer_plogi_op[]
Fibre Channel peer PLOGI interface operations.
Definition fc.c:1476
struct fc_port_id fc_ptp_low_port_id
Point-to-point low port ID.
Definition fc.c:74
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
const char * fc_ntoa(const struct fc_name *wwn)
Format Fibre Channel WWN.
Definition fc.c:127
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
static void fc_ulp_prli_done(struct fc_ulp *ulp, int rc)
Handle PRLI completion.
Definition fc.c:1766
static void fc_ulp_examine(struct fc_link_state *link)
Examine Fibre Channel upper-layer protocol link state.
Definition fc.c:1779
void fc_peer_logout(struct fc_peer *peer, int rc)
Log out Fibre Channel peer.
Definition fc.c:1348
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:942
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_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
static struct interface_operation fc_ulp_prli_op[]
Fibre Channel upper-layer protocol PRLI interface operations.
Definition fc.c:1810
static unsigned int fc_new_seq_id(void)
Create local Fibre Channel sequence identifier.
Definition fc.c:348
struct fc_port_id fc_empty_port_id
Unassigned port ID.
Definition fc.c:65
static struct interface_descriptor fc_port_ns_plogi_desc
Fibre Channel port name server PLOGI interface descriptor.
Definition fc.c:1178
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
static unsigned int fc_new_xchg_id(void)
Create local Fibre Channel exchange identifier.
Definition fc.c:335
static void fc_ulp_close(struct fc_ulp *ulp, int rc)
Close Fibre Channel upper-layer protocol.
Definition fc.c:1583
static void fc_peer_increment(struct fc_peer *peer)
Increment Fibre Channel peer active usage count.
Definition fc.c:1272
static void fc_link_err(struct fc_link_state *link, int rc)
Mark Fibre Channel link as down.
Definition fc.c:210
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
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:1881
struct fc_port * fc_port_find(const char *name)
Find Fibre Channel port by name.
Definition fc.c:1225
const char * fc_id_ntoa(const struct fc_port_id *id)
Format Fibre Channel port ID.
Definition fc.c:92
static void fc_port_window_changed(struct fc_port *port)
Handle change of flow control window.
Definition fc.c:1127
static void fc_xchg_expired(struct retry_timer *timer, int over __unused)
Handle exchange timeout.
Definition fc.c:406
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:1400
static struct fc_ulp * fc_ulp_create(struct fc_peer *peer, unsigned int type)
Create Fibre Channel upper-layer protocl.
Definition fc.c:1825
struct fc_port_id fc_gs_port_id
Generic services port ID.
Definition fc.c:71
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:1190
static void fc_link_expired(struct retry_timer *timer, int over __unused)
Handle Fibre Channel link retry timer expiry.
Definition fc.c:234
static void fc_link_examine(struct fc_link_state *link)
Examine Fibre Channel link state.
Definition fc.c:226
static void fc_peer_decrement(struct fc_peer *peer)
Decrement Fibre Channel peer active usage count.
Definition fc.c:1283
static struct interface_operation fc_port_transport_op[]
Fibre Channel port transport interface operations.
Definition fc.c:1152
static void fc_port_close(struct fc_port *port, int rc)
Close Fibre Channel port.
Definition fc.c:806
static void fc_peer_examine(struct fc_link_state *link)
Examine Fibre Channel peer link state.
Definition fc.c:1421
fc_exchange_flags
Fibre Channel exchange flags.
Definition fc.c:318
@ FC_XCHG_ORIGINATOR
We are the exchange originator.
Definition fc.c:320
@ FC_XCHG_SEQ_FIRST
This is the first sequence of the exchange.
Definition fc.c:324
@ FC_XCHG_SEQ_INITIATIVE
We have the sequence initiative.
Definition fc.c:322
#define FC_TIMEOUT
Fibre Channel timeout.
Definition fc.c:328
void fc_ulp_logout(struct fc_ulp *ulp, int rc)
Log out Fibre Channel upper-layer protocol.
Definition fc.c:1728
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:1301
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:1916
static void fc_link_stop(struct fc_link_state *link)
Stop monitoring Fibre Channel link state.
Definition fc.c:275
void fc_port_logout(struct fc_port *port, int rc)
Log out Fibre Channel port.
Definition fc.c:1040
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:1856
static void fc_ulp_free(struct refcnt *refcnt)
Free Fibre Channel upper-layer protocol.
Definition fc.c:1570
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
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:1658
int fc_id_aton(const char *id_text, struct fc_port_id *id)
Parse Fibre Channel port ID.
Definition fc.c:107
static void fc_peer_plogi_done(struct fc_peer *peer, int rc)
Handle PLOGI completion.
Definition fc.c:1384
#define EUNKNOWN_LINK_STATUS
Default link status code.
Definition fc.c:186
static struct interface_descriptor fc_xchg_ulp_desc
Fibre Channel exchange ULP interface descriptor.
Definition fc.c:685
Fibre Channel.
@ FC_R_CTL_DATA
Device Data.
Definition fc.h:162
@ FC_R_CTL_ELS
Extended Link Services.
Definition fc.h:163
#define FC_LINK_RETRY_DELAY
Delay between failed link-up attempts.
Definition fc.h:87
static void fc_peer_put(struct fc_peer *peer)
Drop reference to Fibre Channel peer.
Definition fc.h:391
static struct fc_ulp * fc_ulp_get(struct fc_ulp *ulp)
Get reference to Fibre Channel upper-layer protocol.
Definition fc.h:475
#define FC_RESPONDERS
Fibre Channel responder table.
Definition fc.h:240
#define FC_R_CTL_INFO_MASK
Fibre Channel Routing Control Information mask.
Definition fc.h:188
@ FC_TYPE_CT
Common Transport.
Definition fc.h:195
@ FC_TYPE_ELS
Extended Link Service.
Definition fc.h:193
static void fc_ulp_user_put(struct fc_ulp_user *user)
Drop reference to Fibre Channel upper-layer protocol user.
Definition fc.h:508
@ FC_R_CTL_UNCAT
Uncategorized.
Definition fc.h:177
@ FC_R_CTL_UNSOL_DATA
Unsolicited Data.
Definition fc.h:181
@ FC_R_CTL_UNSOL_CTRL
Unsolicited Control.
Definition fc.h:179
@ FC_R_CTL_DATA_DESC
Data Descriptor.
Definition fc.h:182
@ FC_R_CTL_UNSOL_CMD
Unsolicited Command.
Definition fc.h:183
@ FC_R_CTL_SOL_DATA
Solicited Data.
Definition fc.h:178
@ FC_R_CTL_CMD_STAT
Command Status.
Definition fc.h:184
@ FC_R_CTL_SOL_CTRL
Solicited Control.
Definition fc.h:180
@ FC_PORT_HAS_FABRIC
Port is attached to a fabric.
Definition fc.h:293
@ FC_PORT_HAS_NS
Port is logged in to a name server.
Definition fc.h:295
static void fc_ulp_put(struct fc_ulp *ulp)
Drop reference to Fibre Channel upper-layer protocol.
Definition fc.h:486
static void fc_port_put(struct fc_port *port)
Drop reference to Fibre Channel port.
Definition fc.h:316
#define FC_NAME_STRLEN
Length of Fibre Channel name text.
Definition fc.h:35
@ FC_ULP_ORIGINATED_LOGIN_OK
A login originated by us has succeeded.
Definition fc.h:450
static struct fc_peer * fc_peer_get(struct fc_peer *peer)
Get reference to Fibre Channel peer.
Definition fc.h:380
struct list_head fc_peers
#define FC_RX_ID_UNKNOWN
Responder exchange identifier used before first response.
Definition fc.h:214
static int fc_link_ok(struct fc_link_state *link)
Check Fibre Channel link state.
Definition fc.h:109
static struct fc_port * fc_port_get(struct fc_port *port)
Get reference to Fibre Channel port.
Definition fc.h:305
#define FC_PORT_ID_STRLEN
Length of Fibre Channel port identifier next.
Definition fc.h:43
@ FC_F_CTL_ES_FIRST
First Sequence of Exchange.
Definition fc.h:202
@ FC_F_CTL_ES_END
Last Data Frame of Sequence.
Definition fc.h:204
@ FC_F_CTL_ES_TRANSFER
Transfer Sequence Initiative.
Definition fc.h:205
@ FC_F_CTL_ES_LAST
Last Sequence of Exchange.
Definition fc.h:203
@ FC_F_CTL_ES_RESPONDER
Responder of Exchange.
Definition fc.h:200
struct list_head fc_ports
@ FC_F_CTL_MISC_REL_OFF
Relative Offset Present.
Definition fc.h:210
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:497
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:1130
int fc_els_flogi(struct interface *parent, struct fc_port *port)
Create FLOGI request.
Definition fcels.c:583
int fc_els_plogi(struct interface *parent, struct fc_port *port, struct fc_port_id *peer_port_id)
Create PLOGI request.
Definition fcels.c:736
Fibre Channel Extended Link Services.
#define FC_LOGIN_DEFAULT_MTU
Fibre Channel default MTU.
Definition fcels.h:169
Fibre Channel name server lookups.
#define AF_FC
Fibre Channel addresses.
Definition socket.h:66
#define __unused
Declare a variable or data structure as unused.
Definition compiler.h:598
#define DBGC2(...)
Definition compiler.h:547
#define DBGC(...)
Definition compiler.h:530
#define DBGC_HDA(...)
Definition compiler.h:531
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:921
#define REQUIRE_OBJECT(object)
Require an object.
Definition compiler.h:227
#define EINVAL
Invalid argument.
Definition errno.h:472
#define ETIMEDOUT
Connection timed out.
Definition errno.h:713
#define EPIPE
Broken pipe.
Definition errno.h:663
#define ENOMEM
Not enough space.
Definition errno.h:578
#define EBUSY
Device or resource busy.
Definition errno.h:382
#define ECANCELED
Operation canceled.
Definition errno.h:387
#define ENOTCONN
The socket is not connected.
Definition errno.h:613
#define REQUIRING_SYMBOL(symbol)
Specify the file's requiring symbol.
Definition compiler.h:140
u16 fc
802.11 Frame Control field
Definition ieee80211.h:0
#define ntohl(value)
Definition byteswap.h:135
#define htonl(value)
Definition byteswap.h:134
#define htons(value)
Definition byteswap.h:136
#define ntohs(value)
Definition byteswap.h:137
struct hv_monitor_parameter param[4][32]
Parameters.
Definition hyperv.h:13
iPXE timers
String functions.
void * memcpy(void *dest, const void *src, size_t len) __nonnull
void * memset(void *dest, int character, size_t len) __nonnull
void intf_close(struct interface *intf, int rc)
Close an object interface.
Definition interface.c:250
void intf_plug_plug(struct interface *a, struct interface *b)
Plug two object interfaces together.
Definition interface.c:108
void intf_shutdown(struct interface *intf, int rc)
Shut down an object interface.
Definition interface.c:279
void intf_restart(struct interface *intf, int rc)
Shut down and restart an object interface.
Definition interface.c:344
Object interfaces.
#define INTF_DESC(object_type, intf, operations)
Define an object interface descriptor.
Definition interface.h:81
static void intf_init(struct interface *intf, struct interface_descriptor *desc, struct refcnt *refcnt)
Initialise an object interface.
Definition interface.h:204
#define INTF_OP(op_type, object_type, op_func)
Define an object interface operation.
Definition interface.h:33
void free_iob(struct io_buffer *iobuf)
Free I/O buffer.
Definition iobuf.c:153
I/O buffers.
#define iob_push(iobuf, len)
Definition iobuf.h:149
#define iob_disown(iobuf)
Disown an I/O buffer.
Definition iobuf.h:277
static size_t iob_len(struct io_buffer *iobuf)
Calculate length of data in an I/O buffer.
Definition iobuf.h:220
#define iob_reserve(iobuf, len)
Definition iobuf.h:132
#define iob_pull(iobuf, len)
Definition iobuf.h:167
unsigned long tmp
Definition linux_pci.h:65
Linked lists.
#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:459
#define list_add_tail(new, head)
Add a new entry to the tail of a list.
Definition list.h:94
#define list_for_each_entry(pos, head, member)
Iterate over entries in a list.
Definition list.h:432
#define list_del(list)
Delete an entry from a list.
Definition list.h:120
#define INIT_LIST_HEAD(list)
Initialise a list head.
Definition list.h:46
#define list_empty(list)
Test whether a list is empty.
Definition list.h:137
#define LIST_HEAD(list)
Declare a static list head.
Definition list.h:38
#define list_check_contains_entry(entry, head, member)
Check list contains a specified entry.
Definition list.h:550
#define list_add(new, head)
Add a new entry to the head of a list.
Definition list.h:70
void * zalloc(size_t size)
Allocate cleared memory.
Definition malloc.c:718
void * malloc(size_t size)
Allocate memory.
Definition malloc.c:677
struct mschapv2_challenge peer
Peer challenge.
Definition mschapv2.h:1
Reference counting.
static void(* free)(struct refcnt *refcnt))
Definition refcnt.h:55
#define ref_get(refcnt)
Get additional reference to object.
Definition refcnt.h:93
#define ref_put(refcnt)
Drop reference to object.
Definition refcnt.h:107
#define ref_init(refcnt, free)
Initialise a reference counter.
Definition refcnt.h:65
void start_timer_fixed(struct retry_timer *timer, unsigned long timeout)
Start timer with a specified timeout.
Definition retry.c:65
void stop_timer(struct retry_timer *timer)
Stop timer.
Definition retry.c:118
Retry timers.
static void start_timer_nodelay(struct retry_timer *timer)
Start timer with no delay.
Definition retry.h:100
#define container_of(ptr, type, field)
Get containing structure.
Definition stddef.h:36
char * strerror(int errno)
Retrieve string representation of error number.
Definition strerror.c:79
unsigned long strtoul(const char *string, char **endp, int base)
Convert string to numeric value.
Definition string.c:516
int strcmp(const char *first, const char *second)
Compare strings.
Definition string.c:174
int memcmp(const void *first, const void *second, size_t len)
Compare memory regions.
Definition string.c:115
A Fibre Channel exchange.
Definition fc.c:287
uint16_t seq_cnt
Active sequence count.
Definition fc.c:308
unsigned int type
Data structure type.
Definition fc.c:298
struct fc_port_id peer_port_id
Peer port ID.
Definition fc.c:296
struct refcnt refcnt
Reference count.
Definition fc.c:289
struct interface ulp
Upper-layer protocol interface.
Definition fc.c:314
uint16_t peer_xchg_id
Peer exchange ID.
Definition fc.c:304
unsigned int flags
Flags.
Definition fc.c:300
struct fc_port * port
Fibre Channel port.
Definition fc.c:291
uint16_t xchg_id
Local exchange ID.
Definition fc.c:302
struct retry_timer timer
Timeout timer.
Definition fc.c:311
struct list_head list
List of active exchanges within this port.
Definition fc.c:293
uint8_t seq_id
Active sequence ID.
Definition fc.c:306
A Fibre Channel Frame Header.
Definition fc.h:121
uint8_t f_ctl_es
Frame control - exchange and sequence.
Definition fc.h:137
struct fc_port_id d_id
Destination ID.
Definition fc.h:129
uint16_t rx_id
Responder exchange ID.
Definition fc.h:151
uint8_t type
Data structure type.
Definition fc.h:135
uint8_t f_ctl_misc
Frame control - miscellaneous.
Definition fc.h:141
uint32_t parameter
Parameter.
Definition fc.h:157
uint8_t r_ctl
Routing control.
Definition fc.h:127
uint8_t seq_id
Sequence ID.
Definition fc.h:143
struct fc_port_id s_id
Source ID.
Definition fc.h:133
uint16_t seq_cnt
Sequence count.
Definition fc.h:147
uint16_t ox_id
Originator exchange ID.
Definition fc.h:149
A Fibre Channel name.
Definition fc.h:30
A Fibre Channel name server query.
Definition fcns.c:45
A Fibre Channel peer.
Definition fc.h:341
struct fc_link_state link
Link state monitor.
Definition fc.h:351
struct fc_port * port
Fibre Channel port, if known.
Definition fc.h:355
struct list_head list
List of all peers.
Definition fc.h:345
struct fc_name port_wwn
Port name.
Definition fc.h:348
struct fc_port_id port_id
Peer port ID, if known.
Definition fc.h:357
A Fibre Channel port identifier.
Definition fc.h:38
A Fibre Channel port.
Definition fc.h:253
struct fc_name node_wwn
Node name.
Definition fc.h:264
struct fc_name port_wwn
Port name.
Definition fc.h:266
struct list_head list
List of all ports.
Definition fc.h:257
struct fc_port_id port_id
Local port ID.
Definition fc.h:268
struct interface transport
Transport interface.
Definition fc.h:262
A Fibre Channel responder.
Definition fc.h:223
unsigned int type
Type.
Definition fc.h:225
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:234
A Fibre Channel upper-layer protocol user.
Definition fc.h:454
void(* examine)(struct fc_ulp_user *user)
Examine link state.
Definition fc.h:465
struct list_head list
List of users.
Definition fc.h:458
struct fc_ulp * ulp
Fibre Channel upper layer protocol.
Definition fc.h:456
A Fibre Channel upper-layer protocol.
Definition fc.h:414
unsigned int type
Type.
Definition fc.h:423
unsigned int flags
Flags.
Definition fc.h:425
size_t param_len
Service parameter length.
Definition fc.h:434
struct fc_peer * peer
Fibre Channel peer.
Definition fc.h:418
struct list_head users
Active users of this upper-layer protocol.
Definition fc.h:444
struct interface prli
PRLI interface.
Definition fc.h:430
struct fc_link_state link
Link state monitor.
Definition fc.h:428
struct list_head list
List of upper-layer protocols.
Definition fc.h:420
struct refcnt refcnt
Reference count.
Definition fc.h:416
void * param
Service parameters, if any.
Definition fc.h:432
An object interface descriptor.
Definition interface.h:56
An object interface operation.
Definition interface.h:18
An object interface.
Definition interface.h:125
A persistent I/O buffer.
Definition iobuf.h:98
void * data
Start of data.
Definition iobuf.h:113
A doubly-linked list entry (or list head).
Definition list.h:19
A reference counter.
Definition refcnt.h:27
A retry timer.
Definition retry.h:22
Fibre Channel socket address.
Definition fc.h:48
sa_family_t sfc_family
Socket address family (part of struct sockaddr).
Definition fc.h:53
struct fc_port_id sfc_port_id
Port ID.
Definition fc.h:55
Generalized socket address structure.
Definition socket.h:97
A timer.
Definition timer.h:29
Data transfer metadata.
Definition xfer.h:23
unsigned int flags
Flags.
Definition xfer.h:29
struct sockaddr * dest
Destination socket address, or NULL.
Definition xfer.h:42
off_t offset
Offset of data within stream.
Definition xfer.h:38
struct sockaddr * src
Source socket address, or NULL.
Definition xfer.h:40
struct sockaddr sa
Definition syslog.c:57
Linker tables.
#define for_each_table_entry(pointer, table)
Iterate through all entries within a linker table.
Definition tables.h:386
int snprintf(char *buf, size_t size, const char *fmt,...)
Write a formatted string to a buffer.
Definition vsprintf.c:383
size_t xfer_window(struct interface *intf)
Check flow control window.
Definition xfer.c:117
int xfer_deliver(struct interface *intf, struct io_buffer *iobuf, struct xfer_metadata *meta)
Deliver datagram.
Definition xfer.c:195
struct io_buffer * xfer_alloc_iob(struct interface *intf, size_t len)
Allocate I/O buffer.
Definition xfer.c:159
void xfer_window_changed(struct interface *intf)
Report change of flow control window.
Definition xfer.c:147
int xfer_deliver_iob(struct interface *intf, struct io_buffer *iobuf)
Deliver datagram as I/O buffer without metadata.
Definition xfer.c:256
Data transfer interfaces.
#define XFER_FL_ABS_OFFSET
Offset is absolute.
Definition xfer.h:48
#define XFER_FL_OVER
Sender is relinquishing use of half-duplex channel.
Definition xfer.h:51
#define XFER_FL_RESPONSE
Data content is a response.
Definition xfer.h:64
#define XFER_FL_CMD_STAT
Data content represents a command or status message.
Definition xfer.h:61
#define XFER_FL_OUT
This is the final data transfer.
Definition xfer.h:54