|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+/*
|
|
|
2
|
+ * Copyright (C) 2008 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
|
+#include <stdint.h>
|
|
|
20
|
+#include <stdlib.h>
|
|
|
21
|
+#include <string.h>
|
|
|
22
|
+#include <errno.h>
|
|
|
23
|
+#include <byteswap.h>
|
|
|
24
|
+#include <gpxe/iobuf.h>
|
|
|
25
|
+#include <gpxe/infiniband.h>
|
|
|
26
|
+#include <gpxe/ib_packet.h>
|
|
|
27
|
+
|
|
|
28
|
+/**
|
|
|
29
|
+ * @file
|
|
|
30
|
+ *
|
|
|
31
|
+ * Infiniband Packet Formats
|
|
|
32
|
+ *
|
|
|
33
|
+ */
|
|
|
34
|
+
|
|
|
35
|
+/**
|
|
|
36
|
+ * Add IB headers
|
|
|
37
|
+ *
|
|
|
38
|
+ * @v ibdev Infiniband device
|
|
|
39
|
+ * @v iobuf I/O buffer to contain headers
|
|
|
40
|
+ * @v qp Queue pair
|
|
|
41
|
+ * @v payload_len Payload length
|
|
|
42
|
+ * @v av Address vector
|
|
|
43
|
+ */
|
|
|
44
|
+int ib_push ( struct ib_device *ibdev, struct io_buffer *iobuf,
|
|
|
45
|
+ struct ib_queue_pair *qp, size_t payload_len,
|
|
|
46
|
+ const struct ib_address_vector *av ) {
|
|
|
47
|
+ struct ib_local_route_header *lrh;
|
|
|
48
|
+ struct ib_global_route_header *grh;
|
|
|
49
|
+ struct ib_base_transport_header *bth;
|
|
|
50
|
+ struct ib_datagram_extended_transport_header *deth;
|
|
|
51
|
+ size_t orig_iob_len = iob_len ( iobuf );
|
|
|
52
|
+ size_t pad_len;
|
|
|
53
|
+ size_t lrh_len;
|
|
|
54
|
+ size_t grh_len;
|
|
|
55
|
+ unsigned int vl;
|
|
|
56
|
+ unsigned int lnh;
|
|
|
57
|
+
|
|
|
58
|
+ DBGC2 ( ibdev, "IBDEV %p TX %04x:%08lx => %04x:%08lx (key %08lx)\n",
|
|
|
59
|
+ ibdev, ibdev->lid, qp->qpn, av->lid, av->qpn, av->qkey );
|
|
|
60
|
+
|
|
|
61
|
+ /* Calculate packet length */
|
|
|
62
|
+ pad_len = ( (-payload_len) & 0x3 );
|
|
|
63
|
+ payload_len += pad_len;
|
|
|
64
|
+ payload_len += 4; /* ICRC */
|
|
|
65
|
+
|
|
|
66
|
+ /* Reserve space for headers */
|
|
|
67
|
+ orig_iob_len = iob_len ( iobuf );
|
|
|
68
|
+ deth = iob_push ( iobuf, sizeof ( *deth ) );
|
|
|
69
|
+ bth = iob_push ( iobuf, sizeof ( *bth ) );
|
|
|
70
|
+ grh_len = ( payload_len + iob_len ( iobuf ) - orig_iob_len );
|
|
|
71
|
+ grh = ( av->gid_present ?
|
|
|
72
|
+ iob_push ( iobuf, sizeof ( *grh ) ) : NULL );
|
|
|
73
|
+ lrh = iob_push ( iobuf, sizeof ( *lrh ) );
|
|
|
74
|
+ lrh_len = ( payload_len + iob_len ( iobuf ) - orig_iob_len );
|
|
|
75
|
+
|
|
|
76
|
+ /* Construct LRH */
|
|
|
77
|
+ vl = ( ( av->qpn == IB_QPN_SMP ) ? IB_VL_SMP : IB_VL_DEFAULT );
|
|
|
78
|
+ lrh->vl__lver = ( vl << 4 );
|
|
|
79
|
+ lnh = ( grh ? IB_LNH_GRH : IB_LNH_BTH );
|
|
|
80
|
+ lrh->sl__lnh = ( ( av->sl << 4 ) | lnh );
|
|
|
81
|
+ lrh->dlid = htons ( av->lid );
|
|
|
82
|
+ lrh->length = htons ( lrh_len >> 2 );
|
|
|
83
|
+ lrh->slid = htons ( ibdev->lid );
|
|
|
84
|
+
|
|
|
85
|
+ /* Construct GRH, if required */
|
|
|
86
|
+ if ( grh ) {
|
|
|
87
|
+ grh->ipver__tclass__flowlabel =
|
|
|
88
|
+ htonl ( IB_GRH_IPVER_IPv6 << 28 );
|
|
|
89
|
+ grh->paylen = htons ( grh_len );
|
|
|
90
|
+ grh->nxthdr = IB_GRH_NXTHDR_IBA;
|
|
|
91
|
+ grh->hoplmt = 0;
|
|
|
92
|
+ memcpy ( &grh->sgid, &ibdev->gid, sizeof ( grh->sgid ) );
|
|
|
93
|
+ memcpy ( &grh->dgid, &av->gid, sizeof ( grh->dgid ) );
|
|
|
94
|
+ }
|
|
|
95
|
+
|
|
|
96
|
+ /* Construct BTH */
|
|
|
97
|
+ bth->opcode = BTH_OPCODE_UD_SEND;
|
|
|
98
|
+ bth->se__m__padcnt__tver = ( pad_len << 4 );
|
|
|
99
|
+ bth->pkey = htons ( ibdev->pkey );
|
|
|
100
|
+ bth->dest_qp = htonl ( av->qpn );
|
|
|
101
|
+ bth->ack__psn = htonl ( ( ibdev->psn++ ) & 0xffffffUL );
|
|
|
102
|
+
|
|
|
103
|
+ /* Construct DETH */
|
|
|
104
|
+ deth->qkey = htonl ( av->qkey );
|
|
|
105
|
+ deth->src_qp = htonl ( qp->qpn );
|
|
|
106
|
+
|
|
|
107
|
+ DBGCP_HDA ( ibdev, 0, iobuf->data,
|
|
|
108
|
+ ( iob_len ( iobuf ) - orig_iob_len ) );
|
|
|
109
|
+
|
|
|
110
|
+ return 0;
|
|
|
111
|
+}
|
|
|
112
|
+
|
|
|
113
|
+/**
|
|
|
114
|
+ * Remove IB headers
|
|
|
115
|
+ *
|
|
|
116
|
+ * @v ibdev Infiniband device
|
|
|
117
|
+ * @v iobuf I/O buffer containing headers
|
|
|
118
|
+ * @v qp Queue pair to fill in, or NULL
|
|
|
119
|
+ * @v payload_len Payload length to fill in, or NULL
|
|
|
120
|
+ * @v av Address vector to fill in
|
|
|
121
|
+ */
|
|
|
122
|
+int ib_pull ( struct ib_device *ibdev, struct io_buffer *iobuf,
|
|
|
123
|
+ struct ib_queue_pair **qp, size_t *payload_len,
|
|
|
124
|
+ struct ib_address_vector *av ) {
|
|
|
125
|
+ struct ib_local_route_header *lrh;
|
|
|
126
|
+ struct ib_global_route_header *grh;
|
|
|
127
|
+ struct ib_base_transport_header *bth;
|
|
|
128
|
+ struct ib_datagram_extended_transport_header *deth;
|
|
|
129
|
+ size_t orig_iob_len = iob_len ( iobuf );
|
|
|
130
|
+ unsigned int lnh;
|
|
|
131
|
+ size_t pad_len;
|
|
|
132
|
+ unsigned long qpn;
|
|
|
133
|
+ unsigned int lid;
|
|
|
134
|
+
|
|
|
135
|
+ /* Clear return values */
|
|
|
136
|
+ if ( qp )
|
|
|
137
|
+ *qp = NULL;
|
|
|
138
|
+ if ( payload_len )
|
|
|
139
|
+ *payload_len = 0;
|
|
|
140
|
+ memset ( av, 0, sizeof ( *av ) );
|
|
|
141
|
+
|
|
|
142
|
+ /* Extract LRH */
|
|
|
143
|
+ if ( iob_len ( iobuf ) < sizeof ( *lrh ) ) {
|
|
|
144
|
+ DBGC ( ibdev, "IBDEV %p RX too short (%zd bytes) for LRH\n",
|
|
|
145
|
+ ibdev, iob_len ( iobuf ) );
|
|
|
146
|
+ return -EINVAL;
|
|
|
147
|
+ }
|
|
|
148
|
+ lrh = iobuf->data;
|
|
|
149
|
+ iob_pull ( iobuf, sizeof ( *lrh ) );
|
|
|
150
|
+ av->lid = ntohs ( lrh->slid );
|
|
|
151
|
+ av->sl = ( lrh->sl__lnh >> 4 );
|
|
|
152
|
+ lnh = ( lrh->sl__lnh & 0x3 );
|
|
|
153
|
+ lid = ntohs ( lrh->dlid );
|
|
|
154
|
+
|
|
|
155
|
+ /* Reject unsupported packets */
|
|
|
156
|
+ if ( ! ( ( lnh == IB_LNH_BTH ) || ( lnh == IB_LNH_GRH ) ) ) {
|
|
|
157
|
+ DBGC ( ibdev, "IBDEV %p RX unsupported LNH %x\n",
|
|
|
158
|
+ ibdev, lnh );
|
|
|
159
|
+ return -ENOTSUP;
|
|
|
160
|
+ }
|
|
|
161
|
+
|
|
|
162
|
+ /* Extract GRH, if present */
|
|
|
163
|
+ if ( lnh == IB_LNH_GRH ) {
|
|
|
164
|
+ if ( iob_len ( iobuf ) < sizeof ( *grh ) ) {
|
|
|
165
|
+ DBGC ( ibdev, "IBDEV %p RX too short (%zd bytes) "
|
|
|
166
|
+ "for GRH\n", ibdev, iob_len ( iobuf ) );
|
|
|
167
|
+ return -EINVAL;
|
|
|
168
|
+ }
|
|
|
169
|
+ grh = iobuf->data;
|
|
|
170
|
+ iob_pull ( iobuf, sizeof ( *grh ) );
|
|
|
171
|
+ av->gid_present = 1;
|
|
|
172
|
+ memcpy ( &av->gid, &grh->sgid, sizeof ( av->gid ) );
|
|
|
173
|
+ } else {
|
|
|
174
|
+ grh = NULL;
|
|
|
175
|
+ }
|
|
|
176
|
+
|
|
|
177
|
+ /* Extract BTH */
|
|
|
178
|
+ if ( iob_len ( iobuf ) < sizeof ( *bth ) ) {
|
|
|
179
|
+ DBGC ( ibdev, "IBDEV %p RX too short (%zd bytes) for BTH\n",
|
|
|
180
|
+ ibdev, iob_len ( iobuf ) );
|
|
|
181
|
+ return -EINVAL;
|
|
|
182
|
+ }
|
|
|
183
|
+ bth = iobuf->data;
|
|
|
184
|
+ iob_pull ( iobuf, sizeof ( *bth ) );
|
|
|
185
|
+ if ( bth->opcode != BTH_OPCODE_UD_SEND ) {
|
|
|
186
|
+ DBGC ( ibdev, "IBDEV %p unsupported BTH opcode %x\n",
|
|
|
187
|
+ ibdev, bth->opcode );
|
|
|
188
|
+ return -ENOTSUP;
|
|
|
189
|
+ }
|
|
|
190
|
+ qpn = ntohl ( bth->dest_qp );
|
|
|
191
|
+
|
|
|
192
|
+ /* Extract DETH */
|
|
|
193
|
+ if ( iob_len ( iobuf ) < sizeof ( *deth ) ) {
|
|
|
194
|
+ DBGC ( ibdev, "IBDEV %p RX too short (%zd bytes) for DETH\n",
|
|
|
195
|
+ ibdev, iob_len ( iobuf ) );
|
|
|
196
|
+ return -EINVAL;
|
|
|
197
|
+ }
|
|
|
198
|
+ deth = iobuf->data;
|
|
|
199
|
+ iob_pull ( iobuf, sizeof ( *deth ) );
|
|
|
200
|
+ av->qpn = ntohl ( deth->src_qp );
|
|
|
201
|
+ av->qkey = ntohl ( deth->qkey );
|
|
|
202
|
+
|
|
|
203
|
+ /* Calculate payload length, if applicable */
|
|
|
204
|
+ if ( payload_len ) {
|
|
|
205
|
+ pad_len = ( ( bth->se__m__padcnt__tver >> 4 ) & 0x3 );
|
|
|
206
|
+ *payload_len = ( ( ntohs ( lrh->length ) << 2 )
|
|
|
207
|
+ - ( orig_iob_len - iob_len ( iobuf ) )
|
|
|
208
|
+ - pad_len - 4 /* ICRC */ );
|
|
|
209
|
+ }
|
|
|
210
|
+
|
|
|
211
|
+ /* Determine destination QP, if applicable */
|
|
|
212
|
+ if ( qp ) {
|
|
|
213
|
+ if ( IB_LID_MULTICAST ( lid ) && grh ) {
|
|
|
214
|
+ *qp = ib_find_qp_mgid ( ibdev, &grh->dgid );
|
|
|
215
|
+ } else {
|
|
|
216
|
+ *qp = ib_find_qp_qpn ( ibdev, qpn );
|
|
|
217
|
+ }
|
|
|
218
|
+ if ( ! *qp ) {
|
|
|
219
|
+ DBGC ( ibdev, "IBDEV %p RX for nonexistent QP\n",
|
|
|
220
|
+ ibdev );
|
|
|
221
|
+ return -ENODEV;
|
|
|
222
|
+ }
|
|
|
223
|
+ }
|
|
|
224
|
+
|
|
|
225
|
+ DBGC2 ( ibdev, "IBDEV %p RX %04x:%08lx <= %04x:%08lx (key %08lx)\n",
|
|
|
226
|
+ ibdev, lid,
|
|
|
227
|
+ ( IB_LID_MULTICAST( lid ) ? ( qp ? (*qp)->qpn : -1UL ) : qpn ),
|
|
|
228
|
+ av->lid, av->qpn, ntohl ( deth->qkey ) );
|
|
|
229
|
+ DBGCP_HDA ( ibdev, 0,
|
|
|
230
|
+ ( iobuf->data - ( orig_iob_len - iob_len ( iobuf ) ) ),
|
|
|
231
|
+ ( orig_iob_len - iob_len ( iobuf ) ) );
|
|
|
232
|
+
|
|
|
233
|
+ return 0;
|
|
|
234
|
+}
|