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.

fcns.c 6.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. /*
  2. * Copyright (C) 2010 Michael Brown <mbrown@fensystems.co.uk>.
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License as
  6. * published by the Free Software Foundation; either version 2 of the
  7. * License, or any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful, but
  10. * WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  17. * 02110-1301, USA.
  18. */
  19. FILE_LICENCE ( GPL2_OR_LATER );
  20. #include <stddef.h>
  21. #include <stdlib.h>
  22. #include <string.h>
  23. #include <errno.h>
  24. #include <byteswap.h>
  25. #include <ipxe/interface.h>
  26. #include <ipxe/iobuf.h>
  27. #include <ipxe/process.h>
  28. #include <ipxe/xfer.h>
  29. #include <ipxe/fc.h>
  30. #include <ipxe/fcns.h>
  31. /** @file
  32. *
  33. * Fibre Channel name server lookups
  34. *
  35. */
  36. /** A Fibre Channel name server query */
  37. struct fc_ns_query {
  38. /** Reference count */
  39. struct refcnt refcnt;
  40. /** Fibre Channel exchange */
  41. struct interface xchg;
  42. /** Fibre Channel peer */
  43. struct fc_peer *peer;
  44. /** Fibre Channel port */
  45. struct fc_port *port;
  46. /** Process */
  47. struct process process;
  48. /** Success handler
  49. *
  50. * @v peer Fibre Channel peer
  51. * @v port Fibre Channel port
  52. * @v peer_port_id Peer port ID
  53. * @ret rc Return status code
  54. */
  55. int ( * done ) ( struct fc_peer *peer, struct fc_port *port,
  56. struct fc_port_id *peer_port_id );
  57. };
  58. /**
  59. * Free name server query
  60. *
  61. * @v refcnt Reference count
  62. */
  63. static void fc_ns_query_free ( struct refcnt *refcnt ) {
  64. struct fc_ns_query *query =
  65. container_of ( refcnt, struct fc_ns_query, refcnt );
  66. fc_peer_put ( query->peer );
  67. fc_port_put ( query->port );
  68. free ( query );
  69. }
  70. /**
  71. * Close name server query
  72. *
  73. * @v query Name server query
  74. * @v rc Reason for close
  75. */
  76. static void fc_ns_query_close ( struct fc_ns_query *query, int rc ) {
  77. /* Stop process */
  78. process_del ( &query->process );
  79. /* Shut down interfaces */
  80. intf_shutdown ( &query->xchg, rc );
  81. }
  82. /**
  83. * Receive name server query response
  84. *
  85. * @v query Name server query
  86. * @v iobuf I/O buffer
  87. * @v meta Data transfer metadata
  88. * @ret rc Return status code
  89. */
  90. static int fc_ns_query_deliver ( struct fc_ns_query *query,
  91. struct io_buffer *iobuf,
  92. struct xfer_metadata *meta __unused ) {
  93. union fc_ns_response *resp = iobuf->data;
  94. struct fc_port_id *peer_port_id;
  95. int rc;
  96. /* Sanity check */
  97. if ( iob_len ( iobuf ) < sizeof ( resp->ct ) ) {
  98. DBGC ( query, "FCNS %p received underlength response (%zd "
  99. "bytes)\n", query, iob_len ( iobuf ) );
  100. rc = -EINVAL;
  101. goto done;
  102. }
  103. /* Handle response */
  104. switch ( ntohs ( resp->ct.code ) ) {
  105. case FC_GS_ACCEPT:
  106. if ( iob_len ( iobuf ) < sizeof ( resp->gid_pn ) ) {
  107. DBGC ( query, "FCNS %p received underlength accept "
  108. "response (%zd bytes)\n",
  109. query, iob_len ( iobuf ) );
  110. rc = -EINVAL;
  111. goto done;
  112. }
  113. peer_port_id = &resp->gid_pn.port_id.port_id;
  114. DBGC ( query, "FCNS %p resolved %s to %s via %s\n",
  115. query, fc_ntoa ( &query->peer->port_wwn ),
  116. fc_id_ntoa ( peer_port_id ), query->port->name );
  117. if ( ( rc = query->done ( query->peer, query->port,
  118. peer_port_id ) ) != 0 )
  119. goto done;
  120. break;
  121. case FC_GS_REJECT:
  122. DBGC ( query, "FCNS %p rejected (reason %02x explanation "
  123. "%02x)\n", query, resp->reject.ct.reason,
  124. resp->reject.ct.explanation );
  125. break;
  126. default:
  127. DBGC ( query, "FCNS %p received invalid response code %04x\n",
  128. query, ntohs ( resp->ct.code ) );
  129. rc = -ENOTSUP;
  130. goto done;
  131. }
  132. rc = 0;
  133. done:
  134. free_iob ( iobuf );
  135. fc_ns_query_close ( query, rc );
  136. return rc;
  137. }
  138. /**
  139. * Name server query process
  140. *
  141. * @v query Name server query
  142. */
  143. static void fc_ns_query_step ( struct fc_ns_query *query ) {
  144. struct xfer_metadata meta;
  145. struct fc_ns_gid_pn_request gid_pn;
  146. int xchg_id;
  147. int rc;
  148. /* Create exchange */
  149. if ( ( xchg_id = fc_xchg_originate ( &query->xchg, query->port,
  150. &fc_gs_port_id,
  151. FC_TYPE_CT ) ) < 0 ) {
  152. rc = xchg_id;
  153. DBGC ( query, "FCNS %p could not create exchange: %s\n",
  154. query, strerror ( rc ) );
  155. fc_ns_query_close ( query, rc );
  156. return;
  157. }
  158. /* Construct query request */
  159. memset ( &gid_pn, 0, sizeof ( gid_pn ) );
  160. gid_pn.ct.revision = FC_CT_REVISION;
  161. gid_pn.ct.type = FC_GS_TYPE_DS;
  162. gid_pn.ct.subtype = FC_DS_SUBTYPE_NAME;
  163. gid_pn.ct.code = htons ( FC_NS_GET ( FC_NS_PORT_NAME, FC_NS_PORT_ID ));
  164. memcpy ( &gid_pn.port_wwn, &query->peer->port_wwn,
  165. sizeof ( gid_pn.port_wwn ) );
  166. memset ( &meta, 0, sizeof ( meta ) );
  167. meta.flags = XFER_FL_OVER;
  168. /* Send query */
  169. if ( ( rc = xfer_deliver_raw_meta ( &query->xchg, &gid_pn,
  170. sizeof ( gid_pn ), &meta ) ) != 0){
  171. DBGC ( query, "FCNS %p could not deliver query: %s\n",
  172. query, strerror ( rc ) );
  173. fc_ns_query_close ( query, rc );
  174. return;
  175. }
  176. }
  177. /** Name server exchange interface operations */
  178. static struct interface_operation fc_ns_query_xchg_op[] = {
  179. INTF_OP ( xfer_deliver, struct fc_ns_query *, fc_ns_query_deliver ),
  180. INTF_OP ( intf_close, struct fc_ns_query *, fc_ns_query_close ),
  181. };
  182. /** Name server exchange interface descriptor */
  183. static struct interface_descriptor fc_ns_query_xchg_desc =
  184. INTF_DESC ( struct fc_ns_query, xchg, fc_ns_query_xchg_op );
  185. /** Name server process descriptor */
  186. static struct process_descriptor fc_ns_query_process_desc =
  187. PROC_DESC_ONCE ( struct fc_ns_query, process, fc_ns_query_step );
  188. /**
  189. * Issue Fibre Channel name server query
  190. *
  191. * @v peer Fibre Channel peer
  192. * @v port Fibre Channel port
  193. * @ret rc Return status code
  194. */
  195. int fc_ns_query ( struct fc_peer *peer, struct fc_port *port,
  196. int ( * done ) ( struct fc_peer *peer, struct fc_port *port,
  197. struct fc_port_id *peer_port_id ) ) {
  198. struct fc_ns_query *query;
  199. /* Allocate and initialise structure */
  200. query = zalloc ( sizeof ( *query ) );
  201. if ( ! query )
  202. return -ENOMEM;
  203. ref_init ( &query->refcnt, fc_ns_query_free );
  204. intf_init ( &query->xchg, &fc_ns_query_xchg_desc, &query->refcnt );
  205. process_init ( &query->process, &fc_ns_query_process_desc,
  206. &query->refcnt );
  207. query->peer = fc_peer_get ( peer );
  208. query->port = fc_port_get ( port );
  209. query->done = done;
  210. DBGC ( query, "FCNS %p querying %s via %s\n",
  211. query, fc_ntoa ( &query->peer->port_wwn ), port->name );
  212. /* Mortalise self and return */
  213. ref_put ( &query->refcnt );
  214. return 0;
  215. }