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

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