summaryrefslogtreecommitdiff
path: root/drivers/staging/unisys/common-spar/include/channels/channel.h
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/unisys/common-spar/include/channels/channel.h')
-rw-r--r--drivers/staging/unisys/common-spar/include/channels/channel.h661
1 files changed, 661 insertions, 0 deletions
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
index 000000000000..aee204172b21
--- /dev/null
+++ b/drivers/staging/unisys/common-spar/include/channels/channel.h
@@ -0,0 +1,661 @@
+/* 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(readl(&(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, \
+ newstate, logCtx) \
+ do { \
+ ULTRA_CHANNEL_CLIENT_CHK_TRANSITION( \
+ readl(&(((CHANNEL_HEADER __iomem *) \
+ (pChan))->CliStateOS)), \
+ 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, "CliStateOS", \
+ ULTRA_CHANNELCLI_STRING( \
+ readl(&((CHANNEL_HEADER __iomem *) \
+ (pChan))->CliStateOS)), \
+ readl(&((CHANNEL_HEADER __iomem *) \
+ (pChan))->CliStateOS), \
+ ULTRA_CHANNELCLI_STRING(newstate), \
+ newstate, \
+ PathName_Last_N_Nodes(__FILE__, 4), __LINE__); \
+ writel(newstate, &((CHANNEL_HEADER __iomem *) \
+ (pChan))->CliStateOS); \
+ 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 visor_signal_remove
+ * 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 __iomem *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_IO(&(((CHANNEL_HEADER __iomem *) (pChannel))->Type),
+ &expectedTypeGuid, sizeof(GUID)) != 0) {
+ CHANNEL_GUID_MISMATCH(expectedTypeGuid, channelName,
+ "type", expectedTypeGuid,
+ ((CHANNEL_HEADER __iomem *)
+ (pChannel))->Type, fileName,
+ lineNumber, logCtx);
+ return 0;
+ }
+ if (expectedMinBytes > 0) /* caller wants us to verify
+ * channel size */
+ if (readq(&((CHANNEL_HEADER __iomem *)
+ (pChannel))->Size) < expectedMinBytes) {
+ CHANNEL_U64_MISMATCH(expectedTypeGuid, channelName,
+ "size", expectedMinBytes,
+ ((CHANNEL_HEADER __iomem *)
+ (pChannel))->Size, fileName,
+ lineNumber, logCtx);
+ return 0;
+ }
+ if (expectedVersionId > 0) /* caller wants us to verify
+ * channel version */
+ if (readl(&((CHANNEL_HEADER __iomem *) (pChannel))->VersionId)
+ != expectedVersionId) {
+ CHANNEL_U32_MISMATCH(expectedTypeGuid, channelName,
+ "version", expectedVersionId,
+ ((CHANNEL_HEADER __iomem *)
+ (pChannel))->VersionId, fileName,
+ lineNumber, logCtx);
+ return 0;
+ }
+ if (expectedSignature > 0) /* caller wants us to verify
+ * channel signature */
+ if (readq(&((CHANNEL_HEADER __iomem *) (pChannel))->Signature)
+ != expectedSignature) {
+ CHANNEL_U64_MISMATCH(expectedTypeGuid, channelName,
+ "signature", expectedSignature,
+ ((CHANNEL_HEADER __iomem *)
+ (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 __iomem *pChannel, U8 *chanId,
+ void *logCtx, char *file, int line, char *func)
+{
+ CHANNEL_HEADER __iomem *pChan = pChannel;
+
+ if (readl(&pChan->CliStateOS) == CHANNELCLI_DISABLED) {
+ if ((readb(&pChan->CliErrorOS)
+ & ULTRA_CLIERROROS_THROTTLEMSG_DISABLED) == 0) {
+ /* we are NOT throttling this message */
+ writeb(readb(&pChan->CliErrorOS) |
+ ULTRA_CLIERROROS_THROTTLEMSG_DISABLED,
+ &pChan->CliErrorOS);
+ /* 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 ((readl(&pChan->CliStateOS) != CHANNELCLI_OWNED)
+ && (readl(&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(
+ readl(&pChan->CliStateOS)),
+ readl(&pChan->CliStateOS),
+ ULTRA_CHANNELCLI_STRING(CHANNELCLI_OWNED),
+ CHANNELCLI_OWNED,
+ PathName_Last_N_Nodes((U8 *) file, 4), line);
+ writel(CHANNELCLI_OWNED, &pChan->CliStateOS);
+ MEMORYBARRIER;
+ }
+ if (readl(&pChan->CliStateOS) == CHANNELCLI_OWNED) {
+ if (readb(&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);
+ writeb(0, &pChan->CliErrorOS);
+ }
+ 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 (readl(&pChan->CliStateOS) != CHANNELCLI_ATTACHED) {
+ if ((readb(&pChan->CliErrorOS)
+ & ULTRA_CLIERROROS_THROTTLEMSG_NOTATTACHED) == 0) {
+ /* we are NOT throttling this message */
+ writeb(readb(&pChan->CliErrorOS) |
+ ULTRA_CLIERROROS_THROTTLEMSG_NOTATTACHED,
+ &pChan->CliErrorOS);
+ /* 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(
+ readl(&pChan->CliStateOS)),
+ readl(&pChan->CliStateOS),
+ PathName_Last_N_Nodes((U8 *) file, 4),
+ line);
+ }
+ return 0;
+ }
+ writel(CHANNELCLI_BUSY, &pChan->CliStateOS);
+ MEMORYBARRIER;
+ if (readl(&pChan->CliStateBoot) == CHANNELCLI_BUSY) {
+ if ((readb(&pChan->CliErrorOS)
+ & ULTRA_CLIERROROS_THROTTLEMSG_BUSY) == 0) {
+ /* we are NOT throttling this message */
+ writeb(readb(&pChan->CliErrorOS) |
+ ULTRA_CLIERROROS_THROTTLEMSG_BUSY,
+ &pChan->CliErrorOS);
+ /* 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);
+ }
+ /* reset busy */
+ writel(CHANNELCLI_ATTACHED, &pChan->CliStateOS);
+ MEMORYBARRIER;
+ return 0;
+ }
+ if (readb(&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);
+ writeb(0, &pChan->CliErrorOS);
+ }
+ return 1;
+}
+
+static inline void
+ULTRA_channel_client_release_os(void __iomem *pChannel, U8 *chanId,
+ void *logCtx, char *file, int line, char *func)
+{
+ CHANNEL_HEADER __iomem *pChan = pChannel;
+ if (readb(&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);
+ writeb(0, &pChan->CliErrorOS);
+ }
+ if (readl(&pChan->CliStateOS) == CHANNELCLI_OWNED)
+ return;
+ if (readl(&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(
+ readl(&pChan->CliStateOS)),
+ readl(&pChan->CliStateOS),
+ PathName_Last_N_Nodes((U8 *) file, 4), line);
+ /* return; */
+ }
+ writel(CHANNELCLI_ATTACHED, &pChan->CliStateOS); /* 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 visor_signal_insert(CHANNEL_HEADER __iomem *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 visor_signal_remove(CHANNEL_HEADER __iomem *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 visor_signalqueue_empty(CHANNEL_HEADER __iomem *pChannel,
+ U32 Queue);
+
+#endif