diff options
Diffstat (limited to 'drivers/staging/unisys/common-spar/include/channels')
7 files changed, 2916 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 0000000..aee2041 --- /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 diff --git a/drivers/staging/unisys/common-spar/include/channels/channel_guid.h b/drivers/staging/unisys/common-spar/include/channels/channel_guid.h new file mode 100644 index 0000000..ae0dc2b --- /dev/null +++ b/drivers/staging/unisys/common-spar/include/channels/channel_guid.h @@ -0,0 +1,64 @@ +/* Copyright © 2010 - 2013 UNISYS CORPORATION + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + */ + +/* + * CHANNEL Guids + */ + +/* Used in IOChannel + * {414815ed-c58c-11da-95a9-00e08161165f} + */ +#define ULTRA_VHBA_CHANNEL_PROTOCOL_GUID \ + { 0x414815ed, 0xc58c, 0x11da, \ + { 0x95, 0xa9, 0x0, 0xe0, 0x81, 0x61, 0x16, 0x5f } } +static const GUID UltraVhbaChannelProtocolGuid = + ULTRA_VHBA_CHANNEL_PROTOCOL_GUID; + +/* Used in IOChannel + * {8cd5994d-c58e-11da-95a9-00e08161165f} + */ +#define ULTRA_VNIC_CHANNEL_PROTOCOL_GUID \ + { 0x8cd5994d, 0xc58e, 0x11da, \ + { 0x95, 0xa9, 0x0, 0xe0, 0x81, 0x61, 0x16, 0x5f } } +static const GUID UltraVnicChannelProtocolGuid = + ULTRA_VNIC_CHANNEL_PROTOCOL_GUID; + +/* Used in IOChannel + * {72120008-4AAB-11DC-8530-444553544200} + */ +#define ULTRA_SIOVM_GUID \ + { 0x72120008, 0x4AAB, 0x11DC, \ + { 0x85, 0x30, 0x44, 0x45, 0x53, 0x54, 0x42, 0x00 } } +static const GUID UltraSIOVMGuid = ULTRA_SIOVM_GUID; + + +/* Used in visornoop/visornoop_main.c + * {5b52c5ac-e5f5-4d42-8dff-429eaecd221f} + */ +#define ULTRA_CONTROLDIRECTOR_CHANNEL_PROTOCOL_GUID \ + { 0x5b52c5ac, 0xe5f5, 0x4d42, \ + { 0x8d, 0xff, 0x42, 0x9e, 0xae, 0xcd, 0x22, 0x1f } } + +static const GUID UltraControlDirectorChannelProtocolGuid = + ULTRA_CONTROLDIRECTOR_CHANNEL_PROTOCOL_GUID; + +/* Used in visorchipset/visorchipset_main.c + * {B4E79625-AEDE-4EAA-9E11-D3EDDCD4504C} + */ +#define ULTRA_DIAG_POOL_CHANNEL_PROTOCOL_GUID \ + {0xb4e79625, 0xaede, 0x4eaa, \ + { 0x9e, 0x11, 0xd3, 0xed, 0xdc, 0xd4, 0x50, 0x4c } } + + diff --git a/drivers/staging/unisys/common-spar/include/channels/controlframework.h b/drivers/staging/unisys/common-spar/include/channels/controlframework.h new file mode 100644 index 0000000..5126433 --- /dev/null +++ b/drivers/staging/unisys/common-spar/include/channels/controlframework.h @@ -0,0 +1,77 @@ +/* Copyright © 2010 - 2013 UNISYS CORPORATION + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + */ + +/* + * Module Name: + * controlframework.h + * + * Abstract: This file defines common structures in the unmanaged + * Ultravisor (mostly EFI) space. + * + */ + +#ifndef _CONTROL_FRAMEWORK_H_ +#define _CONTROL_FRAMEWORK_H_ + +#include "commontypes.h" +#include "channel.h" + +#define ULTRA_MEMORY_COUNT_Ki 1024 + +/* Scale order 0 is one 32-bit (4-byte) word (in 64 or 128-bit + * architecture potentially 64 or 128-bit word) */ +#define ULTRA_MEMORY_PAGE_WORD 4 + +/* Define Ki scale page to be traditional 4KB page */ +#define ULTRA_MEMORY_PAGE_Ki (ULTRA_MEMORY_PAGE_WORD * ULTRA_MEMORY_COUNT_Ki) +typedef struct _ULTRA_SEGMENT_STATE { + U16 Enabled:1; /* Bit 0: May enter other states */ + U16 Active:1; /* Bit 1: Assigned to active partition */ + U16 Alive:1; /* Bit 2: Configure message sent to + * service/server */ + U16 Revoked:1; /* Bit 3: similar to partition state + * ShuttingDown */ + U16 Allocated:1; /* Bit 4: memory (device/port number) + * has been selected by Command */ + U16 Known:1; /* Bit 5: has been introduced to the + * service/guest partition */ + U16 Ready:1; /* Bit 6: service/Guest partition has + * responded to introduction */ + U16 Operating:1; /* Bit 7: resource is configured and + * operating */ + /* Note: don't use high bit unless we need to switch to ushort + * which is non-compliant */ +} ULTRA_SEGMENT_STATE; +static const ULTRA_SEGMENT_STATE SegmentStateRunning = { + 1, 1, 1, 0, 1, 1, 1, 1 +}; +static const ULTRA_SEGMENT_STATE SegmentStatePaused = { + 1, 1, 1, 0, 1, 1, 1, 0 +}; +static const ULTRA_SEGMENT_STATE SegmentStateStandby = { + 1, 1, 0, 0, 1, 1, 1, 0 +}; +typedef union { + U64 Full; + struct { + U8 Major; /* will be 1 for the first release and + * increment thereafter */ + U8 Minor; + U16 Maintenance; + U32 Revision; /* Subversion revision */ + } Part; +} ULTRA_COMPONENT_VERSION; + +#endif /* _CONTROL_FRAMEWORK_H_ not defined */ diff --git a/drivers/staging/unisys/common-spar/include/channels/controlvmchannel.h b/drivers/staging/unisys/common-spar/include/channels/controlvmchannel.h new file mode 100644 index 0000000..47f1c4f --- /dev/null +++ b/drivers/staging/unisys/common-spar/include/channels/controlvmchannel.h @@ -0,0 +1,619 @@ +/* Copyright © 2010 - 2013 UNISYS CORPORATION + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + */ + +#ifndef __CONTROLVMCHANNEL_H__ +#define __CONTROLVMCHANNEL_H__ + +#include "commontypes.h" +#include "channel.h" +#include "controlframework.h" +enum { INVALID_GUEST_FIRMWARE, SAMPLE_GUEST_FIRMWARE, + TIANO32_GUEST_FIRMWARE, TIANO64_GUEST_FIRMWARE +}; + +/* {2B3C2D10-7EF5-4ad8-B966-3448B7386B3D} */ +#define ULTRA_CONTROLVM_CHANNEL_PROTOCOL_GUID \ + {0x2b3c2d10, 0x7ef5, 0x4ad8, \ + {0xb9, 0x66, 0x34, 0x48, 0xb7, 0x38, 0x6b, 0x3d} } + +static const GUID UltraControlvmChannelProtocolGuid = + ULTRA_CONTROLVM_CHANNEL_PROTOCOL_GUID; + +#define ULTRA_CONTROLVM_CHANNEL_PROTOCOL_SIGNATURE \ + ULTRA_CHANNEL_PROTOCOL_SIGNATURE +#define CONTROLVM_MESSAGE_MAX 64 + +/* Must increment this whenever you insert or delete fields within +* this channel struct. Also increment whenever you change the meaning +* of fields within this channel struct so as to break pre-existing +* software. Note that you can usually add fields to the END of the +* channel struct withOUT needing to increment this. */ +#define ULTRA_CONTROLVM_CHANNEL_PROTOCOL_VERSIONID 1 + +#define ULTRA_CONTROLVM_CHANNEL_OK_CLIENT(pChannel, logCtx) \ + (ULTRA_check_channel_client(pChannel, \ + UltraControlvmChannelProtocolGuid, \ + "controlvm", \ + sizeof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL), \ + ULTRA_CONTROLVM_CHANNEL_PROTOCOL_VERSIONID, \ + ULTRA_CONTROLVM_CHANNEL_PROTOCOL_SIGNATURE, \ + __FILE__, __LINE__, logCtx)) +#define ULTRA_CONTROLVM_CHANNEL_OK_SERVER(actualBytes, logCtx) \ + (ULTRA_check_channel_server(UltraControlvmChannelProtocolGuid, \ + "controlvm", \ + sizeof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL), \ + actualBytes, __FILE__, __LINE__, logCtx)) + +#define MY_DEVICE_INDEX 0 +#define MAX_MACDATA_LEN 8 /* number of bytes for MAC address in config packet */ +#define MAX_SERIAL_NUM 32 + +#define DISK_ZERO_PUN_NUMBER 1 /* Target ID on the SCSI bus for LUN 0 */ +#define DISK_ZERO_LUN_NUMBER 3 /* Logical Unit Number */ + +/* Defines for various channel queues... */ +#define CONTROLVM_QUEUE_REQUEST 0 +#define CONTROLVM_QUEUE_RESPONSE 1 +#define CONTROLVM_QUEUE_EVENT 2 +#define CONTROLVM_QUEUE_ACK 3 + +/* Max number of messages stored during IOVM creation to be reused + * after crash */ +#define CONTROLVM_CRASHMSG_MAX 2 + +/** Ids for commands that may appear in either queue of a ControlVm channel. + * + * Commands that are initiated by the command partition (CP), by an IO or + * console service partition (SP), or by a guest partition (GP)are: + * - issued on the RequestQueue queue (q #0) in the ControlVm channel + * - responded to on the ResponseQueue queue (q #1) in the ControlVm channel + * + * Events that are initiated by an IO or console service partition (SP) or + * by a guest partition (GP) are: + * - issued on the EventQueue queue (q #2) in the ControlVm channel + * - responded to on the EventAckQueue queue (q #3) in the ControlVm channel + */ +typedef enum { + CONTROLVM_INVALID = 0, + /* SWITCH commands required Parameter: SwitchNumber */ + /* BUS commands required Parameter: BusNumber */ + CONTROLVM_BUS_CREATE = 0x101, /* CP --> SP, GP */ + CONTROLVM_BUS_DESTROY = 0x102, /* CP --> SP, GP */ + CONTROLVM_BUS_CONFIGURE = 0x104, /* CP --> SP */ + CONTROLVM_BUS_CHANGESTATE = 0x105, /* CP --> SP, GP */ + CONTROLVM_BUS_CHANGESTATE_EVENT = 0x106, /* SP, GP --> CP */ +/* DEVICE commands required Parameter: BusNumber, DeviceNumber */ + + CONTROLVM_DEVICE_CREATE = 0x201, /* CP --> SP, GP */ + CONTROLVM_DEVICE_DESTROY = 0x202, /* CP --> SP, GP */ + CONTROLVM_DEVICE_CONFIGURE = 0x203, /* CP --> SP */ + CONTROLVM_DEVICE_CHANGESTATE = 0x204, /* CP --> SP, GP */ + CONTROLVM_DEVICE_CHANGESTATE_EVENT = 0x205, /* SP, GP --> CP */ + CONTROLVM_DEVICE_RECONFIGURE = 0x206, /* CP --> Boot */ +/* DISK commands required Parameter: BusNumber, DeviceNumber */ + CONTROLVM_DISK_CREATE = 0x221, /* CP --> SP */ + CONTROLVM_DISK_DESTROY = 0x222, /* CP --> SP */ + CONTROLVM_DISK_CONFIGURE = 0x223, /* CP --> SP */ + CONTROLVM_DISK_CHANGESTATE = 0x224, /* CP --> SP */ +/* CHIPSET commands */ + CONTROLVM_CHIPSET_INIT = 0x301, /* CP --> SP, GP */ + CONTROLVM_CHIPSET_STOP = 0x302, /* CP --> SP, GP */ + CONTROLVM_CHIPSET_SHUTDOWN = 0x303, /* CP --> SP */ + CONTROLVM_CHIPSET_READY = 0x304, /* CP --> SP */ + CONTROLVM_CHIPSET_SELFTEST = 0x305, /* CP --> SP */ + +} CONTROLVM_ID; + +struct InterruptInfo { + /**< specifies interrupt info. It is used to send interrupts + * for this channel. The peer at the end of this channel + * who has registered an interrupt (using recv fields + * above) will receive the interrupt. Passed as a parameter + * to Issue_VMCALL_IO_QUEUE_TRANSITION, which generates the + * interrupt. Currently this is used by IOPart-SP to wake + * up GP when Data Channel transitions from empty to + * non-empty.*/ + U64 sendInterruptHandle; + + /**< specifies interrupt handle. It is used to retrieve the + * corresponding interrupt pin from Monitor; and the + * interrupt pin is used to connect to the corresponding + * intrrupt. Used by IOPart-GP only. */ + U64 recvInterruptHandle; + + /**< specifies interrupt vector. It, interrupt pin, and shared are + * used to connect to the corresponding interrupt. Used by + * IOPart-GP only. */ + U32 recvInterruptVector; + + /**< specifies if the recvInterrupt is shared. It, interrupt pin + * and vector are used to connect to 0 = not shared; 1 = shared. + * the corresponding interrupt. Used by IOPart-GP only. */ + U8 recvInterruptShared; + U8 reserved[3]; /* Natural alignment purposes */ +}; + +struct PciId { + U16 Domain; + U8 Bus; + U8 Slot; + U8 Func; + U8 Reserved[3]; /* Natural alignment purposes */ +}; + +struct PciConfigHdr { + U16 VendorId; + U16 SubSysVendor; + U16 DeviceId; + U16 SubSysDevice; + U32 ClassCode; + U32 Reserved; /* Natural alignment purposes */ +}; + +struct ScsiId { + U32 Bus; + U32 Target; + U32 Lun; + U32 Host; /* Command should ignore this for * + * DiskArrival/RemovalEvents */ +}; + +struct WWID { + U32 wwid1; + U32 wwid2; +}; + +struct virtDiskInfo { + U32 switchNo; /* defined by SWITCH_CREATE */ + U32 externalPortNo; /* 0 for SAS RAID provided (external) + * virtual disks, 1 for virtual disk + * images, 2 for gold disk images */ + U16 VirtualDiskIndex; /* Index of disk descriptor in the + * VirtualDisk segment associated with + * externalPortNo */ + U16 Reserved1; + U32 Reserved2; +}; + +typedef enum { + CONTROLVM_ACTION_NONE = 0, + CONTROLVM_ACTION_SET_RESTORE = 0x05E7, + CONTROLVM_ACTION_CLEAR_RESTORE = 0x0C18, + CONTROLVM_ACTION_RESTORING = 0x08E5, + CONTROLVM_ACTION_RESTORE_BUSY = 0x0999, + CONTROLVM_ACTION_CLEAR_NVRAM = 0xB01 +} CONTROLVM_ACTION; + +typedef enum _ULTRA_TOOL_ACTIONS { + /* enumeration that defines intended action */ + ULTRA_TOOL_ACTION_NONE = 0, /* normal boot of boot disk */ + ULTRA_TOOL_ACTION_INSTALL = 1, /* install source disk(s) to boot + * disk */ + ULTRA_TOOL_ACTION_CAPTURE = 2, /* capture boot disk to target disk(s) + * as 'gold image' */ + ULTRA_TOOL_ACTION_REPAIR = 3, /* use source disk(s) to repair + * installation on boot disk */ + ULTRA_TOOL_ACTION_CLEAN = 4, /* 'scrub' virtual disk before + * releasing back to storage pool */ + ULTRA_TOOL_ACTION_UPGRADE = 5, /* upgrade to use content of images + * referenced from newer blueprint */ + ULTRA_TOOL_ACTION_DIAG = 6, /* use tool to invoke diagnostic script + * provided by blueprint */ + ULTRA_TOOL_ACTION_FAILED = 7, /* used when tool fails installation + and cannot continue */ + ULTRA_TOOL_ACTION_COUNT = 8 +} ULTRA_TOOL_ACTIONS; + +typedef struct _ULTRA_EFI_SPAR_INDICATION { + U64 BootToFirmwareUI:1; /* Bit 0: Stop in uefi ui */ + U64 ClearNvram:1; /* Bit 1: Clear NVRAM */ + U64 ClearCmos:1; /* Bit 2: Clear CMOS */ + U64 BootToTool:1; /* Bit 3: Run install tool */ + /* remaining bits are available */ +} ULTRA_EFI_SPAR_INDICATION; + +typedef enum { + ULTRA_CHIPSET_FEATURE_REPLY = 0x00000001, + ULTRA_CHIPSET_FEATURE_PARA_HOTPLUG = 0x00000002, + ULTRA_CHIPSET_FEATURE_PCIVBUS = 0x00000004 +} ULTRA_CHIPSET_FEATURE; + +/** This is the common structure that is at the beginning of every + * ControlVm message (both commands and responses) in any ControlVm + * queue. Commands are easily distinguished from responses by + * looking at the flags.response field. + */ +typedef struct _CONTROLVM_MESSAGE_HEADER { + U32 Id; /* See CONTROLVM_ID. */ + /* For requests, indicates the message type. */ + /* For responses, indicates the type of message we are responding to. */ + + U32 MessageSize; /* Includes size of this struct + size + * of message */ + U32 SegmentIndex; /* Index of segment containing Vm + * message/information */ + U32 CompletionStatus; /* Error status code or result of + * message completion */ + struct { + U32 failed:1; /**< =1 in a response to * signify + * failure */ + U32 responseExpected:1; /**< =1 in all messages that expect a + * response (Control ignores this + * bit) */ + U32 server:1; /**< =1 in all bus & device-related + * messages where the message + * receiver is to act as the bus or + * device server */ + U32 testMessage:1; /**< =1 for testing use only + * (Control and Command ignore this + * bit) */ + U32 partialCompletion:1; /**< =1 if there are forthcoming + * responses/acks associated + * with this message */ + U32 preserve:1; /**< =1 this is to let us know to + * preserve channel contents + * (for running guests)*/ + U32 writerInDiag:1; /**< =1 the DiagWriter is active in the + * Diagnostic Partition*/ + + /* remaining bits in this 32-bit word are available */ + } Flags; + U32 Reserved; /* Natural alignment */ + U64 MessageHandle; /* Identifies the particular message instance, + * and is used to match particular */ + /* request instances with the corresponding response instance. */ + U64 PayloadVmOffset; /* Offset of payload area from start of this + * instance of ControlVm segment */ + U32 PayloadMaxBytes; /* Maximum bytes allocated in payload + * area of ControlVm segment */ + U32 PayloadBytes; /* Actual number of bytes of payload + * area to copy between IO/Command; */ + /* if non-zero, there is a payload to copy. */ +} CONTROLVM_MESSAGE_HEADER; + +typedef struct _CONTROLVM_PACKET_DEVICE_CREATE { + U32 busNo; /**< bus # (0..n-1) from the msg receiver's + * perspective */ + + /* Control uses header SegmentIndex field to access bus number... */ + U32 devNo; /**< bus-relative (0..n-1) device number */ + U64 channelAddr; /**< Guest physical address of the channel, which + * can be dereferenced by the receiver + * of this ControlVm command */ + U64 channelBytes; /**< specifies size of the channel in bytes */ + GUID dataTypeGuid;/**< specifies format of data in channel */ + GUID devInstGuid; /**< instance guid for the device */ + struct InterruptInfo intr; /**< specifies interrupt information */ +} CONTROLVM_PACKET_DEVICE_CREATE; /* for CONTROLVM_DEVICE_CREATE */ + +typedef struct _CONTROLVM_PACKET_DEVICE_CONFIGURE { + U32 busNo; /**< bus # (0..n-1) from the msg + * receiver's perspective */ + + /* Control uses header SegmentIndex field to access bus number... */ + U32 devNo; /**< bus-relative (0..n-1) device number */ +} CONTROLVM_PACKET_DEVICE_CONFIGURE; /* for CONTROLVM_DEVICE_CONFIGURE */ + +typedef struct _CONTROLVM_MESSAGE_DEVICE_CREATE { + CONTROLVM_MESSAGE_HEADER Header; + CONTROLVM_PACKET_DEVICE_CREATE Packet; +} CONTROLVM_MESSAGE_DEVICE_CREATE; /* total 128 bytes */ + +typedef struct _CONTROLVM_MESSAGE_DEVICE_CONFIGURE { + CONTROLVM_MESSAGE_HEADER Header; + CONTROLVM_PACKET_DEVICE_CONFIGURE Packet; +} CONTROLVM_MESSAGE_DEVICE_CONFIGURE; /* total 56 bytes */ + +/* This is the format for a message in any ControlVm queue. */ +typedef struct _CONTROLVM_MESSAGE_PACKET { + union { + + /* BEGIN Request messages */ + struct { + U32 busNo; /*< bus # (0..n-1) from the msg + * receiver's perspective */ + + /* Control uses header SegmentIndex field to access bus number... */ + U32 deviceCount; /*< indicates the max number of + * devices on this bus */ + U64 channelAddr; /*< Guest physical address of the + * channel, which can be + * dereferenced by the receiver + * of this ControlVm command */ + U64 channelBytes; /*< size of the channel in bytes */ + GUID busDataTypeGuid;/*< indicates format of data in bus + * channel */ + GUID busInstGuid; /*< instance guid for the bus */ + } createBus; /* for CONTROLVM_BUS_CREATE */ + struct { + U32 busNo; /*< bus # (0..n-1) from the msg + * receiver's perspective */ + + /* Control uses header SegmentIndex field to access bus number... */ + U32 reserved; /* Natural alignment purposes */ + } destroyBus; /* for CONTROLVM_BUS_DESTROY */ + struct { + U32 busNo; /*< bus # (0..n-1) from the + * msg receiver's + * perspective */ + + /* Control uses header SegmentIndex field to access bus number... */ + U32 reserved1; /* for alignment purposes */ + U64 guestHandle; /* This is used to convert + * guest physical address to real + * physical address for DMA, for ex. */ + U64 recvBusInterruptHandle;/*< specifies interrupt + * info. It is used by SP to register + * to receive interrupts from the CP. + * This interrupt is used for bus + * level notifications. The + * corresponding + * sendBusInterruptHandle is kept in + * CP. */ + } configureBus; /* for CONTROLVM_BUS_CONFIGURE */ + + /* for CONTROLVM_DEVICE_CREATE */ + CONTROLVM_PACKET_DEVICE_CREATE createDevice; + struct { + U32 busNo; /*< bus # (0..n-1) from the msg + * receiver's perspective */ + + /* Control uses header SegmentIndex field to access bus number... */ + U32 devNo; /*< bus-relative (0..n-1) device + * number */ + } destroyDevice; /* for CONTROLVM_DEVICE_DESTROY */ + + /* for CONTROLVM_DEVICE_CONFIGURE */ + CONTROLVM_PACKET_DEVICE_CONFIGURE configureDevice; + struct { + U32 busNo; /*< bus # (0..n-1) from the msg + * receiver's perspective */ + + /* Control uses header SegmentIndex field to access bus number... */ + U32 devNo; /*< bus-relative (0..n-1) device + * number */ + } reconfigureDevice; /* for CONTROLVM_DEVICE_RECONFIGURE */ + struct { + U32 busNo; + ULTRA_SEGMENT_STATE state; + U8 reserved[2]; /* Natural alignment purposes */ + } busChangeState; /* for CONTROLVM_BUS_CHANGESTATE */ + struct { + U32 busNo; + U32 devNo; + ULTRA_SEGMENT_STATE state; + struct { + U32 physicalDevice:1; /* =1 if message is for + * a physical device */ + /* remaining bits in this 32-bit word are available */ + } flags; + U8 reserved[2]; /* Natural alignment purposes */ + } deviceChangeState; /* for CONTROLVM_DEVICE_CHANGESTATE */ + struct { + U32 busNo; + U32 devNo; + ULTRA_SEGMENT_STATE state; + U8 reserved[6]; /* Natural alignment purposes */ + } deviceChangeStateEvent; /* for CONTROLVM_DEVICE_CHANGESTATE_EVENT */ + struct { + U32 busCount; /*< indicates the max number of busses */ + U32 switchCount; /*< indicates the max number of + * switches (applicable for service + * partition only) */ + ULTRA_CHIPSET_FEATURE features; + U32 platformNumber; /* Platform Number */ + } initChipset; /* for CONTROLVM_CHIPSET_INIT */ + struct { + U32 Options; /*< reserved */ + U32 Test; /*< bit 0 set to run embedded selftest */ + } chipsetSelftest; /* for CONTROLVM_CHIPSET_SELFTEST */ + + /* END Request messages */ + + /* BEGIN Response messages */ + + /* END Response messages */ + + /* BEGIN Event messages */ + + /* END Event messages */ + + /* BEGIN Ack messages */ + + /* END Ack messages */ + U64 addr; /*< a physical address of something, that + * can be dereferenced by the receiver of + * this ControlVm command (depends on + * command id) */ + U64 handle; /*< a handle of something (depends on + * command id) */ + }; +} CONTROLVM_MESSAGE_PACKET; + +/* All messages in any ControlVm queue have this layout. */ +typedef struct _CONTROLVM_MESSAGE { + CONTROLVM_MESSAGE_HEADER hdr; + CONTROLVM_MESSAGE_PACKET cmd; +} CONTROLVM_MESSAGE; + +typedef struct _DEVICE_MAP { + GUEST_PHYSICAL_ADDRESS DeviceChannelAddress; + U64 DeviceChannelSize; + U32 CA_Index; + U32 Reserved; /* natural alignment */ + U64 Reserved2; /* Align structure on 32-byte boundary */ +} DEVICE_MAP; + +typedef struct _GUEST_DEVICES { + DEVICE_MAP VideoChannel; + DEVICE_MAP KeyboardChannel; + DEVICE_MAP NetworkChannel; + DEVICE_MAP StorageChannel; + DEVICE_MAP ConsoleChannel; + U32 PartitionIndex; + U32 Pad; +} GUEST_DEVICES; + +typedef struct _ULTRA_CONTROLVM_CHANNEL_PROTOCOL { + CHANNEL_HEADER Header; + GUEST_PHYSICAL_ADDRESS gpControlVm; /* guest physical address of + * this channel */ + GUEST_PHYSICAL_ADDRESS gpPartitionTables; /* guest physical address of + * partition tables */ + GUEST_PHYSICAL_ADDRESS gpDiagGuest; /* guest physical address of + * diagnostic channel */ + GUEST_PHYSICAL_ADDRESS gpBootRomDisk; /* guest phys addr of (read + * only) Boot ROM disk */ + GUEST_PHYSICAL_ADDRESS gpBootRamDisk; /* guest phys addr of writable + * Boot RAM disk */ + GUEST_PHYSICAL_ADDRESS gpAcpiTable; /* guest phys addr of acpi + * table */ + GUEST_PHYSICAL_ADDRESS gpControlChannel; /* guest phys addr of control + * channel */ + GUEST_PHYSICAL_ADDRESS gpDiagRomDisk; /* guest phys addr of diagnostic + * ROM disk */ + GUEST_PHYSICAL_ADDRESS gpNvram; /* guest phys addr of NVRAM + * channel */ + U64 RequestPayloadOffset; /* Offset to request payload area */ + U64 EventPayloadOffset; /* Offset to event payload area */ + U32 RequestPayloadBytes; /* Bytes available in request payload + * area */ + U32 EventPayloadBytes; /* Bytes available in event payload area */ + U32 ControlChannelBytes; + U32 NvramChannelBytes; /* Bytes in PartitionNvram segment */ + U32 MessageBytes; /* sizeof(CONTROLVM_MESSAGE) */ + U32 MessageCount; /* CONTROLVM_MESSAGE_MAX */ + GUEST_PHYSICAL_ADDRESS gpSmbiosTable; /* guest phys addr of SMBIOS + * tables */ + GUEST_PHYSICAL_ADDRESS gpPhysicalSmbiosTable; /* guest phys addr of + * SMBIOS table */ + /* ULTRA_MAX_GUESTS_PER_SERVICE */ + GUEST_DEVICES gpObsoleteGuestDevices[16]; + + /* guest physical address of EFI firmware image base */ + GUEST_PHYSICAL_ADDRESS VirtualGuestFirmwareImageBase; + + /* guest physical address of EFI firmware entry point */ + GUEST_PHYSICAL_ADDRESS VirtualGuestFirmwareEntryPoint; + + /* guest EFI firmware image size */ + U64 VirtualGuestFirmwareImageSize; + + /* GPA = 1MB where EFI firmware image is copied to */ + GUEST_PHYSICAL_ADDRESS VirtualGuestFirmwareBootBase; + GUEST_PHYSICAL_ADDRESS VirtualGuestImageBase; + GUEST_PHYSICAL_ADDRESS VirtualGuestImageSize; + U64 PrototypeControlChannelOffset; + GUEST_PHYSICAL_ADDRESS VirtualGuestPartitionHandle; + + U16 RestoreAction; /* Restore Action field to restore the guest + * partition */ + U16 DumpAction; /* For Windows guests it shows if the visordisk + * is running in dump mode */ + U16 NvramFailCount; + U16 SavedCrashMsgCount; /* = CONTROLVM_CRASHMSG_MAX */ + U32 SavedCrashMsgOffset; /* Offset to request payload area needed + * for crash dump */ + U32 InstallationError; /* Type of error encountered during + * installation */ + U32 InstallationTextId; /* Id of string to display */ + U16 InstallationRemainingSteps; /* Number of remaining installation + * steps (for progress bars) */ + U8 ToolAction; /* ULTRA_TOOL_ACTIONS Installation Action + * field */ + U8 Reserved; /* alignment */ + ULTRA_EFI_SPAR_INDICATION EfiSparIndication; + ULTRA_EFI_SPAR_INDICATION EfiSparIndicationSupported; + U32 SPReserved; + U8 Reserved2[28]; /* Force signals to begin on 128-byte cache + * line */ + SIGNAL_QUEUE_HEADER RequestQueue; /* Service or guest partition + * uses this queue to send + * requests to Control */ + SIGNAL_QUEUE_HEADER ResponseQueue; /* Control uses this queue to + * respond to service or guest + * partition requests */ + SIGNAL_QUEUE_HEADER EventQueue; /* Control uses this queue to + * send events to service or + * guest partition */ + SIGNAL_QUEUE_HEADER EventAckQueue; /* Service or guest partition + * uses this queue to ack + * Control events */ + + /* Request fixed-size message pool - does not include payload */ + CONTROLVM_MESSAGE RequestMsg[CONTROLVM_MESSAGE_MAX]; + + /* Response fixed-size message pool - does not include payload */ + CONTROLVM_MESSAGE ResponseMsg[CONTROLVM_MESSAGE_MAX]; + + /* Event fixed-size message pool - does not include payload */ + CONTROLVM_MESSAGE EventMsg[CONTROLVM_MESSAGE_MAX]; + + /* Ack fixed-size message pool - does not include payload */ + CONTROLVM_MESSAGE EventAckMsg[CONTROLVM_MESSAGE_MAX]; + + /* Message stored during IOVM creation to be reused after crash */ + CONTROLVM_MESSAGE SavedCrashMsg[CONTROLVM_CRASHMSG_MAX]; +} ULTRA_CONTROLVM_CHANNEL_PROTOCOL; + +/* Offsets for VM channel attributes... */ +#define VM_CH_REQ_QUEUE_OFFSET \ + offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, RequestQueue) +#define VM_CH_RESP_QUEUE_OFFSET \ + offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, ResponseQueue) +#define VM_CH_EVENT_QUEUE_OFFSET \ + offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, EventQueue) +#define VM_CH_ACK_QUEUE_OFFSET \ + offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, EventAckQueue) +#define VM_CH_REQ_MSG_OFFSET \ + offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, RequestMsg) +#define VM_CH_RESP_MSG_OFFSET \ + offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, ResponseMsg) +#define VM_CH_EVENT_MSG_OFFSET \ + offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, EventMsg) +#define VM_CH_ACK_MSG_OFFSET \ + offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, EventAckMsg) +#define VM_CH_CRASH_MSG_OFFSET \ + offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, SavedCrashMsg) + +/* The following header will be located at the beginning of PayloadVmOffset for + * various ControlVm commands. The receiver of a ControlVm command with a + * PayloadVmOffset will dereference this address and then use ConnectionOffset, + * InitiatorOffset, and TargetOffset to get the location of UTF-8 formatted + * strings that can be parsed to obtain command-specific information. The value + * of TotalLength should equal PayloadBytes. The format of the strings at + * PayloadVmOffset will take different forms depending on the message. See the + * following Wiki page for more information: + * https://ustr-linux-1.na.uis.unisys.com/spar/index.php/ControlVm_Parameters_Area + */ +typedef struct _ULTRA_CONTROLVM_PARAMETERS_HEADER { + U32 TotalLength; + U32 HeaderLength; + U32 ConnectionOffset; + U32 ConnectionLength; + U32 InitiatorOffset; + U32 InitiatorLength; + U32 TargetOffset; + U32 TargetLength; + U32 ClientOffset; + U32 ClientLength; + U32 NameOffset; + U32 NameLength; + GUID Id; + U32 Revision; + U32 Reserved; /* Natural alignment */ +} ULTRA_CONTROLVM_PARAMETERS_HEADER; + +#endif /* __CONTROLVMCHANNEL_H__ */ diff --git a/drivers/staging/unisys/common-spar/include/channels/diagchannel.h b/drivers/staging/unisys/common-spar/include/channels/diagchannel.h new file mode 100644 index 0000000..c93515e --- /dev/null +++ b/drivers/staging/unisys/common-spar/include/channels/diagchannel.h @@ -0,0 +1,427 @@ +/* Copyright © 2010 - 2013 UNISYS CORPORATION + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + */ + +/*++ + * + * Module Name: + * + * diagchannel.h + * + * Abstract: + * + * This file defines the DiagChannel protocol. This protocol is used to aid in + * preserving event data sent by external applications. This protocol provides + * a region for event data to reside in. This data will eventually be sent to + * the Boot Partition where it will be committed to memory and/or disk. This + * file contains platform-independent data that can be built using any + * Supervisor build environment (Windows, Linux, EFI). + * +*/ + +#ifndef _DIAG_CHANNEL_H_ +#define _DIAG_CHANNEL_H_ + +#include "commontypes.h" +#include "channel.h" + +/* {EEA7A573-DB82-447c-8716-EFBEAAAE4858} */ +#define ULTRA_DIAG_CHANNEL_PROTOCOL_GUID \ + {0xeea7a573, 0xdb82, 0x447c, \ + {0x87, 0x16, 0xef, 0xbe, 0xaa, 0xae, 0x48, 0x58} } + +static const GUID UltraDiagChannelProtocolGuid = + ULTRA_DIAG_CHANNEL_PROTOCOL_GUID; + +/* {E850F968-3263-4484-8CA5-2A35D087A5A8} */ +#define ULTRA_DIAG_ROOT_CHANNEL_PROTOCOL_GUID \ + {0xe850f968, 0x3263, 0x4484, \ + {0x8c, 0xa5, 0x2a, 0x35, 0xd0, 0x87, 0xa5, 0xa8} } + +#define ULTRA_DIAG_CHANNEL_PROTOCOL_SIGNATURE ULTRA_CHANNEL_PROTOCOL_SIGNATURE + +/* Must increment this whenever you insert or delete fields within this channel +* struct. Also increment whenever you change the meaning of fields within this +* channel struct so as to break pre-existing software. Note that you can +* usually add fields to the END of the channel struct withOUT needing to +* increment this. */ +#define ULTRA_DIAG_CHANNEL_PROTOCOL_VERSIONID 2 + +#define ULTRA_DIAG_CHANNEL_OK_CLIENT(pChannel, logCtx) \ + (ULTRA_check_channel_client(pChannel, \ + UltraDiagChannelProtocolGuid, \ + "diag", \ + sizeof(ULTRA_DIAG_CHANNEL_PROTOCOL), \ + ULTRA_DIAG_CHANNEL_PROTOCOL_VERSIONID, \ + ULTRA_DIAG_CHANNEL_PROTOCOL_SIGNATURE, \ + __FILE__, __LINE__, logCtx)) +#define ULTRA_DIAG_CHANNEL_OK_SERVER(actualBytes, logCtx) \ + (ULTRA_check_channel_server(UltraDiagChannelProtocolGuid, \ + "diag", \ + sizeof(ULTRA_DIAG_CHANNEL_PROTOCOL), \ + actualBytes, __FILE__, __LINE__, logCtx)) +#define MAX_MODULE_NAME_SIZE 128 /* Maximum length of module name... */ +#define MAX_ADDITIONAL_INFO_SIZE 256 /* Maximum length of any additional info + * accompanying event... */ +#define MAX_SUBSYSTEMS 64 /* Maximum number of subsystems allowed in + * DiagChannel... */ +#define LOW_SUBSYSTEMS 32 /* Half of MAX_SUBSYSTEMS to allow 64-bit + * math */ +#define SUBSYSTEM_DEBUG 0 /* Standard subsystem for debug events */ +#define SUBSYSTEM_DEFAULT 1 /* Default subsystem for legacy calls to + * ReportEvent */ + +/* few useful subsystem mask values */ +#define SUBSYSTEM_MASK_DEBUG 0x01 /* Standard subsystem for debug + * events */ +#define SUBSYSTEM_MASK_DEFAULT 0x02 /* Default subsystem for legacy calls to + * ReportEvents */ + +/* Event parameter "Severity" is overloaded with Cause in byte 2 and Severity in + * byte 0, bytes 1 and 3 are reserved */ +#define SEVERITY_MASK 0x0FF /* mask out all but the Severity in byte 0 */ +#define CAUSE_MASK 0x0FF0000 /* mask out all but the cause in byte 2 */ +#define CAUSE_SHIFT_AMT 16 /* shift 2 bytes to place it in byte 2 */ + +/* SubsystemSeverityFilter */ +#define SEVERITY_FILTER_MASK 0x0F /* mask out the Cause half, SeverityFilter is + * in the lower nibble */ +#define CAUSE_FILTER_MASK 0xF0 /* mask out the Severity half, CauseFilter is in + * the upper nibble */ +#define CAUSE_FILTER_SHIFT_AMT 4 /* shift amount to place it in lower or upper + * nibble */ + +/* Copied from EFI's EFI_TIME struct in efidef.h. EFI headers are not allowed +* in some of the Supervisor areas, such as Monitor, so it has been "ported" here +* for use in diagnostic event timestamps... */ +typedef struct _DIAG_EFI_TIME { + U16 Year; /* 1998 - 20XX */ + U8 Month; /* 1 - 12 */ + U8 Day; /* 1 - 31 */ + U8 Hour; /* 0 - 23 */ + U8 Minute; /* 0 - 59 */ + U8 Second; /* 0 - 59 */ + U8 Pad1; + U32 Nanosecond; /* 0 - 999, 999, 999 */ + S16 TimeZone; /* -1440 to 1440 or 2047 */ + U8 Daylight; + U8 Pad2; +} DIAG_EFI_TIME; + +typedef enum { + ULTRA_COMPONENT_GUEST = 0, + ULTRA_COMPONENT_MONITOR = 0x01, + ULTRA_COMPONENT_CCM = 0x02, /* Common Control module */ + /* RESERVED 0x03 - 0x7 */ + + /* Ultravisor Components */ + ULTRA_COMPONENT_BOOT = 0x08, + ULTRA_COMPONENT_IDLE = 0x09, + ULTRA_COMPONENT_CONTROL = 0x0A, + ULTRA_COMPONENT_LOGGER = 0x0B, + ULTRA_COMPONENT_ACPI = 0X0C, + /* RESERVED 0x0D - 0x0F */ + + /* sPAR Components */ + ULTRA_COMPONENT_COMMAND = 0x10, + ULTRA_COMPONENT_IODRIVER = 0x11, + ULTRA_COMPONENT_CONSOLE = 0x12, + ULTRA_COMPONENT_OPERATIONS = 0x13, + ULTRA_COMPONENT_MANAGEMENT = 0x14, + ULTRA_COMPONENT_DIAG = 0x15, + ULTRA_COMPONENT_HWDIAG = 0x16, + ULTRA_COMPONENT_PSERVICES = 0x17, + ULTRA_COMPONENT_PDIAG = 0x18 + /* RESERVED 0x18 - 0x1F */ +} ULTRA_COMPONENT_TYPES; + +/* Structure: DIAG_CHANNEL_EVENT Purpose: Contains attributes that make up an + * event to be written to the DIAG_CHANNEL memory. Attributes: EventId: Id of + * the diagnostic event to write to memory. Severity: Severity of the event + * (Error, Info, etc). ModuleName: Module/file name where event originated. + * LineNumber: Line number in module name where event originated. Timestamp: + * Date/time when event was received by ReportEvent, and written to DiagChannel. + * Reserved: Padding to align structure on a 64-byte cache line boundary. + * AdditionalInfo: Array of characters for additional event info (may be + * empty). */ +typedef struct _DIAG_CHANNEL_EVENT { + U32 EventId; + U32 Severity; + U8 ModuleName[MAX_MODULE_NAME_SIZE]; + U32 LineNumber; + DIAG_EFI_TIME Timestamp; /* Size = 16 bytes */ + U32 PartitionNumber; /* Filled in by Diag Switch as pool blocks are + * filled */ + U16 VirtualProcessorNumber; + U16 LogicalProcessorNumber; + U8 ComponentType; /* ULTRA_COMPONENT_TYPES */ + U8 Subsystem; + U16 Reserved0; /* pad to U64 alignment */ + U32 BlockNumber; /* filled in by DiagSwitch as pool blocks are + * filled */ + U32 BlockNumberHigh; + U32 EventNumber; /* filled in by DiagSwitch as pool blocks are + * filled */ + U32 EventNumberHigh; + + /* The BlockNumber and EventNumber fields are set only by DiagSwitch + * and referenced only by WinDiagDisplay formatting tool as + * additional diagnostic information. Other tools including + * WinDiagDisplay currently ignore these 'Reserved' bytes. */ + U8 Reserved[8]; + U8 AdditionalInfo[MAX_ADDITIONAL_INFO_SIZE]; + + /* NOTE: Changesto DIAG_CHANNEL_EVENT generally need to be reflected in + * existing copies * + * - for AppOS at + * GuestLinux/visordiag_early/supervisor_diagchannel.h * + * - for WinDiagDisplay at + * EFI/Ultra/Tools/WinDiagDisplay/WinDiagDisplay/diagstruct.h */ +} DIAG_CHANNEL_EVENT; + +/* Levels of severity for diagnostic events, in order from lowest severity to +* highest (i.e. fatal errors are the most severe, and should always be logged, +* but info events rarely need to be logged except during debugging). The values +* DIAG_SEVERITY_ENUM_BEGIN and DIAG_SEVERITY_ENUM_END are not valid severity +* values. They exist merely to dilineate the list, so that future additions +* won't require changes to the driver (i.e. when checking for out-of-range +* severities in SetSeverity). The values DIAG_SEVERITY_OVERRIDE and +* DIAG_SEVERITY_SHUTOFF are not valid severity values for logging events but +* they are valid for controlling the amount of event data. This enum is also +* defined in DotNet\sParFramework\ControlFramework\ControlFramework.cs. If a +* change is made to this enum, they should also be reflected in that file. */ +typedef enum { DIAG_SEVERITY_ENUM_BEGIN = 0, + DIAG_SEVERITY_OVERRIDE = DIAG_SEVERITY_ENUM_BEGIN, + DIAG_SEVERITY_VERBOSE = DIAG_SEVERITY_OVERRIDE, /* 0 */ + DIAG_SEVERITY_INFO = DIAG_SEVERITY_VERBOSE + 1, /* 1 */ + DIAG_SEVERITY_WARNING = DIAG_SEVERITY_INFO + 1, /* 2 */ + DIAG_SEVERITY_ERR = DIAG_SEVERITY_WARNING + 1, /* 3 */ + DIAG_SEVERITY_PRINT = DIAG_SEVERITY_ERR + 1, /* 4 */ + DIAG_SEVERITY_SHUTOFF = DIAG_SEVERITY_PRINT + 1, /* 5 */ + DIAG_SEVERITY_ENUM_END = DIAG_SEVERITY_SHUTOFF, /* 5 */ + DIAG_SEVERITY_NONFATAL_ERR = DIAG_SEVERITY_ERR, + DIAG_SEVERITY_FATAL_ERR = DIAG_SEVERITY_PRINT +} DIAG_SEVERITY; + +/* Event Cause enums +* +* Levels of cause for diagnostic events, in order from least to greatest cause +* Internal errors are most urgent since ideally they should never exist +* Invalid requests are preventable by avoiding invalid inputs +* Operations errors depend on environmental factors which may impact which +* requests are possible +* Manifest provides intermediate value to capture firmware and configuration +* version information +* Trace provides suplimental debug information in release firmware +* Unknown Log captures unclasified LogEvent calls. +* Debug is the least urgent since it provides suplimental debug information only +* in debug firmware +* Unknown Debug captures unclassified DebugEvent calls. +* This enum is also defined in +* DotNet\sParFramework\ControlFramework\ControlFramework.cs. +* If a change is made to this enum, they should also be reflected in that +* file. */ + + + +/* A cause value "DIAG_CAUSE_FILE_XFER" together with a severity value of +* "DIAG_SEVERITY_PRINT" (=4), is used for transferring text or binary file to +* the Diag partition. This cause-severity combination will be used by Logger +* DiagSwitch to segregate events into block types. The files are transferred in +* 256 byte chunks maximum, in the AdditionalInfo field of the DIAG_CHANNEL_EVENT +* structure. In the file transfer mode, some event fields will have different +* meaning: EventId specifies the file offset, severity specifies the block type, +* ModuleName specifies the filename, LineNumber specifies the number of valid +* data bytes in an event and AdditionalInfo contains up to 256 bytes of data. */ + +/* The Diag DiagWriter appends event blocks to events.raw as today, and for data + * blocks uses DIAG_CHANNEL_EVENT + * PartitionNumber to extract and append 'AdditionalInfo' to filename (specified + * by ModuleName). */ + +/* The Dell PDiag uses this new mechanism to stash DSET .zip onto the + * 'diagnostic' virtual disk. */ +typedef enum { + DIAG_CAUSE_UNKNOWN = 0, + DIAG_CAUSE_UNKNOWN_DEBUG = DIAG_CAUSE_UNKNOWN + 1, /* 1 */ + DIAG_CAUSE_DEBUG = DIAG_CAUSE_UNKNOWN_DEBUG + 1, /* 2 */ + DIAG_CAUSE_UNKNOWN_LOG = DIAG_CAUSE_DEBUG + 1, /* 3 */ + DIAG_CAUSE_TRACE = DIAG_CAUSE_UNKNOWN_LOG + 1, /* 4 */ + DIAG_CAUSE_MANIFEST = DIAG_CAUSE_TRACE + 1, /* 5 */ + DIAG_CAUSE_OPERATIONS_ERROR = DIAG_CAUSE_MANIFEST + 1, /* 6 */ + DIAG_CAUSE_INVALID_REQUEST = DIAG_CAUSE_OPERATIONS_ERROR + 1, /* 7 */ + DIAG_CAUSE_INTERNAL_ERROR = DIAG_CAUSE_INVALID_REQUEST + 1, /* 8 */ + DIAG_CAUSE_FILE_XFER = DIAG_CAUSE_INTERNAL_ERROR + 1, /* 9 */ + DIAG_CAUSE_ENUM_END = DIAG_CAUSE_FILE_XFER /* 9 */ +} DIAG_CAUSE; + +/* Event Cause category defined into the byte 2 of Severity */ +#define CAUSE_DEBUG (DIAG_CAUSE_DEBUG << CAUSE_SHIFT_AMT) +#define CAUSE_TRACE (DIAG_CAUSE_TRACE << CAUSE_SHIFT_AMT) +#define CAUSE_MANIFEST (DIAG_CAUSE_MANIFEST << CAUSE_SHIFT_AMT) +#define CAUSE_OPERATIONS_ERROR (DIAG_CAUSE_OPERATIONS_ERROR << CAUSE_SHIFT_AMT) +#define CAUSE_INVALID_REQUEST (DIAG_CAUSE_INVALID_REQUEST << CAUSE_SHIFT_AMT) +#define CAUSE_INTERNAL_ERROR (DIAG_CAUSE_INTERNAL_ERROR << CAUSE_SHIFT_AMT) +#define CAUSE_FILE_XFER (DIAG_CAUSE_FILE_XFER << CAUSE_SHIFT_AMT) +#define CAUSE_ENUM_END CAUSE_FILE_XFER + +/* Combine Cause and Severity categories into one */ +#define CAUSE_DEBUG_SEVERITY_VERBOSE \ + (CAUSE_DEBUG | DIAG_SEVERITY_VERBOSE) +#define CAUSE_TRACE_SEVERITY_VERBOSE \ + (CAUSE_TRACE | DIAG_SEVERITY_VERBOSE) +#define CAUSE_MANIFEST_SEVERITY_VERBOSE\ + (CAUSE_MANIFEST | DIAG_SEVERITY_VERBOSE) +#define CAUSE_OPERATIONS_SEVERITY_VERBOSE \ + (CAUSE_OPERATIONS_ERROR | DIAG_SEVERITY_VERBOSE) +#define CAUSE_INVALID_SEVERITY_VERBOSE \ + (CAUSE_INVALID_REQUEST | DIAG_SEVERITY_VERBOSE) +#define CAUSE_INTERNAL_SEVERITY_VERBOSE \ + (CAUSE_INTERNAL_ERROR | DIAG_SEVERITY_VERBOSE) + +#define CAUSE_DEBUG_SEVERITY_INFO \ + (CAUSE_DEBUG | DIAG_SEVERITY_INFO) +#define CAUSE_TRACE_SEVERITY_INFO \ + (CAUSE_TRACE | DIAG_SEVERITY_INFO) +#define CAUSE_MANIFEST_SEVERITY_INFO \ + (CAUSE_MANIFEST | DIAG_SEVERITY_INFO) +#define CAUSE_OPERATIONS_SEVERITY_INFO \ + (CAUSE_OPERATIONS_ERROR | DIAG_SEVERITY_INFO) +#define CAUSE_INVALID_SEVERITY_INFO \ + (CAUSE_INVALID_REQUEST | DIAG_SEVERITY_INFO) +#define CAUSE_INTERNAL_SEVERITY_INFO \ + (CAUSE_INTERNAL_ERROR | DIAG_SEVERITY_INFO) + +#define CAUSE_DEBUG_SEVERITY_WARN \ + (CAUSE_DEBUG | DIAG_SEVERITY_WARNING) +#define CAUSE_TRACE_SEVERITY_WARN \ + (CAUSE_TRACE | DIAG_SEVERITY_WARNING) +#define CAUSE_MANIFEST_SEVERITY_WARN \ + (CAUSE_MANIFEST | DIAG_SEVERITY_WARNING) +#define CAUSE_OPERATIONS_SEVERITY_WARN \ + (CAUSE_OPERATIONS_ERROR | DIAG_SEVERITY_WARNING) +#define CAUSE_INVALID_SEVERITY_WARN \ + (CAUSE_INVALID_REQUEST | DIAG_SEVERITY_WARNING) +#define CAUSE_INTERNAL_SEVERITY_WARN \ + (CAUSE_INTERNAL_ERROR | DIAG_SEVERITY_WARNING) + +#define CAUSE_DEBUG_SEVERITY_ERR \ + (CAUSE_DEBUG | DIAG_SEVERITY_ERR) +#define CAUSE_TRACE_SEVERITY_ERR \ + (CAUSE_TRACE | DIAG_SEVERITY_ERR) +#define CAUSE_MANIFEST_SEVERITY_ERR \ + (CAUSE_MANIFEST | DIAG_SEVERITY_ERR) +#define CAUSE_OPERATIONS_SEVERITY_ERR \ + (CAUSE_OPERATIONS_ERROR | DIAG_SEVERITY_ERR) +#define CAUSE_INVALID_SEVERITY_ERR \ + (CAUSE_INVALID_REQUEST | DIAG_SEVERITY_ERR) +#define CAUSE_INTERNAL_SEVERITY_ERR \ + (CAUSE_INTERNAL_ERROR | DIAG_SEVERITY_ERR) + +#define CAUSE_DEBUG_SEVERITY_PRINT \ + (CAUSE_DEBUG | DIAG_SEVERITY_PRINT) +#define CAUSE_TRACE_SEVERITY_PRINT \ + (CAUSE_TRACE | DIAG_SEVERITY_PRINT) +#define CAUSE_MANIFEST_SEVERITY_PRINT \ + (CAUSE_MANIFEST | DIAG_SEVERITY_PRINT) +#define CAUSE_OPERATIONS_SEVERITY_PRINT \ + (CAUSE_OPERATIONS_ERROR | DIAG_SEVERITY_PRINT) +#define CAUSE_INVALID_SEVERITY_PRINT \ + (CAUSE_INVALID_REQUEST | DIAG_SEVERITY_PRINT) +#define CAUSE_INTERNAL_SEVERITY_PRINT \ + (CAUSE_INTERNAL_ERROR | DIAG_SEVERITY_PRINT) +#define CAUSE_FILE_XFER_SEVERITY_PRINT \ + (CAUSE_FILE_XFER | DIAG_SEVERITY_PRINT) + +/* Structure: DIAG_CHANNEL_PROTOCOL_HEADER + * + * Purpose: Contains attributes that make up the header specific to the + * DIAG_CHANNEL area. + * + * Attributes: + * + * DiagLock: Diag Channel spinlock. + * + *IsChannelInitialized: 1 iff SignalInit was called for this channel; otherwise + * 0, and assume the channel is not ready for use yet. + * + * Reserved: Padding to allign the fields in this structure. + * + *SubsystemSeverityFilter: Level of severity on a subsystem basis that controls + * whether events are logged. Any event's severity for a + * particular subsystem below this level will be discarded. + */ +typedef struct _DIAG_CHANNEL_PROTOCOL_HEADER { + volatile U32 DiagLock; + U8 IsChannelInitialized; + U8 Reserved[3]; + U8 SubsystemSeverityFilter[64]; +} DIAG_CHANNEL_PROTOCOL_HEADER; + +/* The Diagram for the Diagnostic Channel: */ +/* ----------------------- */ +/* | Channel Header | Defined by ULTRA_CHANNEL_PROTOCOL */ +/* ----------------------- */ +/* | Signal Queue Header | Defined by SIGNAL_QUEUE_HEADER */ +/* ----------------------- */ +/* | DiagChannel Header | Defined by DIAG_CHANNEL_PROTOCOL_HEADER */ +/* ----------------------- */ +/* | Channel Event Info | Defined by (DIAG_CHANNEL_EVENT * MAX_EVENTS) */ +/* ----------------------- */ +/* | Reserved | Reserved (pad out to 4MB) */ +/* ----------------------- */ + +/* Offsets/sizes for diagnostic channel attributes... */ +#define DIAG_CH_QUEUE_HEADER_OFFSET (sizeof(ULTRA_CHANNEL_PROTOCOL)) +#define DIAG_CH_QUEUE_HEADER_SIZE (sizeof(SIGNAL_QUEUE_HEADER)) +#define DIAG_CH_PROTOCOL_HEADER_OFFSET \ + (DIAG_CH_QUEUE_HEADER_OFFSET + DIAG_CH_QUEUE_HEADER_SIZE) +#define DIAG_CH_PROTOCOL_HEADER_SIZE (sizeof(DIAG_CHANNEL_PROTOCOL_HEADER)) +#define DIAG_CH_EVENT_OFFSET \ + (DIAG_CH_PROTOCOL_HEADER_OFFSET + DIAG_CH_PROTOCOL_HEADER_SIZE) +#define DIAG_CH_SIZE (4096 * 1024) + +/* For Control and Idle Partitions with larger (8 MB) diagnostic(root) + * channels */ +#define DIAG_CH_LRG_SIZE (2 * DIAG_CH_SIZE) /* 8 MB */ + +/* + * Structure: ULTRA_DIAG_CHANNEL_PROTOCOL + * + * Purpose: Contains attributes that make up the DIAG_CHANNEL memory. + * + * Attributes: + * + * CommonChannelHeader: Header info common to all channels. + * + * QueueHeader: Queue header common to all channels - used to determine where to + * store event. + * + * DiagChannelHeader: Diagnostic channel header info (see + * DIAG_CHANNEL_PROTOCOL_HEADER comments). + * + * Events: Area where diagnostic events (up to MAX_EVENTS) are written. + * + *Reserved: Reserved area to allow for correct channel size padding. +*/ +typedef struct _ULTRA_DIAG_CHANNEL_PROTOCOL { + ULTRA_CHANNEL_PROTOCOL CommonChannelHeader; + SIGNAL_QUEUE_HEADER QueueHeader; + DIAG_CHANNEL_PROTOCOL_HEADER DiagChannelHeader; + DIAG_CHANNEL_EVENT Events[(DIAG_CH_SIZE - DIAG_CH_EVENT_OFFSET) / + sizeof(DIAG_CHANNEL_EVENT)]; +} +ULTRA_DIAG_CHANNEL_PROTOCOL; + +#endif diff --git a/drivers/staging/unisys/common-spar/include/channels/iochannel.h b/drivers/staging/unisys/common-spar/include/channels/iochannel.h new file mode 100644 index 0000000..8de1d24 --- /dev/null +++ b/drivers/staging/unisys/common-spar/include/channels/iochannel.h @@ -0,0 +1,933 @@ +/* Copyright © 2010 - 2013 UNISYS CORPORATION */ +/* All rights reserved. */ +#ifndef __IOCHANNEL_H__ +#define __IOCHANNEL_H__ + +/* +* Everything needed for IOPart-GuestPart communication is define in +* this file. Note: Everything is OS-independent because this file is +* used by Windows, Linux and possible EFI drivers. */ + + +/* +* Communication flow between the IOPart and GuestPart uses the channel headers +* channel state. The following states are currently being used: +* UNINIT(All Zeroes), CHANNEL_ATTACHING, CHANNEL_ATTACHED, CHANNEL_OPENED +* +* additional states will be used later. No locking is needed to switch between +* states due to the following rules: +* +* 1. IOPart is only the only partition allowed to change from UNIT +* 2. IOPart is only the only partition allowed to change from +* CHANNEL_ATTACHING +* 3. GuestPart is only the only partition allowed to change from +* CHANNEL_ATTACHED +* +* The state changes are the following: IOPart sees the channel is in UNINIT, +* UNINIT -> CHANNEL_ATTACHING (performed only by IOPart) +* CHANNEL_ATTACHING -> CHANNEL_ATTACHED (performed only by IOPart) +* CHANNEL_ATTACHED -> CHANNEL_OPENED (performed only by GuestPart) +*/ + +#include "commontypes.h" +#include "vmcallinterface.h" + +#define _ULTRA_CONTROLVM_CHANNEL_INLINE_ +#include <linux/dma-direction.h> +#include "controlvmchannel.h" +#include "vbuschannel.h" +#undef _ULTRA_CONTROLVM_CHANNEL_INLINE_ +#include "channel.h" + +/* + * CHANNEL Guids + */ + +#include "channel_guid.h" + +#define ULTRA_VHBA_CHANNEL_PROTOCOL_SIGNATURE ULTRA_CHANNEL_PROTOCOL_SIGNATURE +#define ULTRA_VNIC_CHANNEL_PROTOCOL_SIGNATURE ULTRA_CHANNEL_PROTOCOL_SIGNATURE +#define ULTRA_VSWITCH_CHANNEL_PROTOCOL_SIGNATURE \ + ULTRA_CHANNEL_PROTOCOL_SIGNATURE + +/* Must increment these whenever you insert or delete fields within this channel +* struct. Also increment whenever you change the meaning of fields within this +* channel struct so as to break pre-existing software. Note that you can +* usually add fields to the END of the channel struct withOUT needing to +* increment this. */ +#define ULTRA_VHBA_CHANNEL_PROTOCOL_VERSIONID 2 +#define ULTRA_VNIC_CHANNEL_PROTOCOL_VERSIONID 2 +#define ULTRA_VSWITCH_CHANNEL_PROTOCOL_VERSIONID 1 + +#define ULTRA_VHBA_CHANNEL_OK_CLIENT(pChannel, logCtx) \ + (ULTRA_check_channel_client(pChannel, UltraVhbaChannelProtocolGuid, \ + "vhba", MIN_IO_CHANNEL_SIZE, \ + ULTRA_VHBA_CHANNEL_PROTOCOL_VERSIONID, \ + ULTRA_VHBA_CHANNEL_PROTOCOL_SIGNATURE, \ + __FILE__, __LINE__, logCtx)) +#define ULTRA_VHBA_CHANNEL_OK_SERVER(actualBytes, logCtx) \ + (ULTRA_check_channel_server(UltraVhbaChannelProtocolGuid, \ + "vhba", MIN_IO_CHANNEL_SIZE, actualBytes, \ + __FILE__, __LINE__, logCtx)) +#define ULTRA_VNIC_CHANNEL_OK_CLIENT(pChannel, logCtx) \ + (ULTRA_check_channel_client(pChannel, UltraVnicChannelProtocolGuid, \ + "vnic", MIN_IO_CHANNEL_SIZE, \ + ULTRA_VNIC_CHANNEL_PROTOCOL_VERSIONID, \ + ULTRA_VNIC_CHANNEL_PROTOCOL_SIGNATURE, \ + __FILE__, __LINE__, logCtx)) +#define ULTRA_VNIC_CHANNEL_OK_SERVER(actualBytes, logCtx) \ + (ULTRA_check_channel_server(UltraVnicChannelProtocolGuid, \ + "vnic", MIN_IO_CHANNEL_SIZE, actualBytes, \ + __FILE__, __LINE__, logCtx)) +#define ULTRA_VSWITCH_CHANNEL_OK_CLIENT(pChannel, logCtx) \ + (ULTRA_check_channel_client(pChannel, UltraVswitchChannelProtocolGuid, \ + "vswitch", MIN_IO_CHANNEL_SIZE, \ + ULTRA_VSWITCH_CHANNEL_PROTOCOL_VERSIONID, \ + ULTRA_VSWITCH_CHANNEL_PROTOCOL_SIGNATURE, \ + __FILE__, __LINE__, logCtx)) +#define ULTRA_VSWITCH_CHANNEL_OK_SERVER(actualBytes, logCtx) \ + (ULTRA_check_channel_server(UltraVswitchChannelProtocolGuid, \ + "vswitch", MIN_IO_CHANNEL_SIZE, \ + actualBytes, \ + __FILE__, __LINE__, logCtx)) +/* +* Everything necessary to handle SCSI & NIC traffic between Guest Partition and +* IO Partition is defined below. */ + + +/* +* Defines and enums. +*/ + +#define MINNUM(a, b) (((a) < (b)) ? (a) : (b)) +#define MAXNUM(a, b) (((a) > (b)) ? (a) : (b)) + +/* these define the two queues per data channel between iopart and + * ioguestparts */ +#define IOCHAN_TO_IOPART 0 /* used by ioguestpart to 'insert' signals to + * iopart */ +#define IOCHAN_FROM_GUESTPART 0 /* used by iopart to 'remove' signals from + * ioguestpart - same queue as previous queue */ + +#define IOCHAN_TO_GUESTPART 1 /* used by iopart to 'insert' signals to + * ioguestpart */ +#define IOCHAN_FROM_IOPART 1 /* used by ioguestpart to 'remove' signals from + * iopart - same queue as previous queue */ + +/* these define the two queues per control channel between controlpart and "its" + * guests, which includes the iopart */ +#define CTRLCHAN_TO_CTRLGUESTPART 0 /* used by ctrlguestpart to 'insert' signals + * to ctrlpart */ +#define CTLRCHAN_FROM_CTRLPART 0 /* used by ctrlpart to 'remove' signals from + * ctrlquestpart - same queue as previous + * queue */ + +#define CTRLCHAN_TO_CTRLPART 1 /* used by ctrlpart to 'insert' signals to + * ctrlguestpart */ +#define CTRLCHAN_FROM_CTRLGUESTPART 1 /* used by ctrguestpart to 'remove' + * signals from ctrlpart - same queue as + * previous queue */ + +/* these define the Event & Ack queues per control channel Events are generated +* by CTRLGUESTPART and sent to CTRLPART; Acks are generated by CTRLPART and sent +* to CTRLGUESTPART. */ +#define CTRLCHAN_EVENT_TO_CTRLPART 2 /* used by ctrlguestpart to 'insert' Events + * to ctrlpart */ +#define CTRLCHAN_EVENT_FROM_CTRLGUESTPART 2 /* used by ctrlpart to 'remove' + * Events from ctrlguestpart */ + +#define CTRLCHAN_ACK_TO_CTRLGUESTPART 3 /* used by ctrlpart to 'insert' Acks to + * ctrlguestpart */ +#define CTRLCHAN_ACK_FROM_CTRLPART 3 /* used by ctrlguestpart to 'remove' Events + * from ctrlpart */ + +/* size of cdb - i.e., scsi cmnd */ +#define MAX_CMND_SIZE 16 + +#define MAX_SENSE_SIZE 64 + +#define MAX_PHYS_INFO 64 + +/* Because GuestToGuestCopy is limited to 4KiB segments, and we have limited the +* Emulex Driver to 256 scatter list segments via the lpfc_sg_seg_cnt parameter +* to 256, the maximum I/O size is limited to 256 * 4 KiB = 1 MB */ +#define MAX_IO_SIZE (1024*1024) /* 1 MB */ + +/* NOTE 1: lpfc defines its support for segments in +* #define LPFC_SG_SEG_CNT 64 +* +* NOTE 2: In Linux, frags array in skb is currently allocated to be +* MAX_SKB_FRAGS size, which is 18 which is smaller than MAX_PHYS_INFO for +* now. */ + +#ifndef MAX_SERIAL_NUM +#define MAX_SERIAL_NUM 32 +#endif /* MAX_SERIAL_NUM */ + +#define MAX_SCSI_BUSES 1 +#define MAX_SCSI_TARGETS 8 +#define MAX_SCSI_LUNS 16 +#define MAX_SCSI_FROM_HOST 0xFFFFFFFF /* Indicator to use Physical HBA + * SCSI Host value */ + +/* various types of network packets that can be sent in cmdrsp */ +typedef enum { NET_RCV_POST = 0, /* submit buffer to hold receiving + * incoming packet */ + /* virtnic -> uisnic */ + NET_RCV, /* incoming packet received */ + /* uisnic -> virtpci */ + NET_XMIT, /* for outgoing net packets */ + /* virtnic -> uisnic */ + NET_XMIT_DONE, /* outgoing packet xmitted */ + /* uisnic -> virtpci */ + NET_RCV_ENBDIS, /* enable/disable packet reception */ + /* virtnic -> uisnic */ + NET_RCV_ENBDIS_ACK, /* acknowledge enable/disable packet + * reception */ + /* uisnic -> virtnic */ + NET_RCV_PROMISC, /* enable/disable promiscuous mode */ + /* virtnic -> uisnic */ + NET_CONNECT_STATUS, /* indicate the loss or restoration of a network + * connection */ + /* uisnic -> virtnic */ + NET_MACADDR, /* indicates the client has requested to update + * its MAC addr */ + NET_MACADDR_ACK, /* Mac addres */ + +} NET_TYPES; + +#define ETH_HEADER_SIZE 14 /* size of ethernet header */ + +#define ETH_MIN_DATA_SIZE 46 /* minimum eth data size */ +#define ETH_MIN_PACKET_SIZE (ETH_HEADER_SIZE + ETH_MIN_DATA_SIZE) + +#define ETH_DEF_DATA_SIZE 1500 /* default data size */ +#define ETH_DEF_PACKET_SIZE (ETH_HEADER_SIZE + ETH_DEF_DATA_SIZE) + +#define ETH_MAX_MTU 16384 /* maximum data size */ + +#ifndef MAX_MACADDR_LEN +#define MAX_MACADDR_LEN 6 /* number of bytes in MAC address */ +#endif /* MAX_MACADDR_LEN */ + +#define ETH_IS_LOCALLY_ADMINISTERED(Address) \ + (((U8 *) (Address))[0] & ((U8) 0x02)) +#define NIC_VENDOR_ID 0x0008000B + +/* various types of scsi task mgmt commands */ +typedef enum { TASK_MGMT_ABORT_TASK = + 1, TASK_MGMT_BUS_RESET, TASK_MGMT_LUN_RESET, + TASK_MGMT_TARGET_RESET, +} TASK_MGMT_TYPES; + +/* various types of vdisk mgmt commands */ +typedef enum { VDISK_MGMT_ACQUIRE = 1, VDISK_MGMT_RELEASE, +} VDISK_MGMT_TYPES; + +/* this is used in the vdest field */ +#define VDEST_ALL 0xFFFF + +#define MIN_NUMSIGNALS 64 +#define MAX_NUMSIGNALS 4096 + +/* MAX_NET_RCV_BUF specifies the number of rcv buffers that are created by each +* guest's virtnic and posted to uisnic. Uisnic, for each channel, keeps the rcv +* buffers posted and uses them to receive data on behalf of the guest's virtnic. +* NOTE: the num_rcv_bufs is configurable for each VNIC. So the following is +* simply an upperlimit on what each VNIC can provide. Setting it to half of the +* NUMSIGNALS to prevent queue full deadlocks */ +#define MAX_NET_RCV_BUFS (MIN_NUMSIGNALS / 2) + +/* + * structs with pragma pack */ + + +/* ///////////// BEGIN PRAGMA PACK PUSH 1 ///////////////////////// */ +/* ///////////// ONLY STRUCT TYPE SHOULD BE BELOW */ + +#pragma pack(push, 1) + +struct guest_phys_info { + U64 address; + U64 length; +}; + +#define GPI_ENTRIES_PER_PAGE (PAGE_SIZE / sizeof(struct guest_phys_info)) + +struct uisscsi_dest { + U32 channel; /* channel == bus number */ + U32 id; /* id == target number */ + U32 lun; /* lun == logical unit number */ +}; + +struct vhba_wwnn { + U32 wwnn1; + U32 wwnn2; +}; + +/* WARNING: Values stired in this structure must contain maximum counts (not + * maximum values). */ +struct vhba_config_max { /* 20 bytes */ + U32 max_channel; /* maximum channel for devices attached to this + * bus */ + U32 max_id; /* maximum SCSI ID for devices attached to this + * bus */ + U32 max_lun; /* maximum SCSI LUN for devices attached to this + * bus */ + U32 cmd_per_lun; /* maximum number of outstanding commands per + * lun that are allowed at one time */ + U32 max_io_size; /* maximum io size for devices attached to this + * bus */ + /* max io size is often determined by the resource of the hba. e.g */ + /* max scatter gather list length * page size / sector size */ +}; + +struct uiscmdrsp_scsi { + void *scsicmd; /* the handle to the cmd that was received - + * send it back as is in the rsp packet. */ + U8 cmnd[MAX_CMND_SIZE]; /* the cdb for the command */ + U32 bufflen; /* length of data to be transferred out or in */ + U16 guest_phys_entries; /* Number of entries in scatter-gather (sg) + * list */ + struct guest_phys_info gpi_list[MAX_PHYS_INFO]; /* physical address + * information for each + * fragment */ + enum dma_data_direction data_dir; /* direction of the data, if any */ + struct uisscsi_dest vdest; /* identifies the virtual hba, id, + * channel, lun to which cmd was sent */ + + /* the following fields are needed to queue the rsp back to cmd + * originator */ + int linuxstat; /* the original Linux status - for use by linux + * vdisk code */ + U8 scsistat; /* the scsi status */ + U8 addlstat; /* non-scsi status - covers cases like timeout + * needed by windows guests */ +#define ADDL_RESET 1 +#define ADDL_TIMEOUT 2 +#define ADDL_INTERNAL_ERROR 3 +#define ADDL_SEL_TIMEOUT 4 +#define ADDL_CMD_TIMEOUT 5 +#define ADDL_BAD_TARGET 6 +#define ADDL_RETRY 7 + + /* the following fields are need to determine the result of command */ + U8 sensebuf[MAX_SENSE_SIZE]; /* sense info in case cmd failed; */ + /* it holds the sense_data struct; */ + /* see that struct for details. */ + void *vdisk; /* contains pointer to the vdisk so that we can clean up + * when the IO completes. */ + int no_disk_result; /* used to return no disk inquiry result */ + /* when no_disk_result is set to 1, */ + /* scsi.scsistat is SAM_STAT_GOOD */ + /* scsi.addlstat is 0 */ + /* scsi.linuxstat is SAM_STAT_GOOD */ + /* That is, there is NO error. */ +}; + +/* +* Defines to support sending correct inquiry result when no disk is +* configured. */ + +/* From SCSI SPC2 - + * + * If the target is not capable of supporting a device on this logical unit, the + * device server shall set this field to 7Fh (PERIPHERAL QUALIFIER set to 011b + * and PERIPHERAL DEVICE TYPE set to 1Fh). + * + *The device server is capable of supporting the specified peripheral device + *type on this logical unit. However, the physical device is not currently + *connected to this logical unit. + */ + +#define DEV_NOT_PRESENT 0x7f /* old name - compatibility */ +#define DEV_NOT_CAPABLE 0x7f /* peripheral qualifier of 0x3 */ + /* peripheral type of 0x1f */ + /* specifies no device but target present */ + +#define DEV_DISK_CAPABLE_NOT_PRESENT 0x20 /* peripheral qualifier of 0x1 */ + /* peripheral type of 0 - disk */ + /* specifies device capable, but not present */ + +#define DEV_PROC_CAPABLE_NOT_PRESENT 0x23 /* peripheral qualifier of 0x1 */ + /* peripheral type of 3 - processor */ + /* specifies device capable, but not present */ + +#define DEV_HISUPPORT 0x10; /* HiSup = 1; shows support for report luns */ + /* must be returned for lun 0. */ + +/* NOTE: Linux code assumes inquiry contains 36 bytes. Without checking length +* in buf[4] some linux code accesses bytes beyond 5 to retrieve vendor, product +* & revision. Yikes! So let us always send back 36 bytes, the minimum for +* inquiry result. */ +#define NO_DISK_INQUIRY_RESULT_LEN 36 + +#define MIN_INQUIRY_RESULT_LEN 5 /* we need at least 5 bytes minimum for inquiry + * result */ + +/* SCSI device version for no disk inquiry result */ +#define SCSI_SPC2_VER 4 /* indicates SCSI SPC2 (SPC3 is 5) */ + +/* Windows and Linux want different things for a non-existent lun. So, we'll let + * caller pass in the peripheral qualifier and type. + * NOTE:[4] SCSI returns (n-4); so we return length-1-4 or length-5. */ + +#define SET_NO_DISK_INQUIRY_RESULT(buf, len, lun, lun0notpresent, notpresent) \ + do { \ + MEMSET(buf, 0, \ + MINNUM(len, \ + (unsigned int) NO_DISK_INQUIRY_RESULT_LEN)); \ + buf[2] = (U8) SCSI_SPC2_VER; \ + if (lun == 0) { \ + buf[0] = (U8) lun0notpresent; \ + buf[3] = (U8) DEV_HISUPPORT; \ + } else \ + buf[0] = (U8) notpresent; \ + buf[4] = (U8) ( \ + MINNUM(len, \ + (unsigned int) NO_DISK_INQUIRY_RESULT_LEN) - 5); \ + if (len >= NO_DISK_INQUIRY_RESULT_LEN) { \ + buf[8] = 'D'; \ + buf[9] = 'E'; \ + buf[10] = 'L'; \ + buf[11] = 'L'; \ + buf[16] = 'P'; \ + buf[17] = 'S'; \ + buf[18] = 'E'; \ + buf[19] = 'U'; \ + buf[20] = 'D'; \ + buf[21] = 'O'; \ + buf[22] = ' '; \ + buf[23] = 'D'; \ + buf[24] = 'E'; \ + buf[25] = 'V'; \ + buf[26] = 'I'; \ + buf[27] = 'C'; \ + buf[28] = 'E'; \ + buf[30] = ' '; \ + buf[31] = '.'; \ + } \ + } while (0) + + +/* +* Struct & Defines to support sense information. +*/ + + +/* The following struct is returned in sensebuf field in uiscmdrsp_scsi. It is +* initialized in exactly the manner that is recommended in Windows (hence the +* odd values). +* When set, these fields will have the following values: +* ErrorCode = 0x70 indicates current error +* Valid = 1 indicates sense info is valid +* SenseKey contains sense key as defined by SCSI specs. +* AdditionalSenseCode contains sense key as defined by SCSI specs. +* AdditionalSenseCodeQualifier contains qualifier to sense code as defined by +* scsi docs. +* AdditionalSenseLength contains will be sizeof(sense_data)-8=10. +*/ +struct sense_data { + U8 ErrorCode:7; + U8 Valid:1; + U8 SegmentNumber; + U8 SenseKey:4; + U8 Reserved:1; + U8 IncorrectLength:1; + U8 EndOfMedia:1; + U8 FileMark:1; + U8 Information[4]; + U8 AdditionalSenseLength; + U8 CommandSpecificInformation[4]; + U8 AdditionalSenseCode; + U8 AdditionalSenseCodeQualifier; + U8 FieldReplaceableUnitCode; + U8 SenseKeySpecific[3]; +}; + +/* some SCSI ADSENSE codes */ +#ifndef SCSI_ADSENSE_LUN_NOT_READY +#define SCSI_ADSENSE_LUN_NOT_READY 0x04 +#endif /* */ +#ifndef SCSI_ADSENSE_ILLEGAL_COMMAND +#define SCSI_ADSENSE_ILLEGAL_COMMAND 0x20 +#endif /* */ +#ifndef SCSI_ADSENSE_ILLEGAL_BLOCK +#endif /* */ +#ifndef SCSI_ADSENSE_ILLEGAL_BLOCK +#define SCSI_ADSENSE_ILLEGAL_BLOCK 0x21 +#endif /* */ +#ifndef SCSI_ADSENSE_INVALID_CDB +#define SCSI_ADSENSE_INVALID_CDB 0x24 +#endif /* */ +#ifndef SCSI_ADSENSE_INVALID_LUN +#define SCSI_ADSENSE_INVALID_LUN 0x25 +#endif /* */ +#ifndef SCSI_ADWRITE_PROTECT +#define SCSI_ADWRITE_PROTECT 0x27 +#endif /* */ +#ifndef SCSI_ADSENSE_MEDIUM_CHANGED +#define SCSI_ADSENSE_MEDIUM_CHANGED 0x28 +#endif /* */ +#ifndef SCSI_ADSENSE_BUS_RESET +#define SCSI_ADSENSE_BUS_RESET 0x29 +#endif /* */ +#ifndef SCSI_ADSENSE_NO_MEDIA_IN_DEVICE +#define SCSI_ADSENSE_NO_MEDIA_IN_DEVICE 0x3a +#endif /* */ + +struct net_pkt_xmt { + int len; /* full length of data in the packet */ + int num_frags; /* number of fragments in frags containing data */ + struct phys_info frags[MAX_PHYS_INFO]; /* physical page information for + * each fragment */ + char ethhdr[ETH_HEADER_SIZE]; /* the ethernet header */ + struct { + + /* these are needed for csum at uisnic end */ + U8 valid; /* 1 = rest of this struct is valid - else + * ignore */ + U8 hrawoffv; /* 1 = hwrafoff is valid */ + U8 nhrawoffv; /* 1 = nhwrafoff is valid */ + U16 protocol; /* specifies packet protocol */ + U32 csum; /* value used to set skb->csum at IOPart */ + U32 hrawoff; /* value used to set skb->h.raw at IOPart */ + /* hrawoff points to the start of the TRANSPORT LAYER HEADER */ + U32 nhrawoff; /* value used to set skb->nh.raw at IOPart */ + /* nhrawoff points to the start of the NETWORK LAYER HEADER */ + } lincsum; + + /* **** NOTE **** + * The full packet is described in frags but the ethernet header is + * separately kept in ethhdr so that uisnic doesn't have "MAP" the + * guest memory to get to the header. uisnic needs ethhdr to + * determine how to route the packet. + */ +}; + +struct net_pkt_xmtdone { + U32 xmt_done_result; /* result of NET_XMIT */ +#define XMIT_SUCCESS 0 +#define XMIT_FAILED 1 +}; + +/* RCVPOST_BUF_SIZe must be at most page_size(4096) - cache_line_size (64) The +* reason is because dev_skb_alloc which is used to generate RCV_POST skbs in +* virtnic requires that there is "overhead" in the buffer, and pads 16 bytes. I +* prefer to use 1 full cache line size for "overhead" so that transfers are +* better. IOVM requires that a buffer be represented by 1 phys_info structure +* which can only cover page_size. */ +#define RCVPOST_BUF_SIZE 4032 +#define MAX_NET_RCV_CHAIN \ + ((ETH_MAX_MTU+ETH_HEADER_SIZE + RCVPOST_BUF_SIZE-1) / RCVPOST_BUF_SIZE) + +struct net_pkt_rcvpost { + /* rcv buf size must be large enough to include ethernet data len + + * ethernet header len - we are choosing 2K because it is guaranteed + * to be describable */ + struct phys_info frag; /* physical page information for the + * single fragment 2K rcv buf */ + U64 UniqueNum; /* This is used to make sure that + * receive posts are returned to */ + /* the Adapter which sent them origonally. */ +}; + +struct net_pkt_rcv { + + /* the number of receive buffers that can be chained */ + /* is based on max mtu and size of each rcv buf */ + U32 rcv_done_len; /* length of received data */ + U8 numrcvbufs; /* number of receive buffers that contain the */ + /* incoming data; guest end MUST chain these together. */ + void *rcvbuf[MAX_NET_RCV_CHAIN]; /* the list of receive buffers + * that must be chained; */ + /* each entry is a receive buffer provided by NET_RCV_POST. */ + /* NOTE: first rcvbuf in the chain will also be provided in net.buf. */ + U64 UniqueNum; + U32 RcvsDroppedDelta; +}; + +struct net_pkt_enbdis { + void *context; + U16 enable; /* 1 = enable, 0 = disable */ +}; + +struct net_pkt_macaddr { + void *context; + U8 macaddr[MAX_MACADDR_LEN]; /* 6 bytes */ +}; + +/* cmd rsp packet used for VNIC network traffic */ +struct uiscmdrsp_net { + NET_TYPES type; + void *buf; + union { + struct net_pkt_xmt xmt; /* used for NET_XMIT */ + struct net_pkt_xmtdone xmtdone; /* used for NET_XMIT_DONE */ + struct net_pkt_rcvpost rcvpost; /* used for NET_RCV_POST */ + struct net_pkt_rcv rcv; /* used for NET_RCV */ + struct net_pkt_enbdis enbdis; /* used for NET_RCV_ENBDIS, */ + /* NET_RCV_ENBDIS_ACK, */ + /* NET_RCV_PROMSIC, */ + /* and NET_CONNECT_STATUS */ + struct net_pkt_macaddr macaddr; + }; +}; + +struct uiscmdrsp_scsitaskmgmt { + TASK_MGMT_TYPES tasktype; + + /* the type of task */ + struct uisscsi_dest vdest; + + /* the vdisk for which this task mgmt is generated */ + void *scsicmd; + + /* This is some handle that the guest has saved off for its own use. + * Its value is preserved by iopart & returned as is in the task mgmt + * rsp. */ + void *notify; + + /* For linux guests, this is a pointer to wait_queue_head that a + * thread is waiting on to see if the taskmgmt command has completed. + * For windows guests, this is a pointer to a location that a waiting + * thread is testing to see if the taskmgmt command has completed. + * When the rsp is received by guest, the thread receiving the + * response uses this to notify the the thread waiting for taskmgmt + * command completion. Its value is preserved by iopart & returned + * as is in the task mgmt rsp. */ + void *notifyresult; + + /* this is a handle to location in guest where the result of the + * taskmgmt command (result field) is to saved off when the response + * is handled. Its value is preserved by iopart & returned as is in + * the task mgmt rsp. */ + char result; + + /* result of taskmgmt command - set by IOPart - values are: */ +#define TASK_MGMT_FAILED 0 +#define TASK_MGMT_SUCCESS 1 +}; + +/* The following is used by uissd to send disk add/remove notifications to + * Guest */ +/* Note that the vHba pointer is not used by the Client/Guest side. */ +struct uiscmdrsp_disknotify { + U8 add; /* 0-remove, 1-add */ + void *vHba; /* Pointer to vhba_info for channel info to + * route msg */ + U32 channel, id, lun; /* SCSI Path of Disk to added or removed */ +}; + +/* The following is used by virthba/vSCSI to send the Acquire/Release commands +* to the IOVM. */ +struct uiscmdrsp_vdiskmgmt { + VDISK_MGMT_TYPES vdisktype; + + /* the type of task */ + struct uisscsi_dest vdest; + + /* the vdisk for which this task mgmt is generated */ + void *scsicmd; + + /* This is some handle that the guest has saved off for its own use. + * Its value is preserved by iopart & returned as is in the task mgmt + * rsp. */ + void *notify; + + /* For linux guests, this is a pointer to wait_queue_head that a + * thread is waiting on to see if the taskmgmt command has completed. + * For windows guests, this is a pointer to a location that a waiting + * thread is testing to see if the taskmgmt command has completed. + * When the rsp is received by guest, the thread receiving the + * response uses this to notify the the thread waiting for taskmgmt + * command completion. Its value is preserved by iopart & returned + * as is in the task mgmt rsp. */ + void *notifyresult; + + /* this is a handle to location in guest where the result of the + * taskmgmt command (result field) is to saved off when the response + * is handled. Its value is preserved by iopart & returned as is in + * the task mgmt rsp. */ + char result; + + /* result of taskmgmt command - set by IOPart - values are: */ +#define VDISK_MGMT_FAILED 0 +#define VDISK_MGMT_SUCCESS 1 +}; + +/* keeping cmd & rsp info in one structure for now cmd rsp packet for scsi */ +struct uiscmdrsp { + char cmdtype; + + /* describes what type of information is in the struct */ +#define CMD_SCSI_TYPE 1 +#define CMD_NET_TYPE 2 +#define CMD_SCSITASKMGMT_TYPE 3 +#define CMD_NOTIFYGUEST_TYPE 4 +#define CMD_VDISKMGMT_TYPE 5 + union { + struct uiscmdrsp_scsi scsi; + struct uiscmdrsp_net net; + struct uiscmdrsp_scsitaskmgmt scsitaskmgmt; + struct uiscmdrsp_disknotify disknotify; + struct uiscmdrsp_vdiskmgmt vdiskmgmt; + }; + void *private_data; /* used to send the response when the cmd is + * done (scsi & scsittaskmgmt). */ + struct uiscmdrsp *next; /* General Purpose Queue Link */ + struct uiscmdrsp *activeQ_next; /* Used to track active commands */ + struct uiscmdrsp *activeQ_prev; /* Used to track active commands */ +}; + +/* This is just the header of the IO channel. It is assumed that directly after +* this header there is a large region of memory which contains the command and +* response queues as specified in cmdQ and rspQ SIGNAL_QUEUE_HEADERS. */ +typedef struct _ULTRA_IO_CHANNEL_PROTOCOL { + CHANNEL_HEADER ChannelHeader; + SIGNAL_QUEUE_HEADER cmdQ; + SIGNAL_QUEUE_HEADER rspQ; + union { + struct { + struct vhba_wwnn wwnn; /* 8 bytes */ + struct vhba_config_max max; /* 20 bytes */ + } vhba; /* 28 */ + struct { + U8 macaddr[MAX_MACADDR_LEN]; /* 6 bytes */ + U32 num_rcv_bufs; /* 4 */ + U32 mtu; /* 4 */ + GUID zoneGuid; /* 16 */ + } vnic; /* total 30 */ + }; + +#define MAX_CLIENTSTRING_LEN 1024 + U8 clientString[MAX_CLIENTSTRING_LEN]; /* NULL terminated - so holds + * max - 1 bytes */ +} ULTRA_IO_CHANNEL_PROTOCOL; + +#pragma pack(pop) +/* ///////////// END PRAGMA PACK PUSH 1 /////////////////////////// */ + +/* define offsets to members of struct uiscmdrsp */ +#define OFFSET_CMDTYPE OFFSETOF(struct uiscmdrsp, cmdtype) +#define OFFSET_SCSI OFFSETOF(struct uiscmdrsp, scsi) +#define OFFSET_NET OFFSETOF(struct uiscmdrsp, net) +#define OFFSET_SCSITASKMGMT OFFSETOF(struct uiscmdrsp, scsitaskmgmt) +#define OFFSET_NEXT OFFSETOF(struct uiscmdrsp, next) + +/* define offsets to members of struct uiscmdrsp_net */ +#define OFFSET_TYPE OFFSETOF(struct uiscmdrsp_net, type) +#define OFFSET_BUF OFFSETOF(struct uiscmdrsp_net, buf) +#define OFFSET_XMT OFFSETOF(struct uiscmdrsp_net, xmt) +#define OFFSET_XMT_DONE_RESULT OFFSETOF(struct uiscmdrsp_net, xmtdone) +#define OFFSET_RCVPOST OFFSETOF(struct uiscmdrsp_net, rcvpost) +#define OFFSET_RCV_DONE_LEN OFFSETOF(struct uiscmdrsp_net, rcv) +#define OFFSET_ENBDIS OFFSETOF(struct uiscmdrsp_net, enbdis) + +/* define offsets to members of struct net_pkt_rcvpost */ +#define OFFSET_TOTALLEN OFFSETOF(struct net_pkt_rcvpost, totallen) +#define OFFSET_FRAG OFFSETOF(struct net_pkt_rcvpost, frag) + +/* +* INLINE functions for initializing and accessing I/O data channels +*/ + + +#define NUMSIGNALS(x, q) (((ULTRA_IO_CHANNEL_PROTOCOL *)(x))->q.MaxSignalSlots) +#define SIZEOF_PROTOCOL (COVER(sizeof(ULTRA_IO_CHANNEL_PROTOCOL), 64)) +#define SIZEOF_CMDRSP (COVER(sizeof(struct uiscmdrsp), 64)) + +#define IO_CHANNEL_SIZE(x) COVER(SIZEOF_PROTOCOL + \ + (NUMSIGNALS(x, cmdQ) + \ + NUMSIGNALS(x, rspQ)) * SIZEOF_CMDRSP, 4096) +#define MIN_IO_CHANNEL_SIZE COVER(SIZEOF_PROTOCOL + \ + 2 * MIN_NUMSIGNALS * SIZEOF_CMDRSP, 4096) +#ifdef __GNUC__ +/* These defines should only ever be used in service partitons */ +/* because they rely on the size of uiscmdrsp */ +#define QSLOTSFROMBYTES(bytes) (((bytes-SIZEOF_PROTOCOL)/2)/SIZEOF_CMDRSP) +#define QSIZEFROMBYTES(bytes) (QSLOTSFROMBYTES(bytes)*SIZEOF_CMDRSP) +#define SignalQInit(x) \ + do { \ + x->cmdQ.Size = QSIZEFROMBYTES(x->ChannelHeader.Size); \ + x->cmdQ.oSignalBase = SIZEOF_PROTOCOL - \ + OFFSETOF(ULTRA_IO_CHANNEL_PROTOCOL, cmdQ); \ + x->cmdQ.SignalSize = SIZEOF_CMDRSP; \ + x->cmdQ.MaxSignalSlots = \ + QSLOTSFROMBYTES(x->ChannelHeader.Size); \ + x->cmdQ.MaxSignals = x->cmdQ.MaxSignalSlots - 1; \ + x->rspQ.Size = QSIZEFROMBYTES(x->ChannelHeader.Size); \ + x->rspQ.oSignalBase = \ + (SIZEOF_PROTOCOL + x->cmdQ.Size) - \ + OFFSETOF(ULTRA_IO_CHANNEL_PROTOCOL, rspQ); \ + x->rspQ.SignalSize = SIZEOF_CMDRSP; \ + x->rspQ.MaxSignalSlots = \ + QSLOTSFROMBYTES(x->ChannelHeader.Size); \ + x->rspQ.MaxSignals = x->rspQ.MaxSignalSlots - 1; \ + x->ChannelHeader.oChannelSpace = \ + OFFSETOF(ULTRA_IO_CHANNEL_PROTOCOL, cmdQ); \ + } while (0) + +#define INIT_CLIENTSTRING(chan, type, clientStr, clientStrLen) \ + do { \ + if (clientStr) { \ + chan->ChannelHeader.oClientString = \ + OFFSETOF(type, clientString); \ + MEMCPY(chan->clientString, clientStr, \ + MINNUM(clientStrLen, \ + (U32) (MAX_CLIENTSTRING_LEN - 1))); \ + chan->clientString[MINNUM(clientStrLen, \ + (U32) (MAX_CLIENTSTRING_LEN \ + - 1))] \ + = '\0'; \ + } \ + else \ + if (clientStrLen > 0) \ + return 0; \ + } while (0) + + +#define ULTRA_IO_CHANNEL_SERVER_READY(x, chanId, logCtx) \ + ULTRA_CHANNEL_SERVER_TRANSITION(x, chanId, SrvState, CHANNELSRV_READY, \ + logCtx); + +#define ULTRA_IO_CHANNEL_SERVER_NOTREADY(x, chanId, logCtx) \ + ULTRA_CHANNEL_SERVER_TRANSITION(x, chanId, SrvState, \ + CHANNELSRV_UNINITIALIZED, logCtx); + +static inline int ULTRA_VHBA_init_channel(ULTRA_IO_CHANNEL_PROTOCOL *x, + struct vhba_wwnn *wwnn, + struct vhba_config_max *max, + unsigned char *clientStr, + U32 clientStrLen, U64 bytes) { + MEMSET(x, 0, sizeof(ULTRA_IO_CHANNEL_PROTOCOL)); + x->ChannelHeader.VersionId = ULTRA_VHBA_CHANNEL_PROTOCOL_VERSIONID; + x->ChannelHeader.Signature = ULTRA_VHBA_CHANNEL_PROTOCOL_SIGNATURE; + x->ChannelHeader.SrvState = CHANNELSRV_UNINITIALIZED; + x->ChannelHeader.HeaderSize = sizeof(x->ChannelHeader); + x->ChannelHeader.Size = COVER(bytes, 4096); + x->ChannelHeader.Type = UltraVhbaChannelProtocolGuid; + x->ChannelHeader.ZoneGuid = Guid0; + x->vhba.wwnn = *wwnn; + x->vhba.max = *max; + INIT_CLIENTSTRING(x, ULTRA_IO_CHANNEL_PROTOCOL, clientStr, + clientStrLen); + SignalQInit(x); + if ((x->cmdQ.MaxSignalSlots > MAX_NUMSIGNALS) || + (x->rspQ.MaxSignalSlots > MAX_NUMSIGNALS)) { + return 0; + } + if ((x->cmdQ.MaxSignalSlots < MIN_NUMSIGNALS) || + (x->rspQ.MaxSignalSlots < MIN_NUMSIGNALS)) { + return 0; + } + return 1; +} + +static inline void ULTRA_VHBA_set_max(ULTRA_IO_CHANNEL_PROTOCOL *x, + struct vhba_config_max *max) { + x->vhba.max = *max; +} + +static inline int ULTRA_VNIC_init_channel(ULTRA_IO_CHANNEL_PROTOCOL *x, + unsigned char *macaddr, + U32 num_rcv_bufs, U32 mtu, + GUID zoneGuid, + unsigned char *clientStr, + U32 clientStrLen, + U64 bytes) { + MEMSET(x, 0, sizeof(ULTRA_IO_CHANNEL_PROTOCOL)); + x->ChannelHeader.VersionId = ULTRA_VNIC_CHANNEL_PROTOCOL_VERSIONID; + x->ChannelHeader.Signature = ULTRA_VNIC_CHANNEL_PROTOCOL_SIGNATURE; + x->ChannelHeader.SrvState = CHANNELSRV_UNINITIALIZED; + x->ChannelHeader.HeaderSize = sizeof(x->ChannelHeader); + x->ChannelHeader.Size = COVER(bytes, 4096); + x->ChannelHeader.Type = UltraVnicChannelProtocolGuid; + x->ChannelHeader.ZoneGuid = Guid0; + MEMCPY(x->vnic.macaddr, macaddr, MAX_MACADDR_LEN); + x->vnic.num_rcv_bufs = num_rcv_bufs; + x->vnic.mtu = mtu; + x->vnic.zoneGuid = zoneGuid; + INIT_CLIENTSTRING(x, ULTRA_IO_CHANNEL_PROTOCOL, clientStr, + clientStrLen); + SignalQInit(x); + if ((x->cmdQ.MaxSignalSlots > MAX_NUMSIGNALS) || + (x->rspQ.MaxSignalSlots > MAX_NUMSIGNALS)) { + return 0; + } + if ((x->cmdQ.MaxSignalSlots < MIN_NUMSIGNALS) || + (x->rspQ.MaxSignalSlots < MIN_NUMSIGNALS)) { + return 0; + } + return 1; +} + +#endif /* __GNUC__ */ + +/* +* INLINE function for expanding a guest's pfn-off-size into multiple 4K page +* pfn-off-size entires. +*/ + + +/* we deal with 4K page sizes when we it comes to passing page information + * between */ +/* Guest and IOPartition. */ +#define PI_PAGE_SIZE 0x1000 +#define PI_PAGE_MASK 0x0FFF +#define PI_PAGE_SHIFT 12 + +/* returns next non-zero index on success or zero on failure (i.e. out of + * room) + */ +static INLINE U16 +add_physinfo_entries(U32 inp_pfn, /* input - specifies the pfn to be used + * to add entries */ + U16 inp_off, /* input - specifies the off to be used + * to add entries */ + U32 inp_len, /* input - specifies the len to be used + * to add entries */ + U16 index, /* input - index in array at which new + * entries are added */ + U16 max_pi_arr_entries, /* input - specifies the maximum + * entries pi_arr can hold */ + struct phys_info pi_arr[]) /* input & output - array to + * which entries are added */ +{ + U32 len; + U16 i, firstlen; + + firstlen = PI_PAGE_SIZE - inp_off; + if (inp_len <= firstlen) { + + /* the input entry spans only one page - add as is */ + if (index >= max_pi_arr_entries) + return 0; + pi_arr[index].pi_pfn = inp_pfn; + pi_arr[index].pi_off = (U16) inp_off; + pi_arr[index].pi_len = (U16) inp_len; + return index + 1; + } + + /* this entry spans multiple pages */ + for (len = inp_len, i = 0; len; + len -= pi_arr[index + i].pi_len, i++) { + if (index + i >= max_pi_arr_entries) + return 0; + pi_arr[index + i].pi_pfn = inp_pfn + i; + if (i == 0) { + pi_arr[index].pi_off = inp_off; + pi_arr[index].pi_len = firstlen; + } + + else { + pi_arr[index + i].pi_off = 0; + pi_arr[index + i].pi_len = + (U16) MINNUM(len, (U32) PI_PAGE_SIZE); + } + + } + return index + i; +} + +#endif /* __IOCHANNEL_H__ */ diff --git a/drivers/staging/unisys/common-spar/include/channels/vbuschannel.h b/drivers/staging/unisys/common-spar/include/channels/vbuschannel.h new file mode 100644 index 0000000..99dbbcf --- /dev/null +++ b/drivers/staging/unisys/common-spar/include/channels/vbuschannel.h @@ -0,0 +1,135 @@ +/* Copyright © 2010 - 2013 UNISYS CORPORATION + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + */ + +#ifndef __VBUSCHANNEL_H__ +#define __VBUSCHANNEL_H__ + +/* The vbus channel is the channel area provided via the BUS_CREATE controlvm + * message for each virtual bus. This channel area is provided to both server + * and client ends of the bus. The channel header area is initialized by + * the server, and the remaining information is filled in by the client. + * We currently use this for the client to provide various information about + * the client devices and client drivers for the server end to see. + */ +#include "commontypes.h" +#include "vbusdeviceinfo.h" +#include "channel.h" + +/* {193b331b-c58f-11da-95a9-00e08161165f} */ +#define ULTRA_VBUS_CHANNEL_PROTOCOL_GUID \ + {0x193b331b, 0xc58f, 0x11da, \ + {0x95, 0xa9, 0x0, 0xe0, 0x81, 0x61, 0x16, 0x5f} } +static const GUID UltraVbusChannelProtocolGuid = + ULTRA_VBUS_CHANNEL_PROTOCOL_GUID; + +#define ULTRA_VBUS_CHANNEL_PROTOCOL_SIGNATURE ULTRA_CHANNEL_PROTOCOL_SIGNATURE + +/* Must increment this whenever you insert or delete fields within this channel +* struct. Also increment whenever you change the meaning of fields within this +* channel struct so as to break pre-existing software. Note that you can +* usually add fields to the END of the channel struct withOUT needing to +* increment this. */ +#define ULTRA_VBUS_CHANNEL_PROTOCOL_VERSIONID 1 + +#define ULTRA_VBUS_CHANNEL_OK_CLIENT(pChannel, logCtx) \ + (ULTRA_check_channel_client(pChannel, \ + UltraVbusChannelProtocolGuid, \ + "vbus", \ + sizeof(ULTRA_VBUS_CHANNEL_PROTOCOL), \ + ULTRA_VBUS_CHANNEL_PROTOCOL_VERSIONID, \ + ULTRA_VBUS_CHANNEL_PROTOCOL_SIGNATURE, \ + __FILE__, __LINE__, logCtx)) + +#define ULTRA_VBUS_CHANNEL_OK_SERVER(actualBytes, logCtx) \ + (ULTRA_check_channel_server(UltraVbusChannelProtocolGuid, \ + "vbus", \ + sizeof(ULTRA_VBUS_CHANNEL_PROTOCOL), \ + actualBytes, \ + __FILE__, __LINE__, logCtx)) + + +#pragma pack(push, 1) /* both GCC and VC now allow this pragma */ +typedef struct _ULTRA_VBUS_HEADERINFO { + U32 structBytes; /* size of this struct in bytes */ + U32 deviceInfoStructBytes; /* sizeof(ULTRA_VBUS_DEVICEINFO) */ + U32 devInfoCount; /* num of items in DevInfo member */ + /* (this is the allocated size) */ + U32 chpInfoByteOffset; /* byte offset from beginning of this struct */ + /* to the the ChpInfo struct (below) */ + U32 busInfoByteOffset; /* byte offset from beginning of this struct */ + /* to the the BusInfo struct (below) */ + U32 devInfoByteOffset; /* byte offset from beginning of this struct */ + /* to the the DevInfo array (below) */ + U8 reserved[104]; +} ULTRA_VBUS_HEADERINFO; + +typedef struct _ULTRA_VBUS_CHANNEL_PROTOCOL { + ULTRA_CHANNEL_PROTOCOL ChannelHeader; /* initialized by server */ + ULTRA_VBUS_HEADERINFO HdrInfo; /* initialized by server */ + /* the remainder of this channel is filled in by the client */ + ULTRA_VBUS_DEVICEINFO ChpInfo; /* describes client chipset device and + * driver */ + ULTRA_VBUS_DEVICEINFO BusInfo; /* describes client bus device and + * driver */ + ULTRA_VBUS_DEVICEINFO DevInfo[0]; /* describes client device and + * driver for */ + /* each device on the bus */ +} ULTRA_VBUS_CHANNEL_PROTOCOL; + +#define VBUS_CH_SIZE_EXACT(MAXDEVICES) \ + (sizeof(ULTRA_VBUS_CHANNEL_PROTOCOL) + ((MAXDEVICES) * \ + sizeof(ULTRA_VBUS_DEVICEINFO))) +#define VBUS_CH_SIZE(MAXDEVICES) COVER(VBUS_CH_SIZE_EXACT(MAXDEVICES), 4096) + +static INLINE void +ULTRA_VBUS_init_channel(ULTRA_VBUS_CHANNEL_PROTOCOL __iomem *x, + int bytesAllocated) +{ + /* Please note that the memory at <x> does NOT necessarily have space + * for DevInfo structs allocated at the end, which is why we do NOT use + * <bytesAllocated> to clear. */ + memset_io(x, 0, sizeof(ULTRA_VBUS_CHANNEL_PROTOCOL)); + if (bytesAllocated < (int) sizeof(ULTRA_VBUS_CHANNEL_PROTOCOL)) + return; + writel(ULTRA_VBUS_CHANNEL_PROTOCOL_VERSIONID, + &x->ChannelHeader.VersionId); + writeq(ULTRA_VBUS_CHANNEL_PROTOCOL_SIGNATURE, + &x->ChannelHeader.Signature); + writel(CHANNELSRV_READY, &x->ChannelHeader.SrvState); + writel(sizeof(x->ChannelHeader), &x->ChannelHeader.HeaderSize); + writeq(bytesAllocated, &x->ChannelHeader.Size); + memcpy_toio(&x->ChannelHeader.Type, &UltraVbusChannelProtocolGuid, + sizeof(x->ChannelHeader.Type)); + memcpy_toio(&x->ChannelHeader.ZoneGuid, &Guid0, + sizeof(x->ChannelHeader.ZoneGuid)); + writel(sizeof(ULTRA_VBUS_HEADERINFO), &x->HdrInfo.structBytes); + writel(sizeof(ULTRA_VBUS_HEADERINFO), &x->HdrInfo.chpInfoByteOffset); + writel(readl(&x->HdrInfo.chpInfoByteOffset) + + sizeof(ULTRA_VBUS_DEVICEINFO), + &x->HdrInfo.busInfoByteOffset); + writel(readl(&x->HdrInfo.busInfoByteOffset) + + sizeof(ULTRA_VBUS_DEVICEINFO), + &x->HdrInfo.devInfoByteOffset); + writel(sizeof(ULTRA_VBUS_DEVICEINFO), + &x->HdrInfo.deviceInfoStructBytes); + bytesAllocated -= (sizeof(ULTRA_CHANNEL_PROTOCOL) + + readl(&x->HdrInfo.devInfoByteOffset)); + writel(bytesAllocated / readl(&x->HdrInfo.deviceInfoStructBytes), + &x->HdrInfo.devInfoCount); +} + +#pragma pack(pop) + +#endif |