[patch 5/8] staging: visoruislib driver used to handle requests from virtpci

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The visoruislib module is a support library, used to handle requests
from virtpci.

Signed-off-by: Ken Cox <jkc@xxxxxxxxxx>
Cc: Ben Romer <sparmaintainer@xxxxxxxxxx>

Index: linux-2.6.staging/drivers/staging/unisys/Kconfig
===================================================================
--- linux-2.6.staging.orig/drivers/staging/unisys/Kconfig
+++ linux-2.6.staging/drivers/staging/unisys/Kconfig
@@ -13,5 +13,6 @@ source "drivers/staging/unisys/visorutil
 source "drivers/staging/unisys/visorchannel/Kconfig"
 source "drivers/staging/unisys/visorchipset/Kconfig"
 source "drivers/staging/unisys/channels/Kconfig"
+source "drivers/staging/unisys/uislib/Kconfig"

 endif # UNISYSSPAR
Index: linux-2.6.staging/drivers/staging/unisys/Makefile
===================================================================
--- linux-2.6.staging.orig/drivers/staging/unisys/Makefile
+++ linux-2.6.staging/drivers/staging/unisys/Makefile
@@ -5,4 +5,4 @@ obj-$(CONFIG_UNISYS_VISORUTIL)        += visor
 obj-$(CONFIG_UNISYS_VISORCHANNEL)    += visorchannel/
 obj-$(CONFIG_UNISYS_VISORCHIPSET)    += visorchipset/
 obj-$(CONFIG_UNISYS_CHANNELSTUB)    += channels/
-
+obj-$(CONFIG_UNISYS_UISLIB)        += uislib/
Index: linux-2.6.staging/drivers/staging/unisys/include/sparstop.h
===================================================================
--- /dev/null
+++ linux-2.6.staging/drivers/staging/unisys/include/sparstop.h
@@ -0,0 +1,30 @@
+/* sparstop.h
+ *
+ * Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ */
+
+#ifndef __SPARSTOP_H__
+#define __SPARSTOP_H__
+
+#include "timskmod.h"
+#include "version.h"
+#include <linux/ctype.h>
+
+typedef void (*SPARSTOP_COMPLETE_FUNC) (void *context, int status);
+
+int sp_stop(void *context, SPARSTOP_COMPLETE_FUNC get_complete_func);
+void test_remove_stop_device(void);
+
+#endif
Index: linux-2.6.staging/drivers/staging/unisys/uislib/Kconfig
===================================================================
--- /dev/null
+++ linux-2.6.staging/drivers/staging/unisys/uislib/Kconfig
@@ -0,0 +1,10 @@
+#
+# Unisys uislib configuration
+#
+
+config UNISYS_UISLIB
+    tristate "Unisys uislib driver"
+    depends on UNISYSSPAR && UNISYS_VISORCHIPSET && UNISYS_CHANNELSTUB
+    ---help---
+    If you say Y here, you will enable the Unisys uislib driver.
+
Index: linux-2.6.staging/drivers/staging/unisys/uislib/Makefile
===================================================================
--- /dev/null
+++ linux-2.6.staging/drivers/staging/unisys/uislib/Makefile
@@ -0,0 +1,17 @@
+#
+# Makefile for Unisys uislib
+#
+
+obj-$(CONFIG_UNISYS_UISLIB)    += visoruislib.o
+
+visoruislib-y := uislib.o uisqueue.o  uisthread.o  uisutils.o
+
+ccflags-y += -Idrivers/staging/unisys/include
+ccflags-y += -Idrivers/staging/unisys/channels
+ccflags-y += -Idrivers/staging/unisys/visorchipset
+ccflags-y += -Idrivers/staging/unisys/sparstopdriver
+ccflags-y += -Idrivers/staging/unisys/common-spar/include
+ccflags-y += -Idrivers/staging/unisys/common-spar/include/channels
+
+ccflags-y += -DCONFIG_SPAR_GUEST -DGUESTDRIVERBUILD -DNOAUTOVERSION
+
Index: linux-2.6.staging/drivers/staging/unisys/uislib/uislib.c
===================================================================
--- /dev/null
+++ linux-2.6.staging/drivers/staging/unisys/uislib/uislib.c
@@ -0,0 +1,2536 @@
+/* uislib.c
+ *
+ * Copyright � 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ */
+
+/* @ALL_INSPECTED */
+#define EXPORT_SYMTAB
+#include <linux/kernel.h>
+#include <linux/highmem.h>
+#ifdef CONFIG_MODVERSIONS
+#include <config/modversions.h>
+#endif
+#include <linux/module.h>
+
+#include "commontypes.h"
+
+#include <linux/version.h>
+#include "uniklog.h"
+#include "diagnostics/appos_subsystems.h"
+#include "uisutils.h"
+#include "vbuschannel.h"
+
+#include <linux/proc_fs.h>
+#include <linux/uaccess.h>    /* for copy_from_user */
+#include <linux/ctype.h>    /* for toupper */
+#include <linux/list.h>
+
+#include "sparstop.h"
+#include "visorchipset.h"
+#include "chanstub.h"
+#include "version.h"
+#include "guestlinuxdebug.h"
+
+#define SET_PROC_OWNER(x, y)
+
+#define UISLIB_TEST_PROC
+#define POLLJIFFIES_NORMAL 1
+/* Choose whether or not you want to wakeup the request-polling thread
+ * after an IO termination:
+ * this is shorter than using __FILE__ (full path name) in
+ * debug/info/error messages
+ */
+#define CURRENT_FILE_PC UISLIB_PC_uislib_c
+#define __MYFILE__ "uislib.c"
+
+/* global function pointers that act as callback functions into virtpcimod */
+int (*VirtControlChanFunc)(struct guest_msgs *);
+
+static int ProcReadBufferValid;
+static char *ProcReadBuffer;    /* Note this MUST be global,
+                     * because the contents must */
+static unsigned int chipset_inited;
+int callback_count = 0;
+#define WAIT_ON_CALLBACK(handle)    \
+    do {            \
+        if (handle)        \
+            break;        \
+        UIS_THREAD_WAIT;    \
+    } while (1)
+
+static struct bus_info *BusListHead;
+static rwlock_t BusListLock;
+static int BusListCount;    /* number of buses in the list */
+static int MaxBusCount;        /* maximum number of buses expected */
+static U64 PhysicalDataChan;
+static int PlatformNumber;
+
+/* This is a list of controlvm messages which could not complete
+ * immediately, but instead must be occasionally retried until they
+ * ultimately succeed/fail.  When this happens,
+ * msg->hdr.Flags.responseExpected determines whether or not we will
+ * send a controlvm response.
+ */
+struct controlvm_retry_entry {
+    CONTROLVM_MESSAGE msg;
+    struct io_msgs cmd;
+    void *obj;
+    int (*controlChanFunc)(struct io_msgs *);
+    struct list_head list_link;
+};
+LIST_HEAD(ControlVmRetryQHead);
+
+static struct uisthread_info Incoming_ThreadInfo;
+static BOOL Incoming_Thread_Started = FALSE;
+LIST_HEAD(List_Polling_Device_Channels);
+unsigned long long tot_moved_to_tail_cnt = 0;
+unsigned long long tot_wait_cnt = 0;
+unsigned long long tot_wakeup_cnt = 0;
+unsigned long long tot_schedule_cnt = 0;
+int en_smart_wakeup = 1;
+static DEFINE_SEMAPHORE(Lock_Polling_Device_Channels);    /* unlocked */
+DECLARE_WAIT_QUEUE_HEAD(Wakeup_Polling_Device_Channels);
+static int Go_Polling_Device_Channels;
+
+static struct proc_dir_entry *uislib_proc_dir;
+static struct proc_dir_entry *uislib_proc_vbus_dir;
+static struct proc_dir_entry *vnic_proc_entry; /* Used to be "datachan" */
+static struct proc_dir_entry *ctrlchan_proc_entry;
+static struct proc_dir_entry *pmem_proc_entry;
+static struct proc_dir_entry *info_proc_entry;
+static struct proc_dir_entry *switch_proc_entry;
+static struct proc_dir_entry *extport_proc_entry;
+static struct proc_dir_entry *platformnumber_proc_entry;
+static struct proc_dir_entry *bus_proc_entry;
+static struct proc_dir_entry *dev_proc_entry;
+static struct proc_dir_entry *chipset_proc_entry;
+static struct proc_dir_entry *cycles_before_wait_proc_entry;
+static struct proc_dir_entry *reset_counts_proc_entry;
+static struct proc_dir_entry *smart_wakeup_proc_entry;
+static struct proc_dir_entry *disable_proc_entry;
+
+#define DIR_PROC_ENTRY "uislib"
+#define DIR_VBUS_PROC_ENTRY "vbus"
+#define VNIC_PROC_ENTRY_FN "vnic"    /* Used to be "datachan" */
+#define CTRLCHAN_PROC_ENTRY_FN "ctrlchan"
+#define PMEM_PROC_ENTRY_FN "phys_to_virt"
+#define INFO_PROC_ENTRY_FN "info"
+#define SWITCH_PROC_ENTRY_FN "switch"
+#define SWITCH_COUNT_PROC_ENTRY_FN "switch_count"
+#define EXTPORT_PROC_ENTRY_FN "extport"
+#define PLATFORMNUMBER_PROC_ENTRY_FN "platform"
+#define BUS_PROC_ENTRY_FN "bus"
+#define DEV_PROC_ENTRY_FN "device"
+#define CHIPSET_PROC_ENTRY_FN "chipset"
+#define CYCLES_BEFORE_WAIT_PROC_ENTRY_FN "cycles_before_wait"
+#define RESET_COUNTS_PROC_ENTRY_FN "reset_counts"
+#define SMART_WAKEUP_PROC_ENTRY_FN "smart_wakeup"
+#define CALLHOME_PROC_ENTRY_FN "callhome"
+#define CALLHOME_THROTTLED_PROC_ENTRY_FN "callhome_throttled"
+#define DISABLE_PROC_ENTRY_FN "switch_state"
+#ifdef UISLIB_TEST_PROC
+static struct proc_dir_entry *test_proc_entry;
+#define TEST_PROC_ENTRY_FN "test"
+#endif
+unsigned long long cycles_before_wait, wait_cycles;
+
+/*****************************************************/
+/* local functions                                   */
+/*****************************************************/
+
+static int proc_info_vbus_show(struct seq_file *m, void *v);
+static int
+proc_info_vbus_open(struct inode *inode, struct file *filp)
+{
+    /* proc_info_vbus_show will grab this from seq_file.private: */
+    struct bus_info *bus = PDE_DATA(inode);
+    return single_open(filp, proc_info_vbus_show, bus);
+}
+
+static const struct file_operations proc_info_vbus_fops = {
+    .open = proc_info_vbus_open,
+    .read = seq_read,
+    .llseek = seq_lseek,
+    .release = single_release,
+};
+
+static ssize_t uislib_proc_read_writeonly(struct file *file,
+                      char __user *buffer,
+                      size_t count, loff_t *ppos);
+
+static ssize_t vnic_proc_write(struct file *file, const char __user *buffer,
+                   size_t count, loff_t *ppos);
+
+static const struct file_operations proc_vnic_fops = {
+    .read = uislib_proc_read_writeonly,
+    .write = vnic_proc_write,
+};
+
+static ssize_t chipset_proc_write(struct file *file, const char __user *buffer,
+                  size_t count, loff_t *ppos);
+
+static const struct file_operations proc_chipset_fops = {
+    .read = uislib_proc_read_writeonly,
+    .write = chipset_proc_write,
+};
+
+static ssize_t info_proc_read(struct file *file, char __user *buf,
+                  size_t len, loff_t *offset);
+static const struct file_operations proc_info_fops = {
+    .read = info_proc_read,
+};
+
+static ssize_t platformnumber_proc_read(struct file *file, char __user *buf,
+                    size_t len, loff_t *offset);
+static const struct file_operations proc_platformnumber_fops = {
+    .read = platformnumber_proc_read,
+};
+
+static ssize_t cycles_before_wait_proc_write(struct file *file,
+                         const char __user *buffer,
+                         size_t count, loff_t *ppos);
+static const struct file_operations proc_cycles_before_wait_fops = {
+    .read = uislib_proc_read_writeonly,
+    .write = cycles_before_wait_proc_write,
+};
+
+static ssize_t reset_counts_proc_write(struct file *file,
+                       const char __user *buffer,
+                       size_t count, loff_t *ppos);
+static const struct file_operations proc_reset_counts_fops = {
+    .read = uislib_proc_read_writeonly,
+    .write = reset_counts_proc_write,
+};
+
+static ssize_t smart_wakeup_proc_write(struct file *file,
+                       const char __user *buffer,
+                       size_t count, loff_t *ppos);
+static const struct file_operations proc_smart_wakeup_fops = {
+    .read = uislib_proc_read_writeonly,
+    .write = smart_wakeup_proc_write,
+};
+
+static ssize_t test_proc_write(struct file *file,
+                   const char __user *buffer,
+                   size_t count, loff_t *ppos);
+static const struct file_operations proc_test_fops = {
+    .read = uislib_proc_read_writeonly,
+    .write = test_proc_write,
+};
+
+static ssize_t bus_proc_write(struct file *file,
+                  const char __user *buffer,
+                  size_t count, loff_t *ppos);
+static const struct file_operations proc_bus_fops = {
+    .read = uislib_proc_read_writeonly,
+    .write = bus_proc_write,
+};
+
+static ssize_t dev_proc_write(struct file *file,
+                  const char __user *buffer,
+                  size_t count, loff_t *ppos);
+static const struct file_operations proc_dev_fops = {
+    .read = uislib_proc_read_writeonly,
+    .write = dev_proc_write,
+};
+
+static void
+init_msg_header(CONTROLVM_MESSAGE *msg, U32 id, uint rsp, uint svr)
+{
+    memset(msg, 0, sizeof(CONTROLVM_MESSAGE));
+    msg->hdr.Id = id;
+    msg->hdr.Flags.responseExpected = rsp;
+    msg->hdr.Flags.server = svr;
+}
+
+static void
+create_bus_proc_entries(struct bus_info *bus)
+{
+    bus->proc_dir = proc_mkdir(bus->name, uislib_proc_vbus_dir);
+    if (!bus->proc_dir) {
+        LOGERR("failed to create /proc/uislib/vbus/%s directory",
+               bus->name);
+        return;
+    }
+    bus->proc_info = proc_create_data("info", 0, bus->proc_dir,
+                      &proc_info_vbus_fops, bus);
+    if (!bus->proc_info) {
+        LOGERR("failed to create /proc/uislib/vbus/%s/info", bus->name);
+        remove_proc_entry(bus->name, uislib_proc_vbus_dir);
+        bus->proc_dir = NULL;
+        return;
+    }
+    SET_PROC_OWNER(bus->proc_info, THIS_MODULE);
+
+}
+
+static void *
+init_vbus_channel(U64 channelAddr, U32 channelBytes, int isServer)
+{
+    void *rc = NULL;
+    void *pChan = uislib_ioremap_cache(channelAddr, channelBytes);
+    if (!pChan) {
+ LOGERR("CONTROLVM_BUS_CREATE error: ioremap_cache of channelAddr:%Lx for channelBytes:%llu failed",
+             (unsigned long long) channelAddr,
+             (unsigned long long) channelBytes);
+        RETPTR(NULL);
+    }
+    if (isServer) {
+        memset(pChan, 0, channelBytes);
+        if (!ULTRA_VBUS_CHANNEL_OK_SERVER(channelBytes, NULL)) {
+            ERRDRV("%s channel cannot be used", __func__);
+            uislib_iounmap(pChan);
+            RETPTR(NULL);
+        }
+        ULTRA_VBUS_init_channel(pChan, channelBytes);
+    } else {
+        if (!ULTRA_VBUS_CHANNEL_OK_CLIENT(pChan, NULL)) {
+            ERRDRV("%s channel cannot be used", __func__);
+            uislib_iounmap(pChan);
+            RETPTR(NULL);
+        }
+    }
+    RETPTR(pChan);
+Away:
+    return rc;
+}
+
+static int
+create_bus(CONTROLVM_MESSAGE *msg, char *buf)
+{
+    U32 busNo, deviceCount;
+    struct bus_info *tmp, *bus;
+    size_t size;
+
+    if (MaxBusCount == BusListCount) {
+ LOGERR("CONTROLVM_BUS_CREATE Failed: max buses:%d already created\n",
+             MaxBusCount);
+        POSTCODE_LINUX_3(BUS_CREATE_FAILURE_PC, MaxBusCount,
+                 POSTCODE_SEVERITY_ERR);
+        return CONTROLVM_RESP_ERROR_MAX_BUSES;
+    }
+
+    busNo = msg->cmd.createBus.busNo;
+    deviceCount = msg->cmd.createBus.deviceCount;
+
+    POSTCODE_LINUX_4(BUS_CREATE_ENTRY_PC, busNo, deviceCount,
+             POSTCODE_SEVERITY_INFO);
+
+    size =
+        sizeof(struct bus_info) +
+        (deviceCount * sizeof(struct device_info *));
+    bus = UISMALLOC(size, GFP_ATOMIC);
+    if (!bus) {
+        LOGERR("CONTROLVM_BUS_CREATE Failed: kmalloc for bus failed.\n");
+        POSTCODE_LINUX_3(BUS_CREATE_FAILURE_PC, busNo,
+                 POSTCODE_SEVERITY_ERR);
+        return CONTROLVM_RESP_ERROR_KMALLOC_FAILED;
+    }
+
+    memset(bus, 0, size);
+
+    /* Currently by default, the bus Number is the GuestHandle.
+     * Configure Bus message can override this.
+     */
+    if (msg->hdr.Flags.testMessage) {
+        /* This implies we're the IOVM so set guest handle to 0... */
+        bus->guestHandle = 0;
+        bus->busNo = busNo;
+        bus->localVnic = 1;
+    } else
+        bus->busNo = bus->guestHandle = busNo;
+    sprintf(bus->name, "%d", (int) bus->busNo);
+    bus->deviceCount = deviceCount;
+    bus->device =
+        (struct device_info **) ((char *) bus + sizeof(struct bus_info));
+    bus->busInstGuid = msg->cmd.createBus.busInstGuid;
+    bus->busChannelBytes = 0;
+    bus->pBusChannel = NULL;
+
+    /* add bus to our bus list - but check for duplicates first */
+    read_lock(&BusListLock);
+    for (tmp = BusListHead; tmp; tmp = tmp->next) {
+        if (tmp->busNo == bus->busNo)
+            break;
+    }
+    read_unlock(&BusListLock);
+    if (tmp) {
+        /* found a bus already in the list with same busNo -
+         * reject add
+         */
+        LOGERR("CONTROLVM_BUS_CREATE Failed: bus %d already exists.\n",
+               bus->busNo);
+        POSTCODE_LINUX_3(BUS_CREATE_FAILURE_PC, bus->busNo,
+                 POSTCODE_SEVERITY_ERR);
+        UISFREE(bus, size);
+        return CONTROLVM_RESP_ERROR_ALREADY_DONE;
+    }
+    if ((msg->cmd.createBus.channelAddr != 0)
+        && (msg->cmd.createBus.channelBytes != 0)) {
+        bus->busChannelBytes = msg->cmd.createBus.channelBytes;
+        bus->pBusChannel =
+            init_vbus_channel(msg->cmd.createBus.channelAddr,
+                      msg->cmd.createBus.channelBytes,
+                      msg->hdr.Flags.server);
+    }
+    /* the msg is bound for virtpci; send guest_msgs struct to callback */
+    if (!msg->hdr.Flags.server) {
+        struct guest_msgs cmd;
+        cmd.msgtype = GUEST_ADD_VBUS;
+        cmd.add_vbus.busNo = busNo;
+        cmd.add_vbus.chanptr = bus->pBusChannel;
+        cmd.add_vbus.deviceCount = deviceCount;
+        cmd.add_vbus.busTypeGuid = msg->cmd.createBus.busDataTypeGuid;
+        cmd.add_vbus.busInstGuid = msg->cmd.createBus.busInstGuid;
+        if (!VirtControlChanFunc) {
+            UISFREE(bus, size);
+ LOGERR("CONTROLVM_BUS_CREATE Failed: virtpci callback not registered.");
+            POSTCODE_LINUX_3(BUS_CREATE_FAILURE_PC, bus->busNo,
+                     POSTCODE_SEVERITY_ERR);
+            return CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_FAILURE;
+        }
+        if (!VirtControlChanFunc(&cmd)) {
+            UISFREE(bus, size);
+ LOGERR("CONTROLVM_BUS_CREATE Failed: virtpci GUEST_ADD_VBUS returned error.");
+            POSTCODE_LINUX_3(BUS_CREATE_FAILURE_PC, bus->busNo,
+                     POSTCODE_SEVERITY_ERR);
+            return
+                CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_CALLBACK_ERROR;
+        }
+    }
+    create_bus_proc_entries(bus);
+
+    /* add bus at the head of our list */
+    write_lock(&BusListLock);
+    if (!BusListHead)
+        BusListHead = bus;
+    else {
+        bus->next = BusListHead;
+        BusListHead = bus;
+    }
+    BusListCount++;
+    write_unlock(&BusListLock);
+
+    POSTCODE_LINUX_3(BUS_CREATE_EXIT_PC, bus->busNo,
+             POSTCODE_SEVERITY_INFO);
+    return CONTROLVM_RESP_SUCCESS;
+}
+
+static int
+destroy_bus(CONTROLVM_MESSAGE *msg, char *buf)
+{
+    int i;
+    struct bus_info *bus, *prev = NULL;
+    U32 busNo;
+
+    busNo = msg->cmd.destroyBus.busNo;
+
+    /* find and delete the bus */
+    read_lock(&BusListLock);
+    for (bus = BusListHead; bus; prev = bus, bus = bus->next) {
+        if (bus->busNo == busNo) {
+            /* found the bus - ensure that all device
+             * slots are NULL
+             */
+            for (i = 0; i < bus->deviceCount; i++) {
+                if (bus->device[i] != NULL) {
+ LOGERR("CONTROLVM_BUS_DESTROY Failed: device %i attached to bus %d.",
+                         i, busNo);
+                    read_unlock(&BusListLock);
+                    return CONTROLVM_RESP_ERROR_BUS_DEVICE_ATTACHED;
+                }
+            }
+            read_unlock(&BusListLock);
+            /* the msg is bound for virtpci; send
+             * guest_msgs struct to callback
+             */
+            if (!msg->hdr.Flags.server) {
+                struct guest_msgs cmd;
+                cmd.msgtype = GUEST_DEL_VBUS;
+                cmd.del_vbus.busNo = busNo;
+                if (!VirtControlChanFunc) {
+ LOGERR("CONTROLVM_BUS_DESTROY Failed: virtpci callback not registered.");
+                    return CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_FAILURE;
+                }
+                if (!VirtControlChanFunc(&cmd)) {
+ LOGERR("CONTROLVM_BUS_DESTROY Failed: virtpci GUEST_DEL_VBUS returned error."); + return CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_CALLBACK_ERROR;
+                }
+            }
+            /* remove the bus from the list */
+            write_lock(&BusListLock);
+            if (prev)    /* not at head */
+                prev->next = bus->next;
+            else
+                BusListHead = bus->next;
+            BusListCount--;
+            write_unlock(&BusListLock);
+            break;
+        }
+    }
+
+    if (!bus) {
+        LOGERR("CONTROLVM_BUS_DESTROY Failed: failed to find bus %d.\n",
+               busNo);
+        read_unlock(&BusListLock);
+        return CONTROLVM_RESP_ERROR_ALREADY_DONE;
+    }
+    if (bus->proc_info) {
+        remove_proc_entry("info", bus->proc_dir);
+        bus->proc_info = NULL;
+    }
+    if (bus->proc_dir) {
+        remove_proc_entry(bus->name, uislib_proc_vbus_dir);
+        bus->proc_dir = NULL;
+    }
+    if (bus->pBusChannel) {
+        uislib_iounmap(bus->pBusChannel);
+        bus->pBusChannel = NULL;
+    }
+
+    UISFREE(bus,
+        sizeof(struct bus_info) +
+        (bus->deviceCount * sizeof(struct device_info *)));
+    return CONTROLVM_RESP_SUCCESS;
+}
+
+static int
+create_device(CONTROLVM_MESSAGE *msg, char *buf)
+{
+    struct device_info *dev;
+    struct bus_info *bus;
+    U32 busNo, devNo;
+    int result = CONTROLVM_RESP_SUCCESS;
+    U64 minSize = MIN_IO_CHANNEL_SIZE;
+    ReqHandlerInfo_t *pReqHandler;
+
+    busNo = msg->cmd.createDevice.busNo;
+    devNo = msg->cmd.createDevice.devNo;
+
+    POSTCODE_LINUX_4(DEVICE_CREATE_ENTRY_PC, devNo, busNo,
+             POSTCODE_SEVERITY_INFO);
+
+    dev = UISMALLOC(sizeof(struct device_info), GFP_ATOMIC);
+    if (!dev) {
+ LOGERR("CONTROLVM_DEVICE_CREATE Failed: kmalloc for dev failed.\n");
+        POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, devNo, busNo,
+                 POSTCODE_SEVERITY_ERR);
+        return CONTROLVM_RESP_ERROR_KMALLOC_FAILED;
+    }
+
+    memset(dev, 0, sizeof(struct device_info));
+    dev->channelTypeGuid = msg->cmd.createDevice.dataTypeGuid;
+    dev->intr = msg->cmd.createDevice.intr;
+    dev->channelAddr = msg->cmd.createDevice.channelAddr;
+    dev->busNo = busNo;
+    dev->devNo = devNo;
+    sema_init(&dev->interrupt_callback_lock, 1);    /* unlocked */
+ sprintf(dev->devid, "vbus%u:dev%u", (unsigned) busNo, (unsigned) devNo);
+    /* map the channel memory for the device. */
+    if (msg->hdr.Flags.testMessage)
+        dev->chanptr = __va(dev->channelAddr);
+    else {
+        pReqHandler = ReqHandlerFind(dev->channelTypeGuid);
+        if (pReqHandler)
+            /* generic service handler registered for this
+             * channel
+             */
+            minSize = pReqHandler->min_channel_bytes;
+        if (minSize > msg->cmd.createDevice.channelBytes) {
+ LOGERR("CONTROLVM_DEVICE_CREATE Failed: channel size is too small, channel size:0x%lx, required size:0x%lx",
+                 (ulong) msg->cmd.createDevice.channelBytes,
+                 (ulong) minSize);
+            POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, devNo, busNo,
+                     POSTCODE_SEVERITY_ERR);
+            result = CONTROLVM_RESP_ERROR_CHANNEL_SIZE_TOO_SMALL;
+            goto Away;
+        }
+        dev->chanptr =
+            uislib_ioremap_cache(dev->channelAddr,
+                     msg->cmd.createDevice.channelBytes);
+        if (!dev->chanptr) {
+ LOGERR("CONTROLVM_DEVICE_CREATE Failed: ioremap_cache of channelAddr:%Lx for channelBytes:%llu failed",
+                 dev->channelAddr,
+                 msg->cmd.createDevice.channelBytes);
+            result = CONTROLVM_RESP_ERROR_IOREMAP_FAILED;
+            POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, devNo, busNo,
+                     POSTCODE_SEVERITY_ERR);
+            goto Away;
+        }
+    }
+    dev->devInstGuid = msg->cmd.createDevice.devInstGuid;
+    dev->channelBytes = msg->cmd.createDevice.channelBytes;
+
+    read_lock(&BusListLock);
+    for (bus = BusListHead; bus; bus = bus->next) {
+        if (bus->busNo == busNo) {
+            /* make sure the device number is valid */
+            if (devNo >= bus->deviceCount) {
+ LOGERR("CONTROLVM_DEVICE_CREATE Failed: device (%d) >= deviceCount (%d).",
+                     devNo, bus->deviceCount);
+                result = CONTROLVM_RESP_ERROR_MAX_DEVICES;
+                POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC,
+                         devNo, busNo,
+                         POSTCODE_SEVERITY_ERR);
+                read_unlock(&BusListLock);
+                goto Away;
+            }
+            /* make sure this device is not already set */
+            if (bus->device[devNo]) {
+ LOGERR("CONTROLVM_DEVICE_CREATE Failed: device %d is already exists.",
+                     devNo);
+                POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC,
+                         devNo, busNo,
+                         POSTCODE_SEVERITY_ERR);
+                result = CONTROLVM_RESP_ERROR_ALREADY_DONE;
+                read_unlock(&BusListLock);
+                goto Away;
+            }
+            read_unlock(&BusListLock);
+            /* the msg is bound for virtpci; send
+             * guest_msgs struct to callback
+             */
+            if (!msg->hdr.Flags.server) {
+                struct guest_msgs cmd;
+                if (!memcmp
+                    (&dev->channelTypeGuid,
+                     &UltraVhbaChannelProtocolGuid,
+                     sizeof(GUID))) {
+                    WAIT_FOR_VALID_GUID(((CHANNEL_HEADER
+                                  *) (dev->
+                                  chanptr))->
+                                Type);
+                    if (!ULTRA_VHBA_CHANNEL_OK_CLIENT
+                        (dev->chanptr, NULL)) {
+ LOGERR("CONTROLVM_DEVICE_CREATE Failed:[CLIENT]VHBA dev %d chan invalid.",
+                             devNo);
+                        POSTCODE_LINUX_4
+                            (DEVICE_CREATE_FAILURE_PC,
+                             devNo, busNo,
+                             POSTCODE_SEVERITY_ERR);
+                        result = CONTROLVM_RESP_ERROR_CHANNEL_INVALID;
+                        goto Away;
+                    }
+                    cmd.msgtype = GUEST_ADD_VHBA;
+                    cmd.add_vhba.chanptr = dev->chanptr;
+                    cmd.add_vhba.busNo = busNo;
+                    cmd.add_vhba.deviceNo = devNo;
+                    cmd.add_vhba.devInstGuid =
+                        dev->devInstGuid;
+                    cmd.add_vhba.intr = dev->intr;
+                } else
+                    if (!memcmp
+                    (&dev->channelTypeGuid,
+                     &UltraVnicChannelProtocolGuid,
+                     sizeof(GUID))) {
+                    WAIT_FOR_VALID_GUID(((CHANNEL_HEADER
+                                  *) (dev->
+                                  chanptr))->
+                                Type);
+                    if (!ULTRA_VNIC_CHANNEL_OK_CLIENT
+                        (dev->chanptr, NULL)) {
+ LOGERR("CONTROLVM_DEVICE_CREATE Failed: VNIC[CLIENT] dev %d chan invalid.",
+                             devNo);
+                        POSTCODE_LINUX_4
+                            (DEVICE_CREATE_FAILURE_PC,
+                             devNo, busNo,
+                             POSTCODE_SEVERITY_ERR);
+                        result = CONTROLVM_RESP_ERROR_CHANNEL_INVALID;
+                        goto Away;
+                    }
+                    cmd.msgtype = GUEST_ADD_VNIC;
+                    cmd.add_vnic.chanptr = dev->chanptr;
+                    cmd.add_vnic.busNo = busNo;
+                    cmd.add_vnic.deviceNo = devNo;
+                    cmd.add_vnic.devInstGuid =
+                        dev->devInstGuid;
+                    cmd.add_vhba.intr = dev->intr;
+                } else {
+ LOGERR("CONTROLVM_DEVICE_CREATE Failed: unknown channelTypeGuid.\n");
+                    POSTCODE_LINUX_4
+                        (DEVICE_CREATE_FAILURE_PC, devNo,
+                         busNo, POSTCODE_SEVERITY_ERR);
+                    result = CONTROLVM_RESP_ERROR_CHANNEL_TYPE_UNKNOWN;
+                    goto Away;
+                }
+
+                if (!VirtControlChanFunc) {
+ LOGERR("CONTROLVM_DEVICE_CREATE Failed: virtpci callback not registered.");
+                    POSTCODE_LINUX_4
+                        (DEVICE_CREATE_FAILURE_PC, devNo,
+                         busNo, POSTCODE_SEVERITY_ERR);
+                    result = CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_FAILURE;
+                    goto Away;
+                }
+
+                if (!VirtControlChanFunc(&cmd)) {
+ LOGERR("CONTROLVM_DEVICE_CREATE Failed: virtpci GUEST_ADD_[VHBA||VNIC] returned error.");
+                    POSTCODE_LINUX_4
+                        (DEVICE_CREATE_FAILURE_PC, devNo,
+                         busNo, POSTCODE_SEVERITY_ERR);
+ result = CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_CALLBACK_ERROR;
+                    goto Away;
+                }
+            }
+            bus->device[devNo] = dev;
+            POSTCODE_LINUX_4(DEVICE_CREATE_SUCCESS_PC, devNo, busNo,
+                     POSTCODE_SEVERITY_INFO);
+            return CONTROLVM_RESP_SUCCESS;
+        }
+    }
+    read_unlock(&BusListLock);
+
+ LOGERR("CONTROLVM_DEVICE_CREATE Failed: failed to find bus %d.", busNo);
+    POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, devNo, busNo,
+             POSTCODE_SEVERITY_ERR);
+    result = CONTROLVM_RESP_ERROR_BUS_INVALID;
+
+Away:
+    if (!msg->hdr.Flags.testMessage) {
+        uislib_iounmap(dev->chanptr);
+        dev->chanptr = NULL;
+    }
+
+    UISFREE(dev, sizeof(struct device_info));
+    return result;
+}
+
+static int
+pause_device(CONTROLVM_MESSAGE *msg)
+{
+    U32 busNo, devNo;
+    struct bus_info *bus;
+    struct device_info *dev;
+    struct guest_msgs cmd;
+
+    busNo = msg->cmd.deviceChangeState.busNo;
+    devNo = msg->cmd.deviceChangeState.devNo;
+
+    read_lock(&BusListLock);
+    for (bus = BusListHead; bus; bus = bus->next) {
+        if (bus->busNo == busNo) {
+            /* make sure the device number is valid */
+            if (devNo >= bus->deviceCount) {
+ LOGERR("CONTROLVM_DEVICE_CHANGESTATE:pause Failed: device(%d) >= deviceCount(%d).",
+                     devNo, bus->deviceCount);
+                read_unlock(&BusListLock);
+                return CONTROLVM_RESP_ERROR_DEVICE_INVALID;
+            }
+            /* make sure this device exists */
+            dev = bus->device[devNo];
+            if (!dev) {
+ LOGERR("CONTROLVM_DEVICE_CHANGESTATE:pause Failed: device %d does not exist.",
+                     devNo);
+                read_unlock(&BusListLock);
+                return CONTROLVM_RESP_ERROR_ALREADY_DONE;
+            }
+            read_unlock(&BusListLock);
+            /* the msg is bound for virtpci; send
+             * guest_msgs struct to callback
+             */
+            if (!memcmp
+                (&dev->channelTypeGuid,
+                 &UltraVhbaChannelProtocolGuid, sizeof(GUID))) {
+                cmd.msgtype = GUEST_PAUSE_VHBA;
+                cmd.pause_vhba.chanptr = dev->chanptr;
+            } else
+                if (!memcmp
+                (&dev->channelTypeGuid,
+                 &UltraVnicChannelProtocolGuid,
+                 sizeof(GUID))) {
+                cmd.msgtype = GUEST_PAUSE_VNIC;
+                cmd.pause_vnic.chanptr = dev->chanptr;
+            } else {
+ LOGERR("CONTROLVM_DEVICE_CHANGESTATE:pause Failed: unknown channelTypeGuid.\n");
+                return
+                    CONTROLVM_RESP_ERROR_CHANNEL_TYPE_UNKNOWN;
+            }
+
+            if (!VirtControlChanFunc) {
+ LOGERR("CONTROLVM_DEVICE_CHANGESTATE Failed: virtpci callback not registered.");
+                return
+                    CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_FAILURE;
+            }
+
+            if (!VirtControlChanFunc(&cmd)) {
+ LOGERR("CONTROLVM_DEVICE_CHANGESTATE:pause Failed: virtpci GUEST_PAUSE_[VHBA||VNIC] returned error.");
+                return CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_CALLBACK_ERROR;
+            }
+            break;
+        }
+    }
+
+    if (!bus) {
+ LOGERR("CONTROLVM_DEVICE_CHANGESTATE:pause Failed: bus %d does not exist",
+             busNo);
+        read_unlock(&BusListLock);
+        return CONTROLVM_RESP_ERROR_BUS_INVALID;
+    }
+
+    return CONTROLVM_RESP_SUCCESS;
+}
+
+static int
+resume_device(CONTROLVM_MESSAGE *msg)
+{
+    U32 busNo, devNo;
+    struct bus_info *bus;
+    struct device_info *dev;
+    struct guest_msgs cmd;
+
+    busNo = msg->cmd.deviceChangeState.busNo;
+    devNo = msg->cmd.deviceChangeState.devNo;
+
+    read_lock(&BusListLock);
+    for (bus = BusListHead; bus; bus = bus->next) {
+        if (bus->busNo == busNo) {
+            /* make sure the device number is valid */
+            if (devNo >= bus->deviceCount) {
+ LOGERR("CONTROLVM_DEVICE_CHANGESTATE:resume Failed: device(%d) >= deviceCount(%d).",
+                     devNo, bus->deviceCount);
+                read_unlock(&BusListLock);
+                return CONTROLVM_RESP_ERROR_DEVICE_INVALID;
+            }
+            /* make sure this device exists */
+            dev = bus->device[devNo];
+            if (!dev) {
+ LOGERR("CONTROLVM_DEVICE_CHANGESTATE:resume Failed: device %d does not exist.",
+                     devNo);
+                read_unlock(&BusListLock);
+                return CONTROLVM_RESP_ERROR_ALREADY_DONE;
+            }
+            read_unlock(&BusListLock);
+            /* the msg is bound for virtpci; send
+             * guest_msgs struct to callback
+             */
+            if (!memcmp(&dev->channelTypeGuid,
+                    &UltraVhbaChannelProtocolGuid,
+                    sizeof(GUID))) {
+                cmd.msgtype = GUEST_RESUME_VHBA;
+                cmd.resume_vhba.chanptr = dev->chanptr;
+            } else
+                if (!memcmp(&dev->channelTypeGuid,
+                    &UltraVnicChannelProtocolGuid,
+                    sizeof(GUID))) {
+                cmd.msgtype = GUEST_RESUME_VNIC;
+                cmd.resume_vnic.chanptr = dev->chanptr;
+            } else {
+ LOGERR("CONTROLVM_DEVICE_CHANGESTATE:resume Failed: unknown channelTypeGuid.\n");
+                return
+                    CONTROLVM_RESP_ERROR_CHANNEL_TYPE_UNKNOWN;
+            }
+
+            if (!VirtControlChanFunc) {
+ LOGERR("CONTROLVM_DEVICE_CHANGESTATE Failed: virtpci callback not registered.");
+                return
+                    CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_FAILURE;
+            }
+
+            if (!VirtControlChanFunc(&cmd)) {
+ LOGERR("CONTROLVM_DEVICE_CHANGESTATE:resume Failed: virtpci GUEST_RESUME_[VHBA||VNIC] returned error.");
+                return CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_CALLBACK_ERROR;
+            }
+            break;
+        }
+    }
+
+    if (!bus) {
+ LOGERR("CONTROLVM_DEVICE_CHANGESTATE:resume Failed: bus %d does not exist",
+             busNo);
+        read_unlock(&BusListLock);
+        return CONTROLVM_RESP_ERROR_BUS_INVALID;
+    }
+
+    return CONTROLVM_RESP_SUCCESS;
+}
+
+static int
+destroy_device(CONTROLVM_MESSAGE *msg, char *buf)
+{
+    U32 busNo, devNo;
+    struct bus_info *bus;
+    struct device_info *dev;
+    struct guest_msgs cmd;
+
+    busNo = msg->cmd.destroyDevice.busNo;
+    devNo = msg->cmd.destroyDevice.devNo;
+
+    read_lock(&BusListLock);
+    LOGINF("destroy_device called for busNo=%u, devNo=%u", busNo, devNo);
+    for (bus = BusListHead; bus; bus = bus->next) {
+        if (bus->busNo == busNo) {
+            /* make sure the device number is valid */
+            if (devNo >= bus->deviceCount) {
+ LOGERR("CONTROLVM_DEVICE_DESTORY Failed: device(%d) >= deviceCount(%d).",
+                     devNo, bus->deviceCount);
+                read_unlock(&BusListLock);
+                return CONTROLVM_RESP_ERROR_DEVICE_INVALID;
+            }
+            /* make sure this device exists */
+            dev = bus->device[devNo];
+            if (!dev) {
+ LOGERR("CONTROLVM_DEVICE_DESTROY Failed: device %d does not exist.",
+                     devNo);
+                read_unlock(&BusListLock);
+                return CONTROLVM_RESP_ERROR_ALREADY_DONE;
+            }
+            read_unlock(&BusListLock);
+            /* the msg is bound for virtpci; send
+             * guest_msgs struct to callback
+             */
+            if (!memcmp
+                (&dev->channelTypeGuid,
+                 &UltraVhbaChannelProtocolGuid, sizeof(GUID))) {
+                cmd.msgtype = GUEST_DEL_VHBA;
+                cmd.del_vhba.chanptr = dev->chanptr;
+            } else
+                if (!memcmp
+                (&dev->channelTypeGuid,
+                 &UltraVnicChannelProtocolGuid,
+                 sizeof(GUID))) {
+                cmd.msgtype = GUEST_DEL_VNIC;
+                cmd.del_vnic.chanptr = dev->chanptr;
+            } else {
+ LOGERR("CONTROLVM_DEVICE_DESTROY Failed: unknown channelTypeGuid.\n");
+                return
+                    CONTROLVM_RESP_ERROR_CHANNEL_TYPE_UNKNOWN;
+            }
+
+            if (!VirtControlChanFunc) {
+ LOGERR("CONTROLVM_DEVICE_DESTORY Failed: virtpci callback not registered.");
+                return
+                    CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_FAILURE;
+            }
+
+            if (!VirtControlChanFunc(&cmd)) {
+ LOGERR("CONTROLVM_DEVICE_DESTROY Failed: virtpci GUEST_DEL_[VHBA||VNIC] returned error.");
+                return CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_CALLBACK_ERROR;
+            }
+/* you must disable channel interrupts BEFORE you unmap the channel,
+ * because if you unmap first, there may still be some activity going
+ * on which accesses the channel and you will get a "unable to handle
+ * kernel paging request"
+ */
+            if (dev->polling) {
+                LOGINF("calling uislib_disable_channel_interrupts");
+                uislib_disable_channel_interrupts(busNo, devNo);
+            }
+            /* unmap the channel memory for the device. */
+            if (!msg->hdr.Flags.testMessage) {
+                LOGINF("destroy_device, doing iounmap");
+                uislib_iounmap(dev->chanptr);
+            }
+            UISFREE(dev, sizeof(struct device_info));
+            bus->device[devNo] = NULL;
+            break;
+        }
+    }
+
+    if (!bus) {
+        LOGERR("CONTROLVM_DEVICE_DESTROY Failed: bus %d does not exist",
+               busNo);
+        read_unlock(&BusListLock);
+        return CONTROLVM_RESP_ERROR_BUS_INVALID;
+    }
+
+    return CONTROLVM_RESP_SUCCESS;
+}
+
+void
+ULTRA_disp_channel_header(CHANNEL_HEADER *x)
+{
+ LOGINF("Sig=%llx, HdrSz=%lx, Sz=%llx, Feat=%llx, hPart=%llx, Hndl=%llx, ChSpace=%llx, Ver=%lx, PartIdx=%lx\n",
+         x->Signature, (long unsigned int) x->HeaderSize, x->Size,
+         x->Features, x->PartitionHandle, x->Handle, x->oChannelSpace,
+         (long unsigned int) x->VersionId,
+         (long unsigned int) x->PartitionIndex);
+
+ LOGINF("ClientStr=%lx, CliStBoot=%lx, CmdStCli=%lx, CliStOS=%lx, ChCharistics=%lx, CmdStSrv=%lx, SrvSt=%lx\n",
+         (long unsigned int) x->oClientString,
+         (long unsigned int) x->CliStateBoot,
+         (long unsigned int) x->CmdStateCli,
+         (long unsigned int) x->CliStateOS,
+         (long unsigned int) x->ChannelCharacteristics,
+         (long unsigned int) x->CmdStateSrv,
+         (long unsigned int) x->SrvState);
+
+}
+
+void
+ULTRA_disp_channel(ULTRA_IO_CHANNEL_PROTOCOL *x)
+{
+    ULTRA_disp_channel_header(&x->ChannelHeader);
+    LOGINF("cmdQ.Type=%lx\n", (long unsigned int) x->cmdQ.Type);
+    LOGINF("cmdQ.Size=%llx\n", x->cmdQ.Size);
+    LOGINF("cmdQ.oSignalBase=%llx\n", x->cmdQ.oSignalBase);
+ LOGINF("cmdQ.SignalSize=%lx\n", (long unsigned int) x->cmdQ.SignalSize);
+    LOGINF("cmdQ.MaxSignalSlots=%lx\n",
+           (long unsigned int) x->cmdQ.MaxSignalSlots);
+ LOGINF("cmdQ.MaxSignals=%lx\n", (long unsigned int) x->cmdQ.MaxSignals);
+    LOGINF("rspQ.Type=%lx\n", (long unsigned int) x->rspQ.Type);
+    LOGINF("rspQ.Size=%llx\n", x->rspQ.Size);
+    LOGINF("rspQ.oSignalBase=%llx\n", x->rspQ.oSignalBase);
+ LOGINF("rspQ.SignalSize=%lx\n", (long unsigned int) x->rspQ.SignalSize);
+    LOGINF("rspQ.MaxSignalSlots=%lx\n",
+           (long unsigned int) x->rspQ.MaxSignalSlots);
+ LOGINF("rspQ.MaxSignals=%lx\n", (long unsigned int) x->rspQ.MaxSignals);
+    LOGINF("SIZEOF_CMDRSP=%lx\n", SIZEOF_CMDRSP);
+    LOGINF("SIZEOF_PROTOCOL=%lx\n", SIZEOF_PROTOCOL);
+}
+
+void
+ULTRA_disp_vnic_channel(ULTRA_IO_CHANNEL_PROTOCOL *x)
+{
+    LOGINF("num_rcv_bufs=%lx\n", (long unsigned int) x->vnic.num_rcv_bufs);
+    LOGINF("mtu=%lx\n", (long unsigned int) x->vnic.mtu);
+}
+
+static int
+init_chipset(CONTROLVM_MESSAGE *msg, char *buf)
+{
+    POSTCODE_LINUX_2(CHIPSET_INIT_ENTRY_PC, POSTCODE_SEVERITY_INFO);
+
+    MaxBusCount = msg->cmd.initChipset.busCount;
+    PlatformNumber = msg->cmd.initChipset.platformNumber;
+    PhysicalDataChan = 0;
+
+    /* We need to make sure we have our functions registered
+    * before processing messages.  If we are a test vehicle the
+    * testMessage for init_chipset will be set.  We can ignore the
+    * waits for the callbacks, since this will be manually entered
+    * from a user.  If no testMessage is set, we will wait for the
+    * functions.
+    */
+    if (!msg->hdr.Flags.testMessage)
+        WAIT_ON_CALLBACK(VirtControlChanFunc);
+
+    chipset_inited = 1;
+    POSTCODE_LINUX_2(CHIPSET_INIT_EXIT_PC, POSTCODE_SEVERITY_INFO);
+
+    return CONTROLVM_RESP_SUCCESS;
+}
+
+static int
+stop_chipset(CONTROLVM_MESSAGE *msg, char *buf)
+{
+    /* Check that all buses and switches have been torn down and
+     * destroyed.
+     */
+    if (BusListHead) {
+        /* Buses still exist. */
+        LOGERR("CONTROLVM_CHIPSET_STOP: BusListHead is not NULL");
+        return CONTROLVM_RESP_ERROR_CHIPSET_STOP_FAILED_BUS;
+    }
+    if (BusListCount) {
+        /* BusListHead is NULL, but BusListCount != 0 */
+        LOGERR("CONTROLVM_CHIPSET_STOP: BusListCount != 0");
+        return CONTROLVM_RESP_ERROR_CHIPSET_STOP_FAILED_BUS;
+    }
+
+    /* Buses are shut down. */
+    return visorchipset_chipset_notready();
+}
+
+static int
+delete_bus_glue(U32 busNo)
+{
+    CONTROLVM_MESSAGE msg;
+
+    init_msg_header(&msg, CONTROLVM_BUS_DESTROY, 0, 0);
+    msg.cmd.destroyBus.busNo = busNo;
+    if (destroy_bus(&msg, NULL) != CONTROLVM_RESP_SUCCESS) {
+        LOGERR("destroy_bus failed. busNo=0x%x\n", busNo);
+        return 0;
+    }
+    return 1;
+}
+
+static int
+delete_device_glue(U32 busNo, U32 devNo)
+{
+    CONTROLVM_MESSAGE msg;
+
+    init_msg_header(&msg, CONTROLVM_DEVICE_DESTROY, 0, 0);
+    msg.cmd.destroyDevice.busNo = busNo;
+    msg.cmd.destroyDevice.devNo = devNo;
+    if (destroy_device(&msg, NULL) != CONTROLVM_RESP_SUCCESS) {
+        LOGERR("destroy_device failed. busNo=0x%x devNo=0x%x\n", busNo,
+               devNo);
+        return 0;
+    }
+    return 1;
+}
+
+int
+uislib_client_inject_add_bus(U32 busNo, GUID instGuid,
+                 U64 channelAddr, ulong nChannelBytes)
+{
+    CONTROLVM_MESSAGE msg;
+
+    LOGINF("enter busNo=0x%x\n", busNo);
+    /* step 0: init the chipset */
+    POSTCODE_LINUX_3(CHIPSET_INIT_ENTRY_PC, busNo, POSTCODE_SEVERITY_INFO);
+
+    if (!chipset_inited) {
+        /* step: initialize the chipset */
+        init_msg_header(&msg, CONTROLVM_CHIPSET_INIT, 0, 0);
+        /* this change is needed so that console will come up
+        * OK even when the bus 0 create comes in late.  If the
+        * bus 0 create is the first create, then the add_vnic
+        * will work fine, but if the bus 0 create arrives
+        * after number 4, then the add_vnic will fail, and the
+        * ultraboot will fail.
+        */
+        msg.cmd.initChipset.busCount = 23;
+        msg.cmd.initChipset.switchCount = 0;
+        if (init_chipset(&msg, NULL) != CONTROLVM_RESP_SUCCESS) {
+            LOGERR("init_chipset failed.\n");
+            return 0;
+        }
+        LOGINF("chipset initialized\n");
+        POSTCODE_LINUX_3(CHIPSET_INIT_EXIT_PC, busNo,
+                 POSTCODE_SEVERITY_INFO);
+    }
+
+    /* step 1: create a bus */
+ POSTCODE_LINUX_3(BUS_CREATE_ENTRY_PC, busNo, POSTCODE_SEVERITY_WARNING);
+    init_msg_header(&msg, CONTROLVM_BUS_CREATE, 0, 0);
+    msg.cmd.createBus.busNo = busNo;
+    msg.cmd.createBus.deviceCount = 23;    /* devNo+1; */
+    msg.cmd.createBus.channelAddr = channelAddr;
+    msg.cmd.createBus.channelBytes = nChannelBytes;
+    if (create_bus(&msg, NULL) != CONTROLVM_RESP_SUCCESS) {
+        LOGERR("create_bus failed.\n");
+        POSTCODE_LINUX_3(BUS_CREATE_FAILURE_PC, busNo,
+                 POSTCODE_SEVERITY_ERR);
+        return 0;
+    }
+    POSTCODE_LINUX_3(BUS_CREATE_EXIT_PC, busNo, POSTCODE_SEVERITY_INFO);
+
+    return 1;
+}
+EXPORT_SYMBOL(uislib_client_inject_add_bus);
+
+
+int
+uislib_client_inject_del_bus(U32 busNo)
+{
+    return delete_bus_glue(busNo);
+}
+EXPORT_SYMBOL(uislib_client_inject_del_bus);
+
+int
+uislib_client_inject_pause_vhba(U32 busNo, U32 devNo)
+{
+    CONTROLVM_MESSAGE msg;
+    int rc;
+
+    init_msg_header(&msg, CONTROLVM_DEVICE_CHANGESTATE, 0, 0);
+    msg.cmd.deviceChangeState.busNo = busNo;
+    msg.cmd.deviceChangeState.devNo = devNo;
+    msg.cmd.deviceChangeState.state = SegmentStateStandby;
+    rc = pause_device(&msg);
+    if (rc != CONTROLVM_RESP_SUCCESS) {
+        LOGERR("VHBA pause_device failed. busNo=0x%x devNo=0x%x\n",
+               busNo, devNo);
+        return rc;
+    }
+    return 0;
+}
+EXPORT_SYMBOL(uislib_client_inject_pause_vhba);
+
+int
+uislib_client_inject_resume_vhba(U32 busNo, U32 devNo)
+{
+    CONTROLVM_MESSAGE msg;
+    int rc;
+
+    init_msg_header(&msg, CONTROLVM_DEVICE_CHANGESTATE, 0, 0);
+    msg.cmd.deviceChangeState.busNo = busNo;
+    msg.cmd.deviceChangeState.devNo = devNo;
+    msg.cmd.deviceChangeState.state = SegmentStateRunning;
+    rc = resume_device(&msg);
+    if (rc != CONTROLVM_RESP_SUCCESS) {
+        LOGERR("VHBA resume_device failed. busNo=0x%x devNo=0x%x\n",
+               busNo, devNo);
+        return rc;
+    }
+    return 0;
+
+}
+EXPORT_SYMBOL(uislib_client_inject_resume_vhba);
+
+int
+uislib_client_inject_add_vhba(U32 busNo, U32 devNo,
+                  U64 phys_chan_addr, U32 chan_bytes,
+                  int is_test_addr, GUID instGuid,
+                  struct InterruptInfo *intr)
+{
+    CONTROLVM_MESSAGE msg;
+
+    LOGINF(" enter busNo=0x%x devNo=0x%x\n", busNo, devNo);
+    /* chipset init'ed with bus bus has been previously created -
+    * Verify it still exists step 2: create the VHBA device on the
+    * bus
+    */
+    POSTCODE_LINUX_4(VHBA_CREATE_ENTRY_PC, devNo, busNo,
+             POSTCODE_SEVERITY_INFO);
+
+    init_msg_header(&msg, CONTROLVM_DEVICE_CREATE, 0, 0);
+    if (is_test_addr)
+        /* signify that the physical channel address does NOT
+         * need to be ioremap()ed
+         */
+        msg.hdr.Flags.testMessage = 1;
+    msg.cmd.createDevice.busNo = busNo;
+    msg.cmd.createDevice.devNo = devNo;
+    msg.cmd.createDevice.devInstGuid = instGuid;
+    if (intr)
+        msg.cmd.createDevice.intr = *intr;
+    else
+        memset(&msg.cmd.createDevice.intr, 0,
+               sizeof(struct InterruptInfo));
+    msg.cmd.createDevice.channelAddr = phys_chan_addr;
+    if (chan_bytes < MIN_IO_CHANNEL_SIZE) {
+ LOGERR("wrong channel size.chan_bytes = 0x%x IO_CHANNEL_SIZE= 0x%x\n",
+             chan_bytes, (unsigned int) MIN_IO_CHANNEL_SIZE);
+        POSTCODE_LINUX_4(VHBA_CREATE_FAILURE_PC, chan_bytes,
+                 MIN_IO_CHANNEL_SIZE, POSTCODE_SEVERITY_ERR);
+        return 0;
+    }
+    msg.cmd.createDevice.channelBytes = chan_bytes;
+    msg.cmd.createDevice.dataTypeGuid = UltraVhbaChannelProtocolGuid;
+    if (create_device(&msg, NULL) != CONTROLVM_RESP_SUCCESS) {
+        LOGERR("VHBA create_device failed.\n");
+        POSTCODE_LINUX_4(VHBA_CREATE_FAILURE_PC, devNo, busNo,
+                 POSTCODE_SEVERITY_ERR);
+        return 0;
+    }
+    POSTCODE_LINUX_4(VHBA_CREATE_SUCCESS_PC, devNo, busNo,
+             POSTCODE_SEVERITY_INFO);
+    return 1;
+}
+EXPORT_SYMBOL(uislib_client_inject_add_vhba);
+
+int
+uislib_client_inject_del_vhba(U32 busNo, U32 devNo)
+{
+    return delete_device_glue(busNo, devNo);
+}
+EXPORT_SYMBOL(uislib_client_inject_del_vhba);
+
+int
+uislib_client_inject_add_vnic(U32 busNo, U32 devNo,
+                  U64 phys_chan_addr, U32 chan_bytes,
+                  int is_test_addr, GUID instGuid,
+                  struct InterruptInfo *intr)
+{
+    CONTROLVM_MESSAGE msg;
+
+    LOGINF(" enter busNo=0x%x devNo=0x%x\n", busNo, devNo);
+    /* chipset init'ed with bus bus has been previously created -
+    * Verify it still exists step 2: create the VNIC device on the
+    * bus
+    */
+    POSTCODE_LINUX_4(VNIC_CREATE_ENTRY_PC, devNo, busNo,
+             POSTCODE_SEVERITY_INFO);
+
+    init_msg_header(&msg, CONTROLVM_DEVICE_CREATE, 0, 0);
+    if (is_test_addr)
+        /* signify that the physical channel address does NOT
+         * need to be ioremap()ed
+         */
+        msg.hdr.Flags.testMessage = 1;
+    msg.cmd.createDevice.busNo = busNo;
+    msg.cmd.createDevice.devNo = devNo;
+    msg.cmd.createDevice.devInstGuid = instGuid;
+    if (intr)
+        msg.cmd.createDevice.intr = *intr;
+    else
+        memset(&msg.cmd.createDevice.intr, 0,
+               sizeof(struct InterruptInfo));
+    msg.cmd.createDevice.channelAddr = phys_chan_addr;
+    if (chan_bytes < MIN_IO_CHANNEL_SIZE) {
+ LOGERR("wrong channel size.chan_bytes = 0x%x IO_CHANNEL_SIZE= 0x%x\n",
+             chan_bytes, (unsigned int) MIN_IO_CHANNEL_SIZE);
+        POSTCODE_LINUX_4(VNIC_CREATE_FAILURE_PC, chan_bytes,
+                 MIN_IO_CHANNEL_SIZE, POSTCODE_SEVERITY_ERR);
+        return 0;
+    }
+    msg.cmd.createDevice.channelBytes = chan_bytes;
+    msg.cmd.createDevice.dataTypeGuid = UltraVnicChannelProtocolGuid;
+    if (create_device(&msg, NULL) != CONTROLVM_RESP_SUCCESS) {
+        LOGERR("VNIC create_device failed.\n");
+        POSTCODE_LINUX_4(VNIC_CREATE_FAILURE_PC, devNo, busNo,
+                 POSTCODE_SEVERITY_ERR);
+        return 0;
+    }
+
+    POSTCODE_LINUX_4(VNIC_CREATE_SUCCESS_PC, devNo, busNo,
+             POSTCODE_SEVERITY_INFO);
+    return 1;
+}
+EXPORT_SYMBOL(uislib_client_inject_add_vnic);
+
+int
+uislib_client_inject_pause_vnic(U32 busNo, U32 devNo)
+{
+    CONTROLVM_MESSAGE msg;
+    int rc;
+
+    init_msg_header(&msg, CONTROLVM_DEVICE_CHANGESTATE, 0, 0);
+    msg.cmd.deviceChangeState.busNo = busNo;
+    msg.cmd.deviceChangeState.devNo = devNo;
+    msg.cmd.deviceChangeState.state = SegmentStateStandby;
+    rc = pause_device(&msg);
+    if (rc != CONTROLVM_RESP_SUCCESS) {
+        LOGERR("VNIC pause_device failed. busNo=0x%x devNo=0x%x\n",
+               busNo, devNo);
+        return -1;
+    }
+    return 0;
+}
+EXPORT_SYMBOL(uislib_client_inject_pause_vnic);
+
+int
+uislib_client_inject_resume_vnic(U32 busNo, U32 devNo)
+{
+    CONTROLVM_MESSAGE msg;
+    int rc;
+
+    init_msg_header(&msg, CONTROLVM_DEVICE_CHANGESTATE, 0, 0);
+    msg.cmd.deviceChangeState.busNo = busNo;
+    msg.cmd.deviceChangeState.devNo = devNo;
+    msg.cmd.deviceChangeState.state = SegmentStateRunning;
+    rc = resume_device(&msg);
+    if (rc != CONTROLVM_RESP_SUCCESS) {
+        LOGERR("VNIC resume_device failed. busNo=0x%x devNo=0x%x\n",
+               busNo, devNo);
+        return -1;
+    }
+    return 0;
+
+}
+EXPORT_SYMBOL(uislib_client_inject_resume_vnic);
+
+int
+uislib_client_inject_del_vnic(U32 busNo, U32 devNo)
+{
+    return delete_device_glue(busNo, devNo);
+}
+EXPORT_SYMBOL(uislib_client_inject_del_vnic);
+
+int
+uislib_client_add_vnic(U32 busNo)
+{
+    BOOL busCreated = FALSE;
+    int devNo = 0;        /* Default to 0, since only one device
+                 * will be created for this bus... */
+    GUID dummyGuid = GUID0;
+    CONTROLVM_MESSAGE msg;
+
+    init_msg_header(&msg, CONTROLVM_BUS_CREATE, 0, 0);
+    msg.hdr.Flags.testMessage = 1;
+    msg.cmd.createBus.busNo = busNo;
+    msg.cmd.createBus.deviceCount = 4;
+    msg.cmd.createBus.channelAddr = 0;
+    msg.cmd.createBus.channelBytes = 0;
+    if (create_bus(&msg, NULL) != CONTROLVM_RESP_SUCCESS) {
+        LOGERR("client create_bus failed");
+        return 0;
+    }
+    busCreated = TRUE;
+
+    init_msg_header(&msg, CONTROLVM_DEVICE_CREATE, 0, 0);
+    msg.hdr.Flags.testMessage = 1;
+    msg.cmd.createDevice.busNo = busNo;
+    msg.cmd.createDevice.devNo = devNo;
+    msg.cmd.createDevice.devInstGuid = dummyGuid;
+    memset(&msg.cmd.createDevice.intr, 0, sizeof(struct InterruptInfo));
+    msg.cmd.createDevice.channelAddr = PhysicalDataChan;
+    msg.cmd.createDevice.channelBytes = MIN_IO_CHANNEL_SIZE;
+    msg.cmd.createDevice.dataTypeGuid = UltraVnicChannelProtocolGuid;
+    if (create_device(&msg, NULL) != CONTROLVM_RESP_SUCCESS) {
+        LOGERR("client create_device failed");
+        goto AwayCleanup;
+    }
+
+    return 1;
+
+AwayCleanup:
+    if (busCreated) {
+        init_msg_header(&msg, CONTROLVM_BUS_DESTROY, 0, 0);
+        msg.hdr.Flags.testMessage = 1;
+        msg.cmd.destroyBus.busNo = busNo;
+        if (destroy_bus(&msg, NULL) != CONTROLVM_RESP_SUCCESS)
+            LOGERR("client destroy_bus failed.\n");
+    }
+
+    return 0;
+}                /* end uislib_client_add_vnic */
+EXPORT_SYMBOL(uislib_client_add_vnic);
+
+int
+uislib_client_delete_vnic(U32 busNo)
+{
+    int devNo = 0;        /* Default to 0, since only one device
+                 * will be created for this bus... */
+    CONTROLVM_MESSAGE msg;
+
+    init_msg_header(&msg, CONTROLVM_DEVICE_DESTROY, 0, 0);
+    msg.hdr.Flags.testMessage = 1;
+    msg.cmd.destroyDevice.busNo = busNo;
+    msg.cmd.destroyDevice.devNo = devNo;
+    if (destroy_device(&msg, NULL) != CONTROLVM_RESP_SUCCESS) {
+        /* Don't error exit - try to see if bus can be destroyed... */
+        LOGERR("client destroy_device failed.\n");
+    }
+
+    init_msg_header(&msg, CONTROLVM_BUS_DESTROY, 0, 0);
+    msg.hdr.Flags.testMessage = 1;
+    msg.cmd.destroyBus.busNo = busNo;
+    if (destroy_bus(&msg, NULL) != CONTROLVM_RESP_SUCCESS)
+        LOGERR("client destroy_bus failed.\n");
+
+    return 1;
+}
+EXPORT_SYMBOL(uislib_client_delete_vnic);
+
+                /* end client_delete_vnic */
+
+static atomic_t Malloc_BytesInUse = ATOMIC_INIT(0);
+static atomic_t Malloc_BuffersInUse = ATOMIC_INIT(0);
+static atomic_t Malloc_FailuresAlloc = ATOMIC_INIT(0);
+static atomic_t Malloc_FailuresFree = ATOMIC_INIT(0);
+static atomic_t Malloc_TotalMallocs = ATOMIC_INIT(0);
+static atomic_t Malloc_TotalFrees = ATOMIC_INIT(0);
+
+void *
+uislib_malloc(size_t siz, gfp_t gfp, U8 contiguous, char *fn, int ln)
+{
+    void *p = NULL;
+
+    if (contiguous == 0) {
+        /* Allocate non-contiguous memory, such as in the
+        * add_vnic and add_vhba methods where we are rebooting
+        * the guest, for example.  Otherwise the contiguous
+        * memory allocation attempt results in an
+        * out-of-memory crash in the IOVM...
+        */
+        p = vmalloc(siz);
+    } else {
+        /* __GFP_NORETRY means "ok to fail", meaning kmalloc()
+        * can return NULL.  If you do NOT specify
+        * __GFP_NORETRY, Linux will go to extreme measures to
+        * get memory for you (like, invoke oom killer), which
+        * will probably cripple the system.
+        */
+        p = kmalloc(siz, gfp | __GFP_NORETRY);
+    }
+    if (p == NULL) {
+        LOGERR("uislib_malloc failed to alloc %d bytes @%s:%d",
+               (int) siz, fn, ln);
+        atomic_inc(&Malloc_FailuresAlloc);
+        return NULL;
+    }
+    atomic_add((int) (siz), &Malloc_BytesInUse);
+    atomic_inc(&Malloc_BuffersInUse);
+    atomic_inc(&Malloc_TotalMallocs);    /* will eventually overflow */
+    return p;
+}
+EXPORT_SYMBOL(uislib_malloc);
+
+void
+uislib_free(void *p, size_t siz, U8 contiguous, char *fn, int ln)
+{
+    if (p == NULL) {
+        LOGERR("uislib_free NULL pointer @%s:%d", fn, ln);
+        atomic_inc(&Malloc_FailuresFree);
+        return;
+    }
+
+    if (contiguous == 0)
+        vfree(p);
+    else
+        kfree(p);
+    atomic_sub((int) (siz), &Malloc_BytesInUse);
+    atomic_dec(&Malloc_BuffersInUse);
+    atomic_inc(&Malloc_TotalFrees);    /* will eventually overflow */
+}
+EXPORT_SYMBOL(uislib_free);
+
+void *
+uislib_cache_alloc(struct kmem_cache *cur_pool, char *fn, int ln)
+{
+    /* __GFP_NORETRY means "ok to fail", meaning kmalloc() can
+    * return NULL.  If you do NOT specify __GFP_NORETRY, Linux
+    * will go to extreme measures to get memory for you (like,
+    * invoke oom killer), which will probably cripple the system.
+    */
+    void *p = kmem_cache_alloc(cur_pool, GFP_ATOMIC | __GFP_NORETRY);
+    if (p == NULL) {
+        LOGERR("uislib_malloc failed to alloc uiscmdrsp @%s:%d",
+               fn, ln);
+        return NULL;
+    }
+    return p;
+}
+EXPORT_SYMBOL(uislib_cache_alloc);
+
+void
+uislib_cache_free(struct kmem_cache *cur_pool, void *p, char *fn, int ln)
+{
+    if (p == NULL) {
+        LOGERR("uislib_free NULL pointer @%s:%d", fn, ln);
+        return;
+    }
+    kmem_cache_free(cur_pool, p);
+}
+EXPORT_SYMBOL(uislib_cache_free);
+
+/*****************************************************/
+/* proc filesystem callback functions                */
+/*****************************************************/
+
+static ssize_t
+vnic_proc_write(struct file *file, const char __user *buffer,
+        size_t count, loff_t *ppos)
+{
+    int action = 0xffff, busNo = 0, i, result = 0;
+    char buf[count];
+    char direction;
+/* GUID guid; */
+    if (copy_from_user(buf, buffer, count)) {
+        LOGERR("echo > /proc/uislib/vnic copy_from_user ****FAILED.\n");
+        return -EFAULT;
+    }
+
+    i = sscanf(buf, "%d%c", &action, &direction);
+    if (i != 2) {
+        LOGERR("unable to parse vnic proc parameters.\n");
+        return -EFAULT;
+    }
+
+    if ((direction != '-') && (direction != '+')) {
+        LOGERR("unable to determine whether to add or delete vnic\n");
+        return -EFAULT;
+    }
+
+    /* if (i < 1), i.e., if we didn't even read the action field,
+    * then action will default to 0xffff and the code below will
+    * fall through the switch and print usage.
+    */
+    switch (action) {
+    case 0:
+        /* call client method... */
+        busNo = 0;    /* All client drivers use bus value of 0... */
+        if (direction == '+')
+            result = uislib_client_add_vnic(busNo);
+        else
+            result = uislib_client_delete_vnic(busNo);
+        if (!result) {
+            LOGERR("echo 0%c > /proc/uislib/vnic failed (client end)",
+                 direction);
+            return -EFAULT;
+        }
+        return count;
+
+    default:
+        break;
+    }
+
+ LOGERR("USAGE: echo <action><direction (up/down)> > /proc/uislib/vnic");
+    LOGERR(" ");
+    LOGERR("Client Syntax");
+    LOGERR("-------------");
+    LOGERR("0+    ==> add vnic");
+    LOGERR("0-    ==> delete vnic");
+    LOGERR(" ");
+    return count;
+}                /* end vnic_proc_write */
+
+static ssize_t
+chipset_proc_write(struct file *file, const char __user *buffer,
+           size_t count, loff_t *ppos)
+{
+    int i, action = 0xffff;
+    char buf[count];
+    CONTROLVM_MESSAGE msg;
+
+    memset(&msg, 0, sizeof(CONTROLVM_MESSAGE));
+
+    if (copy_from_user(buf, buffer, count)) {
+        LOGERR("copy_from_user ****FAILED.\n");
+        return -EFAULT;
+    }
+
+    if (chipset_inited) {
+        LOGINF("Chipset already initialized\n");
+        return -EFAULT;
+    }
+    i = sscanf(buf, "%x", &action);
+
+    /* if (i < 1), i.e., if we didn't even read the action field,
+    * then action will default to 0xffff and the code below will
+    * fall through the switch and print usage.
+    */
+    switch (action) {
+    case 1:
+        /* GUEST */
+        /* step: initialize the chipset */
+        init_msg_header(&msg, CONTROLVM_CHIPSET_INIT, 0, 0);
+        msg.hdr.Flags.testMessage = 0;
+        msg.cmd.initChipset.busCount = 23;
+        msg.cmd.initChipset.switchCount = 23;
+
+        if (init_chipset(&msg, NULL) != CONTROLVM_RESP_SUCCESS) {
+            LOGERR("init_chipset failed.\n");
+            return 0;
+        }
+        return 1;
+    case 2:
+        /* BOTH */
+        init_msg_header(&msg, CONTROLVM_CHIPSET_INIT, 0, 0);
+        msg.hdr.Flags.testMessage = 1;
+        msg.cmd.initChipset.busCount = 23;
+        msg.cmd.initChipset.switchCount = 23;
+
+        if (init_chipset(&msg, NULL) != CONTROLVM_RESP_SUCCESS) {
+            LOGERR("init_chipset failed.\n");
+            return 0;
+        }
+        return 1;
+
+    default:
+        break;
+    }
+
+    LOGERR("usage: 1 ==> init_chipset client\n");
+    LOGERR("usage: 2 ==> init_chipset test\n");
+    return -EFAULT;
+}
+
+#define PROCLINE(...)                            \
+    do {                                \
+        if (util_add_proc_line_ex(&tot, buff,            \
+                      buff_len, __VA_ARGS__) < 0) {    \
+            goto err_done;                    \
+        }                            \
+    } while (0)
+
+static int
+info_proc_read_helper(char **buff, int *buff_len)
+{
+    int i, tot = 0;
+    struct bus_info *bus;
+
+    PROCLINE("\nBuses:\n");
+
+    read_lock(&BusListLock);
+    for (bus = BusListHead; bus; bus = bus->next) {
+
+        PROCLINE("    bus=0x%p, busNo=%d, deviceCount=%d\n",
+             bus, bus->busNo, bus->deviceCount);
+
+        PROCLINE("        Devices:\n");
+
+        for (i = 0; i < bus->deviceCount; i++) {
+            if (bus->device[i]) {
+ PROCLINE(" busNo %d, device[%i]: 0x%p, chanptr=0x%p, swtch=0x%p\n",
+                     bus->busNo, i, bus->device[i],
+                     bus->device[i]->chanptr,
+                     bus->device[i]->swtch);
+ PROCLINE(" first_busy_cnt=%llu, moved_to_tail_cnt=%llu, last_on_list_cnt=%llu\n",
+                     bus->device[i]->first_busy_cnt,
+                     bus->device[i]->moved_to_tail_cnt,
+                     bus->device[i]->last_on_list_cnt);
+            }
+        }
+    }
+    read_unlock(&BusListLock);
+
+    PROCLINE("Malloc bytes in use: %d\n", atomic_read(&Malloc_BytesInUse));
+    PROCLINE("Malloc buffers in use: %d\n",
+         atomic_read(&Malloc_BuffersInUse));
+    PROCLINE("Malloc allocation failures: %d\n",
+         atomic_read(&Malloc_FailuresAlloc));
+    PROCLINE("Malloc free failures: %d\n",
+         atomic_read(&Malloc_FailuresFree));
+    PROCLINE("Malloc total mallocs: %u (may overflow)\n",
+         (unsigned) atomic_read(&Malloc_TotalMallocs));
+    PROCLINE("Malloc total frees: %u (may overflow)\n",
+         (unsigned) atomic_read(&Malloc_TotalFrees));
+    PROCLINE("UisUtils_Registered_Services: %d\n",
+         atomic_read(&UisUtils_Registered_Services));
+
+    PROCLINE("cycles_before_wait %llu wait_cycles:%llu\n",
+         cycles_before_wait, wait_cycles);
+ PROCLINE("tot_wakeup_cnt %llu:tot_wait_cnt %llu:tot_schedule_cnt %llu\n",
+         tot_wakeup_cnt, tot_wait_cnt, tot_schedule_cnt);
+    PROCLINE("en_smart_wakeup %d\n", en_smart_wakeup);
+    PROCLINE("tot_moved_to_tail_cnt %llu\n", tot_moved_to_tail_cnt);
+
+    return tot;
+err_done:
+
+    return -1;
+}
+
+static ssize_t
+info_proc_read(struct file *file, char __user *buf, size_t len, loff_t *offset)
+{
+    char *temp;
+    int totalBytes = 0;
+    int remaining_bytes = PROC_READ_BUFFER_SIZE;
+
+/* *start = buf; */
+    if (ProcReadBuffer == NULL) {
+        DBGINF("ProcReadBuffer == NULL; allocating buffer.\n.");
+        ProcReadBuffer = UISVMALLOC(PROC_READ_BUFFER_SIZE);
+
+        if (ProcReadBuffer == NULL) {
+            LOGERR("failed to allocate buffer to provide proc data.\n");
+            return -ENOMEM;
+        }
+    }
+
+    temp = ProcReadBuffer;
+
+    if ((*offset == 0) || (!ProcReadBufferValid)) {
+        DBGINF("calling info_proc_read_helper.\n");
+        /* if the read fails, then -1 will be returned */
+        totalBytes = info_proc_read_helper(&temp, &remaining_bytes);
+        ProcReadBufferValid = 1;
+    } else
+        totalBytes = strlen(ProcReadBuffer);
+
+    return simple_read_from_buffer(buf, len, offset,
+                       ProcReadBuffer, totalBytes);
+}
+
+static ssize_t
+platformnumber_proc_read(struct file *file, char __user *buf,
+             size_t len, loff_t *offset)
+{
+    int length = 0;
+    char *vbuf;
+    loff_t pos = *offset;
+
+    if (pos < 0)
+        return -EINVAL;
+
+    if (pos > 0 || !len)
+        return 0;
+
+    vbuf = kzalloc(len, GFP_KERNEL);
+    if (!vbuf)
+        return -ENOMEM;
+
+    length = sprintf(vbuf, "%d\n", PlatformNumber);
+
+    if (copy_to_user(buf, vbuf, length)) {
+        kfree(vbuf);
+        return -EFAULT;
+    }
+
+    kfree(vbuf);
+    *offset += length;
+    return length;
+}
+
+#ifdef UISLIB_TEST_PROC
+
+/* proc/uislib/vbus/<x>/info */
+static int
+proc_info_vbus_show(struct seq_file *m, void *v)
+{
+    struct bus_info *bus = m->private;
+    int i, devInfoCount, x;
+    char buf[999];
+
+    if (bus == NULL)
+        return 0;
+ seq_printf(m, "Client device / client driver info for %s partition (vbus #%d):\n",
+           bus->partitionName, bus->busNo);
+    if ((bus->busChannelBytes == 0) || (bus->pBusChannel == NULL))
+        return 0;
+    devInfoCount =
+        (bus->busChannelBytes -
+         sizeof(ULTRA_VBUS_CHANNEL_PROTOCOL)) /
+        sizeof(ULTRA_VBUS_DEVICEINFO);
+    x = VBUSCHANNEL_devInfoToStringBuffer(bus->pBusChannel->ChpInfo, buf,
+                          sizeof(buf) - 1, -1);
+    buf[x] = '\0';
+    seq_printf(m, "%s", buf);
+    x = VBUSCHANNEL_devInfoToStringBuffer(bus->pBusChannel->BusInfo,
+                          buf, sizeof(buf) - 1, -1);
+    buf[x] = '\0';
+    seq_printf(m, "%s", buf);
+    for (i = 0; i < devInfoCount; i++) {
+        x = VBUSCHANNEL_devInfoToStringBuffer(bus->pBusChannel->
+                              DevInfo[i], buf,
+                              sizeof(buf) - 1, i);
+        if (x > 0) {
+            buf[x] = '\0';
+            seq_printf(m, "%s", buf);
+        }
+    }
+    return 0;
+}
+
+static ssize_t
+bus_proc_write(struct file *file, const char __user *buffer,
+           size_t count, loff_t *ppos)
+{
+    int server_flag = 0;
+    int i, action = 0xffff, result;
+    char buf[count];
+    CONTROLVM_MESSAGE msg;
+    U32 busNo, deviceCount;
+
+    memset(&msg, 0, sizeof(CONTROLVM_MESSAGE));
+
+    if (copy_from_user(buf, buffer, count)) {
+        LOGERR("echo > /proc/uislib/bus: copy_from_user ****FAILED.");
+        return -EFAULT;
+    }
+
+    i = sscanf(buf, "%x-%d-%d", &action, &busNo, &deviceCount);
+
+    /* if (i < 1), i.e., if we didn't even read the action field,
+    * then action will default to 0xffff and the code below will
+    * fall through the switch and print usage.
+    */
+    switch (action) {
+    case 0:
+        /* destroy a bus */
+        if (i != 2)
+            break;
+        init_msg_header(&msg, CONTROLVM_BUS_DESTROY, 0, server_flag);
+        msg.cmd.destroyBus.busNo = busNo;
+
+        result = destroy_bus(&msg, NULL);
+
+        if (result != CONTROLVM_RESP_SUCCESS) {
+ LOGERR("echo 0-%d > /proc/uislib/bus {CONTROLVM_BUS_DESTROY Failed} Result(%d)",
+                 busNo, result);
+            return -EFAULT;
+        }
+        return count;
+    case 1:
+        /* create a bus */
+        if (i != 3)
+            break;
+        init_msg_header(&msg, CONTROLVM_BUS_CREATE, 0, server_flag);
+        msg.cmd.createBus.busNo = busNo;
+        msg.cmd.createBus.deviceCount = deviceCount;
+
+        result = create_bus(&msg, NULL);
+
+        if (result != CONTROLVM_RESP_SUCCESS) {
+ LOGERR("echo 1-%d-%d > /proc/uislib/bus {CONTROLVM_BUS_CREATE Failed} Result(%d)",
+                 busNo, deviceCount, result);
+            return -EFAULT;
+        }
+
+        return count;
+    default:
+        break;
+    }
+
+    LOGERR("USAGE: echo <action>-<busNo>... > /proc/uislib/bus");
+    LOGERR(" ");
+    LOGERR("Destruct Syntax     ControlVM Message Id");
+    LOGERR("---------------     ---------------------");
+    LOGERR("0-<busNo>       ==> CONTROLVM_BUS_DESTROY");
+    LOGERR(" ");
+    LOGERR("Construct Syntax            ControlVM Message Id");
+    LOGERR("-----------------------     -------------------- ");
+    LOGERR("1-<busNo>-<deviceCount> ==> CONTROLVM_BUS_CREATE");
+
+    return -EFAULT;
+}
+
+static ssize_t
+uislib_proc_read_writeonly(struct file *file, char __user *buffer,
+           size_t count, loff_t *ppos)
+{
+    return 0;
+}
+
+static ssize_t
+dev_proc_write(struct file *file, const char __user *buffer,
+           size_t count, loff_t *ppos)
+{
+    int server_flag = 0;
+    CONTROLVM_MESSAGE msg;
+    U32 busNo, devNo;
+    char buf[count];
+    unsigned int chanptr;
+    int type, i, action = 0xffff, result;
+
+    if (copy_from_user(buf, buffer, count)) {
+        LOGERR("echo > /proc/uislib/device: copy_from_user ****FAILED.");
+        return -EFAULT;
+    }
+
+    i = sscanf(buf, "%x-%d-%d-%x-%d",
+           &action, &busNo, &devNo, &chanptr, &type);
+
+    switch (action) {
+    case 0:
+        if (i != 3)
+            break;
+
+        /* destroy a device */
+        init_msg_header(&msg, CONTROLVM_DEVICE_DESTROY, 0, server_flag);
+        msg.cmd.destroyDevice.busNo = busNo;
+        msg.cmd.destroyDevice.devNo = devNo;
+
+        result = destroy_device(&msg, NULL);
+
+        if (result != CONTROLVM_RESP_SUCCESS) {
+ LOGERR("echo 0-%d-%d > /proc/uislib/device {CONTROLVM_DEVICE_DESTROY Failed} Result(%d)",
+                 busNo, devNo, result);
+            return -EFAULT;
+        }
+
+        return count;
+
+    case 1:
+        if (i != 5)
+            break;
+
+        /* create a device */
+        init_msg_header(&msg, CONTROLVM_DEVICE_CREATE, 0, server_flag);
+        msg.cmd.createDevice.busNo = busNo;
+        msg.cmd.createDevice.devNo = devNo;
+        msg.cmd.createDevice.channelAddr = __pa(chanptr);
+        msg.cmd.createDevice.channelBytes = MIN_IO_CHANNEL_SIZE;
+
+        if (type == 0)
+            msg.cmd.createDevice.dataTypeGuid =
+                UltraVhbaChannelProtocolGuid;
+        else if (type == 1)
+            msg.cmd.createDevice.dataTypeGuid =
+                UltraVnicChannelProtocolGuid;
+        else {
+ LOGERR("echo 1-%d-%d-%x-<type> > /proc/uislib/devce failed: invalid device type %d.",
+                 busNo, devNo, chanptr, type);
+            return -EFAULT;
+        }
+
+        result = create_device(&msg, NULL);
+
+        if (result != CONTROLVM_RESP_SUCCESS) {
+            if (type == 0)
+ LOGERR("echo 1-%d-%d-%x-0 > /proc/uislib/device {CONTROLVM_DEVICE_CREATE[vHBA] Failed} Result(%d)",
+                     busNo, devNo, chanptr, result);
+            else
+ LOGERR("echo 1-%d-%d-%x-1 > /proc/uislib/device {CONTROLVM_DEVICE_CREATE[vNIC] Failed} Result(%d)",
+                     busNo, devNo, chanptr, result);
+            return -EFAULT;
+        }
+
+    default:
+        break;
+    }
+
+ LOGERR("USAGE: echo <action>-<busNo>-<devNo>... > /proc/uislib/device");
+    LOGERR(" ");
+    LOGERR("Destruct Syntax       ControlVM Message Id");
+    LOGERR("-----------------     ------------------------");
+    LOGERR("0-<busNo>-<devNo> ==> CONTROLVM_DEVICE_DESTROY");
+    LOGERR(" ");
+    LOGERR("Construct Syntax                       ControlVM Message Id");
+    LOGERR
+        ("---------------------------------- ----------------------- ");
+    LOGERR
+ ("1-<busNo>-<devNo>-<chanptr>-<type> ==> CONTROLVM_DEVICE_CREATE");
+    LOGERR("      <type = 0>: vHBA");
+    LOGERR("      <type = 1>: vNIC");
+    LOGERR(" ");
+
+    return -EFAULT;
+}
+
+static ssize_t
+cycles_before_wait_proc_write(struct file *file, const char __user *buffer,
+                  size_t count, loff_t *ppos)
+{
+    char buf[count];
+
+#define CYCLES_BEFORE_WAIT_USE_ERROR  { \
+    LOGERR("Incorrect Call Home Input.\n"); \
+    pr_info("Please pass Call Home Event Parameters in the form:\n"); \
+ pr_info("EventID Category Type[parameter1][parameter2][parameter3][parameter4][parameter5][parameter6]\n"); \
+    return -EFAULT; \
+}
+
+    if (count == 0)
+        CYCLES_BEFORE_WAIT_USE_ERROR;
+
+    if (copy_from_user(buf, buffer, count)) {
+        LOGERR("copy_from_user failed.\n");
+        return -EFAULT;
+    }
+    buf[count - 1] = '\0';    /* Replace the LF at the end of the
+                 * input with a NULL */
+    /* Pull out the cycles_before_wait must be decimal integer */
+    if (sscanf(buf, "%lld", &cycles_before_wait) != 1)
+        CYCLES_BEFORE_WAIT_USE_ERROR;
+
+    return count;
+}
+
+static ssize_t
+reset_counts_proc_write(struct file *file, const char __user *buffer,
+            size_t count, loff_t *ppos)
+{
+    char buf[count];
+    unsigned long long new_value;
+    struct bus_info *bus;
+    int i;
+
+#define RESET_COUNTS_USE_ERROR  { \
+    LOGERR("Incorrect reset_counts Input.\n"); \
+    pr_info("Please pass the new value for the counters:\n"); \
+    pr_info("e.g. echo 0 > reset_counts\n"); \
+    return -EFAULT; \
+    }
+
+    if (count == 0)
+        RESET_COUNTS_USE_ERROR;
+
+    if (copy_from_user(buf, buffer, count)) {
+        LOGERR("copy_from_user failed.\n");
+        return -EFAULT;
+    }
+    buf[count - 1] = '\0';    /* Replace the LF at the end of the
+                 * input with a NULL */
+    /* Pull out the reset_counts must be decimal integer */
+    if (sscanf(buf, "%llu", &new_value) != 1)
+        RESET_COUNTS_USE_ERROR;
+    read_lock(&BusListLock);
+    for (bus = BusListHead; bus; bus = bus->next) {
+
+        for (i = 0; i < bus->deviceCount; i++) {
+            if (bus->device[i]) {
+                bus->device[i]->first_busy_cnt = new_value;
+                bus->device[i]->moved_to_tail_cnt = new_value;
+                bus->device[i]->last_on_list_cnt = new_value;
+            }
+        }
+    }
+    read_unlock(&BusListLock);
+    tot_moved_to_tail_cnt = new_value;
+    tot_wait_cnt = new_value;
+    tot_wakeup_cnt = new_value;
+    tot_schedule_cnt = new_value;
+    return count;
+}
+
+static ssize_t
+smart_wakeup_proc_write(struct file *file, const char __user *buffer,
+            size_t count, loff_t *ppos)
+{
+    char buf[count];
+    int new_value;
+
+#define SMART_WAKEUP_USE_ERROR  { \
+ LOGERR("Incorrect smart_wakeup Input 0 disables smart_wakeup, and 1 enables smart_wakeup.\n"); \
+    pr_info("echo 0 > smart_wakeup\n"); \
+    pr_info("echo 1 > smart_wakeup\n"); \
+    return -EFAULT; \
+    }
+
+    if (count == 0)
+        SMART_WAKEUP_USE_ERROR;
+
+    if (copy_from_user(buf, buffer, count)) {
+        LOGERR("copy_from_user failed.\n");
+        return -EFAULT;
+    }
+    buf[count - 1] = '\0';    /* Replace the LF at the end of the
+                 * input with a NULL */
+    /* Pull out the smart_wakeup must be decimal integer */
+    if (sscanf(buf, "%d", &new_value) != 1)
+        SMART_WAKEUP_USE_ERROR;
+    en_smart_wakeup = new_value;
+    return count;
+}
+
+static ssize_t
+test_proc_write(struct file *file, const char __user *buffer,
+        size_t count, loff_t *ppos)
+{
+    int i, action = 0xffff;
+    char buf[count];
+    CONTROLVM_MESSAGE msg;
+    S64 vrtc_offset;
+
+    memset(&msg, 0, sizeof(CONTROLVM_MESSAGE));
+
+    if (copy_from_user(buf, buffer, count)) {
+        LOGERR("copy_from_user ****FAILED.\n");
+        return -EFAULT;
+    }
+
+    i = sscanf(buf, "%x", &action);
+
+    /* if (i < 1), i.e., if we didn't even read the action field,
+    * then action will default to 0xffff and the code below will
+    * fall through the switch and print usage. */
+    switch (action) {
+    case 6:
+        msg.hdr.Id = CONTROLVM_CHIPSET_STOP;
+        msg.hdr.Flags.responseExpected = 1;
+        stop_chipset(&msg, NULL);
+        break;
+    case 7:
+        vrtc_offset = 0;
+        LOGERR("about to issue QUERY vrtc_offset=%LX", vrtc_offset);
+        vrtc_offset = Issue_VMCALL_QUERY_GUEST_VIRTUAL_TIME_OFFSET();
+        LOGERR("result is vrtc_offset=%LX", vrtc_offset);
+        break;
+    case 8:
+        vrtc_offset = 60;
+        LOGERR("about to increase physical time by 0x%LX seconds",
+               vrtc_offset);
+        vrtc_offset = Issue_VMCALL_UPDATE_PHYSICAL_TIME(vrtc_offset);
+        break;
+    case 9:
+        vrtc_offset = -60;
+        LOGERR("about to decrease physical time by 0x%LX seconds",
+               vrtc_offset);
+        vrtc_offset = Issue_VMCALL_UPDATE_PHYSICAL_TIME(vrtc_offset);
+        break;
+    default:
+        LOGERR("usage: 6 for CHIPSET_STOP\n");
+        LOGERR("       7 for VMCALL_QUERY_GUEST_VIRTUAL_TIME_OFFSET()\n");
+        LOGERR("       8 for VMCALL_UPDATE_PHYSICAL_TIME(60)\n");
+        LOGERR("       9 for VMCALL_UPDATE_PHYSICAL_TIME(-60)\n");
+        return -EFAULT;
+        break;
+    }
+    return count;
+}
+
+#endif                /* UISLIB_TEST_PROC */
+static struct device_info *
+find_dev(U32 busNo, U32 devNo)
+{
+    struct bus_info *bus;
+    struct device_info *dev = NULL;
+
+    read_lock(&BusListLock);
+    for (bus = BusListHead; bus; bus = bus->next) {
+        if (bus->busNo == busNo) {
+            /* make sure the device number is valid */
+            if (devNo >= bus->deviceCount) {
+                LOGERR("%s bad busNo, devNo=%d,%d",
+                       __func__,
+                       (int) (busNo), (int) (devNo));
+                goto Away;
+            }
+            dev = bus->device[devNo];
+            if (!dev)
+                LOGERR("%s bad busNo, devNo=%d,%d",
+                       __func__,
+                       (int) (busNo), (int) (devNo));
+            goto Away;
+        }
+    }
+Away:
+    read_unlock(&BusListLock);
+    return dev;
+}
+
+/*  This thread calls the "interrupt" function for each device that has
+ *  enabled such using uislib_enable_channel_interrupts().  The "interrupt"
+ *  function typically reads and processes the devices's channel input
+ * queue. This thread repeatedly does this, until the thread is told to stop
+ *  (via uisthread_stop()).  Sleeping rules:
+ * - If we have called the "interrupt" function for all devices, and all of + * them have reported "nothing processed" (returned 0), then we will go to
+ *    sleep for a maximum of POLLJIFFIES_NORMAL jiffies.
+ *  - If anyone calls uislib_force_channel_interrupt(), the above jiffy
+ *    sleep will be interrupted, and we will resume calling the "interrupt"
+ *    function for all devices.
+ *  - The list of devices is dynamically re-ordered in order to
+ *    attempt to preserve fairness.  Whenever we spin thru the list of
+ *    devices and call the dev->interrupt() function, if we find
+ *    devices which report that there is still more work to do, the
+ *    the first such device we find is moved to the end of the device
+ *    list.  This ensures that extremely busy devices don't starve out
+ *    less-busy ones.
+ *
+ */
+static int
+Process_Incoming(void *v)
+{
+    unsigned long long cur_cycles, old_cycles, idle_cycles, delta_cycles;
+    struct list_head *new_tail = NULL;
+    int i;
+    UIS_DAEMONIZE("dev_incoming");
+    for (i = 0; i < 16; i++) {
+        old_cycles = get_cycles();
+        wait_event_timeout(Wakeup_Polling_Device_Channels,
+                   0, POLLJIFFIES_NORMAL);
+        cur_cycles = get_cycles();
+        if (wait_cycles == 0) {
+            wait_cycles = (cur_cycles - old_cycles);
+        } else {
+            if (wait_cycles < (cur_cycles - old_cycles))
+                wait_cycles = (cur_cycles - old_cycles);
+        }
+    }
+    LOGINF("wait_cycles=%llu", wait_cycles);
+    cycles_before_wait = wait_cycles;
+    idle_cycles = 0;
+    Go_Polling_Device_Channels = 0;
+    while (1) {
+        struct list_head *lelt, *tmp;
+        struct device_info *dev = NULL;
+
+        /* poll each channel for input */
+        LOCKSEM_UNINTERRUPTIBLE(&Lock_Polling_Device_Channels);
+        new_tail = NULL;
+        list_for_each_safe(lelt, tmp, &List_Polling_Device_Channels) {
+            int rc = 0;
+            dev = list_entry(lelt, struct device_info,
+                     list_polling_device_channels);
+ LOCKSEM_UNINTERRUPTIBLE(&dev->interrupt_callback_lock);
+            if (dev->interrupt)
+                rc = dev->interrupt(dev->interrupt_context);
+            else
+                continue;
+            UNLOCKSEM(&dev->interrupt_callback_lock);
+            if (rc) {
+                /* dev->interrupt returned, but there
+                * is still more work to do.
+                * Reschedule work to occur as soon as
+                * possible. */
+                idle_cycles = 0;
+                if (new_tail == NULL) {
+                    dev->first_busy_cnt++;
+                    if (!
+                        (list_is_last
+                         (lelt,
+                          &List_Polling_Device_Channels))) {
+                        new_tail = lelt;
+                        dev->moved_to_tail_cnt++;
+                    } else
+                        dev->last_on_list_cnt++;
+                }
+
+            }
+            if (Incoming_ThreadInfo.should_stop)
+                break;
+        }
+        if (new_tail != NULL) {
+            tot_moved_to_tail_cnt++;
+            list_move_tail(new_tail, &List_Polling_Device_Channels);
+        }
+        UNLOCKSEM(&Lock_Polling_Device_Channels);
+        cur_cycles = get_cycles();
+        delta_cycles = cur_cycles - old_cycles;
+        old_cycles = cur_cycles;
+
+        /* At this point, we have scanned thru all of the
+        * channels, and at least one of the following is true:
+        * - there is no input waiting on any of the channels
+        * - we have received a signal to stop this thread
+        */
+        if (Incoming_ThreadInfo.should_stop)
+            break;
+        if (en_smart_wakeup == 0xFF) {
+ LOGINF("en_smart_wakeup set to 0xff, to force exiting process_incoming");
+            break;
+        }
+        /* wait for POLLJIFFIES_NORMAL jiffies, or until
+        * someone wakes up Wakeup_Polling_Device_Channels,
+        * whichever comes first only do a wait when we have
+        * been idle for cycles_before_wait cycles.
+        */
+        if (idle_cycles > cycles_before_wait) {
+            Go_Polling_Device_Channels = 0;
+            tot_wait_cnt++;
+            wait_event_timeout(Wakeup_Polling_Device_Channels,
+                       Go_Polling_Device_Channels,
+                       POLLJIFFIES_NORMAL);
+            Go_Polling_Device_Channels = 1;
+        } else {
+            tot_schedule_cnt++;
+            schedule();
+            idle_cycles = idle_cycles + delta_cycles;
+        }
+    }
+    DBGINF("exiting.\n");
+    complete_and_exit(&Incoming_ThreadInfo.has_stopped, 0);
+}
+
+static BOOL
+Initialize_incoming_thread(void)
+{
+    if (Incoming_Thread_Started)
+        return TRUE;
+    if (!uisthread_start(&Incoming_ThreadInfo,
+                 &Process_Incoming, NULL, "dev_incoming")) {
+        LOGERR("uisthread_start Initialize_incoming_thread ****FAILED");
+        return FALSE;
+    }
+    Incoming_Thread_Started = TRUE;
+    return TRUE;
+}
+
+/*  Add a new device/channel to the list being processed by
+ *  Process_Incoming().
+ *  <interrupt> - indicates the function to call periodically.
+ *  <interrupt_context> - indicates the data to pass to the <interrupt>
+ *                        function.
+ */
+void
+uislib_enable_channel_interrupts(U32 busNo, U32 devNo,
+                 int (*interrupt)(void *),
+                 void *interrupt_context)
+{
+    struct device_info *dev;
+    dev = find_dev(busNo, devNo);
+    if (!dev) {
+        LOGERR("%s busNo=%d, devNo=%d", __func__, (int) (busNo),
+               (int) (devNo));
+        return;
+    }
+    LOCKSEM_UNINTERRUPTIBLE(&Lock_Polling_Device_Channels);
+    Initialize_incoming_thread();
+    dev->interrupt = interrupt;
+    dev->interrupt_context = interrupt_context;
+    dev->polling = TRUE;
+    list_add_tail(&(dev->list_polling_device_channels),
+              &List_Polling_Device_Channels);
+    UNLOCKSEM(&Lock_Polling_Device_Channels);
+}
+EXPORT_SYMBOL(uislib_enable_channel_interrupts);
+
+/*  Remove a device/channel from the list being processed by
+ *  Process_Incoming().
+ */
+void
+uislib_disable_channel_interrupts(U32 busNo, U32 devNo)
+{
+    struct device_info *dev;
+    dev = find_dev(busNo, devNo);
+    if (!dev) {
+        LOGERR("%s busNo=%d, devNo=%d", __func__, (int) (busNo),
+               (int) (devNo));
+        return;
+    }
+    LOCKSEM_UNINTERRUPTIBLE(&Lock_Polling_Device_Channels);
+    list_del(&dev->list_polling_device_channels);
+    dev->polling = FALSE;
+    dev->interrupt = NULL;
+    UNLOCKSEM(&Lock_Polling_Device_Channels);
+}
+EXPORT_SYMBOL(uislib_disable_channel_interrupts);
+
+static void
+do_wakeup_polling_device_channels(struct work_struct *dummy)
+{
+    if (!Go_Polling_Device_Channels) {
+        Go_Polling_Device_Channels = 1;
+        wake_up(&Wakeup_Polling_Device_Channels);
+    }
+}
+
+DECLARE_WORK(Work_wakeup_polling_device_channels,
+         do_wakeup_polling_device_channels);
+
+/* Call this function when you want to send a hint to Process_Incoming() that
+ *  your device might have more requests.
+ */
+void
+uislib_force_channel_interrupt(U32 busNo, U32 devNo)
+{
+    if (en_smart_wakeup == 0)
+        return;
+    if (Go_Polling_Device_Channels)
+        return;
+    /* The point of using schedule_work() instead of just doing
+     * the work inline is to force a slight delay before waking up
+     * the Process_Incoming() thread.
+     */
+    tot_wakeup_cnt++;
+    schedule_work(&Work_wakeup_polling_device_channels);
+}
+EXPORT_SYMBOL(uislib_force_channel_interrupt);
+
+/*****************************************************/
+/* Module Init & Exit functions                      */
+/*****************************************************/
+
+static int __init
+uislib_mod_init(void)
+{
+
+    LOGINF("MONITORAPIS");
+
+    LOGINF("sizeof(struct uiscmdrsp):%lu bytes\n",
+           (ulong) sizeof(struct uiscmdrsp));
+    LOGINF("sizeof(struct phys_info):%lu\n",
+           (ulong) sizeof(struct phys_info));
+    LOGINF("sizeof(uiscmdrsp_scsi):%lu\n",
+           (ulong) sizeof(struct uiscmdrsp_scsi));
+    LOGINF("sizeof(uiscmdrsp_net):%lu\n",
+           (ulong) sizeof(struct uiscmdrsp_net));
+    LOGINF("sizeof(CONTROLVM_MESSAGE):%lu bytes\n",
+           (ulong) sizeof(CONTROLVM_MESSAGE));
+    LOGINF("sizeof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL):%lu bytes\n",
+           (ulong) sizeof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL));
+    LOGINF("sizeof(CHANNEL_HEADER):%lu bytes\n",
+           (ulong) sizeof(CHANNEL_HEADER));
+    LOGINF("sizeof(ULTRA_IO_CHANNEL_PROTOCOL):%lu bytes\n",
+           (ulong) sizeof(ULTRA_IO_CHANNEL_PROTOCOL));
+    LOGINF("SIZEOF_CMDRSP:%lu bytes\n", SIZEOF_CMDRSP);
+    LOGINF("SIZEOF_PROTOCOL:%lu bytes\n", SIZEOF_PROTOCOL);
+
+    /* initialize global pointers to NULL */
+    BusListHead = NULL;
+    BusListCount = MaxBusCount = 0;
+    rwlock_init(&BusListLock);
+    VirtControlChanFunc = NULL;
+
+    /* Issue VMCALL_GET_CONTROLVM_ADDR to get CtrlChanPhysAddr and
+     * then map this physical address to a virtual address. */
+    POSTCODE_LINUX_2(DRIVER_ENTRY_PC, POSTCODE_SEVERITY_INFO);
+
+    /* create the proc entries for the channels */
+    uislib_proc_dir = proc_mkdir(DIR_PROC_ENTRY, NULL);
+    /* (e.g., for /proc/uislib/vbus/<x>/info) */
+ uislib_proc_vbus_dir = proc_mkdir(DIR_VBUS_PROC_ENTRY, uislib_proc_dir);
+
+    vnic_proc_entry = proc_create(VNIC_PROC_ENTRY_FN, 0, uislib_proc_dir,
+                      &proc_vnic_fops);
+    SET_PROC_OWNER(vnic_proc_entry, THIS_MODULE);
+
+    /* for testing purposes only, create the proc entries for
+     * enqueuing Control Channel messages */
+    chipset_proc_entry =
+        proc_create(CHIPSET_PROC_ENTRY_FN, 0, uislib_proc_dir,
+            &proc_chipset_fops);
+    SET_PROC_OWNER(chipset_proc_entry, THIS_MODULE);
+
+    info_proc_entry = proc_create(INFO_PROC_ENTRY_FN, 0, uislib_proc_dir,
+                      &proc_info_fops);
+    SET_PROC_OWNER(info_proc_entry, THIS_MODULE);
+
+    platformnumber_proc_entry =
+        proc_create(PLATFORMNUMBER_PROC_ENTRY_FN, 0, uislib_proc_dir,
+            &proc_platformnumber_fops);
+    SET_PROC_OWNER(platformnumberinfo_proc_entry, THIS_MODULE);
+
+    cycles_before_wait_proc_entry =
+        proc_create(CYCLES_BEFORE_WAIT_PROC_ENTRY_FN, 0, uislib_proc_dir,
+            &proc_cycles_before_wait_fops);
+    SET_PROC_OWNER(cycles_before_wait_proc_entry, THIS_MODULE);
+
+    reset_counts_proc_entry =
+        proc_create(RESET_COUNTS_PROC_ENTRY_FN, 0, uislib_proc_dir,
+            &proc_reset_counts_fops);
+    SET_PROC_OWNER(reset_counts_proc_entry, THIS_MODULE);
+
+    smart_wakeup_proc_entry =
+        proc_create(SMART_WAKEUP_PROC_ENTRY_FN, 0, uislib_proc_dir,
+            &proc_smart_wakeup_fops);
+    SET_PROC_OWNER(smart_wakeup_proc_entry, THIS_MODULE);
+
+#ifdef UISLIB_TEST_PROC
+    test_proc_entry = proc_create(TEST_PROC_ENTRY_FN, 0, uislib_proc_dir,
+                      &proc_test_fops);
+    SET_PROC_OWNER(test_proc_entry, THIS_MODULE);
+
+    bus_proc_entry = proc_create(BUS_PROC_ENTRY_FN, 0, uislib_proc_dir,
+                     &proc_bus_fops);
+    SET_PROC_OWNER(bus_proc_entry, THIS_MODULE);
+
+    dev_proc_entry = proc_create(DEV_PROC_ENTRY_FN, 0, uislib_proc_dir,
+                     &proc_dev_fops);
+    SET_PROC_OWNER(dev_proc_entry, THIS_MODULE);
+#endif                /* UISLIB_TEST_PROC */
+    POSTCODE_LINUX_3(DRIVER_EXIT_PC, 0, POSTCODE_SEVERITY_INFO);
+    return 0;
+}
+
+static void __exit
+uislib_mod_exit(void)
+{
+    if (disable_proc_entry)
+        remove_proc_entry(DISABLE_PROC_ENTRY_FN, uislib_proc_dir);
+    if (cycles_before_wait_proc_entry)
+        remove_proc_entry(CYCLES_BEFORE_WAIT_PROC_ENTRY_FN,
+                  uislib_proc_dir);
+    if (reset_counts_proc_entry)
+        remove_proc_entry(RESET_COUNTS_PROC_ENTRY_FN, uislib_proc_dir);
+    if (smart_wakeup_proc_entry)
+        remove_proc_entry(SMART_WAKEUP_PROC_ENTRY_FN, uislib_proc_dir);
+    if (ctrlchan_proc_entry)
+        remove_proc_entry(CTRLCHAN_PROC_ENTRY_FN, uislib_proc_dir);
+    if (pmem_proc_entry)
+        remove_proc_entry(PMEM_PROC_ENTRY_FN, uislib_proc_dir);
+    if (info_proc_entry)
+        remove_proc_entry(INFO_PROC_ENTRY_FN, uislib_proc_dir);
+    if (switch_proc_entry)
+        remove_proc_entry(SWITCH_PROC_ENTRY_FN, uislib_proc_dir);
+    if (extport_proc_entry)
+        remove_proc_entry(EXTPORT_PROC_ENTRY_FN, uislib_proc_dir);
+    if (platformnumber_proc_entry)
+        remove_proc_entry(PLATFORMNUMBER_PROC_ENTRY_FN,
+                  uislib_proc_dir);
+    if (bus_proc_entry)
+        remove_proc_entry(BUS_PROC_ENTRY_FN, uislib_proc_dir);
+    if (dev_proc_entry)
+        remove_proc_entry(DEV_PROC_ENTRY_FN, uislib_proc_dir);
+    if (vnic_proc_entry)
+        remove_proc_entry(VNIC_PROC_ENTRY_FN, uislib_proc_dir);
+    if (chipset_proc_entry)
+        remove_proc_entry(CHIPSET_PROC_ENTRY_FN, uislib_proc_dir);
+    if (uislib_proc_vbus_dir)
+        remove_proc_entry(DIR_VBUS_PROC_ENTRY, uislib_proc_dir);
+    if (uislib_proc_dir)
+        remove_proc_entry(DIR_PROC_ENTRY, NULL);
+
+    if (ProcReadBuffer) {
+        UISVFREE(ProcReadBuffer, PROC_READ_BUFFER_SIZE);
+        ProcReadBuffer = NULL;
+    }
+
+    DBGINF("goodbye.\n");
+    return;
+}
+
+module_init(uislib_mod_init);
+module_exit(uislib_mod_exit);
+
+int uis_mandatory_services = -1;
+
+module_param_named(mandatory_services, uis_mandatory_services,
+           int, S_IRUGO);
+MODULE_PARM_DESC(uis_mandatory_services,
+ "number of server drivers we expect to register (default=-1 for legacy behavior)");
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Usha Srinivasan");
+MODULE_ALIAS("uislib");
+  /* this is extracted during depmod and kept in modules.dep */
Index: linux-2.6.staging/drivers/staging/unisys/uislib/uisqueue.c
===================================================================
--- /dev/null
+++ linux-2.6.staging/drivers/staging/unisys/uislib/uisqueue.c
@@ -0,0 +1,166 @@
+/* uisqueue.c
+ *
+ * Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ */
+
+/* @ALL_INSPECTED */
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include "uisutils.h"
+
+#include "chanstub.h"
+
+/* this is shorter than using __FILE__ (full path name) in
+ * debug/info/error messages */
+#define CURRENT_FILE_PC UISLIB_PC_uisqueue_c
+#define __MYFILE__ "uisqueue.c"
+
+#define RETVOID    do { goto Away; } while (0)
+#define RETINT(x)  do { rc = (x); goto Away; } while (0)
+#define RETPTR(x)  do { rc = (x); goto Away; } while (0)
+#define RETBOOL(x) do { rc = (x); goto Away; } while (0)
+
+#define CHECK_CACHE_ALIGN 0
+
+/*****************************************************/
+/* Exported functions                                */
+/*****************************************************/
+unsigned long long
+uisqueue_InterlockedOr(volatile unsigned long long *Target,
+               unsigned long long Set)
+{
+    unsigned long long i;
+    unsigned long long j;
+
+    j = *Target;
+    do {
+        i = j;
+        j = uislibcmpxchg64((unsigned long long *) Target,
+                    i, i | Set, sizeof(*(Target)));
+
+    } while (i != j);
+
+    return j;
+}
+EXPORT_SYMBOL(uisqueue_InterlockedOr);
+
+unsigned long long
+uisqueue_InterlockedAnd(volatile unsigned long long *Target,
+            unsigned long long Set)
+{
+    unsigned long long i;
+    unsigned long long j;
+
+    j = *Target;
+    do {
+        i = j;
+        j = uislibcmpxchg64((unsigned long long *) Target,
+                    i, i & Set, sizeof(*(Target)));
+
+    } while (i != j);
+
+    return j;
+}
+EXPORT_SYMBOL(uisqueue_InterlockedAnd);
+
+static U8
+do_locked_client_insert(struct uisqueue_info *queueinfo,
+            unsigned int whichqueue,
+            void *pSignal,
+            spinlock_t *lock,
+            unsigned char issueInterruptIfEmpty,
+            U64 interruptHandle, U8 *channelId)
+{
+    unsigned long flags;
+    unsigned char queueWasEmpty;
+    unsigned int locked = 0;
+    unsigned int acquired = 0;
+    U8 rc = 0;
+
+    spin_lock_irqsave(lock, flags);
+    locked = 1;
+
+    if (!ULTRA_CHANNEL_CLIENT_ACQUIRE_OS(queueinfo->chan, channelId, NULL))
+        RETINT(0);
+
+    acquired = 1;
+
+    queueWasEmpty = SignalQueueIsEmpty(queueinfo->chan, whichqueue);
+    if (!SignalInsert(queueinfo->chan, whichqueue, pSignal))
+        RETINT(0);
+    ULTRA_CHANNEL_CLIENT_RELEASE_OS(queueinfo->chan, channelId, NULL);
+    acquired = 0;
+    spin_unlock_irqrestore(lock, flags);
+    locked = 0;
+
+    queueinfo->packets_sent++;
+
+    RETINT(1);
+
+Away:
+    if (acquired) {
+        ULTRA_CHANNEL_CLIENT_RELEASE_OS(queueinfo->chan, channelId,
+                        NULL);
+        acquired = 0;
+    }
+    if (locked) {
+        spin_unlock_irqrestore((spinlock_t *) lock, flags);
+        locked = 0;
+    }
+
+    return rc;
+}
+
+int
+uisqueue_put_cmdrsp_with_lock_client(struct uisqueue_info *queueinfo,
+                     struct uiscmdrsp *cmdrsp,
+                     unsigned int whichqueue,
+                     void *insertlock,
+                     unsigned char issueInterruptIfEmpty,
+                     U64 interruptHandle,
+                     char oktowait, U8 *channelId)
+{
+    while (!do_locked_client_insert(queueinfo, whichqueue, cmdrsp,
+                    (spinlock_t *) insertlock,
+                    issueInterruptIfEmpty,
+                    interruptHandle, channelId)) {
+        if (oktowait != OK_TO_WAIT) {
+ LOGERR("****FAILED SignalInsert failed; cannot wait; insert aborted\n");
+            return 0;    /* failed to queue */
+        }
+        /* try again */
+        LOGERR("****FAILED SignalInsert failed; waiting to try again\n");
+        set_current_state(TASK_INTERRUPTIBLE);
+        schedule_timeout(msecs_to_jiffies(10));
+    }
+    return 1;
+}
+EXPORT_SYMBOL(uisqueue_put_cmdrsp_with_lock_client);
+
+/* uisqueue_get_cmdrsp gets the cmdrsp entry at the head of the queue
+ * returns NULL if queue is empty */
+int
+uisqueue_get_cmdrsp(struct uisqueue_info *queueinfo,
+            void *cmdrsp, unsigned int whichqueue)
+{
+    if (!SignalRemove(queueinfo->chan, whichqueue, cmdrsp))
+        return 0;
+
+    queueinfo->packets_received++;
+
+    return 1;        /* Success */
+}
+EXPORT_SYMBOL(uisqueue_get_cmdrsp);
Index: linux-2.6.staging/drivers/staging/unisys/uislib/uisthread.c
===================================================================
--- /dev/null
+++ linux-2.6.staging/drivers/staging/unisys/uislib/uisthread.c
@@ -0,0 +1,85 @@
+/* uisthread.c
+ *
+ * Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ */
+
+/* @ALL_INSPECTED */
+#include <asm/processor.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/kthread.h>
+#include "uniklog.h"
+#include "uisutils.h"
+#include "uisthread.h"
+
+#define KILL(a, b, c) kill_pid(find_vpid(a), b, c)
+
+/* this is shorter than using __FILE__ (full path name) in
+ * debug/info/error messages
+ */
+#define CURRENT_FILE_PC UISLIB_PC_uisthread_c
+#define __MYFILE__ "uisthread.c"
+
+/*****************************************************/
+/* Exported functions                                */
+/*****************************************************/
+
+/* returns 0 for failure, 1 for success */
+int
+uisthread_start(struct uisthread_info *thrinfo,
+        int (*threadfn)(void *), void *thrcontext, char *name)
+{
+    thrinfo->should_stop = 0;
+    /* used to stop the thread */
+    init_completion(&thrinfo->has_stopped);
+    thrinfo->task = kthread_create(threadfn, thrcontext, name, NULL);
+    if (thrinfo->task == NULL) {
+        thrinfo->id = 0;
+        return 0;    /* failure */
+    }
+    thrinfo->id = thrinfo->task->pid;
+    wake_up_process(thrinfo->task);
+    LOGINF("started thread pid:%d\n", thrinfo->id);
+    return 1;
+
+}
+EXPORT_SYMBOL(uisthread_start);
+
+void
+uisthread_stop(struct uisthread_info *thrinfo)
+{
+    int ret;
+    int stopped = 0;
+    if (thrinfo->id == 0)
+        return;        /* thread not running */
+
+    LOGINF("uisthread_stop stopping id:%d\n", thrinfo->id);
+    thrinfo->should_stop = 1;
+    ret = KILL(thrinfo->id, SIGHUP, 1);
+    if (ret) {
+        LOGERR("unable to signal thread %d\n", ret);
+    } else {
+        /* give up if the thread has NOT died in 1 minute */
+        if (wait_for_completion_timeout(&thrinfo->has_stopped, 60 * HZ))
+            stopped = 1;
+        else
+            LOGERR("timed out trying to signal thread\n");
+    }
+    if (stopped) {
+        LOGINF("uisthread_stop stopped id:%d\n", thrinfo->id);
+        thrinfo->id = 0;
+    }
+}
+EXPORT_SYMBOL(uisthread_stop);
Index: linux-2.6.staging/drivers/staging/unisys/uislib/uisutils.c
===================================================================
--- /dev/null
+++ linux-2.6.staging/drivers/staging/unisys/uislib/uisutils.c
@@ -0,0 +1,349 @@
+/* uisutils.c
+ *
+ * Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ */
+
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <commontypes.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include "uniklog.h"
+#include "uisutils.h"
+#include "version.h"
+#include "vbushelper.h"
+#include "guidutils.h"
+#include <linux/skbuff.h>
+#ifdef CONFIG_HIGHMEM
+#include <linux/highmem.h>
+#endif
+
+/* this is shorter than using __FILE__ (full path name) in
+ * debug/info/error messages
+ */
+#define CURRENT_FILE_PC UISLIB_PC_uisutils_c
+#define __MYFILE__ "uisutils.c"
+
+/* exports */
+atomic_t UisUtils_Registered_Services = ATOMIC_INIT(0);
+                    /* num registrations via
+                     * uisctrl_register_req_handler() or
+                     * uisctrl_register_req_handler_ex() */
+
+
+/*****************************************************/
+/* Utility functions                                 */
+/*****************************************************/
+
+int
+util_add_proc_line_ex(int *total, char **buffer, int *buffer_remaining,
+              char *format, ...)
+{
+    va_list args;
+    int len;
+
+    DBGINF("buffer = 0x%p : *buffer = 0x%p.\n", buffer, *buffer);
+    va_start(args, format);
+    len = vsnprintf(*buffer, *buffer_remaining, format, args);
+    if (len >= *buffer_remaining) {
+        *buffer += *buffer_remaining;
+        *total += *buffer_remaining;
+        *buffer_remaining = 0;
+        LOGERR("bytes remaining is too small!\n");
+        return -1;
+    }
+    *buffer_remaining -= len;
+    *buffer += len;
+    *total += len;
+    return len;
+}
+EXPORT_SYMBOL(util_add_proc_line_ex);
+
+int
+uisctrl_register_req_handler(int type, void *fptr,
+                 ULTRA_VBUS_DEVICEINFO *chipset_DriverInfo)
+{
+    LOGINF("type = %d, fptr = 0x%p.\n", type, fptr);
+
+    switch (type) {
+    case 2:
+        if (fptr) {
+            if (!VirtControlChanFunc)
+                atomic_inc(&UisUtils_Registered_Services);
+            VirtControlChanFunc = fptr;
+        } else {
+            if (VirtControlChanFunc)
+                atomic_dec(&UisUtils_Registered_Services);
+            VirtControlChanFunc = NULL;
+        }
+        break;
+
+    default:
+        LOGERR("invalid type %d.\n", type);
+        return 0;
+    }
+    if (chipset_DriverInfo)
+        BusDeviceInfo_Init(chipset_DriverInfo,
+                   "chipset", "uislib",
+                   VERSION, NULL, __DATE__, __TIME__);
+
+    return 1;
+}
+EXPORT_SYMBOL(uisctrl_register_req_handler);
+
+int
+uisctrl_register_req_handler_ex(GUID switchTypeGuid,
+                const char *switch_type_name,
+                int (*controlfunc)(struct io_msgs *),
+                unsigned long min_channel_bytes,
+                int (*Server_Channel_Ok)(unsigned long
+                              channelBytes),
+                int (*Server_Channel_Init)
+                 (void *x, unsigned char *clientStr,
+                  U32 clientStrLen, U64 bytes),
+                ULTRA_VBUS_DEVICEINFO *chipset_DriverInfo)
+{
+    char s[99];
+    ReqHandlerInfo_t *pReqHandlerInfo;
+    int rc = 0;        /* assume failure */
+    LOGINF("type=%s, controlfunc=0x%p.\n",
+           GUID_format1(&switchTypeGuid, s), controlfunc);
+    if (!controlfunc) {
+        LOGERR("%s: controlfunc must be supplied\n",
+               GUID_format1(&switchTypeGuid, s));
+        goto Away;
+    }
+    if (!Server_Channel_Ok) {
+        LOGERR("%s: Server_Channel_Ok must be supplied\n",
+               GUID_format1(&switchTypeGuid, s));
+        goto Away;
+    }
+    if (!Server_Channel_Init) {
+        LOGERR("%s: Server_Channel_Init must be supplied\n",
+               GUID_format1(&switchTypeGuid, s));
+        goto Away;
+    }
+    pReqHandlerInfo = ReqHandlerAdd(switchTypeGuid,
+                    switch_type_name,
+                    controlfunc,
+                    min_channel_bytes,
+                    Server_Channel_Ok, Server_Channel_Init);
+    if (!pReqHandlerInfo) {
+        LOGERR("failed to add %s to server list\n",
+               GUID_format1(&switchTypeGuid, s));
+        goto Away;
+    }
+
+    atomic_inc(&UisUtils_Registered_Services);
+    rc = 1;            /* success */
+Away:
+    if (rc) {
+        if (chipset_DriverInfo)
+            BusDeviceInfo_Init(chipset_DriverInfo,
+                       "chipset", "uislib",
+                       VERSION, NULL,
+                       __DATE__, __TIME__);
+    } else
+        LOGERR("failed to register type %s.\n",
+               GUID_format1(&switchTypeGuid, s));
+
+    return rc;
+}
+EXPORT_SYMBOL(uisctrl_register_req_handler_ex);
+
+int
+uisctrl_unregister_req_handler_ex(GUID switchTypeGuid)
+{
+    char s[99];
+    int rc = 0;        /* assume failure */
+    LOGINF("type=%s.\n", GUID_format1(&switchTypeGuid, s));
+    if (ReqHandlerDel(switchTypeGuid) < 0) {
+        LOGERR("failed to remove %s from server list\n",
+               GUID_format1(&switchTypeGuid, s));
+        goto Away;
+    }
+    atomic_dec(&UisUtils_Registered_Services);
+    rc = 1;            /* success */
+Away:
+    if (!rc)
+        LOGERR("failed to unregister type %s.\n",
+               GUID_format1(&switchTypeGuid, s));
+    return rc;
+}
+EXPORT_SYMBOL(uisctrl_unregister_req_handler_ex);
+
+/*
+ * unsigned int util_copy_fragsinfo_from_skb(unsigned char *calling_ctx,
+ *                         void *skb_in,
+ *                         unsigned int firstfraglen,
+ *                         unsigned int frags_max,
+ *                         struct phys_info frags[])
+ *
+ *    calling_ctx - input -   a string that is displayed to show
+ *                who called * this func
+ * void *skb_in - skb whose frag info we're copying type is hidden so we
+ *            don't need to include skbbuff in uisutils.h which is
+ *            included in non-networking code.
+ *    unsigned int firstfraglen - input - length of first fragment in skb
+ *    unsigned int frags_max - input - max len of frags array
+ *    struct phys_info frags[] - output - frags array filled in on output
+ *                        return value indicates number of
+ *                        entries filled in frags
+ */
+unsigned int
+util_copy_fragsinfo_from_skb(unsigned char *calling_ctx, void *skb_in,
+                 unsigned int firstfraglen, unsigned int frags_max,
+                 struct phys_info frags[])
+{
+    unsigned int count = 0, ii, size, offset = 0, numfrags;
+    struct sk_buff *skb = skb_in;
+
+    numfrags = skb_shinfo(skb)->nr_frags;
+
+    while (firstfraglen) {
+        if (count == frags_max) {
+            LOGERR("%s frags array too small: max:%d count:%d\n",
+                   calling_ctx, frags_max, count);
+            return -1;    /* failure */
+        }
+        frags[count].pi_pfn =
+            page_to_pfn(virt_to_page(skb->data + offset));
+        frags[count].pi_off =
+            (unsigned long) (skb->data + offset) & PI_PAGE_MASK;
+        size =
+            min(firstfraglen,
+            (unsigned int) (PI_PAGE_SIZE - frags[count].pi_off));
+        /* can take smallest of firstfraglen(what's left) OR
+        * bytes left in the page
+        */
+        frags[count].pi_len = size;
+        firstfraglen -= size;
+        offset += size;
+        count++;
+    }
+    if (numfrags) {
+        if ((count + numfrags) > frags_max) {
+ LOGERR("**** FAILED %s frags array too small: max:%d count+nr_frags:%d\n",
+                 calling_ctx, frags_max, count + numfrags);
+            return -1;    /* failure */
+        }
+
+        for (ii = 0; ii < numfrags; ii++) {
+ count = add_physinfo_entries(page_to_pfn(skb_frag_page(&skb_shinfo(skb)->frags[ii])), /* pfn */
+                             skb_shinfo(skb)->frags[ii].
+                             page_offset,
+                             skb_shinfo(skb)->frags[ii].
+                             size, count, frags_max,
+                             frags);
+            if (count == 0) {
+                LOGERR("**** FAILED to add physinfo entries\n");
+                return -1;    /* failure */
+            }
+        }
+    }
+    if (skb_shinfo(skb)->frag_list) {
+        struct sk_buff *skbinlist;
+        int c;
+        for (skbinlist = skb_shinfo(skb)->frag_list; skbinlist;
+             skbinlist = skbinlist->next) {
+
+            c = util_copy_fragsinfo_from_skb("recursive", skbinlist,
+                             skbinlist->len -
+                             skbinlist->data_len,
+                             frags_max - count,
+                             &frags[count]);
+            if (c == -1) {
+                LOGERR("**** FAILED recursive call failed\n");
+                return -1;
+            }
+            count += c;
+        }
+    }
+    return count;
+}
+EXPORT_SYMBOL(util_copy_fragsinfo_from_skb);
+
+static LIST_HEAD(ReqHandlerInfo_list);    /* list of ReqHandlerInfo_t */
+static DEFINE_SPINLOCK(ReqHandlerInfo_list_lock);
+
+ReqHandlerInfo_t *
+ReqHandlerAdd(GUID switchTypeGuid,
+          const char *switch_type_name,
+          int (*controlfunc)(struct io_msgs *),
+          unsigned long min_channel_bytes,
+          int (*Server_Channel_Ok)(unsigned long channelBytes),
+          int (*Server_Channel_Init)
+ (void *x, unsigned char *clientStr, U32 clientStrLen, U64 bytes))
+{
+    ReqHandlerInfo_t *rc = NULL;
+
+    rc = UISMALLOC(sizeof(*rc), GFP_ATOMIC);
+    if (!rc)
+        return NULL;
+    memset(rc, 0, sizeof(*rc));
+    rc->switchTypeGuid = switchTypeGuid;
+    rc->controlfunc = controlfunc;
+    rc->min_channel_bytes = min_channel_bytes;
+    rc->Server_Channel_Ok = Server_Channel_Ok;
+    rc->Server_Channel_Init = Server_Channel_Init;
+    if (switch_type_name)
+        strncpy(rc->switch_type_name, switch_type_name,
+            sizeof(rc->switch_type_name) - 1);
+    spin_lock(&ReqHandlerInfo_list_lock);
+    list_add_tail(&(rc->list_link), &ReqHandlerInfo_list);
+    spin_unlock(&ReqHandlerInfo_list_lock);
+
+    return rc;
+}
+
+ReqHandlerInfo_t *
+ReqHandlerFind(GUID switchTypeGuid)
+{
+    struct list_head *lelt, *tmp;
+    ReqHandlerInfo_t *entry = NULL;
+    spin_lock(&ReqHandlerInfo_list_lock);
+    list_for_each_safe(lelt, tmp, &ReqHandlerInfo_list) {
+        entry = list_entry(lelt, ReqHandlerInfo_t, list_link);
+        if (memcmp
+            (&entry->switchTypeGuid, &switchTypeGuid,
+             sizeof(GUID)) == 0) {
+            spin_unlock(&ReqHandlerInfo_list_lock);
+            return entry;
+        }
+    }
+    spin_unlock(&ReqHandlerInfo_list_lock);
+    return NULL;
+}
+
+int
+ReqHandlerDel(GUID switchTypeGuid)
+{
+    struct list_head *lelt, *tmp;
+    ReqHandlerInfo_t *entry = NULL;
+    int rc = -1;
+    spin_lock(&ReqHandlerInfo_list_lock);
+    list_for_each_safe(lelt, tmp, &ReqHandlerInfo_list) {
+        entry = list_entry(lelt, ReqHandlerInfo_t, list_link);
+        if (memcmp
+            (&entry->switchTypeGuid, &switchTypeGuid,
+             sizeof(GUID)) == 0) {
+            list_del(lelt);
+            UISFREE(entry, sizeof(*entry));
+            rc++;
+        }
+    }
+    spin_unlock(&ReqHandlerInfo_list_lock);
+    return rc;
+}



_______________________________________________
devel mailing list
devel@xxxxxxxxxxxxxxxxxxxxxx
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel





[Index of Archives]     [Linux Driver Backports]     [DMA Engine]     [Linux GPIO]     [Linux SPI]     [Video for Linux]     [Linux USB Devel]     [Linux Coverity]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux