Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

fcels.c 33KB

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