aboutsummaryrefslogtreecommitdiffstats
path: root/scripts/docproc.c
diff options
context:
space:
mode:
authorAnish Bhatt <anish@chelsio.com>2014-10-16 18:59:19 -0400
committerChristoph Hellwig <hch@lst.de>2014-10-28 04:57:00 -0400
commitdd9ad67e9bcb71e2efeb5b2f38c9202c013aa74c (patch)
treed4d4343e5c1c0d72d533041854096ec7d1caf73c /scripts/docproc.c
parentb1dd2aac4cc0892b82ec60232ed37e3b0af776cc (diff)
libcxgbi : support ipv6 address host_param
libcxgbi was always returning an ipv4 address for ISCSI_HOST_PARAM_IPADDRESS, return appropriate address based on address family Signed-off-by: Anish Bhatt <anish@chelsio.com> Signed-off-by: Karen Xie <kxie@chelsio.com> Reviewed-by: Mike Christie <michaelc@cs.wisc.edu> Signed-off-by: Christoph Hellwig <hch@lst.de>
Diffstat (limited to 'scripts/docproc.c')
0 files changed, 0 insertions, 0 deletions
/a> 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534
/*P:050
 * Lguest guests use a very simple method to describe devices.  It's a
 * series of device descriptors contained just above the top of normal Guest
 * memory.
 *
 * We use the standard "virtio" device infrastructure, which provides us with a
 * console, a network and a block driver.  Each one expects some configuration
 * information and a "virtqueue" or two to send and receive data.
:*/
#include <linux/init.h>
#include <linux/bootmem.h>
#include <linux/lguest_launcher.h>
#include <linux/virtio.h>
#include <linux/virtio_config.h>
#include <linux/interrupt.h>
#include <linux/virtio_ring.h>
#include <linux/err.h>
#include <linux/export.h>
#include <linux/slab.h>
#include <asm/io.h>
#include <asm/paravirt.h>
#include <asm/lguest_hcall.h>

/* The pointer to our (page) of device descriptions. */
static void *lguest_devices;

/*
 * For Guests, device memory can be used as normal memory, so we cast away the
 * __iomem to quieten sparse.
 */
static inline void *lguest_map(unsigned long phys_addr, unsigned long pages)
{
	return (__force void *)ioremap_cache(phys_addr, PAGE_SIZE*pages);
}

static inline void lguest_unmap(void *addr)
{
	iounmap((__force void __iomem *)addr);
}

/*D:100
 * Each lguest device is just a virtio device plus a pointer to its entry
 * in the lguest_devices page.
 */
struct lguest_device {
	struct virtio_device vdev;

	/* The entry in the lguest_devices page for this device. */
	struct lguest_device_desc *desc;
};

/*
 * Since the virtio infrastructure hands us a pointer to the virtio_device all
 * the time, it helps to have a curt macro to get a pointer to the struct
 * lguest_device it's enclosed in.
 */
#define to_lgdev(vd) container_of(vd, struct lguest_device, vdev)

/*D:130
 * Device configurations
 *
 * The configuration information for a device consists of one or more
 * virtqueues, a feature bitmap, and some configuration bytes.  The
 * configuration bytes don't really matter to us: the Launcher sets them up, and
 * the driver will look at them during setup.
 *
 * A convenient routine to return the device's virtqueue config array:
 * immediately after the descriptor.
 */
static struct lguest_vqconfig *lg_vq(const struct lguest_device_desc *desc)
{
	return (void *)(desc + 1);
}

/* The features come immediately after the virtqueues. */
static u8 *lg_features(const struct lguest_device_desc *desc)
{
	return (void *)(lg_vq(desc) + desc->num_vq);
}

/* The config space comes after the two feature bitmasks. */
static u8 *lg_config(const struct lguest_device_desc *desc)
{
	return lg_features(desc) + desc->feature_len * 2;
}

/* The total size of the config page used by this device (incl. desc) */
static unsigned desc_size(const struct lguest_device_desc *desc)
{
	return sizeof(*desc)
		+ desc->num_vq * sizeof(struct lguest_vqconfig)
		+ desc->feature_len * 2
		+ desc->config_len;
}

/* This gets the device's feature bits. */
static u32 lg_get_features(struct virtio_device *vdev)
{
	unsigned int i;
	u32 features = 0;
	struct lguest_device_desc *desc = to_lgdev(vdev)->desc;
	u8 *in_features = lg_features(desc);

	/* We do this the slow but generic way. */
	for (i = 0; i < min(desc->feature_len * 8, 32); i++)
		if (in_features[i / 8] & (1 << (i % 8)))
			features |= (1 << i);

	return features;
}

/*
 * To notify on reset or feature finalization, we (ab)use the NOTIFY
 * hypercall, with the descriptor address of the device.
 */
static void status_notify(struct virtio_device *vdev)
{
	unsigned long offset = (void *)to_lgdev(vdev)->desc - lguest_devices;

	hcall(LHCALL_NOTIFY, (max_pfn << PAGE_SHIFT) + offset, 0, 0, 0);
}

/*
 * The virtio core takes the features the Host offers, and copies the ones
 * supported by the driver into the vdev->features array.  Once that's all
 * sorted out, this routine is called so we can tell the Host which features we
 * understand and accept.
 */
static void lg_finalize_features(struct virtio_device *vdev)
{
	unsigned int i, bits;
	struct lguest_device_desc *desc = to_lgdev(vdev)->desc;
	/* Second half of bitmap is features we accept. */
	u8 *out_features = lg_features(desc) + desc->feature_len;

	/* Give virtio_ring a chance to accept features. */
	vring_transport_features(vdev);

	/*
	 * The vdev->feature array is a Linux bitmask: this isn't the same as a
	 * the simple array of bits used by lguest devices for features.  So we
	 * do this slow, manual conversion which is completely general.
	 */
	memset(out_features, 0, desc->feature_len);
	bits = min_t(unsigned, desc->feature_len, sizeof(vdev->features)) * 8;
	for (i = 0; i < bits; i++) {
		if (test_bit(i, vdev->features))
			out_features[i / 8] |= (1 << (i % 8));
	}

	/* Tell Host we've finished with this device's feature negotiation */
	status_notify(vdev);
}

/* Once they've found a field, getting a copy of it is easy. */
static void lg_get(struct virtio_device *vdev, unsigned int offset,
		   void *buf, unsigned len)
{
	struct lguest_device_desc *desc = to_lgdev(vdev)->desc;

	/* Check they didn't ask for more than the length of the config! */
	BUG_ON(offset + len > desc->config_len);
	memcpy(buf, lg_config(desc) + offset, len);
}

/* Setting the contents is also trivial. */
static void lg_set(struct virtio_device *vdev, unsigned int offset,
		   const void *buf, unsigned len)
{
	struct lguest_device_desc *desc = to_lgdev(vdev)->desc;

	/* Check they didn't ask for more than the length of the config! */
	BUG_ON(offset + len > desc->config_len);
	memcpy(lg_config(desc) + offset, buf, len);
}

/*
 * The operations to get and set the status word just access the status field
 * of the device descriptor.
 */
static u8 lg_get_status(struct virtio_device *vdev)
{
	return to_lgdev(vdev)->desc->status;
}

static void lg_set_status(struct virtio_device *vdev, u8 status)
{
	BUG_ON(!status);
	to_lgdev(vdev)->desc->status = status;

	/* Tell Host immediately if we failed. */
	if (status & VIRTIO_CONFIG_S_FAILED)
		status_notify(vdev);
}

static void lg_reset(struct virtio_device *vdev)
{
	/* 0 status means "reset" */
	to_lgdev(vdev)->desc->status = 0;
	status_notify(vdev);
}

/*
 * Virtqueues
 *
 * The other piece of infrastructure virtio needs is a "virtqueue": a way of
 * the Guest device registering buffers for the other side to read from or
 * write into (ie. send and receive buffers).  Each device can have multiple
 * virtqueues: for example the console driver uses one queue for sending and
 * another for receiving.
 *
 * Fortunately for us, a very fast shared-memory-plus-descriptors virtqueue
 * already exists in virtio_ring.c.  We just need to connect it up.
 *
 * We start with the information we need to keep about each virtqueue.
 */

/*D:140 This is the information we remember about each virtqueue. */
struct lguest_vq_info {
	/* A copy of the information contained in the device config. */
	struct lguest_vqconfig config;

	/* The address where we mapped the virtio ring, so we can unmap it. */
	void *pages;
};

/*
 * When the virtio_ring code wants to prod the Host, it calls us here and we
 * make a hypercall.  We hand the physical address of the virtqueue so the Host
 * knows which virtqueue we're talking about.
 */
static void lg_notify(struct virtqueue *vq)
{
	/*
	 * We store our virtqueue information in the "priv" pointer of the
	 * virtqueue structure.
	 */
	struct lguest_vq_info *lvq = vq->priv;

	hcall(LHCALL_NOTIFY, lvq->config.pfn << PAGE_SHIFT, 0, 0, 0);
}

/* An extern declaration inside a C file is bad form.  Don't do it. */
extern int lguest_setup_irq(unsigned int irq);

/*
 * This routine finds the Nth virtqueue described in the configuration of
 * this device and sets it up.
 *
 * This is kind of an ugly duckling.  It'd be nicer to have a standard
 * representation of a virtqueue in the configuration space, but it seems that
 * everyone wants to do it differently.  The KVM coders want the Guest to
 * allocate its own pages and tell the Host where they are, but for lguest it's
 * simpler for the Host to simply tell us where the pages are.
 */
static struct virtqueue *lg_find_vq(struct virtio_device *vdev,
				    unsigned index,
				    void (*callback)(struct virtqueue *vq),
				    const char *name)
{
	struct lguest_device *ldev = to_lgdev(vdev);
	struct lguest_vq_info *lvq;
	struct virtqueue *vq;
	int err;

	if (!name)
		return NULL;

	/* We must have this many virtqueues. */
	if (index >= ldev->desc->num_vq)