[infiniband] Add last_opened_ibdev(), analogous to last_opened_netdev()
[people/oremanj/gpxe.git] / src / net / infiniband.c
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., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18
19 FILE_LICENCE ( GPL2_OR_LATER );
20
21 #include <stdint.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <byteswap.h>
27 #include <errno.h>
28 #include <assert.h>
29 #include <gpxe/list.h>
30 #include <gpxe/if_arp.h>
31 #include <gpxe/netdevice.h>
32 #include <gpxe/iobuf.h>
33 #include <gpxe/ipoib.h>
34 #include <gpxe/process.h>
35 #include <gpxe/infiniband.h>
36 #include <gpxe/ib_mi.h>
37 #include <gpxe/ib_sma.h>
38
39 /** @file
40  *
41  * Infiniband protocol
42  *
43  */
44
45 /** List of Infiniband devices */
46 struct list_head ib_devices = LIST_HEAD_INIT ( ib_devices );
47
48 /** List of open Infiniband devices, in reverse order of opening */
49 static struct list_head open_ib_devices = LIST_HEAD_INIT ( open_ib_devices );
50
51 /***************************************************************************
52  *
53  * Completion queues
54  *
55  ***************************************************************************
56  */
57
58 /**
59  * Create completion queue
60  *
61  * @v ibdev             Infiniband device
62  * @v num_cqes          Number of completion queue entries
63  * @v op                Completion queue operations
64  * @ret cq              New completion queue
65  */
66 struct ib_completion_queue *
67 ib_create_cq ( struct ib_device *ibdev, unsigned int num_cqes,
68                struct ib_completion_queue_operations *op ) {
69         struct ib_completion_queue *cq;
70         int rc;
71
72         DBGC ( ibdev, "IBDEV %p creating completion queue\n", ibdev );
73
74         /* Allocate and initialise data structure */
75         cq = zalloc ( sizeof ( *cq ) );
76         if ( ! cq )
77                 goto err_alloc_cq;
78         cq->ibdev = ibdev;
79         list_add ( &cq->list, &ibdev->cqs );
80         cq->num_cqes = num_cqes;
81         INIT_LIST_HEAD ( &cq->work_queues );
82         cq->op = op;
83
84         /* Perform device-specific initialisation and get CQN */
85         if ( ( rc = ibdev->op->create_cq ( ibdev, cq ) ) != 0 ) {
86                 DBGC ( ibdev, "IBDEV %p could not initialise completion "
87                        "queue: %s\n", ibdev, strerror ( rc ) );
88                 goto err_dev_create_cq;
89         }
90
91         DBGC ( ibdev, "IBDEV %p created %d-entry completion queue %p (%p) "
92                "with CQN %#lx\n", ibdev, num_cqes, cq,
93                ib_cq_get_drvdata ( cq ), cq->cqn );
94         return cq;
95
96         ibdev->op->destroy_cq ( ibdev, cq );
97  err_dev_create_cq:
98         list_del ( &cq->list );
99         free ( cq );
100  err_alloc_cq:
101         return NULL;
102 }
103
104 /**
105  * Destroy completion queue
106  *
107  * @v ibdev             Infiniband device
108  * @v cq                Completion queue
109  */
110 void ib_destroy_cq ( struct ib_device *ibdev,
111                      struct ib_completion_queue *cq ) {
112         DBGC ( ibdev, "IBDEV %p destroying completion queue %#lx\n",
113                ibdev, cq->cqn );
114         assert ( list_empty ( &cq->work_queues ) );
115         ibdev->op->destroy_cq ( ibdev, cq );
116         list_del ( &cq->list );
117         free ( cq );
118 }
119
120 /**
121  * Poll completion queue
122  *
123  * @v ibdev             Infiniband device
124  * @v cq                Completion queue
125  */
126 void ib_poll_cq ( struct ib_device *ibdev,
127                   struct ib_completion_queue *cq ) {
128         struct ib_work_queue *wq;
129
130         /* Poll completion queue */
131         ibdev->op->poll_cq ( ibdev, cq );
132
133         /* Refill receive work queues */
134         list_for_each_entry ( wq, &cq->work_queues, list ) {
135                 if ( ! wq->is_send )
136                         ib_refill_recv ( ibdev, wq->qp );
137         }
138 }
139
140 /***************************************************************************
141  *
142  * Work queues
143  *
144  ***************************************************************************
145  */
146
147 /**
148  * Create queue pair
149  *
150  * @v ibdev             Infiniband device
151  * @v type              Queue pair type
152  * @v num_send_wqes     Number of send work queue entries
153  * @v send_cq           Send completion queue
154  * @v num_recv_wqes     Number of receive work queue entries
155  * @v recv_cq           Receive completion queue
156  * @ret qp              Queue pair
157  *
158  * The queue pair will be left in the INIT state; you must call
159  * ib_modify_qp() before it is ready to use for sending and receiving.
160  */
161 struct ib_queue_pair * ib_create_qp ( struct ib_device *ibdev,
162                                       enum ib_queue_pair_type type,
163                                       unsigned int num_send_wqes,
164                                       struct ib_completion_queue *send_cq,
165                                       unsigned int num_recv_wqes,
166                                       struct ib_completion_queue *recv_cq ) {
167         struct ib_queue_pair *qp;
168         size_t total_size;
169         int rc;
170
171         DBGC ( ibdev, "IBDEV %p creating queue pair\n", ibdev );
172
173         /* Allocate and initialise data structure */
174         total_size = ( sizeof ( *qp ) +
175                        ( num_send_wqes * sizeof ( qp->send.iobufs[0] ) ) +
176                        ( num_recv_wqes * sizeof ( qp->recv.iobufs[0] ) ) );
177         qp = zalloc ( total_size );
178         if ( ! qp )
179                 goto err_alloc_qp;
180         qp->ibdev = ibdev;
181         list_add ( &qp->list, &ibdev->qps );
182         qp->type = type;
183         qp->send.qp = qp;
184         qp->send.is_send = 1;
185         qp->send.cq = send_cq;
186         list_add ( &qp->send.list, &send_cq->work_queues );
187         qp->send.psn = ( random() & 0xffffffUL );
188         qp->send.num_wqes = num_send_wqes;
189         qp->send.iobufs = ( ( ( void * ) qp ) + sizeof ( *qp ) );
190         qp->recv.qp = qp;
191         qp->recv.cq = recv_cq;
192         list_add ( &qp->recv.list, &recv_cq->work_queues );
193         qp->recv.psn = ( random() & 0xffffffUL );
194         qp->recv.num_wqes = num_recv_wqes;
195         qp->recv.iobufs = ( ( ( void * ) qp ) + sizeof ( *qp ) +
196                             ( num_send_wqes * sizeof ( qp->send.iobufs[0] ) ));
197         INIT_LIST_HEAD ( &qp->mgids );
198
199         /* Perform device-specific initialisation and get QPN */
200         if ( ( rc = ibdev->op->create_qp ( ibdev, qp ) ) != 0 ) {
201                 DBGC ( ibdev, "IBDEV %p could not initialise queue pair: "
202                        "%s\n", ibdev, strerror ( rc ) );
203                 goto err_dev_create_qp;
204         }
205         DBGC ( ibdev, "IBDEV %p created queue pair %p (%p) with QPN %#lx\n",
206                ibdev, qp, ib_qp_get_drvdata ( qp ), qp->qpn );
207         DBGC ( ibdev, "IBDEV %p QPN %#lx has %d send entries at [%p,%p)\n",
208                ibdev, qp->qpn, num_send_wqes, qp->send.iobufs,
209                qp->recv.iobufs );
210         DBGC ( ibdev, "IBDEV %p QPN %#lx has %d receive entries at [%p,%p)\n",
211                ibdev, qp->qpn, num_recv_wqes, qp->recv.iobufs,
212                ( ( ( void * ) qp ) + total_size ) );
213
214         /* Calculate externally-visible QPN */
215         switch ( type ) {
216         case IB_QPT_SMI:
217                 qp->ext_qpn = IB_QPN_SMI;
218                 break;
219         case IB_QPT_GSI:
220                 qp->ext_qpn = IB_QPN_GSI;
221                 break;
222         default:
223                 qp->ext_qpn = qp->qpn;
224                 break;
225         }
226         if ( qp->ext_qpn != qp->qpn ) {
227                 DBGC ( ibdev, "IBDEV %p QPN %#lx has external QPN %#lx\n",
228                        ibdev, qp->qpn, qp->ext_qpn );
229         }
230
231         return qp;
232
233         ibdev->op->destroy_qp ( ibdev, qp );
234  err_dev_create_qp:
235         list_del ( &qp->send.list );
236         list_del ( &qp->recv.list );
237         list_del ( &qp->list );
238         free ( qp );
239  err_alloc_qp:
240         return NULL;
241 }
242
243 /**
244  * Modify queue pair
245  *
246  * @v ibdev             Infiniband device
247  * @v qp                Queue pair
248  * @v av                New address vector, if applicable
249  * @ret rc              Return status code
250  */
251 int ib_modify_qp ( struct ib_device *ibdev, struct ib_queue_pair *qp ) {
252         int rc;
253
254         DBGC ( ibdev, "IBDEV %p modifying QPN %#lx\n", ibdev, qp->qpn );
255
256         if ( ( rc = ibdev->op->modify_qp ( ibdev, qp ) ) != 0 ) {
257                 DBGC ( ibdev, "IBDEV %p could not modify QPN %#lx: %s\n",
258                        ibdev, qp->qpn, strerror ( rc ) );
259                 return rc;
260         }
261
262         return 0;
263 }
264
265 /**
266  * Destroy queue pair
267  *
268  * @v ibdev             Infiniband device
269  * @v qp                Queue pair
270  */
271 void ib_destroy_qp ( struct ib_device *ibdev, struct ib_queue_pair *qp ) {
272         struct io_buffer *iobuf;
273         unsigned int i;
274
275         DBGC ( ibdev, "IBDEV %p destroying QPN %#lx\n",
276                ibdev, qp->qpn );
277
278         assert ( list_empty ( &qp->mgids ) );
279
280         /* Perform device-specific destruction */
281         ibdev->op->destroy_qp ( ibdev, qp );
282
283         /* Complete any remaining I/O buffers with errors */
284         for ( i = 0 ; i < qp->send.num_wqes ; i++ ) {
285                 if ( ( iobuf = qp->send.iobufs[i] ) != NULL )
286                         ib_complete_send ( ibdev, qp, iobuf, -ECANCELED );
287         }
288         for ( i = 0 ; i < qp->recv.num_wqes ; i++ ) {
289                 if ( ( iobuf = qp->recv.iobufs[i] ) != NULL ) {
290                         ib_complete_recv ( ibdev, qp, NULL, iobuf,
291                                            -ECANCELED );
292                 }
293         }
294
295         /* Remove work queues from completion queue */
296         list_del ( &qp->send.list );
297         list_del ( &qp->recv.list );
298
299         /* Free QP */
300         list_del ( &qp->list );
301         free ( qp );
302 }
303
304 /**
305  * Find queue pair by QPN
306  *
307  * @v ibdev             Infiniband device
308  * @v qpn               Queue pair number
309  * @ret qp              Queue pair, or NULL
310  */
311 struct ib_queue_pair * ib_find_qp_qpn ( struct ib_device *ibdev,
312                                         unsigned long qpn ) {
313         struct ib_queue_pair *qp;
314
315         list_for_each_entry ( qp, &ibdev->qps, list ) {
316                 if ( ( qpn == qp->qpn ) || ( qpn == qp->ext_qpn ) )
317                         return qp;
318         }
319         return NULL;
320 }
321
322 /**
323  * Find queue pair by multicast GID
324  *
325  * @v ibdev             Infiniband device
326  * @v gid               Multicast GID
327  * @ret qp              Queue pair, or NULL
328  */
329 struct ib_queue_pair * ib_find_qp_mgid ( struct ib_device *ibdev,
330                                          struct ib_gid *gid ) {
331         struct ib_queue_pair *qp;
332         struct ib_multicast_gid *mgid;
333
334         list_for_each_entry ( qp, &ibdev->qps, list ) {
335                 list_for_each_entry ( mgid, &qp->mgids, list ) {
336                         if ( memcmp ( &mgid->gid, gid,
337                                       sizeof ( mgid->gid ) ) == 0 ) {
338                                 return qp;
339                         }
340                 }
341         }
342         return NULL;
343 }
344
345 /**
346  * Find work queue belonging to completion queue
347  *
348  * @v cq                Completion queue
349  * @v qpn               Queue pair number
350  * @v is_send           Find send work queue (rather than receive)
351  * @ret wq              Work queue, or NULL if not found
352  */
353 struct ib_work_queue * ib_find_wq ( struct ib_completion_queue *cq,
354                                     unsigned long qpn, int is_send ) {
355         struct ib_work_queue *wq;
356
357         list_for_each_entry ( wq, &cq->work_queues, list ) {
358                 if ( ( wq->qp->qpn == qpn ) && ( wq->is_send == is_send ) )
359                         return wq;
360         }
361         return NULL;
362 }
363
364 /**
365  * Post send work queue entry
366  *
367  * @v ibdev             Infiniband device
368  * @v qp                Queue pair
369  * @v av                Address vector
370  * @v iobuf             I/O buffer
371  * @ret rc              Return status code
372  */
373 int ib_post_send ( struct ib_device *ibdev, struct ib_queue_pair *qp,
374                    struct ib_address_vector *av,
375                    struct io_buffer *iobuf ) {
376         struct ib_address_vector av_copy;
377         int rc;
378
379         /* Check queue fill level */
380         if ( qp->send.fill >= qp->send.num_wqes ) {
381                 DBGC ( ibdev, "IBDEV %p QPN %#lx send queue full\n",
382                        ibdev, qp->qpn );
383                 return -ENOBUFS;
384         }
385
386         /* Use default address vector if none specified */
387         if ( ! av )
388                 av = &qp->av;
389
390         /* Make modifiable copy of address vector */
391         memcpy ( &av_copy, av, sizeof ( av_copy ) );
392         av = &av_copy;
393
394         /* Fill in optional parameters in address vector */
395         if ( ! av->qkey )
396                 av->qkey = qp->qkey;
397         if ( ! av->rate )
398                 av->rate = IB_RATE_2_5;
399
400         /* Post to hardware */
401         if ( ( rc = ibdev->op->post_send ( ibdev, qp, av, iobuf ) ) != 0 ) {
402                 DBGC ( ibdev, "IBDEV %p QPN %#lx could not post send WQE: "
403                        "%s\n", ibdev, qp->qpn, strerror ( rc ) );
404                 return rc;
405         }
406
407         qp->send.fill++;
408         return 0;
409 }
410
411 /**
412  * Post receive work queue entry
413  *
414  * @v ibdev             Infiniband device
415  * @v qp                Queue pair
416  * @v iobuf             I/O buffer
417  * @ret rc              Return status code
418  */
419 int ib_post_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp,
420                    struct io_buffer *iobuf ) {
421         int rc;
422
423         /* Check packet length */
424         if ( iob_tailroom ( iobuf ) < IB_MAX_PAYLOAD_SIZE ) {
425                 DBGC ( ibdev, "IBDEV %p QPN %#lx wrong RX buffer size (%zd)\n",
426                        ibdev, qp->qpn, iob_tailroom ( iobuf ) );
427                 return -EINVAL;
428         }
429
430         /* Check queue fill level */
431         if ( qp->recv.fill >= qp->recv.num_wqes ) {
432                 DBGC ( ibdev, "IBDEV %p QPN %#lx receive queue full\n",
433                        ibdev, qp->qpn );
434                 return -ENOBUFS;
435         }
436
437         /* Post to hardware */
438         if ( ( rc = ibdev->op->post_recv ( ibdev, qp, iobuf ) ) != 0 ) {
439                 DBGC ( ibdev, "IBDEV %p QPN %#lx could not post receive WQE: "
440                        "%s\n", ibdev, qp->qpn, strerror ( rc ) );
441                 return rc;
442         }
443
444         qp->recv.fill++;
445         return 0;
446 }
447
448 /**
449  * Complete send work queue entry
450  *
451  * @v ibdev             Infiniband device
452  * @v qp                Queue pair
453  * @v iobuf             I/O buffer
454  * @v rc                Completion status code
455  */
456 void ib_complete_send ( struct ib_device *ibdev, struct ib_queue_pair *qp,
457                         struct io_buffer *iobuf, int rc ) {
458
459         if ( qp->send.cq->op->complete_send ) {
460                 qp->send.cq->op->complete_send ( ibdev, qp, iobuf, rc );
461         } else {
462                 free_iob ( iobuf );
463         }
464         qp->send.fill--;
465 }
466
467 /**
468  * Complete receive work queue entry
469  *
470  * @v ibdev             Infiniband device
471  * @v qp                Queue pair
472  * @v av                Address vector
473  * @v iobuf             I/O buffer
474  * @v rc                Completion status code
475  */
476 void ib_complete_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp,
477                         struct ib_address_vector *av,
478                         struct io_buffer *iobuf, int rc ) {
479
480         if ( qp->recv.cq->op->complete_recv ) {
481                 qp->recv.cq->op->complete_recv ( ibdev, qp, av, iobuf, rc );
482         } else {
483                 free_iob ( iobuf );
484         }
485         qp->recv.fill--;
486 }
487
488 /**
489  * Refill receive work queue
490  *
491  * @v ibdev             Infiniband device
492  * @v qp                Queue pair
493  */
494 void ib_refill_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp ) {
495         struct io_buffer *iobuf;
496         int rc;
497
498         /* Keep filling while unfilled entries remain */
499         while ( qp->recv.fill < qp->recv.num_wqes ) {
500
501                 /* Allocate I/O buffer */
502                 iobuf = alloc_iob ( IB_MAX_PAYLOAD_SIZE );
503                 if ( ! iobuf ) {
504                         /* Non-fatal; we will refill on next attempt */
505                         return;
506                 }
507
508                 /* Post I/O buffer */
509                 if ( ( rc = ib_post_recv ( ibdev, qp, iobuf ) ) != 0 ) {
510                         DBGC ( ibdev, "IBDEV %p could not refill: %s\n",
511                                ibdev, strerror ( rc ) );
512                         free_iob ( iobuf );
513                         /* Give up */
514                         return;
515                 }
516         }
517 }
518
519 /***************************************************************************
520  *
521  * Link control
522  *
523  ***************************************************************************
524  */
525
526 /**
527  * Open port
528  *
529  * @v ibdev             Infiniband device
530  * @ret rc              Return status code
531  */
532 int ib_open ( struct ib_device *ibdev ) {
533         int rc;
534
535         /* Increment device open request counter */
536         if ( ibdev->open_count++ > 0 ) {
537                 /* Device was already open; do nothing */
538                 return 0;
539         }
540
541         /* Create subnet management interface */
542         ibdev->smi = ib_create_mi ( ibdev, IB_QPT_SMI );
543         if ( ! ibdev->smi ) {
544                 DBGC ( ibdev, "IBDEV %p could not create SMI\n", ibdev );
545                 rc = -ENOMEM;
546                 goto err_create_smi;
547         }
548
549         /* Create subnet management agent */
550         if ( ( rc = ib_create_sma ( ibdev, ibdev->smi ) ) != 0 ) {
551                 DBGC ( ibdev, "IBDEV %p could not create SMA: %s\n",
552                        ibdev, strerror ( rc ) );
553                 goto err_create_sma;
554         }
555
556         /* Create general services interface */
557         ibdev->gsi = ib_create_mi ( ibdev, IB_QPT_GSI );
558         if ( ! ibdev->gsi ) {
559                 DBGC ( ibdev, "IBDEV %p could not create GSI\n", ibdev );
560                 rc = -ENOMEM;
561                 goto err_create_gsi;
562         }
563
564         /* Open device */
565         if ( ( rc = ibdev->op->open ( ibdev ) ) != 0 ) {
566                 DBGC ( ibdev, "IBDEV %p could not open: %s\n",
567                        ibdev, strerror ( rc ) );
568                 goto err_open;
569         }
570
571         /* Add to head of open devices list */
572         list_add ( &ibdev->open_list, &open_ib_devices );
573
574         assert ( ibdev->open_count == 1 );
575         return 0;
576
577         ibdev->op->close ( ibdev );
578  err_open:
579         ib_destroy_mi ( ibdev, ibdev->gsi );
580  err_create_gsi:
581         ib_destroy_sma ( ibdev, ibdev->smi );
582  err_create_sma:
583         ib_destroy_mi ( ibdev, ibdev->smi );
584  err_create_smi:
585         assert ( ibdev->open_count == 1 );
586         ibdev->open_count = 0;
587         return rc;
588 }
589
590 /**
591  * Close port
592  *
593  * @v ibdev             Infiniband device
594  */
595 void ib_close ( struct ib_device *ibdev ) {
596
597         /* Decrement device open request counter */
598         ibdev->open_count--;
599
600         /* Close device if this was the last remaining requested opening */
601         if ( ibdev->open_count == 0 ) {
602                 list_del ( &ibdev->open_list );
603                 ib_destroy_mi ( ibdev, ibdev->gsi );
604                 ib_destroy_sma ( ibdev, ibdev->smi );
605                 ib_destroy_mi ( ibdev, ibdev->smi );
606                 ibdev->op->close ( ibdev );
607         }
608 }
609
610 /***************************************************************************
611  *
612  * Multicast
613  *
614  ***************************************************************************
615  */
616
617 /**
618  * Attach to multicast group
619  *
620  * @v ibdev             Infiniband device
621  * @v qp                Queue pair
622  * @v gid               Multicast GID
623  * @ret rc              Return status code
624  *
625  * Note that this function handles only the local device's attachment
626  * to the multicast GID; it does not issue the relevant MADs to join
627  * the multicast group on the subnet.
628  */
629 int ib_mcast_attach ( struct ib_device *ibdev, struct ib_queue_pair *qp,
630                       struct ib_gid *gid ) {
631         struct ib_multicast_gid *mgid;
632         int rc;
633
634         /* Add to software multicast GID list */
635         mgid = zalloc ( sizeof ( *mgid ) );
636         if ( ! mgid ) {
637                 rc = -ENOMEM;
638                 goto err_alloc_mgid;
639         }
640         memcpy ( &mgid->gid, gid, sizeof ( mgid->gid ) );
641         list_add ( &mgid->list, &qp->mgids );
642
643         /* Add to hardware multicast GID list */
644         if ( ( rc = ibdev->op->mcast_attach ( ibdev, qp, gid ) ) != 0 )
645                 goto err_dev_mcast_attach;
646
647         return 0;
648
649  err_dev_mcast_attach:
650         list_del ( &mgid->list );
651         free ( mgid );
652  err_alloc_mgid:
653         return rc;
654 }
655
656 /**
657  * Detach from multicast group
658  *
659  * @v ibdev             Infiniband device
660  * @v qp                Queue pair
661  * @v gid               Multicast GID
662  */
663 void ib_mcast_detach ( struct ib_device *ibdev, struct ib_queue_pair *qp,
664                        struct ib_gid *gid ) {
665         struct ib_multicast_gid *mgid;
666
667         /* Remove from hardware multicast GID list */
668         ibdev->op->mcast_detach ( ibdev, qp, gid );
669
670         /* Remove from software multicast GID list */
671         list_for_each_entry ( mgid, &qp->mgids, list ) {
672                 if ( memcmp ( &mgid->gid, gid, sizeof ( mgid->gid ) ) == 0 ) {
673                         list_del ( &mgid->list );
674                         free ( mgid );
675                         break;
676                 }
677         }
678 }
679
680 /***************************************************************************
681  *
682  * Miscellaneous
683  *
684  ***************************************************************************
685  */
686
687 /**
688  * Get Infiniband HCA information
689  *
690  * @v ibdev             Infiniband device
691  * @ret hca_guid        HCA GUID
692  * @ret num_ports       Number of ports
693  */
694 int ib_get_hca_info ( struct ib_device *ibdev,
695                       struct ib_gid_half *hca_guid ) {
696         struct ib_device *tmp;
697         int num_ports = 0;
698
699         /* Search for IB devices with the same physical device to
700          * identify port count and a suitable Node GUID.
701          */
702         for_each_ibdev ( tmp ) {
703                 if ( tmp->dev != ibdev->dev )
704                         continue;
705                 if ( num_ports == 0 ) {
706                         memcpy ( hca_guid, &tmp->gid.u.half[1],
707                                  sizeof ( *hca_guid ) );
708                 }
709                 num_ports++;
710         }
711         return num_ports;
712 }
713
714 /**
715  * Set port information
716  *
717  * @v ibdev             Infiniband device
718  * @v mad               Set port information MAD
719  */
720 int ib_set_port_info ( struct ib_device *ibdev, union ib_mad *mad ) {
721         int rc;
722
723         /* Adapters with embedded SMAs do not need to support this method */
724         if ( ! ibdev->op->set_port_info ) {
725                 DBGC ( ibdev, "IBDEV %p does not support setting port "
726                        "information\n", ibdev );
727                 return -ENOTSUP;
728         }
729
730         if ( ( rc = ibdev->op->set_port_info ( ibdev, mad ) ) != 0 ) {
731                 DBGC ( ibdev, "IBDEV %p could not set port information: %s\n",
732                        ibdev, strerror ( rc ) );
733                 return rc;
734         }
735
736         return 0;
737 };
738
739 /**
740  * Set partition key table
741  *
742  * @v ibdev             Infiniband device
743  * @v mad               Set partition key table MAD
744  */
745 int ib_set_pkey_table ( struct ib_device *ibdev, union ib_mad *mad ) {
746         int rc;
747
748         /* Adapters with embedded SMAs do not need to support this method */
749         if ( ! ibdev->op->set_pkey_table ) {
750                 DBGC ( ibdev, "IBDEV %p does not support setting partition "
751                        "key table\n", ibdev );
752                 return -ENOTSUP;
753         }
754
755         if ( ( rc = ibdev->op->set_pkey_table ( ibdev, mad ) ) != 0 ) {
756                 DBGC ( ibdev, "IBDEV %p could not set partition key table: "
757                        "%s\n", ibdev, strerror ( rc ) );
758                 return rc;
759         }
760
761         return 0;
762 };
763
764 /***************************************************************************
765  *
766  * Event queues
767  *
768  ***************************************************************************
769  */
770
771 /**
772  * Handle Infiniband link state change
773  *
774  * @v ibdev             Infiniband device
775  */
776 void ib_link_state_changed ( struct ib_device *ibdev ) {
777
778         /* Notify IPoIB of link state change */
779         ipoib_link_state_changed ( ibdev );
780 }
781
782 /**
783  * Poll event queue
784  *
785  * @v ibdev             Infiniband device
786  */
787 void ib_poll_eq ( struct ib_device *ibdev ) {
788         struct ib_completion_queue *cq;
789
790         /* Poll device's event queue */
791         ibdev->op->poll_eq ( ibdev );
792
793         /* Poll all completion queues */
794         list_for_each_entry ( cq, &ibdev->cqs, list )
795                 ib_poll_cq ( ibdev, cq );
796 }
797
798 /**
799  * Single-step the Infiniband event queue
800  *
801  * @v process           Infiniband event queue process
802  */
803 static void ib_step ( struct process *process __unused ) {
804         struct ib_device *ibdev;
805
806         for_each_ibdev ( ibdev )
807                 ib_poll_eq ( ibdev );
808 }
809
810 /** Infiniband event queue process */
811 struct process ib_process __permanent_process = {
812         .list = LIST_HEAD_INIT ( ib_process.list ),
813         .step = ib_step,
814 };
815
816 /***************************************************************************
817  *
818  * Infiniband device creation/destruction
819  *
820  ***************************************************************************
821  */
822
823 /**
824  * Allocate Infiniband device
825  *
826  * @v priv_size         Size of driver private data area
827  * @ret ibdev           Infiniband device, or NULL
828  */
829 struct ib_device * alloc_ibdev ( size_t priv_size ) {
830         struct ib_device *ibdev;
831         void *drv_priv;
832         size_t total_len;
833
834         total_len = ( sizeof ( *ibdev ) + priv_size );
835         ibdev = zalloc ( total_len );
836         if ( ibdev ) {
837                 drv_priv = ( ( ( void * ) ibdev ) + sizeof ( *ibdev ) );
838                 ib_set_drvdata ( ibdev, drv_priv );
839                 INIT_LIST_HEAD ( &ibdev->cqs );
840                 INIT_LIST_HEAD ( &ibdev->qps );
841                 ibdev->lid = IB_LID_NONE;
842                 ibdev->pkey = IB_PKEY_NONE;
843         }
844         return ibdev;
845 }
846
847 /**
848  * Register Infiniband device
849  *
850  * @v ibdev             Infiniband device
851  * @ret rc              Return status code
852  */
853 int register_ibdev ( struct ib_device *ibdev ) {
854         int rc;
855
856         /* Add to device list */
857         ibdev_get ( ibdev );
858         list_add_tail ( &ibdev->list, &ib_devices );
859
860         /* Add IPoIB device */
861         if ( ( rc = ipoib_probe ( ibdev ) ) != 0 ) {
862                 DBGC ( ibdev, "IBDEV %p could not add IPoIB device: %s\n",
863                        ibdev, strerror ( rc ) );
864                 goto err_ipoib_probe;
865         }
866
867         DBGC ( ibdev, "IBDEV %p registered (phys %s)\n", ibdev,
868                ibdev->dev->name );
869         return 0;
870
871  err_ipoib_probe:
872         list_del ( &ibdev->list );
873         ibdev_put ( ibdev );
874         return rc;
875 }
876
877 /**
878  * Unregister Infiniband device
879  *
880  * @v ibdev             Infiniband device
881  */
882 void unregister_ibdev ( struct ib_device *ibdev ) {
883
884         /* Close device */
885         ipoib_remove ( ibdev );
886
887         /* Remove from device list */
888         list_del ( &ibdev->list );
889         ibdev_put ( ibdev );
890         DBGC ( ibdev, "IBDEV %p unregistered\n", ibdev );
891 }
892
893 /**
894  * Find Infiniband device by GID
895  *
896  * @v gid               GID
897  * @ret ibdev           Infiniband device, or NULL
898  */
899 struct ib_device * find_ibdev ( struct ib_gid *gid ) {
900         struct ib_device *ibdev;
901
902         for_each_ibdev ( ibdev ) {
903                 if ( memcmp ( gid, &ibdev->gid, sizeof ( *gid ) ) == 0 )
904                         return ibdev;
905         }
906         return NULL;
907 }
908
909 /**
910  * Get most recently opened Infiniband device
911  *
912  * @ret ibdev           Most recently opened Infiniband device, or NULL
913  */
914 struct ib_device * last_opened_ibdev ( void ) {
915         struct ib_device *ibdev;
916
917         list_for_each_entry ( ibdev, &open_ib_devices, open_list ) {
918                 assert ( ibdev->open_count != 0 );
919                 return ibdev;
920         }
921
922         return NULL;
923 }