Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

fcels.c 33KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341
  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. /* Stop process */
  219. process_del ( &els->process );
  220. /* Create exchange */
  221. if ( ( xchg_id = fc_xchg_originate ( &els->xchg, els->port,
  222. &els->peer_port_id,
  223. FC_TYPE_ELS ) ) < 0 ) {
  224. rc = xchg_id;
  225. DBGC ( els, FCELS_FMT " could not create exchange: %s\n",
  226. FCELS_ARGS ( els ), strerror ( rc ) );
  227. fc_els_close ( els, rc );
  228. return;
  229. }
  230. /* Transmit request */
  231. if ( ( rc = els->handler->tx ( els ) ) != 0 ) {
  232. DBGC ( els, FCELS_FMT " could not transmit request: %s\n",
  233. FCELS_ARGS ( els ), strerror ( rc ) );
  234. fc_els_close ( els, rc );
  235. return;
  236. }
  237. }
  238. /** Fibre Channel ELS process descriptor */
  239. static struct process_descriptor fc_els_process_desc =
  240. PROC_DESC ( struct fc_els, process, fc_els_step );
  241. /**
  242. * Create ELS transaction
  243. *
  244. * @v port Fibre Channel port
  245. * @v port_id Local port ID
  246. * @v peer_port_id Peer port ID
  247. * @ret els Fibre Channel ELS transaction, or NULL
  248. */
  249. static struct fc_els * fc_els_create ( struct fc_port *port,
  250. struct fc_port_id *port_id,
  251. struct fc_port_id *peer_port_id ) {
  252. struct fc_els *els;
  253. /* Allocate and initialise structure */
  254. els = zalloc ( sizeof ( *els ) );
  255. if ( ! els )
  256. return NULL;
  257. ref_init ( &els->refcnt, fc_els_free );
  258. intf_init ( &els->job, &fc_els_job_desc, &els->refcnt );
  259. intf_init ( &els->xchg, &fc_els_xchg_desc, &els->refcnt );
  260. process_init_stopped ( &els->process, &fc_els_process_desc,
  261. &els->refcnt );
  262. els->port = fc_port_get ( port );
  263. memcpy ( &els->port_id, port_id, sizeof ( els->port_id ) );
  264. memcpy ( &els->peer_port_id, peer_port_id,
  265. sizeof ( els->peer_port_id ) );
  266. return els;
  267. }
  268. /**
  269. * Create ELS request
  270. *
  271. * @v job Parent job-control interface
  272. * @v port Fibre Channel port
  273. * @v peer_port_id Peer port ID
  274. * @v handler ELS handler
  275. * @ret rc Return status code
  276. */
  277. int fc_els_request ( struct interface *job, struct fc_port *port,
  278. struct fc_port_id *peer_port_id,
  279. struct fc_els_handler *handler ) {
  280. struct fc_els *els;
  281. /* Allocate and initialise structure */
  282. els = fc_els_create ( port, &port->port_id, peer_port_id );
  283. if ( ! els )
  284. return -ENOMEM;
  285. els->handler = handler;
  286. els->flags = FC_ELS_REQUEST;
  287. process_add ( &els->process );
  288. /* Attach to parent job interface, mortalise self, and return */
  289. intf_plug_plug ( &els->job, job );
  290. ref_put ( &els->refcnt );
  291. return 0;
  292. }
  293. /**
  294. * Create ELS response
  295. *
  296. * @v xchg Exchange interface
  297. * @v port Fibre Channel port
  298. * @v port_id Local port ID
  299. * @v peer_port_id Peer port ID
  300. * @ret rc Return status code
  301. */
  302. static int fc_els_respond ( struct interface *xchg, struct fc_port *port,
  303. struct fc_port_id *port_id,
  304. struct fc_port_id *peer_port_id ) {
  305. struct fc_els *els;
  306. /* Allocate and initialise structure */
  307. els = fc_els_create ( port, port_id, peer_port_id );
  308. if ( ! els )
  309. return -ENOMEM;
  310. /* Attach to exchange interface, mortalise self, and return */
  311. intf_plug_plug ( &els->xchg, xchg );
  312. ref_put ( &els->refcnt );
  313. return 0;
  314. }
  315. /** Fibre Channel ELS responder */
  316. struct fc_responder fc_els_responder __fc_responder = {
  317. .type = FC_TYPE_ELS,
  318. .respond = fc_els_respond,
  319. };
  320. /******************************************************************************
  321. *
  322. * Unknown ELS handler
  323. *
  324. ******************************************************************************
  325. */
  326. /**
  327. * Transmit unknown ELS request
  328. *
  329. * @v els Fibre Channel ELS transaction
  330. * @ret rc Return status code
  331. */
  332. static int fc_els_unknown_tx ( struct fc_els *els __unused ) {
  333. return -ENOTSUP;
  334. }
  335. /**
  336. * Transmit unknown ELS response
  337. *
  338. * @v els Fibre Channel ELS transaction
  339. * @ret rc Return status code
  340. */
  341. static int fc_els_unknown_tx_response ( struct fc_els *els ) {
  342. struct fc_ls_rjt_frame ls_rjt;
  343. /* Construct LS_RJT */
  344. memset ( &ls_rjt, 0, sizeof ( ls_rjt ) );
  345. ls_rjt.command = FC_ELS_LS_RJT;
  346. ls_rjt.reason = FC_ELS_RJT_UNSUPPORTED;
  347. /* Transmit LS_RJT */
  348. return fc_els_tx ( els, &ls_rjt, sizeof ( ls_rjt ) );
  349. }
  350. /**
  351. * Receive unknown ELS
  352. *
  353. * @v els Fibre Channel ELS transaction
  354. * @v data ELS frame
  355. * @v len Length of ELS frame
  356. * @ret rc Return status code
  357. */
  358. static int fc_els_unknown_rx ( struct fc_els *els, void *data, size_t len ) {
  359. int rc;
  360. DBGC ( els, FCELS_FMT ":\n", FCELS_ARGS ( els ) );
  361. DBGC_HDA ( els, 0, data, len );
  362. /* Transmit response, if applicable */
  363. if ( ! fc_els_is_request ( els ) ) {
  364. if ( ( rc = fc_els_unknown_tx_response ( els ) ) != 0 )
  365. return rc;
  366. }
  367. return 0;
  368. }
  369. /**
  370. * Detect unknown ELS
  371. *
  372. * @v els Fibre Channel ELS transaction
  373. * @v data ELS frame
  374. * @v len Length of ELS frame
  375. * @ret rc Return status code
  376. */
  377. static int fc_els_unknown_detect ( struct fc_els *els __unused,
  378. const void *data __unused,
  379. size_t len __unused ) {
  380. return -ENOTSUP;
  381. }
  382. /** Unknown ELS handler */
  383. struct fc_els_handler fc_els_unknown_handler __fc_els_handler = {
  384. .name = "UNKNOWN",
  385. .tx = fc_els_unknown_tx,
  386. .rx = fc_els_unknown_rx,
  387. .detect = fc_els_unknown_detect,
  388. };
  389. /******************************************************************************
  390. *
  391. * FLOGI
  392. *
  393. ******************************************************************************
  394. */
  395. /**
  396. * Transmit FLOGI
  397. *
  398. * @v els Fibre Channel ELS transaction
  399. * @ret rc Return status code
  400. */
  401. static int fc_els_flogi_tx ( struct fc_els *els ) {
  402. struct fc_login_frame flogi;
  403. /* Construct FLOGI */
  404. memset ( &flogi, 0, sizeof ( flogi ) );
  405. flogi.command = fc_els_tx_command ( els, FC_ELS_FLOGI );
  406. flogi.common.version = htons ( FC_LOGIN_VERSION );
  407. flogi.common.credit = htons ( FC_LOGIN_DEFAULT_B2B );
  408. flogi.common.flags = htons ( FC_LOGIN_CONTINUOUS_OFFSET );
  409. flogi.common.mtu = htons ( FC_LOGIN_DEFAULT_MTU );
  410. memcpy ( &flogi.port_wwn, &els->port->port_wwn,
  411. sizeof ( flogi.port_wwn ) );
  412. memcpy ( &flogi.node_wwn, &els->port->node_wwn,
  413. sizeof ( flogi.node_wwn ) );
  414. flogi.class3.flags = htons ( FC_LOGIN_CLASS_VALID |
  415. FC_LOGIN_CLASS_SEQUENTIAL );
  416. /* Transmit FLOGI */
  417. return fc_els_tx ( els, &flogi, sizeof ( flogi ) );
  418. }
  419. /**
  420. * Receive FLOGI
  421. *
  422. * @v els Fibre Channel ELS transaction
  423. * @v data ELS frame
  424. * @v len Length of ELS frame
  425. * @ret rc Return status code
  426. */
  427. static int fc_els_flogi_rx ( struct fc_els *els, void *data, size_t len ) {
  428. struct fc_login_frame *flogi = data;
  429. int has_fabric;
  430. int rc;
  431. /* Sanity check */
  432. if ( len < sizeof ( *flogi ) ) {
  433. DBGC ( els, FCELS_FMT " received underlength frame:\n",
  434. FCELS_ARGS ( els ) );
  435. DBGC_HDA ( els, 0, data, len );
  436. return -EINVAL;
  437. }
  438. /* Extract parameters */
  439. has_fabric = ( flogi->common.flags & htons ( FC_LOGIN_F_PORT ) );
  440. DBGC ( els, FCELS_FMT " has node %s\n", FCELS_ARGS ( els ),
  441. fc_ntoa ( &flogi->node_wwn ) );
  442. DBGC ( els, FCELS_FMT " has port %s\n", FCELS_ARGS ( els ),
  443. fc_ntoa ( &flogi->port_wwn ) );
  444. if ( has_fabric ) {
  445. DBGC ( els, FCELS_FMT " has fabric with", FCELS_ARGS ( els ) );
  446. DBGC ( els, " local ID %s\n", fc_id_ntoa ( &els->port_id ) );
  447. } else {
  448. DBGC ( els, FCELS_FMT " has point-to-point link\n",
  449. FCELS_ARGS ( els ) );
  450. }
  451. /* Log in port */
  452. if ( ( rc = fc_port_login ( els->port, &els->port_id, &flogi->node_wwn,
  453. &flogi->port_wwn, has_fabric ) ) != 0 ) {
  454. DBGC ( els, FCELS_FMT " could not log in port: %s\n",
  455. FCELS_ARGS ( els ), strerror ( rc ) );
  456. return rc;
  457. }
  458. /* Send any responses to the newly-assigned peer port ID, if
  459. * applicable.
  460. */
  461. if ( ! has_fabric ) {
  462. memcpy ( &els->peer_port_id, &els->port->ptp_link_port_id,
  463. sizeof ( els->peer_port_id ) );
  464. }
  465. /* Transmit response, if applicable */
  466. if ( ! fc_els_is_request ( els ) ) {
  467. if ( ( rc = fc_els_flogi_tx ( els ) ) != 0 )
  468. return rc;
  469. }
  470. return 0;
  471. }
  472. /**
  473. * Detect FLOGI
  474. *
  475. * @v els Fibre Channel ELS transaction
  476. * @v data ELS frame
  477. * @v len Length of ELS frame
  478. * @ret rc Return status code
  479. */
  480. static int fc_els_flogi_detect ( struct fc_els *els __unused, const void *data,
  481. size_t len __unused ) {
  482. const struct fc_login_frame *flogi = data;
  483. /* Check for FLOGI */
  484. if ( flogi->command != FC_ELS_FLOGI )
  485. return -EINVAL;
  486. return 0;
  487. }
  488. /** FLOGI ELS handler */
  489. struct fc_els_handler fc_els_flogi_handler __fc_els_handler = {
  490. .name = "FLOGI",
  491. .tx = fc_els_flogi_tx,
  492. .rx = fc_els_flogi_rx,
  493. .detect = fc_els_flogi_detect,
  494. };
  495. /**
  496. * Create FLOGI request
  497. *
  498. * @v parent Parent interface
  499. * @v port Fibre Channel port
  500. * @ret rc Return status code
  501. */
  502. int fc_els_flogi ( struct interface *parent, struct fc_port *port ) {
  503. return fc_els_request ( parent, port, &fc_f_port_id,
  504. &fc_els_flogi_handler );
  505. }
  506. /******************************************************************************
  507. *
  508. * PLOGI
  509. *
  510. ******************************************************************************
  511. */
  512. /**
  513. * Transmit PLOGI
  514. *
  515. * @v els Fibre Channel ELS transaction
  516. * @ret rc Return status code
  517. */
  518. static int fc_els_plogi_tx ( struct fc_els *els ) {
  519. struct fc_login_frame plogi;
  520. /* Construct PLOGI */
  521. memset ( &plogi, 0, sizeof ( plogi ) );
  522. plogi.command = fc_els_tx_command ( els, FC_ELS_PLOGI );
  523. plogi.common.version = htons ( FC_LOGIN_VERSION );
  524. plogi.common.credit = htons ( FC_LOGIN_DEFAULT_B2B );
  525. plogi.common.flags = htons ( FC_LOGIN_CONTINUOUS_OFFSET );
  526. plogi.common.mtu = htons ( FC_LOGIN_DEFAULT_MTU );
  527. plogi.common.u.plogi.max_seq = htons ( FC_LOGIN_DEFAULT_MAX_SEQ );
  528. plogi.common.u.plogi.rel_offs = htons ( FC_LOGIN_DEFAULT_REL_OFFS );
  529. plogi.common.e_d_tov = htonl ( FC_LOGIN_DEFAULT_E_D_TOV );
  530. memcpy ( &plogi.port_wwn, &els->port->port_wwn,
  531. sizeof ( plogi.port_wwn ) );
  532. memcpy ( &plogi.node_wwn, &els->port->node_wwn,
  533. sizeof ( plogi.node_wwn ) );
  534. plogi.class3.flags = htons ( FC_LOGIN_CLASS_VALID |
  535. FC_LOGIN_CLASS_SEQUENTIAL );
  536. plogi.class3.mtu = htons ( FC_LOGIN_DEFAULT_MTU );
  537. plogi.class3.max_seq = htons ( FC_LOGIN_DEFAULT_MAX_SEQ );
  538. plogi.class3.max_seq_per_xchg = 1;
  539. /* Transmit PLOGI */
  540. return fc_els_tx ( els, &plogi, sizeof ( plogi ) );
  541. }
  542. /**
  543. * Receive PLOGI
  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_plogi_rx ( struct fc_els *els, void *data, size_t len ) {
  551. struct fc_login_frame *plogi = data;
  552. struct fc_peer *peer;
  553. int rc;
  554. /* Sanity checks */
  555. if ( len < sizeof ( *plogi ) ) {
  556. DBGC ( els, FCELS_FMT " received underlength frame:\n",
  557. FCELS_ARGS ( els ) );
  558. DBGC_HDA ( els, 0, data, len );
  559. rc = -EINVAL;
  560. goto err_sanity;
  561. }
  562. if ( ! fc_link_ok ( &els->port->link ) ) {
  563. DBGC ( els, FCELS_FMT " received while port link is down\n",
  564. FCELS_ARGS ( els ) );
  565. rc = -EINVAL;
  566. goto err_sanity;
  567. }
  568. /* Extract parameters */
  569. DBGC ( els, FCELS_FMT " has node %s\n", FCELS_ARGS ( els ),
  570. fc_ntoa ( &plogi->node_wwn ) );
  571. DBGC ( els, FCELS_FMT " has port %s as %s\n",
  572. FCELS_ARGS ( els ), fc_ntoa ( &plogi->port_wwn ),
  573. fc_id_ntoa ( &els->peer_port_id ) );
  574. /* Get peer */
  575. peer = fc_peer_get_wwn ( &plogi->port_wwn );
  576. if ( ! peer ) {
  577. DBGC ( els, FCELS_FMT " could not create peer\n",
  578. FCELS_ARGS ( els ) );
  579. rc = -ENOMEM;
  580. goto err_peer_get_wwn;
  581. }
  582. /* Record login */
  583. if ( ( rc = fc_peer_login ( peer, els->port,
  584. &els->peer_port_id ) ) != 0 ) {
  585. DBGC ( els, FCELS_FMT " could not log in peer: %s\n",
  586. FCELS_ARGS ( els ), strerror ( rc ) );
  587. goto err_login;
  588. }
  589. /* Transmit response, if applicable */
  590. if ( ! fc_els_is_request ( els ) ) {
  591. if ( ( rc = fc_els_plogi_tx ( els ) ) != 0 )
  592. goto err_plogi_tx;
  593. }
  594. /* Drop temporary reference to peer */
  595. fc_peer_put ( peer );
  596. return 0;
  597. err_plogi_tx:
  598. err_login:
  599. fc_peer_put ( peer );
  600. err_peer_get_wwn:
  601. err_sanity:
  602. return rc;
  603. }
  604. /**
  605. * Detect PLOGI
  606. *
  607. * @v els Fibre Channel ELS transaction
  608. * @v data ELS frame
  609. * @v len Length of ELS frame
  610. * @ret rc Return status code
  611. */
  612. static int fc_els_plogi_detect ( struct fc_els *els __unused, const void *data,
  613. size_t len __unused ) {
  614. const struct fc_login_frame *plogi = data;
  615. /* Check for PLOGI */
  616. if ( plogi->command != FC_ELS_PLOGI )
  617. return -EINVAL;
  618. return 0;
  619. }
  620. /** PLOGI ELS handler */
  621. struct fc_els_handler fc_els_plogi_handler __fc_els_handler = {
  622. .name = "PLOGI",
  623. .tx = fc_els_plogi_tx,
  624. .rx = fc_els_plogi_rx,
  625. .detect = fc_els_plogi_detect,
  626. };
  627. /**
  628. * Create PLOGI request
  629. *
  630. * @v parent Parent interface
  631. * @v port Fibre Channel port
  632. * @v peer_port_id Peer port ID
  633. * @ret rc Return status code
  634. */
  635. int fc_els_plogi ( struct interface *parent, struct fc_port *port,
  636. struct fc_port_id *peer_port_id ) {
  637. return fc_els_request ( parent, port, peer_port_id,
  638. &fc_els_plogi_handler );
  639. }
  640. /******************************************************************************
  641. *
  642. * LOGO
  643. *
  644. ******************************************************************************
  645. */
  646. /**
  647. * Transmit LOGO request
  648. *
  649. * @v els Fibre Channel ELS transaction
  650. * @ret rc Return status code
  651. */
  652. static int fc_els_logo_tx ( struct fc_els *els ) {
  653. struct fc_logout_request_frame logo;
  654. /* Construct LOGO */
  655. memset ( &logo, 0, sizeof ( logo ) );
  656. logo.command = FC_ELS_LOGO;
  657. memcpy ( &logo.port_id, &els->port->port_id, sizeof ( logo.port_id ) );
  658. memcpy ( &logo.port_wwn, &els->port->port_wwn,
  659. sizeof ( logo.port_wwn ) );
  660. /* Transmit LOGO */
  661. return fc_els_tx ( els, &logo, sizeof ( logo ) );
  662. }
  663. /**
  664. * Transmit LOGO response
  665. *
  666. * @v els Fibre Channel ELS transaction
  667. * @ret rc Return status code
  668. */
  669. static int fc_els_logo_tx_response ( struct fc_els *els ) {
  670. struct fc_logout_response_frame logo;
  671. /* Construct LOGO */
  672. memset ( &logo, 0, sizeof ( logo ) );
  673. logo.command = FC_ELS_LS_ACC;
  674. /* Transmit LOGO */
  675. return fc_els_tx ( els, &logo, sizeof ( logo ) );
  676. }
  677. /**
  678. * Log out individual peer or whole port as applicable
  679. *
  680. * @v els Fibre Channel ELS transaction
  681. * @v port_id Peer port ID
  682. */
  683. static void fc_els_logo_logout ( struct fc_els *els,
  684. struct fc_port_id *peer_port_id ) {
  685. struct fc_peer *peer;
  686. if ( ( memcmp ( peer_port_id, &fc_f_port_id,
  687. sizeof ( *peer_port_id ) ) == 0 ) ||
  688. ( memcmp ( peer_port_id, &els->port->port_id,
  689. sizeof ( *peer_port_id ) ) == 0 ) ) {
  690. fc_port_logout ( els->port, 0 );
  691. } else {
  692. peer = fc_peer_get_port_id ( els->port, peer_port_id );
  693. if ( peer ) {
  694. fc_peer_logout ( peer, 0 );
  695. fc_peer_put ( peer );
  696. }
  697. }
  698. }
  699. /**
  700. * Receive LOGO request
  701. *
  702. * @v els Fibre Channel ELS transaction
  703. * @v data ELS frame
  704. * @v len Length of ELS frame
  705. * @ret rc Return status code
  706. */
  707. static int fc_els_logo_rx_request ( struct fc_els *els, void *data,
  708. size_t len ) {
  709. struct fc_logout_request_frame *logo = data;
  710. int rc;
  711. /* Sanity check */
  712. if ( len < sizeof ( *logo ) ) {
  713. DBGC ( els, FCELS_FMT " received underlength frame:\n",
  714. FCELS_ARGS ( els ) );
  715. DBGC_HDA ( els, 0, data, len );
  716. return -EINVAL;
  717. }
  718. DBGC ( els, FCELS_FMT " has port %s as %s\n", FCELS_ARGS ( els ),
  719. fc_ntoa ( &logo->port_wwn ), fc_id_ntoa ( &logo->port_id ) );
  720. /* Log out individual peer or whole port as applicable */
  721. fc_els_logo_logout ( els, &logo->port_id );
  722. /* Transmit repsonse */
  723. if ( ( rc = fc_els_logo_tx_response ( els ) ) != 0 )
  724. return rc;
  725. return 0;
  726. }
  727. /**
  728. * Receive LOGO response
  729. *
  730. * @v els Fibre Channel ELS transaction
  731. * @v data ELS frame
  732. * @v len Length of ELS frame
  733. * @ret rc Return status code
  734. */
  735. static int fc_els_logo_rx_response ( struct fc_els *els, void *data __unused,
  736. size_t len __unused ) {
  737. /* Log out individual peer or whole port as applicable */
  738. fc_els_logo_logout ( els, &els->peer_port_id );
  739. return 0;
  740. }
  741. /**
  742. * Receive LOGO
  743. *
  744. * @v els Fibre Channel ELS transaction
  745. * @v data ELS frame
  746. * @v len Length of ELS frame
  747. * @ret rc Return status code
  748. */
  749. static int fc_els_logo_rx ( struct fc_els *els, void *data, size_t len ) {
  750. if ( fc_els_is_request ( els ) ) {
  751. return fc_els_logo_rx_response ( els, data, len );
  752. } else {
  753. return fc_els_logo_rx_request ( els, data, len );
  754. }
  755. }
  756. /**
  757. * Detect LOGO
  758. *
  759. * @v els Fibre Channel ELS transaction
  760. * @v data ELS frame
  761. * @v len Length of ELS frame
  762. * @ret rc Return status code
  763. */
  764. static int fc_els_logo_detect ( struct fc_els *els __unused, const void *data,
  765. size_t len __unused ) {
  766. const struct fc_logout_request_frame *logo = data;
  767. /* Check for LOGO */
  768. if ( logo->command != FC_ELS_LOGO )
  769. return -EINVAL;
  770. return 0;
  771. }
  772. /** LOGO ELS handler */
  773. struct fc_els_handler fc_els_logo_handler __fc_els_handler = {
  774. .name = "LOGO",
  775. .tx = fc_els_logo_tx,
  776. .rx = fc_els_logo_rx,
  777. .detect = fc_els_logo_detect,
  778. };
  779. /**
  780. * Create LOGO request
  781. *
  782. * @v parent Parent interface
  783. * @v port Fibre Channel port
  784. * @v peer_port_id Peer port ID
  785. * @ret rc Return status code
  786. */
  787. int fc_els_logo ( struct interface *parent, struct fc_port *port,
  788. struct fc_port_id *peer_port_id ) {
  789. return fc_els_request ( parent, port, peer_port_id,
  790. &fc_els_logo_handler );
  791. }
  792. /******************************************************************************
  793. *
  794. * PRLI
  795. *
  796. ******************************************************************************
  797. */
  798. /**
  799. * Find PRLI descriptor
  800. *
  801. * @v type Upper-layer protocol type
  802. * @ret descriptor PRLI descriptor, or NULL
  803. */
  804. static struct fc_els_prli_descriptor *
  805. fc_els_prli_descriptor ( unsigned int type ) {
  806. struct fc_els_prli_descriptor *descriptor;
  807. for_each_table_entry ( descriptor, FC_ELS_PRLI_DESCRIPTORS ) {
  808. if ( descriptor->type == type )
  809. return descriptor;
  810. }
  811. return NULL;
  812. }
  813. /**
  814. * Transmit PRLI
  815. *
  816. * @v els Fibre Channel ELS transaction
  817. * @v descriptor ELS PRLI descriptor
  818. * @v param Service parameters
  819. * @ret rc Return status code
  820. */
  821. int fc_els_prli_tx ( struct fc_els *els,
  822. struct fc_els_prli_descriptor *descriptor, void *param ) {
  823. struct {
  824. struct fc_prli_frame frame;
  825. uint8_t param[descriptor->param_len];
  826. } __attribute__ (( packed )) prli;
  827. struct fc_ulp *ulp;
  828. int rc;
  829. /* Get ULP */
  830. ulp = fc_ulp_get_port_id_type ( els->port, &els->peer_port_id,
  831. descriptor->type );
  832. if ( ! ulp ) {
  833. rc = -ENOMEM;
  834. goto err_get_port_id_type;
  835. }
  836. /* Build frame for transmission */
  837. memset ( &prli, 0, sizeof ( prli ) );
  838. prli.frame.command = fc_els_tx_command ( els, FC_ELS_PRLI );
  839. prli.frame.page_len =
  840. ( sizeof ( prli.frame.page ) + sizeof ( prli.param ) );
  841. prli.frame.len = htons ( sizeof ( prli ) );
  842. prli.frame.page.type = descriptor->type;
  843. if ( fc_els_is_request ( els ) ) {
  844. prli.frame.page.flags |= htons ( FC_PRLI_ESTABLISH );
  845. } else if ( fc_link_ok ( &ulp->link ) ) {
  846. prli.frame.page.flags |= htons ( FC_PRLI_ESTABLISH |
  847. FC_PRLI_RESPONSE_SUCCESS );
  848. }
  849. memcpy ( &prli.param, param, sizeof ( prli.param ) );
  850. /* Transmit frame */
  851. if ( ( rc = fc_els_tx ( els, &prli, sizeof ( prli ) ) ) != 0 )
  852. goto err_tx;
  853. /* Drop temporary reference to ULP */
  854. fc_ulp_put ( ulp );
  855. return 0;
  856. err_tx:
  857. fc_ulp_put ( ulp );
  858. err_get_port_id_type:
  859. return rc;
  860. }
  861. /**
  862. * Receive PRLI
  863. *
  864. * @v els Fibre Channel ELS transaction
  865. * @v descriptor ELS PRLI descriptor
  866. * @v frame ELS frame
  867. * @v len Length of ELS frame
  868. * @ret rc Return status code
  869. */
  870. int fc_els_prli_rx ( struct fc_els *els,
  871. struct fc_els_prli_descriptor *descriptor,
  872. void *data, size_t len ) {
  873. struct {
  874. struct fc_prli_frame frame;
  875. uint8_t param[descriptor->param_len];
  876. } __attribute__ (( packed )) *prli = data;
  877. struct fc_ulp *ulp;
  878. int rc;
  879. /* Sanity check */
  880. if ( len < sizeof ( *prli ) ) {
  881. DBGC ( els, FCELS_FMT " received underlength frame:\n",
  882. FCELS_ARGS ( els ) );
  883. DBGC_HDA ( els, 0, data, len );
  884. rc = -EINVAL;
  885. goto err_sanity;
  886. }
  887. DBGC ( els, FCELS_FMT " has parameters:\n", FCELS_ARGS ( els ) );
  888. DBGC_HDA ( els, 0, prli->param, sizeof ( prli->param ) );
  889. /* Get ULP */
  890. ulp = fc_ulp_get_port_id_type ( els->port, &els->peer_port_id,
  891. descriptor->type );
  892. if ( ! ulp ) {
  893. rc = -ENOMEM;
  894. goto err_get_port_id_type;
  895. }
  896. /* Sanity check */
  897. if ( ! fc_link_ok ( &ulp->peer->link ) ) {
  898. DBGC ( els, FCELS_FMT " received while peer link is down\n",
  899. FCELS_ARGS ( els ) );
  900. rc = -EINVAL;
  901. goto err_link;
  902. }
  903. /* Log in ULP, if applicable */
  904. if ( prli->frame.page.flags & htons ( FC_PRLI_ESTABLISH ) ) {
  905. if ( ( rc = fc_ulp_login ( ulp, prli->param,
  906. sizeof ( prli->param ),
  907. fc_els_is_request ( els ) ) ) != 0 ){
  908. DBGC ( els, FCELS_FMT " could not log in ULP: %s\n",
  909. FCELS_ARGS ( els ), strerror ( rc ) );
  910. goto err_login;
  911. }
  912. } else {
  913. if ( fc_els_is_request ( els ) ) {
  914. fc_ulp_logout ( ulp, -EACCES );
  915. } else {
  916. /* This is just an information-gathering PRLI; do not
  917. * log in or out
  918. */
  919. }
  920. }
  921. /* Transmit response, if applicable */
  922. if ( ! fc_els_is_request ( els ) ) {
  923. if ( ( rc = els->handler->tx ( els ) ) != 0 )
  924. goto err_tx;
  925. }
  926. /* Drop temporary reference to ULP */
  927. fc_ulp_put ( ulp );
  928. return 0;
  929. err_tx:
  930. err_login:
  931. err_link:
  932. fc_ulp_put ( ulp );
  933. err_get_port_id_type:
  934. err_sanity:
  935. return rc;
  936. }
  937. /**
  938. * Detect PRLI
  939. *
  940. * @v els Fibre Channel ELS transaction
  941. * @v descriptor ELS PRLI descriptor
  942. * @v data ELS frame
  943. * @v len Length of ELS frame
  944. * @ret rc Return status code
  945. */
  946. int fc_els_prli_detect ( struct fc_els *els __unused,
  947. struct fc_els_prli_descriptor *descriptor,
  948. const void *data, size_t len ) {
  949. const struct {
  950. struct fc_prli_frame frame;
  951. uint8_t param[descriptor->param_len];
  952. } __attribute__ (( packed )) *prli = data;
  953. /* Check for PRLI */
  954. if ( prli->frame.command != FC_ELS_PRLI )
  955. return -EINVAL;
  956. /* Check for sufficient length to contain service parameter page */
  957. if ( len < sizeof ( *prli ) )
  958. return -EINVAL;
  959. /* Check for upper-layer protocol type */
  960. if ( prli->frame.page.type != descriptor->type )
  961. return -EINVAL;
  962. return 0;
  963. }
  964. /**
  965. * Create PRLI request
  966. *
  967. * @v parent Parent interface
  968. * @v port Fibre Channel port
  969. * @v peer_port_id Peer port ID
  970. * @v type Upper-layer protocol type
  971. * @ret rc Return status code
  972. */
  973. int fc_els_prli ( struct interface *parent, struct fc_port *port,
  974. struct fc_port_id *peer_port_id, unsigned int type ) {
  975. struct fc_els_prli_descriptor *descriptor;
  976. /* Find a PRLI descriptor */
  977. descriptor = fc_els_prli_descriptor ( type );
  978. if ( ! descriptor )
  979. return -ENOTSUP;
  980. return fc_els_request ( parent, port, peer_port_id,
  981. descriptor->handler );
  982. }
  983. /******************************************************************************
  984. *
  985. * RTV
  986. *
  987. ******************************************************************************
  988. */
  989. /**
  990. * Transmit RTV response
  991. *
  992. * @v els Fibre Channel ELS transaction
  993. * @ret rc Return status code
  994. */
  995. static int fc_els_rtv_tx_response ( struct fc_els *els ) {
  996. struct fc_rtv_response_frame rtv;
  997. /* Construct RTV */
  998. memset ( &rtv, 0, sizeof ( rtv ) );
  999. rtv.command = FC_ELS_LS_ACC;
  1000. rtv.e_d_tov = htonl ( FC_LOGIN_DEFAULT_E_D_TOV );
  1001. /* Transmit RTV */
  1002. return fc_els_tx ( els, &rtv, sizeof ( rtv ) );
  1003. }
  1004. /**
  1005. * Receive RTV
  1006. *
  1007. * @v els Fibre Channel ELS transaction
  1008. * @v data ELS frame
  1009. * @v len Length of ELS frame
  1010. * @ret rc Return status code
  1011. */
  1012. static int fc_els_rtv_rx ( struct fc_els *els, void *data __unused,
  1013. size_t len __unused ) {
  1014. int rc;
  1015. DBGC ( els, FCELS_FMT "\n", FCELS_ARGS ( els ) );
  1016. /* Transmit response */
  1017. if ( ! fc_els_is_request ( els ) ) {
  1018. if ( ( rc = fc_els_rtv_tx_response ( els ) ) != 0 )
  1019. return rc;
  1020. }
  1021. return 0;
  1022. }
  1023. /**
  1024. * Detect RTV
  1025. *
  1026. * @v els Fibre Channel ELS transaction
  1027. * @v data ELS frame
  1028. * @v len Length of ELS frame
  1029. * @ret rc Return status code
  1030. */
  1031. static int fc_els_rtv_detect ( struct fc_els *els __unused, const void *data,
  1032. size_t len __unused ) {
  1033. const struct fc_rtv_request_frame *rtv = data;
  1034. /* Check for RTV */
  1035. if ( rtv->command != FC_ELS_RTV )
  1036. return -EINVAL;
  1037. return 0;
  1038. }
  1039. /** RTV ELS handler */
  1040. struct fc_els_handler fc_els_rtv_handler __fc_els_handler = {
  1041. .name = "RTV",
  1042. .tx = fc_els_unknown_tx,
  1043. .rx = fc_els_rtv_rx,
  1044. .detect = fc_els_rtv_detect,
  1045. };
  1046. /******************************************************************************
  1047. *
  1048. * ECHO
  1049. *
  1050. ******************************************************************************
  1051. */
  1052. /** ECHO request data */
  1053. struct fc_echo_request_frame {
  1054. /** ECHO frame header */
  1055. struct fc_echo_frame_header echo;
  1056. /** Magic marker */
  1057. uint32_t magic;
  1058. } __attribute__ (( packed ));
  1059. /** ECHO magic marker */
  1060. #define FC_ECHO_MAGIC 0x69505845
  1061. /**
  1062. * Transmit ECHO
  1063. *
  1064. * @v els Fibre Channel ELS transaction
  1065. * @ret rc Return status code
  1066. */
  1067. static int fc_els_echo_tx ( struct fc_els *els ) {
  1068. struct fc_echo_request_frame echo;
  1069. /* Construct ECHO */
  1070. memset ( &echo, 0, sizeof ( echo ) );
  1071. echo.echo.command = FC_ELS_ECHO;
  1072. echo.magic = htonl ( FC_ECHO_MAGIC );
  1073. /* Transmit ECHO */
  1074. return fc_els_tx ( els, &echo, sizeof ( echo ) );
  1075. }
  1076. /**
  1077. * Receive ECHO request
  1078. *
  1079. * @v els Fibre Channel ELS transaction
  1080. * @v data ELS frame
  1081. * @v len Length of ELS frame
  1082. * @ret rc Return status code
  1083. */
  1084. static int fc_els_echo_rx_request ( struct fc_els *els, void *data,
  1085. size_t len ) {
  1086. struct {
  1087. struct fc_echo_frame_header echo;
  1088. char payload[ len - sizeof ( struct fc_echo_frame_header ) ];
  1089. } *echo = data;
  1090. int rc;
  1091. DBGC ( els, FCELS_FMT "\n", FCELS_ARGS ( els ) );
  1092. /* Transmit response */
  1093. echo->echo.command = FC_ELS_LS_ACC;
  1094. if ( ( rc = fc_els_tx ( els, echo, sizeof ( *echo ) ) ) != 0 )
  1095. return rc;
  1096. /* Nothing to do */
  1097. return 0;
  1098. }
  1099. /**
  1100. * Receive ECHO response
  1101. *
  1102. * @v els Fibre Channel ELS transaction
  1103. * @v data ELS frame
  1104. * @v len Length of ELS frame
  1105. * @ret rc Return status code
  1106. */
  1107. static int fc_els_echo_rx_response ( struct fc_els *els, void *data,
  1108. size_t len ) {
  1109. struct fc_echo_request_frame *echo = data;
  1110. DBGC ( els, FCELS_FMT "\n", FCELS_ARGS ( els ) );
  1111. /* Check response is correct */
  1112. if ( ( len != sizeof ( *echo ) ) ||
  1113. ( echo->magic != htonl ( FC_ECHO_MAGIC ) ) ) {
  1114. DBGC ( els, FCELS_FMT " received bad echo response\n",
  1115. FCELS_ARGS ( els ) );
  1116. DBGC_HDA ( els, 0, data, len );
  1117. return -EIO;
  1118. }
  1119. return 0;
  1120. }
  1121. /**
  1122. * Receive ECHO
  1123. *
  1124. * @v els Fibre Channel ELS transaction
  1125. * @v data ELS frame
  1126. * @v len Length of ELS frame
  1127. * @ret rc Return status code
  1128. */
  1129. static int fc_els_echo_rx ( struct fc_els *els, void *data, size_t len ) {
  1130. if ( fc_els_is_request ( els ) ) {
  1131. return fc_els_echo_rx_response ( els, data, len );
  1132. } else {
  1133. return fc_els_echo_rx_request ( els, data, len );
  1134. }
  1135. }
  1136. /**
  1137. * Detect ECHO
  1138. *
  1139. * @v els Fibre Channel ELS transaction
  1140. * @v data ELS frame
  1141. * @v len Length of ELS frame
  1142. * @ret rc Return status code
  1143. */
  1144. static int fc_els_echo_detect ( struct fc_els *els __unused, const void *data,
  1145. size_t len __unused ) {
  1146. const struct fc_echo_frame_header *echo = data;
  1147. /* Check for ECHO */
  1148. if ( echo->command != FC_ELS_ECHO )
  1149. return -EINVAL;
  1150. return 0;
  1151. }
  1152. /** ECHO ELS handler */
  1153. struct fc_els_handler fc_els_echo_handler __fc_els_handler = {
  1154. .name = "ECHO",
  1155. .tx = fc_els_echo_tx,
  1156. .rx = fc_els_echo_rx,
  1157. .detect = fc_els_echo_detect,
  1158. };