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
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.
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
32 #include <ipxe/interface.h>
33 #include <ipxe/xfer.h>
34 #include <ipxe/iobuf.h>
35 #include <ipxe/process.h>
37 #include <ipxe/fcels.h>
41 * Fibre Channel Extended Link Services
45 /** Fibre Channel ELS transaction debug message format */
46 #define FCELS_FMT "FCELS %s %s %s %s"
48 /** Fibre Channel ELS transaction debug message arguments */
49 #define FCELS_ARGS( els ) \
51 ( (els)->handler ? (els)->handler->name : "unknown ELS" ), \
52 ( fc_els_is_request ( els ) ? "to" : "from" ), \
53 fc_id_ntoa ( &(els)->peer_port_id )
55 struct fc_els_handler fc_els_unknown_handler __fc_els_handler;
58 * Free Fibre Channel ELS transaction
60 * @v refcnt Reference count
62 static void fc_els_free ( struct refcnt *refcnt ) {
63 struct fc_els *els = container_of ( refcnt, struct fc_els, refcnt );
65 assert ( ! process_running ( &els->process ) );
66 fc_port_put ( els->port );
71 * Close Fibre Channel ELS transaction
73 * @v els Fibre Channel ELS transaction
74 * @v rc Reason for close
76 static void fc_els_close ( struct fc_els *els, int rc ) {
79 DBGC ( els, FCELS_FMT " complete (%s)\n",
80 FCELS_ARGS ( els ), strerror ( rc ) );
84 process_del ( &els->process );
86 /* Shut down interfaces */
87 intf_shutdown ( &els->xchg, rc );
88 intf_shutdown ( &els->job, rc );
92 * Detect Fibre Channel ELS frame handler
94 * @v els Fibre Channel ELS transaction
95 * @v command ELS command code
96 * @ret handler ELS handler, or NULL
98 static struct fc_els_handler * fc_els_detect ( struct fc_els *els,
101 const struct fc_els_frame_common *frame = data;
102 struct fc_els_handler *handler;
106 if ( len < sizeof ( *frame ) )
109 /* Try each handler in turn */
110 for_each_table_entry ( handler, FC_ELS_HANDLERS ) {
111 if ( ( rc = handler->detect ( els, data, len ) ) == 0 )
119 * Transmit Fibre Channel ELS frame
121 * @v els Fibre Channel ELS transaction
122 * @v data Data to transmit
123 * @v len Length of data
124 * @ret rc Return status code
126 int fc_els_tx ( struct fc_els *els, const void *data, size_t len ) {
127 struct xfer_metadata meta;
128 struct sockaddr_fc dest;
131 DBGC2 ( els, FCELS_FMT " transmitting:\n", FCELS_ARGS ( els ) );
132 DBGC2_HDA ( els, 0, data, len );
134 /* Construct metadata */
135 memset ( &meta, 0, sizeof ( meta ) );
136 meta.flags = ( fc_els_is_request ( els ) ?
137 XFER_FL_OVER : ( XFER_FL_RESPONSE | XFER_FL_OUT ) );
138 meta.dest = fc_fill_sockaddr ( &dest, &els->peer_port_id );
141 if ( ( rc = xfer_deliver_raw_meta ( &els->xchg, data, len,
143 DBGC ( els, FCELS_FMT " could not deliver frame: %s\n",
144 FCELS_ARGS ( els ), strerror ( rc ) );
152 * Receive Fibre Channel ELS frame
154 * @v els Fibre Channel ELS transaction
155 * @v iobuf I/O buffer
156 * @v meta Data transfer metadata
157 * @ret rc Return status code
159 static int fc_els_rx ( struct fc_els *els,
160 struct io_buffer *iobuf,
161 struct xfer_metadata *meta ) {
162 struct fc_els_frame_common *frame = iobuf->data;
163 struct sockaddr_fc *src = ( ( struct sockaddr_fc * ) meta->src );
164 struct sockaddr_fc *dest = ( ( struct sockaddr_fc * ) meta->dest );
165 size_t len = iob_len ( iobuf );
169 if ( len < sizeof ( *frame ) ) {
170 DBGC ( els, FCELS_FMT " received underlength frame:\n",
171 FCELS_ARGS ( els ) );
172 DBGC_HDA ( els, 0, frame, len );
177 DBGC ( els, FCELS_FMT " received frame missing source "
178 "address:\n", FCELS_ARGS ( els ) );
183 DBGC ( els, FCELS_FMT " received frame missing destination "
184 "address:\n", FCELS_ARGS ( els ) );
189 /* Check for rejection responses */
190 if ( fc_els_is_request ( els ) &&
191 ( frame->command != FC_ELS_LS_ACC ) ) {
192 DBGC ( els, FCELS_FMT " rejected:\n", FCELS_ARGS ( els ) );
193 DBGC_HDA ( els, 0, frame, len );
198 /* Update port IDs */
199 memcpy ( &els->port_id, &dest->sfc_port_id, sizeof ( els->port_id ) );
200 memcpy ( &els->peer_port_id, &src->sfc_port_id,
201 sizeof ( els->peer_port_id ) );
203 /* Determine handler, if necessary */
204 if ( ! els->handler )
205 els->handler = fc_els_detect ( els, frame, len );
206 if ( ! els->handler )
207 els->handler = &fc_els_unknown_handler;
209 DBGC2 ( els, FCELS_FMT " received:\n", FCELS_ARGS ( els ) );
210 DBGC2_HDA ( els, 0, frame, len );
212 /* Handle received frame */
213 if ( ( rc = els->handler->rx ( els, frame, len ) ) != 0 ) {
214 DBGC ( els, FCELS_FMT " could not handle received frame: "
215 "%s\n", FCELS_ARGS ( els ), strerror ( rc ) );
216 DBGC_HDA ( els, 0, frame, len );
221 /* Free I/O buffer */
224 /* Close transaction */
225 fc_els_close ( els, rc );
230 /** Fibre Channel ELS exchange interface operations */
231 static struct interface_operation fc_els_xchg_op[] = {
232 INTF_OP ( xfer_deliver, struct fc_els *, fc_els_rx ),
233 INTF_OP ( intf_close, struct fc_els *, fc_els_close ),
236 /** Fibre Channel ELS exchange interface descriptor */
237 static struct interface_descriptor fc_els_xchg_desc =
238 INTF_DESC ( struct fc_els, xchg, fc_els_xchg_op );
240 /** Fibre Channel ELS job control interface operations */
241 static struct interface_operation fc_els_job_op[] = {
242 INTF_OP ( intf_close, struct fc_els *, fc_els_close ),
245 /** Fibre Channel ELS job control interface descriptor */
246 static struct interface_descriptor fc_els_job_desc =
247 INTF_DESC ( struct fc_els, job, fc_els_job_op );
250 * Fibre Channel ELS process
252 * @v els Fibre Channel ELS transaction
254 static void fc_els_step ( struct fc_els *els ) {
259 assert ( fc_els_is_request ( els ) );
261 /* Create exchange */
262 if ( ( xchg_id = fc_xchg_originate ( &els->xchg, els->port,
264 FC_TYPE_ELS ) ) < 0 ) {
266 DBGC ( els, FCELS_FMT " could not create exchange: %s\n",
267 FCELS_ARGS ( els ), strerror ( rc ) );
268 fc_els_close ( els, rc );
272 /* Transmit request */
273 if ( ( rc = els->handler->tx ( els ) ) != 0 ) {
274 DBGC ( els, FCELS_FMT " could not transmit request: %s\n",
275 FCELS_ARGS ( els ), strerror ( rc ) );
276 fc_els_close ( els, rc );
281 /** Fibre Channel ELS process descriptor */
282 static struct process_descriptor fc_els_process_desc =
283 PROC_DESC_ONCE ( struct fc_els, process, fc_els_step );
286 * Create ELS transaction
288 * @v port Fibre Channel port
289 * @v port_id Local port ID
290 * @v peer_port_id Peer port ID
291 * @ret els Fibre Channel ELS transaction, or NULL
293 static struct fc_els * fc_els_create ( struct fc_port *port,
294 struct fc_port_id *port_id,
295 struct fc_port_id *peer_port_id ) {
298 /* Allocate and initialise structure */
299 els = zalloc ( sizeof ( *els ) );
302 ref_init ( &els->refcnt, fc_els_free );
303 intf_init ( &els->job, &fc_els_job_desc, &els->refcnt );
304 intf_init ( &els->xchg, &fc_els_xchg_desc, &els->refcnt );
305 process_init_stopped ( &els->process, &fc_els_process_desc,
307 els->port = fc_port_get ( port );
308 memcpy ( &els->port_id, port_id, sizeof ( els->port_id ) );
309 memcpy ( &els->peer_port_id, peer_port_id,
310 sizeof ( els->peer_port_id ) );
317 * @v job Parent job-control interface
318 * @v port Fibre Channel port
319 * @v peer_port_id Peer port ID
320 * @v handler ELS handler
321 * @ret rc Return status code
323 int fc_els_request ( struct interface *job, struct fc_port *port,
324 struct fc_port_id *peer_port_id,
325 struct fc_els_handler *handler ) {
328 /* Allocate and initialise structure */
329 els = fc_els_create ( port, &port->port_id, peer_port_id );
332 els->handler = handler;
333 els->flags = FC_ELS_REQUEST;
334 process_add ( &els->process );
336 /* Attach to parent job interface, mortalise self, and return */
337 intf_plug_plug ( &els->job, job );
338 ref_put ( &els->refcnt );
343 * Create ELS response
345 * @v xchg Exchange interface
346 * @v port Fibre Channel port
347 * @v port_id Local port ID
348 * @v peer_port_id Peer port ID
349 * @ret rc Return status code
351 static int fc_els_respond ( struct interface *xchg, struct fc_port *port,
352 struct fc_port_id *port_id,
353 struct fc_port_id *peer_port_id ) {
356 /* Allocate and initialise structure */
357 els = fc_els_create ( port, port_id, peer_port_id );
361 /* Attach to exchange interface, mortalise self, and return */
362 intf_plug_plug ( &els->xchg, xchg );
363 ref_put ( &els->refcnt );
367 /** Fibre Channel ELS responder */
368 struct fc_responder fc_els_responder __fc_responder = {
370 .respond = fc_els_respond,
373 /******************************************************************************
375 * Unknown ELS handler
377 ******************************************************************************
381 * Transmit unknown ELS request
383 * @v els Fibre Channel ELS transaction
384 * @ret rc Return status code
386 static int fc_els_unknown_tx ( struct fc_els *els __unused ) {
391 * Transmit unknown ELS response
393 * @v els Fibre Channel ELS transaction
394 * @ret rc Return status code
396 static int fc_els_unknown_tx_response ( struct fc_els *els ) {
397 struct fc_ls_rjt_frame ls_rjt;
399 /* Construct LS_RJT */
400 memset ( &ls_rjt, 0, sizeof ( ls_rjt ) );
401 ls_rjt.command = FC_ELS_LS_RJT;
402 ls_rjt.reason = FC_ELS_RJT_UNSUPPORTED;
404 /* Transmit LS_RJT */
405 return fc_els_tx ( els, &ls_rjt, sizeof ( ls_rjt ) );
409 * Receive unknown ELS
411 * @v els Fibre Channel ELS transaction
413 * @v len Length of ELS frame
414 * @ret rc Return status code
416 static int fc_els_unknown_rx ( struct fc_els *els, void *data, size_t len ) {
419 DBGC ( els, FCELS_FMT ":\n", FCELS_ARGS ( els ) );
420 DBGC_HDA ( els, 0, data, len );
422 /* Transmit response, if applicable */
423 if ( ! fc_els_is_request ( els ) ) {
424 if ( ( rc = fc_els_unknown_tx_response ( els ) ) != 0 )
434 * @v els Fibre Channel ELS transaction
436 * @v len Length of ELS frame
437 * @ret rc Return status code
439 static int fc_els_unknown_detect ( struct fc_els *els __unused,
440 const void *data __unused,
441 size_t len __unused ) {
445 /** Unknown ELS handler */
446 struct fc_els_handler fc_els_unknown_handler __fc_els_handler = {
448 .tx = fc_els_unknown_tx,
449 .rx = fc_els_unknown_rx,
450 .detect = fc_els_unknown_detect,
453 /******************************************************************************
457 ******************************************************************************
463 * @v els Fibre Channel ELS transaction
464 * @ret rc Return status code
466 static int fc_els_flogi_tx ( struct fc_els *els ) {
467 struct fc_login_frame flogi;
469 /* Construct FLOGI */
470 memset ( &flogi, 0, sizeof ( flogi ) );
471 flogi.command = fc_els_tx_command ( els, FC_ELS_FLOGI );
472 flogi.common.version = htons ( FC_LOGIN_VERSION );
473 flogi.common.credit = htons ( FC_LOGIN_DEFAULT_B2B );
474 flogi.common.flags = htons ( FC_LOGIN_CONTINUOUS_OFFSET );
475 flogi.common.mtu = htons ( FC_LOGIN_DEFAULT_MTU );
476 memcpy ( &flogi.port_wwn, &els->port->port_wwn,
477 sizeof ( flogi.port_wwn ) );
478 memcpy ( &flogi.node_wwn, &els->port->node_wwn,
479 sizeof ( flogi.node_wwn ) );
480 flogi.class3.flags = htons ( FC_LOGIN_CLASS_VALID |
481 FC_LOGIN_CLASS_SEQUENTIAL );
484 return fc_els_tx ( els, &flogi, sizeof ( flogi ) );
490 * @v els Fibre Channel ELS transaction
492 * @v len Length of ELS frame
493 * @ret rc Return status code
495 static int fc_els_flogi_rx ( struct fc_els *els, void *data, size_t len ) {
496 struct fc_login_frame *flogi = data;
501 if ( len < sizeof ( *flogi ) ) {
502 DBGC ( els, FCELS_FMT " received underlength frame:\n",
503 FCELS_ARGS ( els ) );
504 DBGC_HDA ( els, 0, data, len );
508 /* Extract parameters */
509 has_fabric = ( flogi->common.flags & htons ( FC_LOGIN_F_PORT ) );
510 DBGC ( els, FCELS_FMT " has node %s\n", FCELS_ARGS ( els ),
511 fc_ntoa ( &flogi->node_wwn ) );
512 DBGC ( els, FCELS_FMT " has port %s\n", FCELS_ARGS ( els ),
513 fc_ntoa ( &flogi->port_wwn ) );
515 DBGC ( els, FCELS_FMT " has fabric with", FCELS_ARGS ( els ) );
516 DBGC ( els, " local ID %s\n", fc_id_ntoa ( &els->port_id ) );
518 DBGC ( els, FCELS_FMT " has point-to-point link\n",
519 FCELS_ARGS ( els ) );
523 if ( ( rc = fc_port_login ( els->port, &els->port_id, &flogi->node_wwn,
524 &flogi->port_wwn, has_fabric ) ) != 0 ) {
525 DBGC ( els, FCELS_FMT " could not log in port: %s\n",
526 FCELS_ARGS ( els ), strerror ( rc ) );
530 /* Send any responses to the newly-assigned peer port ID, if
533 if ( ! has_fabric ) {
534 memcpy ( &els->peer_port_id, &els->port->ptp_link_port_id,
535 sizeof ( els->peer_port_id ) );
538 /* Transmit response, if applicable */
539 if ( ! fc_els_is_request ( els ) ) {
540 if ( ( rc = fc_els_flogi_tx ( els ) ) != 0 )
550 * @v els Fibre Channel ELS transaction
552 * @v len Length of ELS frame
553 * @ret rc Return status code
555 static int fc_els_flogi_detect ( struct fc_els *els __unused, const void *data,
556 size_t len __unused ) {
557 const struct fc_login_frame *flogi = data;
559 /* Check for FLOGI */
560 if ( flogi->command != FC_ELS_FLOGI )
566 /** FLOGI ELS handler */
567 struct fc_els_handler fc_els_flogi_handler __fc_els_handler = {
569 .tx = fc_els_flogi_tx,
570 .rx = fc_els_flogi_rx,
571 .detect = fc_els_flogi_detect,
575 * Create FLOGI request
577 * @v parent Parent interface
578 * @v port Fibre Channel port
579 * @ret rc Return status code
581 int fc_els_flogi ( struct interface *parent, struct fc_port *port ) {
583 return fc_els_request ( parent, port, &fc_f_port_id,
584 &fc_els_flogi_handler );
587 /******************************************************************************
591 ******************************************************************************
597 * @v els Fibre Channel ELS transaction
598 * @ret rc Return status code
600 static int fc_els_plogi_tx ( struct fc_els *els ) {
601 struct fc_login_frame plogi;
603 /* Construct PLOGI */
604 memset ( &plogi, 0, sizeof ( plogi ) );
605 plogi.command = fc_els_tx_command ( els, FC_ELS_PLOGI );
606 plogi.common.version = htons ( FC_LOGIN_VERSION );
607 plogi.common.credit = htons ( FC_LOGIN_DEFAULT_B2B );
608 plogi.common.flags = htons ( FC_LOGIN_CONTINUOUS_OFFSET );
609 plogi.common.mtu = htons ( FC_LOGIN_DEFAULT_MTU );
610 plogi.common.u.plogi.max_seq = htons ( FC_LOGIN_DEFAULT_MAX_SEQ );
611 plogi.common.u.plogi.rel_offs = htons ( FC_LOGIN_DEFAULT_REL_OFFS );
612 plogi.common.e_d_tov = htonl ( FC_LOGIN_DEFAULT_E_D_TOV );
613 memcpy ( &plogi.port_wwn, &els->port->port_wwn,
614 sizeof ( plogi.port_wwn ) );
615 memcpy ( &plogi.node_wwn, &els->port->node_wwn,
616 sizeof ( plogi.node_wwn ) );
617 plogi.class3.flags = htons ( FC_LOGIN_CLASS_VALID |
618 FC_LOGIN_CLASS_SEQUENTIAL );
619 plogi.class3.mtu = htons ( FC_LOGIN_DEFAULT_MTU );
620 plogi.class3.max_seq = htons ( FC_LOGIN_DEFAULT_MAX_SEQ );
621 plogi.class3.max_seq_per_xchg = 1;
624 return fc_els_tx ( els, &plogi, sizeof ( plogi ) );
630 * @v els Fibre Channel ELS transaction
632 * @v len Length of ELS frame
633 * @ret rc Return status code
635 static int fc_els_plogi_rx ( struct fc_els *els, void *data, size_t len ) {
636 struct fc_login_frame *plogi = data;
637 struct fc_peer *peer;
641 if ( len < sizeof ( *plogi ) ) {
642 DBGC ( els, FCELS_FMT " received underlength frame:\n",
643 FCELS_ARGS ( els ) );
644 DBGC_HDA ( els, 0, data, len );
648 if ( ! fc_link_ok ( &els->port->link ) ) {
649 DBGC ( els, FCELS_FMT " received while port link is down\n",
650 FCELS_ARGS ( els ) );
655 /* Extract parameters */
656 DBGC ( els, FCELS_FMT " has node %s\n", FCELS_ARGS ( els ),
657 fc_ntoa ( &plogi->node_wwn ) );
658 DBGC ( els, FCELS_FMT " has port %s as %s\n",
659 FCELS_ARGS ( els ), fc_ntoa ( &plogi->port_wwn ),
660 fc_id_ntoa ( &els->peer_port_id ) );
663 peer = fc_peer_get_wwn ( &plogi->port_wwn );
665 DBGC ( els, FCELS_FMT " could not create peer\n",
666 FCELS_ARGS ( els ) );
668 goto err_peer_get_wwn;
672 if ( ( rc = fc_peer_login ( peer, els->port,
673 &els->peer_port_id ) ) != 0 ) {
674 DBGC ( els, FCELS_FMT " could not log in peer: %s\n",
675 FCELS_ARGS ( els ), strerror ( rc ) );
679 /* Transmit response, if applicable */
680 if ( ! fc_els_is_request ( els ) ) {
681 if ( ( rc = fc_els_plogi_tx ( els ) ) != 0 )
685 /* Drop temporary reference to peer */
686 fc_peer_put ( peer );
692 fc_peer_put ( peer );
701 * @v els Fibre Channel ELS transaction
703 * @v len Length of ELS frame
704 * @ret rc Return status code
706 static int fc_els_plogi_detect ( struct fc_els *els __unused, const void *data,
707 size_t len __unused ) {
708 const struct fc_login_frame *plogi = data;
710 /* Check for PLOGI */
711 if ( plogi->command != FC_ELS_PLOGI )
717 /** PLOGI ELS handler */
718 struct fc_els_handler fc_els_plogi_handler __fc_els_handler = {
720 .tx = fc_els_plogi_tx,
721 .rx = fc_els_plogi_rx,
722 .detect = fc_els_plogi_detect,
726 * Create PLOGI request
728 * @v parent Parent interface
729 * @v port Fibre Channel port
730 * @v peer_port_id Peer port ID
731 * @ret rc Return status code
733 int fc_els_plogi ( struct interface *parent, struct fc_port *port,
734 struct fc_port_id *peer_port_id ) {
736 return fc_els_request ( parent, port, peer_port_id,
737 &fc_els_plogi_handler );
740 /******************************************************************************
744 ******************************************************************************
748 * Transmit LOGO request
750 * @v els Fibre Channel ELS transaction
751 * @ret rc Return status code
753 static int fc_els_logo_tx ( struct fc_els *els ) {
754 struct fc_logout_request_frame logo;
757 memset ( &logo, 0, sizeof ( logo ) );
758 logo.command = FC_ELS_LOGO;
759 memcpy ( &logo.port_id, &els->port->port_id, sizeof ( logo.port_id ) );
760 memcpy ( &logo.port_wwn, &els->port->port_wwn,
761 sizeof ( logo.port_wwn ) );
764 return fc_els_tx ( els, &logo, sizeof ( logo ) );
768 * Transmit LOGO response
770 * @v els Fibre Channel ELS transaction
771 * @ret rc Return status code
773 static int fc_els_logo_tx_response ( struct fc_els *els ) {
774 struct fc_logout_response_frame logo;
777 memset ( &logo, 0, sizeof ( logo ) );
778 logo.command = FC_ELS_LS_ACC;
781 return fc_els_tx ( els, &logo, sizeof ( logo ) );
785 * Log out individual peer or whole port as applicable
787 * @v els Fibre Channel ELS transaction
788 * @v port_id Peer port ID
790 static void fc_els_logo_logout ( struct fc_els *els,
791 struct fc_port_id *peer_port_id ) {
792 struct fc_peer *peer;
794 if ( ( memcmp ( peer_port_id, &fc_f_port_id,
795 sizeof ( *peer_port_id ) ) == 0 ) ||
796 ( memcmp ( peer_port_id, &els->port->port_id,
797 sizeof ( *peer_port_id ) ) == 0 ) ) {
798 fc_port_logout ( els->port, 0 );
800 peer = fc_peer_get_port_id ( els->port, peer_port_id );
802 fc_peer_logout ( peer, 0 );
803 fc_peer_put ( peer );
809 * Receive LOGO request
811 * @v els Fibre Channel ELS transaction
813 * @v len Length of ELS frame
814 * @ret rc Return status code
816 static int fc_els_logo_rx_request ( struct fc_els *els, void *data,
818 struct fc_logout_request_frame *logo = data;
822 if ( len < sizeof ( *logo ) ) {
823 DBGC ( els, FCELS_FMT " received underlength frame:\n",
824 FCELS_ARGS ( els ) );
825 DBGC_HDA ( els, 0, data, len );
829 DBGC ( els, FCELS_FMT " has port %s as %s\n", FCELS_ARGS ( els ),
830 fc_ntoa ( &logo->port_wwn ), fc_id_ntoa ( &logo->port_id ) );
832 /* Log out individual peer or whole port as applicable */
833 fc_els_logo_logout ( els, &logo->port_id );
835 /* Transmit repsonse */
836 if ( ( rc = fc_els_logo_tx_response ( els ) ) != 0 )
843 * Receive LOGO response
845 * @v els Fibre Channel ELS transaction
847 * @v len Length of ELS frame
848 * @ret rc Return status code
850 static int fc_els_logo_rx_response ( struct fc_els *els, void *data __unused,
851 size_t len __unused ) {
853 /* Log out individual peer or whole port as applicable */
854 fc_els_logo_logout ( els, &els->peer_port_id );
862 * @v els Fibre Channel ELS transaction
864 * @v len Length of ELS frame
865 * @ret rc Return status code
867 static int fc_els_logo_rx ( struct fc_els *els, void *data, size_t len ) {
869 if ( fc_els_is_request ( els ) ) {
870 return fc_els_logo_rx_response ( els, data, len );
872 return fc_els_logo_rx_request ( els, data, len );
879 * @v els Fibre Channel ELS transaction
881 * @v len Length of ELS frame
882 * @ret rc Return status code
884 static int fc_els_logo_detect ( struct fc_els *els __unused, const void *data,
885 size_t len __unused ) {
886 const struct fc_logout_request_frame *logo = data;
889 if ( logo->command != FC_ELS_LOGO )
895 /** LOGO ELS handler */
896 struct fc_els_handler fc_els_logo_handler __fc_els_handler = {
898 .tx = fc_els_logo_tx,
899 .rx = fc_els_logo_rx,
900 .detect = fc_els_logo_detect,
904 * Create LOGO request
906 * @v parent Parent interface
907 * @v port Fibre Channel port
908 * @v peer_port_id Peer port ID
909 * @ret rc Return status code
911 int fc_els_logo ( struct interface *parent, struct fc_port *port,
912 struct fc_port_id *peer_port_id ) {
914 return fc_els_request ( parent, port, peer_port_id,
915 &fc_els_logo_handler );
918 /******************************************************************************
922 ******************************************************************************
926 * Find PRLI descriptor
928 * @v type Upper-layer protocol type
929 * @ret descriptor PRLI descriptor, or NULL
931 static struct fc_els_prli_descriptor *
932 fc_els_prli_descriptor ( unsigned int type ) {
933 struct fc_els_prli_descriptor *descriptor;
935 for_each_table_entry ( descriptor, FC_ELS_PRLI_DESCRIPTORS ) {
936 if ( descriptor->type == type )
945 * @v els Fibre Channel ELS transaction
946 * @v descriptor ELS PRLI descriptor
947 * @v param Service parameters
948 * @ret rc Return status code
950 int fc_els_prli_tx ( struct fc_els *els,
951 struct fc_els_prli_descriptor *descriptor, void *param ) {
953 struct fc_prli_frame frame;
954 uint8_t param[descriptor->param_len];
955 } __attribute__ (( packed )) prli;
960 ulp = fc_ulp_get_port_id_type ( els->port, &els->peer_port_id,
964 goto err_get_port_id_type;
967 /* Build frame for transmission */
968 memset ( &prli, 0, sizeof ( prli ) );
969 prli.frame.command = fc_els_tx_command ( els, FC_ELS_PRLI );
970 prli.frame.page_len =
971 ( sizeof ( prli.frame.page ) + sizeof ( prli.param ) );
972 prli.frame.len = htons ( sizeof ( prli ) );
973 prli.frame.page.type = descriptor->type;
974 if ( fc_els_is_request ( els ) ) {
975 prli.frame.page.flags |= htons ( FC_PRLI_ESTABLISH );
976 } else if ( fc_link_ok ( &ulp->link ) ) {
977 prli.frame.page.flags |= htons ( FC_PRLI_ESTABLISH |
978 FC_PRLI_RESPONSE_SUCCESS );
980 memcpy ( &prli.param, param, sizeof ( prli.param ) );
983 if ( ( rc = fc_els_tx ( els, &prli, sizeof ( prli ) ) ) != 0 )
986 /* Drop temporary reference to ULP */
993 err_get_port_id_type:
1000 * @v els Fibre Channel ELS transaction
1001 * @v descriptor ELS PRLI descriptor
1002 * @v frame ELS frame
1003 * @v len Length of ELS frame
1004 * @ret rc Return status code
1006 int fc_els_prli_rx ( struct fc_els *els,
1007 struct fc_els_prli_descriptor *descriptor,
1008 void *data, size_t len ) {
1010 struct fc_prli_frame frame;
1011 uint8_t param[descriptor->param_len];
1012 } __attribute__ (( packed )) *prli = data;
1017 if ( len < sizeof ( *prli ) ) {
1018 DBGC ( els, FCELS_FMT " received underlength frame:\n",
1019 FCELS_ARGS ( els ) );
1020 DBGC_HDA ( els, 0, data, len );
1025 DBGC ( els, FCELS_FMT " has parameters:\n", FCELS_ARGS ( els ) );
1026 DBGC_HDA ( els, 0, prli->param, sizeof ( prli->param ) );
1029 ulp = fc_ulp_get_port_id_type ( els->port, &els->peer_port_id,
1033 goto err_get_port_id_type;
1037 if ( ! fc_link_ok ( &ulp->peer->link ) ) {
1038 DBGC ( els, FCELS_FMT " received while peer link is down\n",
1039 FCELS_ARGS ( els ) );
1044 /* Log in ULP, if applicable */
1045 if ( prli->frame.page.flags & htons ( FC_PRLI_ESTABLISH ) ) {
1046 if ( ( rc = fc_ulp_login ( ulp, prli->param,
1047 sizeof ( prli->param ),
1048 fc_els_is_request ( els ) ) ) != 0 ){
1049 DBGC ( els, FCELS_FMT " could not log in ULP: %s\n",
1050 FCELS_ARGS ( els ), strerror ( rc ) );
1054 if ( fc_els_is_request ( els ) ) {
1055 fc_ulp_logout ( ulp, -EACCES );
1057 /* This is just an information-gathering PRLI; do not
1063 /* Transmit response, if applicable */
1064 if ( ! fc_els_is_request ( els ) ) {
1065 if ( ( rc = els->handler->tx ( els ) ) != 0 )
1069 /* Drop temporary reference to ULP */
1078 err_get_port_id_type:
1086 * @v els Fibre Channel ELS transaction
1087 * @v descriptor ELS PRLI descriptor
1089 * @v len Length of ELS frame
1090 * @ret rc Return status code
1092 int fc_els_prli_detect ( struct fc_els *els __unused,
1093 struct fc_els_prli_descriptor *descriptor,
1094 const void *data, size_t len ) {
1096 struct fc_prli_frame frame;
1097 uint8_t param[descriptor->param_len];
1098 } __attribute__ (( packed )) *prli = data;
1100 /* Check for PRLI */
1101 if ( prli->frame.command != FC_ELS_PRLI )
1104 /* Check for sufficient length to contain service parameter page */
1105 if ( len < sizeof ( *prli ) )
1108 /* Check for upper-layer protocol type */
1109 if ( prli->frame.page.type != descriptor->type )
1116 * Create PRLI request
1118 * @v parent Parent interface
1119 * @v port Fibre Channel port
1120 * @v peer_port_id Peer port ID
1121 * @v type Upper-layer protocol type
1122 * @ret rc Return status code
1124 int fc_els_prli ( struct interface *parent, struct fc_port *port,
1125 struct fc_port_id *peer_port_id, unsigned int type ) {
1126 struct fc_els_prli_descriptor *descriptor;
1128 /* Find a PRLI descriptor */
1129 descriptor = fc_els_prli_descriptor ( type );
1133 return fc_els_request ( parent, port, peer_port_id,
1134 descriptor->handler );
1137 /******************************************************************************
1141 ******************************************************************************
1145 * Transmit RTV response
1147 * @v els Fibre Channel ELS transaction
1148 * @ret rc Return status code
1150 static int fc_els_rtv_tx_response ( struct fc_els *els ) {
1151 struct fc_rtv_response_frame rtv;
1154 memset ( &rtv, 0, sizeof ( rtv ) );
1155 rtv.command = FC_ELS_LS_ACC;
1156 rtv.e_d_tov = htonl ( FC_LOGIN_DEFAULT_E_D_TOV );
1159 return fc_els_tx ( els, &rtv, sizeof ( rtv ) );
1165 * @v els Fibre Channel ELS transaction
1167 * @v len Length of ELS frame
1168 * @ret rc Return status code
1170 static int fc_els_rtv_rx ( struct fc_els *els, void *data __unused,
1171 size_t len __unused ) {
1174 DBGC ( els, FCELS_FMT "\n", FCELS_ARGS ( els ) );
1176 /* Transmit response */
1177 if ( ! fc_els_is_request ( els ) ) {
1178 if ( ( rc = fc_els_rtv_tx_response ( els ) ) != 0 )
1188 * @v els Fibre Channel ELS transaction
1190 * @v len Length of ELS frame
1191 * @ret rc Return status code
1193 static int fc_els_rtv_detect ( struct fc_els *els __unused, const void *data,
1194 size_t len __unused ) {
1195 const struct fc_rtv_request_frame *rtv = data;
1198 if ( rtv->command != FC_ELS_RTV )
1204 /** RTV ELS handler */
1205 struct fc_els_handler fc_els_rtv_handler __fc_els_handler = {
1207 .tx = fc_els_unknown_tx,
1208 .rx = fc_els_rtv_rx,
1209 .detect = fc_els_rtv_detect,
1212 /******************************************************************************
1216 ******************************************************************************
1219 /** ECHO request data */
1220 struct fc_echo_request_frame {
1221 /** ECHO frame header */
1222 struct fc_echo_frame_header echo;
1225 } __attribute__ (( packed ));
1227 /** ECHO magic marker */
1228 #define FC_ECHO_MAGIC 0x69505845
1233 * @v els Fibre Channel ELS transaction
1234 * @ret rc Return status code
1236 static int fc_els_echo_tx ( struct fc_els *els ) {
1237 struct fc_echo_request_frame echo;
1239 /* Construct ECHO */
1240 memset ( &echo, 0, sizeof ( echo ) );
1241 echo.echo.command = FC_ELS_ECHO;
1242 echo.magic = htonl ( FC_ECHO_MAGIC );
1245 return fc_els_tx ( els, &echo, sizeof ( echo ) );
1249 * Receive ECHO request
1251 * @v els Fibre Channel ELS transaction
1253 * @v len Length of ELS frame
1254 * @ret rc Return status code
1256 static int fc_els_echo_rx_request ( struct fc_els *els, void *data,
1259 struct fc_echo_frame_header echo;
1260 char payload[ len - sizeof ( struct fc_echo_frame_header ) ];
1264 DBGC ( els, FCELS_FMT "\n", FCELS_ARGS ( els ) );
1266 /* Transmit response */
1267 echo->echo.command = FC_ELS_LS_ACC;
1268 if ( ( rc = fc_els_tx ( els, echo, sizeof ( *echo ) ) ) != 0 )
1276 * Receive ECHO response
1278 * @v els Fibre Channel ELS transaction
1280 * @v len Length of ELS frame
1281 * @ret rc Return status code
1283 static int fc_els_echo_rx_response ( struct fc_els *els, void *data,
1285 struct fc_echo_request_frame *echo = data;
1287 DBGC ( els, FCELS_FMT "\n", FCELS_ARGS ( els ) );
1289 /* Check response is correct */
1290 if ( ( len != sizeof ( *echo ) ) ||
1291 ( echo->magic != htonl ( FC_ECHO_MAGIC ) ) ) {
1292 DBGC ( els, FCELS_FMT " received bad echo response\n",
1293 FCELS_ARGS ( els ) );
1294 DBGC_HDA ( els, 0, data, len );
1304 * @v els Fibre Channel ELS transaction
1306 * @v len Length of ELS frame
1307 * @ret rc Return status code
1309 static int fc_els_echo_rx ( struct fc_els *els, void *data, size_t len ) {
1311 if ( fc_els_is_request ( els ) ) {
1312 return fc_els_echo_rx_response ( els, data, len );
1314 return fc_els_echo_rx_request ( els, data, len );
1321 * @v els Fibre Channel ELS transaction
1323 * @v len Length of ELS frame
1324 * @ret rc Return status code
1326 static int fc_els_echo_detect ( struct fc_els *els __unused, const void *data,
1327 size_t len __unused ) {
1328 const struct fc_echo_frame_header *echo = data;
1330 /* Check for ECHO */
1331 if ( echo->command != FC_ELS_ECHO )
1337 /** ECHO ELS handler */
1338 struct fc_els_handler fc_els_echo_handler __fc_els_handler = {
1340 .tx = fc_els_echo_tx,
1341 .rx = fc_els_echo_rx,
1342 .detect = fc_els_echo_detect,