staging: unisys: visorbus: error_store convert ret to err
[linux-2.6-block.git] / drivers / staging / unisys / visorbus / visorchipset.c
index 97778d733e1efcbf423623eb3c8be5abf979858c..b883800ace8ffb5d1f8235d2b262a40a948a3056 100644 (file)
  */
 
 #include <linux/acpi.h>
-#include <linux/cdev.h>
 #include <linux/ctype.h>
 #include <linux/fs.h>
 #include <linux/mm.h>
 #include <linux/nls.h>
 #include <linux/netdevice.h>
-#include <linux/platform_device.h>
 #include <linux/uuid.h>
 #include <linux/crash_dump.h>
 
 
 #define CURRENT_FILE_PC VISOR_BUS_PC_visorchipset_c
 
-#define POLLJIFFIES_CONTROLVMCHANNEL_FAST   1
+#define POLLJIFFIES_CONTROLVMCHANNEL_FAST 1
 #define POLLJIFFIES_CONTROLVMCHANNEL_SLOW 100
 
 #define MAX_CONTROLVM_PAYLOAD_BYTES (1024 * 128)
 
-#define VISORCHIPSET_MMAP_CONTROLCHANOFFSET    0x00000000
-
 #define UNISYS_SPAR_LEAF_ID 0x40000000
 
 /* The s-Par leaf ID returns "UnisysSpar64" encoded across ebx, ecx, edx */
 #define UNISYS_SPAR_ID_ECX 0x70537379
 #define UNISYS_SPAR_ID_EDX 0x34367261
 
-/*
- * Module parameters
- */
-static int visorchipset_major;
-
-static int
-visorchipset_open(struct inode *inode, struct file *file)
-{
-       unsigned int minor_number = iminor(inode);
-
-       if (minor_number)
-               return -ENODEV;
-       return 0;
-}
-
-static int
-visorchipset_release(struct inode *inode, struct file *file)
-{
-       return 0;
-}
-
 /*
  * When the controlvm channel is idle for at least MIN_IDLE_SECONDS,
  * we switch to slow polling mode. As soon as we get a controlvm
  * message, we switch back to fast polling mode.
  */
 #define MIN_IDLE_SECONDS 10
-static unsigned long poll_jiffies = POLLJIFFIES_CONTROLVMCHANNEL_FAST;
-/* when we got our last controlvm message */
-static unsigned long most_recent_message_jiffies;
 
 struct parser_context {
        unsigned long allocbytes;
@@ -85,22 +57,26 @@ struct parser_context {
        char data[0];
 };
 
-static struct delayed_work periodic_controlvm_work;
-
-static struct cdev file_cdev;
-static struct visorchannel **file_controlvm_channel;
-
-static struct visorchannel *controlvm_channel;
-static unsigned long controlvm_payload_bytes_buffered;
+struct visorchipset_device {
+       struct acpi_device *acpi_device;
+       unsigned long poll_jiffies;
+       /* when we got our last controlvm message */
+       unsigned long most_recent_message_jiffies;
+       struct delayed_work periodic_controlvm_work;
+       struct visorchannel *controlvm_channel;
+       unsigned long controlvm_payload_bytes_buffered;
+       /*
+        * The following variables are used to handle the scenario where we are
+        * unable to offload the payload from a controlvm message due to memory
+        * requirements. In this scenario, we simply stash the controlvm
+        * message, then attempt to process it again the next time
+        * controlvm_periodic_work() runs.
+        */
+       struct controlvm_message controlvm_pending_msg;
+       bool controlvm_pending_msg_valid;
+};
 
-/*
- * The following globals are used to handle the scenario where we are unable to
- * offload the payload from a controlvm message due to memory requirements. In
- * this scenario, we simply stash the controlvm message, then attempt to
- * process it again the next time controlvm_periodic_work() runs.
- */
-static struct controlvm_message controlvm_pending_msg;
-static bool controlvm_pending_msg_valid;
+static struct visorchipset_device *chipset_dev;
 
 struct parahotplug_request {
        struct list_head list;
@@ -109,19 +85,21 @@ struct parahotplug_request {
        struct controlvm_message msg;
 };
 
-/* info for /dev/visorchipset */
-static dev_t major_dev = -1; /*< indicates major num for device */
-
 /* prototypes for attributes */
 static ssize_t toolaction_show(struct device *dev,
                               struct device_attribute *attr,
                               char *buf)
 {
        u8 tool_action = 0;
+       int err;
+
+       err = visorchannel_read(chipset_dev->controlvm_channel,
+                               offsetof(struct spar_controlvm_channel_protocol,
+                                        tool_action),
+                               &tool_action, sizeof(u8));
+       if (err)
+               return err;
 
-       visorchannel_read(controlvm_channel,
-                         offsetof(struct spar_controlvm_channel_protocol,
-                                  tool_action), &tool_action, sizeof(u8));
        return sprintf(buf, "%u\n", tool_action);
 }
 
@@ -130,19 +108,19 @@ static ssize_t toolaction_store(struct device *dev,
                                const char *buf, size_t count)
 {
        u8 tool_action;
-       int ret;
+       int err;
 
        if (kstrtou8(buf, 10, &tool_action))
                return -EINVAL;
 
-       ret = visorchannel_write
-               (controlvm_channel,
+       err = visorchannel_write
+               (chipset_dev->controlvm_channel,
                 offsetof(struct spar_controlvm_channel_protocol,
                          tool_action),
                 &tool_action, sizeof(u8));
 
-       if (ret)
-               return ret;
+       if (err)
+               return err;
        return count;
 }
 static DEVICE_ATTR_RW(toolaction);
@@ -152,11 +130,16 @@ static ssize_t boottotool_show(struct device *dev,
                               char *buf)
 {
        struct efi_spar_indication efi_spar_indication;
+       int err;
+
+       err = visorchannel_read(chipset_dev->controlvm_channel,
+                               offsetof(struct spar_controlvm_channel_protocol,
+                                        efi_spar_ind),
+                               &efi_spar_indication,
+                               sizeof(struct efi_spar_indication));
 
-       visorchannel_read(controlvm_channel,
-                         offsetof(struct spar_controlvm_channel_protocol,
-                                  efi_spar_ind), &efi_spar_indication,
-                         sizeof(struct efi_spar_indication));
+       if (err)
+               return err;
        return sprintf(buf, "%u\n", efi_spar_indication.boot_to_tool);
 }
 
@@ -164,21 +147,21 @@ static ssize_t boottotool_store(struct device *dev,
                                struct device_attribute *attr,
                                const char *buf, size_t count)
 {
-       int val, ret;
+       int val, err;
        struct efi_spar_indication efi_spar_indication;
 
        if (kstrtoint(buf, 10, &val))
                return -EINVAL;
 
        efi_spar_indication.boot_to_tool = val;
-       ret = visorchannel_write
-               (controlvm_channel,
+       err = visorchannel_write
+               (chipset_dev->controlvm_channel,
                 offsetof(struct spar_controlvm_channel_protocol,
                          efi_spar_ind), &(efi_spar_indication),
                 sizeof(struct efi_spar_indication));
 
-       if (ret)
-               return ret;
+       if (err)
+               return err;
        return count;
 }
 static DEVICE_ATTR_RW(boottotool);
@@ -187,11 +170,14 @@ static ssize_t error_show(struct device *dev, struct device_attribute *attr,
                          char *buf)
 {
        u32 error = 0;
+       int err;
 
-       visorchannel_read(controlvm_channel,
-                         offsetof(struct spar_controlvm_channel_protocol,
-                                  installation_error),
-                         &error, sizeof(u32));
+       err = visorchannel_read(chipset_dev->controlvm_channel,
+                               offsetof(struct spar_controlvm_channel_protocol,
+                                        installation_error),
+                               &error, sizeof(u32));
+       if (err)
+               return err;
        return sprintf(buf, "%i\n", error);
 }
 
@@ -199,18 +185,18 @@ static ssize_t error_store(struct device *dev, struct device_attribute *attr,
                           const char *buf, size_t count)
 {
        u32 error;
-       int ret;
+       int err;
 
        if (kstrtou32(buf, 10, &error))
                return -EINVAL;
 
-       ret = visorchannel_write
-               (controlvm_channel,
+       err = visorchannel_write
+               (chipset_dev->controlvm_channel,
                 offsetof(struct spar_controlvm_channel_protocol,
                          installation_error),
                 &error, sizeof(u32));
-       if (ret)
-               return ret;
+       if (err)
+               return err;
        return count;
 }
 static DEVICE_ATTR_RW(error);
@@ -219,12 +205,16 @@ static ssize_t textid_show(struct device *dev, struct device_attribute *attr,
                           char *buf)
 {
        u32 text_id = 0;
+       int err;
+
+       err = visorchannel_read
+                       (chipset_dev->controlvm_channel,
+                        offsetof(struct spar_controlvm_channel_protocol,
+                                 installation_text_id),
+                        &text_id, sizeof(u32));
+       if (err)
+               return err;
 
-       visorchannel_read
-               (controlvm_channel,
-                offsetof(struct spar_controlvm_channel_protocol,
-                         installation_text_id),
-                &text_id, sizeof(u32));
        return sprintf(buf, "%i\n", text_id);
 }
 
@@ -238,7 +228,7 @@ static ssize_t textid_store(struct device *dev, struct device_attribute *attr,
                return -EINVAL;
 
        ret = visorchannel_write
-               (controlvm_channel,
+               (chipset_dev->controlvm_channel,
                 offsetof(struct spar_controlvm_channel_protocol,
                          installation_text_id),
                 &text_id, sizeof(u32));
@@ -252,11 +242,15 @@ static ssize_t remaining_steps_show(struct device *dev,
                                    struct device_attribute *attr, char *buf)
 {
        u16 remaining_steps = 0;
+       int err;
+
+       err = visorchannel_read(chipset_dev->controlvm_channel,
+                               offsetof(struct spar_controlvm_channel_protocol,
+                                        installation_remaining_steps),
+                               &remaining_steps, sizeof(u16));
+       if (err)
+               return err;
 
-       visorchannel_read(controlvm_channel,
-                         offsetof(struct spar_controlvm_channel_protocol,
-                                  installation_remaining_steps),
-                         &remaining_steps, sizeof(u16));
        return sprintf(buf, "%hu\n", remaining_steps);
 }
 
@@ -271,7 +265,7 @@ static ssize_t remaining_steps_store(struct device *dev,
                return -EINVAL;
 
        ret = visorchannel_write
-               (controlvm_channel,
+               (chipset_dev->controlvm_channel,
                 offsetof(struct spar_controlvm_channel_protocol,
                          installation_remaining_steps),
                 &remaining_steps, sizeof(u16));
@@ -292,7 +286,7 @@ parser_id_get(struct parser_context *ctx)
 
 static void parser_done(struct parser_context *ctx)
 {
-       controlvm_payload_bytes_buffered -= ctx->param_bytes;
+       chipset_dev->controlvm_payload_bytes_buffered -= ctx->param_bytes;
        kfree(ctx);
 }
 
@@ -405,7 +399,7 @@ controlvm_respond_chipset_init(struct controlvm_message_header *msg_hdr,
 
        controlvm_init_response(&outmsg, msg_hdr, response);
        outmsg.cmd.init_chipset.features = features;
-       return visorchannel_signalinsert(controlvm_channel,
+       return visorchannel_signalinsert(chipset_dev->controlvm_channel,
                                         CONTROLVM_QUEUE_REQUEST, &outmsg);
 }
 
@@ -455,7 +449,7 @@ controlvm_respond(struct controlvm_message_header *msg_hdr, int response)
        if (outmsg.hdr.flags.test_message == 1)
                return -EINVAL;
 
-       return visorchannel_signalinsert(controlvm_channel,
+       return visorchannel_signalinsert(chipset_dev->controlvm_channel,
                                         CONTROLVM_QUEUE_REQUEST, &outmsg);
 }
 
@@ -468,7 +462,7 @@ static int controlvm_respond_physdev_changestate(
        controlvm_init_response(&outmsg, msg_hdr, response);
        outmsg.cmd.device_change_state.state = state;
        outmsg.cmd.device_change_state.flags.phys_device = 1;
-       return visorchannel_signalinsert(controlvm_channel,
+       return visorchannel_signalinsert(chipset_dev->controlvm_channel,
                                         CONTROLVM_QUEUE_REQUEST, &outmsg);
 }
 
@@ -484,7 +478,7 @@ save_crash_message(struct controlvm_message *msg, enum crash_obj_type typ)
        u16 local_crash_msg_count;
        int err;
 
-       err = visorchannel_read(controlvm_channel,
+       err = visorchannel_read(chipset_dev->controlvm_channel,
                                offsetof(struct spar_controlvm_channel_protocol,
                                         saved_crash_message_count),
                                &local_crash_msg_count, sizeof(u16));
@@ -501,7 +495,7 @@ save_crash_message(struct controlvm_message *msg, enum crash_obj_type typ)
                return -EIO;
        }
 
-       err = visorchannel_read(controlvm_channel,
+       err = visorchannel_read(chipset_dev->controlvm_channel,
                                offsetof(struct spar_controlvm_channel_protocol,
                                         saved_crash_message_offset),
                                &local_crash_msg_offset, sizeof(u32));
@@ -514,7 +508,7 @@ save_crash_message(struct controlvm_message *msg, enum crash_obj_type typ)
        switch (typ) {
        case CRASH_DEV:
                local_crash_msg_offset += sizeof(struct controlvm_message);
-               err = visorchannel_write(controlvm_channel,
+               err = visorchannel_write(chipset_dev->controlvm_channel,
                                         local_crash_msg_offset,
                                         msg,
                                         sizeof(struct controlvm_message));
@@ -525,7 +519,7 @@ save_crash_message(struct controlvm_message *msg, enum crash_obj_type typ)
                }
                break;
        case CRASH_BUS:
-               err = visorchannel_write(controlvm_channel,
+               err = visorchannel_write(chipset_dev->controlvm_channel,
                                         local_crash_msg_offset,
                                         msg,
                                         sizeof(struct controlvm_message));
@@ -576,7 +570,7 @@ device_changestate_responder(enum controlvm_id cmd_id,
        outmsg.cmd.device_change_state.dev_no = dev_no;
        outmsg.cmd.device_change_state.state = response_state;
 
-       return visorchannel_signalinsert(controlvm_channel,
+       return visorchannel_signalinsert(chipset_dev->controlvm_channel,
                                         CONTROLVM_QUEUE_REQUEST, &outmsg);
 }
 
@@ -1004,7 +998,7 @@ err_respond:
 
 #define PARAHOTPLUG_TIMEOUT_MS 2000
 
-/**
+/*
  * parahotplug_next_id() - generate unique int to match an outstanding
  *                         CONTROLVM message with a udev script /sys
  *                         response
@@ -1019,7 +1013,7 @@ parahotplug_next_id(void)
        return atomic_inc_return(&id);
 }
 
-/**
+/*
  * parahotplug_next_expiration() - returns the time (in jiffies) when a
  *                                 CONTROLVM message on the list should expire
  *                                 -- PARAHOTPLUG_TIMEOUT_MS in the future
@@ -1032,7 +1026,7 @@ parahotplug_next_expiration(void)
        return jiffies + msecs_to_jiffies(PARAHOTPLUG_TIMEOUT_MS);
 }
 
-/**
+/*
  * parahotplug_request_create() - create a parahotplug_request, which is
  *                                basically a wrapper for a CONTROLVM_MESSAGE
  *                                that we can stick on a list
@@ -1056,7 +1050,7 @@ parahotplug_request_create(struct controlvm_message *msg)
        return req;
 }
 
-/**
+/*
  * parahotplug_request_destroy() - free a parahotplug_request
  * @req: the request to deallocate
  */
@@ -1069,7 +1063,7 @@ parahotplug_request_destroy(struct parahotplug_request *req)
 static LIST_HEAD(parahotplug_request_list);
 static DEFINE_SPINLOCK(parahotplug_request_list_lock); /* lock for above */
 
-/**
+/*
  * parahotplug_request_complete() - mark request as complete
  * @id:     the id of the request
  * @active: indicates whether the request is assigned to active partition
@@ -1113,7 +1107,7 @@ parahotplug_request_complete(int id, u16 active)
        return -EINVAL;
 }
 
-/**
+/*
  * devicedisabled_store() - disables the hotplug device
  * @dev:   sysfs interface variable not utilized in this function
  * @attr:  sysfs interface variable not utilized in this function
@@ -1143,7 +1137,7 @@ static ssize_t devicedisabled_store(struct device *dev,
 }
 static DEVICE_ATTR_WO(devicedisabled);
 
-/**
+/*
  * deviceenabled_store() - enables the hotplug device
  * @dev:   sysfs interface variable not utilized in this function
  * @attr:  sysfs interface variable not utilized in this function
@@ -1201,26 +1195,14 @@ static const struct attribute_group *visorchipset_dev_groups[] = {
        NULL
 };
 
-static void visorchipset_dev_release(struct device *dev)
-{
-}
-
-/* /sys/devices/platform/visorchipset */
-static struct platform_device visorchipset_platform_device = {
-       .name = "visorchipset",
-       .id = -1,
-       .dev.groups = visorchipset_dev_groups,
-       .dev.release = visorchipset_dev_release,
-};
-
-/**
+/*
  * parahotplug_request_kickoff() - initiate parahotplug request
  * @req: the request to initiate
  *
  * Cause uevent to run the user level script to do the disable/enable specified
  * in the parahotplug_request.
  */
-static void
+static int
 parahotplug_request_kickoff(struct parahotplug_request *req)
 {
        struct controlvm_message_packet *cmd = &req->msg.cmd;
@@ -1241,24 +1223,25 @@ parahotplug_request_kickoff(struct parahotplug_request *req)
        sprintf(env_func, "SPAR_PARAHOTPLUG_FUNCTION=%d",
                cmd->device_change_state.dev_no & 0x7);
 
-       kobject_uevent_env(&visorchipset_platform_device.dev.kobj, KOBJ_CHANGE,
-                          envp);
+       return kobject_uevent_env(&chipset_dev->acpi_device->dev.kobj,
+                                 KOBJ_CHANGE, envp);
 }
 
-/**
+/*
  * parahotplug_process_message() - enables or disables a PCI device by kicking
  *                                 off a udev script
  * @inmsg: the message indicating whether to enable or disable
  */
-static void
+static int
 parahotplug_process_message(struct controlvm_message *inmsg)
 {
        struct parahotplug_request *req;
+       int err;
 
        req = parahotplug_request_create(inmsg);
 
        if (!req)
-               return;
+               return -ENOMEM;
 
        if (inmsg->cmd.device_change_state.state.active) {
                /*
@@ -1272,25 +1255,37 @@ parahotplug_process_message(struct controlvm_message *inmsg)
                 * devices are automatically enabled at
                 * initialization.
                 */
-               parahotplug_request_kickoff(req);
+               err = parahotplug_request_kickoff(req);
+               if (err)
+                       goto err_respond;
                controlvm_respond_physdev_changestate
                        (&inmsg->hdr,
                         CONTROLVM_RESP_SUCCESS,
                         inmsg->cmd.device_change_state.state);
                parahotplug_request_destroy(req);
-       } else {
-               /*
-                * For disable messages, add the request to the
-                * request list before kicking off the udev script. It
-                * won't get responded to until the script has
-                * indicated it's done.
-                */
-               spin_lock(&parahotplug_request_list_lock);
-               list_add_tail(&req->list, &parahotplug_request_list);
-               spin_unlock(&parahotplug_request_list_lock);
-
-               parahotplug_request_kickoff(req);
+               return 0;
        }
+
+       /*
+        * For disable messages, add the request to the
+        * request list before kicking off the udev script. It
+        * won't get responded to until the script has
+        * indicated it's done.
+        */
+       spin_lock(&parahotplug_request_list_lock);
+       list_add_tail(&req->list, &parahotplug_request_list);
+       spin_unlock(&parahotplug_request_list_lock);
+
+       err = parahotplug_request_kickoff(req);
+       if (err)
+               goto err_respond;
+       return 0;
+
+err_respond:
+       controlvm_respond_physdev_changestate
+                               (&inmsg->hdr, err,
+                                inmsg->cmd.device_change_state.state);
+       return err;
 }
 
 /*
@@ -1303,12 +1298,15 @@ parahotplug_process_message(struct controlvm_message *inmsg)
 static int
 chipset_ready_uevent(struct controlvm_message_header *msg_hdr)
 {
-       kobject_uevent(&visorchipset_platform_device.dev.kobj, KOBJ_ONLINE);
+       int res;
+
+       res = kobject_uevent(&chipset_dev->acpi_device->dev.kobj,
+                            KOBJ_ONLINE);
 
        if (msg_hdr->flags.response_expected)
-               return controlvm_respond(msg_hdr, CONTROLVM_RESP_SUCCESS);
+               controlvm_respond(msg_hdr, res);
 
-       return 0;
+       return res;
 }
 
 /*
@@ -1323,15 +1321,16 @@ chipset_selftest_uevent(struct controlvm_message_header *msg_hdr)
 {
        char env_selftest[20];
        char *envp[] = { env_selftest, NULL };
+       int res;
 
        sprintf(env_selftest, "SPARSP_SELFTEST=%d", 1);
-       kobject_uevent_env(&visorchipset_platform_device.dev.kobj, KOBJ_CHANGE,
-                          envp);
+       res = kobject_uevent_env(&chipset_dev->acpi_device->dev.kobj,
+                                KOBJ_CHANGE, envp);
 
        if (msg_hdr->flags.response_expected)
-               return controlvm_respond(msg_hdr, CONTROLVM_RESP_SUCCESS);
+               controlvm_respond(msg_hdr, res);
 
-       return 0;
+       return res;
 }
 
 /*
@@ -1344,15 +1343,17 @@ chipset_selftest_uevent(struct controlvm_message_header *msg_hdr)
 static int
 chipset_notready_uevent(struct controlvm_message_header *msg_hdr)
 {
-       kobject_uevent(&visorchipset_platform_device.dev.kobj, KOBJ_OFFLINE);
+       int res;
 
+       res = kobject_uevent(&chipset_dev->acpi_device->dev.kobj,
+                            KOBJ_OFFLINE);
        if (msg_hdr->flags.response_expected)
-               return controlvm_respond(msg_hdr, CONTROLVM_RESP_SUCCESS);
+               controlvm_respond(msg_hdr, res);
 
-       return 0;
+       return res;
 }
 
-static inline unsigned int
+static unsigned int
 issue_vmcall_io_controlvm_addr(u64 *control_addr, u32 *control_bytes)
 {
        struct vmcall_io_controlvm_addr_params params;
@@ -1360,7 +1361,7 @@ issue_vmcall_io_controlvm_addr(u64 *control_addr, u32 *control_bytes)
        u64 physaddr;
 
        physaddr = virt_to_phys(&params);
-       ISSUE_IO_VMCALL(VMCALL_IO_CONTROLVM_ADDR, physaddr, result);
+       ISSUE_IO_VMCALL(VMCALL_CONTROLVM_ADDR, physaddr, result);
        if (VMCALL_SUCCESSFUL(result)) {
                *control_addr = params.address;
                *control_bytes = params.channel_bytes;
@@ -1398,7 +1399,7 @@ setup_crash_devices_work_queue(struct work_struct *work)
        chipset_init(&msg);
 
        /* get saved message count */
-       if (visorchannel_read(controlvm_channel,
+       if (visorchannel_read(chipset_dev->controlvm_channel,
                              offsetof(struct spar_controlvm_channel_protocol,
                                       saved_crash_message_count),
                              &local_crash_msg_count, sizeof(u16)) < 0) {
@@ -1415,7 +1416,7 @@ setup_crash_devices_work_queue(struct work_struct *work)
        }
 
        /* get saved crash message offset */
-       if (visorchannel_read(controlvm_channel,
+       if (visorchannel_read(chipset_dev->controlvm_channel,
                              offsetof(struct spar_controlvm_channel_protocol,
                                       saved_crash_message_offset),
                              &local_crash_msg_offset, sizeof(u32)) < 0) {
@@ -1425,7 +1426,7 @@ setup_crash_devices_work_queue(struct work_struct *work)
        }
 
        /* read create device message for storage bus offset */
-       if (visorchannel_read(controlvm_channel,
+       if (visorchannel_read(chipset_dev->controlvm_channel,
                              local_crash_msg_offset,
                              &local_crash_bus_msg,
                              sizeof(struct controlvm_message)) < 0) {
@@ -1435,7 +1436,7 @@ setup_crash_devices_work_queue(struct work_struct *work)
        }
 
        /* read create device message for storage device */
-       if (visorchannel_read(controlvm_channel,
+       if (visorchannel_read(chipset_dev->controlvm_channel,
                              local_crash_msg_offset +
                              sizeof(struct controlvm_message),
                              &local_crash_dev_msg,
@@ -1534,136 +1535,6 @@ device_resume_response(struct visor_device *dev_info, int response)
        dev_info->pending_msg_hdr = NULL;
 }
 
-static int
-visorchipset_mmap(struct file *file, struct vm_area_struct *vma)
-{
-       unsigned long physaddr = 0;
-       unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
-       u64 addr = 0;
-
-       /* sv_enable_dfp(); */
-       if (offset & (PAGE_SIZE - 1))
-               return -ENXIO;  /* need aligned offsets */
-
-       switch (offset) {
-       case VISORCHIPSET_MMAP_CONTROLCHANOFFSET:
-               vma->vm_flags |= VM_IO;
-               if (!*file_controlvm_channel)
-                       return -ENXIO;
-
-               visorchannel_read
-                       (*file_controlvm_channel,
-                        offsetof(struct spar_controlvm_channel_protocol,
-                                 gp_control_channel),
-                        &addr, sizeof(addr));
-               if (!addr)
-                       return -ENXIO;
-
-               physaddr = (unsigned long)addr;
-               if (remap_pfn_range(vma, vma->vm_start,
-                                   physaddr >> PAGE_SHIFT,
-                                   vma->vm_end - vma->vm_start,
-                                   /*pgprot_noncached */
-                                   (vma->vm_page_prot))) {
-                       return -EAGAIN;
-               }
-               break;
-       default:
-               return -ENXIO;
-       }
-       return 0;
-}
-
-static inline s64 issue_vmcall_query_guest_virtual_time_offset(void)
-{
-       u64 result = VMCALL_SUCCESS;
-       u64 physaddr = 0;
-
-       ISSUE_IO_VMCALL(VMCALL_QUERY_GUEST_VIRTUAL_TIME_OFFSET, physaddr,
-                       result);
-       return result;
-}
-
-static inline int issue_vmcall_update_physical_time(u64 adjustment)
-{
-       int result = VMCALL_SUCCESS;
-
-       ISSUE_IO_VMCALL(VMCALL_UPDATE_PHYSICAL_TIME, adjustment, result);
-       return result;
-}
-
-static long visorchipset_ioctl(struct file *file, unsigned int cmd,
-                              unsigned long arg)
-{
-       u64 adjustment;
-       s64 vrtc_offset;
-
-       switch (cmd) {
-       case VMCALL_QUERY_GUEST_VIRTUAL_TIME_OFFSET:
-               /* get the physical rtc offset */
-               vrtc_offset = issue_vmcall_query_guest_virtual_time_offset();
-               if (copy_to_user((void __user *)arg, &vrtc_offset,
-                                sizeof(vrtc_offset))) {
-                       return -EFAULT;
-               }
-               return 0;
-       case VMCALL_UPDATE_PHYSICAL_TIME:
-               if (copy_from_user(&adjustment, (void __user *)arg,
-                                  sizeof(adjustment))) {
-                       return -EFAULT;
-               }
-               return issue_vmcall_update_physical_time(adjustment);
-       default:
-               return -EFAULT;
-       }
-}
-
-static const struct file_operations visorchipset_fops = {
-       .owner = THIS_MODULE,
-       .open = visorchipset_open,
-       .read = NULL,
-       .write = NULL,
-       .unlocked_ioctl = visorchipset_ioctl,
-       .release = visorchipset_release,
-       .mmap = visorchipset_mmap,
-};
-
-static int
-visorchipset_file_init(dev_t major_dev, struct visorchannel **controlvm_channel)
-{
-       int rc = 0;
-
-       file_controlvm_channel = controlvm_channel;
-       cdev_init(&file_cdev, &visorchipset_fops);
-       file_cdev.owner = THIS_MODULE;
-       if (MAJOR(major_dev) == 0) {
-               rc = alloc_chrdev_region(&major_dev, 0, 1, "visorchipset");
-               /* dynamic major device number registration required */
-               if (rc < 0)
-                       return rc;
-       } else {
-               /* static major device number registration required */
-               rc = register_chrdev_region(major_dev, 1, "visorchipset");
-               if (rc < 0)
-                       return rc;
-       }
-       rc = cdev_add(&file_cdev, MKDEV(MAJOR(major_dev), 0), 1);
-       if (rc < 0) {
-               unregister_chrdev_region(major_dev, 1);
-               return rc;
-       }
-       return 0;
-}
-
-static void
-visorchipset_file_cleanup(dev_t major_dev)
-{
-       if (file_cdev.ops)
-               cdev_del(&file_cdev);
-       file_cdev.ops = NULL;
-       unregister_chrdev_region(major_dev, 1);
-}
-
 static struct parser_context *
 parser_init_byte_stream(u64 addr, u32 bytes, bool local, bool *retry)
 {
@@ -1677,7 +1548,7 @@ parser_init_byte_stream(u64 addr, u32 bytes, bool local, bool *retry)
         * '\0'-terminated
         */
        allocbytes++;
-       if ((controlvm_payload_bytes_buffered + bytes)
+       if ((chipset_dev->controlvm_payload_bytes_buffered + bytes)
            > MAX_CONTROLVM_PAYLOAD_BYTES) {
                *retry = true;
                return NULL;
@@ -1710,7 +1581,7 @@ parser_init_byte_stream(u64 addr, u32 bytes, bool local, bool *retry)
        }
 
        ctx->byte_stream = true;
-       controlvm_payload_bytes_buffered += ctx->param_bytes;
+       chipset_dev->controlvm_payload_bytes_buffered += ctx->param_bytes;
 
        return ctx;
 
@@ -1719,22 +1590,20 @@ err_finish_ctx:
        return NULL;
 }
 
-/**
+/*
  * handle_command() - process a controlvm message
  * @inmsg:        the message to process
  * @channel_addr: address of the controlvm channel
  *
  * Return:
- *    false - this function will return false only in the case where the
- *            controlvm message was NOT processed, but processing must be
- *            retried before reading the next controlvm message; a
- *            scenario where this can occur is when we need to throttle
- *            the allocation of memory in which to copy out controlvm
- *            payload data
- *    true  - processing of the controlvm message completed,
- *            either successfully or with an error
+ *     0       - Successfully processed the message
+ *     -EAGAIN - ControlVM message was not processed and should be retried
+ *               reading the next controlvm message; a scenario where this can
+ *               occur is when we need to throttle the allocation of memory in
+ *               which to copy out controlvm payload data.
+ *     < 0     - error: ControlVM message was processed but an error occurred.
  */
-static bool
+static int
 handle_command(struct controlvm_message inmsg, u64 channel_addr)
 {
        struct controlvm_message_packet *cmd = &inmsg.cmd;
@@ -1743,11 +1612,13 @@ handle_command(struct controlvm_message inmsg, u64 channel_addr)
        struct parser_context *parser_ctx = NULL;
        bool local_addr;
        struct controlvm_message ackmsg;
+       int err = 0;
 
        /* create parsing context if necessary */
        local_addr = (inmsg.hdr.flags.test_message == 1);
        if (channel_addr == 0)
-               return true;
+               return -EINVAL;
+
        parm_addr = channel_addr + inmsg.hdr.payload_vm_offset;
        parm_bytes = inmsg.hdr.payload_bytes;
 
@@ -1763,66 +1634,68 @@ handle_command(struct controlvm_message inmsg, u64 channel_addr)
                    parser_init_byte_stream(parm_addr, parm_bytes,
                                            local_addr, &retry);
                if (!parser_ctx && retry)
-                       return false;
+                       return -EAGAIN;
        }
 
        if (!local_addr) {
                controlvm_init_response(&ackmsg, &inmsg.hdr,
                                        CONTROLVM_RESP_SUCCESS);
-               if (controlvm_channel)
-                       visorchannel_signalinsert(controlvm_channel,
-                                                 CONTROLVM_QUEUE_ACK,
-                                                 &ackmsg);
+               err = visorchannel_signalinsert(chipset_dev->controlvm_channel,
+                                               CONTROLVM_QUEUE_ACK,
+                                               &ackmsg);
+               if (err)
+                       return err;
        }
        switch (inmsg.hdr.id) {
        case CONTROLVM_CHIPSET_INIT:
-               chipset_init(&inmsg);
+               err = chipset_init(&inmsg);
                break;
        case CONTROLVM_BUS_CREATE:
-               bus_create(&inmsg);
+               err = bus_create(&inmsg);
                break;
        case CONTROLVM_BUS_DESTROY:
-               bus_destroy(&inmsg);
+               err = bus_destroy(&inmsg);
                break;
        case CONTROLVM_BUS_CONFIGURE:
-               bus_configure(&inmsg, parser_ctx);
+               err = bus_configure(&inmsg, parser_ctx);
                break;
        case CONTROLVM_DEVICE_CREATE:
-               my_device_create(&inmsg);
+               err = my_device_create(&inmsg);
                break;
        case CONTROLVM_DEVICE_CHANGESTATE:
                if (cmd->device_change_state.flags.phys_device) {
-                       parahotplug_process_message(&inmsg);
+                       err = parahotplug_process_message(&inmsg);
                } else {
                        /*
                         * save the hdr and cmd structures for later use
                         * when sending back the response to Command
                         */
-                       my_device_changestate(&inmsg);
+                       err = my_device_changestate(&inmsg);
                        break;
                }
                break;
        case CONTROLVM_DEVICE_DESTROY:
-               my_device_destroy(&inmsg);
+               err = my_device_destroy(&inmsg);
                break;
        case CONTROLVM_DEVICE_CONFIGURE:
-               /* no op for now, just send a respond that we passed */
+               /* no op just send a respond that we passed */
                if (inmsg.hdr.flags.response_expected)
                        controlvm_respond(&inmsg.hdr, CONTROLVM_RESP_SUCCESS);
                break;
        case CONTROLVM_CHIPSET_READY:
-               chipset_ready_uevent(&inmsg.hdr);
+               err = chipset_ready_uevent(&inmsg.hdr);
                break;
        case CONTROLVM_CHIPSET_SELFTEST:
-               chipset_selftest_uevent(&inmsg.hdr);
+               err = chipset_selftest_uevent(&inmsg.hdr);
                break;
        case CONTROLVM_CHIPSET_STOP:
-               chipset_notready_uevent(&inmsg.hdr);
+               err = chipset_notready_uevent(&inmsg.hdr);
                break;
        default:
+               err = -ENOMSG;
                if (inmsg.hdr.flags.response_expected)
-                       controlvm_respond
-                               (&inmsg.hdr, -CONTROLVM_RESP_ID_UNKNOWN);
+                       controlvm_respond(&inmsg.hdr,
+                                         -CONTROLVM_RESP_ID_UNKNOWN);
                break;
        }
 
@@ -1830,31 +1703,35 @@ handle_command(struct controlvm_message inmsg, u64 channel_addr)
                parser_done(parser_ctx);
                parser_ctx = NULL;
        }
-       return true;
+       return err;
 }
 
-/**
+/*
  * read_controlvm_event() - retreives the next message from the
  *                          CONTROLVM_QUEUE_EVENT queue in the controlvm
  *                          channel
  * @msg: pointer to the retrieved message
  *
- * Return: true if a valid message was retrieved or false otherwise
+ * Return: 0 if valid message was retrieved or -error
  */
-static bool
+static int
 read_controlvm_event(struct controlvm_message *msg)
 {
-       if (!visorchannel_signalremove(controlvm_channel,
-                                      CONTROLVM_QUEUE_EVENT, msg)) {
-               /* got a message */
-               if (msg->hdr.flags.test_message == 1)
-                       return false;
-               return true;
-       }
-       return false;
+       int err;
+
+       err = visorchannel_signalremove(chipset_dev->controlvm_channel,
+                                       CONTROLVM_QUEUE_EVENT, msg);
+       if (err)
+               return err;
+
+       /* got a message */
+       if (msg->hdr.flags.test_message == 1)
+               return -EINVAL;
+
+       return 0;
 }
 
-/**
+/*
  * parahotplug_process_list() - remove any request from the list that's been on
  *                              there too long and respond with an error
  */
@@ -1889,67 +1766,69 @@ static void
 controlvm_periodic_work(struct work_struct *work)
 {
        struct controlvm_message inmsg;
-       bool got_command = false;
-       bool handle_command_failed = false;
-
-       while (!visorchannel_signalremove(controlvm_channel,
-                                         CONTROLVM_QUEUE_RESPONSE,
-                                         &inmsg))
-               ;
-       if (!got_command) {
-               if (controlvm_pending_msg_valid) {
-                       /*
-                        * we throttled processing of a prior
-                        * msg, so try to process it again
-                        * rather than reading a new one
-                        */
-                       inmsg = controlvm_pending_msg;
-                       controlvm_pending_msg_valid = false;
-                       got_command = true;
-               } else {
-                       got_command = read_controlvm_event(&inmsg);
-               }
+       int err;
+
+       /* Drain the RESPONSE queue make it empty */
+       do {
+               err = visorchannel_signalremove(chipset_dev->controlvm_channel,
+                                               CONTROLVM_QUEUE_RESPONSE,
+                                               &inmsg);
+       } while (!err);
+
+       if (err != -EAGAIN)
+               goto schedule_out;
+
+       if (chipset_dev->controlvm_pending_msg_valid) {
+               /*
+                * we throttled processing of a prior
+                * msg, so try to process it again
+                * rather than reading a new one
+                */
+               inmsg = chipset_dev->controlvm_pending_msg;
+               chipset_dev->controlvm_pending_msg_valid = false;
+               err = 0;
+       } else {
+               err = read_controlvm_event(&inmsg);
        }
 
-       handle_command_failed = false;
-       while (got_command && (!handle_command_failed)) {
-               most_recent_message_jiffies = jiffies;
-               if (handle_command(inmsg,
-                                  visorchannel_get_physaddr
-                                  (controlvm_channel)))
-                       got_command = read_controlvm_event(&inmsg);
-               else {
-                       /*
-                        * this is a scenario where throttling
-                        * is required, but probably NOT an
-                        * error...; we stash the current
-                        * controlvm msg so we will attempt to
-                        * reprocess it on our next loop
-                        */
-                       handle_command_failed = true;
-                       controlvm_pending_msg = inmsg;
-                       controlvm_pending_msg_valid = true;
+       while (!err) {
+               chipset_dev->most_recent_message_jiffies = jiffies;
+               err = handle_command(inmsg,
+                                    visorchannel_get_physaddr
+                                    (chipset_dev->controlvm_channel));
+               if (err == -EAGAIN) {
+                       chipset_dev->controlvm_pending_msg = inmsg;
+                       chipset_dev->controlvm_pending_msg_valid = true;
+                       break;
                }
+
+               err = read_controlvm_event(&inmsg);
        }
 
        /* parahotplug_worker */
        parahotplug_process_list();
 
-       if (time_after(jiffies,
-                      most_recent_message_jiffies + (HZ * MIN_IDLE_SECONDS))) {
+schedule_out:
+       if (time_after(jiffies, chipset_dev->most_recent_message_jiffies +
+                               (HZ * MIN_IDLE_SECONDS))) {
                /*
                 * it's been longer than MIN_IDLE_SECONDS since we
                 * processed our last controlvm message; slow down the
                 * polling
                 */
-               if (poll_jiffies != POLLJIFFIES_CONTROLVMCHANNEL_SLOW)
-                       poll_jiffies = POLLJIFFIES_CONTROLVMCHANNEL_SLOW;
+               if (chipset_dev->poll_jiffies !=
+                                             POLLJIFFIES_CONTROLVMCHANNEL_SLOW)
+                       chipset_dev->poll_jiffies =
+                                             POLLJIFFIES_CONTROLVMCHANNEL_SLOW;
        } else {
-               if (poll_jiffies != POLLJIFFIES_CONTROLVMCHANNEL_FAST)
-                       poll_jiffies = POLLJIFFIES_CONTROLVMCHANNEL_FAST;
+               if (chipset_dev->poll_jiffies !=
+                                             POLLJIFFIES_CONTROLVMCHANNEL_FAST)
+                       chipset_dev->poll_jiffies =
+                                             POLLJIFFIES_CONTROLVMCHANNEL_FAST;
        }
 
-       schedule_delayed_work(&periodic_controlvm_work, poll_jiffies);
+       schedule_delayed_work(&chipset_dev->periodic_controlvm_work,
+                             chipset_dev->poll_jiffies);
 }
 
 static int
@@ -1958,61 +1837,70 @@ visorchipset_init(struct acpi_device *acpi_device)
        int err = -ENODEV;
        u64 addr;
        uuid_le uuid = SPAR_CONTROLVM_CHANNEL_PROTOCOL_UUID;
+       struct visorchannel *controlvm_channel;
 
        addr = controlvm_get_channel_address();
        if (!addr)
                goto error;
 
-       controlvm_channel = visorchannel_create_with_lock(addr, 0,
-                                                         GFP_KERNEL, uuid);
-       if (!controlvm_channel)
+       chipset_dev = kzalloc(sizeof(*chipset_dev), GFP_KERNEL);
+       if (!chipset_dev)
                goto error;
 
-       if (!SPAR_CONTROLVM_CHANNEL_OK_CLIENT(
-                               visorchannel_get_header(controlvm_channel)))
-               goto error_destroy_channel;
+       acpi_device->driver_data = chipset_dev;
+
+       chipset_dev->acpi_device = acpi_device;
+       chipset_dev->poll_jiffies = POLLJIFFIES_CONTROLVMCHANNEL_FAST;
+       controlvm_channel = visorchannel_create_with_lock(addr,
+                                                         0, GFP_KERNEL, uuid);
+
+       if (!controlvm_channel)
+               goto error_free_chipset_dev;
+
+       chipset_dev->controlvm_channel = controlvm_channel;
 
-       major_dev = MKDEV(visorchipset_major, 0);
-       err = visorchipset_file_init(major_dev, &controlvm_channel);
+       err = sysfs_create_groups(&chipset_dev->acpi_device->dev.kobj,
+                                 visorchipset_dev_groups);
        if (err < 0)
                goto error_destroy_channel;
 
+       if (!SPAR_CONTROLVM_CHANNEL_OK_CLIENT(
+                               visorchannel_get_header(controlvm_channel)))
+               goto error_delete_groups;
+
        /* if booting in a crash kernel */
        if (is_kdump_kernel())
-               INIT_DELAYED_WORK(&periodic_controlvm_work,
+               INIT_DELAYED_WORK(&chipset_dev->periodic_controlvm_work,
                                  setup_crash_devices_work_queue);
        else
-               INIT_DELAYED_WORK(&periodic_controlvm_work,
+               INIT_DELAYED_WORK(&chipset_dev->periodic_controlvm_work,
                                  controlvm_periodic_work);
 
-       most_recent_message_jiffies = jiffies;
-       poll_jiffies = POLLJIFFIES_CONTROLVMCHANNEL_FAST;
-       schedule_delayed_work(&periodic_controlvm_work, poll_jiffies);
+       chipset_dev->most_recent_message_jiffies = jiffies;
+       chipset_dev->poll_jiffies = POLLJIFFIES_CONTROLVMCHANNEL_FAST;
+       schedule_delayed_work(&chipset_dev->periodic_controlvm_work,
+                             chipset_dev->poll_jiffies);
 
-       visorchipset_platform_device.dev.devt = major_dev;
-       if (platform_device_register(&visorchipset_platform_device) < 0) {
-               POSTCODE_LINUX(DEVICE_REGISTER_FAILURE_PC, 0, 0,
-                              DIAG_SEVERITY_ERR);
-               err = -ENODEV;
-               goto error_cancel_work;
-       }
        POSTCODE_LINUX(CHIPSET_INIT_SUCCESS_PC, 0, 0, DIAG_SEVERITY_PRINT);
 
        err = visorbus_init();
        if (err < 0)
-               goto error_unregister;
+               goto error_cancel_work;
 
        return 0;
 
-error_unregister:
-       platform_device_unregister(&visorchipset_platform_device);
-
 error_cancel_work:
-       cancel_delayed_work_sync(&periodic_controlvm_work);
-       visorchipset_file_cleanup(major_dev);
+       cancel_delayed_work_sync(&chipset_dev->periodic_controlvm_work);
+
+error_delete_groups:
+       sysfs_remove_groups(&chipset_dev->acpi_device->dev.kobj,
+                           visorchipset_dev_groups);
 
 error_destroy_channel:
-       visorchannel_destroy(controlvm_channel);
+       visorchannel_destroy(chipset_dev->controlvm_channel);
+
+error_free_chipset_dev:
+       kfree(chipset_dev);
 
 error:
        POSTCODE_LINUX(CHIPSET_INIT_FAILURE_PC, 0, err, DIAG_SEVERITY_ERR);
@@ -2025,13 +1913,13 @@ visorchipset_exit(struct acpi_device *acpi_device)
        POSTCODE_LINUX(DRIVER_EXIT_PC, 0, 0, DIAG_SEVERITY_PRINT);
 
        visorbus_exit();
+       cancel_delayed_work_sync(&chipset_dev->periodic_controlvm_work);
+       sysfs_remove_groups(&chipset_dev->acpi_device->dev.kobj,
+                           visorchipset_dev_groups);
 
-       cancel_delayed_work_sync(&periodic_controlvm_work);
-
-       visorchannel_destroy(controlvm_channel);
+       visorchannel_destroy(chipset_dev->controlvm_channel);
+       kfree(chipset_dev);
 
-       visorchipset_file_cleanup(visorchipset_platform_device.dev.devt);
-       platform_device_unregister(&visorchipset_platform_device);
        POSTCODE_LINUX(DRIVER_EXIT_PC, 0, 0, DIAG_SEVERITY_PRINT);
 
        return 0;
@@ -2090,10 +1978,6 @@ static void exit_unisys(void)
        acpi_bus_unregister_driver(&unisys_acpi_driver);
 }
 
-module_param_named(major, visorchipset_major, int, 0444);
-MODULE_PARM_DESC(visorchipset_major,
-                "major device number to use for the device node");
-
 module_init(init_unisys);
 module_exit(exit_unisys);