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_gma.c 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  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 <errno.h>
  23. #include <stdio.h>
  24. #include <unistd.h>
  25. #include <byteswap.h>
  26. #include <gpxe/infiniband.h>
  27. #include <gpxe/iobuf.h>
  28. #include <gpxe/ib_gma.h>
  29. /**
  30. * @file
  31. *
  32. * Infiniband General Management Agent
  33. *
  34. */
  35. /** A MAD request */
  36. struct ib_mad_request {
  37. /** Associated GMA */
  38. struct ib_gma *gma;
  39. /** List of outstanding MAD requests */
  40. struct list_head list;
  41. /** Retry timer */
  42. struct retry_timer timer;
  43. /** Destination address */
  44. struct ib_address_vector av;
  45. /** MAD request */
  46. union ib_mad mad;
  47. };
  48. /** GMA number of send WQEs
  49. *
  50. * This is a policy decision.
  51. */
  52. #define IB_GMA_NUM_SEND_WQES 4
  53. /** GMA number of receive WQEs
  54. *
  55. * This is a policy decision.
  56. */
  57. #define IB_GMA_NUM_RECV_WQES 2
  58. /** GMA number of completion queue entries
  59. *
  60. * This is a policy decision
  61. */
  62. #define IB_GMA_NUM_CQES 8
  63. /** TID magic signature */
  64. #define IB_GMA_TID_MAGIC ( ( 'g' << 24 ) | ( 'P' << 16 ) | ( 'X' << 8 ) | 'E' )
  65. /** TID to use for next MAD request */
  66. static unsigned int next_request_tid;
  67. /*****************************************************************************
  68. *
  69. * General management agent
  70. *
  71. *****************************************************************************
  72. */
  73. /**
  74. * Call attribute handler
  75. *
  76. * @v gma General management agent
  77. * @v mad MAD
  78. * @ret mad MAD response
  79. */
  80. static union ib_mad * ib_handle_mad ( struct ib_gma *gma, union ib_mad *mad ) {
  81. struct ib_mad_hdr *hdr = &mad->hdr;
  82. struct ib_gma_handler *handler;
  83. for_each_table_entry ( handler, IB_GMA_HANDLERS ) {
  84. if ( ( ( handler->mgmt_class & ~handler->mgmt_class_ignore ) ==
  85. ( hdr->mgmt_class & ~handler->mgmt_class_ignore ) ) &&
  86. ( handler->class_version == hdr->class_version ) &&
  87. ( handler->method == hdr->method ) &&
  88. ( handler->attr_id == hdr->attr_id ) ) {
  89. return handler->handle ( gma, mad );
  90. }
  91. }
  92. hdr->method = IB_MGMT_METHOD_TRAP;
  93. hdr->status = htons ( IB_MGMT_STATUS_UNSUPPORTED_METHOD_ATTR );
  94. return mad;
  95. }
  96. /**
  97. * Complete GMA receive
  98. *
  99. *
  100. * @v ibdev Infiniband device
  101. * @v qp Queue pair
  102. * @v av Address vector
  103. * @v iobuf I/O buffer
  104. * @v rc Completion status code
  105. */
  106. static void ib_gma_complete_recv ( struct ib_device *ibdev,
  107. struct ib_queue_pair *qp,
  108. struct ib_address_vector *av,
  109. struct io_buffer *iobuf, int rc ) {
  110. struct ib_gma *gma = ib_qp_get_ownerdata ( qp );
  111. struct ib_mad_request *request;
  112. union ib_mad *mad;
  113. struct ib_mad_hdr *hdr;
  114. union ib_mad *response;
  115. /* Ignore errors */
  116. if ( rc != 0 ) {
  117. DBGC ( gma, "GMA %p RX error: %s\n", gma, strerror ( rc ) );
  118. goto out;
  119. }
  120. /* Sanity checks */
  121. if ( iob_len ( iobuf ) != sizeof ( *mad ) ) {
  122. DBGC ( gma, "GMA %p RX bad size (%zd bytes)\n",
  123. gma, iob_len ( iobuf ) );
  124. DBGC_HDA ( gma, 0, iobuf->data, iob_len ( iobuf ) );
  125. goto out;
  126. }
  127. mad = iobuf->data;
  128. hdr = &mad->hdr;
  129. if ( hdr->base_version != IB_MGMT_BASE_VERSION ) {
  130. DBGC ( gma, "GMA %p unsupported base version %x\n",
  131. gma, hdr->base_version );
  132. DBGC_HDA ( gma, 0, mad, sizeof ( *mad ) );
  133. goto out;
  134. }
  135. DBGC ( gma, "GMA %p RX TID %08x%08x (%02x,%02x,%02x,%04x) status "
  136. "%04x\n", gma, ntohl ( hdr->tid[0] ), ntohl ( hdr->tid[1] ),
  137. hdr->mgmt_class, hdr->class_version, hdr->method,
  138. ntohs ( hdr->attr_id ), ntohs ( hdr->status ) );
  139. DBGC2_HDA ( gma, 0, mad, sizeof ( *mad ) );
  140. /* Dequeue request if applicable */
  141. list_for_each_entry ( request, &gma->requests, list ) {
  142. if ( memcmp ( &request->mad.hdr.tid, &hdr->tid,
  143. sizeof ( request->mad.hdr.tid ) ) == 0 ) {
  144. stop_timer ( &request->timer );
  145. list_del ( &request->list );
  146. free ( request );
  147. break;
  148. }
  149. }
  150. /* Handle MAD */
  151. if ( ( response = ib_handle_mad ( gma, mad ) ) == NULL )
  152. goto out;
  153. /* Re-use I/O buffer for response */
  154. memcpy ( mad, response, sizeof ( *mad ) );
  155. DBGC ( gma, "GMA %p TX TID %08x%08x (%02x,%02x,%02x,%04x) status "
  156. "%04x\n", gma, ntohl ( hdr->tid[0] ), ntohl ( hdr->tid[1] ),
  157. hdr->mgmt_class, hdr->class_version, hdr->method,
  158. ntohs ( hdr->attr_id ), ntohs ( hdr->status ) );
  159. DBGC2_HDA ( gma, 0, mad, sizeof ( *mad ) );
  160. /* Send MAD response, if applicable */
  161. if ( ( rc = ib_post_send ( ibdev, qp, av,
  162. iob_disown ( iobuf ) ) ) != 0 ) {
  163. DBGC ( gma, "GMA %p could not send MAD response: %s\n",
  164. gma, strerror ( rc ) );
  165. goto out;
  166. }
  167. out:
  168. free_iob ( iobuf );
  169. }
  170. /** GMA completion operations */
  171. static struct ib_completion_queue_operations ib_gma_completion_ops = {
  172. .complete_recv = ib_gma_complete_recv,
  173. };
  174. /**
  175. * Transmit MAD request
  176. *
  177. * @v gma General management agent
  178. * @v request MAD request
  179. * @ret rc Return status code
  180. */
  181. static int ib_gma_send ( struct ib_gma *gma, struct ib_mad_request *request ) {
  182. struct io_buffer *iobuf;
  183. int rc;
  184. DBGC ( gma, "GMA %p TX TID %08x%08x (%02x,%02x,%02x,%04x)\n",
  185. gma, ntohl ( request->mad.hdr.tid[0] ),
  186. ntohl ( request->mad.hdr.tid[1] ), request->mad.hdr.mgmt_class,
  187. request->mad.hdr.class_version, request->mad.hdr.method,
  188. ntohs ( request->mad.hdr.attr_id ) );
  189. DBGC2_HDA ( gma, 0, &request->mad, sizeof ( request->mad ) );
  190. /* Construct I/O buffer */
  191. iobuf = alloc_iob ( sizeof ( request->mad ) );
  192. if ( ! iobuf ) {
  193. DBGC ( gma, "GMA %p could not allocate buffer for TID "
  194. "%08x%08x\n", gma, ntohl ( request->mad.hdr.tid[0] ),
  195. ntohl ( request->mad.hdr.tid[1] ) );
  196. return -ENOMEM;
  197. }
  198. memcpy ( iob_put ( iobuf, sizeof ( request->mad ) ), &request->mad,
  199. sizeof ( request->mad ) );
  200. /* Send I/O buffer */
  201. if ( ( rc = ib_post_send ( gma->ibdev, gma->qp, &request->av,
  202. iobuf ) ) != 0 ) {
  203. DBGC ( gma, "GMA %p could not send TID %08x%08x: %s\n",
  204. gma, ntohl ( request->mad.hdr.tid[0] ),
  205. ntohl ( request->mad.hdr.tid[1] ), strerror ( rc ) );
  206. free_iob ( iobuf );
  207. return rc;
  208. }
  209. return 0;
  210. }
  211. /**
  212. * Handle MAD request timer expiry
  213. *
  214. * @v timer Retry timer
  215. * @v expired Failure indicator
  216. */
  217. static void ib_gma_timer_expired ( struct retry_timer *timer, int expired ) {
  218. struct ib_mad_request *request =
  219. container_of ( timer, struct ib_mad_request, timer );
  220. struct ib_gma *gma = request->gma;
  221. /* Abandon TID if we have tried too many times */
  222. if ( expired ) {
  223. DBGC ( gma, "GMA %p abandoning TID %08x%08x\n",
  224. gma, ntohl ( request->mad.hdr.tid[0] ),
  225. ntohl ( request->mad.hdr.tid[1] ) );
  226. list_del ( &request->list );
  227. free ( request );
  228. return;
  229. }
  230. /* Restart retransmission timer */
  231. start_timer ( timer );
  232. /* Resend request */
  233. ib_gma_send ( gma, request );
  234. }
  235. /**
  236. * Issue MAD request
  237. *
  238. * @v gma General management agent
  239. * @v mad MAD request
  240. * @v av Destination address, or NULL for SM
  241. * @v retry Request should be retried until a response arrives
  242. * @ret rc Return status code
  243. */
  244. int ib_gma_request ( struct ib_gma *gma, union ib_mad *mad,
  245. struct ib_address_vector *av, int retry ) {
  246. struct ib_device *ibdev = gma->ibdev;
  247. struct ib_mad_request *request;
  248. /* Allocate and initialise structure */
  249. request = zalloc ( sizeof ( *request ) );
  250. if ( ! request ) {
  251. DBGC ( gma, "GMA %p could not allocate MAD request\n", gma );
  252. return -ENOMEM;
  253. }
  254. request->gma = gma;
  255. request->timer.expired = ib_gma_timer_expired;
  256. /* Determine address vector */
  257. if ( av ) {
  258. memcpy ( &request->av, av, sizeof ( request->av ) );
  259. } else {
  260. request->av.lid = ibdev->sm_lid;
  261. request->av.sl = ibdev->sm_sl;
  262. request->av.qpn = IB_QPN_GSI;
  263. request->av.qkey = IB_QKEY_GSI;
  264. }
  265. /* Copy MAD body */
  266. memcpy ( &request->mad, mad, sizeof ( request->mad ) );
  267. /* Allocate TID */
  268. request->mad.hdr.tid[0] = htonl ( IB_GMA_TID_MAGIC );
  269. request->mad.hdr.tid[1] = htonl ( ++next_request_tid );
  270. /* Send initial request. Ignore errors; the retry timer will
  271. * take care of those we care about.
  272. */
  273. ib_gma_send ( gma, request );
  274. /* Add to list and start timer if applicable */
  275. if ( retry ) {
  276. list_add ( &request->list, &gma->requests );
  277. start_timer ( &request->timer );
  278. } else {
  279. free ( request );
  280. }
  281. return 0;
  282. }
  283. /**
  284. * Create GMA
  285. *
  286. * @v ibdev Infiniband device
  287. * @v type Queue pair type
  288. * @ret gma General management agent, or NULL
  289. */
  290. struct ib_gma * ib_create_gma ( struct ib_device *ibdev,
  291. enum ib_queue_pair_type type ) {
  292. struct ib_gma *gma;
  293. int rc;
  294. /* Allocate and initialise fields */
  295. gma = zalloc ( sizeof ( *gma ) );
  296. if ( ! gma )
  297. goto err_alloc;
  298. gma->ibdev = ibdev;
  299. INIT_LIST_HEAD ( &gma->requests );
  300. /* Create completion queue */
  301. gma->cq = ib_create_cq ( ibdev, IB_GMA_NUM_CQES,
  302. &ib_gma_completion_ops );
  303. if ( ! gma->cq ) {
  304. DBGC ( gma, "GMA %p could not allocate completion queue\n",
  305. gma );
  306. goto err_create_cq;
  307. }
  308. /* Create queue pair */
  309. gma->qp = ib_create_qp ( ibdev, type, IB_GMA_NUM_SEND_WQES, gma->cq,
  310. IB_GMA_NUM_RECV_WQES, gma->cq );
  311. if ( ! gma->qp ) {
  312. DBGC ( gma, "GMA %p could not allocate queue pair\n", gma );
  313. goto err_create_qp;
  314. }
  315. ib_qp_set_ownerdata ( gma->qp, gma );
  316. DBGC ( gma, "GMA %p running on QPN %#lx\n", gma, gma->qp->qpn );
  317. /* Set queue key */
  318. gma->qp->qkey = ( ( type == IB_QPT_SMI ) ? IB_QKEY_SMI : IB_QKEY_GSI );
  319. if ( ( rc = ib_modify_qp ( ibdev, gma->qp ) ) != 0 ) {
  320. DBGC ( gma, "GMA %p could not set queue key: %s\n",
  321. gma, strerror ( rc ) );
  322. goto err_modify_qp;
  323. }
  324. /* Fill receive ring */
  325. ib_refill_recv ( ibdev, gma->qp );
  326. return gma;
  327. err_modify_qp:
  328. ib_destroy_qp ( ibdev, gma->qp );
  329. err_create_qp:
  330. ib_destroy_cq ( ibdev, gma->cq );
  331. err_create_cq:
  332. free ( gma );
  333. err_alloc:
  334. return NULL;
  335. }
  336. /**
  337. * Destroy GMA
  338. *
  339. * @v gma General management agent
  340. */
  341. void ib_destroy_gma ( struct ib_gma *gma ) {
  342. struct ib_device *ibdev = gma->ibdev;
  343. struct ib_mad_request *request;
  344. struct ib_mad_request *tmp;
  345. /* Flush any outstanding requests */
  346. list_for_each_entry_safe ( request, tmp, &gma->requests, list ) {
  347. stop_timer ( &request->timer );
  348. list_del ( &request->list );
  349. free ( request );
  350. }
  351. ib_destroy_qp ( ibdev, gma->qp );
  352. ib_destroy_cq ( ibdev, gma->cq );
  353. free ( gma );
  354. }