2 * Copyright (C) 2010 Michael Brown <mbrown@fensystems.co.uk>.
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.
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.
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
20 FILE_LICENCE ( GPL2_OR_LATER );
28 #include <ipxe/interface.h>
29 #include <ipxe/xfer.h>
30 #include <ipxe/iobuf.h>
31 #include <ipxe/process.h>
33 #include <ipxe/fcels.h>
37 * Fibre Channel Extended Link Services
41 /** Fibre Channel ELS transaction debug message format */
42 #define FCELS_FMT "FCELS %s %s %s %s"
44 /** Fibre Channel ELS transaction debug message arguments */
45 #define FCELS_ARGS( els ) \
47 ( (els)->handler ? (els)->handler->name : "unknown ELS" ), \
48 ( fc_els_is_request ( els ) ? "to" : "from" ), \
49 fc_id_ntoa ( &(els)->peer_port_id )
51 struct fc_els_handler fc_els_unknown_handler __fc_els_handler;
54 * Free Fibre Channel ELS transaction
56 * @v refcnt Reference count
58 static void fc_els_free ( struct refcnt *refcnt ) {
59 struct fc_els *els = container_of ( refcnt, struct fc_els, refcnt );
61 assert ( ! process_running ( &els->process ) );
62 fc_port_put ( els->port );
67 * Close Fibre Channel ELS transaction
69 * @v els Fibre Channel ELS transaction
70 * @v rc Reason for close
72 static void fc_els_close ( struct fc_els *els, int rc ) {
75 DBGC ( els, FCELS_FMT " complete (%s)\n",
76 FCELS_ARGS ( els ), strerror ( rc ) );
80 process_del ( &els->process );
82 /* Shut down interfaces */
83 intf_shutdown ( &els->xchg, rc );
84 intf_shutdown ( &els->job, rc );
88 * Detect Fibre Channel ELS frame handler
90 * @v els Fibre Channel ELS transaction
91 * @v command ELS command code
92 * @ret handler ELS handler, or NULL
94 static struct fc_els_handler * fc_els_detect ( struct fc_els *els,
97 const struct fc_els_frame_common *frame = data;
98 struct fc_els_handler *handler;
102 if ( len < sizeof ( *frame ) )
105 /* Try each handler in turn */
106 for_each_table_entry ( handler, FC_ELS_HANDLERS ) {
107 if ( ( rc = handler->detect ( els, data, len ) ) == 0 )
115 * Transmit Fibre Channel ELS frame
117 * @v els Fibre Channel ELS transaction
118 * @v data Data to transmit
119 * @v len Length of data
120 * @ret rc Return status code
122 int fc_els_tx ( struct fc_els *els, const void *data, size_t len ) {
123 struct xfer_metadata meta;
124 struct sockaddr_fc dest;
127 DBGC2 ( els, FCELS_FMT " transmitting:\n", FCELS_ARGS ( els ) );
128 DBGC2_HDA ( els, 0, data, len );
130 /* Construct metadata */
131 memset ( &meta, 0, sizeof ( meta ) );
132 meta.flags = ( fc_els_is_request ( els ) ?
133 XFER_FL_OVER : ( XFER_FL_RESPONSE | XFER_FL_OUT ) );
134 meta.dest = fc_fill_sockaddr ( &dest, &els->peer_port_id );
137 if ( ( rc = xfer_deliver_raw_meta ( &els->xchg, data, len,
139 DBGC ( els, FCELS_FMT " could not deliver frame: %s\n",
140 FCELS_ARGS ( els ), strerror ( rc ) );
148 * Receive Fibre Channel ELS frame
150 * @v els Fibre Channel ELS transaction
151 * @v iobuf I/O buffer
152 * @v meta Data transfer metadata
153 * @ret rc Return status code
155 static int fc_els_rx ( struct fc_els *els,
156 struct io_buffer *iobuf,
157 struct xfer_metadata *meta ) {
158 struct fc_els_frame_common *frame = iobuf->data;
159 struct sockaddr_fc *src = ( ( struct sockaddr_fc * ) meta->src );
160 struct sockaddr_fc *dest = ( ( struct sockaddr_fc * ) meta->dest );
161 size_t len = iob_len ( iobuf );
165 if ( len < sizeof ( *frame ) ) {
166 DBGC ( els, FCELS_FMT " received underlength frame:\n",
167 FCELS_ARGS ( els ) );
168 DBGC_HDA ( els, 0, frame, len );
173 DBGC ( els, FCELS_FMT " received frame missing source "
174 "address:\n", FCELS_ARGS ( els ) );
179 DBGC ( els, FCELS_FMT " received frame missing destination "
180 "address:\n", FCELS_ARGS ( els ) );
185 /* Check for rejection responses */
186 if ( fc_els_is_request ( els ) &&
187 ( frame->command != FC_ELS_LS_ACC ) ) {
188 DBGC ( els, FCELS_FMT " rejected:\n", FCELS_ARGS ( els ) );
189 DBGC_HDA ( els, 0, frame, len );
194 /* Update port IDs */
195 memcpy ( &els->port_id, &dest->sfc_port_id, sizeof ( els->port_id ) );
196 memcpy ( &els->peer_port_id, &src->sfc_port_id,
197 sizeof ( els->peer_port_id ) );
199 /* Determine handler, if necessary */
200 if ( ! els->handler )
201 els->handler = fc_els_detect ( els, frame, len );
202 if ( ! els->handler )
203 els->handler = &fc_els_unknown_handler;
205 DBGC2 ( els, FCELS_FMT " received:\n", FCELS_ARGS ( els ) );
206 DBGC2_HDA ( els, 0, frame, len );
208 /* Handle received frame */
209 if ( ( rc = els->handler->rx ( els, frame, len ) ) != 0 ) {
210 DBGC ( els, FCELS_FMT " could not handle received frame: "
211 "%s\n", FCELS_ARGS ( els ), strerror ( rc ) );
212 DBGC_HDA ( els, 0, frame, len );
217 /* Free I/O buffer */
220 /* Close transaction */
221 fc_els_close ( els, rc );
226 /** Fibre Channel ELS exchange interface operations */
227 static struct interface_operation fc_els_xchg_op[] = {
228 INTF_OP ( xfer_deliver, struct fc_els *, fc_els_rx ),
229 INTF_OP ( intf_close, struct fc_els *, fc_els_close ),
232 /** Fibre Channel ELS exchange interface descriptor */
233 static struct interface_descriptor fc_els_xchg_desc =
234 INTF_DESC ( struct fc_els, xchg, fc_els_xchg_op );
236 /** Fibre Channel ELS job control interface operations */
237 static struct interface_operation fc_els_job_op[] = {
238 INTF_OP ( intf_close, struct fc_els *, fc_els_close ),
241 /** Fibre Channel ELS job control interface descriptor */
242 static struct interface_descriptor fc_els_job_desc =
243 INTF_DESC ( struct fc_els, job, fc_els_job_op );
246 * Fibre Channel ELS process
248 * @v els Fibre Channel ELS transaction
250 static void fc_els_step ( struct fc_els *els ) {
255 assert ( fc_els_is_request ( els ) );
257 /* Create exchange */
258 if ( ( xchg_id = fc_xchg_originate ( &els->xchg, els->port,
260 FC_TYPE_ELS ) ) < 0 ) {
262 DBGC ( els, FCELS_FMT " could not create exchange: %s\n",
263 FCELS_ARGS ( els ), strerror ( rc ) );
264 fc_els_close ( els, rc );
268 /* Transmit request */
269 if ( ( rc = els->handler->tx ( els ) ) != 0 ) {
270 DBGC ( els, FCELS_FMT " could not transmit request: %s\n",
271 FCELS_ARGS ( els ), strerror ( rc ) );
272 fc_els_close ( els, rc );
277 /** Fibre Channel ELS process descriptor */
278 static struct process_descriptor fc_els_process_desc =
279 PROC_DESC_ONCE ( struct fc_els, process, fc_els_step );
282 * Create ELS transaction
284 * @v port Fibre Channel port
285 * @v port_id Local port ID
286 * @v peer_port_id Peer port ID
287 * @ret els Fibre Channel ELS transaction, or NULL
289 static struct fc_els * fc_els_create ( struct fc_port *port,
290 struct fc_port_id *port_id,
291 struct fc_port_id *peer_port_id ) {
294 /* Allocate and initialise structure */
295 els = zalloc ( sizeof ( *els ) );
298 ref_init ( &els->refcnt, fc_els_free );
299 intf_init ( &els->job, &fc_els_job_desc, &els->refcnt );
300 intf_init ( &els->xchg, &fc_els_xchg_desc, &els->refcnt );
301 process_init_stopped ( &els->process, &fc_els_process_desc,
303 els->port = fc_port_get ( port );
304 memcpy ( &els->port_id, port_id, sizeof ( els->port_id ) );
305 memcpy ( &els->peer_port_id, peer_port_id,
306 sizeof ( els->peer_port_id ) );
313 * @v job Parent job-control interface
314 * @v port Fibre Channel port
315 * @v peer_port_id Peer port ID
316 * @v handler ELS handler
317 * @ret rc Return status code
319 int fc_els_request ( struct interface *job, struct fc_port *port,
320 struct fc_port_id *peer_port_id,
321 struct fc_els_handler *handler ) {
324 /* Allocate and initialise structure */
325 els = fc_els_create ( port, &port->port_id, peer_port_id );
328 els->handler = handler;
329 els->flags = FC_ELS_REQUEST;
330 process_add ( &els->process );
332 /* Attach to parent job interface, mortalise self, and return */
333 intf_plug_plug ( &els->job, job );
334 ref_put ( &els->refcnt );
339 * Create ELS response
341 * @v xchg Exchange interface
342 * @v port Fibre Channel port
343 * @v port_id Local port ID
344 * @v peer_port_id Peer port ID
345 * @ret rc Return status code
347 static int fc_els_respond ( struct interface *xchg, struct fc_port *port,
348 struct fc_port_id *port_id,
349 struct fc_port_id *peer_port_id ) {
352 /* Allocate and initialise structure */
353 els = fc_els_create ( port, port_id, peer_port_id );
357 /* Attach to exchange interface, mortalise self, and return */
358 intf_plug_plug ( &els->xchg, xchg );
359 ref_put ( &els->refcnt );
363 /** Fibre Channel ELS responder */
364 struct fc_responder fc_els_responder __fc_responder = {
366 .respond = fc_els_respond,
369 /******************************************************************************
371 * Unknown ELS handler
373 ******************************************************************************
377 * Transmit unknown ELS request
379 * @v els Fibre Channel ELS transaction
380 * @ret rc Return status code
382 static int fc_els_unknown_tx ( struct fc_els *els __unused ) {
387 * Transmit unknown ELS response
389 * @v els Fibre Channel ELS transaction
390 * @ret rc Return status code
392 static int fc_els_unknown_tx_response ( struct fc_els *els ) {
393 struct fc_ls_rjt_frame ls_rjt;
395 /* Construct LS_RJT */
396 memset ( &ls_rjt, 0, sizeof ( ls_rjt ) );
397 ls_rjt.command = FC_ELS_LS_RJT;
398 ls_rjt.reason = FC_ELS_RJT_UNSUPPORTED;
400 /* Transmit LS_RJT */
401 return fc_els_tx ( els, &ls_rjt, sizeof ( ls_rjt ) );
405 * Receive unknown ELS
407 * @v els Fibre Channel ELS transaction
409 * @v len Length of ELS frame
410 * @ret rc Return status code
412 static int fc_els_unknown_rx ( struct fc_els *els, void *data, size_t len ) {
415 DBGC ( els, FCELS_FMT ":\n", FCELS_ARGS ( els ) );
416 DBGC_HDA ( els, 0, data, len );
418 /* Transmit response, if applicable */
419 if ( ! fc_els_is_request ( els ) ) {
420 if ( ( rc = fc_els_unknown_tx_response ( els ) ) != 0 )
430 * @v els Fibre Channel ELS transaction
432 * @v len Length of ELS frame
433 * @ret rc Return status code
435 static int fc_els_unknown_detect ( struct fc_els *els __unused,
436 const void *data __unused,
437 size_t len __unused ) {
441 /** Unknown ELS handler */
442 struct fc_els_handler fc_els_unknown_handler __fc_els_handler = {
444 .tx = fc_els_unknown_tx,
445 .rx = fc_els_unknown_rx,
446 .detect = fc_els_unknown_detect,
449 /******************************************************************************
453 ******************************************************************************
459 * @v els Fibre Channel ELS transaction
460 * @ret rc Return status code
462 static int fc_els_flogi_tx ( struct fc_els *els ) {
463 struct fc_login_frame flogi;
465 /* Construct FLOGI */
466 memset ( &flogi, 0, sizeof ( flogi ) );
467 flogi.command = fc_els_tx_command ( els, FC_ELS_FLOGI );
468 flogi.common.version = htons ( FC_LOGIN_VERSION );
469 flogi.common.credit = htons ( FC_LOGIN_DEFAULT_B2B );
470 flogi.common.flags = htons ( FC_LOGIN_CONTINUOUS_OFFSET );
471 flogi.common.mtu = htons ( FC_LOGIN_DEFAULT_MTU );
472 memcpy ( &flogi.port_wwn, &els->port->port_wwn,
473 sizeof ( flogi.port_wwn ) );
474 memcpy ( &flogi.node_wwn, &els->port->node_wwn,
475 sizeof ( flogi.node_wwn ) );
476 flogi.class3.flags = htons ( FC_LOGIN_CLASS_VALID |
477 FC_LOGIN_CLASS_SEQUENTIAL );
480 return fc_els_tx ( els, &flogi, sizeof ( flogi ) );
486 * @v els Fibre Channel ELS transaction
488 * @v len Length of ELS frame
489 * @ret rc Return status code
491 static int fc_els_flogi_rx ( struct fc_els *els, void *data, size_t len ) {
492 struct fc_login_frame *flogi = data;
497 if ( len < sizeof ( *flogi ) ) {
498 DBGC ( els, FCELS_FMT " received underlength frame:\n",
499 FCELS_ARGS ( els ) );
500 DBGC_HDA ( els, 0, data, len );
504 /* Extract parameters */
505 has_fabric = ( flogi->common.flags & htons ( FC_LOGIN_F_PORT ) );
506 DBGC ( els, FCELS_FMT " has node %s\n", FCELS_ARGS ( els ),
507 fc_ntoa ( &flogi->node_wwn ) );
508 DBGC ( els, FCELS_FMT " has port %s\n", FCELS_ARGS ( els ),
509 fc_ntoa ( &flogi->port_wwn ) );
511 DBGC ( els, FCELS_FMT " has fabric with", FCELS_ARGS ( els ) );
512 DBGC ( els, " local ID %s\n", fc_id_ntoa ( &els->port_id ) );
514 DBGC ( els, FCELS_FMT " has point-to-point link\n",
515 FCELS_ARGS ( els ) );
519 if ( ( rc = fc_port_login ( els->port, &els->port_id, &flogi->node_wwn,
520 &flogi->port_wwn, has_fabric ) ) != 0 ) {
521 DBGC ( els, FCELS_FMT " could not log in port: %s\n",
522 FCELS_ARGS ( els ), strerror ( rc ) );
526 /* Send any responses to the newly-assigned peer port ID, if
529 if ( ! has_fabric ) {
530 memcpy ( &els->peer_port_id, &els->port->ptp_link_port_id,
531 sizeof ( els->peer_port_id ) );
534 /* Transmit response, if applicable */
535 if ( ! fc_els_is_request ( els ) ) {
536 if ( ( rc = fc_els_flogi_tx ( els ) ) != 0 )
546 * @v els Fibre Channel ELS transaction
548 * @v len Length of ELS frame
549 * @ret rc Return status code
551 static int fc_els_flogi_detect ( struct fc_els *els __unused, const void *data,
552 size_t len __unused ) {
553 const struct fc_login_frame *flogi = data;
555 /* Check for FLOGI */
556 if ( flogi->command != FC_ELS_FLOGI )
562 /** FLOGI ELS handler */
563 struct fc_els_handler fc_els_flogi_handler __fc_els_handler = {
565 .tx = fc_els_flogi_tx,
566 .rx = fc_els_flogi_rx,
567 .detect = fc_els_flogi_detect,
571 * Create FLOGI request
573 * @v parent Parent interface
574 * @v port Fibre Channel port
575 * @ret rc Return status code
577 int fc_els_flogi ( struct interface *parent, struct fc_port *port ) {
579 return fc_els_request ( parent, port, &fc_f_port_id,
580 &fc_els_flogi_handler );
583 /******************************************************************************
587 ******************************************************************************
593 * @v els Fibre Channel ELS transaction
594 * @ret rc Return status code
596 static int fc_els_plogi_tx ( struct fc_els *els ) {
597 struct fc_login_frame plogi;
599 /* Construct PLOGI */
600 memset ( &plogi, 0, sizeof ( plogi ) );
601 plogi.command = fc_els_tx_command ( els, FC_ELS_PLOGI );
602 plogi.common.version = htons ( FC_LOGIN_VERSION );
603 plogi.common.credit = htons ( FC_LOGIN_DEFAULT_B2B );
604 plogi.common.flags = htons ( FC_LOGIN_CONTINUOUS_OFFSET );
605 plogi.common.mtu = htons ( FC_LOGIN_DEFAULT_MTU );
606 plogi.common.u.plogi.max_seq = htons ( FC_LOGIN_DEFAULT_MAX_SEQ );
607 plogi.common.u.plogi.rel_offs = htons ( FC_LOGIN_DEFAULT_REL_OFFS );
608 plogi.common.e_d_tov = htonl ( FC_LOGIN_DEFAULT_E_D_TOV );
609 memcpy ( &plogi.port_wwn, &els->port->port_wwn,
610 sizeof ( plogi.port_wwn ) );
611 memcpy ( &plogi.node_wwn, &els->port->node_wwn,
612 sizeof ( plogi.node_wwn ) );
613 plogi.class3.flags = htons ( FC_LOGIN_CLASS_VALID |
614 FC_LOGIN_CLASS_SEQUENTIAL );
615 plogi.class3.mtu = htons ( FC_LOGIN_DEFAULT_MTU );
616 plogi.class3.max_seq = htons ( FC_LOGIN_DEFAULT_MAX_SEQ );
617 plogi.class3.max_seq_per_xchg = 1;
620 return fc_els_tx ( els, &plogi, sizeof ( plogi ) );
626 * @v els Fibre Channel ELS transaction
628 * @v len Length of ELS frame
629 * @ret rc Return status code
631 static int fc_els_plogi_rx ( struct fc_els *els, void *data, size_t len ) {
632 struct fc_login_frame *plogi = data;
633 struct fc_peer *peer;
637 if ( len < sizeof ( *plogi ) ) {
638 DBGC ( els, FCELS_FMT " received underlength frame:\n",
639 FCELS_ARGS ( els ) );
640 DBGC_HDA ( els, 0, data, len );
644 if ( ! fc_link_ok ( &els->port->link ) ) {
645 DBGC ( els, FCELS_FMT " received while port link is down\n",
646 FCELS_ARGS ( els ) );
651 /* Extract parameters */
652 DBGC ( els, FCELS_FMT " has node %s\n", FCELS_ARGS ( els ),
653 fc_ntoa ( &plogi->node_wwn ) );
654 DBGC ( els, FCELS_FMT " has port %s as %s\n",
655 FCELS_ARGS ( els ), fc_ntoa ( &plogi->port_wwn ),
656 fc_id_ntoa ( &els->peer_port_id ) );
659 peer = fc_peer_get_wwn ( &plogi->port_wwn );
661 DBGC ( els, FCELS_FMT " could not create peer\n",
662 FCELS_ARGS ( els ) );
664 goto err_peer_get_wwn;
668 if ( ( rc = fc_peer_login ( peer, els->port,
669 &els->peer_port_id ) ) != 0 ) {
670 DBGC ( els, FCELS_FMT " could not log in peer: %s\n",
671 FCELS_ARGS ( els ), strerror ( rc ) );
675 /* Transmit response, if applicable */
676 if ( ! fc_els_is_request ( els ) ) {
677 if ( ( rc = fc_els_plogi_tx ( els ) ) != 0 )
681 /* Drop temporary reference to peer */
682 fc_peer_put ( peer );
688 fc_peer_put ( peer );
697 * @v els Fibre Channel ELS transaction
699 * @v len Length of ELS frame
700 * @ret rc Return status code
702 static int fc_els_plogi_detect ( struct fc_els *els __unused, const void *data,
703 size_t len __unused ) {
704 const struct fc_login_frame *plogi = data;
706 /* Check for PLOGI */
707 if ( plogi->command != FC_ELS_PLOGI )
713 /** PLOGI ELS handler */
714 struct fc_els_handler fc_els_plogi_handler __fc_els_handler = {
716 .tx = fc_els_plogi_tx,
717 .rx = fc_els_plogi_rx,
718 .detect = fc_els_plogi_detect,
722 * Create PLOGI request
724 * @v parent Parent interface
725 * @v port Fibre Channel port
726 * @v peer_port_id Peer port ID
727 * @ret rc Return status code
729 int fc_els_plogi ( struct interface *parent, struct fc_port *port,
730 struct fc_port_id *peer_port_id ) {
732 return fc_els_request ( parent, port, peer_port_id,
733 &fc_els_plogi_handler );
736 /******************************************************************************
740 ******************************************************************************
744 * Transmit LOGO request
746 * @v els Fibre Channel ELS transaction
747 * @ret rc Return status code
749 static int fc_els_logo_tx ( struct fc_els *els ) {
750 struct fc_logout_request_frame logo;
753 memset ( &logo, 0, sizeof ( logo ) );
754 logo.command = FC_ELS_LOGO;
755 memcpy ( &logo.port_id, &els->port->port_id, sizeof ( logo.port_id ) );
756 memcpy ( &logo.port_wwn, &els->port->port_wwn,
757 sizeof ( logo.port_wwn ) );
760 return fc_els_tx ( els, &logo, sizeof ( logo ) );
764 * Transmit LOGO response
766 * @v els Fibre Channel ELS transaction
767 * @ret rc Return status code
769 static int fc_els_logo_tx_response ( struct fc_els *els ) {
770 struct fc_logout_response_frame logo;
773 memset ( &logo, 0, sizeof ( logo ) );
774 logo.command = FC_ELS_LS_ACC;
777 return fc_els_tx ( els, &logo, sizeof ( logo ) );
781 * Log out individual peer or whole port as applicable
783 * @v els Fibre Channel ELS transaction
784 * @v port_id Peer port ID
786 static void fc_els_logo_logout ( struct fc_els *els,
787 struct fc_port_id *peer_port_id ) {
788 struct fc_peer *peer;
790 if ( ( memcmp ( peer_port_id, &fc_f_port_id,
791 sizeof ( *peer_port_id ) ) == 0 ) ||
792 ( memcmp ( peer_port_id, &els->port->port_id,
793 sizeof ( *peer_port_id ) ) == 0 ) ) {
794 fc_port_logout ( els->port, 0 );
796 peer = fc_peer_get_port_id ( els->port, peer_port_id );
798 fc_peer_logout ( peer, 0 );
799 fc_peer_put ( peer );
805 * Receive LOGO request
807 * @v els Fibre Channel ELS transaction
809 * @v len Length of ELS frame
810 * @ret rc Return status code
812 static int fc_els_logo_rx_request ( struct fc_els *els, void *data,
814 struct fc_logout_request_frame *logo = data;
818 if ( len < sizeof ( *logo ) ) {
819 DBGC ( els, FCELS_FMT " received underlength frame:\n",
820 FCELS_ARGS ( els ) );
821 DBGC_HDA ( els, 0, data, len );
825 DBGC ( els, FCELS_FMT " has port %s as %s\n", FCELS_ARGS ( els ),
826 fc_ntoa ( &logo->port_wwn ), fc_id_ntoa ( &logo->port_id ) );
828 /* Log out individual peer or whole port as applicable */
829 fc_els_logo_logout ( els, &logo->port_id );
831 /* Transmit repsonse */
832 if ( ( rc = fc_els_logo_tx_response ( els ) ) != 0 )
839 * Receive LOGO response
841 * @v els Fibre Channel ELS transaction
843 * @v len Length of ELS frame
844 * @ret rc Return status code
846 static int fc_els_logo_rx_response ( struct fc_els *els, void *data __unused,
847 size_t len __unused ) {
849 /* Log out individual peer or whole port as applicable */
850 fc_els_logo_logout ( els, &els->peer_port_id );
858 * @v els Fibre Channel ELS transaction
860 * @v len Length of ELS frame
861 * @ret rc Return status code
863 static int fc_els_logo_rx ( struct fc_els *els, void *data, size_t len ) {
865 if ( fc_els_is_request ( els ) ) {
866 return fc_els_logo_rx_response ( els, data, len );
868 return fc_els_logo_rx_request ( els, data, len );
875 * @v els Fibre Channel ELS transaction
877 * @v len Length of ELS frame
878 * @ret rc Return status code
880 static int fc_els_logo_detect ( struct fc_els *els __unused, const void *data,
881 size_t len __unused ) {
882 const struct fc_logout_request_frame *logo = data;
885 if ( logo->command != FC_ELS_LOGO )
891 /** LOGO ELS handler */
892 struct fc_els_handler fc_els_logo_handler __fc_els_handler = {
894 .tx = fc_els_logo_tx,
895 .rx = fc_els_logo_rx,
896 .detect = fc_els_logo_detect,
900 * Create LOGO request
902 * @v parent Parent interface
903 * @v port Fibre Channel port
904 * @v peer_port_id Peer port ID
905 * @ret rc Return status code
907 int fc_els_logo ( struct interface *parent, struct fc_port *port,
908 struct fc_port_id *peer_port_id ) {
910 return fc_els_request ( parent, port, peer_port_id,
911 &fc_els_logo_handler );
914 /******************************************************************************
918 ******************************************************************************
922 * Find PRLI descriptor
924 * @v type Upper-layer protocol type
925 * @ret descriptor PRLI descriptor, or NULL
927 static struct fc_els_prli_descriptor *
928 fc_els_prli_descriptor ( unsigned int type ) {
929 struct fc_els_prli_descriptor *descriptor;
931 for_each_table_entry ( descriptor, FC_ELS_PRLI_DESCRIPTORS ) {
932 if ( descriptor->type == type )
941 * @v els Fibre Channel ELS transaction
942 * @v descriptor ELS PRLI descriptor
943 * @v param Service parameters
944 * @ret rc Return status code
946 int fc_els_prli_tx ( struct fc_els *els,
947 struct fc_els_prli_descriptor *descriptor, void *param ) {
949 struct fc_prli_frame frame;
950 uint8_t param[descriptor->param_len];
951 } __attribute__ (( packed )) prli;
956 ulp = fc_ulp_get_port_id_type ( els->port, &els->peer_port_id,
960 goto err_get_port_id_type;
963 /* Build frame for transmission */
964 memset ( &prli, 0, sizeof ( prli ) );
965 prli.frame.command = fc_els_tx_command ( els, FC_ELS_PRLI );
966 prli.frame.page_len =
967 ( sizeof ( prli.frame.page ) + sizeof ( prli.param ) );
968 prli.frame.len = htons ( sizeof ( prli ) );
969 prli.frame.page.type = descriptor->type;
970 if ( fc_els_is_request ( els ) ) {
971 prli.frame.page.flags |= htons ( FC_PRLI_ESTABLISH );
972 } else if ( fc_link_ok ( &ulp->link ) ) {
973 prli.frame.page.flags |= htons ( FC_PRLI_ESTABLISH |
974 FC_PRLI_RESPONSE_SUCCESS );
976 memcpy ( &prli.param, param, sizeof ( prli.param ) );
979 if ( ( rc = fc_els_tx ( els, &prli, sizeof ( prli ) ) ) != 0 )
982 /* Drop temporary reference to ULP */
989 err_get_port_id_type:
996 * @v els Fibre Channel ELS transaction
997 * @v descriptor ELS PRLI descriptor
999 * @v len Length of ELS frame
1000 * @ret rc Return status code
1002 int fc_els_prli_rx ( struct fc_els *els,
1003 struct fc_els_prli_descriptor *descriptor,
1004 void *data, size_t len ) {
1006 struct fc_prli_frame frame;
1007 uint8_t param[descriptor->param_len];
1008 } __attribute__ (( packed )) *prli = data;
1013 if ( len < sizeof ( *prli ) ) {
1014 DBGC ( els, FCELS_FMT " received underlength frame:\n",
1015 FCELS_ARGS ( els ) );
1016 DBGC_HDA ( els, 0, data, len );
1021 DBGC ( els, FCELS_FMT " has parameters:\n", FCELS_ARGS ( els ) );
1022 DBGC_HDA ( els, 0, prli->param, sizeof ( prli->param ) );
1025 ulp = fc_ulp_get_port_id_type ( els->port, &els->peer_port_id,
1029 goto err_get_port_id_type;
1033 if ( ! fc_link_ok ( &ulp->peer->link ) ) {
1034 DBGC ( els, FCELS_FMT " received while peer link is down\n",
1035 FCELS_ARGS ( els ) );
1040 /* Log in ULP, if applicable */
1041 if ( prli->frame.page.flags & htons ( FC_PRLI_ESTABLISH ) ) {
1042 if ( ( rc = fc_ulp_login ( ulp, prli->param,
1043 sizeof ( prli->param ),
1044 fc_els_is_request ( els ) ) ) != 0 ){
1045 DBGC ( els, FCELS_FMT " could not log in ULP: %s\n",
1046 FCELS_ARGS ( els ), strerror ( rc ) );
1050 if ( fc_els_is_request ( els ) ) {
1051 fc_ulp_logout ( ulp, -EACCES );
1053 /* This is just an information-gathering PRLI; do not
1059 /* Transmit response, if applicable */
1060 if ( ! fc_els_is_request ( els ) ) {
1061 if ( ( rc = els->handler->tx ( els ) ) != 0 )
1065 /* Drop temporary reference to ULP */
1074 err_get_port_id_type:
1082 * @v els Fibre Channel ELS transaction
1083 * @v descriptor ELS PRLI descriptor
1085 * @v len Length of ELS frame
1086 * @ret rc Return status code
1088 int fc_els_prli_detect ( struct fc_els *els __unused,
1089 struct fc_els_prli_descriptor *descriptor,
1090 const void *data, size_t len ) {
1092 struct fc_prli_frame frame;
1093 uint8_t param[descriptor->param_len];
1094 } __attribute__ (( packed )) *prli = data;
1096 /* Check for PRLI */
1097 if ( prli->frame.command != FC_ELS_PRLI )
1100 /* Check for sufficient length to contain service parameter page */
1101 if ( len < sizeof ( *prli ) )
1104 /* Check for upper-layer protocol type */
1105 if ( prli->frame.page.type != descriptor->type )
1112 * Create PRLI request
1114 * @v parent Parent interface
1115 * @v port Fibre Channel port
1116 * @v peer_port_id Peer port ID
1117 * @v type Upper-layer protocol type
1118 * @ret rc Return status code
1120 int fc_els_prli ( struct interface *parent, struct fc_port *port,
1121 struct fc_port_id *peer_port_id, unsigned int type ) {
1122 struct fc_els_prli_descriptor *descriptor;
1124 /* Find a PRLI descriptor */
1125 descriptor = fc_els_prli_descriptor ( type );
1129 return fc_els_request ( parent, port, peer_port_id,
1130 descriptor->handler );
1133 /******************************************************************************
1137 ******************************************************************************
1141 * Transmit RTV response
1143 * @v els Fibre Channel ELS transaction
1144 * @ret rc Return status code
1146 static int fc_els_rtv_tx_response ( struct fc_els *els ) {
1147 struct fc_rtv_response_frame rtv;
1150 memset ( &rtv, 0, sizeof ( rtv ) );
1151 rtv.command = FC_ELS_LS_ACC;
1152 rtv.e_d_tov = htonl ( FC_LOGIN_DEFAULT_E_D_TOV );
1155 return fc_els_tx ( els, &rtv, sizeof ( rtv ) );
1161 * @v els Fibre Channel ELS transaction
1163 * @v len Length of ELS frame
1164 * @ret rc Return status code
1166 static int fc_els_rtv_rx ( struct fc_els *els, void *data __unused,
1167 size_t len __unused ) {
1170 DBGC ( els, FCELS_FMT "\n", FCELS_ARGS ( els ) );
1172 /* Transmit response */
1173 if ( ! fc_els_is_request ( els ) ) {
1174 if ( ( rc = fc_els_rtv_tx_response ( els ) ) != 0 )
1184 * @v els Fibre Channel ELS transaction
1186 * @v len Length of ELS frame
1187 * @ret rc Return status code
1189 static int fc_els_rtv_detect ( struct fc_els *els __unused, const void *data,
1190 size_t len __unused ) {
1191 const struct fc_rtv_request_frame *rtv = data;
1194 if ( rtv->command != FC_ELS_RTV )
1200 /** RTV ELS handler */
1201 struct fc_els_handler fc_els_rtv_handler __fc_els_handler = {
1203 .tx = fc_els_unknown_tx,
1204 .rx = fc_els_rtv_rx,
1205 .detect = fc_els_rtv_detect,
1208 /******************************************************************************
1212 ******************************************************************************
1215 /** ECHO request data */
1216 struct fc_echo_request_frame {
1217 /** ECHO frame header */
1218 struct fc_echo_frame_header echo;
1221 } __attribute__ (( packed ));
1223 /** ECHO magic marker */
1224 #define FC_ECHO_MAGIC 0x69505845
1229 * @v els Fibre Channel ELS transaction
1230 * @ret rc Return status code
1232 static int fc_els_echo_tx ( struct fc_els *els ) {
1233 struct fc_echo_request_frame echo;
1235 /* Construct ECHO */
1236 memset ( &echo, 0, sizeof ( echo ) );
1237 echo.echo.command = FC_ELS_ECHO;
1238 echo.magic = htonl ( FC_ECHO_MAGIC );
1241 return fc_els_tx ( els, &echo, sizeof ( echo ) );
1245 * Receive ECHO request
1247 * @v els Fibre Channel ELS transaction
1249 * @v len Length of ELS frame
1250 * @ret rc Return status code
1252 static int fc_els_echo_rx_request ( struct fc_els *els, void *data,
1255 struct fc_echo_frame_header echo;
1256 char payload[ len - sizeof ( struct fc_echo_frame_header ) ];
1260 DBGC ( els, FCELS_FMT "\n", FCELS_ARGS ( els ) );
1262 /* Transmit response */
1263 echo->echo.command = FC_ELS_LS_ACC;
1264 if ( ( rc = fc_els_tx ( els, echo, sizeof ( *echo ) ) ) != 0 )
1272 * Receive ECHO response
1274 * @v els Fibre Channel ELS transaction
1276 * @v len Length of ELS frame
1277 * @ret rc Return status code
1279 static int fc_els_echo_rx_response ( struct fc_els *els, void *data,
1281 struct fc_echo_request_frame *echo = data;
1283 DBGC ( els, FCELS_FMT "\n", FCELS_ARGS ( els ) );
1285 /* Check response is correct */
1286 if ( ( len != sizeof ( *echo ) ) ||
1287 ( echo->magic != htonl ( FC_ECHO_MAGIC ) ) ) {
1288 DBGC ( els, FCELS_FMT " received bad echo response\n",
1289 FCELS_ARGS ( els ) );
1290 DBGC_HDA ( els, 0, data, len );
1300 * @v els Fibre Channel ELS transaction
1302 * @v len Length of ELS frame
1303 * @ret rc Return status code
1305 static int fc_els_echo_rx ( struct fc_els *els, void *data, size_t len ) {
1307 if ( fc_els_is_request ( els ) ) {
1308 return fc_els_echo_rx_response ( els, data, len );
1310 return fc_els_echo_rx_request ( els, data, len );
1317 * @v els Fibre Channel ELS transaction
1319 * @v len Length of ELS frame
1320 * @ret rc Return status code
1322 static int fc_els_echo_detect ( struct fc_els *els __unused, const void *data,
1323 size_t len __unused ) {
1324 const struct fc_echo_frame_header *echo = data;
1326 /* Check for ECHO */
1327 if ( echo->command != FC_ELS_ECHO )
1333 /** ECHO ELS handler */
1334 struct fc_els_handler fc_els_echo_handler __fc_els_handler = {
1336 .tx = fc_els_echo_tx,
1337 .rx = fc_els_echo_rx,
1338 .detect = fc_els_echo_detect,