/*static char *SCCSID = "@(#)pageio.h	6.2 91/02/22";*/
/*      SCCSID = @(#)pageio.h	6.2 91/02/22  */

/*      IBM/Microsoft Confidential
 *
 *      Copyright (c) IBM Corporation 1987, 1989
 *      Copyright (c) Microsoft Corporation 1987, 1989
 *
 *      All Rights Reserved
 */

typedef unsigned long hSFN;

/***ET PageCmd structure fields
 *
 * pgcmd_cmd:           command code for Read, Write, WriteVerify
 *                      Use same values as new req packets.
 *
 * pgcmd_priority:      Same values as for req packets.
 *
 * pgcmd_status:
 *
 *      Input:  MUST BE 0.
 *
 *      Output: Status byte
 *
 *              Low nibble is completion state.
 *
 *              IF (low nibble == 0)
 *                      then an error occured before
 *                      this operation reached the
 *                      device, so it was never even
 *                      attempted.  In this case the
 *                      high nibble is meaningless.
 *              ELSE (low nibble != 0)
 *                      this operation was attempted,
 *                      and the high nibble reports
 *                      whether it succeeded.
 *
 *                      IF (high nibble == 0)
 *                              Operation was a success
 *                      ELSE (high nibble != 0)
 *                              Operation was a failure
 *
 *              If the return value from the FSD_DoPageIO call
 *              was 0, then all operations were performed and
 *              completed successfully.  If it was non-0,
 *              then some operations failed, and some others
 *              may not even have been attempted.  Examine
 *              the status byte to see which ones.
 *
 *      NOTE -  Since the values of these bits may change
 *              at interrupt time, they must be tested with
 *              interrupts off.
 *
 * pgcmd_error:         I24 code that describes the error, as
 *                      defined in the new grouped-I/O packet
 *                      interface.  (Old I24 codes, plus some
 *                      new ones.)  ONLY defined if Status
 *                      indicates an error.
 *
 * pgcmd_addr:          Physical or Virtual (16:16) address of the page frame
 *                      depending on the flags set on return from OpenPageFile.
 *                      Must point to a page boundary.  Byte address.
 *
 * pgcmd_fileOffset:    Logical address in file of the disk page frame.
 *                      Must point to a page boundary in the file. Byte offset.
 */

typedef struct PageCmd {
    uchar_t     pgcmd_cmd;
    uchar_t     pgcmd_priority;
    uchar_t     pgcmd_status;
    uchar_t     pgcmd_error;
    ulong_t     pgcmd_addr;
    ulong_t     pgcmd_fileOffset;
} PageCmd;


/***ET PageCmdHeader structure fields
 *
 *
 * pgcmdh_InFlags:      Input bit flags
 *                      0   = force order.  Set if operations must be performed
 *                              in the order they appear in the list.
 *                      1-7 = reserved - must be zero
 *
 * pgcmdh_OutFlags:     Output bit flags - MUST BE ZERO ON ENTRY
 *
 *              bit
 *              0       Done - Set by the FSD (or emulator) when the operation
 *                      has completed.  All other status flags must be set
 *                      before the FSD sets the Done bit.
 *
 *                      NOTE - None of the status values for individual
 *                      commands should be examined until the Done bit is set.
 *
 *                      NOTE - When (if) async IO is implemented, the caller
 *                      must test the Done bit with interrupts off as it may
 *                      change at interrupt time.  For now, all IO is
 *                      synchronous so this is not necessary (the Done bit will
 *                      always be set before FSD_DoPageIO returns).
 *
 *              1       Error - Valid ONLY after the Done bit has been set.
 *                      Set by the FSD (or emulator) to indicate that an error
 *                      occured.  If this bit is set, the caller must check the
 *                      status values in each command to see which commands
 *                      failed.  If this is clear, then all requested IO
 *                      completed sucessfully so the caller does not need to
 *                      check the status of each command.
 *
 *              2-7     Reserved - must be zero
 *
 * pgcmdh_OpCount:      Number of operations.
 *
 * pgcmdh_Pad:          to preserve DWORD alignment
 *
 * pgcmdh_Reserved1;    (PostAddr)
 *
 *      global linear address, callable AT INTERRUPT TIME.
 *
 *      For async operations, this address will be called when the
 *      operation is complete, either due to error or success.  The
 *      address will be called with PostCookie passed as a parameter
 *      on the stack.  PostAddr will clean the stack.
 *      When the entry point is called, it must QUICKLY adjust any
 *      status, and return.
 *      Must always be set, since in this interface, all calls are
 *      async.  If sync is desired, the page manager will do the
 *      block and run itself.
 *      The routine may be called in interrupt context, so only
 *      interrupt time operations are allowed.
 *      The interrupt state (cli/sti) must be preserved.
 *      Any registers may be used, the caller will preserve the ones
 *      it cares about.
 *
 * pgcmdh_Reserved2;    (PostCookie)
 *
 *      cookie to be passed to PostAddr
 *
 *      Reserved2 (PostCookie) is intended to hold the cookie to be
 *      passed to the  routine to be called when the IO is complete.
 *      Note that we cannot pass the flat 32 bit pointer to the page
 *      command header as the cookie because the pointer has been
 *      thunked into a 16:16 pointer with a GDT and an FSD cannot
 *      convert it back.
 *
 * pgcmdh_Reserved3:    (Priority)
 *
 *      The reserved word is intended to hold a handle that can
 *      be used by the page manager to boost I/O request priority
 *      from low to high.  It's not clear if we'll need it, so
 *      it's reserved for now.
 *
 * On input, Reserved1, Reserved2 and Reserved3 do NOT have to be
 * zero.  They can any random value as they are unused.  When (if)
 * these functions are implemented, the pager will set the appropriate
 * values.  Old FSDs will still work because they will always complete
 * all IO before returning.
 *
 * pgcmdh_PageCmdList:  The actual commands.
 */

typedef struct PageCmdHeader {
    uchar_t             pgcmdh_InFlags;
    uchar_t             pgcmdh_OutFlags;
    uchar_t             pgcmdh_OpCount;
    uchar_t             pgcmdh_Pad;
    ulong_t             pgcmdh_Reserved1;
    ulong_t             pgcmdh_Reserved2;
    ulong_t             pgcmdh_Reserved3;
    struct PageCmd      pgcmdh_PageCmdList[1];
} PageCmdHeader;

/*XLATOFF*/
typedef struct PageCmdHeader_s {
    uchar_t             pgcmdh_InFlags;
    uchar_t             pgcmdh_OutFlags;
    uchar_t             pgcmdh_OpCount;
    uchar_t             pgcmdh_Pad;
    ulong_t             pgcmdh_Reserved1;
    ulong_t             pgcmdh_Reserved2;
    ulong_t             pgcmdh_Reserved3;
} PageCmdHeader_t;
/*XLATON*/

extern  int     FSD_OpenPageFile(ulong_t * pFlags, char * Name,
                                 ulong_t * hFile, ulong_t * pcMaxReq);

extern  int     FSD_AllocatePageSpace(ulong_t hFile, ulong_t lSize,
                                      ulong_t lWantContig);

extern  int     FSD_DoPageIO(ulong_t hFile, PageCmdHeader * p);

extern  int     FSD_FlushBuf(ushort_t hVPB, ushort_t usDiscard);

extern  int     FSD_GetPageMediaInfo(ulong_t hFile, ulong_t * pFlags);

// FSD_OpenPageFile Flags values
#define PGIO_FIRSTOPEN  0x00000001
#define PGIO_PADDR      0x00004000
#define PGIO_VADDR      0x00008000

// FSD_DoPageIO InFlags values
#define PGIO_FI_ORDER   0x01

// FSD_DoPageIO OutFlags values
#define PGIO_FO_DONE    0x01
#define PGIO_FO_ERROR   0x02

// FSD_DoPageIO Status values
#define PGIO_ATTEMPTED  0x0f
#define PGIO_FAILED     0xf0


// Structure of a pageio save block; this is where we store some per-open
// data.  Each open needs a GDT selector for later thunking (we allocate it
// at open time because we don't want to grow the GDT at page time!!).  Each
// open also needs a buffer for later saving critical TCB variables into; again
// we can't allocate at page time.  The SFT pointer for an open is also stored
// here.  We pass the linear (0:32) pointer to one of these blocks as the handle
// to the page file.
// We also save a flag telling us whether the device the FSD is opening the swap
// file onto can support scatter/gather.  This allows us to call the emulator
// routine for DoPageIO instead of having the overhead of calling the FSD only
// to have it tell us it can't handle the DoPageIO request.
//
typedef struct PgIOSaveBlock {
    ushort_t    PgIOSave_GDT;           // will hold gdt selector
    ushort_t    PgIOSave_flags;         // flag (see above)
    ulong_t     PgIOSave_SFT;           // will be 16:16 pointer
    uchar_t     PgIOSave_TCB;           // tcb var save area
} PgIOSaveBlock;
