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.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. /*
  2. * Copyright (C) 2007 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 <stdint.h>
  21. #include <string.h>
  22. #include <byteswap.h>
  23. #include <errno.h>
  24. #include <ipxe/list.h>
  25. #include <ipxe/infiniband.h>
  26. #include <ipxe/ib_mi.h>
  27. #include <ipxe/ib_mcast.h>
  28. /** @file
  29. *
  30. * Infiniband multicast groups
  31. *
  32. */
  33. /**
  34. * Generate multicast membership MAD
  35. *
  36. * @v ibdev Infiniband device
  37. * @v gid Multicast GID
  38. * @v join Join (rather than leave) group
  39. * @v mad MAD to fill in
  40. */
  41. static void ib_mcast_mad ( struct ib_device *ibdev, union ib_gid *gid,
  42. int join, union ib_mad *mad ) {
  43. struct ib_mad_sa *sa = &mad->sa;
  44. /* Construct multicast membership record request */
  45. memset ( sa, 0, sizeof ( *sa ) );
  46. sa->mad_hdr.mgmt_class = IB_MGMT_CLASS_SUBN_ADM;
  47. sa->mad_hdr.class_version = IB_SA_CLASS_VERSION;
  48. sa->mad_hdr.method =
  49. ( join ? IB_MGMT_METHOD_SET : IB_MGMT_METHOD_DELETE );
  50. sa->mad_hdr.attr_id = htons ( IB_SA_ATTR_MC_MEMBER_REC );
  51. sa->sa_hdr.comp_mask[1] =
  52. htonl ( IB_SA_MCMEMBER_REC_MGID | IB_SA_MCMEMBER_REC_PORT_GID |
  53. IB_SA_MCMEMBER_REC_JOIN_STATE );
  54. sa->sa_data.mc_member_record.scope__join_state = 1;
  55. memcpy ( &sa->sa_data.mc_member_record.mgid, gid,
  56. sizeof ( sa->sa_data.mc_member_record.mgid ) );
  57. memcpy ( &sa->sa_data.mc_member_record.port_gid, &ibdev->gid,
  58. sizeof ( sa->sa_data.mc_member_record.port_gid ) );
  59. }
  60. /**
  61. * Handle multicast membership record join response
  62. *
  63. * @v ibdev Infiniband device
  64. * @v mi Management interface
  65. * @v madx Management transaction
  66. * @v rc Status code
  67. * @v mad Received MAD (or NULL on error)
  68. * @v av Source address vector (or NULL on error)
  69. */
  70. static void ib_mcast_complete ( struct ib_device *ibdev,
  71. struct ib_mad_interface *mi __unused,
  72. struct ib_mad_transaction *madx,
  73. int rc, union ib_mad *mad,
  74. struct ib_address_vector *av __unused ) {
  75. struct ib_mc_membership *membership = ib_madx_get_ownerdata ( madx );
  76. struct ib_queue_pair *qp = membership->qp;
  77. union ib_gid *gid = &membership->gid;
  78. struct ib_mc_member_record *mc_member_record =
  79. &mad->sa.sa_data.mc_member_record;
  80. int joined;
  81. unsigned long qkey;
  82. /* Report failures */
  83. if ( ( rc == 0 ) && ( mad->hdr.status != htons ( IB_MGMT_STATUS_OK ) ))
  84. rc = -ENOTCONN;
  85. if ( rc != 0 ) {
  86. DBGC ( ibdev, "IBDEV %p QPN %lx join failed: %s\n",
  87. ibdev, qp->qpn, strerror ( rc ) );
  88. goto out;
  89. }
  90. /* Extract values from MAD */
  91. joined = ( mad->hdr.method == IB_MGMT_METHOD_GET_RESP );
  92. qkey = ntohl ( mc_member_record->qkey );
  93. DBGC ( ibdev, "IBDEV %p QPN %lx %s " IB_GID_FMT " qkey %lx\n",
  94. ibdev, qp->qpn, ( joined ? "joined" : "left" ),
  95. IB_GID_ARGS ( gid ), qkey );
  96. /* Set queue key */
  97. qp->qkey = qkey;
  98. if ( ( rc = ib_modify_qp ( ibdev, qp ) ) != 0 ) {
  99. DBGC ( ibdev, "IBDEV %p QPN %lx could not modify qkey: %s\n",
  100. ibdev, qp->qpn, strerror ( rc ) );
  101. goto out;
  102. }
  103. out:
  104. /* Destroy the completed transaction */
  105. ib_destroy_madx ( ibdev, mi, madx );
  106. membership->madx = NULL;
  107. /* Hand off to upper completion handler */
  108. membership->complete ( ibdev, qp, membership, rc, mad );
  109. }
  110. /** Multicast membership management transaction completion operations */
  111. static struct ib_mad_transaction_operations ib_mcast_op = {
  112. .complete = ib_mcast_complete,
  113. };
  114. /**
  115. * Join multicast group
  116. *
  117. * @v ibdev Infiniband device
  118. * @v qp Queue pair
  119. * @v membership Multicast group membership
  120. * @v gid Multicast GID to join
  121. * @v joined Join completion handler
  122. * @ret rc Return status code
  123. */
  124. int ib_mcast_join ( struct ib_device *ibdev, struct ib_queue_pair *qp,
  125. struct ib_mc_membership *membership, union ib_gid *gid,
  126. void ( * complete ) ( struct ib_device *ibdev,
  127. struct ib_queue_pair *qp,
  128. struct ib_mc_membership *membership,
  129. int rc, union ib_mad *mad ) ) {
  130. union ib_mad mad;
  131. int rc;
  132. DBGC ( ibdev, "IBDEV %p QPN %lx joining " IB_GID_FMT "\n",
  133. ibdev, qp->qpn, IB_GID_ARGS ( gid ) );
  134. /* Initialise structure */
  135. membership->qp = qp;
  136. memcpy ( &membership->gid, gid, sizeof ( membership->gid ) );
  137. membership->complete = complete;
  138. /* Attach queue pair to multicast GID */
  139. if ( ( rc = ib_mcast_attach ( ibdev, qp, gid ) ) != 0 ) {
  140. DBGC ( ibdev, "IBDEV %p QPN %lx could not attach: %s\n",
  141. ibdev, qp->qpn, strerror ( rc ) );
  142. goto err_mcast_attach;
  143. }
  144. /* Initiate multicast membership join */
  145. ib_mcast_mad ( ibdev, gid, 1, &mad );
  146. membership->madx = ib_create_madx ( ibdev, ibdev->gsi, &mad, NULL,
  147. &ib_mcast_op );
  148. if ( ! membership->madx ) {
  149. DBGC ( ibdev, "IBDEV %p QPN %lx could not create join "
  150. "transaction\n", ibdev, qp->qpn );
  151. rc = -ENOMEM;
  152. goto err_create_madx;
  153. }
  154. ib_madx_set_ownerdata ( membership->madx, membership );
  155. return 0;
  156. ib_destroy_madx ( ibdev, ibdev->gsi, membership->madx );
  157. err_create_madx:
  158. ib_mcast_detach ( ibdev, qp, gid );
  159. err_mcast_attach:
  160. return rc;
  161. }
  162. /**
  163. * Leave multicast group
  164. *
  165. * @v ibdev Infiniband device
  166. * @v qp Queue pair
  167. * @v membership Multicast group membership
  168. */
  169. void ib_mcast_leave ( struct ib_device *ibdev, struct ib_queue_pair *qp,
  170. struct ib_mc_membership *membership ) {
  171. union ib_gid *gid = &membership->gid;
  172. union ib_mad mad;
  173. int rc;
  174. DBGC ( ibdev, "IBDEV %p QPN %lx leaving " IB_GID_FMT "\n",
  175. ibdev, qp->qpn, IB_GID_ARGS ( gid ) );
  176. /* Detach from multicast GID */
  177. ib_mcast_detach ( ibdev, qp, &membership->gid );
  178. /* Cancel multicast membership join, if applicable */
  179. if ( membership->madx ) {
  180. ib_destroy_madx ( ibdev, ibdev->gsi, membership->madx );
  181. membership->madx = NULL;
  182. }
  183. /* Send a single group leave MAD */
  184. ib_mcast_mad ( ibdev, &membership->gid, 0, &mad );
  185. if ( ( rc = ib_mi_send ( ibdev, ibdev->gsi, &mad, NULL ) ) != 0 ) {
  186. DBGC ( ibdev, "IBDEV %p QPN %lx could not send leave request: "
  187. "%s\n", ibdev, qp->qpn, strerror ( rc ) );
  188. }
  189. }