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

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