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