staging: visorchannel module
authorKen Cox <jkc@redhat.com>
Tue, 4 Mar 2014 13:58:06 +0000 (07:58 -0600)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 5 Mar 2014 00:57:45 +0000 (16:57 -0800)
The visorchannel module is a support library that abstracts reading
and writing a channel in memory.

Signed-off-by: Ken Cox <jkc@redhat.com>
Cc: Ben Romer <sparmaintainer@unisys.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
12 files changed:
drivers/staging/unisys/Kconfig
drivers/staging/unisys/Makefile
drivers/staging/unisys/common-spar/include/channels/channel.h [new file with mode: 0644]
drivers/staging/unisys/common-spar/include/version.h [new file with mode: 0644]
drivers/staging/unisys/include/commontypes.h [new file with mode: 0644]
drivers/staging/unisys/include/guidutils.h [new file with mode: 0644]
drivers/staging/unisys/visorchannel/Kconfig [new file with mode: 0644]
drivers/staging/unisys/visorchannel/Makefile [new file with mode: 0644]
drivers/staging/unisys/visorchannel/globals.h [new file with mode: 0644]
drivers/staging/unisys/visorchannel/visorchannel.h [new file with mode: 0644]
drivers/staging/unisys/visorchannel/visorchannel_funcs.c [new file with mode: 0644]
drivers/staging/unisys/visorchannel/visorchannel_main.c [new file with mode: 0644]

index 60bbca0bde7148252028c27fbf801a082cecc912..15f16d6b73e37138e5375ba3ea825c4ca632e7a5 100644 (file)
@@ -10,5 +10,6 @@ menuconfig UNISYSSPAR
 if UNISYSSPAR
 
 source "drivers/staging/unisys/visorutil/Kconfig"
+source "drivers/staging/unisys/visorchannel/Kconfig"
 
 endif # UNISYSSPAR
index 129c28fb50f00b41308b6b583cc74886c9203690..a457d8b49b36cce18857860669b38be76fa4c250 100644 (file)
@@ -2,4 +2,5 @@
 # Makefile for Unisys SPAR drivers
 #
 obj-$(CONFIG_UNISYS_VISORUTIL)         += visorutil/
+obj-$(CONFIG_UNISYS_VISORCHANNEL)      += visorchannel/
 
diff --git a/drivers/staging/unisys/common-spar/include/channels/channel.h b/drivers/staging/unisys/common-spar/include/channels/channel.h
new file mode 100644 (file)
index 0000000..83906b4
--- /dev/null
@@ -0,0 +1,645 @@
+/* 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 __CHANNEL_H__
+#define __CHANNEL_H__
+
+/*
+* Whenever this file is changed a corresponding change must be made in
+* the Console/ServicePart/visordiag_early/supervisor_channel.h file
+* which is needed for Linux kernel compiles. These two files must be
+* in sync.
+*/
+
+/* define the following to prevent include nesting in kernel header
+ * files of similar abreviated content
+ */
+#define __SUPERVISOR_CHANNEL_H__
+
+#include "commontypes.h"
+
+#define SIGNATURE_16(A, B) ((A) | (B<<8))
+#define SIGNATURE_32(A, B, C, D) \
+       (SIGNATURE_16(A, B) | (SIGNATURE_16(C, D) << 16))
+#define SIGNATURE_64(A, B, C, D, E, F, G, H) \
+       (SIGNATURE_32(A, B, C, D) | ((U64)(SIGNATURE_32(E, F, G, H)) << 32))
+
+#ifndef lengthof
+#define lengthof(TYPE, MEMBER) (sizeof(((TYPE *)0)->MEMBER))
+#endif
+#ifndef COVERQ
+#define COVERQ(v, d)  (((v)+(d)-1) / (d))
+#endif
+#ifndef COVER
+#define COVER(v, d)   ((d)*COVERQ(v, d))
+#endif
+
+#ifndef GUID0
+#define GUID0 {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0} }
+#endif
+
+/*  The C language is inconsistent with respect to where it allows literal
+ *  constants, especially literal constant structs.  Literal constant structs
+ *  are allowed for initialization only, whereas other types of literal
+ *  constants are allowed anywhere.  We get around this inconsistency by
+ *  declaring a "static const" variable for each GUID.  This variable can be
+ *  used in expressions where the literal constant would not be allowed.
+ */
+static const GUID Guid0 = GUID0;
+
+#define ULTRA_CHANNEL_PROTOCOL_SIGNATURE  SIGNATURE_32('E', 'C', 'N', 'L')
+
+typedef enum {
+       CHANNELSRV_UNINITIALIZED = 0,   /* channel is in an undefined state */
+       CHANNELSRV_READY = 1    /* channel has been initialized by server */
+} CHANNEL_SERVERSTATE;
+
+typedef enum {
+       CHANNELCLI_DETACHED = 0,
+       CHANNELCLI_DISABLED = 1,        /* client can see channel but is NOT
+                                        * allowed to use it unless given TBD
+                                        * explicit request (should actually be
+                                        * < DETACHED) */
+       CHANNELCLI_ATTACHING = 2,       /* legacy EFI client request
+                                        * for EFI server to attach */
+       CHANNELCLI_ATTACHED = 3,        /* idle, but client may want
+                                        * to use channel any time */
+       CHANNELCLI_BUSY = 4,    /* client either wants to use or is
+                                * using channel */
+       CHANNELCLI_OWNED = 5    /* "no worries" state - client can
+                                * access channel anytime */
+} CHANNEL_CLIENTSTATE;
+static inline const U8 *
+ULTRA_CHANNELCLI_STRING(U32 v)
+{
+       switch (v) {
+       case CHANNELCLI_DETACHED:
+               return (const U8 *) ("DETACHED");
+       case CHANNELCLI_DISABLED:
+               return (const U8 *) ("DISABLED");
+       case CHANNELCLI_ATTACHING:
+               return (const U8 *) ("ATTACHING");
+       case CHANNELCLI_ATTACHED:
+               return (const U8 *) ("ATTACHED");
+       case CHANNELCLI_BUSY:
+               return (const U8 *) ("BUSY");
+       case CHANNELCLI_OWNED:
+               return (const U8 *) ("OWNED");
+       default:
+               break;
+       }
+       return (const U8 *) ("?");
+}
+
+#define ULTRA_CHANNELSRV_IS_READY(x)     ((x) == CHANNELSRV_READY)
+#define ULTRA_CHANNEL_SERVER_READY(pChannel) \
+       (ULTRA_CHANNELSRV_IS_READY((pChannel)->SrvState))
+
+#define ULTRA_VALID_CHANNELCLI_TRANSITION(o, n)                                \
+       (((((o) == CHANNELCLI_DETACHED) && ((n) == CHANNELCLI_DISABLED)) || \
+         (((o) == CHANNELCLI_ATTACHING) && ((n) == CHANNELCLI_DISABLED)) || \
+         (((o) == CHANNELCLI_ATTACHED) && ((n) == CHANNELCLI_DISABLED)) || \
+         (((o) == CHANNELCLI_ATTACHING) && ((n) == CHANNELCLI_DETACHED)) || \
+         (((o) == CHANNELCLI_ATTACHED) && ((n) == CHANNELCLI_DETACHED)) || \
+         (((o) == CHANNELCLI_DETACHED) && ((n) == CHANNELCLI_ATTACHING)) || \
+         (((o) == CHANNELCLI_ATTACHING) && ((n) == CHANNELCLI_ATTACHED)) || \
+         (((o) == CHANNELCLI_DETACHED) && ((n) == CHANNELCLI_ATTACHED)) || \
+         (((o) == CHANNELCLI_BUSY) && ((n) == CHANNELCLI_ATTACHED)) || \
+         (((o) == CHANNELCLI_ATTACHED) && ((n) == CHANNELCLI_BUSY)) || \
+         (((o) == CHANNELCLI_DETACHED) && ((n) == CHANNELCLI_OWNED)) || \
+         (((o) == CHANNELCLI_DISABLED) && ((n) == CHANNELCLI_OWNED)) || \
+         (((o) == CHANNELCLI_ATTACHING) && ((n) == CHANNELCLI_OWNED)) || \
+         (((o) == CHANNELCLI_ATTACHED) && ((n) == CHANNELCLI_OWNED)) || \
+         (((o) == CHANNELCLI_BUSY) && ((n) == CHANNELCLI_OWNED)) || (0)) \
+        ? (1) : (0))
+
+#define ULTRA_CHANNEL_CLIENT_CHK_TRANSITION(old, new, chanId, logCtx,  \
+                                           file, line)                 \
+       do {                                                            \
+               if (!ULTRA_VALID_CHANNELCLI_TRANSITION(old, new))       \
+                       UltraLogEvent(logCtx,                           \
+                                     CHANNELSTATE_DIAG_EVENTID_TRANSITERR, \
+                                     CHANNELSTATE_DIAG_SEVERITY, \
+                                     CHANNELSTATE_DIAG_SUBSYS,         \
+                                     __func__, __LINE__,               \
+                                     "%s Channel StateTransition INVALID! (%s) %s(%d)-->%s(%d) @%s:%d\n", \
+                                     chanId, "CliState<x>",            \
+                                     ULTRA_CHANNELCLI_STRING(old),     \
+                                     old,                              \
+                                     ULTRA_CHANNELCLI_STRING(new),     \
+                                     new,                              \
+                                     PathName_Last_N_Nodes((U8 *)file, 4), \
+                                     line);                            \
+       } while (0)
+
+#define ULTRA_CHANNEL_CLIENT_TRANSITION(pChan, chanId, field, \
+                                       newstate, logCtx)               \
+       do {                                                            \
+               ULTRA_CHANNEL_CLIENT_CHK_TRANSITION(                    \
+                       (((CHANNEL_HEADER *)(pChan))->field), newstate, \
+                       chanId, logCtx, __FILE__, __LINE__);            \
+               UltraLogEvent(logCtx, CHANNELSTATE_DIAG_EVENTID_TRANSITOK, \
+                       CHANNELSTATE_DIAG_SEVERITY, \
+                             CHANNELSTATE_DIAG_SUBSYS,                 \
+                             __func__, __LINE__,                       \
+                             "%s Channel StateTransition (%s) %s(%d)-->%s(%d) @%s:%d\n", \
+                             chanId, #field,                           \
+                             ULTRA_CHANNELCLI_STRING(((CHANNEL_HEADER *) \
+                                                      (pChan))->field), \
+                             ((CHANNEL_HEADER *)(pChan))->field,       \
+                             ULTRA_CHANNELCLI_STRING(newstate),        \
+                             newstate,                                 \
+                             PathName_Last_N_Nodes(__FILE__, 4), __LINE__); \
+               ((CHANNEL_HEADER *)(pChan))->field = newstate;          \
+               MEMORYBARRIER;                                          \
+       } while (0)
+
+#define ULTRA_CHANNEL_CLIENT_ACQUIRE_OS(pChan, chanId, logCtx) \
+       ULTRA_channel_client_acquire_os(pChan, chanId, logCtx,          \
+                                       (char *)__FILE__, __LINE__,     \
+                                       (char *)__func__)
+#define ULTRA_CHANNEL_CLIENT_RELEASE_OS(pChan, chanId, logCtx) \
+       ULTRA_channel_client_release_os(pChan, chanId, logCtx,  \
+               (char *)__FILE__, __LINE__, (char *)__func__)
+
+/* Values for ULTRA_CHANNEL_PROTOCOL.CliErrorBoot: */
+/* throttling invalid boot channel statetransition error due to client
+ * disabled */
+#define ULTRA_CLIERRORBOOT_THROTTLEMSG_DISABLED    0x01
+
+/* throttling invalid boot channel statetransition error due to client
+ * not attached */
+#define ULTRA_CLIERRORBOOT_THROTTLEMSG_NOTATTACHED 0x02
+
+/* throttling invalid boot channel statetransition error due to busy channel */
+#define ULTRA_CLIERRORBOOT_THROTTLEMSG_BUSY        0x04
+
+/* Values for ULTRA_CHANNEL_PROTOCOL.CliErrorOS: */
+/* throttling invalid guest OS channel statetransition error due to
+ * client disabled */
+#define ULTRA_CLIERROROS_THROTTLEMSG_DISABLED      0x01
+
+/* throttling invalid guest OS channel statetransition error due to
+ * client not attached */
+#define ULTRA_CLIERROROS_THROTTLEMSG_NOTATTACHED   0x02
+
+/* throttling invalid guest OS channel statetransition error due to
+ * busy channel */
+#define ULTRA_CLIERROROS_THROTTLEMSG_BUSY          0x04
+
+/* Values for ULTRA_CHANNEL_PROTOCOL.Features: This define exists so
+* that windows guest can look at the FeatureFlags in the io channel,
+* and configure the windows driver to use interrupts or not based on
+* this setting.  This flag is set in uislib after the
+* ULTRA_VHBA_init_channel is called.  All feature bits for all
+* channels should be defined here.  The io channel feature bits are
+* defined right here */
+#define ULTRA_IO_DRIVER_ENABLES_INTS (0x1ULL << 1)
+#define ULTRA_IO_CHANNEL_IS_POLLING (0x1ULL << 3)
+#define ULTRA_IO_IOVM_IS_OK_WITH_DRIVER_DISABLING_INTS (0x1ULL << 4)
+#define ULTRA_IO_DRIVER_DISABLES_INTS (0x1ULL << 5)
+#define ULTRA_IO_DRIVER_SUPPORTS_ENHANCED_RCVBUF_CHECKING (0x1ULL << 6)
+
+#pragma pack(push, 1)          /* both GCC and VC now allow this pragma */
+/* Common Channel Header */
+typedef struct _CHANNEL_HEADER {
+       U64 Signature;          /* Signature */
+       U32 LegacyState;        /* DEPRECATED - being replaced by */
+       /* /              SrvState, CliStateBoot, and CliStateOS below */
+       U32 HeaderSize;         /* sizeof(CHANNEL_HEADER) */
+       U64 Size;               /* Total size of this channel in bytes */
+       U64 Features;           /* Flags to modify behavior */
+       GUID Type;              /* Channel type: data, bus, control, etc. */
+       U64 PartitionHandle;    /* ID of guest partition */
+       U64 Handle;             /* Device number of this channel in client */
+       U64 oChannelSpace;      /* Offset in bytes to channel specific area */
+       U32 VersionId;          /* CHANNEL_HEADER Version ID */
+       U32 PartitionIndex;     /* Index of guest partition */
+       GUID ZoneGuid;          /* Guid of Channel's zone */
+       U32 oClientString;      /* offset from channel header to
+                                * nul-terminated ClientString (0 if
+                                * ClientString not present) */
+       U32 CliStateBoot;       /* CHANNEL_CLIENTSTATE of pre-boot
+                                * EFI client of this channel */
+       U32 CmdStateCli;        /* CHANNEL_COMMANDSTATE (overloaded in
+                                * Windows drivers, see ServerStateUp,
+                                * ServerStateDown, etc) */
+       U32 CliStateOS;         /* CHANNEL_CLIENTSTATE of Guest OS
+                                * client of this channel */
+       U32 ChannelCharacteristics;     /* CHANNEL_CHARACTERISTIC_<xxx> */
+       U32 CmdStateSrv;        /* CHANNEL_COMMANDSTATE (overloaded in
+                                * Windows drivers, see ServerStateUp,
+                                * ServerStateDown, etc) */
+       U32 SrvState;           /* CHANNEL_SERVERSTATE */
+       U8 CliErrorBoot;        /* bits to indicate err states for
+                                * boot clients, so err messages can
+                                * be throttled */
+       U8 CliErrorOS;          /* bits to indicate err states for OS
+                                * clients, so err messages can be
+                                * throttled */
+       U8 Filler[1];           /* Pad out to 128 byte cacheline */
+       /* Please add all new single-byte values below here */
+       U8 RecoverChannel;
+} CHANNEL_HEADER, *pCHANNEL_HEADER, ULTRA_CHANNEL_PROTOCOL;
+
+#define ULTRA_CHANNEL_ENABLE_INTS (0x1ULL << 0)
+
+/* Subheader for the Signal Type variation of the Common Channel */
+typedef struct _SIGNAL_QUEUE_HEADER {
+       /* 1st cache line */
+       U32 VersionId;          /* SIGNAL_QUEUE_HEADER Version ID */
+       U32 Type;               /* Queue type: storage, network */
+       U64 Size;               /* Total size of this queue in bytes */
+       U64 oSignalBase;        /* Offset to signal queue area */
+       U64 FeatureFlags;       /* Flags to modify behavior */
+       U64 NumSignalsSent;     /* Total # of signals placed in this queue */
+       U64 NumOverflows;       /* Total # of inserts failed due to
+                                * full queue */
+       U32 SignalSize;         /* Total size of a signal for this queue */
+       U32 MaxSignalSlots;     /* Max # of slots in queue, 1 slot is
+                                * always empty */
+       U32 MaxSignals;         /* Max # of signals in queue
+                                * (MaxSignalSlots-1) */
+       U32 Head;               /* Queue head signal # */
+       /* 2nd cache line */
+       U64 NumSignalsReceived; /* Total # of signals removed from this queue */
+       U32 Tail;               /* Queue tail signal # (on separate
+                                * cache line) */
+       U32 Reserved1;          /* Reserved field */
+       U64 Reserved2;          /* Resrved field */
+       U64 ClientQueue;
+       U64 NumInterruptsReceived;      /* Total # of Interrupts received.  This
+                                        * is incremented by the ISR in the
+                                        * guest windows driver */
+       U64 NumEmptyCnt;        /* Number of times that SignalRemove
+                                * is called and returned Empty
+                                * Status. */
+       U32 ErrorFlags;         /* Error bits set during SignalReinit
+                                * to denote trouble with client's
+                                * fields */
+       U8 Filler[12];          /* Pad out to 64 byte cacheline */
+} SIGNAL_QUEUE_HEADER, *pSIGNAL_QUEUE_HEADER;
+
+#pragma pack(pop)
+
+#define SignalInit(chan, QHDRFLD, QDATAFLD, QDATATYPE, ver, typ)       \
+       do {                                                            \
+               MEMSET(&chan->QHDRFLD, 0, sizeof(chan->QHDRFLD));       \
+               chan->QHDRFLD.VersionId = ver;                          \
+               chan->QHDRFLD.Type = typ;                               \
+               chan->QHDRFLD.Size = sizeof(chan->QDATAFLD);            \
+               chan->QHDRFLD.SignalSize = sizeof(QDATATYPE);           \
+               chan->QHDRFLD.oSignalBase = (UINTN)(chan->QDATAFLD)-    \
+                       (UINTN)(&chan->QHDRFLD);                        \
+               chan->QHDRFLD.MaxSignalSlots =                          \
+                       sizeof(chan->QDATAFLD)/sizeof(QDATATYPE);       \
+               chan->QHDRFLD.MaxSignals = chan->QHDRFLD.MaxSignalSlots-1; \
+       } while (0)
+
+/* Generic function useful for validating any type of channel when it is
+ * received by the client that will be accessing the channel.
+ * Note that <logCtx> is only needed for callers in the EFI environment, and
+ * is used to pass the EFI_DIAG_CAPTURE_PROTOCOL needed to log messages.
+ */
+static inline int
+ULTRA_check_channel_client(void *pChannel,
+                          GUID expectedTypeGuid,
+                          char *channelName,
+                          U64 expectedMinBytes,
+                          U32 expectedVersionId,
+                          U64 expectedSignature,
+                          char *fileName, int lineNumber, void *logCtx)
+{
+       if (MEMCMP(&expectedTypeGuid, &Guid0, sizeof(GUID)) != 0)
+               /* caller wants us to verify type GUID */
+               if (MEMCMP(&(((CHANNEL_HEADER *) (pChannel))->Type),
+                          &expectedTypeGuid, sizeof(GUID)) != 0) {
+                       CHANNEL_GUID_MISMATCH(expectedTypeGuid, channelName,
+                                             "type", expectedTypeGuid,
+                                             ((CHANNEL_HEADER *)
+                                              (pChannel))->Type, fileName,
+                                             lineNumber, logCtx);
+                       return 0;
+               }
+       if (expectedMinBytes > 0)       /* caller wants us to verify
+                                        * channel size */
+               if (((CHANNEL_HEADER *) (pChannel))->Size < expectedMinBytes) {
+                       CHANNEL_U64_MISMATCH(expectedTypeGuid, channelName,
+                                            "size", expectedMinBytes,
+                                            ((CHANNEL_HEADER *)
+                                             (pChannel))->Size, fileName,
+                                            lineNumber, logCtx);
+                       return 0;
+               }
+       if (expectedVersionId > 0)      /* caller wants us to verify
+                                        * channel version */
+               if (((CHANNEL_HEADER *) (pChannel))->VersionId !=
+                   expectedVersionId) {
+                       CHANNEL_U32_MISMATCH(expectedTypeGuid, channelName,
+                                            "version", expectedVersionId,
+                                            ((CHANNEL_HEADER *)
+                                             (pChannel))->VersionId, fileName,
+                                            lineNumber, logCtx);
+                       return 0;
+               }
+       if (expectedSignature > 0)      /* caller wants us to verify
+                                        * channel signature */
+               if (((CHANNEL_HEADER *) (pChannel))->Signature !=
+                   expectedSignature) {
+                       CHANNEL_U64_MISMATCH(expectedTypeGuid, channelName,
+                                            "signature", expectedSignature,
+                                            ((CHANNEL_HEADER *)
+                                             (pChannel))->Signature, fileName,
+                                            lineNumber, logCtx);
+                       return 0;
+               }
+       return 1;
+}
+
+/* Generic function useful for validating any type of channel when it is about
+ * to be initialized by the server of the channel.
+ * Note that <logCtx> is only needed for callers in the EFI environment, and
+ * is used to pass the EFI_DIAG_CAPTURE_PROTOCOL needed to log messages.
+ */
+static inline int
+ULTRA_check_channel_server(GUID typeGuid,
+                          char *channelName,
+                          U64 expectedMinBytes,
+                          U64 actualBytes,
+                          char *fileName, int lineNumber, void *logCtx)
+{
+       if (expectedMinBytes > 0)       /* caller wants us to verify
+                                        * channel size */
+               if (actualBytes < expectedMinBytes) {
+                       CHANNEL_U64_MISMATCH(typeGuid, channelName, "size",
+                                            expectedMinBytes, actualBytes,
+                                            fileName, lineNumber, logCtx);
+                       return 0;
+               }
+       return 1;
+}
+
+/* Given a file pathname <s> (with '/' or '\' separating directory nodes),
+ * returns a pointer to the beginning of a node within that pathname such
+ * that the number of nodes from that pointer to the end of the string is
+ * NOT more than <n>.  Note that if the pathname has less than <n> nodes
+ * in it, the return pointer will be to the beginning of the string.
+ */
+static inline U8 *
+PathName_Last_N_Nodes(U8 *s, unsigned int n)
+{
+       U8 *p = s;
+       unsigned int node_count = 0;
+       while (*p != '\0') {
+               if ((*p == '/') || (*p == '\\'))
+                       node_count++;
+               p++;
+       }
+       if (node_count <= n)
+               return s;
+       while (n > 0) {
+               p--;
+               if (p == s)
+                       break;  /* should never happen, unless someone
+                                * is changing the string while we are
+                                * looking at it!! */
+               if ((*p == '/') || (*p == '\\'))
+                       n--;
+       }
+       return p + 1;
+}
+
+static inline int
+ULTRA_channel_client_acquire_os(void *pChannel, U8 *chanId, void *logCtx,
+                               char *file, int line, char *func)
+{
+       CHANNEL_HEADER *pChan = (CHANNEL_HEADER *) (pChannel);
+
+       if (pChan->CliStateOS == CHANNELCLI_DISABLED) {
+               if ((pChan->
+                    CliErrorOS & ULTRA_CLIERROROS_THROTTLEMSG_DISABLED) == 0) {
+                       /* we are NOT throttling this message */
+                       pChan->CliErrorOS |=
+                               ULTRA_CLIERROROS_THROTTLEMSG_DISABLED;
+                       /* throttle until acquire successful */
+
+                       UltraLogEvent(logCtx,
+                                     CHANNELSTATE_DIAG_EVENTID_TRANSITERR,
+                                     CHANNELSTATE_DIAG_SEVERITY,
+                                     CHANNELSTATE_DIAG_SUBSYS, func, line,
+                                     "%s Channel StateTransition INVALID! - acquire failed because OS client DISABLED @%s:%d\n",
+                                     chanId, PathName_Last_N_Nodes(
+                                             (U8 *) file, 4), line);
+               }
+               return 0;
+       }
+       if ((pChan->CliStateOS != CHANNELCLI_OWNED)
+           && (pChan->CliStateBoot == CHANNELCLI_DISABLED)) {
+               /* Our competitor is DISABLED, so we can transition to OWNED */
+               UltraLogEvent(logCtx, CHANNELSTATE_DIAG_EVENTID_TRANSITOK,
+                             CHANNELSTATE_DIAG_SEVERITY,
+                             CHANNELSTATE_DIAG_SUBSYS, func, line,
+                             "%s Channel StateTransition (%s) %s(%d)-->%s(%d) @%s:%d\n",
+                             chanId, "CliStateOS",
+                             ULTRA_CHANNELCLI_STRING(pChan->CliStateOS),
+                             pChan->CliStateOS,
+                             ULTRA_CHANNELCLI_STRING(CHANNELCLI_OWNED),
+                             CHANNELCLI_OWNED,
+                             PathName_Last_N_Nodes((U8 *) file, 4), line);
+               pChan->CliStateOS = CHANNELCLI_OWNED;
+               MEMORYBARRIER;
+       }
+       if (pChan->CliStateOS == CHANNELCLI_OWNED) {
+               if (pChan->CliErrorOS != 0) {
+                       /* we are in an error msg throttling state;
+                        * come out of it */
+                       UltraLogEvent(logCtx,
+                                     CHANNELSTATE_DIAG_EVENTID_TRANSITOK,
+                                     CHANNELSTATE_DIAG_SEVERITY,
+                                     CHANNELSTATE_DIAG_SUBSYS, func, line,
+                                     "%s Channel OS client acquire now successful @%s:%d\n",
+                                     chanId, PathName_Last_N_Nodes((U8 *) file,
+                                                                   4), line);
+                       pChan->CliErrorOS = 0;
+               }
+               return 1;
+       }
+
+       /* We have to do it the "hard way".  We transition to BUSY,
+       * and can use the channel iff our competitor has not also
+       * transitioned to BUSY. */
+       if (pChan->CliStateOS != CHANNELCLI_ATTACHED) {
+               if ((pChan->
+                    CliErrorOS & ULTRA_CLIERROROS_THROTTLEMSG_NOTATTACHED) ==
+                   0) {
+                       /* we are NOT throttling this message */
+                       pChan->CliErrorOS |=
+                               ULTRA_CLIERROROS_THROTTLEMSG_NOTATTACHED;
+                       /* throttle until acquire successful */
+                       UltraLogEvent(logCtx,
+                                     CHANNELSTATE_DIAG_EVENTID_TRANSITERR,
+                                     CHANNELSTATE_DIAG_SEVERITY,
+                                     CHANNELSTATE_DIAG_SUBSYS, func, line,
+                                     "%s Channel StateTransition INVALID! - acquire failed because OS client NOT ATTACHED (state=%s(%d)) @%s:%d\n",
+                                     chanId,
+                                     ULTRA_CHANNELCLI_STRING(pChan->CliStateOS),
+                                     pChan->CliStateOS,
+                                     PathName_Last_N_Nodes((U8 *) file, 4),
+                                     line);
+               }
+               return 0;
+       }
+       pChan->CliStateOS = CHANNELCLI_BUSY;
+       MEMORYBARRIER;
+       if (pChan->CliStateBoot == CHANNELCLI_BUSY) {
+               if ((pChan->CliErrorOS & ULTRA_CLIERROROS_THROTTLEMSG_BUSY) ==
+                   0) {
+                       /* we are NOT throttling this message */
+                       pChan->CliErrorOS |= ULTRA_CLIERROROS_THROTTLEMSG_BUSY;
+                       /* throttle until acquire successful */
+                       UltraLogEvent(logCtx,
+                                     CHANNELSTATE_DIAG_EVENTID_TRANSITBUSY,
+                                     CHANNELSTATE_DIAG_SEVERITY,
+                                     CHANNELSTATE_DIAG_SUBSYS, func, line,
+                                     "%s Channel StateTransition failed - host OS acquire failed because boot BUSY @%s:%d\n",
+                                     chanId, PathName_Last_N_Nodes((U8 *) file,
+                                                                   4), line);
+               }
+               pChan->CliStateOS = CHANNELCLI_ATTACHED;        /* reset busy */
+               MEMORYBARRIER;
+               return 0;
+       }
+       if (pChan->CliErrorOS != 0) {
+               /* we are in an error msg throttling state; come out of it */
+               UltraLogEvent(logCtx, CHANNELSTATE_DIAG_EVENTID_TRANSITOK,
+                             CHANNELSTATE_DIAG_SEVERITY,
+                             CHANNELSTATE_DIAG_SUBSYS, func, line,
+                             "%s Channel OS client acquire now successful @%s:%d\n",
+                             chanId, PathName_Last_N_Nodes((U8 *) file, 4),
+                             line);
+               pChan->CliErrorOS = 0;
+       }
+       return 1;
+}
+
+static inline void
+ULTRA_channel_client_release_os(void *pChannel, U8 *chanId, void *logCtx,
+                               char *file, int line, char *func)
+{
+       CHANNEL_HEADER *pChan = (CHANNEL_HEADER *) (pChannel);
+       if (pChan->CliErrorOS != 0) {
+               /* we are in an error msg throttling state; come out of it */
+               UltraLogEvent(logCtx, CHANNELSTATE_DIAG_EVENTID_TRANSITOK,
+                             CHANNELSTATE_DIAG_SEVERITY,
+                             CHANNELSTATE_DIAG_SUBSYS, func, line,
+                             "%s Channel OS client error state cleared @%s:%d\n",
+                             chanId, PathName_Last_N_Nodes((U8 *) file, 4),
+                             line);
+               pChan->CliErrorOS = 0;
+       }
+       if (pChan->CliStateOS == CHANNELCLI_OWNED)
+               return;
+       if (pChan->CliStateOS != CHANNELCLI_BUSY) {
+               UltraLogEvent(logCtx, CHANNELSTATE_DIAG_EVENTID_TRANSITERR,
+                             CHANNELSTATE_DIAG_SEVERITY,
+                             CHANNELSTATE_DIAG_SUBSYS, func, line,
+                             "%s Channel StateTransition INVALID! - release failed because OS client NOT BUSY (state=%s(%d)) @%s:%d\n",
+                             chanId,
+                             ULTRA_CHANNELCLI_STRING(pChan->CliStateOS),
+                             pChan->CliStateOS,
+                             PathName_Last_N_Nodes((U8 *) file, 4), line);
+               /* return; */
+       }
+       pChan->CliStateOS = CHANNELCLI_ATTACHED;        /* release busy */
+}
+
+/*
+* Routine Description:
+* Tries to insert the prebuilt signal pointed to by pSignal into the nth
+* Queue of the Channel pointed to by pChannel
+*
+* Parameters:
+* pChannel: (IN) points to the IO Channel
+* Queue: (IN) nth Queue of the IO Channel
+* pSignal: (IN) pointer to the signal
+*
+* Assumptions:
+* - pChannel, Queue and pSignal are valid.
+* - If insertion fails due to a full queue, the caller will determine the
+* retry policy (e.g. wait & try again, report an error, etc.).
+*
+* Return value: 1 if the insertion succeeds, 0 if the queue was
+* full.
+*/
+
+unsigned char SignalInsert(pCHANNEL_HEADER pChannel, U32 Queue, void *pSignal);
+
+/*
+* Routine Description:
+* Removes one signal from Channel pChannel's nth Queue at the
+* time of the call and copies it into the memory pointed to by
+* pSignal.
+*
+* Parameters:
+* pChannel: (IN) points to the IO Channel
+* Queue: (IN) nth Queue of the IO Channel
+* pSignal: (IN) pointer to where the signals are to be copied
+*
+* Assumptions:
+* - pChannel and Queue are valid.
+* - pSignal points to a memory area large enough to hold queue's SignalSize
+*
+* Return value: 1 if the removal succeeds, 0 if the queue was
+* empty.
+*/
+
+unsigned char SignalRemove(pCHANNEL_HEADER pChannel, U32 Queue, void *pSignal);
+
+/*
+* Routine Description:
+* Removes all signals present in Channel pChannel's nth Queue at the
+* time of the call and copies them into the memory pointed to by
+* pSignal.  Returns the # of signals copied as the value of the routine.
+*
+* Parameters:
+* pChannel: (IN) points to the IO Channel
+* Queue: (IN) nth Queue of the IO Channel
+* pSignal: (IN) pointer to where the signals are to be copied
+*
+* Assumptions:
+* - pChannel and Queue are valid.
+* - pSignal points to a memory area large enough to hold Queue's MaxSignals
+* # of signals, each of which is Queue's SignalSize.
+*
+* Return value:
+* # of signals copied.
+*/
+unsigned int SignalRemoveAll(pCHANNEL_HEADER pChannel, U32 Queue,
+                            void *pSignal);
+
+/*
+* Routine Description:
+* Determine whether a signal queue is empty.
+*
+* Parameters:
+* pChannel: (IN) points to the IO Channel
+* Queue: (IN) nth Queue of the IO Channel
+*
+* Return value:
+* 1 if the signal queue is empty, 0 otherwise.
+*/
+unsigned char SignalQueueIsEmpty(pCHANNEL_HEADER pChannel, U32 Queue);
+
+#endif
diff --git a/drivers/staging/unisys/common-spar/include/version.h b/drivers/staging/unisys/common-spar/include/version.h
new file mode 100644 (file)
index 0000000..00b0ebb
--- /dev/null
@@ -0,0 +1,46 @@
+/* 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.
+ */
+
+/* version.h */
+
+/*  Common version/release info needed by all components goes here.
+ *  (This file must compile cleanly in all environments.)
+ *  Ultimately, this will be combined with defines generated dynamically as
+ *  part of the sysgen, and some of the defines below may in fact end up
+ *  being replaced with dynamically generated ones.
+ */
+#ifndef __VERSION_H__
+#define __VERSION_H__
+
+#define SPARVER1 "1"
+#define SPARVER2 "0"
+#define SPARVER3 "0"
+#define SPARVER4 "0"
+
+#define  VERSION        SPARVER1 "." SPARVER2 "." SPARVER3 "." SPARVER4
+#define  VERSIONDATE    __DATE__
+
+/* Here are various version forms needed in Windows environments.
+ */
+#define VISOR_PRODUCTVERSION      SPARVERCOMMA
+#define VISOR_PRODUCTVERSION_STR  SPARVER1 "." SPARVER2 "." SPARVER3 "." \
+       SPARVER4
+#define VISOR_OBJECTVERSION_STR   SPARVER1 "," SPARVER2 "," SPARVER3 "," \
+       SPARVER4
+
+#define  COPYRIGHT      "Unisys Corporation"
+#define  COPYRIGHTDATE  "2010 - 2013"
+
+#endif
diff --git a/drivers/staging/unisys/include/commontypes.h b/drivers/staging/unisys/include/commontypes.h
new file mode 100644 (file)
index 0000000..ae46bed
--- /dev/null
@@ -0,0 +1,166 @@
+/* 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 _COMMONTYPES_H_
+#define _COMMONTYPES_H_
+
+/* define the following to prevent include nesting in kernel header files of
+ * similar abreviated content */
+#define _SUPERVISOR_COMMONTYPES_H_
+
+#ifdef __KERNEL__
+#include <linux/types.h>
+#include <linux/version.h>
+#else
+#include <stdint.h>
+#include <syslog.h>
+#endif
+
+#define U8  uint8_t
+#define U16 uint16_t
+#define U32 uint32_t
+#define U64 uint64_t
+#define S8  int8_t
+#define S16 int16_t
+#define S32 int32_t
+#define S64 int64_t
+
+#ifdef __KERNEL__
+
+#ifdef CONFIG_X86_32
+#define UINTN U32
+#else
+#define UINTN U64
+#endif
+
+#else
+
+#include <stdint.h>
+#if __WORDSIZE == 32
+#define UINTN U32
+#elif __WORDSIZE == 64
+#define UINTN U64
+#else
+#error Unsupported __WORDSIZE
+#endif
+
+#endif
+
+typedef struct {
+       U32 data1;
+       U16 data2;
+       U16 data3;
+       U8 data4[8];
+} __attribute__ ((__packed__)) GUID;
+
+#ifndef GUID0
+#define GUID0 {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0} }
+#endif
+typedef U64 GUEST_PHYSICAL_ADDRESS;
+
+#define MEMSET(ptr, val, len) memset(ptr, val, len)
+#define MEMCMP(m1, m2, len) memcmp(m1, m2, len)
+#define STRLEN(s) ((UINTN)strlen((const char *)s))
+#define STRCPY(d, s) (strcpy((char *)d, (const char *)s))
+
+#define INLINE inline
+#define OFFSETOF offsetof
+
+#ifdef __KERNEL__
+#define MEMORYBARRIER mb()
+#define MEMCPY(dest, src, len) memcpy(dest, src, len)
+
+#define CHANNEL_GUID_MISMATCH(chType, chName, field, expected, actual, fil, \
+                             lin, logCtx)                              \
+       do {                                                            \
+               char s1[50], s2[50], s3[50];                            \
+               pr_err("Channel mismatch on channel=%s(%s) field=%s expected=%s actual=%s @%s:%d\n", \
+                      chName, GUID_format2(&chType, s1), field,        \
+                      GUID_format2(&expected, s2), GUID_format2(&actual, s3), \
+                      fil, lin);                                       \
+       } while (0)
+#define CHANNEL_U32_MISMATCH(chType, chName, field, expected, actual, fil, \
+                            lin, logCtx)                               \
+       do {                                                            \
+               char s1[50];                                            \
+               pr_err("Channel mismatch on channel=%s(%s) field=%s expected=0x%-8.8lx actual=0x%-8.8lx @%s:%d\n", \
+                      chName, GUID_format2(&chType, s1), field,        \
+                      (unsigned long)expected, (unsigned long)actual,  \
+                      fil, lin);                                       \
+       } while (0)
+
+#define CHANNEL_U64_MISMATCH(chType, chName, field, expected, actual, fil, \
+                            lin, logCtx)                               \
+       do {                                                            \
+               char s1[50];                                            \
+               pr_err("Channel mismatch on channel=%s(%s) field=%s expected=0x%-8.8Lx actual=0x%-8.8Lx @%s:%d\n", \
+                      chName, GUID_format2(&chType, s1), field,        \
+                      (unsigned long long)expected,                    \
+                      (unsigned long long)actual,                      \
+                      fil, lin);                                       \
+       } while (0)
+
+#define UltraLogEvent(logCtx, EventId, Severity, SubsystemMask, pFunctionName, \
+                     LineNumber, Str, args...)                         \
+       pr_info(Str, ## args)
+
+#else
+#define MEMCPY(dest, src, len) memcpy(dest, src, len)
+
+#define MEMORYBARRIER mb()
+
+#define CHANNEL_GUID_MISMATCH(chType, chName, field, expected, actual, fil, \
+                             lin, logCtx)                              \
+       do {                                                            \
+               char s1[50], s2[50], s3[50];                            \
+               syslog(LOG_USER | LOG_ERR,                              \
+                      "Channel mismatch on channel=%s(%s) field=%s expected=%s actual=%s @%s:%d", \
+                      chName, GUID_format2(&chType, s1), field,        \
+                      GUID_format2(&expected, s2), GUID_format2(&actual, s3), \
+                      fil, lin);                                       \
+       } while (0)
+
+#define CHANNEL_U32_MISMATCH(chType, chName, field, expected, actual, fil, \
+                            lin, logCtx)                               \
+       do {                                                            \
+               char s1[50];                                            \
+               syslog(LOG_USER | LOG_ERR,                              \
+                      "Channel mismatch on channel=%s(%s) field=%s expected=0x%-8.8lx actual=0x%-8.8lx @%s:%d", \
+                      chName, GUID_format2(&chType, s1), field,        \
+                      (unsigned long)expected, (unsigned long)actual,  \
+                      fil, lin);                                       \
+       } while (0)
+
+#define CHANNEL_U64_MISMATCH(chType, chName, field, expected, actual, fil, \
+                            lin, logCtx)                               \
+       do {                                                            \
+               char s1[50];                                            \
+               syslog(LOG_USER | LOG_ERR,                              \
+                      "Channel mismatch on channel=%s(%s) field=%s expected=0x%-8.8Lx actual=0x%-8.8Lx @%s:%d", \
+                      chName, GUID_format2(&chType, s1), field,        \
+                      (unsigned long long)expected,                    \
+                      (unsigned long long)actual,                      \
+                      fil, lin);                                       \
+       } while (0)
+
+#define UltraLogEvent(logCtx, EventId, Severity, SubsystemMask, pFunctionName, \
+                     LineNumber, Str, args...)                         \
+       syslog(LOG_USER | LOG_INFO, Str, ## args)
+#endif
+
+#define VolatileBarrier() MEMORYBARRIER
+
+#endif
+#include "guidutils.h"
diff --git a/drivers/staging/unisys/include/guidutils.h b/drivers/staging/unisys/include/guidutils.h
new file mode 100644 (file)
index 0000000..75caf92
--- /dev/null
@@ -0,0 +1,203 @@
+/* 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.
+ */
+
+/* guidutils.h
+ *
+ * These are GUID manipulation inlines that can be used from either
+ * kernel-mode or user-mode.
+ *
+ */
+#ifndef __GUIDUTILS_H__
+#define __GUIDUTILS_H__
+
+#ifdef __KERNEL__
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#define GUID_STRTOUL kstrtoul
+#else
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define GUID_STRTOUL strtoul
+#endif
+
+static inline char *
+GUID_format1(const GUID *guid, char *s)
+{
+       sprintf(s, "{%-8.8lx-%-4.4x-%-4.4x-%-2.2x%-2.2x%-2.2x%-2.2x%-2.2x%-2.2x%-2.2x%-2.2x}",
+               (ulong) guid->data1,
+               guid->data2,
+               guid->data3,
+               guid->data4[0],
+               guid->data4[1],
+               guid->data4[2],
+               guid->data4[3],
+               guid->data4[4], guid->data4[5], guid->data4[6], guid->data4[7]);
+       return s;
+}
+
+/** Format a GUID in Microsoft's 'what in the world were they thinking'
+ *  format.
+ */
+static inline char *
+GUID_format2(const GUID *guid, char *s)
+{
+       sprintf(s, "{%-8.8lx-%-4.4x-%-4.4x-%-2.2x%-2.2x-%-2.2x%-2.2x%-2.2x%-2.2x%-2.2x%-2.2x}",
+               (ulong) guid->data1,
+               guid->data2,
+               guid->data3,
+               guid->data4[0],
+               guid->data4[1],
+               guid->data4[2],
+               guid->data4[3],
+               guid->data4[4], guid->data4[5], guid->data4[6], guid->data4[7]);
+       return s;
+}
+
+/**
+ * Like GUID_format2 but without the curly braces and the
+ * hex digits in upper case
+ */
+static inline char *
+GUID_format3(const GUID *guid, char *s)
+{
+       sprintf(s, "%-8.8lX-%-4.4X-%-4.4X-%-2.2X%-2.2X-%-2.2X%-2.2X%-2.2X%-2.2X%-2.2X%-2.2X",
+               (ulong) guid->data1,
+               guid->data2,
+               guid->data3,
+               guid->data4[0],
+               guid->data4[1],
+               guid->data4[2],
+               guid->data4[3],
+               guid->data4[4], guid->data4[5], guid->data4[6], guid->data4[7]);
+       return s;
+}
+
+/** Parse a guid string in any of these forms:
+ *      {11111111-2222-3333-4455-66778899aabb}
+ *      {11111111-2222-3333-445566778899aabb}
+ *      11111111-2222-3333-4455-66778899aabb
+ *      11111111-2222-3333-445566778899aabb
+ */
+static inline GUID
+GUID_scan(U8 *p)
+{
+       GUID guid = GUID0;
+       U8 x[33];
+       int count = 0;
+       int c, i = 0;
+       U8 cdata1[9];
+       U8 cdata2[5];
+       U8 cdata3[5];
+       U8 cdata4[3];
+       int dashcount = 0;
+       int brace = 0;
+       unsigned long uldata;
+
+       if (!p)
+               return guid;
+       if (*p == '{') {
+               p++;
+               brace = 1;
+       }
+       while (count < 32) {
+               if (*p == '}')
+                       return guid;
+               if (*p == '\0')
+                       return guid;
+               c = toupper(*p);
+               p++;
+               if (c == '-') {
+                       switch (dashcount) {
+                       case 0:
+                               if (i != 8)
+                                       return guid;
+                               break;
+                       case 1:
+                               if (i != 4)
+                                       return guid;
+                               break;
+                       case 2:
+                               if (i != 4)
+                                       return guid;
+                               break;
+                       case 3:
+                               if (i != 4)
+                                       return guid;
+                               break;
+                       default:
+                               return guid;
+                       }
+                       dashcount++;
+                       i = 0;
+                       continue;
+               }
+               if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F'))
+                       i++;
+               else
+                       return guid;
+               x[count++] = c;
+       }
+       x[count] = '\0';
+       if (brace) {
+               if (*p == '}')
+                       p++;
+               else
+                       return guid;
+       }
+       if (dashcount == 3 || dashcount == 4)
+               ;
+       else
+               return guid;
+       memset(cdata1, 0, sizeof(cdata1));
+       memset(cdata2, 0, sizeof(cdata2));
+       memset(cdata3, 0, sizeof(cdata3));
+       memset(cdata4, 0, sizeof(cdata4));
+       memcpy(cdata1, x + 0, 8);
+       memcpy(cdata2, x + 8, 4);
+       memcpy(cdata3, x + 12, 4);
+
+       if (GUID_STRTOUL((char *) cdata1, 16, &uldata) == 0)
+               guid.data1 = (U32)uldata;
+       if (GUID_STRTOUL((char *) cdata2, 16, &uldata) == 0)
+               guid.data2 = (U16)uldata;
+       if (GUID_STRTOUL((char *) cdata3, 16, &uldata) == 0)
+               guid.data3 = (U16)uldata;
+
+       for (i = 0; i < 8; i++) {
+               memcpy(cdata4, x + 16 + (i * 2), 2);
+               if (GUID_STRTOUL((char *) cdata4, 16, &uldata) == 0)
+                       guid.data4[i] = (U8) uldata;
+       }
+
+       return guid;
+}
+
+static inline char *
+GUID_sanitize(char *inputGuidStr, char *outputGuidStr)
+{
+       GUID g;
+       GUID guid0 = GUID0;
+       *outputGuidStr = '\0';
+       g = GUID_scan((U8 *) inputGuidStr);
+       if (memcmp(&g, &guid0, sizeof(GUID)) == 0)
+               return outputGuidStr;   /* bad GUID format */
+       return GUID_format1(&g, outputGuidStr);
+}
+
+#endif
diff --git a/drivers/staging/unisys/visorchannel/Kconfig b/drivers/staging/unisys/visorchannel/Kconfig
new file mode 100644 (file)
index 0000000..41c3b4b
--- /dev/null
@@ -0,0 +1,10 @@
+#
+# Unisys visorchannel configuration
+#
+
+config UNISYS_VISORCHANNEL
+       tristate "Unisys visorchannel driver"
+       depends on UNISYSSPAR && UNISYS_VISORUTIL
+       ---help---
+       If you say Y here, you will enable the Unisys visorchannel driver.
+
diff --git a/drivers/staging/unisys/visorchannel/Makefile b/drivers/staging/unisys/visorchannel/Makefile
new file mode 100644 (file)
index 0000000..f0060be
--- /dev/null
@@ -0,0 +1,14 @@
+#
+# Makefile for Unisys visorchannel
+#
+
+obj-$(CONFIG_UNISYS_VISORCHANNEL)      += visorchannel.o
+
+visorchannel-y := visorchannel_main.o visorchannel_funcs.o
+
+ccflags-y += -Idrivers/staging/unisys/include
+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 += -DCONFIG_SPAR_GUEST -DGUESTDRIVERBUILD -DNOAUTOVERSION
+
diff --git a/drivers/staging/unisys/visorchannel/globals.h b/drivers/staging/unisys/visorchannel/globals.h
new file mode 100644 (file)
index 0000000..668f832
--- /dev/null
@@ -0,0 +1,29 @@
+/* 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 __VISORCHANNEL_GLOBALS_H__
+#define __VISORCHANNEL_GLOBALS_H__
+
+#include "uniklog.h"
+#include "timskmod.h"
+#include "memregion.h"
+#include "version.h"
+
+#define MYDRVNAME "visorchannel"
+
+
+#endif
diff --git a/drivers/staging/unisys/visorchannel/visorchannel.h b/drivers/staging/unisys/visorchannel/visorchannel.h
new file mode 100644 (file)
index 0000000..4546686
--- /dev/null
@@ -0,0 +1,106 @@
+/* visorchannel.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 __VISORCHANNEL_H__
+#define __VISORCHANNEL_H__
+
+#include "commontypes.h"
+#include "memregion.h"
+#include "channel.h"
+#ifndef HOSTADDRESS
+#define HOSTADDRESS U64
+#endif
+#ifndef BOOL
+#define BOOL int
+#endif
+
+/* VISORCHANNEL is an opaque structure to users.
+ * Fields are declared only in the implementation .c files.
+ */
+typedef struct VISORCHANNEL_Tag VISORCHANNEL;
+
+/* Note that for visorchannel_create() and visorchannel_create_overlapped(),
+ * <channelBytes> and <guid> arguments may be 0 if we are a channel CLIENT.
+ * In this case, the values can simply be read from the channel header.
+ */
+VISORCHANNEL *visorchannel_create(HOSTADDRESS physaddr,
+                                 ulong channelBytes, GUID guid);
+VISORCHANNEL *visorchannel_create_overlapped(ulong channelBytes,
+                                            VISORCHANNEL *parent, ulong off,
+                                            GUID guid);
+VISORCHANNEL *visorchannel_create_with_lock(HOSTADDRESS physaddr,
+                                           ulong channelBytes, GUID guid);
+VISORCHANNEL *visorchannel_create_overlapped_with_lock(ulong channelBytes,
+                                                      VISORCHANNEL *parent,
+                                                      ulong off, GUID guid);
+void visorchannel_destroy(VISORCHANNEL *channel);
+int visorchannel_read(VISORCHANNEL *channel, ulong offset,
+                     void *local, ulong nbytes);
+int visorchannel_write(VISORCHANNEL *channel, ulong offset,
+                      void *local, ulong nbytes);
+int visorchannel_clear(VISORCHANNEL *channel, ulong offset,
+                      U8 ch, ulong nbytes);
+BOOL visorchannel_signalremove(VISORCHANNEL *channel, U32 queue, void *msg);
+BOOL visorchannel_signalinsert(VISORCHANNEL *channel, U32 queue, void *msg);
+int visorchannel_signalqueue_slots_avail(VISORCHANNEL *channel, U32 queue);
+int visorchannel_signalqueue_max_slots(VISORCHANNEL *channel, U32 queue);
+
+HOSTADDRESS visorchannel_get_physaddr(VISORCHANNEL *channel);
+ulong visorchannel_get_nbytes(VISORCHANNEL *channel);
+char *visorchannel_id(VISORCHANNEL *channel, char *s);
+char *visorchannel_zoneid(VISORCHANNEL *channel, char *s);
+U64 visorchannel_get_clientpartition(VISORCHANNEL *channel);
+GUID visorchannel_get_GUID(VISORCHANNEL *channel);
+MEMREGION *visorchannel_get_memregion(VISORCHANNEL *channel);
+char *visorchannel_GUID_id(GUID *guid, char *s);
+void visorchannel_debug(VISORCHANNEL *channel, int nQueues,
+                       struct seq_file *seq, U32 off);
+void visorchannel_dump_section(VISORCHANNEL *chan, char *s,
+                              int off, int len, struct seq_file *seq);
+void *visorchannel_get_header(VISORCHANNEL *channel);
+
+#define        VISORCHANNEL_CHANGE_SERVER_STATE(chan, chanId, newstate)        \
+       do {                                                            \
+               U8 *p = (U8 *)visorchannel_get_header(chan);            \
+               if (p) {                                                \
+                       ULTRA_CHANNEL_SERVER_TRANSITION(p, chanId, SrvState, \
+                                                       newstate, logCtx); \
+                       visorchannel_write                              \
+                               (chan,                                  \
+                                offsetof(ULTRA_CHANNEL_PROTOCOL, SrvState), \
+                                p +                                    \
+                                offsetof(ULTRA_CHANNEL_PROTOCOL, SrvState), \
+                                sizeof(U32));                          \
+               }                                                       \
+       } while (0)
+
+#define        VISORCHANNEL_CHANGE_CLIENT_STATE(chan, chanId, newstate)        \
+       do {                                                            \
+               U8 *p = (U8 *)visorchannel_get_header(chan);            \
+               if (p) {                                                \
+                       ULTRA_CHANNEL_CLIENT_TRANSITION(p, chanId, CliStateOS, \
+                                                       newstate, logCtx); \
+                       visorchannel_write                              \
+                               (chan,                                  \
+                                offsetof(ULTRA_CHANNEL_PROTOCOL, CliStateOS), \
+                                p +                                    \
+                                offsetof(ULTRA_CHANNEL_PROTOCOL, CliStateOS), \
+                                sizeof(U32));                          \
+               }                                                       \
+       } while (0)
+
+#endif
diff --git a/drivers/staging/unisys/visorchannel/visorchannel_funcs.c b/drivers/staging/unisys/visorchannel/visorchannel_funcs.c
new file mode 100644 (file)
index 0000000..509c77b
--- /dev/null
@@ -0,0 +1,765 @@
+/* visorchannel_funcs.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 provides Supervisor channel communication primitives, which are
+ *  independent of the mechanism used to access the channel data.  All channel
+ *  data is accessed using the memregion abstraction.  (memregion has both
+ *  a CM2 implementation and a direct memory implementation.)
+ */
+
+#include "globals.h"
+#include "visorchannel.h"
+#include "guidutils.h"
+
+#define MYDRVNAME "visorchannel"
+
+struct VISORCHANNEL_Tag {
+       MEMREGION *memregion;   /* from memregion_create() */
+       CHANNEL_HEADER chan_hdr;
+       GUID guid;
+       ulong size;
+       BOOL needs_lock;
+       spinlock_t insert_lock;
+       spinlock_t remove_lock;
+
+       struct {
+               SIGNAL_QUEUE_HEADER req_queue;
+               SIGNAL_QUEUE_HEADER rsp_queue;
+               SIGNAL_QUEUE_HEADER event_queue;
+               SIGNAL_QUEUE_HEADER ack_queue;
+       } safe_uis_queue;
+};
+
+/* Creates the VISORCHANNEL abstraction for a data area in memory, but does
+ * NOT modify this data area.
+ */
+static VISORCHANNEL *
+visorchannel_create_guts(HOSTADDRESS physaddr, ulong channelBytes,
+                        VISORCHANNEL *parent, ulong off, GUID guid,
+                        BOOL needs_lock)
+{
+       VISORCHANNEL *p = NULL;
+       void *rc = NULL;
+
+       p = kmalloc(sizeof(VISORCHANNEL), GFP_KERNEL|__GFP_NORETRY);
+       if (p == NULL)
+               FAIL("allocation failed", 0);
+       p->memregion = NULL;
+       p->needs_lock = needs_lock;
+       spin_lock_init(&p->insert_lock);
+       spin_lock_init(&p->remove_lock);
+
+       /* prepare chan_hdr (abstraction to read/write channel memory) */
+       if (parent == NULL)
+               p->memregion =
+                   memregion_create(physaddr, sizeof(CHANNEL_HEADER));
+       else
+               p->memregion =
+                   memregion_create_overlapped
+                   (parent->memregion, off, sizeof(CHANNEL_HEADER));
+       if (p->memregion == NULL)
+               FAIL("memregion_create failed", 0);
+       if (memregion_read(p->memregion, 0, &p->chan_hdr,
+                          sizeof(CHANNEL_HEADER)) < 0)
+               FAIL("memregion_read failed", 0);
+       if (channelBytes == 0)
+               /* we had better be a CLIENT of this channel */
+               channelBytes = (ulong) p->chan_hdr.Size;
+       if (STRUCTSEQUAL(guid, Guid0))
+               /* we had better be a CLIENT of this channel */
+               guid = p->chan_hdr.Type;
+       if (memregion_resize(p->memregion, channelBytes) < 0)
+               FAIL("memregion_resize failed", 0);
+       p->size = channelBytes;
+       p->guid = guid;
+
+       RETPTR(p);
+
+Away:
+
+       if (rc == NULL) {
+               if (p != NULL) {
+                       visorchannel_destroy(p);
+                       p = NULL;
+               }
+       }
+       return rc;
+}
+
+VISORCHANNEL *
+visorchannel_create(HOSTADDRESS physaddr, ulong channelBytes, GUID guid)
+{
+       return visorchannel_create_guts(physaddr, channelBytes, NULL, 0, guid,
+                                       FALSE);
+}
+EXPORT_SYMBOL_GPL(visorchannel_create);
+
+VISORCHANNEL *
+visorchannel_create_with_lock(HOSTADDRESS physaddr, ulong channelBytes,
+                             GUID guid)
+{
+       return visorchannel_create_guts(physaddr, channelBytes, NULL, 0, guid,
+                                       TRUE);
+}
+EXPORT_SYMBOL_GPL(visorchannel_create_with_lock);
+
+VISORCHANNEL *
+visorchannel_create_overlapped(ulong channelBytes,
+                              VISORCHANNEL *parent, ulong off, GUID guid)
+{
+       return visorchannel_create_guts(0, channelBytes, parent, off, guid,
+                                       FALSE);
+}
+EXPORT_SYMBOL_GPL(visorchannel_create_overlapped);
+
+VISORCHANNEL *
+visorchannel_create_overlapped_with_lock(ulong channelBytes,
+                                        VISORCHANNEL *parent, ulong off,
+                                        GUID guid)
+{
+       return visorchannel_create_guts(0, channelBytes, parent, off, guid,
+                                       TRUE);
+}
+EXPORT_SYMBOL_GPL(visorchannel_create_overlapped_with_lock);
+
+void
+visorchannel_destroy(VISORCHANNEL *channel)
+{
+       if (channel == NULL)
+               return;
+       if (channel->memregion != NULL) {
+               memregion_destroy(channel->memregion);
+               channel->memregion = NULL;
+       }
+       kfree(channel);
+}
+EXPORT_SYMBOL_GPL(visorchannel_destroy);
+
+HOSTADDRESS
+visorchannel_get_physaddr(VISORCHANNEL *channel)
+{
+       return memregion_get_physaddr(channel->memregion);
+}
+EXPORT_SYMBOL_GPL(visorchannel_get_physaddr);
+
+ulong
+visorchannel_get_nbytes(VISORCHANNEL *channel)
+{
+       return channel->size;
+}
+EXPORT_SYMBOL_GPL(visorchannel_get_nbytes);
+
+char *
+visorchannel_GUID_id(GUID *guid, char *s)
+{
+       return GUID_format1(guid, s);
+}
+EXPORT_SYMBOL_GPL(visorchannel_GUID_id);
+
+char *
+visorchannel_id(VISORCHANNEL *channel, char *s)
+{
+       return visorchannel_GUID_id(&channel->guid, s);
+}
+EXPORT_SYMBOL_GPL(visorchannel_id);
+
+char *
+visorchannel_zoneid(VISORCHANNEL *channel, char *s)
+{
+       return visorchannel_GUID_id(&channel->chan_hdr.ZoneGuid, s);
+}
+EXPORT_SYMBOL_GPL(visorchannel_zoneid);
+
+HOSTADDRESS
+visorchannel_get_clientpartition(VISORCHANNEL *channel)
+{
+       return channel->chan_hdr.PartitionHandle;
+}
+EXPORT_SYMBOL_GPL(visorchannel_get_clientpartition);
+
+GUID
+visorchannel_get_GUID(VISORCHANNEL *channel)
+{
+       return channel->guid;
+}
+EXPORT_SYMBOL_GPL(visorchannel_get_GUID);
+
+MEMREGION *
+visorchannel_get_memregion(VISORCHANNEL *channel)
+{
+       return channel->memregion;
+}
+EXPORT_SYMBOL_GPL(visorchannel_get_memregion);
+
+pSIGNAL_QUEUE_HEADER
+visorchannel_get_safe_queue(VISORCHANNEL *pchannel, U32 queue)
+{
+       switch (queue) {
+       case 0:
+               return &pchannel->safe_uis_queue.req_queue;
+       case 1:
+               return &pchannel->safe_uis_queue.rsp_queue;
+       case 2:
+               return &pchannel->safe_uis_queue.event_queue;
+       case 3:
+               return &pchannel->safe_uis_queue.ack_queue;
+       default:
+               ERRDRV("Invalid queue value %d\n", queue);
+               return NULL;
+       }
+}                              /* end visorchannel_get_safe_queue */
+
+int
+visorchannel_read(VISORCHANNEL *channel, ulong offset,
+                 void *local, ulong nbytes)
+{
+       int rc = memregion_read(channel->memregion, offset, local, nbytes);
+       if ((rc >= 0) && (offset == 0) && (nbytes >= sizeof(CHANNEL_HEADER)))
+               memcpy(&channel->chan_hdr, local, sizeof(CHANNEL_HEADER));
+       return rc;
+}
+EXPORT_SYMBOL_GPL(visorchannel_read);
+
+int
+visorchannel_write(VISORCHANNEL *channel, ulong offset,
+                  void *local, ulong nbytes)
+{
+       if (offset == 0 && nbytes >= sizeof(CHANNEL_HEADER))
+               memcpy(&channel->chan_hdr, local, sizeof(CHANNEL_HEADER));
+       return memregion_write(channel->memregion, offset, local, nbytes);
+}
+EXPORT_SYMBOL_GPL(visorchannel_write);
+
+int
+visorchannel_clear(VISORCHANNEL *channel, ulong offset, U8 ch, ulong nbytes)
+{
+       int rc = -1;
+       int bufsize = 65536;
+       int written = 0;
+       U8 *buf = vmalloc(bufsize);
+
+       if (buf == NULL) {
+               ERRDRV("%s failed memory allocation", __func__);
+               RETINT(-1);
+       }
+       memset(buf, ch, bufsize);
+       while (nbytes > 0) {
+               ulong thisbytes = bufsize;
+               int x = -1;
+               if (nbytes < thisbytes)
+                       thisbytes = nbytes;
+               x = memregion_write(channel->memregion, offset + written,
+                                   buf, thisbytes);
+               if (x < 0)
+                       RETINT(x);
+               written += thisbytes;
+               nbytes -= thisbytes;
+       }
+       RETINT(0);
+
+Away:
+       if (buf != NULL) {
+               vfree(buf);
+               buf = NULL;
+       }
+       return rc;
+}
+EXPORT_SYMBOL_GPL(visorchannel_clear);
+
+void *
+visorchannel_get_header(VISORCHANNEL *channel)
+{
+       return (void *) &(channel->chan_hdr);
+}
+EXPORT_SYMBOL_GPL(visorchannel_get_header);
+
+/** Return offset of a specific SIGNAL_QUEUE_HEADER from the beginning of a
+ *  channel header
+ */
+#define SIG_QUEUE_OFFSET(chan_hdr, q) \
+       ((chan_hdr)->oChannelSpace + ((q) * sizeof(SIGNAL_QUEUE_HEADER)))
+
+/** Return offset of a specific queue entry (data) from the beginning of a
+ *  channel header
+ */
+#define SIG_DATA_OFFSET(chan_hdr, q, sig_hdr, slot) \
+       (SIG_QUEUE_OFFSET(chan_hdr, q) + (sig_hdr)->oSignalBase + \
+           ((slot) * (sig_hdr)->SignalSize))
+
+/** Write the contents of a specific field within a SIGNAL_QUEUE_HEADER back
+ *  into host memory
+ */
+#define SIG_WRITE_FIELD(channel, queue, sig_hdr, FIELD)                \
+       (memregion_write(channel->memregion,                        \
+                        SIG_QUEUE_OFFSET(&channel->chan_hdr, queue)+\
+                          offsetof(SIGNAL_QUEUE_HEADER, FIELD),     \
+                        &((sig_hdr)->FIELD),                       \
+                        sizeof((sig_hdr)->FIELD)) >= 0)
+
+static BOOL
+sig_read_header(VISORCHANNEL *channel, U32 queue,
+               SIGNAL_QUEUE_HEADER *sig_hdr)
+{
+       BOOL rc = FALSE;
+
+       if (channel->chan_hdr.oChannelSpace < sizeof(CHANNEL_HEADER))
+               FAIL("oChannelSpace too small", FALSE);
+
+       /* Read the appropriate SIGNAL_QUEUE_HEADER into local memory. */
+
+       if (memregion_read(channel->memregion,
+                          SIG_QUEUE_OFFSET(&channel->chan_hdr, queue),
+                          sig_hdr, sizeof(SIGNAL_QUEUE_HEADER)) < 0) {
+               ERRDRV("queue=%d SIG_QUEUE_OFFSET=%d",
+                      queue, (int)SIG_QUEUE_OFFSET(&channel->chan_hdr, queue));
+               FAIL("memregion_read of signal queue failed", FALSE);
+       }
+       RETBOOL(TRUE);
+Away:
+       return rc;
+}
+
+static BOOL
+sig_do_data(VISORCHANNEL *channel, U32 queue,
+           SIGNAL_QUEUE_HEADER *sig_hdr, U32 slot, void *data, BOOL is_write)
+{
+       BOOL rc = FALSE;
+       int signal_data_offset = SIG_DATA_OFFSET(&channel->chan_hdr, queue,
+                                                sig_hdr, slot);
+       if (is_write) {
+               if (memregion_write(channel->memregion, signal_data_offset,
+                                   data, sig_hdr->SignalSize) < 0)
+                       FAIL("memregion_write of signal data failed", FALSE);
+       } else {
+               if (memregion_read(channel->memregion, signal_data_offset,
+                                  data, sig_hdr->SignalSize) < 0)
+                       FAIL("memregion_read of signal data failed", FALSE);
+       }
+       RETBOOL(TRUE);
+Away:
+       return rc;
+}
+
+static inline BOOL
+sig_read_data(VISORCHANNEL *channel, U32 queue,
+             SIGNAL_QUEUE_HEADER *sig_hdr, U32 slot, void *data)
+{
+       return sig_do_data(channel, queue, sig_hdr, slot, data, FALSE);
+}
+
+static inline BOOL
+sig_write_data(VISORCHANNEL *channel, U32 queue,
+              SIGNAL_QUEUE_HEADER *sig_hdr, U32 slot, void *data)
+{
+       return sig_do_data(channel, queue, sig_hdr, slot, data, TRUE);
+}
+
+static inline unsigned char
+safe_sig_queue_validate(pSIGNAL_QUEUE_HEADER psafe_sqh,
+                       pSIGNAL_QUEUE_HEADER punsafe_sqh,
+                       U32 *phead, U32 *ptail)
+{
+       if ((*phead >= psafe_sqh->MaxSignalSlots)
+           || (*ptail >= psafe_sqh->MaxSignalSlots)) {
+               /* Choose 0 or max, maybe based on current tail value */
+               *phead = 0;
+               *ptail = 0;
+
+               /* Sync with client as necessary */
+               punsafe_sqh->Head = *phead;
+               punsafe_sqh->Tail = *ptail;
+
+               ERRDRV("safe_sig_queue_validate: head = 0x%x, tail = 0x%x, MaxSlots = 0x%x",
+                    *phead, *ptail, psafe_sqh->MaxSignalSlots);
+               return 0;
+       }
+       return 1;
+}                              /* end safe_sig_queue_validate */
+
+BOOL
+visorchannel_signalremove(VISORCHANNEL *channel, U32 queue, void *msg)
+{
+       BOOL rc = FALSE;
+       SIGNAL_QUEUE_HEADER sig_hdr;
+
+       if (channel->needs_lock)
+               spin_lock(&channel->remove_lock);
+
+       if (!sig_read_header(channel, queue, &sig_hdr))
+               RETBOOL(FALSE);
+       if (sig_hdr.Head == sig_hdr.Tail)
+               RETBOOL(FALSE); /* no signals to remove */
+       sig_hdr.Tail = (sig_hdr.Tail + 1) % sig_hdr.MaxSignalSlots;
+       if (!sig_read_data(channel, queue, &sig_hdr, sig_hdr.Tail, msg))
+               FAIL("sig_read_data failed", FALSE);
+       sig_hdr.NumSignalsReceived++;
+
+       /* For each data field in SIGNAL_QUEUE_HEADER that was modified,
+        * update host memory.
+        */
+       MEMORYBARRIER;
+       if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, Tail))
+               FAIL("memregion_write of Tail failed", FALSE);
+       if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, NumSignalsReceived))
+               FAIL("memregion_write of NumSignalsReceived failed", FALSE);
+
+       RETBOOL(TRUE);
+
+Away:
+       if (channel->needs_lock)
+               spin_unlock(&channel->remove_lock);
+
+       return rc;
+}
+EXPORT_SYMBOL_GPL(visorchannel_signalremove);
+
+BOOL
+visorchannel_safesignalremove(VISORCHANNEL *channel, U32 queue, void *msg)
+{
+       BOOL rc = FALSE;
+       SIGNAL_QUEUE_HEADER *psafe_sqh, unsafe_sqh;
+       int stat;
+
+       if (channel->needs_lock)
+               spin_lock(&channel->remove_lock);
+
+       if (!sig_read_header(channel, queue, &unsafe_sqh))
+               RETBOOL(FALSE);
+
+       psafe_sqh = visorchannel_get_safe_queue(channel, queue);
+       if (psafe_sqh == NULL) {
+               ERRDRV("safesignalremove: get_safe_queue failed\n");
+               RETBOOL(FALSE);
+       }
+
+       stat =
+           safe_sig_queue_validate(psafe_sqh, &unsafe_sqh, &unsafe_sqh.Head,
+                                   &unsafe_sqh.Tail);
+       if (stat == 0) {
+               ERRDRV("safe_signal_remove: safe_sig_queue_validate failed, queue = %d",
+                    queue);
+               RETBOOL(FALSE);
+       }
+
+       if (unsafe_sqh.Head == unsafe_sqh.Tail)
+               RETBOOL(FALSE); /* no signals to remove */
+       unsafe_sqh.Tail = (unsafe_sqh.Tail + 1) % psafe_sqh->MaxSignalSlots;
+       if (!sig_read_data(channel, queue, psafe_sqh, unsafe_sqh.Tail, msg))
+               FAIL("sig_read_data failed", FALSE);
+       unsafe_sqh.NumSignalsReceived++;
+
+       /* For each data field in SIGNAL_QUEUE_HEADER that was modified,
+        * update host memory.
+        */
+       MEMORYBARRIER;
+       if (!SIG_WRITE_FIELD(channel, queue, &unsafe_sqh, Tail))
+               FAIL("memregion_write of Tail failed", FALSE);
+       if (!SIG_WRITE_FIELD(channel, queue, &unsafe_sqh, NumSignalsReceived))
+               FAIL("memregion_write of NumSignalsReceived failed", FALSE);
+
+       RETBOOL(TRUE);
+
+Away:
+       if (channel->needs_lock)
+               spin_unlock(&channel->remove_lock);
+
+       return rc;
+}                              /* end visorchannel_safesignalremove */
+
+BOOL
+visorchannel_signalinsert(VISORCHANNEL *channel, U32 queue, void *msg)
+{
+       BOOL rc = FALSE;
+       SIGNAL_QUEUE_HEADER sig_hdr;
+
+       if (channel->needs_lock)
+               spin_lock(&channel->insert_lock);
+
+       if (!sig_read_header(channel, queue, &sig_hdr))
+               RETBOOL(FALSE);
+
+       sig_hdr.Head = ((sig_hdr.Head + 1) % sig_hdr.MaxSignalSlots);
+       if (sig_hdr.Head == sig_hdr.Tail) {
+#if 0
+               ERRDRV("visorchannel queue #%d overflow (max slots=%d)",
+                      queue, sig_hdr.MaxSignalSlots);
+#endif
+               sig_hdr.NumOverflows++;
+               if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, NumOverflows))
+                       FAIL("memregion_write of NumOverflows failed", FALSE);
+               RETBOOL(FALSE);
+       }
+
+       if (!sig_write_data(channel, queue, &sig_hdr, sig_hdr.Head, msg))
+               FAIL("sig_write_data failed", FALSE);
+       sig_hdr.NumSignalsSent++;
+
+       /* For each data field in SIGNAL_QUEUE_HEADER that was modified,
+        * update host memory.
+        */
+       MEMORYBARRIER;
+       if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, Head))
+               FAIL("memregion_write of Head failed", FALSE);
+       if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, NumSignalsSent))
+               FAIL("memregion_write of NumSignalsSent failed", FALSE);
+
+       RETBOOL(TRUE);
+
+Away:
+       if (channel->needs_lock)
+               spin_unlock(&channel->insert_lock);
+
+       return rc;
+}
+EXPORT_SYMBOL_GPL(visorchannel_signalinsert);
+
+
+int
+visorchannel_signalqueue_slots_avail(VISORCHANNEL *channel, U32 queue)
+{
+       SIGNAL_QUEUE_HEADER sig_hdr;
+       U32 slots_avail, slots_used;
+       U32 head, tail;
+
+       if (!sig_read_header(channel, queue, &sig_hdr))
+               return 0;
+       head = sig_hdr.Head;
+       tail = sig_hdr.Tail;
+       if (head < tail)
+               head = head + sig_hdr.MaxSignalSlots;
+       slots_used = (head - tail);
+       slots_avail = sig_hdr.MaxSignals - slots_used;
+       return (int) slots_avail;
+}
+EXPORT_SYMBOL_GPL(visorchannel_signalqueue_slots_avail);
+
+int
+visorchannel_signalqueue_max_slots(VISORCHANNEL *channel, U32 queue)
+{
+       SIGNAL_QUEUE_HEADER sig_hdr;
+       if (!sig_read_header(channel, queue, &sig_hdr))
+               return 0;
+       return (int) sig_hdr.MaxSignals;
+}
+EXPORT_SYMBOL_GPL(visorchannel_signalqueue_max_slots);
+
+BOOL
+visorchannel_safesignalinsert(VISORCHANNEL *channel, U32 queue, void *msg)
+{
+       BOOL rc = FALSE;
+       SIGNAL_QUEUE_HEADER *psafe_sqh, unsafe_sqh;
+       int stat;
+
+       if (channel->needs_lock)
+               spin_lock(&channel->insert_lock);
+
+       if (!sig_read_header(channel, queue, &unsafe_sqh))
+               RETBOOL(FALSE);
+
+       psafe_sqh = visorchannel_get_safe_queue(channel, queue);
+       if (psafe_sqh == NULL) {
+               ERRDRV("safesignalinsert: get_safe_queue failed\n");
+               RETBOOL(FALSE);
+       }
+
+       unsafe_sqh.Head = ((unsafe_sqh.Head + 1) % psafe_sqh->MaxSignalSlots);
+
+       stat =
+           safe_sig_queue_validate(psafe_sqh, &unsafe_sqh, &unsafe_sqh.Head,
+                                   &unsafe_sqh.Tail);
+       if (stat == 0) {
+               ERRDRV("safe_signal_insert: safe_sig_queue_validate failed, queue = %d",
+                    queue);
+               RETBOOL(FALSE);
+       }
+
+       if (unsafe_sqh.Head == unsafe_sqh.Tail) {
+#if 0
+               ERRDRV("visorchannel queue #%d overflow (max slots=%d)",
+                      queue, psafe_sqh->MaxSignalSlots);
+#endif
+               unsafe_sqh.NumOverflows++;
+               if (!SIG_WRITE_FIELD(channel, queue, &unsafe_sqh, NumOverflows))
+                       FAIL("memregion_write of NumOverflows failed", FALSE);
+               RETBOOL(FALSE);
+       }
+
+       if (!sig_write_data(channel, queue, psafe_sqh, unsafe_sqh.Head, msg))
+               FAIL("sig_write_data failed", FALSE);
+       unsafe_sqh.NumSignalsSent++;
+
+       /* For each data field in SIGNAL_QUEUE_HEADER that was modified,
+        * update host memory.
+        */
+       MEMORYBARRIER;
+       if (!SIG_WRITE_FIELD(channel, queue, &unsafe_sqh, Head))
+               FAIL("memregion_write of Head failed", FALSE);
+       if (!SIG_WRITE_FIELD(channel, queue, &unsafe_sqh, NumSignalsSent))
+               FAIL("memregion_write of NumSignalsSent failed", FALSE);
+
+       RETBOOL(TRUE);
+
+Away:
+       if (channel->needs_lock)
+               spin_unlock(&channel->insert_lock);
+
+       return rc;
+}                              /* end visorchannel_safesignalinsert */
+
+static void
+sigqueue_debug(SIGNAL_QUEUE_HEADER *q, int which, struct seq_file *seq)
+{
+       seq_printf(seq, "Signal Queue #%d\n", which);
+       seq_printf(seq, "   VersionId          = %lu\n", (ulong) q->VersionId);
+       seq_printf(seq, "   Type               = %lu\n", (ulong) q->Type);
+       seq_printf(seq, "   oSignalBase        = %llu\n",
+                  (long long) q->oSignalBase);
+       seq_printf(seq, "   SignalSize         = %lu\n", (ulong) q->SignalSize);
+       seq_printf(seq, "   MaxSignalSlots     = %lu\n",
+                  (ulong) q->MaxSignalSlots);
+       seq_printf(seq, "   MaxSignals         = %lu\n", (ulong) q->MaxSignals);
+       seq_printf(seq, "   FeatureFlags       = %-16.16Lx\n",
+                  (long long) q->FeatureFlags);
+       seq_printf(seq, "   NumSignalsSent     = %llu\n",
+                  (long long) q->NumSignalsSent);
+       seq_printf(seq, "   NumSignalsReceived = %llu\n",
+                  (long long) q->NumSignalsReceived);
+       seq_printf(seq, "   NumOverflows       = %llu\n",
+                  (long long) q->NumOverflows);
+       seq_printf(seq, "   Head               = %lu\n", (ulong) q->Head);
+       seq_printf(seq, "   Tail               = %lu\n", (ulong) q->Tail);
+}
+
+void
+visorchannel_debug(VISORCHANNEL *channel, int nQueues,
+                  struct seq_file *seq, U32 off)
+{
+       HOSTADDRESS addr = 0;
+       ulong nbytes = 0, nbytes_region = 0;
+       MEMREGION *memregion = NULL;
+       CHANNEL_HEADER hdr;
+       CHANNEL_HEADER *phdr = &hdr;
+       char s[99];
+       int i = 0;
+       int errcode = 0;
+
+       if (channel == NULL) {
+               ERRDRV("%s no channel", __func__);
+               return;
+       }
+       memregion = channel->memregion;
+       if (memregion == NULL) {
+               ERRDRV("%s no memregion", __func__);
+               return;
+       }
+       addr = memregion_get_physaddr(memregion);
+       nbytes_region = memregion_get_nbytes(memregion);
+       errcode = visorchannel_read(channel, off,
+                                   phdr, sizeof(CHANNEL_HEADER));
+       if (errcode < 0) {
+               seq_printf(seq,
+                          "Read of channel header failed with errcode=%d)\n",
+                          errcode);
+               if (off == 0) {
+                       phdr = &channel->chan_hdr;
+                       seq_puts(seq, "(following data may be stale)\n");
+               } else
+                       return;
+       }
+       nbytes = (ulong) (phdr->Size);
+       seq_printf(seq, "--- Begin channel @0x%-16.16Lx for 0x%lx bytes (region=0x%lx bytes) ---\n",
+                  addr + off, nbytes, nbytes_region);
+       seq_printf(seq, "Type            = %s\n", GUID_format2(&phdr->Type, s));
+       seq_printf(seq, "ZoneGuid        = %s\n",
+                  GUID_format2(&phdr->ZoneGuid, s));
+       seq_printf(seq, "Signature       = 0x%-16.16Lx\n",
+                  (long long) phdr->Signature);
+       seq_printf(seq, "LegacyState     = %lu\n", (ulong) phdr->LegacyState);
+       seq_printf(seq, "SrvState        = %lu\n", (ulong) phdr->SrvState);
+       seq_printf(seq, "CliStateBoot    = %lu\n", (ulong) phdr->CliStateBoot);
+       seq_printf(seq, "CliStateOS      = %lu\n", (ulong) phdr->CliStateOS);
+       seq_printf(seq, "HeaderSize      = %lu\n", (ulong) phdr->HeaderSize);
+       seq_printf(seq, "Size            = %llu\n", (long long) phdr->Size);
+       seq_printf(seq, "Features        = 0x%-16.16llx\n",
+                  (long long) phdr->Features);
+       seq_printf(seq, "PartitionHandle = 0x%-16.16llx\n",
+                  (long long) phdr->PartitionHandle);
+       seq_printf(seq, "Handle          = 0x%-16.16llx\n",
+                  (long long) phdr->Handle);
+       seq_printf(seq, "VersionId       = %lu\n", (ulong) phdr->VersionId);
+       seq_printf(seq, "oChannelSpace   = %llu\n",
+                  (long long) phdr->oChannelSpace);
+       if ((phdr->oChannelSpace == 0) || (errcode < 0))
+               ;
+       else
+               for (i = 0; i < nQueues; i++) {
+                       SIGNAL_QUEUE_HEADER q;
+                       errcode = visorchannel_read(channel,
+                                                   off + phdr->oChannelSpace +
+                                                   (i * sizeof(q)),
+                                                   &q, sizeof(q));
+                       if (errcode < 0) {
+                               seq_printf(seq,
+                                          "failed to read signal queue #%d from channel @0x%-16.16Lx errcode=%d\n",
+                                          i, addr, errcode);
+                               continue;
+                       }
+                       sigqueue_debug(&q, i, seq);
+               }
+       seq_printf(seq, "--- End   channel @0x%-16.16Lx for 0x%lx bytes ---\n",
+                  addr + off, nbytes);
+}
+EXPORT_SYMBOL_GPL(visorchannel_debug);
+
+void
+visorchannel_dump_section(VISORCHANNEL *chan, char *s,
+                         int off, int len, struct seq_file *seq)
+{
+       char *buf = NULL, *fmtbuf = NULL;
+       int fmtbufsize = 0;
+       int i = 0;
+       int errcode = 0;
+
+       fmtbufsize = 100 * COVQ(len, 16);
+       buf = kmalloc(len, GFP_KERNEL|__GFP_NORETRY);
+       fmtbuf = kmalloc(fmtbufsize, GFP_KERNEL|__GFP_NORETRY);
+       if (buf == NULL || fmtbuf == NULL)
+               goto Away;
+
+       errcode = visorchannel_read(chan, off, buf, len);
+       if (errcode < 0) {
+               ERRDRV("%s failed to read %s from channel errcode=%d",
+                      s, __func__, errcode);
+               goto Away;
+       }
+       seq_printf(seq, "channel %s:\n", s);
+       hexDumpToBuffer(fmtbuf, fmtbufsize, "  ", buf, len, 16);
+       for (i = 0; fmtbuf[i] != '\0'; i++)
+               seq_printf(seq, "%c", fmtbuf[i]);
+
+Away:
+       if (buf != NULL) {
+               kfree(buf);
+               buf = NULL;
+       }
+       if (fmtbuf != NULL) {
+               kfree(fmtbuf);
+               fmtbuf = NULL;
+       }
+}
+EXPORT_SYMBOL_GPL(visorchannel_dump_section);
diff --git a/drivers/staging/unisys/visorchannel/visorchannel_main.c b/drivers/staging/unisys/visorchannel/visorchannel_main.c
new file mode 100644 (file)
index 0000000..482ee0a
--- /dev/null
@@ -0,0 +1,49 @@
+/* visorchannel_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.
+ */
+
+/*
+ *  This is a module "wrapper" around visorchannel_funcs.
+ */
+
+#include "globals.h"
+#include "channel.h"
+#include "visorchannel.h"
+#include "guidutils.h"
+
+#define MYDRVNAME "visorchannel"
+
+static int __init
+visorchannel_init(void)
+{
+       INFODRV("driver version %s loaded", VERSION);
+       return 0;
+}
+
+static void
+visorchannel_exit(void)
+{
+       INFODRV("driver unloaded");
+}
+
+module_init(visorchannel_init);
+module_exit(visorchannel_exit);
+
+MODULE_AUTHOR("Unisys");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Supervisor channel driver for service partition: ver "
+                  VERSION);
+MODULE_VERSION(VERSION);