--- /dev/null
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no 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. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/*
+ * hgfsEscape.c --
+ *
+ * Escape and unescape illegal filenames for different platforms.
+ *
+ */
+
+#ifdef __KERNEL__
+# include "driver-config.h"
+# include <linux/string.h>
+#elif defined(__FreeBSD__)
+# if defined(_KERNEL)
+# include <sys/libkern.h>
+# define strchr(s,c) index(s,c)
+# else
+# include <string.h>
+# endif
+# define memmove(s1,s2,n) bcopy(s2,s1,n)
+#elif defined(__APPLE__) && defined(KERNEL)
+# include <string.h>
+#elif !defined(sun)
+# include <stdlib.h>
+# include <string.h>
+#else
+# include <string.h>
+#endif
+
+#include "vmware.h"
+#include "hgfsEscape.h"
+#include "cpName.h"
+
+#ifdef _WIN32
+
+#define UNREFERENCED_PARAMETER(P) (P)
+
+/* These characters are illegal in Windows file names. */
+const char* HGFS_ILLEGAL_CHARS = "/\\*?:\"<>|";
+const char* HGFS_SUBSTITUTE_CHARS = "!@#$^&(){}";
+/* Last character of a file name in Windows can be neither dot nor space. */
+const char* HGFS_ILLEGAL_LAST_CHARS = ". ";
+
+/* http://msdn.microsoft.com/en-us/library/aa365247.aspx */
+char *HgfsReservedNames[] = {"CON", "PRN", "AUX", "NUL"};
+char *HgfsReservedNamesWithNumber[] = {"COM", "LPT"};
+
+#define HGFS_RESERVED_NAME_CHARS_LENGTH 3
+#define HGFS_RESERVED_NAME_WITH_NUMBER_CHARS_LENGTH (HGFS_RESERVED_NAME_CHARS_LENGTH + 1)
+/* Check for special escaping cases - reserved names and illegal last characters. */
+#define IS_SPECIAL_CASE_ESCAPE(b,o,l) HgfsIsSpecialCaseEscape(b,o,l)
+/* Process Windows reserved names. */
+#define PROCESS_RESERVED_NAME(b,s,p,o,c) \
+if (!HgfsProcessReservedName(b,s,p,o,c)) \
+{ \
+ return FALSE; \
+}
+/* Process Windows reserved names. */
+#define PROCESS_LAST_CHARACTER(b,s,p,c) \
+if (!HgfsProcessLastCharacter(b,s,p,c)) \
+{ \
+ return FALSE; \
+}
+
+#else // _WIN32
+
+#define UNREFERENCED_PARAMETER(P)
+/* There is no special escape sequences on other than Windows platforms. */
+#define IS_SPECIAL_CASE_ESCAPE(b,o,l) FALSE
+/* There is no reserved names on other then Windows platforms. */
+#define PROCESS_RESERVED_NAME(b,s,p,o,c)
+/* There is no special processing for the last character on non-Windows platforms. */
+#define PROCESS_LAST_CHARACTER(b,s,p,c)
+
+#if defined(__APPLE__)
+/* These characters are illegal in MAC OS file names. */
+const char* HGFS_ILLEGAL_CHARS = "/:";
+const char* HGFS_SUBSTITUTE_CHARS = "!&";
+#else // __APPLE__
+/* These characters are illegal in Linux file names. */
+const char* HGFS_ILLEGAL_CHARS = "/";
+const char* HGFS_SUBSTITUTE_CHARS = "!";
+#endif // __APPLE__
+
+#endif // _WIN32
+
+#define HGFS_ESCAPE_CHAR '%'
+#define HGFS_ESCAPE_SUBSTITUE_CHAR ']'
+
+typedef enum {
+ HGFS_ESCAPE_ILLEGAL_CHARACTER,
+ HGFS_ESCAPE_RESERVED_NAME,
+ HGFS_ESCAPE_ILLEGAL_LAST_CHARACTER,
+ HGFS_ESCAPE_ESCAPE_SEQUENCE,
+ HGFS_ESCAPE_COMPLETE
+} HgfsEscapeReason;
+
+
+typedef Bool (*HgfsEnumCallback)(char const *bufIn,
+ uint32 offset,
+ HgfsEscapeReason reason,
+ void* context);
+
+/*
+ * The structure is used by HgfsAddEscapeCharacter to keep context information between
+ * invocations
+ * All offsets defined in this structure are in characters, not bytes
+ */
+typedef struct {
+ uint32 processedOffset; // Offset of the first unprocessed input character
+ uint32 outputBufferLength; // Number of characters in the output buffer
+ uint32 outputOffset; // Number of characters that are already in the output
+ char *outputBuffer; // Pointer to the output buffer
+} HgfsEscapeContext;
+
+static void HgfsEscapeUndoComponent(char *bufIn, uint32 *totalLength);
+static int HgfsEscapeGetComponentSize(char const *bufIn, uint32 sizeIn);
+static int HgfsEscapeDoComponent(char const *bufIn, uint32 sizeIn, uint32 sizeBufOut,
+ char *bufOut);
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsAddEscapeCharacter --
+ *
+ * Callback function that is called by HgfsEnumerate to insert an escape sequence
+ * into the input name.
+ *
+ * Results:
+ * TRUE if successful, FALSE if there is an error like the output buffer is
+ * too small.
+ *
+ * Side effects:
+ * Updates the output buffer pointer (stored in the context variable).
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+HgfsAddEscapeCharacter(char const * bufIn, // IN: input name
+ uint32 offset, // IN: offset that requires escaping
+ HgfsEscapeReason reason, // IN: reason for esaping
+ void *context) // IN/OUT: convertion context
+{
+ HgfsEscapeContext *escapeContext = (HgfsEscapeContext *)context;
+ uint32 charactersToCopy;
+ uint32 outputSpace;
+ char* illegal;
+ Bool result = TRUE;
+
+ ASSERT(offset >= escapeContext->processedOffset); // Scanning forward
+ charactersToCopy = offset - escapeContext->processedOffset;
+
+ if (escapeContext->outputOffset + charactersToCopy >
+ escapeContext->outputBufferLength) {
+ return FALSE;
+ }
+
+ memcpy(escapeContext->outputBuffer + escapeContext->outputOffset,
+ bufIn + escapeContext->processedOffset, charactersToCopy * sizeof *bufIn);
+ escapeContext->outputOffset += charactersToCopy;
+ escapeContext->processedOffset += charactersToCopy;
+
+ outputSpace = escapeContext->outputBufferLength - escapeContext->outputOffset;
+
+ switch(reason) {
+ case HGFS_ESCAPE_ILLEGAL_CHARACTER:
+ if (outputSpace < 2) {
+ return FALSE;
+ }
+ illegal = strchr(HGFS_ILLEGAL_CHARS, bufIn[escapeContext->processedOffset]);
+ escapeContext->processedOffset++; // Skip illegal input character
+ ASSERT(illegal != NULL);
+ escapeContext->outputBuffer[escapeContext->outputOffset] =
+ HGFS_SUBSTITUTE_CHARS[illegal - HGFS_ILLEGAL_CHARS];
+ escapeContext->outputOffset++;
+ escapeContext->outputBuffer[escapeContext->outputOffset] = HGFS_ESCAPE_CHAR;
+ escapeContext->outputOffset++;
+ break;
+
+ case HGFS_ESCAPE_RESERVED_NAME:
+ if (outputSpace < 1) {
+ return FALSE;
+ }
+ escapeContext->outputBuffer[escapeContext->outputOffset] = HGFS_ESCAPE_CHAR;
+ escapeContext->outputOffset++;
+ break;
+
+ case HGFS_ESCAPE_ILLEGAL_LAST_CHARACTER:
+ if (outputSpace < 1) {
+ return FALSE;
+ }
+ escapeContext->outputBuffer[escapeContext->outputOffset] = HGFS_ESCAPE_CHAR;
+ escapeContext->outputOffset++;
+ break;
+
+ case HGFS_ESCAPE_ESCAPE_SEQUENCE:
+ if (outputSpace < 2) {
+ return FALSE;
+ }
+ escapeContext->processedOffset++; // Skip input esape character
+ escapeContext->outputBuffer[escapeContext->outputOffset] = HGFS_ESCAPE_SUBSTITUE_CHAR;
+ escapeContext->outputOffset++;
+ escapeContext->outputBuffer[escapeContext->outputOffset] = HGFS_ESCAPE_CHAR;
+ escapeContext->outputOffset++;
+ break;
+
+ case HGFS_ESCAPE_COMPLETE:
+ if (outputSpace < 1) {
+ return FALSE;
+ }
+ escapeContext->outputBuffer[escapeContext->outputOffset] = '\0';
+ break;
+
+ default:
+ result = FALSE;
+ ASSERT(FALSE);
+ }
+ return result;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsCountEscapeChars --
+ *
+ * Callback function that is called by HgfsEnumerate to count additional characters
+ * that need to be inserted in the input name.
+ *
+ * Results:
+ * TRUE since it never fails.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+HgfsCountEscapeChars(char const *bufIn, // IN: input name
+ uint32 offset, // IN: offset where escape is needed
+ HgfsEscapeReason reason, // IN: reason for escaping
+ void *context) // IN/OUT: context info
+{
+ UNREFERENCED_PARAMETER(bufIn);
+ UNREFERENCED_PARAMETER(offset);
+ if (reason != HGFS_ESCAPE_COMPLETE) {
+ uint32 *counter = (uint32*)context;
+ (*counter)++;
+ }
+ return TRUE;
+}
+
+
+#ifdef _WIN32
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsLetterToUpper --
+ *
+ * Converts lowercase English letters to uppercase.
+ * If the symbol is not a lowercase English letter returns the original character.
+ *
+ * Results:
+ * Converted character.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static char
+HgfsLetterToUpper(char letter)
+{
+ if (letter >= 'a' && letter <= 'z') {
+ return letter - ('a' - 'A');
+ }
+ return letter;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsIsEqualPrefix --
+ *
+ * Verifies if the string prefix is equal to the given prefix.
+ * It assumes that the prefix includes only uppercase English letters or numbers
+ * and it does not have any international characters.
+ * The string must be either NULL terminated or not shorter then the prefix.
+ *
+ * Results:
+ * TRUE if the uppcased string starts with the given prefix. False otherwise.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+HgfsIsEqualPrefix(char const *prefix, // IN: prefix to check
+ char const *string, // IN: input string
+ uint32 prefixLength) // IN: length of the prefix in characters
+{
+ int i;
+ for (i = 0; i < prefixLength; i++) {
+ ASSERT(prefix[i] > 0 && (prefix[i] < 'a' || prefix[i] > 'z' ));
+ if (prefix[i] != HgfsLetterToUpper(string[i])) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsIsReservedPrefix --
+ *
+ * Verifies if the name's prefix is one of the reserved names.
+ *
+ * Results:
+ * TRUE if the name's prefix is one of the reserved names.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+HgfsIsReservedPrefix(char const *bufIn) // IN: input name
+{
+ uint32 i;
+ for (i = 0; i < ARRAYSIZE(HgfsReservedNames); i++) {
+ if (HgfsIsEqualPrefix(HgfsReservedNames[i], bufIn,
+ HGFS_RESERVED_NAME_CHARS_LENGTH)) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsIsReservedPrefixWithNumber --
+ *
+ * Verifies if the name's prefix is one of the reserved names with number:
+ * COM1-9 or LPT1-9.
+ *
+ * Results:
+ * TRUE if the name's prefix is one of the reserved names with number.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+HgfsIsReservedPrefixWithNumber(char const *bufIn) // IN: input name
+{
+ uint32 i;
+ for (i = 0; i < ARRAYSIZE(HgfsReservedNamesWithNumber); i++) {
+ if (HgfsIsEqualPrefix(HgfsReservedNamesWithNumber[i], bufIn,
+ HGFS_RESERVED_NAME_CHARS_LENGTH) &&
+ bufIn[HGFS_RESERVED_NAME_CHARS_LENGTH] >= '1' &&
+ bufIn[HGFS_RESERVED_NAME_CHARS_LENGTH] <= '9') {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsIsSpecialCaseEscape --
+ *
+ * Verifies if the escape character is a part of special case escape sequence
+ * that exists only in Windows - escaped reserved name or escaped illegal last
+ * character.
+ *
+ * Results:
+ * TRUE if the name's prefix is one of the reserved names with number.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+HgfsIsSpecialCaseEscape(char const *bufIn, // IN: input name
+ uint32 offset, // IN: offset of the escape character
+ uint32 length) // IN: length of the name in characters
+{
+ if (offset + 1 == length &&
+ strchr(HGFS_ILLEGAL_LAST_CHARS, bufIn[offset - 1]) != NULL) {
+ return TRUE;
+ }
+ if (offset == HGFS_RESERVED_NAME_CHARS_LENGTH &&
+ (length == HGFS_RESERVED_NAME_CHARS_LENGTH + 1 || bufIn[offset+1] == '.')) {
+ return HgfsIsReservedPrefix(bufIn);
+ }
+ if (offset == HGFS_RESERVED_NAME_WITH_NUMBER_CHARS_LENGTH &&
+ (length == HGFS_RESERVED_NAME_WITH_NUMBER_CHARS_LENGTH + 1 ||
+ bufIn[offset+1] == '.')) {
+ return HgfsIsReservedPrefixWithNumber(bufIn);
+ }
+ return FALSE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsProcessReservedName --
+ *
+ * Verifies if the name is one of reserved Windows file names.
+ * If it is a reserved name invokes callback that performs required
+ * processing.
+ *
+ * Results:
+ * TRUE if no processing is required of if processing succeeded,
+ * FALSE if processing failed.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+HgfsProcessReservedName(char const *bufIn, // IN: Unescaped input buffer
+ uint32 sizeIn, // IN: Length of the input
+ HgfsEnumCallback processEscape, // IN: Callack that is invoked
+ // if input is reserved name
+ uint32 *offset, // OUT: New offset in the input
+ void *context) // IN/OUT: Context for callback
+{
+ /* Look reserved names: CON, PRN, AUX, NUL. */
+ if (sizeIn >= HGFS_RESERVED_NAME_CHARS_LENGTH && HgfsIsReservedPrefix(bufIn)) {
+ if (HGFS_RESERVED_NAME_CHARS_LENGTH == sizeIn ||
+ bufIn[HGFS_RESERVED_NAME_CHARS_LENGTH] == '.') {
+ if (!processEscape(bufIn, HGFS_RESERVED_NAME_CHARS_LENGTH,
+ HGFS_ESCAPE_RESERVED_NAME, context)) {
+ return FALSE;
+ }
+ *offset = HGFS_RESERVED_NAME_CHARS_LENGTH;
+ }
+ }
+
+ /* Look reserved names with numbers: COM1-9 and LPT1-9. */
+ if (sizeIn >= HGFS_RESERVED_NAME_WITH_NUMBER_CHARS_LENGTH &&
+ HgfsIsReservedPrefixWithNumber(bufIn)) {
+ if (HGFS_RESERVED_NAME_WITH_NUMBER_CHARS_LENGTH == sizeIn ||
+ bufIn[HGFS_RESERVED_NAME_WITH_NUMBER_CHARS_LENGTH] == '.') {
+ if (!processEscape(bufIn, HGFS_RESERVED_NAME_WITH_NUMBER_CHARS_LENGTH,
+ HGFS_ESCAPE_RESERVED_NAME, context)) {
+ return FALSE;
+ }
+ *offset = HGFS_RESERVED_NAME_WITH_NUMBER_CHARS_LENGTH;
+ }
+ }
+ return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsProcessLastCharacter --
+ *
+ * Verifies if the trailing character in the name is a valid last character.
+ * In Windows it is illegal to have a file name that ends with dot ('.') or
+ * space (' '). The only exception is "." and ".." directory names.
+ * If the last character is invalid the function invokes a callback to process it.
+ *
+ * Results:
+ * TRUE if no processing is required of if processing succeeded,
+ * FALSE if processing failed.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+HgfsProcessLastCharacter(char const *bufIn, // IN: Unescaped input buffer
+ uint32 sizeIn, // IN: Length of the input
+ HgfsEnumCallback processEscape, // IN: Callack that is invoked
+ // when escaping is needed
+ void *context) // IN/OUT: Callback context
+{
+
+ /* If the filename is '.' or '..' we shouldn't escape it. */
+ if ((sizeIn == 1 && bufIn[0] == '.') ||
+ (sizeIn == 2 && bufIn[0] == '.' && bufIn[1] == '.')) {
+ return TRUE;
+ }
+
+ /* Invoke the callback if the last character is illegal. */
+ if (strchr(HGFS_ILLEGAL_LAST_CHARS, bufIn[sizeIn - 1]) != NULL) {
+ if (!processEscape(bufIn, sizeIn, HGFS_ESCAPE_ILLEGAL_LAST_CHARACTER, context)) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+#endif // WIN32
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsIsEscapeSequence --
+ *
+ * Verifies if input buffer has an escape sequence at the position
+ * defined by offset.
+ *
+ * Results:
+ * TRUE if there is an escape sequence at the position defined by offset.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+HgfsIsEscapeSequence(char const *bufIn, // IN: input name
+ uint32 offset, // IN: offset of the escape character
+ uint32 length) // IN: length of the name in characters
+{
+ if (bufIn[offset] == HGFS_ESCAPE_CHAR && offset > 0) {
+ char *substitute;
+ if (bufIn[offset - 1] == HGFS_ESCAPE_SUBSTITUE_CHAR) {
+ return TRUE;
+ }
+ substitute = strchr(HGFS_SUBSTITUTE_CHARS, bufIn[offset - 1]);
+ if (substitute != NULL) {
+ return TRUE;
+ }
+ return IS_SPECIAL_CASE_ESCAPE(bufIn,offset,length);
+ }
+ return FALSE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsEscapeEnumerate --
+ *
+ * The function scans the input buffer and calls processEscape callback for every
+ * place in the input buffer which require escaping.
+ *
+ * Callback does the required processing. There are two different callbacks -
+ * one counts extra symbols that are needed for escaping and another produces
+ * escaped output name based on input name.
+ *
+ * 1. The first function calculates number of extra characters. It just increments
+ * a counter which is passed to it in context variable every time it is called
+ * for the reason different from "complete processing" assuming that
+ * exactly one extra character is required to escape any invalid input.
+ *
+ * 2. The second function produces output name by copying everything from input
+ * name into the output name up to the place which require escaping and
+ * then inserts appropriate escape sequence into the output. It keeps track of its
+ * progress and keeps pointer to the output buffer in the context variable.
+ * HgfsEscapeEnumerate calls calback function one more time at the end of the
+ * input buffer to let callback finish processing of the input (for example copy
+ * the rest of the name after the last escape sequence from input buffer to
+ * output buffer).
+ *
+ * Results:
+ * TRUE if the input has been processed successfully by the callback, false otherwise.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+HgfsEscapeEnumerate(char const *bufIn, // IN: Buffer with unescaped input
+ uint32 sizeIn, // IN: Number of input *characters*
+ HgfsEnumCallback processEscape, // IN: Callack that is invoked every
+ // time escaping is required
+ void *context) // IN/OUT: Context for processEscape
+{
+ /* First look for invalid characters in the input name. */
+ uint32 i, offset = 0;
+ if (sizeIn == 0) {
+ return TRUE;
+ }
+
+ ASSERT(processEscape);
+
+ PROCESS_RESERVED_NAME(bufIn, sizeIn, processEscape, &offset, context);
+
+ for (i = offset; i < sizeIn; i++) {
+ if (strchr(HGFS_ILLEGAL_CHARS, bufIn[i]) != NULL) {
+ if (!processEscape(bufIn, i, HGFS_ESCAPE_ILLEGAL_CHARACTER, context)) {
+ return FALSE;
+ }
+ } else if (HgfsIsEscapeSequence(bufIn, i, sizeIn)) {
+ if (!processEscape(bufIn, i, HGFS_ESCAPE_ESCAPE_SEQUENCE, context)) {
+ return FALSE;
+ }
+ }
+ }
+
+ PROCESS_LAST_CHARACTER(bufIn, sizeIn, processEscape, context);
+
+ if (!processEscape(bufIn, sizeIn, HGFS_ESCAPE_COMPLETE, context)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsEscape_Do --
+ *
+ * Escape any characters that are not legal in a windows filename.
+ * Escape reserved file names that can't be used in Windows.
+ * We also of course have to escape the escape character, which is "%",
+ * when it is part of a character sequence that would require unescaping
+ *
+ * sizeBufOut must account for the NUL terminator.
+ *
+ * Results:
+ * On success, the size (excluding the NUL terminator) of the
+ * escaped, NUL terminated buffer.
+ * On failure (bufOut not big enough to hold result), negative value.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int
+HgfsEscape_Do(char const *bufIn, // IN: Buffer with unescaped input
+ uint32 sizeIn, // IN: Size of input buffer
+ uint32 sizeBufOut, // IN: Size of output buffer
+ char *bufOut) // OUT: Buffer for escaped output
+{
+ const char *currentComponent = bufIn;
+ uint32 sizeLeft = sizeBufOut;
+ char *outPointer = bufOut;
+ const char *end = bufIn + sizeIn;
+ const char *next;
+ ASSERT(sizeIn > 0);
+ if (bufIn[sizeIn - 1] == '\0') {
+ /*
+ * In some cases a NUL terminated string is passed to HgfsEscape_Do
+ * so it make sense to support such input even if CPName_GetComponent
+ * does not. Detect this case and make the input compliant with
+ * CPName_GetComponent by removing terminating NUL.
+ */
+ end--;
+ sizeIn--;
+ }
+ /*
+ * Absolute symbolic link name starts with the '\0'. HgfsEscapeDo needs to work
+ * with such names. Leading NULL symbols should be skipped here since
+ * CPName_GetComponent does not support such names.
+ */
+ while (*currentComponent == '\0' && currentComponent - bufIn < sizeIn) {
+ currentComponent++;
+ sizeLeft--;
+ *outPointer++ = '\0';
+ }
+ while (currentComponent - bufIn < sizeIn) {
+ int escapedLength;
+ uint32 componentSize = CPName_GetComponent(currentComponent, end, &next);
+
+ escapedLength = HgfsEscapeDoComponent(currentComponent, componentSize,
+ sizeLeft, outPointer);
+ if (escapedLength < 0) {
+ return escapedLength;
+ }
+ currentComponent = next;
+ sizeLeft -= escapedLength + 1;
+ outPointer += escapedLength + 1;
+ }
+ return (int) (outPointer - bufOut) - 1; // Do not count the last NUL terminator
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsEscape_GetSize --
+ *
+ * Calculates required size in bytes for the buffer that is needed to hold escaped
+ * cross platform path name. Returns 0 if no escaping is required.
+ *
+ * Results:
+ * On success, the size (excluding the NUL terminator) of the
+ * escaped, NUL terminated buffer.
+ * Returns 0 if the name is a valid Windows file name.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int
+HgfsEscape_GetSize(char const *bufIn, // IN: Buffer with unescaped input
+ uint32 sizeIn) // IN: Size of the input buffer
+{
+ uint32 result = 0;
+ const char *currentComponent = bufIn;
+ const char *end = bufIn + sizeIn;
+ const char *next;
+
+ if (sizeIn == 0) { // No need toescape empty name.
+ return 0;
+ }
+ if (bufIn[sizeIn - 1] == '\0') {
+ /*
+ * In some cases a NUL terminated string is passed to HgfsEscape_GeSize
+ * so it make sense to support such input even if CPName_GetComponent
+ * does not. Detect this case and make the input compliant with
+ * CPName_GetComponent by removing terminating NUL.
+ */
+ end--;
+ sizeIn--;
+ }
+ /* Skip leading NULs to keep CPName_GetComponent happy. */
+ while (*currentComponent == '\0' && currentComponent - bufIn < sizeIn) {
+ currentComponent++;
+ }
+ while (currentComponent - bufIn < sizeIn) {
+ uint32 componentSize = CPName_GetComponent(currentComponent, end, &next);
+ result += HgfsEscapeGetComponentSize(currentComponent, componentSize);
+ currentComponent = next;
+ }
+ return (result == 0) ? 0 : result + sizeIn;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsEscape_Undo --
+ *
+ * Unescape a buffer that was escaped using HgfsEscapeBuffer.
+ *
+ * The unescaping is done in place in the input buffer, and
+ * can not fail.
+ *
+ * Results:
+ * The size (excluding the NUL terminator) of the unescaped, NUL
+ * terminated buffer.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int
+HgfsEscape_Undo(char *bufIn, // IN: Characters to be unescaped
+ uint32 sizeIn) // IN: Number of characters in bufIn
+{
+ uint32 componentSize = strlen(bufIn) + 1;
+ uint32 unprocessedSize = sizeIn + 1;
+ uint32 result = 0;
+ char *currentComponent = bufIn;
+ while (currentComponent != NULL) {
+ HgfsEscapeUndoComponent(currentComponent, &unprocessedSize);
+ componentSize = strlen(currentComponent) + 1; // Unescaped size
+ result += componentSize;
+ if (unprocessedSize > 1) {
+ currentComponent = currentComponent + componentSize;
+ componentSize = strlen(currentComponent) + 1; // Size of the next component
+ } else {
+ currentComponent = NULL;
+ }
+ }
+ return result - 1;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsEscapeUndoComponent --
+ *
+ * Unescape a buffer that was escaped using HgfsEscapeBuffer.
+ *
+ * The unescaping is done in place in the input buffer, and
+ * can not fail.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+HgfsEscapeUndoComponent(char *bufIn, // IN: Characters to be unescaped
+ uint32 *unprocessedLength) // IN: Unprocessed characters
+ // in the whole name
+{
+ size_t offset;
+ size_t sizeIn = strlen(bufIn);
+ char* curOutBuffer = bufIn;
+ char* escapePointer;
+ ASSERT(bufIn);
+
+ escapePointer = strchr(curOutBuffer, HGFS_ESCAPE_CHAR);
+ while (escapePointer != NULL) {
+ offset = escapePointer - bufIn;
+ if (HgfsIsEscapeSequence(bufIn, offset, sizeIn)) {
+ char* substitute = strchr(HGFS_SUBSTITUTE_CHARS, bufIn[offset - 1]);
+ if (substitute != NULL) {
+ bufIn[offset - 1] = HGFS_ILLEGAL_CHARS[substitute - HGFS_SUBSTITUTE_CHARS];
+ } else if (bufIn[offset - 1] == HGFS_ESCAPE_SUBSTITUE_CHAR) {
+ bufIn[offset - 1] = HGFS_ESCAPE_CHAR;
+ }
+ memmove(escapePointer, escapePointer + 1, (*unprocessedLength) - offset - 1);
+ (*unprocessedLength)--;
+ sizeIn--;
+ if (sizeIn > 0) {
+ escapePointer = strchr(escapePointer, HGFS_ESCAPE_CHAR);
+ } else {
+ escapePointer = NULL;
+ }
+ } else {
+ escapePointer = strchr(escapePointer + 1, HGFS_ESCAPE_CHAR);
+ }
+ }
+ ASSERT((*unprocessedLength) > sizeIn);
+ (*unprocessedLength) -= sizeIn + 1;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsEscapeDoComponent --
+ *
+ * Escape any characters that are not legal in a windows filename.
+ * Escape reserved file names that can't be used in Windows.
+ * We also of course have to escape the escape character, which is "%",
+ * when it is part of a character sequence that would require unescaping
+ *
+ * sizeBufOut must account for the NUL terminator.
+ *
+ * Results:
+ * On success, the size (excluding the NUL terminator) of the
+ * escaped, NUL terminated buffer.
+ * On failure (bufOut not big enough to hold result), negative value.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int
+HgfsEscapeDoComponent(char const *bufIn, // IN: Buffer with unescaped input
+ uint32 sizeIn, // IN: Size of input buffer
+ uint32 sizeBufOut, // IN: Size of output buffer
+ char *bufOut) // OUT: Buffer for escaped output
+{
+ HgfsEscapeContext conversionContext;
+ conversionContext.processedOffset = 0;
+ conversionContext.outputBufferLength = sizeBufOut / sizeof *bufOut;
+ conversionContext.outputOffset = 0;
+ conversionContext.outputBuffer = bufOut;
+
+ if (!HgfsEscapeEnumerate(bufIn, sizeIn, HgfsAddEscapeCharacter, &conversionContext)) {
+ return -1;
+ }
+ return conversionContext.outputOffset * sizeof *bufOut;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsEscapeGetComponentSize --
+ *
+ * Calculates number of addtitional characters that are needed to escape
+ * name for one NUL terminated component of the path.
+ *
+ * Results:
+ * Number of additional escape characters needed to escape the name.
+ * Returns 0 if no escaping is required.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int
+HgfsEscapeGetComponentSize(char const *bufIn, // IN: Buffer with unescaped input
+ uint32 sizeIn) // IN: Size of the in input buffer
+{
+ int result = 0;
+ HgfsEscapeEnumerate(bufIn, sizeIn, HgfsCountEscapeChars, &result);
+ return result;
+}
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no 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. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/*
+ * hgfsEscape.h --
+ *
+ * Escape and unescape filenames that are not legal on a particular
+ * platform.
+ *
+ */
+
+#ifndef __HGFS_ESCAPE_H__
+#define __HGFS_ESCAPE_H__
+
+int HgfsEscape_GetSize(char const *bufIn, // IN
+ uint32 sizeIn); // IN
+int HgfsEscape_Do(char const *bufIn, // IN
+ uint32 sizeIn, // IN
+ uint32 sizeBufOut, // IN
+ char *bufOut); // OUT
+
+int HgfsEscape_Undo(char *bufIn, // IN
+ uint32 sizeIn); // IN
+
+#endif // __HGFS_ESCAPE_H__
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. 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 version 2 and no 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. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ *********************************************************/
+
+/*
+ * hgfsEscape.c --
+ *
+ * Escape and unescape illegal filenames for different platforms.
+ *
+ */
+
+#ifdef __KERNEL__
+# include "driver-config.h"
+# include <linux/string.h>
+#elif defined(__FreeBSD__)
+# if defined(_KERNEL)
+# include <sys/libkern.h>
+# define strchr(s,c) index(s,c)
+# else
+# include <string.h>
+# endif
+# define memmove(s1,s2,n) bcopy(s2,s1,n)
+#elif defined(__APPLE__) && defined(KERNEL)
+# include <string.h>
+#elif !defined(sun)
+# include <stdlib.h>
+# include <string.h>
+#else
+# include <string.h>
+#endif
+
+#include "vmware.h"
+#include "hgfsEscape.h"
+#include "cpName.h"
+
+#ifdef _WIN32
+
+#define UNREFERENCED_PARAMETER(P) (P)
+
+/* These characters are illegal in Windows file names. */
+const char* HGFS_ILLEGAL_CHARS = "/\\*?:\"<>|";
+const char* HGFS_SUBSTITUTE_CHARS = "!@#$^&(){}";
+/* Last character of a file name in Windows can be neither dot nor space. */
+const char* HGFS_ILLEGAL_LAST_CHARS = ". ";
+
+/* http://msdn.microsoft.com/en-us/library/aa365247.aspx */
+char *HgfsReservedNames[] = {"CON", "PRN", "AUX", "NUL"};
+char *HgfsReservedNamesWithNumber[] = {"COM", "LPT"};
+
+#define HGFS_RESERVED_NAME_CHARS_LENGTH 3
+#define HGFS_RESERVED_NAME_WITH_NUMBER_CHARS_LENGTH (HGFS_RESERVED_NAME_CHARS_LENGTH + 1)
+/* Check for special escaping cases - reserved names and illegal last characters. */
+#define IS_SPECIAL_CASE_ESCAPE(b,o,l) HgfsIsSpecialCaseEscape(b,o,l)
+/* Process Windows reserved names. */
+#define PROCESS_RESERVED_NAME(b,s,p,o,c) \
+if (!HgfsProcessReservedName(b,s,p,o,c)) \
+{ \
+ return FALSE; \
+}
+/* Process Windows reserved names. */
+#define PROCESS_LAST_CHARACTER(b,s,p,c) \
+if (!HgfsProcessLastCharacter(b,s,p,c)) \
+{ \
+ return FALSE; \
+}
+
+#else // _WIN32
+
+#define UNREFERENCED_PARAMETER(P)
+/* There is no special escape sequences on other than Windows platforms. */
+#define IS_SPECIAL_CASE_ESCAPE(b,o,l) FALSE
+/* There is no reserved names on other then Windows platforms. */
+#define PROCESS_RESERVED_NAME(b,s,p,o,c)
+/* There is no special processing for the last character on non-Windows platforms. */
+#define PROCESS_LAST_CHARACTER(b,s,p,c)
+
+#if defined(__APPLE__)
+/* These characters are illegal in MAC OS file names. */
+const char* HGFS_ILLEGAL_CHARS = "/:";
+const char* HGFS_SUBSTITUTE_CHARS = "!&";
+#else // __APPLE__
+/* These characters are illegal in Linux file names. */
+const char* HGFS_ILLEGAL_CHARS = "/";
+const char* HGFS_SUBSTITUTE_CHARS = "!";
+#endif // __APPLE__
+
+#endif // _WIN32
+
+#define HGFS_ESCAPE_CHAR '%'
+#define HGFS_ESCAPE_SUBSTITUE_CHAR ']'
+
+typedef enum {
+ HGFS_ESCAPE_ILLEGAL_CHARACTER,
+ HGFS_ESCAPE_RESERVED_NAME,
+ HGFS_ESCAPE_ILLEGAL_LAST_CHARACTER,
+ HGFS_ESCAPE_ESCAPE_SEQUENCE,
+ HGFS_ESCAPE_COMPLETE
+} HgfsEscapeReason;
+
+
+typedef Bool (*HgfsEnumCallback)(char const *bufIn,
+ uint32 offset,
+ HgfsEscapeReason reason,
+ void* context);
+
+/*
+ * The structure is used by HgfsAddEscapeCharacter to keep context information between
+ * invocations
+ * All offsets defined in this structure are in characters, not bytes
+ */
+typedef struct {
+ uint32 processedOffset; // Offset of the first unprocessed input character
+ uint32 outputBufferLength; // Number of characters in the output buffer
+ uint32 outputOffset; // Number of characters that are already in the output
+ char *outputBuffer; // Pointer to the output buffer
+} HgfsEscapeContext;
+
+static void HgfsEscapeUndoComponent(char *bufIn, uint32 *totalLength);
+static int HgfsEscapeGetComponentSize(char const *bufIn, uint32 sizeIn);
+static int HgfsEscapeDoComponent(char const *bufIn, uint32 sizeIn, uint32 sizeBufOut,
+ char *bufOut);
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsAddEscapeCharacter --
+ *
+ * Callback function that is called by HgfsEnumerate to insert an escape sequence
+ * into the input name.
+ *
+ * Results:
+ * TRUE if successful, FALSE if there is an error like the output buffer is
+ * too small.
+ *
+ * Side effects:
+ * Updates the output buffer pointer (stored in the context variable).
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+HgfsAddEscapeCharacter(char const * bufIn, // IN: input name
+ uint32 offset, // IN: offset that requires escaping
+ HgfsEscapeReason reason, // IN: reason for esaping
+ void *context) // IN/OUT: convertion context
+{
+ HgfsEscapeContext *escapeContext = (HgfsEscapeContext *)context;
+ uint32 charactersToCopy;
+ uint32 outputSpace;
+ char* illegal;
+ Bool result = TRUE;
+
+ ASSERT(offset >= escapeContext->processedOffset); // Scanning forward
+ charactersToCopy = offset - escapeContext->processedOffset;
+
+ if (escapeContext->outputOffset + charactersToCopy >
+ escapeContext->outputBufferLength) {
+ return FALSE;
+ }
+
+ memcpy(escapeContext->outputBuffer + escapeContext->outputOffset,
+ bufIn + escapeContext->processedOffset, charactersToCopy * sizeof *bufIn);
+ escapeContext->outputOffset += charactersToCopy;
+ escapeContext->processedOffset += charactersToCopy;
+
+ outputSpace = escapeContext->outputBufferLength - escapeContext->outputOffset;
+
+ switch(reason) {
+ case HGFS_ESCAPE_ILLEGAL_CHARACTER:
+ if (outputSpace < 2) {
+ return FALSE;
+ }
+ illegal = strchr(HGFS_ILLEGAL_CHARS, bufIn[escapeContext->processedOffset]);
+ escapeContext->processedOffset++; // Skip illegal input character
+ ASSERT(illegal != NULL);
+ escapeContext->outputBuffer[escapeContext->outputOffset] =
+ HGFS_SUBSTITUTE_CHARS[illegal - HGFS_ILLEGAL_CHARS];
+ escapeContext->outputOffset++;
+ escapeContext->outputBuffer[escapeContext->outputOffset] = HGFS_ESCAPE_CHAR;
+ escapeContext->outputOffset++;
+ break;
+
+ case HGFS_ESCAPE_RESERVED_NAME:
+ if (outputSpace < 1) {
+ return FALSE;
+ }
+ escapeContext->outputBuffer[escapeContext->outputOffset] = HGFS_ESCAPE_CHAR;
+ escapeContext->outputOffset++;
+ break;
+
+ case HGFS_ESCAPE_ILLEGAL_LAST_CHARACTER:
+ if (outputSpace < 1) {
+ return FALSE;
+ }
+ escapeContext->outputBuffer[escapeContext->outputOffset] = HGFS_ESCAPE_CHAR;
+ escapeContext->outputOffset++;
+ break;
+
+ case HGFS_ESCAPE_ESCAPE_SEQUENCE:
+ if (outputSpace < 2) {
+ return FALSE;
+ }
+ escapeContext->processedOffset++; // Skip input esape character
+ escapeContext->outputBuffer[escapeContext->outputOffset] = HGFS_ESCAPE_SUBSTITUE_CHAR;
+ escapeContext->outputOffset++;
+ escapeContext->outputBuffer[escapeContext->outputOffset] = HGFS_ESCAPE_CHAR;
+ escapeContext->outputOffset++;
+ break;
+
+ case HGFS_ESCAPE_COMPLETE:
+ if (outputSpace < 1) {
+ return FALSE;
+ }
+ escapeContext->outputBuffer[escapeContext->outputOffset] = '\0';
+ break;
+
+ default:
+ result = FALSE;
+ ASSERT(FALSE);
+ }
+ return result;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsCountEscapeChars --
+ *
+ * Callback function that is called by HgfsEnumerate to count additional characters
+ * that need to be inserted in the input name.
+ *
+ * Results:
+ * TRUE since it never fails.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+HgfsCountEscapeChars(char const *bufIn, // IN: input name
+ uint32 offset, // IN: offset where escape is needed
+ HgfsEscapeReason reason, // IN: reason for escaping
+ void *context) // IN/OUT: context info
+{
+ UNREFERENCED_PARAMETER(bufIn);
+ UNREFERENCED_PARAMETER(offset);
+ if (reason != HGFS_ESCAPE_COMPLETE) {
+ uint32 *counter = (uint32*)context;
+ (*counter)++;
+ }
+ return TRUE;
+}
+
+
+#ifdef _WIN32
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsLetterToUpper --
+ *
+ * Converts lowercase English letters to uppercase.
+ * If the symbol is not a lowercase English letter returns the original character.
+ *
+ * Results:
+ * Converted character.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static char
+HgfsLetterToUpper(char letter)
+{
+ if (letter >= 'a' && letter <= 'z') {
+ return letter - ('a' - 'A');
+ }
+ return letter;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsIsEqualPrefix --
+ *
+ * Verifies if the string prefix is equal to the given prefix.
+ * It assumes that the prefix includes only uppercase English letters or numbers
+ * and it does not have any international characters.
+ * The string must be either NULL terminated or not shorter then the prefix.
+ *
+ * Results:
+ * TRUE if the uppcased string starts with the given prefix. False otherwise.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+HgfsIsEqualPrefix(char const *prefix, // IN: prefix to check
+ char const *string, // IN: input string
+ uint32 prefixLength) // IN: length of the prefix in characters
+{
+ int i;
+ for (i = 0; i < prefixLength; i++) {
+ ASSERT(prefix[i] > 0 && (prefix[i] < 'a' || prefix[i] > 'z' ));
+ if (prefix[i] != HgfsLetterToUpper(string[i])) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsIsReservedPrefix --
+ *
+ * Verifies if the name's prefix is one of the reserved names.
+ *
+ * Results:
+ * TRUE if the name's prefix is one of the reserved names.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+HgfsIsReservedPrefix(char const *bufIn) // IN: input name
+{
+ uint32 i;
+ for (i = 0; i < ARRAYSIZE(HgfsReservedNames); i++) {
+ if (HgfsIsEqualPrefix(HgfsReservedNames[i], bufIn,
+ HGFS_RESERVED_NAME_CHARS_LENGTH)) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsIsReservedPrefixWithNumber --
+ *
+ * Verifies if the name's prefix is one of the reserved names with number:
+ * COM1-9 or LPT1-9.
+ *
+ * Results:
+ * TRUE if the name's prefix is one of the reserved names with number.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+HgfsIsReservedPrefixWithNumber(char const *bufIn) // IN: input name
+{
+ uint32 i;
+ for (i = 0; i < ARRAYSIZE(HgfsReservedNamesWithNumber); i++) {
+ if (HgfsIsEqualPrefix(HgfsReservedNamesWithNumber[i], bufIn,
+ HGFS_RESERVED_NAME_CHARS_LENGTH) &&
+ bufIn[HGFS_RESERVED_NAME_CHARS_LENGTH] >= '1' &&
+ bufIn[HGFS_RESERVED_NAME_CHARS_LENGTH] <= '9') {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsIsSpecialCaseEscape --
+ *
+ * Verifies if the escape character is a part of special case escape sequence
+ * that exists only in Windows - escaped reserved name or escaped illegal last
+ * character.
+ *
+ * Results:
+ * TRUE if the name's prefix is one of the reserved names with number.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+HgfsIsSpecialCaseEscape(char const *bufIn, // IN: input name
+ uint32 offset, // IN: offset of the escape character
+ uint32 length) // IN: length of the name in characters
+{
+ if (offset + 1 == length &&
+ strchr(HGFS_ILLEGAL_LAST_CHARS, bufIn[offset - 1]) != NULL) {
+ return TRUE;
+ }
+ if (offset == HGFS_RESERVED_NAME_CHARS_LENGTH &&
+ (length == HGFS_RESERVED_NAME_CHARS_LENGTH + 1 || bufIn[offset+1] == '.')) {
+ return HgfsIsReservedPrefix(bufIn);
+ }
+ if (offset == HGFS_RESERVED_NAME_WITH_NUMBER_CHARS_LENGTH &&
+ (length == HGFS_RESERVED_NAME_WITH_NUMBER_CHARS_LENGTH + 1 ||
+ bufIn[offset+1] == '.')) {
+ return HgfsIsReservedPrefixWithNumber(bufIn);
+ }
+ return FALSE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsProcessReservedName --
+ *
+ * Verifies if the name is one of reserved Windows file names.
+ * If it is a reserved name invokes callback that performs required
+ * processing.
+ *
+ * Results:
+ * TRUE if no processing is required of if processing succeeded,
+ * FALSE if processing failed.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+HgfsProcessReservedName(char const *bufIn, // IN: Unescaped input buffer
+ uint32 sizeIn, // IN: Length of the input
+ HgfsEnumCallback processEscape, // IN: Callack that is invoked
+ // if input is reserved name
+ uint32 *offset, // OUT: New offset in the input
+ void *context) // IN/OUT: Context for callback
+{
+ /* Look reserved names: CON, PRN, AUX, NUL. */
+ if (sizeIn >= HGFS_RESERVED_NAME_CHARS_LENGTH && HgfsIsReservedPrefix(bufIn)) {
+ if (HGFS_RESERVED_NAME_CHARS_LENGTH == sizeIn ||
+ bufIn[HGFS_RESERVED_NAME_CHARS_LENGTH] == '.') {
+ if (!processEscape(bufIn, HGFS_RESERVED_NAME_CHARS_LENGTH,
+ HGFS_ESCAPE_RESERVED_NAME, context)) {
+ return FALSE;
+ }
+ *offset = HGFS_RESERVED_NAME_CHARS_LENGTH;
+ }
+ }
+
+ /* Look reserved names with numbers: COM1-9 and LPT1-9. */
+ if (sizeIn >= HGFS_RESERVED_NAME_WITH_NUMBER_CHARS_LENGTH &&
+ HgfsIsReservedPrefixWithNumber(bufIn)) {
+ if (HGFS_RESERVED_NAME_WITH_NUMBER_CHARS_LENGTH == sizeIn ||
+ bufIn[HGFS_RESERVED_NAME_WITH_NUMBER_CHARS_LENGTH] == '.') {
+ if (!processEscape(bufIn, HGFS_RESERVED_NAME_WITH_NUMBER_CHARS_LENGTH,
+ HGFS_ESCAPE_RESERVED_NAME, context)) {
+ return FALSE;
+ }
+ *offset = HGFS_RESERVED_NAME_WITH_NUMBER_CHARS_LENGTH;
+ }
+ }
+ return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsProcessLastCharacter --
+ *
+ * Verifies if the trailing character in the name is a valid last character.
+ * In Windows it is illegal to have a file name that ends with dot ('.') or
+ * space (' '). The only exception is "." and ".." directory names.
+ * If the last character is invalid the function invokes a callback to process it.
+ *
+ * Results:
+ * TRUE if no processing is required of if processing succeeded,
+ * FALSE if processing failed.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+HgfsProcessLastCharacter(char const *bufIn, // IN: Unescaped input buffer
+ uint32 sizeIn, // IN: Length of the input
+ HgfsEnumCallback processEscape, // IN: Callack that is invoked
+ // when escaping is needed
+ void *context) // IN/OUT: Callback context
+{
+
+ /* If the filename is '.' or '..' we shouldn't escape it. */
+ if ((sizeIn == 1 && bufIn[0] == '.') ||
+ (sizeIn == 2 && bufIn[0] == '.' && bufIn[1] == '.')) {
+ return TRUE;
+ }
+
+ /* Invoke the callback if the last character is illegal. */
+ if (strchr(HGFS_ILLEGAL_LAST_CHARS, bufIn[sizeIn - 1]) != NULL) {
+ if (!processEscape(bufIn, sizeIn, HGFS_ESCAPE_ILLEGAL_LAST_CHARACTER, context)) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+#endif // WIN32
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsIsEscapeSequence --
+ *
+ * Verifies if input buffer has an escape sequence at the position
+ * defined by offset.
+ *
+ * Results:
+ * TRUE if there is an escape sequence at the position defined by offset.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+HgfsIsEscapeSequence(char const *bufIn, // IN: input name
+ uint32 offset, // IN: offset of the escape character
+ uint32 length) // IN: length of the name in characters
+{
+ if (bufIn[offset] == HGFS_ESCAPE_CHAR && offset > 0) {
+ char *substitute;
+ if (bufIn[offset - 1] == HGFS_ESCAPE_SUBSTITUE_CHAR) {
+ return TRUE;
+ }
+ substitute = strchr(HGFS_SUBSTITUTE_CHARS, bufIn[offset - 1]);
+ if (substitute != NULL) {
+ return TRUE;
+ }
+ return IS_SPECIAL_CASE_ESCAPE(bufIn,offset,length);
+ }
+ return FALSE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsEscapeEnumerate --
+ *
+ * The function scans the input buffer and calls processEscape callback for every
+ * place in the input buffer which require escaping.
+ *
+ * Callback does the required processing. There are two different callbacks -
+ * one counts extra symbols that are needed for escaping and another produces
+ * escaped output name based on input name.
+ *
+ * 1. The first function calculates number of extra characters. It just increments
+ * a counter which is passed to it in context variable every time it is called
+ * for the reason different from "complete processing" assuming that
+ * exactly one extra character is required to escape any invalid input.
+ *
+ * 2. The second function produces output name by copying everything from input
+ * name into the output name up to the place which require escaping and
+ * then inserts appropriate escape sequence into the output. It keeps track of its
+ * progress and keeps pointer to the output buffer in the context variable.
+ * HgfsEscapeEnumerate calls calback function one more time at the end of the
+ * input buffer to let callback finish processing of the input (for example copy
+ * the rest of the name after the last escape sequence from input buffer to
+ * output buffer).
+ *
+ * Results:
+ * TRUE if the input has been processed successfully by the callback, false otherwise.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+HgfsEscapeEnumerate(char const *bufIn, // IN: Buffer with unescaped input
+ uint32 sizeIn, // IN: Number of input *characters*
+ HgfsEnumCallback processEscape, // IN: Callack that is invoked every
+ // time escaping is required
+ void *context) // IN/OUT: Context for processEscape
+{
+ /* First look for invalid characters in the input name. */
+ uint32 i, offset = 0;
+ if (sizeIn == 0) {
+ return TRUE;
+ }
+
+ ASSERT(processEscape);
+
+ PROCESS_RESERVED_NAME(bufIn, sizeIn, processEscape, &offset, context);
+
+ for (i = offset; i < sizeIn; i++) {
+ if (strchr(HGFS_ILLEGAL_CHARS, bufIn[i]) != NULL) {
+ if (!processEscape(bufIn, i, HGFS_ESCAPE_ILLEGAL_CHARACTER, context)) {
+ return FALSE;
+ }
+ } else if (HgfsIsEscapeSequence(bufIn, i, sizeIn)) {
+ if (!processEscape(bufIn, i, HGFS_ESCAPE_ESCAPE_SEQUENCE, context)) {
+ return FALSE;
+ }
+ }
+ }
+
+ PROCESS_LAST_CHARACTER(bufIn, sizeIn, processEscape, context);
+
+ if (!processEscape(bufIn, sizeIn, HGFS_ESCAPE_COMPLETE, context)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsEscape_Do --
+ *
+ * Escape any characters that are not legal in a windows filename.
+ * Escape reserved file names that can't be used in Windows.
+ * We also of course have to escape the escape character, which is "%",
+ * when it is part of a character sequence that would require unescaping
+ *
+ * sizeBufOut must account for the NUL terminator.
+ *
+ * Results:
+ * On success, the size (excluding the NUL terminator) of the
+ * escaped, NUL terminated buffer.
+ * On failure (bufOut not big enough to hold result), negative value.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int
+HgfsEscape_Do(char const *bufIn, // IN: Buffer with unescaped input
+ uint32 sizeIn, // IN: Size of input buffer
+ uint32 sizeBufOut, // IN: Size of output buffer
+ char *bufOut) // OUT: Buffer for escaped output
+{
+ const char *currentComponent = bufIn;
+ uint32 sizeLeft = sizeBufOut;
+ char *outPointer = bufOut;
+ const char *end = bufIn + sizeIn;
+ const char *next;
+ ASSERT(sizeIn > 0);
+ if (bufIn[sizeIn - 1] == '\0') {
+ /*
+ * In some cases a NUL terminated string is passed to HgfsEscape_Do
+ * so it make sense to support such input even if CPName_GetComponent
+ * does not. Detect this case and make the input compliant with
+ * CPName_GetComponent by removing terminating NUL.
+ */
+ end--;
+ sizeIn--;
+ }
+ /*
+ * Absolute symbolic link name starts with the '\0'. HgfsEscapeDo needs to work
+ * with such names. Leading NULL symbols should be skipped here since
+ * CPName_GetComponent does not support such names.
+ */
+ while (*currentComponent == '\0' && currentComponent - bufIn < sizeIn) {
+ currentComponent++;
+ sizeLeft--;
+ *outPointer++ = '\0';
+ }
+ while (currentComponent - bufIn < sizeIn) {
+ int escapedLength;
+ uint32 componentSize = CPName_GetComponent(currentComponent, end, &next);
+
+ escapedLength = HgfsEscapeDoComponent(currentComponent, componentSize,
+ sizeLeft, outPointer);
+ if (escapedLength < 0) {
+ return escapedLength;
+ }
+ currentComponent = next;
+ sizeLeft -= escapedLength + 1;
+ outPointer += escapedLength + 1;
+ }
+ return (int) (outPointer - bufOut) - 1; // Do not count the last NUL terminator
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsEscape_GetSize --
+ *
+ * Calculates required size in bytes for the buffer that is needed to hold escaped
+ * cross platform path name. Returns 0 if no escaping is required.
+ *
+ * Results:
+ * On success, the size (excluding the NUL terminator) of the
+ * escaped, NUL terminated buffer.
+ * Returns 0 if the name is a valid Windows file name.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int
+HgfsEscape_GetSize(char const *bufIn, // IN: Buffer with unescaped input
+ uint32 sizeIn) // IN: Size of the input buffer
+{
+ uint32 result = 0;
+ const char *currentComponent = bufIn;
+ const char *end = bufIn + sizeIn;
+ const char *next;
+
+ if (sizeIn == 0) { // No need toescape empty name.
+ return 0;
+ }
+ if (bufIn[sizeIn - 1] == '\0') {
+ /*
+ * In some cases a NUL terminated string is passed to HgfsEscape_GeSize
+ * so it make sense to support such input even if CPName_GetComponent
+ * does not. Detect this case and make the input compliant with
+ * CPName_GetComponent by removing terminating NUL.
+ */
+ end--;
+ sizeIn--;
+ }
+ /* Skip leading NULs to keep CPName_GetComponent happy. */
+ while (*currentComponent == '\0' && currentComponent - bufIn < sizeIn) {
+ currentComponent++;
+ }
+ while (currentComponent - bufIn < sizeIn) {
+ uint32 componentSize = CPName_GetComponent(currentComponent, end, &next);
+ result += HgfsEscapeGetComponentSize(currentComponent, componentSize);
+ currentComponent = next;
+ }
+ return (result == 0) ? 0 : result + sizeIn;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsEscape_Undo --
+ *
+ * Unescape a buffer that was escaped using HgfsEscapeBuffer.
+ *
+ * The unescaping is done in place in the input buffer, and
+ * can not fail.
+ *
+ * Results:
+ * The size (excluding the NUL terminator) of the unescaped, NUL
+ * terminated buffer.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int
+HgfsEscape_Undo(char *bufIn, // IN: Characters to be unescaped
+ uint32 sizeIn) // IN: Number of characters in bufIn
+{
+ uint32 componentSize = strlen(bufIn) + 1;
+ uint32 unprocessedSize = sizeIn + 1;
+ uint32 result = 0;
+ char *currentComponent = bufIn;
+ while (currentComponent != NULL) {
+ HgfsEscapeUndoComponent(currentComponent, &unprocessedSize);
+ componentSize = strlen(currentComponent) + 1; // Unescaped size
+ result += componentSize;
+ if (unprocessedSize > 1) {
+ currentComponent = currentComponent + componentSize;
+ componentSize = strlen(currentComponent) + 1; // Size of the next component
+ } else {
+ currentComponent = NULL;
+ }
+ }
+ return result - 1;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsEscapeUndoComponent --
+ *
+ * Unescape a buffer that was escaped using HgfsEscapeBuffer.
+ *
+ * The unescaping is done in place in the input buffer, and
+ * can not fail.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+HgfsEscapeUndoComponent(char *bufIn, // IN: Characters to be unescaped
+ uint32 *unprocessedLength) // IN: Unprocessed characters
+ // in the whole name
+{
+ size_t offset;
+ size_t sizeIn = strlen(bufIn);
+ char* curOutBuffer = bufIn;
+ char* escapePointer;
+ ASSERT(bufIn);
+
+ escapePointer = strchr(curOutBuffer, HGFS_ESCAPE_CHAR);
+ while (escapePointer != NULL) {
+ offset = escapePointer - bufIn;
+ if (HgfsIsEscapeSequence(bufIn, offset, sizeIn)) {
+ char* substitute = strchr(HGFS_SUBSTITUTE_CHARS, bufIn[offset - 1]);
+ if (substitute != NULL) {
+ bufIn[offset - 1] = HGFS_ILLEGAL_CHARS[substitute - HGFS_SUBSTITUTE_CHARS];
+ } else if (bufIn[offset - 1] == HGFS_ESCAPE_SUBSTITUE_CHAR) {
+ bufIn[offset - 1] = HGFS_ESCAPE_CHAR;
+ }
+ memmove(escapePointer, escapePointer + 1, (*unprocessedLength) - offset - 1);
+ (*unprocessedLength)--;
+ sizeIn--;
+ if (sizeIn > 0) {
+ escapePointer = strchr(escapePointer, HGFS_ESCAPE_CHAR);
+ } else {
+ escapePointer = NULL;
+ }
+ } else {
+ escapePointer = strchr(escapePointer + 1, HGFS_ESCAPE_CHAR);
+ }
+ }
+ ASSERT((*unprocessedLength) > sizeIn);
+ (*unprocessedLength) -= sizeIn + 1;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsEscapeDoComponent --
+ *
+ * Escape any characters that are not legal in a windows filename.
+ * Escape reserved file names that can't be used in Windows.
+ * We also of course have to escape the escape character, which is "%",
+ * when it is part of a character sequence that would require unescaping
+ *
+ * sizeBufOut must account for the NUL terminator.
+ *
+ * Results:
+ * On success, the size (excluding the NUL terminator) of the
+ * escaped, NUL terminated buffer.
+ * On failure (bufOut not big enough to hold result), negative value.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int
+HgfsEscapeDoComponent(char const *bufIn, // IN: Buffer with unescaped input
+ uint32 sizeIn, // IN: Size of input buffer
+ uint32 sizeBufOut, // IN: Size of output buffer
+ char *bufOut) // OUT: Buffer for escaped output
+{
+ HgfsEscapeContext conversionContext;
+ conversionContext.processedOffset = 0;
+ conversionContext.outputBufferLength = sizeBufOut / sizeof *bufOut;
+ conversionContext.outputOffset = 0;
+ conversionContext.outputBuffer = bufOut;
+
+ if (!HgfsEscapeEnumerate(bufIn, sizeIn, HgfsAddEscapeCharacter, &conversionContext)) {
+ return -1;
+ }
+ return conversionContext.outputOffset * sizeof *bufOut;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsEscapeGetComponentSize --
+ *
+ * Calculates number of addtitional characters that are needed to escape
+ * name for one NUL terminated component of the path.
+ *
+ * Results:
+ * Number of additional escape characters needed to escape the name.
+ * Returns 0 if no escaping is required.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int
+HgfsEscapeGetComponentSize(char const *bufIn, // IN: Buffer with unescaped input
+ uint32 sizeIn) // IN: Size of the in input buffer
+{
+ int result = 0;
+ HgfsEscapeEnumerate(bufIn, sizeIn, HgfsCountEscapeChars, &result);
+ return result;
+}
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. 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 version 2 and no 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. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ *********************************************************/
+
+/*
+ * hgfsEscape.h --
+ *
+ * Escape and unescape filenames that are not legal on a particular
+ * platform.
+ *
+ */
+
+#ifndef __HGFS_ESCAPE_H__
+#define __HGFS_ESCAPE_H__
+
+int HgfsEscape_GetSize(char const *bufIn, // IN
+ uint32 sizeIn); // IN
+int HgfsEscape_Do(char const *bufIn, // IN
+ uint32 sizeIn, // IN
+ uint32 sizeBufOut, // IN
+ char *bufOut); // OUT
+
+int HgfsEscape_Undo(char *bufIn, // IN
+ uint32 sizeIn); // IN
+
+#endif // __HGFS_ESCAPE_H__
--- /dev/null
+PACKAGE_NAME=open-vm-tools
+PACKAGE_VERSION=2008.11.18
+MAKE[0]="make -C pvscsi VM_UNAME=\$kernelver; \
+ make -C vmblock VM_UNAME=\$kernelver; \
+ make -C vmhgfs VM_UNAME=\$kernelver; \
+ make -C vmmemctl VM_UNAME=\$kernelver; \
+ make -C vmsync VM_UNAME=\$kernelver; \
+ make -C vmxnet VM_UNAME=\$kernelver; \
+ make -C vsock VM_UNAME=\$kernelver; \
+ make -C vmci VM_UNAME=\$kernelver; \
+ make -C vmxnet3 VM_UNAME=\$kernelver"
+CLEAN[0]="make -C pvscsi clean; \
+ make -C vmblock clean; \
+ make -C vmhgfs clean; \
+ make -C vmmemctl clean; \
+ make -C vmsync clean; \
+ make -C vmxnet clean; \
+ make -C vsock clean; \
+ make -C vmci clean; \
+ make -C vmxnet3 clean"
+BUILT_MODULE_NAME[0]="pvscsi"
+BUILT_MODULE_NAME[1]="vmblock"
+BUILT_MODULE_NAME[2]="vmci"
+BUILT_MODULE_NAME[3]="vmhgfs"
+BUILT_MODULE_NAME[4]="vmmemctl"
+BUILT_MODULE_NAME[5]="vmsync"
+BUILT_MODULE_NAME[6]="vmxnet"
+BUILT_MODULE_NAME[7]="vmxnet3"
+BUILT_MODULE_NAME[8]="vsock"
+BUILT_MODULE_LOCATION[0]="pvscsi/"
+BUILT_MODULE_LOCATION[1]="vmblock/"
+BUILT_MODULE_LOCATION[2]="vmci/"
+BUILT_MODULE_LOCATION[3]="vmhgfs/"
+BUILT_MODULE_LOCATION[4]="vmmemctl/"
+BUILT_MODULE_LOCATION[5]="vmsync/"
+BUILT_MODULE_LOCATION[6]="vmxnet/"
+BUILT_MODULE_LOCATION[7]="vmxnet3/"
+BUILT_MODULE_LOCATION[8]="vsock/"
+DEST_MODULE_LOCATION[0]="/kernel/drivers/scsi"
+DEST_MODULE_LOCATION[1]="/kernel/fs/vmblock"
+DEST_MODULE_LOCATION[2]="/kernel/drivers/misc"
+DEST_MODULE_LOCATION[3]="/kernel/fs/vmhgfs"
+DEST_MODULE_LOCATION[4]="/kernel/drivers/misc"
+DEST_MODULE_LOCATION[5]="/kernel/drivers/misc"
+DEST_MODULE_LOCATION[6]="/kernel/drivers/net"
+DEST_MODULE_LOCATION[7]="/kernel/drivers/net"
+DEST_MODULE_LOCATION[8]="/kernel/net/vsock"
+AUTOINSTALL="YES"
--- /dev/null
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
--- /dev/null
+#!/usr/bin/make -f
+##########################################################
+# Copyright (C) 1998 VMware, Inc. 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 version 2 and no 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. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+#
+##########################################################
+
+####
+#### VMware kernel module Makefile to be distributed externally
+####
+
+####
+#### SRCROOT _must_ be a relative path.
+####
+SRCROOT = .
+
+VM_UNAME = $(shell uname -r)
+
+# Header directory for the running kernel
+HEADER_DIR = /lib/modules/$(VM_UNAME)/build/include
+
+BUILD_DIR = $(HEADER_DIR)/..
+
+DRIVER := pvscsi
+PRODUCT := @PRODUCT@
+
+# Grep program
+GREP = /bin/grep
+
+vm_check_gcc = $(shell if $(CC) $(1) -S -o /dev/null -xc /dev/null \
+ > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi)
+vm_check_file = $(shell if test -f $(1); then echo "yes"; else echo "no"; fi)
+
+ifndef VM_KBUILD
+VM_KBUILD := no
+ifeq ($(call vm_check_file,$(BUILD_DIR)/Makefile), yes)
+ifneq ($(call vm_check_file,$(BUILD_DIR)/Rules.make), yes)
+VM_KBUILD := 26
+endif
+endif
+export VM_KBUILD
+endif
+
+ifndef VM_KBUILD_SHOWN
+ifeq ($(VM_KBUILD), no)
+VM_DUMMY := $(shell echo >&2 "Using standalone build system.")
+else
+ifeq ($(VM_KBUILD), 24)
+VM_DUMMY := $(shell echo >&2 "Using 2.4.x kernel build system.")
+else
+VM_DUMMY := $(shell echo >&2 "Using 2.6.x kernel build system.")
+endif
+endif
+VM_KBUILD_SHOWN := yes
+export VM_KBUILD_SHOWN
+endif
+
+ifneq ($(VM_KBUILD), no)
+
+VMCCVER := $(shell $(CC) -dumpversion)
+
+# If there is no version defined, we are in toplevel pass, not yet in kernel makefiles...
+ifeq ($(VERSION),)
+
+ifeq ($(VM_KBUILD), 24)
+DRIVER_KO := $(DRIVER).o
+else
+DRIVER_KO := $(DRIVER).ko
+endif
+
+.PHONY: $(DRIVER_KO)
+
+auto-build: $(DRIVER_KO)
+ cp -f $< $(SRCROOT)/../$(DRIVER).o
+
+# $(DRIVER_KO) is a phony target, so compare file times explicitly
+$(DRIVER): $(DRIVER_KO)
+ if [ $< -nt $@ ] || [ ! -e $@ ] ; then cp -f $< $@; fi
+
+# Pass gcc version down the chain, so we can detect if kernel attempts to use unapproved compiler
+VM_CCVER := $(VMCCVER)
+export VM_CCVER
+VM_CC := $(CC)
+export VM_CC
+
+MAKEOVERRIDES := $(filter-out CC=%,$(MAKEOVERRIDES))
+
+#
+# Define a setup target that gets built before the actual driver.
+# This target may not be used at all, but if it is then it will be defined
+# in Makefile.kernel
+#
+prebuild:: ;
+postbuild:: ;
+
+$(DRIVER_KO): prebuild
+ make -C $(BUILD_DIR) SUBDIRS=$$PWD SRCROOT=$$PWD/$(SRCROOT) modules
+ make -C $$PWD SRCROOT=$$PWD/$(SRCROOT) postbuild
+
+else
+
+ifneq ($(VM_CCVER), $(VMCCVER))
+$(warning *** Inappropriate build environment: you wanted to use gcc \
+ version $(VM_CCVER) while kernel attempts to use gcc version $(VMCCVER).)
+$(error For proper build you'll have to replace $(CC) with symbolic \
+ link to $(VM_CC))
+endif
+
+endif
+
+vm_check_build = $(shell if $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) \
+ $(CPPFLAGS) $(CFLAGS) $(CFLAGS_KERNEL) \
+ $(EXTRA_CFLAGS) -Iinclude2/asm/mach-default \
+ -DKBUILD_BASENAME=\"$(DRIVER)\" \
+ -Werror -S -o /dev/null -xc $(1) \
+ > /dev/null 2>&1; then echo "$(2)"; else echo "$(3)"; fi)
+
+CC_WARNINGS := -Wall -Wstrict-prototypes
+CC_OPTS := $(GLOBAL_DEFS) $(CC_WARNINGS) -DVMW_USING_KBUILD
+ifdef VMX86_DEVEL
+CC_OPTS += -DVMX86_DEVEL
+endif
+ifdef VMX86_DEBUG
+CC_OPTS += -DVMX86_DEBUG
+endif
+
+include $(SRCROOT)/Makefile.kernel
+
+ifdef TOPDIR
+ifeq ($(VM_KBUILD), 24)
+
+O_TARGET := $(DRIVER).o
+
+obj-y := $($(DRIVER)-y)
+
+include $(TOPDIR)/Rules.make
+endif
+endif
+
+else
+
+include $(SRCROOT)/Makefile.normal
+
+endif
+
+#.SILENT:
--- /dev/null
+#!/usr/bin/make -f
+##########################################################
+# Copyright (C) 1998 VMware, Inc. 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 version 2 and no 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. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+#
+##########################################################
+
+####
+#### VMware pvscsi Makefile to be distributed externally
+####
+
+INCLUDE := -I.
+
+EXTRA_CFLAGS := $(CC_OPTS) $(INCLUDE)
+
+obj-m += $(DRIVER).o
+
+clean:
+ rm -rf $(wildcard $(DRIVER).mod.c $(DRIVER).ko .tmp_versions \
+ Module.symvers Modules.symvers Module.markers modules.order \
+ $(foreach dir,./,$(addprefix $(dir),.*.cmd .*.o.flags *.o)))
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2006 VMware, Inc. 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 version 2 and no 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. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ *********************************************************/
+
+#include <linux/autoconf.h>
+#include <linux/version.h>
+
+/*
+ * All kernels before 2.6.22 take 6 arguments. All kernels since
+ * 2.6.23-rc1 take 5 arguments. Only kernels between 2.6.22 and
+ * 2.6.23-rc1 are questionable - we could ignore them if we wanted,
+ * nobody cares about them even now. But unfortunately RedHat is
+ * re-releasing 2.6.X-rc kernels under 2.6.(X-1) name, so they
+ * are releasing 2.6.23-rc1 as 2.6.22-5055-something, so we have
+ * to do autodetection for them.
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
+/* Success... */
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23)
+#error "This test intentionally fails on 2.6.23 and newer kernels."
+#else
+#include <linux/slab.h>
+
+struct kmem_cache *kmemtest(void) {
+ return kmem_cache_create("test", 12, 0, 0, NULL, NULL);
+}
+
+#endif
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2006 VMware, Inc. 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 version 2 and no 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. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ *********************************************************/
+
+#include <linux/autoconf.h>
+#include <linux/version.h>
+
+/*
+ * Between 2.6.23 and 2.6.24-rc1 ctor prototype was changed from
+ * ctor(ptr, cache, flags) to ctor(cache, ptr). Unfortunately there
+ * is no typedef for ctor, so we have to redefine kmem_cache_create
+ * to find out ctor prototype. This assumes that kmem_cache_create
+ * takes 5 arguments and not 6 - that change occured between
+ * 2.6.22 and 2.6.23-rc1. If prototype matches, then this is old
+ * kernel.
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
+#error "This test intentionally fails on 2.6.24 and newer kernels."
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23)
+#include <linux/slab.h>
+
+struct kmem_cache *kmem_cache_create(const char *, size_t, size_t,
+ unsigned long,
+ void (*)(void *, struct kmem_cache *, unsigned long));
+
+#endif
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2003 VMware, Inc. 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 version 2 and no 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. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ *********************************************************/
+
+#include <linux/autoconf.h>
+
+#ifdef CONFIG_X86_VOYAGER
+APATH/mach-voyager
+#endif
+#ifdef CONFIG_X86_VISWS
+APATH/mach-visws
+#endif
+#ifdef CONFIG_X86_NUMAQ
+APATH/mach-numaq
+#endif
+#ifdef CONFIG_X86_BIGSMP
+APATH/mach-bigsmp
+#endif
+#ifdef CONFIG_X86_SUMMIT
+APATH/mach-summit
+#endif
+#ifdef CONFIG_X86_GENERICARCH
+APATH/mach-generic
+#endif
+APATH/mach-default
+
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2003 VMware, Inc. 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 version 2 and no 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. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ *********************************************************/
+
+#ifndef __COMPAT_INTERRUPT_H__
+# define __COMPAT_INTERRUPT_H__
+
+
+#include <linux/interrupt.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 69)
+/*
+ * We cannot just define irqreturn_t, as some 2.4.x kernels have
+ * typedef void irqreturn_t; for "increasing" backward compatibility.
+ */
+typedef void compat_irqreturn_t;
+#define COMPAT_IRQ_NONE
+#define COMPAT_IRQ_HANDLED
+#define COMPAT_IRQ_RETVAL(x)
+#else
+typedef irqreturn_t compat_irqreturn_t;
+#define COMPAT_IRQ_NONE IRQ_NONE
+#define COMPAT_IRQ_HANDLED IRQ_HANDLED
+#define COMPAT_IRQ_RETVAL(x) IRQ_RETVAL(x)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)
+#define COMPAT_IRQF_DISABLED SA_INTERRUPT
+#define COMPAT_IRQF_SHARED SA_SHIRQ
+#else
+#define COMPAT_IRQF_DISABLED IRQF_DISABLED
+#define COMPAT_IRQF_SHARED IRQF_SHARED
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+#define COMPAT_IRQ_HANDLER_ARGS(irq, devp) (int irq, void *devp, struct pt_regs *regs)
+#else
+#define COMPAT_IRQ_HANDLER_ARGS(irq, devp) (int irq, void *devp)
+#endif
+
+#endif /* __COMPAT_INTERRUPT_H__ */
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2003 VMware, Inc. 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 version 2 and no 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. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ *********************************************************/
+
+#ifndef __COMPAT_IOPORT_H__
+# define __COMPAT_IOPORT_H__
+
+
+#include <linux/ioport.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0)
+static inline void *
+compat_request_region(unsigned long start, unsigned long len, const char *name)
+{
+ if (check_region(start, len)) {
+ return NULL;
+ }
+ request_region(start, len, name);
+ return (void*)1;
+}
+#else
+#define compat_request_region(start, len, name) request_region(start, len, name)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 7)
+/* mmap io support starts from 2.3.7, fail the call for kernel prior to that */
+static inline void *
+compat_request_mem_region(unsigned long start, unsigned long len, const char *name)
+{
+ return NULL;
+}
+
+static inline void
+compat_release_mem_region(unsigned long start, unsigned long len)
+{
+ return;
+}
+#else
+#define compat_request_mem_region(start, len, name) request_mem_region(start, len, name)
+#define compat_release_mem_region(start, len) release_mem_region(start, len)
+#endif
+
+/* these two macro defs are needed by compat_pci_request_region */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 15)
+# define IORESOURCE_IO 0x00000100
+# define IORESOURCE_MEM 0x00000200
+#endif
+
+#endif /* __COMPAT_IOPORT_H__ */
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2007 VMware, Inc. 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 version 2 and no 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. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ *********************************************************/
+
+/*
+ * compat_module.h --
+ */
+
+#ifndef __COMPAT_MODULE_H__
+# define __COMPAT_MODULE_H__
+
+
+#include <linux/module.h>
+
+
+/*
+ * Modules wishing to use the GPL license are required to include a
+ * MODULE_LICENSE definition in their module source as of 2.4.10.
+ */
+#ifndef MODULE_LICENSE
+#define MODULE_LICENSE(license)
+#endif
+
+/*
+ * To make use of our own home-brewed MODULE_INFO, we need macros to
+ * concatenate two expressions to "__mod_", and and to convert an
+ * expression into a string. I'm sure we've got these in our codebase,
+ * but I'd rather not introduce such a dependency in a compat header.
+ */
+#ifndef __module_cat
+#define __module_cat_1(a, b) __mod_ ## a ## b
+#define __module_cat(a, b) __module_cat_1(a, b)
+#endif
+
+#ifndef __stringify
+#define __stringify_1(x) #x
+#define __stringify(x) __stringify_1(x)
+#endif
+
+/*
+ * MODULE_INFO was born in 2.5.69.
+ */
+#ifndef MODULE_INFO
+#define MODULE_INFO(tag, info) \
+static const char __module_cat(tag, __LINE__)[] \
+ __attribute__((section(".modinfo"), unused)) = __stringify(tag) "=" info
+#endif
+
+/*
+ * MODULE_VERSION was born in 2.6.4. The earlier form appends a long "\0xxx"
+ * string to the module's version, but that was removed in 2.6.10, so we'll
+ * ignore it in our wrapper.
+ */
+#ifndef MODULE_VERSION
+#define MODULE_VERSION(_version) MODULE_INFO(version, _version)
+#endif
+
+#endif /* __COMPAT_MODULE_H__ */
--- /dev/null
+/*********************************************************
+ * Copyright (C) 1999 VMware, Inc. 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 version 2 and no 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. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ *********************************************************/
+
+/*
+ * compat_pci.h: PCI compatibility wrappers.
+ */
+
+#ifndef __COMPAT_PCI_H__
+#define __COMPAT_PCI_H__
+
+#include "compat_ioport.h"
+#include <linux/pci.h>
+#ifndef KERNEL_2_1
+# include <linux/bios32.h>
+#endif
+
+
+/* 2.0.x has useless struct pci_dev; remap it to our own */
+#ifndef KERNEL_2_1
+#define pci_dev vmw_pci_driver_instance
+#endif
+
+
+/* 2.0/2.2 does not have pci driver API */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0)
+struct vmw_pci_driver_instance {
+ struct vmw_pci_driver_instance *next;
+ void *driver_data;
+ struct pci_driver *pcidrv;
+#ifdef KERNEL_2_1
+ struct pci_dev *pcidev;
+#else
+ unsigned char bus;
+ unsigned char devfn;
+ unsigned int irq;
+#endif
+};
+#endif
+
+
+/* 2.0 has pcibios_* calls only... We have to provide pci_* compatible wrappers. */
+#ifndef KERNEL_2_1
+static inline int
+pci_read_config_byte(struct pci_dev *pdev, // IN: PCI slot
+ unsigned char where, // IN: Byte to read
+ u8 *value) // OUT: Value read
+{
+ return pcibios_read_config_byte(pdev->bus, pdev->devfn, where, value);
+}
+
+static inline int
+pci_read_config_dword(struct pci_dev *pdev, // IN: PCI slot
+ unsigned char where, // IN: Dword to read
+ u32 *value) // OUT: Value read
+{
+ return pcibios_read_config_dword(pdev->bus, pdev->devfn, where, value);
+}
+
+static inline int
+pci_write_config_dword(struct pci_dev *pdev, // IN: PCI slot
+ unsigned char where, // IN: Dword to write
+ u32 value) // IN: Value to write
+{
+ return pcibios_write_config_dword(pdev->bus, pdev->devfn, where, value);
+}
+#endif
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * compat_pci_name --
+ *
+ * Return human readable PCI slot name. Note that some implementations
+ * return a pointer to the static storage, so returned value may be
+ * overwritten by subsequent calls to this function.
+ *
+ * Results:
+ * Returns pointer to the string with slot name.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 22)
+#define compat_pci_name(pdev) pci_name(pdev)
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0)
+#define compat_pci_name(pdev) (pdev)->slot_name
+#elif defined(KERNEL_2_1)
+static inline const char*
+compat_pci_name(struct pci_dev* pdev)
+{
+ static char slot_name[12];
+ sprintf(slot_name, "%02X:%02X.%X", pdev->bus->number,
+ PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
+ return slot_name;
+}
+#else
+static inline const char*
+compat_pci_name(struct pci_dev* pdev)
+{
+ static char slot_name[12];
+ sprintf(slot_name, "%02X:%02X.%X", pdev->bus,
+ PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
+ return slot_name;
+}
+#endif
+
+
+/* pci_resource_start comes in 4 flavors - 2.0, 2.2, early 2.3, 2.4+ */
+#ifndef KERNEL_2_1
+static inline unsigned long
+compat_pci_resource_start(struct pci_dev *pdev,
+ unsigned int index)
+{
+ u32 addr;
+
+ if (pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0 + index * 4, &addr)) {
+ printk(KERN_ERR "Unable to read base address %u from PCI slot %s!\n",
+ index, compat_pci_name(pdev));
+ return ~0UL;
+ }
+ if (addr & PCI_BASE_ADDRESS_SPACE) {
+ return addr & PCI_BASE_ADDRESS_IO_MASK;
+ } else {
+ return addr & PCI_BASE_ADDRESS_MEM_MASK;
+ }
+}
+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 1)
+# define compat_pci_resource_start(dev, index) \
+ (((dev)->base_address[index] & PCI_BASE_ADDRESS_SPACE) \
+ ? ((dev)->base_address[index] & PCI_BASE_ADDRESS_IO_MASK) \
+ : ((dev)->base_address[index] & PCI_BASE_ADDRESS_MEM_MASK))
+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 43)
+# define compat_pci_resource_start(dev, index) \
+ ((dev)->resource[index].start)
+#else
+# define compat_pci_resource_start(dev, index) \
+ pci_resource_start(dev, index)
+#endif
+
+/* since 2.3.15, a new set of s/w res flags IORESOURCE_ is introduced,
+ * we fake them by returning either IORESOURCE_{IO, MEM} prior to 2.3.15 since
+ * this is what compat_pci_request_region uses
+ */
+#ifndef KERNEL_2_1
+static inline unsigned long
+compat_pci_resource_flags(struct pci_dev *pdev,
+ unsigned int index)
+{
+ u32 addr;
+
+ if (pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0 + index * 4, &addr)) {
+ printk(KERN_ERR "Unable to read base address %u from PCI slot %s!\n",
+ index, compat_pci_name(pdev));
+ return ~0UL;
+ }
+ if (addr & PCI_BASE_ADDRESS_SPACE) {
+ return IORESOURCE_IO;
+ } else {
+ return IORESOURCE_MEM;
+ }
+}
+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 1)
+# define compat_pci_resource_flags(dev, index) \
+ (((dev)->base_address[index] & PCI_BASE_ADDRESS_SPACE) \
+ ? IORESOURCE_IO: IORESOURCE_MEM)
+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 15)
+ /* IORESOURCE_xxx appeared in 2.3.15 and is set in resource[].flags */
+# define compat_pci_resource_flags(dev, index) ((dev)->resource[index].flags)
+#else
+# define compat_pci_resource_flags(dev, index) pci_resource_flags(dev, index)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 18)
+static inline unsigned long
+compat_pci_resource_len(struct pci_dev *pdev, // IN
+ unsigned int index) // IN
+{
+ u32 addr, mask;
+ unsigned char reg = PCI_BASE_ADDRESS_0 + index * 4;
+
+ if (pci_read_config_dword(pdev, reg, &addr) || addr == 0xFFFFFFFF) {
+ return 0;
+ }
+
+ pci_write_config_dword(pdev, reg, 0xFFFFFFFF);
+ pci_read_config_dword(pdev, reg, &mask);
+ pci_write_config_dword(pdev, reg, addr);
+
+ if (mask == 0 || mask == 0xFFFFFFFF) {
+ return 0;
+ }
+ if (addr & PCI_BASE_ADDRESS_SPACE) {
+ return 65536 - (mask & PCI_BASE_ADDRESS_IO_MASK & 0xFFFF);
+ } else {
+ return -(mask & PCI_BASE_ADDRESS_MEM_MASK);
+ }
+}
+#else
+#define compat_pci_resource_len(dev, index) pci_resource_len(dev, index)
+#endif
+
+/* pci_request_region appears in 2.4.20 */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 20)
+static inline int
+compat_pci_request_region(struct pci_dev *pdev, int bar, char *name)
+{
+ if (compat_pci_resource_len(pdev, bar) == 0) {
+ return 0;
+ }
+
+ if (compat_pci_resource_flags(pdev, bar) & IORESOURCE_IO) {
+ if (!compat_request_region(compat_pci_resource_start(pdev, bar),
+ compat_pci_resource_len(pdev, bar),
+ name)) {
+ return -EBUSY;
+ }
+ } else if (compat_pci_resource_flags(pdev, bar) & IORESOURCE_MEM) {
+ if (!compat_request_mem_region(compat_pci_resource_start(pdev, bar),
+ compat_pci_resource_len(pdev, bar),
+ name)) {
+ return -EBUSY;
+ }
+ }
+
+ return 0;
+}
+
+static inline void
+compat_pci_release_region(struct pci_dev *pdev, int bar)
+{
+ if (compat_pci_resource_len(pdev, bar) != 0) {
+ if (compat_pci_resource_flags(pdev, bar) & IORESOURCE_IO) {
+ release_region(compat_pci_resource_start(pdev, bar),
+ compat_pci_resource_len(pdev, bar));
+ } else if (compat_pci_resource_flags(pdev, bar) & IORESOURCE_MEM) {
+ compat_release_mem_region(compat_pci_resource_start(pdev, bar),
+ compat_pci_resource_len(pdev, bar));
+ }
+ }
+}
+#else
+#define compat_pci_request_region(pdev, bar, name) pci_request_region(pdev, bar, name)
+#define compat_pci_release_region(pdev, bar) pci_release_region(pdev, bar)
+#endif
+
+/* pci_request_regions appeears in 2.4.3 */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 3)
+static inline int
+compat_pci_request_regions(struct pci_dev *pdev, char *name)
+{
+ int i;
+
+ for (i = 0; i < 6; i++) {
+ if (compat_pci_request_region(pdev, i, name)) {
+ goto release;
+ }
+ }
+ return 0;
+
+release:
+ while (--i >= 0) {
+ compat_pci_release_region(pdev, i);
+ }
+ return -EBUSY;
+}
+static inline void
+compat_pci_release_regions(struct pci_dev *pdev)
+{
+ int i;
+
+ for (i = 0; i < 6; i++) {
+ compat_pci_release_region(pdev, i);
+ }
+}
+#else
+#define compat_pci_request_regions(pdev, name) pci_request_regions(pdev, name)
+#define compat_pci_release_regions(pdev) pci_release_regions(pdev)
+#endif
+
+/* pci_enable_device is available since 2.4.0 */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0)
+#define compat_pci_enable_device(pdev) (0)
+#else
+#define compat_pci_enable_device(pdev) pci_enable_device(pdev)
+#endif
+
+
+/* pci_set_master is available since 2.2.0 */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 0)
+#define compat_pci_set_master(pdev) (0)
+#else
+#define compat_pci_set_master(pdev) pci_set_master(pdev)
+#endif
+
+
+/* pci_disable_device is available since 2.4.4 */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 4)
+#define compat_pci_disable_device(pdev) do {} while (0)
+#else
+#define compat_pci_disable_device(pdev) pci_disable_device(pdev)
+#endif
+
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0)
+/*
+ * Devices supported by particular pci driver. While 2.4+ kernels
+ * can do match on subsystem and class too, we support match on
+ * vendor/device IDs only.
+ */
+struct pci_device_id {
+ unsigned int vendor, device;
+ unsigned long driver_data;
+};
+#define PCI_DEVICE(vend, dev) .vendor = (vend), .device = (dev)
+
+/* PCI driver */
+struct pci_driver {
+ const char *name;
+ const struct pci_device_id *id_table;
+ int (*probe)(struct pci_dev* dev, const struct pci_device_id* id);
+ void (*remove)(struct pci_dev* dev);
+};
+
+
+/*
+ * Note that this is static variable. Maybe everything below should be in
+ * separate compat_pci.c file, but currently only user of this file is vmxnet,
+ * and vmxnet has only one file, so it is fine. Also with vmxnet all
+ * functions below are called just once, so difference between 'inline' and
+ * separate compat_pci.c should be very small.
+ */
+
+static struct vmw_pci_driver_instance *pci_driver_instances = NULL;
+
+#ifdef KERNEL_2_1
+#define vmw_pci_device(instance) (instance)->pcidev
+#else
+#define vmw_pci_device(instance) (instance)
+#endif
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * pci_register_driver --
+ *
+ * Create driver instances for all matching PCI devices in the box.
+ *
+ * Results:
+ * Returns 0 for success, negative error value for failure.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static inline int
+pci_register_driver(struct pci_driver *drv)
+{
+ const struct pci_device_id *chipID;
+
+ for (chipID = drv->id_table; chipID->vendor; chipID++) {
+#ifdef KERNEL_2_1
+ struct pci_dev *pdev;
+
+ for (pdev = NULL;
+ (pdev = pci_find_device(chipID->vendor, chipID->device, pdev)) != NULL; ) {
+#else
+ int adapter;
+ unsigned char bus, devfn, irq;
+
+ for (adapter = 0;
+ pcibios_find_device(chipID->vendor, chipID->device, adapter,
+ &bus, &devfn) == 0;
+ adapter++) {
+#endif
+ struct vmw_pci_driver_instance *pdi;
+ int err;
+
+ pdi = kmalloc(sizeof *pdi, GFP_KERNEL);
+ if (!pdi) {
+ printk(KERN_ERR "Not enough memory.\n");
+ break;
+ }
+ pdi->pcidrv = drv;
+#ifdef KERNEL_2_1
+ pdi->pcidev = pdev;
+#else
+ pdi->bus = bus;
+ pdi->devfn = devfn;
+ if (pci_read_config_byte(pdi, PCI_INTERRUPT_LINE, &irq)) {
+ pdi->irq = -1;
+ } else {
+ pdi->irq = irq;
+ }
+#endif
+ pdi->driver_data = NULL;
+ pdi->next = pci_driver_instances;
+ pci_driver_instances = pdi;
+ err = drv->probe(vmw_pci_device(pdi), chipID);
+ if (err) {
+ pci_driver_instances = pdi->next;
+ kfree(pdi);
+ }
+ }
+ }
+ return 0;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * compat_pci_unregister_driver --
+ *
+ * Shut down PCI driver - unbind all device instances from driver.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static inline void
+pci_unregister_driver(struct pci_driver *drv)
+{
+ struct vmw_pci_driver_instance **ppdi;
+
+ ppdi = &pci_driver_instances;
+ while (1) {
+ struct vmw_pci_driver_instance *pdi = *ppdi;
+
+ if (!pdi) {
+ break;
+ }
+ if (pdi->pcidrv == drv) {
+ drv->remove(vmw_pci_device(pdi));
+ *ppdi = pdi->next;
+ kfree(pdi);
+ } else {
+ ppdi = &pdi->next;
+ }
+ }
+}
+#else
+/* provide PCI_DEVICE for early 2.4.x kernels */
+#ifndef PCI_DEVICE
+#define PCI_DEVICE(vend, dev) .vendor = (vend), .device = (dev), \
+ .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID
+#endif
+#endif
+
+
+/* provide dummy MODULE_DEVICE_TABLE for 2.0/2.2 */
+#ifndef MODULE_DEVICE_TABLE
+#define MODULE_DEVICE_TABLE(bus, devices)
+#endif
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * pci_set_drvdata --
+ *
+ * Set per-device driver's private data.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * pci_get_drvdata --
+ *
+ * Retrieve per-device driver's private data.
+ *
+ * Results:
+ * per-device driver's data previously set by pci_set_drvdata,
+ * or NULL on failure.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+#ifndef KERNEL_2_1
+/* 2.0.x is simple, we have driver_data directly in pci_dev */
+#define pci_set_drvdata(pdev, data) do { (pdev)->driver_data = (data); } while (0)
+#define pci_get_drvdata(pdev) (pdev)->driver_data
+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0)
+/* 2.2.x is trickier, we have to find driver instance first */
+static inline void
+pci_set_drvdata(struct pci_dev *pdev, void* data)
+{
+ struct vmw_pci_driver_instance *pdi;
+
+ for (pdi = pci_driver_instances; pdi; pdi = pdi->next) {
+ if (pdi->pcidev == pdev) {
+ pdi->driver_data = data;
+ return;
+ }
+ }
+ printk(KERN_ERR "pci_set_drvdata issued for unknown device %p\n", pdev);
+}
+
+static inline void *
+pci_get_drvdata(struct pci_dev *pdev)
+{
+ struct vmw_pci_driver_instance *pdi;
+
+ for (pdi = pci_driver_instances; pdi; pdi = pdi->next) {
+ if (pdi->pcidev == pdev) {
+ return pdi->driver_data;
+ }
+ }
+ printk(KERN_ERR "pci_get_drvdata issued for unknown device %p\n", pdev);
+ return NULL;
+}
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,48)
+# define PCI_DMA_BIDIRECTIONAL 0
+# define PCI_DMA_TODEVICE 1
+# define PCI_DMA_FROMDEVICE 2
+# define PCI_DMA_NONE 3
+#endif
+
+/*
+ * Power Management related compat wrappers.
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 10)
+# define compat_pci_save_state(pdev) pci_save_state((pdev), NULL)
+# define compat_pci_restore_state(pdev) pci_restore_state((pdev), NULL)
+#else
+# define compat_pci_save_state(pdev) pci_save_state((pdev))
+# define compat_pci_restore_state(pdev) pci_restore_state((pdev))
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 11)
+# define pm_message_t u32
+# define compat_pci_choose_state(pdev, state) (state)
+# define PCI_D0 0
+# define PCI_D3hot 3
+#else
+# define compat_pci_choose_state(pdev, state) pci_choose_state((pdev), (state))
+#endif
+
+/* 2.6.14 changed the PCI shutdown callback */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
+# define COMPAT_PCI_SHUTDOWN(func) .driver = { .shutdown = (func), }
+# define COMPAT_PCI_DECLARE_SHUTDOWN(func, var) (func)(struct device *(var))
+# define COMPAT_PCI_TO_DEV(dev) (to_pci_dev(dev))
+#else
+# define COMPAT_PCI_SHUTDOWN(func) .shutdown = (func)
+# define COMPAT_PCI_DECLARE_SHUTDOWN(func, var) (func)(struct pci_dev *(var))
+# define COMPAT_PCI_TO_DEV(dev) (dev)
+#endif
+
+
+#endif /* __COMPAT_PCI_H__ */
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2002 VMware, Inc. 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 version 2 and no 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. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ *********************************************************/
+
+#ifndef __COMPAT_SCSI_H__
+# define __COMPAT_SCSI_H__
+
+
+/* The scsi_bufflen() API appeared somewhere in time --hpreg */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23)
+# define scsi_bufflen(cmd) ((cmd)->request_bufflen)
+# define scsi_sg_count(cmd) ((cmd)->use_sg)
+# define scsi_sglist(cmd) ((struct scatterlist *)(cmd)->request_buffer)
+# define scsi_set_resid(cmd, _resid) ((cmd)->resid = _resid)
+#endif
+
+/*
+ * Using scsi_sglist to access the request buffer looks strange
+ * so instead we define this macro. What happened is later kernel
+ * put all SCSI data in sglists, since it simplifies passing buffers
+ */
+#define scsi_request_buffer(cmd) scsi_sglist(cmd)
+
+#endif /* __COMPAT_SCSI_H__ */
--- /dev/null
+/*********************************************************
+ * Copyright (C) 1998 VMware, Inc. 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 version 2 and no 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. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ *********************************************************/
+
+#ifndef __COMPAT_VERSION_H__
+# define __COMPAT_VERSION_H__
+
+#define INCLUDE_ALLOW_VMMON
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_VMCORE
+#define INCLUDE_ALLOW_VMNIXMOD
+#define INCLUDE_ALLOW_DISTRIBUTE
+#include "includeCheck.h"
+
+
+#ifndef __linux__
+# error "linux-version.h"
+#endif
+
+
+#include <linux/version.h>
+
+/* Appeared in 2.1.90 --hpreg */
+#ifndef KERNEL_VERSION
+# define KERNEL_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c))
+#endif
+
+
+/*
+ * Distinguish relevant classes of Linux kernels.
+ *
+ * The convention is that version X defines all
+ * the KERNEL_Y symbols where Y <= X.
+ *
+ * XXX Do not add more definitions here. This way of doing things does not
+ * scale, and we are going to phase it out soon --hpreg
+ */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 1, 0)
+# define KERNEL_2_1
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 2, 0)
+# define KERNEL_2_2
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 1)
+# define KERNEL_2_3_1
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 15)
+/* new networking */
+# define KERNEL_2_3_15
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 25)
+/* new procfs */
+# define KERNEL_2_3_25
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 29)
+/* even newer procfs */
+# define KERNEL_2_3_29
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 43)
+/* softnet changes */
+# define KERNEL_2_3_43
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 47)
+/* more softnet changes */
+# define KERNEL_2_3_47
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 99)
+/* name in netdevice struct is array and not pointer */
+# define KERNEL_2_3_99
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0)
+/* New 'owner' member at the beginning of struct file_operations */
+# define KERNEL_2_4_0
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 8)
+/* New netif_rx_ni() --hpreg */
+# define KERNEL_2_4_8
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 22)
+/* New vmap() */
+# define KERNEL_2_4_22
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 2)
+/* New kdev_t, major()/minor() API --hpreg */
+# define KERNEL_2_5_2
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 5)
+/* New sk_alloc(), pte_offset_map()/pte_unmap() --hpreg */
+# define KERNEL_2_5_5
+#endif
+
+
+#endif /* __COMPAT_VERSION_H__ */
--- /dev/null
+/*********************************************************
+ * Copyright (C) 1998 VMware, Inc. 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 version 2 and no 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. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ *********************************************************/
+
+/*
+ * Sets the proper defines from the Linux header files
+ *
+ * This file must be included before the inclusion of any kernel header file,
+ * with the exception of linux/autoconf.h and linux/version.h --hpreg
+ */
+
+#ifndef __VMX_CONFIG_H__
+#define __VMX_CONFIG_H__
+
+#define INCLUDE_ALLOW_VMCORE
+#define INCLUDE_ALLOW_VMMON
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_VMNIXMOD
+#include "includeCheck.h"
+
+#include <linux/autoconf.h>
+#include "compat_version.h"
+
+/*
+ * We rely on Kernel Module support. Check here.
+ */
+#ifndef CONFIG_MODULES
+# error "No Module support in this kernel. Please configure with CONFIG_MODULES"
+#endif
+
+/*
+ * 2.2 kernels still use __SMP__ (derived from CONFIG_SMP
+ * in the main Makefile), so we do it here.
+ */
+
+#ifdef CONFIG_SMP
+# define __SMP__ 1
+#endif
+
+#if defined(CONFIG_MODVERSIONS) && defined(KERNEL_2_1)
+# if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,60)
+/*
+ * MODVERSIONS might be already defined when using kernel's Makefiles.
+ */
+# ifndef MODVERSIONS
+# define MODVERSIONS
+# endif
+# include <linux/modversions.h>
+# endif
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
+/*
+ * Force the uintptr_t definition to come from linux/types.h instead of vm_basic_types.h.
+ */
+# include <linux/types.h>
+# define _STDINT_H 1
+#endif
+
+#ifndef __KERNEL__
+# define __KERNEL__
+#endif
+
+#endif
--- /dev/null
+/*********************************************************
+ * Copyright (C) 1998 VMware, Inc. 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 version 2 and no 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. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ *********************************************************/
+
+/*
+ * includeCheck.h --
+ *
+ * Restrict include file use.
+ *
+ * In every .h file, define one or more of these
+ *
+ * INCLUDE_ALLOW_VMX
+ * INCLUDE_ALLOW_USERLEVEL
+ * INCLUDE_ALLOW_VMMEXT
+ * INCLUDE_ALLOW_VMCORE
+ * INCLUDE_ALLOW_MODULE
+ * INCLUDE_ALLOW_VMNIXMOD
+ * INCLUDE_ALLOW_VMKERNEL
+ * INCLUDE_ALLOW_DISTRIBUTE
+ * INCLUDE_ALLOW_VMK_MODULE
+ * INCLUDE_ALLOW_VMKDRIVERS
+ * INCLUDE_ALLOW_VMIROM
+ *
+ * Then include this file.
+ *
+ * Any file that has INCLUDE_ALLOW_DISTRIBUTE defined will potentially
+ * be distributed in source form along with GPLed code. Ensure
+ * that this is acceptable.
+ */
+
+
+/*
+ * Declare a VMCORE-only variable to help classify object
+ * files. The variable goes in the common block and does
+ * not create multiple definition link-time conflicts.
+ */
+
+#if defined VMCORE && defined VMX86_DEVEL && defined VMX86_DEBUG && \
+ defined linux && !defined MODULE && \
+ !defined COMPILED_WITH_VMCORE
+#define COMPILED_WITH_VMCORE compiled_with_vmcore
+#ifdef ASM
+ .comm compiled_with_vmcore, 0
+#else
+ asm(".comm compiled_with_vmcore, 0");
+#endif /* ASM */
+#endif
+
+
+#if defined VMCORE && \
+ !(defined VMX86_VMX || defined VMM || \
+ defined MONITOR_APP || defined VMMON)
+#error "Makefile problem: VMCORE without VMX86_VMX or \
+ VMM or MONITOR_APP or MODULE."
+#endif
+
+#if defined VMCORE && !defined INCLUDE_ALLOW_VMCORE
+#error "The surrounding include file is not allowed in vmcore."
+#endif
+#undef INCLUDE_ALLOW_VMCORE
+
+#if defined VMX86_VMX && !defined VMCORE && \
+ !(defined INCLUDE_ALLOW_VMX || defined INCLUDE_ALLOW_USERLEVEL)
+#error "The surrounding include file is not allowed in the VMX."
+#endif
+#undef INCLUDE_ALLOW_VMX
+
+#if defined USERLEVEL && !defined VMX86_VMX && !defined VMCORE && \
+ !defined INCLUDE_ALLOW_USERLEVEL
+#error "The surrounding include file is not allowed at userlevel."
+#endif
+#undef INCLUDE_ALLOW_USERLEVEL
+
+#if defined VMM && !defined VMCORE && \
+ !defined INCLUDE_ALLOW_VMMEXT
+#error "The surrounding include file is not allowed in the monitor."
+#endif
+#undef INCLUDE_ALLOW_VMMEXT
+
+#if defined MODULE && !defined VMKERNEL_MODULE && !defined VMNIXMOD && \
+ !defined VMMON && !defined INCLUDE_ALLOW_MODULE
+#error "The surrounding include file is not allowed in driver modules."
+#endif
+#undef INCLUDE_ALLOW_MODULE
+
+#if defined VMMON && !defined INCLUDE_ALLOW_VMMON
+#error "The surrounding include file is not allowed in vmmon."
+#endif
+#undef INCLUDE_ALLOW_VMMON
+
+#if defined VMKERNEL && !defined INCLUDE_ALLOW_VMKERNEL
+#error "The surrounding include file is not allowed in the vmkernel."
+#endif
+#undef INCLUDE_ALLOW_VMKERNEL
+
+#if defined GPLED_CODE && !defined INCLUDE_ALLOW_DISTRIBUTE
+#error "The surrounding include file is not allowed in GPL code."
+#endif
+#undef INCLUDE_ALLOW_DISTRIBUTE
+
+#if defined VMKERNEL_MODULE && !defined VMKERNEL && \
+ !defined INCLUDE_ALLOW_VMK_MODULE && !defined INCLUDE_ALLOW_VMKDRIVERS
+#error "The surrounding include file is not allowed in vmkernel modules."
+#endif
+#undef INCLUDE_ALLOW_VMK_MODULE
+#undef INCLUDE_ALLOW_VMKDRIVERS
+
+#if defined VMNIXMOD && !defined INCLUDE_ALLOW_VMNIXMOD
+#ifndef VMNIXMOD_VM
+#error "The surrounding include file is not allowed in vmnixmod."
+#endif
+#endif
+#undef INCLUDE_ALLOW_VMNIXMOD
+
+#if defined VMIROM && ! defined INCLUDE_ALLOW_VMIROM
+#error "The surrounding include file is not allowed in vmirom."
+#endif
+#undef INCLUDE_ALLOW_VMIROM
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. 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 version 2 and no 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. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ *********************************************************/
+
+/*
+ * pvscsi.c --
+ *
+ * This is a driver for the VMware PVSCSI paravirt SCSI device.
+ * The PVSCSI device is a SCSI adapter for virtual disks which
+ * is implemented as a PCIe device.
+ */
+
+#include "driver-config.h"
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/mm.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+
+#include "compat_scsi.h"
+#include "compat_pci.h"
+#include "compat_interrupt.h"
+
+#include "pvscsi_defs.h"
+#include "pvscsi_version.h"
+#include "scsi_defs.h"
+#include "vm_device_version.h"
+#include "vm_assert.h"
+
+/**************************************************************
+ *
+ * VMWARE PVSCSI Linux interaction
+ *
+ * All Linux specific driver routines and operations should
+ * go here.
+ *
+ **************************************************************/
+
+#define PVSCSI_LINUX_DRIVER_DESC "VMware PVSCSI driver"
+
+/* Module definitions */
+MODULE_DESCRIPTION(PVSCSI_LINUX_DRIVER_DESC);
+MODULE_AUTHOR("VMware, Inc.");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION(PVSCSI_DRIVER_VERSION_STRING);
+
+#define PVSCSI_DRIVER_VECTORS_USED 1
+#define DEFAULT_PAGES_PER_RING 8
+#define PVSCSI_LINUX_DEFAULT_QUEUE_DEPTH 64
+
+/* MSI has horrible performance in < 2.6.13 due to needless mask frotzing */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13)
+#define DISABLE_MSI 0
+#else
+#define DISABLE_MSI 1
+#endif
+
+/* MSI-X has horrible performance in < 2.6.19 due to needless mask frobbing */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
+#define DISABLE_MSIX 0
+#else
+#define DISABLE_MSIX 1
+#endif
+
+/* Command line parameters */
+static int pvscsi_debug_level;
+module_param_call(pvscsi_debug_level, param_set_int, param_get_int,
+ &pvscsi_debug_level, 0600);
+MODULE_PARM_DESC(pvscsi_debug_level, "Debug logging level - (default=0)");
+
+static int pvscsi_ring_pages = DEFAULT_PAGES_PER_RING;
+module_param_call(pvscsi_ring_pages, param_set_int, param_get_int,
+ &pvscsi_ring_pages, 0600);
+MODULE_PARM_DESC(pvscsi_ring_pages, "Pages per ring - (default="
+ XSTR(DEFAULT_PAGES_PER_RING) ")");
+
+static int pvscsi_cmd_per_lun = PVSCSI_LINUX_DEFAULT_QUEUE_DEPTH;
+module_param_call(pvscsi_cmd_per_lun, param_set_int, param_get_int,
+ &pvscsi_cmd_per_lun, 0600);
+MODULE_PARM_DESC(pvscsi_cmd_per_lun, "Maximum commands per lun - (default="
+ XSTR(PVSCSI_MAX_REQ_QUEUE_DEPTH) ")");
+
+static int pvscsi_disable_msi = DISABLE_MSI;
+module_param_call(pvscsi_disable_msi, param_set_int, param_get_int,
+ &pvscsi_disable_msi, 0600);
+MODULE_PARM_DESC(pvscsi_disable_msi, "Disable MSI use in driver - (default="
+ XSTR(DISABLE_MSI) ")");
+
+static int pvscsi_disable_msix = DISABLE_MSIX;
+module_param_call(pvscsi_disable_msix, param_set_int, param_get_int,
+ &pvscsi_disable_msix, 0600);
+MODULE_PARM_DESC(pvscsi_disable_msix, "Disable MSI-X use in driver - (default="
+ XSTR(DISABLE_MSIX) ")");
+
+static int __init pvscsi_init(void);
+static int __devinit pvscsi_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id);
+static const char *pvscsi_info(struct Scsi_Host *host);
+static int pvscsi_queue(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *));
+static int pvscsi_abort(struct scsi_cmnd *cmd);
+static int pvscsi_host_reset(struct scsi_cmnd *cmd);
+static int pvscsi_bus_reset(struct scsi_cmnd *cmd);
+static int pvscsi_device_reset(struct scsi_cmnd *cmd);
+static irqreturn_t pvscsi_isr COMPAT_IRQ_HANDLER_ARGS(irq, devp);
+static void pvscsi_remove(struct pci_dev *pdev);
+static void COMPAT_PCI_DECLARE_SHUTDOWN(pvscsi_shutdown, dev);
+static void __exit pvscsi_exit(void);
+
+static struct pci_device_id pvscsi_pci_tbl[] = {
+ {PCI_VENDOR_ID_VMWARE, PCI_DEVICE_ID_VMWARE_PVSCSI,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {0,}
+};
+MODULE_DEVICE_TABLE(pci, pvscsi_pci_tbl);
+
+static struct pci_driver pvscsi_pci_driver = {
+ .name = "pvscsi",
+ .id_table = pvscsi_pci_tbl,
+ .probe = pvscsi_probe,
+ .remove = __devexit_p(pvscsi_remove),
+ COMPAT_PCI_SHUTDOWN(pvscsi_shutdown)
+};
+
+#ifdef CONFIG_PCI_MSI
+static const struct msix_entry base_entries[PVSCSI_DRIVER_VECTORS_USED] = {
+ { 0, PVSCSI_VECTOR_COMPLETION },
+};
+#endif
+
+static struct scsi_host_template pvscsi_template = {
+ .module = THIS_MODULE,
+ .name = "VMware PVSCSI Host Adapter",
+ .proc_name = "pvscsi",
+ .info = pvscsi_info,
+ .queuecommand = pvscsi_queue,
+ .this_id = -1,
+ .sg_tablesize = PVSCSI_MAX_NUM_SG_ENTRIES_PER_SEGMENT,
+ .dma_boundary = UINT_MAX,
+ .max_sectors = 0xffff,
+ .use_clustering = ENABLE_CLUSTERING,
+ .eh_abort_handler = pvscsi_abort,
+ .eh_device_reset_handler = pvscsi_device_reset,
+ .eh_bus_reset_handler = pvscsi_bus_reset,
+ .eh_host_reset_handler = pvscsi_host_reset,
+};
+
+struct PVSCSISGList {
+ PVSCSISGElement sge[PVSCSI_MAX_NUM_SG_ENTRIES_PER_SEGMENT];
+};
+
+/* Private per-request struct */
+struct pvscsi_ctx {
+ /*
+ * We use cmd->scsi_done to store the completion callback.
+ * The index of the context in cmd_map serves as the context ID for a
+ * 1-to-1 mapping completions back to requests.
+ */
+ struct scsi_cmnd *cmd;
+ struct PVSCSISGList *sgl;
+ struct list_head list;
+};
+
+/* Private per-adapter struct */
+struct pvscsi_adapter {
+ unsigned long base;
+ unsigned long iomap;
+ unsigned int irq;
+ char rev;
+ char use_msi;
+ char use_msix;
+ char log;
+
+ spinlock_t hw_lock;
+ RingReqDesc *req_ring;
+ unsigned req_pages;
+ unsigned req_depth;
+
+ RingCmpDesc *cmp_ring;
+ unsigned cmp_pages;
+ unsigned cmp_depth;
+
+ RingsState *ring_state;
+
+ struct pci_dev *dev;
+ struct Scsi_Host *host;
+
+ struct list_head cmd_pool;
+ struct pvscsi_ctx *cmd_map;
+ unsigned last_map;
+
+ int irq_vectors[PVSCSI_DRIVER_VECTORS_USED];
+};
+
+#define HOST_ADAPTER(host) ((struct pvscsi_adapter *)(host)->hostdata)
+
+/* Low-level adapter function prototypes */
+static inline u32 pvscsi_read_intr_status(const struct pvscsi_adapter *adapter);
+static inline void pvscsi_write_intr_status(const struct pvscsi_adapter *adapter,
+ u32 val);
+static inline void pvscsi_write_intr_mask(const struct pvscsi_adapter *adapter,
+ u32 val);
+static void pvscsi_abort_cmd(const struct pvscsi_adapter *adapter,
+ const struct pvscsi_ctx *ctx);
+static void pvscsi_kick_io(const struct pvscsi_adapter *adapter, unsigned char op);
+static void pvscsi_process_request_ring(const struct pvscsi_adapter *adapter);
+static void ll_adapter_reset(const struct pvscsi_adapter *adapter);
+static void ll_bus_reset(const struct pvscsi_adapter *adapter);
+static void ll_device_reset(const struct pvscsi_adapter *adapter, u32 target);
+static void pvscsi_setup_rings(struct pvscsi_adapter *adapter);
+static void pvscsi_process_completion_ring(struct pvscsi_adapter *adapter);
+
+static inline int pvscsi_queue_ring(struct pvscsi_adapter *adapter,
+ struct pvscsi_ctx *ctx,
+ struct scsi_cmnd *cmd);
+static inline void pvscsi_complete_request(struct pvscsi_adapter *adapter,
+ const RingCmpDesc *e);
+
+#define LOG(level, fmt, args...) \
+do { \
+ if (pvscsi_debug_level > level) \
+ printk(KERN_DEBUG "pvscsi: " fmt, args); \
+} while (0)
+
+module_init(pvscsi_init);
+static int __init pvscsi_init(void)
+{
+ printk(KERN_DEBUG "%s - version %s\n",
+ PVSCSI_LINUX_DRIVER_DESC, PVSCSI_DRIVER_VERSION_STRING);
+ return pci_register_driver(&pvscsi_pci_driver);
+}
+
+module_exit(pvscsi_exit);
+static void __exit pvscsi_exit(void)
+{
+ pci_unregister_driver(&pvscsi_pci_driver);
+}
+
+static inline void pvscsi_free_sgls(struct pvscsi_adapter *adapter)
+{
+ unsigned i, max;
+ struct pvscsi_ctx *ctx = adapter->cmd_map;
+
+ max = adapter->req_depth;
+ for (i = 0; i < max; ++i, ++ctx)
+ kfree(ctx->sgl);
+}
+
+static inline int pvscsi_setup_msix(struct pvscsi_adapter *adapter)
+{
+#ifdef CONFIG_PCI_MSI
+ int ret;
+ unsigned i;
+ struct msix_entry entries[PVSCSI_DRIVER_VECTORS_USED];
+
+ memcpy(entries, base_entries, sizeof entries);
+ ret = pci_enable_msix(adapter->dev, entries, ARRAY_SIZE(entries));
+ if (ret != 0)
+ return ret;
+
+ for (i = 0; i < PVSCSI_DRIVER_VECTORS_USED; i++)
+ adapter->irq_vectors[i] = entries[i].vector;
+
+ return 0;
+#else
+ return -1;
+#endif
+}
+
+static inline void pvscsi_shutdown_msi(struct pvscsi_adapter *adapter)
+{
+#ifdef CONFIG_PCI_MSI
+
+ if (adapter->use_msi)
+ pci_disable_msi(adapter->dev);
+
+ if (adapter->use_msix) {
+#if 0
+ /* For when multiple vectors are supported */
+ unsigned i;
+ for (i = 0; i < PVSCSI_DRIVER_VECTORS_USED; i++)
+ if (adapter->irq_vectors[i] != -1)
+ free_irq(adapter->irq_vectors[i], adapter);
+#endif
+ pci_disable_msix(adapter->dev);
+ }
+#endif
+}
+
+static void pvscsi_release_resources(struct pvscsi_adapter *adapter)
+{
+ if (adapter->irq)
+ free_irq(adapter->irq, adapter);
+
+ pvscsi_shutdown_msi(adapter);
+
+ if (adapter->iomap)
+ iounmap((void *)adapter->iomap);
+
+ pci_release_regions(adapter->dev);
+
+ if (adapter->cmd_map) {
+ pvscsi_free_sgls(adapter);
+ kfree(adapter->cmd_map);
+ }
+
+ kfree(adapter->ring_state);
+
+ if (adapter->req_ring)
+ vfree(adapter->req_ring);
+
+ if (adapter->cmp_ring)
+ vfree(adapter->cmp_ring);
+}
+
+static int __devinit pvscsi_allocate_rings(struct pvscsi_adapter *adapter)
+{
+ adapter->ring_state = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!adapter->ring_state)
+ return -ENOMEM;
+
+ adapter->req_pages = MIN(PVSCSI_MAX_NUM_PAGES_REQ_RING,
+ pvscsi_ring_pages);
+ adapter->req_depth = adapter->req_pages *
+ PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE;
+ adapter->req_ring = vmalloc(adapter->req_pages * PAGE_SIZE);
+ if (!adapter->req_ring)
+ return -ENOMEM;
+
+ adapter->cmp_pages = MIN(PVSCSI_MAX_NUM_PAGES_CMP_RING,
+ pvscsi_ring_pages);
+ adapter->cmp_depth = adapter->cmp_pages *
+ PVSCSI_MAX_NUM_CMP_ENTRIES_PER_PAGE;
+ adapter->cmp_ring = vmalloc(adapter->cmp_pages * PAGE_SIZE);
+ if (!adapter->cmp_ring)
+ return -ENOMEM;
+
+ return 0;
+}
+
+/*
+ * Allocate scatter gather lists.
+ *
+ * These are statically allocated. Trying to be clever was not worth it.
+ *
+ * Dynamic allocation can fail, and we can't go deeep into the memory
+ * allocator, since we're a SCSI driver, and trying too hard to allocate
+ * memory might generate disk I/O. We also don't want to fail disk I/O
+ * in that case because we can't get an allocation - the I/O could be
+ * trying to swap out data to free memory. Since that is pathological,
+ * just use a statically allocated scatter list.
+ *
+ */
+static int __devinit pvscsi_allocate_sg(struct pvscsi_adapter *adapter)
+{
+ unsigned i, max;
+ struct pvscsi_ctx *ctx = adapter->cmd_map;
+
+ max = adapter->req_depth;
+ ASSERT_ON_COMPILE(sizeof(struct PVSCSISGList) <= PAGE_SIZE);
+ for (i = 0; i < max; ++i, ++ctx) {
+ ctx->sgl = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ BUG_ON((long)ctx->sgl & ~PAGE_MASK);
+ if (!ctx->sgl) {
+ for (; i >= 0; --i, --ctx) {
+ kfree(ctx->sgl);
+ ctx->sgl = NULL;
+ }
+ return -ENOMEM;
+ }
+ }
+
+ return 0;
+}
+
+static int __devinit
+pvscsi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ int error = -ENODEV;
+ u8 pci_bus, pci_dev_func, rev;
+ unsigned long base, remap, i;
+ struct Scsi_Host *host;
+ int irq;
+ struct pvscsi_adapter *adapter;
+
+ if (pci_enable_device(pdev))
+ return error;
+
+ if (pdev->vendor != PCI_VENDOR_ID_VMWARE)
+ goto out_disable_device;
+
+ pci_bus = pdev->bus->number;
+ pci_dev_func = pdev->devfn;
+ pci_read_config_byte(pdev, PCI_CLASS_REVISION, &rev);
+
+ if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) ||
+ pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) {
+ if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) &&
+ pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) {
+ printk(KERN_ERR "pvscsi: unable to set usable DMA mask\n");
+ goto out_disable_device;
+ }
+ }
+
+ printk(KERN_NOTICE "pvscsi: found VMware PVSCSI rev %d on "
+ "bus %d:slot %d:func %d\n", rev, pci_bus,
+ PCI_SLOT(pci_dev_func), PCI_FUNC(pci_dev_func));
+
+ pvscsi_template.can_queue =
+ MIN(PVSCSI_MAX_NUM_PAGES_REQ_RING, pvscsi_ring_pages) *
+ PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE;
+ pvscsi_template.cmd_per_lun =
+ MIN(pvscsi_template.can_queue, pvscsi_cmd_per_lun);
+ host = scsi_host_alloc(&pvscsi_template, sizeof(struct pvscsi_adapter));
+ if (!host) {
+ printk(KERN_ERR "pvscsi: failed to allocate host\n");
+ goto out_disable_device;
+ }
+
+ adapter = HOST_ADAPTER(host);
+ memset(adapter, 0, sizeof(*adapter));
+ for (i = 0; i < PVSCSI_DRIVER_VECTORS_USED; i++)
+ adapter->irq_vectors[i] = -1;
+ adapter->dev = pdev;
+ adapter->host = host;
+ adapter->rev = rev;
+
+ spin_lock_init(&adapter->hw_lock);
+
+ host->max_channel = 0;
+ host->max_id = 16;
+ host->max_lun = 1;
+
+ if (pci_request_regions(pdev, "pvscsi")) {
+ printk(KERN_ERR "pvscsi: pci memory selection failed\n");
+ goto out_free_host;
+ }
+
+ /* Find the BARs for memory mapped I/O */
+ base = 0;
+ for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+ if ((pci_resource_flags(pdev, i) & PCI_BASE_ADDRESS_SPACE_IO))
+ continue;
+
+ /* Skip non-kick memory mapped space */
+ if (pci_resource_len(pdev, i) < PVSCSI_MEM_SPACE_NUM_PAGES * PAGE_SIZE)
+ continue;
+
+ base = pci_resource_start(pdev, i);
+ break;
+ }
+
+ if (!base) {
+ printk(KERN_ERR "pvscsi: adapter has no suitable MMIO region\n");
+ goto out_release_resources;
+ }
+ remap = (unsigned long)ioremap(base, PVSCSI_MEM_SPACE_SIZE);
+ if (!remap) {
+ printk(KERN_ERR "pvscsi: can't ioremap 0x%lx\n", base);
+ goto out_release_resources;
+ }
+ adapter->iomap = remap;
+
+ pci_set_master(pdev);
+ pci_set_drvdata(pdev, host);
+
+ ll_adapter_reset(adapter);
+ error = pvscsi_allocate_rings(adapter);
+ if (error) {
+ printk(KERN_ERR "pvscsi: unable to allocate ring memory\n");
+ goto out_release_resources;
+ }
+
+ /*
+ * Setup the rings; from this point on we should reset
+ * the adapter if anything goes wrong.
+ */
+ pvscsi_setup_rings(adapter);
+
+ adapter->cmd_map = kmalloc(adapter->req_depth *
+ sizeof(struct pvscsi_ctx), GFP_KERNEL);
+ if (!adapter->cmd_map) {
+ printk(KERN_ERR "pvscsi: failed to allocate memory.\n");
+ goto out_reset_adapter;
+ }
+ memset(adapter->cmd_map, 0, adapter->req_depth *
+ sizeof(struct pvscsi_ctx));
+
+ INIT_LIST_HEAD(&adapter->cmd_pool);
+ for (i = 0; i < adapter->req_depth; i++) {
+ struct pvscsi_ctx *ctx = adapter->cmd_map + i;
+ list_add(&ctx->list, &adapter->cmd_pool);
+ }
+
+ /* Now allocate a DMA-able cache for SG lists */
+ if (pvscsi_allocate_sg(adapter) != 0) {
+ printk(KERN_WARNING "pvscsi: unable to allocate SG cache\n");
+ printk(KERN_WARNING "pvscsi: disabling scatter/gather.\n");
+ host->sg_tablesize = 1;
+ }
+
+ /* Setup MSI if possible */
+#ifdef CONFIG_PCI_MSI
+ if (!pvscsi_disable_msix && pvscsi_setup_msix(adapter) == 0) {
+ printk(KERN_INFO "pvscsi: enabled MSI-X\n");
+ adapter->use_msix = 1;
+ } else if (!pvscsi_disable_msi && pci_enable_msi(pdev) == 0) {
+ printk(KERN_INFO "pvscsi: enabled MSI\n");
+ adapter->use_msi = 1;
+ } else
+ printk(KERN_INFO "pvscsi: using normal PCI interrupts\n");
+#else
+ printk(KERN_INFO "pvscsi: this kernel does not support MSI, consider enabling it\n");
+#endif
+
+ /* Now get an IRQ. For MSI-X, we only use one vector currently, vector zero */
+ ASSERT_ON_COMPILE(PVSCSI_DRIVER_VECTORS_USED == 1);
+ irq = adapter->use_msix ? adapter->irq_vectors[0] : pdev->irq;
+ if (request_irq(irq, pvscsi_isr, COMPAT_IRQF_SHARED, "pvscsi", adapter)) {
+ printk(KERN_ERR "pvscsi: unable to request IRQ %d\n", irq);
+ goto out_reset_adapter;
+ }
+ adapter->irq = irq;
+
+ error = scsi_add_host(host, &pdev->dev);
+ if (error) {
+ printk(KERN_ERR "pvscsi: scsi_add_host failed: %d\n", error);
+ goto out_reset_adapter;
+ }
+
+ /* Enable device interrupts */
+ pvscsi_write_intr_mask(adapter, PVSCSI_INTR_ALL);
+
+ scsi_scan_host(host);
+
+ return 0;
+
+out_reset_adapter:
+ ll_adapter_reset(adapter);
+out_release_resources:
+ pvscsi_release_resources(adapter);
+out_free_host:
+ scsi_host_put(host);
+out_disable_device:
+ pci_set_drvdata(pdev, NULL);
+ pci_disable_device(pdev);
+
+ return error;
+}
+
+static const char *pvscsi_info(struct Scsi_Host *host)
+{
+ static char buf[512];
+ struct pvscsi_adapter *adapter = HOST_ADAPTER(host);
+
+ sprintf(buf, "VMware PVSCSI storage adapter rev %c, %u reqs (%u pages), %u cmps (%u pages), cmd_per_lun=%u",
+ adapter->rev + 'A' - 1,
+ adapter->req_depth, adapter->req_pages,
+ adapter->cmp_depth, adapter->cmp_pages,
+ pvscsi_template.cmd_per_lun);
+ return buf;
+}
+
+static struct pvscsi_ctx *
+pvscsi_find_context(const struct pvscsi_adapter *adapter, struct scsi_cmnd *cmd)
+{
+ struct pvscsi_ctx *ctx, *end;
+
+ end = &adapter->cmd_map[adapter->req_depth];
+ for (ctx = adapter->cmd_map; ctx < end; ctx++)
+ if (ctx->cmd == cmd)
+ return ctx;
+
+ return NULL;
+}
+
+static struct pvscsi_ctx *
+pvscsi_allocate_context(struct pvscsi_adapter *adapter, struct scsi_cmnd *cmd)
+{
+ struct pvscsi_ctx *ctx;
+
+ if (list_empty(&adapter->cmd_pool))
+ return NULL;
+
+ ctx = list_entry(adapter->cmd_pool.next, struct pvscsi_ctx, list);
+ ctx->cmd = cmd;
+ list_del(&ctx->list);
+
+ return ctx;
+}
+
+static inline struct scsi_cmnd *
+pvscsi_free_context(struct pvscsi_adapter *adapter, struct pvscsi_ctx *ctx)
+{
+ struct scsi_cmnd *cmd;
+
+ cmd = ctx->cmd;
+ ctx->cmd = NULL;
+ list_add(&ctx->list, &adapter->cmd_pool);
+
+ return cmd;
+}
+
+/*
+ * Map a pvscsi_ctx struct to a context ID field value; we map to a simple
+ * non-zero integer.
+ */
+static inline u64
+pvscsi_map_context(const struct pvscsi_adapter *adapter, const struct pvscsi_ctx *ctx)
+{
+ return (ctx - adapter->cmd_map) + 1;
+}
+
+static inline struct pvscsi_ctx *
+pvscsi_get_context(const struct pvscsi_adapter *adapter, u64 context)
+{
+ return &adapter->cmd_map[context - 1];
+}
+
+static int pvscsi_queue(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
+{
+ struct Scsi_Host *host = cmd->device->host;
+ struct pvscsi_adapter *adapter = HOST_ADAPTER(host);
+ struct pvscsi_ctx *ctx;
+ unsigned long flags;
+
+ spin_lock_irqsave(&adapter->hw_lock, flags);
+
+ ctx = pvscsi_allocate_context(adapter, cmd);
+ if (!ctx || pvscsi_queue_ring(adapter, ctx, cmd) != 0) {
+ if (ctx)
+ pvscsi_free_context(adapter, ctx);
+ spin_unlock_irqrestore(&adapter->hw_lock, flags);
+ return SCSI_MLQUEUE_HOST_BUSY;
+ }
+
+ cmd->scsi_done = done;
+
+ LOG(3, "queued cmd %p, ctx %p, op=%x\n", cmd, ctx, cmd->cmnd[0]);
+
+ spin_unlock_irqrestore(&adapter->hw_lock, flags);
+
+ pvscsi_kick_io(adapter, cmd->cmnd[0]);
+
+ return 0;
+}
+
+static int pvscsi_abort(struct scsi_cmnd *cmd)
+{
+ struct pvscsi_adapter *adapter = HOST_ADAPTER(cmd->device->host);
+ struct pvscsi_ctx *ctx;
+ unsigned long flags;
+
+ printk(KERN_DEBUG "pvscsi: attempting task abort on %p, %p\n",
+ adapter, cmd);
+
+ spin_lock_irqsave(&adapter->hw_lock, flags);
+
+ /*
+ * Poll the completion ring first - we might be trying to abort
+ * a command that is waiting to be dispatched in the completion ring.
+ */
+ pvscsi_process_completion_ring(adapter);
+
+ /*
+ * If there is no context for the command, it either already succeeded
+ * or else was never properly issued. Not our problem.
+ */
+ ctx = pvscsi_find_context(adapter, cmd);
+ if (!ctx) {
+ LOG(1, "Failed to abort cmd %p\n", cmd);
+ goto out;
+ }
+
+ pvscsi_abort_cmd(adapter, ctx);
+
+ pvscsi_process_completion_ring(adapter);
+
+out:
+ spin_unlock_irqrestore(&adapter->hw_lock, flags);
+ return SUCCESS;
+}
+
+static inline void
+pvscsi_free_sg(const struct pvscsi_adapter *adapter, struct scsi_cmnd *cmd)
+{
+ unsigned count = scsi_sg_count(cmd);
+
+ if (count) {
+ struct scatterlist *sg = scsi_sglist(cmd);
+ pci_unmap_sg(adapter->dev, sg, count, cmd->sc_data_direction);
+ }
+}
+
+/*
+ * Abort all outstanding requests. This is only safe to use if the completion
+ * ring will never be walked again or the device has been reset, because it
+ * destroys the 1-1 mapping between context field passed to emulation and our
+ * request structure.
+ */
+static inline void pvscsi_reset_all(struct pvscsi_adapter *adapter)
+{
+ unsigned i;
+
+ for (i = 0; i < adapter->req_depth; i++) {
+ struct pvscsi_ctx *ctx = &adapter->cmd_map[i];
+ struct scsi_cmnd *cmd = ctx->cmd;
+ if (cmd) {
+ printk(KERN_ERR "pvscsi: forced reset on cmd %p\n", cmd);
+ pvscsi_free_sg(adapter, cmd);
+ pvscsi_free_context(adapter, ctx);
+ cmd->result = (DID_RESET << 16);
+ cmd->scsi_done(cmd);
+ }
+ }
+}
+
+static int pvscsi_host_reset(struct scsi_cmnd *cmd)
+{
+ struct Scsi_Host *host = cmd->device->host;
+ struct pvscsi_adapter *adapter = HOST_ADAPTER(host);
+ unsigned long flags;
+
+ printk(KERN_NOTICE "pvscsi: attempting host reset on %p\n", adapter);
+
+ /*
+ * We're going to tear down the entire ring structure and set it back
+ * up, so stalling new requests until all completions are flushed and
+ * the rings are back in place.
+ */
+ spin_lock_irqsave(&adapter->hw_lock, flags);
+
+ pvscsi_process_request_ring(adapter);
+ ll_adapter_reset(adapter);
+
+ /*
+ * Now process any completions. Note we do this AFTER adapter reset,
+ * which is strange, but stops races where completions get posted
+ * between processing the ring and issuing the reset. The backend will
+ * not touch the ring memory after reset, so the immediately pre-reset
+ * completion ring state is still valid.
+ */
+ pvscsi_process_completion_ring(adapter);
+
+ pvscsi_reset_all(adapter);
+ pvscsi_setup_rings(adapter);
+ pvscsi_write_intr_mask(adapter, PVSCSI_INTR_ALL);
+
+ spin_unlock_irqrestore(&adapter->hw_lock, flags);
+
+ return SUCCESS;
+}
+
+static int pvscsi_bus_reset(struct scsi_cmnd *cmd)
+{
+ struct Scsi_Host *host = cmd->device->host;
+ struct pvscsi_adapter *adapter = HOST_ADAPTER(host);
+ unsigned long flags;
+
+ printk(KERN_NOTICE "pvscsi: attempting bus reset on %p\n", adapter);
+
+ /*
+ * We don't want to queue new requests for this bus after
+ * flushing all pending requests to emulation, since new
+ * requests could then sneak in during this bus reset phase,
+ * so take the lock now.
+ */
+ spin_lock_irqsave(&adapter->hw_lock, flags);
+
+ pvscsi_process_request_ring(adapter);
+ ll_bus_reset(adapter);
+ pvscsi_process_completion_ring(adapter);
+
+ spin_unlock_irqrestore(&adapter->hw_lock, flags);
+
+ return SUCCESS;
+}
+
+static int pvscsi_device_reset(struct scsi_cmnd *cmd)
+{
+ struct Scsi_Host *host = cmd->device->host;
+ struct pvscsi_adapter *adapter = HOST_ADAPTER(host);
+ unsigned long flags;
+
+ printk(KERN_NOTICE "pvscsi: attempting device reset on %p,%d\n",
+ adapter, cmd->device->id);
+
+ /*
+ * We don't want to queue new requests for this device after flushing
+ * all pending requests to emulation, since new requests could then
+ * sneak in during this device reset phase, so take the lock now.
+ */
+ spin_lock_irqsave(&adapter->hw_lock, flags);
+
+ pvscsi_process_request_ring(adapter);
+ ll_device_reset(adapter, cmd->device->id);
+ pvscsi_process_completion_ring(adapter);
+
+ spin_unlock_irqrestore(&adapter->hw_lock, flags);
+
+ return SUCCESS;
+}
+
+static irqreturn_t pvscsi_isr COMPAT_IRQ_HANDLER_ARGS(irq, devp)
+{
+ struct pvscsi_adapter *adapter = devp;
+ int handled = FALSE;
+
+ if (adapter->use_msi || adapter->use_msix)
+ handled = TRUE;
+ else {
+ u32 val = pvscsi_read_intr_status(adapter);
+ handled = (val & PVSCSI_INTR_ALL) != 0;
+ if (handled)
+ pvscsi_write_intr_status(devp, val);
+ }
+
+ if (handled) {
+ unsigned long flags;
+ spin_lock_irqsave(&adapter->hw_lock, flags);
+ pvscsi_process_completion_ring(adapter);
+ spin_unlock_irqrestore(&adapter->hw_lock, flags);
+ }
+
+ LOG(2, "pvscsi_isr %d\n", handled);
+
+ return IRQ_RETVAL(handled);
+}
+
+/* Shutdown an entire device, syncinc all outstanding I/O */
+static void __pvscsi_shutdown(struct pvscsi_adapter *adapter)
+{
+ pvscsi_write_intr_mask(adapter, 0);
+ if (adapter->irq) {
+ free_irq(adapter->irq, adapter);
+ adapter->irq = 0;
+ }
+
+#ifdef CONFIG_PCI_MSI
+ if (adapter->use_msi) {
+ pci_disable_msi(adapter->dev);
+ adapter->use_msi = 0;
+ }
+#endif
+
+ pvscsi_process_request_ring(adapter);
+ pvscsi_process_completion_ring(adapter);
+ ll_adapter_reset(adapter);
+}
+
+static void COMPAT_PCI_DECLARE_SHUTDOWN(pvscsi_shutdown, dev)
+{
+ struct Scsi_Host *host = pci_get_drvdata(COMPAT_PCI_TO_DEV(dev));
+ struct pvscsi_adapter *adapter = HOST_ADAPTER(host);
+
+ __pvscsi_shutdown(adapter);
+}
+
+static void pvscsi_remove(struct pci_dev *pdev)
+{
+ struct Scsi_Host *host = pci_get_drvdata(pdev);
+ struct pvscsi_adapter *adapter = HOST_ADAPTER(host);
+
+ scsi_remove_host(host);
+
+ __pvscsi_shutdown(adapter);
+ pvscsi_release_resources(adapter);
+
+ scsi_host_put(host);
+
+ pci_set_drvdata(pdev, NULL);
+ pci_disable_device(pdev);
+}
+
+
+/**************************************************************
+ *
+ * VMWARE Hypervisor ring / SCSI mid-layer interactions
+ *
+ * Functions which have to deal with both ring semantics
+ * and Linux SCSI internals are placed here.
+ *
+ **************************************************************/
+
+static inline struct PVSCSISGList *
+pvscsi_create_sg(struct pvscsi_ctx *ctx, struct scatterlist *sg, unsigned count)
+{
+ unsigned i;
+ struct PVSCSISGList *sgl;
+ struct PVSCSISGElement *sge;
+
+ sgl = ctx->sgl;
+
+ BUG_ON(count > PVSCSI_MAX_NUM_SG_ENTRIES_PER_SEGMENT);
+
+ sge = &sgl->sge[0];
+ for (i = 0; i < count; i++, sg++) {
+ sge[i].addr = sg_dma_address(sg);
+ sge[i].length = sg_dma_len(sg);
+ sge[i].flags = 0;
+ }
+
+ return sgl;
+}
+
+/*
+ * Map all data buffers for a command into PCI space and
+ * setup the scatter/gather list if needed.
+ */
+static inline void
+pvscsi_map_buffers(struct pvscsi_adapter *adapter, struct pvscsi_ctx *ctx,
+ struct scsi_cmnd *cmd, RingReqDesc *e)
+{
+ unsigned count;
+ unsigned bufflen = scsi_bufflen(cmd);
+
+ e->dataLen = bufflen;
+ e->dataAddr = 0;
+ if (bufflen == 0)
+ return;
+
+ count = scsi_sg_count(cmd);
+ if (count != 0) {
+ struct scatterlist *sg = scsi_sglist(cmd);
+ int segs = pci_map_sg(adapter->dev, sg, count,
+ cmd->sc_data_direction);
+ if (segs > 1) {
+ struct PVSCSISGList *sgl;
+
+ e->flags |= PVSCSI_FLAG_CMD_WITH_SG_LIST;
+ sgl = pvscsi_create_sg(ctx, sg, segs);
+ e->dataAddr = __pa(sgl);
+ } else
+ e->dataAddr = sg_dma_address(sg);
+ } else {
+ e->dataAddr = __pa(scsi_request_buffer(cmd));
+ }
+}
+
+/*
+ * Translate a Linux SCSI request into a request ring entry.
+ */
+static inline int
+pvscsi_queue_ring(struct pvscsi_adapter *adapter, struct pvscsi_ctx *ctx,
+ struct scsi_cmnd *cmd)
+{
+ RingsState *s;
+ RingReqDesc *e, *ring;
+
+ s = adapter->ring_state;
+ ring = adapter->req_ring;
+
+ /*
+ * If this condition holds, we might have room on the request ring, but
+ * we might not have room on the completion ring for the response.
+ * However, we have already ruled out this possibility - we would not
+ * have successfully allocated a context if it were true, since we only
+ * have one context per request entry. Check for it anyway, since it
+ * would be a serious bug.
+ */
+ if (s->reqProdIdx - s->cmpConsIdx >= adapter->req_depth) {
+ printk(KERN_ERR "pvscsi: ring full: reqProdIdx=%d cmpConsIdx=%d\n",
+ s->reqProdIdx, s->cmpConsIdx);
+ return -1;
+ }
+
+ e = ring + (s->reqProdIdx % adapter->req_depth);
+ {
+ struct scsi_device *sdev;
+ sdev = cmd->device;
+ e->bus = sdev->channel;
+ e->target = sdev->id;
+ memset(e->lun, 0, sizeof(e->lun));
+ e->lun[1] = sdev->lun;
+ }
+ if (cmd->sense_buffer) {
+ e->senseLen = SCSI_SENSE_BUFFERSIZE;
+ e->senseAddr = __pa(cmd->sense_buffer);
+ } else {
+ e->senseLen = 0;
+ e->senseAddr = 0;
+ }
+ e->cdbLen = cmd->cmd_len;
+ e->vcpuHint = smp_processor_id();
+ memcpy(e->cdb, cmd->cmnd, e->cdbLen);
+
+ e->tag = SIMPLE_QUEUE_TAG;
+ if (cmd->device->tagged_supported) {
+ if (cmd->tag == HEAD_OF_QUEUE_TAG ||
+ cmd->tag == ORDERED_QUEUE_TAG)
+ e->tag = cmd->tag;
+ }
+
+ if (cmd->sc_data_direction == DMA_FROM_DEVICE)
+ e->flags = PVSCSI_FLAG_CMD_DIR_TOHOST;
+ else if (cmd->sc_data_direction == DMA_TO_DEVICE)
+ e->flags = PVSCSI_FLAG_CMD_DIR_TODEVICE;
+ else if (cmd->sc_data_direction == DMA_NONE)
+ e->flags = PVSCSI_FLAG_CMD_DIR_NONE;
+ else
+ e->flags = 0;
+
+ pvscsi_map_buffers(adapter, ctx, cmd, e);
+
+ /*
+ * Fill in the context entry so we can recognize this
+ * request off the completion queue
+ */
+ e->context = pvscsi_map_context(adapter, ctx);
+
+ barrier();
+
+ s->reqProdIdx++;
+
+ return 0;
+}
+
+/*
+ * Pull a completion descriptor off and pass the completion back
+ * to the SCSI mid layer.
+ */
+static inline void
+pvscsi_complete_request(struct pvscsi_adapter *adapter, const RingCmpDesc *e)
+{
+ struct pvscsi_ctx *ctx;
+ struct scsi_cmnd *cmd;
+ u32 btstat = e->hostStatus;
+ u32 sdstat = e->scsiStatus;
+
+ ctx = pvscsi_get_context(adapter, e->context);
+ cmd = pvscsi_free_context(adapter, ctx);
+ cmd->result = 0;
+
+ if (sdstat != SAM_STAT_GOOD &&
+ (btstat == BTSTAT_SUCCESS ||
+ btstat == BTSTAT_LINKED_COMMAND_COMPLETED ||
+ btstat == BTSTAT_LINKED_COMMAND_COMPLETED_WITH_FLAG))
+ switch (sdstat) {
+ case SAM_STAT_CHECK_CONDITION:
+ /*
+ * Sense data is set by the emulation.
+ * Linux seems to want DID_OK despite the error.
+ */
+ cmd->result = (DID_OK << 16) | (SAM_STAT_CHECK_CONDITION);
+ if (cmd->sense_buffer)
+ cmd->result |= (DRIVER_SENSE << 24);
+ break;
+ case SAM_STAT_BUSY:
+ /* Back off. */
+ cmd->result = (DID_OK << 16) | sdstat;
+ break;
+ default:
+ cmd->result = (DID_ERROR << 16);
+ LOG(0, "Unhandled SCSI status: 0x%x\n", sdstat);
+ }
+
+ else
+ switch (btstat) {
+ case BTSTAT_SUCCESS:
+ case BTSTAT_LINKED_COMMAND_COMPLETED:
+ case BTSTAT_LINKED_COMMAND_COMPLETED_WITH_FLAG:
+ /* If everything went fine, let's move on.. */
+ cmd->result = (DID_OK << 16);
+ break;
+
+ case BTSTAT_DATARUN:
+ case BTSTAT_DATA_UNDERRUN:
+ /* Report residual data in underruns */
+ scsi_set_resid(cmd, scsi_bufflen(cmd) - e->dataLen);
+ cmd->result = (DID_ERROR << 16);
+ break;
+
+ case BTSTAT_SELTIMEO:
+ /* Our emulation returns this for non-connected devs */
+ cmd->result = (DID_BAD_TARGET << 16);
+ break;
+
+ case BTSTAT_LUNMISMATCH:
+ case BTSTAT_TAGREJECT:
+ case BTSTAT_BADMSG:
+ cmd->result = (DRIVER_INVALID << 24);
+ /* fall through */
+
+ case BTSTAT_HAHARDWARE:
+ case BTSTAT_INVPHASE:
+ case BTSTAT_HATIMEOUT:
+ case BTSTAT_NORESPONSE:
+ case BTSTAT_DISCONNECT:
+ case BTSTAT_HASOFTWARE:
+ case BTSTAT_BUSFREE:
+ case BTSTAT_SENSFAILED:
+ cmd->result |= (DID_ERROR << 16);
+ break;
+
+ case BTSTAT_SENTRST:
+ case BTSTAT_RECVRST:
+ case BTSTAT_BUSRESET:
+ cmd->result = (DID_RESET << 16);
+ break;
+
+ case BTSTAT_ABORTQUEUE:
+ cmd->result = (DID_ABORT << 16);
+ break;
+
+ case BTSTAT_SCSIPARITY:
+ cmd->result = (DID_PARITY << 16);
+ break;
+
+ default:
+ cmd->result = (DID_ERROR << 16);
+ LOG(0, "Unknown completion status: 0x%x\n", btstat);
+ }
+
+ LOG(3, "cmd=%p %x ctx=%p result=0x%x status=0x%x,%x\n",
+ cmd, cmd->cmnd[0], ctx, cmd->result, btstat, sdstat);
+
+ pvscsi_free_sg(adapter, cmd);
+
+ cmd->scsi_done(cmd);
+}
+
+
+/**************************************************************
+ *
+ * VMWARE PVSCSI Hypervisor Communication Implementation
+ *
+ * This code should be maintained to match the Windows driver
+ * as closely as possible. This code is largely independent
+ * of any Linux internals.
+ *
+ **************************************************************/
+
+static inline void pvscsi_reg_write(const struct pvscsi_adapter *adapter,
+ u32 offset, u32 val)
+{
+ writel(val, (void *)(adapter->iomap + offset));
+}
+
+static inline u32 pvscsi_reg_read(const struct pvscsi_adapter *adapter,
+ u32 offset)
+{
+ return readl((void *)(adapter->iomap + offset));
+}
+
+static inline u32 pvscsi_read_intr_status(const struct pvscsi_adapter *adapter)
+{
+ return pvscsi_reg_read(adapter, PVSCSI_REG_OFFSET_INTR_STATUS);
+}
+
+static inline void pvscsi_write_intr_status(const struct pvscsi_adapter *adapter,
+ u32 val)
+{
+ pvscsi_reg_write(adapter, PVSCSI_REG_OFFSET_INTR_STATUS, val);
+}
+
+static inline void pvscsi_write_intr_mask(const struct pvscsi_adapter *adapter,
+ u32 val)
+{
+ pvscsi_reg_write(adapter, PVSCSI_REG_OFFSET_INTR_MASK, val);
+}
+
+static inline void pvscsi_write_cmd_desc(const struct pvscsi_adapter *adapter,
+ u32 cmd, void *desc, size_t len)
+{
+ u32 *ptr = (u32 *)desc;
+ unsigned i;
+
+ len /= sizeof(u32);
+ pvscsi_reg_write(adapter, PVSCSI_REG_OFFSET_COMMAND, cmd);
+ for (i = 0; i < len; i++)
+ pvscsi_reg_write(adapter, PVSCSI_REG_OFFSET_COMMAND_DATA, ptr[i]);
+}
+
+static void pvscsi_abort_cmd(const struct pvscsi_adapter *adapter,
+ const struct pvscsi_ctx *ctx)
+{
+ struct CmdDescAbortCmd cmd;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.target = ctx->cmd->device->id;
+ cmd.context = pvscsi_map_context(adapter, ctx);
+
+ pvscsi_write_cmd_desc(adapter, PVSCSI_CMD_ABORT_CMD, &cmd, sizeof(cmd));
+}
+
+static inline void pvscsi_kick_rw_io(const struct pvscsi_adapter *adapter)
+{
+ pvscsi_reg_write(adapter, PVSCSI_REG_OFFSET_KICK_RW_IO, 0);
+}
+
+/* Get device to respond immediately */
+static void pvscsi_process_request_ring(const struct pvscsi_adapter *adapter)
+{
+ pvscsi_reg_write(adapter, PVSCSI_REG_OFFSET_KICK_NON_RW_IO, 0);
+}
+
+static inline int scsi_is_rw(unsigned char op)
+{
+ return op == READ_6 || op == WRITE_6 ||
+ op == READ_10 || op == WRITE_10 ||
+ op == READ_12 || op == WRITE_12 ||
+ op == READ_16 || op == WRITE_16;
+}
+
+static void pvscsi_kick_io(const struct pvscsi_adapter *adapter, unsigned char op)
+{
+ if (scsi_is_rw(op))
+ pvscsi_kick_rw_io(adapter);
+ else
+ pvscsi_process_request_ring(adapter);
+}
+
+static void ll_adapter_reset(const struct pvscsi_adapter *adapter)
+{
+ u32 val;
+
+ LOG(0, "Adapter Reset on %p\n", adapter);
+
+ pvscsi_write_cmd_desc(adapter, PVSCSI_CMD_ADAPTER_RESET, NULL, 0);
+ val = pvscsi_read_intr_status(adapter);
+ LOG(0, "Adapter Reset done: %u\n", val);
+}
+
+static void ll_bus_reset(const struct pvscsi_adapter *adapter)
+{
+ LOG(0, "Reseting bus on %p\n", adapter);
+
+ pvscsi_write_cmd_desc(adapter, PVSCSI_CMD_RESET_BUS, NULL, 0);
+}
+
+static void ll_device_reset(const struct pvscsi_adapter *adapter, u32 target)
+{
+ struct CmdDescResetDevice cmd;
+
+ LOG(0, "Reseting device: target=%u\n", target);
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.target = target;
+
+ pvscsi_write_cmd_desc(adapter, PVSCSI_CMD_RESET_DEVICE, &cmd, sizeof(cmd));
+}
+
+static void pvscsi_setup_rings(struct pvscsi_adapter *adapter)
+{
+ struct CmdDescSetupRings cmd;
+ unsigned i, pages;
+ void *base;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.ringsStatePPN = __pa(adapter->ring_state) >> PAGE_SHIFT;
+
+ cmd.reqRingNumPages = pages = adapter->req_pages;
+ for (i = 0, base = adapter->req_ring; i < pages; i++, base += PAGE_SIZE)
+ cmd.reqRingPPNs[i] = page_to_pfn(vmalloc_to_page(base));
+
+ cmd.cmpRingNumPages = pages = adapter->cmp_pages;
+ for (i = 0, base = adapter->cmp_ring; i < pages; i++, base += PAGE_SIZE)
+ cmd.cmpRingPPNs[i] = page_to_pfn(vmalloc_to_page(base));
+
+ memset(adapter->ring_state, 0, PAGE_SIZE);
+ memset(adapter->req_ring, 0, adapter->req_pages * PAGE_SIZE);
+ memset(adapter->cmp_ring, 0, adapter->cmp_pages * PAGE_SIZE);
+
+ pvscsi_write_cmd_desc(adapter, PVSCSI_CMD_SETUP_RINGS, &cmd, sizeof(cmd));
+}
+
+static void pvscsi_process_completion_ring(struct pvscsi_adapter *adapter)
+{
+ RingsState *s = adapter->ring_state;
+ RingCmpDesc *ring = adapter->cmp_ring;
+
+ while (s->cmpConsIdx != s->cmpProdIdx) {
+ RingCmpDesc *e = ring + (s->cmpConsIdx % adapter->cmp_depth);
+
+ pvscsi_complete_request(adapter, e);
+ smp_wmb();
+ s->cmpConsIdx++;
+ }
+}
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. 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 version 2 and no 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. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ *********************************************************/
+
+#ifndef __PVSCSI_DEFS_H__
+#define __PVSCSI_DEFS_H__
+
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_VMMEXT
+#define INCLUDE_ALLOW_VMX
+#define INCLUDE_ALLOW_VMCORE
+#define INCLUDE_ALLOW_VMKERNEL
+#include "includeCheck.h"
+
+#include "vm_basic_types.h"
+
+
+/*
+ * Memory mapped i/o register offsets.
+ */
+
+enum PVSCSIRegOffset {
+ PVSCSI_REG_OFFSET_COMMAND = 0x0,
+ PVSCSI_REG_OFFSET_COMMAND_DATA = 0x4,
+ PVSCSI_REG_OFFSET_COMMAND_STATUS = 0x8,
+ PVSCSI_REG_OFFSET_LAST_STS_0 = 0x100,
+ PVSCSI_REG_OFFSET_LAST_STS_1 = 0x104,
+ PVSCSI_REG_OFFSET_LAST_STS_2 = 0x108,
+ PVSCSI_REG_OFFSET_LAST_STS_3 = 0x10C,
+ PVSCSI_REG_OFFSET_INTR_STATUS = 0x100c,
+ PVSCSI_REG_OFFSET_INTR_MASK = 0x2010,
+ PVSCSI_REG_OFFSET_KICK_NON_RW_IO = 0x3014,
+ PVSCSI_REG_OFFSET_KICK_RW_IO = 0x4018,
+};
+
+
+/*
+ * I/O space register offsets.
+ */
+
+enum PVSCSIIoRegOffset {
+ PVSCSI_IO_REG_OFFSET_OFFSET = 0,
+ PVSCSI_IO_REG_OFFSET_DATA = 4,
+};
+
+/*
+ * Configuration pages. Structure sizes are 4 byte multiples.
+ */
+
+enum ConfigPageType {
+ PVSCSI_CONFIG_PAGE_CONTROLLER = 0x1958,
+ PVSCSI_CONFIG_PAGE_PHY = 0x1959,
+ PVSCSI_CONFIG_PAGE_DEVICE = 0x195a,
+};
+
+/*
+ * For controller address,
+ * 63 31 0
+ * |-----------------------------|------------------------------|
+ * <--- controller constant----> <--------- All zeros --------->
+ *
+ * For phy address,
+ * 63 31 0
+ * |-----------------------------|------------------------------|
+ * <-- phy type constant -----> <--------- phy num ----------->
+ *
+ * For device address,
+ * 63 31 15 0
+ * |-----------------------------|--------------|---------------|
+ * <--bus/target type constant--> <--- bus ---> <--- target --->
+ */
+
+#define PVSCSI_CONFIG_ADDR_TYPE(addr) HIDWORD(addr)
+#define PVSCSI_CONFIG_ADDR_PHYNUM(addr) LODWORD(addr)
+#define PVSCSI_CONFIG_ADDR_BUS(addr) HIWORD(addr)
+#define PVSCSI_CONFIG_ADDR_TARGET(addr) LOWORD(addr)
+
+enum ConfigPageAddressType {
+ PVSCSI_CONFIG_CONTROLLER_ADDRESS = 0x2120,
+ PVSCSI_CONFIG_BUSTARGET_ADDRESS = 0x2121,
+ PVSCSI_CONFIG_PHY_ADDRESS = 0x2122,
+};
+
+typedef
+#include "vmware_pack_begin.h"
+struct PVSCSIConfigPageHeader {
+ uint32 pageNum;
+ uint16 numDwords; /* Including the header. */
+ uint16 hostStatus;
+ uint16 scsiStatus;
+ uint16 reserved[3];
+}
+#include "vmware_pack_end.h"
+PVSCSIConfigPageHeader;
+
+typedef
+#include "vmware_pack_begin.h"
+struct PVSCSIConfigPageController {
+ PVSCSIConfigPageHeader header;
+ uint64 nodeWWN; /* Device name as defined in the SAS spec. */
+ uint16 manufacturer[64];
+ uint16 serialNumber[64];
+ uint16 opromVersion[32];
+ uint16 hwVersion[32];
+ uint16 firmwareVersion[32];
+ uint32 numPhys;
+ uint8 useConsecutivePhyWWNs;
+ uint8 reserved[3];
+}
+#include "vmware_pack_end.h"
+PVSCSIConfigPageController;
+
+enum AttachedDeviceType {
+ PVSCSI_SAS_DEVICE = 1,
+ PVSCSI_SATA_DEVICE = 2,
+};
+
+typedef
+#include "vmware_pack_begin.h"
+struct PVSCSIConfigPagePhy {
+ PVSCSIConfigPageHeader header;
+ uint64 phyWWN;
+ uint64 attachedDeviceWWN; /* 0 => no attached device. */
+ uint8 attachedDeviceType;
+ uint8 reserved[7];
+}
+#include "vmware_pack_end.h"
+PVSCSIConfigPagePhy;
+
+typedef
+#include "vmware_pack_begin.h"
+struct PVSCSIConfigPageDevice {
+ PVSCSIConfigPageHeader header;
+ uint64 deviceWWN;
+ uint64 phyWWN;
+ uint32 phyNum;
+ uint8 target;
+ uint8 bus;
+ uint8 reserved[2];
+}
+#include "vmware_pack_end.h"
+PVSCSIConfigPageDevice;
+
+/*
+ * Virtual h/w commands.
+ */
+
+enum PVSCSICommands {
+ PVSCSI_CMD_FIRST = 0, /* NB: has to be first */
+
+ PVSCSI_CMD_ADAPTER_RESET = 1,
+ PVSCSI_CMD_ISSUE_SCSI = 2,
+ PVSCSI_CMD_SETUP_RINGS = 3,
+ PVSCSI_CMD_RESET_BUS = 4,
+ PVSCSI_CMD_RESET_DEVICE = 5,
+ PVSCSI_CMD_ABORT_CMD = 6,
+ PVSCSI_CMD_CONFIG = 7,
+
+ PVSCSI_CMD_LAST = 8 /* NB: has to be last */
+};
+
+
+/*
+ * Command descriptors.
+ */
+
+struct CmdDescIssueSCSI {
+ PA reqAddr;
+ PA cmpAddr;
+};
+
+struct CmdDescResetDevice {
+ uint32 target;
+ uint8 lun[8];
+};
+
+struct CmdDescAbortCmd {
+ uint64 context;
+ uint32 target;
+ uint32 _pad;
+};
+
+
+#define PVSCSI_SETUP_RINGS_MAX_NUM_PAGES 32
+struct CmdDescSetupRings {
+ uint32 reqRingNumPages;
+ uint32 cmpRingNumPages;
+ PPN64 ringsStatePPN;
+ PPN64 reqRingPPNs[PVSCSI_SETUP_RINGS_MAX_NUM_PAGES];
+ PPN64 cmpRingPPNs[PVSCSI_SETUP_RINGS_MAX_NUM_PAGES];
+};
+
+#include "vmware_pack_begin.h"
+struct CmdDescConfigCmd {
+ PA cmpAddr;
+ uint64 configPageAddress;
+ uint32 configPageNum;
+ uint32 _pad;
+}
+#include "vmware_pack_end.h"
+;
+
+/*
+ * Rings state.
+ */
+
+typedef struct RingsState {
+ uint32 reqProdIdx;
+ uint32 reqConsIdx;
+ uint32 reqNumEntriesLog2;
+
+ uint32 cmpProdIdx;
+ uint32 cmpConsIdx;
+ uint32 cmpNumEntriesLog2;
+} RingsState;
+
+
+/*
+ * Request descriptor.
+ *
+ * sizeof(RingReqDesc) = 128
+ *
+ * - context: is a unique identifier of a command. It could normally be any
+ * 64bit value, however we currently store it in the serialNumber variable
+ * of struct SCSI_Command, so we have the following restrictions due to the
+ * way this field is handled in the vmkernel storage stack:
+ * * this value can't be 0,
+ * * the upper 32bit need to be 0 since serialNumber is as a uint32.
+ * Currently tracked as PR 292060.
+ * - dataLen: contains the total number of bytes that need to be transferred.
+ * - dataAddr:
+ * * if PVSCSI_FLAG_CMD_WITH_SG_LIST is set: dataAddr is the PA of the first
+ * s/g table segment, each s/g segment is entirely contained on a single
+ * page of physical memory,
+ * * if PVSCSI_FLAG_CMD_WITH_SG_LIST is NOT set, then dataAddr is the PA of
+ * the buffer used for the DMA transfer,
+ * - flags:
+ * * PVSCSI_FLAG_CMD_WITH_SG_LIST: see dataAddr above,
+ * * PVSCSI_FLAG_CMD_DIR_NONE: no DMA involved,
+ * * PVSCSI_FLAG_CMD_DIR_TOHOST: transfer from device to main memory,
+ * * PVSCSI_FLAG_CMD_DIR_TODEVICE: transfer from main memory to device,
+ * * PVSCSI_FLAG_CMD_OUT_OF_BAND_CDB: reserved to handle CDBs larger than
+ * 16bytes. To be specified.
+ * - vcpuHint: vcpuId of the processor that will be most likely waiting for the
+ * completion of the i/o. For guest OSes that use lowest priority message
+ * delivery mode (such as windows), we use this "hint" to deliver the
+ * completion action to the proper vcpu. For now, we can use the vcpuId of
+ * the processor that initiated the i/o as a likely candidate for the vcpu
+ * that will be waiting for the completion..
+ */
+
+#define PVSCSI_FLAG_CMD_WITH_SG_LIST (1 << 0)
+#define PVSCSI_FLAG_CMD_OUT_OF_BAND_CDB (1 << 1)
+#define PVSCSI_FLAG_CMD_DIR_NONE (1 << 2)
+#define PVSCSI_FLAG_CMD_DIR_TOHOST (1 << 3)
+#define PVSCSI_FLAG_CMD_DIR_TODEVICE (1 << 4)
+
+typedef
+#include "vmware_pack_begin.h"
+struct RingReqDesc {
+ uint64 context;
+ PA dataAddr;
+ uint64 dataLen;
+ PA senseAddr;
+ uint32 senseLen;
+ uint32 flags;
+ uint8 cdb[16];
+ uint8 cdbLen;
+ uint8 lun[8];
+ uint8 tag;
+ uint8 bus;
+ uint8 target;
+ uint8 vcpuHint;
+ uint8 unused[59];
+}
+#include "vmware_pack_end.h"
+RingReqDesc;
+
+
+/*
+ * Scatter-gather list management.
+ *
+ * As described above, when PVSCSI_FLAG_CMD_WITH_SG_LIST is set in the
+ * RingReqDesc.flags, then RingReqDesc.dataAddr is the PA of the first s/g
+ * table segment.
+ *
+ * - each segment of the s/g table contain a succession of struct
+ * PVSCSISGElement.
+ * - each segment is entirely contained on a single physical page of memory.
+ * - a "chain" s/g element has the flag PVSCSI_SGE_FLAG_CHAIN_ELEMENT set in
+ * PVSCSISGElement.flags and in this case:
+ * * addr is the PA of the next s/g segment,
+ * * length is undefined, assumed to be 0.
+ */
+
+#define PVSCSI_MAX_NUM_SG_ENTRIES_PER_SEGMENT 128
+
+/*
+ * MAX_CHAIN_SEGMENTS could probably be much smaller, but if the guest takes
+ * more than 128 pages to give us the SG list, then the guest is pretty clearly
+ * broken.
+ */
+
+#define PVSCSI_MAX_NUM_SG_SEGMENTS 128
+#define PVSCSI_SGE_FLAG_CHAIN_ELEMENT (1 << 0)
+
+typedef struct PVSCSISGElement {
+ PA addr;
+ uint32 length;
+ uint32 flags;
+} PVSCSISGElement;
+
+
+/*
+ * Completion descriptor.
+ *
+ * sizeof(RingCmpDesc) = 32
+ *
+ * - context: identifier of the command. The same thing that was specified
+ * under "context" as part of struct RingReqDesc at initiation time,
+ * - dataLen: number of bytes transferred for the actual i/o operation,
+ * - senseLen: number of bytes written into the sense buffer,
+ * - hostStatus: adapter status,
+ * - scsiStatus: device status,
+ */
+
+typedef struct RingCmpDesc {
+ uint64 context;
+ uint64 dataLen;
+ uint32 senseLen;
+ uint16 hostStatus;
+ uint16 scsiStatus;
+ uint32 _pad[2];
+} RingCmpDesc;
+
+
+/*
+ * Interrupt status / IRQ bits.
+ */
+
+#define PVSCSI_INTR_CMPL_0 (1 << 0)
+#define PVSCSI_INTR_CMPL_1 (1 << 1)
+#define PVSCSI_INTR_CMPL_MASK MASK(2)
+
+#define PVSCSI_INTR_ALL PVSCSI_INTR_CMPL_MASK
+#define PVSCSI_MAX_INTRS 24
+
+
+/*
+ * Enumeration of supported MSI-X vectors
+ */
+#define PVSCSI_VECTOR_COMPLETION 0
+
+
+/*
+ * Misc constants for the rings.
+ */
+
+#define PVSCSI_MAX_NUM_PAGES_REQ_RING PVSCSI_SETUP_RINGS_MAX_NUM_PAGES
+#define PVSCSI_MAX_NUM_PAGES_CMP_RING PVSCSI_SETUP_RINGS_MAX_NUM_PAGES
+
+#define PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE (PAGE_SIZE / sizeof(RingReqDesc))
+#define PVSCSI_MAX_NUM_CMP_ENTRIES_PER_PAGE (PAGE_SIZE / sizeof(RingCmpDesc))
+
+#define PVSCSI_MAX_REQ_QUEUE_DEPTH \
+ (PVSCSI_MAX_NUM_PAGES_REQ_RING * PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE)
+#define PVSCSI_MAX_CMP_QUEUE_DEPTH \
+ (PVSCSI_MAX_NUM_PAGES_CMP_RING * PVSCSI_MAX_NUM_CMP_ENTRIES_PER_PAGE)
+#define PVSCSI_MAX_QUEUE_DEPTH \
+ MAX(PVSCSI_MAX_REQ_QUEUE_DEPTH, PVSCSI_MAX_CMP_QUEUE_DEPTH)
+
+/*
+ * Misc constants related to the BARs.
+ */
+
+#define PVSCSI_NUM_REGS 7
+#define PVSCSI_NUM_IO_REGS 2
+
+/*
+ * The following only gives a functional number if the result is a power of
+ * two.
+ */
+#define PVSCSI_IO_SPACE_MASK (PVSCSI_NUM_IO_REGS * sizeof(uint32) - 1)
+
+#define PVSCSI_MEM_SPACE_COMMAND_NUM_PAGES 1
+#define PVSCSI_MEM_SPACE_INTR_STATUS_NUM_PAGES 1
+#define PVSCSI_MEM_SPACE_MISC_NUM_PAGES 2
+#define PVSCSI_MEM_SPACE_KICK_IO_NUM_PAGES 2
+#define PVSCSI_MEM_SPACE_MSIX_NUM_PAGES 2
+
+#define PVSCSI_MEM_SPACE_COMMAND_PAGE 0
+#define PVSCSI_MEM_SPACE_INTR_STATUS_PAGE 1
+#define PVSCSI_MEM_SPACE_MISC_PAGE 2
+#define PVSCSI_MEM_SPACE_KICK_IO_PAGE 4
+#define PVSCSI_MEM_SPACE_MSIX_TABLE_PAGE 6
+#define PVSCSI_MEM_SPACE_MSIX_PBA_PAGE 7
+
+
+#define PVSCSI_MEM_SPACE_NUM_PAGES \
+ (PVSCSI_MEM_SPACE_COMMAND_NUM_PAGES + \
+ PVSCSI_MEM_SPACE_INTR_STATUS_NUM_PAGES + \
+ PVSCSI_MEM_SPACE_MISC_NUM_PAGES + \
+ PVSCSI_MEM_SPACE_KICK_IO_NUM_PAGES + \
+ PVSCSI_MEM_SPACE_MSIX_NUM_PAGES)
+
+#define PVSCSI_MEM_SPACE_SIZE (PVSCSI_MEM_SPACE_NUM_PAGES * PAGE_SIZE)
+#define PVSCSI_MEM_SPACE_MASK (CONST64U(PVSCSI_MEM_SPACE_SIZE - 1))
+
+/*
+ * For simplicity of implementation, the MSI-X array is combined into
+ * the single 64-bit memory BAR; these values are used to initialize the
+ * MSI-X capability PCIe field.
+ */
+#define PVSCSI_MSIX_TABLE_OFF (PVSCSI_MEM_SPACE_MSIX_TABLE_PAGE * PAGE_SIZE)
+#define PVSCSI_MSIX_PBA_OFF (PVSCSI_MEM_SPACE_MSIX_PBA_PAGE * PAGE_SIZE)
+#define PVSCSI_MSIX_BIR 1
+
+#endif /* __PVSCSI_DEFS_H__ */
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. 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 version 2 and no 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. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ *********************************************************/
+
+/*
+ * pvscsi_version.h --
+ *
+ * Version definitions for the Linux PVSCSI driver.
+ */
+
+#ifndef _PVSCSI_VERSION_H_
+#define _PVSCSI_VERSION_H_
+
+#define PVSCSI_DRIVER_VERSION 0.0.0.6
+#define PVSCSI_DRIVER_VERSION_COMMAS 0,0,0,6
+#define PVSCSI_DRIVER_VERSION_STRING "0.0.0.6"
+
+#endif /* _PVSCSI_VERSION_H_ */
--- /dev/null
+/*********************************************************
+ * Copyright (C) 1998 VMware, Inc. 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 version 2 and no 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. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ *********************************************************/
+
+/*
+ * scsi_defs.h
+ *
+ * General SCSI definitions
+ */
+
+#ifndef _SCSI_DEFS_H_
+#define _SCSI_DEFS_H_
+
+#define INCLUDE_ALLOW_USERLEVEL
+#define INCLUDE_ALLOW_VMMEXT
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_VMNIXMOD
+#define INCLUDE_ALLOW_VMK_MODULE
+#define INCLUDE_ALLOW_VMKERNEL
+#define INCLUDE_ALLOW_DISTRIBUTE
+#include "includeCheck.h"
+
+#include "vm_basic_defs.h" // for offsetof()
+
+/*
+ * Non-exhaustive list of SCSI operation codes. Note that
+ * some codes are defined differently according to the target
+ * device. Also, codes may have slightly different meanings
+ * and/or names based on the version of the SCSI spec.
+ *
+ * NB: Command descriptions come from the "SCSI Book" and not
+ * from the SCSI specifications (YMMV).
+ */
+#define SCSI_CMD_TEST_UNIT_READY 0x00 // test if LUN ready to accept a command
+#define SCSI_CMD_REZERO_UNIT 0x01 // seek to track 0
+#define SCSI_CMD_REQUEST_SENSE 0x03 // return detailed error information
+#define SCSI_CMD_FORMAT_UNIT 0x04 //
+#define SCSI_CMD_READ_BLOCKLIMITS 0x05 //
+#define SCSI_CMD_REASSIGN_BLOCKS 0x07 //
+#define SCSI_CMD_INIT_ELEMENT_STATUS 0x07 // Media changer
+#define SCSI_CMD_READ6 0x08 // read w/ limited addressing
+#define SCSI_CMD_WRITE6 0x0a // write w/ limited addressing
+#define SCSI_CMD_PRINT 0x0a // print data
+#define SCSI_CMD_SEEK6 0x0b // seek to LBN
+#define SCSI_CMD_SLEW_AND_PRINT 0x0b // advance and print
+#define SCSI_CMD_READ_REVERSE 0x0f // read backwards
+#define SCSI_CMD_WRITE_FILEMARKS 0x10 //
+#define SCSI_CMD_SYNC_BUFFER 0x10 // print contents of buffer
+#define SCSI_CMD_SPACE 0x11 //
+#define SCSI_CMD_INQUIRY 0x12 // return LUN-specific information
+#define SCSI_CMD_RECOVER_BUFFERED 0x14 // recover buffered data
+#define SCSI_CMD_MODE_SELECT 0x15 // set device parameters
+#define SCSI_CMD_RESERVE_UNIT 0x16 // make LUN accessible only to certain initiators
+#define SCSI_CMD_RELEASE_UNIT 0x17 // make LUN accessible to other initiators
+#define SCSI_CMD_COPY 0x18 // autonomous copy from/to another device
+#define SCSI_CMD_ERASE 0x19 //
+#define SCSI_CMD_MODE_SENSE 0x1a // read device parameters
+#define SCSI_CMD_START_UNIT 0x1b // load/unload medium
+#define SCSI_CMD_SCAN 0x1b // perform scan
+#define SCSI_CMD_STOP_PRINT 0x1b // interrupt printing
+#define SCSI_CMD_RECV_DIAGNOSTIC 0x1c // read self-test results
+#define SCSI_CMD_SEND_DIAGNOSTIC 0x1d // initiate self-test
+#define SCSI_CMD_MEDIUM_REMOVAL 0x1e // lock/unlock door
+#define SCSI_CMD_READ_FORMAT_CAPACITIES 0x23 // read format capacities
+#define SCSI_CMD_SET_WINDOW 0x24 // set scanning window
+#define SCSI_CMD_GET_WINDOW 0x25 // get scanning window
+#define SCSI_CMD_READ_CAPACITY 0x25 // read number of logical blocks
+#define SCSI_CMD_READ10 0x28 // read
+#define SCSI_CMD_READ_GENERATION 0x29 // read max generation address of LBN
+#define SCSI_CMD_WRITE10 0x2a // write
+#define SCSI_CMD_SEEK10 0x2b // seek LBN
+#define SCSI_CMD_POSITION_TO_ELEMENT 0x2b // media changer
+#define SCSI_CMD_ERASE10 0x2c
+#define SCSI_CMD_READ_UPDATED_BLOCK 0x2d // read specific version of changed block
+#define SCSI_CMD_WRITE_VERIFY 0x2e // write w/ verify of success
+#define SCSI_CMD_VERIFY 0x2f // verify success
+#define SCSI_CMD_SEARCH_DATA_HIGH 0x30 // search for data pattern
+#define SCSI_CMD_SEARCH_DATA_EQUAL 0x31 // search for data pattern
+#define SCSI_CMD_SEARCH_DATA_LOW 0x32 // search for data pattern
+#define SCSI_CMD_SET_LIMITS 0x33 // define logical block boundaries
+#define SCSI_CMD_PREFETCH 0x34 // read data into buffer
+#define SCSI_CMD_READ_POSITION 0x34 // read current tape position
+#define SCSI_CMD_SYNC_CACHE 0x35 // re-read data into buffer
+#define SCSI_CMD_LOCKUNLOCK_CACHE 0x36 // lock/unlock data in cache
+#define SCSI_CMD_READ_DEFECT_DATA 0x37 //
+#define SCSI_CMD_MEDIUM_SCAN 0x38 // search for free area
+#define SCSI_CMD_COMPARE 0x39 // compare data
+#define SCSI_CMD_COPY_VERIFY 0x3a // autonomous copy w/ verify
+#define SCSI_CMD_WRITE_BUFFER 0x3b // write data buffer
+#define SCSI_CMD_READ_BUFFER 0x3c // read data buffer
+#define SCSI_CMD_UPDATE_BLOCK 0x3d // substitute block with an updated one
+#define SCSI_CMD_READ_LONG 0x3e // read data and ECC
+#define SCSI_CMD_WRITE_LONG 0x3f // write data and ECC
+#define SCSI_CMD_CHANGE_DEF 0x40 // set SCSI version
+#define SCSI_CMD_WRITE_SAME 0x41 //
+#define SCSI_CMD_READ_SUBCHANNEL 0x42 // read subchannel data and status
+#define SCSI_CMD_READ_TOC 0x43 // read contents table
+#define SCSI_CMD_READ_HEADER 0x44 // read LBN header
+#define SCSI_CMD_PLAY_AUDIO10 0x45 // audio playback
+#define SCSI_CMD_GET_CONFIGURATION 0x46 // get configuration (SCSI-3)
+#define SCSI_CMD_PLAY_AUDIO_MSF 0x47 // audio playback starting at MSF address
+#define SCSI_CMD_PLAY_AUDIO_TRACK 0x48 // audio playback starting at track/index
+#define SCSI_CMD_PLAY_AUDIO_RELATIVE 0x49 // audio playback starting at relative track
+#define SCSI_CMD_GET_EVENT_STATUS_NOTIFICATION 0x4a
+#define SCSI_CMD_PAUSE 0x4b // audio playback pause/resume
+#define SCSI_CMD_LOG_SELECT 0x4c // select statistics
+#define SCSI_CMD_LOG_SENSE 0x4d // read statistics
+#define SCSI_CMD_STOP_PLAY 0x4e // audio playback stop
+#define SCSI_CMD_READ_DISC_INFO 0x51 // info on CDRs
+#define SCSI_CMD_READ_TRACK_INFO 0x52 // track info on CDRs
+#define SCSI_CMD_RESERVE_TRACK 0x53 // leave space for data on CDRs
+#define SCSI_CMD_SEND_OPC_INFORMATION 0x54 // Optimum Power Calibration
+#define SCSI_CMD_MODE_SELECT10 0x55 // set device parameters
+#define SCSI_CMD_RESERVE_UNIT10 0x56 //
+#define SCSI_CMD_RELEASE_UNIT10 0x57 //
+#define SCSI_CMD_REPAIR_TRACK 0x58
+#define SCSI_CMD_MODE_SENSE10 0x5a // read device parameters
+#define SCSI_CMD_CLOSE_SESSION 0x5b // close area/sesssion (recordable)
+#define SCSI_CMD_READ_BUFFER_CAPACITY 0x5c // CDR burning info.
+#define SCSI_CMD_SEND_CUE_SHEET 0x5d // (CDR Related?)
+#define SCSI_CMD_PERSISTENT_RESERVE_IN 0x5e //
+#define SCSI_CMD_PERSISTENT_RESERVE_OUT 0x5f //
+#define SCSI_CMD_XDWRITE_EXTENDED 0x80
+#define SCSI_CMD_REBUILD 0x81
+#define SCSI_CMD_REGENERATE 0x82
+#define SCSI_CMD_EXTENDED_COPY 0x83 // extended copy
+#define SCSI_CMD_RECEIVE_COPY_RESULTS 0x84 // receive copy results
+#define SCSI_CMD_READ16 0x88 // read data
+#define SCSI_CMD_WRITE16 0x8a // write data
+#define SCSI_CMD_ORWRITE16 0x8b
+#define SCSI_CMD_READ_ATTRIBUTE 0x8c // read attribute
+#define SCSI_CMD_WRITE_ATTRIBUTE 0x8d // write attribute
+#define SCSI_CMD_WRITE_VERIFY16 0x8e
+#define SCSI_CMD_VERIFY16 0x8f
+#define SCSI_CMD_PREFETCH16 0x90
+#define SCSI_CMD_SYNC_CACHE16 0x91
+#define SCSI_CMD_WRITE_SAME16 0x93
+#define SCSI_CMD_READ_CAPACITY16 0x9e // read number of logical blocks
+#define SCSI_CMD_WRITE_LONG16 0x9f
+#define SCSI_CMD_REPORT_LUNS 0xa0 //
+#define SCSI_CMD_BLANK 0xa1 // erase RW media
+#define SCSI_CMD_SECURITY_PROTOCOL_IN 0xa2 //
+#define SCSI_CMD_MAINTENANCE_IN 0xa3 // service actions define reports
+#define SCSI_CMD_MAINTENANCE_OUT 0xa4 // service actions define changes
+#define SCSI_CMD_SEND_KEY 0xa3
+#define SCSI_CMD_REPORT_KEY 0xa4 // report key (SCSI-3)
+#define SCSI_CMD_MOVE_MEDIUM 0xa5 //
+#define SCSI_CMD_PLAY_AUDIO12 0xa5 // audio playback
+#define SCSI_CMD_EXCHANGE_MEDIUM 0xa6 //
+#define SCSI_CMD_LOADCD 0xa6 //
+#define SCSI_CMD_SET_READ_AHEAD 0xa7
+#define SCSI_CMD_READ12 0xa8 // read (SCSI-3)
+#define SCSI_CMD_PLAY_TRACK_RELATIVE 0xa9 // audio playback starting at relative track
+#define SCSI_CMD_WRITE12 0xaa // write data
+#define SCSI_CMD_READ_MEDIA_SERIAL_NUMBER 0xab //
+#define SCSI_CMD_ERASE12 0xac // erase logical block
+#define SCSI_CMD_GET_PERFORMANCE 0xac //
+#define SCSI_CMD_READ_DVD_STRUCTURE 0xad // read DVD structure (SCSI-3)
+#define SCSI_CMD_WRITE_VERIFY12 0xae // write logical block, verify success
+#define SCSI_CMD_VERIFY12 0xaf // verify data
+#define SCSI_CMD_SEARCH_DATA_HIGH12 0xb0 // search data pattern
+#define SCSI_CMD_SEARCH_DATA_EQUAL12 0xb1 // search data pattern
+#define SCSI_CMD_SEARCH_DATA_LOW12 0xb2 // search data pattern
+#define SCSI_CMD_SET_LIMITS12 0xb3 // set block limits
+#define SCSI_CMD_REQUEST_VOLUME_ELEMENT_ADDR 0xb5 //
+#define SCSI_CMD_SECURITY_PROTOCOL_OUT 0xb5
+#define SCSI_CMD_SEND_VOLUME_TAG 0xb6 //
+#define SCSI_CMD_SET_STREAMING 0xb6 // For avoiding over/underrun
+#define SCSI_CMD_READ_DEFECT_DATA12 0xb7 // read defect data information
+#define SCSI_CMD_READ_ELEMENT_STATUS 0xb8 // read element status
+#define SCSI_CMD_SELECT_CDROM_SPEED 0xb8 // set data rate
+#define SCSI_CMD_READ_CD_MSF 0xb9 // read CD information (all formats, MSF addresses)
+#define SCSI_CMD_AUDIO_SCAN 0xba // fast audio playback
+#define SCSI_CMD_SET_CDROM_SPEED 0xbb // (proposed)
+#define SCSI_CMD_SEND_CDROM_XA_DATA 0xbc
+#define SCSI_CMD_PLAY_CD 0xbc
+#define SCSI_CMD_MECH_STATUS 0xbd
+#define SCSI_CMD_READ_CD 0xbe // read CD information (all formats, MSF addresses)
+#define SCSI_CMD_SEND_DVD_STRUCTURE 0xbf // burning DVDs?
+
+/*
+ * A workaround for a specific scanner (NIKON LS-2000).
+ * Can be removed once Linux backend uses 2.4.x interface
+ */
+#define SCSI_CMD_VENDOR_NIKON_UNKNOWN 0xe1
+
+#define SCSI_SENSE_KEY_NONE 0x0 // there is no sense information
+#define SCSI_SENSE_KEY_RECOVERED_ERROR 0x1 // the last command completed succesfully but used error correction in the process
+#define SCSI_SENSE_KEY_NOT_READY 0x2 // the addressed LUN is not ready to be accessed
+#define SCSI_SENSE_KEY_MEDIUM_ERROR 0x3 // the target detected a data error on the medium
+#define SCSI_SENSE_KEY_HARDWARE_ERROR 0x4 // the target detected a hardware error during a command or self-test
+#define SCSI_SENSE_KEY_ILLEGAL_REQUEST 0x5 // either the command or the parameter list contains an error
+#define SCSI_SENSE_KEY_UNIT_ATTENTION 0x6 // the LUN has been reset (bus reset of medium change)
+#define SCSI_SENSE_KEY_DATA_PROTECT 0x7 // access to the data is blocked
+#define SCSI_SENSE_KEY_BLANK_CHECK 0x8 // reached an unexpected written or unwritten region of the medium
+#define SCSI_SENSE_KEY_COPY_ABORTED 0xa // COPY, COMPARE, or COPY AND VERIFY was aborted
+#define SCSI_SENSE_KEY_ABORTED_CMD 0xb // the target aborted the command
+#define SCSI_SENSE_KEY_EQUAL 0xc // comparison for SEARCH DATA was unsuccessful
+#define SCSI_SENSE_KEY_VOLUME_OVERFLOW 0xd // the medium is full
+#define SCSI_SENSE_KEY_MISCOMPARE 0xe // source and data on the medium do not agree
+
+/*
+ * The Additional Sense Code - ASC and
+ * Additional Sense Code Qualifiers - ASCQ
+ * always come in pairs.
+ *
+ * Note:
+ * These values are found at senseBuffer[12} and senseBuffer[13].
+ * You may see references to these in legacy code. New code should make an
+ * attempt to use the ASC/ASCQ syntax.
+ */
+#define SCSI_ASC_LU_NOT_READY 0x04 // logical unit not ready
+#define SCSI_ASC_LU_NOT_READY_ASCQ_UNIT_BECOMING_READY 0x01
+#define SCSI_ASC_LU_NOT_READY_ASCQ_INIT_CMD_REQUIRED 0x02 // initializing command required
+#define SCSI_ASC_LU_NOT_READY_ASCQ_MANUAL_INTERVENTION_REQUIRED 0x03
+#define SCSI_ASC_LU_NOT_READY_ASCQ_TARGET_PORT_IN_TRANSITION 0x0a // an ascq
+#define SCSI_ASC_LU_NOT_READY_ASCQ_TARGET_PORT_IN_STANDBY_MODE 0x0b // an ascq
+#define SCSI_ASC_LU_NO_RESPONSE_TO_SELECTION 0x05 // logical unit doesn't respond to selection
+#define SCSI_ASC_NO_REFERENCE_POSITION_FOUND 0x06
+#define SCSI_ASC_WRITE_ERROR 0x0c // Write error
+#define SCSI_ASC_UNRECOVERED_READ_ERROR 0x11 // Unrecovered read error
+#define SCSI_ASC_PARAM_LIST_LENGTH_ERROR 0x1a // parameter list length error
+#define SCSI_ASC_INVALID_COMMAND_OPERATION 0x20 // invalid command operation code
+#define SCSI_ASC_INVALID_FIELD_IN_CDB 0x24
+#define SCSI_ASC_LU_NOT_SUPPORTED 0x25 // LU has been removed
+#define SCSI_ASC_INVALID_FIELD_IN_PARAMETER_LIST 0x26
+#define SCSI_ASC_WRITE_PROTECTED 0x27 // device is write protected
+#define SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED 0x28 // after changing medium
+#define SCSI_ASC_POWER_ON_OR_RESET 0x29 // device power-on or SCSI reset
+#define SCSI_ASC_ASYMMETRIC_ACCESS_STATE_CHANGED 0x2a
+#define SCSI_ASC_INCOMPATIBLE_MEDIUM 0x30 // Generic bad medium error
+#define SCSI_ASC_SAVING_PARAMS_NOT_SUPPORTED 0x39 // Saving parameters not supported
+#define SCSI_ASC_MEDIUM_NOT_PRESENT 0x3a // changing medium
+#define SCSI_ASC_MEDIUM_NOT_PRESENT_ASCQ_TRAY_OPEN 0x02 // an ascq
+#define SCSI_ASC_INVALID_MESSAGE_ERROR 0x49
+#define SCSI_ASC_COMMAND_PHASE_ERROR 0x4a
+#define SCSI_ASC_DATA_PHASE_ERROR 0x4b
+#define SCSI_ASC_MEDIUM_REMOVAL_FAILED 0x53 // w/ 0x4 it is failed, 0x5 is prevented
+#define SCSI_ASC_INSUFFICIENT_REGISTRATION_RESOURCES 0x55 // during persistent reservations
+#define SCSI_ASCQ_INSUFFICIENT_REGISTRATION_RESOURCES 0x04
+#define SCSI_ASCQ_ASYMMETRIC_ACCESS_STATE_CHANGED 0x06
+#define SCSI_ASCQ_TARGET_PORT_IN_STANDBY_STATE 0x0b
+#define SCSI_ASCQ_TARGET_PORT_IN_UNAVAILABLE_STATE 0x0c
+#define SCSI_ASC_INVALID_MODE_FOR_THIS_TRACK 0x64
+
+#define SCSI_TAG_ENABLE 0x20 // Set to indicate tag is valid
+#define SCSI_TAG_SIMPLE (SCSI_TAG_ENABLE|0x0) // No constraint
+#define SCSI_TAG_HEAD (SCSI_TAG_ENABLE|0x1) // Always first
+#define SCSI_TAG_ORDER (SCSI_TAG_ENABLE|0x2) // Syncronizing
+
+#define SCSI_CMD_START_UNIT_START_BIT 0x01 // Value of Start bit for SCSI_CMD_START_UNIT
+
+/*
+ * SCSI Command Data Blocks (CDBs) come in at least four flavors:
+ *
+ * 1. 6-byte commands were originally spec'd and limit the addressable
+ * storage to 1GByte (21 bits x 512 bytes/logical block).
+ * 2. 10-byte commands first appeared in SCSI-2; they have a 32-bit
+ * logical block number range but transfers are limited to 64KB.
+ * 3. 12-byte commands also appeared in SCSI-2; they differ mainly
+ * int that large amounts of data may be transferred (32-bit data length).
+ * 4. 16-byte commands were added in SCSI-3; they have additional space
+ * for unspecified command data.
+ *
+ * We do not support 16-byte CDB's, only 6-, 10-, and 12-byte versions.
+ */
+typedef struct {
+ uint32 opcode:8, // operation code
+ lun:3, // logical unit number
+ lbn:21; // logical block number
+ uint8 len; // data length
+ uint8 ctrl; // control byte
+} SCSICDB6;
+typedef
+#include "vmware_pack_begin.h"
+struct {
+ uint8 opcode;
+ uint8 :5,
+ lun:3;
+ uint32 lbn;
+ uint8 reserved;
+ uint16 len;
+ uint8 ctrl;
+}
+#include "vmware_pack_end.h"
+SCSICDB10;
+typedef
+#include "vmware_pack_begin.h"
+struct {
+ uint8 opcode;
+ uint8 :5,
+ lun:3;
+ uint32 lbn;
+ uint32 len;
+ uint8 reserved;
+ uint8 ctrl;
+}
+#include "vmware_pack_end.h"
+SCSICDB12;
+
+/*
+ * Format of INQUIRY request and response blocks.
+ * These are defined here because many SCSI devices
+ * need them.
+ */
+typedef struct {
+ uint8 opcode; // INQUIRY (0x12)
+ uint8 evpd :1, // enhanced vital product data
+ cmddt :1, // command support data (new in SCSI-3)
+ resv12:3,
+ lun :3;
+ uint8 pagecode; // only valid when cmddt or evdp is set
+ uint8 reserved;
+ uint8 len;
+ uint8 ctrl;
+} SCSIInquiryCmd;
+
+/*
+ * Format of the SCSI-3 INQUIRY command as defined in SPC-3
+ */
+typedef struct {
+ uint8 opcode; // INQUIRY (0x12)
+ uint8 evpd :1, // Enhanced Vital Product Data
+ obslt :1, // Obsolete as per SPC-3
+ resv :6; // The remaining bits are all RESERVED
+ uint8 pagecode; // Only valid when evpd is set
+ uint8 lenMSB; // The SPC-3 spec has a 2 byte len field
+ uint8 len;
+ uint8 ctrl;
+} SCSI3InquiryCmd;
+
+typedef struct {
+ uint8 devclass :5, // SCSI device class
+#define SCSI_CLASS_DISK 0x00 // disk drive
+#define SCSI_CLASS_TAPE 0x01 // tape drive
+#define SCSI_CLASS_PRINTER 0x02 // printer
+#define SCSI_CLASS_CPU 0x03 // processor device
+#define SCSI_CLASS_WORM 0x04 // WORM drive
+#define SCSI_CLASS_CDROM 0x05 // CD-ROM drive
+#define SCSI_CLASS_SCANNER 0x06 // scanner
+#define SCSI_CLASS_OPTICAL 0x07 // optical disk
+#define SCSI_CLASS_MEDIA 0x08 // media changer
+#define SCSI_CLASS_COM 0x09 // communication device
+#define IDE_CLASS_CDROM 0x0a // IDE CD-ROM drive
+#define IDE_CLASS_OTHER 0x0b // Generic IDE
+#define SCSI_CLASS_RAID 0x0c // RAID controller (SCSI-3, reserved in SCSI-2)
+#define SCSI_CLASS_SES 0x0d // SCSI Enclosure Services device (t10 SES)
+#define SCSI_CLASS_UNKNOWN 0x1f // unknown device
+ pqual :3; // peripheral qualifier
+#define SCSI_PQUAL_CONNECTED 0 // device described is connected to the LUN
+#define SCSI_PQUAL_NOTCONNECTED 1 // target supports such a device, but none is connected
+#define SCSI_PQUAL_NODEVICE 3 // target does not support a physical device for this LUN
+ uint8 :7, // reserved for SCSI-1
+ rmb:1; // removable bit
+ uint8 ansi :3, // ANSI version
+#define SCSI_ANSI_SCSI1 0x0 // device supports SCSI-1
+#define SCSI_ANSI_CCS 0x1 // device supports the CCS
+#define SCSI_ANSI_SCSI2 0x2 // device supports SCSI-2
+#define SCSI_ANSI_SCSI3_SPC 0x3 // device supports SCSI-3 version SPC
+#define SCSI_ANSI_SCSI3_SPC2 0x4 // device supports SCSI-3 version SPC-2
+#define SCSI_ANSI_SCSI3_SPC3 0x5 // device supports SCSI-3 version SPC-3
+#define SCSI_ANSI_SCSI3_SPC4 0x6 // device supports SCSI-3 version SPC-4
+ ecma :3, // ECMA version
+ iso :2; // ISO version
+ uint8 dataformat :4, // format of the following standard data
+ :1,
+ naca :1,
+ tio :1, // device supports TERMINATE I/O PROCESS message
+ aen :1; // asynchronous event notification capability
+ uint8 optlen; // length of additional data that follows
+ uint8 :8;
+#define SCSI_TPGS_NONE 0x0
+#define SCSI_TPGS_IMPLICIT_ONLY 0x1
+#define SCSI_TPGS_IMPLICIT SCSI_TPGS_IMPLICIT_ONLY
+#define SCSI_TPGS_EXPLICIT_ONLY 0x2
+#define SCSI_TPGS_EXPLICIT SCSI_TPGS_EXPLICIT_ONLY
+#define SCSI_TPGS_BOTH_IMPLICIT_AND_EXPLICIT 0x3
+#define SCSI_TPGS_BOTH SCSI_TPGS_BOTH_IMPLICIT_AND_EXPLICIT
+ uint8 adr16 :1, // device supports 16-bit wide SCSI addresses
+ adr32 :1, // device supports 32-bit wide SCSI addresses
+ arq :1,
+ mchngr :1, // device has attached media changer (SCSI-3)
+ dualp :1, // device is dual-ported (SCSI-3)
+ port :1, // port A or port B when dual-ported (SCSI-3)
+ :2;
+ uint8 sftr :1, // device supports soft reset capability
+ que :1, // device supports tagged commands
+ trndis :1, // device supports transfer disable messages (SCSI-3)
+ link :1, // device supports linked commands
+ sync :1, // device supports synchronous transfers
+ w16 :1, // device supports 16-bit wide SCSI data transfers
+ w32 :1, // device supports 32-bit wide SCSI data transfers
+ rel :1; // device supports relative addressing
+ uint8 manufacturer[8]; // manufacturer's name in ascii
+ uint8 product[16]; // product name in ascii
+ uint8 revision[4]; // product version number in ascii
+ uint8 vendor1[20]; // vendor unique data (opaque)
+ uint8 reserved[40];
+} SCSIInquiryResponse; // standard INQUIRY response format
+
+/*
+ * Same as SCSIInquiryResponse, except that only 36 bytes long. See above
+ * for some defines. You should use this one and not one above unless you
+ * need vendor1/reserved fields.
+ */
+typedef struct {
+ uint8 devclass :5, // SCSI device class
+ pqual :3; // peripheral qualifier
+ uint8 :7, // reserved for SCSI-1
+ rmb:1; // removable bit
+ uint8 ansi :3, // ANSI version
+ ecma :3, // ECMA version
+ iso :2; // ISO version
+ uint8 dataformat :4, // format of the following standard data
+ :1,
+ naca :1,
+ tio :1, // device supports TERMINATE I/O PROCESS message
+ aen :1; // asynchronous event notification capability
+ uint8 optlen; // length of additional data that follows
+ uint8 :8;
+ uint8 adr16 :1, // device supports 16-bit wide SCSI addresses
+ adr32 :1, // device supports 32-bit wide SCSI addresses
+ arq :1,
+ mchngr :1, // device has attached media changer (SCSI-3)
+ dualp :1, // device is dual-ported (SCSI-3)
+ port :1, // port A or port B when dual-ported (SCSI-3)
+ :2;
+ uint8 sftr :1, // device supports soft reset capability
+ que :1, // device supports tagged commands
+ trndis :1, // device supports transfer disable messages (SCSI-3)
+ link :1, // device supports linked commands
+ sync :1, // device supports synchronous transfers
+ w16 :1, // device supports 16-bit wide SCSI data transfers
+ w32 :1, // device supports 32-bit wide SCSI data transfers
+ rel :1; // device supports relative addressing
+ uint8 manufacturer[8]; // manufacturer's name in ascii
+ uint8 product[16]; // product name in ascii
+ uint8 revision[4]; // product version number in ascii
+} SCSIInquiry36Response; // standard INQUIRY response format
+
+#define SCSI_STANDARD_INQUIRY_MIN_LENGTH 36
+
+#define SCSI_INQ_PAGE_0x00 0x00
+#define SCSI_INQ_PAGE_0x80 0x80
+#define SCSI_INQ_PAGE_0x83 0x83
+
+/*
+ * The following structures define the Page format supported by the
+ * vscsi layer in vmkernel. The SPC-3 r23 spec defines a very generic
+ * layout of these pages, however the structures here are customized
+ * for vmkernel.
+ */
+typedef
+#include "vmware_pack_begin.h"
+struct SCSIInqPage00ResponseHeader {
+ uint8 devClass :5,
+ pQual :3;
+ uint8 pageCode;
+ uint8 reserved1;
+ uint8 pageLength;
+}
+#include "vmware_pack_end.h"
+SCSIInqPage00ResponseHeader;
+
+typedef
+#include "vmware_pack_begin.h"
+struct SCSIInqPage80ResponseHeader {
+ uint8 devClass :5,
+ pQual :3;
+ uint8 pageCode;
+ uint8 reserved1;
+ uint8 pageLength;
+}
+#include "vmware_pack_end.h"
+SCSIInqPage80ResponseHeader;
+
+// Inquiry page 0x83: Identifier Type
+#define SCSI_IDENTIFIERTYPE_VENDOR_SPEC 0x0
+#define SCSI_IDENTIFIERTYPE_T10 0x1
+#define SCSI_IDENTIFIERTYPE_EUI 0x2
+#define SCSI_IDENTIFIERTYPE_NAA 0x3
+#define SCSI_IDENTIFIERTYPE_RTPI 0x4
+#define SCSI_IDENTIFIERTYPE_TPG 0x5
+#define SCSI_IDENTIFIERTYPE_LUG 0x6
+#define SCSI_IDENTIFIERTYPE_MD5 0x7
+#define SCSI_IDENTIFIERTYPE_SNS 0x8
+#define SCSI_IDENTIFIERTYPE_RESERVED 0x9
+#define SCSI_IDENTIFIERTYPE_MAX SCSI_IDENTIFIERTYPE_RESERVED
+
+// Inquiry page 0x83: Transport Layer
+#define SCSI_PROTOCOLID_FCP2 0x0
+#define SCSI_PROTOCOLID_SPI5 0x1
+#define SCSI_PROTOCOLID_SSAS3P 0x2
+#define SCSI_PROTOCOLID_SBP3 0x3
+#define SCSI_PROTOCOLID_SRP 0x4
+#define SCSI_PROTOCOLID_ISCSI 0x5
+#define SCSI_PROTOCOLID_SAS 0x6
+#define SCSI_PROTOCOLID_ADT 0x7
+#define SCSI_PROTOCOLID_ATA 0x8
+#define SCSI_PROTOCOLID_RESERVED 0xE
+#define SCSI_PROTOCOLID_NO_PROTOCOL 0xF
+
+// Inquiry page 0x83: UUID Encoding
+#define SCSI_CODESET_BINARY 0x1
+#define SCSI_CODESET_ASCII 0x2
+#define SCSI_CODESET_UTF8 0x3
+#define SCSI_CODESET_RESERVED 0xF
+
+// Inquiry page 0x83: UUID Entity
+#define SCSI_ASSOCIATION_LUN 0x0
+#define SCSI_ASSOCIATION_TARGET_PORT 0x1
+#define SCSI_ASSOCIATION_TARGET_DEVICE 0x2
+#define SCSI_ASSOCIATION_RESERVED 0x3
+
+typedef
+#include "vmware_pack_begin.h"
+struct SCSIInqPage83ResponseHeader {
+ uint8 devClass :5,
+ pQual :3;
+ uint8 pageCode;
+ uint16 pageLength;
+}
+#include "vmware_pack_end.h"
+SCSIInqPage83ResponseHeader;
+
+typedef
+#include "vmware_pack_begin.h"
+struct SCSIInqPage83ResponseDescriptor {
+ /* Identification Descriptor follows */
+ uint8 codeSet :4,
+ protocolId :4;
+ uint8 idType :4,
+ association :2,
+ reserved1 :1,
+ piv :1;
+ uint8 reserved2;
+ uint8 idLength;
+}
+#include "vmware_pack_end.h"
+SCSIInqPage83ResponseDescriptor;
+
+typedef
+#include "vmware_pack_begin.h"
+struct SCSIInquiryVPDResponseHeader {
+ uint8 devclass :5, // SCSI device class
+ pqual :3; // peripheral qualifier
+ uint8 pageCode; // 0
+ uint8 reserved;
+ uint8 payloadLen; // Number of additional bytes
+}
+#include "vmware_pack_end.h"
+SCSIInquiryVPDResponseHeader;
+
+typedef
+#include "vmware_pack_begin.h"
+struct SCSIReportLunsCmd {
+ uint8 opcode;
+ uint8 reserved1;
+ uint8 selectReport;
+ uint8 reserved2[3];
+ uint32 allocLen;
+ uint16 reserved3;
+}
+#include "vmware_pack_end.h"
+SCSIReportLunsCmd;
+
+typedef
+#include "vmware_pack_begin.h"
+struct SCSIReportLunsResponse {
+ uint32 len;
+ uint32 reserved;
+ struct {
+ uint8 addressMethod:3,
+ busIdentifier:5;
+ uint8 singleLevelLun;
+ uint16 secondLevelLun;
+ uint16 thirdLevelLun;
+ uint16 fourthLevelLun;
+ } lun[1];
+}
+#include "vmware_pack_end.h"
+SCSIReportLunsResponse;
+
+#define SCSI_REPORT_LUNS_RESPONSE_LEN(n) (sizeof(SCSIReportLunsResponse) + ((n)-1) * sizeof(((SCSIReportLunsResponse*)0)->lun[0]))
+
+/*
+ * Format of 6- and 10-byte versions of the MODE SELECT
+ * and MODE SENSE request and response blocks.
+ * These are defined here because multiple SCSI devices
+ * may need them.
+ */
+typedef struct {
+ uint8 opcode; // operation code
+ uint8 :3,
+ dbd :1, // disable block descriptors
+ :1,
+ lun :3; // logical unit number
+ uint8 page :6, // page code
+#define SCSI_MS_PAGE_VENDOR 0x00 // vendor-specific (ALL)
+#define SCSI_MS_PAGE_RWERROR 0x01 // read/write error (DISK/TAPE/CDROM/OPTICAL)
+#define SCSI_MS_PAGE_CONNECT 0x02 // disconnect/connect (ALL)
+#define SCSI_MS_PAGE_FORMAT 0x03 // format (DISK)
+#define SCSI_MS_PAGE_PARALLEL 0x03 // parallel interface (PRINTER)
+#define SCSI_MS_PAGE_UNITS 0x03 // measurement units (SCANNER)
+#define SCSI_MS_PAGE_GEOMETRY 0x04 // rigid disk geometry (DISK)
+#define SCSI_MS_PAGE_SERIAL 0x04 // serial interface (PRINTER)
+#define SCSI_MS_PAGE_FLEXIBLE 0x05 // flexible disk geometry (DISK)
+#define SCSI_MS_PAGE_PRINTER 0x05 // printer operations (PRINTER)
+#define SCSI_MS_PAGE_OPTICAL 0x06 // optical memory (OPTICAL)
+#define SCSI_MS_PAGE_VERIFY 0x07 // verification error (DISK/CDROM/OPTICAL)
+#define SCSI_MS_PAGE_CACHE 0x08 // cache (DISK/CDROM/OPTICAL)
+#define SCSI_MS_PAGE_PERIPH 0x09 // peripheral device (ALL)
+#define SCSI_MS_PAGE_CONTROL 0x0a // control mode (ALL)
+#define SCSI_MS_PAGE_MEDIUM 0x0b // medium type (DISK/CDROM/OPTICAL)
+#define SCSI_MS_PAGE_NOTCH 0x0c // notch partitions (DISK)
+#define SCSI_MS_PAGE_CDROM 0x0d // CD-ROM (CDROM)
+#define SCSI_MS_PAGE_CDAUDIO 0x0e // CD-ROM audio (CDROM)
+#define SCSI_MS_PAGE_COMPRESS 0x0f // data compression (TAPE)
+#define SCSI_MS_PAGE_CONFIG 0x10 // device configuration (TAPE)
+#define SCSI_MS_PAGE_EXCEPT 0x1c // informal exception (ALL:SCSI-3)
+#define SCSI_MS_PAGE_CDCAPS 0x2a // CD-ROM capabilities and mechanical status (CDROM)
+// more defined...
+#define SCSI_MS_PAGE_ALL 0x3f // all available pages (ALL)
+ pcf :2; // page control field
+#define SCSI_MS_PCF_CURRENT 0x00 // current values
+#define SCSI_MS_PCF_VOLATILE 0x01 // changeable values
+#define SCSI_MS_PCF_DEFAULT 0x02 // default values
+#define SCSI_MS_PCF_SAVED 0x03 // saved values
+ uint8 subpage;
+ uint8 length; // data length
+ uint8 ctrl; // control byte
+} SCSIModeSenseCmd;
+
+
+/*
+ * FORMAT UNIT command
+ */
+typedef
+#include "vmware_pack_begin.h"
+struct {
+ uint8 opcode; // FORMAT UNIT (0x4)
+ uint8 dlf :3, // defect list format
+ cmplst :1, // complete list
+ fmtdata:1, // format data
+ lun :3;
+ uint8 vendor;
+ uint16 interleave;
+ uint8 control;
+}
+#include "vmware_pack_end.h"
+SCSIFormatCmd;
+
+/*
+ * Format Defect List header
+ */
+typedef struct {
+ uint8 reserved;
+ uint8 fov :1, // Format options valid
+ dpry :1, // disable primary
+ dcrt :1, // disable certification
+ stpf :1, // stop format
+ ip :1, // initialization pattern
+ dsp :1, // disable saving parameters
+ immed :1, // immediate
+ vs :1;
+ uint16 length; // Defect list length
+} SCSIDefectListHdr;
+
+typedef
+#include "vmware_pack_begin.h"
+struct {
+ uint8 opcode; // operation code
+ uint8 :3,
+ dbd :1, // disable block descriptors
+ :1,
+ lun :3; // logical unit number
+ uint8 page :6, // page code
+ pcf :2; // page control field
+ uint8 reserved[4];
+ uint16 length; // data length
+ uint8 ctrl; // control byte
+}
+#include "vmware_pack_end.h"
+SCSIModeSense10Cmd;
+
+typedef struct {
+ uint8 opcode; // operation code
+ uint8 sp :1, // save pages
+ :3,
+ pf :1, // page format
+ lun :3; // logical unit number
+ uint8 reserved[2];
+ uint8 len; // data length
+ uint8 ctrl; // control byte
+} SCSIModeSelectCmd;
+
+typedef
+#include "vmware_pack_begin.h"
+struct {
+ uint8 opcode; // operation code
+ uint8 sp :1, // save pages
+ :3,
+ pf :1, // page format
+ lun :3; // logical unit number
+ uint8 reserved[5];
+ uint16 len; // data length
+ uint8 ctrl; // control byte
+}
+#include "vmware_pack_end.h"
+SCSIModeSelect10Cmd;
+
+typedef struct {
+ uint8 len; // data length
+ uint8 mediaType;
+ uint8 devSpecific; // device specific
+ uint8 bdLen; // block descriptor length
+} SCSIModeHeader6;
+
+typedef struct {
+ uint16 len; // data length
+ uint8 mediaType;
+ uint8 devSpecific; // device specific
+ uint16 reserved;
+ uint16 bdLen; // block descriptor length
+} SCSIModeHeader10;
+
+typedef struct {
+ uint8 reserved1:4;
+ uint8 dpofua:1; // disable page out / force unit access
+ uint8 reserved2:2;
+ uint8 wp:1; // write protected
+} SCSIBlockModeSenseDeviceParameter;
+
+/*
+ * Command structure for a SCSI Reserve command.
+ */
+typedef
+#include "vmware_pack_begin.h"
+struct {
+ uint8 opcode:8; // operation code
+ uint8 ext:1,
+ tid:3,
+ tparty:1,
+ lun:3; // logical unit number
+ uint8 resid;
+ uint16 extlen;
+ uint8 control;
+}
+#include "vmware_pack_end.h"
+SCSIReserveCmd;
+
+/*
+ * There are three mandatory mode parameter pages for all device
+ * types (a fourth is added in SCSI-3). The following structures
+ * define these pages as sent+received with MODE SENSE and SELECT.
+ */
+typedef struct { // connect/disconnect page
+ uint8 page :6, // page code: 0x02
+ :1,
+ ps :1;
+ uint8 len; // page length (0x0e)
+ uint8 bufFull;
+ uint8 bufEmpty;
+ uint16 maxBusInactiveTime;
+ uint16 maxBusFreeTime;
+ uint16 maxConnectTime;
+ uint16 maxBurstLength;
+ uint8 dtdc :3,
+ dimm :1, // disconnect immediate (SCSI-3)
+ :3,
+ emdp :1; // enable MODIFY DATA POINTER (SCSI-3)
+} SCSIConnectPage;
+
+typedef struct { // peripheral device page
+ uint8 page :6, // page code: 0x09
+ :1,
+ ps :1;
+ uint8 len; // page length (n-1)
+ uint16 ifID; // physical interface identifier
+ uint8 reserved[4];
+ uint8 undefined[1]; // variable-length vendor-specific data
+} SCSIPeriphPage;
+
+typedef struct {
+ uint8 page :6, // page code: 0x0a
+ :1,
+ ps :1;
+ uint8 len; // page length (0x06)
+ uint8 rlec :1,
+ gltsd :1,
+ :2,
+ :4;
+ uint8 dque :1, // disable tagged queuing
+ qerr :1, //
+ :2,
+ qalg :4; // queue algorithm
+ uint8 eaenp :1, // error AEN permission
+ uaaenp:1, // unit attention AEN permission
+ raenp :1, // ready AEN permission
+ :4,
+ eeca :1; //
+ uint8 reserved;
+ uint16 aenWaitTime; // AEN waiting time after initialization
+ uint16 busyTimeout; // busy timeout in 100ms (SCSI-3)
+} SCSIControlPage;
+
+typedef struct {
+ uint8 page :6, // page code: 0x09
+ :1,
+ ps :1;
+ uint8 len; // page length 0x06
+ uint8 dcr :1, // error recover parameters
+ dte :1, // diable transfer on seeing recovered error
+ per :1, // post error: report recovered errors
+ :1,
+ rc :1, // read continuous: don't delay data transfer to correct errors
+ tb :1, // transfer block when unrecovered
+ :2;
+ uint8 readRetries; // read retry count
+ uint8 reserved[4];
+} SCSIRWErrorPage;
+
+typedef struct {
+ uint8 page :6, // page code: 0x0d
+ :1,
+ ps :1;
+ uint8 len; // page length 0x06
+ uint8 :8;
+ uint8 inactive:4, // head inactivity timeout
+ :4;
+ uint16 secsPerMinute; // number of MSF seconds per MSF minute
+ uint16 framesPerSec; // number of MSF frames per MSF second
+} SCSICDROMPage;
+
+typedef struct {
+ uint8 page :6, // page code: 0x0e
+ :1,
+ ps :1;
+ uint8 len; // page length 0x0e
+ uint8 :1,
+ sotb :1,
+ immediate:1,
+ :5;
+ uint8 :8;
+ uint8 :8;
+ uint8 lbaFactor:4,
+ :3,
+ aprv :1;
+ uint16 lbaPerSec; // number of LBAs per second
+ uint8 port0 :4, // output port 0 select
+ :4;
+ uint8 port0Volume;
+ uint8 port1 :4, // output port 1 select
+ :4;
+ uint8 port1Volume;
+ uint8 port2 :4, // output port 2 select
+ :4;
+ uint8 port2Volume;
+ uint8 port3 :4, // output port 3 select
+ :4;
+ uint8 port3Volume;
+} SCSICDROMAudioPage;
+
+typedef struct {
+ uint8 page :6, // page code: 0x2a
+ :1,
+ ps :1;
+ uint8 len; // page length 0x12
+ uint8 cdrRd :1,// CD-R read per Orange Book Part II
+ cdeRd :1,// CD-E read per Orange Book Part III
+ method2 :1,// CD-R media w/ Addressing Method 2
+ :5;
+ uint8 cdrWr :1,// CD-R write per Orange Book Part II
+ cdeWr :1,// CD-E write per Orange Book Part III
+ :6;
+ uint8 audioPlay :1,// drive is capable of audio play
+ composite :1,// drive is capable of delivering composite audio+video
+ digPort1 :1,// drive supports digital output (IEC958) on port 1
+ digPort2 :1,// drive supports digital output on port 2
+ mode2Form1 :1,// drive reads Mode 2 Form 1 (XA) format
+ mode2Form2 :1,// drive reads Mode 2 Form 2 format
+ multiSession:1,// drive reads multi-session or Photo-CD discs
+ :1;
+ uint8 cdDA :1,// CD-DA commands (Red Book) supported
+ daAccu :1,// CD-DA stream is accurate
+ rwSupported :1,// R-W supported
+ rwDeinter :1,// R-W subchannel data de-interleaved and corrected
+ c2Ptrs :1,// C2 Error Pointers supported
+ isrc :1,// drive returns International Standard Recording Code Info
+ upc :1,// drive returns Media Catalog Number
+ :1;
+ uint8 lock :1,// PREVENT/ALLOW commands lock media into drive
+ lockState :1,// current state of drive
+ jumpers :1,// state of prevent/allow jumpers
+ eject :1,// drive can eject disc via START/STOP command
+ :1,
+ loadType :3;// loading mechanism type
+ uint8 sv :1,// separate volume
+ scm :1,// separate channel mute
+ sdp :1,// supports disc present in MECHANISM STATUS command
+ sss :1,// s/w slot selection w/ LOAD/UNLOCK command
+ :4;
+ uint16 maxSpeed; // maximum speed supported (in KB/s)
+ uint16 numVolLevels; // number of volume levels supported
+ uint16 bufSize; // buffer size supported by drive (KBytes)
+ uint16 curSpeed; // current speed selected (in KB/s)
+ uint8 reserved;
+ uint8 :1,// format of digital data output
+ bck :1,// data is valid on the falling edge of BCK
+ rck :1,// HIGH on LRCK indicates left channel
+ lsbf :1,// LSB first
+ length :2,
+ :2;
+ uint8 reserved2[2];
+} SCSICDROMCapabilitiesPage;
+
+typedef struct {
+ uint8 page :6, // page code: 0x03
+ :1,
+ ps :1;
+ uint8 len; // page length 0x16
+ uint16 tracksPerZone;
+ uint16 repSectorsPerZone;
+ uint16 repTracksPerZone;
+ uint16 replTracksPerLUN;
+ uint16 sectorsPerTrack;
+ uint16 bytesPerSector;
+ uint16 interleave;
+ uint16 trackSkew;
+ uint16 cylinderSkew;
+ uint8 :3,
+ surf :1,
+ rmb :1,
+ hsec :1,
+ ssec :1;
+ uint8 reserved[3];
+} SCSIFormatPage;
+
+typedef uint8 uint24[3];
+
+typedef struct {
+ uint8 page :6, // page code: 0x04
+ :1,
+ ps :1;
+ uint8 len; // page length 0x16
+ uint24 cylinders; // number of cylinders
+ uint8 heads; // number of heads
+ uint24 writeCompCylinder; // starting cylinder for write compensation
+ uint24 writeCurCylinder; // starting cylinder for reduce write current
+ uint16 stepRate;
+ uint24 landingZone; // cylinder number of landing zone
+ uint8 rpl :1,
+ :7;
+ uint8 rotOffset; // rotational offset
+ uint8 :8;
+ uint16 rotRate; // medium rotation rate
+ uint8 reserved[2];
+} SCSIGeometryPage;
+
+typedef struct {
+ uint8 page :6, // page code: 0x08
+ :1,
+ ps :1;
+ uint8 len; // page length 0x0a (0x12 for SCSI-3)
+ uint8 rcd :1,
+ mf :1,
+ wce :1,
+ :5;
+ uint8 readPri:4, // read retention priority
+ writePri:4; // write retention priority
+ uint16 prefetchDisable;// disable pre-fetch transfer length
+ uint16 prefetchMin; // pre-fetch minimum
+ uint16 prefetchMax; // pre-fetch maximum
+ uint16 prefetchAbsMax;// absolute pre-fetch maximum
+} SCSICachePage;
+
+typedef struct {
+ uint8 page :6, // page code: 0x08
+ :1,
+ ps :1;
+ uint8 len; // page length 0x16
+ uint8 :6,
+ lpn :1,
+ nd :1;
+ uint8 :8;
+ uint16 maxNotches; // maximum number of notches
+ uint16 activeNotch;
+ uint32 activeStart; // beginning of active notch
+ uint32 activeEnd; // end of active notch
+} SCSINotchPage;
+
+typedef struct {
+ uint8 page :6, // page code: 0x06
+ :1,
+ ps :1;
+ uint8 len; // page length 0x02
+ uint8 rubr :1,
+ :7;
+ uint8 :8;
+} SCSIOpticalPage;
+typedef struct {
+ uint8 page :6, // page code: 0x0f
+ :1,
+ ps :1;
+ uint8 len; // page length 0x0e
+ uint8 :6,
+ dcc :1,
+ dce :1;
+ uint8 :5,
+ red :2,
+ dde :1;
+ uint8 compAlg[4];
+ uint8 decompAlg[4];
+ uint8 reserved[4];
+} SCSICompressionPage;
+
+typedef struct {
+ uint8 page :6, // page code: 0x10
+ :1,
+ ps :1;
+ uint8 len; // page length 0x0e
+ uint8 format:5, // active format
+ car :1,
+ cap :1,
+ :1;
+ uint8 partition; // active partition
+ uint8 wbeRatio; // write buffer empty ratio
+ uint8 rbeRatio; // read buffer empty ratio
+ uint16 writeDelay;
+ uint8 rew :1,
+ rb0 :1,
+ sofc :2,
+ avc :1,
+ rsmk :1,
+ bis :1,
+ dbr :1;
+ uint8 gapSize;
+ uint8 :3,
+ sew :1,
+ eeg :1,
+ eod :3;
+ uint24 bufSizeAtEW;
+ uint8 compression;
+ uint8 :8;
+} SCSIDeviceConfigPage;
+
+typedef struct {
+ uint8 page :6, // page code: 0x03
+ :1,
+ ps :1;
+ uint8 len; // page length 0x06
+ uint8 unit; // measurement unit
+ uint8 :8;
+ uint16 divisor;
+ uint16 :16;
+} SCSIUnitsPage;
+
+
+/*
+ * Format of START STOP UNIT (0x1b).
+ */
+typedef
+#include "vmware_pack_begin.h"
+struct {
+ uint8 opcode; // 0x1b
+ uint8 immed:1,
+ rsvd:7;
+ uint8 reserved[2];
+ uint8 start:1,
+ loej:1, // load/eject
+ rsvd1:2,
+ power:4;
+ uint8 control;
+}
+#include "vmware_pack_end.h"
+SCSIStartStopUnitCmd;
+
+
+/*
+ * Format of ALLOW PREVENT MEDIUM REMOVAL (0x1e).
+ */
+typedef
+#include "vmware_pack_begin.h"
+struct {
+ uint8 opcode; // 0x1e
+ uint8 reserved[3];
+ uint8 prevent:2,
+ :6;
+ uint8 control;
+}
+#include "vmware_pack_end.h"
+SCSIMediumRemovalCmd;
+
+
+/*
+ * Format of READ CAPACITY (10) and (16) request and response blocks.
+ * These are defined here because multiple SCSI devices
+ * need them.
+ */
+typedef
+#include "vmware_pack_begin.h"
+struct {
+ uint8 opcode; // 0x25
+ uint8 rel :1,
+ :4,
+ lun :3;
+#define SCSI_RW10_MAX_LBN 0xffffffffu
+ uint32 lbn;
+ uint8 reserved[2];
+ uint8 pmi :1,
+ :7;
+ uint8 control;
+}
+#include "vmware_pack_end.h"
+SCSIReadCapacityCmd;
+
+typedef struct {
+ uint32 lbn;
+ uint32 blocksize;
+} SCSIReadCapacityResponse;
+
+typedef
+#include "vmware_pack_begin.h"
+struct {
+ uint8 opcode; // 0x9e
+#define SCSI_READ_CAPACITY16_SERVICE_ACTION 0x10
+ uint8 action:5,
+ :3;
+ uint64 lbn;
+ uint32 len;
+ uint8 pmi :1,
+ rel :1,
+ :6;
+ uint8 control;
+}
+#include "vmware_pack_end.h"
+SCSIReadCapacity16Cmd;
+
+typedef
+#include "vmware_pack_begin.h"
+struct {
+ uint64 lbn;
+ uint32 blocksize;
+}
+#include "vmware_pack_end.h"
+SCSIReadCapacity16Response;
+
+/*
+ * Format of READ/WRITE (6), (10), (12) and (16)
+ * request. These are defined here because multiple SCSI
+ * devices need them.
+ */
+typedef
+#include "vmware_pack_begin.h"
+struct {
+ uint32 opcode:8,
+ lun:3,
+ lbn:21;
+ uint8 length;
+ uint8 control;
+}
+#include "vmware_pack_end.h"
+SCSIReadWrite6Cmd;
+
+typedef
+#include "vmware_pack_begin.h"
+struct {
+ uint8 opcode;
+ uint8 rel :1,
+ :2,
+ flua :1,
+ dpo :1,
+ lun :3;
+ uint32 lbn;
+ uint8 reserved;
+ uint16 length;
+ uint8 control;
+}
+#include "vmware_pack_end.h"
+SCSIReadWrite10Cmd;
+
+typedef
+#include "vmware_pack_begin.h"
+struct {
+ uint8 opcode;
+ uint8 rel :1,
+ :2,
+ flua :1,
+ dpo :1,
+ lun :3;
+ uint32 lbn;
+ uint32 length;
+ uint8 reserved;
+ uint8 control;
+}
+#include "vmware_pack_end.h"
+SCSIReadWrite12Cmd;
+
+typedef
+#include "vmware_pack_begin.h"
+struct {
+ uint8 opcode;
+ uint8 rel :1,
+ :2,
+ flua :1,
+ dpo :1,
+ :3;
+ uint64 lbn;
+ uint32 length;
+ uint8 reserved;
+ uint8 control;
+}
+#include "vmware_pack_end.h"
+SCSIReadWrite16Cmd;
+
+typedef
+#include "vmware_pack_begin.h"
+struct {
+ uint8 opcode;
+ uint8 xtnt :1, // extent-based reservation
+ ptyID :3, // 3rd party reservation ID
+ pty :1, // 3rd party reservation
+ lun :3; // logical unit number
+ uint8 resvID; // SCSI-3: reservation ID
+ uint16 resvListLen; // SCSI-3: reservation list length
+ uint8 ctrl; // control byte
+}
+#include "vmware_pack_end.h"
+SCSIReserveUnitCmd;
+
+typedef
+#include "vmware_pack_begin.h"
+struct {
+ uint8 opcode;
+ uint8 xtnt :1, // extent-based reservation
+ ptyID :3, // 3rd party reservation ID
+ pty :1, // 3rd party reservation
+ lun :3; // logical unit number
+ uint8 resvID; // SCSI-3: reservation ID
+ uint8 reserved[2];
+ uint8 ctrl; // control byte
+}
+#include "vmware_pack_end.h"
+SCSIReleaseUnitCmd;
+
+typedef
+#include "vmware_pack_begin.h"
+struct {
+ uint8 opcode;
+ uint8 uniO :1, // unit offline
+ devO :1, // device offline
+ st :1, // self-test
+ :1,
+ pf :1, // page format
+ lun :3; // logical unit number
+ uint8 reserved;
+ uint16 len; // data length
+ uint8 ctrl; // control byte
+}
+#include "vmware_pack_end.h"
+SCSISendDiagnosticCmd;
+
+typedef
+#include "vmware_pack_begin.h"
+struct {
+ uint8 opcode;
+ uint8 relAdr :1, // relative address
+ bytChk :1, // byte
+ blkvfy :1, // blank blocks verification, scsi-3
+ :1,
+ dpo :1, // cache control bit
+ lun :3; // logical unit number
+ uint32 lbn; // logical block address
+ uint8 reserved;
+ uint16 len; // verification length
+ uint8 ctrl; // control byte
+}
+#include "vmware_pack_end.h"
+SCSIVerify10Cmd;
+
+typedef
+#include "vmware_pack_begin.h"
+struct {
+ uint8 opcode;
+ uint8 polled :1, // asynchronous or not
+ :7;
+ uint8 reserved0[2];
+#define SCSI_GESN_CLASS_RSVD0 (1 << 0)
+#define SCSI_GESN_CLASS_OP_CHANGE (1 << 1)
+#define SCSI_GESN_CLASS_POW_MGMT (1 << 2)
+#define SCSI_GESN_CLASS_EXT_REQ (1 << 3)
+#define SCSI_GESN_CLASS_MEDIA (1 << 4)
+#define SCSI_GESN_CLASS_MULTI_HOST (1 << 5)
+#define SCSI_GESN_CLASS_DEV_BUSY (1 << 6)
+#define SCSI_GESN_CLASS_RSVD1 (1 << 7)
+ uint8 notifyClassReq; // the class of events we are interested in
+ uint8 reserved1[2];
+ uint16 length; // allocation length
+ uint8 control;
+}
+#include "vmware_pack_end.h"
+SCSIGetEventStatusNotificationCmd;
+
+/*
+ * Format of Persistent Reservation Commands per SPC-3 r23, required for
+ * virtualizing reservations.
+ */
+
+/* Persistent Reserve IN service actions */
+typedef enum {
+ READ_KEYS = 0x0,
+ READ_RESERVATION = 0x1,
+ REPORT_CAPABILITIES = 0x2,
+ READ_FULL_STATUS = 0x3
+} SCSIPersistentReserveInServiceAction;
+
+/*
+ * Persistent reservation type codes
+ */
+typedef enum {
+ WRITE_EXCL = 0x1,
+ EXCL_ACCESS = 0x3,
+ WRITE_EXCL_REG_ONLY = 0x5,
+ EXCL_ACCESS_REG_ONLY = 0x6,
+ WRITE_EXCL_ALL_REG = 0x7,
+ EXCL_ACCESS_ALL_REG = 0x8
+} SCSIPersistentReserveTypeCode;
+
+typedef
+#include "vmware_pack_begin.h"
+struct {
+ uint8 opcode;
+ uint8 serviceAction :5,
+ reserved :3;
+ uint8 reserved1[5];
+ uint16 allocationLength;
+ uint8 control;
+}
+#include "vmware_pack_end.h"
+SCSIPersistentReserveInCmd;
+
+/* Persistent Reserve Out Service Actions */
+typedef enum {
+ REGISTER = 0x0,
+ PRESERVE = 0x1,
+ PRELEASE = 0x2,
+ CLEAR = 0x3,
+ PREEMPT = 0x4,
+ PREEMPT_AND_ABORT = 0x5,
+ REGISTER_AND_IGNORE_EXISTING_KEY = 0x6,
+ REGISTER_AND_MOVE = 0x7
+} SCSIPersistentReserveOutServiceAction;
+
+
+typedef
+#include "vmware_pack_begin.h"
+struct {
+ uint8 opcode;
+ uint8 serviceAction :5,
+ reserved :3;
+ uint8 type :4,
+ scope :4;
+ uint8 reserved1[2];
+ uint32 parameterListLength;
+ uint8 control;
+}
+#include "vmware_pack_end.h"
+SCSIPersistentReserveOutCmd;
+
+typedef
+#include "vmware_pack_begin.h"
+struct {
+ uint64 reservationKey;
+ uint64 serviceActionResKey;
+ uint8 obsolete1[4];
+ uint8 aptpl :1,
+ reserved1 :1,
+ all_tg_pt :1,
+ spec_i_pt :1,
+ reserved2 :4;
+ uint8 reserved3;
+ uint8 obsolete2[2];
+ /*
+ * Per SPC-3 r23, the parameter list length shall be 24 bytes in length if the
+ * following are true:
+ * a. the SPEC_I_PT but is set to 0
+ * b. service action is not REGISTER AND MOVE
+ *
+ * This is currently the only supported mode in the vmkernel,
+ * so no additional parameter data is included in this struct
+ */
+}
+#include "vmware_pack_end.h"
+SCSIPersistentReserveOutPList;
+
+typedef
+#include "vmware_pack_begin.h"
+struct {
+ uint32 prGeneration;
+ uint32 additionalLength;
+ uint64 reservationKey;
+ uint8 obsolete[4];
+ uint8 reserved;
+ uint8 type :4,
+ scope :4;
+ uint8 obsolete1[2];
+}
+#include "vmware_pack_end.h"
+SCSIPRReadReservationResp;
+
+
+/*
+ * Format of the sense data structure maintained in each SCSI
+ * device. Devices should fill in this data structure whenever
+ * they return a CHECK status for a SCSI command. The contents
+ * is returned to the initiator either through the adapter doing
+ * an auto-sense request or the initiator doing an explicit
+ * REQUEST SENSE SCSI operation. A device keeps only one copy
+ * of sense data at a time; the base SCSI device support invalidates
+ * this data structure before each SCSI operation as needed.
+ */
+typedef
+#include "vmware_pack_begin.h"
+struct {
+ uint8 error :7, // 0x70 for current command, 0x71 for earlier command
+#define SCSI_SENSE_ERROR_CURCMD 0x70 // sense data is for "current command"
+#define SCSI_SENSE_ERROR_PREVCMD 0x71 // sense data is for an earlier command
+ valid :1; // sense data valid
+/* NB: Please Note that the valid bit above does NOT tell you whether
+ * the sense is actually valid and thus the name is really badly chosen
+ * (even though it is the official name from the SCSI II specification).
+ * The SCSI II spec. states "A valid bit of zero indicates that the
+ * information field is not as defined in this International Standard".
+ * we have seen that many tape drives are capable of returning sense
+ * without this bit set....
+ */
+ uint8 segment; // segment number
+ uint8 key :4, // sense key
+ :1,
+ ili :1,
+ eom :1,
+ filmrk :1;
+ uint8 info[4]; // general information
+ uint8 optLen; // length of optional data that follows
+ uint8 cmdInfo[4]; // command-specific information
+ uint8 code; // sense code
+ uint8 xcode; // extended sense code
+ uint8 fru; //
+ uint8 bitpos :3,
+ bpv :1,
+ :2,
+ cd :1, // 1 if error in command, 0 if in data
+ sksv :1; // sense key specific data is valid
+ uint16 epos; // offset of first byte in error
+
+ // Some vendors want to return additional data which
+ // requires a sense buffer of up to 64 bytes.
+ uint8 additional[46];
+}
+#include "vmware_pack_end.h"
+SCSISenseData;
+
+
+/*
+ * Read (DVD) Disc Structure definitions.
+ */
+typedef
+#include "vmware_pack_begin.h"
+struct {
+ uint8 opcode;
+#define SCSI_RDS_MT_DVD 0x0
+#define SCSI_RDS_MT_BD 0x1
+ uint8 mediaType:4,
+ :4;
+ uint32 address;
+ uint8 layerNumber;
+ /* Layer, Address */
+#define SCSI_RDS_GDS_AACS_VOLUME_ID 0x80
+#define SCSI_RDS_GDS_AACS_MEDIA_SERIAL_NUM 0x81
+#define SCSI_RDS_GDS_AACS_MEDIA_ID 0x82
+#define SCSI_RDS_GDS_AACS_MEDIA_KEY 0x83 /* Layer number, Pack Number */
+#define SCSI_RDS_GDS_LAYERS_LIST 0x90
+#define SCSI_RDS_GDS_WRITE_PROTECT 0xC0
+#define SCSI_RDS_GDS_CAPABILITY_LIST 0xFF
+
+#define SCSI_RDS_DVD_PHYSICAL_INFO_LEADIN 0x00 /* Layer, - */
+#define SCSI_RDS_DVD_COPYRIGHT_INFO_LEADIN 0x01 /* Layer, - */
+#define SCSI_RDS_DVD_DISC_KEY 0x02
+#define SCSI_RDS_DVD_BURST_CUTTING_AREA 0x03
+#define SCSI_RDS_DVD_DISC_MANUFACTURING 0x04 /* Layer, - */
+#define SCSI_RDS_DVD_COPYRIGHT_INFO_SECTOR 0x05 /* -, LBA */
+#define SCSI_RDS_DVD_MEDIA_ID 0x06
+#define SCSI_RDS_DVD_MEDIA_KEY 0x07 /* -, Pack Number */
+#define SCSI_RDS_DVD_DVDRAM_DDS_INFO 0x08
+#define SCSI_RDS_DVD_DVDRAM_MEDIUM_STATUS 0x09
+#define SCSI_RDS_DVD_DVDRAM_SPARE_AREA 0x0A
+#define SCSI_RDS_DVD_DVDRAM_RECORDING_TYPE 0x0B
+#define SCSI_RDS_DVD_RMD_BORDEROUT 0x0C
+#define SCSI_RDS_DVD_RMD_SECTOR 0x0D /* -, Start Field Number of RMA blocks */
+#define SCSI_RDS_DVD_PRERECORDED_LEADIN 0x0E
+#define SCSI_RDS_DVD_DVDR_MEDIA_ID 0x0F
+#define SCSI_RDS_DVD_DVDR_PHYSICAL_INFO 0x10 /* Layer, - */
+#define SCSI_RDS_DVD_ADIP_INFO 0x11 /* Layer, - */
+#define SCSI_RDS_DVD_HDDVD_CPI 0x12 /* Layer, - */
+#define SCSI_RDS_DVD_HDVD_COPYRIGHT_DATA 0x15 /* Layer, Start Copyright Sector */
+#define SCSI_RDS_DVD_HDDVDR_MEDIUM_STATUS 0x19
+#define SCSI_RDS_DVD_HDDVDR_RMD 0x1A
+
+#define SCSI_RDS_DVD_DL_LAYER_CAPACITY 0x20
+#define SCSI_RDS_DVD_DL_MIDDLE_ZONE_START 0x21
+#define SCSI_RDS_DVD_DL_JUMP_INTERVAL_SIZE 0x22
+#define SCSI_RDS_DVD_DL_MANUAL_LAYER_JUMP 0x23
+#define SCSI_RDS_DVD_DL_REMAPPING 0x24 /* -, Anchor Point Number */
+
+#define SCSI_RDS_DVD_DCB_IDENTIFIER 0x30 /* Session Number, Content Descriptor */
+#define SCSI_RDS_DVD_MTA_ECC 0x31 /* -, PSN */
+
+#define SCSI_RDS_BD_DI 0x00
+#define SCSI_RDS_BD_DDS 0x08
+#define SCSI_RDS_BD_CARTRIDGE_STATUS 0x09
+#define SCSI_RDS_BD_SPARE_AREA 0x0A
+#define SCSI_RDS_BD_RAW_DFL 0x12 /* -, Offset */
+#define SCSI_RDS_BD_PAC 0x30 /* -, ID and Format Number */
+ uint8 format;
+ uint16 length;
+ uint8 :6,
+ agid:2;
+ uint8 control;
+}
+#include "vmware_pack_end.h"
+SCSIReadDiscStructureCmd;
+
+typedef
+#include "vmware_pack_begin.h"
+struct {
+ uint16 length;
+ uint16 rsvd;
+ uint8 partVersion:4,
+#define SCSI_RDS_DC_DVD_ROM 0x0
+#define SCSI_RDS_DC_DVD_RAM 0x1
+#define SCSI_RDS_DC_DVD_R 0x2
+#define SCSI_RDS_DC_DVD_RW 0x3
+#define SCSI_RDS_DC_HD_DVD_ROM 0x4
+#define SCSI_RDS_DC_HD_DVD_RAM 0x5
+#define SCSI_RDS_DC_HD_DVD_R 0x6
+#define SCSI_RDS_DC_DVD_PLUS_RW 0x9
+#define SCSI_RDS_DC_DVD_PLUS_R 0xA
+#define SCSI_RDS_DC_DVD_PLUS_RW_DL 0xD
+#define SCSI_RDS_DC_DVD_PLUS_R_DL 0xE
+ diskCategory:4;
+#define SCSI_RDS_MR_1X 0x0
+#define SCSI_RDS_MR_2X 0x1
+#define SCSI_RDS_MR_4X 0x2
+#define SCSI_RDS_MR_8X 0x3
+#define SCSI_RDS_MR_16X 0x4
+#define SCSI_RDS_MR_UNSPECIFIED 0xF
+ uint8 maximumRate:4,
+#define SCSI_RDS_DS_120MM 0x0
+#define SCSI_RDS_DS_80MM 0x1
+ discSize:4;
+/* layerType is bitvector */
+#define SCSI_RDS_LT_EMBOSSED 0x1
+#define SCSI_RDS_LT_RECORDABLE 0x2
+#define SCSI_RDS_LT_REWRITEABLE 0x4
+ uint8 layerType:4,
+ track:1,
+#define SCSI_RDS_LAYERS_SL 0x0
+#define SCSI_RDS_LAYERS_DL 0x1
+ layers:2,
+ :1;
+#define SCSI_RDS_TD_740NM 0x0
+#define SCSI_RDS_TD_800NM 0x1
+#define SCSI_RDS_TD_615NM 0x2
+#define SCSI_RDS_TD_400NM 0x3
+#define SCSI_RDS_TD_340NM 0x4
+ uint8 trackDensity:4,
+#define SCSI_RDS_LD_267NM 0x0
+#define SCSI_RDS_LD_293NM 0x1
+#define SCSI_RDS_LD_420NM 0x2
+#define SCSI_RDS_LD_285NM 0x4
+#define SCSI_RDS_LD_153NM 0x5
+#define SCSI_RDS_LD_135NM 0x6
+#define SCSI_RDS_LD_353NM 0x8
+ linearDensity:4;
+#define SCSI_RDS_STARTPSN_DVD 0x030000
+#define SCSI_RDS_STARTPSN_DVDRAM 0x031000
+#define SCSI_RDS_MAXSIZE_DVD 0xF80000
+ uint32 startPSN;
+ uint32 endPSN;
+ uint32 endPSNLayer0;
+ uint8 :7,
+ bca:1;
+ uint8 rsvd2[2048 - 17];
+}
+#include "vmware_pack_end.h"
+SCSIRDSDVDPhysicalInfoLeadin;
+
+
+/*
+ * Host and device status definitions.
+ *
+ * These mimic the BusLogic adapter-specific definitions but are
+ * intended to be adapter-independent (i.e. adapters that don't
+ * define these values directly or define them with different values
+ * must map them to known values).
+ */
+
+/*
+ * host adapter status/error codes
+ */
+typedef enum {
+ BTSTAT_SUCCESS = 0x00, // CCB complete normally with no errors
+ BTSTAT_LINKED_COMMAND_COMPLETED = 0x0a,
+ BTSTAT_LINKED_COMMAND_COMPLETED_WITH_FLAG = 0x0b,
+ BTSTAT_DATA_UNDERRUN = 0x0c,
+ BTSTAT_SELTIMEO = 0x11, // SCSI selection timeout
+ BTSTAT_DATARUN = 0x12, // data overrun/underrun
+ BTSTAT_BUSFREE = 0x13, // unexpected bus free
+ BTSTAT_INVPHASE = 0x14, // invalid bus phase or sequence requested by target
+ BTSTAT_INVCODE = 0x15, // invalid action code in outgoing mailbox
+ BTSTAT_INVOPCODE = 0x16, // invalid operation code in CCB
+ BTSTAT_LUNMISMATCH = 0x17, // linked CCB has different LUN from first CCB
+ BTSTAT_INVPARAM = 0x1a, // invalid parameter in CCB or segment list
+ BTSTAT_SENSFAILED = 0x1b, // auto request sense failed
+ BTSTAT_TAGREJECT = 0x1c, // SCSI II tagged queueing message rejected by target
+ BTSTAT_BADMSG = 0x1d, // unsupported message received by the host adapter
+ BTSTAT_HAHARDWARE = 0x20, // host adapter hardware failed
+ BTSTAT_NORESPONSE = 0x21, // target did not respond to SCSI ATN, sent a SCSI RST
+ BTSTAT_SENTRST = 0x22, // host adapter asserted a SCSI RST
+ BTSTAT_RECVRST = 0x23, // other SCSI devices asserted a SCSI RST
+ BTSTAT_DISCONNECT = 0x24, // target device reconnected improperly (w/o tag)
+ BTSTAT_BUSRESET = 0x25, // host adapter issued BUS device reset
+ BTSTAT_ABORTQUEUE = 0x26, // abort queue generated
+ BTSTAT_HASOFTWARE = 0x27, // host adapter software error
+ BTSTAT_HATIMEOUT = 0x30, // host adapter hardware timeout error
+ BTSTAT_SCSIPARITY = 0x34, // SCSI parity error detected
+} HostBusAdapterStatus;
+
+// scsi device status values
+typedef enum {
+ SDSTAT_GOOD = 0x00, // no errors
+ SDSTAT_CHECK = 0x02, // check condition
+ SDSTAT_CONDITION_MET = 0x04, // condition met
+ SDSTAT_BUSY = 0x08, // device busy
+ SDSTAT_INTERMEDIATE = 0x10,
+ SDSTAT_INTERMEDIATE_CONDITION = 0x14,
+ SDSTAT_RESERVATION_CONFLICT = 0x18, // device reserved by another host
+ SDSTAT_COMMAND_TERMINATED = 0x22,
+ SDSTAT_TASK_SET_FULL = 0x28,
+ SDSTAT_ACA_ACTIVE = 0x30,
+ SDSTAT_TASK_ABORTED = 0x40,
+} SCSIDeviceStatus;
+
+typedef enum {
+ SCSI_XFER_AUTO = 0, // transfer direction depends on opcode
+ SCSI_XFER_TOHOST = 1, // data is from device -> adapter
+ SCSI_XFER_TODEVICE = 2, // data is from adapter -> device
+ SCSI_XFER_NONE = 3 // data transfer is suppressed
+} SCSIXferType;
+
+typedef enum {
+ SCSI_EMULATE = 0, // emulate this command
+ SCSI_DONT_EMULATE = 1, // do not emulate this command but log a message
+ SCSI_DONT_EMULATE_DONT_LOG = 2 // do not emulate this command or log a message
+} SCSIEmulation;
+
+#define HBA_SCSI_ID 7 //default HBA SCSI ID
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * SCSICdb_IsRead --
+ *
+ * This function returns TRUE if the scsi command passed as an argument is
+ * a read.
+ *
+ * Results:
+ * TRUE/FALSE
+ *
+ * Side effects:
+ * None.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+static INLINE Bool
+SCSICdb_IsRead(uint8 cdb0) // IN
+{
+ return cdb0 == SCSI_CMD_READ6
+ || cdb0 == SCSI_CMD_READ10
+ || cdb0 == SCSI_CMD_READ12
+ || cdb0 == SCSI_CMD_READ16;
+}
+
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * SCSICdb_IsWrite --
+ *
+ * This function returns TRUE if the scsi command passed as an argument is
+ * a write.
+ *
+ * Results:
+ * TRUE/FALSE
+ *
+ * Side effects:
+ * None.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+static INLINE Bool
+SCSICdb_IsWrite(uint8 cdb0) // IN
+{
+ return cdb0 == SCSI_CMD_WRITE6
+ || cdb0 == SCSI_CMD_WRITE10
+ || cdb0 == SCSI_CMD_WRITE12
+ || cdb0 == SCSI_CMD_WRITE16;
+}
+
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * SCSICdb_IsRW --
+ *
+ * This function returns TRUE if the scsi command passed as an argument is
+ * a read or write.
+ *
+ * Results:
+ * TRUE/FALSE
+ *
+ * Side effects:
+ * None.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+static INLINE Bool
+SCSICdb_IsRW(uint8 cdb0) // IN
+{
+ return SCSICdb_IsRead(cdb0) || SCSICdb_IsWrite(cdb0);
+}
+
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * SCSICdb_GetLengthFieldOffset --
+ *
+ * Returns the offset in bytes of the 'length' field in the CDB
+ * of a given command.
+ *
+ * Results:
+ * Offset of 'length' field.
+ *
+ * Side effects:
+ * None.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+static INLINE uint16
+SCSICdb_GetLengthFieldOffset(uint8 cmd)
+{
+ switch (cmd) {
+ case SCSI_CMD_READ10:
+ case SCSI_CMD_WRITE10:
+ return offsetof(SCSIReadWrite10Cmd, length);
+ case SCSI_CMD_READ6:
+ case SCSI_CMD_WRITE6:
+ return offsetof(SCSIReadWrite6Cmd, length);
+ case SCSI_CMD_READ16:
+ case SCSI_CMD_WRITE16:
+ return offsetof(SCSIReadWrite16Cmd, length);
+ case SCSI_CMD_READ12:
+ case SCSI_CMD_WRITE12:
+ return offsetof(SCSIReadWrite12Cmd, length);
+ default:
+ return 0;
+ }
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * SCSI3InquiryLen --
+ *
+ * Returns 16-bit allocation length specified in SCSI3 Inquriy CMD cmd
+ *
+ * Results:
+ * 16-bit allocation length.
+ *
+ * Side effects:
+ * None.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+static INLINE uint16
+SCSI3InquiryLen(SCSI3InquiryCmd *inqCmd) // IN
+{
+ return (inqCmd->lenMSB << 8) + inqCmd->len;
+}
+
+
+typedef
+#include "vmware_pack_begin.h"
+struct SCSICmdInfo {
+ uint8 code;
+ uint8 xferType;
+ char *name;
+ uint8 emulation;
+}
+#include "vmware_pack_end.h"
+SCSICmdInfo;
+
+/* This array contains the data below defined in SCSI_CMD_INFO_DATA, but
+ * can't assign the data here because it would be included in all .o, so
+ * it should be initialized in one .o file for each part of the product.
+ * In vmm, this is currently initialized in buslogicMdev.c.
+ * In vmx, this is currently initialized in usbAnalyzer.c.
+ * In vmkernel, this is currently initialized in vmk_scsi.c.
+ */
+extern SCSICmdInfo scsiCmdInfo[256];
+#define SCSI_CMD_GET_CODE(cmd) (scsiCmdInfo[cmd].code)
+#define SCSI_CMD_GET_XFERTYPE(cmd) (scsiCmdInfo[cmd].xferType)
+#define SCSI_CMD_GET_NAME(cmd) (scsiCmdInfo[cmd].name)
+#define SCSI_CMD_GET_EMULATION(cmd) (scsiCmdInfo[cmd].emulation)
+
+#define SCSI_CMD_INFO_DATA \
+ {SCSI_CMD_TEST_UNIT_READY, SCSI_XFER_NONE, "TEST UNIT READY", SCSI_EMULATE}, \
+ {SCSI_CMD_REZERO_UNIT, SCSI_XFER_NONE, "REWIND/REZERO UNIT", SCSI_DONT_EMULATE}, \
+ {0x02, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_REQUEST_SENSE, SCSI_XFER_TOHOST, "REQUEST SENSE", SCSI_EMULATE}, \
+ {SCSI_CMD_FORMAT_UNIT, SCSI_XFER_TODEVICE, "FORMAT UNIT", SCSI_EMULATE}, \
+ {SCSI_CMD_READ_BLOCKLIMITS, SCSI_XFER_TOHOST, "READ BLOCK LIMITS", SCSI_DONT_EMULATE},\
+ {0x06, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_INIT_ELEMENT_STATUS, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_READ6, SCSI_XFER_TOHOST, "READ(6)", SCSI_EMULATE}, \
+ {0x09, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_WRITE6, SCSI_XFER_TODEVICE, "WRITE(6)", SCSI_EMULATE}, \
+ {SCSI_CMD_SLEW_AND_PRINT, SCSI_XFER_TODEVICE, NULL, SCSI_DONT_EMULATE}, \
+ {0x0c, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x0d, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x0e, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_READ_REVERSE, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_SYNC_BUFFER, SCSI_XFER_NONE, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_SPACE, SCSI_XFER_NONE, "SPACE", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_INQUIRY, SCSI_XFER_TOHOST, "INQUIRY", SCSI_EMULATE}, \
+ {0x13, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_RECOVER_BUFFERED, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_MODE_SELECT, SCSI_XFER_TODEVICE, "MODE SELECT(6)", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_RESERVE_UNIT, SCSI_XFER_NONE, "RESERVE(6)", SCSI_EMULATE}, \
+ {SCSI_CMD_RELEASE_UNIT, SCSI_XFER_NONE, "RELEASE(6)", SCSI_EMULATE}, \
+ {SCSI_CMD_COPY, SCSI_XFER_AUTO, "COPY AND VERIFY", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_ERASE, SCSI_XFER_NONE, "ERASE", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_MODE_SENSE, SCSI_XFER_TOHOST, "MODE SENSE(6)", SCSI_EMULATE}, \
+ {SCSI_CMD_SCAN, SCSI_XFER_TODEVICE, NULL, SCSI_EMULATE}, \
+ {SCSI_CMD_RECV_DIAGNOSTIC, SCSI_XFER_AUTO, "RECEIVE DIAGNOSTIC RESULTS", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_SEND_DIAGNOSTIC, SCSI_XFER_TODEVICE, "SEND DIAGNOSTIC", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_MEDIUM_REMOVAL, SCSI_XFER_NONE, "LOCK/UNLOCK DOOR", SCSI_DONT_EMULATE_DONT_LOG}, \
+ {0x1f, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x20, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x21, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x22, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_READ_FORMAT_CAPACITIES, SCSI_XFER_TOHOST, "READ FORMAT CAPACITIES", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_SET_WINDOW, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_READ_CAPACITY, SCSI_XFER_TOHOST, "READ CAPACITY", SCSI_EMULATE}, \
+ {0x26, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x27, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_READ10, SCSI_XFER_TOHOST, "READ(10)", SCSI_EMULATE}, \
+ {SCSI_CMD_READ_GENERATION, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_WRITE10, SCSI_XFER_TODEVICE, "WRITE(10)", SCSI_EMULATE}, \
+ {SCSI_CMD_SEEK10, SCSI_XFER_NONE, NULL, SCSI_DONT_EMULATE}, \
+ {0x2c, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_READ_UPDATED_BLOCK, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_WRITE_VERIFY, SCSI_XFER_AUTO, "WRITE VERIFY", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_VERIFY, SCSI_XFER_NONE, "VERIFY", SCSI_EMULATE}, \
+ {SCSI_CMD_SEARCH_DATA_HIGH, SCSI_XFER_AUTO, "SEARCH HIGH", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_SEARCH_DATA_EQUAL, SCSI_XFER_AUTO, "SEARCH EQUAL", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_SEARCH_DATA_LOW, SCSI_XFER_AUTO, "SEARCH LOW", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_SET_LIMITS, SCSI_XFER_AUTO, "SET LIMITS", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_READ_POSITION, SCSI_XFER_TOHOST, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_SYNC_CACHE, SCSI_XFER_NONE, "SYNC CACHE", SCSI_EMULATE}, \
+ {SCSI_CMD_LOCKUNLOCK_CACHE, SCSI_XFER_AUTO, "LOCK/UNLOCK CACHE", SCSI_DONT_EMULATE},\
+ {SCSI_CMD_READ_DEFECT_DATA, SCSI_XFER_AUTO, "READ DEFECT DATA", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_MEDIUM_SCAN, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_COMPARE, SCSI_XFER_AUTO, "COMPARE", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_COPY_VERIFY, SCSI_XFER_AUTO, "COPY AND VERIFY", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_WRITE_BUFFER, SCSI_XFER_AUTO, "WRITE BUFFER", SCSI_DONT_EMULATE_DONT_LOG}, \
+ {SCSI_CMD_READ_BUFFER, SCSI_XFER_AUTO, "READ BUFFER", SCSI_DONT_EMULATE_DONT_LOG}, \
+ {SCSI_CMD_UPDATE_BLOCK, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_READ_LONG, SCSI_XFER_AUTO, "READ LONG", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_WRITE_LONG, SCSI_XFER_AUTO, "WRITE LONG", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_CHANGE_DEF, SCSI_XFER_NONE, "CHANGE DEFINITION", SCSI_DONT_EMULATE},\
+ {SCSI_CMD_WRITE_SAME, SCSI_XFER_AUTO, "WRITE SAME", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_READ_SUBCHANNEL, SCSI_XFER_TOHOST, "READ SUBCHANNEL", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_READ_TOC, SCSI_XFER_TOHOST, "READ TOC", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_READ_HEADER, SCSI_XFER_TOHOST, "READ HEADER", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_PLAY_AUDIO10, SCSI_XFER_NONE, "PLAY AUDIO(10)", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_GET_CONFIGURATION, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_PLAY_AUDIO_MSF, SCSI_XFER_NONE, "PLAY AUDIO MSF", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_PLAY_AUDIO_TRACK, SCSI_XFER_AUTO, "PLAY AUDIO TRACK", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_PLAY_AUDIO_RELATIVE, SCSI_XFER_AUTO, "PLAY AUDIO RELATIVE", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_GET_EVENT_STATUS_NOTIFICATION, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_PAUSE, SCSI_XFER_NONE, "PAUSE/RESUME", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_LOG_SELECT, SCSI_XFER_TODEVICE, "LOG SELECT", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_LOG_SENSE, SCSI_XFER_TOHOST, "LOG SENSE", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_STOP_PLAY, SCSI_XFER_NONE, "STOP PLAY", SCSI_DONT_EMULATE}, \
+ {0x4f, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x50, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_READ_DISC_INFO, SCSI_XFER_TOHOST, "CDR INFO", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_READ_TRACK_INFO, SCSI_XFER_TOHOST, "TRACK INFO", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_RESERVE_TRACK, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x54, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_MODE_SELECT10, SCSI_XFER_TODEVICE, "MODE SELECT(10)", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_RESERVE_UNIT10, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_RELEASE_UNIT10, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x58, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x59, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_MODE_SENSE10, SCSI_XFER_TOHOST, "MODE SENSE(10)", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_CLOSE_SESSION, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_READ_BUFFER_CAPACITY, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_SEND_CUE_SHEET, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_PERSISTENT_RESERVE_IN, SCSI_XFER_TOHOST, "PERSISTENT RESERVE IN", SCSI_EMULATE}, \
+ {SCSI_CMD_PERSISTENT_RESERVE_OUT, SCSI_XFER_TODEVICE, "PERSISTENT RESERVE OUT", SCSI_EMULATE}, \
+ {0x60, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x61, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x62, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x63, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x64, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x65, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x66, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x67, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x68, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x69, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x6a, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x6b, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x6c, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x6d, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x6e, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x6f, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x70, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x71, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x72, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x73, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x74, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x75, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x76, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x77, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x78, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x79, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x7a, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x7b, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x7c, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x7d, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x7e, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x7f, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x80, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x81, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x82, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x83, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x84, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x85, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x86, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x87, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_READ16, SCSI_XFER_TOHOST, "READ(16)", SCSI_EMULATE}, \
+ {0x89, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_WRITE16, SCSI_XFER_TODEVICE, "WRITE(16)", SCSI_EMULATE}, \
+ {0x8b, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x8c, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x8d, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x8e, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_VERIFY16, SCSI_XFER_NONE, "VERIFY(16)", SCSI_EMULATE}, \
+ {0x90, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x91, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x92, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x93, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x94, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x95, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x96, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x97, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x98, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x99, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x9a, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x9b, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x9c, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0x9d, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_READ_CAPACITY16, SCSI_XFER_TOHOST, "READ CAPACITY 16", SCSI_EMULATE}, \
+ {0x9f, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_REPORT_LUNS, SCSI_XFER_AUTO, "REPORT LUNS", SCSI_EMULATE},\
+ {SCSI_CMD_BLANK, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xa2, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_SEND_KEY, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_REPORT_KEY, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_PLAY_AUDIO12, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_LOADCD, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xa7, SCSI_XFER_AUTO, "MOVE MEDIUM", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_READ12, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_PLAY_TRACK_RELATIVE, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_WRITE12, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xab, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_ERASE12, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_READ_DVD_STRUCTURE, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_WRITE_VERIFY12, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_VERIFY12, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_SEARCH_DATA_HIGH12, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_SEARCH_DATA_EQUAL12, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_SEARCH_DATA_LOW12, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_SET_LIMITS12, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xb4, SCSI_XFER_AUTO, "READ ELEMENT STATUS", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_REQUEST_VOLUME_ELEMENT_ADDR, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_SET_STREAMING, SCSI_XFER_TODEVICE, "SET STREAMING", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_READ_DEFECT_DATA12, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_SELECT_CDROM_SPEED, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_READ_CD_MSF, SCSI_XFER_TOHOST, "READ CD MSF", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_AUDIO_SCAN, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_SET_CDROM_SPEED, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_PLAY_CD, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_MECH_STATUS, SCSI_XFER_TOHOST, "MECHANISM STATUS", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_READ_CD, SCSI_XFER_TOHOST, "READ CD MSF", SCSI_DONT_EMULATE}, \
+ {SCSI_CMD_SEND_DVD_STRUCTURE, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xc0, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xc1, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xc2, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xc3, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xc4, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xc5, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xc6, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xc7, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xc8, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xc9, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xca, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xcb, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xcc, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xcd, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xce, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xcf, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xd0, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xd1, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xd2, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xd3, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xd4, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xd5, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xd6, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xd7, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xd8, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xd9, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xda, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xdb, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xdc, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xdd, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xde, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xdf, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xe0, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xe1, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xe2, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xe3, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xe4, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xe5, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xe6, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xe7, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xe8, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xe9, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xea, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xeb, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xec, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xed, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xee, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xef, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xf0, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xf1, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xf2, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xf3, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xf4, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xf5, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xf6, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xf7, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xf8, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xf9, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xfa, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xfb, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xfc, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xfd, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xfe, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+ {0xff, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE},
+
+#endif
--- /dev/null
+/*********************************************************
+ * Copyright (C) 1998-2004 VMware, Inc. 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 version 2 and no 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. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ *********************************************************/
+
+/*
+ * vm_assert.h --
+ *
+ * The basic assertion facility for all VMware code.
+ *
+ * For proper use, see
+ * http://vmweb.vmware.com/~mts/WebSite/guide/programming/asserts.html
+ */
+
+#ifndef _VM_ASSERT_H_
+#define _VM_ASSERT_H_
+
+#define INCLUDE_ALLOW_USERLEVEL
+#define INCLUDE_ALLOW_VMMEXT
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_VMMON
+#define INCLUDE_ALLOW_VMNIXMOD
+#define INCLUDE_ALLOW_VMKERNEL
+#define INCLUDE_ALLOW_VMKDRIVERS
+#define INCLUDE_ALLOW_VMK_MODULE
+#define INCLUDE_ALLOW_DISTRIBUTE
+#define INCLUDE_ALLOW_VMCORE
+#define INCLUDE_ALLOW_VMIROM
+#include "includeCheck.h"
+
+// XXX not necessary except some places include vm_assert.h improperly
+#include "vm_basic_types.h"
+#include "vm_basic_defs.h"
+
+
+/*
+ * XXX old file code
+ */
+
+#ifdef FILECODEINT
+#error "Don't define FILECODEINT. It is obsolete."
+#endif
+#ifdef FILECODE
+#error "Don't define FILECODE. It is obsolete."
+#endif
+
+
+/*
+ * Panic and log functions
+ */
+
+EXTERN void Log(const char *fmt, ...) PRINTF_DECL(1, 2);
+EXTERN void Warning(const char *fmt, ...) PRINTF_DECL(1, 2);
+EXTERN NORETURN void Panic(const char *fmt, ...) PRINTF_DECL(1, 2);
+
+EXTERN void LogThrottled(uint32 *count, const char *fmt, ...)
+ PRINTF_DECL(2, 3);
+EXTERN void WarningThrottled(uint32 *count, const char *fmt, ...)
+ PRINTF_DECL(2, 3);
+
+/* DB family: messages which are parsed by logfile database system */
+#define WarningDB Warning
+#define LogDB Log
+#define WarningThrottledDB WarningThrottled
+#define LogThrottledDB LogThrottled
+
+
+/*
+ * Stress testing: redefine ASSERT_IFNOT() to taste
+ */
+
+#ifndef ASSERT_IFNOT
+ #ifdef __cplusplus
+ #define ASSERT_IFNOT(cond, panic) (UNLIKELY(!(cond)) ? (panic) : (void)0)
+ #else
+ #define ASSERT_IFNOT(cond, panic) (UNLIKELY(!(cond)) ? (panic) : 0)
+ #endif
+#endif
+
+
+/*
+ * Assert, panic, and log macros
+ *
+ * Some of these are redefined below undef !VMX86_DEBUG.
+ * ASSERT() is special cased because of interaction with Windows DDK.
+ */
+
+#if defined VMX86_DEBUG || defined ASSERT_ALWAYS_AVAILABLE
+#undef ASSERT
+#define ASSERT(cond) \
+ ASSERT_IFNOT(cond, _ASSERT_PANIC(AssertAssert))
+#endif
+#define ASSERT_BUG(bug, cond) \
+ ASSERT_IFNOT(cond, _ASSERT_PANIC_BUG(bug, AssertAssert))
+#define ASSERT_BUG_DEBUGONLY(bug, cond) ASSERT_BUG(bug, cond)
+
+#define PANIC() _ASSERT_PANIC(AssertPanic)
+#define PANIC_BUG(bug) _ASSERT_PANIC_BUG(bug, AssertPanic)
+
+#define ASSERT_NOT_IMPLEMENTED(cond) \
+ ASSERT_IFNOT(cond, NOT_IMPLEMENTED())
+#define ASSERT_NOT_IMPLEMENTED_BUG(bug, cond) \
+ ASSERT_IFNOT(cond, NOT_IMPLEMENTED_BUG(bug))
+
+#define NOT_IMPLEMENTED() _ASSERT_PANIC(AssertNotImplemented)
+#define NOT_IMPLEMENTED_BUG(bug) _ASSERT_PANIC_BUG(bug, AssertNotImplemented)
+
+#define NOT_REACHED() _ASSERT_PANIC(AssertNotReached)
+#define NOT_REACHED_BUG(bug) _ASSERT_PANIC_BUG(bug, AssertNotReached)
+
+#define ASSERT_MEM_ALLOC(cond) \
+ ASSERT_IFNOT(cond, _ASSERT_PANIC(AssertMemAlloc))
+
+#ifdef VMX86_DEVEL
+ #define ASSERT_LENGTH(real, expected) \
+ ASSERT_IFNOT((real) == (expected), \
+ Panic(AssertLengthFmt, __FILE__, __LINE__, real, expected))
+#else
+ #define ASSERT_LENGTH(real, expected) ASSERT((real) == (expected))
+#endif
+
+#ifdef VMX86_DEVEL
+ #define ASSERT_DEVEL(cond) ASSERT(cond)
+#else
+ #define ASSERT_DEVEL(cond) ((void) 0)
+#endif
+
+#define ASSERT_NO_INTERRUPTS() ASSERT(!INTERRUPTS_ENABLED())
+#define ASSERT_HAS_INTERRUPTS() ASSERT(INTERRUPTS_ENABLED())
+
+#define ASSERT_LOG_UNEXPECTED(bug, cond) \
+ (UNLIKELY(!(cond)) ? LOG_UNEXPECTED(bug) : 0)
+#ifdef VMX86_DEVEL
+ #define LOG_UNEXPECTED(bug) \
+ Warning(AssertUnexpectedFmt, __FILE__, __LINE__, bug)
+#else
+ #define LOG_UNEXPECTED(bug) \
+ Log(AssertUnexpectedFmt, __FILE__, __LINE__, bug)
+#endif
+
+#define ASSERT_NOT_TESTED(cond) (UNLIKELY(!(cond)) ? NOT_TESTED() : 0)
+#ifdef VMX86_DEVEL
+ #define NOT_TESTED() Warning(AssertNotTestedFmt, __FILE__, __LINE__)
+#else
+ #define NOT_TESTED() Log(AssertNotTestedFmt, __FILE__, __LINE__)
+#endif
+
+#define NOT_TESTED_ONCE() \
+ do { \
+ static Bool alreadyPrinted = FALSE; \
+ if (UNLIKELY(!alreadyPrinted)) { \
+ alreadyPrinted = TRUE; \
+ NOT_TESTED(); \
+ } \
+ } while (0)
+
+#define NOT_TESTED_1024() \
+ do { \
+ static uint16 count = 0; \
+ if (UNLIKELY(count == 0)) { NOT_TESTED(); } \
+ count = (count + 1) & 1023; \
+ } while (0)
+
+#define LOG_ONCE(_s) \
+ do { \
+ static Bool logged = FALSE; \
+ if (!logged) { \
+ Log _s; \
+ logged = TRUE; \
+ } \
+ } while (0)
+
+
+/*
+ * Redefine macros that are only in debug versions
+ */
+
+#if !defined VMX86_DEBUG && !defined ASSERT_ALWAYS_AVAILABLE // {
+
+#undef ASSERT
+#define ASSERT(cond) ((void) 0)
+
+#undef ASSERT_BUG_DEBUGONLY
+#define ASSERT_BUG_DEBUGONLY(bug, cond) ((void) 0)
+
+#undef ASSERT_LENGTH
+#define ASSERT_LENGTH(real, expected) ((void) 0)
+
+/*
+ * Expand NOT_REACHED() as appropriate for each situation.
+ *
+ * Mainly, we want the compiler to infer the same control-flow
+ * information as it would from Panic(). Otherwise, different
+ * compilation options will lead to different control-flow-derived
+ * errors, causing some make targets to fail while others succeed.
+ *
+ * VC++ has the __assume() built-in function which we don't trust
+ * (see bug 43485); gcc has no such construct; we just panic in
+ * userlevel code. The monitor doesn't want to pay the size penalty
+ * (measured at 212 bytes for the release vmm for a minimal infinite
+ * loop; panic would cost even more) so it does without and lives
+ * with the inconsistency.
+ */
+
+#ifdef VMM
+#undef NOT_REACHED
+#define NOT_REACHED() ((void) 0)
+#else
+// keep debug definition
+#endif
+
+#undef ASSERT_LOG_UNEXPECTED
+#define ASSERT_LOG_UNEXPECTED(bug, cond) ((void) 0)
+
+#undef LOG_UNEXPECTED
+#define LOG_UNEXPECTED(bug) ((void) 0)
+
+#undef ASSERT_NOT_TESTED
+#define ASSERT_NOT_TESTED(cond) ((void) 0)
+#undef NOT_TESTED
+#define NOT_TESTED() ((void) 0)
+#undef NOT_TESTED_ONCE
+#define NOT_TESTED_ONCE() ((void) 0)
+#undef NOT_TESTED_1024
+#define NOT_TESTED_1024() ((void) 0)
+
+#endif // !VMX86_DEBUG }
+
+
+/*
+ * Compile-time assertions.
+ *
+ * ASSERT_ON_COMPILE does not use the common
+ * switch (0) { case 0: case (e): ; } trick because some compilers (e.g. MSVC)
+ * generate code for it.
+ *
+ * The implementation uses both enum and typedef because the typedef alone is
+ * insufficient; gcc allows arrays to be declared with non-constant expressions
+ * (even in typedefs, where it makes no sense).
+ */
+
+#define ASSERT_ON_COMPILE(e) \
+ do { \
+ enum { AssertOnCompileMisused = ((e) ? 1 : -1) }; \
+ typedef char AssertOnCompileFailed[AssertOnCompileMisused]; \
+ } while (0)
+
+
+/*
+ * To put an ASSERT_ON_COMPILE() outside a function, wrap it
+ * in MY_ASSERTS(). The first parameter must be unique in
+ * each .c file where it appears. For example,
+ *
+ * MY_ASSERTS(FS3_INT,
+ * ASSERT_ON_COMPILE(sizeof(FS3_DiskLock) == 128);
+ * ASSERT_ON_COMPILE(sizeof(FS3_DiskLockReserved) == DISK_BLOCK_SIZE);
+ * ASSERT_ON_COMPILE(sizeof(FS3_DiskBlock) == DISK_BLOCK_SIZE);
+ * ASSERT_ON_COMPILE(sizeof(Hardware_DMIUUID) == 16);
+ * )
+ *
+ * Caution: ASSERT() within MY_ASSERTS() is silently ignored.
+ * The same goes for anything else not evaluated at compile time.
+ */
+
+#define MY_ASSERTS(name, assertions) \
+ static INLINE void name(void) { \
+ assertions \
+ }
+
+
+/*
+ * Internal macros, functions, and strings
+ *
+ * The monitor wants to save space at call sites, so it has specialized
+ * functions for each situation. User level wants to save on implementation
+ * so it uses generic functions.
+ */
+
+#if !defined VMM || defined MONITOR_APP // {
+
+#define _ASSERT_PANIC(name) \
+ Panic(_##name##Fmt "\n", __FILE__, __LINE__)
+#define _ASSERT_PANIC_BUG(bug, name) \
+ Panic(_##name##Fmt " bugNr=%d\n", __FILE__, __LINE__, bug)
+
+#define AssertLengthFmt _AssertLengthFmt
+#define AssertUnexpectedFmt _AssertUnexpectedFmt
+#define AssertNotTestedFmt _AssertNotTestedFmt
+
+#endif // }
+
+// these don't have newline so a bug can be tacked on
+#define _AssertPanicFmt "PANIC %s:%d"
+#define _AssertAssertFmt "ASSERT %s:%d"
+#define _AssertNotImplementedFmt "NOT_IMPLEMENTED %s:%d"
+#define _AssertNotReachedFmt "NOT_REACHED %s:%d"
+#define _AssertMemAllocFmt "MEM_ALLOC %s:%d"
+
+// these are complete formats with newline
+#define _AssertLengthFmt "LENGTH %s:%d r=%#x e=%#x\n"
+#define _AssertUnexpectedFmt "UNEXPECTED %s:%d bugNr=%d\n"
+#define _AssertNotTestedFmt "NOT_TESTED %s:%d\n"
+
+#endif /* ifndef _VM_ASSERT_H_ */
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2003 VMware, Inc. 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 version 2 and no 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. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ *********************************************************/
+
+/*
+ * vm_basic_defs.h --
+ *
+ * Standard macros for VMware source code.
+ */
+
+#ifndef _VM_BASIC_DEFS_H_
+#define _VM_BASIC_DEFS_H_
+
+#define INCLUDE_ALLOW_USERLEVEL
+#define INCLUDE_ALLOW_VMMEXT
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_VMMON
+#define INCLUDE_ALLOW_VMNIXMOD
+#define INCLUDE_ALLOW_VMKERNEL
+#define INCLUDE_ALLOW_VMKDRIVERS
+#define INCLUDE_ALLOW_VMK_MODULE
+#define INCLUDE_ALLOW_DISTRIBUTE
+#define INCLUDE_ALLOW_VMCORE
+#define INCLUDE_ALLOW_VMIROM
+#include "includeCheck.h"
+#include "vm_basic_types.h" // For INLINE.
+
+/* Checks for FreeBSD, filtering out VMKERNEL. */
+#define __IS_FREEBSD__ (!defined(VMKERNEL) && defined(__FreeBSD__))
+#define __IS_FREEBSD_VER__(ver) (__IS_FREEBSD__ && __FreeBSD_version >= (ver))
+
+#if defined _WIN32 && defined USERLEVEL
+ #include <stddef.h> /*
+ * We re-define offsetof macro from stddef, make
+ * sure that its already defined before we do it
+ */
+ #include <windows.h> // for Sleep() and LOWORD() etc.
+#endif
+
+
+/*
+ * Simple macros
+ */
+
+#if (defined __APPLE__ || defined __FreeBSD__) && \
+ (!defined KERNEL && !defined _KERNEL && !defined VMKERNEL && !defined __KERNEL__)
+# include <stddef.h>
+#else
+// XXX the __cplusplus one matches that of VC++, to prevent redefinition warning
+// XXX the other one matches that of gcc3.3.3/glibc2.2.4 to prevent redefinition warnings
+#ifndef offsetof
+#ifdef __cplusplus
+#define offsetof(s,m) (size_t)&(((s *)0)->m)
+#else
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+#endif
+#endif // __APPLE__
+
+#ifndef ARRAYSIZE
+#define ARRAYSIZE(a) (sizeof (a) / sizeof *(a))
+#endif
+
+#ifndef MIN
+#define MIN(_a, _b) (((_a) < (_b)) ? (_a) : (_b))
+#endif
+
+/* The Solaris 9 cross-compiler complains about these not being used */
+#ifndef sun
+static INLINE int
+Min(int a, int b)
+{
+ return a < b ? a : b;
+}
+#endif
+
+#ifndef MAX
+#define MAX(_a, _b) (((_a) > (_b)) ? (_a) : (_b))
+#endif
+
+#ifndef sun
+static INLINE int
+Max(int a, int b)
+{
+ return a > b ? a : b;
+}
+#endif
+
+#define ROUNDUP(x,y) (((x) + (y) - 1) / (y) * (y))
+#define ROUNDDOWN(x,y) ((x) / (y) * (y))
+#define ROUNDUPBITS(x, bits) (((uintptr_t) (x) + MASK(bits)) & ~MASK(bits))
+#define ROUNDDOWNBITS(x, bits) ((uintptr_t) (x) & ~MASK(bits))
+#define CEILING(x, y) (((x) + (y) - 1) / (y))
+#if defined __APPLE__
+#include <machine/param.h>
+#undef MASK
+#endif
+#define MASK(n) ((1 << (n)) - 1) /* make an n-bit mask */
+#define DWORD_ALIGN(x) ((((x)+3) >> 2) << 2)
+#define QWORD_ALIGN(x) ((((x)+4) >> 3) << 3)
+
+#define IMPLIES(a,b) (!(a) || (b))
+
+/*
+ * Not everybody (e.g., the monitor) has NULL
+ */
+
+#ifndef NULL
+#ifdef __cplusplus
+#define NULL 0
+#else
+#define NULL ((void *)0)
+#endif
+#endif
+
+
+/*
+ * Token concatenation
+ *
+ * The C preprocessor doesn't prescan arguments when they are
+ * concatenated or stringified. So we need extra levels of
+ * indirection to convince the preprocessor to expand its
+ * arguments.
+ */
+
+#define CONC(x, y) x##y
+#define XCONC(x, y) CONC(x, y)
+#define XXCONC(x, y) XCONC(x, y)
+#define MAKESTR(x) #x
+#define XSTR(x) MAKESTR(x)
+
+
+/*
+ * Page operations
+ *
+ * It has been suggested that these definitions belong elsewhere
+ * (like x86types.h). However, I deem them common enough
+ * (since even regular user-level programs may want to do
+ * page-based memory manipulation) to be here.
+ * -- edward
+ */
+
+#ifndef PAGE_SHIFT // {
+#if defined VM_I386
+ #define PAGE_SHIFT 12
+#elif defined __APPLE__
+ #define PAGE_SHIFT 12
+#else
+ #error
+#endif
+#endif // }
+
+#ifndef PAGE_SIZE
+#define PAGE_SIZE (1<<PAGE_SHIFT)
+#endif
+
+#ifndef PAGE_MASK
+#define PAGE_MASK (PAGE_SIZE - 1)
+#endif
+
+#ifndef PAGE_OFFSET
+#define PAGE_OFFSET(_addr) ((uintptr_t)(_addr)&(PAGE_SIZE-1))
+#endif
+
+#ifndef VM_PAGE_BASE
+#define VM_PAGE_BASE(_addr) ((_addr)&~(PAGE_SIZE-1))
+#endif
+
+#ifndef VM_PAGES_SPANNED
+#define VM_PAGES_SPANNED(_addr, _size) \
+ ((((_addr) & (PAGE_SIZE - 1)) + (_size) + (PAGE_SIZE - 1)) >> PAGE_SHIFT)
+#endif
+
+#ifndef BYTES_2_PAGES
+#define BYTES_2_PAGES(_nbytes) ((_nbytes) >> PAGE_SHIFT)
+#endif
+
+#ifndef PAGES_2_BYTES
+#define PAGES_2_BYTES(_npages) (((uint64)(_npages)) << PAGE_SHIFT)
+#endif
+
+#ifndef MBYTES_2_PAGES
+#define MBYTES_2_PAGES(_nbytes) ((_nbytes) << (20 - PAGE_SHIFT))
+#endif
+
+#ifndef PAGES_2_MBYTES
+#define PAGES_2_MBYTES(_npages) ((_npages) >> (20 - PAGE_SHIFT))
+#endif
+
+#ifndef VM_PAE_LARGE_PAGE_SHIFT
+#define VM_PAE_LARGE_PAGE_SHIFT 21
+#endif
+
+#ifndef VM_PAE_LARGE_PAGE_SIZE
+#define VM_PAE_LARGE_PAGE_SIZE (1 << VM_PAE_LARGE_PAGE_SHIFT)
+#endif
+
+#ifndef VM_PAE_LARGE_PAGE_MASK
+#define VM_PAE_LARGE_PAGE_MASK (VM_PAE_LARGE_PAGE_SIZE - 1)
+#endif
+
+#ifndef VM_PAE_LARGE_2_SMALL_PAGES
+#define VM_PAE_LARGE_2_SMALL_PAGES (BYTES_2_PAGES(VM_PAE_LARGE_PAGE_SIZE))
+#endif
+
+/*
+ * Word operations
+ */
+
+#ifndef LOWORD
+#define LOWORD(_dw) ((_dw) & 0xffff)
+#endif
+#ifndef HIWORD
+#define HIWORD(_dw) (((_dw) >> 16) & 0xffff)
+#endif
+
+#ifndef LOBYTE
+#define LOBYTE(_w) ((_w) & 0xff)
+#endif
+#ifndef HIBYTE
+#define HIBYTE(_w) (((_w) >> 8) & 0xff)
+#endif
+
+#define HIDWORD(_qw) ((uint32)((_qw) >> 32))
+#define LODWORD(_qw) ((uint32)(_qw))
+#define QWORD(_hi, _lo) ((((uint64)(_hi)) << 32) | ((uint32)(_lo)))
+
+
+/*
+ * Deposit a field _src at _pos bits from the right,
+ * with a length of _len, into the integer _target.
+ */
+
+#define DEPOSIT_BITS(_src,_pos,_len,_target) { \
+ unsigned mask = ((1 << _len) - 1); \
+ unsigned shiftedmask = ((1 << _len) - 1) << _pos; \
+ _target = (_target & ~shiftedmask) | ((_src & mask) << _pos); \
+}
+
+
+/*
+ * Get return address.
+ */
+
+#ifdef _MSC_VER
+#ifdef __cplusplus
+extern "C"
+#endif
+void *_ReturnAddress(void);
+#pragma intrinsic(_ReturnAddress)
+#define GetReturnAddress() _ReturnAddress()
+#elif __GNUC__
+#define GetReturnAddress() __builtin_return_address(0)
+#endif
+
+
+#ifdef __GNUC__
+#ifndef sun
+
+/*
+ * Get the frame pointer. We use this assembly hack instead of
+ * __builtin_frame_address() due to a bug introduced in gcc 4.1.1
+ */
+static INLINE_SINGLE_CALLER uintptr_t
+GetFrameAddr(void)
+{
+ uintptr_t bp;
+#if (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ == 0))
+ bp = (uintptr_t)__builtin_frame_address(0);
+#elif (__GNUC__ == 4 && __GNUC_MINOR__ == 1 && __GNUC_PATCHLEVEL__ <= 3)
+# if defined(VMM64) || defined(VM_X86_64)
+ __asm__ __volatile__("movq %%rbp, %0\n" : "=g" (bp));
+# else
+ __asm__ __volatile__("movl %%ebp, %0\n" : "=g" (bp));
+# endif
+#else
+ __asm__ __volatile__(
+#ifdef __linux__
+ ".print \"This newer version of GCC may or may not have the "
+ "__builtin_frame_address bug. Need to update this. "
+ "See bug 147638.\"\n"
+ ".abort"
+#else /* MacOS */
+ ".abort \"This newer version of GCC may or may not have the "
+ "__builtin_frame_address bug. Need to update this. "
+ "See bug 147638.\"\n"
+#endif
+ : "=g" (bp)
+ );
+#endif
+ return bp;
+}
+
+
+/*
+ * Returns the frame pointer of the calling function.
+ * Equivalent to __builtin_frame_address(1).
+ */
+static INLINE_SINGLE_CALLER uintptr_t
+GetCallerFrameAddr(void)
+{
+ return *(uintptr_t*)GetFrameAddr();
+}
+
+#endif // sun
+#endif // __GNUC__
+
+/*
+ * Data prefetch was added in gcc 3.1.1
+ * http://www.gnu.org/software/gcc/gcc-3.1/changes.html
+ */
+#ifdef __GNUC__
+# if ((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ > 1) || \
+ (__GNUC__ == 3 && __GNUC_MINOR__ == 1 && __GNUC_PATCHLEVEL__ >= 1))
+# define PREFETCH_R(var) __builtin_prefetch((var), 0 /* read */, \
+ 3 /* high temporal locality */)
+# define PREFETCH_W(var) __builtin_prefetch((var), 1 /* write */, \
+ 3 /* high temporal locality */)
+# else
+# define PREFETCH_R(var) ((void)(var))
+# define PREFETCH_W(var) ((void)(var))
+# endif
+#endif /* __GNUC__ */
+
+
+#ifdef USERLEVEL // {
+
+/*
+ * Note this might be a problem on NT b/c while sched_yield guarantees it
+ * moves you to the end of your priority list, Sleep(0) offers no such
+ * guarantee. Bummer. --Jeremy.
+ */
+
+#if defined(N_PLAT_NLM)
+/* We do not have YIELD() as we do not need it yet... */
+#elif defined(_WIN32)
+# define YIELD() Sleep(0)
+#else
+# include <sched.h> // For sched_yield. Don't ask. --Jeremy.
+# define YIELD() sched_yield()
+#endif
+
+
+/*
+ * Standardize some Posix names on Windows.
+ */
+
+#ifdef _WIN32 // {
+
+#define snprintf _snprintf
+#define vsnprintf _vsnprintf
+#define strtok_r strtok_s
+
+typedef int uid_t;
+typedef int gid_t;
+
+static INLINE void
+sleep(unsigned int sec)
+{
+ Sleep(sec * 1000);
+}
+
+static INLINE void
+usleep(unsigned long usec)
+{
+ Sleep(CEILING(usec, 1000));
+}
+
+typedef int pid_t;
+#define F_OK 0
+#define X_OK 1
+#define W_OK 2
+#define R_OK 4
+
+#endif // }
+
+/*
+ * Macro for username comparison.
+ */
+
+#ifdef _WIN32 // {
+#define USERCMP(x,y) Str_Strcasecmp(x,y)
+#else
+#define USERCMP(x,y) strcmp(x,y)
+#endif // }
+
+
+#endif // }
+
+#ifndef va_copy
+
+#ifdef _WIN32
+
+/*
+ * Windows needs va_copy. This works for both 32 and 64-bit Windows
+ * based on inspection of how varags.h from the Visual C CRTL is
+ * implemented. (Future versions of the RTL may break this).
+ */
+
+#define va_copy(dest, src) ((dest) = (src))
+
+#elif defined(__APPLE__) && defined(KERNEL)
+
+/*
+ * MacOS kernel-mode needs va_copy. Based on inspection of stdarg.h
+ * from the MacOSX10.4u.sdk kernel framework, this should work.
+ * (Future versions of the SDK may break this).
+ */
+
+#define va_copy(dest, src) ((dest) = (src))
+
+#elif defined(__GNUC__) && (__GNUC__ < 3)
+
+/*
+ * Old versions of gcc recognize __va_copy, but not va_copy.
+ */
+
+#define va_copy(dest, src) __va_copy(dest, src)
+
+#endif // _WIN32
+
+#endif // va_copy
+
+/*
+ * This one is outside USERLEVEL because it's used by
+ * files compiled into the Windows hgfs driver or the display
+ * driver.
+ */
+
+#ifdef _WIN32
+#define PATH_MAX 256
+#ifndef strcasecmp
+#define strcasecmp(_s1,_s2) _stricmp((_s1),(_s2))
+#endif
+#ifndef strncasecmp
+#define strncasecmp(_s1,_s2,_n) _strnicmp((_s1),(_s2),(_n))
+#endif
+#endif
+
+/*
+ * Convenience macro for COMMUNITY_SOURCE
+ */
+#undef EXCLUDE_COMMUNITY_SOURCE
+#ifdef COMMUNITY_SOURCE
+ #define EXCLUDE_COMMUNITY_SOURCE(x)
+#else
+ #define EXCLUDE_COMMUNITY_SOURCE(x) x
+#endif
+
+#undef COMMUNITY_SOURCE_INTEL_SECRET
+#if !defined(COMMUNITY_SOURCE) || defined(INTEL_SOURCE)
+/*
+ * It's ok to include INTEL_SECRET source code for non-commsrc,
+ * or for drops directed at Intel.
+ */
+ #define COMMUNITY_SOURCE_INTEL_SECRET
+#endif
+
+/*
+ * Convenience macros and definitions. Can often be used instead of #ifdef.
+ */
+
+#undef DEBUG_ONLY
+#undef SL_DEBUG_ONLY
+#undef VMX86_SL_DEBUG
+#ifdef VMX86_DEBUG
+#define vmx86_debug 1
+#define DEBUG_ONLY(x) x
+/*
+ * Be very, very, very careful with SL_DEBUG. Pls ask ganesh or min before
+ * using it.
+ */
+#define VMX86_SL_DEBUG
+#define vmx86_sl_debug 1
+#define SL_DEBUG_ONLY(x) x
+#else
+#define vmx86_debug 0
+#define DEBUG_ONLY(x)
+#define vmx86_sl_debug 0
+#define SL_DEBUG_ONLY(x)
+#endif
+
+#ifdef VMX86_STATS
+#define vmx86_stats 1
+#define STATS_ONLY(x) x
+#else
+#define vmx86_stats 0
+#define STATS_ONLY(x)
+#endif
+
+#ifdef VMX86_DEVEL
+#define vmx86_devel 1
+#define DEVEL_ONLY(x) x
+#else
+#define vmx86_devel 0
+#define DEVEL_ONLY(x)
+#endif
+
+#ifdef VMX86_LOG
+#define vmx86_log 1
+#define LOG_ONLY(x) x
+#else
+#define vmx86_log 0
+#define LOG_ONLY(x)
+#endif
+
+#ifdef VMX86_VMM_SERIAL_LOGGING
+#define vmx86_vmm_serial_log 1
+#define VMM_SERIAL_LOG_ONLY(x) x
+#else
+#define vmx86_vmm_serial_log 0
+#define VMM_SERIAL_LOG_ONLY(x)
+#endif
+
+#ifdef VMX86_SERVER
+#define vmx86_server 1
+#define SERVER_ONLY(x) x
+#define HOSTED_ONLY(x)
+#else
+#define vmx86_server 0
+#define SERVER_ONLY(x)
+#define HOSTED_ONLY(x) x
+#endif
+
+#ifdef VMX86_WGS
+#define vmx86_wgs 1
+#define WGS_ONLY(x) x
+#else
+#define vmx86_wgs 0
+#define WGS_ONLY(x)
+#endif
+
+#ifdef VMKERNEL
+#define vmkernel 1
+#define VMKERNEL_ONLY(x) x
+#else
+#define vmkernel 0
+#define VMKERNEL_ONLY(x)
+#endif
+
+#ifdef _WIN32
+#define WIN32_ONLY(x) x
+#define POSIX_ONLY(x)
+#else
+#define WIN32_ONLY(x)
+#define POSIX_ONLY(x) x
+#endif
+
+#ifdef VMM
+#define VMM_ONLY(x) x
+#define USER_ONLY(x)
+#else
+#define VMM_ONLY(x)
+#define USER_ONLY(x) x
+#endif
+
+/* VMVISOR ifdef only allowed in the vmkernel */
+#ifdef VMKERNEL
+#ifdef VMVISOR
+#define vmvisor 1
+#define VMVISOR_ONLY(x) x
+#else
+#define vmvisor 0
+#define VMVISOR_ONLY(x)
+#endif
+#endif
+
+#ifdef _WIN32
+#define VMW_INVALID_HANDLE INVALID_HANDLE_VALUE
+#else
+#define VMW_INVALID_HANDLE (-1)
+#endif
+
+#ifdef _WIN32
+#define fsync(fd) _commit(fd)
+#define fileno(f) _fileno(f)
+#else
+#endif
+
+/*
+ * Debug output macros for Windows drivers (the Eng variant is for
+ * display/printer drivers only.
+ */
+#ifdef _WIN32
+#ifndef USES_OLD_WINDDK
+#if defined(VMX86_DEBUG) || defined(ASSERT_ALWAYS_AVAILABLE)
+#define WinDrvPrint(arg, ...) DbgPrint(arg, __VA_ARGS__)
+#define WinDrvEngPrint(arg, ...) EngDbgPrint(arg, __VA_ARGS__)
+#else
+#define WinDrvPrint(arg, ...)
+#define WinDrvEngPrint(arg, ...)
+#endif
+#endif
+#endif // _WIN32
+
+#endif // ifndef _VM_BASIC_DEFS_H_
--- /dev/null
+/*********************************************************
+ * Copyright (C) 1998-2008 VMware, Inc. 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 version 2 and no 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. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ *********************************************************/
+
+/*
+ *
+ * vm_basic_types.h --
+ *
+ * basic data types.
+ */
+
+
+#ifndef _VM_BASIC_TYPES_H_
+#define _VM_BASIC_TYPES_H_
+
+#define INCLUDE_ALLOW_USERLEVEL
+#define INCLUDE_ALLOW_VMMEXT
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_VMMON
+#define INCLUDE_ALLOW_VMNIXMOD
+#define INCLUDE_ALLOW_VMKERNEL
+#define INCLUDE_ALLOW_VMKDRIVERS
+#define INCLUDE_ALLOW_VMK_MODULE
+#define INCLUDE_ALLOW_DISTRIBUTE
+#define INCLUDE_ALLOW_VMCORE
+#define INCLUDE_ALLOW_VMIROM
+#include "includeCheck.h"
+
+/* STRICT ANSI means the Xserver build and X defines Bool differently. */
+#if !defined(__STRICT_ANSI__) || defined(__FreeBSD__)
+typedef char Bool;
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#define IsBool(x) (((x) & ~1) == 0)
+#define IsBool2(x, y) ((((x) | (y)) & ~1) == 0)
+
+/*
+ * Macros __i386__ and __ia64 are intrinsically defined by GCC
+ */
+#ifdef __i386__
+#define VM_I386
+#endif
+
+#ifdef _WIN64
+#define __x86_64__
+#endif
+
+#ifdef __x86_64__
+#define VM_X86_64
+#define VM_I386
+#define vm_x86_64 (1)
+#else
+#define vm_x86_64 (0)
+#endif
+
+
+
+#ifdef _WIN32
+/* safe assumption for a while */
+#define VM_I386
+#endif
+
+#ifdef _MSC_VER
+typedef unsigned __int64 uint64;
+typedef signed __int64 int64;
+
+#pragma warning (3 :4505) // unreferenced local function
+#pragma warning (disable :4018) // signed/unsigned mismatch
+#pragma warning (disable :4761) // integral size mismatch in argument; conversion supplied
+#pragma warning (disable :4305) // truncation from 'const int' to 'short'
+#pragma warning (disable :4244) // conversion from 'unsigned short' to 'unsigned char'
+#pragma warning (disable :4267) // truncation of 'size_t'
+#pragma warning (disable :4146) // unary minus operator applied to unsigned type, result still unsigned
+#pragma warning (disable :4142) // benign redefinition of type
+
+#elif __GNUC__
+/* The Xserver source compiles with -ansi -pendantic */
+#ifndef __STRICT_ANSI__
+#if defined(VM_X86_64)
+typedef unsigned long uint64;
+typedef long int64;
+#else
+typedef unsigned long long uint64;
+typedef long long int64;
+#endif
+#elif __FreeBSD__
+typedef unsigned long long uint64;
+typedef long long int64;
+#endif
+#else
+#error - Need compiler define for int64/uint64
+#endif
+
+typedef unsigned int uint32;
+typedef unsigned short uint16;
+typedef unsigned char uint8;
+
+typedef int int32;
+typedef short int16;
+typedef char int8;
+
+/*
+ * FreeBSD (for the tools build) unconditionally defines these in
+ * sys/inttypes.h so don't redefine them if this file has already
+ * been included. [greg]
+ *
+ * This applies to Solaris as well.
+ */
+
+/*
+ * Before trying to do the includes based on OS defines, see if we can use
+ * feature-based defines to get as much functionality as possible
+ */
+
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_INTTYPES_H
+#include <sys/inttypes.h>
+#endif
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#ifdef __FreeBSD__
+#include <sys/param.h> /* For __FreeBSD_version */
+#endif
+
+#if !defined(USING_AUTOCONF)
+# if defined(__FreeBSD__) || defined(sun)
+# ifdef KLD_MODULE
+# include <sys/types.h>
+# else
+# if !defined(VMKERNEL) && (__FreeBSD_version >= 500043)
+# include <inttypes.h>
+# include <sys/types.h>
+# else
+# include <sys/inttypes.h>
+# endif
+# endif
+# elif defined __APPLE__
+# if KERNEL
+# include <sys/unistd.h>
+# include <sys/types.h> /* mostly for size_t */
+# include <stdint.h>
+# else
+# include <unistd.h>
+# include <inttypes.h>
+# include <stdlib.h>
+# include <stdint.h>
+# endif
+# else
+# if !defined(__intptr_t_defined) && !defined(intptr_t)
+# define __intptr_t_defined
+# define intptr_t intptr_t
+# ifdef VM_I386
+# ifdef VM_X86_64
+typedef int64 intptr_t;
+# else
+typedef int32 intptr_t;
+# endif
+# endif
+# endif
+
+# ifndef _STDINT_H
+# ifdef VM_I386
+# ifdef VM_X86_64
+typedef uint64 uintptr_t;
+# else
+typedef uint32 uintptr_t;
+# endif
+# endif
+# endif
+# endif
+#endif
+
+
+/*
+ * Time
+ * XXX These should be cleaned up. -- edward
+ */
+
+typedef int64 VmTimeType; /* Time in microseconds */
+typedef int64 VmTimeRealClock; /* Real clock kept in microseconds */
+typedef int64 VmTimeVirtualClock; /* Virtual Clock kept in CPU cycles */
+
+/*
+ * Printf format specifiers for size_t and 64-bit number.
+ * Use them like this:
+ * printf("%"FMT64"d\n", big);
+ *
+ * FMTH is for handles/fds.
+ */
+
+#ifdef _MSC_VER
+ #define FMT64 "I64"
+ #ifdef VM_X86_64
+ #define FMTSZ "I64"
+ #define FMTPD "I64"
+ #define FMTH "I64"
+ #else
+ #define FMTSZ "I"
+ #define FMTPD "I"
+ #define FMTH "I"
+ #endif
+#elif __GNUC__
+ #define FMTH ""
+ #if defined(N_PLAT_NLM) || defined(sun) || \
+ (defined(__FreeBSD__) && (__FreeBSD__ + 0) && ((__FreeBSD__ + 0) < 5))
+ /*
+ * Why (__FreeBSD__ + 0)? See bug 141008.
+ * Yes, we really need to test both (__FreeBSD__ + 0) and
+ * ((__FreeBSD__ + 0) < 5). No, we can't remove "+ 0" from
+ * ((__FreeBSD__ + 0) < 5).
+ */
+ #ifdef VM_X86_64
+ #define FMTSZ "l"
+ #define FMTPD "l"
+ #else
+ #define FMTSZ ""
+ #define FMTPD ""
+ #endif
+ #elif defined(__linux__) \
+ || (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L) \
+ || (defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112L) \
+ || (defined(_POSIX2_VERSION) && _POSIX2_VERSION >= 200112L)
+ /* BSD/Darwin, Linux */
+ #define FMTSZ "z"
+
+ #if defined(VM_X86_64) || defined(__APPLE__)
+ #define FMTPD "l"
+ #else
+ #define FMTPD ""
+ #endif
+ #else
+ /* Systems with a pre-C99 libc */
+ #define FMTSZ "Z"
+ #ifdef VM_X86_64
+ #define FMTPD "l"
+ #else
+ #define FMTPD ""
+ #endif
+ #endif
+ #ifdef VM_X86_64
+ #define FMT64 "l"
+ #elif defined(sun) || defined(__APPLE__) || defined(__FreeBSD__)
+ #define FMT64 "ll"
+ #else
+ #define FMT64 "L"
+ #endif
+#else
+ #error - Need compiler define for FMT64 and FMTSZ
+#endif
+
+/*
+ * Suffix for 64-bit constants. Use it like this:
+ * CONST64(0x7fffffffffffffff) for signed or
+ * CONST64U(0x7fffffffffffffff) for unsigned.
+ *
+ * 2004.08.30(thutt):
+ * The vmcore/asm64/gen* programs are compiled as 32-bit
+ * applications, but must handle 64 bit constants. If the
+ * 64-bit-constant defining macros are already defined, the
+ * definition will not be overwritten.
+ */
+
+#if !defined(CONST64) || !defined(CONST64U)
+#ifdef _MSC_VER
+#define CONST64(c) c##I64
+#define CONST64U(c) c##uI64
+#elif __GNUC__
+#ifdef VM_X86_64
+#define CONST64(c) c##L
+#define CONST64U(c) c##uL
+#else
+#define CONST64(c) c##LL
+#define CONST64U(c) c##uLL
+#endif
+#else
+#error - Need compiler define for CONST64
+#endif
+#endif
+
+/*
+ * Use CONST3264/CONST3264U if you want a constant to be
+ * treated as a 32-bit number on 32-bit compiles and
+ * a 64-bit number on 64-bit compiles. Useful in the case
+ * of shifts, like (CONST3264U(1) << x), where x could be
+ * more than 31 on a 64-bit compile.
+ */
+
+#ifdef VM_X86_64
+ #define CONST3264(a) CONST64(a)
+ #define CONST3264U(a) CONST64U(a)
+#else
+ #define CONST3264(a) (a)
+ #define CONST3264U(a) (a)
+#endif
+
+#define MIN_INT32 ((int32)0x80000000)
+#define MAX_INT32 ((int32)0x7fffffff)
+
+#define MIN_UINT32 ((uint32)0)
+#define MAX_UINT32 ((uint32)0xffffffff)
+
+#define MIN_INT64 (CONST64(0x8000000000000000))
+#define MAX_INT64 (CONST64(0x7fffffffffffffff))
+
+#define MIN_UINT64 (CONST64U(0))
+#define MAX_UINT64 (CONST64U(0xffffffffffffffff))
+
+typedef uint8 *TCA; /* Pointer into TC (usually). */
+
+/*
+ * Type big enough to hold an integer between 0..100
+ */
+typedef uint8 Percent;
+#define AsPercent(v) ((Percent)(v))
+#define CHOOSE_PERCENT AsPercent(101)
+
+
+typedef uintptr_t VA;
+typedef uintptr_t VPN;
+
+typedef uint64 PA;
+typedef uint32 PPN;
+
+typedef uint64 PhysMemOff;
+typedef uint64 PhysMemSize;
+
+/* The Xserver source compiles with -ansi -pendantic */
+#ifndef __STRICT_ANSI__
+typedef uint64 BA;
+#endif
+typedef uint32 BPN;
+typedef uint32 PageNum;
+typedef unsigned MemHandle;
+typedef int32 World_ID;
+
+#define INVALID_WORLD_ID ((World_ID)-1)
+
+typedef World_ID User_CartelID;
+#define INVALID_CARTEL_ID INVALID_WORLD_ID
+
+typedef User_CartelID User_SessionID;
+#define INVALID_SESSION_ID INVALID_CARTEL_ID
+
+typedef User_CartelID User_CartelGroupID;
+#define INVALID_CARTELGROUP_ID INVALID_CARTEL_ID
+
+typedef uint32 Worldlet_ID;
+#define INVALID_WORLDLET_ID ((Worldlet_ID)-1)
+
+/* world page number */
+typedef uint32 WPN;
+
+/* The Xserver source compiles with -ansi -pendantic */
+#ifndef __STRICT_ANSI__
+typedef uint64 MA;
+typedef uint32 MPN;
+#endif
+
+/*
+ * This type should be used for variables that contain sector
+ * position/quantity.
+ */
+typedef uint64 SectorType;
+
+/*
+ * Linear address
+ */
+
+typedef uintptr_t LA;
+typedef uintptr_t LPN;
+#define LA_2_LPN(_la) ((_la) >> PAGE_SHIFT)
+#define LPN_2_LA(_lpn) ((_lpn) << PAGE_SHIFT)
+
+#define LAST_LPN ((((LA) 1) << (8 * sizeof(LA) - PAGE_SHIFT)) - 1)
+#define LAST_LPN32 ((((LA32)1) << (8 * sizeof(LA32) - PAGE_SHIFT)) - 1)
+#define LAST_LPN64 ((((LA64)1) << (8 * sizeof(LA64) - PAGE_SHIFT)) - 1)
+
+/* Valid bits in a LPN. */
+#define LPN_MASK LAST_LPN
+#define LPN_MASK32 LAST_LPN32
+#define LPN_MASK64 LAST_LPN64
+
+/*
+ * On 64 bit platform, address and page number types default
+ * to 64 bit. When we need to represent a 32 bit address, we use
+ * types defined below.
+ *
+ * On 32 bit platform, the following types are the same as the
+ * default types.
+ */
+typedef uint32 VA32;
+typedef uint32 VPN32;
+typedef uint32 LA32;
+typedef uint32 LPN32;
+typedef uint32 PA32;
+typedef uint32 PPN32;
+typedef uint32 MA32;
+typedef uint32 MPN32;
+
+/*
+ * On 64 bit platform, the following types are the same as the
+ * default types.
+ */
+typedef uint64 VA64;
+typedef uint64 VPN64;
+typedef uint64 LA64;
+typedef uint64 LPN64;
+typedef uint64 PA64;
+typedef uint64 PPN64;
+typedef uint64 MA64;
+typedef uint64 MPN64;
+
+/*
+ * VA typedefs for user world apps.
+ */
+typedef VA32 UserVA32;
+typedef VA64 UserVA64;
+typedef UserVA32 UserVAConst; /* Userspace ptr to data that we may only read. */
+typedef UserVA64 UserVA64Const; /* Used by 64-bit syscalls until conversion is finished. */
+#ifdef VMKERNEL
+typedef UserVA32 UserVA;
+#else
+typedef void * UserVA;
+#endif
+
+
+/*
+ * Maximal possible PPN value (errors too) that PhysMem can handle.
+ * Must be at least as large as MAX_PPN which is the maximum PPN
+ * for any region other than buserror.
+ */
+#define PHYSMEM_MAX_PPN ((PPN)0xffffffff)
+#define MAX_PPN ((PPN)0x1fffffff) /* Maximal observable PPN value. */
+#define INVALID_PPN ((PPN)0xffffffff)
+
+#define INVALID_BPN ((BPN) 0x1fffffff)
+
+#define INVALID_MPN ((MPN)-1)
+#define MEMREF_MPN ((MPN)-2)
+#define RESERVED_MPN ((MPN) 0)
+/* Support 43 bits of address space. */
+#define MAX_MPN ((MPN)0x7fffffff)
+
+#define INVALID_LPN ((LPN)-1)
+#define INVALID_VPN ((VPN)-1)
+#define INVALID_LPN64 ((LPN64)-1)
+#define INVALID_PAGENUM ((PageNum)-1)
+#define INVALID_WPN ((WPN) -1)
+
+
+/*
+ * Format modifier for printing VA, LA, and VPN.
+ * Use them like this: Log("%#"FMTLA"x\n", laddr)
+ */
+
+#if defined(VMM64) || defined(FROBOS64) || vm_x86_64 || defined __APPLE__
+# define FMTLA "l"
+# define FMTVA "l"
+# define FMTVPN "l"
+#else
+# define FMTLA ""
+# define FMTVA ""
+# define FMTVPN ""
+#endif
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+#define CONST const
+
+
+#ifndef INLINE
+# ifdef _MSC_VER
+# define INLINE __inline
+# else
+# define INLINE inline
+# endif
+#endif
+
+
+/*
+ * Annotation for data that may be exported into a DLL and used by other
+ * apps that load that DLL and import the data.
+ */
+#if defined(_WIN32) && defined(VMX86_IMPORT_DLLDATA)
+# define VMX86_EXTERN_DATA extern __declspec(dllimport)
+#else // !_WIN32
+# define VMX86_EXTERN_DATA extern
+#endif
+
+#if defined(_WIN32) && !defined(VMX86_NO_THREADS)
+#define THREADSPECIFIC __declspec(thread)
+#else
+#define THREADSPECIFIC
+#endif
+
+/*
+ * Due to the wonderful "registry redirection" feature introduced in
+ * 64-bit Windows, if you access any key under HKLM\Software in 64-bit
+ * code, you need to open/create/delete that key with
+ * VMKEY_WOW64_32KEY if you want a consistent view with 32-bit code.
+ */
+
+#ifdef _WIN32
+#ifdef _WIN64
+#define VMW_KEY_WOW64_32KEY KEY_WOW64_32KEY
+#else
+#define VMW_KEY_WOW64_32KEY 0x0
+#endif
+#endif
+
+
+/*
+ * Consider the following reasons functions are inlined:
+ *
+ * 1) inlined for performance reasons
+ * 2) inlined because it's a single-use function
+ *
+ * Functions which meet only condition 2 should be marked with this
+ * inline macro; It is not critical to be inlined (but there is a
+ * code-space & runtime savings by doing so), so when other callers
+ * are added the inline-ness should be removed.
+ */
+
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)
+/*
+ * Starting at version 3.3, gcc does not always inline functions marked
+ * 'inline' (it depends on their size). To force gcc to do so, one must use the
+ * extra __always_inline__ attribute.
+ */
+# define INLINE_SINGLE_CALLER INLINE __attribute__((__always_inline__))
+# if defined(VMM) \
+ && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 1))
+# warning Verify INLINE_SINGLE_CALLER '__always_inline__' attribute (did \
+ monitor size change?)
+# endif
+#else
+# define INLINE_SINGLE_CALLER INLINE
+#endif
+
+/*
+ * Used when a hard guaranteed of no inlining is needed. Very few
+ * instances need this since the absence of INLINE is a good hint
+ * that gcc will not do inlining.
+ */
+
+#if defined(__GNUC__) && defined(VMM)
+#define ABSOLUTELY_NOINLINE __attribute__((__noinline__))
+#endif
+
+/*
+ * Attributes placed on function declarations to tell the compiler
+ * that the function never returns.
+ */
+
+#ifdef _MSC_VER
+#define NORETURN __declspec(noreturn)
+#elif __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 9)
+#define NORETURN __attribute__((__noreturn__))
+#else
+#define NORETURN
+#endif
+
+/*
+ * GCC 3.2 inline asm needs the + constraint for input/ouput memory operands.
+ * Older GCCs don't know about it --hpreg
+ */
+
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 2)
+# define VM_ASM_PLUS 1
+#else
+# define VM_ASM_PLUS 0
+#endif
+
+/*
+ * Branch prediction hints:
+ * LIKELY(exp) - Expression exp is likely TRUE.
+ * UNLIKELY(exp) - Expression exp is likely FALSE.
+ * Usage example:
+ * if (LIKELY(excCode == EXC_NONE)) {
+ * or
+ * if (UNLIKELY(REAL_MODE(vc))) {
+ *
+ * We know how to predict branches on gcc3 and later (hopefully),
+ * all others we don't so we do nothing.
+ */
+
+#if (__GNUC__ >= 3)
+/*
+ * gcc3 uses __builtin_expect() to inform the compiler of an expected value.
+ * We use this to inform the static branch predictor. The '!!' in LIKELY
+ * will convert any !=0 to a 1.
+ */
+#define LIKELY(_exp) __builtin_expect(!!(_exp), 1)
+#define UNLIKELY(_exp) __builtin_expect((_exp), 0)
+#else
+#define LIKELY(_exp) (_exp)
+#define UNLIKELY(_exp) (_exp)
+#endif
+
+/*
+ * GCC's argument checking for printf-like functions
+ * This is conditional until we have replaced all `"%x", void *'
+ * with `"0x%08x", (uint32) void *'. Note that %p prints different things
+ * on different platforms. Argument checking is enabled for the
+ * vmkernel, which has already been cleansed.
+ *
+ * fmtPos is the position of the format string argument, beginning at 1
+ * varPos is the position of the variable argument, beginning at 1
+ */
+
+#if defined(__GNUC__)
+# define PRINTF_DECL(fmtPos, varPos) __attribute__((__format__(__printf__, fmtPos, varPos)))
+#else
+# define PRINTF_DECL(fmtPos, varPos)
+#endif
+
+#if defined(__GNUC__)
+# define SCANF_DECL(fmtPos, varPos) __attribute__((__format__(__scanf__, fmtPos, varPos)))
+#else
+# define SCANF_DECL(fmtPos, varPos)
+#endif
+
+/*
+ * UNUSED_PARAM should surround the parameter name and type declaration,
+ * e.g. "int MyFunction(int var1, UNUSED_PARAM(int var2))"
+ *
+ */
+
+#ifndef UNUSED_PARAM
+# if defined(__GNUC__)
+# define UNUSED_PARAM(_parm) _parm __attribute__((__unused__))
+# else
+# define UNUSED_PARAM(_parm) _parm
+# endif
+#endif
+
+/*
+ * REGPARM defaults to REGPARM3, i.e., a requent that gcc
+ * puts the first three arguments in registers. (It is fine
+ * if the function has fewer than three args.) Gcc only.
+ * Syntactically, put REGPARM where you'd put INLINE or NORETURN.
+ */
+
+#if defined(__GNUC__)
+# define REGPARM0 __attribute__((regparm(0)))
+# define REGPARM1 __attribute__((regparm(1)))
+# define REGPARM2 __attribute__((regparm(2)))
+# define REGPARM3 __attribute__((regparm(3)))
+# define REGPARM REGPARM3
+#else
+# define REGPARM0
+# define REGPARM1
+# define REGPARM2
+# define REGPARM3
+# define REGPARM
+#endif
+
+/*
+ * ALIGNED specifies minimum alignment in "n" bytes.
+ */
+
+#ifdef __GNUC__
+#define ALIGNED(n) __attribute__((__aligned__(n)))
+#else
+#define ALIGNED(n)
+#endif
+
+/*
+ ***********************************************************************
+ * STRUCT_OFFSET_CHECK -- */ /**
+ *
+ * \brief Check if the actual offsef of a member in a structure
+ * is what is expected
+ *
+ *
+ * \param[in] STRUCT Structure the member is a part of.
+ * \param[in] MEMBER Member to check the offset of.
+ * \param[in] OFFSET Expected offset of MEMBER in STRUCTURE.
+ * \param[in] DEBUG_EXTRA Additional bytes to be added to OFFSET to
+ * compensate for extra info in debug builds.
+ *
+ ***********************************************************************
+ */
+#ifdef VMX86_DEBUG
+#define STRUCT_OFFSET_CHECK(STRUCT, MEMBER, OFFSET, DEBUG_EXTRA) \
+ ASSERT_ON_COMPILE(vmk_offsetof(STRUCT, MEMBER) == (OFFSET + DEBUG_EXTRA))
+#else
+#define STRUCT_OFFSET_CHECK(STRUCT, MEMBER, OFFSET, DEBUG_EXTRA) \
+ ASSERT_ON_COMPILE(vmk_offsetof(STRUCT, MEMBER) == OFFSET)
+#endif
+
+/*
+ ***********************************************************************
+ * STRUCT_SIZE_CHECK -- */ /**
+ *
+ * \brief Check if the actual size of a structure is what is expected
+ *
+ *
+ * \param[in] STRUCT Structure whose size is to be checked.
+ * \param[in] SIZE Expected size of STRUCT.
+ * \param[in] DEBUG_EXTRA Additional bytes to be added to SIZE to
+ * compensate for extra info in debug builds.
+ *
+ ***********************************************************************
+ */
+#ifdef VMX86_DEBUG
+#define STRUCT_SIZE_CHECK(STRUCT, SIZE, DEBUG_EXTRA) \
+ ASSERT_ON_COMPILE(sizeof(STRUCT) == (SIZE + DEBUG_EXTRA))
+#else
+#define STRUCT_SIZE_CHECK(STRUCT, SIZE, DEBUG_EXTRA) \
+ ASSERT_ON_COMPILE(sizeof(STRUCT) == SIZE)
+#endif
+
+/*
+ * __func__ is a stringified function name that is part of the C99 standard. The block
+ * below defines __func__ on older systems where the compiler does not support that
+ * macro.
+ */
+#if defined(__GNUC__) \
+ && ((__GNUC__ == 2 && __GNUC_MINOR < 96) \
+ || (__GNUC__ < 2))
+# define __func__ __FUNCTION__
+#endif
+
+/*
+ * Once upon a time, this was used to silence compiler warnings that
+ * get generated when the compiler thinks that a function returns
+ * when it is marked noreturn. Don't do it. Use NOT_REACHED().
+ */
+
+#define INFINITE_LOOP() do { } while (1)
+
+/*
+ * On FreeBSD (for the tools build), size_t is typedef'd if _BSD_SIZE_T_
+ * is defined. Use the same logic here so we don't define it twice. [greg]
+ */
+#ifdef __FreeBSD__
+# ifdef _BSD_SIZE_T_
+# undef _BSD_SIZE_T_
+# ifdef VM_I386
+# ifdef VM_X86_64
+ typedef uint64 size_t;
+# else
+ typedef uint32 size_t;
+# endif
+# endif /* VM_I386 */
+# endif
+
+# ifdef _BSD_SSIZE_T_
+# undef _BSD_SSIZE_T_
+# define _SSIZE_T
+# define __ssize_t_defined
+# define _SSIZE_T_DECLARED
+# ifdef VM_I386
+# ifdef VM_X86_64
+ typedef int64 ssize_t;
+# else
+ typedef int32 ssize_t;
+# endif
+# endif /* VM_I386 */
+# endif
+
+#else
+# ifndef _SIZE_T
+# define _SIZE_T
+# ifdef VM_I386
+# ifdef VM_X86_64
+ typedef uint64 size_t;
+# else
+ typedef uint32 size_t;
+# endif
+# endif /* VM_I386 */
+# endif
+
+# if !defined(FROBOS) && !defined(_SSIZE_T) && !defined(ssize_t) && \
+ !defined(__ssize_t_defined) && !defined(_SSIZE_T_DECLARED)
+# define _SSIZE_T
+# define __ssize_t_defined
+# define _SSIZE_T_DECLARED
+# ifdef VM_I386
+# ifdef VM_X86_64
+ typedef int64 ssize_t;
+# else
+ typedef int32 ssize_t;
+# endif
+# endif /* VM_I386 */
+# endif
+
+#endif
+
+/*
+ * Format modifier for printing pid_t. On sun the pid_t is a ulong, but on
+ * Linux it's an int.
+ * Use this like this: printf("The pid is %"FMTPID".\n", pid);
+ */
+#ifdef sun
+# ifdef VM_X86_64
+# define FMTPID "d"
+# else
+# define FMTPID "lu"
+# endif
+#else
+# define FMTPID "d"
+#endif
+
+/*
+ * Format modifier for printing uid_t. On sun the uid_t is a ulong, but on
+ * Linux it's an int.
+ * Use this like this: printf("The uid is %"FMTUID".\n", uid);
+ */
+#ifdef sun
+# ifdef VM_X86_64
+# define FMTUID "u"
+# else
+# define FMTUID "lu"
+# endif
+#else
+# define FMTUID "u"
+#endif
+
+/*
+ * Format modifier for printing mode_t. On sun the mode_t is a ulong, but on
+ * Linux it's an int.
+ * Use this like this: printf("The mode is %"FMTMODE".\n", mode);
+ */
+#ifdef sun
+# ifdef VM_X86_64
+# define FMTMODE "o"
+# else
+# define FMTMODE "lo"
+# endif
+#else
+# define FMTMODE "o"
+#endif
+
+/*
+ * Format modifier for printing time_t. Most platforms define a time_t to be
+ * a long int, but on FreeBSD (as of 5.0, it seems), the time_t is a signed
+ * size quantity. Refer to the definition of FMTSZ to see why we need silly
+ * preprocessor arithmetic.
+ * Use this like this: printf("The mode is %"FMTTIME".\n", time);
+ */
+#if defined(__FreeBSD__) && (__FreeBSD__ + 0) && ((__FreeBSD__ + 0) >= 5)
+# define FMTTIME FMTSZ"d"
+#else
+# define FMTTIME "ld"
+#endif
+
+/*
+ * Define MXSemaHandle here so both vmmon and vmx see this definition.
+ */
+
+#ifdef _WIN32
+typedef uintptr_t MXSemaHandle;
+#else
+typedef int MXSemaHandle;
+#endif
+
+/*
+ * Define type for poll device handles.
+ */
+
+#ifdef _WIN32
+typedef uintptr_t PollDevHandle;
+#else
+typedef int PollDevHandle;
+#endif
+
+/*
+ * Define the utf16_t type.
+ */
+
+#if defined(_WIN32) && defined(_NATIVE_WCHAR_T_DEFINED)
+typedef wchar_t utf16_t;
+#else
+typedef uint16 utf16_t;
+#endif
+
+#endif /* _VM_BASIC_TYPES_H_ */
--- /dev/null
+/*********************************************************
+ * Copyright (C) 1998 VMware, Inc. 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 version 2 and no 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. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ *********************************************************/
+
+#ifndef VM_DEVICE_VERSION_H
+#define VM_DEVICE_VERSION_H
+
+#define INCLUDE_ALLOW_USERLEVEL
+#define INCLUDE_ALLOW_VMMEXT
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_VMKERNEL
+#define INCLUDE_ALLOW_VMCORE
+#include "includeCheck.h"
+
+#ifdef _WIN32
+#include "guiddef.h"
+#endif
+
+/* Our own PCI IDs
+ * VMware SVGA II (Unified VGA)
+ * VMware SVGA (PCI Accelerator)
+ * VMware vmxnet (Idealized NIC)
+ * VMware vmxscsi (Abortive idealized SCSI controller)
+ * VMware chipset (Subsystem ID for our motherboards)
+ * VMware e1000 (Subsystem ID)
+ * VMware vmxnet3 (Uniform Pass Through NIC)
+ */
+#define PCI_VENDOR_ID_VMWARE 0x15AD
+#define PCI_DEVICE_ID_VMWARE_SVGA2 0x0405
+#define PCI_DEVICE_ID_VMWARE_SVGA 0x0710
+#define PCI_DEVICE_ID_VMWARE_NET 0x0720
+#define PCI_DEVICE_ID_VMWARE_SCSI 0x0730
+#define PCI_DEVICE_ID_VMWARE_VMCI 0x0740
+#define PCI_DEVICE_ID_VMWARE_CHIPSET 0x1976
+#define PCI_DEVICE_ID_VMWARE_82545EM 0x0750 /* single port */
+#define PCI_DEVICE_ID_VMWARE_82546EB 0x0760 /* dual port */
+#define PCI_DEVICE_ID_VMWARE_EHCI 0x0770
+#define PCI_DEVICE_ID_VMWARE_1394 0x0780
+#define PCI_DEVICE_ID_VMWARE_BRIDGE 0x0790
+#define PCI_DEVICE_ID_VMWARE_ROOTPORT 0x07A0
+#define PCI_DEVICE_ID_VMWARE_VMXNET3 0x07B0
+#define PCI_DEVICE_ID_VMWARE_PVSCSI 0x07C0
+
+/* The hypervisor device might grow. Please leave room
+ * for 7 more subfunctions.
+ */
+#define PCI_DEVICE_ID_VMWARE_HYPER 0x0800
+#define PCI_DEVICE_ID_VMWARE_VMI 0x0801
+
+#define PCI_DEVICE_VMI_CLASS 0x05
+#define PCI_DEVICE_VMI_SUBCLASS 0x80
+#define PCI_DEVICE_VMI_INTERFACE 0x00
+#define PCI_DEVICE_VMI_REVISION 0x01
+
+/* From linux/pci_ids.h:
+ * AMD Lance Ethernet controller
+ * BusLogic SCSI controller
+ * Ensoniq ES1371 sound controller
+ */
+#define PCI_VENDOR_ID_AMD 0x1022
+#define PCI_DEVICE_ID_AMD_VLANCE 0x2000
+#define PCI_VENDOR_ID_BUSLOGIC 0x104B
+#define PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC 0x0140
+#define PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER 0x1040
+#define PCI_VENDOR_ID_ENSONIQ 0x1274
+#define PCI_DEVICE_ID_ENSONIQ_ES1371 0x1371
+
+/* From linux/pci_ids.h:
+ * Intel 82439TX (430 HX North Bridge)
+ * Intel 82371AB (PIIX4 South Bridge)
+ * Intel 82443BX (440 BX North Bridge and AGP Bridge)
+ * Intel 82545EM (e1000, server adapter, single port)
+ * Intel 82546EB (e1000, server adapter, dual port)
+ * Intel ICH7_16 (Hight Definition Audio controller)
+ */
+#define PCI_VENDOR_ID_INTEL 0x8086
+#define PCI_DEVICE_ID_INTEL_82439TX 0x7100
+#define PCI_DEVICE_ID_INTEL_82371AB_0 0x7110
+#define PCI_DEVICE_ID_INTEL_82371AB_2 0x7112
+#define PCI_DEVICE_ID_INTEL_82371AB_3 0x7113
+#define PCI_DEVICE_ID_INTEL_82371AB 0x7111
+#define PCI_DEVICE_ID_INTEL_82443BX 0x7190
+#define PCI_DEVICE_ID_INTEL_82443BX_1 0x7191
+#define PCI_DEVICE_ID_INTEL_82443BX_2 0x7192 /* Used when no AGP support */
+#define PCI_DEVICE_ID_INTEL_82545EM 0x100f
+#define PCI_DEVICE_ID_INTEL_82546EB 0x1010
+#define PCI_DEVICE_ID_INTEL_ICH7_16 0x27d8
+
+
+/************* Strings for IDE Identity Fields **************************/
+#define VIDE_ID_SERIAL_STR "00000000000000000001" /* Must be 20 Bytes */
+#define VIDE_ID_FIRMWARE_STR "00000001" /* Must be 8 Bytes */
+
+/* No longer than 40 Bytes */
+#define VIDE_ATA_MODEL_STR PRODUCT_GENERIC_NAME " Virtual IDE Hard Drive"
+#define VIDE_ATAPI_MODEL_STR PRODUCT_GENERIC_NAME " Virtual IDE CDROM Drive"
+
+#define ATAPI_VENDOR_ID "NECVMWar" /* Must be 8 Bytes */
+#define ATAPI_PRODUCT_ID PRODUCT_GENERIC_NAME " IDE CDROM" /* Must be 16 Bytes */
+#define ATAPI_REV_LEVEL "1.00" /* Must be 4 Bytes */
+
+#define IDE_NUM_INTERFACES 2 /* support for two interfaces */
+#define IDE_DRIVES_PER_IF 2
+
+/************* Strings for SCSI Identity Fields **************************/
+#define SCSI_DISK_MODEL_STR PRODUCT_GENERIC_NAME " Virtual SCSI Hard Drive"
+#define SCSI_DISK_VENDOR_NAME COMPANY_NAME
+#define SCSI_DISK_REV_LEVEL "1.0"
+#define SCSI_CDROM_MODEL_STR PRODUCT_GENERIC_NAME " Virtual SCSI CDROM Drive"
+#define SCSI_CDROM_VENDOR_NAME COMPANY_NAME
+#define SCSI_CDROM_REV_LEVEL "1.0"
+
+/************* SCSI implementation limits ********************************/
+#define SCSI_MAX_CONTROLLERS 4 // Need more than 1 for MSCS clustering
+#define SCSI_MAX_DEVICES 16 // BT-958 emulates only 16
+#define SCSI_IDE_CHANNEL SCSI_MAX_CONTROLLERS
+#define SCSI_IDE_HOSTED_CHANNEL (SCSI_MAX_CONTROLLERS + 1)
+#define SCSI_MAX_CHANNELS (SCSI_MAX_CONTROLLERS + 2)
+
+/************* Strings for the VESA BIOS Identity Fields *****************/
+#define VBE_OEM_STRING COMPANY_NAME " SVGA"
+#define VBE_VENDOR_NAME COMPANY_NAME
+#define VBE_PRODUCT_NAME PRODUCT_GENERIC_NAME
+
+/************* PCI implementation limits ********************************/
+#define PCI_MAX_BRIDGES 15
+
+/************* Ethernet implementation limits ***************************/
+#define MAX_ETHERNET_CARDS 10
+
+/************* PCI Passthrough implementation limits ********************/
+#define MAX_PCI_PASSTHRU_DEVICES 2
+
+/************* USB implementation limits ********************************/
+#define MAX_USB_DEVICES_PER_HOST_CONTROLLER 127
+
+/************* Strings for Host USB Driver *******************************/
+
+#ifdef _WIN32
+
+/*
+ * Globally unique ID for the VMware device interface. Define INITGUID before including
+ * this header file to instantiate the variable.
+ */
+DEFINE_GUID(GUID_DEVICE_INTERFACE_VMWARE_USB_DEVICES,
+0x2da1fe75, 0xaab3, 0x4d2c, 0xac, 0xdf, 0x39, 0x8, 0x8c, 0xad, 0xa6, 0x65);
+
+/*
+ * Globally unique ID for the VMware device setup class.
+ */
+DEFINE_GUID(GUID_CLASS_VMWARE_USB_DEVICES,
+0x3b3e62a5, 0x3556, 0x4d7e, 0xad, 0xad, 0xf5, 0xfa, 0x3a, 0x71, 0x2b, 0x56);
+
+/*
+ * This string defines the device ID string of a VMware USB device.
+ * The format is USB\Vid_XXXX&Pid_YYYY, where XXXX and YYYY are the
+ * hexadecimal representations of the vendor and product ids, respectively.
+ *
+ * The official vendor ID for VMware, Inc. is 0x0E0F.
+ * The product id for USB generic devices is 0x0001.
+ */
+#define USB_VMWARE_DEVICE_ID_WIDE L"USB\\Vid_0E0F&Pid_0001"
+#define USB_DEVICE_ID_LENGTH (sizeof(USB_VMWARE_DEVICE_ID_WIDE) / sizeof(WCHAR))
+
+#ifdef UNICODE
+#define USB_PNP_SETUP_CLASS_NAME L"VMwareUSBDevices"
+#define USB_PNP_DRIVER_NAME L"vmusb"
+#else
+#define USB_PNP_SETUP_CLASS_NAME "VMwareUSBDevices"
+#define USB_PNP_DRIVER_NAME "vmusb"
+#endif
+#endif
+
+#endif /* VM_DEVICE_VERSION_H */
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2002 VMware, Inc. 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 version 2 and no 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. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ *********************************************************/
+
+/*
+ * vmware_pack_begin.h --
+ *
+ * Begin of structure packing. See vmware_pack_init.h for details.
+ *
+ * Note that we do not use the following construct in this include file,
+ * because we want to emit the code every time the file is included --hpreg
+ *
+ * #ifndef foo
+ * # define foo
+ * ...
+ * #endif
+ *
+ */
+
+
+#include "vmware_pack_init.h"
+
+
+#ifdef _MSC_VER
+# pragma pack(push, 1)
+#elif __GNUC__
+#else
+# error Compiler packing...
+#endif
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2002 VMware, Inc. 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 version 2 and no 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. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ *********************************************************/
+
+/*
+ * vmware_pack_end.h --
+ *
+ * End of structure packing. See vmware_pack_init.h for details.
+ *
+ * Note that we do not use the following construct in this include file,
+ * because we want to emit the code every time the file is included --hpreg
+ *
+ * #ifndef foo
+ * # define foo
+ * ...
+ * #endif
+ *
+ */
+
+
+#include "vmware_pack_init.h"
+
+
+#ifdef _MSC_VER
+# pragma pack(pop)
+#elif __GNUC__
+__attribute__((__packed__))
+#else
+# error Compiler packing...
+#endif
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2002 VMware, Inc. 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 version 2 and no 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. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ *********************************************************/
+
+#ifndef __VMWARE_PACK_INIT_H__
+# define __VMWARE_PACK_INIT_H__
+
+
+/*
+ * vmware_pack_init.h --
+ *
+ * Platform-independent code to make the compiler pack (i.e. have them
+ * occupy the smallest possible space) structure definitions. The following
+ * constructs are known to work --hpreg
+ *
+ * #include "vmware_pack_begin.h"
+ * struct foo {
+ * ...
+ * }
+ * #include "vmware_pack_end.h"
+ * ;
+ *
+ * typedef
+ * #include "vmware_pack_begin.h"
+ * struct foo {
+ * ...
+ * }
+ * #include "vmware_pack_end.h"
+ * foo;
+ */
+
+
+#ifdef _MSC_VER
+/*
+ * MSVC 6.0 emits warning 4103 when the pack push and pop pragma pairing is
+ * not balanced within 1 included file. That is annoying because our scheme
+ * is based on the pairing being balanced between 2 included files.
+ *
+ * So we disable this warning, but this is safe because the compiler will also
+ * emit warning 4161 when there is more pops than pushes within 1 main
+ * file --hpreg
+ */
+
+# pragma warning(disable:4103)
+#elif __GNUC__
+#else
+# error Compiler packing...
+#endif
+
+
+#endif /* __VMWARE_PACK_INIT_H__ */
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. 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 version 2 and no 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. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ *********************************************************/
+
+/*
+ * hgfsEscape.c --
+ *
+ * Escape and unescape illegal filenames for different platforms.
+ *
+ */
+
+#ifdef __KERNEL__
+# include "driver-config.h"
+# include <linux/string.h>
+#elif defined(__FreeBSD__)
+# if defined(_KERNEL)
+# include <sys/libkern.h>
+# define strchr(s,c) index(s,c)
+# else
+# include <string.h>
+# endif
+# define memmove(s1,s2,n) bcopy(s2,s1,n)
+#elif defined(__APPLE__) && defined(KERNEL)
+# include <string.h>
+#elif !defined(sun)
+# include <stdlib.h>
+# include <string.h>
+#else
+# include <string.h>
+#endif
+
+#include "vmware.h"
+#include "hgfsEscape.h"
+#include "cpName.h"
+
+#ifdef _WIN32
+
+#define UNREFERENCED_PARAMETER(P) (P)
+
+/* These characters are illegal in Windows file names. */
+const char* HGFS_ILLEGAL_CHARS = "/\\*?:\"<>|";
+const char* HGFS_SUBSTITUTE_CHARS = "!@#$^&(){}";
+/* Last character of a file name in Windows can be neither dot nor space. */
+const char* HGFS_ILLEGAL_LAST_CHARS = ". ";
+
+/* http://msdn.microsoft.com/en-us/library/aa365247.aspx */
+char *HgfsReservedNames[] = {"CON", "PRN", "AUX", "NUL"};
+char *HgfsReservedNamesWithNumber[] = {"COM", "LPT"};
+
+#define HGFS_RESERVED_NAME_CHARS_LENGTH 3
+#define HGFS_RESERVED_NAME_WITH_NUMBER_CHARS_LENGTH (HGFS_RESERVED_NAME_CHARS_LENGTH + 1)
+/* Check for special escaping cases - reserved names and illegal last characters. */
+#define IS_SPECIAL_CASE_ESCAPE(b,o,l) HgfsIsSpecialCaseEscape(b,o,l)
+/* Process Windows reserved names. */
+#define PROCESS_RESERVED_NAME(b,s,p,o,c) \
+if (!HgfsProcessReservedName(b,s,p,o,c)) \
+{ \
+ return FALSE; \
+}
+/* Process Windows reserved names. */
+#define PROCESS_LAST_CHARACTER(b,s,p,c) \
+if (!HgfsProcessLastCharacter(b,s,p,c)) \
+{ \
+ return FALSE; \
+}
+
+#else // _WIN32
+
+#define UNREFERENCED_PARAMETER(P)
+/* There is no special escape sequences on other than Windows platforms. */
+#define IS_SPECIAL_CASE_ESCAPE(b,o,l) FALSE
+/* There is no reserved names on other then Windows platforms. */
+#define PROCESS_RESERVED_NAME(b,s,p,o,c)
+/* There is no special processing for the last character on non-Windows platforms. */
+#define PROCESS_LAST_CHARACTER(b,s,p,c)
+
+#if defined(__APPLE__)
+/* These characters are illegal in MAC OS file names. */
+const char* HGFS_ILLEGAL_CHARS = "/:";
+const char* HGFS_SUBSTITUTE_CHARS = "!&";
+#else // __APPLE__
+/* These characters are illegal in Linux file names. */
+const char* HGFS_ILLEGAL_CHARS = "/";
+const char* HGFS_SUBSTITUTE_CHARS = "!";
+#endif // __APPLE__
+
+#endif // _WIN32
+
+#define HGFS_ESCAPE_CHAR '%'
+#define HGFS_ESCAPE_SUBSTITUE_CHAR ']'
+
+typedef enum {
+ HGFS_ESCAPE_ILLEGAL_CHARACTER,
+ HGFS_ESCAPE_RESERVED_NAME,
+ HGFS_ESCAPE_ILLEGAL_LAST_CHARACTER,
+ HGFS_ESCAPE_ESCAPE_SEQUENCE,
+ HGFS_ESCAPE_COMPLETE
+} HgfsEscapeReason;
+
+
+typedef Bool (*HgfsEnumCallback)(char const *bufIn,
+ uint32 offset,
+ HgfsEscapeReason reason,
+ void* context);
+
+/*
+ * The structure is used by HgfsAddEscapeCharacter to keep context information between
+ * invocations
+ * All offsets defined in this structure are in characters, not bytes
+ */
+typedef struct {
+ uint32 processedOffset; // Offset of the first unprocessed input character
+ uint32 outputBufferLength; // Number of characters in the output buffer
+ uint32 outputOffset; // Number of characters that are already in the output
+ char *outputBuffer; // Pointer to the output buffer
+} HgfsEscapeContext;
+
+static void HgfsEscapeUndoComponent(char *bufIn, uint32 *totalLength);
+static int HgfsEscapeGetComponentSize(char const *bufIn, uint32 sizeIn);
+static int HgfsEscapeDoComponent(char const *bufIn, uint32 sizeIn, uint32 sizeBufOut,
+ char *bufOut);
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsAddEscapeCharacter --
+ *
+ * Callback function that is called by HgfsEnumerate to insert an escape sequence
+ * into the input name.
+ *
+ * Results:
+ * TRUE if successful, FALSE if there is an error like the output buffer is
+ * too small.
+ *
+ * Side effects:
+ * Updates the output buffer pointer (stored in the context variable).
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+HgfsAddEscapeCharacter(char const * bufIn, // IN: input name
+ uint32 offset, // IN: offset that requires escaping
+ HgfsEscapeReason reason, // IN: reason for esaping
+ void *context) // IN/OUT: convertion context
+{
+ HgfsEscapeContext *escapeContext = (HgfsEscapeContext *)context;
+ uint32 charactersToCopy;
+ uint32 outputSpace;
+ char* illegal;
+ Bool result = TRUE;
+
+ ASSERT(offset >= escapeContext->processedOffset); // Scanning forward
+ charactersToCopy = offset - escapeContext->processedOffset;
+
+ if (escapeContext->outputOffset + charactersToCopy >
+ escapeContext->outputBufferLength) {
+ return FALSE;
+ }
+
+ memcpy(escapeContext->outputBuffer + escapeContext->outputOffset,
+ bufIn + escapeContext->processedOffset, charactersToCopy * sizeof *bufIn);
+ escapeContext->outputOffset += charactersToCopy;
+ escapeContext->processedOffset += charactersToCopy;
+
+ outputSpace = escapeContext->outputBufferLength - escapeContext->outputOffset;
+
+ switch(reason) {
+ case HGFS_ESCAPE_ILLEGAL_CHARACTER:
+ if (outputSpace < 2) {
+ return FALSE;
+ }
+ illegal = strchr(HGFS_ILLEGAL_CHARS, bufIn[escapeContext->processedOffset]);
+ escapeContext->processedOffset++; // Skip illegal input character
+ ASSERT(illegal != NULL);
+ escapeContext->outputBuffer[escapeContext->outputOffset] =
+ HGFS_SUBSTITUTE_CHARS[illegal - HGFS_ILLEGAL_CHARS];
+ escapeContext->outputOffset++;
+ escapeContext->outputBuffer[escapeContext->outputOffset] = HGFS_ESCAPE_CHAR;
+ escapeContext->outputOffset++;
+ break;
+
+ case HGFS_ESCAPE_RESERVED_NAME:
+ if (outputSpace < 1) {
+ return FALSE;
+ }
+ escapeContext->outputBuffer[escapeContext->outputOffset] = HGFS_ESCAPE_CHAR;
+ escapeContext->outputOffset++;
+ break;
+
+ case HGFS_ESCAPE_ILLEGAL_LAST_CHARACTER:
+ if (outputSpace < 1) {
+ return FALSE;
+ }
+ escapeContext->outputBuffer[escapeContext->outputOffset] = HGFS_ESCAPE_CHAR;
+ escapeContext->outputOffset++;
+ break;
+
+ case HGFS_ESCAPE_ESCAPE_SEQUENCE:
+ if (outputSpace < 2) {
+ return FALSE;
+ }
+ escapeContext->processedOffset++; // Skip input esape character
+ escapeContext->outputBuffer[escapeContext->outputOffset] = HGFS_ESCAPE_SUBSTITUE_CHAR;
+ escapeContext->outputOffset++;
+ escapeContext->outputBuffer[escapeContext->outputOffset] = HGFS_ESCAPE_CHAR;
+ escapeContext->outputOffset++;
+ break;
+
+ case HGFS_ESCAPE_COMPLETE:
+ if (outputSpace < 1) {
+ return FALSE;
+ }
+ escapeContext->outputBuffer[escapeContext->outputOffset] = '\0';
+ break;
+
+ default:
+ result = FALSE;
+ ASSERT(FALSE);
+ }
+ return result;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsCountEscapeChars --
+ *
+ * Callback function that is called by HgfsEnumerate to count additional characters
+ * that need to be inserted in the input name.
+ *
+ * Results:
+ * TRUE since it never fails.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+HgfsCountEscapeChars(char const *bufIn, // IN: input name
+ uint32 offset, // IN: offset where escape is needed
+ HgfsEscapeReason reason, // IN: reason for escaping
+ void *context) // IN/OUT: context info
+{
+ UNREFERENCED_PARAMETER(bufIn);
+ UNREFERENCED_PARAMETER(offset);
+ if (reason != HGFS_ESCAPE_COMPLETE) {
+ uint32 *counter = (uint32*)context;
+ (*counter)++;
+ }
+ return TRUE;
+}
+
+
+#ifdef _WIN32
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsLetterToUpper --
+ *
+ * Converts lowercase English letters to uppercase.
+ * If the symbol is not a lowercase English letter returns the original character.
+ *
+ * Results:
+ * Converted character.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static char
+HgfsLetterToUpper(char letter)
+{
+ if (letter >= 'a' && letter <= 'z') {
+ return letter - ('a' - 'A');
+ }
+ return letter;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsIsEqualPrefix --
+ *
+ * Verifies if the string prefix is equal to the given prefix.
+ * It assumes that the prefix includes only uppercase English letters or numbers
+ * and it does not have any international characters.
+ * The string must be either NULL terminated or not shorter then the prefix.
+ *
+ * Results:
+ * TRUE if the uppcased string starts with the given prefix. False otherwise.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+HgfsIsEqualPrefix(char const *prefix, // IN: prefix to check
+ char const *string, // IN: input string
+ uint32 prefixLength) // IN: length of the prefix in characters
+{
+ int i;
+ for (i = 0; i < prefixLength; i++) {
+ ASSERT(prefix[i] > 0 && (prefix[i] < 'a' || prefix[i] > 'z' ));
+ if (prefix[i] != HgfsLetterToUpper(string[i])) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsIsReservedPrefix --
+ *
+ * Verifies if the name's prefix is one of the reserved names.
+ *
+ * Results:
+ * TRUE if the name's prefix is one of the reserved names.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+HgfsIsReservedPrefix(char const *bufIn) // IN: input name
+{
+ uint32 i;
+ for (i = 0; i < ARRAYSIZE(HgfsReservedNames); i++) {
+ if (HgfsIsEqualPrefix(HgfsReservedNames[i], bufIn,
+ HGFS_RESERVED_NAME_CHARS_LENGTH)) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsIsReservedPrefixWithNumber --
+ *
+ * Verifies if the name's prefix is one of the reserved names with number:
+ * COM1-9 or LPT1-9.
+ *
+ * Results:
+ * TRUE if the name's prefix is one of the reserved names with number.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+HgfsIsReservedPrefixWithNumber(char const *bufIn) // IN: input name
+{
+ uint32 i;
+ for (i = 0; i < ARRAYSIZE(HgfsReservedNamesWithNumber); i++) {
+ if (HgfsIsEqualPrefix(HgfsReservedNamesWithNumber[i], bufIn,
+ HGFS_RESERVED_NAME_CHARS_LENGTH) &&
+ bufIn[HGFS_RESERVED_NAME_CHARS_LENGTH] >= '1' &&
+ bufIn[HGFS_RESERVED_NAME_CHARS_LENGTH] <= '9') {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsIsSpecialCaseEscape --
+ *
+ * Verifies if the escape character is a part of special case escape sequence
+ * that exists only in Windows - escaped reserved name or escaped illegal last
+ * character.
+ *
+ * Results:
+ * TRUE if the name's prefix is one of the reserved names with number.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+HgfsIsSpecialCaseEscape(char const *bufIn, // IN: input name
+ uint32 offset, // IN: offset of the escape character
+ uint32 length) // IN: length of the name in characters
+{
+ if (offset + 1 == length &&
+ strchr(HGFS_ILLEGAL_LAST_CHARS, bufIn[offset - 1]) != NULL) {
+ return TRUE;
+ }
+ if (offset == HGFS_RESERVED_NAME_CHARS_LENGTH &&
+ (length == HGFS_RESERVED_NAME_CHARS_LENGTH + 1 || bufIn[offset+1] == '.')) {
+ return HgfsIsReservedPrefix(bufIn);
+ }
+ if (offset == HGFS_RESERVED_NAME_WITH_NUMBER_CHARS_LENGTH &&
+ (length == HGFS_RESERVED_NAME_WITH_NUMBER_CHARS_LENGTH + 1 ||
+ bufIn[offset+1] == '.')) {
+ return HgfsIsReservedPrefixWithNumber(bufIn);
+ }
+ return FALSE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsProcessReservedName --
+ *
+ * Verifies if the name is one of reserved Windows file names.
+ * If it is a reserved name invokes callback that performs required
+ * processing.
+ *
+ * Results:
+ * TRUE if no processing is required of if processing succeeded,
+ * FALSE if processing failed.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+HgfsProcessReservedName(char const *bufIn, // IN: Unescaped input buffer
+ uint32 sizeIn, // IN: Length of the input
+ HgfsEnumCallback processEscape, // IN: Callack that is invoked
+ // if input is reserved name
+ uint32 *offset, // OUT: New offset in the input
+ void *context) // IN/OUT: Context for callback
+{
+ /* Look reserved names: CON, PRN, AUX, NUL. */
+ if (sizeIn >= HGFS_RESERVED_NAME_CHARS_LENGTH && HgfsIsReservedPrefix(bufIn)) {
+ if (HGFS_RESERVED_NAME_CHARS_LENGTH == sizeIn ||
+ bufIn[HGFS_RESERVED_NAME_CHARS_LENGTH] == '.') {
+ if (!processEscape(bufIn, HGFS_RESERVED_NAME_CHARS_LENGTH,
+ HGFS_ESCAPE_RESERVED_NAME, context)) {
+ return FALSE;
+ }
+ *offset = HGFS_RESERVED_NAME_CHARS_LENGTH;
+ }
+ }
+
+ /* Look reserved names with numbers: COM1-9 and LPT1-9. */
+ if (sizeIn >= HGFS_RESERVED_NAME_WITH_NUMBER_CHARS_LENGTH &&
+ HgfsIsReservedPrefixWithNumber(bufIn)) {
+ if (HGFS_RESERVED_NAME_WITH_NUMBER_CHARS_LENGTH == sizeIn ||
+ bufIn[HGFS_RESERVED_NAME_WITH_NUMBER_CHARS_LENGTH] == '.') {
+ if (!processEscape(bufIn, HGFS_RESERVED_NAME_WITH_NUMBER_CHARS_LENGTH,
+ HGFS_ESCAPE_RESERVED_NAME, context)) {
+ return FALSE;
+ }
+ *offset = HGFS_RESERVED_NAME_WITH_NUMBER_CHARS_LENGTH;
+ }
+ }
+ return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsProcessLastCharacter --
+ *
+ * Verifies if the trailing character in the name is a valid last character.
+ * In Windows it is illegal to have a file name that ends with dot ('.') or
+ * space (' '). The only exception is "." and ".." directory names.
+ * If the last character is invalid the function invokes a callback to process it.
+ *
+ * Results:
+ * TRUE if no processing is required of if processing succeeded,
+ * FALSE if processing failed.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+HgfsProcessLastCharacter(char const *bufIn, // IN: Unescaped input buffer
+ uint32 sizeIn, // IN: Length of the input
+ HgfsEnumCallback processEscape, // IN: Callack that is invoked
+ // when escaping is needed
+ void *context) // IN/OUT: Callback context
+{
+
+ /* If the filename is '.' or '..' we shouldn't escape it. */
+ if ((sizeIn == 1 && bufIn[0] == '.') ||
+ (sizeIn == 2 && bufIn[0] == '.' && bufIn[1] == '.')) {
+ return TRUE;
+ }
+
+ /* Invoke the callback if the last character is illegal. */
+ if (strchr(HGFS_ILLEGAL_LAST_CHARS, bufIn[sizeIn - 1]) != NULL) {
+ if (!processEscape(bufIn, sizeIn, HGFS_ESCAPE_ILLEGAL_LAST_CHARACTER, context)) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+#endif // WIN32
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsIsEscapeSequence --
+ *
+ * Verifies if input buffer has an escape sequence at the position
+ * defined by offset.
+ *
+ * Results:
+ * TRUE if there is an escape sequence at the position defined by offset.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+HgfsIsEscapeSequence(char const *bufIn, // IN: input name
+ uint32 offset, // IN: offset of the escape character
+ uint32 length) // IN: length of the name in characters
+{
+ if (bufIn[offset] == HGFS_ESCAPE_CHAR && offset > 0) {
+ char *substitute;
+ if (bufIn[offset - 1] == HGFS_ESCAPE_SUBSTITUE_CHAR) {
+ return TRUE;
+ }
+ substitute = strchr(HGFS_SUBSTITUTE_CHARS, bufIn[offset - 1]);
+ if (substitute != NULL) {
+ return TRUE;
+ }
+ return IS_SPECIAL_CASE_ESCAPE(bufIn,offset,length);
+ }
+ return FALSE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsEscapeEnumerate --
+ *
+ * The function scans the input buffer and calls processEscape callback for every
+ * place in the input buffer which require escaping.
+ *
+ * Callback does the required processing. There are two different callbacks -
+ * one counts extra symbols that are needed for escaping and another produces
+ * escaped output name based on input name.
+ *
+ * 1. The first function calculates number of extra characters. It just increments
+ * a counter which is passed to it in context variable every time it is called
+ * for the reason different from "complete processing" assuming that
+ * exactly one extra character is required to escape any invalid input.
+ *
+ * 2. The second function produces output name by copying everything from input
+ * name into the output name up to the place which require escaping and
+ * then inserts appropriate escape sequence into the output. It keeps track of its
+ * progress and keeps pointer to the output buffer in the context variable.
+ * HgfsEscapeEnumerate calls calback function one more time at the end of the
+ * input buffer to let callback finish processing of the input (for example copy
+ * the rest of the name after the last escape sequence from input buffer to
+ * output buffer).
+ *
+ * Results:
+ * TRUE if the input has been processed successfully by the callback, false otherwise.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+HgfsEscapeEnumerate(char const *bufIn, // IN: Buffer with unescaped input
+ uint32 sizeIn, // IN: Number of input *characters*
+ HgfsEnumCallback processEscape, // IN: Callack that is invoked every
+ // time escaping is required
+ void *context) // IN/OUT: Context for processEscape
+{
+ /* First look for invalid characters in the input name. */
+ uint32 i, offset = 0;
+ if (sizeIn == 0) {
+ return TRUE;
+ }
+
+ ASSERT(processEscape);
+
+ PROCESS_RESERVED_NAME(bufIn, sizeIn, processEscape, &offset, context);
+
+ for (i = offset; i < sizeIn; i++) {
+ if (strchr(HGFS_ILLEGAL_CHARS, bufIn[i]) != NULL) {
+ if (!processEscape(bufIn, i, HGFS_ESCAPE_ILLEGAL_CHARACTER, context)) {
+ return FALSE;
+ }
+ } else if (HgfsIsEscapeSequence(bufIn, i, sizeIn)) {
+ if (!processEscape(bufIn, i, HGFS_ESCAPE_ESCAPE_SEQUENCE, context)) {
+ return FALSE;
+ }
+ }
+ }
+
+ PROCESS_LAST_CHARACTER(bufIn, sizeIn, processEscape, context);
+
+ if (!processEscape(bufIn, sizeIn, HGFS_ESCAPE_COMPLETE, context)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsEscape_Do --
+ *
+ * Escape any characters that are not legal in a windows filename.
+ * Escape reserved file names that can't be used in Windows.
+ * We also of course have to escape the escape character, which is "%",
+ * when it is part of a character sequence that would require unescaping
+ *
+ * sizeBufOut must account for the NUL terminator.
+ *
+ * Results:
+ * On success, the size (excluding the NUL terminator) of the
+ * escaped, NUL terminated buffer.
+ * On failure (bufOut not big enough to hold result), negative value.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int
+HgfsEscape_Do(char const *bufIn, // IN: Buffer with unescaped input
+ uint32 sizeIn, // IN: Size of input buffer
+ uint32 sizeBufOut, // IN: Size of output buffer
+ char *bufOut) // OUT: Buffer for escaped output
+{
+ const char *currentComponent = bufIn;
+ uint32 sizeLeft = sizeBufOut;
+ char *outPointer = bufOut;
+ const char *end = bufIn + sizeIn;
+ const char *next;
+ ASSERT(sizeIn > 0);
+ if (bufIn[sizeIn - 1] == '\0') {
+ /*
+ * In some cases a NUL terminated string is passed to HgfsEscape_Do
+ * so it make sense to support such input even if CPName_GetComponent
+ * does not. Detect this case and make the input compliant with
+ * CPName_GetComponent by removing terminating NUL.
+ */
+ end--;
+ sizeIn--;
+ }
+ /*
+ * Absolute symbolic link name starts with the '\0'. HgfsEscapeDo needs to work
+ * with such names. Leading NULL symbols should be skipped here since
+ * CPName_GetComponent does not support such names.
+ */
+ while (*currentComponent == '\0' && currentComponent - bufIn < sizeIn) {
+ currentComponent++;
+ sizeLeft--;
+ *outPointer++ = '\0';
+ }
+ while (currentComponent - bufIn < sizeIn) {
+ int escapedLength;
+ uint32 componentSize = CPName_GetComponent(currentComponent, end, &next);
+
+ escapedLength = HgfsEscapeDoComponent(currentComponent, componentSize,
+ sizeLeft, outPointer);
+ if (escapedLength < 0) {
+ return escapedLength;
+ }
+ currentComponent = next;
+ sizeLeft -= escapedLength + 1;
+ outPointer += escapedLength + 1;
+ }
+ return (int) (outPointer - bufOut) - 1; // Do not count the last NUL terminator
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsEscape_GetSize --
+ *
+ * Calculates required size in bytes for the buffer that is needed to hold escaped
+ * cross platform path name. Returns 0 if no escaping is required.
+ *
+ * Results:
+ * On success, the size (excluding the NUL terminator) of the
+ * escaped, NUL terminated buffer.
+ * Returns 0 if the name is a valid Windows file name.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int
+HgfsEscape_GetSize(char const *bufIn, // IN: Buffer with unescaped input
+ uint32 sizeIn) // IN: Size of the input buffer
+{
+ uint32 result = 0;
+ const char *currentComponent = bufIn;
+ const char *end = bufIn + sizeIn;
+ const char *next;
+
+ if (sizeIn == 0) { // No need toescape empty name.
+ return 0;
+ }
+ if (bufIn[sizeIn - 1] == '\0') {
+ /*
+ * In some cases a NUL terminated string is passed to HgfsEscape_GeSize
+ * so it make sense to support such input even if CPName_GetComponent
+ * does not. Detect this case and make the input compliant with
+ * CPName_GetComponent by removing terminating NUL.
+ */
+ end--;
+ sizeIn--;
+ }
+ /* Skip leading NULs to keep CPName_GetComponent happy. */
+ while (*currentComponent == '\0' && currentComponent - bufIn < sizeIn) {
+ currentComponent++;
+ }
+ while (currentComponent - bufIn < sizeIn) {
+ uint32 componentSize = CPName_GetComponent(currentComponent, end, &next);
+ result += HgfsEscapeGetComponentSize(currentComponent, componentSize);
+ currentComponent = next;
+ }
+ return (result == 0) ? 0 : result + sizeIn;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsEscape_Undo --
+ *
+ * Unescape a buffer that was escaped using HgfsEscapeBuffer.
+ *
+ * The unescaping is done in place in the input buffer, and
+ * can not fail.
+ *
+ * Results:
+ * The size (excluding the NUL terminator) of the unescaped, NUL
+ * terminated buffer.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int
+HgfsEscape_Undo(char *bufIn, // IN: Characters to be unescaped
+ uint32 sizeIn) // IN: Number of characters in bufIn
+{
+ uint32 componentSize = strlen(bufIn) + 1;
+ uint32 unprocessedSize = sizeIn + 1;
+ uint32 result = 0;
+ char *currentComponent = bufIn;
+ while (currentComponent != NULL) {
+ HgfsEscapeUndoComponent(currentComponent, &unprocessedSize);
+ componentSize = strlen(currentComponent) + 1; // Unescaped size
+ result += componentSize;
+ if (unprocessedSize > 1) {
+ currentComponent = currentComponent + componentSize;
+ componentSize = strlen(currentComponent) + 1; // Size of the next component
+ } else {
+ currentComponent = NULL;
+ }
+ }
+ return result - 1;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsEscapeUndoComponent --
+ *
+ * Unescape a buffer that was escaped using HgfsEscapeBuffer.
+ *
+ * The unescaping is done in place in the input buffer, and
+ * can not fail.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+HgfsEscapeUndoComponent(char *bufIn, // IN: Characters to be unescaped
+ uint32 *unprocessedLength) // IN: Unprocessed characters
+ // in the whole name
+{
+ size_t offset;
+ size_t sizeIn = strlen(bufIn);
+ char* curOutBuffer = bufIn;
+ char* escapePointer;
+ ASSERT(bufIn);
+
+ escapePointer = strchr(curOutBuffer, HGFS_ESCAPE_CHAR);
+ while (escapePointer != NULL) {
+ offset = escapePointer - bufIn;
+ if (HgfsIsEscapeSequence(bufIn, offset, sizeIn)) {
+ char* substitute = strchr(HGFS_SUBSTITUTE_CHARS, bufIn[offset - 1]);
+ if (substitute != NULL) {
+ bufIn[offset - 1] = HGFS_ILLEGAL_CHARS[substitute - HGFS_SUBSTITUTE_CHARS];
+ } else if (bufIn[offset - 1] == HGFS_ESCAPE_SUBSTITUE_CHAR) {
+ bufIn[offset - 1] = HGFS_ESCAPE_CHAR;
+ }
+ memmove(escapePointer, escapePointer + 1, (*unprocessedLength) - offset - 1);
+ (*unprocessedLength)--;
+ sizeIn--;
+ if (sizeIn > 0) {
+ escapePointer = strchr(escapePointer, HGFS_ESCAPE_CHAR);
+ } else {
+ escapePointer = NULL;
+ }
+ } else {
+ escapePointer = strchr(escapePointer + 1, HGFS_ESCAPE_CHAR);
+ }
+ }
+ ASSERT((*unprocessedLength) > sizeIn);
+ (*unprocessedLength) -= sizeIn + 1;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsEscapeDoComponent --
+ *
+ * Escape any characters that are not legal in a windows filename.
+ * Escape reserved file names that can't be used in Windows.
+ * We also of course have to escape the escape character, which is "%",
+ * when it is part of a character sequence that would require unescaping
+ *
+ * sizeBufOut must account for the NUL terminator.
+ *
+ * Results:
+ * On success, the size (excluding the NUL terminator) of the
+ * escaped, NUL terminated buffer.
+ * On failure (bufOut not big enough to hold result), negative value.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int
+HgfsEscapeDoComponent(char const *bufIn, // IN: Buffer with unescaped input
+ uint32 sizeIn, // IN: Size of input buffer
+ uint32 sizeBufOut, // IN: Size of output buffer
+ char *bufOut) // OUT: Buffer for escaped output
+{
+ HgfsEscapeContext conversionContext;
+ conversionContext.processedOffset = 0;
+ conversionContext.outputBufferLength = sizeBufOut / sizeof *bufOut;
+ conversionContext.outputOffset = 0;
+ conversionContext.outputBuffer = bufOut;
+
+ if (!HgfsEscapeEnumerate(bufIn, sizeIn, HgfsAddEscapeCharacter, &conversionContext)) {
+ return -1;
+ }
+ return conversionContext.outputOffset * sizeof *bufOut;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsEscapeGetComponentSize --
+ *
+ * Calculates number of addtitional characters that are needed to escape
+ * name for one NUL terminated component of the path.
+ *
+ * Results:
+ * Number of additional escape characters needed to escape the name.
+ * Returns 0 if no escaping is required.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int
+HgfsEscapeGetComponentSize(char const *bufIn, // IN: Buffer with unescaped input
+ uint32 sizeIn) // IN: Size of the in input buffer
+{
+ int result = 0;
+ HgfsEscapeEnumerate(bufIn, sizeIn, HgfsCountEscapeChars, &result);
+ return result;
+}
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2007 VMware, Inc. 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 version 2 and no 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. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ *********************************************************/
+
+/*
+ * vmciHostKernelAPI.h --
+ *
+ * Kernel API exported from the VMCI host driver.
+ */
+
+#ifndef __VMCI_HOSTKERNELAPI_H__
+#define __VMCI_HOSTKERNELAPI_H__
+
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_VMMON
+#define INCLUDE_ALLOW_VMCORE
+#define INCLUDE_ALLOW_VMK_MODULE
+#define INCLUDE_ALLOW_VMKERNEL
+#define INCLUDE_ALLOW_DISTRIBUTE
+#include "includeCheck.h"
+
+
+/* VMCI host kernel API version number. */
+#define VMCI_HOST_KERNEL_API_VERSION 1
+
+/* Macros to operate on the driver version number. */
+#define VMCI_MAJOR_VERSION(v) (((v) >> 16) & 0xffff)
+#define VMCI_MINOR_VERSION(v) ((v) & 0xffff)
+
+#include "vmci_defs.h"
+#ifdef VMKERNEL
+#include "vm_atomic.h"
+#include "return_status.h"
+#include "util_copy_dist.h"
+#endif
+#include "vmci_defs.h"
+#include "vmci_call_defs.h"
+
+
+#ifdef VMKERNEL
+#endif
+
+
+/* VMCI Datagram API. */
+
+int VMCIHost_DatagramCreateHnd(VMCIId resourceID, uint32 flags,
+ VMCIDatagramRecvCB recvCB, void *clientData,
+ VMCIHandle *outHandle);
+int VMCIDatagram_CreateHnd(VMCIId resourceID, uint32 flags,
+ VMCIDatagramRecvCB recvCB, void *clientData,
+ VMCIHandle *outHandle);
+int VMCIDatagram_CreateHndPriv(VMCIId resourceID, uint32 flags,
+ VMCIPrivilegeFlags privFlags,
+ VMCIDatagramRecvCB recvCB, void *clientData,
+ VMCIHandle *outHandle);
+int VMCIDatagram_DestroyHnd(VMCIHandle handle);
+int VMCIDatagram_Send(VMCIDatagram *msg);
+
+
+/* VMCI Event API */
+
+typedef void (*VMCI_EventCB)(VMCIId subID, VMCI_EventData *ed,
+ void *clientData);
+
+int VMCIEvent_Subscribe(VMCI_Event event, VMCI_EventCB callback,
+ void *callbackData, VMCIId *subID);
+int VMCIEvent_Unsubscribe(VMCIId subID);
+
+/*
+ * Since QP API for non-VMKernel hosts is defined in vmci_queue_pair.h, here
+ * declarations are included only for VMKERNEL
+ */
+#ifdef VMKERNEL
+
+/*
+ * For guest kernels, the VMCIQueue is directly mapped onto the
+ * metadata page of the queue. In vmkernel, we use the VMCIQueue
+ * structure to store the information necessary to retrieve the MPNs
+ * of the queue. By redefining the structure, queue pair code using
+ * the API below will be portable between guests and host kernels.
+ */
+
+typedef struct VMCIQueue {
+ uint32 offset; // Start page of queue in backing store
+ uint32 len; // Number of pages in the queue
+ struct QueuePairEntry *entry; // Endpoint state for the queue pair
+} VMCIQueue;
+
+
+/* VMCI Queuepair API */
+void VMCIQueue_Init(const VMCIHandle handle, VMCIQueue *queue);
+void VMCIQueue_GetPointers(const VMCIQueue *produceQ, const VMCIQueue *consumeQ,
+ uint64 *producerTail, uint64 *consumerHead);
+int VMCIQueuePair_Alloc(VMCIHandle *handle, VMCIQueue **produceQ,
+ uint64 produceSize, VMCIQueue **consumeQ,
+ uint64 consumeSize, VMCIId peer, uint32 flags);
+int VMCIQueuePair_Detach(VMCIHandle handle);
+int64 VMCIQueue_FreeSpace(const VMCIQueue *produceQueue,
+ const VMCIQueue *consumeQueue,
+ const uint64 produceQSize);
+int64 VMCIQueue_BufReady(const VMCIQueue *consumeQueue,
+ const VMCIQueue *produceQueue,
+ const uint64 consumeQSize);
+ssize_t VMCIQueue_Enqueue(VMCIQueue *produceQueue, const VMCIQueue *consumeQueue,
+ const uint64 produceQSize, const void *buf,
+ size_t bufSize, Util_BufferType bufType);
+ssize_t VMCIQueue_Peek(VMCIQueue *produceQueue, const VMCIQueue *consumeQueue,
+ const uint64 consumeQSize, void *buf,
+ size_t bufSize, Util_BufferType bufType);
+ssize_t VMCIQueue_PeekV(VMCIQueue *produceQueue, const VMCIQueue *consumeQueue,
+ const uint64 consumeQSize, void *buf,
+ size_t bufSize, Util_BufferType bufType);
+ssize_t VMCIQueue_Discard(VMCIQueue *produceQueue, const VMCIQueue *consumeQueue,
+ const uint64 consumeQSize, size_t bufSize);
+ssize_t VMCIQueue_Dequeue(VMCIQueue *produceQueue, const VMCIQueue *consumeQueue,
+ const uint64 consumeQSize, void *buf,
+ size_t bufSize, Util_BufferType bufType);
+ssize_t VMCIQueue_EnqueueV(VMCIQueue *produceQueue, const VMCIQueue *consumeQueue,
+ const uint64 produceQSize, const void *buf,
+ size_t bufSize, Util_BufferType bufType);
+ssize_t VMCIQueue_DequeueV(VMCIQueue *produceQueue, const VMCIQueue *consumeQueue,
+ const uint64 consumeQSize, void *buf,
+ size_t bufSize, Util_BufferType bufType);
+#endif /* VMKERNEL */
+
+#endif /* !__VMCI_HOSTKERNELAPI_H__ */
+