| /* Copyright (C) 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__ |
| |
| #include <linux/uuid.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 abbreviated 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 |
| |
| #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 */ |
| uuid_le 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 */ |
| uuid_le 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, |
| uuid_le expectedTypeGuid, |
| char *channelName, |
| U64 expectedMinBytes, |
| U32 expectedVersionId, |
| U64 expectedSignature, |
| char *fileName, int lineNumber, void *logCtx) |
| { |
| if (uuid_le_cmp(expectedTypeGuid, NULL_UUID_LE) != 0) |
| /* caller wants us to verify type GUID */ |
| if (MEMCMP_IO(&(((CHANNEL_HEADER __iomem *) (pChannel))->Type), |
| &expectedTypeGuid, sizeof(uuid_le)) != 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, |
| readq(&((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, |
| readl(&((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, |
| readq(&((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(uuid_le 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 |