You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

fcels.c 33KB

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