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.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  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 <stddef.h>
  25. #include <stdlib.h>
  26. #include <string.h>
  27. #include <errno.h>
  28. #include <byteswap.h>
  29. #include <ipxe/interface.h>
  30. #include <ipxe/iobuf.h>
  31. #include <ipxe/process.h>
  32. #include <ipxe/xfer.h>
  33. #include <ipxe/fc.h>
  34. #include <ipxe/fcns.h>
  35. /** @file
  36. *
  37. * Fibre Channel name server lookups
  38. *
  39. */
  40. /** A Fibre Channel name server query */
  41. struct fc_ns_query {
  42. /** Reference count */
  43. struct refcnt refcnt;
  44. /** Fibre Channel exchange */
  45. struct interface xchg;
  46. /** Fibre Channel peer */
  47. struct fc_peer *peer;
  48. /** Fibre Channel port */
  49. struct fc_port *port;
  50. /** Process */
  51. struct process process;
  52. /** Success handler
  53. *
  54. * @v peer Fibre Channel peer
  55. * @v port Fibre Channel port
  56. * @v peer_port_id Peer port ID
  57. * @ret rc Return status code
  58. */
  59. int ( * done ) ( struct fc_peer *peer, struct fc_port *port,
  60. struct fc_port_id *peer_port_id );
  61. };
  62. /**
  63. * Free name server query
  64. *
  65. * @v refcnt Reference count
  66. */
  67. static void fc_ns_query_free ( struct refcnt *refcnt ) {
  68. struct fc_ns_query *query =
  69. container_of ( refcnt, struct fc_ns_query, refcnt );
  70. fc_peer_put ( query->peer );
  71. fc_port_put ( query->port );
  72. free ( query );
  73. }
  74. /**
  75. * Close name server query
  76. *
  77. * @v query Name server query
  78. * @v rc Reason for close
  79. */
  80. static void fc_ns_query_close ( struct fc_ns_query *query, int rc ) {
  81. /* Stop process */
  82. process_del ( &query->process );
  83. /* Shut down interfaces */
  84. intf_shutdown ( &query->xchg, rc );
  85. }
  86. /**
  87. * Receive name server query response
  88. *
  89. * @v query Name server query
  90. * @v iobuf I/O buffer
  91. * @v meta Data transfer metadata
  92. * @ret rc Return status code
  93. */
  94. static int fc_ns_query_deliver ( struct fc_ns_query *query,
  95. struct io_buffer *iobuf,
  96. struct xfer_metadata *meta __unused ) {
  97. union fc_ns_response *resp = iobuf->data;
  98. struct fc_port_id *peer_port_id;
  99. int rc;
  100. /* Sanity check */
  101. if ( iob_len ( iobuf ) < sizeof ( resp->ct ) ) {
  102. DBGC ( query, "FCNS %p received underlength response (%zd "
  103. "bytes)\n", query, iob_len ( iobuf ) );
  104. rc = -EINVAL;
  105. goto done;
  106. }
  107. /* Handle response */
  108. switch ( ntohs ( resp->ct.code ) ) {
  109. case FC_GS_ACCEPT:
  110. if ( iob_len ( iobuf ) < sizeof ( resp->gid_pn ) ) {
  111. DBGC ( query, "FCNS %p received underlength accept "
  112. "response (%zd bytes)\n",
  113. query, iob_len ( iobuf ) );
  114. rc = -EINVAL;
  115. goto done;
  116. }
  117. peer_port_id = &resp->gid_pn.port_id.port_id;
  118. DBGC ( query, "FCNS %p resolved %s to %s via %s\n",
  119. query, fc_ntoa ( &query->peer->port_wwn ),
  120. fc_id_ntoa ( peer_port_id ), query->port->name );
  121. if ( ( rc = query->done ( query->peer, query->port,
  122. peer_port_id ) ) != 0 )
  123. goto done;
  124. break;
  125. case FC_GS_REJECT:
  126. DBGC ( query, "FCNS %p rejected (reason %02x explanation "
  127. "%02x)\n", query, resp->reject.ct.reason,
  128. resp->reject.ct.explanation );
  129. break;
  130. default:
  131. DBGC ( query, "FCNS %p received invalid response code %04x\n",
  132. query, ntohs ( resp->ct.code ) );
  133. rc = -ENOTSUP;
  134. goto done;
  135. }
  136. rc = 0;
  137. done:
  138. free_iob ( iobuf );
  139. fc_ns_query_close ( query, rc );
  140. return rc;
  141. }
  142. /**
  143. * Name server query process
  144. *
  145. * @v query Name server query
  146. */
  147. static void fc_ns_query_step ( struct fc_ns_query *query ) {
  148. struct xfer_metadata meta;
  149. struct fc_ns_gid_pn_request gid_pn;
  150. int xchg_id;
  151. int rc;
  152. /* Create exchange */
  153. if ( ( xchg_id = fc_xchg_originate ( &query->xchg, query->port,
  154. &fc_gs_port_id,
  155. FC_TYPE_CT ) ) < 0 ) {
  156. rc = xchg_id;
  157. DBGC ( query, "FCNS %p could not create exchange: %s\n",
  158. query, strerror ( rc ) );
  159. fc_ns_query_close ( query, rc );
  160. return;
  161. }
  162. /* Construct query request */
  163. memset ( &gid_pn, 0, sizeof ( gid_pn ) );
  164. gid_pn.ct.revision = FC_CT_REVISION;
  165. gid_pn.ct.type = FC_GS_TYPE_DS;
  166. gid_pn.ct.subtype = FC_DS_SUBTYPE_NAME;
  167. gid_pn.ct.code = htons ( FC_NS_GET ( FC_NS_PORT_NAME, FC_NS_PORT_ID ));
  168. memcpy ( &gid_pn.port_wwn, &query->peer->port_wwn,
  169. sizeof ( gid_pn.port_wwn ) );
  170. memset ( &meta, 0, sizeof ( meta ) );
  171. meta.flags = XFER_FL_OVER;
  172. /* Send query */
  173. if ( ( rc = xfer_deliver_raw_meta ( &query->xchg, &gid_pn,
  174. sizeof ( gid_pn ), &meta ) ) != 0){
  175. DBGC ( query, "FCNS %p could not deliver query: %s\n",
  176. query, strerror ( rc ) );
  177. fc_ns_query_close ( query, rc );
  178. return;
  179. }
  180. }
  181. /** Name server exchange interface operations */
  182. static struct interface_operation fc_ns_query_xchg_op[] = {
  183. INTF_OP ( xfer_deliver, struct fc_ns_query *, fc_ns_query_deliver ),
  184. INTF_OP ( intf_close, struct fc_ns_query *, fc_ns_query_close ),
  185. };
  186. /** Name server exchange interface descriptor */
  187. static struct interface_descriptor fc_ns_query_xchg_desc =
  188. INTF_DESC ( struct fc_ns_query, xchg, fc_ns_query_xchg_op );
  189. /** Name server process descriptor */
  190. static struct process_descriptor fc_ns_query_process_desc =
  191. PROC_DESC_ONCE ( struct fc_ns_query, process, fc_ns_query_step );
  192. /**
  193. * Issue Fibre Channel name server query
  194. *
  195. * @v peer Fibre Channel peer
  196. * @v port Fibre Channel port
  197. * @ret rc Return status code
  198. */
  199. int fc_ns_query ( struct fc_peer *peer, struct fc_port *port,
  200. int ( * done ) ( struct fc_peer *peer, struct fc_port *port,
  201. struct fc_port_id *peer_port_id ) ) {
  202. struct fc_ns_query *query;
  203. /* Allocate and initialise structure */
  204. query = zalloc ( sizeof ( *query ) );
  205. if ( ! query )
  206. return -ENOMEM;
  207. ref_init ( &query->refcnt, fc_ns_query_free );
  208. intf_init ( &query->xchg, &fc_ns_query_xchg_desc, &query->refcnt );
  209. process_init ( &query->process, &fc_ns_query_process_desc,
  210. &query->refcnt );
  211. query->peer = fc_peer_get ( peer );
  212. query->port = fc_port_get ( port );
  213. query->done = done;
  214. DBGC ( query, "FCNS %p querying %s via %s\n",
  215. query, fc_ntoa ( &query->peer->port_wwn ), port->name );
  216. /* Mortalise self and return */
  217. ref_put ( &query->refcnt );
  218. return 0;
  219. }