From: Marcelo Vanzin Date: Wed, 19 Nov 2008 01:36:49 +0000 (-0800) Subject: 2008.11.18-130226 X-Git-Tag: 2008.11.18-130226 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=91fa010a6b7265ff87c8039a0c895140b489dbcf;p=thirdparty%2Fopen-vm-tools.git 2008.11.18-130226 --- diff --git a/open-vm-tools/lib/hgfs/hgfsEscape.c b/open-vm-tools/lib/hgfs/hgfsEscape.c new file mode 100644 index 000000000..739405279 --- /dev/null +++ b/open-vm-tools/lib/hgfs/hgfsEscape.c @@ -0,0 +1,942 @@ +/********************************************************* + * 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 +#elif defined(__FreeBSD__) +# if defined(_KERNEL) +# include +# define strchr(s,c) index(s,c) +# else +# include +# endif +# define memmove(s1,s2,n) bcopy(s2,s1,n) +#elif defined(__APPLE__) && defined(KERNEL) +# include +#elif !defined(sun) +# include +# include +#else +# include +#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; +} diff --git a/open-vm-tools/lib/include/hgfsEscape.h b/open-vm-tools/lib/include/hgfsEscape.h new file mode 100644 index 000000000..680566933 --- /dev/null +++ b/open-vm-tools/lib/include/hgfsEscape.h @@ -0,0 +1,40 @@ +/********************************************************* + * 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__ diff --git a/open-vm-tools/modules/freebsd/vmhgfs/hgfsEscape.c b/open-vm-tools/modules/freebsd/vmhgfs/hgfsEscape.c new file mode 100644 index 000000000..fb1e06108 --- /dev/null +++ b/open-vm-tools/modules/freebsd/vmhgfs/hgfsEscape.c @@ -0,0 +1,942 @@ +/********************************************************* + * 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 +#elif defined(__FreeBSD__) +# if defined(_KERNEL) +# include +# define strchr(s,c) index(s,c) +# else +# include +# endif +# define memmove(s1,s2,n) bcopy(s2,s1,n) +#elif defined(__APPLE__) && defined(KERNEL) +# include +#elif !defined(sun) +# include +# include +#else +# include +#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; +} diff --git a/open-vm-tools/modules/freebsd/vmhgfs/hgfsEscape.h b/open-vm-tools/modules/freebsd/vmhgfs/hgfsEscape.h new file mode 100644 index 000000000..66fb58e16 --- /dev/null +++ b/open-vm-tools/modules/freebsd/vmhgfs/hgfsEscape.h @@ -0,0 +1,40 @@ +/********************************************************* + * 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__ diff --git a/open-vm-tools/modules/linux/dkms.conf b/open-vm-tools/modules/linux/dkms.conf new file mode 100644 index 000000000..ffed427f4 --- /dev/null +++ b/open-vm-tools/modules/linux/dkms.conf @@ -0,0 +1,48 @@ +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" diff --git a/open-vm-tools/modules/linux/pvscsi/COPYING b/open-vm-tools/modules/linux/pvscsi/COPYING new file mode 100644 index 000000000..d511905c1 --- /dev/null +++ b/open-vm-tools/modules/linux/pvscsi/COPYING @@ -0,0 +1,339 @@ + 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. + + + Copyright (C) + + 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. + + , 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. diff --git a/open-vm-tools/modules/linux/pvscsi/Makefile b/open-vm-tools/modules/linux/pvscsi/Makefile new file mode 100644 index 000000000..650fd67d2 --- /dev/null +++ b/open-vm-tools/modules/linux/pvscsi/Makefile @@ -0,0 +1,158 @@ +#!/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: diff --git a/open-vm-tools/modules/linux/pvscsi/Makefile.kernel b/open-vm-tools/modules/linux/pvscsi/Makefile.kernel new file mode 100644 index 000000000..938d72cf2 --- /dev/null +++ b/open-vm-tools/modules/linux/pvscsi/Makefile.kernel @@ -0,0 +1,33 @@ +#!/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))) diff --git a/open-vm-tools/modules/linux/pvscsi/autoconf/cachecreate.c b/open-vm-tools/modules/linux/pvscsi/autoconf/cachecreate.c new file mode 100644 index 000000000..88c51c199 --- /dev/null +++ b/open-vm-tools/modules/linux/pvscsi/autoconf/cachecreate.c @@ -0,0 +1,42 @@ +/********************************************************* + * 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 +#include + +/* + * 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 + +struct kmem_cache *kmemtest(void) { + return kmem_cache_create("test", 12, 0, 0, NULL, NULL); +} + +#endif diff --git a/open-vm-tools/modules/linux/pvscsi/autoconf/cachector.c b/open-vm-tools/modules/linux/pvscsi/autoconf/cachector.c new file mode 100644 index 000000000..bbc124dea --- /dev/null +++ b/open-vm-tools/modules/linux/pvscsi/autoconf/cachector.c @@ -0,0 +1,40 @@ +/********************************************************* + * 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 +#include + +/* + * 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 + +struct kmem_cache *kmem_cache_create(const char *, size_t, size_t, + unsigned long, + void (*)(void *, struct kmem_cache *, unsigned long)); + +#endif diff --git a/open-vm-tools/modules/linux/pvscsi/autoconf/geninclude.c b/open-vm-tools/modules/linux/pvscsi/autoconf/geninclude.c new file mode 100644 index 000000000..f37a20f10 --- /dev/null +++ b/open-vm-tools/modules/linux/pvscsi/autoconf/geninclude.c @@ -0,0 +1,40 @@ +/********************************************************* + * 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 + +#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 + diff --git a/open-vm-tools/modules/linux/pvscsi/compat_interrupt.h b/open-vm-tools/modules/linux/pvscsi/compat_interrupt.h new file mode 100644 index 000000000..1d72a4bb5 --- /dev/null +++ b/open-vm-tools/modules/linux/pvscsi/compat_interrupt.h @@ -0,0 +1,55 @@ +/********************************************************* + * 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 + +#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__ */ diff --git a/open-vm-tools/modules/linux/pvscsi/compat_ioport.h b/open-vm-tools/modules/linux/pvscsi/compat_ioport.h new file mode 100644 index 000000000..bacdb50b6 --- /dev/null +++ b/open-vm-tools/modules/linux/pvscsi/compat_ioport.h @@ -0,0 +1,63 @@ +/********************************************************* + * 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 + +#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__ */ diff --git a/open-vm-tools/modules/linux/pvscsi/compat_module.h b/open-vm-tools/modules/linux/pvscsi/compat_module.h new file mode 100644 index 000000000..66fc469f8 --- /dev/null +++ b/open-vm-tools/modules/linux/pvscsi/compat_module.h @@ -0,0 +1,72 @@ +/********************************************************* + * 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 + + +/* + * 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__ */ diff --git a/open-vm-tools/modules/linux/pvscsi/compat_pci.h b/open-vm-tools/modules/linux/pvscsi/compat_pci.h new file mode 100644 index 000000000..b499b2847 --- /dev/null +++ b/open-vm-tools/modules/linux/pvscsi/compat_pci.h @@ -0,0 +1,590 @@ +/********************************************************* + * 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 +#ifndef KERNEL_2_1 +# include +#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__ */ diff --git a/open-vm-tools/modules/linux/pvscsi/compat_scsi.h b/open-vm-tools/modules/linux/pvscsi/compat_scsi.h new file mode 100644 index 000000000..e0a4ba707 --- /dev/null +++ b/open-vm-tools/modules/linux/pvscsi/compat_scsi.h @@ -0,0 +1,38 @@ +/********************************************************* + * 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__ */ diff --git a/open-vm-tools/modules/linux/pvscsi/compat_version.h b/open-vm-tools/modules/linux/pvscsi/compat_version.h new file mode 100644 index 000000000..baf9634ed --- /dev/null +++ b/open-vm-tools/modules/linux/pvscsi/compat_version.h @@ -0,0 +1,121 @@ +/********************************************************* + * 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 + +/* 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__ */ diff --git a/open-vm-tools/modules/linux/pvscsi/driver-config.h b/open-vm-tools/modules/linux/pvscsi/driver-config.h new file mode 100644 index 000000000..95f27de70 --- /dev/null +++ b/open-vm-tools/modules/linux/pvscsi/driver-config.h @@ -0,0 +1,78 @@ +/********************************************************* + * 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 +#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 +# 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 +# define _STDINT_H 1 +#endif + +#ifndef __KERNEL__ +# define __KERNEL__ +#endif + +#endif diff --git a/open-vm-tools/modules/linux/pvscsi/includeCheck.h b/open-vm-tools/modules/linux/pvscsi/includeCheck.h new file mode 100644 index 000000000..b3d5bb373 --- /dev/null +++ b/open-vm-tools/modules/linux/pvscsi/includeCheck.h @@ -0,0 +1,132 @@ +/********************************************************* + * 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 diff --git a/open-vm-tools/modules/linux/pvscsi/pvscsi.c b/open-vm-tools/modules/linux/pvscsi/pvscsi.c new file mode 100644 index 000000000..8411a4d31 --- /dev/null +++ b/open-vm-tools/modules/linux/pvscsi/pvscsi.c @@ -0,0 +1,1301 @@ +/********************************************************* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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++; + } +} diff --git a/open-vm-tools/modules/linux/pvscsi/pvscsi_defs.h b/open-vm-tools/modules/linux/pvscsi/pvscsi_defs.h new file mode 100644 index 000000000..3fa81f5ee --- /dev/null +++ b/open-vm-tools/modules/linux/pvscsi/pvscsi_defs.h @@ -0,0 +1,432 @@ +/********************************************************* + * 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__ */ diff --git a/open-vm-tools/modules/linux/pvscsi/pvscsi_version.h b/open-vm-tools/modules/linux/pvscsi/pvscsi_version.h new file mode 100644 index 000000000..ee3edde1a --- /dev/null +++ b/open-vm-tools/modules/linux/pvscsi/pvscsi_version.h @@ -0,0 +1,32 @@ +/********************************************************* + * 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_ */ diff --git a/open-vm-tools/modules/linux/pvscsi/scsi_defs.h b/open-vm-tools/modules/linux/pvscsi/scsi_defs.h new file mode 100644 index 000000000..9454ba8d8 --- /dev/null +++ b/open-vm-tools/modules/linux/pvscsi/scsi_defs.h @@ -0,0 +1,2104 @@ +/********************************************************* + * 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 diff --git a/open-vm-tools/modules/linux/pvscsi/vm_assert.h b/open-vm-tools/modules/linux/pvscsi/vm_assert.h new file mode 100644 index 000000000..2e70ae1fe --- /dev/null +++ b/open-vm-tools/modules/linux/pvscsi/vm_assert.h @@ -0,0 +1,317 @@ +/********************************************************* + * 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_ */ diff --git a/open-vm-tools/modules/linux/pvscsi/vm_basic_defs.h b/open-vm-tools/modules/linux/pvscsi/vm_basic_defs.h new file mode 100644 index 000000000..c307fa7b7 --- /dev/null +++ b/open-vm-tools/modules/linux/pvscsi/vm_basic_defs.h @@ -0,0 +1,610 @@ +/********************************************************* + * 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 /* + * We re-define offsetof macro from stddef, make + * sure that its already defined before we do it + */ + #include // for Sleep() and LOWORD() etc. +#endif + + +/* + * Simple macros + */ + +#if (defined __APPLE__ || defined __FreeBSD__) && \ + (!defined KERNEL && !defined _KERNEL && !defined VMKERNEL && !defined __KERNEL__) +# include +#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 +#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 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 // 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_ diff --git a/open-vm-tools/modules/linux/pvscsi/vm_basic_types.h b/open-vm-tools/modules/linux/pvscsi/vm_basic_types.h new file mode 100644 index 000000000..5e5e7cd03 --- /dev/null +++ b/open-vm-tools/modules/linux/pvscsi/vm_basic_types.h @@ -0,0 +1,912 @@ +/********************************************************* + * 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 +#endif +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_INTTYPES_H +#include +#endif +#ifdef HAVE_STDINT_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif + +#ifdef __FreeBSD__ +#include /* For __FreeBSD_version */ +#endif + +#if !defined(USING_AUTOCONF) +# if defined(__FreeBSD__) || defined(sun) +# ifdef KLD_MODULE +# include +# else +# if !defined(VMKERNEL) && (__FreeBSD_version >= 500043) +# include +# include +# else +# include +# endif +# endif +# elif defined __APPLE__ +# if KERNEL +# include +# include /* mostly for size_t */ +# include +# else +# include +# include +# include +# include +# 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_ */ diff --git a/open-vm-tools/modules/linux/pvscsi/vm_device_version.h b/open-vm-tools/modules/linux/pvscsi/vm_device_version.h new file mode 100644 index 000000000..083fbcd1d --- /dev/null +++ b/open-vm-tools/modules/linux/pvscsi/vm_device_version.h @@ -0,0 +1,188 @@ +/********************************************************* + * 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 */ diff --git a/open-vm-tools/modules/linux/pvscsi/vmware_pack_begin.h b/open-vm-tools/modules/linux/pvscsi/vmware_pack_begin.h new file mode 100644 index 000000000..8bec4571b --- /dev/null +++ b/open-vm-tools/modules/linux/pvscsi/vmware_pack_begin.h @@ -0,0 +1,43 @@ +/********************************************************* + * 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 diff --git a/open-vm-tools/modules/linux/pvscsi/vmware_pack_end.h b/open-vm-tools/modules/linux/pvscsi/vmware_pack_end.h new file mode 100644 index 000000000..c87cda908 --- /dev/null +++ b/open-vm-tools/modules/linux/pvscsi/vmware_pack_end.h @@ -0,0 +1,44 @@ +/********************************************************* + * 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 diff --git a/open-vm-tools/modules/linux/pvscsi/vmware_pack_init.h b/open-vm-tools/modules/linux/pvscsi/vmware_pack_init.h new file mode 100644 index 000000000..ecb636afd --- /dev/null +++ b/open-vm-tools/modules/linux/pvscsi/vmware_pack_init.h @@ -0,0 +1,65 @@ +/********************************************************* + * 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__ */ diff --git a/open-vm-tools/modules/linux/vmhgfs/hgfsEscape.c b/open-vm-tools/modules/linux/vmhgfs/hgfsEscape.c new file mode 100644 index 000000000..fb1e06108 --- /dev/null +++ b/open-vm-tools/modules/linux/vmhgfs/hgfsEscape.c @@ -0,0 +1,942 @@ +/********************************************************* + * 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 +#elif defined(__FreeBSD__) +# if defined(_KERNEL) +# include +# define strchr(s,c) index(s,c) +# else +# include +# endif +# define memmove(s1,s2,n) bcopy(s2,s1,n) +#elif defined(__APPLE__) && defined(KERNEL) +# include +#elif !defined(sun) +# include +# include +#else +# include +#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; +} diff --git a/open-vm-tools/modules/linux/vsock/include/vmciHostKernelAPI.h b/open-vm-tools/modules/linux/vsock/include/vmciHostKernelAPI.h new file mode 100644 index 000000000..e8e25a913 --- /dev/null +++ b/open-vm-tools/modules/linux/vsock/include/vmciHostKernelAPI.h @@ -0,0 +1,141 @@ +/********************************************************* + * 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__ */ +