Annotation of qemu/roms/ipxe/src/net/infiniband/ib_mi.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (C) 2009 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 <stdio.h>
                     26: #include <unistd.h>
                     27: #include <byteswap.h>
                     28: #include <ipxe/infiniband.h>
                     29: #include <ipxe/iobuf.h>
                     30: #include <ipxe/ib_mi.h>
                     31: 
                     32: /**
                     33:  * @file
                     34:  *
                     35:  * Infiniband management interfaces
                     36:  *
                     37:  */
                     38: 
                     39: /** Management interface number of send WQEs
                     40:  *
                     41:  * This is a policy decision.
                     42:  */
                     43: #define IB_MI_NUM_SEND_WQES 4
                     44: 
                     45: /** Management interface number of receive WQEs
                     46:  *
                     47:  * This is a policy decision.
                     48:  */
                     49: #define IB_MI_NUM_RECV_WQES 2
                     50: 
                     51: /** Management interface number of completion queue entries
                     52:  *
                     53:  * This is a policy decision
                     54:  */
                     55: #define IB_MI_NUM_CQES 8
                     56: 
                     57: /** TID magic signature */
                     58: #define IB_MI_TID_MAGIC ( ( 'i' << 24 ) | ( 'P' << 16 ) | ( 'X' << 8 ) | 'E' )
                     59: 
                     60: /** TID to use for next MAD */
                     61: static unsigned int next_tid;
                     62: 
                     63: /**
                     64:  * Handle received MAD
                     65:  *
                     66:  * @v ibdev            Infiniband device
                     67:  * @v mi               Management interface
                     68:  * @v mad              Received MAD
                     69:  * @v av               Source address vector
                     70:  * @ret rc             Return status code
                     71:  */
                     72: static int ib_mi_handle ( struct ib_device *ibdev,
                     73:                          struct ib_mad_interface *mi,
                     74:                          union ib_mad *mad,
                     75:                          struct ib_address_vector *av ) {
                     76:        struct ib_mad_hdr *hdr = &mad->hdr;
                     77:        struct ib_mad_transaction *madx;
                     78:        struct ib_mad_agent *agent;
                     79: 
                     80:        /* Look for a matching transaction by TID */
                     81:        list_for_each_entry ( madx, &mi->madx, list ) {
                     82:                if ( memcmp ( &hdr->tid, &madx->mad.hdr.tid,
                     83:                              sizeof ( hdr->tid ) ) != 0 )
                     84:                        continue;
                     85:                /* Found a matching transaction */
                     86:                madx->op->complete ( ibdev, mi, madx, 0, mad, av );
                     87:                return 0;
                     88:        }
                     89: 
                     90:        /* If there is no matching transaction, look for a listening agent */
                     91:        for_each_table_entry ( agent, IB_MAD_AGENTS ) {
                     92:                if ( ( ( agent->mgmt_class & IB_MGMT_CLASS_MASK ) !=
                     93:                       ( hdr->mgmt_class & IB_MGMT_CLASS_MASK ) ) ||
                     94:                     ( agent->class_version != hdr->class_version ) ||
                     95:                     ( agent->attr_id != hdr->attr_id ) )
                     96:                        continue;
                     97:                /* Found a matching agent */
                     98:                agent->handle ( ibdev, mi, mad, av );
                     99:                return 0;
                    100:        }
                    101: 
                    102:        /* Otherwise, ignore it */
                    103:        DBGC ( mi, "MI %p RX TID %08x%08x ignored\n",
                    104:               mi, ntohl ( hdr->tid[0] ), ntohl ( hdr->tid[1] ) );
                    105:        return -ENOTSUP;
                    106: }
                    107: 
                    108: /**
                    109:  * Complete receive via management interface
                    110:  *
                    111:  *
                    112:  * @v ibdev            Infiniband device
                    113:  * @v qp               Queue pair
                    114:  * @v av               Address vector
                    115:  * @v iobuf            I/O buffer
                    116:  * @v rc               Completion status code
                    117:  */
                    118: static void ib_mi_complete_recv ( struct ib_device *ibdev,
                    119:                                  struct ib_queue_pair *qp,
                    120:                                  struct ib_address_vector *av,
                    121:                                  struct io_buffer *iobuf, int rc ) {
                    122:        struct ib_mad_interface *mi = ib_qp_get_ownerdata ( qp );
                    123:        union ib_mad *mad;
                    124:        struct ib_mad_hdr *hdr;
                    125: 
                    126:        /* Ignore errors */
                    127:        if ( rc != 0 ) {
                    128:                DBGC ( mi, "MI %p RX error: %s\n", mi, strerror ( rc ) );
                    129:                goto out;
                    130:        }
                    131: 
                    132:        /* Sanity checks */
                    133:        if ( iob_len ( iobuf ) != sizeof ( *mad ) ) {
                    134:                DBGC ( mi, "MI %p RX bad size (%zd bytes)\n",
                    135:                       mi, iob_len ( iobuf ) );
                    136:                DBGC_HDA ( mi, 0, iobuf->data, iob_len ( iobuf ) );
                    137:                goto out;
                    138:        }
                    139:        mad = iobuf->data;
                    140:        hdr = &mad->hdr;
                    141:        if ( hdr->base_version != IB_MGMT_BASE_VERSION ) {
                    142:                DBGC ( mi, "MI %p RX unsupported base version %x\n",
                    143:                       mi, hdr->base_version );
                    144:                DBGC_HDA ( mi, 0, mad, sizeof ( *mad ) );
                    145:                goto out;
                    146:        }
                    147:        DBGC ( mi, "MI %p RX TID %08x%08x (%02x,%02x,%02x,%04x) status "
                    148:               "%04x\n", mi, ntohl ( hdr->tid[0] ), ntohl ( hdr->tid[1] ),
                    149:               hdr->mgmt_class, hdr->class_version, hdr->method,
                    150:               ntohs ( hdr->attr_id ), ntohs ( hdr->status ) );
                    151:        DBGC2_HDA ( mi, 0, mad, sizeof ( *mad ) );
                    152: 
                    153:        /* Handle MAD */
                    154:        if ( ( rc = ib_mi_handle ( ibdev, mi, mad, av ) ) != 0 )
                    155:                goto out;
                    156: 
                    157:  out:
                    158:        free_iob ( iobuf );
                    159: }
                    160: 
                    161: /** Management interface completion operations */
                    162: static struct ib_completion_queue_operations ib_mi_completion_ops = {
                    163:        .complete_recv = ib_mi_complete_recv,
                    164: };
                    165: 
                    166: /**
                    167:  * Transmit MAD
                    168:  *
                    169:  * @v ibdev            Infiniband device
                    170:  * @v mi               Management interface
                    171:  * @v mad              MAD
                    172:  * @v av               Destination address vector
                    173:  * @ret rc             Return status code
                    174:  */
                    175: int ib_mi_send ( struct ib_device *ibdev, struct ib_mad_interface *mi,
                    176:                 union ib_mad *mad, struct ib_address_vector *av ) {
                    177:        struct ib_mad_hdr *hdr = &mad->hdr;
                    178:        struct io_buffer *iobuf;
                    179:        int rc;
                    180: 
                    181:        /* Set common fields */
                    182:        hdr->base_version = IB_MGMT_BASE_VERSION;
                    183:        if ( ( hdr->tid[0] == 0 ) && ( hdr->tid[1] == 0 ) ) {
                    184:                hdr->tid[0] = htonl ( IB_MI_TID_MAGIC );
                    185:                hdr->tid[1] = htonl ( ++next_tid );
                    186:        }
                    187:        DBGC ( mi, "MI %p TX TID %08x%08x (%02x,%02x,%02x,%04x) status "
                    188:               "%04x\n", mi, ntohl ( hdr->tid[0] ), ntohl ( hdr->tid[1] ),
                    189:               hdr->mgmt_class, hdr->class_version, hdr->method,
                    190:               ntohs ( hdr->attr_id ), ntohs ( hdr->status ) );
                    191:        DBGC2_HDA ( mi, 0, mad, sizeof ( *mad ) );
                    192: 
                    193:        /* Construct directed route portion of response, if necessary */
                    194:        if ( hdr->mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE ) {
                    195:                struct ib_mad_smp *smp = &mad->smp;
                    196:                unsigned int hop_pointer;
                    197:                unsigned int hop_count;
                    198: 
                    199:                smp->mad_hdr.status |= htons ( IB_SMP_STATUS_D_INBOUND );
                    200:                hop_pointer = smp->mad_hdr.class_specific.smp.hop_pointer;
                    201:                hop_count = smp->mad_hdr.class_specific.smp.hop_count;
                    202:                assert ( hop_count == hop_pointer );
                    203:                if ( hop_pointer < ( sizeof ( smp->return_path.hops ) /
                    204:                                     sizeof ( smp->return_path.hops[0] ) ) ) {
                    205:                        smp->return_path.hops[hop_pointer] = ibdev->port;
                    206:                } else {
                    207:                        DBGC ( mi, "MI %p TX TID %08x%08x invalid hop pointer "
                    208:                               "%d\n", mi, ntohl ( hdr->tid[0] ),
                    209:                               ntohl ( hdr->tid[1] ), hop_pointer );
                    210:                        return -EINVAL;
                    211:                }
                    212:        }
                    213: 
                    214:        /* Construct I/O buffer */
                    215:        iobuf = alloc_iob ( sizeof ( *mad ) );
                    216:        if ( ! iobuf ) {
                    217:                DBGC ( mi, "MI %p could not allocate buffer for TID "
                    218:                       "%08x%08x\n",
                    219:                       mi, ntohl ( hdr->tid[0] ), ntohl ( hdr->tid[1] ) );
                    220:                return -ENOMEM;
                    221:        }
                    222:        memcpy ( iob_put ( iobuf, sizeof ( *mad ) ), mad, sizeof ( *mad ) );
                    223: 
                    224:        /* Send I/O buffer */
                    225:        if ( ( rc = ib_post_send ( ibdev, mi->qp, av, iobuf ) ) != 0 ) {
                    226:                DBGC ( mi, "MI %p TX TID %08x%08x failed: %s\n",
                    227:                       mi,  ntohl ( hdr->tid[0] ), ntohl ( hdr->tid[1] ),
                    228:                       strerror ( rc ) );
                    229:                free_iob ( iobuf );
                    230:                return rc;
                    231:        }
                    232: 
                    233:        return 0;
                    234: }
                    235: 
                    236: /**
                    237:  * Handle management transaction timer expiry
                    238:  *
                    239:  * @v timer            Retry timer
                    240:  * @v expired          Failure indicator
                    241:  */
                    242: static void ib_mi_timer_expired ( struct retry_timer *timer, int expired ) {
                    243:        struct ib_mad_transaction *madx =
                    244:                container_of ( timer, struct ib_mad_transaction, timer );
                    245:        struct ib_mad_interface *mi = madx->mi;
                    246:        struct ib_device *ibdev = mi->ibdev;
                    247:        struct ib_mad_hdr *hdr = &madx->mad.hdr;
                    248: 
                    249:        /* Abandon transaction if we have tried too many times */
                    250:        if ( expired ) {
                    251:                DBGC ( mi, "MI %p abandoning TID %08x%08x\n",
                    252:                       mi, ntohl ( hdr->tid[0] ), ntohl ( hdr->tid[1] ) );
                    253:                madx->op->complete ( ibdev, mi, madx, -ETIMEDOUT, NULL, NULL );
                    254:                return;
                    255:        }
                    256: 
                    257:        /* Restart retransmission timer */
                    258:        start_timer ( timer );
                    259: 
                    260:        /* Resend MAD */
                    261:        ib_mi_send ( ibdev, mi, &madx->mad, &madx->av );
                    262: }
                    263: 
                    264: /**
                    265:  * Create management transaction
                    266:  *
                    267:  * @v ibdev            Infiniband device
                    268:  * @v mi               Management interface
                    269:  * @v mad              MAD to send
                    270:  * @v av               Destination address, or NULL to use SM's GSI
                    271:  * @v op               Management transaction operations
                    272:  * @ret madx           Management transaction, or NULL
                    273:  */
                    274: struct ib_mad_transaction *
                    275: ib_create_madx ( struct ib_device *ibdev, struct ib_mad_interface *mi,
                    276:                 union ib_mad *mad, struct ib_address_vector *av,
                    277:                 struct ib_mad_transaction_operations *op ) {
                    278:        struct ib_mad_transaction *madx;
                    279: 
                    280:        /* Allocate and initialise structure */
                    281:        madx = zalloc ( sizeof ( *madx ) );
                    282:        if ( ! madx )
                    283:                return NULL;
                    284:        timer_init ( &madx->timer, ib_mi_timer_expired, NULL );
                    285:        madx->mi = mi;
                    286:        madx->op = op;
                    287: 
                    288:        /* Determine address vector */
                    289:        if ( av ) {
                    290:                memcpy ( &madx->av, av, sizeof ( madx->av ) );
                    291:        } else {
                    292:                madx->av.lid = ibdev->sm_lid;
                    293:                madx->av.sl = ibdev->sm_sl;
                    294:                madx->av.qpn = IB_QPN_GSI;
                    295:                madx->av.qkey = IB_QKEY_GSI;
                    296:        }
                    297: 
                    298:        /* Copy MAD */
                    299:        memcpy ( &madx->mad, mad, sizeof ( madx->mad ) );
                    300: 
                    301:        /* Add to list and start timer to send initial MAD */
                    302:        list_add ( &madx->list, &mi->madx );
                    303:        start_timer_nodelay ( &madx->timer );
                    304: 
                    305:        return madx;
                    306: }
                    307: 
                    308: /**
                    309:  * Destroy management transaction
                    310:  *
                    311:  * @v ibdev            Infiniband device
                    312:  * @v mi               Management interface
                    313:  * @v madx             Management transaction
                    314:  */
                    315: void ib_destroy_madx ( struct ib_device *ibdev __unused,
                    316:                       struct ib_mad_interface *mi __unused,
                    317:                       struct ib_mad_transaction *madx ) {
                    318: 
                    319:        /* Stop timer and remove from list */
                    320:        stop_timer ( &madx->timer );
                    321:        list_del ( &madx->list );
                    322: 
                    323:        /* Free transaction */
                    324:        free ( madx );
                    325: }
                    326: 
                    327: /**
                    328:  * Create management interface
                    329:  *
                    330:  * @v ibdev            Infiniband device
                    331:  * @v type             Queue pair type
                    332:  * @ret mi             Management agent, or NULL
                    333:  */
                    334: struct ib_mad_interface * ib_create_mi ( struct ib_device *ibdev,
                    335:                                         enum ib_queue_pair_type type ) {
                    336:        struct ib_mad_interface *mi;
                    337:        int rc;
                    338: 
                    339:        /* Allocate and initialise fields */
                    340:        mi = zalloc ( sizeof ( *mi ) );
                    341:        if ( ! mi )
                    342:                goto err_alloc;
                    343:        mi->ibdev = ibdev;
                    344:        INIT_LIST_HEAD ( &mi->madx );
                    345: 
                    346:        /* Create completion queue */
                    347:        mi->cq = ib_create_cq ( ibdev, IB_MI_NUM_CQES, &ib_mi_completion_ops );
                    348:        if ( ! mi->cq ) {
                    349:                DBGC ( mi, "MI %p could not allocate completion queue\n", mi );
                    350:                goto err_create_cq;
                    351:        }
                    352: 
                    353:        /* Create queue pair */
                    354:        mi->qp = ib_create_qp ( ibdev, type, IB_MI_NUM_SEND_WQES, mi->cq,
                    355:                                IB_MI_NUM_RECV_WQES, mi->cq );
                    356:        if ( ! mi->qp ) {
                    357:                DBGC ( mi, "MI %p could not allocate queue pair\n", mi );
                    358:                goto err_create_qp;
                    359:        }
                    360:        ib_qp_set_ownerdata ( mi->qp, mi );
                    361:        DBGC ( mi, "MI %p (%s) running on QPN %#lx\n",
                    362:               mi, ( ( type == IB_QPT_SMI ) ? "SMI" : "GSI" ), mi->qp->qpn );
                    363: 
                    364:        /* Set queue key */
                    365:        mi->qp->qkey = ( ( type == IB_QPT_SMI ) ? IB_QKEY_SMI : IB_QKEY_GSI );
                    366:        if ( ( rc = ib_modify_qp ( ibdev, mi->qp ) ) != 0 ) {
                    367:                DBGC ( mi, "MI %p could not set queue key: %s\n",
                    368:                       mi, strerror ( rc ) );
                    369:                goto err_modify_qp;
                    370:        }
                    371: 
                    372:        /* Fill receive ring */
                    373:        ib_refill_recv ( ibdev, mi->qp );
                    374:        return mi;
                    375: 
                    376:  err_modify_qp:
                    377:        ib_destroy_qp ( ibdev, mi->qp );
                    378:  err_create_qp:
                    379:        ib_destroy_cq ( ibdev, mi->cq );
                    380:  err_create_cq:
                    381:        free ( mi );
                    382:  err_alloc:
                    383:        return NULL;
                    384: }
                    385: 
                    386: /**
                    387:  * Destroy management interface
                    388:  *
                    389:  * @v mi               Management interface
                    390:  */
                    391: void ib_destroy_mi ( struct ib_device *ibdev, struct ib_mad_interface *mi ) {
                    392:        struct ib_mad_transaction *madx;
                    393:        struct ib_mad_transaction *tmp;
                    394: 
                    395:        /* Flush any outstanding requests */
                    396:        list_for_each_entry_safe ( madx, tmp, &mi->madx, list ) {
                    397:                DBGC ( mi, "MI %p destroyed while TID %08x%08x in progress\n",
                    398:                       mi, ntohl ( madx->mad.hdr.tid[0] ),
                    399:                       ntohl ( madx->mad.hdr.tid[1] ) );
                    400:                madx->op->complete ( ibdev, mi, madx, -ECANCELED, NULL, NULL );
                    401:        }
                    402: 
                    403:        ib_destroy_qp ( ibdev, mi->qp );
                    404:        ib_destroy_cq ( ibdev, mi->cq );
                    405:        free ( mi );
                    406: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.