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