選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

fc.c 47KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813
  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 <stddef.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <stdio.h>
  23. #include <errno.h>
  24. #include <assert.h>
  25. #include <byteswap.h>
  26. #include <ipxe/refcnt.h>
  27. #include <ipxe/list.h>
  28. #include <ipxe/tables.h>
  29. #include <ipxe/timer.h>
  30. #include <ipxe/retry.h>
  31. #include <ipxe/interface.h>
  32. #include <ipxe/xfer.h>
  33. #include <ipxe/iobuf.h>
  34. #include <ipxe/fc.h>
  35. #include <ipxe/fcels.h>
  36. /** @file
  37. *
  38. * Fibre Channel
  39. *
  40. */
  41. /** List of Fibre Channel ports */
  42. LIST_HEAD ( fc_ports );
  43. /** List of Fibre Channel peers */
  44. LIST_HEAD ( fc_peers );
  45. /******************************************************************************
  46. *
  47. * Well-known addresses
  48. *
  49. ******************************************************************************
  50. */
  51. /** Unassigned port ID */
  52. struct fc_port_id fc_empty_port_id = { .bytes = { 0x00, 0x00, 0x00 } };
  53. /** F_Port contoller port ID */
  54. struct fc_port_id fc_f_port_id = { .bytes = { 0xff, 0xff, 0xfe } };
  55. /** Point-to-point low port ID */
  56. struct fc_port_id fc_ptp_low_port_id = { .bytes = { 0x01, 0x01, 0x01 } };
  57. /** Point-to-point high port ID */
  58. struct fc_port_id fc_ptp_high_port_id = { .bytes = { 0x01, 0x01, 0x02 } };
  59. /******************************************************************************
  60. *
  61. * Utility functions
  62. *
  63. ******************************************************************************
  64. */
  65. /**
  66. * Format Fibre Channel port ID
  67. *
  68. * @v id Fibre Channel port ID
  69. * @ret id_text Port ID text
  70. */
  71. const char * fc_id_ntoa ( const struct fc_port_id *id ) {
  72. static char id_text[ FC_PORT_ID_STRLEN + 1 /* NUL */ ];
  73. snprintf ( id_text, sizeof ( id_text ), "%02x.%02x.%02x",
  74. id->bytes[0], id->bytes[1], id->bytes[2] );
  75. return id_text;
  76. }
  77. /**
  78. * Parse Fibre Channel port ID
  79. *
  80. * @v id_text Port ID text
  81. * @ret id Fibre Channel port ID
  82. * @ret rc Return status code
  83. */
  84. int fc_id_aton ( const char *id_text, struct fc_port_id *id ) {
  85. char *ptr = ( ( char * ) id_text );
  86. unsigned int i = 0;
  87. while ( 1 ) {
  88. id->bytes[i++] = strtoul ( ptr, &ptr, 16 );
  89. if ( i == sizeof ( id->bytes ) )
  90. return ( ( *ptr == '\0' ) ? 0 : -EINVAL );
  91. if ( *ptr != '.' )
  92. return -EINVAL;
  93. ptr++;
  94. }
  95. }
  96. /**
  97. * Format Fibre Channel WWN
  98. *
  99. * @v wwn Fibre Channel WWN
  100. * @ret wwn_text WWN text
  101. */
  102. const char * fc_ntoa ( const struct fc_name *wwn ) {
  103. static char wwn_text[ FC_NAME_STRLEN + 1 /* NUL */ ];
  104. snprintf ( wwn_text, sizeof ( wwn_text ),
  105. "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
  106. wwn->bytes[0], wwn->bytes[1], wwn->bytes[2], wwn->bytes[3],
  107. wwn->bytes[4], wwn->bytes[5], wwn->bytes[6], wwn->bytes[7] );
  108. return wwn_text;
  109. }
  110. /**
  111. * Parse Fibre Channel WWN
  112. *
  113. * @v wwn_text WWN text
  114. * @ret wwn Fibre Channel WWN
  115. * @ret rc Return status code
  116. */
  117. int fc_aton ( const char *wwn_text, struct fc_name *wwn ) {
  118. char *ptr = ( ( char * ) wwn_text );
  119. unsigned int i = 0;
  120. while ( 1 ) {
  121. wwn->bytes[i++] = strtoul ( ptr, &ptr, 16 );
  122. if ( i == sizeof ( wwn->bytes ) )
  123. return ( ( *ptr == '\0' ) ? 0 : -EINVAL );
  124. if ( *ptr != ':' )
  125. return -EINVAL;
  126. ptr++;
  127. }
  128. }
  129. /**
  130. * Fill Fibre Channel socket address
  131. *
  132. * @v sa_fc Fibre Channel socket address to fill in
  133. * @v id Fibre Channel port ID
  134. * @ret sa Socket address
  135. */
  136. struct sockaddr * fc_fill_sockaddr ( struct sockaddr_fc *sa_fc,
  137. struct fc_port_id *id ) {
  138. union {
  139. struct sockaddr sa;
  140. struct sockaddr_fc fc;
  141. } *u = container_of ( sa_fc, typeof ( *u ), fc );
  142. memset ( sa_fc, 0, sizeof ( *sa_fc ) );
  143. sa_fc->sfc_family = AF_FC;
  144. memcpy ( &sa_fc->sfc_port_id, id, sizeof ( sa_fc->sfc_port_id ) );
  145. return &u->sa;
  146. }
  147. /******************************************************************************
  148. *
  149. * Fibre Channel link state
  150. *
  151. ******************************************************************************
  152. */
  153. /** Default link status code */
  154. #define EUNKNOWN_LINK_STATUS __einfo_error ( EINFO_EUNKNOWN_LINK_STATUS )
  155. #define EINFO_EUNKNOWN_LINK_STATUS \
  156. __einfo_uniqify ( EINFO_EINPROGRESS, 0x01, "Unknown" )
  157. /**
  158. * Mark Fibre Channel link as up
  159. *
  160. * @v link Fibre Channel link state monitor
  161. */
  162. static void fc_link_up ( struct fc_link_state *link ) {
  163. /* Stop retry timer */
  164. stop_timer ( &link->timer );
  165. /* Record link state */
  166. link->rc = 0;
  167. }
  168. /**
  169. * Mark Fibre Channel link as down
  170. *
  171. * @v link Fibre Channel link state monitor
  172. * @v rc Link state
  173. */
  174. static void fc_link_err ( struct fc_link_state *link, int rc ) {
  175. /* Record link state */
  176. if ( rc == 0 )
  177. rc = -EUNKNOWN_LINK_STATUS;
  178. link->rc = rc;
  179. /* Schedule another link examination */
  180. start_timer_fixed ( &link->timer, FC_LINK_RETRY_DELAY );
  181. }
  182. /**
  183. * Examine Fibre Channel link state
  184. *
  185. * @v link Fibre Channel link state monitor
  186. */
  187. static void fc_link_examine ( struct fc_link_state *link ) {
  188. link->examine ( link );
  189. }
  190. /**
  191. * Handle Fibre Channel link retry timer expiry
  192. */
  193. static void fc_link_expired ( struct retry_timer *timer, int over __unused ) {
  194. struct fc_link_state *link =
  195. container_of ( timer, struct fc_link_state, timer );
  196. /* Schedule another link examination */
  197. start_timer_fixed ( &link->timer, FC_LINK_RETRY_DELAY );
  198. /* Examine link */
  199. fc_link_examine ( link );
  200. }
  201. /**
  202. * Initialise Fibre Channel link state monitor
  203. *
  204. * @v link Fibre Channel link state monitor
  205. * @v examine Examine link state method
  206. * @v refcnt Reference counter
  207. */
  208. static void fc_link_init ( struct fc_link_state *link,
  209. void ( * examine ) ( struct fc_link_state *link ),
  210. struct refcnt *refcnt ) {
  211. link->rc = -EUNKNOWN_LINK_STATUS;
  212. timer_init ( &link->timer, fc_link_expired, refcnt );
  213. link->examine = examine;
  214. }
  215. /**
  216. * Start monitoring Fibre Channel link state
  217. *
  218. * @v link Fibre Channel link state monitor
  219. */
  220. static void fc_link_start ( struct fc_link_state *link ) {
  221. start_timer_nodelay ( &link->timer );
  222. }
  223. /**
  224. * Stop monitoring Fibre Channel link state
  225. *
  226. * @v link Fibre Channel link state monitor
  227. */
  228. static void fc_link_stop ( struct fc_link_state *link ) {
  229. stop_timer ( &link->timer );
  230. }
  231. /******************************************************************************
  232. *
  233. * Fibre Channel exchanges
  234. *
  235. ******************************************************************************
  236. */
  237. /** A Fibre Channel exchange */
  238. struct fc_exchange {
  239. /** Reference count */
  240. struct refcnt refcnt;
  241. /** Fibre Channel port */
  242. struct fc_port *port;
  243. /** List of active exchanges within this port */
  244. struct list_head list;
  245. /** Peer port ID */
  246. struct fc_port_id peer_port_id;
  247. /** Data structure type */
  248. unsigned int type;
  249. /** Flags */
  250. unsigned int flags;
  251. /** Local exchange ID */
  252. uint16_t xchg_id;
  253. /** Peer exchange ID */
  254. uint16_t peer_xchg_id;
  255. /** Active sequence ID */
  256. uint8_t seq_id;
  257. /** Active sequence count */
  258. uint16_t seq_cnt;
  259. /** Timeout timer */
  260. struct retry_timer timer;
  261. /** Upper-layer protocol interface */
  262. struct interface ulp;
  263. };
  264. /** Fibre Channel exchange flags */
  265. enum fc_exchange_flags {
  266. /** We are the exchange originator */
  267. FC_XCHG_ORIGINATOR = 0x0001,
  268. /** We have the sequence initiative */
  269. FC_XCHG_SEQ_INITIATIVE = 0x0002,
  270. /** This is the first sequence of the exchange */
  271. FC_XCHG_SEQ_FIRST = 0x0004,
  272. };
  273. /** Fibre Channel timeout */
  274. #define FC_TIMEOUT ( 1 * TICKS_PER_SEC )
  275. /**
  276. * Create local Fibre Channel exchange identifier
  277. *
  278. * @ret xchg_id Local exchange ID
  279. */
  280. static unsigned int fc_new_xchg_id ( void ) {
  281. static uint16_t next_id = 0x0000;
  282. /* We must avoid using FC_RX_ID_UNKNOWN (0xffff) */
  283. next_id += 2;
  284. return next_id;
  285. }
  286. /**
  287. * Create local Fibre Channel sequence identifier
  288. *
  289. * @ret seq_id Local sequence identifier
  290. */
  291. static unsigned int fc_new_seq_id ( void ) {
  292. static uint8_t seq_id = 0x00;
  293. return (++seq_id);
  294. }
  295. /**
  296. * Free Fibre Channel exchange
  297. *
  298. * @v refcnt Reference count
  299. */
  300. static void fc_xchg_free ( struct refcnt *refcnt ) {
  301. struct fc_exchange *xchg =
  302. container_of ( refcnt, struct fc_exchange, refcnt );
  303. assert ( ! timer_running ( &xchg->timer ) );
  304. assert ( list_empty ( &xchg->list ) );
  305. fc_port_put ( xchg->port );
  306. free ( xchg );
  307. }
  308. /**
  309. * Close Fibre Channel exchange
  310. *
  311. * @v xchg Fibre Channel exchange
  312. * @v rc Reason for close
  313. */
  314. static void fc_xchg_close ( struct fc_exchange *xchg, int rc ) {
  315. struct fc_port *port = xchg->port;
  316. if ( rc != 0 ) {
  317. DBGC2 ( port, "FCXCHG %s/%04x closed: %s\n",
  318. port->name, xchg->xchg_id, strerror ( rc ) );
  319. }
  320. /* Stop timer */
  321. stop_timer ( &xchg->timer );
  322. /* If list still holds a reference, remove from list of open
  323. * exchanges and drop list's reference.
  324. */
  325. if ( ! list_empty ( &xchg->list ) ) {
  326. list_del ( &xchg->list );
  327. INIT_LIST_HEAD ( &xchg->list );
  328. ref_put ( &xchg->refcnt );
  329. }
  330. /* Shutdown interfaces */
  331. intf_shutdown ( &xchg->ulp, rc );
  332. }
  333. /**
  334. * Handle exchange timeout
  335. *
  336. * @v timer Timeout timer
  337. * @v over Failure indicator
  338. */
  339. static void fc_xchg_expired ( struct retry_timer *timer, int over __unused ) {
  340. struct fc_exchange *xchg =
  341. container_of ( timer, struct fc_exchange, timer );
  342. struct fc_port *port = xchg->port;
  343. DBGC ( port, "FCXCHG %s/%04x timed out\n", port->name, xchg->xchg_id );
  344. /* Terminate the exchange */
  345. fc_xchg_close ( xchg, -ETIMEDOUT );
  346. }
  347. /**
  348. * Check Fibre Channel exchange window
  349. *
  350. * @v xchg Fibre Channel exchange
  351. * @ret len Length opf window
  352. */
  353. static size_t fc_xchg_window ( struct fc_exchange *xchg __unused ) {
  354. /* We don't currently store the path MTU */
  355. return FC_LOGIN_DEFAULT_MTU;
  356. }
  357. /**
  358. * Allocate Fibre Channel I/O buffer
  359. *
  360. * @v xchg Fibre Channel exchange
  361. * @v len Payload length
  362. * @ret iobuf I/O buffer, or NULL
  363. */
  364. static struct io_buffer * fc_xchg_alloc_iob ( struct fc_exchange *xchg,
  365. size_t len ) {
  366. struct fc_port *port = xchg->port;
  367. struct io_buffer *iobuf;
  368. iobuf = xfer_alloc_iob ( &port->transport,
  369. ( sizeof ( struct fc_frame_header ) + len ) );
  370. if ( iobuf ) {
  371. iob_reserve ( iobuf, sizeof ( struct fc_frame_header ) );
  372. }
  373. return iobuf;
  374. }
  375. /**
  376. * Transmit data as part of a Fibre Channel exchange
  377. *
  378. * @v xchg Fibre Channel exchange
  379. * @v iobuf I/O buffer
  380. * @v meta Data transfer metadata
  381. * @ret rc Return status code
  382. */
  383. static int fc_xchg_tx ( struct fc_exchange *xchg, struct io_buffer *iobuf,
  384. struct xfer_metadata *meta ) {
  385. struct fc_port *port = xchg->port;
  386. struct sockaddr_fc *dest = ( ( struct sockaddr_fc * ) meta->dest );
  387. struct fc_frame_header *fchdr;
  388. unsigned int r_ctl;
  389. unsigned int f_ctl_es;
  390. int rc;
  391. /* Sanity checks */
  392. if ( ! ( xchg->flags & FC_XCHG_SEQ_INITIATIVE ) ) {
  393. DBGC ( port, "FCXCHG %s/%04x cannot transmit while not "
  394. "holding sequence initiative\n",
  395. port->name, xchg->xchg_id );
  396. rc = -EBUSY;
  397. goto done;
  398. }
  399. /* Calculate routing control */
  400. if ( xchg->type == FC_TYPE_ELS ) {
  401. r_ctl = FC_R_CTL_ELS;
  402. if ( meta->flags & XFER_FL_RESPONSE ) {
  403. r_ctl |= FC_R_CTL_SOL_CTRL;
  404. } else {
  405. r_ctl |= FC_R_CTL_UNSOL_CTRL;
  406. }
  407. } else {
  408. r_ctl = FC_R_CTL_DATA;
  409. switch ( meta->flags &
  410. ( XFER_FL_CMD_STAT | XFER_FL_RESPONSE ) ) {
  411. case ( XFER_FL_CMD_STAT | XFER_FL_RESPONSE ):
  412. r_ctl |= FC_R_CTL_CMD_STAT;
  413. break;
  414. case ( XFER_FL_CMD_STAT ):
  415. r_ctl |= FC_R_CTL_UNSOL_CMD;
  416. break;
  417. case ( XFER_FL_RESPONSE ):
  418. r_ctl |= FC_R_CTL_SOL_DATA;
  419. break;
  420. default:
  421. r_ctl |= FC_R_CTL_UNSOL_DATA;
  422. break;
  423. }
  424. }
  425. /* Calculate exchange and sequence control */
  426. f_ctl_es = 0;
  427. if ( ! ( xchg->flags & FC_XCHG_ORIGINATOR ) )
  428. f_ctl_es |= FC_F_CTL_ES_RESPONDER;
  429. if ( xchg->flags & FC_XCHG_SEQ_FIRST )
  430. f_ctl_es |= FC_F_CTL_ES_FIRST;
  431. if ( meta->flags & XFER_FL_OUT )
  432. f_ctl_es |= ( FC_F_CTL_ES_END | FC_F_CTL_ES_LAST );
  433. if ( meta->flags & XFER_FL_OVER )
  434. f_ctl_es |= ( FC_F_CTL_ES_END | FC_F_CTL_ES_TRANSFER );
  435. /* Create frame header */
  436. fchdr = iob_push ( iobuf, sizeof ( *fchdr ) );
  437. memset ( fchdr, 0, sizeof ( *fchdr ) );
  438. fchdr->r_ctl = r_ctl;
  439. memcpy ( &fchdr->d_id,
  440. ( dest ? &dest->sfc_port_id : &xchg->peer_port_id ),
  441. sizeof ( fchdr->d_id ) );
  442. memcpy ( &fchdr->s_id, &port->port_id, sizeof ( fchdr->s_id ) );
  443. fchdr->type = xchg->type;
  444. fchdr->f_ctl_es = f_ctl_es;
  445. fchdr->seq_id = xchg->seq_id;
  446. fchdr->seq_cnt = htons ( xchg->seq_cnt++ );
  447. fchdr->ox_id = htons ( ( xchg->flags & FC_XCHG_ORIGINATOR ) ?
  448. xchg->xchg_id : xchg->peer_xchg_id );
  449. fchdr->rx_id = htons ( ( xchg->flags & FC_XCHG_ORIGINATOR ) ?
  450. xchg->peer_xchg_id : xchg->xchg_id );
  451. if ( meta->flags & XFER_FL_ABS_OFFSET ) {
  452. fchdr->f_ctl_misc |= FC_F_CTL_MISC_REL_OFF;
  453. fchdr->parameter = htonl ( meta->offset );
  454. }
  455. /* Relinquish sequence initiative if applicable */
  456. if ( meta->flags & XFER_FL_OVER ) {
  457. xchg->flags &= ~( FC_XCHG_SEQ_INITIATIVE | FC_XCHG_SEQ_FIRST );
  458. xchg->seq_cnt = 0;
  459. }
  460. /* Reset timeout */
  461. start_timer_fixed ( &xchg->timer, FC_TIMEOUT );
  462. /* Deliver frame */
  463. if ( ( rc = xfer_deliver_iob ( &port->transport,
  464. iob_disown ( iobuf ) ) ) != 0 ) {
  465. DBGC ( port, "FCXCHG %s/%04x cannot transmit: %s\n",
  466. port->name, xchg->xchg_id, strerror ( rc ) );
  467. goto done;
  468. }
  469. done:
  470. free_iob ( iobuf );
  471. return rc;
  472. }
  473. /** Mapping from Fibre Channel routing control information to xfer metadata */
  474. static const uint8_t fc_r_ctl_info_meta_flags[ FC_R_CTL_INFO_MASK + 1 ] = {
  475. [FC_R_CTL_UNCAT] = ( 0 ),
  476. [FC_R_CTL_SOL_DATA] = ( XFER_FL_RESPONSE ),
  477. [FC_R_CTL_UNSOL_CTRL] = ( XFER_FL_CMD_STAT ),
  478. [FC_R_CTL_SOL_CTRL] = ( XFER_FL_CMD_STAT ),
  479. [FC_R_CTL_UNSOL_DATA] = ( 0 ),
  480. [FC_R_CTL_DATA_DESC] = ( XFER_FL_CMD_STAT ),
  481. [FC_R_CTL_UNSOL_CMD] = ( XFER_FL_CMD_STAT ),
  482. [FC_R_CTL_CMD_STAT] = ( XFER_FL_CMD_STAT | XFER_FL_RESPONSE ),
  483. };
  484. /**
  485. * Receive data as part of a Fibre Channel exchange
  486. *
  487. * @v xchg Fibre Channel exchange
  488. * @v iobuf I/O buffer
  489. * @v meta Data transfer metadata
  490. * @ret rc Return status code
  491. */
  492. static int fc_xchg_rx ( struct fc_exchange *xchg, struct io_buffer *iobuf,
  493. struct xfer_metadata *meta __unused ) {
  494. struct fc_port *port = xchg->port;
  495. struct fc_frame_header *fchdr = iobuf->data;
  496. struct xfer_metadata fc_meta;
  497. struct sockaddr_fc src;
  498. struct sockaddr_fc dest;
  499. int rc;
  500. /* Record peer exchange ID */
  501. xchg->peer_xchg_id =
  502. ntohs ( ( fchdr->f_ctl_es & FC_F_CTL_ES_RESPONDER ) ?
  503. fchdr->rx_id : fchdr->ox_id );
  504. /* Sequence checks */
  505. if ( xchg->flags & FC_XCHG_SEQ_INITIATIVE ) {
  506. DBGC ( port, "FCXCHG %s/%04x received frame while holding "
  507. "sequence initiative\n", port->name, xchg->xchg_id );
  508. rc = -EBUSY;
  509. goto done;
  510. }
  511. if ( ntohs ( fchdr->seq_cnt ) != xchg->seq_cnt ) {
  512. DBGC ( port, "FCXCHG %s/%04x received out-of-order frame %d "
  513. "(expected %d)\n", port->name, xchg->xchg_id,
  514. ntohs ( fchdr->seq_cnt ), xchg->seq_cnt );
  515. rc = -EPIPE;
  516. goto done;
  517. }
  518. if ( xchg->seq_cnt == 0 )
  519. xchg->seq_id = fchdr->seq_id;
  520. xchg->seq_cnt++;
  521. if ( fchdr->seq_id != xchg->seq_id ) {
  522. DBGC ( port, "FCXCHG %s/%04x received frame for incorrect "
  523. "sequence %02x (expected %02x)\n", port->name,
  524. xchg->xchg_id, fchdr->seq_id, xchg->seq_id );
  525. rc = -EPIPE;
  526. goto done;
  527. }
  528. /* Check for end of sequence and transfer of sequence initiative */
  529. if ( fchdr->f_ctl_es & FC_F_CTL_ES_END ) {
  530. xchg->seq_cnt = 0;
  531. if ( fchdr->f_ctl_es & FC_F_CTL_ES_TRANSFER ) {
  532. xchg->flags |= FC_XCHG_SEQ_INITIATIVE;
  533. xchg->seq_id = fc_new_seq_id();
  534. }
  535. }
  536. /* Construct metadata */
  537. memset ( &fc_meta, 0, sizeof ( fc_meta ) );
  538. fc_meta.flags =
  539. fc_r_ctl_info_meta_flags[ fchdr->r_ctl & FC_R_CTL_INFO_MASK ];
  540. if ( fchdr->f_ctl_es & FC_F_CTL_ES_TRANSFER ) {
  541. fc_meta.flags |= XFER_FL_OVER;
  542. }
  543. if ( ( fchdr->f_ctl_es & FC_F_CTL_ES_LAST ) &&
  544. ( fchdr->f_ctl_es & FC_F_CTL_ES_END ) ) {
  545. fc_meta.flags |= XFER_FL_OUT;
  546. }
  547. if ( fchdr->f_ctl_misc & FC_F_CTL_MISC_REL_OFF ) {
  548. fc_meta.flags |= XFER_FL_ABS_OFFSET;
  549. fc_meta.offset = ntohl ( fchdr->parameter );
  550. }
  551. fc_meta.src = fc_fill_sockaddr ( &src, &fchdr->s_id );
  552. fc_meta.dest = fc_fill_sockaddr ( &dest, &fchdr->d_id );
  553. /* Reset timeout */
  554. start_timer_fixed ( &xchg->timer, FC_TIMEOUT );
  555. /* Deliver via exchange's ULP interface */
  556. iob_pull ( iobuf, sizeof ( *fchdr ) );
  557. if ( ( rc = xfer_deliver ( &xchg->ulp, iob_disown ( iobuf ),
  558. &fc_meta ) ) != 0 ) {
  559. DBGC ( port, "FCXCHG %s/%04x cannot deliver frame: %s\n",
  560. port->name, xchg->xchg_id, strerror ( rc ) );
  561. goto done;
  562. }
  563. /* Close exchange if applicable */
  564. if ( ( fchdr->f_ctl_es & FC_F_CTL_ES_LAST ) &&
  565. ( fchdr->f_ctl_es & FC_F_CTL_ES_END ) ) {
  566. fc_xchg_close ( xchg, 0 );
  567. }
  568. done:
  569. free_iob ( iobuf );
  570. return rc;
  571. }
  572. /** Fibre Channel exchange ULP interface operations */
  573. static struct interface_operation fc_xchg_ulp_op[] = {
  574. INTF_OP ( xfer_deliver, struct fc_exchange *, fc_xchg_tx ),
  575. INTF_OP ( xfer_alloc_iob, struct fc_exchange *, fc_xchg_alloc_iob ),
  576. INTF_OP ( xfer_window, struct fc_exchange *, fc_xchg_window ),
  577. INTF_OP ( intf_close, struct fc_exchange *, fc_xchg_close ),
  578. };
  579. /** Fibre Channel exchange ULP interface descriptor */
  580. static struct interface_descriptor fc_xchg_ulp_desc =
  581. INTF_DESC ( struct fc_exchange, ulp, fc_xchg_ulp_op );
  582. /**
  583. * Create new Fibre Channel exchange
  584. *
  585. * @v port Fibre Channel port
  586. * @v peer_port_id Peer port ID
  587. * @ret xchg Exchange, or NULL
  588. */
  589. static struct fc_exchange * fc_xchg_create ( struct fc_port *port,
  590. struct fc_port_id *peer_port_id,
  591. unsigned int type ) {
  592. struct fc_exchange *xchg;
  593. /* Allocate and initialise structure */
  594. xchg = zalloc ( sizeof ( *xchg ) );
  595. if ( ! xchg )
  596. return NULL;
  597. ref_init ( &xchg->refcnt, fc_xchg_free );
  598. intf_init ( &xchg->ulp, &fc_xchg_ulp_desc, &xchg->refcnt );
  599. timer_init ( &xchg->timer, fc_xchg_expired, &xchg->refcnt );
  600. xchg->port = fc_port_get ( port );
  601. memcpy ( &xchg->peer_port_id, peer_port_id,
  602. sizeof ( xchg->peer_port_id ) );
  603. xchg->type = type;
  604. xchg->xchg_id = fc_new_xchg_id();
  605. xchg->peer_xchg_id = FC_RX_ID_UNKNOWN;
  606. xchg->seq_id = fc_new_seq_id();
  607. /* Transfer reference to list of exchanges and return */
  608. list_add ( &xchg->list, &port->xchgs );
  609. return xchg;
  610. }
  611. /**
  612. * Originate a new Fibre Channel exchange
  613. *
  614. * @v parent Interface to which to attach
  615. * @v port Fibre Channel port
  616. * @v peer_port_id Peer port ID
  617. * @ret xchg_id Exchange ID, or negative error
  618. */
  619. int fc_xchg_originate ( struct interface *parent, struct fc_port *port,
  620. struct fc_port_id *peer_port_id, unsigned int type ) {
  621. struct fc_exchange *xchg;
  622. /* Allocate and initialise structure */
  623. xchg = fc_xchg_create ( port, peer_port_id, type );
  624. if ( ! xchg )
  625. return -ENOMEM;
  626. xchg->flags = ( FC_XCHG_ORIGINATOR | FC_XCHG_SEQ_INITIATIVE |
  627. FC_XCHG_SEQ_FIRST );
  628. DBGC2 ( port, "FCXCHG %s/%04x originating to %s (type %02x)\n",
  629. port->name, xchg->xchg_id, fc_id_ntoa ( &xchg->peer_port_id ),
  630. xchg->type );
  631. /* Attach to parent interface and return */
  632. intf_plug_plug ( &xchg->ulp, parent );
  633. return xchg->xchg_id;
  634. }
  635. /**
  636. * Open a new responder Fibre Channel exchange
  637. *
  638. * @v port Fibre Channel port
  639. * @v fchdr Fibre Channel frame header
  640. * @ret xchg Fibre Channel exchange, or NULL
  641. */
  642. static struct fc_exchange * fc_xchg_respond ( struct fc_port *port,
  643. struct fc_frame_header *fchdr ) {
  644. struct fc_exchange *xchg;
  645. struct fc_responder *responder;
  646. unsigned int type = fchdr->type;
  647. int rc;
  648. /* Allocate and initialise structure */
  649. xchg = fc_xchg_create ( port, &fchdr->s_id, type );
  650. if ( ! xchg )
  651. return NULL;
  652. xchg->seq_id = fchdr->seq_id;
  653. DBGC2 ( port, "FCXCHG %s/%04x responding to %s xchg %04x (type "
  654. "%02x)\n", port->name, xchg->xchg_id,
  655. fc_id_ntoa ( &xchg->peer_port_id ),
  656. ntohs ( fchdr->ox_id ), xchg->type );
  657. /* Find a responder, if any */
  658. for_each_table_entry ( responder, FC_RESPONDERS ) {
  659. if ( responder->type == type ) {
  660. if ( ( rc = responder->respond ( &xchg->ulp, port,
  661. &fchdr->d_id,
  662. &fchdr->s_id ) ) !=0 ){
  663. DBGC ( port, "FCXCHG %s/%04x could not "
  664. "respond: %s\n", port->name,
  665. xchg->xchg_id, strerror ( rc ) );
  666. }
  667. }
  668. break;
  669. }
  670. /* We may or may not have a ULP attached at this point, but
  671. * the exchange does exist.
  672. */
  673. return xchg;
  674. }
  675. /******************************************************************************
  676. *
  677. * Fibre Channel ports
  678. *
  679. ******************************************************************************
  680. */
  681. /**
  682. * Close Fibre Channel port
  683. *
  684. * @v port Fibre Channel port
  685. * @v rc Reason for close
  686. */
  687. static void fc_port_close ( struct fc_port *port, int rc ) {
  688. struct fc_exchange *xchg;
  689. struct fc_exchange *tmp;
  690. DBGC ( port, "FCPORT %s closed\n", port->name );
  691. /* Log out port, if necessary */
  692. if ( fc_link_ok ( &port->link ) )
  693. fc_port_logout ( port, rc );
  694. /* Stop link monitor */
  695. fc_link_stop ( &port->link );
  696. /* Shut down interfaces */
  697. intf_shutdown ( &port->transport, rc );
  698. intf_shutdown ( &port->flogi, rc );
  699. /* Shut down any remaining exchanges */
  700. list_for_each_entry_safe ( xchg, tmp, &port->xchgs, list )
  701. fc_xchg_close ( xchg, rc );
  702. /* Remove from list of ports */
  703. list_del ( &port->list );
  704. INIT_LIST_HEAD ( &port->list );
  705. }
  706. /**
  707. * Identify Fibre Channel exchange by local exchange ID
  708. *
  709. * @v port Fibre Channel port
  710. * @v xchg_id Local exchange ID
  711. * @ret xchg Fibre Channel exchange, or NULL
  712. */
  713. static struct fc_exchange * fc_port_demux ( struct fc_port *port,
  714. unsigned int xchg_id ) {
  715. struct fc_exchange *xchg;
  716. list_for_each_entry ( xchg, &port->xchgs, list ) {
  717. if ( xchg->xchg_id == xchg_id )
  718. return xchg;
  719. }
  720. return NULL;
  721. }
  722. /**
  723. * Handle received frame from Fibre Channel port
  724. *
  725. * @v port Fibre Channel port
  726. * @v iobuf I/O buffer
  727. * @v meta Data transfer metadata
  728. * @ret rc Return status code
  729. */
  730. static int fc_port_deliver ( struct fc_port *port, struct io_buffer *iobuf,
  731. struct xfer_metadata *meta ) {
  732. struct fc_frame_header *fchdr = iobuf->data;
  733. unsigned int xchg_id;
  734. struct fc_exchange *xchg;
  735. int rc;
  736. /* Sanity check */
  737. if ( iob_len ( iobuf ) < sizeof ( *fchdr ) ) {
  738. DBGC ( port, "FCPORT %s received underlength frame (%zd "
  739. "bytes)\n", port->name, iob_len ( iobuf ) );
  740. rc = -EINVAL;
  741. goto err_sanity;
  742. }
  743. /* Verify local port ID */
  744. if ( ( memcmp ( &fchdr->d_id, &port->port_id,
  745. sizeof ( fchdr->d_id ) ) != 0 ) &&
  746. ( memcmp ( &fchdr->d_id, &fc_f_port_id,
  747. sizeof ( fchdr->d_id ) ) != 0 ) &&
  748. ( memcmp ( &port->port_id, &fc_empty_port_id,
  749. sizeof ( port->port_id ) ) != 0 ) ) {
  750. DBGC ( port, "FCPORT %s received frame for incorrect port ID "
  751. "%s\n", port->name, fc_id_ntoa ( &fchdr->d_id ) );
  752. rc = -ENOTCONN;
  753. goto err_port_id;
  754. }
  755. /* Demultiplex amongst active exchanges */
  756. xchg_id = ntohs ( ( fchdr->f_ctl_es & FC_F_CTL_ES_RESPONDER ) ?
  757. fchdr->ox_id : fchdr->rx_id );
  758. xchg = fc_port_demux ( port, xchg_id );
  759. /* If we have no active exchange and this frame starts a new
  760. * exchange, try to create a new responder exchange
  761. */
  762. if ( ( fchdr->f_ctl_es & FC_F_CTL_ES_FIRST ) &&
  763. ( fchdr->seq_cnt == 0 ) ) {
  764. /* Create new exchange */
  765. xchg = fc_xchg_respond ( port, fchdr );
  766. if ( ! xchg ) {
  767. DBGC ( port, "FCPORT %s cannot create new exchange\n",
  768. port->name );
  769. rc = -ENOMEM;
  770. goto err_respond;
  771. }
  772. }
  773. /* Fail if no exchange exists */
  774. if ( ! xchg ) {
  775. DBGC ( port, "FCPORT %s xchg %04x unknown\n",
  776. port->name, xchg_id );
  777. rc = -ENOTCONN;
  778. goto err_no_xchg;
  779. }
  780. /* Pass received frame to exchange */
  781. ref_get ( &xchg->refcnt );
  782. if ( ( rc = fc_xchg_rx ( xchg, iob_disown ( iobuf ), meta ) ) != 0 )
  783. goto err_xchg_rx;
  784. err_xchg_rx:
  785. ref_put ( &xchg->refcnt );
  786. err_no_xchg:
  787. err_respond:
  788. err_port_id:
  789. err_sanity:
  790. free_iob ( iobuf );
  791. return rc;
  792. }
  793. /**
  794. * Log in Fibre Channel port
  795. *
  796. * @v port Fibre Channel port
  797. * @v port_id Local port ID
  798. * @v link_node_wwn Link node name
  799. * @v link_port_wwn Link port name
  800. * @v has_fabric Link is to a fabric
  801. * @ret rc Return status code
  802. */
  803. int fc_port_login ( struct fc_port *port, struct fc_port_id *port_id,
  804. const struct fc_name *link_node_wwn,
  805. const struct fc_name *link_port_wwn, int has_fabric ) {
  806. struct fc_peer *peer;
  807. struct fc_peer *tmp;
  808. /* Perform implicit logout if logged in and details differ */
  809. if ( fc_link_ok ( &port->link ) &&
  810. ( ( ( !! ( port->flags & FC_PORT_HAS_FABRIC ) ) !=
  811. ( !! has_fabric ) ) ||
  812. ( memcmp ( &port->link_node_wwn, link_node_wwn,
  813. sizeof ( port->link_node_wwn ) ) != 0 ) ||
  814. ( memcmp ( &port->link_port_wwn, link_port_wwn,
  815. sizeof ( port->link_port_wwn ) ) != 0 ) ||
  816. ( has_fabric &&
  817. ( memcmp ( &port->port_id, port_id,
  818. sizeof ( port->port_id ) ) != 0 ) ) ) ) {
  819. fc_port_logout ( port, 0 );
  820. }
  821. /* Log in, if applicable */
  822. if ( ! fc_link_ok ( &port->link ) ) {
  823. /* Record link port name */
  824. memcpy ( &port->link_node_wwn, link_node_wwn,
  825. sizeof ( port->link_node_wwn ) );
  826. memcpy ( &port->link_port_wwn, link_port_wwn,
  827. sizeof ( port->link_port_wwn ) );
  828. DBGC ( port, "FCPORT %s logged in to %s",
  829. port->name, fc_ntoa ( &port->link_node_wwn ) );
  830. DBGC ( port, " port %s\n", fc_ntoa ( &port->link_port_wwn ) );
  831. /* Calculate local (and possibly remote) port IDs */
  832. if ( has_fabric ) {
  833. port->flags |= FC_PORT_HAS_FABRIC;
  834. memcpy ( &port->port_id, port_id,
  835. sizeof ( port->port_id ) );
  836. } else {
  837. port->flags &= ~FC_PORT_HAS_FABRIC;
  838. if ( memcmp ( &port->port_wwn, link_port_wwn,
  839. sizeof ( port->port_wwn ) ) > 0 ) {
  840. memcpy ( &port->port_id, &fc_ptp_high_port_id,
  841. sizeof ( port->port_id ) );
  842. memcpy ( &port->ptp_link_port_id,
  843. &fc_ptp_low_port_id,
  844. sizeof ( port->ptp_link_port_id ) );
  845. } else {
  846. memcpy ( &port->port_id, &fc_ptp_low_port_id,
  847. sizeof ( port->port_id ) );
  848. memcpy ( &port->ptp_link_port_id,
  849. &fc_ptp_high_port_id,
  850. sizeof ( port->ptp_link_port_id ) );
  851. }
  852. }
  853. DBGC ( port, "FCPORT %s logged in via a %s, with local ID "
  854. "%s\n", port->name,
  855. ( ( port->flags & FC_PORT_HAS_FABRIC ) ?
  856. "fabric" : "point-to-point link" ),
  857. fc_id_ntoa ( &port->port_id ) );
  858. }
  859. /* Record login */
  860. fc_link_up ( &port->link );
  861. /* Notify peers of link state change */
  862. list_for_each_entry_safe ( peer, tmp, &fc_peers, list ) {
  863. fc_peer_get ( peer );
  864. fc_link_examine ( &peer->link );
  865. fc_peer_put ( peer );
  866. }
  867. return 0;
  868. }
  869. /**
  870. * Log out Fibre Channel port
  871. *
  872. * @v port Fibre Channel port
  873. * @v rc Reason for logout
  874. */
  875. void fc_port_logout ( struct fc_port *port, int rc ) {
  876. struct fc_peer *peer;
  877. struct fc_peer *tmp;
  878. DBGC ( port, "FCPORT %s logged out: %s\n",
  879. port->name, strerror ( rc ) );
  880. /* Erase port details */
  881. memset ( &port->port_id, 0, sizeof ( port->port_id ) );
  882. /* Record logout */
  883. fc_link_err ( &port->link, rc );
  884. /* Notify peers of link state change */
  885. list_for_each_entry_safe ( peer, tmp, &fc_peers, list ) {
  886. fc_peer_get ( peer );
  887. fc_link_examine ( &peer->link );
  888. fc_peer_put ( peer );
  889. }
  890. }
  891. /**
  892. * Handle FLOGI completion
  893. *
  894. * @v port Fibre Channel port
  895. * @v rc Reason for completion
  896. */
  897. static void fc_port_flogi_done ( struct fc_port *port, int rc ) {
  898. intf_restart ( &port->flogi, rc );
  899. if ( rc != 0 )
  900. fc_port_logout ( port, rc );
  901. }
  902. /**
  903. * Examine Fibre Channel port link state
  904. *
  905. * @ link Fibre Channel link state monitor
  906. */
  907. static void fc_port_examine ( struct fc_link_state *link ) {
  908. struct fc_port *port = container_of ( link, struct fc_port, link );
  909. int rc;
  910. /* Do nothing if already logged in */
  911. if ( fc_link_ok ( &port->link ) )
  912. return;
  913. DBGC ( port, "FCPORT %s attempting login\n", port->name );
  914. /* Try to create FLOGI ELS */
  915. intf_restart ( &port->flogi, -ECANCELED );
  916. if ( ( rc = fc_els_flogi ( &port->flogi, port ) ) != 0 ) {
  917. DBGC ( port, "FCPORT %s could not initiate FLOGI: %s\n",
  918. port->name, strerror ( rc ) );
  919. fc_port_logout ( port, rc );
  920. return;
  921. }
  922. }
  923. /**
  924. * Handle change of flow control window
  925. *
  926. * @v port Fibre Channel port
  927. */
  928. static void fc_port_window_changed ( struct fc_port *port ) {
  929. size_t window;
  930. /* Check if transport layer is ready */
  931. window = xfer_window ( &port->transport );
  932. if ( window > 0 ) {
  933. /* Transport layer is ready. Start login if the link
  934. * is not already up.
  935. */
  936. if ( ! fc_link_ok ( &port->link ) )
  937. fc_link_start ( &port->link );
  938. } else {
  939. /* Transport layer is not ready. Log out port and
  940. * wait for transport layer before attempting log in
  941. * again.
  942. */
  943. fc_port_logout ( port, -ENOTCONN );
  944. fc_link_stop ( &port->link );
  945. }
  946. }
  947. /** Fibre Channel port transport interface operations */
  948. static struct interface_operation fc_port_transport_op[] = {
  949. INTF_OP ( xfer_deliver, struct fc_port *, fc_port_deliver ),
  950. INTF_OP ( xfer_window_changed, struct fc_port *,
  951. fc_port_window_changed ),
  952. INTF_OP ( intf_close, struct fc_port *, fc_port_close ),
  953. };
  954. /** Fibre Channel port transport interface descriptor */
  955. static struct interface_descriptor fc_port_transport_desc =
  956. INTF_DESC ( struct fc_port, transport, fc_port_transport_op );
  957. /** Fibre Channel port FLOGI interface operations */
  958. static struct interface_operation fc_port_flogi_op[] = {
  959. INTF_OP ( intf_close, struct fc_port *, fc_port_flogi_done ),
  960. };
  961. /** Fibre Channel port FLOGI interface descriptor */
  962. static struct interface_descriptor fc_port_flogi_desc =
  963. INTF_DESC ( struct fc_port, flogi, fc_port_flogi_op );
  964. /**
  965. * Create Fibre Channel port
  966. *
  967. * @v transport Transport interface
  968. * @v node Fibre Channel node name
  969. * @v port Fibre Channel port name
  970. * @ret rc Return status code
  971. */
  972. int fc_port_open ( struct interface *transport, const struct fc_name *node_wwn,
  973. const struct fc_name *port_wwn ) {
  974. static unsigned int portindex = 0;
  975. struct fc_port *port;
  976. /* Allocate and initialise structure */
  977. port = zalloc ( sizeof ( *port ) );
  978. if ( ! port )
  979. return -ENOMEM;
  980. ref_init ( &port->refcnt, NULL );
  981. intf_init ( &port->transport, &fc_port_transport_desc, &port->refcnt );
  982. fc_link_init ( &port->link, fc_port_examine, &port->refcnt );
  983. intf_init ( &port->flogi, &fc_port_flogi_desc, &port->refcnt );
  984. list_add_tail ( &port->list, &fc_ports );
  985. INIT_LIST_HEAD ( &port->xchgs );
  986. memcpy ( &port->node_wwn, node_wwn, sizeof ( port->node_wwn ) );
  987. memcpy ( &port->port_wwn, port_wwn, sizeof ( port->port_wwn ) );
  988. /* Create device name */
  989. snprintf ( port->name, sizeof ( port->name ), "fc%d", portindex++ );
  990. DBGC ( port, "FCPORT %s opened as %s",
  991. port->name, fc_ntoa ( &port->node_wwn ) );
  992. DBGC ( port, " port %s\n", fc_ntoa ( &port->port_wwn ) );
  993. /* Attach to transport layer, mortalise self, and return */
  994. intf_plug_plug ( &port->transport, transport );
  995. ref_put ( &port->refcnt );
  996. return 0;
  997. }
  998. /**
  999. * Find Fibre Channel port by name
  1000. *
  1001. * @v name Fibre Channel port name
  1002. * @ret port Fibre Channel port, or NULL
  1003. */
  1004. struct fc_port * fc_port_find ( const char *name ) {
  1005. struct fc_port *port;
  1006. list_for_each_entry ( port, &fc_ports, list ) {
  1007. if ( strcmp ( name, port->name ) == 0 )
  1008. return port;
  1009. }
  1010. return NULL;
  1011. }
  1012. /**
  1013. * Find Fibre Channel port by link node name
  1014. *
  1015. * @v link_port_wwn Link node name
  1016. * @ret port Fibre Channel port, or NULL
  1017. */
  1018. static struct fc_port *
  1019. fc_port_find_link_wwn ( struct fc_name *link_port_wwn ) {
  1020. struct fc_port *port;
  1021. list_for_each_entry ( port, &fc_ports, list ) {
  1022. if ( fc_link_ok ( &port->link ) &&
  1023. ( memcmp ( &port->link_port_wwn, link_port_wwn,
  1024. sizeof ( port->link_port_wwn ) ) == 0 ) ) {
  1025. return port;
  1026. }
  1027. }
  1028. return NULL;
  1029. }
  1030. /******************************************************************************
  1031. *
  1032. * Fibre Channel peers
  1033. *
  1034. ******************************************************************************
  1035. */
  1036. /**
  1037. * Close Fibre Channel peer
  1038. *
  1039. * @v peer Fibre Channel peer
  1040. * @v rc Reason for close
  1041. */
  1042. static void fc_peer_close ( struct fc_peer *peer, int rc ) {
  1043. DBGC ( peer, "FCPEER %s closed: %s\n",
  1044. fc_ntoa ( &peer->port_wwn ) , strerror ( rc ) );
  1045. /* Sanity check */
  1046. assert ( list_empty ( &peer->ulps ) );
  1047. /* Stop link timer */
  1048. fc_link_stop ( &peer->link );
  1049. /* Shut down interfaces */
  1050. intf_shutdown ( &peer->plogi, rc );
  1051. /* Remove from list of peers */
  1052. list_del ( &peer->list );
  1053. INIT_LIST_HEAD ( &peer->list );
  1054. }
  1055. /**
  1056. * Increment Fibre Channel peer active usage count
  1057. *
  1058. * @v peer Fibre Channel peer
  1059. */
  1060. static void fc_peer_increment ( struct fc_peer *peer ) {
  1061. /* Increment our usage count */
  1062. peer->usage++;
  1063. }
  1064. /**
  1065. * Decrement Fibre Channel peer active usage count
  1066. *
  1067. * @v peer Fibre Channel peer
  1068. */
  1069. static void fc_peer_decrement ( struct fc_peer *peer ) {
  1070. /* Sanity check */
  1071. assert ( peer->usage > 0 );
  1072. /* Decrement our usage count and log out if we reach zero */
  1073. if ( peer->usage-- == 0 )
  1074. fc_peer_logout ( peer, 0 );
  1075. }
  1076. /**
  1077. * Log in Fibre Channel peer
  1078. *
  1079. * @v peer Fibre Channel peer
  1080. * @v port Fibre Channel port
  1081. * @v port_id Port ID
  1082. * @ret rc Return status code
  1083. */
  1084. int fc_peer_login ( struct fc_peer *peer, struct fc_port *port,
  1085. struct fc_port_id *port_id ) {
  1086. struct fc_ulp *ulp;
  1087. struct fc_ulp *tmp;
  1088. /* Perform implicit logout if logged in and details differ */
  1089. if ( fc_link_ok ( &peer->link ) &&
  1090. ( ( peer->port != port ) ||
  1091. ( memcmp ( &peer->port_id, port_id,
  1092. sizeof ( peer->port_id ) ) !=0 ) ) ) {
  1093. fc_peer_logout ( peer, 0 );
  1094. }
  1095. /* Log in, if applicable */
  1096. if ( ! fc_link_ok ( &peer->link ) ) {
  1097. /* Record peer details */
  1098. assert ( peer->port == NULL );
  1099. peer->port = fc_port_get ( port );
  1100. memcpy ( &peer->port_id, port_id, sizeof ( peer->port_id ) );
  1101. DBGC ( peer, "FCPEER %s logged in via %s as %s\n",
  1102. fc_ntoa ( &peer->port_wwn ), peer->port->name,
  1103. fc_id_ntoa ( &peer->port_id ) );
  1104. /* Add login reference */
  1105. fc_peer_get ( peer );
  1106. }
  1107. /* Record login */
  1108. fc_link_up ( &peer->link );
  1109. /* Notify ULPs of link state change */
  1110. list_for_each_entry_safe ( ulp, tmp, &peer->ulps, list ) {
  1111. fc_ulp_get ( ulp );
  1112. fc_link_examine ( &ulp->link );
  1113. fc_ulp_put ( ulp );
  1114. }
  1115. return 0;
  1116. }
  1117. /**
  1118. * Log out Fibre Channel peer
  1119. *
  1120. * @v peer Fibre Channel peer
  1121. * @v rc Reason for logout
  1122. */
  1123. void fc_peer_logout ( struct fc_peer *peer, int rc ) {
  1124. struct fc_ulp *ulp;
  1125. struct fc_ulp *tmp;
  1126. DBGC ( peer, "FCPEER %s logged out: %s\n",
  1127. fc_ntoa ( &peer->port_wwn ), strerror ( rc ) );
  1128. /* Drop login reference, if applicable */
  1129. if ( fc_link_ok ( &peer->link ) )
  1130. fc_peer_put ( peer );
  1131. /* Erase peer details */
  1132. fc_port_put ( peer->port );
  1133. peer->port = NULL;
  1134. /* Record logout */
  1135. fc_link_err ( &peer->link, rc );
  1136. /* Notify ULPs of link state change */
  1137. list_for_each_entry_safe ( ulp, tmp, &peer->ulps, list ) {
  1138. fc_ulp_get ( ulp );
  1139. fc_link_examine ( &ulp->link );
  1140. fc_ulp_put ( ulp );
  1141. }
  1142. /* Close peer if there are no active users */
  1143. if ( peer->usage == 0 )
  1144. fc_peer_close ( peer, rc );
  1145. }
  1146. /**
  1147. * Handle PLOGI completion
  1148. *
  1149. * @v peer Fibre Channel peer
  1150. * @v rc Reason for completion
  1151. */
  1152. static void fc_peer_plogi_done ( struct fc_peer *peer, int rc ) {
  1153. intf_restart ( &peer->plogi, rc );
  1154. if ( rc != 0 )
  1155. fc_peer_logout ( peer, rc );
  1156. }
  1157. /**
  1158. * Examine Fibre Channel peer link state
  1159. *
  1160. * @ link Fibre Channel link state monitor
  1161. */
  1162. static void fc_peer_examine ( struct fc_link_state *link ) {
  1163. struct fc_peer *peer = container_of ( link, struct fc_peer, link );
  1164. struct fc_port *port;
  1165. struct fc_port_id *peer_port_id;
  1166. int rc;
  1167. /* Check to see if underlying port link has gone down */
  1168. if ( peer->port && ( ! fc_link_ok ( &peer->port->link ) ) ) {
  1169. fc_peer_logout ( peer, -ENOTCONN );
  1170. return;
  1171. }
  1172. /* Do nothing if already logged in */
  1173. if ( fc_link_ok ( &peer->link ) )
  1174. return;
  1175. DBGC ( peer, "FCPEER %s attempting login\n",
  1176. fc_ntoa ( &peer->port_wwn ) );
  1177. /* Sanity check */
  1178. assert ( peer->port == NULL );
  1179. /* Look for a port with the peer attached via a point-to-point link */
  1180. port = fc_port_find_link_wwn ( &peer->port_wwn );
  1181. if ( ! port ) {
  1182. DBGC ( peer, "FCPEER %s could not find a point-to-point "
  1183. "link\n", fc_ntoa ( &peer->port_wwn ) );
  1184. fc_peer_logout ( peer, -ENOENT );
  1185. return;
  1186. }
  1187. peer_port_id = &port->ptp_link_port_id;
  1188. /* Try to create PLOGI ELS */
  1189. intf_restart ( &peer->plogi, -ECANCELED );
  1190. if ( ( rc = fc_els_plogi ( &peer->plogi, port, peer_port_id ) ) != 0 ) {
  1191. DBGC ( peer, "FCPEER %s could not initiate PLOGI: %s\n",
  1192. fc_ntoa ( &peer->port_wwn ), strerror ( rc ) );
  1193. fc_peer_logout ( peer, rc );
  1194. return;
  1195. }
  1196. }
  1197. /** Fibre Channel peer PLOGI interface operations */
  1198. static struct interface_operation fc_peer_plogi_op[] = {
  1199. INTF_OP ( intf_close, struct fc_peer *, fc_peer_plogi_done ),
  1200. };
  1201. /** Fibre Channel peer PLOGI interface descriptor */
  1202. static struct interface_descriptor fc_peer_plogi_desc =
  1203. INTF_DESC ( struct fc_peer, plogi, fc_peer_plogi_op );
  1204. /**
  1205. * Create Fibre Channel peer
  1206. *
  1207. * @v port_wwn Node name
  1208. * @ret peer Fibre Channel peer, or NULL
  1209. */
  1210. static struct fc_peer * fc_peer_create ( const struct fc_name *port_wwn ) {
  1211. struct fc_peer *peer;
  1212. /* Allocate and initialise structure */
  1213. peer = zalloc ( sizeof ( *peer ) );
  1214. if ( ! peer )
  1215. return NULL;
  1216. ref_init ( &peer->refcnt, NULL );
  1217. fc_link_init ( &peer->link, fc_peer_examine, &peer->refcnt );
  1218. intf_init ( &peer->plogi, &fc_peer_plogi_desc, &peer->refcnt );
  1219. list_add_tail ( &peer->list, &fc_peers );
  1220. memcpy ( &peer->port_wwn, port_wwn, sizeof ( peer->port_wwn ) );
  1221. INIT_LIST_HEAD ( &peer->ulps );
  1222. /* Start link monitor */
  1223. fc_link_start ( &peer->link );
  1224. DBGC ( peer, "FCPEER %s created\n", fc_ntoa ( &peer->port_wwn ) );
  1225. return peer;
  1226. }
  1227. /**
  1228. * Get Fibre Channel peer by node name
  1229. *
  1230. * @v port_wwn Node name
  1231. * @ret peer Fibre Channel peer, or NULL
  1232. */
  1233. struct fc_peer * fc_peer_get_wwn ( const struct fc_name *port_wwn ) {
  1234. struct fc_peer *peer;
  1235. /* Look for an existing peer */
  1236. list_for_each_entry ( peer, &fc_peers, list ) {
  1237. if ( memcmp ( &peer->port_wwn, port_wwn,
  1238. sizeof ( peer->port_wwn ) ) == 0 )
  1239. return fc_peer_get ( peer );
  1240. }
  1241. /* Create a new peer */
  1242. peer = fc_peer_create ( port_wwn );
  1243. if ( ! peer )
  1244. return NULL;
  1245. return peer;
  1246. }
  1247. /**
  1248. * Get Fibre Channel peer by port ID
  1249. *
  1250. * @v port Fibre Channel port
  1251. * @v peer_port_id Peer port ID
  1252. * @ret peer Fibre Channel peer, or NULL
  1253. */
  1254. struct fc_peer * fc_peer_get_port_id ( struct fc_port *port,
  1255. const struct fc_port_id *peer_port_id ){
  1256. struct fc_peer *peer;
  1257. /* Look for an existing peer */
  1258. list_for_each_entry ( peer, &fc_peers, list ) {
  1259. if ( ( peer->port == port ) &&
  1260. ( memcmp ( &peer->port_id, peer_port_id,
  1261. sizeof ( peer->port_id ) ) == 0 ) )
  1262. return fc_peer_get ( peer );
  1263. }
  1264. /* Cannot create a new peer, since we have no port name to use */
  1265. return NULL;
  1266. }
  1267. /******************************************************************************
  1268. *
  1269. * Fibre Channel upper-layer protocols
  1270. *
  1271. ******************************************************************************
  1272. */
  1273. /**
  1274. * Close Fibre Channel upper-layer protocol
  1275. *
  1276. * @v ulp Fibre Channel upper-layer protocol
  1277. * @v rc Reason for close
  1278. */
  1279. static void fc_ulp_close ( struct fc_ulp *ulp, int rc ) {
  1280. DBGC ( ulp, "FCULP %s/%02x closed: %s\n",
  1281. fc_ntoa ( &ulp->peer->port_wwn ), ulp->type, strerror ( rc ) );
  1282. /* Sanity check */
  1283. assert ( ulp->usage == 0 );
  1284. /* Stop link monitor */
  1285. fc_link_stop ( &ulp->link );
  1286. /* Shut down interfaces */
  1287. intf_shutdown ( &ulp->prli, rc );
  1288. /* Remove from list of ULPs */
  1289. list_del ( &ulp->list );
  1290. INIT_LIST_HEAD ( &ulp->list );
  1291. /* Drop peer reference */
  1292. fc_peer_put ( ulp->peer );
  1293. ulp->peer = NULL;
  1294. }
  1295. /**
  1296. * Increment Fibre Channel upper-layer protocol active usage count
  1297. *
  1298. * @v ulp Fibre Channel ulp
  1299. */
  1300. void fc_ulp_increment ( struct fc_ulp *ulp ) {
  1301. /* Increment peer's usage count */
  1302. fc_peer_increment ( ulp->peer );
  1303. /* Increment our usage count */
  1304. ulp->usage++;
  1305. }
  1306. /**
  1307. * Decrement Fibre Channel upper-layer protocol active usage count
  1308. *
  1309. * @v ulp Fibre Channel ulp
  1310. */
  1311. void fc_ulp_decrement ( struct fc_ulp *ulp ) {
  1312. struct fc_peer *peer = ulp->peer;
  1313. /* Sanity check */
  1314. assert ( ulp->usage > 0 );
  1315. /* Decrement our usage count and log out if we reach zero */
  1316. if ( ulp->usage-- == 0 )
  1317. fc_ulp_logout ( ulp, 0 );
  1318. /* Decrement our peer's usage count */
  1319. fc_peer_decrement ( peer );
  1320. }
  1321. /**
  1322. * Log in Fibre Channel upper-layer protocol
  1323. *
  1324. * @v ulp Fibre Channel upper-layer protocol
  1325. * @v param Service parameters
  1326. * @v param_len Length of service parameters
  1327. * @v originated Login was originated by us
  1328. * @ret rc Return status code
  1329. */
  1330. int fc_ulp_login ( struct fc_ulp *ulp, const void *param, size_t param_len,
  1331. int originated ) {
  1332. /* Perform implicit logout if logged in and service parameters differ */
  1333. if ( fc_link_ok ( &ulp->link ) &&
  1334. ( ( ulp->param_len != param_len ) ||
  1335. ( memcmp ( ulp->param, param, ulp->param_len ) != 0 ) ) ) {
  1336. fc_ulp_logout ( ulp, 0 );
  1337. }
  1338. /* Log in, if applicable */
  1339. if ( ! fc_link_ok ( &ulp->link ) ) {
  1340. /* Record service parameters */
  1341. assert ( ulp->param == NULL );
  1342. assert ( ulp->param_len == 0 );
  1343. ulp->param = malloc ( param_len );
  1344. if ( ! ulp->param ) {
  1345. DBGC ( ulp, "FCULP %s/%02x could not record "
  1346. "parameters\n",
  1347. fc_ntoa ( &ulp->peer->port_wwn ), ulp->type );
  1348. return -ENOMEM;
  1349. }
  1350. memcpy ( ulp->param, param, param_len );
  1351. ulp->param_len = param_len;
  1352. DBGC ( ulp, "FCULP %s/%02x logged in with parameters:\n",
  1353. fc_ntoa ( &ulp->peer->port_wwn ), ulp->type );
  1354. DBGC_HDA ( ulp, 0, ulp->param, ulp->param_len );
  1355. /* Add login reference */
  1356. fc_ulp_get ( ulp );
  1357. }
  1358. /* Record login */
  1359. fc_link_up ( &ulp->link );
  1360. /* Work around a bug in some versions of the Linux Fibre
  1361. * Channel stack, which fail to fully initialise image pairs
  1362. * established via a PRLI originated by the Linux stack
  1363. * itself.
  1364. */
  1365. if ( originated )
  1366. ulp->flags |= FC_ULP_ORIGINATED_LOGIN_OK;
  1367. if ( ! ( ulp->flags & FC_ULP_ORIGINATED_LOGIN_OK ) ) {
  1368. DBGC ( ulp, "FCULP %s/%02x sending extra PRLI to work around "
  1369. "Linux bug\n",
  1370. fc_ntoa ( &ulp->peer->port_wwn ), ulp->type );
  1371. fc_link_start ( &ulp->link );
  1372. }
  1373. return 0;
  1374. }
  1375. /**
  1376. * Log out Fibre Channel upper-layer protocol
  1377. *
  1378. * @v ulp Fibre Channel upper-layer protocol
  1379. * @v rc Reason for logout
  1380. */
  1381. void fc_ulp_logout ( struct fc_ulp *ulp, int rc ) {
  1382. DBGC ( ulp, "FCULP %s/%02x logged out: %s\n",
  1383. fc_ntoa ( &ulp->peer->port_wwn ), ulp->type, strerror ( rc ) );
  1384. /* Drop login reference, if applicable */
  1385. if ( fc_link_ok ( &ulp->link ) )
  1386. fc_ulp_put ( ulp );
  1387. /* Discard service parameters */
  1388. free ( ulp->param );
  1389. ulp->param = NULL;
  1390. ulp->param_len = 0;
  1391. ulp->flags = 0;
  1392. /* Record logout */
  1393. fc_link_err ( &ulp->link, rc );
  1394. /* Close ULP if there are no clients attached */
  1395. if ( ulp->usage == 0 )
  1396. fc_ulp_close ( ulp, rc );
  1397. }
  1398. /**
  1399. * Handle PRLI completion
  1400. *
  1401. * @v ulp Fibre Channel upper-layer protocol
  1402. * @v rc Reason for completion
  1403. */
  1404. static void fc_ulp_prli_done ( struct fc_ulp *ulp, int rc ) {
  1405. intf_restart ( &ulp->prli, rc );
  1406. if ( rc != 0 )
  1407. fc_ulp_logout ( ulp, rc );
  1408. }
  1409. /**
  1410. * Examine Fibre Channel upper-layer protocol link state
  1411. *
  1412. * @ link Fibre Channel link state monitor
  1413. */
  1414. static void fc_ulp_examine ( struct fc_link_state *link ) {
  1415. struct fc_ulp *ulp = container_of ( link, struct fc_ulp, link );
  1416. int rc;
  1417. /* Check to see if underlying peer link has gone down */
  1418. if ( ! fc_link_ok ( &ulp->peer->link ) ) {
  1419. fc_ulp_logout ( ulp, -ENOTCONN );
  1420. return;
  1421. }
  1422. /* Do nothing if already logged in */
  1423. if ( fc_link_ok ( &ulp->link ) &&
  1424. ( ulp->flags & FC_ULP_ORIGINATED_LOGIN_OK ) )
  1425. return;
  1426. DBGC ( ulp, "FCULP %s/%02x attempting login\n",
  1427. fc_ntoa ( &ulp->peer->port_wwn ), ulp->type );
  1428. /* Try to create PRLI ELS */
  1429. intf_restart ( &ulp->prli, -ECANCELED );
  1430. if ( ( rc = fc_els_prli ( &ulp->prli, ulp->peer->port,
  1431. &ulp->peer->port_id, ulp->type ) ) != 0 ) {
  1432. DBGC ( ulp, "FCULP %s/%02x could not initiate PRLI: %s\n",
  1433. fc_ntoa ( &ulp->peer->port_wwn ), ulp->type,
  1434. strerror ( rc ) );
  1435. fc_ulp_logout ( ulp, rc );
  1436. return;
  1437. }
  1438. }
  1439. /** Fibre Channel upper-layer protocol PRLI interface operations */
  1440. static struct interface_operation fc_ulp_prli_op[] = {
  1441. INTF_OP ( intf_close, struct fc_ulp *, fc_ulp_prli_done ),
  1442. };
  1443. /** Fibre Channel upper-layer protocol PRLI interface descriptor */
  1444. static struct interface_descriptor fc_ulp_prli_desc =
  1445. INTF_DESC ( struct fc_ulp, prli, fc_ulp_prli_op );
  1446. /**
  1447. * Create Fibre Channel upper-layer protocl
  1448. *
  1449. * @v peer Fibre Channel peer
  1450. * @v type Type
  1451. * @ret ulp Fibre Channel upper-layer protocol, or NULL
  1452. */
  1453. static struct fc_ulp * fc_ulp_create ( struct fc_peer *peer,
  1454. unsigned int type ) {
  1455. struct fc_ulp *ulp;
  1456. /* Allocate and initialise structure */
  1457. ulp = zalloc ( sizeof ( *ulp ) );
  1458. if ( ! ulp )
  1459. return NULL;
  1460. ref_init ( &ulp->refcnt, NULL );
  1461. fc_link_init ( &ulp->link, fc_ulp_examine, &ulp->refcnt );
  1462. intf_init ( &ulp->prli, &fc_ulp_prli_desc, &ulp->refcnt );
  1463. ulp->peer = fc_peer_get ( peer );
  1464. list_add_tail ( &ulp->list, &peer->ulps );
  1465. ulp->type = type;
  1466. /* Start link state monitor */
  1467. fc_link_start ( &ulp->link );
  1468. DBGC ( ulp, "FCULP %s/%02x created\n",
  1469. fc_ntoa ( &ulp->peer->port_wwn ), ulp->type );
  1470. return ulp;
  1471. }
  1472. /**
  1473. * Get Fibre Channel upper-layer protocol by peer and type
  1474. *
  1475. * @v peer Fibre Channel peer
  1476. * @v type Type
  1477. * @ret ulp Fibre Channel upper-layer protocol, or NULL
  1478. */
  1479. static struct fc_ulp * fc_ulp_get_type ( struct fc_peer *peer,
  1480. unsigned int type ) {
  1481. struct fc_ulp *ulp;
  1482. /* Look for an existing ULP */
  1483. list_for_each_entry ( ulp, &peer->ulps, list ) {
  1484. if ( ulp->type == type )
  1485. return fc_ulp_get ( ulp );
  1486. }
  1487. /* Create a new ULP */
  1488. ulp = fc_ulp_create ( peer, type );
  1489. if ( ! ulp )
  1490. return NULL;
  1491. return ulp;
  1492. }
  1493. /**
  1494. * Get Fibre Channel upper-layer protocol by port name and type
  1495. *
  1496. * @v port_wwn Port name
  1497. * @v type Type
  1498. * @ret ulp Fibre Channel upper-layer protocol, or NULL
  1499. */
  1500. struct fc_ulp * fc_ulp_get_wwn_type ( const struct fc_name *port_wwn,
  1501. unsigned int type ) {
  1502. struct fc_ulp *ulp;
  1503. struct fc_peer *peer;
  1504. /* Get peer */
  1505. peer = fc_peer_get_wwn ( port_wwn );
  1506. if ( ! peer )
  1507. goto err_peer_get_wwn;
  1508. /* Get ULP */
  1509. ulp = fc_ulp_get_type ( peer, type );
  1510. if ( ! ulp )
  1511. goto err_ulp_get_type;
  1512. /* Drop temporary reference to peer */
  1513. fc_peer_put ( peer );
  1514. return ulp;
  1515. fc_ulp_put ( ulp );
  1516. err_ulp_get_type:
  1517. fc_peer_put ( peer );
  1518. err_peer_get_wwn:
  1519. return NULL;
  1520. }
  1521. /**
  1522. * Get Fibre Channel upper-layer protocol by port ID and type
  1523. *
  1524. * @v port Fibre Channel port
  1525. * @v peer_port_id Peer port ID
  1526. * @v type Type
  1527. * @ret ulp Fibre Channel upper-layer protocol, or NULL
  1528. */
  1529. struct fc_ulp * fc_ulp_get_port_id_type ( struct fc_port *port,
  1530. const struct fc_port_id *peer_port_id,
  1531. unsigned int type ) {
  1532. struct fc_ulp *ulp;
  1533. struct fc_peer *peer;
  1534. /* Get peer */
  1535. peer = fc_peer_get_port_id ( port, peer_port_id );
  1536. if ( ! peer )
  1537. goto err_peer_get_wwn;
  1538. /* Get ULP */
  1539. ulp = fc_ulp_get_type ( peer, type );
  1540. if ( ! ulp )
  1541. goto err_ulp_get_type;
  1542. /* Drop temporary reference to peer */
  1543. fc_peer_put ( peer );
  1544. return ulp;
  1545. fc_ulp_put ( ulp );
  1546. err_ulp_get_type:
  1547. fc_peer_put ( peer );
  1548. err_peer_get_wwn:
  1549. return NULL;
  1550. }