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.

ib_cm.c 9.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. /*
  2. * Copyright (C) 2009 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 <stdint.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <byteswap.h>
  23. #include <errno.h>
  24. #include <assert.h>
  25. #include <gpxe/list.h>
  26. #include <gpxe/process.h>
  27. #include <gpxe/infiniband.h>
  28. #include <gpxe/ib_gma.h>
  29. #include <gpxe/ib_pathrec.h>
  30. #include <gpxe/ib_cm.h>
  31. /**
  32. * @file
  33. *
  34. * Infiniband communication management
  35. *
  36. */
  37. /** An outstanding connection request */
  38. struct ib_cm_request {
  39. /** List of all outstanding requests */
  40. struct list_head list;
  41. /** Local communication ID */
  42. uint32_t local_id;
  43. /** Remote communication ID */
  44. uint32_t remote_id;
  45. /** Queue pair */
  46. struct ib_queue_pair *qp;
  47. /** Target service ID */
  48. struct ib_gid_half service_id;
  49. /** Connection process */
  50. struct process process;
  51. /** Notification handler
  52. *
  53. * @v qp Queue pair
  54. * @v rc Connection status code
  55. * @v private_data Private data
  56. * @v private_data_len Length of private data
  57. */
  58. void ( * notify ) ( struct ib_queue_pair *qp, int rc,
  59. void *private_data, size_t private_data_len );
  60. /** Private data length */
  61. size_t private_data_len;
  62. /** Private data */
  63. uint8_t private_data[0];
  64. };
  65. /** List of all outstanding connection requests */
  66. static LIST_HEAD ( ib_cm_requests );
  67. /**
  68. * Send connection request
  69. *
  70. * @v request Connection request
  71. * @ret rc Return status code
  72. */
  73. static int ib_cm_send_request ( struct ib_cm_request *request ) {
  74. struct ib_queue_pair *qp = request->qp;
  75. struct ib_device *ibdev = qp->ibdev;
  76. struct ib_gma *gma = ibdev->gma;
  77. union ib_mad mad;
  78. struct ib_mad_cm *cm = &mad.cm;
  79. struct ib_cm_connect_request *connect_req =
  80. &cm->cm_data.connect_request;
  81. size_t private_data_len;
  82. int rc;
  83. /* Construct connection request */
  84. memset ( cm, 0, sizeof ( *cm ) );
  85. cm->mad_hdr.base_version = IB_MGMT_BASE_VERSION;
  86. cm->mad_hdr.mgmt_class = IB_MGMT_CLASS_CM;
  87. cm->mad_hdr.class_version = IB_CM_CLASS_VERSION;
  88. cm->mad_hdr.method = IB_MGMT_METHOD_SEND;
  89. cm->mad_hdr.attr_id = htons ( IB_CM_ATTR_CONNECT_REQUEST );
  90. connect_req->local_id = htonl ( request->local_id );
  91. memcpy ( &connect_req->service_id, &request->service_id,
  92. sizeof ( connect_req->service_id ) );
  93. ib_get_hca_info ( ibdev, &connect_req->local_ca );
  94. connect_req->local_qpn__responder_resources =
  95. htonl ( ( qp->qpn << 8 ) | 1 );
  96. connect_req->local_eecn__initiator_depth = htonl ( ( 0 << 8 ) | 1 );
  97. connect_req->remote_eecn__remote_timeout__service_type__ee_flow_ctrl =
  98. htonl ( ( 0x14 << 3 ) | ( IB_CM_TRANSPORT_RC << 1 ) |
  99. ( 0 << 0 ) );
  100. connect_req->starting_psn__local_timeout__retry_count =
  101. htonl ( ( qp->recv.psn << 8 ) | ( 0x14 << 3 ) |
  102. ( 0x07 << 0 ) );
  103. connect_req->pkey = htons ( ibdev->pkey );
  104. connect_req->payload_mtu__rdc_exists__rnr_retry =
  105. ( ( IB_MTU_2048 << 4 ) | ( 1 << 3 ) | ( 0x07 << 0 ) );
  106. connect_req->max_cm_retries__srq =
  107. ( ( 0x0f << 4 ) | ( 0 << 3 ) );
  108. connect_req->primary.local_lid = htons ( ibdev->lid );
  109. connect_req->primary.remote_lid = htons ( request->qp->av.lid );
  110. memcpy ( &connect_req->primary.local_gid, &ibdev->gid,
  111. sizeof ( connect_req->primary.local_gid ) );
  112. memcpy ( &connect_req->primary.remote_gid, &request->qp->av.gid,
  113. sizeof ( connect_req->primary.remote_gid ) );
  114. connect_req->primary.flow_label__rate =
  115. htonl ( ( 0 << 12 ) | ( request->qp->av.rate << 0 ) );
  116. connect_req->primary.hop_limit = 0;
  117. connect_req->primary.sl__subnet_local =
  118. ( ( request->qp->av.sl << 4 ) | ( 1 << 3 ) );
  119. connect_req->primary.local_ack_timeout = ( 0x13 << 3 );
  120. private_data_len = request->private_data_len;
  121. if ( private_data_len > sizeof ( connect_req->private_data ) )
  122. private_data_len = sizeof ( connect_req->private_data );
  123. memcpy ( &connect_req->private_data, &request->private_data,
  124. private_data_len );
  125. /* Send request */
  126. if ( ( rc = ib_gma_request ( gma, &mad, NULL, 1 ) ) != 0 ) {
  127. DBGC ( gma, "GMA %p could not send connection request: %s\n",
  128. gma, strerror ( rc ) );
  129. return rc;
  130. }
  131. return 0;
  132. }
  133. /**
  134. * Connection request process step
  135. *
  136. * @v process Connection request process
  137. */
  138. static void ib_cm_step ( struct process *process ) {
  139. struct ib_cm_request *request =
  140. container_of ( process, struct ib_cm_request, process );
  141. struct ib_queue_pair *qp = request->qp;
  142. struct ib_device *ibdev = qp->ibdev;
  143. int rc;
  144. /* Wait until path can be resolved */
  145. if ( ( rc = ib_resolve_path ( ibdev, &request->qp->av ) ) != 0 )
  146. return;
  147. /* Wait until request can be sent */
  148. if ( ( rc = ib_cm_send_request ( request ) ) != 0 )
  149. return;
  150. /* Stop process */
  151. process_del ( process );
  152. }
  153. /**
  154. * Identify connection request by communication ID
  155. *
  156. * @v local_id Local communication ID
  157. * @v remote_id Remote communication ID
  158. * @ret request Connection request, or NULL
  159. */
  160. static struct ib_cm_request * ib_cm_find_request ( uint32_t local_id,
  161. uint32_t remote_id ) {
  162. struct ib_cm_request *request;
  163. list_for_each_entry ( request, &ib_cm_requests, list ) {
  164. if ( request->local_id == local_id ) {
  165. request->remote_id = remote_id;
  166. return request;
  167. }
  168. }
  169. return NULL;
  170. }
  171. /**
  172. * Handle connection reply
  173. *
  174. * @v gma General management agent
  175. * @v mad MAD
  176. * @ret response MAD response
  177. */
  178. static union ib_mad * ib_cm_connect_reply ( struct ib_gma *gma,
  179. union ib_mad *mad ) {
  180. struct ib_cm_connect_reply *connect_rep =
  181. &mad->cm.cm_data.connect_reply;
  182. struct ib_cm_ready_to_use *ready =
  183. &mad->cm.cm_data.ready_to_use;
  184. struct ib_cm_request *request;
  185. int rc;
  186. /* Identify request */
  187. request = ib_cm_find_request ( ntohl ( connect_rep->remote_id ),
  188. ntohl ( connect_rep->local_id ) );
  189. if ( ! request ) {
  190. DBGC ( gma, "GMA %p received connection reply with unknown "
  191. "ID %08x\n", gma, ntohl ( connect_rep->remote_id ) );
  192. return NULL;
  193. }
  194. /* Extract fields */
  195. request->qp->av.qpn = ( ntohl ( connect_rep->local_qpn ) >> 8 );
  196. request->qp->send.psn = ( ntohl ( connect_rep->starting_psn ) >> 8 );
  197. DBGC ( gma, "GMA %p QPN %lx connected to QPN %lx PSN %x\n", gma,
  198. request->qp->qpn, request->qp->av.qpn, request->qp->send.psn );
  199. /* Modify queue pair */
  200. if ( ( rc = ib_modify_qp ( request->qp->ibdev, request->qp ) ) != 0 ) {
  201. DBGC ( gma, "GMA %p QPN %lx could not modify queue pair: %s\n",
  202. gma, request->qp->qpn, strerror ( rc ) );
  203. return NULL;
  204. }
  205. /* Inform recipient that we are now connected */
  206. request->notify ( request->qp, 0, &connect_rep->private_data,
  207. sizeof ( connect_rep->private_data ) );
  208. /* Construct ready to use reply */
  209. mad->hdr.attr_id = htons ( IB_CM_ATTR_READY_TO_USE );
  210. memset ( ready, 0, sizeof ( *ready ) );
  211. ready->local_id = htonl ( request->local_id );
  212. ready->remote_id = htonl ( request->remote_id );
  213. return mad;
  214. }
  215. /**
  216. * Handle connection rejection
  217. *
  218. * @v gma General management agent
  219. * @v mad MAD
  220. * @ret response MAD response
  221. */
  222. static union ib_mad * ib_cm_connect_reject ( struct ib_gma *gma,
  223. union ib_mad *mad ) {
  224. struct ib_cm_connect_reject *connect_rej =
  225. &mad->cm.cm_data.connect_reject;
  226. struct ib_cm_request *request;
  227. uint16_t reason;
  228. /* Identify request */
  229. request = ib_cm_find_request ( ntohl ( connect_rej->remote_id ),
  230. ntohl ( connect_rej->local_id ) );
  231. if ( ! request ) {
  232. DBGC ( gma, "GMA %p received connection rejection with "
  233. "unknown ID %08x\n", gma,
  234. ntohl ( connect_rej->remote_id ) );
  235. return NULL;
  236. }
  237. /* Extract fields */
  238. reason = ntohs ( connect_rej->reason );
  239. DBGC ( gma, "GMA %p QPN %lx connection rejected (reason %d)\n",
  240. gma, request->qp->qpn, reason );
  241. /* Inform recipient that we are now disconnected */
  242. request->notify ( request->qp, -ENOTCONN, &connect_rej->private_data,
  243. sizeof ( connect_rej->private_data ) );
  244. return NULL;
  245. }
  246. /** Communication management MAD handlers */
  247. struct ib_gma_handler ib_cm_handlers[] __ib_gma_handler = {
  248. {
  249. .mgmt_class = IB_MGMT_CLASS_CM,
  250. .class_version = IB_CM_CLASS_VERSION,
  251. .method = IB_MGMT_METHOD_SEND,
  252. .attr_id = htons ( IB_CM_ATTR_CONNECT_REPLY ),
  253. .handle = ib_cm_connect_reply,
  254. },
  255. {
  256. .mgmt_class = IB_MGMT_CLASS_CM,
  257. .class_version = IB_CM_CLASS_VERSION,
  258. .method = IB_MGMT_METHOD_SEND,
  259. .attr_id = htons ( IB_CM_ATTR_CONNECT_REJECT ),
  260. .handle = ib_cm_connect_reject,
  261. },
  262. };
  263. /**
  264. * Connect to remote QP
  265. *
  266. * @v qp Queue pair
  267. * @v dgid Target GID
  268. * @v service_id Target service ID
  269. * @v private_data Private data
  270. * @v private_data_len Length of private data
  271. * @ret rc Return status code
  272. */
  273. int ib_cm_connect ( struct ib_queue_pair *qp, struct ib_gid *dgid,
  274. struct ib_gid_half *service_id,
  275. void *private_data, size_t private_data_len,
  276. void ( * notify ) ( struct ib_queue_pair *qp, int rc,
  277. void *private_data,
  278. size_t private_data_len ) ) {
  279. struct ib_cm_request *request;
  280. /* Allocate and initialise request */
  281. request = zalloc ( sizeof ( *request ) + private_data_len );
  282. if ( ! request )
  283. return -ENOMEM;
  284. list_add ( &request->list, &ib_cm_requests );
  285. request->local_id = random();
  286. request->qp = qp;
  287. memset ( &qp->av, 0, sizeof ( qp->av ) );
  288. qp->av.gid_present = 1;
  289. memcpy ( &qp->av.gid, dgid, sizeof ( qp->av.gid ) );
  290. memcpy ( &request->service_id, service_id,
  291. sizeof ( request->service_id ) );
  292. request->notify = notify;
  293. request->private_data_len = private_data_len;
  294. memcpy ( &request->private_data, private_data, private_data_len );
  295. process_init ( &request->process, ib_cm_step, NULL );
  296. return 0;
  297. }