Commit e423812a authored by Ken Cox's avatar Ken Cox Committed by Greg Kroah-Hartman
Browse files

staging: visorchannel module



The visorchannel module is a support library that abstracts reading
and writing a channel in memory.

Signed-off-by: default avatarKen Cox <jkc@redhat.com>
Cc: Ben Romer <sparmaintainer@unisys.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 9d9baadd
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -10,5 +10,6 @@ menuconfig UNISYSSPAR
if UNISYSSPAR

source "drivers/staging/unisys/visorutil/Kconfig"
source "drivers/staging/unisys/visorchannel/Kconfig"

endif # UNISYSSPAR
+1 −0
Original line number Diff line number Diff line
@@ -2,4 +2,5 @@
# Makefile for Unisys SPAR drivers
#
obj-$(CONFIG_UNISYS_VISORUTIL)		+= visorutil/
obj-$(CONFIG_UNISYS_VISORCHANNEL)	+= visorchannel/
+645 −0
Original line number Diff line number Diff line
/* 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
+46 −0

File added.

Preview size limit exceeded, changes collapsed.

+166 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading