00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 FILE_LICENCE ( GPL2_OR_LATER );
00020
00021 #include <stdint.h>
00022 #include <stdlib.h>
00023 #include <string.h>
00024 #include <errno.h>
00025 #include <byteswap.h>
00026 #include <gpxe/iobuf.h>
00027 #include <gpxe/infiniband.h>
00028 #include <gpxe/ib_packet.h>
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046 int ib_push ( struct ib_device *ibdev, struct io_buffer *iobuf,
00047 struct ib_queue_pair *qp, size_t payload_len,
00048 const struct ib_address_vector *av ) {
00049 struct ib_local_route_header *lrh;
00050 struct ib_global_route_header *grh;
00051 struct ib_base_transport_header *bth;
00052 struct ib_datagram_extended_transport_header *deth;
00053 size_t orig_iob_len = iob_len ( iobuf );
00054 size_t pad_len;
00055 size_t lrh_len;
00056 size_t grh_len;
00057 unsigned int vl;
00058 unsigned int lnh;
00059
00060 DBGC2 ( ibdev, "IBDEV %p TX %04x:%08lx => %04x:%08lx (key %08lx)\n",
00061 ibdev, ibdev->lid, qp->ext_qpn, av->lid, av->qpn, av->qkey );
00062
00063
00064 pad_len = ( (-payload_len) & 0x3 );
00065 payload_len += pad_len;
00066 payload_len += 4;
00067
00068
00069 orig_iob_len = iob_len ( iobuf );
00070 deth = iob_push ( iobuf, sizeof ( *deth ) );
00071 bth = iob_push ( iobuf, sizeof ( *bth ) );
00072 grh_len = ( payload_len + iob_len ( iobuf ) - orig_iob_len );
00073 grh = ( av->gid_present ?
00074 iob_push ( iobuf, sizeof ( *grh ) ) : NULL );
00075 lrh = iob_push ( iobuf, sizeof ( *lrh ) );
00076 lrh_len = ( payload_len + iob_len ( iobuf ) - orig_iob_len );
00077
00078
00079 vl = ( ( qp->ext_qpn == IB_QPN_SMI ) ? IB_VL_SMP : IB_VL_DEFAULT );
00080 lrh->vl__lver = ( vl << 4 );
00081 lnh = ( grh ? IB_LNH_GRH : IB_LNH_BTH );
00082 lrh->sl__lnh = ( ( av->sl << 4 ) | lnh );
00083 lrh->dlid = htons ( av->lid );
00084 lrh->length = htons ( lrh_len >> 2 );
00085 lrh->slid = htons ( ibdev->lid );
00086
00087
00088 if ( grh ) {
00089 grh->ipver__tclass__flowlabel =
00090 htonl ( IB_GRH_IPVER_IPv6 << 28 );
00091 grh->paylen = htons ( grh_len );
00092 grh->nxthdr = IB_GRH_NXTHDR_IBA;
00093 grh->hoplmt = 0;
00094 memcpy ( &grh->sgid, &ibdev->gid, sizeof ( grh->sgid ) );
00095 memcpy ( &grh->dgid, &av->gid, sizeof ( grh->dgid ) );
00096 }
00097
00098
00099 bth->opcode = BTH_OPCODE_UD_SEND;
00100 bth->se__m__padcnt__tver = ( pad_len << 4 );
00101 bth->pkey = htons ( ibdev->pkey );
00102 bth->dest_qp = htonl ( av->qpn );
00103 bth->ack__psn = htonl ( ( qp->send.psn++ ) & 0xffffffUL );
00104
00105
00106 deth->qkey = htonl ( av->qkey );
00107 deth->src_qp = htonl ( qp->ext_qpn );
00108
00109 DBGCP_HDA ( ibdev, 0, iobuf->data,
00110 ( iob_len ( iobuf ) - orig_iob_len ) );
00111
00112 return 0;
00113 }
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124 int ib_pull ( struct ib_device *ibdev, struct io_buffer *iobuf,
00125 struct ib_queue_pair **qp, size_t *payload_len,
00126 struct ib_address_vector *av ) {
00127 struct ib_local_route_header *lrh;
00128 struct ib_global_route_header *grh;
00129 struct ib_base_transport_header *bth;
00130 struct ib_datagram_extended_transport_header *deth;
00131 size_t orig_iob_len = iob_len ( iobuf );
00132 unsigned int lnh;
00133 size_t pad_len;
00134 unsigned long qpn;
00135 unsigned int lid;
00136
00137
00138 if ( qp )
00139 *qp = NULL;
00140 if ( payload_len )
00141 *payload_len = 0;
00142 memset ( av, 0, sizeof ( *av ) );
00143
00144
00145 if ( iob_len ( iobuf ) < sizeof ( *lrh ) ) {
00146 DBGC ( ibdev, "IBDEV %p RX too short (%zd bytes) for LRH\n",
00147 ibdev, iob_len ( iobuf ) );
00148 return -EINVAL;
00149 }
00150 lrh = iobuf->data;
00151 iob_pull ( iobuf, sizeof ( *lrh ) );
00152 av->lid = ntohs ( lrh->slid );
00153 av->sl = ( lrh->sl__lnh >> 4 );
00154 lnh = ( lrh->sl__lnh & 0x3 );
00155 lid = ntohs ( lrh->dlid );
00156
00157
00158 if ( ! ( ( lnh == IB_LNH_BTH ) || ( lnh == IB_LNH_GRH ) ) ) {
00159 DBGC ( ibdev, "IBDEV %p RX unsupported LNH %x\n",
00160 ibdev, lnh );
00161 return -ENOTSUP;
00162 }
00163
00164
00165 if ( lnh == IB_LNH_GRH ) {
00166 if ( iob_len ( iobuf ) < sizeof ( *grh ) ) {
00167 DBGC ( ibdev, "IBDEV %p RX too short (%zd bytes) "
00168 "for GRH\n", ibdev, iob_len ( iobuf ) );
00169 return -EINVAL;
00170 }
00171 grh = iobuf->data;
00172 iob_pull ( iobuf, sizeof ( *grh ) );
00173 av->gid_present = 1;
00174 memcpy ( &av->gid, &grh->sgid, sizeof ( av->gid ) );
00175 } else {
00176 grh = NULL;
00177 }
00178
00179
00180 if ( iob_len ( iobuf ) < sizeof ( *bth ) ) {
00181 DBGC ( ibdev, "IBDEV %p RX too short (%zd bytes) for BTH\n",
00182 ibdev, iob_len ( iobuf ) );
00183 return -EINVAL;
00184 }
00185 bth = iobuf->data;
00186 iob_pull ( iobuf, sizeof ( *bth ) );
00187 if ( bth->opcode != BTH_OPCODE_UD_SEND ) {
00188 DBGC ( ibdev, "IBDEV %p unsupported BTH opcode %x\n",
00189 ibdev, bth->opcode );
00190 return -ENOTSUP;
00191 }
00192 qpn = ntohl ( bth->dest_qp );
00193
00194
00195 if ( iob_len ( iobuf ) < sizeof ( *deth ) ) {
00196 DBGC ( ibdev, "IBDEV %p RX too short (%zd bytes) for DETH\n",
00197 ibdev, iob_len ( iobuf ) );
00198 return -EINVAL;
00199 }
00200 deth = iobuf->data;
00201 iob_pull ( iobuf, sizeof ( *deth ) );
00202 av->qpn = ntohl ( deth->src_qp );
00203 av->qkey = ntohl ( deth->qkey );
00204
00205
00206 if ( payload_len ) {
00207 pad_len = ( ( bth->se__m__padcnt__tver >> 4 ) & 0x3 );
00208 *payload_len = ( ( ntohs ( lrh->length ) << 2 )
00209 - ( orig_iob_len - iob_len ( iobuf ) )
00210 - pad_len - 4 );
00211 }
00212
00213
00214 if ( qp ) {
00215 if ( IB_LID_MULTICAST ( lid ) && grh ) {
00216 if ( ! ( *qp = ib_find_qp_mgid ( ibdev, &grh->dgid ))){
00217 DBGC ( ibdev, "IBDEV %p RX for unknown MGID "
00218 "%08x:%08x:%08x:%08x\n", ibdev,
00219 ntohl ( grh->dgid.u.dwords[0] ),
00220 ntohl ( grh->dgid.u.dwords[1] ),
00221 ntohl ( grh->dgid.u.dwords[2] ),
00222 ntohl ( grh->dgid.u.dwords[3] ) );
00223 return -ENODEV;
00224 }
00225 } else {
00226 if ( ! ( *qp = ib_find_qp_qpn ( ibdev, qpn ) ) ) {
00227 DBGC ( ibdev, "IBDEV %p RX for nonexistent "
00228 "QPN %lx\n", ibdev, qpn );
00229 return -ENODEV;
00230 }
00231 }
00232 assert ( *qp );
00233 }
00234
00235 DBGC2 ( ibdev, "IBDEV %p RX %04x:%08lx <= %04x:%08lx (key %08x)\n",
00236 ibdev, lid, ( IB_LID_MULTICAST( lid ) ?
00237 ( qp ? (*qp)->ext_qpn : -1UL ) : qpn ),
00238 av->lid, av->qpn, ntohl ( deth->qkey ) );
00239 DBGCP_HDA ( ibdev, 0,
00240 ( iobuf->data - ( orig_iob_len - iob_len ( iobuf ) ) ),
00241 ( orig_iob_len - iob_len ( iobuf ) ) );
00242
00243 return 0;
00244 }