1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 /*
  28  * Xen inter-domain backend - GLDv3 driver edition.
  29  *
  30  * A traditional GLDv3 driver used to communicate with a guest
  31  * domain.  This driver is typically plumbed underneath the IP stack
  32  * or a software ethernet bridge.
  33  */
  34 
  35 #include "xnb.h"
  36 
  37 #include <sys/sunddi.h>
  38 #include <sys/conf.h>
  39 #include <sys/modctl.h>
  40 #include <sys/strsubr.h>
  41 #include <sys/dlpi.h>
  42 #include <sys/pattr.h>
  43 #include <sys/mac_provider.h>
  44 #include <sys/mac_ether.h>
  45 #include <xen/sys/xendev.h>
  46 #include <sys/note.h>
  47 
  48 /* Required driver entry points for GLDv3 */
  49 static int      xnbu_m_start(void *);
  50 static void     xnbu_m_stop(void *);
  51 static int      xnbu_m_set_mac_addr(void *, const uint8_t *);
  52 static int      xnbu_m_set_multicast(void *, boolean_t, const uint8_t *);
  53 static int      xnbu_m_set_promiscuous(void *, boolean_t);
  54 static int      xnbu_m_stat(void *, uint_t, uint64_t *);
  55 static boolean_t xnbu_m_getcapab(void *, mac_capab_t, void *);
  56 static mblk_t   *xnbu_m_send(void *, mblk_t *);
  57 
  58 typedef struct xnbu {
  59         mac_handle_t            u_mh;
  60         boolean_t               u_need_sched;
  61 } xnbu_t;
  62 
  63 static mac_callbacks_t xnbu_callbacks = {
  64         MC_GETCAPAB,
  65         xnbu_m_stat,
  66         xnbu_m_start,
  67         xnbu_m_stop,
  68         xnbu_m_set_promiscuous,
  69         xnbu_m_set_multicast,
  70         xnbu_m_set_mac_addr,
  71         xnbu_m_send,
  72         NULL,
  73         NULL,
  74         xnbu_m_getcapab
  75 };
  76 
  77 static void
  78 xnbu_to_host(xnb_t *xnbp, mblk_t *mp)
  79 {
  80         xnbu_t *xnbup = xnbp->xnb_flavour_data;
  81         boolean_t sched = B_FALSE;
  82 
  83         ASSERT(mp != NULL);
  84 
  85         mac_rx(xnbup->u_mh, NULL, mp);
  86 
  87         mutex_enter(&xnbp->xnb_rx_lock);
  88 
  89         /*
  90          * If a transmit attempt failed because we ran out of ring
  91          * space and there is now some space, re-enable the transmit
  92          * path.
  93          */
  94         if (xnbup->u_need_sched &&
  95             RING_HAS_UNCONSUMED_REQUESTS(&xnbp->xnb_rx_ring)) {
  96                 sched = B_TRUE;
  97                 xnbup->u_need_sched = B_FALSE;
  98         }
  99 
 100         mutex_exit(&xnbp->xnb_rx_lock);
 101 
 102         if (sched)
 103                 mac_tx_update(xnbup->u_mh);
 104 }
 105 
 106 static mblk_t *
 107 xnbu_cksum_from_peer(xnb_t *xnbp, mblk_t *mp, uint16_t flags)
 108 {
 109         /*
 110          * Take a conservative approach - if the checksum is blank
 111          * then we fill it in.
 112          *
 113          * If the consumer of the packet is IP then we might actually
 114          * only need fill it in if the data is not validated, but how
 115          * do we know who might end up with the packet?
 116          */
 117 
 118         if ((flags & NETTXF_csum_blank) != 0) {
 119                 /*
 120                  * The checksum is blank.  We must fill it in here.
 121                  */
 122                 mp = xnb_process_cksum_flags(xnbp, mp, 0);
 123 
 124                 /*
 125                  * Because we calculated the checksum ourselves we
 126                  * know that it must be good, so we assert this.
 127                  */
 128                 flags |= NETTXF_data_validated;
 129         }
 130 
 131         if ((flags & NETTXF_data_validated) != 0) {
 132                 /*
 133                  * The checksum is asserted valid.
 134                  */
 135                 mac_hcksum_set(mp, 0, 0, 0, 0, HCK_FULLCKSUM_OK);
 136         }
 137 
 138         return (mp);
 139 }
 140 
 141 static uint16_t
 142 xnbu_cksum_to_peer(xnb_t *xnbp, mblk_t *mp)
 143 {
 144         _NOTE(ARGUNUSED(xnbp));
 145         uint16_t r = 0;
 146         uint32_t pflags;
 147 
 148         mac_hcksum_get(mp, NULL, NULL, NULL, NULL, &pflags);
 149 
 150         /*
 151          * If the protocol stack has requested checksum
 152          * offload, inform the peer that we have not
 153          * calculated the checksum.
 154          */
 155         if ((pflags & HCK_FULLCKSUM) != 0)
 156                 r |= NETRXF_csum_blank;
 157 
 158         return (r);
 159 }
 160 
 161 static boolean_t
 162 xnbu_start_connect(xnb_t *xnbp)
 163 {
 164         xnbu_t *xnbup = xnbp->xnb_flavour_data;
 165 
 166         mac_link_update(xnbup->u_mh, LINK_STATE_UP);
 167         /*
 168          * We are able to send packets now - bring them on.
 169          */
 170         mac_tx_update(xnbup->u_mh);
 171 
 172         return (B_TRUE);
 173 }
 174 
 175 static boolean_t
 176 xnbu_peer_connected(xnb_t *xnbp)
 177 {
 178         _NOTE(ARGUNUSED(xnbp));
 179 
 180         return (B_TRUE);
 181 }
 182 
 183 static void
 184 xnbu_peer_disconnected(xnb_t *xnbp)
 185 {
 186         xnbu_t *xnbup = xnbp->xnb_flavour_data;
 187 
 188         mac_link_update(xnbup->u_mh, LINK_STATE_DOWN);
 189 }
 190 
 191 /*ARGSUSED*/
 192 static boolean_t
 193 xnbu_hotplug_connected(xnb_t *xnbp)
 194 {
 195         return (B_TRUE);
 196 }
 197 
 198 static mblk_t *
 199 xnbu_m_send(void *arg, mblk_t *mp)
 200 {
 201         xnb_t *xnbp = arg;
 202         xnbu_t *xnbup = xnbp->xnb_flavour_data;
 203         boolean_t sched = B_FALSE;
 204 
 205         mp = xnb_copy_to_peer(arg, mp);
 206 
 207         mutex_enter(&xnbp->xnb_rx_lock);
 208         /*
 209          * If we consumed all of the mblk_t's offered, perhaps we need
 210          * to indicate that we can accept more.  Otherwise we are full
 211          * and need to wait for space.
 212          */
 213         if (mp == NULL) {
 214                 sched = xnbup->u_need_sched;
 215                 xnbup->u_need_sched = B_FALSE;
 216         } else {
 217                 xnbup->u_need_sched = B_TRUE;
 218         }
 219         mutex_exit(&xnbp->xnb_rx_lock);
 220 
 221         /*
 222          * If a previous transmit attempt failed because the ring
 223          * was full, try again now.
 224          */
 225         if (sched)
 226                 mac_tx_update(xnbup->u_mh);
 227 
 228         return (mp);
 229 }
 230 
 231 /*
 232  *  xnbu_m_set_mac_addr() -- set the physical network address on the board
 233  */
 234 /* ARGSUSED */
 235 static int
 236 xnbu_m_set_mac_addr(void *arg, const uint8_t *macaddr)
 237 {
 238         xnb_t *xnbp = arg;
 239         xnbu_t *xnbup = xnbp->xnb_flavour_data;
 240 
 241         bcopy(macaddr, xnbp->xnb_mac_addr, ETHERADDRL);
 242         mac_unicst_update(xnbup->u_mh, xnbp->xnb_mac_addr);
 243 
 244         return (0);
 245 }
 246 
 247 /*
 248  *  xnbu_m_set_multicast() -- set (enable) or disable a multicast address
 249  */
 250 /*ARGSUSED*/
 251 static int
 252 xnbu_m_set_multicast(void *arg, boolean_t add, const uint8_t *mca)
 253 {
 254         /*
 255          * We always accept all packets from the peer, so nothing to
 256          * do for enable or disable.
 257          */
 258         return (0);
 259 }
 260 
 261 
 262 /*
 263  * xnbu_m_set_promiscuous() -- set or reset promiscuous mode on the board
 264  */
 265 /* ARGSUSED */
 266 static int
 267 xnbu_m_set_promiscuous(void *arg, boolean_t on)
 268 {
 269         /*
 270          * We always accept all packets from the peer, so nothing to
 271          * do for enable or disable.
 272          */
 273         return (0);
 274 }
 275 
 276 /*
 277  *  xnbu_m_start() -- start the board receiving and enable interrupts.
 278  */
 279 /*ARGSUSED*/
 280 static int
 281 xnbu_m_start(void *arg)
 282 {
 283         return (0);
 284 }
 285 
 286 /*
 287  * xnbu_m_stop() - disable hardware
 288  */
 289 /*ARGSUSED*/
 290 static void
 291 xnbu_m_stop(void *arg)
 292 {
 293 }
 294 
 295 static int
 296 xnbu_m_stat(void *arg, uint_t stat, uint64_t *val)
 297 {
 298         xnb_t *xnbp = arg;
 299 
 300         mutex_enter(&xnbp->xnb_tx_lock);
 301         mutex_enter(&xnbp->xnb_rx_lock);
 302 
 303 #define map_stat(q, r)                          \
 304         case (MAC_STAT_##q):                    \
 305                 *val = xnbp->xnb_stat_##r;   \
 306                 break
 307 
 308         switch (stat) {
 309 
 310         map_stat(IPACKETS, opackets);
 311         map_stat(OPACKETS, ipackets);
 312         map_stat(RBYTES, obytes);
 313         map_stat(OBYTES, rbytes);
 314 
 315         default:
 316                 mutex_exit(&xnbp->xnb_rx_lock);
 317                 mutex_exit(&xnbp->xnb_tx_lock);
 318 
 319                 return (ENOTSUP);
 320         }
 321 
 322 #undef map_stat
 323 
 324         mutex_exit(&xnbp->xnb_rx_lock);
 325         mutex_exit(&xnbp->xnb_tx_lock);
 326 
 327         return (0);
 328 }
 329 
 330 static boolean_t
 331 xnbu_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
 332 {
 333         _NOTE(ARGUNUSED(arg));
 334 
 335         switch (cap) {
 336         case MAC_CAPAB_HCKSUM: {
 337                 uint32_t *capab = cap_data;
 338 
 339                 *capab = HCKSUM_INET_PARTIAL;
 340                 break;
 341         }
 342         default:
 343                 return (B_FALSE);
 344         }
 345 
 346         return (B_TRUE);
 347 }
 348 
 349 /*
 350  * All packets are passed to the peer, so adding and removing
 351  * multicast addresses is meaningless.
 352  */
 353 static boolean_t
 354 xnbu_mcast_add(xnb_t *xnbp, ether_addr_t *addr)
 355 {
 356         _NOTE(ARGUNUSED(xnbp, addr));
 357 
 358         return (B_TRUE);
 359 }
 360 
 361 static boolean_t
 362 xnbu_mcast_del(xnb_t *xnbp, ether_addr_t *addr)
 363 {
 364         _NOTE(ARGUNUSED(xnbp, addr));
 365 
 366         return (B_TRUE);
 367 }
 368 
 369 static int
 370 xnbu_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
 371 {
 372         static xnb_flavour_t flavour = {
 373                 xnbu_to_host, xnbu_peer_connected, xnbu_peer_disconnected,
 374                 xnbu_hotplug_connected, xnbu_start_connect,
 375                 xnbu_cksum_from_peer, xnbu_cksum_to_peer,
 376                 xnbu_mcast_add, xnbu_mcast_del,
 377         };
 378         xnbu_t *xnbup;
 379         xnb_t *xnbp;
 380         mac_register_t *mr;
 381         int err;
 382 
 383         switch (cmd) {
 384         case DDI_ATTACH:
 385                 break;
 386         case DDI_RESUME:
 387                 return (DDI_SUCCESS);
 388         default:
 389                 return (DDI_FAILURE);
 390         }
 391 
 392         xnbup = kmem_zalloc(sizeof (*xnbup), KM_SLEEP);
 393 
 394         if ((mr = mac_alloc(MAC_VERSION)) == NULL) {
 395                 kmem_free(xnbup, sizeof (*xnbup));
 396                 return (DDI_FAILURE);
 397         }
 398 
 399         if (xnb_attach(dip, &flavour, xnbup) != DDI_SUCCESS) {
 400                 mac_free(mr);
 401                 kmem_free(xnbup, sizeof (*xnbup));
 402                 return (DDI_FAILURE);
 403         }
 404 
 405         xnbp = ddi_get_driver_private(dip);
 406         ASSERT(xnbp != NULL);
 407 
 408         mr->m_dip = dip;
 409         mr->m_driver = xnbp;
 410 
 411         /*
 412          *  Initialize pointers to device specific functions which will be
 413          *  used by the generic layer.
 414          */
 415         mr->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
 416         mr->m_src_addr = xnbp->xnb_mac_addr;
 417         mr->m_callbacks = &xnbu_callbacks;
 418         mr->m_min_sdu = 0;
 419         mr->m_max_sdu = XNBMAXPKT;
 420         /*
 421          * xnbu is a virtual device, and it is not associated with any
 422          * physical device. Its margin size is determined by the maximum
 423          * packet size it can handle, which is PAGESIZE.
 424          */
 425         mr->m_margin = PAGESIZE - XNBMAXPKT - sizeof (struct ether_header);
 426 
 427         (void) memset(xnbp->xnb_mac_addr, 0xff, ETHERADDRL);
 428         xnbp->xnb_mac_addr[0] &= 0xfe;
 429         xnbup->u_need_sched = B_FALSE;
 430 
 431         /*
 432          * Register ourselves with the GLDv3 interface.
 433          */
 434         err = mac_register(mr, &xnbup->u_mh);
 435         mac_free(mr);
 436         if (err != 0) {
 437                 xnb_detach(dip);
 438                 kmem_free(xnbup, sizeof (*xnbup));
 439                 return (DDI_FAILURE);
 440         }
 441 
 442         mac_link_update(xnbup->u_mh, LINK_STATE_DOWN);
 443 
 444         return (DDI_SUCCESS);
 445 }
 446 
 447 /*ARGSUSED*/
 448 int
 449 xnbu_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
 450 {
 451         xnb_t *xnbp = ddi_get_driver_private(dip);
 452         xnbu_t *xnbup = xnbp->xnb_flavour_data;
 453 
 454         switch (cmd) {
 455         case DDI_DETACH:
 456                 break;
 457         case DDI_SUSPEND:
 458                 return (DDI_SUCCESS);
 459         default:
 460                 return (DDI_FAILURE);
 461         }
 462 
 463         ASSERT(xnbp != NULL);
 464         ASSERT(xnbup != NULL);
 465 
 466         mutex_enter(&xnbp->xnb_tx_lock);
 467         mutex_enter(&xnbp->xnb_rx_lock);
 468 
 469         if (!xnbp->xnb_detachable || xnbp->xnb_connected ||
 470             (xnbp->xnb_tx_buf_count > 0)) {
 471                 mutex_exit(&xnbp->xnb_rx_lock);
 472                 mutex_exit(&xnbp->xnb_tx_lock);
 473 
 474                 return (DDI_FAILURE);
 475         }
 476 
 477         mutex_exit(&xnbp->xnb_rx_lock);
 478         mutex_exit(&xnbp->xnb_tx_lock);
 479 
 480         /*
 481          * Attempt to unregister the mac.
 482          */
 483         if ((xnbup->u_mh != NULL) && (mac_unregister(xnbup->u_mh) != 0))
 484                 return (DDI_FAILURE);
 485         kmem_free(xnbup, sizeof (*xnbup));
 486 
 487         xnb_detach(dip);
 488 
 489         return (DDI_SUCCESS);
 490 }
 491 
 492 DDI_DEFINE_STREAM_OPS(ops, nulldev, nulldev, xnbu_attach, xnbu_detach,
 493     nodev, NULL, D_MP, NULL, ddi_quiesce_not_supported);
 494 
 495 static struct modldrv modldrv = {
 496         &mod_driverops, "xnbu driver", &ops
 497 };
 498 
 499 static struct modlinkage modlinkage = {
 500         MODREV_1, { &modldrv, NULL }
 501 };
 502 
 503 int
 504 _init(void)
 505 {
 506         int i;
 507 
 508         mac_init_ops(&ops, "xnbu");
 509 
 510         i = mod_install(&modlinkage);
 511         if (i != DDI_SUCCESS)
 512                 mac_fini_ops(&ops);
 513 
 514         return (i);
 515 }
 516 
 517 int
 518 _fini(void)
 519 {
 520         int i;
 521 
 522         i = mod_remove(&modlinkage);
 523         if (i == DDI_SUCCESS)
 524                 mac_fini_ops(&ops);
 525 
 526         return (i);
 527 }
 528 
 529 int
 530 _info(struct modinfo *modinfop)
 531 {
 532         return (mod_info(&modlinkage, modinfop));
 533 }