SCCSID  equ     "@(#)pageio.asm 6.11 92/01/22"
;
;       IBM/Microsoft Confidential
;
;       Copyright (c) IBM Corporation 1987, 1989
;       Copyright (c) Microsoft Corporation 1987, 1989
;
;       All Rights Reserved
;
;
; IFS/FSD SUPPORT FOR EFFICIENT PAGE IO
;
; External                      Internal
;
;  _FSD_OpenPageFile
;  FS_EM_OpenPageFile
;                               w16_OpenPageFile
;  _FSD_AllocatePageSpace
;  FS_EM_AllocatePageSpace
;                               w16_AllocatePageSpace
;  _FSD_DoPageIo
;  FS_EM_DoPageIO
;                               w16_DoPageIo
;
;  _FSD_GetPageMediaInfo
;
; The purpose of this module is to provide an efficient mechanism for
; paging.  Three calls are provided that enable the page manager to
; open and size a swap file, and to perform page I/O.  The code for these
; calls performs some housekeeping and calls the underlying FSD.
;
; FSD's are not required to support the special paging calls used by the
; FSD_ routines in this module.  If an FSD is loaded that does not export
; entry points for these routines, the relevant entries in the FSC will be
; set to point to emulator routines, whose job is to use existing standard
; file system calls to emulate the functionality of the new paging calls.
; The details of whether the FSD performed the requested function or the
; emulator routine performed it will therefore be transparent to both the
; FSD_ routine and its caller.
;
; Each pagee I/O FSD routine has a 16 and 32 bit component.  The two
; components work together; the 16-bit portion is not designed to be directly
; callable.  The (32-bit) C-callable portions are named _FSD_xxx, and the
; 16-bit assembly portions are named w16_xxx.
;
;   MODIFICATION HISTORY:
;   11/27/95 - MLM defect 72417
;      moved from PTDA to TCB: PathNameType, WFP_Start, cMeta, Sattrib
;
include dosseg.inc
include basemaca.inc
include osmaca.inc
include fnofs.inc
include oldmaca.inc
include devsym.inc
include mi.inc
include sft.inc
include fsc.inc
include curdir.inc
include vpb.inc
include tkexport.inc
include mft.inc
include opncreat.inc
include filemode.inc
include filesys.inc
include error.inc
include selxport.inc
include osconst.inc
include pgexport.inc
include vmexport.inc
include vmowner.inc
include seldesc.inc
include pageio.inc
include protmode.inc
include shutdown.inc
include strat2.inc
include dossymc.inc

        ModName , FNO_PAGEIO_ASM

                                                ;72417 removed PTDA entries now
                                                ;      in TCB

        ReferTask       CurrTCB,WORD

        ReferFlat       _pTCBCur,dword

        ReferGDT        GDT_FSC,WORD        ; GDT selector for FSC segment

        EXTRN           FSD_ChgFilePtr:near
        EXTRN           FSD_Commit:near
        EXTRN           FSD_NewSize:near
        EXTRN           FSD_Read:near
        EXTRN           FSD_Write:near
        EXTRN           WakeShutdownThread:near

; These are for the OpenPageFile routines (which are in INITCODE)

        EXTRNFAR        IncVPBRef
        EXTRNFAR        DecVPBRef
        EXTRNFAR        SFNAlloc
        EXTRNFAR        TransPath
        EXTRNFAR        MFTclose
        EXTRNFAR        StrCpy
        EXTRNFAR        SFLinkFree
        EXTRNFAR        DOS_OpenCreate
        EXTRNFAR        UseCache


        EXTRN32         _IOGetMediaInfo
        EXTRN32         _VMAllocKHB
        EXTRN32         _VMReallocKHB
        EXTRN32         _VMFreeKHB
        EXTRN32         _SELAllocGDT
        EXTRN32         _SELFreeGDT
        EXTRN32         _SELSetDescInfo
        EXTRN32         ioSaveTCB
        EXTRN32         ioRestoreTCB
        EXTRNF32        MFT_Enter
        EXTRN32         _FAT_DOPAGEIO

        EXTRN16         w16_FSD_FlushBuf

; no TCB save area needed if not emulating
PGIO_SAVE_SIZE_NOEM     equ     (size PgIOSaveBlock - 1)
PGIO_SAVE_SIZE_EM       equ     (PGIO_SAVE_SIZE_NOEM + TCBIOCopySize)

; values for PgIOSave_flags

PGIO_EMULATE    equ     01h     ; device doesn't support scatter/gather so we
                                ; emulate DoPageIO for this swap file.

; open mode, flag and attrib flags
PGIO_OPENMODE   equ     open_for_both OR sharing_compat OR locality_semirandom OR open_no_cache
PGIO_OPENFLAG1  equ     nexist_create OR exist_replace
PGIO_OPENFLAG2  equ     nexist_fail  OR exist_open
PGIO_FILEATTR   equ     0

; BUGBUG - these should be defined in fsd.h
PGIO_FIRSTOPEN  equ     00000001h
PGIO_PADDR      equ     00004000h
PGIO_VADDR      equ     00008000h

PGIO_EM_MAXREQ  equ     8       ; max requests for emulator

PGIO_PAGESIZE   equ     4096    ; page size = 4k

; PIS_PADDR and PIS_VADDR are defined in pgexport.inc while
; PGIO_PADDR and PGIO_VADDR are defined in fsd.inc.
; They better match and not conflict with PGIO_FIRSTOPEN!

.errnz PIS_PADDR - PGIO_PADDR
.errnz PIS_VADDR - PGIO_VADDR
.erre  PIS_PADDR - PGIO_FIRSTOPEN
.erre  PIS_VADDR - PGIO_FIRSTOPEN

CpuMode 386

FARCODE HIGH32
CINIT_TEXT segment
;
;***    _FSD_OpenPageFile - C interface layer for FS_OpenPageFile function
;
;       This is the 32-bit portion of FSD_OpenPageFile.
;
;       This routine is the C-callable portion of FSD_OpenPageFile.
;       At open time,  we need to allocate a GDT selector for later thunks,
;       a TCB save area, and an SFT.  We do the first 2 in this routine
;       and let w16_OpenPageFile take care of the SFT.  The GDT selector
;       and 2 pointers are stored as an entry in the private pageio
;       allocation table.
;
;       We make use of registers to pass pointers around.  This enables us
;       to avoid a couple of thunks, but care must be taken.  THIS ROUTINE
;       IS ONLY USABLE AT INIT TIME, because it relies on ss to maintain its
;       context throughout the duration of the call.
;
;       From C: FSD_OpenPageFile(pFlags, pszPagePath, pHandle, pcMaxReq)
;
;       ENTRY:  SS:ESP          return address
;               SS:(ESP+4)      pFlags          - flags on input and output
;               SS:(ESP+8)      pszPagePath     - pointer to swap filename
;               SS:(ESP+C)      pHandle         - where to put handle to file
;               SS:(ESP+10)     pcMaxReq        - where to put max number of
;                                                 entries in cmd list
;
;       RETURNS: error code (or 0 for no error) in eax
;
;       USES: EAX,ECX,EDX
;
;       PSEUDOCODE:
;
;       rc = _alloc(sizeof(pageio save area))   /* block for per-open info */
;       if (!rc) {                              /* block allocated ok */
;           rc = _SELAllocGDT(&savearea.GDT)    /* allocate GDT selector */
;           if (!rc) {                          /* selector was allocated */
;               _SELSetDescInfo(savearea.GDT,   /* get 16:16 ptr to filename */
;                               pathname pointer,...)
;               carry status = w16_OpenPageFile(open flags, 16:16 filename ptr)
;               if (NC) {
;                   save_block.SFT = eax        /* save sft ptr in save area */
;                   *MaxReq = ebx               /* set caller's variables */
;                   *Flags = ecx
;                   rc = 0                      /* indicate no error */
;               } else goto exit1               /* eax=err from 16bit worker */
;           } else goto exit2                   /* error allocating GDT */
;       } else goto exit3                       /* error allocting save block */
;
;       exit1:
;         _SELFreeGDT(save_block.GDT)
;       exit2:
;         _free(pageio save block)
;       exit3:
;         return(rc)
;
Procedure _FSD_OpenPageFile
        ASSUME  DS:FLAT,ES:FLAT,FS:NOTHING,GS:NOTHING,SS:TASKAREA

ArgVar          _opf_pFlags,DWORD       ; bit0=1 = first open
ArgVar          _opf_filename,DWORD     ; pointer to swap file name
ArgVar          _opf_pHandle,DWORD      ; pointer to swap file handle
ArgVar          _opf_pMaxReq,DWORD      ; pointer to max command list size

LocalVar        _opf_pAllocStruc,DWORD  ; pointer to block for tcb vars

        EnterProc

        SaveReg <EBX,ESI,EDI>

; First we allocate a block of memory to hold the GDT selector, flags,
; pSFT and TCB save space.  The space for TCB variables is allocated,
; but will be realloced away if we don't neet it.
; TCB variables only need to be saved when emulating.

        lea     eax,_opf_pAllocStruc    ; offset to localvar pointer
        SSToDS  eax                     ; (flat:)EAX -> localvar

        CCall   _VMAllocKHB,<VM_HKH_PUB_RESRW,PGIO_SAVE_SIZE_EM,PAGEIOOWNER,PG_RESIDENT,eax>
        or      eax,eax                 ; error?
        jnz     _opfx                   ; yes, fail the open

; Now we have to allocate a GDT selector for use in address xlations.
;
        mov     ebx,_opf_pAllocStruc    ; pageio save area we just allocated
        .errnz  PgIOSave_GDT            ; must be first field for next line
        CCall   _SELAllocGDT,<ebx>      ; allocate GDT selector
        or      eax,eax                 ; error?
        LJNZ    _opfx2                  ; yes, deallocate save area and exit
;
; Thunk pointer to filename by using the GDT selector we just allocated
;
        mov     esi,[_opf_pFlags]       ; ESI -> open control flags
        push    [esi]                   ; push flags

        movzx   ecx,[ebx].PgIOSave_GDT  ; isolate GDT selector
        xor     eax,eax
        CCall   _SELSetDescInfo, <SELSD_ALL, D_DATA0, ecx, MAXPATHLEN, [_opf_filename], eax, eax, eax>
        push    word ptr [ebx].PgIOSave_GDT ; (16:16) segment of filename
        push    word ptr 0              ; (16:16) offset of filename
        CALL16  w16_OpenPageFile        ; if NC, EAX=pSFT, EBX=MaxReq, ECX=flags
        jc      SHORT _opfx1            ; error, ax = error code

; eax = max request size
; ebx = flags
; ecx = pointer to SFT

        mov     esi,[_opf_pFlags]       ; FLAT:ESI -> flags var in caller space
        mov     [esi],ebx               ; store flags where caller expects them
        mov     ebx,_opf_pAllocStruc    ; point to pageio save block
        mov     [ebx].PgIOSave_SFT,ecx  ; save pSFT in save area for this file
        mov     [ebx].PgIOSave_flags,0  ; initialize swap file flags
        or      eax,eax                 ; max request size=0?
        jnz     SHORT _opf40            ; no, continue

; emulating DoPageIO so we set the emulate flag and cMaxReq.

        or      [ebx].PgIOSave_flags,PGIO_EMULATE ; must emulate DoPageIO
        mov     eax,PGIO_EM_MAXREQ      ; device doesn't support pageio.
        jmp     SHORT _opf50            ; no, continue


; NOT emulating DoPageIO so we realloc the pageio block.

_opf40: SaveReg <eax,ecx>
        lea     eax,_opf_pAllocStruc    ; offset to localvar pointer
        SSToDS  eax                     ; (flat:)EAX -> localvar

        CCall   _VMReallocKHB,<VM_HKH_PUB_RESRW,eax,PGIO_SAVE_SIZE_NOEM,0>
        or      eax,eax                 ; error? (shrinking should not fail)
        jnz     SHORT _opfie1           ; yes, internal error

        RestoreReg <ecx,eax>

_opf50: mov     esi,[_opf_pMaxReq]      ; FLAT:ESI -> max cmd list req size
        mov     [esi],eax               ; store max size in caller's space

        mov     esi,[_opf_pHandle]      ; FLAT:ESI -> handle to open page file
        mov     [esi],ebx               ; store ptr to save area as handle
        xor     eax,eax                 ; indicate no error
        jmp     SHORT _opfx             ; return to caller
;
; eax = error code from 16-bit worker
;
_opfx1: movzx   eax,ax                  ; thunk error code
        SaveReg <eax>                   ; save return code
        mov     ebx,_opf_pAllocStruc    ; point to pageio save area
        .errnz  PgIOSave_GDT            ; this field must be first in save area
        CCall   _SELFreeGDT,<[ebx]>     ; free GDT selector
        RestoreReg <eax>                ; restore error code
;
; ebx -> pageio save area
; eax = error code
;
_opfx2: SaveReg <eax>                   ; save return code
        CCall   _VMFreeKHB,<VM_HKH_PUB_RESRW,ebx>
        RestoreReg <eax>                ; return code

_opfx:  RestoreReg <EDI,ESI,EBX>
        LeaveProc
        RETC

_opfie1: Panic <"_FSD_OpenPageFile: realloc failed">

EndProc _FSD_OpenPageFile

;***EP  _FSD_GetPageMediaInfo - get media info for swap file
;
;       This routine is a wrapper for IO_GetMediaInfo.
;
;       ENTRY:  SS:ESP          return address
;               SS:(ESP+4)      handle          - handle to open swap file
;               SS:(ESP+8)      pointer to flags dword
;       RETURN: (eax)           error code
;
Procedure _FSD_GetPageMediaInfo
        ASSUME  DS:FLAT,ES:FLAT,FS:NOTHING,GS:NOTHING,SS:TASKAREA

ArgVar  gpmi_hPagefile,DWORD            ; handle to open page file
ArgVar  gpmi_pflags,DWORD               ; pointer to flags

        EnterProc
        SaveReg <edi>

        mov     edx,[gpmi_hPagefile]
        mov     edi,[edx].PgIOSave_SFT
        mov     eax,edi
        ror     eax,16
        mov     fs,ax
        movzx   eax,fs:[di].sf_fsi.sfi_selfsfn          ;#### DCR 1176 Changed to eax
        CCALL32 _IOGetMediaInfo <eax,[gpmi_pflags]>     ;#### DCR 1176 Changed to eax
        RestoreReg <edi>
        LeaveProc
        RETC
EndProc _FSD_GetPageMediaInfo

CINIT_TEXT ends


FARCODE HIGH32
SMLOCK_TEXT segment

;***    _FSD_AllocatePageSpace - C interface layer for FS_AllocatePageSpace
;
;       This is the 32-bit portion of FSD_AllocatePageSpace
;
;       This routine is the C-callable portion of FSD_AllocatePageSpace.
;       Since this routine will be called on behalf of another process, we
;       need to save TCB variables.  Note that no pointer thunks are
;       needed here; this routine simply sets up parameters for the 16-bit
;       worker and calls out to it.
;
;       From C: FSD_AllocatePageSpace(handle, ulSize, ulWantContig)
;
;       ENTRY:  SS:ESP          return address
;               SS:(ESP+4)      handle          - handle to open swap file
;               SS:(ESP+8)      ulSize          - new file size
;               SS:(ESP+C)      ulWantContig    - contiguity request
;
;       Note that the handle is a pointer to a save area where we have saved a
;       pointer to the file's SFT and other file-related variables.
;
;       RETURNS: error code (or 0 for no error) in eax
;
;       USES: EAX,ECX,EDX
;
;       PSEUDOCODE:
;
;       SaveAreaPtr = handle                    /* caller's handle parameter */
;       if (emulating)
;           ioSaveTCB(SaveAreaPtr.TCB)          /* save volatile tcb vars */
;       rc = w16_AllocatePageSpace(SaveAreaPtr.SFT, ulSize, ulWantContig);
;       if (emulating)
;       ioRestoreTCB(SaveAreaPtr.TCB)           /* restore saved tcb vars */
;       return(rc);
;

Procedure _FSD_AllocatePageSpace
        ASSUME  DS:FLAT,ES:FLAT,FS:NOTHING,GS:NOTHING,SS:TASKAREA

ArgVar  _aps_hPagefile,DWORD            ; handle to open page file
ArgVar  _aps_size,DWORD                 ; new file size
ArgVar  _aps_contig,DWORD               ; contiguity value
LocalVar fTK_FF_BUF,BYTE

        EnterProc
        SaveReg <EBX,ESI,EDI>

        mov     fTK_FF_BUF,0
        mov     ebx,_aps_hPagefile      ; get pointer to pageio save area

        test    [ebx].PgIOSave_flags,PGIO_EMULATE ; emulating?
        jz      _aps10                  ; no, don't save TCB vars

        mov     esi,[_pTCBCur]                ; b724126
        test    [esi].TCBForce_Flg,FF_BUF     ; buffer assigned?
        jz      _aps1
        and     [esi].TCBForce_Flg,not FF_BUF ; make like one isn't assigned
        inc     fTK_FF_BUF

_aps1:
        lea     edi,[ebx].PgIOSave_TCB  ; pointer to tcb save portion
        SaveReg <edi>                   ; save tcb save area pointer
        CCALL32 ioSaveTCB               ; save relevant TCB variables

_aps10: SaveReg <ebx>                   ; ebx -> save area

        push    [ebx].PgIOSave_SFT      ; push file's pSFT
        push    [_aps_size]             ; push new file size
        push    [_aps_contig]           ; push contiguity dword
        CALL16  w16_AllocatePageSpace
        movzx   eax,ax

        RestoreReg <ebx>                ; ebx -> save area
        test    [ebx].PgIOSave_flags,PGIO_EMULATE ; emulating?
        jz      _aps30                  ; no, don't restore TCB vars

        RestoreReg <esi>                ; esi -> tcb var iable save area
        CCALL32 ioRestoreTCB            ; restore tcb vars

        cmp     fTK_FF_BUF,0            ; b724126
        je      _aps30
        mov     esi,[_pTCBCur]
        or      [esi].TCBForce_Flg,FF_BUF ; restore the flag

_aps30:
        RestoreReg <EDI,ESI,EBX>
        LeaveProc
        RETC

EndProc _FSD_AllocatePageSpace

;
;***    _FSD_DoPageIO - C interface layer for FS_DoPageIO function
;
;       This is the 32-bit portion of FSD_DoPageIO
;
;       This routine is the C-callable portion of FSD_DoPageIO.  Since this
;       routine will be called on behalf of another process, we need to save TCB
;       variables.  We also have to thunk the pointer to the cmd list, as it is
;       given as 0:32 and we need to pass 16:16 to w16_DoPageIO.
;
;       The 16-bit portion does the real work of this routine.  Here we are
;       mostly concerned with setting up parameters for w16_DoPageIO.
;
;       From C: FSD_DoPageIO(pCMDList)
;
;       ENTRY:  SS:ESP          return address
;               SS:(ESP+4)      hPageFile       - handle to page file
;               SS:(ESP+8)      pCMDLIST        - pointer to list of pageio
;                                                 commands to perform
;
;       RETURNS: error code (or 0 for no error) in eax
;
;       USES: EAX,ECX,EDX
;
;       PSEUDOCODE:
;
;       CMDPtr = pCMDList               /* point to command list */
;       SaveAreaPtr = hPageFile /* handle is pointer to save area for file */
;       if (emulating)
;          ioSaveTCB(SaveAreaPtr.TCB)           /* save volatile tcb vars */
;
;       listsize = (CMDPtr.Opcount * sizeof(CMD)) + sizeof(CMDList header)
;
;       _SELSetDescInfo(SaveAreaPtr.GDT,&CMDList, listsize, ...)  /* 16:16 */
;                                                        /* ptr to cmd list */
;       rc = w16_DoPageIO(SaveAreaPtr.GDT:0,SaveAreaPtr.pSFT,SaveAreaPtr.flags)
;                                                       /* call 16-bit worker */
;       if (emulating)
;          ioRestoreTCB(SaveAreaPtr.TCB)        /* restore saved tcb vars */
;       return(rc);

Procedure _FSD_DoPageIO
        ASSUME  DS:FLAT,ES:FLAT,FS:NOTHING,GS:NOTHING,SS:TASKAREA

ArgVar  _dpio_hPageFile,DWORD           ; handle page file = ptr to save area
ArgVar  _dpio_cmdlst,DWORD              ; pointer to command list

        EnterProc
        SaveReg <EBX,ESI,EDI>

        mov     ebx,_dpio_hPageFile     ; ebx -> save area

        test    [ebx].PgIOSave_flags,PGIO_EMULATE ; emulating?
        jz      _dpi10                  ; no, don't save TCB vars

        lea     edi,[ebx].PgIOSave_TCB  ; save area for tcb vars
        SaveReg <edi>                   ; save ptr to tcb save area
        CCALL32 ioSaveTCB               ; save tcb vars

        ; since this interface is for the swapper, don't call
        ; the hard error deamon since this can cause deadlock
        ; in the swapper when calling to swap in the hard error deamon
        mov     esi,_pTCBCur
        or      [esi].TCBJfnFlag,JFN_FAIL ; ar11359

; We have to thunk the pointer to the cmdlst, from 0:32 -> 16:16.  We'll use
; the selector we've preallocated.

_dpi10: mov     esi,_dpio_cmdlst        ; adress the caller's command list
        movzx   eax,[esi].pgcmdh_OpCount ; get number of operations
        dec     ax                      ; account for command in header struc
        imul    ax,size PageCmd         ; ax = byte size of commands
        add     ax,size PageCmdHeader   ; ax = size of list
;       dec     ax                      ; ax = limit for GDT selector
        movzx   edx,[ebx].PgIOSave_GDT  ; isolate GDT
        xor     ecx,ecx
        CCall   _SELSetDescInfo, <dword ptr SELSD_ALL, D_DATA0, edx, eax, esi, ecx, ecx, ecx>

        SaveReg <ebx>                   ; ebx -> save area

        push    esi                     ; 0:32 pointer of command list
        push    [ebx].PgIOSave_GDT      ; (16:16) segment of command list
        push    word ptr 0              ; (16:16) offset of command list
        push    [ebx].PgIOSave_SFT      ; push pointer to SFT
        push    word ptr [ebx].PgIOSave_flags   ; push instance flags

        CALL16  w16_DoPageIO
        movzx   eax,ax

        RestoreReg <ebx>                ; ebx -> save area
        test    [ebx].PgIOSave_flags,PGIO_EMULATE ; emulating?
        jz      _dpi20                  ; no, don't restore TCB vars

        RestoreReg <esi>                ; tcb save area
        CCALL32 ioRestoreTCB            ; restore tcb vars

_dpi20: RestoreReg <EDI,ESI,EBX>
        LeaveProc
        RETC

EndProc _FSD_DoPageIO

SMLOCK_TEXT ends


        FARCODE INIT
INITCODE segment

BREAK <w16_OpenPageFile - open paging swap file>
;
;***    w16_OpenPageFile -- open paging swap file.
;
;       This is the 16-bit portion of FSD_OpenPageFile.
;
;       This routine will open a swap file.  The same file may be opened
;       more than once.  The first open will create the file.  The file
;       is always entered into sharing with sharing_compat.  This routine
;       may be called an arbitrary number of times, to open/create as many
;       paging files as the paging system needs.  It is up to the caller
;       to specify whether this is the first open for this file.  The file
;       will be replaced if it exists (barring the absence of sharing
;       violations) when first opened, and subsequent opens will have the
;       effect of creating multiple SFTs that refer to the same file.
;
;       The flags parameter is also used to pass back a bits indicating
;       what type of address the pager must pass in Command lists
;       (see pageio.h).
;
;       ENTRY: parameters on stack--    DWORD flags.  Bit0=1 means first open
;                                                       for this file
;                                       DWORD path\filename of swap file
;
;       EXIT:   CY: AX = (non-0) error code from FSD (or emulator)
;               NC: no error.
;                       eax = max # requests that will fit in cmd list
;                       ebx = flags
;                       ecx = 16:16 pointer to SFT
;
;       USES: all
;

        ASSUME  DS:NOTHING,ES:NOTHING,SS:TASKAREA
Procedure w16_OpenPageFile,<far16>
ArgVar          opf_filename,DWORD      ; pointer to swap file name
ArgVar          opf_InFlags,DWORD       ; bit0=1 = first open

LocalVar        opf_pSFT,DWORD          ; pointer to sft we allocate
LocalVar        opf_MaxReq,DWORD
LocalVar        opf_OutFlags,DWORD
LocalVar        opf_openbuf,PMPATHLEN
LocalVar        opf_dummy,WORD          ; KLUDGE: see gshare.asm
LocalVar        opf_dummycds,<SIZE curdir>

        EnterProc
        SaveReg <ds,es>

        CALLFAR SFNAlloc                ; allocate SFT
        jc      opfx20                  ; error, exit

        mov     opf_pSFT.Segmt,es       ; set local var pointer to sft
        mov     opf_pSFT.Offst,di

        mov     eax,opf_InFlags
        and     eax,NOT (PGIO_VADDR OR PGIO_VADDR) ; clear addr type bits
        mov     opf_OutFlags,eax        ; initialize flags fsd will see.

; set up various TCB and SFT fields

        xor     eax,eax
        mov     si,TASKAREA:CurrTCB
                                        ;72417 moved from PTDA to TCB
        mov     TASKAREA:[si].TCBSattrib,ax
                                        ;72417 end
        mov     TASKAREA:[si].TCBModeFlags,ax           ; normal open
        mov     TASKAREA:[si].TCBThisSFT.Offst,di
        mov     TASKAREA:[si].TCBThisSFT.Segmt,es
        mov     es:[di].sf_fsi.sfi_mode,PGIO_OPENMODE
        mov     es:[di].sf_fsi.sfi_mode2,ax
        mov     es:[di].sf_fsi.sfi_position,eax
        mov     es:[di].sf_fsi.sfi_hVPB,NULLVPB
        mov     es:[di].sf_fsi.sfi_type,STYPE_FILE      ; default type
        mov     es:[di].sf_fsi.sfi_size,eax             ; initial size=0

; By using opf_openbuf we preclude use of this routine at any point
; except init time!!

        lea     di,opf_dummycds
        mov     bx,TASKAREA:[CurrTCB]                      ;### PTR B720732
        mov     TASKAREA:[bx].TCBpTmpCDS.Offst,di       ; Initialize TCBpTmpCDS ;### PTR B720732
;### PTR B720732        mov     TASKAREA:[ptda_pCDS],di ; Initialize ptda_pCDS

        lea     di,opf_openbuf          ; TaskArea:di -> wfp buffer
        lds     si,opf_filename         ; ds:si -> swap filename
        CALLFAR TransPath               ;
        LJC     opfx15                  ; error, exit ;### PTR B718280 Changed from opfx10

        TaskContext <ds>,di             ; ds = TASKAREA
        TaskContext <es>,di,NOASSUME    ; es = TASKAREA
        lea     di,opf_openbuf          ; es:di -> wfp swap file name
        mov     si,di                   ; ds:si -> wfp swap file name
        CALLFAR StrCpy                  ; uppercase the name

                                        ;72417 moved from PTDA to TCB
        SetBP_CurrTCB
        test    TASKAREA:[bp].TCBPathNameType,PNType_LOCFILE OR PNType_REMFILE
        UnSetBP_CurrTCB
        LJZ     opfx10                  ; error, must be local or remote file

        SetBP_CurrTCB
        cmp     [bp].TCBcMeta,-1        ; meta chars?
        UnSetBP_CurrTCB
                                        ;72417 end
        jne     opfx10                  ; yes error

        les     di,opf_pSFT             ; es:di -> SFT
        mov     si,TASKAREA:[CurrTCB]
        mov     eax,TASKAREA:[si].TCBThisFSC
        mov     es:[di].sf_FSC,eax      ; sf_FSC is now set up

        ASSUME  es:nothing
                                        ;72417 moved from PTDA to TCB
        SetBP_CurrTCB
        test    [bp].TCBPathNameType,PNType_UNC
        UnSetBP_CurrTCB
                                        ;72417 end
        jnz     opf60                   ; no sharing or VPB for UNC

        SaveReg <BP>
        mov     cx,mft_opanylock        ; break oplock or opbatch
        CALL32  MFT_Enter,nocheck       ; Enter sft into sharing set
        RestoreReg <BP>                 ; BP -> LocalVar frame
        les     di,opf_pSFT             ; es:di -> SFT
IFDEF FSSTRICT
        LJC     opfie1
ENDIF

        mov     si,TASKAREA:[CurrTCB]
        SaveReg <BP>
        mov     bp,TASKAREA:[si].TCBThishVPB    ; bp = hVPB
        mov     es:[di].sf_fsi.sfi_hVPB,bp      ; Set up sfi_hVPB in SFT
        CALLFAR IncVPBRef                       ; reference VPB
        RestoreReg <BP>

; push parms and call the FSD (or emulator)
;
; ES:DI -> sft

        ASSUME  ds:nothing

opf60:  lea     ax,opf_OutFlags         ; push pointer to open flags
        push    ss
        push    ax
        lea     ax,opf_MaxReq           ; push pointer to max cmd list req size
        push    ss
        push    ax
        push    ss
                                        ;72417 moved from PTDA to TCB
        mov     bx,bp
        mov     bp,CurrTCB
        push    [bp].TCBWFP_Start       ; push pointer to swap file name
        mov     bp,bx
                                        ;72417 end
        lea     ax,es:[di].sf_fsi       ; file system independent part of sft
        push    es
        push    ax
        lea     ax,es:[di].sf_fsd       ; file system dependent part of sft
        push    es
        push    ax
        push    PGIO_OPENMODE           ; push  open mode
        mov     ax,PGIO_OPENFLAG1       ; assume firstopen
        test    opf_OutFlags,PGIO_FIRSTOPEN
        jnz     opf65
        mov     ax,PGIO_OPENFLAG2       ; not firstopen
opf65:  push    ax                      ; push open flag
        push    PGIO_FILEATTR           ; push file attribute
        push    0                       ; unused dword
        push    0
        cmp     word ptr es:[di].sf_FSC,FSC_LOCAL       ; FAT?
        jae     SHORT opf80                             ; yes, go call emulator
        lfs     bx,es:[di].sf_FSC
        call    fs:[bx].FS_OPENPAGEFILE
;       call    es:[di].sf_FSC.FS_OPENPAGEFILE          ; not FAT, call FSD
        jmp     SHORT opf90
opf80:  CALLFAR FS_EM_OpenPageFile      ; call emulator routine for FAT
;
; fsd or emulator has returned.  ax=error code.
;
opf90:  or      ax,ax                   ; error?  (clears carry)
        jnz     SHORT opfx10            ; yes, go clean up
        mov     eax,opf_MaxReq          ; eax = max size of cmd list
        mov     ebx,opf_OutFlags        ; ebx = phys/virt flag from fsd
        mov     ecx,opf_pSFT            ; ecx -> SFT
        les     di,opf_pSFT             ; es:di -> SFT
        mov     es:[di].sf_ref_count,1  ; sft opened
        jmp     SHORT opfxx             ; done

; error exit cleanup

opfx10: TaskContext <DS>
        les     di,opf_pSFT             ; es:di -> SFT
        SaveReg <BP>
        mov     bp,es:[di].sf_fsi.sfi_hVPB
        CALLFAR DecVPBRef               ; no longer referencing VPB
        RestoreReg <BP>

                                        ;72417 moved from PTDA to TCB
        SetBP_CurrTCB
        test    [bp].TCBPathNameType,PNType_UNC ; Was this entered in the sharing set?
        UnSetBP_CurrTCB
                                        ;72417 end
        jnz     SHORT opfx15            ; No, Don't remove from MFT
        mov     bx,-1                   ; no handle
        CALLFAR MFTclose

opfx15: les     di,opf_pSFT             ; es:di -> SFT
        mov     es:[di].sf_ref_count,0  ; release sft
        CALLFAR SFLinkFree
opfx20: stc
        mov     ax,ERROR_FILE_NOT_FOUND

opfxx:  RestoreReg <es,ds>
;### PTR B720732        mov     SS:[ptda_pCDS],0        ; Clear ptda_pCDS
        LeaveProc
        RETP    ?aframe                 ; must match parameters!!!

opfie1: Panic <'FSD_OpenPageFile: MFT_Enter'>
EndProc w16_OpenPageFile


;***    FS_EM_OpenPageFile - Emulate FS_OpenPageFile
;
;
;       ENTRY   On entry the stack contains:
;                 pFlags        - ptr to flags
;                 pcMaxReq      - ptr to max # of entries in a PageCommandList
;                 pszName       - fully qualified pathname of swap file
;                 psffsi        - ptr to filesys indep portion of SFT
;                 psffsd        - ptr to filesys depen portion of SFT
;                 OpenMode      - open mode to use (see DosOpen)
;                 OpenFlag      - open flag to use (see DosOpen)
;                 Attr          - attribute to use (see DosOpen)
;                 ulRes         - unused dword (reserved)
;
;
;       EXIT    if some error
;                   AX = non-zero error code
;               if success
;                   AX = zero
;                   pFlags, psffsi, psffsd, and pcMaxReq filled in
;
;       ALGORITHM
;
;       if (FAT)
;           err = DOS_OpenCreate(...);
;       else (FSD)
;           err = FS_OpenCreate(...);
;           if (err)
;               return(err);
;           FS_SetSwap(....)


Procedure  FS_EM_OpenPageFile,faronly
        assume  ds:nothing, es:nothing

ArgVar  mopf_ulRes,DWORD        ; unused dword (reserved)
ArgVar  mopf_Attr,WORD          ; Attribute (see DosOpen)
ArgVar  mopf_OpenFlag,WORD      ; Open Flag (see DosOpen)
ArgVar  mopf_OpenMode,WORD      ; Open Mode (see DosOpen)
ArgVar  mopf_psffsd,DWORD       ; pointer to filesys depen portion of SFT
ArgVar  mopf_psffsi,DWORD       ; pointer to filesys indep portion of SFT
ArgVar  mopf_pszName,DWORD      ; fully qualified pathname of swap file
ArgVar  mopf_pcMaxReq,DWORD     ; ptr to max # of entries in a PageCommandList
ArgVar  mopf_pFlags,DWORD       ; ptr to flags

LocalVar        mopf_Trash,WORD ; pass pointer to this for unwanted info

        EnterProc

        TaskContext <ds>                        ; Get TASKAREA addressability
        mov     si,TASKAREA:CurrTCB             ; ds:si -> CurrTCB
        les     di,TASKAREA:[si].TCBThisSFT     ; es:di -> SFT

        cmp     word ptr es:[di].sf_FSC,FSC_LOCAL       ; FAT?
        LJAE    mopf50                                  ; yes, go call FAT

; FSD - call FS_OPENCREATE and FS_SETSWAP

        mov     di,TASKAREA:CurrTCB             ; (di) = current TCB     ;### PTR B720732
        les     di,TASKAREA:[di].TCBThisCDS     ; (es:di) = CDS pointer  ;### PTR B720732
;### PTR B720732        les     di,TASKAREA:[ThisCDS]   ; es:di -> CDS
        lea     ax,es:[di].cd_fsi
        push    es
        push    ax                      ; pcdfsi -> fs independent part of CDS

        lea     ax,es:[di].cd_fsd       ; not remote device, pass pcdfsd
        push    es
        push    ax                      ; pcdfsd -> fs dependent part of CDS

        push    mopf_pszName            ; Pointer to canonicalized name
        push    -1                      ; iCurDirEnd (Offset of curdir in pName)

        push    mopf_psffsi             ; psffsi -> fs independent part of SFT
        push    mopf_psffsd             ; psffsd -> fs independent part of SFT

        push    0                       ; High word of OpenMode
        push    mopf_OpenMode           ; OpenMode (sharing and access modes)
        push    mopf_OpenFlag           ; OpenFlag (actions to be taken)

        push    ss
        lea     ax,mopf_Trash
        push    ax                      ; pAction (-> action taken)

        push    mopf_Attr               ; attr (file attributes for CREATE)

        push    0
        push    0                       ; pEABuf (-> EABuf)

        lea     ax,mopf_Trash           ; fgenflag ignored
        push    ss
        push    ax

        les     di,TASKAREA:[si].TCBThisSFT     ; es:di -> SFT

        les     di,es:[di].sf_FSC       ; es:di -> FSC
        call    es:[di].FS_OPENCREATE   ; Call the FSD
        or      ax,ax
        jnz     mopfx                   ; Error, exit

; The operation was successful for the FSD.
; Set SF_ISNET bit for remote or UNC names in sf_flags.
; Set the sf_devptr field to zero so that GetHandleInfo(RM) does not barf.
; Map sfi_type info into sf_flags.

        mov     si,CurrTCB
        les     di,TASKAREA:[si].TCBThisSFT     ; es:di -> SFT

        SaveReg <es,di>
        les     di,es:[di].sf_FSC               ; es:di -> FSC
        les     di,es:[di].FS_ATTRIBUTE         ; es:di ->FS_ATTRIBUTE
        mov     ax,word ptr es:[di]
        test    ax,FS_ATTR_UNC or FS_ATTR_REMOTE
        RestoreReg <di,es>                      ; es:di -> SFT
        jz      mopf20                          ; Not a remote or UNC object
        or      es:[di].sf_flags,SF_ISNET       ; Mark this as "network object"
        mov     es:[di].sf_devptr,0             ; Zero out device pointer
                                                ;72417 moved from PTDA to TCB
        SetBP_CurrTCB
        test    TASKAREA:[bp].TCBPathNameType,PNType_UNC
        UnSetBP_CurrTCB
                                                ;72417 end
        jz      mopf20                          ; Not a UNC object
        or      es:[di].sf_flags2,sff2_UNC      ; mark this as UNC object

; Make sure sf_flags is file type

mopf20: and     es:[di].sf_flags,NOT (DEVID_DEVICE OR SF_PIPE OR SF_NMPIPE)
        test    es:[di].sf_fsi.sfi_type,STYPE_MASK      ; file?
    .errnz  STYPE_FILE
        jnz     SHORT mopfie1                           ; no, fail

; FS_OpenCreate succeeded, now call FS_SetSwap

        push    mopf_psffsi             ; psffsi -> fs independent part of SFT
        push    mopf_psffsd             ; psffsd -> fs independent part of SFT
        les     di,es:[di].sf_FSC       ; es:di -> FSC
        call    es:[di].FS_SETSWAP      ; Call the FSD
        or      ax,ax                   ; setswap shouldn't fail
        jnz     mopfie2                 ; error, internal error

        jmp     SHORT mopfx


; FAT - call DOS_OPENCREATE
mopf50: push    mopf_pszName            ; Pointer to canonicalized name

        lea     ax,mopf_Trash           ; ss:ax -> Trash

        push    ss
        push    ax                      ; HandlePtr

        push    ss
        push    ax                      ; ActionPtr

        xor     eax,eax
        push    eax                     ; size = 0
        push    mopf_Attr               ; attr (file attributes for CREATE)
        push    mopf_OpenFlag           ; OpenFlag (actions to be taken)
        push    ax                      ; OpenMode high word
        push    mopf_OpenMode           ; OpenMode (sharing and access modes)
        push    eax                     ; pEABuf (-> EABuf)
        push    eax                     ; null pfhFileHandleLockID
        push    eax                     ; reserved 0

        mov     bx,sp                   ; ss:bx -> Open3Struc
        CALLFAR DOS_OpenCreate          ; call FAT routine

;       Carry flag and AX have been set by Dos_OpenCreate.
;       If Carry Set   (AX) = error code
;       If Carry Clear (AX) = TRASH, so clear it

        jc      mopfx
        xor     ax,ax

mopfx:  les     di,mopf_pFlags                  ; es:di -> flags
        or      dword ptr es:[di],PGIO_VADDR    ; virtual address for emulation
        les     di,mopf_pcMaxReq        ; es:di -> cMaxReq
        mov     dword ptr es:[di],0     ; flag that we are emulating

        LeaveProc
        RETP    ?aframe                 ; must match parameters!!!

mopfie1: Panic <'FS_EM_OpenPageFile: STYPE not file'>
mopfie2: Panic <'FS_EM_OpenPageFile: SF_SetSwap'>
EndProc  FS_EM_OpenPageFile

INITCODE ends


FARCODE HIGH2
HIGH2CODE segment

BREAK <w16_AllocatePageSpace - Adjust the size of the paging file>
;
;***    w16_AllocatePageSpace - Adjust the size of the paging file
;
;       This is the 16-bit portion of FSD_AllocatePageSpace.
;
;       This routine will resize the paging swap file described by the
;       sft passed to it.  The new size is assumed to be valid (ie, a
;       multiple of the page size).  A demand for contiguity may be expressed
;       and will be passed along to the FSD.  If the contiguity dword is
;       non-0, the FSD must allocate any space in the swap file that is not
;       contiguous in chunks of the given size, on boundaries of that size.
;       If these requirements cannot be met the FSD will fail the operation.
;       If the file is shrinking this value is ignored.
;
;       NOTE:   parameter/error checking is non-existant.  Particularly
;               the new size is assumed to an integral multiple of the
;               page size.  In addition, the page manager must not free
;               space in the swap file while I/O to that space is in progress
;               or use an SFT for more than one purpose at a time (such as
;               sizing a file while I/O to it is in progress.)
;
;       NOTE:   Special shutdown processing has been added to this routine.
;               This routine must track threads inside of itself with the
;               shutdown count so that shutdown does not block needed access
;               to the FSD before the resize in progress can complete.
;
;       ENTRY: Parameters on stack--    DWORD pointer to sft, returned from
;                                             previous FSD_OpenPageFile
;
;                                       DWORD new size of swap file
;                                       DWORD contiguity demand.
;
;       EXIT: AX = error code from FSD (or emulator)
;
;       USES: all except DS, ES
;
;       PSEUDOCODE:
;
;       get pSFT from caller's argument frame
;       if (pSFT != FSD_LOCAL)
;          rc = FS_AllocatePageSpace(pSFT.sf_fsi,pSFT.sf_fsd,new_size,want_contig)
;       else
;          rc=FS_EM_AllocatePageSpace(pSFT.sf_fsi,pSFT.sf_fsd,new_size,want_contig)
;       return(rc);
;

Procedure w16_AllocatePageSpace,<far16>
        ASSUME  ds:nothing,es:nothing,ss:TASKAREA

ArgVar  aps_contig,DWORD                ; contiguity value
ArgVar  aps_size,DWORD                  ; new file size
ArgVar  aps_pSFT,DWORD                  ; pointer to sft

        EnterProc

        SaveReg <DS,ES>
        push    GSEL GDT_FSC
        pop     es                      ; es = FSC segment
        cmp     es:[fss_ShutdownFlags],NotShutdown  ; Is shutdown in progress?
        jne     short aps90             ; yes, do not resize page file

        inc     es:[fss_SDWaitCount]    ; we are in a shutdown critical section
        les     di,aps_pSFT             ; es:di -> sft
        lea     ax,es:[di].sf_fsi       ; file system independent part of sft
        push    es
        push    ax
        lea     ax,es:[di].sf_fsd       ; file system dependent part of sft
        push    es
        push    ax
        push    aps_size                ; new file size
        push    aps_contig              ; contiguity value
        cmp     word ptr es:[di].sf_FSC,FSC_LOCAL       ; FAT?
        jae     SHORT aps10                             ; yes, go call emulator
        lfs     bx,es:[di].sf_FSC
        call    fs:[bx].FS_ALLOCATEPAGESPACE
;       call    es:[di].sf_FSC.FS_ALLOCATEPAGESPACE     ; not FAT, call FSD
        jmp     SHORT aps20
aps10:  CALLFAR FS_EM_AllocatePageSpace
;
; error code (or 0 for no error) has been set by FSD or emulator routine.
;

aps20:  push    GSEL GDT_FSC
        pop     es                      ; es = FSC segment
        cmp     es:[fss_ShutdownFlags],NotShutdown  ; Is the system shutdown?
        jne     aps80                   ; yes, we may need to wake the SD thread

        dec     es:[fss_SDWaitCount]    ; we are no longer in SD critical code

apsx:   RestoreReg <ES,DS>
        LeaveProc
        RETP    ?aframe

aps80:  dec     es:[fss_SDWaitCount]    ; Are we the last thread out?
        jnz     short apsx              ;   no, another thread is still active

        call    WakeShutdownThread      ; last thread, wake up shutdown thread
        jmp     short apsx

aps90:  mov     ax,ERROR_ALREADY_SHUTDOWN
        jmp     short apsx

EndProc w16_AllocatePageSpace


;***    FS_EM_AllocatePageSpace - Emulate FS_AllocatePageSpace
;
;
;       ENTRY   On entry the stack contains:
;                 psffsi        - ptr to filesys indep portion of SFT
;                 psffsd        - ptr to filesys depen portion of SFT
;                 lSize         - new size of page file
;                 lWantContig   - contiguity size
;
;
;       EXIT    if some error
;                   AX = non-zero error code
;               if success
;                   AX = zero
;
;       ALGORITHM
;
;       convert psffsi into pointer to sft
;       save psft in TCBThisSFT
;       save current seek position
;       set  current seek position to desired size
;       DMAAdd = 0
;       call FSD_NewSize
;       save current seek position
;
; NOTE: we don't have to lock the SFT because the pager will never send
;       more than one operation on a single SFT at a time.


Procedure FS_EM_AllocatePageSpace,faronly
        ASSUME  ds:nothing,es:nothing,ss:TASKAREA

ArgVar  maps_WantContig,DWORD   ; contiguity size
ArgVar  maps_lSize,DWORD        ; new size of page file
ArgVar  maps_psffsd,DWORD       ; pointer to filesys depen portion of SFT
ArgVar  maps_psffsi,DWORD       ; pointer to filesys indep portion of SFT

        EnterProc

        les     di,maps_psffsi          ; es:di -> fsi part of SFT
        sub     di,sf_fsi               ; es:di -> SFT

;       Set [ThisSFT] and [ThishVPB] for use by FSD_NewSize

        TaskContext ds,si               ; ds = TASKAREA
        mov     si,CurrTCB
        mov     TASKAREA:[si].TCBThisSFT.Offst,di
        mov     TASKAREA:[si].TCBThisSFT.Segmt,es

        mov     ax,es:[di].sf_fsi.sfi_hVPB
        mov     TASKAREA:[si].TCBThishVPB,ax    ; TCBThishVPB = hVPB from SFT

;       Save the current file position from the SFT

        push    es:[di].sf_fsi.sfi_position

;       Set SFT's current position to match target size

        mov     eax,maps_lSize
        mov     es:[di].sf_fsi.sfi_position,eax

;       Set [DMAAdd] so routines internal to FSD_NewSize don't get confused

        mov     TASKAREA:[si].TCBDMAAdd,0

;       FSD_NewSize will do actual truncate/extend for us

        call    FSD_NewSize                     ; go do the actual work
        pop     es:[di].sf_fsi.sfi_position     ; restore file pointer
        jc      mapsx

        mov     ax,FS_COMMIT_ONE                ; just commit this file
        call    FSD_Commit

;       Carry flag and AX have been set by FSD_NewSize or FSD_Commit.
;       If Carry Set   (AX) = error code
;       If Carry Clear (AX) = TRASH, so clear it

        jc      mapsx
        xor     ax,ax                           ; show no error

mapsx:  LeaveProc
        RETP    ?aframe

EndProc FS_EM_AllocatePageSpace


BREAK <w16_DoPageIO - perform paging I/O operations>
;
;***    w16_DoPageIO - perform paging I/O operations
;
;       This is the 16-bit portion of FSD_DoPageIO.
;
;       This routine calls the FSD to perform paging I/O operations on
;       the swap file described by the handle in the command list.
;       If the PGIO_EMULATE flag is set in the flags of the pageio save area
;       (as it would be if the FSD relies on a device driver that does not
;       support scatter/gather I/O) then we go ahead and call the DoPageIO
;       emulator routine.
;
;       ENTRY: parameters on stack--    DWORD 16:16 pointer to page command list
;                                       DWORD 16:16 pointer to SFT
;                                       WORD  pageio save area flags
;
;       EXIT: AX = error code from FSD (or emulator)
;
;       USES: all
;
;       PSEUDOCODE:
;
;       pSFT = pointer to SFT from caller's arguments
;       flags = swap file instance flags from caller's arguments
;       if (pSFT.FSC != FSC_LOCAL  and  flags.emulation_flag not set)
;           rc = FS_DoPageIO(pSFT.sf_fsi,pSFT.sf_fsd,&CMDList)
;       else
;           rc = FS_EM_DoPageIO(pSFT.sf_fsi,pSFT.sf_fsd,&CMDList)
;       return(rc)
;

Procedure w16_DoPageIO,<far16>
        ASSUME  ds:nothing,es:nothing,ss:TASKAREA

ArgVar  dpio_flags,WORD                 ; emulation flag for FS_DoPageIO
ArgVar  dpio_pSFT,DWORD                 ; pointer to SFT
ArgVar  dpio_cmdlst,DWORD               ; pointer to command list
ArgVar  dpio_cmdlst_lin,DWORD           ; linear address of command list

        EnterProc

        SaveReg <DS,ES>

        les     di,dpio_pSFT            ; es:di -> SFT
        cmp     word ptr es:[di].sf_FSC,FSC_LOCAL       ; FAT?
        jb      SHORT dpio5             ; no,

        SaveReg <ax,bx>
        mov     bx,es:[di].sf_fsi.sfi_hVPB
        CALLFAR UseCache
        RestoreReg <bx,ax>
        jc      dpio5

        SaveAlignESP
        movzx   edi,di
        mov     eax,dword ptr es:[di].sf_fsd.sfdFAT_pSFT
        add     eax,edi
        push    eax
        push    dword ptr [dpio_cmdlst_lin] ; pass linear address command list
        mov     ax,es
        movzx   eax,ax
        push    edi
        push    eax
        FlatContext <ds,es>,cx
        CCALL32 _FAT_DOPAGEIO,,<nocall,noalignesp>
        pop     esp
        jmp     short dpiox

dpio5:  lea     ax,es:[di].sf_fsi       ; offset to filesys indep. part of sft
        push    es                      ; pass to fsd
        push    ax
        lea     ax,es:[di].sf_fsd       ; offset to filesys depen. part of sft
        push    es                      ; pass to fsd
        push    ax
        push    dword ptr [dpio_cmdlst] ; pass command list to fsd

        cmp     word ptr es:[di].sf_FSC,FSC_LOCAL       ; FAT?
        jae     SHORT dpio10                    ; yes, go call emulator
        test    dpio_flags,PGIO_EMULATE         ; emulator flag set?
        jnz     SHORT dpio10                    ; yes, go call emulator
;
; fsd is not FAT and swap file's device can handle scatter/gather I/O;
; call the FSD.
;
        lfs     bx,es:[di].sf_FSC               ; (fs:bx) -> FSC
        call    fs:[bx].FS_DOPAGEIO             ; not FAT, call FSD
        jmp     SHORT dpiox                     ; go exit
;
; fsd is actually FAT or the swap file's device cannot handle scatter/gather
; I/O.  Call the emulator.
;
dpio10: CALLFAR FS_EM_DoPageIO
;
; ax = error code from fsd or emulator.
;
dpiox:  RestoreReg <ES,DS>
        LeaveProc
        RETP    ?aframe

EndProc w16_DoPageIO


;***    FS_EM_DoPageIO - Emulate FS_DoPageIO
;
;
;       ENTRY   On entry the stack contains:
;                 psffsi        - ptr to filesys indep portion of SFT
;                 psffsd        - ptr to filesys depen portion of SFT
;                 pList         - ptr to command list
;
;       EXIT    if some error
;                   AX = non-zero error code
;               if success
;                   AX = zero
;
;       ALGORITHM
;
;       convert psffsi into pointer to sft
;       save pSFT in TCBThisSFT
;       while (not at end of list) {
;           error = FSD_ChgFilePtr(...)
;           if error
;               BREAK;
;           if (read)
;               error = FSD_Read(...)
;               set status with data back from read
;           else  //write
;               error = FSD_Write(....)
;               set status with data back from write
;           if error
;               BREAK;
;           advance to next element of pList
;       }
;       pList.OutFlags |= DONE
;       pList.PostAddr(pList)
;
; NOTE: we don't have to lock the SFT because the pager will never send
;       more than one operation on a single SFT at a time.

Procedure FS_EM_DoPageIO,faronly
        ASSUME  ds:nothing,es:nothing,ss:TASKAREA

ArgVar  mdpi_pList,DWORD        ; pointer to command list
ArgVar  mdpi_psffsd,DWORD       ; pointer to filesys depen portion of SFT
ArgVar  mdpi_psffsi,DWORD       ; pointer to filesys indep portion of SFT

LocalVar        mdpi_Trash,WORD ; pass pointer to this for unwanted info

        EnterProc

        les     di,mdpi_psffsi                  ; es:di -> fsi part of SFT
        sub     di,sf_fsi                       ; es:di -> SFT

;       Set [ThisSFT] and [ThishVPB] for use by FSD_ChgFilePtr, FSD_Read/Write

        TaskContext ds,bx               ; ds = TASKAREA
        mov     bx,CurrTCB
        mov     TASKAREA:[bx].TCBThisSFT.Offst,di
        mov     TASKAREA:[bx].TCBThisSFT.Segmt,es       ; TCBThisSFT = SFT

        mov     ax,es:[di].sf_fsi.sfi_hVPB
        mov     TASKAREA:[bx].TCBThishVPB,ax    ; TCBThishVPB = hVPB from SFT

; clear write_thru and set no_cache
        mov     TASKAREA:[bx].TCBJfnFlag,JFN_NCACHE ; TCBJfnFlag = no cache

        lds     si,mdpi_pList                   ; ds:si -> command list header
        ASSUME DS:nothing
        movzx   cx,[si].pgcmdh_OpCount          ; cx = OpCount
        lea     si,[si].pgcmdh_PageCmdList      ; ds:si -> first page command

mdpi10: SaveReg <cx,ds,si,es,di>

; ChgFilePtr
        mov     bx,0                            ; bx = seek absolute
        mov     dx,[si].pgcmd_fileOffset.hiword
        mov     ax,[si].pgcmd_fileOffset.loword ; dx:ax = abs pos
        mov     cx,dx
        mov     si,ax                           ; cx:si = distance
        call    FSD_ChgFilePtr
        jc      short mdpi99                    ; error, exit

        RestoreReg <di,es,si,ds,cx>
        SaveReg    <cx,ds,si,es,di>

        mov     eax,[si].pgcmd_addr             ; eax = page address
        mov     bx,CurrTCB                      ; bx -> CurrTTCB
        mov     TASKAREA:[bx].TCBDMAAdd,eax     ; TCBDMAAdd = page address
        mov     cx,PGIO_PAGESIZE

        cmp     [si].pgcmd_cmd,PB_READ_X
        je      short mdpi40                    ; read

IFDEF FSSTRICT
        cmp     [si].pgcmd_cmd,PB_WRITE_X
        je      short mdpi30                    ; write

        cmp     [si].pgcmd_cmd,PB_WRITEV_X
        je      short mdpi30                    ; writev, just use write

        InternalError <FS_EM_DoPageIO: unknown command in list>
ENDIF

mdpi30: TaskContext ds,bx                       ; ds = TASKAREA
                                                ; needed for FSD_Read/Write
        call    FSD_Write
        jmp     short mdpi50

mdpi40: TaskContext ds,bx                       ; ds = TASKAREA
                                                ; needed for FSD_Read/Write
        call    FSD_Read

mdpi50: jc      short mdpi99                    ; error occured, exit now

        mov     ax,ERROR_DISK_FULL              ; should never fail
        cmp     cx,PGIO_PAGESIZE                ; all data written?
        jne     short mdpi99                    ; no, exit now

        RestoreReg <di,es,si,ds,cx>

        or      [si].pgcmd_status,PGIO_ATTEMPTED ; mark command attempted

        add     si,size PageCmd                 ; ds:si -> next page command
        loop    mdpi10                          ; do the next command

        xor     ax,ax                           ; no error

mdpi90: lds     si,mdpi_pList                   ; ds:si -> command list
        or      ax,ax
        jz      short mdpi95                    ; no errors

        or      [si].pgcmdh_OutFlags,PGIO_FO_ERROR ; mark some error
        xor     ax,ax                           ; (ax) = 0

mdpi95: or      [si].pgcmdh_OutFlags,PGIO_FO_DONE ; mark command list done

IFDEF ASYNC     ;BUGBUG async not supported
        SaveReg <ax>

        push    [si].pgcmdh_PostCookie          ; push cookie (PostAddr cleans)
        FlatContext <ds,es>,cx
        CCALL32 [ebx].pgcmdh_PostAddr

        RestoreReg <ax>
ENDIF ;ASYNC

        LeaveProc
        RETP    ?aframe

;error path: set error code and status (attempted and failed) in page command

mdpi99: RestoreReg <di,es,si,ds,cx>
        mov     [si].pgcmd_error,ERROR_I24_GEN_FAILURE  ; save error code
        or      [si].pgcmd_status,PGIO_ATTEMPTED OR PGIO_FAILED
        jmp     short mdpi90                            ; go finish up

EndProc FS_EM_DoPageIO,NoCheck

HIGH2CODE ends
FARCODE HIGH32
SMLOCK_TEXT segment

;***    _FSD_FlushBuf - C interface layer for FSD_FlushBuf
;
;       This is the 32-bit portion of FSD_FlushBuf
;
;       This routine is the C-callable portion of FSD_FlushBuf.
;       This routine simply sets up parameters for the 16-bit
;       worker and calls out to it.
;
;       From C: FSD_FlushBuf(hVPB, usDiscard)
;
;       ENTRY:  SS:ESP          return address
;               SS:(ESP+4)      hVPB         - hVPB of volume to flush
;               SS:(ESP+6)      usDiscard    - discard/keep buffers after
;                                              flushing
;
;       EXIT    if 'NC' - success
;               if 'C' - error in at least one flush
;                 bx = number of write errors
;
;       USES: EAX,EDX
;
;       PSEUDOCODE:
;
;

Procedure _FSD_FlushBuf
CpuMode 386
        ASSUME  DS:FLAT,ES:FLAT,FS:NOTHING,GS:NOTHING,SS:TASKAREA

ArgVar  _fbf_hVPB,WORD                  ; hVPB of volume to flush
ArgVar  _fbf_usDiscard,WORD             ; discard/keep buffers

        EnterProc
        mov   ax,_fbf_hVPB        ; hVPB of volume to flush
        mov   dx,_fbf_usDiscard   ; hVPB of volume to flush
        CALL16  w16_FSD_FlushBuf
        jc  fbf_100
        xor eax,eax
        jmp fbf_exit
fbf_100:
        mov eax,ERROR_WRITE_FAULT
fbf_exit:
        LeaveProc
        RETC

CpuMode reset
EndProc _FSD_FlushBuf

SMLOCK_TEXT ends
        END
