source "drivers/staging/unisys/visorutil/Kconfig"
source "drivers/staging/unisys/visorchannel/Kconfig"
+source "drivers/staging/unisys/visorchipset/Kconfig"
endif # UNISYSSPAR
#
obj-$(CONFIG_UNISYS_VISORUTIL) += visorutil/
obj-$(CONFIG_UNISYS_VISORCHANNEL) += visorchannel/
+obj-$(CONFIG_UNISYS_VISORCHIPSET) += visorchipset/
--- /dev/null
+/* 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.
+ */
+
+/*
+ * CHANNEL Guids
+ */
+
+/* Used in IOChannel
+ * {414815ed-c58c-11da-95a9-00e08161165f}
+ */
+#define ULTRA_VHBA_CHANNEL_PROTOCOL_GUID \
+ { 0x414815ed, 0xc58c, 0x11da, \
+ { 0x95, 0xa9, 0x0, 0xe0, 0x81, 0x61, 0x16, 0x5f } }
+static const GUID UltraVhbaChannelProtocolGuid =
+ ULTRA_VHBA_CHANNEL_PROTOCOL_GUID;
+
+/* Used in IOChannel
+ * {8cd5994d-c58e-11da-95a9-00e08161165f}
+ */
+#define ULTRA_VNIC_CHANNEL_PROTOCOL_GUID \
+ { 0x8cd5994d, 0xc58e, 0x11da, \
+ { 0x95, 0xa9, 0x0, 0xe0, 0x81, 0x61, 0x16, 0x5f } }
+static const GUID UltraVnicChannelProtocolGuid =
+ ULTRA_VNIC_CHANNEL_PROTOCOL_GUID;
+
+/* Used in IOChannel
+ * {72120008-4AAB-11DC-8530-444553544200}
+ */
+#define ULTRA_SIOVM_GUID \
+ { 0x72120008, 0x4AAB, 0x11DC, \
+ { 0x85, 0x30, 0x44, 0x45, 0x53, 0x54, 0x42, 0x00 } }
+static const GUID UltraSIOVMGuid = ULTRA_SIOVM_GUID;
+
+
+/* Used in visornoop/visornoop_main.c
+ * {5b52c5ac-e5f5-4d42-8dff-429eaecd221f}
+ */
+#define ULTRA_CONTROLDIRECTOR_CHANNEL_PROTOCOL_GUID \
+ { 0x5b52c5ac, 0xe5f5, 0x4d42, \
+ { 0x8d, 0xff, 0x42, 0x9e, 0xae, 0xcd, 0x22, 0x1f } }
+
+static const GUID UltraControlDirectorChannelProtocolGuid =
+ ULTRA_CONTROLDIRECTOR_CHANNEL_PROTOCOL_GUID;
+
+/* Used in visorchipset/visorchipset_main.c
+ * {B4E79625-AEDE-4EAA-9E11-D3EDDCD4504C}
+ */
+#define ULTRA_DIAG_POOL_CHANNEL_PROTOCOL_GUID \
+ {0xb4e79625, 0xaede, 0x4eaa, \
+ { 0x9e, 0x11, 0xd3, 0xed, 0xdc, 0xd4, 0x50, 0x4c } }
+
+
--- /dev/null
+/* 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.
+ */
+
+/*
+ * Module Name:
+ * controlframework.h
+ *
+ * Abstract: This file defines common structures in the unmanaged
+ * Ultravisor (mostly EFI) space.
+ *
+ */
+
+#ifndef _CONTROL_FRAMEWORK_H_
+#define _CONTROL_FRAMEWORK_H_
+
+#include "commontypes.h"
+#include "channel.h"
+
+#define ULTRA_MEMORY_COUNT_Ki 1024
+
+/* Scale order 0 is one 32-bit (4-byte) word (in 64 or 128-bit
+ * architecture potentially 64 or 128-bit word) */
+#define ULTRA_MEMORY_PAGE_WORD 4
+
+/* Define Ki scale page to be traditional 4KB page */
+#define ULTRA_MEMORY_PAGE_Ki (ULTRA_MEMORY_PAGE_WORD * ULTRA_MEMORY_COUNT_Ki)
+typedef struct _ULTRA_SEGMENT_STATE {
+ U16 Enabled:1; /* Bit 0: May enter other states */
+ U16 Active:1; /* Bit 1: Assigned to active partition */
+ U16 Alive:1; /* Bit 2: Configure message sent to
+ * service/server */
+ U16 Revoked:1; /* Bit 3: similar to partition state
+ * ShuttingDown */
+ U16 Allocated:1; /* Bit 4: memory (device/port number)
+ * has been selected by Command */
+ U16 Known:1; /* Bit 5: has been introduced to the
+ * service/guest partition */
+ U16 Ready:1; /* Bit 6: service/Guest partition has
+ * responded to introduction */
+ U16 Operating:1; /* Bit 7: resource is configured and
+ * operating */
+ /* Note: don't use high bit unless we need to switch to ushort
+ * which is non-compliant */
+} ULTRA_SEGMENT_STATE;
+static const ULTRA_SEGMENT_STATE SegmentStateRunning = {
+ 1, 1, 1, 0, 1, 1, 1, 1
+};
+static const ULTRA_SEGMENT_STATE SegmentStatePaused = {
+ 1, 1, 1, 0, 1, 1, 1, 0
+};
+static const ULTRA_SEGMENT_STATE SegmentStateStandby = {
+ 1, 1, 0, 0, 1, 1, 1, 0
+};
+typedef union {
+ U64 Full;
+ struct {
+ U8 Major; /* will be 1 for the first release and
+ * increment thereafter */
+ U8 Minor;
+ U16 Maintenance;
+ U32 Revision; /* Subversion revision */
+ } Part;
+} ULTRA_COMPONENT_VERSION;
+
+#endif /* _CONTROL_FRAMEWORK_H_ not defined */
--- /dev/null
+/* 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 __CONTROLVMCHANNEL_H__
+#define __CONTROLVMCHANNEL_H__
+
+#include "commontypes.h"
+#include "channel.h"
+#include "controlframework.h"
+enum { INVALID_GUEST_FIRMWARE, SAMPLE_GUEST_FIRMWARE,
+ TIANO32_GUEST_FIRMWARE, TIANO64_GUEST_FIRMWARE
+};
+
+/* {2B3C2D10-7EF5-4ad8-B966-3448B7386B3D} */
+#define ULTRA_CONTROLVM_CHANNEL_PROTOCOL_GUID \
+ {0x2b3c2d10, 0x7ef5, 0x4ad8, \
+ {0xb9, 0x66, 0x34, 0x48, 0xb7, 0x38, 0x6b, 0x3d} }
+
+static const GUID UltraControlvmChannelProtocolGuid =
+ ULTRA_CONTROLVM_CHANNEL_PROTOCOL_GUID;
+
+#define ULTRA_CONTROLVM_CHANNEL_PROTOCOL_SIGNATURE \
+ ULTRA_CHANNEL_PROTOCOL_SIGNATURE
+#define CONTROLVM_MESSAGE_MAX 64
+
+/* Must increment this whenever you insert or delete fields within
+* this channel struct. Also increment whenever you change the meaning
+* of fields within this channel struct so as to break pre-existing
+* software. Note that you can usually add fields to the END of the
+* channel struct withOUT needing to increment this. */
+#define ULTRA_CONTROLVM_CHANNEL_PROTOCOL_VERSIONID 1
+
+#define ULTRA_CONTROLVM_CHANNEL_OK_CLIENT(pChannel, logCtx) \
+ (ULTRA_check_channel_client(pChannel, \
+ UltraControlvmChannelProtocolGuid, \
+ "controlvm", \
+ sizeof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL), \
+ ULTRA_CONTROLVM_CHANNEL_PROTOCOL_VERSIONID, \
+ ULTRA_CONTROLVM_CHANNEL_PROTOCOL_SIGNATURE, \
+ __FILE__, __LINE__, logCtx))
+#define ULTRA_CONTROLVM_CHANNEL_OK_SERVER(actualBytes, logCtx) \
+ (ULTRA_check_channel_server(UltraControlvmChannelProtocolGuid, \
+ "controlvm", \
+ sizeof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL), \
+ actualBytes, __FILE__, __LINE__, logCtx))
+
+#define MY_DEVICE_INDEX 0
+#define MAX_MACDATA_LEN 8 /* number of bytes for MAC address in config packet */
+#define MAX_SERIAL_NUM 32
+
+#define DISK_ZERO_PUN_NUMBER 1 /* Target ID on the SCSI bus for LUN 0 */
+#define DISK_ZERO_LUN_NUMBER 3 /* Logical Unit Number */
+
+/* Defines for various channel queues... */
+#define CONTROLVM_QUEUE_REQUEST 0
+#define CONTROLVM_QUEUE_RESPONSE 1
+#define CONTROLVM_QUEUE_EVENT 2
+#define CONTROLVM_QUEUE_ACK 3
+
+/* Max number of messages stored during IOVM creation to be reused
+ * after crash */
+#define CONTROLVM_CRASHMSG_MAX 2
+
+/** Ids for commands that may appear in either queue of a ControlVm channel.
+ *
+ * Commands that are initiated by the command partition (CP), by an IO or
+ * console service partition (SP), or by a guest partition (GP)are:
+ * - issued on the RequestQueue queue (q #0) in the ControlVm channel
+ * - responded to on the ResponseQueue queue (q #1) in the ControlVm channel
+ *
+ * Events that are initiated by an IO or console service partition (SP) or
+ * by a guest partition (GP) are:
+ * - issued on the EventQueue queue (q #2) in the ControlVm channel
+ * - responded to on the EventAckQueue queue (q #3) in the ControlVm channel
+ */
+typedef enum {
+ CONTROLVM_INVALID = 0,
+ /* SWITCH commands required Parameter: SwitchNumber */
+ /* BUS commands required Parameter: BusNumber */
+ CONTROLVM_BUS_CREATE = 0x101, /* CP --> SP, GP */
+ CONTROLVM_BUS_DESTROY = 0x102, /* CP --> SP, GP */
+ CONTROLVM_BUS_CONFIGURE = 0x104, /* CP --> SP */
+ CONTROLVM_BUS_CHANGESTATE = 0x105, /* CP --> SP, GP */
+ CONTROLVM_BUS_CHANGESTATE_EVENT = 0x106, /* SP, GP --> CP */
+/* DEVICE commands required Parameter: BusNumber, DeviceNumber */
+
+ CONTROLVM_DEVICE_CREATE = 0x201, /* CP --> SP, GP */
+ CONTROLVM_DEVICE_DESTROY = 0x202, /* CP --> SP, GP */
+ CONTROLVM_DEVICE_CONFIGURE = 0x203, /* CP --> SP */
+ CONTROLVM_DEVICE_CHANGESTATE = 0x204, /* CP --> SP, GP */
+ CONTROLVM_DEVICE_CHANGESTATE_EVENT = 0x205, /* SP, GP --> CP */
+ CONTROLVM_DEVICE_RECONFIGURE = 0x206, /* CP --> Boot */
+/* DISK commands required Parameter: BusNumber, DeviceNumber */
+ CONTROLVM_DISK_CREATE = 0x221, /* CP --> SP */
+ CONTROLVM_DISK_DESTROY = 0x222, /* CP --> SP */
+ CONTROLVM_DISK_CONFIGURE = 0x223, /* CP --> SP */
+ CONTROLVM_DISK_CHANGESTATE = 0x224, /* CP --> SP */
+/* CHIPSET commands */
+ CONTROLVM_CHIPSET_INIT = 0x301, /* CP --> SP, GP */
+ CONTROLVM_CHIPSET_STOP = 0x302, /* CP --> SP, GP */
+ CONTROLVM_CHIPSET_SHUTDOWN = 0x303, /* CP --> SP */
+ CONTROLVM_CHIPSET_READY = 0x304, /* CP --> SP */
+ CONTROLVM_CHIPSET_SELFTEST = 0x305, /* CP --> SP */
+
+} CONTROLVM_ID;
+
+struct InterruptInfo {
+ /**< specifies interrupt info. It is used to send interrupts
+ * for this channel. The peer at the end of this channel
+ * who has registered an interrupt (using recv fields
+ * above) will receive the interrupt. Passed as a parameter
+ * to Issue_VMCALL_IO_QUEUE_TRANSITION, which generates the
+ * interrupt. Currently this is used by IOPart-SP to wake
+ * up GP when Data Channel transitions from empty to
+ * non-empty.*/
+ U64 sendInterruptHandle;
+
+ /**< specifies interrupt handle. It is used to retrieve the
+ * corresponding interrupt pin from Monitor; and the
+ * interrupt pin is used to connect to the corresponding
+ * intrrupt. Used by IOPart-GP only. */
+ U64 recvInterruptHandle;
+
+ /**< specifies interrupt vector. It, interrupt pin, and shared are
+ * used to connect to the corresponding interrupt. Used by
+ * IOPart-GP only. */
+ U32 recvInterruptVector;
+
+ /**< specifies if the recvInterrupt is shared. It, interrupt pin
+ * and vector are used to connect to 0 = not shared; 1 = shared.
+ * the corresponding interrupt. Used by IOPart-GP only. */
+ U8 recvInterruptShared;
+ U8 reserved[3]; /* Natural alignment purposes */
+};
+
+struct PciId {
+ U16 Domain;
+ U8 Bus;
+ U8 Slot;
+ U8 Func;
+ U8 Reserved[3]; /* Natural alignment purposes */
+};
+
+struct PciConfigHdr {
+ U16 VendorId;
+ U16 SubSysVendor;
+ U16 DeviceId;
+ U16 SubSysDevice;
+ U32 ClassCode;
+ U32 Reserved; /* Natural alignment purposes */
+};
+
+struct ScsiId {
+ U32 Bus;
+ U32 Target;
+ U32 Lun;
+ U32 Host; /* Command should ignore this for *
+ * DiskArrival/RemovalEvents */
+};
+
+struct WWID {
+ U32 wwid1;
+ U32 wwid2;
+};
+
+struct virtDiskInfo {
+ U32 switchNo; /* defined by SWITCH_CREATE */
+ U32 externalPortNo; /* 0 for SAS RAID provided (external)
+ * virtual disks, 1 for virtual disk
+ * images, 2 for gold disk images */
+ U16 VirtualDiskIndex; /* Index of disk descriptor in the
+ * VirtualDisk segment associated with
+ * externalPortNo */
+ U16 Reserved1;
+ U32 Reserved2;
+};
+
+typedef enum {
+ CONTROLVM_ACTION_NONE = 0,
+ CONTROLVM_ACTION_SET_RESTORE = 0x05E7,
+ CONTROLVM_ACTION_CLEAR_RESTORE = 0x0C18,
+ CONTROLVM_ACTION_RESTORING = 0x08E5,
+ CONTROLVM_ACTION_RESTORE_BUSY = 0x0999,
+ CONTROLVM_ACTION_CLEAR_NVRAM = 0xB01
+} CONTROLVM_ACTION;
+
+typedef enum _ULTRA_TOOL_ACTIONS {
+ /* enumeration that defines intended action */
+ ULTRA_TOOL_ACTION_NONE = 0, /* normal boot of boot disk */
+ ULTRA_TOOL_ACTION_INSTALL = 1, /* install source disk(s) to boot
+ * disk */
+ ULTRA_TOOL_ACTION_CAPTURE = 2, /* capture boot disk to target disk(s)
+ * as 'gold image' */
+ ULTRA_TOOL_ACTION_REPAIR = 3, /* use source disk(s) to repair
+ * installation on boot disk */
+ ULTRA_TOOL_ACTION_CLEAN = 4, /* 'scrub' virtual disk before
+ * releasing back to storage pool */
+ ULTRA_TOOL_ACTION_UPGRADE = 5, /* upgrade to use content of images
+ * referenced from newer blueprint */
+ ULTRA_TOOL_ACTION_DIAG = 6, /* use tool to invoke diagnostic script
+ * provided by blueprint */
+ ULTRA_TOOL_ACTION_FAILED = 7, /* used when tool fails installation
+ and cannot continue */
+ ULTRA_TOOL_ACTION_COUNT = 8
+} ULTRA_TOOL_ACTIONS;
+
+typedef struct _ULTRA_EFI_SPAR_INDICATION {
+ U64 BootToFirmwareUI:1; /* Bit 0: Stop in uefi ui */
+ U64 ClearNvram:1; /* Bit 1: Clear NVRAM */
+ U64 ClearCmos:1; /* Bit 2: Clear CMOS */
+ U64 BootToTool:1; /* Bit 3: Run install tool */
+ /* remaining bits are available */
+} ULTRA_EFI_SPAR_INDICATION;
+
+typedef enum {
+ ULTRA_CHIPSET_FEATURE_REPLY = 0x00000001,
+ ULTRA_CHIPSET_FEATURE_PARA_HOTPLUG = 0x00000002,
+ ULTRA_CHIPSET_FEATURE_PCIVBUS = 0x00000004
+} ULTRA_CHIPSET_FEATURE;
+
+/** This is the common structure that is at the beginning of every
+ * ControlVm message (both commands and responses) in any ControlVm
+ * queue. Commands are easily distinguished from responses by
+ * looking at the flags.response field.
+ */
+typedef struct _CONTROLVM_MESSAGE_HEADER {
+ U32 Id; /* See CONTROLVM_ID. */
+ /* For requests, indicates the message type. */
+ /* For responses, indicates the type of message we are responding to. */
+
+ U32 MessageSize; /* Includes size of this struct + size
+ * of message */
+ U32 SegmentIndex; /* Index of segment containing Vm
+ * message/information */
+ U32 CompletionStatus; /* Error status code or result of
+ * message completion */
+ struct {
+ U32 failed:1; /**< =1 in a response to * signify
+ * failure */
+ U32 responseExpected:1; /**< =1 in all messages that expect a
+ * response (Control ignores this
+ * bit) */
+ U32 server:1; /**< =1 in all bus & device-related
+ * messages where the message
+ * receiver is to act as the bus or
+ * device server */
+ U32 testMessage:1; /**< =1 for testing use only
+ * (Control and Command ignore this
+ * bit) */
+ U32 partialCompletion:1; /**< =1 if there are forthcoming
+ * responses/acks associated
+ * with this message */
+ U32 preserve:1; /**< =1 this is to let us know to
+ * preserve channel contents
+ * (for running guests)*/
+ U32 writerInDiag:1; /**< =1 the DiagWriter is active in the
+ * Diagnostic Partition*/
+
+ /* remaining bits in this 32-bit word are available */
+ } Flags;
+ U32 Reserved; /* Natural alignment */
+ U64 MessageHandle; /* Identifies the particular message instance,
+ * and is used to match particular */
+ /* request instances with the corresponding response instance. */
+ U64 PayloadVmOffset; /* Offset of payload area from start of this
+ * instance of ControlVm segment */
+ U32 PayloadMaxBytes; /* Maximum bytes allocated in payload
+ * area of ControlVm segment */
+ U32 PayloadBytes; /* Actual number of bytes of payload
+ * area to copy between IO/Command; */
+ /* if non-zero, there is a payload to copy. */
+} CONTROLVM_MESSAGE_HEADER;
+
+typedef struct _CONTROLVM_PACKET_DEVICE_CREATE {
+ U32 busNo; /**< bus # (0..n-1) from the msg receiver's
+ * perspective */
+
+ /* Control uses header SegmentIndex field to access bus number... */
+ U32 devNo; /**< bus-relative (0..n-1) device number */
+ U64 channelAddr; /**< Guest physical address of the channel, which
+ * can be dereferenced by the receiver
+ * of this ControlVm command */
+ U64 channelBytes; /**< specifies size of the channel in bytes */
+ GUID dataTypeGuid;/**< specifies format of data in channel */
+ GUID devInstGuid; /**< instance guid for the device */
+ struct InterruptInfo intr; /**< specifies interrupt information */
+} CONTROLVM_PACKET_DEVICE_CREATE; /* for CONTROLVM_DEVICE_CREATE */
+
+typedef struct _CONTROLVM_PACKET_DEVICE_CONFIGURE {
+ U32 busNo; /**< bus # (0..n-1) from the msg
+ * receiver's perspective */
+
+ /* Control uses header SegmentIndex field to access bus number... */
+ U32 devNo; /**< bus-relative (0..n-1) device number */
+} CONTROLVM_PACKET_DEVICE_CONFIGURE; /* for CONTROLVM_DEVICE_CONFIGURE */
+
+typedef struct _CONTROLVM_MESSAGE_DEVICE_CREATE {
+ CONTROLVM_MESSAGE_HEADER Header;
+ CONTROLVM_PACKET_DEVICE_CREATE Packet;
+} CONTROLVM_MESSAGE_DEVICE_CREATE; /* total 128 bytes */
+
+typedef struct _CONTROLVM_MESSAGE_DEVICE_CONFIGURE {
+ CONTROLVM_MESSAGE_HEADER Header;
+ CONTROLVM_PACKET_DEVICE_CONFIGURE Packet;
+} CONTROLVM_MESSAGE_DEVICE_CONFIGURE; /* total 56 bytes */
+
+/* This is the format for a message in any ControlVm queue. */
+typedef struct _CONTROLVM_MESSAGE_PACKET {
+ union {
+
+ /* BEGIN Request messages */
+ struct {
+ U32 busNo; /*< bus # (0..n-1) from the msg
+ * receiver's perspective */
+
+ /* Control uses header SegmentIndex field to access bus number... */
+ U32 deviceCount; /*< indicates the max number of
+ * devices on this bus */
+ U64 channelAddr; /*< Guest physical address of the
+ * channel, which can be
+ * dereferenced by the receiver
+ * of this ControlVm command */
+ U64 channelBytes; /*< size of the channel in bytes */
+ GUID busDataTypeGuid;/*< indicates format of data in bus
+ * channel */
+ GUID busInstGuid; /*< instance guid for the bus */
+ } createBus; /* for CONTROLVM_BUS_CREATE */
+ struct {
+ U32 busNo; /*< bus # (0..n-1) from the msg
+ * receiver's perspective */
+
+ /* Control uses header SegmentIndex field to access bus number... */
+ U32 reserved; /* Natural alignment purposes */
+ } destroyBus; /* for CONTROLVM_BUS_DESTROY */
+ struct {
+ U32 busNo; /*< bus # (0..n-1) from the
+ * msg receiver's
+ * perspective */
+
+ /* Control uses header SegmentIndex field to access bus number... */
+ U32 reserved1; /* for alignment purposes */
+ U64 guestHandle; /* This is used to convert
+ * guest physical address to real
+ * physical address for DMA, for ex. */
+ U64 recvBusInterruptHandle;/*< specifies interrupt
+ * info. It is used by SP to register
+ * to receive interrupts from the CP.
+ * This interrupt is used for bus
+ * level notifications. The
+ * corresponding
+ * sendBusInterruptHandle is kept in
+ * CP. */
+ } configureBus; /* for CONTROLVM_BUS_CONFIGURE */
+
+ /* for CONTROLVM_DEVICE_CREATE */
+ CONTROLVM_PACKET_DEVICE_CREATE createDevice;
+ struct {
+ U32 busNo; /*< bus # (0..n-1) from the msg
+ * receiver's perspective */
+
+ /* Control uses header SegmentIndex field to access bus number... */
+ U32 devNo; /*< bus-relative (0..n-1) device
+ * number */
+ } destroyDevice; /* for CONTROLVM_DEVICE_DESTROY */
+
+ /* for CONTROLVM_DEVICE_CONFIGURE */
+ CONTROLVM_PACKET_DEVICE_CONFIGURE configureDevice;
+ struct {
+ U32 busNo; /*< bus # (0..n-1) from the msg
+ * receiver's perspective */
+
+ /* Control uses header SegmentIndex field to access bus number... */
+ U32 devNo; /*< bus-relative (0..n-1) device
+ * number */
+ } reconfigureDevice; /* for CONTROLVM_DEVICE_RECONFIGURE */
+ struct {
+ U32 busNo;
+ ULTRA_SEGMENT_STATE state;
+ U8 reserved[2]; /* Natural alignment purposes */
+ } busChangeState; /* for CONTROLVM_BUS_CHANGESTATE */
+ struct {
+ U32 busNo;
+ U32 devNo;
+ ULTRA_SEGMENT_STATE state;
+ struct {
+ U32 physicalDevice:1; /* =1 if message is for
+ * a physical device */
+ /* remaining bits in this 32-bit word are available */
+ } flags;
+ U8 reserved[2]; /* Natural alignment purposes */
+ } deviceChangeState; /* for CONTROLVM_DEVICE_CHANGESTATE */
+ struct {
+ U32 busNo;
+ U32 devNo;
+ ULTRA_SEGMENT_STATE state;
+ U8 reserved[6]; /* Natural alignment purposes */
+ } deviceChangeStateEvent; /* for CONTROLVM_DEVICE_CHANGESTATE_EVENT */
+ struct {
+ U32 busCount; /*< indicates the max number of busses */
+ U32 switchCount; /*< indicates the max number of
+ * switches (applicable for service
+ * partition only) */
+ ULTRA_CHIPSET_FEATURE features;
+ U32 platformNumber; /* Platform Number */
+ } initChipset; /* for CONTROLVM_CHIPSET_INIT */
+ struct {
+ U32 Options; /*< reserved */
+ U32 Test; /*< bit 0 set to run embedded selftest */
+ } chipsetSelftest; /* for CONTROLVM_CHIPSET_SELFTEST */
+
+ /* END Request messages */
+
+ /* BEGIN Response messages */
+
+ /* END Response messages */
+
+ /* BEGIN Event messages */
+
+ /* END Event messages */
+
+ /* BEGIN Ack messages */
+
+ /* END Ack messages */
+ U64 addr; /*< a physical address of something, that
+ * can be dereferenced by the receiver of
+ * this ControlVm command (depends on
+ * command id) */
+ U64 handle; /*< a handle of something (depends on
+ * command id) */
+ };
+} CONTROLVM_MESSAGE_PACKET;
+
+/* All messages in any ControlVm queue have this layout. */
+typedef struct _CONTROLVM_MESSAGE {
+ CONTROLVM_MESSAGE_HEADER hdr;
+ CONTROLVM_MESSAGE_PACKET cmd;
+} CONTROLVM_MESSAGE;
+
+typedef struct _DEVICE_MAP {
+ GUEST_PHYSICAL_ADDRESS DeviceChannelAddress;
+ U64 DeviceChannelSize;
+ U32 CA_Index;
+ U32 Reserved; /* natural alignment */
+ U64 Reserved2; /* Align structure on 32-byte boundary */
+} DEVICE_MAP;
+
+typedef struct _GUEST_DEVICES {
+ DEVICE_MAP VideoChannel;
+ DEVICE_MAP KeyboardChannel;
+ DEVICE_MAP NetworkChannel;
+ DEVICE_MAP StorageChannel;
+ DEVICE_MAP ConsoleChannel;
+ U32 PartitionIndex;
+ U32 Pad;
+} GUEST_DEVICES;
+
+typedef struct _ULTRA_CONTROLVM_CHANNEL_PROTOCOL {
+ CHANNEL_HEADER Header;
+ GUEST_PHYSICAL_ADDRESS gpControlVm; /* guest physical address of
+ * this channel */
+ GUEST_PHYSICAL_ADDRESS gpPartitionTables; /* guest physical address of
+ * partition tables */
+ GUEST_PHYSICAL_ADDRESS gpDiagGuest; /* guest physical address of
+ * diagnostic channel */
+ GUEST_PHYSICAL_ADDRESS gpBootRomDisk; /* guest phys addr of (read
+ * only) Boot ROM disk */
+ GUEST_PHYSICAL_ADDRESS gpBootRamDisk; /* guest phys addr of writable
+ * Boot RAM disk */
+ GUEST_PHYSICAL_ADDRESS gpAcpiTable; /* guest phys addr of acpi
+ * table */
+ GUEST_PHYSICAL_ADDRESS gpControlChannel; /* guest phys addr of control
+ * channel */
+ GUEST_PHYSICAL_ADDRESS gpDiagRomDisk; /* guest phys addr of diagnostic
+ * ROM disk */
+ GUEST_PHYSICAL_ADDRESS gpNvram; /* guest phys addr of NVRAM
+ * channel */
+ U64 RequestPayloadOffset; /* Offset to request payload area */
+ U64 EventPayloadOffset; /* Offset to event payload area */
+ U32 RequestPayloadBytes; /* Bytes available in request payload
+ * area */
+ U32 EventPayloadBytes; /* Bytes available in event payload area */
+ U32 ControlChannelBytes;
+ U32 NvramChannelBytes; /* Bytes in PartitionNvram segment */
+ U32 MessageBytes; /* sizeof(CONTROLVM_MESSAGE) */
+ U32 MessageCount; /* CONTROLVM_MESSAGE_MAX */
+ GUEST_PHYSICAL_ADDRESS gpSmbiosTable; /* guest phys addr of SMBIOS
+ * tables */
+ GUEST_PHYSICAL_ADDRESS gpPhysicalSmbiosTable; /* guest phys addr of
+ * SMBIOS table */
+ /* ULTRA_MAX_GUESTS_PER_SERVICE */
+ GUEST_DEVICES gpObsoleteGuestDevices[16];
+
+ /* guest physical address of EFI firmware image base */
+ GUEST_PHYSICAL_ADDRESS VirtualGuestFirmwareImageBase;
+
+ /* guest physical address of EFI firmware entry point */
+ GUEST_PHYSICAL_ADDRESS VirtualGuestFirmwareEntryPoint;
+
+ /* guest EFI firmware image size */
+ U64 VirtualGuestFirmwareImageSize;
+
+ /* GPA = 1MB where EFI firmware image is copied to */
+ GUEST_PHYSICAL_ADDRESS VirtualGuestFirmwareBootBase;
+ GUEST_PHYSICAL_ADDRESS VirtualGuestImageBase;
+ GUEST_PHYSICAL_ADDRESS VirtualGuestImageSize;
+ U64 PrototypeControlChannelOffset;
+ GUEST_PHYSICAL_ADDRESS VirtualGuestPartitionHandle;
+
+ U16 RestoreAction; /* Restore Action field to restore the guest
+ * partition */
+ U16 DumpAction; /* For Windows guests it shows if the visordisk
+ * is running in dump mode */
+ U16 NvramFailCount;
+ U16 SavedCrashMsgCount; /* = CONTROLVM_CRASHMSG_MAX */
+ U32 SavedCrashMsgOffset; /* Offset to request payload area needed
+ * for crash dump */
+ U32 InstallationError; /* Type of error encountered during
+ * installation */
+ U32 InstallationTextId; /* Id of string to display */
+ U16 InstallationRemainingSteps; /* Number of remaining installation
+ * steps (for progress bars) */
+ U8 ToolAction; /* ULTRA_TOOL_ACTIONS Installation Action
+ * field */
+ U8 Reserved; /* alignment */
+ ULTRA_EFI_SPAR_INDICATION EfiSparIndication;
+ ULTRA_EFI_SPAR_INDICATION EfiSparIndicationSupported;
+ U32 SPReserved;
+ U8 Reserved2[28]; /* Force signals to begin on 128-byte cache
+ * line */
+ SIGNAL_QUEUE_HEADER RequestQueue; /* Service or guest partition
+ * uses this queue to send
+ * requests to Control */
+ SIGNAL_QUEUE_HEADER ResponseQueue; /* Control uses this queue to
+ * respond to service or guest
+ * partition requests */
+ SIGNAL_QUEUE_HEADER EventQueue; /* Control uses this queue to
+ * send events to service or
+ * guest partition */
+ SIGNAL_QUEUE_HEADER EventAckQueue; /* Service or guest partition
+ * uses this queue to ack
+ * Control events */
+
+ /* Request fixed-size message pool - does not include payload */
+ CONTROLVM_MESSAGE RequestMsg[CONTROLVM_MESSAGE_MAX];
+
+ /* Response fixed-size message pool - does not include payload */
+ CONTROLVM_MESSAGE ResponseMsg[CONTROLVM_MESSAGE_MAX];
+
+ /* Event fixed-size message pool - does not include payload */
+ CONTROLVM_MESSAGE EventMsg[CONTROLVM_MESSAGE_MAX];
+
+ /* Ack fixed-size message pool - does not include payload */
+ CONTROLVM_MESSAGE EventAckMsg[CONTROLVM_MESSAGE_MAX];
+
+ /* Message stored during IOVM creation to be reused after crash */
+ CONTROLVM_MESSAGE SavedCrashMsg[CONTROLVM_CRASHMSG_MAX];
+} ULTRA_CONTROLVM_CHANNEL_PROTOCOL;
+
+/* Offsets for VM channel attributes... */
+#define VM_CH_REQ_QUEUE_OFFSET \
+ offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, RequestQueue)
+#define VM_CH_RESP_QUEUE_OFFSET \
+ offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, ResponseQueue)
+#define VM_CH_EVENT_QUEUE_OFFSET \
+ offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, EventQueue)
+#define VM_CH_ACK_QUEUE_OFFSET \
+ offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, EventAckQueue)
+#define VM_CH_REQ_MSG_OFFSET \
+ offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, RequestMsg)
+#define VM_CH_RESP_MSG_OFFSET \
+ offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, ResponseMsg)
+#define VM_CH_EVENT_MSG_OFFSET \
+ offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, EventMsg)
+#define VM_CH_ACK_MSG_OFFSET \
+ offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, EventAckMsg)
+#define VM_CH_CRASH_MSG_OFFSET \
+ offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, SavedCrashMsg)
+
+/* The following header will be located at the beginning of PayloadVmOffset for
+ * various ControlVm commands. The receiver of a ControlVm command with a
+ * PayloadVmOffset will dereference this address and then use ConnectionOffset,
+ * InitiatorOffset, and TargetOffset to get the location of UTF-8 formatted
+ * strings that can be parsed to obtain command-specific information. The value
+ * of TotalLength should equal PayloadBytes. The format of the strings at
+ * PayloadVmOffset will take different forms depending on the message. See the
+ * following Wiki page for more information:
+ * https://ustr-linux-1.na.uis.unisys.com/spar/index.php/ControlVm_Parameters_Area
+ */
+typedef struct _ULTRA_CONTROLVM_PARAMETERS_HEADER {
+ U32 TotalLength;
+ U32 HeaderLength;
+ U32 ConnectionOffset;
+ U32 ConnectionLength;
+ U32 InitiatorOffset;
+ U32 InitiatorLength;
+ U32 TargetOffset;
+ U32 TargetLength;
+ U32 ClientOffset;
+ U32 ClientLength;
+ U32 NameOffset;
+ U32 NameLength;
+ GUID Id;
+ U32 Revision;
+ U32 Reserved; /* Natural alignment */
+} ULTRA_CONTROLVM_PARAMETERS_HEADER;
+
+#endif /* __CONTROLVMCHANNEL_H__ */
--- /dev/null
+/* 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.
+ */
+
+/*++
+ *
+ * Module Name:
+ *
+ * diagchannel.h
+ *
+ * Abstract:
+ *
+ * This file defines the DiagChannel protocol. This protocol is used to aid in
+ * preserving event data sent by external applications. This protocol provides
+ * a region for event data to reside in. This data will eventually be sent to
+ * the Boot Partition where it will be committed to memory and/or disk. This
+ * file contains platform-independent data that can be built using any
+ * Supervisor build environment (Windows, Linux, EFI).
+ *
+*/
+
+#ifndef _DIAG_CHANNEL_H_
+#define _DIAG_CHANNEL_H_
+
+#include "commontypes.h"
+#include "channel.h"
+
+/* {EEA7A573-DB82-447c-8716-EFBEAAAE4858} */
+#define ULTRA_DIAG_CHANNEL_PROTOCOL_GUID \
+ {0xeea7a573, 0xdb82, 0x447c, \
+ {0x87, 0x16, 0xef, 0xbe, 0xaa, 0xae, 0x48, 0x58} }
+
+static const GUID UltraDiagChannelProtocolGuid =
+ ULTRA_DIAG_CHANNEL_PROTOCOL_GUID;
+
+/* {E850F968-3263-4484-8CA5-2A35D087A5A8} */
+#define ULTRA_DIAG_ROOT_CHANNEL_PROTOCOL_GUID \
+ {0xe850f968, 0x3263, 0x4484, \
+ {0x8c, 0xa5, 0x2a, 0x35, 0xd0, 0x87, 0xa5, 0xa8} }
+
+#define ULTRA_DIAG_CHANNEL_PROTOCOL_SIGNATURE ULTRA_CHANNEL_PROTOCOL_SIGNATURE
+
+/* Must increment this whenever you insert or delete fields within this channel
+* struct. Also increment whenever you change the meaning of fields within this
+* channel struct so as to break pre-existing software. Note that you can
+* usually add fields to the END of the channel struct withOUT needing to
+* increment this. */
+#define ULTRA_DIAG_CHANNEL_PROTOCOL_VERSIONID 2
+
+#define ULTRA_DIAG_CHANNEL_OK_CLIENT(pChannel, logCtx) \
+ (ULTRA_check_channel_client(pChannel, \
+ UltraDiagChannelProtocolGuid, \
+ "diag", \
+ sizeof(ULTRA_DIAG_CHANNEL_PROTOCOL), \
+ ULTRA_DIAG_CHANNEL_PROTOCOL_VERSIONID, \
+ ULTRA_DIAG_CHANNEL_PROTOCOL_SIGNATURE, \
+ __FILE__, __LINE__, logCtx))
+#define ULTRA_DIAG_CHANNEL_OK_SERVER(actualBytes, logCtx) \
+ (ULTRA_check_channel_server(UltraDiagChannelProtocolGuid, \
+ "diag", \
+ sizeof(ULTRA_DIAG_CHANNEL_PROTOCOL), \
+ actualBytes, __FILE__, __LINE__, logCtx))
+#define MAX_MODULE_NAME_SIZE 128 /* Maximum length of module name... */
+#define MAX_ADDITIONAL_INFO_SIZE 256 /* Maximum length of any additional info
+ * accompanying event... */
+#define MAX_SUBSYSTEMS 64 /* Maximum number of subsystems allowed in
+ * DiagChannel... */
+#define LOW_SUBSYSTEMS 32 /* Half of MAX_SUBSYSTEMS to allow 64-bit
+ * math */
+#define SUBSYSTEM_DEBUG 0 /* Standard subsystem for debug events */
+#define SUBSYSTEM_DEFAULT 1 /* Default subsystem for legacy calls to
+ * ReportEvent */
+
+/* few useful subsystem mask values */
+#define SUBSYSTEM_MASK_DEBUG 0x01 /* Standard subsystem for debug
+ * events */
+#define SUBSYSTEM_MASK_DEFAULT 0x02 /* Default subsystem for legacy calls to
+ * ReportEvents */
+
+/* Event parameter "Severity" is overloaded with Cause in byte 2 and Severity in
+ * byte 0, bytes 1 and 3 are reserved */
+#define SEVERITY_MASK 0x0FF /* mask out all but the Severity in byte 0 */
+#define CAUSE_MASK 0x0FF0000 /* mask out all but the cause in byte 2 */
+#define CAUSE_SHIFT_AMT 16 /* shift 2 bytes to place it in byte 2 */
+
+/* SubsystemSeverityFilter */
+#define SEVERITY_FILTER_MASK 0x0F /* mask out the Cause half, SeverityFilter is
+ * in the lower nibble */
+#define CAUSE_FILTER_MASK 0xF0 /* mask out the Severity half, CauseFilter is in
+ * the upper nibble */
+#define CAUSE_FILTER_SHIFT_AMT 4 /* shift amount to place it in lower or upper
+ * nibble */
+
+/* Copied from EFI's EFI_TIME struct in efidef.h. EFI headers are not allowed
+* in some of the Supervisor areas, such as Monitor, so it has been "ported" here
+* for use in diagnostic event timestamps... */
+typedef struct _DIAG_EFI_TIME {
+ U16 Year; /* 1998 - 20XX */
+ U8 Month; /* 1 - 12 */
+ U8 Day; /* 1 - 31 */
+ U8 Hour; /* 0 - 23 */
+ U8 Minute; /* 0 - 59 */
+ U8 Second; /* 0 - 59 */
+ U8 Pad1;
+ U32 Nanosecond; /* 0 - 999, 999, 999 */
+ S16 TimeZone; /* -1440 to 1440 or 2047 */
+ U8 Daylight;
+ U8 Pad2;
+} DIAG_EFI_TIME;
+
+typedef enum {
+ ULTRA_COMPONENT_GUEST = 0,
+ ULTRA_COMPONENT_MONITOR = 0x01,
+ ULTRA_COMPONENT_CCM = 0x02, /* Common Control module */
+ /* RESERVED 0x03 - 0x7 */
+
+ /* Ultravisor Components */
+ ULTRA_COMPONENT_BOOT = 0x08,
+ ULTRA_COMPONENT_IDLE = 0x09,
+ ULTRA_COMPONENT_CONTROL = 0x0A,
+ ULTRA_COMPONENT_LOGGER = 0x0B,
+ ULTRA_COMPONENT_ACPI = 0X0C,
+ /* RESERVED 0x0D - 0x0F */
+
+ /* sPAR Components */
+ ULTRA_COMPONENT_COMMAND = 0x10,
+ ULTRA_COMPONENT_IODRIVER = 0x11,
+ ULTRA_COMPONENT_CONSOLE = 0x12,
+ ULTRA_COMPONENT_OPERATIONS = 0x13,
+ ULTRA_COMPONENT_MANAGEMENT = 0x14,
+ ULTRA_COMPONENT_DIAG = 0x15,
+ ULTRA_COMPONENT_HWDIAG = 0x16,
+ ULTRA_COMPONENT_PSERVICES = 0x17,
+ ULTRA_COMPONENT_PDIAG = 0x18
+ /* RESERVED 0x18 - 0x1F */
+} ULTRA_COMPONENT_TYPES;
+
+/* Structure: DIAG_CHANNEL_EVENT Purpose: Contains attributes that make up an
+ * event to be written to the DIAG_CHANNEL memory. Attributes: EventId: Id of
+ * the diagnostic event to write to memory. Severity: Severity of the event
+ * (Error, Info, etc). ModuleName: Module/file name where event originated.
+ * LineNumber: Line number in module name where event originated. Timestamp:
+ * Date/time when event was received by ReportEvent, and written to DiagChannel.
+ * Reserved: Padding to align structure on a 64-byte cache line boundary.
+ * AdditionalInfo: Array of characters for additional event info (may be
+ * empty). */
+typedef struct _DIAG_CHANNEL_EVENT {
+ U32 EventId;
+ U32 Severity;
+ U8 ModuleName[MAX_MODULE_NAME_SIZE];
+ U32 LineNumber;
+ DIAG_EFI_TIME Timestamp; /* Size = 16 bytes */
+ U32 PartitionNumber; /* Filled in by Diag Switch as pool blocks are
+ * filled */
+ U16 VirtualProcessorNumber;
+ U16 LogicalProcessorNumber;
+ U8 ComponentType; /* ULTRA_COMPONENT_TYPES */
+ U8 Subsystem;
+ U16 Reserved0; /* pad to U64 alignment */
+ U32 BlockNumber; /* filled in by DiagSwitch as pool blocks are
+ * filled */
+ U32 BlockNumberHigh;
+ U32 EventNumber; /* filled in by DiagSwitch as pool blocks are
+ * filled */
+ U32 EventNumberHigh;
+
+ /* The BlockNumber and EventNumber fields are set only by DiagSwitch
+ * and referenced only by WinDiagDisplay formatting tool as
+ * additional diagnostic information. Other tools including
+ * WinDiagDisplay currently ignore these 'Reserved' bytes. */
+ U8 Reserved[8];
+ U8 AdditionalInfo[MAX_ADDITIONAL_INFO_SIZE];
+
+ /* NOTE: Changesto DIAG_CHANNEL_EVENT generally need to be reflected in
+ * existing copies *
+ * - for AppOS at
+ * GuestLinux/visordiag_early/supervisor_diagchannel.h *
+ * - for WinDiagDisplay at
+ * EFI/Ultra/Tools/WinDiagDisplay/WinDiagDisplay/diagstruct.h */
+} DIAG_CHANNEL_EVENT;
+
+/* Levels of severity for diagnostic events, in order from lowest severity to
+* highest (i.e. fatal errors are the most severe, and should always be logged,
+* but info events rarely need to be logged except during debugging). The values
+* DIAG_SEVERITY_ENUM_BEGIN and DIAG_SEVERITY_ENUM_END are not valid severity
+* values. They exist merely to dilineate the list, so that future additions
+* won't require changes to the driver (i.e. when checking for out-of-range
+* severities in SetSeverity). The values DIAG_SEVERITY_OVERRIDE and
+* DIAG_SEVERITY_SHUTOFF are not valid severity values for logging events but
+* they are valid for controlling the amount of event data. This enum is also
+* defined in DotNet\sParFramework\ControlFramework\ControlFramework.cs. If a
+* change is made to this enum, they should also be reflected in that file. */
+typedef enum { DIAG_SEVERITY_ENUM_BEGIN = 0,
+ DIAG_SEVERITY_OVERRIDE = DIAG_SEVERITY_ENUM_BEGIN,
+ DIAG_SEVERITY_VERBOSE = DIAG_SEVERITY_OVERRIDE, /* 0 */
+ DIAG_SEVERITY_INFO = DIAG_SEVERITY_VERBOSE + 1, /* 1 */
+ DIAG_SEVERITY_WARNING = DIAG_SEVERITY_INFO + 1, /* 2 */
+ DIAG_SEVERITY_ERR = DIAG_SEVERITY_WARNING + 1, /* 3 */
+ DIAG_SEVERITY_PRINT = DIAG_SEVERITY_ERR + 1, /* 4 */
+ DIAG_SEVERITY_SHUTOFF = DIAG_SEVERITY_PRINT + 1, /* 5 */
+ DIAG_SEVERITY_ENUM_END = DIAG_SEVERITY_SHUTOFF, /* 5 */
+ DIAG_SEVERITY_NONFATAL_ERR = DIAG_SEVERITY_ERR,
+ DIAG_SEVERITY_FATAL_ERR = DIAG_SEVERITY_PRINT
+} DIAG_SEVERITY;
+
+/* Event Cause enums
+*
+* Levels of cause for diagnostic events, in order from least to greatest cause
+* Internal errors are most urgent since ideally they should never exist
+* Invalid requests are preventable by avoiding invalid inputs
+* Operations errors depend on environmental factors which may impact which
+* requests are possible
+* Manifest provides intermediate value to capture firmware and configuration
+* version information
+* Trace provides suplimental debug information in release firmware
+* Unknown Log captures unclasified LogEvent calls.
+* Debug is the least urgent since it provides suplimental debug information only
+* in debug firmware
+* Unknown Debug captures unclassified DebugEvent calls.
+* This enum is also defined in
+* DotNet\sParFramework\ControlFramework\ControlFramework.cs.
+* If a change is made to this enum, they should also be reflected in that
+* file. */
+
+
+
+/* A cause value "DIAG_CAUSE_FILE_XFER" together with a severity value of
+* "DIAG_SEVERITY_PRINT" (=4), is used for transferring text or binary file to
+* the Diag partition. This cause-severity combination will be used by Logger
+* DiagSwitch to segregate events into block types. The files are transferred in
+* 256 byte chunks maximum, in the AdditionalInfo field of the DIAG_CHANNEL_EVENT
+* structure. In the file transfer mode, some event fields will have different
+* meaning: EventId specifies the file offset, severity specifies the block type,
+* ModuleName specifies the filename, LineNumber specifies the number of valid
+* data bytes in an event and AdditionalInfo contains up to 256 bytes of data. */
+
+/* The Diag DiagWriter appends event blocks to events.raw as today, and for data
+ * blocks uses DIAG_CHANNEL_EVENT
+ * PartitionNumber to extract and append 'AdditionalInfo' to filename (specified
+ * by ModuleName). */
+
+/* The Dell PDiag uses this new mechanism to stash DSET .zip onto the
+ * 'diagnostic' virtual disk. */
+typedef enum {
+ DIAG_CAUSE_UNKNOWN = 0,
+ DIAG_CAUSE_UNKNOWN_DEBUG = DIAG_CAUSE_UNKNOWN + 1, /* 1 */
+ DIAG_CAUSE_DEBUG = DIAG_CAUSE_UNKNOWN_DEBUG + 1, /* 2 */
+ DIAG_CAUSE_UNKNOWN_LOG = DIAG_CAUSE_DEBUG + 1, /* 3 */
+ DIAG_CAUSE_TRACE = DIAG_CAUSE_UNKNOWN_LOG + 1, /* 4 */
+ DIAG_CAUSE_MANIFEST = DIAG_CAUSE_TRACE + 1, /* 5 */
+ DIAG_CAUSE_OPERATIONS_ERROR = DIAG_CAUSE_MANIFEST + 1, /* 6 */
+ DIAG_CAUSE_INVALID_REQUEST = DIAG_CAUSE_OPERATIONS_ERROR + 1, /* 7 */
+ DIAG_CAUSE_INTERNAL_ERROR = DIAG_CAUSE_INVALID_REQUEST + 1, /* 8 */
+ DIAG_CAUSE_FILE_XFER = DIAG_CAUSE_INTERNAL_ERROR + 1, /* 9 */
+ DIAG_CAUSE_ENUM_END = DIAG_CAUSE_FILE_XFER /* 9 */
+} DIAG_CAUSE;
+
+/* Event Cause category defined into the byte 2 of Severity */
+#define CAUSE_DEBUG (DIAG_CAUSE_DEBUG << CAUSE_SHIFT_AMT)
+#define CAUSE_TRACE (DIAG_CAUSE_TRACE << CAUSE_SHIFT_AMT)
+#define CAUSE_MANIFEST (DIAG_CAUSE_MANIFEST << CAUSE_SHIFT_AMT)
+#define CAUSE_OPERATIONS_ERROR (DIAG_CAUSE_OPERATIONS_ERROR << CAUSE_SHIFT_AMT)
+#define CAUSE_INVALID_REQUEST (DIAG_CAUSE_INVALID_REQUEST << CAUSE_SHIFT_AMT)
+#define CAUSE_INTERNAL_ERROR (DIAG_CAUSE_INTERNAL_ERROR << CAUSE_SHIFT_AMT)
+#define CAUSE_FILE_XFER (DIAG_CAUSE_FILE_XFER << CAUSE_SHIFT_AMT)
+#define CAUSE_ENUM_END CAUSE_FILE_XFER
+
+/* Combine Cause and Severity categories into one */
+#define CAUSE_DEBUG_SEVERITY_VERBOSE \
+ (CAUSE_DEBUG | DIAG_SEVERITY_VERBOSE)
+#define CAUSE_TRACE_SEVERITY_VERBOSE \
+ (CAUSE_TRACE | DIAG_SEVERITY_VERBOSE)
+#define CAUSE_MANIFEST_SEVERITY_VERBOSE\
+ (CAUSE_MANIFEST | DIAG_SEVERITY_VERBOSE)
+#define CAUSE_OPERATIONS_SEVERITY_VERBOSE \
+ (CAUSE_OPERATIONS_ERROR | DIAG_SEVERITY_VERBOSE)
+#define CAUSE_INVALID_SEVERITY_VERBOSE \
+ (CAUSE_INVALID_REQUEST | DIAG_SEVERITY_VERBOSE)
+#define CAUSE_INTERNAL_SEVERITY_VERBOSE \
+ (CAUSE_INTERNAL_ERROR | DIAG_SEVERITY_VERBOSE)
+
+#define CAUSE_DEBUG_SEVERITY_INFO \
+ (CAUSE_DEBUG | DIAG_SEVERITY_INFO)
+#define CAUSE_TRACE_SEVERITY_INFO \
+ (CAUSE_TRACE | DIAG_SEVERITY_INFO)
+#define CAUSE_MANIFEST_SEVERITY_INFO \
+ (CAUSE_MANIFEST | DIAG_SEVERITY_INFO)
+#define CAUSE_OPERATIONS_SEVERITY_INFO \
+ (CAUSE_OPERATIONS_ERROR | DIAG_SEVERITY_INFO)
+#define CAUSE_INVALID_SEVERITY_INFO \
+ (CAUSE_INVALID_REQUEST | DIAG_SEVERITY_INFO)
+#define CAUSE_INTERNAL_SEVERITY_INFO \
+ (CAUSE_INTERNAL_ERROR | DIAG_SEVERITY_INFO)
+
+#define CAUSE_DEBUG_SEVERITY_WARN \
+ (CAUSE_DEBUG | DIAG_SEVERITY_WARNING)
+#define CAUSE_TRACE_SEVERITY_WARN \
+ (CAUSE_TRACE | DIAG_SEVERITY_WARNING)
+#define CAUSE_MANIFEST_SEVERITY_WARN \
+ (CAUSE_MANIFEST | DIAG_SEVERITY_WARNING)
+#define CAUSE_OPERATIONS_SEVERITY_WARN \
+ (CAUSE_OPERATIONS_ERROR | DIAG_SEVERITY_WARNING)
+#define CAUSE_INVALID_SEVERITY_WARN \
+ (CAUSE_INVALID_REQUEST | DIAG_SEVERITY_WARNING)
+#define CAUSE_INTERNAL_SEVERITY_WARN \
+ (CAUSE_INTERNAL_ERROR | DIAG_SEVERITY_WARNING)
+
+#define CAUSE_DEBUG_SEVERITY_ERR \
+ (CAUSE_DEBUG | DIAG_SEVERITY_ERR)
+#define CAUSE_TRACE_SEVERITY_ERR \
+ (CAUSE_TRACE | DIAG_SEVERITY_ERR)
+#define CAUSE_MANIFEST_SEVERITY_ERR \
+ (CAUSE_MANIFEST | DIAG_SEVERITY_ERR)
+#define CAUSE_OPERATIONS_SEVERITY_ERR \
+ (CAUSE_OPERATIONS_ERROR | DIAG_SEVERITY_ERR)
+#define CAUSE_INVALID_SEVERITY_ERR \
+ (CAUSE_INVALID_REQUEST | DIAG_SEVERITY_ERR)
+#define CAUSE_INTERNAL_SEVERITY_ERR \
+ (CAUSE_INTERNAL_ERROR | DIAG_SEVERITY_ERR)
+
+#define CAUSE_DEBUG_SEVERITY_PRINT \
+ (CAUSE_DEBUG | DIAG_SEVERITY_PRINT)
+#define CAUSE_TRACE_SEVERITY_PRINT \
+ (CAUSE_TRACE | DIAG_SEVERITY_PRINT)
+#define CAUSE_MANIFEST_SEVERITY_PRINT \
+ (CAUSE_MANIFEST | DIAG_SEVERITY_PRINT)
+#define CAUSE_OPERATIONS_SEVERITY_PRINT \
+ (CAUSE_OPERATIONS_ERROR | DIAG_SEVERITY_PRINT)
+#define CAUSE_INVALID_SEVERITY_PRINT \
+ (CAUSE_INVALID_REQUEST | DIAG_SEVERITY_PRINT)
+#define CAUSE_INTERNAL_SEVERITY_PRINT \
+ (CAUSE_INTERNAL_ERROR | DIAG_SEVERITY_PRINT)
+#define CAUSE_FILE_XFER_SEVERITY_PRINT \
+ (CAUSE_FILE_XFER | DIAG_SEVERITY_PRINT)
+
+/* Structure: DIAG_CHANNEL_PROTOCOL_HEADER
+ *
+ * Purpose: Contains attributes that make up the header specific to the
+ * DIAG_CHANNEL area.
+ *
+ * Attributes:
+ *
+ * DiagLock: Diag Channel spinlock.
+ *
+ *IsChannelInitialized: 1 iff SignalInit was called for this channel; otherwise
+ * 0, and assume the channel is not ready for use yet.
+ *
+ * Reserved: Padding to allign the fields in this structure.
+ *
+ *SubsystemSeverityFilter: Level of severity on a subsystem basis that controls
+ * whether events are logged. Any event's severity for a
+ * particular subsystem below this level will be discarded.
+ */
+typedef struct _DIAG_CHANNEL_PROTOCOL_HEADER {
+ volatile U32 DiagLock;
+ U8 IsChannelInitialized;
+ U8 Reserved[3];
+ U8 SubsystemSeverityFilter[64];
+} DIAG_CHANNEL_PROTOCOL_HEADER;
+
+/* The Diagram for the Diagnostic Channel: */
+/* ----------------------- */
+/* | Channel Header | Defined by ULTRA_CHANNEL_PROTOCOL */
+/* ----------------------- */
+/* | Signal Queue Header | Defined by SIGNAL_QUEUE_HEADER */
+/* ----------------------- */
+/* | DiagChannel Header | Defined by DIAG_CHANNEL_PROTOCOL_HEADER */
+/* ----------------------- */
+/* | Channel Event Info | Defined by (DIAG_CHANNEL_EVENT * MAX_EVENTS) */
+/* ----------------------- */
+/* | Reserved | Reserved (pad out to 4MB) */
+/* ----------------------- */
+
+/* Offsets/sizes for diagnostic channel attributes... */
+#define DIAG_CH_QUEUE_HEADER_OFFSET (sizeof(ULTRA_CHANNEL_PROTOCOL))
+#define DIAG_CH_QUEUE_HEADER_SIZE (sizeof(SIGNAL_QUEUE_HEADER))
+#define DIAG_CH_PROTOCOL_HEADER_OFFSET \
+ (DIAG_CH_QUEUE_HEADER_OFFSET + DIAG_CH_QUEUE_HEADER_SIZE)
+#define DIAG_CH_PROTOCOL_HEADER_SIZE (sizeof(DIAG_CHANNEL_PROTOCOL_HEADER))
+#define DIAG_CH_EVENT_OFFSET \
+ (DIAG_CH_PROTOCOL_HEADER_OFFSET + DIAG_CH_PROTOCOL_HEADER_SIZE)
+#define DIAG_CH_SIZE (4096 * 1024)
+
+/* For Control and Idle Partitions with larger (8 MB) diagnostic(root)
+ * channels */
+#define DIAG_CH_LRG_SIZE (2 * DIAG_CH_SIZE) /* 8 MB */
+
+/*
+ * Structure: ULTRA_DIAG_CHANNEL_PROTOCOL
+ *
+ * Purpose: Contains attributes that make up the DIAG_CHANNEL memory.
+ *
+ * Attributes:
+ *
+ * CommonChannelHeader: Header info common to all channels.
+ *
+ * QueueHeader: Queue header common to all channels - used to determine where to
+ * store event.
+ *
+ * DiagChannelHeader: Diagnostic channel header info (see
+ * DIAG_CHANNEL_PROTOCOL_HEADER comments).
+ *
+ * Events: Area where diagnostic events (up to MAX_EVENTS) are written.
+ *
+ *Reserved: Reserved area to allow for correct channel size padding.
+*/
+typedef struct _ULTRA_DIAG_CHANNEL_PROTOCOL {
+ ULTRA_CHANNEL_PROTOCOL CommonChannelHeader;
+ SIGNAL_QUEUE_HEADER QueueHeader;
+ DIAG_CHANNEL_PROTOCOL_HEADER DiagChannelHeader;
+ DIAG_CHANNEL_EVENT Events[(DIAG_CH_SIZE - DIAG_CH_EVENT_OFFSET) /
+ sizeof(DIAG_CHANNEL_EVENT)];
+}
+ULTRA_DIAG_CHANNEL_PROTOCOL;
+
+#endif
--- /dev/null
+/* Copyright © 2010 - 2013 UNISYS CORPORATION */
+/* All rights reserved. */
+#ifndef __IOCHANNEL_H__
+#define __IOCHANNEL_H__
+
+/*
+* Everything needed for IOPart-GuestPart communication is define in
+* this file. Note: Everything is OS-independent because this file is
+* used by Windows, Linux and possible EFI drivers. */
+
+
+/*
+* Communication flow between the IOPart and GuestPart uses the channel headers
+* channel state. The following states are currently being used:
+* UNINIT(All Zeroes), CHANNEL_ATTACHING, CHANNEL_ATTACHED, CHANNEL_OPENED
+*
+* additional states will be used later. No locking is needed to switch between
+* states due to the following rules:
+*
+* 1. IOPart is only the only partition allowed to change from UNIT
+* 2. IOPart is only the only partition allowed to change from
+* CHANNEL_ATTACHING
+* 3. GuestPart is only the only partition allowed to change from
+* CHANNEL_ATTACHED
+*
+* The state changes are the following: IOPart sees the channel is in UNINIT,
+* UNINIT -> CHANNEL_ATTACHING (performed only by IOPart)
+* CHANNEL_ATTACHING -> CHANNEL_ATTACHED (performed only by IOPart)
+* CHANNEL_ATTACHED -> CHANNEL_OPENED (performed only by GuestPart)
+*/
+
+#include "commontypes.h"
+#include "vmcallinterface.h"
+
+#define _ULTRA_CONTROLVM_CHANNEL_INLINE_
+#include "controlvmchannel.h"
+#include "vbuschannel.h"
+#undef _ULTRA_CONTROLVM_CHANNEL_INLINE_
+#include "channel.h"
+
+/*
+ * CHANNEL Guids
+ */
+
+#include "channel_guid.h"
+
+#define ULTRA_VHBA_CHANNEL_PROTOCOL_SIGNATURE ULTRA_CHANNEL_PROTOCOL_SIGNATURE
+#define ULTRA_VNIC_CHANNEL_PROTOCOL_SIGNATURE ULTRA_CHANNEL_PROTOCOL_SIGNATURE
+#define ULTRA_VSWITCH_CHANNEL_PROTOCOL_SIGNATURE \
+ ULTRA_CHANNEL_PROTOCOL_SIGNATURE
+
+/* Must increment these whenever you insert or delete fields within this channel
+* struct. Also increment whenever you change the meaning of fields within this
+* channel struct so as to break pre-existing software. Note that you can
+* usually add fields to the END of the channel struct withOUT needing to
+* increment this. */
+#define ULTRA_VHBA_CHANNEL_PROTOCOL_VERSIONID 2
+#define ULTRA_VNIC_CHANNEL_PROTOCOL_VERSIONID 2
+#define ULTRA_VSWITCH_CHANNEL_PROTOCOL_VERSIONID 1
+
+#define ULTRA_VHBA_CHANNEL_OK_CLIENT(pChannel, logCtx) \
+ (ULTRA_check_channel_client(pChannel, UltraVhbaChannelProtocolGuid, \
+ "vhba", MIN_IO_CHANNEL_SIZE, \
+ ULTRA_VHBA_CHANNEL_PROTOCOL_VERSIONID, \
+ ULTRA_VHBA_CHANNEL_PROTOCOL_SIGNATURE, \
+ __FILE__, __LINE__, logCtx))
+#define ULTRA_VHBA_CHANNEL_OK_SERVER(actualBytes, logCtx) \
+ (ULTRA_check_channel_server(UltraVhbaChannelProtocolGuid, \
+ "vhba", MIN_IO_CHANNEL_SIZE, actualBytes, \
+ __FILE__, __LINE__, logCtx))
+#define ULTRA_VNIC_CHANNEL_OK_CLIENT(pChannel, logCtx) \
+ (ULTRA_check_channel_client(pChannel, UltraVnicChannelProtocolGuid, \
+ "vnic", MIN_IO_CHANNEL_SIZE, \
+ ULTRA_VNIC_CHANNEL_PROTOCOL_VERSIONID, \
+ ULTRA_VNIC_CHANNEL_PROTOCOL_SIGNATURE, \
+ __FILE__, __LINE__, logCtx))
+#define ULTRA_VNIC_CHANNEL_OK_SERVER(actualBytes, logCtx) \
+ (ULTRA_check_channel_server(UltraVnicChannelProtocolGuid, \
+ "vnic", MIN_IO_CHANNEL_SIZE, actualBytes, \
+ __FILE__, __LINE__, logCtx))
+#define ULTRA_VSWITCH_CHANNEL_OK_CLIENT(pChannel, logCtx) \
+ (ULTRA_check_channel_client(pChannel, UltraVswitchChannelProtocolGuid, \
+ "vswitch", MIN_IO_CHANNEL_SIZE, \
+ ULTRA_VSWITCH_CHANNEL_PROTOCOL_VERSIONID, \
+ ULTRA_VSWITCH_CHANNEL_PROTOCOL_SIGNATURE, \
+ __FILE__, __LINE__, logCtx))
+#define ULTRA_VSWITCH_CHANNEL_OK_SERVER(actualBytes, logCtx) \
+ (ULTRA_check_channel_server(UltraVswitchChannelProtocolGuid, \
+ "vswitch", MIN_IO_CHANNEL_SIZE, \
+ actualBytes, \
+ __FILE__, __LINE__, logCtx))
+/*
+* Everything necessary to handle SCSI & NIC traffic between Guest Partition and
+* IO Partition is defined below. */
+
+
+/*
+* Defines and enums.
+*/
+
+#define MINNUM(a, b) (((a) < (b)) ? (a) : (b))
+#define MAXNUM(a, b) (((a) > (b)) ? (a) : (b))
+
+/* these define the two queues per data channel between iopart and
+ * ioguestparts */
+#define IOCHAN_TO_IOPART 0 /* used by ioguestpart to 'insert' signals to
+ * iopart */
+#define IOCHAN_FROM_GUESTPART 0 /* used by iopart to 'remove' signals from
+ * ioguestpart - same queue as previous queue */
+
+#define IOCHAN_TO_GUESTPART 1 /* used by iopart to 'insert' signals to
+ * ioguestpart */
+#define IOCHAN_FROM_IOPART 1 /* used by ioguestpart to 'remove' signals from
+ * iopart - same queue as previous queue */
+
+/* these define the two queues per control channel between controlpart and "its"
+ * guests, which includes the iopart */
+#define CTRLCHAN_TO_CTRLGUESTPART 0 /* used by ctrlguestpart to 'insert' signals
+ * to ctrlpart */
+#define CTLRCHAN_FROM_CTRLPART 0 /* used by ctrlpart to 'remove' signals from
+ * ctrlquestpart - same queue as previous
+ * queue */
+
+#define CTRLCHAN_TO_CTRLPART 1 /* used by ctrlpart to 'insert' signals to
+ * ctrlguestpart */
+#define CTRLCHAN_FROM_CTRLGUESTPART 1 /* used by ctrguestpart to 'remove'
+ * signals from ctrlpart - same queue as
+ * previous queue */
+
+/* these define the Event & Ack queues per control channel Events are generated
+* by CTRLGUESTPART and sent to CTRLPART; Acks are generated by CTRLPART and sent
+* to CTRLGUESTPART. */
+#define CTRLCHAN_EVENT_TO_CTRLPART 2 /* used by ctrlguestpart to 'insert' Events
+ * to ctrlpart */
+#define CTRLCHAN_EVENT_FROM_CTRLGUESTPART 2 /* used by ctrlpart to 'remove'
+ * Events from ctrlguestpart */
+
+#define CTRLCHAN_ACK_TO_CTRLGUESTPART 3 /* used by ctrlpart to 'insert' Acks to
+ * ctrlguestpart */
+#define CTRLCHAN_ACK_FROM_CTRLPART 3 /* used by ctrlguestpart to 'remove' Events
+ * from ctrlpart */
+
+/* size of cdb - i.e., scsi cmnd */
+#define MAX_CMND_SIZE 16
+enum dma_data_dir {
+ DMA_DIR_BIDIR = 0,
+ DMA_DIR_TO_DEV,
+ DMA_DIR_FROM_DEV,
+ DMA_DIR_NONE
+};
+
+#define MAX_SENSE_SIZE 64
+
+#define MAX_PHYS_INFO 64
+
+/* Because GuestToGuestCopy is limited to 4KiB segments, and we have limited the
+* Emulex Driver to 256 scatter list segments via the lpfc_sg_seg_cnt parameter
+* to 256, the maximum I/O size is limited to 256 * 4 KiB = 1 MB */
+#define MAX_IO_SIZE (1024*1024) /* 1 MB */
+
+/* NOTE 1: lpfc defines its support for segments in
+* #define LPFC_SG_SEG_CNT 64
+*
+* NOTE 2: In Linux, frags array in skb is currently allocated to be
+* MAX_SKB_FRAGS size, which is 18 which is smaller than MAX_PHYS_INFO for
+* now. */
+
+#ifndef MAX_SERIAL_NUM
+#define MAX_SERIAL_NUM 32
+#endif /* MAX_SERIAL_NUM */
+
+#define MAX_SCSI_BUSES 1
+#define MAX_SCSI_TARGETS 8
+#define MAX_SCSI_LUNS 16
+#define MAX_SCSI_FROM_HOST 0xFFFFFFFF /* Indicator to use Physical HBA
+ * SCSI Host value */
+
+/* various types of network packets that can be sent in cmdrsp */
+typedef enum { NET_RCV_POST = 0, /* submit buffer to hold receiving
+ * incoming packet */
+ /* virtnic -> uisnic */
+ NET_RCV, /* incoming packet received */
+ /* uisnic -> virtpci */
+ NET_XMIT, /* for outgoing net packets */
+ /* virtnic -> uisnic */
+ NET_XMIT_DONE, /* outgoing packet xmitted */
+ /* uisnic -> virtpci */
+ NET_RCV_ENBDIS, /* enable/disable packet reception */
+ /* virtnic -> uisnic */
+ NET_RCV_ENBDIS_ACK, /* acknowledge enable/disable packet
+ * reception */
+ /* uisnic -> virtnic */
+ NET_RCV_PROMISC, /* enable/disable promiscuous mode */
+ /* virtnic -> uisnic */
+ NET_CONNECT_STATUS, /* indicate the loss or restoration of a network
+ * connection */
+ /* uisnic -> virtnic */
+ NET_MACADDR, /* indicates the client has requested to update
+ * its MAC addr */
+ NET_MACADDR_ACK, /* Mac addres */
+
+} NET_TYPES;
+
+#define ETH_HEADER_SIZE 14 /* size of ethernet header */
+
+#define ETH_MIN_DATA_SIZE 46 /* minimum eth data size */
+#define ETH_MIN_PACKET_SIZE (ETH_HEADER_SIZE + ETH_MIN_DATA_SIZE)
+
+#define ETH_DEF_DATA_SIZE 1500 /* default data size */
+#define ETH_DEF_PACKET_SIZE (ETH_HEADER_SIZE + ETH_DEF_DATA_SIZE)
+
+#define ETH_MAX_MTU 16384 /* maximum data size */
+
+#ifndef MAX_MACADDR_LEN
+#define MAX_MACADDR_LEN 6 /* number of bytes in MAC address */
+#endif /* MAX_MACADDR_LEN */
+
+#define ETH_IS_LOCALLY_ADMINISTERED(Address) \
+ (((U8 *) (Address))[0] & ((U8) 0x02))
+#define NIC_VENDOR_ID 0x0008000B
+
+/* various types of scsi task mgmt commands */
+typedef enum { TASK_MGMT_ABORT_TASK =
+ 1, TASK_MGMT_BUS_RESET, TASK_MGMT_LUN_RESET,
+ TASK_MGMT_TARGET_RESET,
+} TASK_MGMT_TYPES;
+
+/* various types of vdisk mgmt commands */
+typedef enum { VDISK_MGMT_ACQUIRE = 1, VDISK_MGMT_RELEASE,
+} VDISK_MGMT_TYPES;
+
+/* this is used in the vdest field */
+#define VDEST_ALL 0xFFFF
+
+#define MIN_NUMSIGNALS 64
+#define MAX_NUMSIGNALS 4096
+
+/* MAX_NET_RCV_BUF specifies the number of rcv buffers that are created by each
+* guest's virtnic and posted to uisnic. Uisnic, for each channel, keeps the rcv
+* buffers posted and uses them to receive data on behalf of the guest's virtnic.
+* NOTE: the num_rcv_bufs is configurable for each VNIC. So the following is
+* simply an upperlimit on what each VNIC can provide. Setting it to half of the
+* NUMSIGNALS to prevent queue full deadlocks */
+#define MAX_NET_RCV_BUFS (MIN_NUMSIGNALS / 2)
+
+/*
+ * structs with pragma pack */
+
+
+/* ///////////// BEGIN PRAGMA PACK PUSH 1 ///////////////////////// */
+/* ///////////// ONLY STRUCT TYPE SHOULD BE BELOW */
+
+#pragma pack(push, 1)
+
+struct guest_phys_info {
+ U64 address;
+ U64 length;
+};
+
+#define GPI_ENTRIES_PER_PAGE (PAGE_SIZE / sizeof(struct guest_phys_info))
+
+struct uisscsi_dest {
+ U32 channel; /* channel == bus number */
+ U32 id; /* id == target number */
+ U32 lun; /* lun == logical unit number */
+};
+
+struct vhba_wwnn {
+ U32 wwnn1;
+ U32 wwnn2;
+};
+
+/* WARNING: Values stired in this structure must contain maximum counts (not
+ * maximum values). */
+struct vhba_config_max { /* 20 bytes */
+ U32 max_channel; /* maximum channel for devices attached to this
+ * bus */
+ U32 max_id; /* maximum SCSI ID for devices attached to this
+ * bus */
+ U32 max_lun; /* maximum SCSI LUN for devices attached to this
+ * bus */
+ U32 cmd_per_lun; /* maximum number of outstanding commands per
+ * lun that are allowed at one time */
+ U32 max_io_size; /* maximum io size for devices attached to this
+ * bus */
+ /* max io size is often determined by the resource of the hba. e.g */
+ /* max scatter gather list length * page size / sector size */
+};
+
+struct uiscmdrsp_scsi {
+ void *scsicmd; /* the handle to the cmd that was received -
+ * send it back as is in the rsp packet. */
+ U8 cmnd[MAX_CMND_SIZE]; /* the cdb for the command */
+ U32 bufflen; /* length of data to be transferred out or in */
+ U16 guest_phys_entries; /* Number of entries in scatter-gather (sg)
+ * list */
+ struct guest_phys_info gpi_list[MAX_PHYS_INFO]; /* physical address
+ * information for each
+ * fragment */
+ enum dma_data_dir data_dir; /* direction of the data, if any */
+ struct uisscsi_dest vdest; /* identifies the virtual hba, id,
+ * channel, lun to which cmd was sent */
+
+ /* the following fields are needed to queue the rsp back to cmd
+ * originator */
+ int linuxstat; /* the original Linux status - for use by linux
+ * vdisk code */
+ U8 scsistat; /* the scsi status */
+ U8 addlstat; /* non-scsi status - covers cases like timeout
+ * needed by windows guests */
+#define ADDL_RESET 1
+#define ADDL_TIMEOUT 2
+#define ADDL_INTERNAL_ERROR 3
+#define ADDL_SEL_TIMEOUT 4
+#define ADDL_CMD_TIMEOUT 5
+#define ADDL_BAD_TARGET 6
+#define ADDL_RETRY 7
+
+ /* the following fields are need to determine the result of command */
+ U8 sensebuf[MAX_SENSE_SIZE]; /* sense info in case cmd failed; */
+ /* it holds the sense_data struct; */
+ /* see that struct for details. */
+ void *vdisk; /* contains pointer to the vdisk so that we can clean up
+ * when the IO completes. */
+ int no_disk_result; /* used to return no disk inquiry result */
+ /* when no_disk_result is set to 1, */
+ /* scsi.scsistat is SAM_STAT_GOOD */
+ /* scsi.addlstat is 0 */
+ /* scsi.linuxstat is SAM_STAT_GOOD */
+ /* That is, there is NO error. */
+};
+
+/*
+* Defines to support sending correct inquiry result when no disk is
+* configured. */
+
+/* From SCSI SPC2 -
+ *
+ * If the target is not capable of supporting a device on this logical unit, the
+ * device server shall set this field to 7Fh (PERIPHERAL QUALIFIER set to 011b
+ * and PERIPHERAL DEVICE TYPE set to 1Fh).
+ *
+ *The device server is capable of supporting the specified peripheral device
+ *type on this logical unit. However, the physical device is not currently
+ *connected to this logical unit.
+ */
+
+#define DEV_NOT_PRESENT 0x7f /* old name - compatibility */
+#define DEV_NOT_CAPABLE 0x7f /* peripheral qualifier of 0x3 */
+ /* peripheral type of 0x1f */
+ /* specifies no device but target present */
+
+#define DEV_DISK_CAPABLE_NOT_PRESENT 0x20 /* peripheral qualifier of 0x1 */
+ /* peripheral type of 0 - disk */
+ /* specifies device capable, but not present */
+
+#define DEV_PROC_CAPABLE_NOT_PRESENT 0x23 /* peripheral qualifier of 0x1 */
+ /* peripheral type of 3 - processor */
+ /* specifies device capable, but not present */
+
+#define DEV_HISUPPORT 0x10; /* HiSup = 1; shows support for report luns */
+ /* must be returned for lun 0. */
+
+/* NOTE: Linux code assumes inquiry contains 36 bytes. Without checking length
+* in buf[4] some linux code accesses bytes beyond 5 to retrieve vendor, product
+* & revision. Yikes! So let us always send back 36 bytes, the minimum for
+* inquiry result. */
+#define NO_DISK_INQUIRY_RESULT_LEN 36
+
+#define MIN_INQUIRY_RESULT_LEN 5 /* we need at least 5 bytes minimum for inquiry
+ * result */
+
+/* SCSI device version for no disk inquiry result */
+#define SCSI_SPC2_VER 4 /* indicates SCSI SPC2 (SPC3 is 5) */
+
+/* Windows and Linux want different things for a non-existent lun. So, we'll let
+ * caller pass in the peripheral qualifier and type.
+ * NOTE:[4] SCSI returns (n-4); so we return length-1-4 or length-5. */
+
+#define SET_NO_DISK_INQUIRY_RESULT(buf, len, lun, lun0notpresent, notpresent) \
+ do { \
+ MEMSET(buf, 0, \
+ MINNUM(len, \
+ (unsigned int) NO_DISK_INQUIRY_RESULT_LEN)); \
+ buf[2] = (U8) SCSI_SPC2_VER; \
+ if (lun == 0) { \
+ buf[0] = (U8) lun0notpresent; \
+ buf[3] = (U8) DEV_HISUPPORT; \
+ } else \
+ buf[0] = (U8) notpresent; \
+ buf[4] = (U8) ( \
+ MINNUM(len, \
+ (unsigned int) NO_DISK_INQUIRY_RESULT_LEN) - 5); \
+ if (len >= NO_DISK_INQUIRY_RESULT_LEN) { \
+ buf[8] = 'D'; \
+ buf[9] = 'E'; \
+ buf[10] = 'L'; \
+ buf[11] = 'L'; \
+ buf[16] = 'P'; \
+ buf[17] = 'S'; \
+ buf[18] = 'E'; \
+ buf[19] = 'U'; \
+ buf[20] = 'D'; \
+ buf[21] = 'O'; \
+ buf[22] = ' '; \
+ buf[23] = 'D'; \
+ buf[24] = 'E'; \
+ buf[25] = 'V'; \
+ buf[26] = 'I'; \
+ buf[27] = 'C'; \
+ buf[28] = 'E'; \
+ buf[30] = ' '; \
+ buf[31] = '.'; \
+ } \
+ } while (0)
+
+
+/*
+* Struct & Defines to support sense information.
+*/
+
+
+/* The following struct is returned in sensebuf field in uiscmdrsp_scsi. It is
+* initialized in exactly the manner that is recommended in Windows (hence the
+* odd values).
+* When set, these fields will have the following values:
+* ErrorCode = 0x70 indicates current error
+* Valid = 1 indicates sense info is valid
+* SenseKey contains sense key as defined by SCSI specs.
+* AdditionalSenseCode contains sense key as defined by SCSI specs.
+* AdditionalSenseCodeQualifier contains qualifier to sense code as defined by
+* scsi docs.
+* AdditionalSenseLength contains will be sizeof(sense_data)-8=10.
+*/
+struct sense_data {
+ U8 ErrorCode:7;
+ U8 Valid:1;
+ U8 SegmentNumber;
+ U8 SenseKey:4;
+ U8 Reserved:1;
+ U8 IncorrectLength:1;
+ U8 EndOfMedia:1;
+ U8 FileMark:1;
+ U8 Information[4];
+ U8 AdditionalSenseLength;
+ U8 CommandSpecificInformation[4];
+ U8 AdditionalSenseCode;
+ U8 AdditionalSenseCodeQualifier;
+ U8 FieldReplaceableUnitCode;
+ U8 SenseKeySpecific[3];
+};
+
+/* some SCSI ADSENSE codes */
+#ifndef SCSI_ADSENSE_LUN_NOT_READY
+#define SCSI_ADSENSE_LUN_NOT_READY 0x04
+#endif /* */
+#ifndef SCSI_ADSENSE_ILLEGAL_COMMAND
+#define SCSI_ADSENSE_ILLEGAL_COMMAND 0x20
+#endif /* */
+#ifndef SCSI_ADSENSE_ILLEGAL_BLOCK
+#endif /* */
+#ifndef SCSI_ADSENSE_ILLEGAL_BLOCK
+#define SCSI_ADSENSE_ILLEGAL_BLOCK 0x21
+#endif /* */
+#ifndef SCSI_ADSENSE_INVALID_CDB
+#define SCSI_ADSENSE_INVALID_CDB 0x24
+#endif /* */
+#ifndef SCSI_ADSENSE_INVALID_LUN
+#define SCSI_ADSENSE_INVALID_LUN 0x25
+#endif /* */
+#ifndef SCSI_ADWRITE_PROTECT
+#define SCSI_ADWRITE_PROTECT 0x27
+#endif /* */
+#ifndef SCSI_ADSENSE_MEDIUM_CHANGED
+#define SCSI_ADSENSE_MEDIUM_CHANGED 0x28
+#endif /* */
+#ifndef SCSI_ADSENSE_BUS_RESET
+#define SCSI_ADSENSE_BUS_RESET 0x29
+#endif /* */
+#ifndef SCSI_ADSENSE_NO_MEDIA_IN_DEVICE
+#define SCSI_ADSENSE_NO_MEDIA_IN_DEVICE 0x3a
+#endif /* */
+
+struct net_pkt_xmt {
+ int len; /* full length of data in the packet */
+ int num_frags; /* number of fragments in frags containing data */
+ struct phys_info frags[MAX_PHYS_INFO]; /* physical page information for
+ * each fragment */
+ char ethhdr[ETH_HEADER_SIZE]; /* the ethernet header */
+ struct {
+
+ /* these are needed for csum at uisnic end */
+ U8 valid; /* 1 = rest of this struct is valid - else
+ * ignore */
+ U8 hrawoffv; /* 1 = hwrafoff is valid */
+ U8 nhrawoffv; /* 1 = nhwrafoff is valid */
+ U16 protocol; /* specifies packet protocol */
+ U32 csum; /* value used to set skb->csum at IOPart */
+ U32 hrawoff; /* value used to set skb->h.raw at IOPart */
+ /* hrawoff points to the start of the TRANSPORT LAYER HEADER */
+ U32 nhrawoff; /* value used to set skb->nh.raw at IOPart */
+ /* nhrawoff points to the start of the NETWORK LAYER HEADER */
+ } lincsum;
+
+ /* **** NOTE ****
+ * The full packet is described in frags but the ethernet header is
+ * separately kept in ethhdr so that uisnic doesn't have "MAP" the
+ * guest memory to get to the header. uisnic needs ethhdr to
+ * determine how to route the packet.
+ */
+};
+
+struct net_pkt_xmtdone {
+ U32 xmt_done_result; /* result of NET_XMIT */
+#define XMIT_SUCCESS 0
+#define XMIT_FAILED 1
+};
+
+/* RCVPOST_BUF_SIZe must be at most page_size(4096) - cache_line_size (64) The
+* reason is because dev_skb_alloc which is used to generate RCV_POST skbs in
+* virtnic requires that there is "overhead" in the buffer, and pads 16 bytes. I
+* prefer to use 1 full cache line size for "overhead" so that transfers are
+* better. IOVM requires that a buffer be represented by 1 phys_info structure
+* which can only cover page_size. */
+#define RCVPOST_BUF_SIZE 4032
+#define MAX_NET_RCV_CHAIN \
+ ((ETH_MAX_MTU+ETH_HEADER_SIZE + RCVPOST_BUF_SIZE-1) / RCVPOST_BUF_SIZE)
+
+struct net_pkt_rcvpost {
+ /* rcv buf size must be large enough to include ethernet data len +
+ * ethernet header len - we are choosing 2K because it is guaranteed
+ * to be describable */
+ struct phys_info frag; /* physical page information for the
+ * single fragment 2K rcv buf */
+ U64 UniqueNum; /* This is used to make sure that
+ * receive posts are returned to */
+ /* the Adapter which sent them origonally. */
+};
+
+struct net_pkt_rcv {
+
+ /* the number of receive buffers that can be chained */
+ /* is based on max mtu and size of each rcv buf */
+ U32 rcv_done_len; /* length of received data */
+ U8 numrcvbufs; /* number of receive buffers that contain the */
+ /* incoming data; guest end MUST chain these together. */
+ void *rcvbuf[MAX_NET_RCV_CHAIN]; /* the list of receive buffers
+ * that must be chained; */
+ /* each entry is a receive buffer provided by NET_RCV_POST. */
+ /* NOTE: first rcvbuf in the chain will also be provided in net.buf. */
+ U64 UniqueNum;
+ U32 RcvsDroppedDelta;
+};
+
+struct net_pkt_enbdis {
+ void *context;
+ U16 enable; /* 1 = enable, 0 = disable */
+};
+
+struct net_pkt_macaddr {
+ void *context;
+ U8 macaddr[MAX_MACADDR_LEN]; /* 6 bytes */
+};
+
+/* cmd rsp packet used for VNIC network traffic */
+struct uiscmdrsp_net {
+ NET_TYPES type;
+ void *buf;
+ union {
+ struct net_pkt_xmt xmt; /* used for NET_XMIT */
+ struct net_pkt_xmtdone xmtdone; /* used for NET_XMIT_DONE */
+ struct net_pkt_rcvpost rcvpost; /* used for NET_RCV_POST */
+ struct net_pkt_rcv rcv; /* used for NET_RCV */
+ struct net_pkt_enbdis enbdis; /* used for NET_RCV_ENBDIS, */
+ /* NET_RCV_ENBDIS_ACK, */
+ /* NET_RCV_PROMSIC, */
+ /* and NET_CONNECT_STATUS */
+ struct net_pkt_macaddr macaddr;
+ };
+};
+
+struct uiscmdrsp_scsitaskmgmt {
+ TASK_MGMT_TYPES tasktype;
+
+ /* the type of task */
+ struct uisscsi_dest vdest;
+
+ /* the vdisk for which this task mgmt is generated */
+ void *scsicmd;
+
+ /* This is some handle that the guest has saved off for its own use.
+ * Its value is preserved by iopart & returned as is in the task mgmt
+ * rsp. */
+ void *notify;
+
+ /* For linux guests, this is a pointer to wait_queue_head that a
+ * thread is waiting on to see if the taskmgmt command has completed.
+ * For windows guests, this is a pointer to a location that a waiting
+ * thread is testing to see if the taskmgmt command has completed.
+ * When the rsp is received by guest, the thread receiving the
+ * response uses this to notify the the thread waiting for taskmgmt
+ * command completion. Its value is preserved by iopart & returned
+ * as is in the task mgmt rsp. */
+ void *notifyresult;
+
+ /* this is a handle to location in guest where the result of the
+ * taskmgmt command (result field) is to saved off when the response
+ * is handled. Its value is preserved by iopart & returned as is in
+ * the task mgmt rsp. */
+ char result;
+
+ /* result of taskmgmt command - set by IOPart - values are: */
+#define TASK_MGMT_FAILED 0
+#define TASK_MGMT_SUCCESS 1
+};
+
+/* The following is used by uissd to send disk add/remove notifications to
+ * Guest */
+/* Note that the vHba pointer is not used by the Client/Guest side. */
+struct uiscmdrsp_disknotify {
+ U8 add; /* 0-remove, 1-add */
+ void *vHba; /* Pointer to vhba_info for channel info to
+ * route msg */
+ U32 channel, id, lun; /* SCSI Path of Disk to added or removed */
+};
+
+/* The following is used by virthba/vSCSI to send the Acquire/Release commands
+* to the IOVM. */
+struct uiscmdrsp_vdiskmgmt {
+ VDISK_MGMT_TYPES vdisktype;
+
+ /* the type of task */
+ struct uisscsi_dest vdest;
+
+ /* the vdisk for which this task mgmt is generated */
+ void *scsicmd;
+
+ /* This is some handle that the guest has saved off for its own use.
+ * Its value is preserved by iopart & returned as is in the task mgmt
+ * rsp. */
+ void *notify;
+
+ /* For linux guests, this is a pointer to wait_queue_head that a
+ * thread is waiting on to see if the taskmgmt command has completed.
+ * For windows guests, this is a pointer to a location that a waiting
+ * thread is testing to see if the taskmgmt command has completed.
+ * When the rsp is received by guest, the thread receiving the
+ * response uses this to notify the the thread waiting for taskmgmt
+ * command completion. Its value is preserved by iopart & returned
+ * as is in the task mgmt rsp. */
+ void *notifyresult;
+
+ /* this is a handle to location in guest where the result of the
+ * taskmgmt command (result field) is to saved off when the response
+ * is handled. Its value is preserved by iopart & returned as is in
+ * the task mgmt rsp. */
+ char result;
+
+ /* result of taskmgmt command - set by IOPart - values are: */
+#define VDISK_MGMT_FAILED 0
+#define VDISK_MGMT_SUCCESS 1
+};
+
+/* keeping cmd & rsp info in one structure for now cmd rsp packet for scsi */
+struct uiscmdrsp {
+ char cmdtype;
+
+ /* describes what type of information is in the struct */
+#define CMD_SCSI_TYPE 1
+#define CMD_NET_TYPE 2
+#define CMD_SCSITASKMGMT_TYPE 3
+#define CMD_NOTIFYGUEST_TYPE 4
+#define CMD_VDISKMGMT_TYPE 5
+ union {
+ struct uiscmdrsp_scsi scsi;
+ struct uiscmdrsp_net net;
+ struct uiscmdrsp_scsitaskmgmt scsitaskmgmt;
+ struct uiscmdrsp_disknotify disknotify;
+ struct uiscmdrsp_vdiskmgmt vdiskmgmt;
+ };
+ void *private_data; /* used to send the response when the cmd is
+ * done (scsi & scsittaskmgmt). */
+ struct uiscmdrsp *next; /* General Purpose Queue Link */
+ struct uiscmdrsp *activeQ_next; /* Used to track active commands */
+ struct uiscmdrsp *activeQ_prev; /* Used to track active commands */
+};
+
+/* This is just the header of the IO channel. It is assumed that directly after
+* this header there is a large region of memory which contains the command and
+* response queues as specified in cmdQ and rspQ SIGNAL_QUEUE_HEADERS. */
+typedef struct _ULTRA_IO_CHANNEL_PROTOCOL {
+ CHANNEL_HEADER ChannelHeader;
+ SIGNAL_QUEUE_HEADER cmdQ;
+ SIGNAL_QUEUE_HEADER rspQ;
+ union {
+ struct {
+ struct vhba_wwnn wwnn; /* 8 bytes */
+ struct vhba_config_max max; /* 20 bytes */
+ } vhba; /* 28 */
+ struct {
+ U8 macaddr[MAX_MACADDR_LEN]; /* 6 bytes */
+ U32 num_rcv_bufs; /* 4 */
+ U32 mtu; /* 4 */
+ GUID zoneGuid; /* 16 */
+ } vnic; /* total 30 */
+ };
+
+#define MAX_CLIENTSTRING_LEN 1024
+ U8 clientString[MAX_CLIENTSTRING_LEN]; /* NULL terminated - so holds
+ * max - 1 bytes */
+} ULTRA_IO_CHANNEL_PROTOCOL;
+
+#pragma pack(pop)
+/* ///////////// END PRAGMA PACK PUSH 1 /////////////////////////// */
+
+/* define offsets to members of struct uiscmdrsp */
+#define OFFSET_CMDTYPE OFFSETOF(struct uiscmdrsp, cmdtype)
+#define OFFSET_SCSI OFFSETOF(struct uiscmdrsp, scsi)
+#define OFFSET_NET OFFSETOF(struct uiscmdrsp, net)
+#define OFFSET_SCSITASKMGMT OFFSETOF(struct uiscmdrsp, scsitaskmgmt)
+#define OFFSET_NEXT OFFSETOF(struct uiscmdrsp, next)
+
+/* define offsets to members of struct uiscmdrsp_net */
+#define OFFSET_TYPE OFFSETOF(struct uiscmdrsp_net, type)
+#define OFFSET_BUF OFFSETOF(struct uiscmdrsp_net, buf)
+#define OFFSET_XMT OFFSETOF(struct uiscmdrsp_net, xmt)
+#define OFFSET_XMT_DONE_RESULT OFFSETOF(struct uiscmdrsp_net, xmtdone)
+#define OFFSET_RCVPOST OFFSETOF(struct uiscmdrsp_net, rcvpost)
+#define OFFSET_RCV_DONE_LEN OFFSETOF(struct uiscmdrsp_net, rcv)
+#define OFFSET_ENBDIS OFFSETOF(struct uiscmdrsp_net, enbdis)
+
+/* define offsets to members of struct net_pkt_rcvpost */
+#define OFFSET_TOTALLEN OFFSETOF(struct net_pkt_rcvpost, totallen)
+#define OFFSET_FRAG OFFSETOF(struct net_pkt_rcvpost, frag)
+
+/*
+* INLINE functions for initializing and accessing I/O data channels
+*/
+
+
+#define NUMSIGNALS(x, q) (((ULTRA_IO_CHANNEL_PROTOCOL *)(x))->q.MaxSignalSlots)
+#define SIZEOF_PROTOCOL (COVER(sizeof(ULTRA_IO_CHANNEL_PROTOCOL), 64))
+#define SIZEOF_CMDRSP (COVER(sizeof(struct uiscmdrsp), 64))
+
+#define IO_CHANNEL_SIZE(x) COVER(SIZEOF_PROTOCOL + \
+ (NUMSIGNALS(x, cmdQ) + \
+ NUMSIGNALS(x, rspQ)) * SIZEOF_CMDRSP, 4096)
+#define MIN_IO_CHANNEL_SIZE COVER(SIZEOF_PROTOCOL + \
+ 2 * MIN_NUMSIGNALS * SIZEOF_CMDRSP, 4096)
+#ifdef __GNUC__
+/* These defines should only ever be used in service partitons */
+/* because they rely on the size of uiscmdrsp */
+#define QSLOTSFROMBYTES(bytes) (((bytes-SIZEOF_PROTOCOL)/2)/SIZEOF_CMDRSP)
+#define QSIZEFROMBYTES(bytes) (QSLOTSFROMBYTES(bytes)*SIZEOF_CMDRSP)
+#define SignalQInit(x) \
+ do { \
+ x->cmdQ.Size = QSIZEFROMBYTES(x->ChannelHeader.Size); \
+ x->cmdQ.oSignalBase = SIZEOF_PROTOCOL - \
+ OFFSETOF(ULTRA_IO_CHANNEL_PROTOCOL, cmdQ); \
+ x->cmdQ.SignalSize = SIZEOF_CMDRSP; \
+ x->cmdQ.MaxSignalSlots = \
+ QSLOTSFROMBYTES(x->ChannelHeader.Size); \
+ x->cmdQ.MaxSignals = x->cmdQ.MaxSignalSlots - 1; \
+ x->rspQ.Size = QSIZEFROMBYTES(x->ChannelHeader.Size); \
+ x->rspQ.oSignalBase = \
+ (SIZEOF_PROTOCOL + x->cmdQ.Size) - \
+ OFFSETOF(ULTRA_IO_CHANNEL_PROTOCOL, rspQ); \
+ x->rspQ.SignalSize = SIZEOF_CMDRSP; \
+ x->rspQ.MaxSignalSlots = \
+ QSLOTSFROMBYTES(x->ChannelHeader.Size); \
+ x->rspQ.MaxSignals = x->rspQ.MaxSignalSlots - 1; \
+ x->ChannelHeader.oChannelSpace = \
+ OFFSETOF(ULTRA_IO_CHANNEL_PROTOCOL, cmdQ); \
+ } while (0)
+
+#define INIT_CLIENTSTRING(chan, type, clientStr, clientStrLen) \
+ do { \
+ if (clientStr) { \
+ chan->ChannelHeader.oClientString = \
+ OFFSETOF(type, clientString); \
+ MEMCPY(chan->clientString, clientStr, \
+ MINNUM(clientStrLen, \
+ (U32) (MAX_CLIENTSTRING_LEN - 1))); \
+ chan->clientString[MINNUM(clientStrLen, \
+ (U32) (MAX_CLIENTSTRING_LEN \
+ - 1))] \
+ = '\0'; \
+ } \
+ else \
+ if (clientStrLen > 0) \
+ return 0; \
+ } while (0)
+
+
+#define ULTRA_IO_CHANNEL_SERVER_READY(x, chanId, logCtx) \
+ ULTRA_CHANNEL_SERVER_TRANSITION(x, chanId, SrvState, CHANNELSRV_READY, \
+ logCtx);
+
+#define ULTRA_IO_CHANNEL_SERVER_NOTREADY(x, chanId, logCtx) \
+ ULTRA_CHANNEL_SERVER_TRANSITION(x, chanId, SrvState, \
+ CHANNELSRV_UNINITIALIZED, logCtx);
+
+static inline int ULTRA_VHBA_init_channel(ULTRA_IO_CHANNEL_PROTOCOL *x,
+ struct vhba_wwnn *wwnn,
+ struct vhba_config_max *max,
+ unsigned char *clientStr,
+ U32 clientStrLen, U64 bytes) {
+ MEMSET(x, 0, sizeof(ULTRA_IO_CHANNEL_PROTOCOL));
+ x->ChannelHeader.VersionId = ULTRA_VHBA_CHANNEL_PROTOCOL_VERSIONID;
+ x->ChannelHeader.Signature = ULTRA_VHBA_CHANNEL_PROTOCOL_SIGNATURE;
+ x->ChannelHeader.SrvState = CHANNELSRV_UNINITIALIZED;
+ x->ChannelHeader.HeaderSize = sizeof(x->ChannelHeader);
+ x->ChannelHeader.Size = COVER(bytes, 4096);
+ x->ChannelHeader.Type = UltraVhbaChannelProtocolGuid;
+ x->ChannelHeader.ZoneGuid = Guid0;
+ x->vhba.wwnn = *wwnn;
+ x->vhba.max = *max;
+ INIT_CLIENTSTRING(x, ULTRA_IO_CHANNEL_PROTOCOL, clientStr,
+ clientStrLen);
+ SignalQInit(x);
+ if ((x->cmdQ.MaxSignalSlots > MAX_NUMSIGNALS) ||
+ (x->rspQ.MaxSignalSlots > MAX_NUMSIGNALS)) {
+ return 0;
+ }
+ if ((x->cmdQ.MaxSignalSlots < MIN_NUMSIGNALS) ||
+ (x->rspQ.MaxSignalSlots < MIN_NUMSIGNALS)) {
+ return 0;
+ }
+ return 1;
+}
+
+static inline void ULTRA_VHBA_set_max(ULTRA_IO_CHANNEL_PROTOCOL *x,
+ struct vhba_config_max *max) {
+ x->vhba.max = *max;
+}
+
+static inline int ULTRA_VNIC_init_channel(ULTRA_IO_CHANNEL_PROTOCOL *x,
+ unsigned char *macaddr,
+ U32 num_rcv_bufs, U32 mtu,
+ GUID zoneGuid,
+ unsigned char *clientStr,
+ U32 clientStrLen,
+ U64 bytes) {
+ MEMSET(x, 0, sizeof(ULTRA_IO_CHANNEL_PROTOCOL));
+ x->ChannelHeader.VersionId = ULTRA_VNIC_CHANNEL_PROTOCOL_VERSIONID;
+ x->ChannelHeader.Signature = ULTRA_VNIC_CHANNEL_PROTOCOL_SIGNATURE;
+ x->ChannelHeader.SrvState = CHANNELSRV_UNINITIALIZED;
+ x->ChannelHeader.HeaderSize = sizeof(x->ChannelHeader);
+ x->ChannelHeader.Size = COVER(bytes, 4096);
+ x->ChannelHeader.Type = UltraVnicChannelProtocolGuid;
+ x->ChannelHeader.ZoneGuid = Guid0;
+ MEMCPY(x->vnic.macaddr, macaddr, MAX_MACADDR_LEN);
+ x->vnic.num_rcv_bufs = num_rcv_bufs;
+ x->vnic.mtu = mtu;
+ x->vnic.zoneGuid = zoneGuid;
+ INIT_CLIENTSTRING(x, ULTRA_IO_CHANNEL_PROTOCOL, clientStr,
+ clientStrLen);
+ SignalQInit(x);
+ if ((x->cmdQ.MaxSignalSlots > MAX_NUMSIGNALS) ||
+ (x->rspQ.MaxSignalSlots > MAX_NUMSIGNALS)) {
+ return 0;
+ }
+ if ((x->cmdQ.MaxSignalSlots < MIN_NUMSIGNALS) ||
+ (x->rspQ.MaxSignalSlots < MIN_NUMSIGNALS)) {
+ return 0;
+ }
+ return 1;
+}
+
+#endif /* __GNUC__ */
+
+/*
+* INLINE function for expanding a guest's pfn-off-size into multiple 4K page
+* pfn-off-size entires.
+*/
+
+
+/* we deal with 4K page sizes when we it comes to passing page information
+ * between */
+/* Guest and IOPartition. */
+#define PI_PAGE_SIZE 0x1000
+#define PI_PAGE_MASK 0x0FFF
+#define PI_PAGE_SHIFT 12
+
+/* returns next non-zero index on success or zero on failure (i.e. out of
+ * room)
+ */
+static INLINE U16
+add_physinfo_entries(U32 inp_pfn, /* input - specifies the pfn to be used
+ * to add entries */
+ U16 inp_off, /* input - specifies the off to be used
+ * to add entries */
+ U32 inp_len, /* input - specifies the len to be used
+ * to add entries */
+ U16 index, /* input - index in array at which new
+ * entries are added */
+ U16 max_pi_arr_entries, /* input - specifies the maximum
+ * entries pi_arr can hold */
+ struct phys_info pi_arr[]) /* input & output - array to
+ * which entries are added */
+{
+ U32 len;
+ U16 i, firstlen;
+
+ firstlen = PI_PAGE_SIZE - inp_off;
+ if (inp_len <= firstlen) {
+
+ /* the input entry spans only one page - add as is */
+ if (index >= max_pi_arr_entries)
+ return 0;
+ pi_arr[index].pi_pfn = inp_pfn;
+ pi_arr[index].pi_off = (U16) inp_off;
+ pi_arr[index].pi_len = (U16) inp_len;
+ return index + 1;
+ }
+
+ /* this entry spans multiple pages */
+ for (len = inp_len, i = 0; len;
+ len -= pi_arr[index + i].pi_len, i++) {
+ if (index + i >= max_pi_arr_entries)
+ return 0;
+ pi_arr[index + i].pi_pfn = inp_pfn + i;
+ if (i == 0) {
+ pi_arr[index].pi_off = inp_off;
+ pi_arr[index].pi_len = firstlen;
+ }
+
+ else {
+ pi_arr[index + i].pi_off = 0;
+ pi_arr[index + i].pi_len =
+ (U16) MINNUM(len, (U32) PI_PAGE_SIZE);
+ }
+
+ }
+ return index + i;
+}
+
+#endif /* __IOCHANNEL_H__ */
--- /dev/null
+/* 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 __VBUSCHANNEL_H__
+#define __VBUSCHANNEL_H__
+
+/* The vbus channel is the channel area provided via the BUS_CREATE controlvm
+ * message for each virtual bus. This channel area is provided to both server
+ * and client ends of the bus. The channel header area is initialized by
+ * the server, and the remaining information is filled in by the client.
+ * We currently use this for the client to provide various information about
+ * the client devices and client drivers for the server end to see.
+ */
+#include "commontypes.h"
+#include "vbusdeviceinfo.h"
+#include "channel.h"
+
+/* {193b331b-c58f-11da-95a9-00e08161165f} */
+#define ULTRA_VBUS_CHANNEL_PROTOCOL_GUID \
+ {0x193b331b, 0xc58f, 0x11da, \
+ {0x95, 0xa9, 0x0, 0xe0, 0x81, 0x61, 0x16, 0x5f} }
+static const GUID UltraVbusChannelProtocolGuid =
+ ULTRA_VBUS_CHANNEL_PROTOCOL_GUID;
+
+#define ULTRA_VBUS_CHANNEL_PROTOCOL_SIGNATURE ULTRA_CHANNEL_PROTOCOL_SIGNATURE
+
+/* Must increment this whenever you insert or delete fields within this channel
+* struct. Also increment whenever you change the meaning of fields within this
+* channel struct so as to break pre-existing software. Note that you can
+* usually add fields to the END of the channel struct withOUT needing to
+* increment this. */
+#define ULTRA_VBUS_CHANNEL_PROTOCOL_VERSIONID 1
+
+#define ULTRA_VBUS_CHANNEL_OK_CLIENT(pChannel, logCtx) \
+ (ULTRA_check_channel_client(pChannel, \
+ UltraVbusChannelProtocolGuid, \
+ "vbus", \
+ sizeof(ULTRA_VBUS_CHANNEL_PROTOCOL), \
+ ULTRA_VBUS_CHANNEL_PROTOCOL_VERSIONID, \
+ ULTRA_VBUS_CHANNEL_PROTOCOL_SIGNATURE, \
+ __FILE__, __LINE__, logCtx))
+
+#define ULTRA_VBUS_CHANNEL_OK_SERVER(actualBytes, logCtx) \
+ (ULTRA_check_channel_server(UltraVbusChannelProtocolGuid, \
+ "vbus", \
+ sizeof(ULTRA_VBUS_CHANNEL_PROTOCOL), \
+ actualBytes, \
+ __FILE__, __LINE__, logCtx))
+
+
+#pragma pack(push, 1) /* both GCC and VC now allow this pragma */
+typedef struct _ULTRA_VBUS_HEADERINFO {
+ U32 structBytes; /* size of this struct in bytes */
+ U32 deviceInfoStructBytes; /* sizeof(ULTRA_VBUS_DEVICEINFO) */
+ U32 devInfoCount; /* num of items in DevInfo member */
+ /* (this is the allocated size) */
+ U32 chpInfoByteOffset; /* byte offset from beginning of this struct */
+ /* to the the ChpInfo struct (below) */
+ U32 busInfoByteOffset; /* byte offset from beginning of this struct */
+ /* to the the BusInfo struct (below) */
+ U32 devInfoByteOffset; /* byte offset from beginning of this struct */
+ /* to the the DevInfo array (below) */
+ U8 reserved[104];
+} ULTRA_VBUS_HEADERINFO;
+
+typedef struct _ULTRA_VBUS_CHANNEL_PROTOCOL {
+ ULTRA_CHANNEL_PROTOCOL ChannelHeader; /* initialized by server */
+ ULTRA_VBUS_HEADERINFO HdrInfo; /* initialized by server */
+ /* the remainder of this channel is filled in by the client */
+ ULTRA_VBUS_DEVICEINFO ChpInfo; /* describes client chipset device and
+ * driver */
+ ULTRA_VBUS_DEVICEINFO BusInfo; /* describes client bus device and
+ * driver */
+ ULTRA_VBUS_DEVICEINFO DevInfo[0]; /* describes client device and
+ * driver for */
+ /* each device on the bus */
+} ULTRA_VBUS_CHANNEL_PROTOCOL;
+
+#define VBUS_CH_SIZE_EXACT(MAXDEVICES) \
+ (sizeof(ULTRA_VBUS_CHANNEL_PROTOCOL) + ((MAXDEVICES) * \
+ sizeof(ULTRA_VBUS_DEVICEINFO)))
+#define VBUS_CH_SIZE(MAXDEVICES) COVER(VBUS_CH_SIZE_EXACT(MAXDEVICES), 4096)
+
+static INLINE void
+ULTRA_VBUS_init_channel(ULTRA_VBUS_CHANNEL_PROTOCOL *x, int bytesAllocated)
+{
+ /* Please note that the memory at <x> does NOT necessarily have space
+ * for DevInfo structs allocated at the end, which is why we do NOT use
+ * <bytesAllocated> to clear. */
+ MEMSET(x, 0, sizeof(ULTRA_VBUS_CHANNEL_PROTOCOL));
+ if (bytesAllocated < (int) sizeof(ULTRA_VBUS_CHANNEL_PROTOCOL))
+ return;
+ x->ChannelHeader.VersionId = ULTRA_VBUS_CHANNEL_PROTOCOL_VERSIONID;
+ x->ChannelHeader.Signature = ULTRA_VBUS_CHANNEL_PROTOCOL_SIGNATURE;
+ x->ChannelHeader.SrvState = CHANNELSRV_READY;
+ x->ChannelHeader.HeaderSize = sizeof(x->ChannelHeader);
+ x->ChannelHeader.Size = bytesAllocated;
+ x->ChannelHeader.Type = UltraVbusChannelProtocolGuid;
+ x->ChannelHeader.ZoneGuid = Guid0;
+ x->HdrInfo.structBytes = sizeof(ULTRA_VBUS_HEADERINFO);
+ x->HdrInfo.chpInfoByteOffset = sizeof(ULTRA_VBUS_HEADERINFO);
+ x->HdrInfo.busInfoByteOffset = x->HdrInfo.chpInfoByteOffset
+ + sizeof(ULTRA_VBUS_DEVICEINFO);
+ x->HdrInfo.devInfoByteOffset = x->HdrInfo.busInfoByteOffset
+ + sizeof(ULTRA_VBUS_DEVICEINFO);
+ x->HdrInfo.deviceInfoStructBytes = sizeof(ULTRA_VBUS_DEVICEINFO);
+ bytesAllocated -= (sizeof(ULTRA_CHANNEL_PROTOCOL)
+ + x->HdrInfo.devInfoByteOffset);
+ x->HdrInfo.devInfoCount =
+ bytesAllocated / x->HdrInfo.deviceInfoStructBytes;
+}
+
+#pragma pack(pop)
+
+#endif
--- /dev/null
+/* controlvmcompletionstatus.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.
+ */
+
+/* Defines for all valid values returned in the response message header
+ * completionStatus field. See controlvmchannel.h for description of
+ * the header: _CONTROLVM_MESSAGE_HEADER.
+ */
+
+#ifndef __CONTROLVMCOMPLETIONSTATUS_H__
+#define __CONTROLVMCOMPLETIONSTATUS_H__
+
+/* General Errors------------------------------------------------------[0-99] */
+#define CONTROLVM_RESP_SUCCESS 0
+#define CONTROLVM_RESP_ERROR_ALREADY_DONE 1
+#define CONTROLVM_RESP_ERROR_IOREMAP_FAILED 2
+#define CONTROLVM_RESP_ERROR_KMALLOC_FAILED 3
+#define CONTROLVM_RESP_ERROR_MESSAGE_ID_UNKNOWN 4
+#define CONTROLVM_RESP_ERROR_MESSAGE_ID_INVALID_FOR_CLIENT 5
+
+/* CONTROLVM_INIT_CHIPSET-------------------------------------------[100-199] */
+#define CONTROLVM_RESP_ERROR_CLIENT_SWITCHCOUNT_NONZERO 100
+#define CONTROLVM_RESP_ERROR_EXPECTED_CHIPSET_INIT 101
+
+/* Maximum Limit----------------------------------------------------[200-299] */
+#define CONTROLVM_RESP_ERROR_MAX_BUSES 201 /* BUS_CREATE */
+#define CONTROLVM_RESP_ERROR_MAX_DEVICES 202 /* DEVICE_CREATE */
+/* Payload and Parameter Related------------------------------------[400-499] */
+#define CONTROLVM_RESP_ERROR_PAYLOAD_INVALID 400 /* SWITCH_ATTACHEXTPORT,
+ * DEVICE_CONFIGURE */
+#define CONTROLVM_RESP_ERROR_INITIATOR_PARAMETER_INVALID 401 /* Multiple */
+#define CONTROLVM_RESP_ERROR_TARGET_PARAMETER_INVALID 402 /* DEVICE_CONFIGURE */
+#define CONTROLVM_RESP_ERROR_CLIENT_PARAMETER_INVALID 403 /* DEVICE_CONFIGURE */
+/* Specified[Packet Structure] Value-------------------------------[500-599] */
+#define CONTROLVM_RESP_ERROR_BUS_INVALID 500 /* SWITCH_ATTACHINTPORT,
+ * BUS_CONFIGURE,
+ * DEVICE_CREATE,
+ * DEVICE_CONFIG
+ * DEVICE_DESTROY */
+#define CONTROLVM_RESP_ERROR_DEVICE_INVALID 501 /* SWITCH_ATTACHINTPORT */
+ /* DEVICE_CREATE,
+ * DEVICE_CONFIGURE,
+ * DEVICE_DESTROY */
+#define CONTROLVM_RESP_ERROR_CHANNEL_INVALID 502 /* DEVICE_CREATE,
+ * DEVICE_CONFIGURE */
+/* Partition Driver Callback Interface----------------------[600-699] */
+#define CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_FAILURE 604 /* BUS_CREATE,
+ * BUS_DESTROY,
+ * DEVICE_CREATE,
+ * DEVICE_DESTROY */
+/* Unable to invoke VIRTPCI callback */
+#define CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_CALLBACK_ERROR 605 /* BUS_CREATE,
+ * BUS_DESTROY,
+ * DEVICE_CREATE,
+ * DEVICE_DESTROY */
+/* VIRTPCI Callback returned error */
+#define CONTROLVM_RESP_ERROR_GENERIC_DRIVER_CALLBACK_ERROR 606 /* SWITCH_ATTACHEXTPORT,
+ * SWITCH_DETACHEXTPORT
+ * DEVICE_CONFIGURE */
+
+/* generic device callback returned error */
+/* Bus Related------------------------------------------------------[700-799] */
+#define CONTROLVM_RESP_ERROR_BUS_DEVICE_ATTACHED 700 /* BUS_DESTROY */
+/* Channel Related--------------------------------------------------[800-899] */
+#define CONTROLVM_RESP_ERROR_CHANNEL_TYPE_UNKNOWN 800 /* GET_CHANNELINFO,
+ * DEVICE_DESTROY */
+#define CONTROLVM_RESP_ERROR_CHANNEL_SIZE_TOO_SMALL 801 /* DEVICE_CREATE */
+/* Chipset Shutdown Related---------------------------------------[1000-1099] */
+#define CONTROLVM_RESP_ERROR_CHIPSET_SHUTDOWN_FAILED 1000
+#define CONTROLVM_RESP_ERROR_CHIPSET_SHUTDOWN_ALREADY_ACTIVE 1001
+
+/* Chipset Stop Related-------------------------------------------[1100-1199] */
+#define CONTROLVM_RESP_ERROR_CHIPSET_STOP_FAILED_BUS 1100
+#define CONTROLVM_RESP_ERROR_CHIPSET_STOP_FAILED_SWITCH 1101
+
+/* Device Related-------------------------------------------------[1400-1499] */
+#define CONTROLVM_RESP_ERROR_DEVICE_UDEV_TIMEOUT 1400
+
+#endif /* __CONTROLVMCOMPLETIONSTATUS_H__ not defined */
--- /dev/null
+/* 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.
+ */
+
+/* Please note that this file is to be used ONLY for defining diagnostic
+ * subsystem values for the appos (sPAR Linux service partitions) component.
+ */
+#ifndef __APPOS_SUBSYSTEMS_H__
+#define __APPOS_SUBSYSTEMS_H__
+
+#ifdef __KERNEL__
+#include <linux/kernel.h>
+#include <linux/string.h>
+#else
+#include <stdio.h>
+#include <string.h>
+#endif
+
+static inline char *
+subsys_unknown_to_s(int subsys, char *s, int n)
+{
+ snprintf(s, n, "SUBSYS-%-2.2d", subsys);
+ s[n - 1] = '\0';
+ return s;
+}
+
+#define SUBSYS_TO_MASK(subsys) (1ULL << (subsys))
+
+/* The first SUBSYS_APPOS_MAX subsystems are the same for each AppOS type
+ * (IOVM, SMS, etc.) The rest have unique values for each AppOS type.
+ */
+#define SUBSYS_APPOS_MAX 16
+
+#define SUBSYS_APPOS_DEFAULT 1 /* or "other" */
+#define SUBSYS_APPOS_CHIPSET 2 /* controlvm and other */
+ /* low-level sPAR activity */
+#define SUBSYS_APPOS_BUS 3 /* sPAR bus */
+/* DAK #define SUBSYS_APPOS_DIAG 4 // diagnostics and dump */
+#define SUBSYS_APPOS_CHANNELACCESS 5 /* generic channel access */
+#define SUBSYS_APPOS_NICCLIENT 6 /* virtual NIC client */
+#define SUBSYS_APPOS_HBACLIENT 7 /* virtual HBA client */
+#define SUBSYS_APPOS_CONSOLESERIAL 8 /* sPAR virtual serial console */
+#define SUBSYS_APPOS_UISLIB 9 /* */
+#define SUBSYS_APPOS_VRTCUPDD 10 /* */
+#define SUBSYS_APPOS_WATCHDOG 11 /* watchdog timer and healthcheck */
+#define SUBSYS_APPOS_13 13 /* available */
+#define SUBSYS_APPOS_14 14 /* available */
+#define SUBSYS_APPOS_15 15 /* available */
+#define SUBSYS_APPOS_16 16 /* available */
+static inline char *
+subsys_generic_to_s(int subsys, char *s, int n)
+{
+ switch (subsys) {
+ case SUBSYS_APPOS_DEFAULT:
+ strncpy(s, "APPOS_DEFAULT", n);
+ break;
+ case SUBSYS_APPOS_CHIPSET:
+ strncpy(s, "APPOS_CHIPSET", n);
+ break;
+ case SUBSYS_APPOS_BUS:
+ strncpy(s, "APPOS_BUS", n);
+ break;
+ case SUBSYS_APPOS_CHANNELACCESS:
+ strncpy(s, "APPOS_CHANNELACCESS", n);
+ break;
+ case SUBSYS_APPOS_NICCLIENT:
+ strncpy(s, "APPOS_NICCLIENT", n);
+ break;
+ case SUBSYS_APPOS_HBACLIENT:
+ strncpy(s, "APPOS_HBACLIENT", n);
+ break;
+ case SUBSYS_APPOS_CONSOLESERIAL:
+ strncpy(s, "APPOS_CONSOLESERIAL", n);
+ break;
+ case SUBSYS_APPOS_UISLIB:
+ strncpy(s, "APPOS_UISLIB", n);
+ break;
+ case SUBSYS_APPOS_VRTCUPDD:
+ strncpy(s, "APPOS_VRTCUPDD", n);
+ break;
+ case SUBSYS_APPOS_WATCHDOG:
+ strncpy(s, "APPOS_WATCHDOG", n);
+ break;
+ case SUBSYS_APPOS_13:
+ strncpy(s, "APPOS_13", n);
+ break;
+ case SUBSYS_APPOS_14:
+ strncpy(s, "APPOS_14", n);
+ break;
+ case SUBSYS_APPOS_15:
+ strncpy(s, "APPOS_15", n);
+ break;
+ case SUBSYS_APPOS_16:
+ strncpy(s, "APPOS_16", n);
+ break;
+ default:
+ subsys_unknown_to_s(subsys, s, n);
+ break;
+ }
+ s[n - 1] = '\0';
+ return s;
+}
+
+/* CONSOLE */
+
+#define SUBSYS_CONSOLE_VIDEO (SUBSYS_APPOS_MAX + 1) /* 17 */
+#define SUBSYS_CONSOLE_KBDMOU (SUBSYS_APPOS_MAX + 2) /* 18 */
+#define SUBSYS_CONSOLE_04 (SUBSYS_APPOS_MAX + 4)
+#define SUBSYS_CONSOLE_05 (SUBSYS_APPOS_MAX + 5)
+#define SUBSYS_CONSOLE_06 (SUBSYS_APPOS_MAX + 6)
+#define SUBSYS_CONSOLE_07 (SUBSYS_APPOS_MAX + 7)
+#define SUBSYS_CONSOLE_08 (SUBSYS_APPOS_MAX + 8)
+#define SUBSYS_CONSOLE_09 (SUBSYS_APPOS_MAX + 9)
+#define SUBSYS_CONSOLE_10 (SUBSYS_APPOS_MAX + 10)
+#define SUBSYS_CONSOLE_11 (SUBSYS_APPOS_MAX + 11)
+#define SUBSYS_CONSOLE_12 (SUBSYS_APPOS_MAX + 12)
+#define SUBSYS_CONSOLE_13 (SUBSYS_APPOS_MAX + 13)
+#define SUBSYS_CONSOLE_14 (SUBSYS_APPOS_MAX + 14)
+#define SUBSYS_CONSOLE_15 (SUBSYS_APPOS_MAX + 15)
+#define SUBSYS_CONSOLE_16 (SUBSYS_APPOS_MAX + 16)
+#define SUBSYS_CONSOLE_17 (SUBSYS_APPOS_MAX + 17)
+#define SUBSYS_CONSOLE_18 (SUBSYS_APPOS_MAX + 18)
+#define SUBSYS_CONSOLE_19 (SUBSYS_APPOS_MAX + 19)
+#define SUBSYS_CONSOLE_20 (SUBSYS_APPOS_MAX + 20)
+#define SUBSYS_CONSOLE_21 (SUBSYS_APPOS_MAX + 21)
+#define SUBSYS_CONSOLE_22 (SUBSYS_APPOS_MAX + 22)
+#define SUBSYS_CONSOLE_23 (SUBSYS_APPOS_MAX + 23)
+#define SUBSYS_CONSOLE_24 (SUBSYS_APPOS_MAX + 24)
+#define SUBSYS_CONSOLE_25 (SUBSYS_APPOS_MAX + 25)
+#define SUBSYS_CONSOLE_26 (SUBSYS_APPOS_MAX + 26)
+#define SUBSYS_CONSOLE_27 (SUBSYS_APPOS_MAX + 27)
+#define SUBSYS_CONSOLE_28 (SUBSYS_APPOS_MAX + 28)
+#define SUBSYS_CONSOLE_29 (SUBSYS_APPOS_MAX + 29)
+#define SUBSYS_CONSOLE_30 (SUBSYS_APPOS_MAX + 30)
+#define SUBSYS_CONSOLE_31 (SUBSYS_APPOS_MAX + 31)
+#define SUBSYS_CONSOLE_32 (SUBSYS_APPOS_MAX + 32)
+#define SUBSYS_CONSOLE_33 (SUBSYS_APPOS_MAX + 33)
+#define SUBSYS_CONSOLE_34 (SUBSYS_APPOS_MAX + 34)
+#define SUBSYS_CONSOLE_35 (SUBSYS_APPOS_MAX + 35)
+#define SUBSYS_CONSOLE_36 (SUBSYS_APPOS_MAX + 36)
+#define SUBSYS_CONSOLE_37 (SUBSYS_APPOS_MAX + 37)
+#define SUBSYS_CONSOLE_38 (SUBSYS_APPOS_MAX + 38)
+#define SUBSYS_CONSOLE_39 (SUBSYS_APPOS_MAX + 39)
+#define SUBSYS_CONSOLE_40 (SUBSYS_APPOS_MAX + 40)
+#define SUBSYS_CONSOLE_41 (SUBSYS_APPOS_MAX + 41)
+#define SUBSYS_CONSOLE_42 (SUBSYS_APPOS_MAX + 42)
+#define SUBSYS_CONSOLE_43 (SUBSYS_APPOS_MAX + 43)
+#define SUBSYS_CONSOLE_44 (SUBSYS_APPOS_MAX + 44)
+#define SUBSYS_CONSOLE_45 (SUBSYS_APPOS_MAX + 45)
+#define SUBSYS_CONSOLE_46 (SUBSYS_APPOS_MAX + 46)
+
+static inline char *
+subsys_console_to_s(int subsys, char *s, int n)
+{
+ switch (subsys) {
+ case SUBSYS_CONSOLE_VIDEO:
+ strncpy(s, "CONSOLE_VIDEO", n);
+ break;
+ case SUBSYS_CONSOLE_KBDMOU:
+ strncpy(s, "CONSOLE_KBDMOU", n);
+ break;
+ case SUBSYS_CONSOLE_04:
+ strncpy(s, "CONSOLE_04", n);
+ break;
+ case SUBSYS_CONSOLE_05:
+ strncpy(s, "CONSOLE_05", n);
+ break;
+ case SUBSYS_CONSOLE_06:
+ strncpy(s, "CONSOLE_06", n);
+ break;
+ case SUBSYS_CONSOLE_07:
+ strncpy(s, "CONSOLE_07", n);
+ break;
+ case SUBSYS_CONSOLE_08:
+ strncpy(s, "CONSOLE_08", n);
+ break;
+ case SUBSYS_CONSOLE_09:
+ strncpy(s, "CONSOLE_09", n);
+ break;
+ case SUBSYS_CONSOLE_10:
+ strncpy(s, "CONSOLE_10", n);
+ break;
+ case SUBSYS_CONSOLE_11:
+ strncpy(s, "CONSOLE_11", n);
+ break;
+ case SUBSYS_CONSOLE_12:
+ strncpy(s, "CONSOLE_12", n);
+ break;
+ case SUBSYS_CONSOLE_13:
+ strncpy(s, "CONSOLE_13", n);
+ break;
+ case SUBSYS_CONSOLE_14:
+ strncpy(s, "CONSOLE_14", n);
+ break;
+ case SUBSYS_CONSOLE_15:
+ strncpy(s, "CONSOLE_15", n);
+ break;
+ case SUBSYS_CONSOLE_16:
+ strncpy(s, "CONSOLE_16", n);
+ break;
+ case SUBSYS_CONSOLE_17:
+ strncpy(s, "CONSOLE_17", n);
+ break;
+ case SUBSYS_CONSOLE_18:
+ strncpy(s, "CONSOLE_18", n);
+ break;
+ case SUBSYS_CONSOLE_19:
+ strncpy(s, "CONSOLE_19", n);
+ break;
+ case SUBSYS_CONSOLE_20:
+ strncpy(s, "CONSOLE_20", n);
+ break;
+ case SUBSYS_CONSOLE_21:
+ strncpy(s, "CONSOLE_21", n);
+ break;
+ case SUBSYS_CONSOLE_22:
+ strncpy(s, "CONSOLE_22", n);
+ break;
+ case SUBSYS_CONSOLE_23:
+ strncpy(s, "CONSOLE_23", n);
+ break;
+ case SUBSYS_CONSOLE_24:
+ strncpy(s, "CONSOLE_24", n);
+ break;
+ case SUBSYS_CONSOLE_25:
+ strncpy(s, "CONSOLE_25", n);
+ break;
+ case SUBSYS_CONSOLE_26:
+ strncpy(s, "CONSOLE_26", n);
+ break;
+ case SUBSYS_CONSOLE_27:
+ strncpy(s, "CONSOLE_27", n);
+ break;
+ case SUBSYS_CONSOLE_28:
+ strncpy(s, "CONSOLE_28", n);
+ break;
+ case SUBSYS_CONSOLE_29:
+ strncpy(s, "CONSOLE_29", n);
+ break;
+ case SUBSYS_CONSOLE_30:
+ strncpy(s, "CONSOLE_30", n);
+ break;
+ case SUBSYS_CONSOLE_31:
+ strncpy(s, "CONSOLE_31", n);
+ break;
+ case SUBSYS_CONSOLE_32:
+ strncpy(s, "CONSOLE_32", n);
+ break;
+ case SUBSYS_CONSOLE_33:
+ strncpy(s, "CONSOLE_33", n);
+ break;
+ case SUBSYS_CONSOLE_34:
+ strncpy(s, "CONSOLE_34", n);
+ break;
+ case SUBSYS_CONSOLE_35:
+ strncpy(s, "CONSOLE_35", n);
+ break;
+ case SUBSYS_CONSOLE_36:
+ strncpy(s, "CONSOLE_36", n);
+ break;
+ case SUBSYS_CONSOLE_37:
+ strncpy(s, "CONSOLE_37", n);
+ break;
+ case SUBSYS_CONSOLE_38:
+ strncpy(s, "CONSOLE_38", n);
+ break;
+ case SUBSYS_CONSOLE_39:
+ strncpy(s, "CONSOLE_39", n);
+ break;
+ case SUBSYS_CONSOLE_40:
+ strncpy(s, "CONSOLE_40", n);
+ break;
+ case SUBSYS_CONSOLE_41:
+ strncpy(s, "CONSOLE_41", n);
+ break;
+ case SUBSYS_CONSOLE_42:
+ strncpy(s, "CONSOLE_42", n);
+ break;
+ case SUBSYS_CONSOLE_43:
+ strncpy(s, "CONSOLE_43", n);
+ break;
+ case SUBSYS_CONSOLE_44:
+ strncpy(s, "CONSOLE_44", n);
+ break;
+ case SUBSYS_CONSOLE_45:
+ strncpy(s, "CONSOLE_45", n);
+ break;
+ case SUBSYS_CONSOLE_46:
+ strncpy(s, "CONSOLE_46", n);
+ break;
+ default:
+ subsys_unknown_to_s(subsys, s, n);
+ break;
+ }
+ s[n - 1] = '\0';
+ return s;
+}
+
+#endif
--- /dev/null
+/* 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.
+ */
+
+/* Linux GCC Version (32-bit and 64-bit) */
+static inline unsigned long
+__unisys_vmcall_gnuc(unsigned long tuple, unsigned long reg_ebx,
+ unsigned long reg_ecx)
+{
+ unsigned long result = 0;
+
+ unsigned int cpuid_eax, cpuid_ebx, cpuid_ecx, cpuid_edx;
+ cpuid(0x00000001, &cpuid_eax, &cpuid_ebx, &cpuid_ecx, &cpuid_edx);
+ if (cpuid_ecx & 0x80000000) {
+ __asm__ __volatile__(".byte 0x00f, 0x001, 0x0c1" : "=a"(result) :
+ "a"(tuple), "b"(reg_ebx), "c"(reg_ecx)
+ );
+ } else {
+ result = -1;
+ }
+ return result;
+}
+
+static inline unsigned long
+__unisys_extended_vmcall_gnuc(unsigned long long tuple,
+ unsigned long long reg_ebx,
+ unsigned long long reg_ecx,
+ unsigned long long reg_edx)
+{
+ unsigned long result = 0;
+
+ unsigned int cpuid_eax, cpuid_ebx, cpuid_ecx, cpuid_edx;
+ cpuid(0x00000001, &cpuid_eax, &cpuid_ebx, &cpuid_ecx, &cpuid_edx);
+ if (cpuid_ecx & 0x80000000) {
+ __asm__ __volatile__(".byte 0x00f, 0x001, 0x0c1" : "=a"(result) :
+ "a"(tuple), "b"(reg_ebx), "c"(reg_ecx),
+ "d"(reg_edx));
+ } else {
+ result = -1;
+ }
+ return result;
+ }
--- /dev/null
+/* 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 __VBUSDEVICEINFO_H__
+#define __VBUSDEVICEINFO_H__
+
+#include "commontypes.h"
+
+#pragma pack(push, 1) /* both GCC and VC now allow this pragma */
+
+/* An array of this struct is present in the channel area for each vbus.
+ * (See vbuschannel.h.)
+ * It is filled in by the client side to provide info about the device
+ * and driver from the client's perspective.
+ */
+typedef struct _ULTRA_VBUS_DEVICEINFO {
+ U8 devType[16]; /* short string identifying the device type */
+ U8 drvName[16]; /* driver .sys file name */
+ U8 infoStrings[96]; /* sequence of tab-delimited id strings: */
+ /* <DRIVER_REV> <DRIVER_VERTAG> <DRIVER_COMPILETIME> */
+ U8 reserved[128]; /* pad size to 256 bytes */
+} ULTRA_VBUS_DEVICEINFO;
+
+#pragma pack(pop)
+
+/* Reads chars from the buffer at <src> for <srcmax> bytes, and writes to
+ * the buffer at <p>, which is <remain> bytes long, ensuring never to
+ * overflow the buffer at <p>, using the following rules:
+ * - printable characters are simply copied from the buffer at <src> to the
+ * buffer at <p>
+ * - intervening streaks of non-printable characters in the buffer at <src>
+ * are replaced with a single space in the buffer at <p>
+ * Note that we pay no attention to '\0'-termination.
+ * Returns the number of bytes written to <p>.
+ *
+ * Pass <p> == NULL and <remain> == 0 for this special behavior. In this
+ * case, we simply return the number of bytes that WOULD HAVE been written
+ * to a buffer at <p>, had it been infinitely big.
+ */
+static inline int
+VBUSCHANNEL_sanitize_buffer(char *p, int remain, char *src, int srcmax)
+{
+ int chars = 0;
+ int nonprintable_streak = 0;
+ while (srcmax > 0) {
+ if ((*src >= ' ') && (*src < 0x7f)) {
+ if (nonprintable_streak) {
+ if (remain > 0) {
+ *p = ' ';
+ p++;
+ remain--;
+ chars++;
+ } else if (p == NULL)
+ chars++;
+ nonprintable_streak = 0;
+ }
+ if (remain > 0) {
+ *p = *src;
+ p++;
+ remain--;
+ chars++;
+ } else if (p == NULL)
+ chars++;
+ } else
+ nonprintable_streak = 1;
+ src++;
+ srcmax--;
+ }
+ return chars;
+}
+
+#define VBUSCHANNEL_ADDACHAR(ch, p, remain, chars) \
+ do { \
+ if (remain <= 0) \
+ break; \
+ *p = ch; \
+ p++; chars++; remain--; \
+ } while (0)
+
+/* Converts the non-negative value at <num> to an ascii decimal string
+ * at <p>, writing at most <remain> bytes. Note there is NO '\0' termination
+ * written to <p>.
+ *
+ * Returns the number of bytes written to <p>.
+ *
+ * Note that we create this function because we need to do this operation in
+ * an environment-independent way (since we are in a common header file).
+ */
+static inline int
+VBUSCHANNEL_itoa(char *p, int remain, int num)
+{
+ int digits = 0;
+ char s[32];
+ int i;
+
+ if (num == 0) {
+ /* '0' is a special case */
+ if (remain <= 0)
+ return 0;
+ *p = '0';
+ return 1;
+ }
+ /* form a backwards decimal ascii string in <s> */
+ while (num > 0) {
+ if (digits >= (int) sizeof(s))
+ return 0;
+ s[digits++] = (num % 10) + '0';
+ num = num / 10;
+ }
+ if (remain < digits) {
+ /* not enough room left at <p> to hold number, so fill with
+ * '?' */
+ for (i = 0; i < remain; i++, p++)
+ *p = '?';
+ return remain;
+ }
+ /* plug in the decimal ascii string representing the number, by */
+ /* reversing the string we just built in <s> */
+ i = digits;
+ while (i > 0) {
+ i--;
+ *p = s[i];
+ p++;
+ }
+ return digits;
+}
+
+/* Reads <devInfo>, and converts its contents to a printable string at <p>,
+ * writing at most <remain> bytes. Note there is NO '\0' termination
+ * written to <p>.
+ *
+ * Pass <devix> >= 0 if you want a device index presented.
+ *
+ * Returns the number of bytes written to <p>.
+ */
+static inline int
+VBUSCHANNEL_devInfoToStringBuffer(ULTRA_VBUS_DEVICEINFO devInfo,
+ char *p, int remain, int devix)
+{
+ char *psrc;
+ int nsrc, x, i, pad;
+ int chars = 0;
+
+ psrc = &(devInfo.devType[0]);
+ nsrc = sizeof(devInfo.devType);
+ if (VBUSCHANNEL_sanitize_buffer(NULL, 0, psrc, nsrc) <= 0)
+ return 0;
+
+ /* emit device index */
+ if (devix >= 0) {
+ VBUSCHANNEL_ADDACHAR('[', p, remain, chars);
+ x = VBUSCHANNEL_itoa(p, remain, devix);
+ p += x;
+ remain -= x;
+ chars += x;
+ VBUSCHANNEL_ADDACHAR(']', p, remain, chars);
+ } else {
+ VBUSCHANNEL_ADDACHAR(' ', p, remain, chars);
+ VBUSCHANNEL_ADDACHAR(' ', p, remain, chars);
+ VBUSCHANNEL_ADDACHAR(' ', p, remain, chars);
+ }
+
+ /* emit device type */
+ x = VBUSCHANNEL_sanitize_buffer(p, remain, psrc, nsrc);
+ p += x;
+ remain -= x;
+ chars += x;
+ pad = 15 - x; /* pad device type to be exactly 15 chars */
+ for (i = 0; i < pad; i++)
+ VBUSCHANNEL_ADDACHAR(' ', p, remain, chars);
+ VBUSCHANNEL_ADDACHAR(' ', p, remain, chars);
+
+ /* emit driver name */
+ psrc = &(devInfo.drvName[0]);
+ nsrc = sizeof(devInfo.drvName);
+ x = VBUSCHANNEL_sanitize_buffer(p, remain, psrc, nsrc);
+ p += x;
+ remain -= x;
+ chars += x;
+ pad = 15 - x; /* pad driver name to be exactly 15 chars */
+ for (i = 0; i < pad; i++)
+ VBUSCHANNEL_ADDACHAR(' ', p, remain, chars);
+ VBUSCHANNEL_ADDACHAR(' ', p, remain, chars);
+
+ /* emit strings */
+ psrc = &(devInfo.infoStrings[0]);
+ nsrc = sizeof(devInfo.infoStrings);
+ x = VBUSCHANNEL_sanitize_buffer(p, remain, psrc, nsrc);
+ p += x;
+ remain -= x;
+ chars += x;
+ VBUSCHANNEL_ADDACHAR('\n', p, remain, chars);
+
+ return chars;
+}
+
+#endif
--- /dev/null
+/* 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 __IOMONINTF_H__
+#define __IOMONINTF_H__
+
+/*
+* This file contains all structures needed to support the VMCALLs for IO
+* Virtualization. The VMCALLs are provided by Monitor and used by IO code
+* running on IO Partitions.
+*/
+
+#ifdef __GNUC__
+#include "iovmcall_gnuc.h"
+#endif /* */
+#include "diagchannel.h"
+
+#ifdef VMCALL_IO_CONTROLVM_ADDR
+#undef VMCALL_IO_CONTROLVM_ADDR
+#endif /* */
+
+/* define subsystem number for AppOS, used in uislib driver */
+#define MDS_APPOS 0x4000000000000000 /* subsystem = 62 - AppOS */
+typedef enum { /* VMCALL identification tuples */
+ /* Note: when a new VMCALL is added:
+ * - the 1st 2 hex digits correspond to one of the
+ * VMCALL_MONITOR_INTERFACE types and
+ * - the next 2 hex digits are the nth relative instance of within a
+ * type
+ * E.G. for VMCALL_VIRTPART_RECYCLE_PART,
+ * - the 0x02 identifies it as a VMCALL_VIRTPART type and
+ * - the 0x01 identifies it as the 1st instance of a VMCALL_VIRTPART
+ * type of VMCALL
+ */
+
+ VMCALL_IO_CONTROLVM_ADDR = 0x0501, /* used by all Guests, not just
+ * IO */
+ VMCALL_IO_DIAG_ADDR = 0x0508,
+ VMCALL_IO_VISORSERIAL_ADDR = 0x0509,
+ VMCALL_QUERY_GUEST_VIRTUAL_TIME_OFFSET = 0x0708, /* Allow caller to
+ * query virtual time
+ * offset */
+ VMCALL_CHANNEL_VERSION_MISMATCH = 0x0709,
+ VMCALL_POST_CODE_LOGEVENT = 0x070B, /* LOGEVENT Post Code (RDX) with
+ * specified subsystem mask (RCX
+ * - monitor_subsystems.h) and
+ * severity (RDX) */
+ VMCALL_GENERIC_SURRENDER_QUANTUM_FOREVER = 0x0802, /* Yield the
+ * remainder & all
+ * future quantums of
+ * the caller */
+ VMCALL_MEASUREMENT_DO_NOTHING = 0x0901,
+ VMCALL_UPDATE_PHYSICAL_TIME = 0x0a02 /* Allow
+ * ULTRA_SERVICE_CAPABILITY_TIME
+ * capable guest to make
+ * VMCALL */
+} VMCALL_MONITOR_INTERFACE_METHOD_TUPLE;
+
+#define VMCALL_SUCCESS 0
+#define VMCALL_SUCCESSFUL(result) (result == 0)
+
+#ifdef __GNUC__
+#define unisys_vmcall(tuple, reg_ebx, reg_ecx) \
+ __unisys_vmcall_gnuc(tuple, reg_ebx, reg_ecx)
+#define unisys_extended_vmcall(tuple, reg_ebx, reg_ecx, reg_edx) \
+ __unisys_extended_vmcall_gnuc(tuple, reg_ebx, reg_ecx, reg_edx)
+#define ISSUE_IO_VMCALL(InterfaceMethod, param, result) \
+ (result = unisys_vmcall(InterfaceMethod, (param) & 0xFFFFFFFF, \
+ (param) >> 32))
+#define ISSUE_IO_EXTENDED_VMCALL(InterfaceMethod, param1, param2, \
+ param3, result) \
+ (result = unisys_extended_vmcall(InterfaceMethod, param1, \
+ param2, param3))
+
+ /* The following uses VMCALL_POST_CODE_LOGEVENT interface but is currently
+ * not used much */
+#define ISSUE_IO_VMCALL_POSTCODE_SEVERITY(postcode, severity) \
+do { \
+ U32 _tempresult = VMCALL_SUCCESS; \
+ ISSUE_IO_EXTENDED_VMCALL(VMCALL_POST_CODE_LOGEVENT, severity, \
+ MDS_APPOS, postcode, _tempresult); \
+} while (0)
+#endif
+
+/* Structures for IO VMCALLs */
+
+/* ///////////// BEGIN PRAGMA PACK PUSH 1 ///////////////////////// */
+/* ///////////// ONLY STRUCT TYPE SHOULD BE BELOW */
+#pragma pack(push, 1)
+struct phys_info {
+ U64 pi_pfn;
+ U16 pi_off;
+ U16 pi_len;
+};
+
+#pragma pack(pop)
+/* ///////////// END PRAGMA PACK PUSH 1 /////////////////////////// */
+typedef struct phys_info IO_DATA_STRUCTURE;
+
+/* ///////////// BEGIN PRAGMA PACK PUSH 1 ///////////////////////// */
+/* ///////////// ONLY STRUCT TYPE SHOULD BE BELOW */
+#pragma pack(push, 1)
+/* Parameters to VMCALL_IO_CONTROLVM_ADDR interface */
+typedef struct _VMCALL_IO_CONTROLVM_ADDR_PARAMS {
+ /* The Guest-relative physical address of the ControlVm channel.
+ * This VMCall fills this in with the appropriate address. */
+ U64 ChannelAddress; /* contents provided by this VMCALL (OUT) */
+ /* the size of the ControlVm channel in bytes This VMCall fills this
+ * in with the appropriate address. */
+ U32 ChannelBytes; /* contents provided by this VMCALL (OUT) */
+ U8 Unused[4]; /* Unused Bytes in the 64-Bit Aligned Struct */
+} VMCALL_IO_CONTROLVM_ADDR_PARAMS;
+
+#pragma pack(pop)
+/* ///////////// END PRAGMA PACK PUSH 1 /////////////////////////// */
+
+/* ///////////// BEGIN PRAGMA PACK PUSH 1 ///////////////////////// */
+/* ///////////// ONLY STRUCT TYPE SHOULD BE BELOW */
+#pragma pack(push, 1)
+/* Parameters to VMCALL_IO_DIAG_ADDR interface */
+typedef struct _VMCALL_IO_DIAG_ADDR_PARAMS {
+ /* The Guest-relative physical address of the diagnostic channel.
+ * This VMCall fills this in with the appropriate address. */
+ U64 ChannelAddress; /* contents provided by this VMCALL (OUT) */
+} VMCALL_IO_DIAG_ADDR_PARAMS;
+
+#pragma pack(pop)
+/* ///////////// END PRAGMA PACK PUSH 1 /////////////////////////// */
+
+/* ///////////// BEGIN PRAGMA PACK PUSH 1 ///////////////////////// */
+/* ///////////// ONLY STRUCT TYPE SHOULD BE BELOW */
+#pragma pack(push, 1)
+/* Parameters to VMCALL_IO_VISORSERIAL_ADDR interface */
+typedef struct _VMCALL_IO_VISORSERIAL_ADDR_PARAMS {
+ /* The Guest-relative physical address of the serial console
+ * channel. This VMCall fills this in with the appropriate
+ * address. */
+ U64 ChannelAddress; /* contents provided by this VMCALL (OUT) */
+} VMCALL_IO_VISORSERIAL_ADDR_PARAMS;
+
+#pragma pack(pop)
+/* ///////////// END PRAGMA PACK PUSH 1 /////////////////////////// */
+
+/* Parameters to VMCALL_CHANNEL_MISMATCH interface */
+typedef struct _VMCALL_CHANNEL_VERSION_MISMATCH_PARAMS {
+ U8 ChannelName[32]; /* Null terminated string giving name of channel
+ * (IN) */
+ U8 ItemName[32]; /* Null terminated string giving name of
+ * mismatched item (IN) */
+ U32 SourceLineNumber; /* line# where invoked. (IN) */
+ U8 SourceFileName[36]; /* source code where invoked - Null terminated
+ * string (IN) */
+} VMCALL_CHANNEL_VERSION_MISMATCH_PARAMS;
+
+#endif /* __IOMONINTF_H__ */
--- /dev/null
+/* 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 __GUESTLINUXDEBUG_H__
+#define __GUESTLINUXDEBUG_H__
+
+/*
+* This file contains supporting interface for "vmcallinterface.h", particuarly
+* regarding adding additional structure and functionality to linux
+* ISSUE_IO_VMCALL_POSTCODE_SEVERITY */
+
+
+/******* INFO ON ISSUE_POSTCODE_LINUX() BELOW *******/
+#include "vmcallinterface.h"
+typedef enum { /* POSTCODE driver identifier tuples */
+ /* visorchipset driver files */
+ VISOR_CHIPSET_PC = 0xA0,
+ VISOR_CHIPSET_PC_controlvm_c = 0xA1,
+ VISOR_CHIPSET_PC_controlvm_cm2 = 0xA2,
+ VISOR_CHIPSET_PC_controlvm_direct_c = 0xA3,
+ VISOR_CHIPSET_PC_file_c = 0xA4,
+ VISOR_CHIPSET_PC_parser_c = 0xA5,
+ VISOR_CHIPSET_PC_testing_c = 0xA6,
+ VISOR_CHIPSET_PC_visorchipset_main_c = 0xA7,
+ VISOR_CHIPSET_PC_visorswitchbus_c = 0xA8,
+ /* visorbus driver files */
+ VISOR_BUS_PC = 0xB0,
+ VISOR_BUS_PC_businst_attr_c = 0xB1,
+ VISOR_BUS_PC_channel_attr_c = 0xB2,
+ VISOR_BUS_PC_devmajorminor_attr_c = 0xB3,
+ VISOR_BUS_PC_visorbus_main_c = 0xB4,
+ /* visorclientbus driver files */
+ VISOR_CLIENT_BUS_PC = 0xC0,
+ VISOR_CLIENT_BUS_PC_visorclientbus_main_c = 0xC1,
+ /* virt hba driver files */
+ VIRT_HBA_PC = 0xC2,
+ VIRT_HBA_PC_virthba_c = 0xC3,
+ /* virtpci driver files */
+ VIRT_PCI_PC = 0xC4,
+ VIRT_PCI_PC_virtpci_c = 0xC5,
+ /* virtnic driver files */
+ VIRT_NIC_PC = 0xC6,
+ VIRT_NIC_P_virtnic_c = 0xC7,
+ /* uislib driver files */
+ UISLIB_PC = 0xD0,
+ UISLIB_PC_uislib_c = 0xD1,
+ UISLIB_PC_uisqueue_c = 0xD2,
+ UISLIB_PC_uisthread_c = 0xD3,
+ UISLIB_PC_uisutils_c = 0xD4,
+} DRIVER_PC;
+
+typedef enum { /* POSTCODE event identifier tuples */
+ ATTACH_PORT_ENTRY_PC = 0x001,
+ ATTACH_PORT_FAILURE_PC = 0x002,
+ ATTACH_PORT_SUCCESS_PC = 0x003,
+ BUS_FAILURE_PC = 0x004,
+ BUS_CREATE_ENTRY_PC = 0x005,
+ BUS_CREATE_FAILURE_PC = 0x006,
+ BUS_CREATE_EXIT_PC = 0x007,
+ BUS_CONFIGURE_ENTRY_PC = 0x008,
+ BUS_CONFIGURE_FAILURE_PC = 0x009,
+ BUS_CONFIGURE_EXIT_PC = 0x00A,
+ CHIPSET_INIT_ENTRY_PC = 0x00B,
+ CHIPSET_INIT_SUCCESS_PC = 0x00C,
+ CHIPSET_INIT_FAILURE_PC = 0x00D,
+ CHIPSET_INIT_EXIT_PC = 0x00E,
+ CREATE_WORKQUEUE_PC = 0x00F,
+ CREATE_WORKQUEUE_FAILED_PC = 0x0A0,
+ CONTROLVM_INIT_FAILURE_PC = 0x0A1,
+ DEVICE_CREATE_ENTRY_PC = 0x0A2,
+ DEVICE_CREATE_FAILURE_PC = 0x0A3,
+ DEVICE_CREATE_SUCCESS_PC = 0x0A4,
+ DEVICE_CREATE_EXIT_PC = 0x0A5,
+ DEVICE_ADD_PC = 0x0A6,
+ DEVICE_REGISTER_FAILURE_PC = 0x0A7,
+ DEVICE_CHANGESTATE_ENTRY_PC = 0x0A8,
+ DEVICE_CHANGESTATE_FAILURE_PC = 0x0A9,
+ DEVICE_CHANGESTATE_EXIT_PC = 0x0AA,
+ DRIVER_ENTRY_PC = 0x0AB,
+ DRIVER_EXIT_PC = 0x0AC,
+ MALLOC_FAILURE_PC = 0x0AD,
+ QUEUE_DELAYED_WORK_PC = 0x0AE,
+ UISLIB_THREAD_FAILURE_PC = 0x0B7,
+ VBUS_CHANNEL_ENTRY_PC = 0x0B8,
+ VBUS_CHANNEL_FAILURE_PC = 0x0B9,
+ VBUS_CHANNEL_EXIT_PC = 0x0BA,
+ VHBA_CREATE_ENTRY_PC = 0x0BB,
+ VHBA_CREATE_FAILURE_PC = 0x0BC,
+ VHBA_CREATE_EXIT_PC = 0x0BD,
+ VHBA_CREATE_SUCCESS_PC = 0x0BE,
+ VHBA_COMMAND_HANDLER_PC = 0x0BF,
+ VHBA_PROBE_ENTRY_PC = 0x0C0,
+ VHBA_PROBE_FAILURE_PC = 0x0C1,
+ VHBA_PROBE_EXIT_PC = 0x0C2,
+ VNIC_CREATE_ENTRY_PC = 0x0C3,
+ VNIC_CREATE_FAILURE_PC = 0x0C4,
+ VNIC_CREATE_SUCCESS_PC = 0x0C5,
+ VNIC_PROBE_ENTRY_PC = 0x0C6,
+ VNIC_PROBE_FAILURE_PC = 0x0C7,
+ VNIC_PROBE_EXIT_PC = 0x0C8,
+ VPCI_CREATE_ENTRY_PC = 0x0C9,
+ VPCI_CREATE_FAILURE_PC = 0x0CA,
+ VPCI_CREATE_EXIT_PC = 0x0CB,
+ VPCI_PROBE_ENTRY_PC = 0x0CC,
+ VPCI_PROBE_FAILURE_PC = 0x0CD,
+ VPCI_PROBE_EXIT_PC = 0x0CE,
+ CRASH_DEV_ENTRY_PC = 0x0CF,
+ CRASH_DEV_EXIT_PC = 0x0D0,
+ CRASH_DEV_HADDR_NULL = 0x0D1,
+ CRASH_DEV_CONTROLVM_NULL = 0x0D2,
+ CRASH_DEV_RD_BUS_FAIULRE_PC = 0x0D3,
+ CRASH_DEV_RD_DEV_FAIULRE_PC = 0x0D4,
+ CRASH_DEV_BUS_NULL_FAILURE_PC = 0x0D5,
+ CRASH_DEV_DEV_NULL_FAILURE_PC = 0x0D6,
+ CRASH_DEV_CTRL_RD_FAILURE_PC = 0x0D7,
+ CRASH_DEV_COUNT_FAILURE_PC = 0x0D8,
+ SAVE_MSG_BUS_FAILURE_PC = 0x0D9,
+ SAVE_MSG_DEV_FAILURE_PC = 0x0DA,
+ CALLHOME_INIT_FAILURE_PC = 0x0DB
+} EVENT_PC;
+
+#ifdef __GNUC__
+
+#define POSTCODE_SEVERITY_ERR DIAG_SEVERITY_ERR
+#define POSTCODE_SEVERITY_WARNING DIAG_SEVERITY_WARNING
+#define POSTCODE_SEVERITY_INFO DIAG_SEVERITY_PRINT /* TODO-> Info currently
+ * doesnt show, so we
+ * set info=warning */
+/* example call of POSTCODE_LINUX_2(VISOR_CHIPSET_PC, POSTCODE_SEVERITY_ERR);
+ * Please also note that the resulting postcode is in hex, so if you are
+ * searching for the __LINE__ number, convert it first to decimal. The line
+ * number combined with driver and type of call, will allow you to track down
+ * exactly what line an error occured on, or where the last driver
+ * entered/exited from.
+ */
+
+/* BASE FUNCTIONS */
+#define POSTCODE_LINUX_A(DRIVER_PC, EVENT_PC, pc32bit, severity) \
+do { \
+ unsigned long long post_code_temp; \
+ post_code_temp = (((U64)DRIVER_PC) << 56) | (((U64)EVENT_PC) << 44) | \
+ ((((U64)__LINE__) & 0xFFF) << 32) | \
+ (((U64)pc32bit) & 0xFFFFFFFF); \
+ ISSUE_IO_VMCALL_POSTCODE_SEVERITY(post_code_temp, severity); \
+} while (0)
+
+#define POSTCODE_LINUX_B(DRIVER_PC, EVENT_PC, pc16bit1, pc16bit2, severity) \
+do { \
+ unsigned long long post_code_temp; \
+ post_code_temp = (((U64)DRIVER_PC) << 56) | (((U64)EVENT_PC) << 44) | \
+ ((((U64)__LINE__) & 0xFFF) << 32) | \
+ ((((U64)pc16bit1) & 0xFFFF) << 16) | \
+ (((U64)pc16bit2) & 0xFFFF); \
+ ISSUE_IO_VMCALL_POSTCODE_SEVERITY(post_code_temp, severity); \
+} while (0)
+
+/* MOST COMMON */
+#define POSTCODE_LINUX_2(EVENT_PC, severity) \
+ POSTCODE_LINUX_A(CURRENT_FILE_PC, EVENT_PC, 0x0000, severity);
+
+#define POSTCODE_LINUX_3(EVENT_PC, pc32bit, severity) \
+ POSTCODE_LINUX_A(CURRENT_FILE_PC, EVENT_PC, pc32bit, severity);
+
+
+#define POSTCODE_LINUX_4(EVENT_PC, pc16bit1, pc16bit2, severity) \
+ POSTCODE_LINUX_B(CURRENT_FILE_PC, EVENT_PC, pc16bit1, \
+ pc16bit2, severity);
+
+#endif
+#endif
--- /dev/null
+/* uisqueue.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.
+ */
+
+/*
+ * Unisys IO Virtualization header NOTE: This file contains only Linux
+ * specific structs. All OS-independent structs are in iochannel.h.xx
+ */
+
+#ifndef __UISQUEUE_H__
+#define __UISQUEUE_H__
+
+#include "linux/version.h"
+#include "iochannel.h"
+#include "uniklog.h"
+#include <linux/atomic.h>
+#include <linux/semaphore.h>
+
+#include "controlvmchannel.h"
+#include "controlvmcompletionstatus.h"
+
+struct uisqueue_info {
+
+ pCHANNEL_HEADER chan;
+ /* channel containing queues in which scsi commands &
+ * responses are queued
+ */
+ U64 packets_sent;
+ U64 packets_received;
+ U64 interrupts_sent;
+ U64 interrupts_received;
+ U64 max_not_empty_cnt;
+ U64 total_wakeup_cnt;
+ U64 non_empty_wakeup_cnt;
+
+ struct {
+ SIGNAL_QUEUE_HEADER Reserved1; /* */
+ SIGNAL_QUEUE_HEADER Reserved2; /* */
+ } safe_uis_queue;
+ unsigned int (*send_int_if_needed)(struct uisqueue_info *info,
+ unsigned int whichcqueue,
+ unsigned char issueInterruptIfEmpty,
+ U64 interruptHandle,
+ unsigned char io_termination);
+};
+
+/* uisqueue_put_cmdrsp_with_lock_client queues a commmand or response
+ * to the specified queue, at the tail if the queue is full but
+ * oktowait == 0, then it return 0 indicating failure. otherwise it
+ * wait for the queue to become non-full. If command is queued, return
+ * 1 for success.
+ */
+#define DONT_ISSUE_INTERRUPT 0
+#define ISSUE_INTERRUPT 1
+
+#define DONT_WAIT 0
+#define OK_TO_WAIT 1
+#define UISLIB_LOCK_PREFIX \
+ ".section .smp_locks,\"a\"\n" \
+ _ASM_ALIGN "\n" \
+ _ASM_PTR "661f\n" /* address */ \
+ ".previous\n" \
+ "661:\n\tlock; "
+
+unsigned long long uisqueue_InterlockedOr(volatile unsigned long long *Target,
+ unsigned long long Set);
+unsigned long long uisqueue_InterlockedAnd(volatile unsigned long long *Target,
+ unsigned long long Set);
+
+unsigned int uisqueue_send_int_if_needed(struct uisqueue_info *pqueueinfo,
+ unsigned int whichqueue,
+ unsigned char issueInterruptIfEmpty,
+ U64 interruptHandle,
+ unsigned char io_termination);
+
+int uisqueue_put_cmdrsp_with_lock_client(struct uisqueue_info *queueinfo,
+ struct uiscmdrsp *cmdrsp,
+ unsigned int queue,
+ void *insertlock,
+ unsigned char issueInterruptIfEmpty,
+ U64 interruptHandle,
+ char oktowait,
+ U8 *channelId);
+
+/* uisqueue_get_cmdrsp gets the cmdrsp entry at the head of the queue
+ * and copies it to the area pointed by cmdrsp param.
+ * returns 0 if queue is empty, 1 otherwise
+ */
+int
+
+uisqueue_get_cmdrsp(struct uisqueue_info *queueinfo, void *cmdrsp,
+ unsigned int queue);
+
+#define MAX_NAME_SIZE_UISQUEUE 64
+
+struct extport_info {
+ U8 valid:1;
+ /* if 1, indicates this extport slot is occupied
+ * if 0, indicates that extport slot is unoccupied */
+
+ U32 num_devs_using;
+ /* When extport is added, this is set to 0. For exports
+ * located in NETWORK switches:
+ * Each time a VNIC, i.e., intport, is added to the switch this
+ * is used to assign a pref_pnic for the VNIC and when assigned
+ * to a VNIC this counter is incremented. When a VNIC is
+ * deleted, the extport corresponding to the VNIC's pref_pnic
+ * is located and its num_devs_using is decremented. For VNICs,
+ * num_devs_using is basically used to load-balance transmit
+ * traffic from VNICs.
+ */
+
+ struct switch_info *swtch;
+ struct PciId pci_id;
+ char name[MAX_NAME_SIZE_UISQUEUE];
+ union {
+ struct vhba_wwnn wwnn;
+ unsigned char macaddr[MAX_MACADDR_LEN];
+ };
+};
+
+struct device_info {
+ void *chanptr;
+ U64 channelAddr;
+ U64 channelBytes;
+ GUID channelTypeGuid;
+ GUID devInstGuid;
+ struct InterruptInfo intr;
+ struct switch_info *swtch;
+ char devid[30]; /* "vbus<busno>:dev<devno>" */
+ U16 polling;
+ struct semaphore interrupt_callback_lock;
+ U32 busNo;
+ U32 devNo;
+ int (*interrupt)(void *);
+ void *interrupt_context;
+ void *private_data;
+ struct list_head list_polling_device_channels;
+ unsigned long long moved_to_tail_cnt;
+ unsigned long long first_busy_cnt;
+ unsigned long long last_on_list_cnt;
+};
+
+typedef enum {
+ RECOVERY_LAN = 1,
+ IB_LAN = 2
+} SWITCH_TYPE;
+
+struct bus_info {
+ U32 busNo, deviceCount;
+ struct device_info **device;
+ U64 guestHandle, recvBusInterruptHandle;
+ GUID busInstGuid;
+ ULTRA_VBUS_CHANNEL_PROTOCOL *pBusChannel;
+ int busChannelBytes;
+ struct proc_dir_entry *proc_dir; /* proc/uislib/vbus/<x> */
+ struct proc_dir_entry *proc_info; /* proc/uislib/vbus/<x>/info */
+ char name[25];
+ char partitionName[99];
+ struct bus_info *next;
+ U8 localVnic; /* 1 if local vnic created internally
+ * by IOVM; 0 otherwise... */
+};
+
+#define DEDICATED_SWITCH(pSwitch) ((pSwitch->extPortCount == 1) && \
+ (pSwitch->intPortCount == 1))
+
+struct sn_list_entry {
+ struct uisscsi_dest pdest; /* scsi bus, target, lun for
+ * phys disk */
+ U8 sernum[MAX_SERIAL_NUM]; /* serial num of physical
+ * disk.. The length is always
+ * MAX_SERIAL_NUM, padded with
+ * spaces */
+ struct sn_list_entry *next;
+};
+
+struct networkPolicy {
+ U32 promiscuous:1;
+ U32 macassign:1;
+ U32 peerforwarding:1;
+ U32 nonotify:1;
+ U32 standby:1;
+ U32 callhome:2;
+ char ip_addr[30];
+};
+
+/*
+ * IO messages sent to UisnicControlChanFunc & UissdControlChanFunc by
+ * code that processes the ControlVm channel messages.
+ */
+
+
+typedef enum {
+ IOPART_ADD_VNIC,
+ IOPART_DEL_VNIC,
+ IOPART_DEL_ALL_VNICS,
+ IOPART_ADD_VHBA,
+ IOPART_ADD_VDISK,
+ IOPART_DEL_VHBA,
+ IOPART_DEL_VDISK,
+ IOPART_DEL_ALL_VDISKS_FOR_VHBA,
+ IOPART_DEL_ALL_VHBAS,
+ IOPART_ATTACH_PHBA,
+ IOPART_DETACH_PHBA, /* 10 */
+ IOPART_ATTACH_PNIC,
+ IOPART_DETACH_PNIC,
+ IOPART_DETACH_VHBA,
+ IOPART_DETACH_VNIC,
+ IOPART_PAUSE_VDISK,
+ IOPART_RESUME_VDISK,
+ IOPART_ADD_DEVICE, /* add generic device */
+ IOPART_DEL_DEVICE, /* del generic device */
+} IOPART_MSG_TYPE;
+
+struct add_virt_iopart {
+ void *chanptr; /* pointer to data channel */
+ U64 guestHandle; /* used to convert guest physical
+ * address to real physical address
+ * for DMA, for ex. */
+ U64 recvBusInterruptHandle; /* used to register to receive
+ * bus level interrupts. */
+ struct InterruptInfo intr; /* contains recv & send
+ * interrupt info */
+ /* recvInterruptHandle is used to register to receive
+ * interrupts on the data channel. Used by GuestLinux/Windows
+ * IO drivers to connect to interrupt. sendInterruptHandle is
+ * used by IOPart drivers as parameter to
+ * Issue_VMCALL_IO_QUEUE_TRANSITION to interrupt thread in
+ * guest linux/windows IO drivers when data channel queue for
+ * vhba/vnic goes from EMPTY to NON-EMPTY. */
+ struct switch_info *swtch; /* pointer to the virtual
+ * switch to which the vnic is
+ * connected */
+
+ U8 useG2GCopy; /* Used to determine if a virtual HBA
+ * needs to use G2G copy. */
+ U8 Filler[7];
+
+ U32 busNo;
+ U32 devNo;
+ char *params;
+ ulong params_bytes;
+
+};
+
+struct add_vdisk_iopart {
+ void *chanptr; /* pointer to data channel */
+ int implicit;
+ struct uisscsi_dest vdest; /* scsi bus, target, lun for virt disk */
+ struct uisscsi_dest pdest; /* scsi bus, target, lun for phys disk */
+ U8 sernum[MAX_SERIAL_NUM]; /* serial num of physical disk */
+ U32 serlen; /* length of serial num */
+ U32 busNo;
+ U32 devNo;
+};
+
+struct del_vdisk_iopart {
+ void *chanptr; /* pointer to data channel */
+ struct uisscsi_dest vdest; /* scsi bus, target, lun for virt disk */
+ U32 busNo;
+ U32 devNo;
+};
+
+struct del_virt_iopart {
+ void *chanptr; /* pointer to data channel */
+ U32 busNo;
+ U32 devNo;
+};
+
+struct det_virt_iopart { /* detach internal port */
+ void *chanptr; /* pointer to data channel */
+ struct switch_info *swtch;
+};
+
+struct paures_vdisk_iopart {
+ void *chanptr; /* pointer to data channel */
+ struct uisscsi_dest vdest; /* scsi bus, target, lun for virt disk */
+};
+
+struct add_switch_iopart { /* add switch */
+ struct switch_info *swtch;
+ char *params;
+ ulong params_bytes;
+};
+
+struct del_switch_iopart { /* destroy switch */
+ struct switch_info *swtch;
+};
+
+struct io_msgs {
+
+ IOPART_MSG_TYPE msgtype;
+
+ /* additional params needed by some messages */
+ union {
+ struct add_virt_iopart add_vhba;
+ struct add_virt_iopart add_vnic;
+ struct add_vdisk_iopart add_vdisk;
+ struct del_virt_iopart del_vhba;
+ struct del_virt_iopart del_vnic;
+ struct det_virt_iopart det_vhba;
+ struct det_virt_iopart det_vnic;
+ struct del_vdisk_iopart del_vdisk;
+ struct del_virt_iopart del_all_vdisks_for_vhba;
+ struct add_virt_iopart add_device;
+ struct del_virt_iopart del_device;
+ struct det_virt_iopart det_intport;
+ struct add_switch_iopart add_switch;
+ struct del_switch_iopart del_switch;
+ struct extport_info *extPort; /* for attach or detach
+ * pnic/generic delete all
+ * vhbas/allvnics need no
+ * parameters */
+ struct paures_vdisk_iopart paures_vdisk;
+ };
+};
+
+/*
+* Guest messages sent to VirtControlChanFunc by code that processes
+* the ControlVm channel messages.
+*/
+
+typedef enum {
+ GUEST_ADD_VBUS,
+ GUEST_ADD_VHBA,
+ GUEST_ADD_VNIC,
+ GUEST_DEL_VBUS,
+ GUEST_DEL_VHBA,
+ GUEST_DEL_VNIC,
+ GUEST_DEL_ALL_VHBAS,
+ GUEST_DEL_ALL_VNICS,
+ GUEST_DEL_ALL_VBUSES, /* deletes all vhbas & vnics on all
+ * buses and deletes all buses */
+ GUEST_PAUSE_VHBA,
+ GUEST_PAUSE_VNIC,
+ GUEST_RESUME_VHBA,
+ GUEST_RESUME_VNIC
+} GUESTPART_MSG_TYPE;
+
+struct add_vbus_guestpart {
+ void *chanptr; /* pointer to data channel for bus -
+ * NOT YET USED */
+ U32 busNo; /* bus number to be created/deleted */
+ U32 deviceCount; /* max num of devices on bus */
+ GUID busTypeGuid; /* indicates type of bus */
+ GUID busInstGuid; /* instance guid for device */
+};
+
+struct del_vbus_guestpart {
+ U32 busNo; /* bus number to be deleted */
+ /* once we start using the bus's channel, add can dump busNo
+ * into the channel header and then delete will need only one
+ * parameter, chanptr. */
+};
+
+struct add_virt_guestpart {
+ void *chanptr; /* pointer to data channel */
+ U32 busNo; /* bus number for the operation */
+ U32 deviceNo; /* number of device on the bus */
+ GUID devInstGuid; /* instance guid for device */
+ struct InterruptInfo intr; /* recv/send interrupt info */
+ /* recvInterruptHandle contains info needed in order to
+ * register to receive interrupts on the data channel.
+ * sendInterruptHandle contains handle which is provided to
+ * monitor VMCALL that will cause an interrupt to be generated
+ * for the other end.
+ */
+};
+
+struct pause_virt_guestpart {
+ void *chanptr; /* pointer to data channel */
+};
+
+struct resume_virt_guestpart {
+ void *chanptr; /* pointer to data channel */
+};
+
+struct del_virt_guestpart {
+ void *chanptr; /* pointer to data channel */
+};
+
+struct init_chipset_guestpart {
+ U32 busCount; /* indicates the max number of busses */
+ U32 switchCount; /* indicates the max number of switches */
+};
+
+struct guest_msgs {
+
+ GUESTPART_MSG_TYPE msgtype;
+
+ /* additional params needed by messages */
+ union {
+ struct add_vbus_guestpart add_vbus;
+ struct add_virt_guestpart add_vhba;
+ struct add_virt_guestpart add_vnic;
+ struct pause_virt_guestpart pause_vhba;
+ struct pause_virt_guestpart pause_vnic;
+ struct resume_virt_guestpart resume_vhba;
+ struct resume_virt_guestpart resume_vnic;
+ struct del_vbus_guestpart del_vbus;
+ struct del_virt_guestpart del_vhba;
+ struct del_virt_guestpart del_vnic;
+ struct del_vbus_guestpart del_all_vhbas;
+ struct del_vbus_guestpart del_all_vnics;
+ /* del_all_vbuses needs no parameters */
+ };
+ struct init_chipset_guestpart init_chipset;
+
+};
+
+#ifndef __xg
+#define __xg(x) ((volatile long *)(x))
+#endif
+
+/*
+* Below code is a copy of Linux kernel's cmpxchg function located at
+* this place
+* http://tcsxeon:8080/source/xref/00trunk-AppOS-linux/include/asm-x86/cmpxchg_64.h#84
+* Reason for creating our own version of cmpxchg along with
+* UISLIB_LOCK_PREFIX is to make the operation atomic even for non SMP
+* guests.
+*/
+
+static inline unsigned long
+uislibcmpxchg64(volatile void *ptr, unsigned long old, unsigned long new,
+ int size)
+{
+ unsigned long prev;
+ switch (size) {
+ case 1:
+ __asm__ __volatile__(UISLIB_LOCK_PREFIX "cmpxchgb %b1,%2":"=a"(prev)
+ : "q"(new), "m"(*__xg(ptr)),
+ "0"(old)
+ : "memory");
+ return prev;
+ case 2:
+ __asm__ __volatile__(UISLIB_LOCK_PREFIX "cmpxchgw %w1,%2":"=a"(prev)
+ : "r"(new), "m"(*__xg(ptr)),
+ "0"(old)
+ : "memory");
+ return prev;
+ case 4:
+ __asm__ __volatile__(UISLIB_LOCK_PREFIX "cmpxchgl %k1,%2":"=a"(prev)
+ : "r"(new), "m"(*__xg(ptr)),
+ "0"(old)
+ : "memory");
+ return prev;
+ case 8:
+ __asm__ __volatile__(UISLIB_LOCK_PREFIX "cmpxchgq %1,%2":"=a"(prev)
+ : "r"(new), "m"(*__xg(ptr)),
+ "0"(old)
+ : "memory");
+ return prev;
+ }
+ return old;
+}
+
+#endif /* __UISQUEUE_H__ */
--- /dev/null
+/* uisthread.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.
+ */
+
+/*****************************************************************************/
+/* Unisys thread utilities header */
+/*****************************************************************************/
+
+
+#ifndef __UISTHREAD_H__
+#define __UISTHREAD_H__
+
+
+#include "linux/completion.h"
+
+struct uisthread_info {
+ struct task_struct *task;
+ int id;
+ int should_stop;
+ struct completion has_stopped;
+};
+
+
+/* returns 0 for failure, 1 for success */
+int uisthread_start(
+ struct uisthread_info *thrinfo,
+ int (*threadfn)(void *),
+ void *thrcontext,
+ char *name);
+
+void uisthread_stop(struct uisthread_info *thrinfo);
+
+#endif /* __UISTHREAD_H__ */
--- /dev/null
+/* uisutils.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.
+ */
+
+/*
+ * Unisys Virtual HBA utilities header
+ */
+
+#ifndef __UISUTILS__H__
+#define __UISUTILS__H__
+#include <linux/string.h>
+#include <linux/io.h>
+#include <linux/sched.h>
+#include <linux/gfp.h>
+
+#include "vmcallinterface.h"
+#include "channel.h"
+#include "uisthread.h"
+#include "uisqueue.h"
+#include "diagnostics/appos_subsystems.h"
+#include "vbusdeviceinfo.h"
+#include <linux/atomic.h>
+
+/* This is the MAGIC number stuffed by virthba in host->this_id. Used to
+ * identify virtual hbas.
+ */
+#define UIS_MAGIC_VHBA 707
+
+/* global function pointers that act as callback functions into
+ * uisnicmod, uissdmod, and virtpcimod
+ */
+extern int (*UisnicControlChanFunc)(struct io_msgs *);
+extern int (*UissdControlChanFunc)(struct io_msgs *);
+extern int (*VirtControlChanFunc)(struct guest_msgs *);
+
+/* Return values of above callback functions: */
+#define CCF_ERROR 0 /* completed and failed */
+#define CCF_OK 1 /* completed successfully */
+#define CCF_PENDING 2 /* operation still pending */
+extern atomic_t UisUtils_Registered_Services;
+
+typedef unsigned int MACARRAY[MAX_MACADDR_LEN];
+typedef struct ReqHandlerInfo_struct {
+ GUID switchTypeGuid;
+ 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);
+ char switch_type_name[99];
+ struct list_head list_link; /* links into ReqHandlerInfo_list */
+} ReqHandlerInfo_t;
+
+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 *ReqHandlerFind(GUID switchTypeGuid);
+int ReqHandlerDel(GUID switchTypeGuid);
+
+#define uislib_ioremap_cache(addr, size) \
+ dbg_ioremap_cache(addr, size, __FILE__, __LINE__)
+
+static inline void *
+dbg_ioremap_cache(U64 addr, unsigned long size, char *file, int line)
+{
+ void *new;
+ new = ioremap_cache(addr, size);
+ return new;
+}
+
+#define uislib_ioremap(addr, size) dbg_ioremap(addr, size, __FILE__, __LINE__)
+
+static inline void *
+dbg_ioremap(U64 addr, unsigned long size, char *file, int line)
+{
+ void *new;
+ new = ioremap(addr, size);
+ return new;
+}
+
+#define uislib_iounmap(addr) dbg_iounmap(addr, __FILE__, __LINE__)
+
+static inline void
+dbg_iounmap(void *addr, char *file, int line)
+{
+ iounmap(addr);
+}
+
+#define PROC_READ_BUFFER_SIZE 131072 /* size of the buffer to allocate to
+ * hold all of /proc/XXX/info */
+int util_add_proc_line_ex(int *total, char **buffer, int *buffer_remaining,
+ char *format, ...);
+
+int uisctrl_register_req_handler(int type, void *fptr,
+ ULTRA_VBUS_DEVICEINFO *chipset_DriverInfo);
+int uisctrl_register_req_handler_ex(GUID switchTypeGuid,
+ const char *switch_type_name,
+ int (*fptr)(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);
+
+int uisctrl_unregister_req_handler_ex(GUID switchTypeGuid);
+unsigned char *util_map_virt(struct phys_info *sg);
+void util_unmap_virt(struct phys_info *sg);
+unsigned char *util_map_virt_atomic(struct phys_info *sg);
+void util_unmap_virt_atomic(void *buf);
+int uislib_server_inject_add_vnic(U32 switchNo, U32 BusNo, U32 numIntPorts,
+ U32 numExtPorts, MACARRAY pmac[],
+ pCHANNEL_HEADER **chan);
+void uislib_server_inject_del_vnic(U32 switchNo, U32 busNo, U32 numIntPorts,
+ U32 numExtPorts);
+int uislib_client_inject_add_bus(U32 busNo, GUID instGuid,
+ U64 channelAddr, ulong nChannelBytes);
+int uislib_client_inject_del_bus(U32 busNo);
+
+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);
+int uislib_client_inject_pause_vhba(U32 busNo, U32 devNo);
+int uislib_client_inject_resume_vhba(U32 busNo, U32 devNo);
+int uislib_client_inject_del_vhba(U32 busNo, U32 devNo);
+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);
+int uislib_client_inject_pause_vnic(U32 busNo, U32 devNo);
+int uislib_client_inject_resume_vnic(U32 busNo, U32 devNo);
+int uislib_client_inject_del_vnic(U32 busNo, U32 devNo);
+#ifdef STORAGE_CHANNEL
+U64 uislib_storage_channel(int client_id);
+#endif
+int uislib_get_owned_pdest(struct uisscsi_dest *pdest);
+
+int uislib_send_event(CONTROLVM_ID id, CONTROLVM_MESSAGE_PACKET *event);
+
+/* structure used by vhba & vnic to keep track of queue & thread info */
+struct chaninfo {
+ struct uisqueue_info *queueinfo;
+ /* this specifies the queue structures for a channel */
+ /* ALLOCATED BY THE OTHER END - WE JUST GET A POINTER TO THE MEMORY */
+ spinlock_t insertlock;
+ /* currently used only in virtnic when sending data to uisnic */
+ /* to synchronize the inserts into the signal queue */
+ struct uisthread_info threadinfo;
+ /* this specifies the thread structures used by the thread that */
+ /* handles this channel */
+};
+
+/* this is the wait code for all the threads - it is used to get
+* something from a queue choices: wait_for_completion_interruptible,
+* _timeout, interruptible_timeout
+*/
+#define UIS_THREAD_WAIT_MSEC(x) { \
+ set_current_state(TASK_INTERRUPTIBLE); \
+ schedule_timeout(msecs_to_jiffies(x)); \
+}
+#define UIS_THREAD_WAIT_USEC(x) { \
+ set_current_state(TASK_INTERRUPTIBLE); \
+ schedule_timeout(usecs_to_jiffies(x)); \
+}
+#define UIS_THREAD_WAIT UIS_THREAD_WAIT_MSEC(5)
+#define UIS_THREAD_WAIT_SEC(x) { \
+ set_current_state(TASK_INTERRUPTIBLE); \
+ schedule_timeout((x)*HZ); \
+}
+
+#define ALLOC_CMDRSP(cmdrsp) { \
+ cmdrsp = kmalloc(SIZEOF_CMDRSP, GFP_ATOMIC); \
+ if (cmdrsp != NULL) { \
+ memset(cmdrsp, 0, SIZEOF_CMDRSP); \
+ } \
+}
+
+/* This is a hack until we fix IOVM to initialize the channel header
+ * correctly at DEVICE_CREATE time, INSTEAD OF waiting until
+ * DEVICE_CONFIGURE time.
+ */
+#define WAIT_FOR_VALID_GUID(guid) \
+ do { \
+ while (memcmp(&guid, &Guid0, sizeof(Guid0)) == 0) { \
+ LOGERR("Waiting for non-0 GUID (why???)...\n"); \
+ UIS_THREAD_WAIT_SEC(5); \
+ } \
+ LOGERR("OK... GUID is non-0 now\n"); \
+ } while (0)
+
+/* CopyFragsInfoFromSkb returns the number of entries added to frags array
+ * Returns -1 on failure.
+ */
+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[]);
+
+static inline unsigned int
+Issue_VMCALL_IO_CONTROLVM_ADDR(U64 *ControlAddress, U32 *ControlBytes)
+{
+ VMCALL_IO_CONTROLVM_ADDR_PARAMS params;
+ int result = VMCALL_SUCCESS;
+ U64 physaddr;
+
+ physaddr = virt_to_phys(¶ms);
+ ISSUE_IO_VMCALL(VMCALL_IO_CONTROLVM_ADDR, physaddr, result);
+ if (VMCALL_SUCCESSFUL(result)) {
+ *ControlAddress = params.ChannelAddress;
+ *ControlBytes = params.ChannelBytes;
+ }
+ return result;
+}
+
+static inline unsigned int Issue_VMCALL_IO_DIAG_ADDR(U64 *DiagChannelAddress)
+{
+ VMCALL_IO_DIAG_ADDR_PARAMS params;
+ int result = VMCALL_SUCCESS;
+ U64 physaddr;
+
+ physaddr = virt_to_phys(¶ms);
+ ISSUE_IO_VMCALL(VMCALL_IO_DIAG_ADDR, physaddr, result);
+ if (VMCALL_SUCCESSFUL(result))
+ *DiagChannelAddress = params.ChannelAddress;
+ return result;
+}
+
+static inline unsigned int
+Issue_VMCALL_IO_VISORSERIAL_ADDR(U64 *DiagChannelAddress)
+{
+ VMCALL_IO_VISORSERIAL_ADDR_PARAMS params;
+ int result = VMCALL_SUCCESS;
+ U64 physaddr;
+
+ physaddr = virt_to_phys(¶ms);
+ ISSUE_IO_VMCALL(VMCALL_IO_VISORSERIAL_ADDR, physaddr, result);
+ if (VMCALL_SUCCESSFUL(result))
+ *DiagChannelAddress = params.ChannelAddress;
+ return result;
+}
+
+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 S64 Issue_VMCALL_MEASUREMENT_DO_NOTHING(void)
+{
+ U64 result = VMCALL_SUCCESS;
+ U64 physaddr = 0;
+
+ ISSUE_IO_VMCALL(VMCALL_MEASUREMENT_DO_NOTHING, physaddr, result);
+ return result;
+}
+
+struct log_info_t {
+ volatile unsigned long long last_cycles;
+ unsigned long long delta_sum[64];
+ unsigned long long delta_cnt[64];
+ unsigned long long max_delta[64];
+ unsigned long long min_delta[64];
+};
+
+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 inline unsigned int
+Issue_VMCALL_CHANNEL_MISMATCH(const char *ChannelName,
+ const char *ItemName,
+ U32 SourceLineNumber, const char *path_n_fn)
+{
+ VMCALL_CHANNEL_VERSION_MISMATCH_PARAMS params;
+ int result = VMCALL_SUCCESS;
+ U64 physaddr;
+ char *last_slash = NULL;
+
+ strncpy(params.ChannelName, ChannelName,
+ lengthof(VMCALL_CHANNEL_VERSION_MISMATCH_PARAMS, ChannelName));
+ strncpy(params.ItemName, ItemName,
+ lengthof(VMCALL_CHANNEL_VERSION_MISMATCH_PARAMS, ItemName));
+ params.SourceLineNumber = SourceLineNumber;
+
+ last_slash = strrchr(path_n_fn, '/');
+ if (last_slash != NULL) {
+ last_slash++;
+ strncpy(params.SourceFileName, last_slash,
+ lengthof(VMCALL_CHANNEL_VERSION_MISMATCH_PARAMS,
+ SourceFileName));
+ } else
+ strncpy(params.SourceFileName,
+ "Cannot determine source filename",
+ lengthof(VMCALL_CHANNEL_VERSION_MISMATCH_PARAMS,
+ SourceFileName));
+
+ physaddr = virt_to_phys(¶ms);
+ ISSUE_IO_VMCALL(VMCALL_CHANNEL_VERSION_MISMATCH, physaddr, result);
+ return result;
+}
+
+static inline unsigned int Issue_VMCALL_FATAL_BYE_BYE(void)
+{
+ int result = VMCALL_SUCCESS;
+ U64 physaddr = 0;
+
+ ISSUE_IO_VMCALL(VMCALL_GENERIC_SURRENDER_QUANTUM_FOREVER, physaddr,
+ result);
+ return result;
+}
+
+#define UIS_DAEMONIZE(nam)
+void *uislib_malloc(size_t siz, gfp_t gfp, U8 contiguous, char *fn, int ln);
+#define UISMALLOC(siz, gfp) uislib_malloc(siz, gfp, 1, __FILE__, __LINE__)
+#define UISVMALLOC(siz) uislib_malloc(siz, 0, 0, __FILE__, __LINE__)
+void uislib_free(void *p, size_t siz, U8 contiguous, char *fn, int ln);
+#define UISFREE(p, siz) uislib_free(p, siz, 1, __FILE__, __LINE__)
+#define UISVFREE(p, siz) uislib_free(p, siz, 0, __FILE__, __LINE__)
+void *uislib_cache_alloc(struct kmem_cache *cur_pool, char *fn, int ln);
+#define UISCACHEALLOC(cur_pool) uislib_cache_alloc(cur_pool, __FILE__, __LINE__)
+void uislib_cache_free(struct kmem_cache *cur_pool, void *p, char *fn, int ln);
+#define UISCACHEFREE(cur_pool, p) \
+ uislib_cache_free(cur_pool, p, __FILE__, __LINE__)
+
+void uislib_enable_channel_interrupts(U32 busNo, U32 devNo,
+ int (*interrupt)(void *),
+ void *interrupt_context);
+void uislib_disable_channel_interrupts(U32 busNo, U32 devNo);
+void uislib_force_channel_interrupt(U32 busNo, U32 devNo);
+
+#endif /* __UISUTILS__H__ */
--- /dev/null
+/* vbushelper.h
+ *
+ * Copyright © 2011 - 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 __VBUSHELPER_H__
+#define __VBUSHELPER_H__
+
+#include "vbusdeviceinfo.h"
+
+/* TARGET_HOSTNAME specified as -DTARGET_HOSTNAME=\"thename\" on the
+ * command line */
+
+#define TARGET_HOSTNAME "linuxguest"
+
+static inline void
+BusDeviceInfo_Init(ULTRA_VBUS_DEVICEINFO *pBusDeviceInfo,
+ const char *deviceType, const char *driverName,
+ const char *ver, const char *verTag,
+ const char *buildDate, const char *buildTime)
+{
+ memset(pBusDeviceInfo, 0, sizeof(ULTRA_VBUS_DEVICEINFO));
+ snprintf(pBusDeviceInfo->devType, sizeof(pBusDeviceInfo->devType),
+ "%s", (deviceType) ? deviceType : "unknownType");
+ snprintf(pBusDeviceInfo->drvName, sizeof(pBusDeviceInfo->drvName),
+ "%s", (driverName) ? driverName : "unknownDriver");
+ snprintf(pBusDeviceInfo->infoStrings,
+ sizeof(pBusDeviceInfo->infoStrings), "%s\t%s\t%s %s\t%s",
+ (ver) ? ver : "unknownVer",
+ (verTag) ? verTag : "unknownVerTag",
+ (buildDate) ? buildDate : "noBuildDate",
+ (buildTime) ? buildTime : "nobuildTime", TARGET_HOSTNAME);
+}
+
+#endif
--- /dev/null
+#
+# Unisys visorchipset configuration
+#
+
+config UNISYS_VISORCHIPSET
+ tristate "Unisys visorchipset driver"
+ depends on UNISYSSPAR && UNISYS_VISORUTIL && UNISYS_VISORCHANNEL
+ ---help---
+ If you say Y here, you will enable the Unisys visorchipset driver.
+
--- /dev/null
+#
+# Makefile for Unisys visorchipset
+#
+
+obj-$(CONFIG_UNISYS_VISORCHIPSET) += visorchipset.o
+
+visorchipset-y := visorchipset_main.o controlvm_direct.o file.o filexfer.o \
+ parser.o
+
+ccflags-y += -Idrivers/staging/unisys/include
+ccflags-y += -Idrivers/staging/unisys/uislib
+ccflags-y += -Idrivers/staging/unisys/visorchannel
+ccflags-y += -Idrivers/staging/unisys/common-spar/include
+ccflags-y += -Idrivers/staging/unisys/common-spar/include/channels
+ccflags-y += -Idrivers/staging/unisys/visorutil
+ccflags-y += -Iinclude/generated
+ccflags-y += -DCONFIG_SPAR_GUEST -DGUESTDRIVERBUILD -DNOAUTOVERSION
+
--- /dev/null
+/* controlvm.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 __CONTROLVM_H__
+#define __CONTROLVM_H__
+
+#include "timskmod.h"
+
+int controlvm_init(void);
+void controlvm_deinit(void);
+HOSTADDRESS controlvm_get_channel_address(void);
+
+#endif
--- /dev/null
+/* controlvm_direct.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.
+ */
+
+/* This is a controlvm-related code that is dependent upon firmware running
+ * on a virtual partition.
+ */
+
+#include "globals.h"
+#include "uisutils.h"
+#define CURRENT_FILE_PC VISOR_CHIPSET_PC_controlvm_direct_c
+
+
+/* We can fill in this code when we learn how to make vmcalls... */
+
+
+
+int controlvm_init(void)
+{
+ return 0;
+}
+
+
+
+void controlvm_deinit(void)
+{
+}
+
+
+
+HOSTADDRESS controlvm_get_channel_address(void)
+{
+ static BOOL warned = FALSE;
+ U64 addr = 0;
+
+ U32 size = 0;
+
+ if (!VMCALL_SUCCESSFUL(Issue_VMCALL_IO_CONTROLVM_ADDR(&addr, &size))) {
+ if (!warned) {
+ ERRDRV("%s - vmcall to determine controlvm channel addr failed",
+ __func__);
+ warned = TRUE;
+ }
+ return 0;
+ }
+ INFODRV("controlvm addr=%Lx", addr);
+ return addr;
+}
--- /dev/null
+/* file.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.
+ */
+
+/* This contains the implementation that allows a usermode program to
+ * communicate with the visorchipset driver using a device/file interface.
+ */
+
+#include "globals.h"
+#include "visorchannel.h"
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include "uisutils.h"
+
+#define CURRENT_FILE_PC VISOR_CHIPSET_PC_file_c
+
+static struct cdev Cdev;
+static VISORCHANNEL **PControlVm_channel;
+static dev_t MajorDev = -1; /**< indicates major num for device */
+static BOOL Registered = FALSE;
+
+static int visorchipset_open(struct inode *inode, struct file *file);
+static int visorchipset_release(struct inode *inode, struct file *file);
+static int visorchipset_mmap(struct file *file, struct vm_area_struct *vma);
+#ifdef HAVE_UNLOCKED_IOCTL
+long visorchipset_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
+#else
+int visorchipset_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg);
+#endif
+
+static const struct file_operations visorchipset_fops = {
+ .owner = THIS_MODULE,
+ .open = visorchipset_open,
+ .read = NULL,
+ .write = NULL,
+#ifdef HAVE_UNLOCKED_IOCTL
+ .unlocked_ioctl = visorchipset_ioctl,
+#else
+ .ioctl = visorchipset_ioctl,
+#endif
+ .release = visorchipset_release,
+ .mmap = visorchipset_mmap,
+};
+
+int
+visorchipset_file_init(dev_t majorDev, VISORCHANNEL **pControlVm_channel)
+{
+ int rc = -1;
+
+ PControlVm_channel = pControlVm_channel;
+ MajorDev = majorDev;
+ cdev_init(&Cdev, &visorchipset_fops);
+ Cdev.owner = THIS_MODULE;
+ if (MAJOR(MajorDev) == 0) {
+ /* dynamic major device number registration required */
+ if (alloc_chrdev_region(&MajorDev, 0, 1, MYDRVNAME) < 0) {
+ ERRDRV("Unable to allocate+register char device %s",
+ MYDRVNAME);
+ RETINT(-1);
+ }
+ Registered = TRUE;
+ INFODRV("New major number %d registered\n", MAJOR(MajorDev));
+ } else {
+ /* static major device number registration required */
+ if (register_chrdev_region(MajorDev, 1, MYDRVNAME) < 0) {
+ ERRDRV("Unable to register char device %s", MYDRVNAME);
+ RETINT(-1);
+ }
+ Registered = TRUE;
+ INFODRV("Static major number %d registered\n", MAJOR(MajorDev));
+ }
+ if (cdev_add(&Cdev, MKDEV(MAJOR(MajorDev), 0), 1) < 0)
+ FAIL("failed to create char device", -1);
+ INFODRV("Registered char device for %s (major=%d)",
+ MYDRVNAME, MAJOR(MajorDev));
+ RETINT(0);
+Away:
+ return rc;
+}
+
+void
+visorchipset_file_cleanup(void)
+{
+ if (Cdev.ops != NULL)
+ cdev_del(&Cdev);
+ Cdev.ops = NULL;
+ if (Registered) {
+ if (MAJOR(MajorDev) >= 0) {
+ unregister_chrdev_region(MajorDev, 1);
+ MajorDev = MKDEV(0, 0);
+ }
+ Registered = FALSE;
+ }
+}
+
+static int
+visorchipset_open(struct inode *inode, struct file *file)
+{
+ unsigned minor_number = iminor(inode);
+ int rc = -ENODEV;
+
+ DEBUGDRV("%s", __func__);
+ if (minor_number != 0)
+ RETINT(-ENODEV);
+ file->private_data = NULL;
+ RETINT(0);
+Away:
+ if (rc < 0)
+ ERRDRV("%s minor=%d failed", __func__, minor_number);
+ return rc;
+}
+
+static int
+visorchipset_release(struct inode *inode, struct file *file)
+{
+ int rc = -1;
+ DEBUGDRV("%s", __func__);
+ RETINT(0);
+Away:
+ return rc;
+}
+
+static int
+visorchipset_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ ulong physAddr = 0;
+ ulong offset = vma->vm_pgoff << PAGE_SHIFT;
+ GUEST_PHYSICAL_ADDRESS addr = 0;
+
+ /* sv_enable_dfp(); */
+ DEBUGDRV("%s", __func__);
+ if (offset & (PAGE_SIZE - 1)) {
+ ERRDRV("%s virtual address NOT page-aligned!", __func__);
+ return -ENXIO; /* need aligned offsets */
+ }
+ switch (offset) {
+ case VISORCHIPSET_MMAP_CONTROLCHANOFFSET:
+ vma->vm_flags |= VM_IO;
+ if (*PControlVm_channel == NULL) {
+ ERRDRV("%s no controlvm channel yet", __func__);
+ return -ENXIO;
+ }
+ visorchannel_read(*PControlVm_channel,
+ offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL,
+ gpControlChannel), &addr,
+ sizeof(addr));
+ if (addr == 0) {
+ ERRDRV("%s control channel address is 0", __func__);
+ return -ENXIO;
+ }
+ physAddr = (ulong) (addr);
+ DEBUGDRV("mapping physical address = 0x%lx", physAddr);
+ if (remap_pfn_range(vma, vma->vm_start,
+ physAddr >> PAGE_SHIFT,
+ vma->vm_end - vma->vm_start,
+ /*pgprot_noncached */
+ (vma->vm_page_prot))) {
+ ERRDRV("%s remap_pfn_range failed", __func__);
+ return -EAGAIN;
+ }
+ break;
+ default:
+ return -ENOSYS;
+ }
+ DEBUGDRV("%s success!", __func__);
+ return 0;
+}
+
+#ifdef HAVE_UNLOCKED_IOCTL
+long
+visorchipset_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+#else
+int
+visorchipset_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+#endif
+{
+ int rc = SUCCESS;
+ S64 adjustment;
+ S64 vrtc_offset;
+ DBGINF("entered visorchipset_ioctl, cmd=%d", cmd);
+ 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)))
+ RETINT(-EFAULT);
+ DBGINF("insde visorchipset_ioctl, cmd=%d, vrtc_offset=%lld",
+ cmd, vrtc_offset);
+ break;
+ case VMCALL_UPDATE_PHYSICAL_TIME:
+ if (copy_from_user
+ (&adjustment, (void __user *)arg, sizeof(adjustment)))
+ RETINT(-EFAULT);
+ DBGINF("insde visorchipset_ioctl, cmd=%d, adjustment=%lld", cmd,
+ adjustment);
+ rc = Issue_VMCALL_UPDATE_PHYSICAL_TIME(adjustment);
+ break;
+ default:
+ LOGERR("visorchipset_ioctl received invalid command");
+ RETINT(-EFAULT);
+ break;
+ }
+ RETINT(rc);
+Away:
+ DBGINF("exiting %d!", rc);
+ return rc;
+}
--- /dev/null
+/* file.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 __FILE_H__
+#define __FILE_H__
+
+#include "globals.h"
+
+int visorchipset_file_init(dev_t majorDev, VISORCHANNEL **pControlVm_channel);
+void visorchipset_file_cleanup(void);
+
+#endif
--- /dev/null
+/* filexfer.c
+ *
+ * Copyright © 2013 - 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.
+ */
+
+/* Code here-in is the "glue" that connects controlvm messages with the
+ * sparfilexfer driver, which is used to transfer file contents as payload
+ * across the controlvm channel.
+ */
+
+#include "globals.h"
+#include "controlvm.h"
+#include "visorchipset.h"
+#include "filexfer.h"
+
+#ifdef ENABLE_SPARFILEXFER /* sparfilexfer kernel module enabled in build */
+#include "sparfilexfer.h"
+
+/* Driver-global memory */
+static LIST_HEAD(Request_list); /* list of struct any_request *, via
+ * req_list memb */
+
+/* lock for above pool for allocation of any_request structs, and pool
+* name; note that kmem_cache_create requires that we keep the storage
+* for the pool name for the life of the pool
+ */
+static DEFINE_SPINLOCK(Request_list_lock);
+
+static struct kmem_cache *Request_memory_pool;
+static const char Request_memory_pool_name[] = "filexfer_request_pool";
+size_t Caller_req_context_bytes = 0; /* passed to filexfer_constructor() */
+
+/* This structure defines a single controlvm GETFILE conversation, which
+ * consists of a single controlvm request message and 1 or more controlvm
+ * response messages.
+ */
+struct getfile_request {
+ CONTROLVM_MESSAGE_HEADER controlvm_header;
+ atomic_t buffers_in_use;
+ GET_CONTIGUOUS_CONTROLVM_PAYLOAD_FUNC get_contiguous_controlvm_payload;
+ CONTROLVM_RESPOND_WITH_PAYLOAD_FUNC controlvm_respond_with_payload;
+};
+
+/* This structure defines a single controlvm PUTFILE conversation, which
+ * consists of a single controlvm request with a filename, and additional
+ * controlvm messages with file data.
+ */
+struct putfile_request {
+ GET_CONTROLVM_FILEDATA_FUNC get_controlvm_filedata;
+ CONTROLVM_RESPOND_FUNC controlvm_end_putFile;
+};
+
+/* This structure defines a single file transfer operation, which can either
+ * be a GETFILE or PUTFILE.
+ */
+struct any_request {
+ struct list_head req_list;
+ ulong2 file_request_number;
+ ulong2 data_sequence_number;
+ TRANSMITFILE_DUMP_FUNC dump_func;
+ BOOL is_get;
+ union {
+ struct getfile_request get;
+ struct putfile_request put;
+ };
+ /* Size of caller_context_data will be
+ * <Caller_req_context_bytes> bytes. I aligned this because I
+ * am paranoid about what happens when an arbitrary data
+ * structure with unknown alignment requirements gets copied
+ * here. I want caller_context_data to be aligned to the
+ * coarsest possible alignment boundary that could be required
+ * for any user data structure.
+ */
+ u8 caller_context_data[1] __aligned(sizeof(ulong2);
+};
+
+/*
+ * Links the any_request into the global list of allocated requests
+ * (<Request_list>).
+ */
+static void
+unit_tracking_create(struct list_head *dev_list_link)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&Request_list_lock, flags);
+ list_add(dev_list_link, &Request_list);
+ spin_unlock_irqrestore(&Request_list_lock, flags);
+}
+
+/* Unlinks a any_request from the global list (<Request_list>).
+ */
+static void
+unit_tracking_destroy(struct list_head *dev_list_link)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&Request_list_lock, flags);
+ list_del(dev_list_link);
+ spin_unlock_irqrestore(&Request_list_lock, flags);
+}
+
+/* Allocate memory for and return a new any_request struct, and
+ * link it to the global list of outstanding requests.
+ */
+static struct any_request *
+alloc_request(char *fn, int ln)
+{
+ struct any_request *req = (struct any_request *)
+ (visorchipset_cache_alloc(Request_memory_pool,
+ FALSE,
+ fn, ln));
+ if (!req)
+ return NULL;
+ memset(req, 0, sizeof(struct any_request) + Caller_req_context_bytes);
+ unit_tracking_create(&req->req_list);
+ return req;
+}
+
+/* Book-end for alloc_request().
+ */
+static void
+free_request(struct any_request *req, char *fn, int ln)
+{
+ unit_tracking_destroy(&req->req_list);
+ visorchipset_cache_free(Request_memory_pool, req, fn, ln);
+}
+
+/* Constructor for filexfer.o.
+ */
+int
+filexfer_constructor(size_t req_context_bytes)
+{
+ int rc = -1;
+
+ Caller_req_context_bytes = req_context_bytes;
+ Request_memory_pool =
+ kmem_cache_create(Request_memory_pool_name,
+ sizeof(struct any_request) +
+ Caller_req_context_bytes,
+ 0, SLAB_HWCACHE_ALIGN, NULL);
+ if (!Request_memory_pool) {
+ LOGERR("failed to alloc Request_memory_pool");
+ rc = -ENOMEM;
+ goto Away;
+ }
+ rc = 0;
+Away:
+ if (rc < 0) {
+ if (Request_memory_pool) {
+ kmem_cache_destroy(Request_memory_pool);
+ Request_memory_pool = NULL;
+ }
+ }
+ return rc;
+}
+
+/* Destructor for filexfer.o.
+ */
+void
+filexfer_destructor(void)
+{
+ if (Request_memory_pool) {
+ kmem_cache_destroy(Request_memory_pool);
+ Request_memory_pool = NULL;
+ }
+}
+
+/* This function will obtain an available chunk from the controlvm payload area,
+ * store the size in bytes of the chunk in <actual_size>, and return a pointer
+ * to the chunk. The function is passed to the sparfilexfer driver, which calls
+ * it whenever payload space is required to copy file data into.
+ */
+static void *
+get_empty_bucket_for_getfile_data(void *context,
+ ulong min_size, ulong max_size,
+ ulong *actual_size)
+{
+ void *bucket;
+ struct any_request *req = (struct any_request *) context;
+
+ if (!req->is_get) {
+ LOGERR("%s - unexpected call", __func__);
+ return NULL;
+ }
+ bucket = (*req->get.get_contiguous_controlvm_payload)
+ (min_size, max_size, actual_size);
+ if (bucket != NULL) {
+ atomic_inc(&req->get.buffers_in_use);
+ DBGINF("%s - sent %lu-byte buffer", __func__, *actual_size);
+ }
+ return bucket;
+}
+
+/* This function will send a controlvm response with data in the payload
+ * (whose space was obtained with get_empty_bucket_for_getfile_data). The
+ * function is passed to the sparfilexfer driver, which calls it whenever it
+ * wants to send file data back across the controlvm channel.
+ */
+static int
+send_full_getfile_data_bucket(void *context, void *bucket,
+ ulong bucket_actual_size, ulong bucket_used_size)
+{
+ struct any_request *req = (struct any_request *) context;
+
+ if (!req->is_get) {
+ LOGERR("%s - unexpected call", __func__);
+ return 0;
+ }
+ DBGINF("sending buffer for %lu/%lu",
+ bucket_used_size, bucket_actual_size);
+ if (!(*req->get.controlvm_respond_with_payload)
+ (&req->get.controlvm_header,
+ req->file_request_number,
+ req->data_sequence_number++,
+ 0, bucket, bucket_actual_size, bucket_used_size, TRUE))
+ atomic_dec(&req->get.buffers_in_use);
+ return 0;
+}
+
+/* This function will send a controlvm response indicating the end of a
+ * GETFILE transfer. The function is passed to the sparfilexfer driver.
+ */
+static void
+send_end_of_getfile_data(void *context, int status)
+{
+ struct any_request *req = (struct any_request *) context;
+ if (!req->is_get) {
+ LOGERR("%s - unexpected call", __func__);
+ return;
+ }
+ LOGINF("status=%d", status);
+ (*req->get.controlvm_respond_with_payload)
+ (&req->get.controlvm_header,
+ req->file_request_number,
+ req->data_sequence_number++, status, NULL, 0, 0, FALSE);
+ free_request(req, __FILE__, __LINE__);
+ module_put(THIS_MODULE);
+}
+
+/* This function supplies data for a PUTFILE transfer.
+ * The function is passed to the sparfilexfer driver.
+ */
+static int
+get_putfile_data(void *context, void *pbuf, size_t bufsize,
+ BOOL buf_is_userspace, size_t *bytes_transferred)
+{
+ struct any_request *req = (struct any_request *) context;
+ if (req->is_get) {
+ LOGERR("%s - unexpected call", __func__);
+ return -1;
+ }
+ return (*req->put.get_controlvm_filedata) (&req->caller_context_data[0],
+ pbuf, bufsize,
+ buf_is_userspace,
+ bytes_transferred);
+}
+
+/* This function is called to indicate the end of a PUTFILE transfer.
+ * The function is passed to the sparfilexfer driver.
+ */
+static void
+end_putfile(void *context, int status)
+{
+ struct any_request *req = (struct any_request *) context;
+ if (req->is_get) {
+ LOGERR("%s - unexpected call", __func__);
+ return;
+ }
+ (*req->put.controlvm_end_putFile) (&req->caller_context_data[0],
+ status);
+ free_request(req, __FILE__, __LINE__);
+ module_put(THIS_MODULE);
+}
+
+/* Refer to filexfer.h for description. */
+BOOL
+filexfer_getFile(CONTROLVM_MESSAGE_HEADER *msgHdr,
+ ulong2 file_request_number,
+ uint uplink_index,
+ uint disk_index,
+ char *file_name,
+ GET_CONTIGUOUS_CONTROLVM_PAYLOAD_FUNC
+ get_contiguous_controlvm_payload,
+ CONTROLVM_RESPOND_WITH_PAYLOAD_FUNC
+ controlvm_respond_with_payload,
+ TRANSMITFILE_DUMP_FUNC dump_func)
+{
+ BOOL use_count_up = FALSE;
+ BOOL failed = TRUE;
+ struct any_request *req = alloc_request(__FILE__, __LINE__);
+
+ if (!req) {
+ LOGERR("allocation of any_request failed");
+ goto Away;
+ }
+ /* We need to increment this module's use count because we're handing
+ * off pointers to functions within this module to be used by
+ * another module.
+ */
+ __module_get(THIS_MODULE);
+ use_count_up = TRUE;
+ req->is_get = TRUE;
+ req->file_request_number = file_request_number;
+ req->data_sequence_number = 0;
+ req->dump_func = dump_func;
+ req->get.controlvm_header = *msgHdr;
+ atomic_set(&req->get.buffers_in_use, 0);
+ req->get.get_contiguous_controlvm_payload =
+ get_contiguous_controlvm_payload;
+ req->get.controlvm_respond_with_payload =
+ controlvm_respond_with_payload;
+ if (sparfilexfer_local2remote(req, /* context, passed to
+ * callback funcs */
+ file_name,
+ file_request_number,
+ uplink_index,
+ disk_index,
+ get_empty_bucket_for_getfile_data,
+ send_full_getfile_data_bucket,
+ send_end_of_getfile_data) < 0) {
+ LOGERR("sparfilexfer_local2remote failed");
+ goto Away;
+ }
+ failed = FALSE;
+Away:
+ if (failed) {
+ if (use_count_up) {
+ module_put(THIS_MODULE);
+ use_count_up = FALSE;
+ }
+ if (req) {
+ free_request(req, __FILE__, __LINE__);
+ req = NULL;
+ }
+ return FALSE;
+ } else {
+ return TRUE;
+ /* success; send callbacks will be called for responses */
+ }
+}
+
+/* Refer to filexfer.h for description. */
+void *
+filexfer_putFile(CONTROLVM_MESSAGE_HEADER *msgHdr,
+ ulong2 file_request_number,
+ uint uplink_index,
+ uint disk_index,
+ char *file_name,
+ TRANSMITFILE_INIT_CONTEXT_FUNC init_context,
+ GET_CONTROLVM_FILEDATA_FUNC get_controlvm_filedata,
+ CONTROLVM_RESPOND_FUNC controlvm_end_putFile,
+ TRANSMITFILE_DUMP_FUNC dump_func)
+{
+ BOOL use_count_up = FALSE;
+ BOOL failed = TRUE;
+ struct any_request *req = alloc_request(__FILE__, __LINE__);
+ void *caller_ctx = NULL;
+
+ if (!req) {
+ LOGERR("allocation of any_request failed");
+ goto Away;
+ }
+ caller_ctx = (void *) (&(req->caller_context_data[0]));
+ /* We need to increment this module's use count because we're handing
+ * off pointers to functions within this module to be used by
+ * another module.
+ */
+ __module_get(THIS_MODULE);
+ use_count_up = TRUE;
+ req->is_get = FALSE;
+ req->file_request_number = file_request_number;
+ req->data_sequence_number = 0;
+ req->dump_func = dump_func;
+ req->put.get_controlvm_filedata = get_controlvm_filedata;
+ req->put.controlvm_end_putFile = controlvm_end_putFile;
+ (*init_context) (caller_ctx, msgHdr, file_request_number);
+ if (sparfilexfer_remote2local(req, /* context, passed to
+ * callback funcs */
+ file_name,
+ file_request_number,
+ uplink_index,
+ disk_index,
+ get_putfile_data, end_putfile) < 0) {
+ LOGERR("sparfilexfer_remote2local failed");
+ goto Away;
+ }
+ failed = FALSE;
+Away:
+ if (failed) {
+ if (use_count_up) {
+ module_put(THIS_MODULE);
+ use_count_up = FALSE;
+ }
+ if (req) {
+ free_request(req, __FILE__, __LINE__);
+ req = NULL;
+ }
+ return NULL;
+ } else {
+ return caller_ctx;
+ /* success; callbacks will be called for responses */
+ }
+}
+
+static void
+dump_get_request(struct seq_file *f, struct getfile_request *getreq)
+{
+ seq_printf(f, " buffers_in_use=%d\n",
+ atomic_read(&getreq->buffers_in_use));
+}
+
+static void
+dump_put_request(struct seq_file *f, struct putfile_request *putreq)
+{
+}
+
+static void
+dump_request(struct seq_file *f, struct any_request *req)
+{
+ seq_printf(f, "* %s id=%llu seq=%llu\n",
+ ((req->is_get) ? "Get" : "Put"),
+ req->file_request_number, req->data_sequence_number);
+ if (req->is_get)
+ dump_get_request(f, &req->get);
+ else
+ dump_put_request(f, &req->put);
+ if (req->dump_func)
+ (*req->dump_func) (f, &(req->caller_context_data[0]), " ");
+}
+
+void
+filexfer_dump(struct seq_file *f)
+{
+ ulong flags;
+ struct list_head *entry;
+
+ seq_puts(f, "Outstanding TRANSMIT_FILE requests:\n");
+ spin_lock_irqsave(&Request_list_lock, flags);
+ list_for_each(entry, &Request_list) {
+ struct any_request *req;
+ req = list_entry(entry, struct any_request, req_list);
+ dump_request(f, req);
+ }
+ spin_unlock_irqrestore(&Request_list_lock, flags);
+}
+
+#else /* ifdef ENABLE_SPARFILEXFER */
+int
+filexfer_constructor(size_t req_context_bytes)
+{
+ return 0; /* success */
+}
+
+void
+filexfer_destructor(void)
+{
+}
+
+BOOL
+filexfer_getFile(CONTROLVM_MESSAGE_HEADER *msgHdr,
+ u64 file_request_number,
+ uint uplink_index,
+ uint disk_index,
+ char *file_name,
+ GET_CONTIGUOUS_CONTROLVM_PAYLOAD_FUNC
+ get_contiguous_controlvm_payload,
+ CONTROLVM_RESPOND_WITH_PAYLOAD_FUNC
+ controlvm_respond_with_payload,
+ TRANSMITFILE_DUMP_FUNC dump_func)
+{
+ /* since no sparfilexfer module exists to call, we just fail */
+ return FALSE;
+}
+
+void *
+filexfer_putFile(CONTROLVM_MESSAGE_HEADER *msgHdr,
+ u64 file_request_number,
+ uint uplink_index,
+ uint disk_index,
+ char *file_name,
+ TRANSMITFILE_INIT_CONTEXT_FUNC init_context,
+ GET_CONTROLVM_FILEDATA_FUNC get_controlvm_filedata,
+ CONTROLVM_RESPOND_FUNC controlvm_end_putFile,
+ TRANSMITFILE_DUMP_FUNC dump_func)
+{
+ /* since no sparfilexfer module exists to call, we just fail */
+ return NULL;
+}
+
+void
+filexfer_dump(struct seq_file *f)
+{
+}
+
+#endif /* ifdef ENABLE_SPARFILEXFER */
--- /dev/null
+/* filexfer.h
+ *
+ * Copyright © 2013 - 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.
+ */
+
+/* This header file defines the interface that filexfer.c provides to other
+ * code in the visorchipset driver.
+ */
+
+#ifndef __FILEXFER_H__
+#define __FILEXFER_H__
+
+#include "globals.h"
+#include "controlvmchannel.h"
+#include <linux/seq_file.h>
+
+typedef void *(*GET_CONTIGUOUS_CONTROLVM_PAYLOAD_FUNC) (ulong min_size,
+ ulong max_size,
+ ulong *actual_size);
+
+typedef BOOL
+(*CONTROLVM_RESPOND_WITH_PAYLOAD_FUNC) (CONTROLVM_MESSAGE_HEADER *msgHdr,
+ u64 fileRequestNumber,
+ u64 dataSequenceNumber,
+ int response,
+ void *bucket, ulong payloadChunkSize,
+ ulong payloadUsedBytes, BOOL partial);
+
+typedef void
+(*TRANSMITFILE_INIT_CONTEXT_FUNC)(void *ctx,
+ const CONTROLVM_MESSAGE_HEADER *hdr,
+ u64 file_request_number);
+typedef void (*TRANSMITFILE_DUMP_FUNC) (struct seq_file *f, void *ctx,
+ const char *pfx);
+typedef int (*GET_CONTROLVM_FILEDATA_FUNC) (void *ctx,
+ void *buf, size_t bufsize,
+ BOOL buf_is_userspace,
+ size_t *bytes_transferred);
+typedef void (*CONTROLVM_RESPOND_FUNC) (void *ctx, int response);
+
+/* Call once to initialize filexfer.o.
+ * req_context_bytes number of bytes the caller needs to keep track of each file
+ * transfer conversation. The <ctx_init_value> passed to filexfer_putFile() is
+ * assumed to be this many bytes in size. Code within filexfer.o will copy this
+ * into a dynamically-allocated area, and pass back a pointer to that area in
+ * callback functions.
+ */
+int filexfer_constructor(size_t req_context_bytes);
+
+/* Call once to clean up filexfer.o */
+void filexfer_destructor(void);
+
+/* Call this to dump diagnostic info about all outstanding getFiles/putFiles */
+void filexfer_dump(struct seq_file *f);
+
+/* Call to transfer a file from the local filesystem (i.e., from the environment
+ * where this driver is running) across the controlvm channel to a remote
+ * environment. 1 or more controlvm responses will be sent as a result, each
+ * of which whose payload contains file data. Only the last controlvm message
+ * will have Flags.partialCompletion==0.
+ *
+ * msgHdr the controlvm message header of the GETFILE request which
+ * we just received
+ * file_request_number this is all data from the GETFILE request that
+ * uplink_index define which file is to be transferred
+ * disk_index
+ * file_name
+ * get_contiguous_controlvm_payload function to call when space is needed
+ * in the payload area
+ * controlvm_respond_with_payload function to call to send each controlvm
+ * response containing file data as the
+ * payload; returns FALSE only if the
+ * payload buffer was freed inline
+ * dump_func function to dump context data in
+ * human-readable format
+ *
+ * Returns TRUE iff the file transfer request has been successfully initiated,
+ * or FALSE to indicate failure.
+ */
+BOOL
+filexfer_getFile(CONTROLVM_MESSAGE_HEADER *msgHdr,
+ u64 file_request_number,
+ uint uplink_index,
+ uint disk_index,
+ char *file_name,
+ GET_CONTIGUOUS_CONTROLVM_PAYLOAD_FUNC
+ get_contiguous_controlvm_payload,
+ CONTROLVM_RESPOND_WITH_PAYLOAD_FUNC
+ controlvm_respond_with_payload,
+ TRANSMITFILE_DUMP_FUNC dump_func);
+
+/* Call to create a file in the local filesystem (i.e., in the environment
+ * where this driver is running) from data received as payload in
+ * controlvm channel messages from a remote environment. 1 or more controlvm
+ * messages will be received for this transfer, and only the last will have
+ * Flags.partialCompletion==0.
+ *
+ * msgHdr the controlvm message header of the PUTFILE request which
+ * we just received
+ * file_request_number this is all data from the PUTFILE request that
+ * uplink_index define which file is to be created in the local
+ * disk_index filesystem
+ * file_name
+ * init_context function to call to initialize the
+ * <req_context_bytes>-sized storage area returned by
+ * this func; note that it would NOT be sufficient to
+ * allow the caller to initialize this upon return, as
+ * the the other user-supplied callbacks might have
+ * already been called by then
+ * get_controlvm_filedata function to call to obtain more data for the file
+ * being written; refer to get_controlvm_filedata()
+ * in visorchipset_main.c for a complete description
+ * of parameters
+ * controlvm_end_putFile function to call to indicate that creation of the
+ * local file has completed; set <response> to a
+ * negative value to indicate an error
+ * dump_func function to dump context data in human-readable
+ * format
+ *
+ * Returns a pointer to a dynamically-allocated storage area of size
+ * <req_context_bytes> which the caller can use, or NULL for error. The
+ * caller should NEVER free the returned pointer, but should expect to receive
+ * it as the <ctx> argument when callback functions are called.
+ */
+void *filexfer_putFile(CONTROLVM_MESSAGE_HEADER *msgHdr,
+ u64 file_request_number,
+ uint uplink_index,
+ uint disk_index,
+ char *file_name,
+ TRANSMITFILE_INIT_CONTEXT_FUNC init_context,
+ GET_CONTROLVM_FILEDATA_FUNC get_controlvm_filedata,
+ CONTROLVM_RESPOND_FUNC controlvm_end_putFile,
+ TRANSMITFILE_DUMP_FUNC dump_func);
+
+#endif
--- /dev/null
+/* globals.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 __VISORCHIPSET_GLOBALS_H__
+#define __VISORCHIPSET_GLOBALS_H__
+
+#include "uniklog.h"
+#include "diagnostics/appos_subsystems.h"
+#include "timskmod.h"
+#include "visorchipset.h"
+#include "visorchipset_umode.h"
+#include "version.h"
+
+#define MYDRVNAME "visorchipset"
+
+
+/* module parameters */
+
+extern int visorchipset_testvnic;
+extern int visorchipset_testvnicclient;
+extern int visorchipset_testmsg;
+extern int visorchipset_major;
+extern int visorchipset_serverregwait;
+extern int visorchipset_clientregwait;
+extern int visorchipset_testteardown;
+extern int visorchipset_disable_controlvm;
+extern int visorchipset_crash_kernel;
+extern int visorchipset_holdchipsetready;
+
+#endif
--- /dev/null
+/* parser.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 "parser.h"
+#include "memregion.h"
+#include "controlvmchannel.h"
+#include <linux/ctype.h>
+#include <linux/mm.h>
+
+#define MYDRVNAME "visorchipset_parser"
+#define CURRENT_FILE_PC VISOR_CHIPSET_PC_parser_c
+
+/* We will refuse to allocate more than this many bytes to copy data from
+ * incoming payloads. This serves as a throttling mechanism.
+ */
+#define MAX_CONTROLVM_PAYLOAD_BYTES (1024*128)
+static ulong Controlvm_Payload_Bytes_Buffered;
+
+struct PARSER_CONTEXT_Tag {
+ ulong allocbytes;
+ ulong param_bytes;
+ u8 *curr;
+ ulong bytes_remaining;
+ BOOL byte_stream;
+ char data[0];
+};
+
+static PARSER_CONTEXT *
+parser_init_guts(U64 addr, U32 bytes, BOOL isLocal,
+ BOOL hasStandardPayloadHeader, BOOL *tryAgain)
+{
+ int allocbytes = sizeof(PARSER_CONTEXT) + bytes;
+ PARSER_CONTEXT *rc = NULL;
+ PARSER_CONTEXT *ctx = NULL;
+ MEMREGION *rgn = NULL;
+ ULTRA_CONTROLVM_PARAMETERS_HEADER *phdr = NULL;
+
+ if (tryAgain)
+ *tryAgain = FALSE;
+ if (!hasStandardPayloadHeader)
+ /* alloc and 0 extra byte to ensure payload is
+ * '\0'-terminated
+ */
+ allocbytes++;
+ if ((Controlvm_Payload_Bytes_Buffered + bytes)
+ > MAX_CONTROLVM_PAYLOAD_BYTES) {
+ ERRDRV("%s (%s:%d) - prevented allocation of %d bytes to prevent exceeding throttling max (%d)",
+ __func__, __FILE__, __LINE__, allocbytes,
+ MAX_CONTROLVM_PAYLOAD_BYTES);
+ if (tryAgain)
+ *tryAgain = TRUE;
+ RETPTR(NULL);
+ }
+ ctx = kmalloc(allocbytes, GFP_KERNEL|__GFP_NORETRY);
+ if (ctx == NULL) {
+ ERRDRV("%s (%s:%d) - failed to allocate %d bytes",
+ __func__, __FILE__, __LINE__, allocbytes);
+ if (tryAgain)
+ *tryAgain = TRUE;
+ RETPTR(NULL);
+ }
+ memset(ctx, 0, allocbytes);
+ ctx->allocbytes = allocbytes;
+ ctx->param_bytes = bytes;
+ ctx->curr = NULL;
+ ctx->bytes_remaining = 0;
+ ctx->byte_stream = FALSE;
+ if (isLocal) {
+ void *p;
+ if (addr > virt_to_phys(high_memory - 1)) {
+ ERRDRV("%s - bad local address (0x%-16.16Lx for %lu)",
+ __func__,
+ (unsigned long long) addr, (ulong) bytes);
+ RETPTR(NULL);
+ }
+ p = __va((ulong) (addr));
+ memcpy(ctx->data, p, bytes);
+ } else {
+ rgn = memregion_create(addr, bytes);
+ if (!rgn)
+ RETPTR(NULL);
+ if (memregion_read(rgn, 0, ctx->data, bytes) < 0)
+ RETPTR(NULL);
+ }
+ if (!hasStandardPayloadHeader) {
+ ctx->byte_stream = TRUE;
+ RETPTR(ctx);
+ }
+ phdr = (ULTRA_CONTROLVM_PARAMETERS_HEADER *) (ctx->data);
+ if (phdr->TotalLength != bytes) {
+ ERRDRV("%s - bad total length %lu (should be %lu)",
+ __func__,
+ (ulong) (phdr->TotalLength), (ulong) (bytes));
+ RETPTR(NULL);
+ }
+ if (phdr->TotalLength < phdr->HeaderLength) {
+ ERRDRV("%s - total length < header length (%lu < %lu)",
+ __func__,
+ (ulong) (phdr->TotalLength),
+ (ulong) (phdr->HeaderLength));
+ RETPTR(NULL);
+ }
+ if (phdr->HeaderLength < sizeof(ULTRA_CONTROLVM_PARAMETERS_HEADER)) {
+ ERRDRV("%s - header is too small (%lu < %lu)",
+ __func__,
+ (ulong) (phdr->HeaderLength),
+ (ulong) (sizeof(ULTRA_CONTROLVM_PARAMETERS_HEADER)));
+ RETPTR(NULL);
+ }
+
+ RETPTR(ctx);
+
+Away:
+ if (rgn) {
+ memregion_destroy(rgn);
+ rgn = NULL;
+ }
+ if (rc)
+ Controlvm_Payload_Bytes_Buffered += ctx->param_bytes;
+ else {
+ if (ctx) {
+ parser_done(ctx);
+ ctx = NULL;
+ }
+ }
+ return rc;
+}
+
+PARSER_CONTEXT *
+parser_init(U64 addr, U32 bytes, BOOL isLocal, BOOL *tryAgain)
+{
+ return parser_init_guts(addr, bytes, isLocal, TRUE, tryAgain);
+}
+
+/* Call this instead of parser_init() if the payload area consists of just
+ * a sequence of bytes, rather than a ULTRA_CONTROLVM_PARAMETERS_HEADER
+ * structures. Afterwards, you can call parser_simpleString_get() or
+ * parser_byteStream_get() to obtain the data.
+ */
+PARSER_CONTEXT *
+parser_init_byteStream(U64 addr, U32 bytes, BOOL isLocal, BOOL *tryAgain)
+{
+ return parser_init_guts(addr, bytes, isLocal, FALSE, tryAgain);
+}
+
+/* Obtain '\0'-terminated copy of string in payload area.
+ */
+char *
+parser_simpleString_get(PARSER_CONTEXT *ctx)
+{
+ if (!ctx->byte_stream)
+ return NULL;
+ return ctx->data; /* note this IS '\0'-terminated, because of
+ * the num of bytes we alloc+clear in
+ * parser_init_byteStream() */
+}
+
+/* Obtain a copy of the buffer in the payload area.
+ */
+void *
+parser_byteStream_get(PARSER_CONTEXT *ctx, ulong *nbytes)
+{
+ if (!ctx->byte_stream)
+ return NULL;
+ if (nbytes)
+ *nbytes = ctx->param_bytes;
+ return (void *) ctx->data;
+}
+
+GUID
+parser_id_get(PARSER_CONTEXT *ctx)
+{
+ ULTRA_CONTROLVM_PARAMETERS_HEADER *phdr = NULL;
+
+ if (ctx == NULL) {
+ ERRDRV("%s (%s:%d) - no context",
+ __func__, __FILE__, __LINE__);
+ return Guid0;
+ }
+ phdr = (ULTRA_CONTROLVM_PARAMETERS_HEADER *) (ctx->data);
+ return phdr->Id;
+}
+
+void
+parser_param_start(PARSER_CONTEXT *ctx, PARSER_WHICH_STRING which_string)
+{
+ ULTRA_CONTROLVM_PARAMETERS_HEADER *phdr = NULL;
+
+ if (ctx == NULL) {
+ ERRDRV("%s (%s:%d) - no context",
+ __func__, __FILE__, __LINE__);
+ RETVOID;
+ }
+ phdr = (ULTRA_CONTROLVM_PARAMETERS_HEADER *) (ctx->data);
+ switch (which_string) {
+ case PARSERSTRING_INITIATOR:
+ ctx->curr = ctx->data + phdr->InitiatorOffset;
+ ctx->bytes_remaining = phdr->InitiatorLength;
+ break;
+ case PARSERSTRING_TARGET:
+ ctx->curr = ctx->data + phdr->TargetOffset;
+ ctx->bytes_remaining = phdr->TargetLength;
+ break;
+ case PARSERSTRING_CONNECTION:
+ ctx->curr = ctx->data + phdr->ConnectionOffset;
+ ctx->bytes_remaining = phdr->ConnectionLength;
+ break;
+ case PARSERSTRING_NAME:
+ ctx->curr = ctx->data + phdr->NameOffset;
+ ctx->bytes_remaining = phdr->NameLength;
+ break;
+ default:
+ ERRDRV("%s - bad which_string %d", __func__, which_string);
+ RETVOID;
+ break;
+ }
+ RETVOID;
+
+Away:
+ return;
+}
+
+void
+parser_done(PARSER_CONTEXT *ctx)
+{
+ if (!ctx)
+ return;
+ Controlvm_Payload_Bytes_Buffered -= ctx->param_bytes;
+ kfree(ctx);
+}
+
+/** Return length of string not counting trailing spaces. */
+static int
+string_length_no_trail(char *s, int len)
+{
+ int i = len - 1;
+ while (i >= 0) {
+ if (!isspace(s[i]))
+ return i + 1;
+ i--;
+ }
+ return 0;
+}
+
+/** Grab the next name and value out of the parameter buffer.
+ * The entire parameter buffer looks like this:
+ * <name>=<value>\0
+ * <name>=<value>\0
+ * ...
+ * \0
+ * If successful, the next <name> value is returned within the supplied
+ * <nam> buffer (the value is always upper-cased), and the corresponding
+ * <value> is returned within a kmalloc()ed buffer, whose pointer is
+ * provided as the return value of this function.
+ * (The total number of bytes allocated is strlen(<value>)+1.)
+ *
+ * NULL is returned to indicate failure, which can occur for several reasons:
+ * - all <name>=<value> pairs have already been processed
+ * - bad parameter
+ * - parameter buffer ends prematurely (couldn't find an '=' or '\0' within
+ * the confines of the parameter buffer)
+ * - the <nam> buffer is not large enough to hold the <name> of the next
+ * parameter
+ */
+void *
+parser_param_get(PARSER_CONTEXT *ctx, char *nam, int namesize)
+{
+ u8 *pscan, *pnam = nam;
+ ulong nscan;
+ int value_length = -1, orig_value_length = -1;
+ void *value = NULL;
+ int i;
+ int closing_quote = 0;
+
+ if (!ctx)
+ return NULL;
+ pscan = ctx->curr;
+ nscan = ctx->bytes_remaining;
+ if (nscan == 0)
+ return NULL;
+ if (*pscan == '\0')
+ /* This is the normal return point after you have processed
+ * all of the <name>=<value> pairs in a syntactically-valid
+ * parameter buffer.
+ */
+ return NULL;
+
+ /* skip whitespace */
+ while (isspace(*pscan)) {
+ pscan++;
+ nscan--;
+ if (nscan == 0)
+ return NULL;
+ }
+
+ while (*pscan != ':') {
+ if (namesize <= 0) {
+ ERRDRV("%s - name too big", __func__);
+ return NULL;
+ }
+ *pnam = toupper(*pscan);
+ pnam++;
+ namesize--;
+ pscan++;
+ nscan--;
+ if (nscan == 0) {
+ ERRDRV("%s - unexpected end of input parsing name",
+ __func__);
+ return NULL;
+ }
+ }
+ if (namesize <= 0) {
+ ERRDRV("%s - name too big", __func__);
+ return NULL;
+ }
+ *pnam = '\0';
+ nam[string_length_no_trail(nam, strlen(nam))] = '\0';
+
+ /* point to char immediately after ":" in "<name>:<value>" */
+ pscan++;
+ nscan--;
+ /* skip whitespace */
+ while (isspace(*pscan)) {
+ pscan++;
+ nscan--;
+ if (nscan == 0) {
+ ERRDRV("%s - unexpected end of input looking for value",
+ __func__);
+ return NULL;
+ }
+ }
+ if (nscan == 0) {
+ ERRDRV("%s - unexpected end of input looking for value",
+ __func__);
+ return NULL;
+ }
+ if (*pscan == '\'' || *pscan == '"') {
+ closing_quote = *pscan;
+ pscan++;
+ nscan--;
+ if (nscan == 0) {
+ ERRDRV("%s - unexpected end of input after %c",
+ __func__, closing_quote);
+ return NULL;
+ }
+ }
+
+ /* look for a separator character, terminator character, or
+ * end of data
+ */
+ for (i = 0, value_length = -1; i < nscan; i++) {
+ if (closing_quote) {
+ if (pscan[i] == '\0') {
+ ERRDRV("%s - unexpected end of input parsing quoted value", __func__);
+ return NULL;
+ }
+ if (pscan[i] == closing_quote) {
+ value_length = i;
+ break;
+ }
+ } else
+ if (pscan[i] == ',' || pscan[i] == ';'
+ || pscan[i] == '\0') {
+ value_length = i;
+ break;
+ }
+ }
+ if (value_length < 0) {
+ if (closing_quote) {
+ ERRDRV("%s - unexpected end of input parsing quoted value", __func__);
+ return NULL;
+ }
+ value_length = nscan;
+ }
+ orig_value_length = value_length;
+ if (closing_quote == 0)
+ value_length = string_length_no_trail(pscan, orig_value_length);
+ value = kmalloc(value_length + 1, GFP_KERNEL|__GFP_NORETRY);
+ if (value == NULL)
+ return NULL;
+ memcpy(value, pscan, value_length);
+ ((u8 *) (value))[value_length] = '\0';
+
+ pscan += orig_value_length;
+ nscan -= orig_value_length;
+
+ /* skip past separator or closing quote */
+ if (nscan > 0) {
+ if (*pscan != '\0') {
+ pscan++;
+ nscan--;
+ }
+ }
+
+ if (closing_quote && (nscan > 0)) {
+ /* we still need to skip around the real separator if present */
+ /* first, skip whitespace */
+ while (isspace(*pscan)) {
+ pscan++;
+ nscan--;
+ if (nscan == 0)
+ break;
+ }
+ if (nscan > 0) {
+ if (*pscan == ',' || *pscan == ';') {
+ pscan++;
+ nscan--;
+ } else if (*pscan != '\0') {
+ ERRDRV("%s - missing separator after quoted string", __func__);
+ kfree(value);
+ value = NULL;
+ return NULL;
+ }
+ }
+ }
+ ctx->curr = pscan;
+ ctx->bytes_remaining = nscan;
+ return value;
+}
+
+void *
+parser_string_get(PARSER_CONTEXT *ctx)
+{
+ u8 *pscan;
+ ulong nscan;
+ int value_length = -1;
+ void *value = NULL;
+ int i;
+
+ if (!ctx)
+ return NULL;
+ pscan = ctx->curr;
+ nscan = ctx->bytes_remaining;
+ if (nscan == 0)
+ return NULL;
+ if (!pscan)
+ return NULL;
+ for (i = 0, value_length = -1; i < nscan; i++)
+ if (pscan[i] == '\0') {
+ value_length = i;
+ break;
+ }
+ if (value_length < 0) /* '\0' was not included in the length */
+ value_length = nscan;
+ value = kmalloc(value_length + 1, GFP_KERNEL|__GFP_NORETRY);
+ if (value == NULL)
+ return NULL;
+ if (value_length > 0)
+ memcpy(value, pscan, value_length);
+ ((u8 *) (value))[value_length] = '\0';
+ return value;
+}
--- /dev/null
+/* parser.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 __PARSER_H__
+#define __PARSER_H__
+
+#include "uniklog.h"
+#include "timskmod.h"
+#include "channel.h"
+
+typedef enum {
+ PARSERSTRING_INITIATOR,
+ PARSERSTRING_TARGET,
+ PARSERSTRING_CONNECTION,
+ PARSERSTRING_NAME,
+} PARSER_WHICH_STRING;
+
+typedef struct PARSER_CONTEXT_Tag PARSER_CONTEXT;
+
+PARSER_CONTEXT *parser_init(U64 addr, U32 bytes, BOOL isLocal, BOOL *tryAgain);
+PARSER_CONTEXT *parser_init_byteStream(U64 addr, U32 bytes, BOOL isLocal,
+ BOOL *tryAgain);
+void parser_param_start(PARSER_CONTEXT *ctx, PARSER_WHICH_STRING which_string);
+void *parser_param_get(PARSER_CONTEXT *ctx, char *nam, int namesize);
+void *parser_string_get(PARSER_CONTEXT *ctx);
+GUID parser_id_get(PARSER_CONTEXT *ctx);
+char *parser_simpleString_get(PARSER_CONTEXT *ctx);
+void *parser_byteStream_get(PARSER_CONTEXT *ctx, ulong *nbytes);
+void parser_done(PARSER_CONTEXT *ctx);
+
+#endif
--- /dev/null
+/* testing.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 __VISORCHIPSET_TESTING_H__
+#define __VISORCHIPSET_TESTING_H__
+
+#define VISORCHIPSET_TEST_PROC
+#include "globals.h"
+#include "controlvmchannel.h"
+
+void test_produce_test_message(CONTROLVM_MESSAGE *msg, int isLocalTestAddr);
+BOOL test_consume_test_message(CONTROLVM_MESSAGE *msg);
+void test_manufacture_vnic_client_add(void *p);
+void test_manufacture_vnic_client_add_phys(HOSTADDRESS addr);
+void test_manufacture_preamble_messages(void);
+void test_manufacture_device_attach(ulong busNo, ulong devNo);
+void test_manufacture_device_add(ulong busNo, ulong devNo, GUID dataTypeGuid,
+ void *pChannel);
+void test_manufacture_add_bus(ulong busNo, ulong maxDevices,
+ GUID id, u8 *name, BOOL isServer);
+void test_manufacture_device_destroy(ulong busNo, ulong devNo);
+void test_manufacture_bus_destroy(ulong busNo);
+void test_manufacture_detach_externalPort(ulong switchNo, ulong externalPortNo);
+void test_manufacture_detach_internalPort(ulong switchNo, ulong internalPortNo);
+void test_cleanup(void);
+
+#endif
--- /dev/null
+/* visorchipset.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 __VISORCHIPSET_H__
+#define __VISORCHIPSET_H__
+
+#include "timskmod.h"
+#include "channel.h"
+#include "controlvmchannel.h"
+#include "parser.h"
+#include "procobjecttree.h"
+#include "vbusdeviceinfo.h"
+#include "vbushelper.h"
+
+/** Describes the state from the perspective of which controlvm messages have
+ * been received for a bus or device.
+ */
+typedef struct {
+ U32 created:1;
+ U32 attached:1;
+ U32 configured:1;
+ U32 running:1;
+ /* Add new fields above. */
+ /* Remaining bits in this 32-bit word are unused. */
+} VISORCHIPSET_STATE;
+
+typedef enum {
+ /** address is guest physical, but outside of the physical memory
+ * region that is controlled by the running OS (this is the normal
+ * address type for Supervisor channels)
+ */
+ ADDRTYPE_localPhysical,
+
+ /** address is guest physical, and withIN the confines of the
+ * physical memory controlled by the running OS.
+ */
+ ADDRTYPE_localTest,
+} VISORCHIPSET_ADDRESSTYPE;
+
+typedef enum {
+ CRASH_dev,
+ CRASH_bus,
+} CRASH_OBJ_TYPE;
+
+/** Attributes for a particular Supervisor channel.
+ */
+typedef struct {
+ VISORCHIPSET_ADDRESSTYPE addrType;
+ HOSTADDRESS channelAddr;
+ struct InterruptInfo intr;
+ U64 nChannelBytes;
+ GUID channelTypeGuid;
+ GUID channelInstGuid;
+
+} VISORCHIPSET_CHANNEL_INFO;
+
+/** Attributes for a particular Supervisor device.
+ * Any visorchipset client can query these attributes using
+ * visorchipset_get_client_device_info() or
+ * visorchipset_get_server_device_info().
+ */
+typedef struct {
+ struct list_head entry;
+ U32 busNo;
+ U32 devNo;
+ GUID devInstGuid;
+ VISORCHIPSET_STATE state;
+ VISORCHIPSET_CHANNEL_INFO chanInfo;
+ U32 Reserved1; /* CONTROLVM_ID */
+ U64 Reserved2;
+ U32 switchNo; /* when devState.attached==1 */
+ U32 internalPortNo; /* when devState.attached==1 */
+ CONTROLVM_MESSAGE_HEADER pendingMsgHdr; /* CONTROLVM_MESSAGE */
+ /** For private use by the bus driver */
+ void *bus_driver_context;
+
+} VISORCHIPSET_DEVICE_INFO;
+
+static inline VISORCHIPSET_DEVICE_INFO *
+finddevice(struct list_head *list, U32 busNo, U32 devNo)
+{
+ VISORCHIPSET_DEVICE_INFO *p;
+
+ list_for_each_entry(p, list, entry) {
+ if (p->busNo == busNo && p->devNo == devNo)
+ return p;
+ }
+ return NULL;
+}
+
+static inline void delbusdevices(struct list_head *list, U32 busNo)
+{
+ VISORCHIPSET_DEVICE_INFO *p;
+
+ list_for_each_entry(p, list, entry) {
+ if (p->busNo == busNo) {
+ list_del(&p->entry);
+ kfree(p);
+ }
+ }
+}
+
+/** Attributes for a particular Supervisor bus.
+ * (For a service partition acting as the server for buses/devices, there
+ * is a 1-to-1 relationship between busses and guest partitions.)
+ * Any visorchipset client can query these attributes using
+ * visorchipset_get_client_bus_info() or visorchipset_get_bus_info().
+ */
+typedef struct {
+ struct list_head entry;
+ U32 busNo;
+ VISORCHIPSET_STATE state;
+ VISORCHIPSET_CHANNEL_INFO chanInfo;
+ GUID partitionGuid;
+ U64 partitionHandle;
+ U8 *name; /* UTF8 */
+ U8 *description; /* UTF8 */
+ U64 Reserved1;
+ U32 Reserved2;
+ MYPROCOBJECT *procObject;
+ struct {
+ U32 server:1;
+ /* Add new fields above. */
+ /* Remaining bits in this 32-bit word are unused. */
+ } flags;
+ CONTROLVM_MESSAGE_HEADER pendingMsgHdr; /* CONTROLVM MsgHdr */
+ /** For private use by the bus driver */
+ void *bus_driver_context;
+ U64 devNo;
+
+} VISORCHIPSET_BUS_INFO;
+
+static inline VISORCHIPSET_BUS_INFO *
+findbus(struct list_head *list, U32 busNo)
+{
+ VISORCHIPSET_BUS_INFO *p;
+
+ list_for_each_entry(p, list, entry) {
+ if (p->busNo == busNo)
+ return p;
+ }
+ return NULL;
+}
+
+/** Attributes for a particular Supervisor switch.
+ */
+typedef struct {
+ U32 switchNo;
+ VISORCHIPSET_STATE state;
+ GUID switchTypeGuid;
+ U8 *authService1;
+ U8 *authService2;
+ U8 *authService3;
+ U8 *securityContext;
+ U64 Reserved;
+ U32 Reserved2; /* CONTROLVM_ID */
+ struct device dev;
+ BOOL dev_exists;
+ CONTROLVM_MESSAGE_HEADER pendingMsgHdr;
+
+} VISORCHIPSET_SWITCH_INFO;
+
+/** Attributes for a particular Supervisor external port, which is connected
+ * to a specific switch.
+ */
+typedef struct {
+ U32 switchNo;
+ U32 externalPortNo;
+ VISORCHIPSET_STATE state;
+ GUID networkZoneGuid;
+ int pdPort;
+ U8 *ip;
+ U8 *ipNetmask;
+ U8 *ipBroadcast;
+ U8 *ipNetwork;
+ U8 *ipGateway;
+ U8 *ipDNS;
+ U64 Reserved1;
+ U32 Reserved2; /* CONTROLVM_ID */
+ struct device dev;
+ BOOL dev_exists;
+ CONTROLVM_MESSAGE_HEADER pendingMsgHdr;
+
+} VISORCHIPSET_EXTERNALPORT_INFO;
+
+/** Attributes for a particular Supervisor internal port, which is how a
+ * device connects to a particular switch.
+ */
+typedef struct {
+ U32 switchNo;
+ U32 internalPortNo;
+ VISORCHIPSET_STATE state;
+ U32 busNo; /* valid only when state.attached == 1 */
+ U32 devNo; /* valid only when state.attached == 1 */
+ U64 Reserved1;
+ U32 Reserved2; /* CONTROLVM_ID */
+ CONTROLVM_MESSAGE_HEADER pendingMsgHdr;
+ MYPROCOBJECT *procObject;
+
+} VISORCHIPSET_INTERNALPORT_INFO;
+
+/* These functions will be called from within visorchipset when certain
+ * events happen. (The implementation of these functions is outside of
+ * visorchipset.)
+ */
+typedef struct {
+ void (*bus_create)(ulong busNo);
+ void (*bus_destroy)(ulong busNo);
+ void (*device_create)(ulong busNo, ulong devNo);
+ void (*device_destroy)(ulong busNo, ulong devNo);
+ void (*device_pause)(ulong busNo, ulong devNo);
+ void (*device_resume)(ulong busNo, ulong devNo);
+ int (*get_channel_info)(GUID typeGuid, ulong *minSize,
+ ulong *maxSize);
+} VISORCHIPSET_BUSDEV_NOTIFIERS;
+
+/* These functions live inside visorchipset, and will be called to indicate
+ * responses to specific events (by code outside of visorchipset).
+ * For now, the value for each response is simply either:
+ * 0 = it worked
+ * -1 = it failed
+ */
+typedef struct {
+ void (*bus_create)(ulong busNo, int response);
+ void (*bus_destroy)(ulong busNo, int response);
+ void (*device_create)(ulong busNo, ulong devNo, int response);
+ void (*device_destroy)(ulong busNo, ulong devNo, int response);
+ void (*device_pause)(ulong busNo, ulong devNo, int response);
+ void (*device_resume)(ulong busNo, ulong devNo, int response);
+} VISORCHIPSET_BUSDEV_RESPONDERS;
+
+/** Register functions (in the bus driver) to get called by visorchipset
+ * whenever a bus or device appears for which this service partition is
+ * to be the server for. visorchipset will fill in <responders>, to
+ * indicate functions the bus driver should call to indicate message
+ * responses.
+ */
+void
+visorchipset_register_busdev_client(VISORCHIPSET_BUSDEV_NOTIFIERS *notifiers,
+ VISORCHIPSET_BUSDEV_RESPONDERS *responders,
+ ULTRA_VBUS_DEVICEINFO *driverInfo);
+
+/** Register functions (in the bus driver) to get called by visorchipset
+ * whenever a bus or device appears for which this service partition is
+ * to be the client for. visorchipset will fill in <responders>, to
+ * indicate functions the bus driver should call to indicate message
+ * responses.
+ */
+void
+visorchipset_register_busdev_server(VISORCHIPSET_BUSDEV_NOTIFIERS *notifiers,
+ VISORCHIPSET_BUSDEV_RESPONDERS *responders,
+ ULTRA_VBUS_DEVICEINFO *driverInfo);
+
+typedef void (*SPARREPORTEVENT_COMPLETE_FUNC) (CONTROLVM_MESSAGE *msg,
+ int status);
+
+void device_pause_response(ulong busNo, ulong devNo, int response);
+
+BOOL visorchipset_get_bus_info(ulong busNo, VISORCHIPSET_BUS_INFO *busInfo);
+BOOL visorchipset_get_device_info(ulong busNo, ulong devNo,
+ VISORCHIPSET_DEVICE_INFO *devInfo);
+BOOL visorchipset_get_switch_info(ulong switchNo,
+ VISORCHIPSET_SWITCH_INFO *switchInfo);
+BOOL visorchipset_get_externalport_info(ulong switchNo, ulong externalPortNo,
+ VISORCHIPSET_EXTERNALPORT_INFO
+ *externalPortInfo);
+BOOL visorchipset_set_bus_context(ulong busNo, void *context);
+BOOL visorchipset_set_device_context(ulong busNo, ulong devNo, void *context);
+int visorchipset_chipset_ready(void);
+int visorchipset_chipset_selftest(void);
+int visorchipset_chipset_notready(void);
+void visorchipset_controlvm_respond_reportEvent(CONTROLVM_MESSAGE *msg,
+ void *payload);
+void visorchipset_save_message(CONTROLVM_MESSAGE *msg, CRASH_OBJ_TYPE type);
+void *visorchipset_cache_alloc(struct kmem_cache *pool,
+ BOOL ok_to_block, char *fn, int ln);
+void visorchipset_cache_free(struct kmem_cache *pool, void *p,
+ char *fn, int ln);
+
+#if defined(TRANSMITFILE_DEBUG) || defined(DEBUG)
+#define DBG_GETFILE_PAYLOAD(msg, controlvm_header) \
+ LOGINF(msg, \
+ (ulong)controlvm_header.PayloadVmOffset, \
+ (ulong)controlvm_header.PayloadMaxBytes)
+#define DBG_GETFILE(fmt, ...) LOGINF(fmt, ##__VA_ARGS__)
+#define DBG_PUTFILE(fmt, ...) LOGINF(fmt, ##__VA_ARGS__)
+#else
+#define DBG_GETFILE_PAYLOAD(msg, controlvm_header)
+#define DBG_GETFILE(fmt, ...)
+#define DBG_PUTFILE(fmt, ...)
+#endif
+
+#endif
--- /dev/null
+/* visorchipset_main.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 "globals.h"
+#include "controlvm.h"
+#include "visorchipset.h"
+#include "procobjecttree.h"
+#include "visorchannel.h"
+#include "periodic_work.h"
+#include "testing.h"
+#include "file.h"
+#include "parser.h"
+#include "uniklog.h"
+#include "uisutils.h"
+#include "guidutils.h"
+#include "controlvmcompletionstatus.h"
+#include "guestlinuxdebug.h"
+#include "filexfer.h"
+
+#include <linux/nls.h>
+#include <linux/netdevice.h>
+#include <linux/platform_device.h>
+
+#define CURRENT_FILE_PC VISOR_CHIPSET_PC_visorchipset_main_c
+#define TEST_VNIC_PHYSITF "eth0" /* physical network itf for
+ * vnic loopback test */
+#define TEST_VNIC_SWITCHNO 1
+#define TEST_VNIC_BUSNO 9
+
+#define MAX_NAME_SIZE 128
+#define MAX_IP_SIZE 50
+#define MAXOUTSTANDINGCHANNELCOMMAND 256
+#define POLLJIFFIES_CONTROLVMCHANNEL_FAST 1
+#define POLLJIFFIES_CONTROLVMCHANNEL_SLOW 100
+
+/* 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
+ulong Poll_jiffies = POLLJIFFIES_CONTROLVMCHANNEL_FAST;
+ulong Most_recent_message_jiffies; /* when we got our last
+ * controlvm message */
+static inline char *
+NONULLSTR(char *s)
+{
+ if (s)
+ return s;
+ else
+ return "";
+}
+
+static int serverregistered;
+static int clientregistered;
+
+#define MAX_CHIPSET_EVENTS 2
+static U8 chipset_events[MAX_CHIPSET_EVENTS] = { 0, 0 };
+
+static struct delayed_work Periodic_controlvm_work;
+static struct workqueue_struct *Periodic_controlvm_workqueue;
+DEFINE_SEMAPHORE(NotifierLock);
+
+typedef struct {
+ CONTROLVM_MESSAGE message;
+ unsigned int crc;
+} MESSAGE_ENVELOPE;
+
+static CONTROLVM_MESSAGE_HEADER g_DiagMsgHdr;
+static CONTROLVM_MESSAGE_HEADER g_ChipSetMsgHdr;
+static CONTROLVM_MESSAGE_HEADER g_DelDumpMsgHdr;
+static const GUID UltraDiagPoolChannelProtocolGuid =
+ ULTRA_DIAG_POOL_CHANNEL_PROTOCOL_GUID;
+/* 0xffffff is an invalid Bus/Device number */
+static ulong g_diagpoolBusNo = 0xffffff;
+static ulong g_diagpoolDevNo = 0xffffff;
+static CONTROLVM_MESSAGE_PACKET g_DeviceChangeStatePacket;
+
+/* Only VNIC and VHBA channels are sent to visorclientbus (aka
+ * "visorhackbus")
+ */
+#define FOR_VISORHACKBUS(channel_type_guid) \
+ ((memcmp(&channel_type_guid, &UltraVnicChannelProtocolGuid, \
+ sizeof(GUID)) == 0) || \
+ (memcmp(&channel_type_guid, &UltraVhbaChannelProtocolGuid, \
+ sizeof(GUID)) == 0))
+#define FOR_VISORBUS(channel_type_guid) (!(FOR_VISORHACKBUS(channel_type_guid)))
+
+#define is_diagpool_channel(channel_type_guid) \
+ (memcmp(&channel_type_guid, \
+ &UltraDiagPoolChannelProtocolGuid, sizeof(GUID)) == 0)
+
+typedef enum {
+ PARTPROP_invalid,
+ PARTPROP_name,
+ PARTPROP_description,
+ PARTPROP_handle,
+ PARTPROP_busNumber,
+ /* add new properties above, but don't forget to change
+ * InitPartitionProperties() and show_partition_property() also...
+ */
+ PARTPROP_last
+} PARTITION_property;
+static const char *PartitionTypeNames[] = { "partition", NULL };
+
+static char *PartitionPropertyNames[PARTPROP_last + 1];
+static void
+InitPartitionProperties(void)
+{
+ char **p = PartitionPropertyNames;
+ p[PARTPROP_invalid] = "";
+ p[PARTPROP_name] = "name";
+ p[PARTPROP_description] = "description";
+ p[PARTPROP_handle] = "handle";
+ p[PARTPROP_busNumber] = "busNumber";
+ p[PARTPROP_last] = NULL;
+}
+
+typedef enum {
+ CTLVMPROP_invalid,
+ CTLVMPROP_physAddr,
+ CTLVMPROP_controlChannelAddr,
+ CTLVMPROP_controlChannelBytes,
+ CTLVMPROP_sparBootPart,
+ CTLVMPROP_sparStoragePart,
+ CTLVMPROP_livedumpLength,
+ CTLVMPROP_livedumpCrc32,
+ /* add new properties above, but don't forget to change
+ * InitControlVmProperties() show_controlvm_property() also...
+ */
+ CTLVMPROP_last
+} CONTROLVM_property;
+
+static const char *ControlVmTypeNames[] = { "controlvm", NULL };
+
+static char *ControlVmPropertyNames[CTLVMPROP_last + 1];
+static void
+InitControlVmProperties(void)
+{
+ char **p = ControlVmPropertyNames;
+ p[CTLVMPROP_invalid] = "";
+ p[CTLVMPROP_physAddr] = "physAddr";
+ p[CTLVMPROP_controlChannelAddr] = "controlChannelAddr";
+ p[CTLVMPROP_controlChannelBytes] = "controlChannelBytes";
+ p[CTLVMPROP_sparBootPart] = "spar_boot_part";
+ p[CTLVMPROP_sparStoragePart] = "spar_storage_part";
+ p[CTLVMPROP_livedumpLength] = "livedumpLength";
+ p[CTLVMPROP_livedumpCrc32] = "livedumpCrc32";
+ p[CTLVMPROP_last] = NULL;
+}
+
+static MYPROCOBJECT *ControlVmObject;
+static MYPROCTYPE *PartitionType;
+static MYPROCTYPE *ControlVmType;
+
+#define VISORCHIPSET_DIAG_PROC_ENTRY_FN "diagdump"
+static struct proc_dir_entry *diag_proc_dir;
+
+#define VISORCHIPSET_CHIPSET_PROC_ENTRY_FN "chipsetready"
+static struct proc_dir_entry *chipset_proc_dir;
+
+#define VISORCHIPSET_PARAHOTPLUG_PROC_ENTRY_FN "parahotplug"
+static struct proc_dir_entry *parahotplug_proc_dir;
+
+static LIST_HEAD(BusInfoList);
+static LIST_HEAD(DevInfoList);
+
+static struct proc_dir_entry *ProcDir;
+static VISORCHANNEL *ControlVm_channel;
+
+static ssize_t visorchipset_proc_read_writeonly(struct file *file,
+ char __user *buf,
+ size_t len, loff_t *offset);
+static ssize_t proc_read_installer(struct file *file, char __user *buf,
+ size_t len, loff_t *offset);
+static ssize_t proc_write_installer(struct file *file,
+ const char __user *buffer,
+ size_t count, loff_t *ppos);
+static ssize_t proc_read_toolaction(struct file *file, char __user *buf,
+ size_t len, loff_t *offset);
+static ssize_t proc_write_toolaction(struct file *file,
+ const char __user *buffer,
+ size_t count, loff_t *ppos);
+static ssize_t proc_read_bootToTool(struct file *file, char __user *buf,
+ size_t len, loff_t *offset);
+static ssize_t proc_write_bootToTool(struct file *file,
+ const char __user *buffer,
+ size_t count, loff_t *ppos);
+static const struct file_operations proc_installer_fops = {
+ .read = proc_read_installer,
+ .write = proc_write_installer,
+};
+
+static const struct file_operations proc_toolaction_fops = {
+ .read = proc_read_toolaction,
+ .write = proc_write_toolaction,
+};
+
+static const struct file_operations proc_bootToTool_fops = {
+ .read = proc_read_bootToTool,
+ .write = proc_write_bootToTool,
+};
+
+typedef struct {
+ U8 *ptr; /* pointer to base address of payload pool */
+ U64 offset; /* offset from beginning of controlvm
+ * channel to beginning of payload * pool */
+ U32 bytes; /* number of bytes in payload pool */
+} CONTROLVM_PAYLOAD_INFO;
+
+/* Manages the request payload in the controlvm channel */
+static CONTROLVM_PAYLOAD_INFO ControlVm_payload_info;
+
+static pCHANNEL_HEADER Test_Vnic_channel;
+
+typedef struct {
+ CONTROLVM_MESSAGE_HEADER Dumpcapture_header;
+ CONTROLVM_MESSAGE_HEADER Gettextdump_header;
+ CONTROLVM_MESSAGE_HEADER Dumpcomplete_header;
+ BOOL Gettextdump_outstanding;
+ u32 crc32;
+ ulong length;
+ atomic_t buffers_in_use;
+ ulong destination;
+} LIVEDUMP_INFO;
+/* Manages the info for a CONTROLVM_DUMP_CAPTURESTATE /
+ * CONTROLVM_DUMP_GETTEXTDUMP / CONTROLVM_DUMP_COMPLETE conversation.
+ */
+static LIVEDUMP_INFO LiveDump_info;
+
+/* 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 CONTROLVM_MESSAGE ControlVm_Pending_Msg;
+static BOOL ControlVm_Pending_Msg_Valid = FALSE;
+
+/* Pool of struct putfile_buffer_entry, for keeping track of pending (incoming)
+ * TRANSMIT_FILE PutFile payloads.
+ */
+static struct kmem_cache *Putfile_buffer_list_pool;
+static const char Putfile_buffer_list_pool_name[] =
+ "controlvm_putfile_buffer_list_pool";
+
+/* This identifies a data buffer that has been received via a controlvm messages
+ * in a remote --> local CONTROLVM_TRANSMIT_FILE conversation.
+ */
+struct putfile_buffer_entry {
+ struct list_head next; /* putfile_buffer_entry list */
+ PARSER_CONTEXT *parser_ctx; /* points to buffer containing input data */
+};
+
+/* List of struct putfile_request *, via next_putfile_request member.
+ * Each entry in this list identifies an outstanding TRANSMIT_FILE
+ * conversation.
+ */
+static LIST_HEAD(Putfile_request_list);
+
+/* This describes a buffer and its current state of transfer (e.g., how many
+ * bytes have already been supplied as putfile data, and how many bytes are
+ * remaining) for a putfile_request.
+ */
+struct putfile_active_buffer {
+ /* a payload from a controlvm message, containing a file data buffer */
+ PARSER_CONTEXT *parser_ctx;
+ /* points within data area of parser_ctx to next byte of data */
+ u8 *pnext;
+ /* # bytes left from <pnext> to the end of this data buffer */
+ size_t bytes_remaining;
+};
+
+#define PUTFILE_REQUEST_SIG 0x0906101302281211
+/* This identifies a single remote --> local CONTROLVM_TRANSMIT_FILE
+ * conversation. Structs of this type are dynamically linked into
+ * <Putfile_request_list>.
+ */
+struct putfile_request {
+ u64 sig; /* PUTFILE_REQUEST_SIG */
+
+ /* header from original TransmitFile request */
+ CONTROLVM_MESSAGE_HEADER controlvm_header;
+ u64 file_request_number; /* from original TransmitFile request */
+
+ /* link to next struct putfile_request */
+ struct list_head next_putfile_request;
+
+ /* most-recent sequence number supplied via a controlvm message */
+ u64 data_sequence_number;
+
+ /* head of putfile_buffer_entry list, which describes the data to be
+ * supplied as putfile data;
+ * - this list is added to when controlvm messages come in that supply
+ * file data
+ * - this list is removed from via the hotplug program that is actually
+ * consuming these buffers to write as file data */
+ struct list_head input_buffer_list;
+ spinlock_t req_list_lock; /* lock for input_buffer_list */
+
+ /* waiters for input_buffer_list to go non-empty */
+ wait_queue_head_t input_buffer_wq;
+
+ /* data not yet read within current putfile_buffer_entry */
+ struct putfile_active_buffer active_buf;
+
+ /* <0 = failed, 0 = in-progress, >0 = successful; */
+ /* note that this must be set with req_list_lock, and if you set <0, */
+ /* it is your responsibility to also free up all of the other objects */
+ /* in this struct (like input_buffer_list, active_buf.parser_ctx) */
+ /* before releasing the lock */
+ int completion_status;
+};
+
+atomic_t Visorchipset_cache_buffers_in_use = ATOMIC_INIT(0);
+
+struct parahotplug_request {
+ struct list_head list;
+ int id;
+ unsigned long expiration;
+ CONTROLVM_MESSAGE msg;
+};
+
+static LIST_HEAD(Parahotplug_request_list);
+static DEFINE_SPINLOCK(Parahotplug_request_list_lock); /* lock for above */
+static void parahotplug_process_list(void);
+
+/* Manages the info for a CONTROLVM_DUMP_CAPTURESTATE /
+ * CONTROLVM_REPORTEVENT.
+ */
+static VISORCHIPSET_BUSDEV_NOTIFIERS BusDev_Server_Notifiers;
+static VISORCHIPSET_BUSDEV_NOTIFIERS BusDev_Client_Notifiers;
+
+static void bus_create_response(ulong busNo, int response);
+static void bus_destroy_response(ulong busNo, int response);
+static void device_create_response(ulong busNo, ulong devNo, int response);
+static void device_destroy_response(ulong busNo, ulong devNo, int response);
+static void device_resume_response(ulong busNo, ulong devNo, int response);
+
+static VISORCHIPSET_BUSDEV_RESPONDERS BusDev_Responders = {
+ .bus_create = bus_create_response,
+ .bus_destroy = bus_destroy_response,
+ .device_create = device_create_response,
+ .device_destroy = device_destroy_response,
+ .device_pause = device_pause_response,
+ .device_resume = device_resume_response,
+};
+
+/* info for /dev/visorchipset */
+static dev_t MajorDev = -1; /**< indicates major num for device */
+
+/* /sys/devices/platform/visorchipset */
+static struct platform_device Visorchipset_platform_device = {
+ .name = "visorchipset",
+ .id = -1,
+};
+
+/* Function prototypes */
+static void controlvm_respond(CONTROLVM_MESSAGE_HEADER *msgHdr, int response);
+static void controlvm_respond_chipset_init(CONTROLVM_MESSAGE_HEADER *msgHdr,
+ int response,
+ ULTRA_CHIPSET_FEATURE features);
+static void controlvm_respond_physdev_changestate(CONTROLVM_MESSAGE_HEADER *
+ msgHdr, int response,
+ ULTRA_SEGMENT_STATE state);
+
+static void
+show_partition_property(struct seq_file *f, void *ctx, int property)
+{
+ VISORCHIPSET_BUS_INFO *info = (VISORCHIPSET_BUS_INFO *) (ctx);
+
+ switch (property) {
+ case PARTPROP_name:
+ seq_printf(f, "%s\n", NONULLSTR(info->name));
+ break;
+ case PARTPROP_description:
+ seq_printf(f, "%s\n", NONULLSTR(info->description));
+ break;
+ case PARTPROP_handle:
+ seq_printf(f, "0x%-16.16Lx\n", info->partitionHandle);
+ break;
+ case PARTPROP_busNumber:
+ seq_printf(f, "%d\n", info->busNo);
+ break;
+ default:
+ seq_printf(f, "(%d??)\n", property);
+ break;
+ }
+}
+
+static void
+show_controlvm_property(struct seq_file *f, void *ctx, int property)
+{
+ /* Note: ctx is not needed since we only have 1 controlvm channel */
+ switch (property) {
+ case CTLVMPROP_physAddr:
+ if (ControlVm_channel == NULL)
+ seq_puts(f, "0x0\n");
+ else
+ seq_printf(f, "0x%-16.16Lx\n",
+ visorchannel_get_physaddr
+ (ControlVm_channel));
+ break;
+ case CTLVMPROP_controlChannelAddr:
+ if (ControlVm_channel == NULL)
+ seq_puts(f, "0x0\n");
+ else {
+ GUEST_PHYSICAL_ADDRESS addr = 0;
+ visorchannel_read(ControlVm_channel,
+ offsetof
+ (ULTRA_CONTROLVM_CHANNEL_PROTOCOL,
+ gpControlChannel), &addr,
+ sizeof(addr));
+ seq_printf(f, "0x%-16.16Lx\n", (u64) (addr));
+ }
+ break;
+ case CTLVMPROP_controlChannelBytes:
+ if (ControlVm_channel == NULL)
+ seq_puts(f, "0x0\n");
+ else {
+ U32 bytes = 0;
+ visorchannel_read(ControlVm_channel,
+ offsetof
+ (ULTRA_CONTROLVM_CHANNEL_PROTOCOL,
+ ControlChannelBytes), &bytes,
+ sizeof(bytes));
+ seq_printf(f, "%lu\n", (ulong) (bytes));
+ }
+ break;
+ case CTLVMPROP_sparBootPart:
+ seq_puts(f, "0:0:0:0/1\n");
+ break;
+ case CTLVMPROP_sparStoragePart:
+ seq_puts(f, "0:0:0:0/2\n");
+ break;
+ case CTLVMPROP_livedumpLength:
+ seq_printf(f, "%lu\n", LiveDump_info.length);
+ break;
+ case CTLVMPROP_livedumpCrc32:
+ seq_printf(f, "%lu\n", (ulong) LiveDump_info.crc32);
+ break;
+ default:
+ seq_printf(f, "(%d??)\n", property);
+ break;
+ }
+}
+
+static void
+proc_Init(void)
+{
+ if (ProcDir == NULL) {
+ ProcDir = proc_mkdir(MYDRVNAME, NULL);
+ if (ProcDir == NULL) {
+ LOGERR("failed to create /proc directory %s",
+ MYDRVNAME);
+ POSTCODE_LINUX_2(CHIPSET_INIT_FAILURE_PC,
+ POSTCODE_SEVERITY_ERR);
+ }
+ }
+}
+
+static void
+proc_DeInit(void)
+{
+ if (ProcDir != NULL)
+ remove_proc_entry(MYDRVNAME, NULL);
+ ProcDir = NULL;
+}
+
+#if 0
+static void
+testUnicode(void)
+{
+ wchar_t unicodeString[] = { 'a', 'b', 'c', 0 };
+ char s[sizeof(unicodeString) * NLS_MAX_CHARSET_SIZE];
+ wchar_t unicode2[99];
+
+ /* NOTE: Either due to a bug, or feature I don't understand, the
+ * kernel utf8_mbstowcs() and utf_wcstombs() do NOT copy the
+ * trailed NUL byte!! REALLY!!!!! Arrrrgggghhhhh
+ */
+
+ LOGINF("sizeof(wchar_t) = %d", sizeof(wchar_t));
+ LOGINF("utf8_wcstombs=%d",
+ chrs = utf8_wcstombs(s, unicodeString, sizeof(s)));
+ if (chrs >= 0)
+ s[chrs] = '\0'; /* GRRRRRRRR */
+ LOGINF("s='%s'", s);
+ LOGINF("utf8_mbstowcs=%d", chrs = utf8_mbstowcs(unicode2, s, 100));
+ if (chrs >= 0)
+ unicode2[chrs] = 0; /* GRRRRRRRR */
+ if (memcmp(unicodeString, unicode2, sizeof(unicodeString)) == 0)
+ LOGINF("strings match... good");
+ else
+ LOGINF("strings did not match!!");
+}
+#endif
+
+static void
+busInfo_clear(void *v)
+{
+ VISORCHIPSET_BUS_INFO *p = (VISORCHIPSET_BUS_INFO *) (v);
+
+ if (p->procObject) {
+ proc_DestroyObject(p->procObject);
+ p->procObject = NULL;
+ }
+ kfree(p->name);
+ p->name = NULL;
+
+ kfree(p->description);
+ p->description = NULL;
+
+ p->state.created = 0;
+ memset(p, 0, sizeof(VISORCHIPSET_BUS_INFO));
+}
+
+static void
+devInfo_clear(void *v)
+{
+ VISORCHIPSET_DEVICE_INFO *p = (VISORCHIPSET_DEVICE_INFO *) (v);
+ p->state.created = 0;
+ memset(p, 0, sizeof(VISORCHIPSET_DEVICE_INFO));
+}
+
+static U8
+check_chipset_events(void)
+{
+ int i;
+ U8 send_msg = 1;
+ /* Check events to determine if response should be sent */
+ for (i = 0; i < MAX_CHIPSET_EVENTS; i++)
+ send_msg &= chipset_events[i];
+ return send_msg;
+}
+
+static void
+clear_chipset_events(void)
+{
+ int i;
+ /* Clear chipset_events */
+ for (i = 0; i < MAX_CHIPSET_EVENTS; i++)
+ chipset_events[i] = 0;
+}
+
+void
+visorchipset_register_busdev_server(VISORCHIPSET_BUSDEV_NOTIFIERS *notifiers,
+ VISORCHIPSET_BUSDEV_RESPONDERS *responders,
+ ULTRA_VBUS_DEVICEINFO *driverInfo)
+{
+ LOCKSEM_UNINTERRUPTIBLE(&NotifierLock);
+ if (notifiers == NULL) {
+ memset(&BusDev_Server_Notifiers, 0,
+ sizeof(BusDev_Server_Notifiers));
+ serverregistered = 0; /* clear flag */
+ } else {
+ BusDev_Server_Notifiers = *notifiers;
+ serverregistered = 1; /* set flag */
+ }
+ if (responders)
+ *responders = BusDev_Responders;
+ if (driverInfo)
+ BusDeviceInfo_Init(driverInfo, "chipset", "visorchipset",
+ VERSION, NULL, __DATE__, __TIME__);
+
+ UNLOCKSEM(&NotifierLock);
+}
+EXPORT_SYMBOL_GPL(visorchipset_register_busdev_server);
+
+void
+visorchipset_register_busdev_client(VISORCHIPSET_BUSDEV_NOTIFIERS *notifiers,
+ VISORCHIPSET_BUSDEV_RESPONDERS *responders,
+ ULTRA_VBUS_DEVICEINFO *driverInfo)
+{
+ LOCKSEM_UNINTERRUPTIBLE(&NotifierLock);
+ if (notifiers == NULL) {
+ memset(&BusDev_Client_Notifiers, 0,
+ sizeof(BusDev_Client_Notifiers));
+ clientregistered = 0; /* clear flag */
+ } else {
+ BusDev_Client_Notifiers = *notifiers;
+ clientregistered = 1; /* set flag */
+ }
+ if (responders)
+ *responders = BusDev_Responders;
+ if (driverInfo)
+ BusDeviceInfo_Init(driverInfo, "chipset(bolts)", "visorchipset",
+ VERSION, NULL, __DATE__, __TIME__);
+ UNLOCKSEM(&NotifierLock);
+}
+EXPORT_SYMBOL_GPL(visorchipset_register_busdev_client);
+
+static void
+cleanup_controlvm_structures(void)
+{
+ VISORCHIPSET_BUS_INFO *bi;
+ VISORCHIPSET_DEVICE_INFO *di;
+
+ list_for_each_entry(bi, &BusInfoList, entry) {
+ busInfo_clear(bi);
+ list_del(&bi->entry);
+ kfree(bi);
+ }
+
+ list_for_each_entry(di, &DevInfoList, entry) {
+ devInfo_clear(di);
+ list_del(&di->entry);
+ kfree(di);
+ }
+}
+
+static void
+chipset_init(CONTROLVM_MESSAGE *inmsg)
+{
+ static int chipset_inited;
+ ULTRA_CHIPSET_FEATURE features = 0;
+ int rc = CONTROLVM_RESP_SUCCESS;
+
+ POSTCODE_LINUX_2(CHIPSET_INIT_ENTRY_PC, POSTCODE_SEVERITY_INFO);
+ if (chipset_inited) {
+ LOGERR("CONTROLVM_CHIPSET_INIT Failed: Already Done.");
+ RETINT(-CONTROLVM_RESP_ERROR_ALREADY_DONE);
+ }
+ chipset_inited = 1;
+ POSTCODE_LINUX_2(CHIPSET_INIT_EXIT_PC, POSTCODE_SEVERITY_INFO);
+
+ /* Set features to indicate we support parahotplug (if Command
+ * also supports it). */
+ features =
+ inmsg->cmd.initChipset.
+ features & ULTRA_CHIPSET_FEATURE_PARA_HOTPLUG;
+
+ /* Set the "reply" bit so Command knows this is a
+ * features-aware driver. */
+ features |= ULTRA_CHIPSET_FEATURE_REPLY;
+
+Away:
+ if (rc < 0)
+ cleanup_controlvm_structures();
+ if (inmsg->hdr.Flags.responseExpected)
+ controlvm_respond_chipset_init(&inmsg->hdr, rc, features);
+}
+
+static void
+controlvm_init_response(CONTROLVM_MESSAGE *msg,
+ CONTROLVM_MESSAGE_HEADER *msgHdr, int response)
+{
+ memset(msg, 0, sizeof(CONTROLVM_MESSAGE));
+ memcpy(&msg->hdr, msgHdr, sizeof(CONTROLVM_MESSAGE_HEADER));
+ msg->hdr.PayloadBytes = 0;
+ msg->hdr.PayloadVmOffset = 0;
+ msg->hdr.PayloadMaxBytes = 0;
+ if (response < 0) {
+ msg->hdr.Flags.failed = 1;
+ msg->hdr.CompletionStatus = (U32) (-response);
+ }
+}
+
+static void
+controlvm_respond(CONTROLVM_MESSAGE_HEADER *msgHdr, int response)
+{
+ CONTROLVM_MESSAGE outmsg;
+ if (!ControlVm_channel)
+ return;
+ controlvm_init_response(&outmsg, msgHdr, response);
+ /* For DiagPool channel DEVICE_CHANGESTATE, we need to send
+ * back the deviceChangeState structure in the packet. */
+ if (msgHdr->Id == CONTROLVM_DEVICE_CHANGESTATE
+ && g_DeviceChangeStatePacket.deviceChangeState.busNo ==
+ g_diagpoolBusNo
+ && g_DeviceChangeStatePacket.deviceChangeState.devNo ==
+ g_diagpoolDevNo)
+ outmsg.cmd = g_DeviceChangeStatePacket;
+ if (outmsg.hdr.Flags.testMessage == 1) {
+ LOGINF("%s controlvm_msg=0x%x response=%d for test message",
+ __func__, outmsg.hdr.Id, response);
+ return;
+ }
+ if (!visorchannel_signalinsert(ControlVm_channel,
+ CONTROLVM_QUEUE_REQUEST, &outmsg)) {
+ LOGERR("signalinsert failed!");
+ return;
+ }
+}
+
+static void
+controlvm_respond_chipset_init(CONTROLVM_MESSAGE_HEADER *msgHdr, int response,
+ ULTRA_CHIPSET_FEATURE features)
+{
+ CONTROLVM_MESSAGE outmsg;
+ if (!ControlVm_channel)
+ return;
+ controlvm_init_response(&outmsg, msgHdr, response);
+ outmsg.cmd.initChipset.features = features;
+ if (!visorchannel_signalinsert(ControlVm_channel,
+ CONTROLVM_QUEUE_REQUEST, &outmsg)) {
+ LOGERR("signalinsert failed!");
+ return;
+ }
+}
+
+static void
+controlvm_respond_physdev_changestate(CONTROLVM_MESSAGE_HEADER *msgHdr,
+ int response, ULTRA_SEGMENT_STATE state)
+{
+ CONTROLVM_MESSAGE outmsg;
+ if (!ControlVm_channel)
+ return;
+ controlvm_init_response(&outmsg, msgHdr, response);
+ outmsg.cmd.deviceChangeState.state = state;
+ outmsg.cmd.deviceChangeState.flags.physicalDevice = 1;
+ if (!visorchannel_signalinsert(ControlVm_channel,
+ CONTROLVM_QUEUE_REQUEST, &outmsg)) {
+ LOGERR("signalinsert failed!");
+ return;
+ }
+}
+
+void
+visorchipset_save_message(CONTROLVM_MESSAGE *msg, CRASH_OBJ_TYPE type)
+{
+ U32 localSavedCrashMsgOffset;
+ U16 localSavedCrashMsgCount;
+
+ /* get saved message count */
+ if (visorchannel_read(ControlVm_channel,
+ offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL,
+ SavedCrashMsgCount),
+ &localSavedCrashMsgCount, sizeof(U16)) < 0) {
+ LOGERR("failed to get Saved Message Count");
+ POSTCODE_LINUX_2(CRASH_DEV_CTRL_RD_FAILURE_PC,
+ POSTCODE_SEVERITY_ERR);
+ return;
+ }
+
+ if (localSavedCrashMsgCount != CONTROLVM_CRASHMSG_MAX) {
+ LOGERR("Saved Message Count incorrect %d",
+ localSavedCrashMsgCount);
+ POSTCODE_LINUX_3(CRASH_DEV_COUNT_FAILURE_PC,
+ localSavedCrashMsgCount,
+ POSTCODE_SEVERITY_ERR);
+ return;
+ }
+
+ /* get saved crash message offset */
+ if (visorchannel_read(ControlVm_channel,
+ offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL,
+ SavedCrashMsgOffset),
+ &localSavedCrashMsgOffset, sizeof(U32)) < 0) {
+ LOGERR("failed to get Saved Message Offset");
+ POSTCODE_LINUX_2(CRASH_DEV_CTRL_RD_FAILURE_PC,
+ POSTCODE_SEVERITY_ERR);
+ return;
+ }
+
+ if (type == CRASH_bus) {
+ if (visorchannel_write(ControlVm_channel,
+ localSavedCrashMsgOffset,
+ msg, sizeof(CONTROLVM_MESSAGE)) < 0) {
+ LOGERR("SAVE_MSG_BUS_FAILURE: Failed to write CrashCreateBusMsg!");
+ POSTCODE_LINUX_2(SAVE_MSG_BUS_FAILURE_PC,
+ POSTCODE_SEVERITY_ERR);
+ return;
+ }
+ } else {
+ if (visorchannel_write(ControlVm_channel,
+ localSavedCrashMsgOffset +
+ sizeof(CONTROLVM_MESSAGE), msg,
+ sizeof(CONTROLVM_MESSAGE)) < 0) {
+ LOGERR("SAVE_MSG_DEV_FAILURE: Failed to write CrashCreateDevMsg!");
+ POSTCODE_LINUX_2(SAVE_MSG_DEV_FAILURE_PC,
+ POSTCODE_SEVERITY_ERR);
+ return;
+ }
+ }
+}
+EXPORT_SYMBOL_GPL(visorchipset_save_message);
+
+static void
+bus_responder(CONTROLVM_ID cmdId, ulong busNo, int response)
+{
+ VISORCHIPSET_BUS_INFO *p = NULL;
+ BOOL need_clear = FALSE;
+
+ p = findbus(&BusInfoList, busNo);
+ if (!p) {
+ LOGERR("internal error busNo=%lu", busNo);
+ return;
+ }
+ if (response < 0) {
+ if ((cmdId == CONTROLVM_BUS_CREATE) &&
+ (response != (-CONTROLVM_RESP_ERROR_ALREADY_DONE)))
+ /* undo the row we just created... */
+ delbusdevices(&DevInfoList, busNo);
+ } else {
+ if (cmdId == CONTROLVM_BUS_CREATE)
+ p->state.created = 1;
+ if (cmdId == CONTROLVM_BUS_DESTROY)
+ need_clear = TRUE;
+ }
+
+ if (p->pendingMsgHdr.Id == CONTROLVM_INVALID) {
+ LOGERR("bus_responder no pending msg");
+ return; /* no controlvm response needed */
+ }
+ if (p->pendingMsgHdr.Id != (U32) cmdId) {
+ LOGERR("expected=%d, found=%d", cmdId, p->pendingMsgHdr.Id);
+ return;
+ }
+ controlvm_respond(&p->pendingMsgHdr, response);
+ p->pendingMsgHdr.Id = CONTROLVM_INVALID;
+ if (need_clear) {
+ busInfo_clear(p);
+ delbusdevices(&DevInfoList, busNo);
+ }
+}
+
+static void
+device_changestate_responder(CONTROLVM_ID cmdId,
+ ulong busNo, ulong devNo, int response,
+ ULTRA_SEGMENT_STATE responseState)
+{
+ VISORCHIPSET_DEVICE_INFO *p = NULL;
+ CONTROLVM_MESSAGE outmsg;
+
+ if (!ControlVm_channel)
+ return;
+
+ p = finddevice(&DevInfoList, busNo, devNo);
+ if (!p) {
+ LOGERR("internal error; busNo=%lu, devNo=%lu", busNo, devNo);
+ return;
+ }
+ if (p->pendingMsgHdr.Id == CONTROLVM_INVALID) {
+ LOGERR("device_responder no pending msg");
+ return; /* no controlvm response needed */
+ }
+ if (p->pendingMsgHdr.Id != cmdId) {
+ LOGERR("expected=%d, found=%d", cmdId, p->pendingMsgHdr.Id);
+ return;
+ }
+
+ controlvm_init_response(&outmsg, &p->pendingMsgHdr, response);
+
+ outmsg.cmd.deviceChangeState.busNo = busNo;
+ outmsg.cmd.deviceChangeState.devNo = devNo;
+ outmsg.cmd.deviceChangeState.state = responseState;
+
+ if (!visorchannel_signalinsert(ControlVm_channel,
+ CONTROLVM_QUEUE_REQUEST, &outmsg)) {
+ LOGERR("signalinsert failed!");
+ return;
+ }
+
+ p->pendingMsgHdr.Id = CONTROLVM_INVALID;
+}
+
+static void
+device_responder(CONTROLVM_ID cmdId, ulong busNo, ulong devNo, int response)
+{
+ VISORCHIPSET_DEVICE_INFO *p = NULL;
+ BOOL need_clear = FALSE;
+
+ p = finddevice(&DevInfoList, busNo, devNo);
+ if (!p) {
+ LOGERR("internal error; busNo=%lu, devNo=%lu", busNo, devNo);
+ return;
+ }
+ if (response >= 0) {
+ if (cmdId == CONTROLVM_DEVICE_CREATE)
+ p->state.created = 1;
+ if (cmdId == CONTROLVM_DEVICE_DESTROY)
+ need_clear = TRUE;
+ }
+
+ if (p->pendingMsgHdr.Id == CONTROLVM_INVALID) {
+ LOGERR("device_responder no pending msg");
+ return; /* no controlvm response needed */
+ }
+ if (p->pendingMsgHdr.Id != (U32) cmdId) {
+ LOGERR("expected=%d, found=%d", cmdId, p->pendingMsgHdr.Id);
+ return;
+ }
+ controlvm_respond(&p->pendingMsgHdr, response);
+ p->pendingMsgHdr.Id = CONTROLVM_INVALID;
+ if (need_clear)
+ devInfo_clear(p);
+}
+
+static void
+bus_epilog(U32 busNo,
+ U32 cmd, CONTROLVM_MESSAGE_HEADER *msgHdr,
+ int response, BOOL needResponse)
+{
+ BOOL notified = FALSE;
+
+ VISORCHIPSET_BUS_INFO *pBusInfo = findbus(&BusInfoList, busNo);
+
+ if (!pBusInfo) {
+ LOGERR("HUH? bad busNo=%d", busNo);
+ return;
+ }
+ if (needResponse) {
+ memcpy(&pBusInfo->pendingMsgHdr, msgHdr,
+ sizeof(CONTROLVM_MESSAGE_HEADER));
+ } else
+ pBusInfo->pendingMsgHdr.Id = CONTROLVM_INVALID;
+
+ LOCKSEM_UNINTERRUPTIBLE(&NotifierLock);
+ if (response == CONTROLVM_RESP_SUCCESS) {
+ switch (cmd) {
+ case CONTROLVM_BUS_CREATE:
+ /* We can't tell from the bus_create
+ * information which of our 2 bus flavors the
+ * devices on this bus will ultimately end up.
+ * FORTUNATELY, it turns out it is harmless to
+ * send the bus_create to both of them. We can
+ * narrow things down a little bit, though,
+ * because we know: - BusDev_Server can handle
+ * either server or client devices
+ * - BusDev_Client can handle ONLY client
+ * devices */
+ if (BusDev_Server_Notifiers.bus_create) {
+ (*BusDev_Server_Notifiers.bus_create) (busNo);
+ notified = TRUE;
+ }
+ if ((!pBusInfo->flags.server) /*client */ &&
+ BusDev_Client_Notifiers.bus_create) {
+ (*BusDev_Client_Notifiers.bus_create) (busNo);
+ notified = TRUE;
+ }
+ break;
+ case CONTROLVM_BUS_DESTROY:
+ if (BusDev_Server_Notifiers.bus_destroy) {
+ (*BusDev_Server_Notifiers.bus_destroy) (busNo);
+ notified = TRUE;
+ }
+ if ((!pBusInfo->flags.server) /*client */ &&
+ BusDev_Client_Notifiers.bus_destroy) {
+ (*BusDev_Client_Notifiers.bus_destroy) (busNo);
+ notified = TRUE;
+ }
+ break;
+ }
+ }
+ if (notified)
+ /* The callback function just called above is responsible
+ * for calling the appropriate VISORCHIPSET_BUSDEV_RESPONDERS
+ * function, which will call bus_responder()
+ */
+ ;
+ else
+ bus_responder(cmd, busNo, response);
+ UNLOCKSEM(&NotifierLock);
+}
+
+static void
+device_epilog(U32 busNo, U32 devNo, ULTRA_SEGMENT_STATE state, U32 cmd,
+ CONTROLVM_MESSAGE_HEADER *msgHdr, int response,
+ BOOL needResponse, BOOL for_visorbus)
+{
+ VISORCHIPSET_BUSDEV_NOTIFIERS *notifiers = NULL;
+ BOOL notified = FALSE;
+
+ VISORCHIPSET_DEVICE_INFO *pDevInfo =
+ finddevice(&DevInfoList, busNo, devNo);
+ char *envp[] = {
+ "SPARSP_DIAGPOOL_PAUSED_STATE = 1",
+ NULL
+ };
+
+ if (!pDevInfo) {
+ LOGERR("HUH? bad busNo=%d, devNo=%d", busNo, devNo);
+ return;
+ }
+ if (for_visorbus)
+ notifiers = &BusDev_Server_Notifiers;
+ else
+ notifiers = &BusDev_Client_Notifiers;
+ if (needResponse) {
+ memcpy(&pDevInfo->pendingMsgHdr, msgHdr,
+ sizeof(CONTROLVM_MESSAGE_HEADER));
+ } else
+ pDevInfo->pendingMsgHdr.Id = CONTROLVM_INVALID;
+
+ LOCKSEM_UNINTERRUPTIBLE(&NotifierLock);
+ if (response >= 0) {
+ switch (cmd) {
+ case CONTROLVM_DEVICE_CREATE:
+ if (notifiers->device_create) {
+ (*notifiers->device_create) (busNo, devNo);
+ notified = TRUE;
+ }
+ break;
+ case CONTROLVM_DEVICE_CHANGESTATE:
+ /* ServerReady / ServerRunning / SegmentStateRunning */
+ if (state.Alive == SegmentStateRunning.Alive &&
+ state.Operating == SegmentStateRunning.Operating) {
+ if (notifiers->device_resume) {
+ (*notifiers->device_resume) (busNo,
+ devNo);
+ notified = TRUE;
+ }
+ }
+ /* ServerNotReady / ServerLost / SegmentStateStandby */
+ else if (state.Alive == SegmentStateStandby.Alive &&
+ state.Operating ==
+ SegmentStateStandby.Operating) {
+ /* technically this is standby case
+ * where server is lost
+ */
+ if (notifiers->device_pause) {
+ (*notifiers->device_pause) (busNo,
+ devNo);
+ notified = TRUE;
+ }
+ } else if (state.Alive == SegmentStatePaused.Alive &&
+ state.Operating ==
+ SegmentStatePaused.Operating) {
+ /* this is lite pause where channel is
+ * still valid just 'pause' of it
+ */
+ if (busNo == g_diagpoolBusNo
+ && devNo == g_diagpoolDevNo) {
+ LOGINF("DEVICE_CHANGESTATE(DiagpoolChannel busNo=%d devNo=%d is pausing...)",
+ busNo, devNo);
+ /* this will trigger the
+ * diag_shutdown.sh script in
+ * the visorchipset hotplug */
+ kobject_uevent_env
+ (&Visorchipset_platform_device.dev.
+ kobj, KOBJ_ONLINE, envp);
+ }
+ }
+ break;
+ case CONTROLVM_DEVICE_DESTROY:
+ if (notifiers->device_destroy) {
+ (*notifiers->device_destroy) (busNo, devNo);
+ notified = TRUE;
+ }
+ break;
+ }
+ }
+ if (notified)
+ /* The callback function just called above is responsible
+ * for calling the appropriate VISORCHIPSET_BUSDEV_RESPONDERS
+ * function, which will call device_responder()
+ */
+ ;
+ else
+ device_responder(cmd, busNo, devNo, response);
+ UNLOCKSEM(&NotifierLock);
+}
+
+static void
+bus_create(CONTROLVM_MESSAGE *inmsg)
+{
+ CONTROLVM_MESSAGE_PACKET *cmd = &inmsg->cmd;
+ ulong busNo = cmd->createBus.busNo;
+ int rc = CONTROLVM_RESP_SUCCESS;
+ VISORCHIPSET_BUS_INFO *pBusInfo = NULL;
+
+
+ pBusInfo = findbus(&BusInfoList, busNo);
+ if (pBusInfo && (pBusInfo->state.created == 1)) {
+ LOGERR("CONTROLVM_BUS_CREATE Failed: bus %lu already exists",
+ busNo);
+ POSTCODE_LINUX_3(BUS_CREATE_FAILURE_PC, busNo,
+ POSTCODE_SEVERITY_ERR);
+ RETINT(-CONTROLVM_RESP_ERROR_ALREADY_DONE);
+ }
+ pBusInfo = kmalloc(sizeof(VISORCHIPSET_BUS_INFO), GFP_KERNEL);
+ if (pBusInfo == NULL) {
+ LOGERR("CONTROLVM_BUS_CREATE Failed: bus %lu kmalloc failed",
+ busNo);
+ POSTCODE_LINUX_3(BUS_CREATE_FAILURE_PC, busNo,
+ POSTCODE_SEVERITY_ERR);
+ RETINT(-CONTROLVM_RESP_ERROR_KMALLOC_FAILED);
+ }
+
+ memset(pBusInfo, 0, sizeof(VISORCHIPSET_BUS_INFO));
+ INIT_LIST_HEAD(&pBusInfo->entry);
+ pBusInfo->busNo = busNo;
+ pBusInfo->devNo = cmd->createBus.deviceCount;
+
+ POSTCODE_LINUX_3(BUS_CREATE_ENTRY_PC, busNo, POSTCODE_SEVERITY_INFO);
+
+ if (inmsg->hdr.Flags.testMessage == 1)
+ pBusInfo->chanInfo.addrType = ADDRTYPE_localTest;
+ else
+ pBusInfo->chanInfo.addrType = ADDRTYPE_localPhysical;
+
+ pBusInfo->flags.server = inmsg->hdr.Flags.server;
+ pBusInfo->chanInfo.channelAddr = cmd->createBus.channelAddr;
+ pBusInfo->chanInfo.nChannelBytes = cmd->createBus.channelBytes;
+ pBusInfo->chanInfo.channelTypeGuid = cmd->createBus.busDataTypeGuid;
+ pBusInfo->chanInfo.channelInstGuid = cmd->createBus.busInstGuid;
+
+ list_add(&pBusInfo->entry, &BusInfoList);
+
+ POSTCODE_LINUX_3(BUS_CREATE_EXIT_PC, busNo, POSTCODE_SEVERITY_INFO);
+
+Away:
+ bus_epilog(busNo, CONTROLVM_BUS_CREATE, &inmsg->hdr,
+ rc, inmsg->hdr.Flags.responseExpected == 1);
+}
+
+static void
+bus_destroy(CONTROLVM_MESSAGE *inmsg)
+{
+ CONTROLVM_MESSAGE_PACKET *cmd = &inmsg->cmd;
+ ulong busNo = cmd->destroyBus.busNo;
+ VISORCHIPSET_BUS_INFO *pBusInfo;
+ int rc = CONTROLVM_RESP_SUCCESS;
+
+ pBusInfo = findbus(&BusInfoList, busNo);
+ if (!pBusInfo) {
+ LOGERR("CONTROLVM_BUS_DESTROY Failed: bus %lu invalid", busNo);
+ RETINT(-CONTROLVM_RESP_ERROR_BUS_INVALID);
+ }
+ if (pBusInfo->state.created == 0) {
+ LOGERR("CONTROLVM_BUS_DESTROY Failed: bus %lu already destroyed",
+ busNo);
+ RETINT(-CONTROLVM_RESP_ERROR_ALREADY_DONE);
+ }
+
+Away:
+ bus_epilog(busNo, CONTROLVM_BUS_DESTROY, &inmsg->hdr,
+ rc, inmsg->hdr.Flags.responseExpected == 1);
+}
+
+static void
+bus_configure(CONTROLVM_MESSAGE *inmsg, PARSER_CONTEXT *parser_ctx)
+{
+ CONTROLVM_MESSAGE_PACKET *cmd = &inmsg->cmd;
+ ulong busNo = cmd->configureBus.busNo;
+ VISORCHIPSET_BUS_INFO *pBusInfo = NULL;
+ int rc = CONTROLVM_RESP_SUCCESS;
+ char s[99];
+
+ busNo = cmd->configureBus.busNo;
+ POSTCODE_LINUX_3(BUS_CONFIGURE_ENTRY_PC, busNo, POSTCODE_SEVERITY_INFO);
+
+ pBusInfo = findbus(&BusInfoList, busNo);
+ if (!pBusInfo) {
+ LOGERR("CONTROLVM_BUS_CONFIGURE Failed: bus %lu invalid",
+ busNo);
+ POSTCODE_LINUX_3(BUS_CONFIGURE_FAILURE_PC, busNo,
+ POSTCODE_SEVERITY_ERR);
+ RETINT(-CONTROLVM_RESP_ERROR_BUS_INVALID);
+ }
+ if (pBusInfo->state.created == 0) {
+ LOGERR("CONTROLVM_BUS_CONFIGURE Failed: Invalid bus %lu - not created yet",
+ busNo);
+ POSTCODE_LINUX_3(BUS_CONFIGURE_FAILURE_PC, busNo,
+ POSTCODE_SEVERITY_ERR);
+ RETINT(-CONTROLVM_RESP_ERROR_BUS_INVALID);
+ }
+ /* TBD - add this check to other commands also... */
+ if (pBusInfo->pendingMsgHdr.Id != CONTROLVM_INVALID) {
+ LOGERR("CONTROLVM_BUS_CONFIGURE Failed: bus %lu MsgId=%u outstanding",
+ busNo, (uint) pBusInfo->pendingMsgHdr.Id);
+ POSTCODE_LINUX_3(BUS_CONFIGURE_FAILURE_PC, busNo,
+ POSTCODE_SEVERITY_ERR);
+ RETINT(-CONTROLVM_RESP_ERROR_MESSAGE_ID_INVALID_FOR_CLIENT);
+ }
+
+ pBusInfo->partitionHandle = cmd->configureBus.guestHandle;
+ pBusInfo->partitionGuid = parser_id_get(parser_ctx);
+ parser_param_start(parser_ctx, PARSERSTRING_NAME);
+ pBusInfo->name = parser_string_get(parser_ctx);
+
+ visorchannel_GUID_id(&pBusInfo->partitionGuid, s);
+ pBusInfo->procObject =
+ proc_CreateObject(PartitionType, s, (void *) (pBusInfo));
+ if (pBusInfo->procObject == NULL) {
+ LOGERR("CONTROLVM_BUS_CONFIGURE Failed: busNo=%lu failed to create /proc entry",
+ busNo);
+ POSTCODE_LINUX_3(BUS_CONFIGURE_FAILURE_PC, busNo,
+ POSTCODE_SEVERITY_ERR);
+ RETINT(-CONTROLVM_RESP_ERROR_KMALLOC_FAILED);
+ }
+ POSTCODE_LINUX_3(BUS_CONFIGURE_EXIT_PC, busNo, POSTCODE_SEVERITY_INFO);
+Away:
+ bus_epilog(busNo, CONTROLVM_BUS_CONFIGURE, &inmsg->hdr,
+ rc, inmsg->hdr.Flags.responseExpected == 1);
+}
+
+static void
+my_device_create(CONTROLVM_MESSAGE *inmsg)
+{
+ CONTROLVM_MESSAGE_PACKET *cmd = &inmsg->cmd;
+ ulong busNo = cmd->createDevice.busNo;
+ ulong devNo = cmd->createDevice.devNo;
+ VISORCHIPSET_DEVICE_INFO *pDevInfo = NULL;
+ VISORCHIPSET_BUS_INFO *pBusInfo = NULL;
+ int rc = CONTROLVM_RESP_SUCCESS;
+
+ pDevInfo = finddevice(&DevInfoList, busNo, devNo);
+ if (pDevInfo && (pDevInfo->state.created == 1)) {
+ LOGERR("CONTROLVM_DEVICE_CREATE Failed: busNo=%lu, devNo=%lu already exists",
+ busNo, devNo);
+ POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, devNo, busNo,
+ POSTCODE_SEVERITY_ERR);
+ RETINT(-CONTROLVM_RESP_ERROR_ALREADY_DONE);
+ }
+ pBusInfo = findbus(&BusInfoList, busNo);
+ if (!pBusInfo) {
+ LOGERR("CONTROLVM_DEVICE_CREATE Failed: Invalid bus %lu - out of range",
+ busNo);
+ POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, devNo, busNo,
+ POSTCODE_SEVERITY_ERR);
+ RETINT(-CONTROLVM_RESP_ERROR_BUS_INVALID);
+ }
+ if (pBusInfo->state.created == 0) {
+ LOGERR("CONTROLVM_DEVICE_CREATE Failed: Invalid bus %lu - not created yet",
+ busNo);
+ POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, devNo, busNo,
+ POSTCODE_SEVERITY_ERR);
+ RETINT(-CONTROLVM_RESP_ERROR_BUS_INVALID);
+ }
+ pDevInfo = kmalloc(sizeof(VISORCHIPSET_DEVICE_INFO), GFP_KERNEL);
+ if (pDevInfo == NULL) {
+ LOGERR("CONTROLVM_DEVICE_CREATE Failed: busNo=%lu, devNo=%lu kmaloc failed",
+ busNo, devNo);
+ POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, devNo, busNo,
+ POSTCODE_SEVERITY_ERR);
+ RETINT(-CONTROLVM_RESP_ERROR_KMALLOC_FAILED);
+ }
+ memset(pDevInfo, 0, sizeof(VISORCHIPSET_DEVICE_INFO));
+ INIT_LIST_HEAD(&pDevInfo->entry);
+ pDevInfo->busNo = busNo;
+ pDevInfo->devNo = devNo;
+ pDevInfo->devInstGuid = cmd->createDevice.devInstGuid;
+ POSTCODE_LINUX_4(DEVICE_CREATE_ENTRY_PC, devNo, busNo,
+ POSTCODE_SEVERITY_INFO);
+
+ if (inmsg->hdr.Flags.testMessage == 1)
+ pDevInfo->chanInfo.addrType = ADDRTYPE_localTest;
+ else
+ pDevInfo->chanInfo.addrType = ADDRTYPE_localPhysical;
+ pDevInfo->chanInfo.channelAddr = cmd->createDevice.channelAddr;
+ pDevInfo->chanInfo.nChannelBytes = cmd->createDevice.channelBytes;
+ pDevInfo->chanInfo.channelTypeGuid = cmd->createDevice.dataTypeGuid;
+ pDevInfo->chanInfo.intr = cmd->createDevice.intr;
+ list_add(&pDevInfo->entry, &DevInfoList);
+ POSTCODE_LINUX_4(DEVICE_CREATE_EXIT_PC, devNo, busNo,
+ POSTCODE_SEVERITY_INFO);
+Away:
+ /* get the bus and devNo for DiagPool channel */
+ if (is_diagpool_channel(pDevInfo->chanInfo.channelTypeGuid)) {
+ g_diagpoolBusNo = busNo;
+ g_diagpoolDevNo = devNo;
+ LOGINF("CONTROLVM_DEVICE_CREATE for DiagPool channel: busNo=%lu, devNo=%lu",
+ g_diagpoolBusNo, g_diagpoolDevNo);
+ }
+ device_epilog(busNo, devNo, SegmentStateRunning,
+ CONTROLVM_DEVICE_CREATE, &inmsg->hdr, rc,
+ inmsg->hdr.Flags.responseExpected == 1,
+ FOR_VISORBUS(pDevInfo->chanInfo.channelTypeGuid));
+}
+
+static void
+my_device_changestate(CONTROLVM_MESSAGE *inmsg)
+{
+ CONTROLVM_MESSAGE_PACKET *cmd = &inmsg->cmd;
+ ulong busNo = cmd->deviceChangeState.busNo;
+ ulong devNo = cmd->deviceChangeState.devNo;
+ ULTRA_SEGMENT_STATE state = cmd->deviceChangeState.state;
+ VISORCHIPSET_DEVICE_INFO *pDevInfo = NULL;
+ int rc = CONTROLVM_RESP_SUCCESS;
+
+ pDevInfo = finddevice(&DevInfoList, busNo, devNo);
+ if (!pDevInfo) {
+ LOGERR("CONTROLVM_DEVICE_CHANGESTATE Failed: busNo=%lu, devNo=%lu invalid (doesn't exist)",
+ busNo, devNo);
+ POSTCODE_LINUX_4(DEVICE_CHANGESTATE_FAILURE_PC, devNo, busNo,
+ POSTCODE_SEVERITY_ERR);
+ RETINT(-CONTROLVM_RESP_ERROR_DEVICE_INVALID);
+ }
+ if (pDevInfo->state.created == 0) {
+ LOGERR("CONTROLVM_DEVICE_CHANGESTATE Failed: busNo=%lu, devNo=%lu invalid (not created)",
+ busNo, devNo);
+ POSTCODE_LINUX_4(DEVICE_CHANGESTATE_FAILURE_PC, devNo, busNo,
+ POSTCODE_SEVERITY_ERR);
+ RETINT(-CONTROLVM_RESP_ERROR_DEVICE_INVALID);
+ }
+Away:
+ if ((rc >= CONTROLVM_RESP_SUCCESS) && pDevInfo)
+ device_epilog(busNo, devNo, state, CONTROLVM_DEVICE_CHANGESTATE,
+ &inmsg->hdr, rc,
+ inmsg->hdr.Flags.responseExpected == 1,
+ FOR_VISORBUS(pDevInfo->chanInfo.channelTypeGuid));
+}
+
+static void
+my_device_destroy(CONTROLVM_MESSAGE *inmsg)
+{
+ CONTROLVM_MESSAGE_PACKET *cmd = &inmsg->cmd;
+ ulong busNo = cmd->destroyDevice.busNo;
+ ulong devNo = cmd->destroyDevice.devNo;
+ VISORCHIPSET_DEVICE_INFO *pDevInfo = NULL;
+ int rc = CONTROLVM_RESP_SUCCESS;
+
+ pDevInfo = finddevice(&DevInfoList, busNo, devNo);
+ if (!pDevInfo) {
+ LOGERR("CONTROLVM_DEVICE_DESTROY Failed: busNo=%lu, devNo=%lu invalid",
+ busNo, devNo);
+ RETINT(-CONTROLVM_RESP_ERROR_DEVICE_INVALID);
+ }
+ if (pDevInfo->state.created == 0) {
+ LOGERR("CONTROLVM_DEVICE_DESTROY Failed: busNo=%lu, devNo=%lu already destroyed",
+ busNo, devNo);
+ RETINT(-CONTROLVM_RESP_ERROR_ALREADY_DONE);
+ }
+
+Away:
+ if ((rc >= CONTROLVM_RESP_SUCCESS) && pDevInfo)
+ device_epilog(busNo, devNo, SegmentStateRunning,
+ CONTROLVM_DEVICE_DESTROY, &inmsg->hdr, rc,
+ inmsg->hdr.Flags.responseExpected == 1,
+ FOR_VISORBUS(pDevInfo->chanInfo.channelTypeGuid));
+}
+
+/* When provided with the physical address of the controlvm channel
+ * (phys_addr), the offset to the payload area we need to manage
+ * (offset), and the size of this payload area (bytes), fills in the
+ * CONTROLVM_PAYLOAD_INFO struct. Returns TRUE for success or FALSE
+ * for failure.
+ */
+static int
+initialize_controlvm_payload_info(HOSTADDRESS phys_addr, U64 offset, U32 bytes,
+ CONTROLVM_PAYLOAD_INFO *info)
+{
+ U8 *payload = NULL;
+ int rc = CONTROLVM_RESP_SUCCESS;
+
+ if (info == NULL) {
+ LOGERR("HUH ? CONTROLVM_PAYLOAD_INIT Failed : Programmer check at %s:%d",
+ __FILE__, __LINE__);
+ RETINT(-CONTROLVM_RESP_ERROR_PAYLOAD_INVALID);
+ }
+ memset(info, 0, sizeof(CONTROLVM_PAYLOAD_INFO));
+ if ((offset == 0) || (bytes == 0)) {
+ LOGERR("CONTROLVM_PAYLOAD_INIT Failed: RequestPayloadOffset=%llu RequestPayloadBytes=%llu!",
+ (u64) offset, (u64) bytes);
+ RETINT(-CONTROLVM_RESP_ERROR_PAYLOAD_INVALID);
+ }
+ payload = ioremap_cache(phys_addr + offset, bytes);
+ if (payload == NULL) {
+ LOGERR("CONTROLVM_PAYLOAD_INIT Failed: ioremap_cache %llu for %llu bytes failed",
+ (u64) offset, (u64) bytes);
+ RETINT(-CONTROLVM_RESP_ERROR_IOREMAP_FAILED);
+ }
+
+ info->offset = offset;
+ info->bytes = bytes;
+ info->ptr = payload;
+ LOGINF("offset=%llu, bytes=%lu, ptr=%p",
+ (u64) (info->offset), (ulong) (info->bytes), info->ptr);
+
+Away:
+ if (rc < 0) {
+ if (payload != NULL) {
+ iounmap(payload);
+ payload = NULL;
+ }
+ }
+ return rc;
+}
+
+static void
+destroy_controlvm_payload_info(CONTROLVM_PAYLOAD_INFO *info)
+{
+ if (info->ptr != NULL) {
+ iounmap(info->ptr);
+ info->ptr = NULL;
+ }
+ memset(info, 0, sizeof(CONTROLVM_PAYLOAD_INFO));
+}
+
+static void
+initialize_controlvm_payload(void)
+{
+ HOSTADDRESS phys_addr = visorchannel_get_physaddr(ControlVm_channel);
+ U64 payloadOffset = 0;
+ U32 payloadBytes = 0;
+ if (visorchannel_read(ControlVm_channel,
+ offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL,
+ RequestPayloadOffset),
+ &payloadOffset, sizeof(payloadOffset)) < 0) {
+ LOGERR("CONTROLVM_PAYLOAD_INIT Failed to read controlvm channel!");
+ POSTCODE_LINUX_2(CONTROLVM_INIT_FAILURE_PC,
+ POSTCODE_SEVERITY_ERR);
+ return;
+ }
+ if (visorchannel_read(ControlVm_channel,
+ offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL,
+ RequestPayloadBytes),
+ &payloadBytes, sizeof(payloadBytes)) < 0) {
+ LOGERR("CONTROLVM_PAYLOAD_INIT Failed to read controlvm channel!");
+ POSTCODE_LINUX_2(CONTROLVM_INIT_FAILURE_PC,
+ POSTCODE_SEVERITY_ERR);
+ return;
+ }
+ initialize_controlvm_payload_info(phys_addr,
+ payloadOffset, payloadBytes,
+ &ControlVm_payload_info);
+}
+
+/* Send ACTION=online for DEVPATH=/sys/devices/platform/visorchipset.
+ * Returns CONTROLVM_RESP_xxx code.
+ */
+int
+visorchipset_chipset_ready(void)
+{
+ kobject_uevent(&Visorchipset_platform_device.dev.kobj, KOBJ_ONLINE);
+ return CONTROLVM_RESP_SUCCESS;
+}
+EXPORT_SYMBOL_GPL(visorchipset_chipset_ready);
+
+int
+visorchipset_chipset_selftest(void)
+{
+ char env_selftest[20];
+ char *envp[] = { env_selftest, NULL };
+ sprintf(env_selftest, "SPARSP_SELFTEST=%d", 1);
+ kobject_uevent_env(&Visorchipset_platform_device.dev.kobj, KOBJ_CHANGE,
+ envp);
+ return CONTROLVM_RESP_SUCCESS;
+}
+EXPORT_SYMBOL_GPL(visorchipset_chipset_selftest);
+
+/* Send ACTION=offline for DEVPATH=/sys/devices/platform/visorchipset.
+ * Returns CONTROLVM_RESP_xxx code.
+ */
+int
+visorchipset_chipset_notready(void)
+{
+ kobject_uevent(&Visorchipset_platform_device.dev.kobj, KOBJ_OFFLINE);
+ return CONTROLVM_RESP_SUCCESS;
+}
+EXPORT_SYMBOL_GPL(visorchipset_chipset_notready);
+
+static void
+chipset_ready(CONTROLVM_MESSAGE_HEADER *msgHdr)
+{
+ int rc = visorchipset_chipset_ready();
+ if (rc != CONTROLVM_RESP_SUCCESS)
+ rc = -rc;
+ if (msgHdr->Flags.responseExpected && !visorchipset_holdchipsetready)
+ controlvm_respond(msgHdr, rc);
+ if (msgHdr->Flags.responseExpected && visorchipset_holdchipsetready) {
+ /* Send CHIPSET_READY response when all modules have been loaded
+ * and disks mounted for the partition
+ */
+ g_ChipSetMsgHdr = *msgHdr;
+ LOGINF("Holding CHIPSET_READY response");
+ }
+}
+
+static void
+chipset_selftest(CONTROLVM_MESSAGE_HEADER *msgHdr)
+{
+ int rc = visorchipset_chipset_selftest();
+ if (rc != CONTROLVM_RESP_SUCCESS)
+ rc = -rc;
+ if (msgHdr->Flags.responseExpected)
+ controlvm_respond(msgHdr, rc);
+}
+
+static void
+chipset_notready(CONTROLVM_MESSAGE_HEADER *msgHdr)
+{
+ int rc = visorchipset_chipset_notready();
+ if (rc != CONTROLVM_RESP_SUCCESS)
+ rc = -rc;
+ if (msgHdr->Flags.responseExpected)
+ controlvm_respond(msgHdr, rc);
+}
+
+/* This is your "one-stop" shop for grabbing the next message from the
+ * CONTROLVM_QUEUE_EVENT queue in the controlvm channel.
+ */
+static BOOL
+read_controlvm_event(CONTROLVM_MESSAGE *msg)
+{
+ if (visorchannel_signalremove(ControlVm_channel,
+ CONTROLVM_QUEUE_EVENT, msg)) {
+ /* got a message */
+ if (msg->hdr.Flags.testMessage == 1) {
+ LOGERR("ignoring bad CONTROLVM_QUEUE_EVENT msg with controlvm_msg_id=0x%x because Flags.testMessage is nonsensical (=1)", msg->hdr.Id);
+ return FALSE;
+ } else
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * The general parahotplug flow works as follows. The visorchipset
+ * driver receives a DEVICE_CHANGESTATE message from Command
+ * specifying a physical device to enable or disable. The CONTROLVM
+ * message handler calls parahotplug_process_message, which then adds
+ * the message to a global list and kicks off a udev event which
+ * causes a user level script to enable or disable the specified
+ * device. The udev script then writes to
+ * /proc/visorchipset/parahotplug, which causes parahotplug_proc_write
+ * to get called, at which point the appropriate CONTROLVM message is
+ * retrieved from the list and responded to.
+ */
+
+#define PARAHOTPLUG_TIMEOUT_MS 2000
+
+/*
+ * Generate unique int to match an outstanding CONTROLVM message with a
+ * udev script /proc response
+ */
+static int
+parahotplug_next_id(void)
+{
+ static atomic_t id = ATOMIC_INIT(0);
+ return atomic_inc_return(&id);
+}
+
+/*
+ * Returns the time (in jiffies) when a CONTROLVM message on the list
+ * should expire -- PARAHOTPLUG_TIMEOUT_MS in the future
+ */
+static unsigned long
+parahotplug_next_expiration(void)
+{
+ return jiffies + PARAHOTPLUG_TIMEOUT_MS * HZ / 1000;
+}
+
+/*
+ * Create a parahotplug_request, which is basically a wrapper for a
+ * CONTROLVM_MESSAGE that we can stick on a list
+ */
+static struct parahotplug_request *
+parahotplug_request_create(CONTROLVM_MESSAGE *msg)
+{
+ struct parahotplug_request *req =
+ kmalloc(sizeof(struct parahotplug_request),
+ GFP_KERNEL|__GFP_NORETRY);
+ if (req == NULL)
+ return NULL;
+
+ req->id = parahotplug_next_id();
+ req->expiration = parahotplug_next_expiration();
+ req->msg = *msg;
+
+ return req;
+}
+
+/*
+ * Free a parahotplug_request.
+ */
+static void
+parahotplug_request_destroy(struct parahotplug_request *req)
+{
+ kfree(req);
+}
+
+/*
+ * Cause uevent to run the user level script to do the disable/enable
+ * specified in (the CONTROLVM message in) the specified
+ * parahotplug_request
+ */
+static void
+parahotplug_request_kickoff(struct parahotplug_request *req)
+{
+ CONTROLVM_MESSAGE_PACKET *cmd = &req->msg.cmd;
+ char env_cmd[40], env_id[40], env_state[40], env_bus[40], env_dev[40],
+ env_func[40];
+ char *envp[] = {
+ env_cmd, env_id, env_state, env_bus, env_dev, env_func, NULL
+ };
+
+ sprintf(env_cmd, "SPAR_PARAHOTPLUG=1");
+ sprintf(env_id, "SPAR_PARAHOTPLUG_ID=%d", req->id);
+ sprintf(env_state, "SPAR_PARAHOTPLUG_STATE=%d",
+ cmd->deviceChangeState.state.Active);
+ sprintf(env_bus, "SPAR_PARAHOTPLUG_BUS=%d",
+ cmd->deviceChangeState.busNo);
+ sprintf(env_dev, "SPAR_PARAHOTPLUG_DEVICE=%d",
+ cmd->deviceChangeState.devNo >> 3);
+ sprintf(env_func, "SPAR_PARAHOTPLUG_FUNCTION=%d",
+ cmd->deviceChangeState.devNo & 0x7);
+
+ LOGINF("parahotplug_request_kickoff: state=%d, bdf=%d/%d/%d, id=%u\n",
+ cmd->deviceChangeState.state.Active,
+ cmd->deviceChangeState.busNo, cmd->deviceChangeState.devNo >> 3,
+ cmd->deviceChangeState.devNo & 7, req->id);
+
+ kobject_uevent_env(&Visorchipset_platform_device.dev.kobj, KOBJ_CHANGE,
+ envp);
+}
+
+/*
+ * Remove any request from the list that's been on there too long and
+ * respond with an error.
+ */
+static void
+parahotplug_process_list(void)
+{
+ struct list_head *pos = NULL;
+ struct list_head *tmp = NULL;
+
+ spin_lock(&Parahotplug_request_list_lock);
+
+ list_for_each_safe(pos, tmp, &Parahotplug_request_list) {
+ struct parahotplug_request *req =
+ list_entry(pos, struct parahotplug_request, list);
+ if (time_after_eq(jiffies, req->expiration)) {
+ list_del(pos);
+ if (req->msg.hdr.Flags.responseExpected)
+ controlvm_respond_physdev_changestate(
+ &req->msg.hdr,
+ CONTROLVM_RESP_ERROR_DEVICE_UDEV_TIMEOUT,
+ req->msg.cmd.deviceChangeState.state);
+ parahotplug_request_destroy(req);
+ }
+ }
+
+ spin_unlock(&Parahotplug_request_list_lock);
+}
+
+/*
+ * Called from the /proc handler, which means the user script has
+ * finished the enable/disable. Find the matching identifier, and
+ * respond to the CONTROLVM message with success.
+ */
+static int
+parahotplug_request_complete(int id, U16 active)
+{
+ struct list_head *pos = NULL;
+ struct list_head *tmp = NULL;
+
+ spin_lock(&Parahotplug_request_list_lock);
+
+ /* Look for a request matching "id". */
+ list_for_each_safe(pos, tmp, &Parahotplug_request_list) {
+ struct parahotplug_request *req =
+ list_entry(pos, struct parahotplug_request, list);
+ if (req->id == id) {
+ /* Found a match. Remove it from the list and
+ * respond.
+ */
+ list_del(pos);
+ spin_unlock(&Parahotplug_request_list_lock);
+ req->msg.cmd.deviceChangeState.state.Active = active;
+ if (req->msg.hdr.Flags.responseExpected)
+ controlvm_respond_physdev_changestate(
+ &req->msg.hdr, CONTROLVM_RESP_SUCCESS,
+ req->msg.cmd.deviceChangeState.state);
+ parahotplug_request_destroy(req);
+ return 0;
+ }
+ }
+
+ spin_unlock(&Parahotplug_request_list_lock);
+ return -1;
+}
+
+/*
+ * Enables or disables a PCI device by kicking off a udev script
+ */
+void
+parahotplug_process_message(CONTROLVM_MESSAGE *inmsg)
+{
+ struct parahotplug_request *req;
+
+ req = parahotplug_request_create(inmsg);
+
+ if (req == NULL) {
+ LOGERR("parahotplug_process_message: couldn't allocate request");
+ return;
+ }
+
+ if (inmsg->cmd.deviceChangeState.state.Active) {
+ /* For enable messages, just respond with success
+ * right away. This is a bit of a hack, but there are
+ * issues with the early enable messages we get (with
+ * either the udev script not detecting that the device
+ * is up, or not getting called at all). Fortunately
+ * the messages that get lost don't matter anyway, as
+ * devices are automatically enabled at
+ * initialization.
+ */
+ parahotplug_request_kickoff(req);
+ controlvm_respond_physdev_changestate(&inmsg->hdr,
+ CONTROLVM_RESP_SUCCESS,
+ inmsg->cmd.
+ deviceChangeState.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);
+ }
+}
+
+/*
+ * Gets called when the udev script writes to
+ * /proc/visorchipset/parahotplug. Expects input in the form of "<id>
+ * <active>" where <id> is the identifier passed to the script that
+ * matches a request on the request list, and <active> is 0 or 1
+ * indicating whether the device is now enabled or not.
+ */
+static ssize_t
+parahotplug_proc_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ char buf[64];
+ uint id;
+ ushort active;
+
+ if (count > sizeof(buf) - 1) {
+ LOGERR("parahotplug_proc_write: count (%d) exceeds size of buffer (%d)",
+ (int) count, (int) sizeof(buf));
+ return -EINVAL;
+ }
+ if (copy_from_user(buf, buffer, count)) {
+ LOGERR("parahotplug_proc_write: copy_from_user failed");
+ return -EFAULT;
+ }
+ buf[count] = '\0';
+
+ if (sscanf(buf, "%u %hu", &id, &active) != 2) {
+ id = 0;
+ active = 0;
+ }
+
+ if (active != 1 && active != 0) {
+ LOGERR("parahotplug_proc_write: invalid active field");
+ return -EINVAL;
+ }
+
+ parahotplug_request_complete((int) id, (U16) active);
+
+ return count;
+}
+
+static const struct file_operations parahotplug_proc_fops = {
+ .owner = THIS_MODULE,
+ .read = visorchipset_proc_read_writeonly,
+ .write = parahotplug_proc_write,
+};
+
+/* Process a controlvm message.
+ * Return result:
+ * 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.
+ */
+static BOOL
+handle_command(CONTROLVM_MESSAGE inmsg, HOSTADDRESS channel_addr)
+{
+ CONTROLVM_MESSAGE_PACKET *cmd = &inmsg.cmd;
+ U64 parametersAddr = 0;
+ U32 parametersBytes = 0;
+ PARSER_CONTEXT *parser_ctx = NULL;
+ BOOL isLocalAddr = FALSE;
+ CONTROLVM_MESSAGE ackmsg;
+
+ /* create parsing context if necessary */
+ isLocalAddr = (inmsg.hdr.Flags.testMessage == 1);
+ if (channel_addr == 0) {
+ LOGERR("HUH? channel_addr is 0!");
+ return TRUE;
+ }
+ parametersAddr = channel_addr + inmsg.hdr.PayloadVmOffset;
+ parametersBytes = inmsg.hdr.PayloadBytes;
+
+ /* Parameter and channel addresses within test messages actually lie
+ * within our OS-controlled memory. We need to know that, because it
+ * makes a difference in how we compute the virtual address.
+ */
+ if (parametersAddr != 0 && parametersBytes != 0) {
+ BOOL retry = FALSE;
+ parser_ctx =
+ parser_init_byteStream(parametersAddr, parametersBytes,
+ isLocalAddr, &retry);
+ if (!parser_ctx) {
+ if (retry) {
+ LOGWRN("throttling to copy payload");
+ return FALSE;
+ }
+ LOGWRN("parsing failed");
+ LOGWRN("inmsg.hdr.Id=0x%lx", (ulong) inmsg.hdr.Id);
+ LOGWRN("parametersAddr=0x%llx", (u64) parametersAddr);
+ LOGWRN("parametersBytes=%lu", (ulong) parametersBytes);
+ LOGWRN("isLocalAddr=%d", isLocalAddr);
+ }
+ }
+
+ if (!isLocalAddr) {
+ controlvm_init_response(&ackmsg, &inmsg.hdr,
+ CONTROLVM_RESP_SUCCESS);
+ if ((ControlVm_channel)
+ &&
+ (!visorchannel_signalinsert
+ (ControlVm_channel, CONTROLVM_QUEUE_ACK, &ackmsg)))
+ LOGWRN("failed to send ACK failed");
+ }
+ switch (inmsg.hdr.Id) {
+ case CONTROLVM_CHIPSET_INIT:
+ LOGINF("CHIPSET_INIT(#busses=%lu,#switches=%lu)",
+ (ulong) inmsg.cmd.initChipset.busCount,
+ (ulong) inmsg.cmd.initChipset.switchCount);
+ chipset_init(&inmsg);
+ break;
+ case CONTROLVM_BUS_CREATE:
+ LOGINF("BUS_CREATE(%lu,#devs=%lu)",
+ (ulong) cmd->createBus.busNo,
+ (ulong) cmd->createBus.deviceCount);
+ bus_create(&inmsg);
+ break;
+ case CONTROLVM_BUS_DESTROY:
+ LOGINF("BUS_DESTROY(%lu)", (ulong) cmd->destroyBus.busNo);
+ bus_destroy(&inmsg);
+ break;
+ case CONTROLVM_BUS_CONFIGURE:
+ LOGINF("BUS_CONFIGURE(%lu)", (ulong) cmd->configureBus.busNo);
+ bus_configure(&inmsg, parser_ctx);
+ break;
+ case CONTROLVM_DEVICE_CREATE:
+ LOGINF("DEVICE_CREATE(%lu,%lu)",
+ (ulong) cmd->createDevice.busNo,
+ (ulong) cmd->createDevice.devNo);
+ my_device_create(&inmsg);
+ break;
+ case CONTROLVM_DEVICE_CHANGESTATE:
+ if (cmd->deviceChangeState.flags.physicalDevice) {
+ LOGINF("DEVICE_CHANGESTATE for physical device (%lu,%lu, active=%lu)",
+ (ulong) cmd->deviceChangeState.busNo,
+ (ulong) cmd->deviceChangeState.devNo,
+ (ulong) cmd->deviceChangeState.state.Active);
+ parahotplug_process_message(&inmsg);
+ } else {
+ LOGINF("DEVICE_CHANGESTATE for virtual device (%lu,%lu, state.Alive=0x%lx)",
+ (ulong) cmd->deviceChangeState.busNo,
+ (ulong) cmd->deviceChangeState.devNo,
+ (ulong) cmd->deviceChangeState.state.Alive);
+ /* save the hdr and cmd structures for later use */
+ /* when sending back the response to Command */
+ my_device_changestate(&inmsg);
+ g_DiagMsgHdr = inmsg.hdr;
+ g_DeviceChangeStatePacket = inmsg.cmd;
+ break;
+ }
+ break;
+ case CONTROLVM_DEVICE_DESTROY:
+ LOGINF("DEVICE_DESTROY(%lu,%lu)",
+ (ulong) cmd->destroyDevice.busNo,
+ (ulong) cmd->destroyDevice.devNo);
+ my_device_destroy(&inmsg);
+ break;
+ case CONTROLVM_DEVICE_CONFIGURE:
+ LOGINF("DEVICE_CONFIGURE(%lu,%lu)",
+ (ulong) cmd->configureDevice.busNo,
+ (ulong) cmd->configureDevice.devNo);
+ /* no op for now, just send a respond that we passed */
+ if (inmsg.hdr.Flags.responseExpected)
+ controlvm_respond(&inmsg.hdr, CONTROLVM_RESP_SUCCESS);
+ break;
+ case CONTROLVM_CHIPSET_READY:
+ LOGINF("CHIPSET_READY");
+ chipset_ready(&inmsg.hdr);
+ break;
+ case CONTROLVM_CHIPSET_SELFTEST:
+ LOGINF("CHIPSET_SELFTEST");
+ chipset_selftest(&inmsg.hdr);
+ break;
+ case CONTROLVM_CHIPSET_STOP:
+ LOGINF("CHIPSET_STOP");
+ chipset_notready(&inmsg.hdr);
+ break;
+ default:
+ LOGERR("unrecognized controlvm cmd=%d", (int) inmsg.hdr.Id);
+ if (inmsg.hdr.Flags.responseExpected)
+ controlvm_respond(&inmsg.hdr,
+ -CONTROLVM_RESP_ERROR_MESSAGE_ID_UNKNOWN);
+ break;
+ }
+
+ if (parser_ctx != NULL) {
+ parser_done(parser_ctx);
+ parser_ctx = NULL;
+ }
+ return TRUE;
+}
+
+static void
+controlvm_periodic_work(struct work_struct *work)
+{
+ VISORCHIPSET_CHANNEL_INFO chanInfo;
+ CONTROLVM_MESSAGE inmsg;
+ char s[99];
+ BOOL gotACommand = FALSE;
+ BOOL handle_command_failed = FALSE;
+ static U64 Poll_Count;
+
+ /* make sure visorbus server is registered for controlvm callbacks */
+ if (visorchipset_serverregwait && !serverregistered)
+ RETVOID;
+ /* make sure visorclientbus server is regsitered for controlvm
+ * callbacks
+ */
+ if (visorchipset_clientregwait && !clientregistered)
+ RETVOID;
+
+ memset(&chanInfo, 0, sizeof(VISORCHIPSET_CHANNEL_INFO));
+ if (!ControlVm_channel) {
+ HOSTADDRESS addr = controlvm_get_channel_address();
+ if (addr != 0) {
+ ControlVm_channel =
+ visorchannel_create_with_lock
+ (addr,
+ sizeof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL),
+ UltraControlvmChannelProtocolGuid);
+ if (ControlVm_channel == NULL)
+ LOGERR("failed to create controlvm channel");
+ else if (ULTRA_CONTROLVM_CHANNEL_OK_CLIENT
+ (visorchannel_get_header(ControlVm_channel),
+ NULL)) {
+ LOGINF("Channel %s (ControlVm) discovered",
+ visorchannel_id(ControlVm_channel, s));
+ initialize_controlvm_payload();
+ } else {
+ LOGERR("controlvm channel is invalid");
+ visorchannel_destroy(ControlVm_channel);
+ ControlVm_channel = NULL;
+ }
+ }
+ }
+
+ Poll_Count++;
+ if ((ControlVm_channel != NULL) || (Poll_Count >= 250))
+ ; /* keep going */
+ else
+ RETVOID;
+
+ /* Check events to determine if response to CHIPSET_READY
+ * should be sent
+ */
+ if (visorchipset_holdchipsetready
+ && (g_ChipSetMsgHdr.Id != CONTROLVM_INVALID)) {
+ if (check_chipset_events() == 1) {
+ LOGINF("Sending CHIPSET_READY response");
+ controlvm_respond(&g_ChipSetMsgHdr, 0);
+ clear_chipset_events();
+ memset(&g_ChipSetMsgHdr, 0,
+ sizeof(CONTROLVM_MESSAGE_HEADER));
+ }
+ }
+
+ if (ControlVm_channel) {
+ while (visorchannel_signalremove(ControlVm_channel,
+ CONTROLVM_QUEUE_RESPONSE,
+ &inmsg)) {
+ if (inmsg.hdr.PayloadMaxBytes != 0) {
+ LOGERR("Payload of size %lu returned @%lu with unexpected message id %d.",
+ (ulong) inmsg.hdr.PayloadMaxBytes,
+ (ulong) inmsg.hdr.PayloadVmOffset,
+ inmsg.hdr.Id);
+ }
+ }
+ if (!gotACommand) {
+ 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;
+ gotACommand = TRUE;
+ } else
+ gotACommand = read_controlvm_event(&inmsg);
+ }
+ }
+
+ handle_command_failed = FALSE;
+ while (gotACommand && (!handle_command_failed)) {
+ Most_recent_message_jiffies = jiffies;
+ if (ControlVm_channel) {
+ if (handle_command(inmsg,
+ visorchannel_get_physaddr
+ (ControlVm_channel)))
+ gotACommand = 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;
+ }
+
+ } else {
+ handle_command(inmsg, 0);
+ gotACommand = FALSE;
+ }
+ }
+
+ /* parahotplug_worker */
+ parahotplug_process_list();
+
+ RETVOID;
+
+Away:
+
+ if (time_after(jiffies,
+ 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) {
+ LOGINF("switched to slow controlvm polling");
+ Poll_jiffies = POLLJIFFIES_CONTROLVMCHANNEL_SLOW;
+ }
+ } else {
+ if (Poll_jiffies != POLLJIFFIES_CONTROLVMCHANNEL_FAST) {
+ Poll_jiffies = POLLJIFFIES_CONTROLVMCHANNEL_FAST;
+ LOGINF("switched to fast controlvm polling");
+ }
+ }
+
+ if (queue_delayed_work(Periodic_controlvm_workqueue,
+ &Periodic_controlvm_work, Poll_jiffies) < 0) {
+ LOGERR("queue_delayed_work failed!");
+ POSTCODE_LINUX_2(QUEUE_DELAYED_WORK_PC, POSTCODE_SEVERITY_ERR);
+ }
+}
+
+static void
+setup_crash_devices_work_queue(struct work_struct *work)
+{
+
+ CONTROLVM_MESSAGE localCrashCreateBusMsg;
+ CONTROLVM_MESSAGE localCrashCreateDevMsg;
+ CONTROLVM_MESSAGE msg;
+ HOSTADDRESS host_addr;
+ U32 localSavedCrashMsgOffset;
+ U16 localSavedCrashMsgCount;
+
+ /* make sure visorbus server is registered for controlvm callbacks */
+ if (visorchipset_serverregwait && !serverregistered)
+ RETVOID;
+
+ /* make sure visorclientbus server is regsitered for controlvm
+ * callbacks
+ */
+ if (visorchipset_clientregwait && !clientregistered)
+ RETVOID;
+
+ POSTCODE_LINUX_2(CRASH_DEV_ENTRY_PC, POSTCODE_SEVERITY_INFO);
+
+ /* send init chipset msg */
+ msg.hdr.Id = CONTROLVM_CHIPSET_INIT;
+ msg.cmd.initChipset.busCount = 23;
+ msg.cmd.initChipset.switchCount = 0;
+
+ chipset_init(&msg);
+
+ host_addr = controlvm_get_channel_address();
+ if (!host_addr) {
+ LOGERR("Huh? Host address is NULL");
+ POSTCODE_LINUX_2(CRASH_DEV_HADDR_NULL, POSTCODE_SEVERITY_ERR);
+ return;
+ }
+
+ ControlVm_channel =
+ visorchannel_create_with_lock
+ (host_addr,
+ sizeof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL),
+ UltraControlvmChannelProtocolGuid);
+
+ if (ControlVm_channel == NULL) {
+ LOGERR("failed to create controlvm channel");
+ POSTCODE_LINUX_2(CRASH_DEV_CONTROLVM_NULL,
+ POSTCODE_SEVERITY_ERR);
+ return;
+ }
+
+ /* get saved message count */
+ if (visorchannel_read(ControlVm_channel,
+ offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL,
+ SavedCrashMsgCount),
+ &localSavedCrashMsgCount, sizeof(U16)) < 0) {
+ LOGERR("failed to get Saved Message Count");
+ POSTCODE_LINUX_2(CRASH_DEV_CTRL_RD_FAILURE_PC,
+ POSTCODE_SEVERITY_ERR);
+ return;
+ }
+
+ if (localSavedCrashMsgCount != CONTROLVM_CRASHMSG_MAX) {
+ LOGERR("Saved Message Count incorrect %d",
+ localSavedCrashMsgCount);
+ POSTCODE_LINUX_3(CRASH_DEV_COUNT_FAILURE_PC,
+ localSavedCrashMsgCount,
+ POSTCODE_SEVERITY_ERR);
+ return;
+ }
+
+ /* get saved crash message offset */
+ if (visorchannel_read(ControlVm_channel,
+ offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL,
+ SavedCrashMsgOffset),
+ &localSavedCrashMsgOffset, sizeof(U32)) < 0) {
+ LOGERR("failed to get Saved Message Offset");
+ POSTCODE_LINUX_2(CRASH_DEV_CTRL_RD_FAILURE_PC,
+ POSTCODE_SEVERITY_ERR);
+ return;
+ }
+
+ /* read create device message for storage bus offset */
+ if (visorchannel_read(ControlVm_channel,
+ localSavedCrashMsgOffset,
+ &localCrashCreateBusMsg,
+ sizeof(CONTROLVM_MESSAGE)) < 0) {
+ LOGERR("CRASH_DEV_RD_BUS_FAIULRE: Failed to read CrashCreateBusMsg!");
+ POSTCODE_LINUX_2(CRASH_DEV_RD_BUS_FAIULRE_PC,
+ POSTCODE_SEVERITY_ERR);
+ return;
+ }
+
+ /* read create device message for storage device */
+ if (visorchannel_read(ControlVm_channel,
+ localSavedCrashMsgOffset +
+ sizeof(CONTROLVM_MESSAGE),
+ &localCrashCreateDevMsg,
+ sizeof(CONTROLVM_MESSAGE)) < 0) {
+ LOGERR("CRASH_DEV_RD_DEV_FAIULRE: Failed to read CrashCreateDevMsg!");
+ POSTCODE_LINUX_2(CRASH_DEV_RD_DEV_FAIULRE_PC,
+ POSTCODE_SEVERITY_ERR);
+ return;
+ }
+
+ /* reuse IOVM create bus message */
+ if (localCrashCreateBusMsg.cmd.createBus.channelAddr != 0)
+ bus_create(&localCrashCreateBusMsg);
+ else {
+ LOGERR("CrashCreateBusMsg is null, no dump will be taken");
+ POSTCODE_LINUX_2(CRASH_DEV_BUS_NULL_FAILURE_PC,
+ POSTCODE_SEVERITY_ERR);
+ return;
+ }
+
+ /* reuse create device message for storage device */
+ if (localCrashCreateDevMsg.cmd.createDevice.channelAddr != 0)
+ my_device_create(&localCrashCreateDevMsg);
+ else {
+ LOGERR("CrashCreateDevMsg is null, no dump will be taken");
+ POSTCODE_LINUX_2(CRASH_DEV_DEV_NULL_FAILURE_PC,
+ POSTCODE_SEVERITY_ERR);
+ return;
+ }
+ LOGINF("Bus and device ready for dumping");
+ POSTCODE_LINUX_2(CRASH_DEV_EXIT_PC, POSTCODE_SEVERITY_INFO);
+ return;
+
+Away:
+
+ Poll_jiffies = POLLJIFFIES_CONTROLVMCHANNEL_SLOW;
+
+ if (queue_delayed_work(Periodic_controlvm_workqueue,
+ &Periodic_controlvm_work, Poll_jiffies) < 0) {
+ LOGERR("queue_delayed_work failed!");
+ POSTCODE_LINUX_2(QUEUE_DELAYED_WORK_PC, POSTCODE_SEVERITY_ERR);
+ }
+}
+
+static void
+bus_create_response(ulong busNo, int response)
+{
+ bus_responder(CONTROLVM_BUS_CREATE, busNo, response);
+}
+
+static void
+bus_destroy_response(ulong busNo, int response)
+{
+ bus_responder(CONTROLVM_BUS_DESTROY, busNo, response);
+}
+
+static void
+device_create_response(ulong busNo, ulong devNo, int response)
+{
+ device_responder(CONTROLVM_DEVICE_CREATE, busNo, devNo, response);
+}
+
+static void
+device_destroy_response(ulong busNo, ulong devNo, int response)
+{
+ device_responder(CONTROLVM_DEVICE_DESTROY, busNo, devNo, response);
+}
+
+void
+device_pause_response(ulong busNo, ulong devNo, int response)
+{
+
+ device_changestate_responder(CONTROLVM_DEVICE_CHANGESTATE,
+ busNo, devNo, response,
+ SegmentStateStandby);
+}
+EXPORT_SYMBOL_GPL(device_pause_response);
+
+static void
+device_resume_response(ulong busNo, ulong devNo, int response)
+{
+ device_changestate_responder(CONTROLVM_DEVICE_CHANGESTATE,
+ busNo, devNo, response,
+ SegmentStateRunning);
+}
+
+BOOL
+visorchipset_get_bus_info(ulong busNo, VISORCHIPSET_BUS_INFO *busInfo)
+{
+ void *p = findbus(&BusInfoList, busNo);
+ if (!p) {
+ LOGERR("(%lu) failed", busNo);
+ return FALSE;
+ }
+ memcpy(busInfo, p, sizeof(VISORCHIPSET_BUS_INFO));
+ return TRUE;
+}
+EXPORT_SYMBOL_GPL(visorchipset_get_bus_info);
+
+BOOL
+visorchipset_set_bus_context(ulong busNo, void *context)
+{
+ VISORCHIPSET_BUS_INFO *p = findbus(&BusInfoList, busNo);
+ if (!p) {
+ LOGERR("(%lu) failed", busNo);
+ return FALSE;
+ }
+ p->bus_driver_context = context;
+ return TRUE;
+}
+EXPORT_SYMBOL_GPL(visorchipset_set_bus_context);
+
+BOOL
+visorchipset_get_device_info(ulong busNo, ulong devNo,
+ VISORCHIPSET_DEVICE_INFO *devInfo)
+{
+ void *p = finddevice(&DevInfoList, busNo, devNo);
+ if (!p) {
+ LOGERR("(%lu,%lu) failed", busNo, devNo);
+ return FALSE;
+ }
+ memcpy(devInfo, p, sizeof(VISORCHIPSET_DEVICE_INFO));
+ return TRUE;
+}
+EXPORT_SYMBOL_GPL(visorchipset_get_device_info);
+
+BOOL
+visorchipset_set_device_context(ulong busNo, ulong devNo, void *context)
+{
+ VISORCHIPSET_DEVICE_INFO *p = finddevice(&DevInfoList, busNo, devNo);
+ if (!p) {
+ LOGERR("(%lu,%lu) failed", busNo, devNo);
+ return FALSE;
+ }
+ p->bus_driver_context = context;
+ return TRUE;
+}
+EXPORT_SYMBOL_GPL(visorchipset_set_device_context);
+
+/* Generic wrapper function for allocating memory from a kmem_cache pool.
+ */
+void *
+visorchipset_cache_alloc(struct kmem_cache *pool, BOOL ok_to_block,
+ char *fn, int ln)
+{
+ gfp_t gfp;
+ void *p;
+
+ if (ok_to_block)
+ gfp = GFP_KERNEL;
+ else
+ gfp = GFP_ATOMIC;
+ /* __GFP_NORETRY means "ok to fail", meaning
+ * kmem_cache_alloc() can return NULL, implying the caller CAN
+ * cope with failure. 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.
+ */
+ gfp |= __GFP_NORETRY;
+ p = kmem_cache_alloc(pool, gfp);
+ if (!p) {
+ LOGERR("kmem_cache_alloc failed early @%s:%d\n", fn, ln);
+ return NULL;
+ }
+ atomic_inc(&Visorchipset_cache_buffers_in_use);
+ return p;
+}
+
+/* Generic wrapper function for freeing memory from a kmem_cache pool.
+ */
+void
+visorchipset_cache_free(struct kmem_cache *pool, void *p, char *fn, int ln)
+{
+ if (!p) {
+ LOGERR("NULL pointer @%s:%d\n", fn, ln);
+ return;
+ }
+ atomic_dec(&Visorchipset_cache_buffers_in_use);
+ kmem_cache_free(pool, p);
+}
+
+#define gettoken(bufp) strsep(bufp, " -\t\n")
+
+static ssize_t
+chipset_proc_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ char buf[512];
+ char *token, *p;
+
+ if (count > sizeof(buf) - 1) {
+ LOGERR("chipset_proc_write: count (%d) exceeds size of buffer (%d)",
+ (int) count, (int) sizeof(buffer));
+ return -EINVAL;
+ }
+ if (copy_from_user(buf, buffer, count)) {
+ LOGERR("chipset_proc_write: copy_from_user failed");
+ return -EFAULT;
+ }
+ buf[count] = '\0';
+
+ p = buf;
+ token = gettoken(&p);
+
+ if (strcmp(token, "CALLHOMEDISK_MOUNTED") == 0) {
+ token = gettoken(&p);
+ /* The Call Home Disk has been mounted */
+ if (strcmp(token, "0") == 0)
+ chipset_events[0] = 1;
+ } else if (strcmp(token, "MODULES_LOADED") == 0) {
+ token = gettoken(&p);
+ /* All modules for the partition have been loaded */
+ if (strcmp(token, "0") == 0)
+ chipset_events[1] = 1;
+ } else if (token == NULL) {
+ /* No event specified */
+ LOGERR("No event was specified to send CHIPSET_READY response");
+ return -1;
+ } else {
+ /* Unsupported event specified */
+ LOGERR("%s is an invalid event for sending CHIPSET_READY response", token);
+ return -1;
+ }
+
+ return count;
+}
+
+static ssize_t
+visorchipset_proc_read_writeonly(struct file *file, char __user *buf,
+ size_t len, loff_t *offset)
+{
+ return 0;
+}
+
+/**
+ * Reads the InstallationError, InstallationTextId,
+ * InstallationRemainingSteps fields of ControlVMChannel.
+ */
+static ssize_t
+proc_read_installer(struct file *file, char __user *buf,
+ size_t len, loff_t *offset)
+{
+ int length = 0;
+ U16 remainingSteps;
+ U32 error, textId;
+ 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;
+
+ visorchannel_read(ControlVm_channel,
+ offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL,
+ InstallationRemainingSteps), &remainingSteps,
+ sizeof(U16));
+ visorchannel_read(ControlVm_channel,
+ offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL,
+ InstallationError), &error, sizeof(U32));
+ visorchannel_read(ControlVm_channel,
+ offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL,
+ InstallationTextId), &textId, sizeof(U32));
+
+ length = sprintf(vbuf, "%u %u %u\n", remainingSteps, error, textId);
+ if (copy_to_user(buf, vbuf, length)) {
+ kfree(vbuf);
+ return -EFAULT;
+ }
+
+ kfree(vbuf);
+ *offset += length;
+ return length;
+}
+
+/**
+ * Writes to the InstallationError, InstallationTextId,
+ * InstallationRemainingSteps fields of
+ * ControlVMChannel.
+ * Input: RemainingSteps Error TextId
+ * Limit 32 characters input
+ */
+#define UINT16_MAX (65535U)
+#define UINT32_MAX (4294967295U)
+static ssize_t
+proc_write_installer(struct file *file,
+ const char __user *buffer, size_t count, loff_t *ppos)
+{
+ char buf[32];
+ U16 remainingSteps;
+ U32 error, textId;
+
+ /* Check to make sure there is no buffer overflow */
+ if (count > (sizeof(buf) - 1))
+ return -EINVAL;
+
+ if (copy_from_user(buf, buffer, count)) {
+ WARN(1, "Error copying from user space\n");
+ return -EFAULT;
+ }
+
+ if (sscanf(buf, "%hu %i %i", &remainingSteps, &error, &textId) != 3) {
+ remainingSteps = UINT16_MAX;
+ error = UINT32_MAX;
+ textId = UINT32_MAX;
+ }
+
+ if (remainingSteps != UINT16_MAX) {
+ if (visorchannel_write
+ (ControlVm_channel,
+ offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL,
+ InstallationRemainingSteps), &remainingSteps,
+ sizeof(U16)) < 0)
+ WARN(1, "Installation Status Write Failed - Write function error - RemainingSteps = %d\n",
+ remainingSteps);
+ }
+
+ if (error != UINT32_MAX) {
+ if (visorchannel_write
+ (ControlVm_channel,
+ offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL,
+ InstallationError), &error, sizeof(U32)) < 0)
+ WARN(1, "Installation Status Write Failed - Write function error - Error = %d\n",
+ error);
+ }
+
+ if (textId != UINT32_MAX) {
+ if (visorchannel_write
+ (ControlVm_channel,
+ offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL,
+ InstallationTextId), &textId, sizeof(U32)) < 0)
+ WARN(1, "Installation Status Write Failed - Write function error - TextId = %d\n",
+ textId);
+ }
+
+ /* So this function isn't called multiple times, must return
+ * size of buffer
+ */
+ return count;
+}
+
+/**
+ * Reads the ToolAction field of ControlVMChannel.
+ */
+static ssize_t
+proc_read_toolaction(struct file *file, char __user *buf,
+ size_t len, loff_t *offset)
+{
+ int length = 0;
+ U8 toolAction;
+ 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;
+
+ visorchannel_read(ControlVm_channel,
+ offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL,
+ ToolAction), &toolAction, sizeof(U8));
+
+ length = sprintf(vbuf, "%u\n", toolAction);
+ if (copy_to_user(buf, vbuf, length)) {
+ kfree(vbuf);
+ return -EFAULT;
+ }
+
+ kfree(vbuf);
+ *offset += length;
+ return length;
+}
+
+/**
+ * Writes to the ToolAction field of ControlVMChannel.
+ * Input: ToolAction
+ * Limit 3 characters input
+ */
+#define UINT8_MAX (255U)
+static ssize_t
+proc_write_toolaction(struct file *file,
+ const char __user *buffer, size_t count, loff_t *ppos)
+{
+ char buf[3];
+ U8 toolAction;
+
+ /* Check to make sure there is no buffer overflow */
+ if (count > (sizeof(buf) - 1))
+ return -EINVAL;
+
+ if (copy_from_user(buf, buffer, count)) {
+ WARN(1, "Error copying from user space\n");
+ return -EFAULT;
+ }
+
+ if (sscanf(buf, "%hhd", &toolAction) != 1)
+ toolAction = UINT8_MAX;
+
+ if (toolAction != UINT8_MAX) {
+ if (visorchannel_write
+ (ControlVm_channel,
+ offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, ToolAction),
+ &toolAction, sizeof(U8)) < 0)
+ WARN(1, "Installation ToolAction Write Failed - ToolAction = %d\n",
+ toolAction);
+ }
+
+ /* So this function isn't called multiple times, must return
+ * size of buffer
+ */
+ return count;
+}
+
+/**
+ * Reads the EfiSparIndication.BootToTool field of ControlVMChannel.
+ */
+static ssize_t
+proc_read_bootToTool(struct file *file, char __user *buf,
+ size_t len, loff_t *offset)
+{
+ int length = 0;
+ ULTRA_EFI_SPAR_INDICATION efiSparIndication;
+ 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;
+
+ visorchannel_read(ControlVm_channel,
+ offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL,
+ EfiSparIndication), &efiSparIndication,
+ sizeof(ULTRA_EFI_SPAR_INDICATION));
+
+ length = sprintf(vbuf, "%d\n", (int) efiSparIndication.BootToTool);
+ if (copy_to_user(buf, vbuf, length)) {
+ kfree(vbuf);
+ return -EFAULT;
+ }
+
+ kfree(vbuf);
+ *offset += length;
+ return length;
+}
+
+/**
+ * Writes to the EfiSparIndication.BootToTool field of ControlVMChannel.
+ * Input: 1 or 0 (1 being on, 0 being off)
+ */
+static ssize_t
+proc_write_bootToTool(struct file *file,
+ const char __user *buffer, size_t count, loff_t *ppos)
+{
+ char buf[3];
+ int inputVal;
+ ULTRA_EFI_SPAR_INDICATION efiSparIndication;
+
+ /* Check to make sure there is no buffer overflow */
+ if (count > (sizeof(buf) - 1))
+ return -EINVAL;
+
+ if (copy_from_user(buf, buffer, count)) {
+ WARN(1, "Error copying from user space\n");
+ return -EFAULT;
+ }
+
+ if (sscanf(buf, "%i", &inputVal) != 1)
+ inputVal = 0;
+
+ efiSparIndication.BootToTool = (inputVal == 1 ? 1 : 0);
+
+ if (visorchannel_write
+ (ControlVm_channel,
+ offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, EfiSparIndication),
+ &efiSparIndication, sizeof(ULTRA_EFI_SPAR_INDICATION)) < 0)
+ printk
+ ("Installation BootToTool Write Failed - BootToTool = %d\n",
+ (int) efiSparIndication.BootToTool);
+
+ /* So this function isn't called multiple times, must return
+ * size of buffer
+ */
+ return count;
+}
+
+static const struct file_operations chipset_proc_fops = {
+ .owner = THIS_MODULE,
+ .read = visorchipset_proc_read_writeonly,
+ .write = chipset_proc_write,
+};
+
+static int __init
+visorchipset_init(void)
+{
+ int rc = 0, x = 0;
+ struct proc_dir_entry *installer_file;
+ struct proc_dir_entry *toolaction_file;
+ struct proc_dir_entry *bootToTool_file;
+
+ LOGINF("chipset driver version %s loaded", VERSION);
+ /* process module options */
+ POSTCODE_LINUX_2(DRIVER_ENTRY_PC, POSTCODE_SEVERITY_INFO);
+
+ LOGINF("option - testvnic=%d", visorchipset_testvnic);
+ LOGINF("option - testvnicclient=%d", visorchipset_testvnicclient);
+ LOGINF("option - testmsg=%d", visorchipset_testmsg);
+ LOGINF("option - testteardown=%d", visorchipset_testteardown);
+ LOGINF("option - major=%d", visorchipset_major);
+ LOGINF("option - serverregwait=%d", visorchipset_serverregwait);
+ LOGINF("option - clientregwait=%d", visorchipset_clientregwait);
+ LOGINF("option - holdchipsetready=%d", visorchipset_holdchipsetready);
+
+ memset(&BusDev_Server_Notifiers, 0, sizeof(BusDev_Server_Notifiers));
+ memset(&BusDev_Client_Notifiers, 0, sizeof(BusDev_Client_Notifiers));
+ memset(&ControlVm_payload_info, 0, sizeof(ControlVm_payload_info));
+ memset(&LiveDump_info, 0, sizeof(LiveDump_info));
+ atomic_set(&LiveDump_info.buffers_in_use, 0);
+
+ if (visorchipset_testvnic)
+ FAIL_WPOSTCODE_2("testvnic option no longer supported", x,
+ CHIPSET_INIT_FAILURE_PC, x);
+
+ controlvm_init();
+ MajorDev = MKDEV(visorchipset_major, 0);
+ TRY_WPOSTCODE_1(visorchipset_file_init(MajorDev, &ControlVm_channel),
+ CHIPSET_INIT_FAILURE_PC);
+ proc_Init();
+ memset(PartitionPropertyNames, 0, sizeof(PartitionPropertyNames));
+ memset(ControlVmPropertyNames, 0, sizeof(ControlVmPropertyNames));
+ InitPartitionProperties();
+ InitControlVmProperties();
+
+ PartitionType = proc_CreateType(ProcDir, PartitionTypeNames,
+ (const char **) PartitionPropertyNames,
+ &show_partition_property);
+ ControlVmType =
+ proc_CreateType(ProcDir, ControlVmTypeNames,
+ (const char **) ControlVmPropertyNames,
+ &show_controlvm_property);
+
+ ControlVmObject = proc_CreateObject(ControlVmType, NULL, NULL);
+
+ /* Setup Installation fields */
+ installer_file = proc_create("installer", 0644, ProcDir,
+ &proc_installer_fops);
+ /* Setup the ToolAction field */
+ toolaction_file = proc_create("toolaction", 0644, ProcDir,
+ &proc_toolaction_fops);
+ /* Setup the BootToTool field */
+ bootToTool_file = proc_create("boottotool", 0644, ProcDir,
+ &proc_bootToTool_fops);
+
+ memset(&g_DiagMsgHdr, 0, sizeof(CONTROLVM_MESSAGE_HEADER));
+
+ chipset_proc_dir = proc_create(VISORCHIPSET_CHIPSET_PROC_ENTRY_FN,
+ 0644, ProcDir, &chipset_proc_fops);
+ memset(&g_ChipSetMsgHdr, 0, sizeof(CONTROLVM_MESSAGE_HEADER));
+
+ parahotplug_proc_dir =
+ proc_create(VISORCHIPSET_PARAHOTPLUG_PROC_ENTRY_FN, 0200,
+ ProcDir, ¶hotplug_proc_fops);
+ memset(&g_DelDumpMsgHdr, 0, sizeof(CONTROLVM_MESSAGE_HEADER));
+
+ if (filexfer_constructor(sizeof(struct putfile_request)) < 0) {
+ FAIL_WPOSTCODE_1("filexfer_constructor failed", -1,
+ CHIPSET_INIT_FAILURE_PC);
+ }
+ Putfile_buffer_list_pool =
+ kmem_cache_create(Putfile_buffer_list_pool_name,
+ sizeof(struct putfile_buffer_entry),
+ 0, SLAB_HWCACHE_ALIGN, NULL);
+ if (!Putfile_buffer_list_pool) {
+ FAIL_WPOSTCODE_1("failed to alloc Putfile_buffer_list_pool", -1,
+ CHIPSET_INIT_FAILURE_PC);
+ }
+ if (visorchipset_disable_controlvm) {
+ LOGINF("visorchipset_init:controlvm disabled");
+ } else {
+ /* if booting in a crash kernel */
+ if (visorchipset_crash_kernel)
+ INIT_DELAYED_WORK(&Periodic_controlvm_work,
+ setup_crash_devices_work_queue);
+ else
+ INIT_DELAYED_WORK(&Periodic_controlvm_work,
+ controlvm_periodic_work);
+ Periodic_controlvm_workqueue =
+ create_singlethread_workqueue("visorchipset_controlvm");
+
+ if (Periodic_controlvm_workqueue == NULL)
+ FAIL_WPOSTCODE_1("cannot create controlvm workqueue",
+ -ENOMEM, CREATE_WORKQUEUE_FAILED_PC);
+ Most_recent_message_jiffies = jiffies;
+ Poll_jiffies = POLLJIFFIES_CONTROLVMCHANNEL_FAST;
+ TRY_WPOSTCODE_1(queue_delayed_work
+ (Periodic_controlvm_workqueue,
+ &Periodic_controlvm_work, Poll_jiffies),
+ QUEUE_DELAYED_WORK_PC);
+ }
+
+ Visorchipset_platform_device.dev.devt = MajorDev;
+ if (platform_device_register(&Visorchipset_platform_device) < 0)
+ FAIL_WPOSTCODE_1
+ ("platform_device_register(visorchipset) failed", -1,
+ DEVICE_REGISTER_FAILURE_PC);
+ LOGINF("visorchipset device created");
+ POSTCODE_LINUX_2(CHIPSET_INIT_SUCCESS_PC, POSTCODE_SEVERITY_INFO);
+ RETINT(0);
+
+Away:
+
+ if (rc) {
+ LOGERR("visorchipset_init failed");
+ POSTCODE_LINUX_3(CHIPSET_INIT_FAILURE_PC, rc,
+ POSTCODE_SEVERITY_ERR);
+ }
+ return rc;
+}
+
+static void
+visorchipset_exit(void)
+{
+ char s[99];
+ POSTCODE_LINUX_2(DRIVER_EXIT_PC, POSTCODE_SEVERITY_INFO);
+
+ if (visorchipset_disable_controlvm) {
+ ;
+ } else {
+ cancel_delayed_work(&Periodic_controlvm_work);
+ flush_workqueue(Periodic_controlvm_workqueue);
+ destroy_workqueue(Periodic_controlvm_workqueue);
+ Periodic_controlvm_workqueue = NULL;
+ destroy_controlvm_payload_info(&ControlVm_payload_info);
+ }
+ Test_Vnic_channel = NULL;
+ if (Putfile_buffer_list_pool) {
+ kmem_cache_destroy(Putfile_buffer_list_pool);
+ Putfile_buffer_list_pool = NULL;
+ }
+ filexfer_destructor();
+ if (ControlVmObject) {
+ proc_DestroyObject(ControlVmObject);
+ ControlVmObject = NULL;
+ }
+ cleanup_controlvm_structures();
+
+ if (ControlVmType) {
+ proc_DestroyType(ControlVmType);
+ ControlVmType = NULL;
+ }
+ if (PartitionType) {
+ proc_DestroyType(PartitionType);
+ PartitionType = NULL;
+ }
+ if (diag_proc_dir) {
+ remove_proc_entry(VISORCHIPSET_DIAG_PROC_ENTRY_FN, ProcDir);
+ diag_proc_dir = NULL;
+ }
+ memset(&g_DiagMsgHdr, 0, sizeof(CONTROLVM_MESSAGE_HEADER));
+
+ if (chipset_proc_dir) {
+ remove_proc_entry(VISORCHIPSET_CHIPSET_PROC_ENTRY_FN, ProcDir);
+ chipset_proc_dir = NULL;
+ }
+ memset(&g_ChipSetMsgHdr, 0, sizeof(CONTROLVM_MESSAGE_HEADER));
+
+ if (parahotplug_proc_dir) {
+ remove_proc_entry(VISORCHIPSET_PARAHOTPLUG_PROC_ENTRY_FN,
+ ProcDir);
+ parahotplug_proc_dir = NULL;
+ }
+
+ memset(&g_DelDumpMsgHdr, 0, sizeof(CONTROLVM_MESSAGE_HEADER));
+
+ proc_DeInit();
+ if (ControlVm_channel != NULL) {
+ LOGINF("Channel %s (ControlVm) disconnected",
+ visorchannel_id(ControlVm_channel, s));
+ visorchannel_destroy(ControlVm_channel);
+ ControlVm_channel = NULL;
+ }
+ controlvm_deinit();
+ visorchipset_file_cleanup();
+ POSTCODE_LINUX_2(DRIVER_EXIT_PC, POSTCODE_SEVERITY_INFO);
+ LOGINF("chipset driver unloaded");
+}
+
+module_param_named(testvnic, visorchipset_testvnic, int, S_IRUGO);
+MODULE_PARM_DESC(visorchipset_testvnic, "1 to test vnic, using dummy VNIC connected via a loopback to a physical ethernet");
+int visorchipset_testvnic = 0;
+
+module_param_named(testvnicclient, visorchipset_testvnicclient, int, S_IRUGO);
+MODULE_PARM_DESC(visorchipset_testvnicclient, "1 to test vnic, using real VNIC channel attached to a separate IOVM guest");
+int visorchipset_testvnicclient = 0;
+
+module_param_named(testmsg, visorchipset_testmsg, int, S_IRUGO);
+MODULE_PARM_DESC(visorchipset_testmsg,
+ "1 to manufacture the chipset, bus, and switch messages");
+int visorchipset_testmsg = 0;
+
+module_param_named(major, visorchipset_major, int, S_IRUGO);
+MODULE_PARM_DESC(visorchipset_major, "major device number to use for the device node");
+int visorchipset_major = 0;
+
+module_param_named(serverregwait, visorchipset_serverregwait, int, S_IRUGO);
+MODULE_PARM_DESC(visorchipset_serverreqwait,
+ "1 to have the module wait for the visor bus to register");
+int visorchipset_serverregwait = 0; /* default is off */
+module_param_named(clientregwait, visorchipset_clientregwait, int, S_IRUGO);
+MODULE_PARM_DESC(visorchipset_clientregwait, "1 to have the module wait for the visorclientbus to register");
+int visorchipset_clientregwait = 1; /* default is on */
+module_param_named(testteardown, visorchipset_testteardown, int, S_IRUGO);
+MODULE_PARM_DESC(visorchipset_testteardown,
+ "1 to test teardown of the chipset, bus, and switch");
+int visorchipset_testteardown = 0; /* default is off */
+module_param_named(disable_controlvm, visorchipset_disable_controlvm, int,
+ S_IRUGO);
+MODULE_PARM_DESC(visorchipset_disable_controlvm,
+ "1 to disable polling of controlVm channel");
+int visorchipset_disable_controlvm = 0; /* default is off */
+module_param_named(crash_kernel, visorchipset_crash_kernel, int, S_IRUGO);
+MODULE_PARM_DESC(visorchipset_crash_kernel,
+ "1 means we are running in crash kernel");
+int visorchipset_crash_kernel = 0; /* default is running in non-crash kernel */
+module_param_named(holdchipsetready, visorchipset_holdchipsetready,
+ int, S_IRUGO);
+MODULE_PARM_DESC(visorchipset_holdchipsetready,
+ "1 to hold response to CHIPSET_READY");
+int visorchipset_holdchipsetready = 0; /* default is to send CHIPSET_READY
+ * response immediately */
+module_init(visorchipset_init);
+module_exit(visorchipset_exit);
+
+MODULE_AUTHOR("Unisys");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Supervisor chipset driver for service partition: ver "
+ VERSION);
+MODULE_VERSION(VERSION);
--- /dev/null
+/* visorchipset_umode.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.
+ */
+
+/** @file *********************************************************************
+ *
+ * This describes structures needed for the interface between the
+ * visorchipset driver and a user-mode component that opens the device.
+ *
+ ******************************************************************************
+ */
+
+#ifndef __VISORCHIPSET_UMODE_H
+#define __VISORCHIPSET_UMODE_H
+
+
+
+/** The user-mode program can access the control channel buffer directly
+ * via this memory map.
+ */
+#define VISORCHIPSET_MMAP_CONTROLCHANOFFSET (0x00000000)
+#define VISORCHIPSET_MMAP_CONTROLCHANSIZE (0x00400000) /* 4MB */
+
+#endif /* __VISORCHIPSET_UMODE_H */