/*static char *SCCSID = "@(#)diskc.c    6.12 92/02/28";*/
#define SCCSID "@(#)diskc.c     6.12 92/02/28"
/********************************************************/
/*              */
/*   IBM/Microsoft Confidential     */
/*              */
/*   Copyright (c) IBM Corporation 1987, 1989 */
/*   Copyright (c) Microsoft Corporation 1987, 1989 */
/*              */
/*   All Rights Reserved        */
//
//      Change History
//
//      59486   Change ioBeginTransfer to call SELGetDescInfo
//              rather than SELGetSize to determine the size of
//              the segment. SELGetSize returns the size of an
//              object when passed the laddr of the object.
//              We are really interested in the size of the
//              segment so we can lock the entire segment,
//              not the size of the object of which the
//              segment is a part.
//
/********************************************************/

#define FNO_NUM FNO_DISKC_C
#define INCL_TYPES      // for basedef.h typedefs
#include <osconst.h>
#include <ostypes.h>
#include <basemac.h>
#include <basedef.h>
#include <fnofs.h>
#include <osmac.h>
#include <error.h>
#include <error2.h>
#include <mi.h>
#include <vmexport.h>
#include <selxport.h>
#include <pgexport.h>
#include <tkexport.h>
#include <smexport.h>
#include <sft.h>
#include <pageio.h>
#include <cache.h>
#include <filesys.h>
#include <dossymc.h>
#include <sigdef.h>
#include <except.h>
#include <sem.h>
#include <screen.h>
#include <dirent.h>
#include <proc.h>
#include <tkptda.h>
#include "fslocal.h"


/***LP  ioBeginTransfer - validate and lock user memory before IO operation
 *
 *  Lock user's memory, checking if room for transfer.
 *
 *  ENTRY:  uSel  - selector of user address
 *    uOff  - offset of user address
 *    cBytes  - count of bytes in transfer
 *    uFlags  - flags for the lock:
 *        VML_DIRTY - transfer will dirty the memory
 *             (i.e., reads from disk into memory)
 *        VML_CONTIG - memory must be contiguous
 *        VML_16M - memory must be below 16M
 *    pPageList - pointer to page list buffer, VM_NO_ADDR
 *          if we don't want pagelist info.
 *    puPLCount - pointer to variable which is set to the
 *          actual number of entries in page list;
 *          VM_NO_ADDR if we don't want pagelist info.
 *
 *  EXIT: returns error code
 *
 *  WARNING: May context switch (in VMLockMem)
 *
 *  NOTES:  There is no longer any need to call ProbeBuff, because
 *    VMLock will return an error if we entire range of memory
 *    is not available or accessible.  If ioBeginTransfer succeeds
 *    then someone down the way is responsible for calling
 *    EndTransfer to release the lock and free the lock handle.
 *    If an error occurs, however, ioBeginTransfer cleans up after
 *    itself and frees any allocated memory.
 *
 *    Special swapper support REMOVED:
 *    Caller must check for swapper IO.
 *
 *
 *    alloc() is still too slow, and should be replaced with
 *    something faster.
 */
unsigned ioBeginTransfer(uSel,uOff,cBytes,uFlags,pPageList,puPLCount)
SEL  uSel;
unsigned uOff;
unsigned cBytes;
unsigned uFlags;
struct pagelist_s *pPageList;
ulong_t     *puPLCount;
{
    ulong_t laddr;
    unsigned  err;
    PBYTE PhysAddr;                                                /*b728905*/
    struct seldesc_s  desc;         /* Descriptor information */        //59486

    /*
     * Convert the 16:16 address into 0:32
     */
    laddr = SELVirtToLin(uOff,uSel);
    if (laddr == (ulong_t)-1) {
  pTCBCur->TCBfIOLock = 0;
  pTSDCur->TSDerrcFault = uSel;
  TKUsrArgFault();
  err = ERROR_PROTECTION_VIOLATION;
  goto bailout;
    }

    /*
     * Check to see if if DOVOLIO sent in a request not to lock this memory
     * down because he already knows that it is resident memory.  (i.e.
     * No swap and no move.
     */
    if ((uFlags & PG_RESIDENT) != 0) {
  pTCBCur->TCBfIOLock = 0;
  if (((void *) puPLCount) != ((void *) VM_NO_ADDR))
    *puPLCount = 0;
  return(NO_ERROR);
    }

    /*
     * Check to see if this is a page manager buffer that we're locking.
     * If so, we don't really need to do the lock.  It's a lot faster to
     * do the check here than in VMLock.
     */
    if (laddr >= PGSegBufLaddr && laddr < (PGSegBufLaddr+BUFSIZE)) {
  pTCBCur->TCBfIOLock = 0;
  if (((void *) puPLCount) != ((void *) VM_NO_ADDR))
    *puPLCount = 0;
  return(NO_ERROR);
    }

    /*
     * Check to see if this is a video buffer that we're locking.
     * If so, we don't really need to do the lock.  It's a lot faster to
     * do the check here than in VMLock.
     */
//      if (laddr == VIDEOBUFADDR) {
        if ((laddr >= VIDEOBUFADDRCOL) && (laddr <= 0x000c0000 - 1)) {   /*b728905*/
          /* check to see if the physical address is = linear address */
          /* if so this is a request to the video buffer */
           err = VMLinToPhys(laddr,SSToDS(&PhysAddr));                 /*b728905*/
           if (laddr == ((ulong_t) PhysAddr)) {                        /*b728905*/
             pTCBCur->TCBfIOLock = 0;
             if (((void *) puPLCount) != ((void *) VM_NO_ADDR))
               *puPLCount = 0;
               return(NO_ERROR);
           }                                                           /*b728905*/
        }

    /*  b736804 - when locking memory of a 16 bit device driver, we must
     *  lock the entire segment.  If we lock only the page(s), the DD may
     *  not be able to lock the entire segment contiguously, and end up
     *  blocked in the kernel forever.
     *  See function pgValidateContig in file pgframe.c
     */
    // start b736804
    if (uFlags & VML_CONTIG) {
       if (pPTDACur->ptda_ProcType != PT_VDM) {
           laddr -= uOff;
//         if (err = SELGetSize(laddr, uSel, 0, 0, SSToDS(&cBytes))) {  //59486
           err = SELGetDescInfo ( uSel, HOBNULL, SSToDS ( & desc ) );   //59486
           if ( err == NO_ERROR )                                       //59486
           {                                                            //59486
             cBytes = desc.desc_cb;                                     //59486
           }                                                            //59486
           else                                                         //59486
           {                                                            //59486
              return(err);
           }
       }
    } else {
       // end   b736804
       uFlags |= VML_TRY_CONTIG;
    }

    /*
     * Lock the memory.
     */
    err = VMLockMem(laddr,cBytes, uFlags,
     (struct vmlh_s *)&(pTCBCur->TCBLockHndl),pPageList,puPLCount);

  pTCBCur->TCBfIOLock = (err == NO_ERROR) ? (char)1:(char)0;
  /*
   * Indicate that an I/O operation is in progress, TCB vars need to
   * be saved in FSH_DoVolIO
   */
  if (err == NO_ERROR) (pTCBCur->TCBVolIONest)++;

bailout:
    return(err);
}

/***LP  FAT_DOPAGEIO - Do Pageio for FAT file system
 *
 *
 *  ENTRY:  SFTI_Sel    - SFT independent selector
 *    SFTI_Off    - SFT independent offset
 *    SFTD_Sel    - SFT dependent selector
 *    SFTD_Off    - SFT dependent offset
 *    CmdList_Sel - Command List selector
 *    CmdList_Off - Command List offset
 *    pCmdList    - Linear address of command list
 *    pSFT      - Linear address of SFT
 *
 *  EXIT: returns error code
 *
 */
int FAT_DOPAGEIO(SEL           SFTI_Sel,
     ushort_t        SFTI_Off,
     PageCmdHeader         *pCmdList,
     sf_entry        *pSFT)

{
   unsigned char i;
   struct PageCmd *pOpList;
   ulong_t ReqListSel,ReqListOff,hVPB,xferaddr,cluster,SecClusPos;
   ulong_t cRun,cSecSwap,rba,laddr;
   register tcb_t *pTCB = pTCBCur;
   int rc;
   PBYTE PhysAddr;
   int fTK_FF_BUF = FALSE;
   sfdFATFS *pSFTFAT;

   pSFTFAT = (sfdFATFS *)&(pSFT->sf_fsd);

   if (pTCBCur->TCBForcedActions & TK_FF_BUF){
      fTK_FF_BUF = TRUE;
      pTCBCur->TCBForcedActions &= ~TK_FF_BUF;
   }

   hVPB = (ulong_t)pSFT->sf_fsi.sfi_hVPB;
   pTCB->TCBThishVPB = pSFT->sf_fsi.sfi_hVPB;
   pTCB->TCBThisSFT = (ulong_t)SFTI_Sel << 16;
   pTCB->TCBThisSFT |= (ulong_t)SFTI_Off;

   ReqListAlloc(SSToDS(&ReqListSel),
    SSToDS(&ReqListOff));
   ReqListInit(ReqListSel,
         ReqListOff,
         hVPB,
         RLCB_KEEP_REQ);

   for (i = 0; i < pCmdList->pgcmdh_OpCount; i++) {

      pOpList = &pCmdList->pgcmdh_PageCmdList[i];
      pOpList->pgcmd_status = PGIO_ATTEMPTED;

      pTCB->TCBDMAAdd = (ulong_t)pOpList->pgcmd_addr;
      laddr = SELVirtToLin((ushort_t)(pTCB->TCBDMAAdd),
         (SEL)((pTCB->TCBDMAAdd) >>16));
      BufAssert (laddr != -1l);


      rc = VMLinToPhys(laddr,SSToDS(&PhysAddr));
      BufAssert (!rc);

      pSFT->sf_fsi.sfi_position = pOpList->pgcmd_fileOffset;

      rc = SetupForIO(PAGESIZE);
      BufAssert (!rc);

      rc = FATReadInit(hVPB);
      BufAssert (!rc);


      SecClusPos = (ulong_t)pTCB->TCBSecClusPos;
      cluster = (ulong_t)pTCB->TCBClusNum;

      cSecSwap = (ulong_t)(PAGESIZE / SECSIZE);
      while (cSecSwap) {

   rc = SetupPhysIO(SSToDS(&cRun),
        SSToDS(&cluster),
        cSecSwap,
        cluster,
        SSToDS(&rba),
        SSToDS(&cSecSwap),
        SSToDS(&xferaddr),
        SecClusPos,
        FALSE,
        hVPB);
   BufAssert (!rc);

   pSFTFAT->sfdFAT_lstclus = pTCB->TCBClusNum;
   pSFTFAT->sfdFAT_cluspos = pTCB->TCBLastPos;

   rc = ReqListAdd_REQ(rba,
           cRun,
           pOpList->pgcmd_cmd,
           ReqListSel,
           ReqListOff,
           pOpList->pgcmd_priority,
           hVPB);
   BufAssert (!rc);

   ReqListAdd_SG(cRun * SECSIZE,
           ReqListSel,
           ReqListOff,
           PhysAddr);

   PhysAddr += cRun * SECSIZE;
   if (cSecSwap){
      rc = IsEOF(cluster,hVPB);
      BufAssert (!rc);
      SecClusPos = 0;    // Start at first sector within cluster
      ++pTCB->TCBLastPos;    //  We'll be using next cluster
   }
      }
   }
   rc = ReqListExecute(ReqListSel,ReqListOff);
   FreeReqList(ReqListSel,ReqListOff);
   if (rc) {
      pCmdList->pgcmdh_OutFlags |= PGIO_FO_ERROR;
   }
   else {
      pCmdList->pgcmdh_OutFlags |= PGIO_FO_DONE;

   }
   if (fTK_FF_BUF)
      pTCBCur->TCBForcedActions |= TK_FF_BUF;
   return(rc);
}
