iPXE
xsigo.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2016 Michael Brown <mbrown@fensystems.co.uk>.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License as
00006  * published by the Free Software Foundation; either version 2 of the
00007  * License, or any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00017  * 02110-1301, USA.
00018  *
00019  * You can also choose to distribute this program under the terms of
00020  * the Unmodified Binary Distribution Licence (as given in the file
00021  * COPYING.UBDL), provided that you have satisfied its requirements.
00022  */
00023 
00024 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
00025 
00026 #include <string.h>
00027 #include <stdio.h>
00028 #include <errno.h>
00029 #include <byteswap.h>
00030 #include <ipxe/version.h>
00031 #include <ipxe/timer.h>
00032 #include <ipxe/malloc.h>
00033 #include <ipxe/iobuf.h>
00034 #include <ipxe/retry.h>
00035 #include <ipxe/process.h>
00036 #include <ipxe/settings.h>
00037 #include <ipxe/infiniband.h>
00038 #include <ipxe/ib_service.h>
00039 #include <ipxe/ib_cmrc.h>
00040 #include <ipxe/if_ether.h>
00041 #include <ipxe/ethernet.h>
00042 #include <ipxe/eoib.h>
00043 #include <ipxe/xsigo.h>
00044 
00045 /** @file
00046  *
00047  * Xsigo virtual Ethernet devices
00048  *
00049  */
00050 
00051 /** A Xsigo device */
00052 struct xsigo_device {
00053         /** Reference count */
00054         struct refcnt refcnt;
00055         /** Underlying Infiniband device */
00056         struct ib_device *ibdev;
00057         /** List of Xsigo devices */
00058         struct list_head list;
00059         /** Device name */
00060         const char *name;
00061 
00062         /** Link opener timer */
00063         struct retry_timer opener;
00064 
00065         /** Discovery timer */
00066         struct retry_timer discovery;
00067         /** Discovery management transaction (if any) */
00068         struct ib_mad_transaction *madx;
00069 
00070         /** List of configuration managers */
00071         struct list_head managers;
00072 };
00073 
00074 /** A Xsigo configuration manager */
00075 struct xsigo_manager {
00076         /** Reference count */
00077         struct refcnt refcnt;
00078         /** Xsigo device */
00079         struct xsigo_device *xdev;
00080         /** List of managers */
00081         struct list_head list;
00082         /** Device name */
00083         char name[16];
00084         /** Manager ID */
00085         struct xsigo_manager_id id;
00086 
00087         /** Data transfer interface */
00088         struct interface xfer;
00089         /** Connection timer */
00090         struct retry_timer reopen;
00091         /** Keepalive timer */
00092         struct retry_timer keepalive;
00093         /** Transmission process */
00094         struct process process;
00095         /** Pending transmissions */
00096         unsigned int pending;
00097         /** Transmit sequence number */
00098         uint32_t seq;
00099 
00100         /** List of virtual Ethernet devices */
00101         struct list_head nics;
00102 };
00103 
00104 /** Configuration manager pending transmissions */
00105 enum xsigo_manager_pending {
00106         /** Send connection request */
00107         XCM_TX_CONNECT = 0x0001,
00108         /** Send registration message */
00109         XCM_TX_REGISTER = 0x0002,
00110 };
00111 
00112 /** A Xsigo virtual Ethernet device */
00113 struct xsigo_nic {
00114         /** Configuration manager */
00115         struct xsigo_manager *xcm;
00116         /** List of virtual Ethernet devices */
00117         struct list_head list;
00118         /** Device name */
00119         char name[16];
00120 
00121         /** Resource identifier */
00122         union ib_guid resource;
00123         /** MAC address */
00124         uint8_t mac[ETH_ALEN];
00125         /** Network ID */
00126         unsigned long network;
00127 };
00128 
00129 /** Configuration manager service ID */
00130 static union ib_guid xcm_service_id = {
00131         .bytes = XCM_SERVICE_ID,
00132 };
00133 
00134 /** List of all Xsigo devices */
00135 static LIST_HEAD ( xsigo_devices );
00136 
00137 /**
00138  * Free Xsigo device
00139  *
00140  * @v refcnt            Reference count
00141  */
00142 static void xsigo_free ( struct refcnt *refcnt ) {
00143         struct xsigo_device *xdev =
00144                 container_of ( refcnt, struct xsigo_device, refcnt );
00145 
00146         /* Sanity checks */
00147         assert ( ! timer_running ( &xdev->opener ) );
00148         assert ( ! timer_running ( &xdev->discovery ) );
00149         assert ( xdev->madx == NULL );
00150         assert ( list_empty ( &xdev->managers ) );
00151 
00152         /* Drop reference to Infiniband device */
00153         ibdev_put ( xdev->ibdev );
00154 
00155         /* Free device */
00156         free ( xdev );
00157 }
00158 
00159 /**
00160  * Free configuration manager
00161  *
00162  * @v refcnt            Reference count
00163  */
00164 static void xcm_free ( struct refcnt *refcnt ) {
00165         struct xsigo_manager *xcm =
00166                 container_of ( refcnt, struct xsigo_manager, refcnt );
00167 
00168         /* Sanity checks */
00169         assert ( ! timer_running ( &xcm->reopen ) );
00170         assert ( ! timer_running ( &xcm->keepalive ) );
00171         assert ( ! process_running ( &xcm->process ) );
00172         assert ( list_empty ( &xcm->nics ) );
00173 
00174         /* Drop reference to Xsigo device */
00175         ref_put ( &xcm->xdev->refcnt );
00176 
00177         /* Free manager */
00178         free ( xcm );
00179 }
00180 
00181 /****************************************************************************
00182  *
00183  * Virtual Ethernet (XVE) devices
00184  *
00185  ****************************************************************************
00186  */
00187 
00188 /**
00189  * Create virtual Ethernet device
00190  *
00191  * @v xcm               Configuration manager
00192  * @v resource          Resource identifier
00193  * @v mac               Ethernet MAC
00194  * @v network           Network identifier
00195  * @v name              Device name
00196  * @ret rc              Return status code
00197  */
00198 static int xve_create ( struct xsigo_manager *xcm, union ib_guid *resource,
00199                         const uint8_t *mac, unsigned long network,
00200                         unsigned long qkey, const char *name ) {
00201         struct xsigo_device *xdev = xcm->xdev;
00202         struct ib_device *ibdev = xdev->ibdev;
00203         struct xsigo_nic *xve;
00204         struct ib_address_vector broadcast;
00205         int rc;
00206 
00207         /* Allocate and initialise structure */
00208         xve = zalloc ( sizeof ( *xve ) );
00209         if ( ! xve ) {
00210                 rc = -ENOMEM;
00211                 goto err_alloc;
00212         }
00213         xve->xcm = xcm;
00214         snprintf ( xve->name, sizeof ( xve->name ), "%s", name );
00215         memcpy ( &xve->resource, resource, sizeof ( xve->resource ) );
00216         memcpy ( xve->mac, mac, ETH_ALEN );
00217         xve->network = network;
00218         DBGC ( xve, "XVE %s created for %s " IB_GUID_FMT "\n",
00219                xve->name, xcm->name, IB_GUID_ARGS ( resource ) );
00220         DBGC ( xve, "XVE %s is MAC %s on network %ld\n",
00221                xve->name, eth_ntoa ( mac ), network );
00222 
00223         /* Construct broadcast address vector */
00224         memset ( &broadcast, 0, sizeof ( broadcast ) );
00225         broadcast.qpn = IB_QPN_BROADCAST;
00226         broadcast.qkey = qkey;
00227         broadcast.gid_present = 1;
00228         broadcast.gid.dwords[0] = htonl ( XVE_PREFIX );
00229         broadcast.gid.words[2] = htons ( ibdev->pkey );
00230         broadcast.gid.dwords[3] = htonl ( network );
00231 
00232         /* Create EoIB device */
00233         if ( ( rc = eoib_create ( ibdev, xve->mac, &broadcast,
00234                                   xve->name ) ) != 0 ) {
00235                 DBGC ( xve, "XVE %s could not create EoIB device: %s\n",
00236                        xve->name, strerror ( rc ) );
00237                 goto err_create;
00238         }
00239 
00240         /* Add to list of virtual Ethernet devices.  Do this only
00241          * after creating the EoIB device, so that our net device
00242          * notifier won't attempt to send an operational state update
00243          * before we have acknowledged the installation.
00244          */
00245         list_add ( &xve->list, &xcm->nics );
00246 
00247         return 0;
00248 
00249         list_del ( &xve->list );
00250  err_create:
00251         free ( xve );
00252  err_alloc:
00253         return rc;
00254 }
00255 
00256 /**
00257  * Find virtual Ethernet device
00258  *
00259  * @v xcm               Configuration manager
00260  * @v resource          Resource identifier
00261  * @ret xve             Virtual Ethernet device, or NULL
00262  */
00263 static struct xsigo_nic * xve_find ( struct xsigo_manager *xcm,
00264                                      union ib_guid *resource ) {
00265         struct xsigo_nic *xve;
00266 
00267         list_for_each_entry ( xve, &xcm->nics, list ) {
00268                 if ( memcmp ( resource, &xve->resource,
00269                               sizeof ( *resource ) ) == 0 )
00270                         return xve;
00271         }
00272         return NULL;
00273 }
00274 
00275 /**
00276  * Destroy virtual Ethernet device
00277  *
00278  * @v xve               Virtual Ethernet device
00279  */
00280 static void xve_destroy ( struct xsigo_nic *xve ) {
00281         struct xsigo_manager *xcm = xve->xcm;
00282         struct xsigo_device *xdev = xcm->xdev;
00283         struct ib_device *ibdev = xdev->ibdev;
00284         struct eoib_device *eoib;
00285 
00286         /* Destroy corresponding EoIB device, if any */
00287         if ( ( eoib = eoib_find ( ibdev, xve->mac ) ) )
00288                 eoib_destroy ( eoib );
00289 
00290         /* Remove from list of virtual Ethernet devices */
00291         list_del ( &xve->list );
00292 
00293         /* Free virtual Ethernet device */
00294         DBGC ( xve, "XVE %s destroyed\n", xve->name );
00295         free ( xve );
00296 }
00297 
00298 /**
00299  * Update virtual Ethernet device MTU
00300  *
00301  * @v xve               Virtual Ethernet device
00302  * @v eoib              EoIB device
00303  * @v mtu               New MTU (excluding Ethernet and EoIB headers)
00304  * @ret rc              Return status code
00305  */
00306 static int xve_update_mtu ( struct xsigo_nic *xve, struct eoib_device *eoib,
00307                             size_t mtu ) {
00308         struct net_device *netdev = eoib->netdev;
00309         size_t max;
00310 
00311         /* Check that we can support this MTU */
00312         max = ( IB_MAX_PAYLOAD_SIZE - ( sizeof ( struct ethhdr ) +
00313                                         sizeof ( struct eoib_header ) ) );
00314         if ( mtu > max ) {
00315                 DBGC ( xve, "XVE %s cannot support MTU %zd (max %zd)\n",
00316                        xve->name, mtu, max );
00317                 return -ERANGE;
00318         }
00319 
00320         /* Update MTU.  No need to close/reopen the network device,
00321          * since our Infiniband stack uses a fixed MTU anyway.  Note
00322          * that the network device sees the Ethernet frame header but
00323          * not the EoIB header.
00324          */
00325         netdev->max_pkt_len = ( mtu + sizeof ( struct ethhdr ) );
00326         netdev->mtu = mtu;
00327         DBGC ( xve, "XVE %s has MTU %zd\n", xve->name, mtu );
00328 
00329         return 0;
00330 }
00331 
00332 /**
00333  * Open virtual Ethernet device
00334  *
00335  * @v xve               Virtual Ethernet device
00336  * @v eoib              EoIB device
00337  * @v open              New administrative state
00338  * @ret rc              Return status code
00339  */
00340 static int xve_open ( struct xsigo_nic *xve, struct eoib_device *eoib ) {
00341         struct net_device *netdev = eoib->netdev;
00342         int rc;
00343 
00344         /* Do nothing if network device is already open */
00345         if ( netdev_is_open ( netdev ) )
00346                 return 0;
00347         DBGC ( xve, "XVE %s opening network device\n", xve->name );
00348 
00349         /* Open network device */
00350         if ( ( rc = netdev_open ( netdev ) ) != 0 ) {
00351                 DBGC ( xve, "XVE %s could not open: %s\n",
00352                        xve->name, strerror ( rc ) );
00353                 return rc;
00354         }
00355 
00356         return 0;
00357 }
00358 
00359 /**
00360  * Close virtual Ethernet device
00361  *
00362  * @v xve               Virtual Ethernet device
00363  * @v eoib              EoIB device
00364  */
00365 static void xve_close ( struct xsigo_nic *xve, struct eoib_device *eoib ) {
00366         struct net_device *netdev = eoib->netdev;
00367 
00368         /* Do nothing if network device is already closed */
00369         if ( ! netdev_is_open ( netdev ) )
00370                 return;
00371 
00372         /* Close network device */
00373         netdev_close ( netdev );
00374         DBGC ( xve, "XVE %s closed network device\n", xve->name );
00375 }
00376 
00377 /**
00378  * Update virtual Ethernet device administrative state
00379  *
00380  * @v xve               Virtual Ethernet device
00381  * @v eoib              EoIB device
00382  * @v open              New administrative state
00383  * @ret rc              Return status code
00384  */
00385 static int xve_update_state ( struct xsigo_nic *xve, struct eoib_device *eoib,
00386                               int open ) {
00387 
00388         /* Open or close device, as applicable */
00389         if ( open ) {
00390                 return xve_open ( xve, eoib );
00391         } else {
00392                 xve_close ( xve, eoib );
00393                 return 0;
00394         }
00395 }
00396 
00397 /**
00398  * Update gateway (TCA)
00399  *
00400  * @v xve               Virtual Ethernet device
00401  * @v eoib              EoIB device
00402  * @v av                Address vector, or NULL if no gateway
00403  * @ret rc              Return status code
00404  */
00405 static int xve_update_tca ( struct xsigo_nic *xve, struct eoib_device *eoib,
00406                             struct ib_address_vector *av ) {
00407 
00408         /* Update gateway address */
00409         eoib_set_gateway ( eoib, av );
00410         if ( av ) {
00411                 DBGC ( xve, "XVE %s has TCA " IB_GID_FMT " data %#lx qkey "
00412                        "%#lx\n", xve->name, IB_GID_ARGS ( &av->gid ), av->qpn,
00413                        av->qkey );
00414         } else {
00415                 DBGC ( xve, "XVE %s has no TCA\n", xve->name );
00416         }
00417 
00418         /* The Linux driver will modify the local device's link state
00419          * to reflect the EoIB-to-Ethernet gateway's link state, but
00420          * this seems philosophically incorrect since communication
00421          * within the EoIB broadcast domain still works regardless of
00422          * the state of the gateway.
00423          */
00424 
00425         return 0;
00426 }
00427 
00428 /****************************************************************************
00429  *
00430  * Server management protocol (XSMP) session messages
00431  *
00432  ****************************************************************************
00433  */
00434 
00435 /**
00436  * Get session message name (for debugging)
00437  *
00438  * @v type              Message type
00439  * @ret name            Message name
00440  */
00441 static const char * xsmp_session_type ( unsigned int type ) {
00442         static char buf[16];
00443 
00444         switch ( type ) {
00445         case XSMP_SESSION_TYPE_HELLO:           return "HELLO";
00446         case XSMP_SESSION_TYPE_REGISTER:        return "REGISTER";
00447         case XSMP_SESSION_TYPE_CONFIRM:         return "CONFIRM";
00448         case XSMP_SESSION_TYPE_REJECT:          return "REJECT";
00449         case XSMP_SESSION_TYPE_SHUTDOWN:        return "SHUTDOWN";
00450         default:
00451                 snprintf ( buf, sizeof ( buf ), "UNKNOWN<%d>", type );
00452                 return buf;
00453         }
00454 }
00455 
00456 /**
00457  * Extract chassis name (for debugging)
00458  *
00459  * @v msg               Session message
00460  * @ret chassis         Chassis name
00461  */
00462 static const char * xsmp_chassis_name ( struct xsmp_session_message *msg ) {
00463         static char chassis[ sizeof ( msg->chassis ) + 1 /* NUL */ ];
00464 
00465         memcpy ( chassis, msg->chassis, sizeof ( msg->chassis ) );
00466         return chassis;
00467 }
00468 
00469 /**
00470  * Extract session name (for debugging)
00471  *
00472  * @v msg               Session message
00473  * @ret session         Session name
00474  */
00475 static const char * xsmp_session_name ( struct xsmp_session_message *msg ) {
00476         static char session[ sizeof ( msg->session ) + 1 /* NUL */ ];
00477 
00478         memcpy ( session, msg->session, sizeof ( msg->session ) );
00479         return session;
00480 }
00481 
00482 /**
00483  * Send session message
00484  *
00485  * @v xcm               Configuration manager
00486  * @v type              Message type
00487  * @ret rc              Return status code
00488  */
00489 static int xsmp_tx_session ( struct xsigo_manager *xcm, unsigned int type ) {
00490         struct xsigo_device *xdev = xcm->xdev;
00491         struct ib_device *ibdev = xdev->ibdev;
00492         struct xsmp_session_message msg;
00493         int rc;
00494 
00495         /* Construct session message */
00496         memset ( &msg, 0, sizeof ( msg ) );
00497         msg.hdr.type = XSMP_TYPE_SESSION;
00498         msg.hdr.len = htons ( sizeof ( msg ) );
00499         msg.hdr.seq = htonl ( ++xcm->seq );
00500         memcpy ( &msg.hdr.src.guid, &ibdev->gid.s.guid,
00501                  sizeof ( msg.hdr.src.guid ) );
00502         memcpy ( &msg.hdr.dst.guid, &xcm->id.guid,
00503                  sizeof ( msg.hdr.dst.guid ) );
00504         msg.type = type;
00505         msg.len = htons ( sizeof ( msg ) - sizeof ( msg.hdr ) );
00506         msg.os_type = XSIGO_OS_TYPE_GENERIC;
00507         msg.resources = htons ( XSIGO_RESOURCE_XVE |
00508                                 XSIGO_RESOURCE_NO_HA );
00509         msg.boot = htonl ( XSMP_BOOT_PXE );
00510         DBGCP ( xcm, "XCM %s TX[%d] session %s\n", xcm->name,
00511                 ntohl ( msg.hdr.seq ), xsmp_session_type ( msg.type ) );
00512         DBGCP_HDA ( xcm, 0, &msg, sizeof ( msg ) );
00513 
00514         /* Send session message */
00515         if ( ( rc = xfer_deliver_raw ( &xcm->xfer, &msg,
00516                                        sizeof ( msg ) ) ) != 0 ) {
00517                 DBGC ( xcm, "XCM %s TX session %s failed: %s\n", xcm->name,
00518                        xsmp_session_type ( msg.type ), strerror ( rc ) );
00519                 return rc;
00520         }
00521 
00522         return 0;
00523 }
00524 
00525 /**
00526  * Send registration message
00527  *
00528  * @v xcm               Configuration manager
00529  * @ret rc              Return status code
00530  */
00531 static inline int xsmp_tx_session_register ( struct xsigo_manager *xcm ) {
00532 
00533         DBGC ( xcm, "XCM %s registering with " IB_GUID_FMT "\n",
00534                xcm->name, IB_GUID_ARGS ( &xcm->id.guid ) );
00535 
00536         /* Send registration message */
00537         return xsmp_tx_session ( xcm, XSMP_SESSION_TYPE_REGISTER );
00538 }
00539 
00540 /**
00541  * Send keepalive message
00542  *
00543  * @v xcm               Configuration manager
00544  * @ret rc              Return status code
00545  */
00546 static int xsmp_tx_session_hello ( struct xsigo_manager *xcm ) {
00547 
00548         /* Send keepalive message */
00549         return xsmp_tx_session ( xcm, XSMP_SESSION_TYPE_HELLO );
00550 }
00551 
00552 /**
00553  * Handle received keepalive message
00554  *
00555  * @v xcm               Configuration manager
00556  * @v msg               Keepalive message
00557  * @ret rc              Return status code
00558  */
00559 static int xsmp_rx_session_hello ( struct xsigo_manager *xcm,
00560                                    struct xsmp_session_message *msg __unused ) {
00561 
00562         /* Respond to keepalive message.  Note that the XCM doesn't
00563          * seem to actually ever send these.
00564          */
00565         return xsmp_tx_session_hello ( xcm );
00566 }
00567 
00568 /**
00569  * Handle received registration confirmation message
00570  *
00571  * @v xcm               Configuration manager
00572  * @v msg               Registration confirmation message
00573  * @ret rc              Return status code
00574  */
00575 static int xsmp_rx_session_confirm ( struct xsigo_manager *xcm,
00576                                      struct xsmp_session_message *msg ) {
00577 
00578         DBGC ( xcm, "XCM %s registered with \"%s\" as \"%s\"\n", xcm->name,
00579                xsmp_chassis_name ( msg ), xsmp_session_name ( msg ) );
00580 
00581         return 0;
00582 }
00583 
00584 /**
00585  * Handle received registration rejection message
00586  *
00587  * @v xcm               Configuration manager
00588  * @v msg               Registration confirmation message
00589  * @ret rc              Return status code
00590  */
00591 static int xsmp_rx_session_reject ( struct xsigo_manager *xcm,
00592                                     struct xsmp_session_message *msg ) {
00593 
00594         DBGC ( xcm, "XCM %s rejected by \"%s\":\n",
00595                xcm->name, xsmp_chassis_name ( msg ) );
00596         DBGC_HDA ( xcm, 0, msg, sizeof ( *msg ) );
00597 
00598         return -EPERM;
00599 }
00600 
00601 /**
00602  * Handle received shutdown message
00603  *
00604  * @v xcm               Configuration manager
00605  * @v msg               Registration confirmation message
00606  * @ret rc              Return status code
00607  */
00608 static int xsmp_rx_session_shutdown ( struct xsigo_manager *xcm,
00609                                       struct xsmp_session_message *msg ) {
00610 
00611         DBGC ( xcm, "XCM %s shut down by \"%s\":\n",
00612                xcm->name, xsmp_chassis_name ( msg ) );
00613         DBGC_HDA ( xcm, 0, msg, sizeof ( *msg ) );
00614 
00615         return -ENOTCONN;
00616 }
00617 
00618 /**
00619  * Handle received session message
00620  *
00621  * @v xcm               Configuration manager
00622  * @v msg               Session message
00623  * @ret rc              Return status code
00624  */
00625 static int xsmp_rx_session ( struct xsigo_manager *xcm,
00626                              struct xsmp_session_message *msg ) {
00627 
00628         DBGCP ( xcm, "XCM %s RX[%d] session %s\n", xcm->name,
00629                 ntohl ( msg->hdr.seq ), xsmp_session_type ( msg->type ) );
00630         DBGCP_HDA ( xcm, 0, msg, sizeof ( *msg ) );
00631 
00632         /* Handle message according to type */
00633         switch ( msg->type ) {
00634         case XSMP_SESSION_TYPE_HELLO:
00635                 return xsmp_rx_session_hello ( xcm, msg );
00636         case XSMP_SESSION_TYPE_CONFIRM:
00637                 return xsmp_rx_session_confirm ( xcm, msg );
00638         case XSMP_SESSION_TYPE_REJECT:
00639                 return xsmp_rx_session_reject ( xcm, msg );
00640         case XSMP_SESSION_TYPE_SHUTDOWN:
00641                 return xsmp_rx_session_shutdown ( xcm, msg );
00642         default:
00643                 DBGC ( xcm, "XCM %s RX[%d] session unexpected %s:\n", xcm->name,
00644                        ntohl ( msg->hdr.seq ), xsmp_session_type ( msg->type ));
00645                 DBGC_HDA ( xcm, 0, msg, sizeof ( *msg ) );
00646                 return -EPROTO;
00647         }
00648 }
00649 
00650 /****************************************************************************
00651  *
00652  * Server management protocol (XSMP) virtual Ethernet (XVE) messages
00653  *
00654  ****************************************************************************
00655  */
00656 
00657 /**
00658  * Get virtual Ethernet message name (for debugging)
00659  *
00660  * @v type              Message type
00661  * @ret name            Message name
00662  */
00663 static const char * xsmp_xve_type ( unsigned int type ) {
00664         static char buf[16];
00665 
00666         switch ( type ) {
00667         case XSMP_XVE_TYPE_INSTALL:             return "INSTALL";
00668         case XSMP_XVE_TYPE_DELETE:              return "DELETE";
00669         case XSMP_XVE_TYPE_UPDATE:              return "UPDATE";
00670         case XSMP_XVE_TYPE_OPER_UP:             return "OPER_UP";
00671         case XSMP_XVE_TYPE_OPER_DOWN:           return "OPER_DOWN";
00672         case XSMP_XVE_TYPE_OPER_REQ:            return "OPER_REQ";
00673         case XSMP_XVE_TYPE_READY:               return "READY";
00674         default:
00675                 snprintf ( buf, sizeof ( buf ), "UNKNOWN<%d>", type );
00676                 return buf;
00677         }
00678 }
00679 
00680 /**
00681  * Send virtual Ethernet message
00682  *
00683  * @v xcm               Configuration manager
00684  * @v msg               Partial message
00685  * @ret rc              Return status code
00686  */
00687 static int xsmp_tx_xve ( struct xsigo_manager *xcm,
00688                          struct xsmp_xve_message *msg ) {
00689         struct xsigo_device *xdev = xcm->xdev;
00690         struct ib_device *ibdev = xdev->ibdev;
00691         int rc;
00692 
00693         /* Fill in common header fields */
00694         msg->hdr.type = XSMP_TYPE_XVE;
00695         msg->hdr.len = htons ( sizeof ( *msg ) );
00696         msg->hdr.seq = htonl ( ++xcm->seq );
00697         memcpy ( &msg->hdr.src.guid, &ibdev->gid.s.guid,
00698                  sizeof ( msg->hdr.src.guid ) );
00699         memcpy ( &msg->hdr.dst.guid, &xcm->id.guid,
00700                  sizeof ( msg->hdr.dst.guid ) );
00701         msg->len = htons ( sizeof ( *msg ) - sizeof ( msg->hdr ) );
00702         DBGCP ( xcm, "XCM %s TX[%d] xve %s code %#02x\n", xcm->name,
00703                 ntohl ( msg->hdr.seq ), xsmp_xve_type ( msg->type ),
00704                 msg->code );
00705         DBGCP_HDA ( xcm, 0, msg, sizeof ( *msg ) );
00706 
00707         /* Send virtual Ethernet message */
00708         if ( ( rc = xfer_deliver_raw ( &xcm->xfer, msg,
00709                                        sizeof ( *msg ) ) ) != 0 ) {
00710                 DBGC ( xcm, "XCM %s TX xve %s failed: %s\n", xcm->name,
00711                        xsmp_xve_type ( msg->type ), strerror ( rc ) );
00712                 return rc;
00713         }
00714 
00715         return 0;
00716 }
00717 
00718 /**
00719  * Send virtual Ethernet message including current device parameters
00720  *
00721  * @v xcm               Configuration manager
00722  * @v msg               Partial virtual Ethernet message
00723  * @v xve               Virtual Ethernet device
00724  * @v eoib              EoIB device
00725  * @ret rc              Return status code
00726  */
00727 static int xsmp_tx_xve_params ( struct xsigo_manager *xcm,
00728                                 struct xsmp_xve_message *msg,
00729                                 struct xsigo_nic *xve,
00730                                 struct eoib_device *eoib ) {
00731         struct xsigo_device *xdev = xcm->xdev;
00732         struct ib_device *ibdev = xdev->ibdev;
00733         struct net_device *netdev = eoib->netdev;
00734 
00735         /* Set successful response code */
00736         msg->code = 0;
00737 
00738         /* Include network identifier, MTU, and current HCA parameters */
00739         msg->network = htonl ( xve->network );
00740         msg->mtu = htons ( netdev->max_pkt_len - sizeof ( struct ethhdr ) );
00741         msg->hca.prefix_le.qword = bswap_64 ( ibdev->gid.s.prefix.qword );
00742         msg->hca.pkey = htons ( ibdev->pkey );
00743         msg->hca.qkey = msg->tca.qkey;
00744         if ( eoib->qp ) {
00745                 msg->hca.data = htonl ( eoib->qp->ext_qpn );
00746                 msg->hca.qkey = htons ( eoib->qp->qkey );
00747         }
00748 
00749         /* The message type field is (ab)used to return the current
00750          * operational status.
00751          */
00752         if ( msg->type == XSMP_XVE_TYPE_OPER_REQ ) {
00753                 msg->type = ( netdev_is_open ( netdev ) ?
00754                               XSMP_XVE_TYPE_OPER_UP : XSMP_XVE_TYPE_OPER_DOWN );
00755         }
00756 
00757         /* Send message */
00758         DBGC ( xve, "XVE %s network %d MTU %d ctrl %#x data %#x qkey %#04x "
00759                "%s\n", xve->name, ntohl ( msg->network ), ntohs ( msg->mtu ),
00760                ntohl ( msg->hca.ctrl ), ntohl ( msg->hca.data ),
00761                ntohs ( msg->hca.qkey ), xsmp_xve_type ( msg->type ) );
00762 
00763         return xsmp_tx_xve ( xcm, msg );
00764 }
00765 
00766 /**
00767  * Send virtual Ethernet error response
00768  *
00769  * @v xcm               Configuration manager
00770  * @v msg               Partial virtual Ethernet message
00771  * @ret rc              Return status code
00772  */
00773 static inline int xsmp_tx_xve_nack ( struct xsigo_manager *xcm,
00774                                      struct xsmp_xve_message *msg ) {
00775 
00776         /* Set error response code.  (There aren't any meaningful
00777          * detailed response codes defined by the wire protocol.)
00778          */
00779         msg->code = XSMP_XVE_CODE_ERROR;
00780 
00781         /* Send message */
00782         return xsmp_tx_xve ( xcm, msg );
00783 }
00784 
00785 /**
00786  * Send virtual Ethernet notification
00787  *
00788  * @v xcm               Configuration manager
00789  * @v type              Message type
00790  * @v xve               Virtual Ethernet device
00791  * @v eoib              EoIB device
00792  * @ret rc              Return status code
00793  */
00794 static int xsmp_tx_xve_notify ( struct xsigo_manager *xcm,
00795                                 unsigned int type,
00796                                 struct xsigo_nic *xve,
00797                                 struct eoib_device *eoib ) {
00798         struct xsmp_xve_message msg;
00799 
00800         /* Construct message */
00801         memset ( &msg, 0, sizeof ( msg ) );
00802         msg.type = type;
00803         memcpy ( &msg.resource, &xve->resource, sizeof ( msg.resource ) );
00804 
00805         /* Send message */
00806         return xsmp_tx_xve_params ( xcm, &msg, xve, eoib );
00807 }
00808 
00809 /**
00810  * Send virtual Ethernet current operational state
00811  *
00812  * @v xcm               Configuration manager
00813  * @v xve               Virtual Ethernet device
00814  * @v eoib              EoIB device
00815  * @ret rc              Return status code
00816  */
00817 static inline int xsmp_tx_xve_oper ( struct xsigo_manager *xcm,
00818                                      struct xsigo_nic *xve,
00819                                      struct eoib_device *eoib ) {
00820 
00821         /* Send notification */
00822         return xsmp_tx_xve_notify ( xcm, XSMP_XVE_TYPE_OPER_REQ, xve, eoib );
00823 }
00824 
00825 /**
00826  * Handle received virtual Ethernet modification message
00827  *
00828  * @v xcm               Configuration manager
00829  * @v msg               Virtual Ethernet message
00830  * @v update            Update bitmask
00831  * @ret rc              Return status code
00832  */
00833 static int xsmp_rx_xve_modify ( struct xsigo_manager *xcm,
00834                                 struct xsmp_xve_message *msg,
00835                                 unsigned int update ) {
00836         struct xsigo_device *xdev = xcm->xdev;
00837         struct ib_device *ibdev = xdev->ibdev;
00838         struct xsigo_nic *xve;
00839         struct eoib_device *eoib;
00840         struct ib_address_vector tca;
00841         size_t mtu;
00842         int rc;
00843 
00844         /* Avoid returning uninitialised HCA parameters in response */
00845         memset ( &msg->hca, 0, sizeof ( msg->hca ) );
00846 
00847         /* Find virtual Ethernet device */
00848         xve = xve_find ( xcm, &msg->resource );
00849         if ( ! xve ) {
00850                 DBGC ( xcm, "XCM %s unrecognised resource " IB_GUID_FMT "\n",
00851                        xcm->name, IB_GUID_ARGS ( &msg->resource ) );
00852                 rc = -ENOENT;
00853                 goto err_no_xve;
00854         }
00855 
00856         /* Find corresponding EoIB device */
00857         eoib = eoib_find ( ibdev, xve->mac );
00858         if ( ! eoib ) {
00859                 DBGC ( xve, "XVE %s has no EoIB device\n", xve->name );
00860                 rc = -EPIPE;
00861                 goto err_no_eoib;
00862         }
00863 
00864         /* The Xsigo management software fails to create the EoIB
00865          * multicast group.  This is a fundamental design flaw.
00866          */
00867         eoib_force_group_creation ( eoib );
00868 
00869         /* Extract modifiable parameters.  Note that the TCA GID is
00870          * erroneously transmitted as little-endian.
00871          */
00872         mtu = ntohs ( msg->mtu );
00873         tca.qpn = ntohl ( msg->tca.data );
00874         tca.qkey = ntohs ( msg->tca.qkey );
00875         tca.gid_present = 1;
00876         tca.gid.s.prefix.qword = bswap_64 ( msg->tca.prefix_le.qword );
00877         tca.gid.s.guid.qword = bswap_64 ( msg->guid_le.qword );
00878 
00879         /* Update MTU, if applicable */
00880         if ( ( update & XSMP_XVE_UPDATE_MTU ) &&
00881              ( ( rc = xve_update_mtu ( xve, eoib, mtu ) ) != 0 ) )
00882                 goto err_mtu;
00883         update &= ~XSMP_XVE_UPDATE_MTU;
00884 
00885         /* Update admin state, if applicable */
00886         if ( ( update & XSMP_XVE_UPDATE_STATE ) &&
00887              ( ( rc = xve_update_state ( xve, eoib, msg->state ) ) != 0 ) )
00888                 goto err_state;
00889         update &= ~XSMP_XVE_UPDATE_STATE;
00890 
00891         /* Remove gateway, if applicable */
00892         if ( ( update & XSMP_XVE_UPDATE_GW_DOWN ) &&
00893              ( ( rc = xve_update_tca ( xve, eoib, NULL ) ) != 0 ) )
00894                 goto err_gw_down;
00895         update &= ~XSMP_XVE_UPDATE_GW_DOWN;
00896 
00897         /* Update gateway, if applicable */
00898         if ( ( update & XSMP_XVE_UPDATE_GW_CHANGE ) &&
00899              ( ( rc = xve_update_tca ( xve, eoib, &tca ) ) != 0 ) )
00900                 goto err_gw_change;
00901         update &= ~XSMP_XVE_UPDATE_GW_CHANGE;
00902 
00903         /* Warn about unexpected updates */
00904         if ( update ) {
00905                 DBGC ( xve, "XVE %s unrecognised update(s) %#08x\n",
00906                        xve->name, update );
00907         }
00908 
00909         xsmp_tx_xve_params ( xcm, msg, xve, eoib );
00910         return 0;
00911 
00912  err_gw_change:
00913  err_gw_down:
00914  err_state:
00915  err_mtu:
00916  err_no_eoib:
00917  err_no_xve:
00918         /* Send NACK */
00919         xsmp_tx_xve_nack ( xcm, msg );
00920         return rc;
00921 }
00922 
00923 /**
00924  * Handle received virtual Ethernet installation message
00925  *
00926  * @v xcm               Configuration manager
00927  * @v msg               Virtual Ethernet message
00928  * @ret rc              Return status code
00929  */
00930 static int xsmp_rx_xve_install ( struct xsigo_manager *xcm,
00931                                  struct xsmp_xve_message *msg ) {
00932         union {
00933                 struct xsmp_xve_mac msg;
00934                 uint8_t raw[ETH_ALEN];
00935         } mac;
00936         char name[ sizeof ( msg->name ) + 1 /* NUL */ ];
00937         unsigned long network;
00938         unsigned long qkey;
00939         unsigned int update;
00940         int rc;
00941 
00942         /* Demangle MAC address (which is erroneously transmitted as
00943          * little-endian).
00944          */
00945         mac.msg.high = bswap_16 ( msg->mac_le.high );
00946         mac.msg.low = bswap_32 ( msg->mac_le.low );
00947 
00948         /* Extract interface name (which may not be NUL-terminated) */
00949         memcpy ( name, msg->name, ( sizeof ( name ) - 1 /* NUL */ ) );
00950         name[ sizeof ( name ) - 1 /* NUL */ ] = '\0';
00951 
00952         /* Extract remaining message parameters */
00953         network = ntohl ( msg->network );
00954         qkey = ntohs ( msg->tca.qkey );
00955         DBGC2 ( xcm, "XCM %s " IB_GUID_FMT " install \"%s\" %s net %ld qkey "
00956                 "%#lx\n", xcm->name, IB_GUID_ARGS ( &msg->resource ), name,
00957                 eth_ntoa ( mac.raw ), network, qkey );
00958 
00959         /* Create virtual Ethernet device, if applicable */
00960         if ( ( xve_find ( xcm, &msg->resource ) == NULL ) &&
00961              ( ( rc = xve_create ( xcm, &msg->resource, mac.raw, network,
00962                                    qkey, name ) ) != 0 ) )
00963                 goto err_create;
00964 
00965         /* Handle remaining parameters as for a modification message */
00966         update = XSMP_XVE_UPDATE_MTU;
00967         if ( msg->uplink == XSMP_XVE_UPLINK )
00968                 update |= XSMP_XVE_UPDATE_GW_CHANGE;
00969         return xsmp_rx_xve_modify ( xcm, msg, update );
00970 
00971  err_create:
00972         /* Send NACK */
00973         xsmp_tx_xve_nack ( xcm, msg );
00974         return rc;
00975 }
00976 
00977 /**
00978  * Handle received virtual Ethernet deletion message
00979  *
00980  * @v xcm               Configuration manager
00981  * @v msg               Virtual Ethernet message
00982  * @ret rc              Return status code
00983  */
00984 static int xsmp_rx_xve_delete ( struct xsigo_manager *xcm,
00985                                 struct xsmp_xve_message *msg ) {
00986         struct xsigo_nic *xve;
00987 
00988         DBGC2 ( xcm, "XCM %s " IB_GUID_FMT " delete\n",
00989                 xcm->name, IB_GUID_ARGS ( &msg->resource ) );
00990 
00991         /* Destroy virtual Ethernet device (if any) */
00992         if ( ( xve = xve_find ( xcm, &msg->resource ) ) )
00993                 xve_destroy ( xve );
00994 
00995         /* Send ACK */
00996         msg->code = 0;
00997         xsmp_tx_xve ( xcm, msg );
00998 
00999         return 0;
01000 }
01001 
01002 /**
01003  * Handle received virtual Ethernet update message
01004  *
01005  * @v xcm               Configuration manager
01006  * @v msg               Virtual Ethernet message
01007  * @ret rc              Return status code
01008  */
01009 static int xsmp_rx_xve_update ( struct xsigo_manager *xcm,
01010                                 struct xsmp_xve_message *msg ) {
01011         unsigned int update = ntohl ( msg->update );
01012 
01013         DBGC2 ( xcm, "XCM %s " IB_GUID_FMT " update (%08x)\n",
01014                 xcm->name, IB_GUID_ARGS ( &msg->resource ), update );
01015 
01016         /* Handle as a modification message */
01017         return xsmp_rx_xve_modify ( xcm, msg, update );
01018 }
01019 
01020 /**
01021  * Handle received virtual Ethernet operational request message
01022  *
01023  * @v xcm               Configuration manager
01024  * @v msg               Virtual Ethernet message
01025  * @ret rc              Return status code
01026  */
01027 static int xsmp_rx_xve_oper_req ( struct xsigo_manager *xcm,
01028                                   struct xsmp_xve_message *msg ) {
01029 
01030         DBGC2 ( xcm, "XCM %s " IB_GUID_FMT " operational request\n",
01031                 xcm->name, IB_GUID_ARGS ( &msg->resource ) );
01032 
01033         /* Handle as a nullipotent modification message */
01034         return xsmp_rx_xve_modify ( xcm, msg, 0 );
01035 }
01036 
01037 /**
01038  * Handle received virtual Ethernet readiness message
01039  *
01040  * @v xcm               Configuration manager
01041  * @v msg               Virtual Ethernet message
01042  * @ret rc              Return status code
01043  */
01044 static int xsmp_rx_xve_ready ( struct xsigo_manager *xcm,
01045                                struct xsmp_xve_message *msg ) {
01046         int rc;
01047 
01048         DBGC2 ( xcm, "XCM %s " IB_GUID_FMT " ready\n",
01049                 xcm->name, IB_GUID_ARGS ( &msg->resource ) );
01050 
01051         /* Handle as a nullipotent modification message */
01052         if ( ( rc = xsmp_rx_xve_modify ( xcm, msg, 0 ) ) != 0 )
01053                 return rc;
01054 
01055         /* Send an unsolicited operational state update, since there
01056          * is no other way to convey the current operational state.
01057          */
01058         msg->type = XSMP_XVE_TYPE_OPER_REQ;
01059         if ( ( rc = xsmp_rx_xve_modify ( xcm, msg, 0 ) ) != 0 )
01060                 return rc;
01061 
01062         return 0;
01063 }
01064 
01065 /**
01066  * Handle received virtual Ethernet message
01067  *
01068  * @v xcm               Configuration manager
01069  * @v msg               Virtual Ethernet message
01070  * @ret rc              Return status code
01071  */
01072 static int xsmp_rx_xve ( struct xsigo_manager *xcm,
01073                          struct xsmp_xve_message *msg ) {
01074 
01075         DBGCP ( xcm, "XCM %s RX[%d] xve %s\n", xcm->name,
01076                 ntohl ( msg->hdr.seq ), xsmp_xve_type ( msg->type ) );
01077         DBGCP_HDA ( xcm, 0, msg, sizeof ( *msg ) );
01078 
01079         /* Handle message according to type */
01080         switch ( msg->type ) {
01081         case XSMP_XVE_TYPE_INSTALL:
01082                 return xsmp_rx_xve_install ( xcm, msg );
01083         case XSMP_XVE_TYPE_DELETE:
01084                 return xsmp_rx_xve_delete ( xcm, msg );
01085         case XSMP_XVE_TYPE_UPDATE:
01086                 return xsmp_rx_xve_update ( xcm, msg );
01087         case XSMP_XVE_TYPE_OPER_REQ:
01088                 return xsmp_rx_xve_oper_req ( xcm, msg );
01089         case XSMP_XVE_TYPE_READY:
01090                 return xsmp_rx_xve_ready ( xcm, msg );
01091         default:
01092                 DBGC ( xcm, "XCM %s RX[%d] xve unexpected %s:\n", xcm->name,
01093                        ntohl ( msg->hdr.seq ), xsmp_xve_type ( msg->type ) );
01094                 DBGC_HDA ( xcm, 0, msg, sizeof ( *msg ) );
01095                 return -EPROTO;
01096         }
01097 }
01098 
01099 /****************************************************************************
01100  *
01101  * Configuration managers (XCM)
01102  *
01103  ****************************************************************************
01104  */
01105 
01106 /**
01107  * Close configuration manager connection
01108  *
01109  * @v xcm               Configuration manager
01110  * @v rc                Reason for close
01111  */
01112 static void xcm_close ( struct xsigo_manager *xcm, int rc ) {
01113 
01114         DBGC ( xcm, "XCM %s closed: %s\n", xcm->name, strerror ( rc ) );
01115 
01116         /* Stop transmission process */
01117         process_del ( &xcm->process );
01118 
01119         /* Stop keepalive timer */
01120         stop_timer ( &xcm->keepalive );
01121 
01122         /* Restart data transfer interface */
01123         intf_restart ( &xcm->xfer, rc );
01124 
01125         /* Schedule reconnection attempt */
01126         start_timer ( &xcm->reopen );
01127 }
01128 
01129 /**
01130  * Send data to configuration manager
01131  *
01132  * @v xcm               Configuration manager
01133  */
01134 static void xcm_step ( struct xsigo_manager *xcm ) {
01135         int rc;
01136 
01137         /* Do nothing unless we have something to send */
01138         if ( ! xcm->pending )
01139                 return;
01140 
01141         /* Send (empty) connection request, if applicable */
01142         if ( xcm->pending & XCM_TX_CONNECT ) {
01143                 if ( ( rc = xfer_deliver_raw ( &xcm->xfer, NULL, 0 ) ) != 0 ) {
01144                         DBGC ( xcm, "XCM %s could not send connection request: "
01145                                "%s\n", xcm->name, strerror ( rc ) );
01146                         goto err;
01147                 }
01148                 xcm->pending &= ~XCM_TX_CONNECT;
01149                 return;
01150         }
01151 
01152         /* Wait until data transfer interface is connected */
01153         if ( ! xfer_window ( &xcm->xfer ) )
01154                 return;
01155 
01156         /* Send registration message, if applicable */
01157         if ( xcm->pending & XCM_TX_REGISTER ) {
01158                 if ( ( rc = xsmp_tx_session_register ( xcm ) ) != 0 )
01159                         goto err;
01160                 xcm->pending &= ~XCM_TX_REGISTER;
01161                 return;
01162         }
01163 
01164         return;
01165 
01166  err:
01167         xcm_close ( xcm, rc );
01168 }
01169 
01170 /**
01171  * Receive data from configuration manager
01172  *
01173  * @v xcm               Configuration manager
01174  * @v iobuf             I/O buffer
01175  * @v meta              Data transfer metadata
01176  * @ret rc              Return status code
01177  */
01178 static int xcm_deliver ( struct xsigo_manager *xcm, struct io_buffer *iobuf,
01179                          struct xfer_metadata *meta __unused ) {
01180         union xsmp_message *msg;
01181         size_t len = iob_len ( iobuf );
01182         int rc;
01183 
01184         /* Sanity check */
01185         if ( len < sizeof ( msg->hdr ) ) {
01186                 DBGC ( xcm, "XCM %s underlength message:\n", xcm->name );
01187                 DBGC_HDA ( xcm, 0, iobuf->data, iob_len ( iobuf ) );
01188                 rc = -EPROTO;
01189                 goto out;
01190         }
01191         msg = iobuf->data;
01192 
01193         /* Handle message according to type */
01194         if ( ! msg->hdr.type ) {
01195 
01196                 /* Ignore unused communication manager private data blocks */
01197                 rc = 0;
01198 
01199         } else if ( ( msg->hdr.type == XSMP_TYPE_SESSION ) &&
01200                     ( len >= sizeof ( msg->sess ) ) ) {
01201 
01202                 /* Session message */
01203                 rc = xsmp_rx_session ( xcm, &msg->sess );
01204 
01205         } else if ( ( msg->hdr.type == XSMP_TYPE_XVE ) &&
01206                     ( len >= sizeof ( msg->xve ) ) ) {
01207 
01208                 /* Virtual Ethernet message */
01209                 xsmp_rx_xve ( xcm, &msg->xve );
01210 
01211                 /* Virtual Ethernet message errors are non-fatal */
01212                 rc = 0;
01213 
01214         } else {
01215 
01216                 /* Unknown message */
01217                 DBGC ( xcm, "XCM %s unexpected message type %d:\n",
01218                        xcm->name, msg->hdr.type );
01219                 DBGC_HDA ( xcm, 0, iobuf->data, iob_len ( iobuf ) );
01220                 rc = -EPROTO;
01221         }
01222 
01223  out:
01224         free_iob ( iobuf );
01225         if ( rc != 0 )
01226                 xcm_close ( xcm, rc );
01227         return rc;
01228 }
01229 
01230 /** Configuration manager data transfer interface operations */
01231 static struct interface_operation xcm_xfer_op[] = {
01232         INTF_OP ( xfer_deliver, struct xsigo_manager *, xcm_deliver ),
01233         INTF_OP ( xfer_window_changed, struct xsigo_manager *, xcm_step ),
01234         INTF_OP ( intf_close, struct xsigo_manager *, xcm_close ),
01235 };
01236 
01237 /** Configuration manager data transfer interface descriptor */
01238 static struct interface_descriptor xcm_xfer_desc =
01239         INTF_DESC ( struct xsigo_manager, xfer, xcm_xfer_op );
01240 
01241 /** Configuration manager process descriptor */
01242 static struct process_descriptor xcm_process_desc =
01243         PROC_DESC_ONCE ( struct xsigo_manager, process, xcm_step );
01244 
01245 /**
01246  * Handle configuration manager connection timer expiry
01247  *
01248  * @v timer             Connection timer
01249  * @v fail              Failure indicator
01250  */
01251 static void xcm_reopen ( struct retry_timer *timer, int fail __unused ) {
01252         struct xsigo_manager *xcm =
01253                 container_of ( timer, struct xsigo_manager, reopen );
01254         struct xsigo_device *xdev = xcm->xdev;
01255         struct ib_device *ibdev = xdev->ibdev;
01256         union ib_gid gid;
01257         int rc;
01258 
01259         /* Stop transmission process */
01260         process_del ( &xcm->process );
01261 
01262         /* Stop keepalive timer */
01263         stop_timer ( &xcm->keepalive );
01264 
01265         /* Restart data transfer interface */
01266         intf_restart ( &xcm->xfer, -ECANCELED );
01267 
01268         /* Reset sequence number */
01269         xcm->seq = 0;
01270 
01271         /* Construct GID */
01272         memcpy ( &gid.s.prefix, &ibdev->gid.s.prefix, sizeof ( gid.s.prefix ) );
01273         memcpy ( &gid.s.guid, &xcm->id.guid, sizeof ( gid.s.guid ) );
01274         DBGC ( xcm, "XCM %s connecting to " IB_GID_FMT "\n",
01275                xcm->name, IB_GID_ARGS ( &gid ) );
01276 
01277         /* Open CMRC connection */
01278         if ( ( rc = ib_cmrc_open ( &xcm->xfer, ibdev, &gid,
01279                                    &xcm_service_id, xcm->name ) ) != 0 ) {
01280                 DBGC ( xcm, "XCM %s could not open CMRC connection: %s\n",
01281                        xcm->name, strerror ( rc ) );
01282                 start_timer ( &xcm->reopen );
01283                 return;
01284         }
01285 
01286         /* Schedule transmissions */
01287         xcm->pending |= ( XCM_TX_CONNECT | XCM_TX_REGISTER );
01288         process_add ( &xcm->process );
01289 
01290         /* Start keepalive timer */
01291         start_timer_fixed ( &xcm->keepalive, XSIGO_KEEPALIVE_INTERVAL );
01292 
01293         return;
01294 }
01295 
01296 /**
01297  * Handle configuration manager keepalive timer expiry
01298  *
01299  * @v timer             Connection timer
01300  * @v fail              Failure indicator
01301  */
01302 static void xcm_keepalive ( struct retry_timer *timer, int fail __unused ) {
01303         struct xsigo_manager *xcm =
01304                 container_of ( timer, struct xsigo_manager, keepalive );
01305         int rc;
01306 
01307         /* Send keepalive message.  The server won't actually respond
01308          * to these, but it gives the RC queue pair a chance to
01309          * complain if it doesn't ever at least get an ACK.
01310          */
01311         if ( ( rc = xsmp_tx_session_hello ( xcm ) ) != 0 ) {
01312                 xcm_close ( xcm, rc );
01313                 return;
01314         }
01315 
01316         /* Restart keepalive timer */
01317         start_timer_fixed ( &xcm->keepalive, XSIGO_KEEPALIVE_INTERVAL );
01318 }
01319 
01320 /**
01321  * Create configuration manager
01322  *
01323  * @v xsigo             Xsigo device
01324  * @v id                Configuration manager ID
01325  * @ret rc              Return status code
01326  */
01327 static int xcm_create ( struct xsigo_device *xdev,
01328                         struct xsigo_manager_id *id ) {
01329         struct xsigo_manager *xcm;
01330 
01331         /* Allocate and initialise structure */
01332         xcm = zalloc ( sizeof ( *xcm ) );
01333         if ( ! xcm )
01334                 return -ENOMEM;
01335         ref_init ( &xcm->refcnt, xcm_free );
01336         xcm->xdev = xdev;
01337         ref_get ( &xcm->xdev->refcnt );
01338         snprintf ( xcm->name, sizeof ( xcm->name ), "%s:xcm-%d",
01339                    xdev->name, ntohs ( id->lid ) );
01340         memcpy ( &xcm->id, id, sizeof ( xcm->id ) );
01341         intf_init ( &xcm->xfer, &xcm_xfer_desc, &xcm->refcnt );
01342         timer_init ( &xcm->keepalive, xcm_keepalive, &xcm->refcnt );
01343         timer_init ( &xcm->reopen, xcm_reopen, &xcm->refcnt );
01344         process_init_stopped ( &xcm->process, &xcm_process_desc, &xcm->refcnt );
01345         INIT_LIST_HEAD ( &xcm->nics );
01346 
01347         /* Start timer to open connection */
01348         start_timer_nodelay ( &xcm->reopen );
01349 
01350         /* Add to list of managers and transfer reference to list */
01351         list_add ( &xcm->list, &xdev->managers );
01352         DBGC ( xcm, "XCM %s created for " IB_GUID_FMT " (LID %d)\n", xcm->name,
01353                IB_GUID_ARGS ( &xcm->id.guid ), ntohs ( id->lid ) );
01354         return 0;
01355 }
01356 
01357 /**
01358  * Find configuration manager
01359  *
01360  * @v xsigo             Xsigo device
01361  * @v id                Configuration manager ID
01362  * @ret xcm             Configuration manager, or NULL
01363  */
01364 static struct xsigo_manager * xcm_find ( struct xsigo_device *xdev,
01365                                          struct xsigo_manager_id *id ) {
01366         struct xsigo_manager *xcm;
01367         union ib_guid *guid = &id->guid;
01368 
01369         /* Find configuration manager */
01370         list_for_each_entry ( xcm, &xdev->managers, list ) {
01371                 if ( memcmp ( guid, &xcm->id.guid, sizeof ( *guid ) ) == 0 )
01372                         return xcm;
01373         }
01374         return NULL;
01375 }
01376 
01377 /**
01378  * Destroy configuration manager
01379  *
01380  * @v xcm               Configuration manager
01381  */
01382 static void xcm_destroy ( struct xsigo_manager *xcm ) {
01383         struct xsigo_nic *xve;
01384 
01385         /* Remove all EoIB NICs */
01386         while ( ( xve = list_first_entry ( &xcm->nics, struct xsigo_nic,
01387                                            list ) ) ) {
01388                 xve_destroy ( xve );
01389         }
01390 
01391         /* Stop transmission process */
01392         process_del ( &xcm->process );
01393 
01394         /* Stop timers */
01395         stop_timer ( &xcm->keepalive );
01396         stop_timer ( &xcm->reopen );
01397 
01398         /* Shut down data transfer interface */
01399         intf_shutdown ( &xcm->xfer, 0 );
01400 
01401         /* Remove from list of managers and drop list's reference */
01402         DBGC ( xcm, "XCM %s destroyed\n", xcm->name );
01403         list_del ( &xcm->list );
01404         ref_put ( &xcm->refcnt );
01405 }
01406 
01407 /**
01408  * Synchronise list of configuration managers
01409  *
01410  * @v xdev              Xsigo device
01411  * @v ids               List of manager IDs
01412  * @v count             Number of manager IDs
01413  * @ret rc              Return status code
01414  */
01415 static int xcm_list ( struct xsigo_device *xdev, struct xsigo_manager_id *ids,
01416                       unsigned int count ) {
01417         struct xsigo_manager_id *id;
01418         struct xsigo_manager *xcm;
01419         struct xsigo_manager *tmp;
01420         struct list_head list;
01421         unsigned int i;
01422         int rc;
01423 
01424         /* Create list of managers to be retained */
01425         INIT_LIST_HEAD ( &list );
01426         for ( i = 0, id = ids ; i < count ; i++, id++ ) {
01427                 if ( ( xcm = xcm_find ( xdev, id ) ) ) {
01428                         list_del ( &xcm->list );
01429                         list_add_tail ( &xcm->list, &list );
01430                 }
01431         }
01432 
01433         /* Destroy any managers not in the list */
01434         list_for_each_entry_safe ( xcm, tmp, &xdev->managers, list )
01435                 xcm_destroy ( xcm );
01436         list_splice ( &list, &xdev->managers );
01437 
01438         /* Create any new managers in the list, and force reconnection
01439          * for any changed LIDs.
01440          */
01441         for ( i = 0, id = ids ; i < count ; i++, id++ ) {
01442                 if ( ( xcm = xcm_find ( xdev, id ) ) ) {
01443                         if ( xcm->id.lid != id->lid )
01444                                 start_timer_nodelay ( &xcm->reopen );
01445                         continue;
01446                 }
01447                 if ( ( rc = xcm_create ( xdev, id ) ) != 0 ) {
01448                         DBGC ( xdev, "XDEV %s could not create manager: %s\n",
01449                                xdev->name, strerror ( rc ) );
01450                         return rc;
01451                 }
01452         }
01453 
01454         return 0;
01455 }
01456 
01457 /****************************************************************************
01458  *
01459  * Configuration manager discovery
01460  *
01461  ****************************************************************************
01462  */
01463 
01464 /** A stage of discovery */
01465 struct xsigo_discovery {
01466         /** Name */
01467         const char *name;
01468         /** Management transaction operations */
01469         struct ib_mad_transaction_operations op;
01470 };
01471 
01472 /**
01473  * Handle configuration manager lookup completion
01474  *
01475  * @v ibdev             Infiniband device
01476  * @v mi                Management interface
01477  * @v madx              Management transaction
01478  * @v rc                Status code
01479  * @v mad               Received MAD (or NULL on error)
01480  * @v av                Source address vector (or NULL on error)
01481  */
01482 static void xsigo_xcm_complete ( struct ib_device *ibdev,
01483                                  struct ib_mad_interface *mi __unused,
01484                                  struct ib_mad_transaction *madx,
01485                                  int rc, union ib_mad *mad,
01486                                  struct ib_address_vector *av __unused ) {
01487         struct xsigo_device *xdev = ib_madx_get_ownerdata ( madx );
01488         union xsigo_mad *xsmad = container_of ( mad, union xsigo_mad, mad );
01489         struct xsigo_managers_reply *reply = &xsmad->reply;
01490 
01491         /* Check for failures */
01492         if ( ( rc == 0 ) && ( mad->hdr.status != htons ( IB_MGMT_STATUS_OK ) ) )
01493                 rc = -ENODEV;
01494         if ( rc != 0 ) {
01495                 DBGC ( xdev, "XDEV %s manager lookup failed: %s\n",
01496                        xdev->name, strerror ( rc ) );
01497                 goto out;
01498         }
01499 
01500         /* Sanity checks */
01501         if ( reply->count > ( sizeof ( reply->manager ) /
01502                               sizeof ( reply->manager[0] ) ) ) {
01503                 DBGC ( xdev, "XDEV %s has too many managers (%d)\n",
01504                        xdev->name, reply->count );
01505                 goto out;
01506         }
01507 
01508         /* Synchronise list of managers */
01509         if ( ( rc = xcm_list ( xdev, reply->manager, reply->count ) ) != 0 )
01510                 goto out;
01511 
01512         /* Report an empty list of managers */
01513         if ( reply->count == 0 )
01514                 DBGC ( xdev, "XDEV %s has no managers\n", xdev->name );
01515 
01516         /* Delay next discovery attempt */
01517         start_timer_fixed ( &xdev->discovery, XSIGO_DISCOVERY_SUCCESS_DELAY );
01518 
01519 out:
01520         /* Destroy the completed transaction */
01521         ib_destroy_madx ( ibdev, ibdev->gsi, madx );
01522         xdev->madx = NULL;
01523 }
01524 
01525 /** Configuration manager lookup discovery stage */
01526 static struct xsigo_discovery xsigo_xcm_discovery = {
01527         .name = "manager",
01528         .op = {
01529                 .complete = xsigo_xcm_complete,
01530         },
01531 };
01532 
01533 /**
01534  * Handle directory service lookup completion
01535  *
01536  * @v ibdev             Infiniband device
01537  * @v mi                Management interface
01538  * @v madx              Management transaction
01539  * @v rc                Status code
01540  * @v mad               Received MAD (or NULL on error)
01541  * @v av                Source address vector (or NULL on error)
01542  */
01543 static void xsigo_xds_complete ( struct ib_device *ibdev,
01544                                  struct ib_mad_interface *mi __unused,
01545                                  struct ib_mad_transaction *madx,
01546                                  int rc, union ib_mad *mad,
01547                                  struct ib_address_vector *av __unused ) {
01548         struct xsigo_device *xdev = ib_madx_get_ownerdata ( madx );
01549         union xsigo_mad *xsmad = container_of ( mad, union xsigo_mad, mad );
01550         struct xsigo_managers_request *request = &xsmad->request;
01551         struct ib_service_record *svc;
01552         struct ib_address_vector dest;
01553         union ib_guid *guid;
01554 
01555         /* Allow for reuse of transaction pointer */
01556         xdev->madx = NULL;
01557 
01558         /* Check for failures */
01559         if ( ( rc == 0 ) && ( mad->hdr.status != htons ( IB_MGMT_STATUS_OK ) ) )
01560                 rc = -ENODEV;
01561         if ( rc != 0 ) {
01562                 DBGC ( xdev, "XDEV %s directory lookup failed: %s\n",
01563                        xdev->name, strerror ( rc ) );
01564                 goto out;
01565         }
01566 
01567         /* Construct address vector */
01568         memset ( &dest, 0, sizeof ( dest ) );
01569         svc = &mad->sa.sa_data.service_record;
01570         dest.lid = ntohs ( svc->data16[0] );
01571         dest.sl = ibdev->sm_sl;
01572         dest.qpn = IB_QPN_GSI;
01573         dest.qkey = IB_QKEY_GSI;
01574         guid = ( ( union ib_guid * ) &svc->data64[0] );
01575         DBGC2 ( xdev, "XDEV %s found directory at LID %d GUID " IB_GUID_FMT
01576                 "\n", xdev->name, dest.lid, IB_GUID_ARGS ( guid ) );
01577 
01578         /* Construct request (reusing MAD buffer) */
01579         memset ( request, 0, sizeof ( *request ) );
01580         request->mad_hdr.mgmt_class = XSIGO_MGMT_CLASS;
01581         request->mad_hdr.class_version = XSIGO_MGMT_CLASS_VERSION;
01582         request->mad_hdr.method = IB_MGMT_METHOD_GET;
01583         request->mad_hdr.attr_id = htons ( XSIGO_ATTR_XCM_REQUEST );
01584         memcpy ( &request->server.guid, &ibdev->gid.s.guid,
01585                  sizeof ( request->server.guid ) );
01586         snprintf ( request->os_version, sizeof ( request->os_version ),
01587                    "%s %s", product_short_name, product_version );
01588         snprintf ( request->arch, sizeof ( request->arch ), _S2 ( ARCH ) );
01589         request->os_type = XSIGO_OS_TYPE_GENERIC;
01590         request->resources = htons ( XSIGO_RESOURCES_PRESENT |
01591                                      XSIGO_RESOURCE_XVE |
01592                                      XSIGO_RESOURCE_NO_HA );
01593 
01594         /* The handling of this request on the server side is a
01595          * textbook example of how not to design a wire protocol.  The
01596          * server uses the _driver_ version number to determine which
01597          * fields are present.
01598          */
01599         request->driver_version = htonl ( 0x2a2a2a );
01600 
01601         /* The build version field is ignored unless it happens to
01602          * contain the substring "xg-".
01603          */
01604         snprintf ( request->build, sizeof ( request->build ),
01605                    "not-xg-%08lx", build_id );
01606 
01607         /* The server side user interface occasionally has no way to
01608          * refer to an entry with an empty hostname.
01609          */
01610         fetch_string_setting ( NULL, &hostname_setting, request->hostname,
01611                                sizeof ( request->hostname ) );
01612         if ( ! request->hostname[0] ) {
01613                 snprintf ( request->hostname, sizeof ( request->hostname ),
01614                            "%s-" IB_GUID_FMT, product_short_name,
01615                            IB_GUID_ARGS ( &ibdev->gid.s.guid ) );
01616         }
01617 
01618         /* Start configuration manager lookup */
01619         xdev->madx = ib_create_madx ( ibdev, ibdev->gsi, mad, &dest,
01620                                       &xsigo_xcm_discovery.op );
01621         if ( ! xdev->madx ) {
01622                 DBGC ( xdev, "XDEV %s could not start manager lookup\n",
01623                        xdev->name );
01624                 goto out;
01625         }
01626         ib_madx_set_ownerdata ( xdev->madx, xdev );
01627 
01628 out:
01629         /* Destroy the completed transaction */
01630         ib_destroy_madx ( ibdev, ibdev->gsi, madx );
01631 }
01632 
01633 /** Directory service lookup discovery stage */
01634 static struct xsigo_discovery xsigo_xds_discovery = {
01635         .name = "directory",
01636         .op = {
01637                 .complete = xsigo_xds_complete,
01638         },
01639 };
01640 
01641 /**
01642  * Discover configuration managers
01643  *
01644  * @v timer             Retry timer
01645  * @v over              Failure indicator
01646  */
01647 static void xsigo_discover ( struct retry_timer *timer, int over __unused ) {
01648         struct xsigo_device *xdev =
01649                 container_of ( timer, struct xsigo_device, discovery );
01650         struct ib_device *ibdev = xdev->ibdev;
01651         struct xsigo_discovery *discovery;
01652 
01653         /* Restart timer */
01654         start_timer_fixed ( &xdev->discovery, XSIGO_DISCOVERY_FAILURE_DELAY );
01655 
01656         /* Cancel any pending discovery transaction */
01657         if ( xdev->madx ) {
01658                 discovery = container_of ( xdev->madx->op,
01659                                            struct xsigo_discovery, op );
01660                 DBGC ( xdev, "XDEV %s timed out waiting for %s lookup\n",
01661                        xdev->name, discovery->name );
01662                 ib_destroy_madx ( ibdev, ibdev->gsi, xdev->madx );
01663                 xdev->madx = NULL;
01664         }
01665 
01666         /* Start directory service lookup */
01667         xdev->madx = ib_create_service_madx ( ibdev, ibdev->gsi,
01668                                               XDS_SERVICE_NAME,
01669                                               &xsigo_xds_discovery.op );
01670         if ( ! xdev->madx ) {
01671                 DBGC ( xdev, "XDEV %s could not start directory lookup\n",
01672                        xdev->name );
01673                 return;
01674         }
01675         ib_madx_set_ownerdata ( xdev->madx, xdev );
01676 }
01677 
01678 /****************************************************************************
01679  *
01680  * Infiniband device driver
01681  *
01682  ****************************************************************************
01683  */
01684 
01685 /**
01686  * Open link and start discovery
01687  *
01688  * @v opener            Link opener
01689  * @v over              Failure indicator
01690  */
01691 static void xsigo_ib_open ( struct retry_timer *opener, int over __unused ) {
01692         struct xsigo_device *xdev =
01693                 container_of ( opener, struct xsigo_device, opener );
01694         struct ib_device *ibdev = xdev->ibdev;
01695         int rc;
01696 
01697         /* Open Infiniband device */
01698         if ( ( rc = ib_open ( ibdev ) ) != 0 ) {
01699                 DBGC ( xdev, "XDEV %s could not open: %s\n",
01700                        xdev->name, strerror ( rc ) );
01701                 /* Delay and try again */
01702                 start_timer_fixed ( &xdev->opener, XSIGO_OPEN_RETRY_DELAY );
01703                 return;
01704         }
01705 
01706         /* If link is already up, then start discovery */
01707         if ( ib_link_ok ( ibdev ) )
01708                 start_timer_nodelay ( &xdev->discovery );
01709 }
01710 
01711 /**
01712  * Probe Xsigo device
01713  *
01714  * @v ibdev             Infiniband device
01715  * @ret rc              Return status code
01716  */
01717 static int xsigo_ib_probe ( struct ib_device *ibdev ) {
01718         struct xsigo_device *xdev;
01719 
01720         /* Allocate and initialise structure */
01721         xdev = zalloc ( sizeof ( *xdev ) );
01722         if ( ! xdev )
01723                 return -ENOMEM;
01724         ref_init ( &xdev->refcnt, xsigo_free );
01725         xdev->ibdev = ibdev_get ( ibdev );
01726         xdev->name = ibdev->name;
01727         timer_init ( &xdev->opener, xsigo_ib_open, &xdev->refcnt );
01728         timer_init ( &xdev->discovery, xsigo_discover, &xdev->refcnt );
01729         INIT_LIST_HEAD ( &xdev->managers );
01730 
01731         /* Start timer to open Infiniband device.  (We are currently
01732          * within the Infiniband device probe callback list; opening
01733          * the device here would have interesting side-effects.)
01734          */
01735         start_timer_nodelay ( &xdev->opener );
01736 
01737         /* Add to list of devices and transfer reference to list */
01738         list_add_tail ( &xdev->list, &xsigo_devices );
01739         DBGC ( xdev, "XDEV %s created for " IB_GUID_FMT "\n",
01740                xdev->name, IB_GUID_ARGS ( &ibdev->gid.s.guid ) );
01741         return 0;
01742 }
01743 
01744 /**
01745  * Handle device or link status change
01746  *
01747  * @v ibdev             Infiniband device
01748  */
01749 static void xsigo_ib_notify ( struct ib_device *ibdev ) {
01750         struct xsigo_device *xdev;
01751 
01752         /* Stop/restart discovery on any attached devices */
01753         list_for_each_entry ( xdev, &xsigo_devices, list ) {
01754 
01755                 /* Skip non-attached devices */
01756                 if ( xdev->ibdev != ibdev )
01757                         continue;
01758 
01759                 /* Stop any ongoing discovery */
01760                 if ( xdev->madx ) {
01761                         ib_destroy_madx ( ibdev, ibdev->gsi, xdev->madx );
01762                         xdev->madx = NULL;
01763                 }
01764                 stop_timer ( &xdev->discovery );
01765 
01766                 /* If link is up, then start discovery */
01767                 if ( ib_link_ok ( ibdev ) )
01768                         start_timer_nodelay ( &xdev->discovery );
01769         }
01770 }
01771 
01772 /**
01773  * Remove Xsigo device
01774  *
01775  * @v ibdev             Infiniband device
01776  */
01777 static void xsigo_ib_remove ( struct ib_device *ibdev ) {
01778         struct xsigo_device *xdev;
01779         struct xsigo_device *tmp;
01780 
01781         /* Remove any attached Xsigo devices */
01782         list_for_each_entry_safe ( xdev, tmp, &xsigo_devices, list ) {
01783 
01784                 /* Skip non-attached devices */
01785                 if ( xdev->ibdev != ibdev )
01786                         continue;
01787 
01788                 /* Stop any ongoing discovery */
01789                 if ( xdev->madx ) {
01790                         ib_destroy_madx ( ibdev, ibdev->gsi, xdev->madx );
01791                         xdev->madx = NULL;
01792                 }
01793                 stop_timer ( &xdev->discovery );
01794 
01795                 /* Destroy all configuration managers */
01796                 xcm_list ( xdev, NULL, 0 );
01797 
01798                 /* Close Infiniband device, if applicable */
01799                 if ( ! timer_running ( &xdev->opener ) )
01800                         ib_close ( xdev->ibdev );
01801 
01802                 /* Stop link opener */
01803                 stop_timer ( &xdev->opener );
01804 
01805                 /* Remove from list of devices and drop list's reference */
01806                 DBGC ( xdev, "XDEV %s destroyed\n", xdev->name );
01807                 list_del ( &xdev->list );
01808                 ref_put ( &xdev->refcnt );
01809         }
01810 }
01811 
01812 /** Xsigo Infiniband driver */
01813 struct ib_driver xsigo_ib_driver __ib_driver = {
01814         .name = "Xsigo",
01815         .probe = xsigo_ib_probe,
01816         .notify = xsigo_ib_notify,
01817         .remove = xsigo_ib_remove,
01818 };
01819 
01820 /****************************************************************************
01821  *
01822  * Network device driver
01823  *
01824  ****************************************************************************
01825  */
01826 
01827 /**
01828  * Handle device or link status change
01829  *
01830  * @v netdev            Network device
01831  */
01832 static void xsigo_net_notify ( struct net_device *netdev ) {
01833         struct xsigo_device *xdev;
01834         struct ib_device *ibdev;
01835         struct xsigo_manager *xcm;
01836         struct xsigo_nic *xve;
01837         struct eoib_device *eoib;
01838 
01839         /* Send current operational state to XCM, if applicable */
01840         list_for_each_entry ( xdev, &xsigo_devices, list ) {
01841                 ibdev = xdev->ibdev;
01842                 list_for_each_entry ( xcm, &xdev->managers, list ) {
01843                         list_for_each_entry ( xve, &xcm->nics, list ) {
01844                                 eoib = eoib_find ( ibdev, xve->mac );
01845                                 if ( ! eoib )
01846                                         continue;
01847                                 if ( eoib->netdev != netdev )
01848                                         continue;
01849                                 xsmp_tx_xve_oper ( xcm, xve, eoib );
01850                         }
01851                 }
01852         }
01853 }
01854 
01855 /** Xsigo network driver */
01856 struct net_driver xsigo_net_driver __net_driver = {
01857         .name = "Xsigo",
01858         .notify = xsigo_net_notify,
01859 };