2 * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
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.
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.
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.
19 FILE_LICENCE ( GPL2_OR_LATER
);
25 #include <gpxe/list.h>
26 #include <gpxe/infiniband.h>
27 #include <gpxe/ib_mi.h>
28 #include <gpxe/ib_mcast.h>
32 * Infiniband multicast groups
37 * Generate multicast membership MAD
39 * @v ibdev Infiniband device
40 * @v gid Multicast GID
41 * @v join Join (rather than leave) group
42 * @v mad MAD to fill in
44 static void ib_mcast_mad ( struct ib_device
*ibdev
, struct ib_gid
*gid
,
45 int join
, union ib_mad
*mad
) {
46 struct ib_mad_sa
*sa
= &mad
->sa
;
48 /* Construct multicast membership record request */
49 memset ( sa
, 0, sizeof ( *sa
) );
50 sa
->mad_hdr
.mgmt_class
= IB_MGMT_CLASS_SUBN_ADM
;
51 sa
->mad_hdr
.class_version
= IB_SA_CLASS_VERSION
;
53 ( join
? IB_MGMT_METHOD_SET
: IB_MGMT_METHOD_DELETE
);
54 sa
->mad_hdr
.attr_id
= htons ( IB_SA_ATTR_MC_MEMBER_REC
);
55 sa
->sa_hdr
.comp_mask
[1] =
56 htonl ( IB_SA_MCMEMBER_REC_MGID
| IB_SA_MCMEMBER_REC_PORT_GID
|
57 IB_SA_MCMEMBER_REC_JOIN_STATE
);
58 sa
->sa_data
.mc_member_record
.scope__join_state
= 1;
59 memcpy ( &sa
->sa_data
.mc_member_record
.mgid
, gid
,
60 sizeof ( sa
->sa_data
.mc_member_record
.mgid
) );
61 memcpy ( &sa
->sa_data
.mc_member_record
.port_gid
, &ibdev
->gid
,
62 sizeof ( sa
->sa_data
.mc_member_record
.port_gid
) );
66 * Handle multicast membership record join response
68 * @v ibdev Infiniband device
69 * @v mi Management interface
70 * @v madx Management transaction
72 * @v mad Received MAD (or NULL on error)
73 * @v av Source address vector (or NULL on error)
75 static void ib_mcast_complete ( struct ib_device
*ibdev
,
76 struct ib_mad_interface
*mi __unused
,
77 struct ib_mad_transaction
*madx
,
78 int rc
, union ib_mad
*mad
,
79 struct ib_address_vector
*av __unused
) {
80 struct ib_mc_membership
*membership
= ib_madx_get_ownerdata ( madx
);
81 struct ib_queue_pair
*qp
= membership
->qp
;
82 struct ib_gid
*gid
= &membership
->gid
;
83 struct ib_mc_member_record
*mc_member_record
=
84 &mad
->sa
.sa_data
.mc_member_record
;
89 if ( ( rc
== 0 ) && ( mad
->hdr
.status
!= htons ( IB_MGMT_STATUS_OK
) ))
92 DBGC ( ibdev
, "IBDEV %p QPN %lx join failed: %s\n",
93 ibdev
, qp
->qpn
, strerror ( rc
) );
97 /* Extract values from MAD */
98 joined
= ( mad
->hdr
.method
== IB_MGMT_METHOD_GET_RESP
);
99 qkey
= ntohl ( mc_member_record
->qkey
);
100 DBGC ( ibdev
, "IBDEV %p QPN %lx %s %08x:%08x:%08x:%08x qkey %lx\n",
101 ibdev
, qp
->qpn
, ( joined
? "joined" : "left" ),
102 ntohl ( gid
->u
.dwords
[0] ), ntohl ( gid
->u
.dwords
[1] ),
103 ntohl ( gid
->u
.dwords
[2] ), ntohl ( gid
->u
.dwords
[3] ),
108 if ( ( rc
= ib_modify_qp ( ibdev
, qp
) ) != 0 ) {
109 DBGC ( ibdev
, "IBDEV %p QPN %lx could not modify qkey: %s\n",
110 ibdev
, qp
->qpn
, strerror ( rc
) );
115 /* Destroy the completed transaction */
116 ib_destroy_madx ( ibdev
, mi
, madx
);
117 membership
->madx
= NULL
;
119 /* Hand off to upper completion handler */
120 membership
->complete ( ibdev
, qp
, membership
, rc
, mad
);
123 /** Multicast membership management transaction completion operations */
124 static struct ib_mad_transaction_operations ib_mcast_op
= {
125 .complete
= ib_mcast_complete
,
129 * Join multicast group
131 * @v ibdev Infiniband device
133 * @v membership Multicast group membership
134 * @v gid Multicast GID to join
135 * @v joined Join completion handler
136 * @ret rc Return status code
138 int ib_mcast_join ( struct ib_device
*ibdev
, struct ib_queue_pair
*qp
,
139 struct ib_mc_membership
*membership
, struct ib_gid
*gid
,
140 void ( * complete
) ( struct ib_device
*ibdev
,
141 struct ib_queue_pair
*qp
,
142 struct ib_mc_membership
*membership
,
143 int rc
, union ib_mad
*mad
) ) {
147 DBGC ( ibdev
, "IBDEV %p QPN %lx joining %08x:%08x:%08x:%08x\n",
148 ibdev
, qp
->qpn
, ntohl ( gid
->u
.dwords
[0] ),
149 ntohl ( gid
->u
.dwords
[1] ), ntohl ( gid
->u
.dwords
[2] ),
150 ntohl ( gid
->u
.dwords
[3] ) );
152 /* Initialise structure */
154 memcpy ( &membership
->gid
, gid
, sizeof ( membership
->gid
) );
155 membership
->complete
= complete
;
157 /* Attach queue pair to multicast GID */
158 if ( ( rc
= ib_mcast_attach ( ibdev
, qp
, gid
) ) != 0 ) {
159 DBGC ( ibdev
, "IBDEV %p QPN %lx could not attach: %s\n",
160 ibdev
, qp
->qpn
, strerror ( rc
) );
161 goto err_mcast_attach
;
164 /* Initiate multicast membership join */
165 ib_mcast_mad ( ibdev
, gid
, 1, &mad
);
166 membership
->madx
= ib_create_madx ( ibdev
, ibdev
->gsi
, &mad
, NULL
,
168 if ( ! membership
->madx
) {
169 DBGC ( ibdev
, "IBDEV %p QPN %lx could not create join "
170 "transaction\n", ibdev
, qp
->qpn
);
172 goto err_create_madx
;
174 ib_madx_set_ownerdata ( membership
->madx
, membership
);
178 ib_destroy_madx ( ibdev
, ibdev
->gsi
, membership
->madx
);
180 ib_mcast_detach ( ibdev
, qp
, gid
);
186 * Leave multicast group
188 * @v ibdev Infiniband device
190 * @v membership Multicast group membership
192 void ib_mcast_leave ( struct ib_device
*ibdev
, struct ib_queue_pair
*qp
,
193 struct ib_mc_membership
*membership
) {
194 struct ib_gid
*gid
= &membership
->gid
;
198 DBGC ( ibdev
, "IBDEV %p QPN %lx leaving %08x:%08x:%08x:%08x\n",
199 ibdev
, qp
->qpn
, ntohl ( gid
->u
.dwords
[0] ),
200 ntohl ( gid
->u
.dwords
[1] ), ntohl ( gid
->u
.dwords
[2] ),
201 ntohl ( gid
->u
.dwords
[3] ) );
203 /* Detach from multicast GID */
204 ib_mcast_detach ( ibdev
, qp
, &membership
->gid
);
206 /* Cancel multicast membership join, if applicable */
207 if ( membership
->madx
) {
208 ib_destroy_madx ( ibdev
, ibdev
->gsi
, membership
->madx
);
209 membership
->madx
= NULL
;
212 /* Send a single group leave MAD */
213 ib_mcast_mad ( ibdev
, &membership
->gid
, 0, &mad
);
214 if ( ( rc
= ib_mi_send ( ibdev
, ibdev
->gsi
, &mad
, NULL
) ) != 0 ) {
215 DBGC ( ibdev
, "IBDEV %p QPN %lx could not send leave request: "
216 "%s\n", ibdev
, qp
->qpn
, strerror ( rc
) );