|
|
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.