/*static char *SCCSID = "@(#)pfread.c	6.2 91/01/14";*/
#define SCCSID "@(#)pfread.c	6.2 91/01/14"
/*
 *	IBM/Microsoft Confidential
 *
 *	Copyright (c) IBM Corporation 1987, 1989
 *	Copyright (c) Microsoft Corporation 1987, 1989
 *
 *	All Rights Reserved
 *
 */

/*  NAME :  PFREAD.C
 *    
 *
 *  DESCRIPTION
 *    
 *      This file contains the functions that perform the read from the disk.
 *
 *
 *  FUNCTIONS DEFINED
 *
 *      PerformRead ()  --  Read sector(s) from disk and store in cache.
 *      MultiSectors () --  Read multiple sectors from the disk.
 *      ReadSector ()   --  Read a single 2k sector from the disk.
 *
 * 
 *  REVISION HISTORY (in reverse chronological order)
 *  ------------------------------------------------------------------------------------------
 *
 *  3/07/95         Uri Stern       Defect 115129.  Error action during read should cause 
 *                                  abort-retry-fail(not destroy process).  We need to  
 *                                  change what is passed in the fAllowed flags of the 
 *                                  FSH_DOVOLIO in MultiSectors and ReadSector so that  
 *                                  harderror does not blow the process away.  @115129
 *
 *  6/15/90         Brian Andrew    Error action if Multisector allocation
 *                                  fails.
 * 
 *  4/9/90          Brian Andrew    Initial version of PerformRead.
 *  4/9/90          Brian Andrew    Initial version of MultiSectors.        
 *
 *
 *  TO DO
 *  ------------------------------------------------------------------------------------------
 */

#define INCL_DOSERRORS
#define INCL_NOPMAPI

#include <os2.h>
#include <fsh.h>

#include "cdfs.h"
#include "sem.h"
#include "path.h"
#include "vol.h"
#include "heap.h"
#include "mem.h"
#include "buffer.h"

#ifdef STATS_H
#include "stats.h"
#endif 

#include "message.h"
#include "fsdata.h"

#ifdef DEBUG
#include "pr_debug.h"
#endif

#include "pr_memin.h"
#include "pr_cache.h"



/***    PerformRead ()  --  Read sector(s) from disk and store in cache.   
 *      
 *  DESCRIPTION
 *
 *      This sector will call the appropriate function to read sector or
 *      sectors from the disk.  It coverts the starting sector and
 *      the sector count base on the physical sector size on the volume
 *      so the result is in chunks of 2k blocks.
 *      
 *      If a successful MultiSector read has been done, the segment
 *      'pSeg' holds the data.  If a succesful single sector read has
 *      been done then 'pbBufChain' and 'pbEndBufChain' point to the
 *      correct buffer.
 *
 *      No semaphores are held by this routine.
 *      
 *      
 *  ENTRY   (Arguements passed to function)
 *      
 *      The following fields in 'pfblVars' are used.
 *      
 *      fMulti          --  Flag indicating if this was multi-sector read.
 *      csSectorCount   --  Offset of last sector from starting sector.
 *      snStartSector   --  Starting sector number.
 *      snAdjStartSect  --  Start sector based on physical sector size.
 *      pvddVolData     --  Pointer to volume dependent data.
 *      csReadSectors   --  Number of device specific sectors to read.
 *      hVPB            --  Handle for VPB.
 *      pbSingleBuf     --  Pointer to BUF for single sector reads.
 *      
 *
 *  GLOBAL  (Global variables accessed by this function)
 *
 *      NONE.   
 *      
 *
 *  GOTO    (Jump targets)
 *
 *      NONE.
 *
 *
 *  RETURN  (Value returned by this function)
 *
 *      NO_ERROR if first sector obtained through either call.
 *      Error code from 'ReadSector' otherwise.
 *
 *
 *  EXIT    (Changes to variables seen outside this function)
 *
 *      The following fields in 'pfblVars' may be modified.
 *
 *      snAdjStartSect  --  Start sector based on physical sector size.
 *      fMulti          --  Flag indicating if this was multi-sector read.
 *      csReadSectors   --  Number of device specific sectors to read.
 *      pbBufChain      --  Points to the single buffer for single buf reads.
 *      pbEndBufChain   --  Points to the single buffer for single buf reads.
 *
 *      
 *  LOCAL   (Variables declared within this function)    
 *      
 *      usRet           --  Error code returned.
 */
USHORT PerformRead (pfblVars)
PFIND_BUF_LOC   pfblVars;
{
	/* Local variables */
	USHORT  usRet;

	/* Set multi flag if multiple sectors are requested */
	/* Test if only one sector requested or 'MultiSectors' fails */
	if (!(pfblVars->fMulti = pfblVars->csSectorCount) ||
		(usRet = MultiSectors (pfblVars)))
	{
		/* Try to read a single 2K block */
		if (!(usRet = ReadSector (
							pfblVars->hVPB,
							&pfblVars->pbBufChain,
							pfblVars->snAdjStartSect,
							pfblVars->csReadSectors)))
		{
			/* Null terminate this as a chain of one */
			((PBUF) pfblVars->pbBufChain)->pbNextBUF = NULL;

			/* Make a chain out of the single sector */
			pfblVars->pbEndBufChain = pfblVars->pbBufChain;
		
			/* Show that this is single sector read */
			pfblVars->fMulti = FALSE;

		} /* end if successful single sector read */

	} /* end if single sector or unsuccessful MultiSectors */

	/* Return the error code */
	return usRet;

} /* end PerformRead */


/***    ReadSector ()   --  Read a single 2K sector from the disk.
 *      
 *  DESCRIPTION
 *
 *      This function allocates a sector buffer and reads a single
 *      block of 2K data into it.  If the number of sectors read (may be
 *      reading 4 * 512 byte sectors) is the same as the number requested
 *      then ERROR_UNCERTAIN_MEDIA is returned.
 *      
 *      All conversions depending on physical sector size have been
 *      done outside this function.  The function does not use a
 *      FIND_BUF_LOC structure since they are not used at mount time.
 *      
 *      
 *  ENTRY   (Arguements passed to function)
 *      
 *      hVPB            --  VPB handle for this volume.
 *      ppbBuf          --  Address to store buffer pointer in.
 *      snStartSector   --  Starting physical sector on disk.
 *      csSectorCount   --  Number of disk sectors to read (totals 2K).
 *      
 *
 *  GLOBAL  (Global variables accessed by this function)
 *
 *      NONE.   
 *      
 *
 *  GOTO    (Jump targets)
 *
 *      NONE.
 *
 *
 *  RETURN  (Value returned by this function)
 *
 *      ERROR_UNCERTAIN_MEDIA if not all sectors could be read
 *      Error returned from FSH_DOVOLIO if error occurred.
 *      Error from 'GetBuf' call if it occurred.
 *      NO_ERROR otherwise.
 *
 *
 *  EXIT    (Changes to variables seen outside this function)
 *
 *      ppbBuf contains pointer to newly allocated buffer.
 *
 *      
 *  LOCAL   (Variables declared within this function)    
 *      
 *      usRet       --  Error return code.   
 *      usLocCount  --  Local variable for copy of sectors read.  
 *
 *  HISTORY: 
 *      03-07-95  115129  Uri Stern    Changed FSH_DOVOLIO to use DOVOLIO_IFERROR 
 *                                     so we need to change the READ_SECTORS macro
 *                                     which is where the call to FSH_DOVOLIO is.
 *                                     There is no change to this routine itself
 *                                     just the READ_SECTORS macro in (PR_CACHE.H)
 */
USHORT ReadSector (hVPB, ppbBuf, snStartSector, csSectorCount)
USHORT      hVPB;         
PPBUF       ppbBuf;       
SECT_NUM    snStartSector;
USHORT      csSectorCount;
{
	/* Local Variables */
	USHORT  usRet;
	USHORT  csLocCount;

	/* Copy the number of sectors to read */
	csLocCount = csSectorCount;

	/* Try to allocate buffer */
	if (!(usRet = GetBuf (ppbBuf)))
	{
		/* If read doesn't faile, check for insufficient sector read */
		if (!(usRet = (READ_SECTORS (
								hVPB,
								(*ppbBuf),
								&csSectorCount,
								snStartSector))))
		{
			/* Compare sectors read with sectors intended */
			if (csSectorCount != csLocCount)
			{
				usRet = ERROR_UNCERTAIN_MEDIA;

			} /* end if insufficient sector read */

		} /* end if error in reading disk */

		/* If error occurred, free the BUF structure */
		if (usRet)
		{
			FREE_BUF (*ppbBuf);
		}

	} /* end if successful allocation */

#ifdef DEBUG
	/* Else print error message */
	else
	{
		dprintf ("\tReadSector: GetBuf failed  --  %d\n", usRet);

	} /* end else BUF allocation failed */
#endif

	/* Return the error code */
	return usRet;

} /* end ReadSector */


/*** MultiSectors ()  -   Read multiple sectors from the disk.
 *
 *  DESCRIPTION
 *
 *      This function is used when multiple sectors are read at one time.
 *      If the first sector is successfully read, then no error is returned.
 *
 *      We first try to allocate the necessary memory.  If the allocation
 *      fails, we return the error.
 *
 *      This means that we will use existing memory elsewhere to try
 *      to recover the first sector only.
 *
 *      All the sectors values have been converted to the correct base before
 *      calling this function.
 *
 *
 *  ENTRY   (Arguements passed to function)
 *      
 *      The following fields in 'pfblVars' are used.
 *
 *      csReadSectors   --  Number of device specific sectors to read.
 *      pvddVolData     --  Pointer to volume dependent data.
 *      pSeg            --  Pointer to buffer to read disk sectors into.
 *      sSel            --  Selector for allocation.
 *      snAdjStartSect  --  Starting sector number.
 *      csSectorCount   --  Offset of last sector from starting sector.
 *      
 *
 *  GLOBAL  (Global variables accessed by this function)
 *
 *      NONE.   
 *      
 *
 *  GOTO    (Jump targets)
 *
 *      NONE.
 *
 *
 *  RETURN  (Value returned by this function)
 *
 *      NO_ERROR if at least one sector read.
 *      Return code from FSH_SEGALLOC if error.
 *      Return code from FSH_DOVOLIO if no sectors read.
 *
 *
 *  EXIT    (Changes to variables seen outside this function)
 *
 *      The following fields in 'pfblVars' may be modified.
 *
 *      csSectorCount   --  Returns the number of 2K sectors read here.
 *      csReadSectors   --  Number of disk sectors read.
 *      pSeg            --  Contains disk data if read successful.
 *      sSel            --  Now has selector for allocated segment.
 *      
 *  LOCAL   (Variables declared within this function)    
 *      
 *      NONE.  
 * 
 *  HISTORY: 
 *      03-07-95  115129  Uri Stern    Changed FSH_DOVOLIO to use DOVOLIO_IFERROR 
 *
 */

USHORT MultiSectors (pfblVars)
PFIND_BUF_LOC   pfblVars;
{
  USHORT      usRet;

  /* Try to allocate the segment to read in the data */
  if (!(usRet = FSH_SEGALLOC( MULTI_ALLOC, 
                              (ULONG) pfblVars->csReadSectors *
                                      pfblVars->pvddVolData->cbSectorSize,
                              &(pfblVars->sSel))))

   {
    /* Remember the selector */
    pfblVars->pSeg = MAKEP (pfblVars->sSel, 0);

    /* Try to read the sectors */
    usRet = FSH_DOVOLIO (DOVOLIO_OP,
                         DOVOLIO_IFERROR,          // UJS 115129 Fix so we don't blow away in hard error
                         pfblVars->hVPB,
                         pfblVars->pSeg,
                         &pfblVars->csReadSectors,
                         pfblVars->snAdjStartSect);

    #ifdef DEBUG
     if (usRet)
      {
       dprintf ("\tMultiSectors:  DOVOLIO failed %d\n", usRet);
      }
    #endif

    /* Convert the sectors read back to our base */
    pfblVars->csSectorCount =
                              pfblVars->csReadSectors /
                              pfblVars->pvddVolData->usSectorBase;

    /* If an error occurred  or no segments read */
    if (usRet || !pfblVars->csSectorCount)
     {
      /* Reset the number of sectors to read */
      pfblVars->csReadSectors = pfblVars->pvddVolData->usSectorBase;

      /* Free the allocated memory */
      FSH_SEGFREE (pfblVars->sSel);

     } /* end if DOVOLIO error */
   } /* end if successful allocation */

  /* Else note unsuccessful allocation */
  else
   {
    #ifdef DEBUG
        dprintf ("\tMultiSectors:  SEGALLOC failed  %d\n", usRet);
    #endif

    /* Reset the number of sectors to read */
    pfblVars->csReadSectors = pfblVars->pvddVolData->usSectorBase;
   }

/* Return usRet */
return usRet;

} /* end MultiSectors */

