/*static char *SCCSID = "@(#)lzread.c  6.4 92/01/31";*/

#define _BTXT _BTXT
#define INCL_DOSERRORS
#include <os2def.h>
#include <bse.h>
#include <fsh.h>
#include "const.h"
#include "misc.h"
#include "chain.h"
#include "buf.h"
#include "dir.h"
#include "volume.h"
#include "storage.h"
#include "tables.h"
#include "pb_ifs.h"
#include "pbmacros.h"
#include "lw.h"
#include "frame.h"
#include "fsdata.h"
#include "assert.h"
#include "log.h"
#include "strat2.h"                     /* Needed by "asyncio.h". */
#include "asyncio.h"                    /* PIOH, PLISTENT, etc. */
#include "heap.h"

#include "pr_BITMP.h"                   // @130910 Needed for SFB call
#include "pr_DEBUG.h"
#include "pr_CACHE.h"
#include "pr_DSKIO.h"
#include "pr_MISC.h"
#include "pr_heap.h"


/*
 ***    LazyRead - Synchronous Buffer Read
 *
 *      LazyRead fills a buffer with the minimum required data
 *      from the disk to complete a lazy read.
 *
 *
 *      ENTRY   pbuf = pointer to buffer header
 *
 *      EXIT    none
 *
 *      Note:  LazyReadIO may block.
 *
 *      HISTORY:
 * WHEN     WHO          DEFECT   DESCRIPTION
 * ---------------------------------------------------------------------------
 * 20Sep95  D.Azzarito   @132506  Don't do I/O if we have it already
 * 02Aug95  D.Azzarito   @130910  Don't allocate a "zero" buffer.
 *
 */
/*  To optimize the read by incomplete sectors, we use a look-up table
    indexed by pbuf->bDirtMask.

        aBufa[pbuf->bDirtMask].offus -- sector offset of first incompletely
          modified (dirty) block into buffer's data block (ith sector in block)
        aBufa[pbuf->bDirtMask].cSecToRead -- count of sectors to read.

*/


struct BUFA_LOOKUP {
        USHORT offus;
        USHORT cSecToRead;
} aBufa2[] = {
#if SPB == 4
        {0,0}, {0,1}, {1,1}, {0,2},
        {2,1}, {0,3}, {1,2}, {0,3},
        {3,1}, {0,4}, {1,3}, {0,4},
        {2,2}, {0,4}, {1,3}, {0,4}
#elif SPB == 8
/*  0 -  7 */       {0,0}, {0,1}, {1,1}, {0,2}, {2,1}, {0,3}, {1,2}, {0,3},
/*  8 - 15 */       {3,1}, {0,4}, {1,3}, {0,4}, {2,2}, {0,4}, {1,3}, {0,4},

/* 16 - 23 */       {4,1}, {0,5}, {1,4}, {0,5}, {2,3}, {0,5}, {1,4}, {0,5},
/* 24 - 31 */       {3,2}, {0,5}, {1,4}, {0,5}, {2,3}, {0,5}, {1,4}, {0,5},

/* 32 - 39 */       {5,1}, {0,6}, {1,5}, {0,6}, {2,4}, {0,6}, {1,5}, {0,6},
/* 40 - 47 */       {3,3}, {0,6}, {1,5}, {0,6}, {2,4}, {0,6}, {1,5}, {0,6},
/* 48 - 55 */       {4,2}, {0,6}, {1,5}, {0,6}, {2,4}, {0,6}, {1,5}, {0,6},
/* 56 - 63 */       {3,3}, {0,6}, {1,5}, {0,6}, {2,4}, {0,6}, {1,5}, {0,6},

/* 64 - 71 */       {6,1}, {0,7}, {1,6}, {0,7}, {2,5}, {0,7}, {1,6}, {0,7},
/* 72 - 79 */       {3,4}, {0,7}, {1,6}, {0,7}, {2,5}, {0,7}, {1,6}, {0,7},
/* 80 - 87 */       {4,3}, {0,7}, {1,6}, {0,7}, {2,5}, {0,7}, {1,6}, {0,7},
/* 88 - 95 */       {3,4}, {0,7}, {1,6}, {0,7}, {2,5}, {0,7}, {1,6}, {0,7},
/* 96 -103 */       {5,2}, {0,7}, {1,6}, {0,7}, {2,5}, {0,7}, {1,6}, {0,7},
/*104 -111 */       {3,4}, {0,7}, {1,6}, {0,7}, {2,5}, {0,7}, {1,6}, {0,7},
/*112 -119 */       {4,3}, {0,7}, {1,6}, {0,7}, {2,5}, {0,7}, {1,6}, {0,7},
/*120 -127 */       {3,4}, {0,7}, {1,6}, {0,7}, {2,5}, {0,7}, {1,6}, {0,7},

/*128 -135 */       {7,1}, {0,8}, {1,7}, {0,8}, {2,6}, {0,8}, {1,7}, {0,8},
/*136 -143 */       {3,5}, {0,8}, {1,7}, {0,8}, {2,6}, {0,8}, {1,7}, {0,8},
/*144 -151 */       {4,4}, {0,8}, {1,7}, {0,8}, {2,6}, {0,8}, {1,7}, {0,8},
/*152 -159 */       {3,5}, {0,8}, {1,7}, {0,8}, {2,6}, {0,8}, {1,7}, {0,8},
/*160 -167 */       {5,3}, {0,8}, {1,7}, {0,8}, {2,6}, {0,8}, {1,7}, {0,8},
/*168 -175 */       {3,5}, {0,8}, {1,7}, {0,8}, {2,6}, {0,8}, {1,7}, {0,8},
/*176 -183 */       {4,4}, {0,8}, {1,7}, {0,8}, {2,6}, {0,8}, {1,7}, {0,8},
/*184 -191 */       {3,5}, {0,8}, {1,7}, {0,8}, {2,6}, {0,8}, {1,7}, {0,8},
/*192 -199 */       {6,2}, {0,8}, {1,7}, {0,8}, {2,6}, {0,8}, {1,7}, {0,8},
/*200 -207 */       {3,5}, {0,8}, {1,7}, {0,8}, {2,6}, {0,8}, {1,7}, {0,8},
/*208 -215 */       {4,4}, {0,8}, {1,7}, {0,8}, {2,6}, {0,8}, {1,7}, {0,8},
/*216 -223 */       {3,5}, {0,8}, {1,7}, {0,8}, {2,6}, {0,8}, {1,7}, {0,8},
/*224 -231 */       {5,3}, {0,8}, {1,7}, {0,8}, {2,6}, {0,8}, {1,7}, {0,8},
/*232 -239 */       {3,5}, {0,8}, {1,7}, {0,8}, {2,6}, {0,8}, {1,7}, {0,8},
/*240 -247 */       {4,4}, {0,8}, {1,7}, {0,8}, {2,6}, {0,8}, {1,7}, {0,8},
/*248 -255 */       {3,5}, {0,8}, {1,7}, {0,8}, {2,6}, {0,8}, {1,7}, {0,8}
#else
#error SPB is not 4 or 8--LazyRead will behave incorrectly.
#endif
            };

BYTE abGIBMask2[8][SPB] = {
#if SPB == 4
          {0x00, 0xf1, 0xf3, 0xf7},
          {0xfe, 0xf2, 0xf6, 0xfe},
          {0xfc, 0xf4, 0xfc, 0xfc},
                 {0xf8, 0xf8, 0xf8, 0xf8},
                    {0x00, 0x1f, 0x3f, 0x7f},
                    {0xef, 0x2f, 0x6f, 0xef},
                    {0xcf, 0x4f, 0xcf, 0xcf},
          {0x8f, 0x8f, 0x8f, 0x8f}

#elif SPB == 8
                         {0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f},
                         {0xfe, 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0x7e, 0xfe},
                         {0xfc, 0x04, 0x0c, 0x1c, 0x3c, 0x7c, 0xfc, 0xfc},
                         {0xf8, 0x08, 0x18, 0x38, 0x78, 0xf8, 0xf8, 0xf8},
                         {0xf0, 0x10, 0x30, 0x70, 0xf0, 0xf0, 0xf0, 0xf0},
                         {0xe0, 0x20, 0x60, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0},
                         {0xc0, 0x40, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0},
                         {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}
#else
#error LazyRead:  SPB is not 4 or 8.
#endif
                      };

UINT
LazyRead (pbuf,pfrm)
PBUFNODE pbuf;       /* pointer to buffer to lazy read */
PFRAME   pfrm;
{
   PBYTE pbWork;
   PBYTE pCacheSrcData, pCacheSrcData2;
   PBYTE pCacheDestData, pCacheDestData2;
   BYTE bDirtMask = 0;  /*  location to save lazy read bits     */
   BYTE bMask;
   USHORT cSecRead;     /* # of sectors actually read */
   UINT ui,ui2;
   USHORT iVol, usSecOff, usByteOff;
   USHORT usLzRdBitMapOff, usRet;                // @132506
   USHORT usRet1 = NO_ERROR;                     // @132506 init return code
   PBUFNODE pbufSave;
   PBLOCK pblkDest;
   SEL sel;
   ULONG ulpblkPhys;

   iVol = IVOLFROMLSN (pbuf->lsnSec);
   pfrm->pvol = VolPtr [iVol];

   ASSERT_BUF (pbuf);

   while (pbuf->cLocked)
   {
      if (WBU (pbuf,pfrm) == WBU_NEW)
      {
          /* When we got the buffer back, it had a different
           * data block in it. The lazy read was resolved
           * while we were blocked.
           */
         return (ERROR_GEN_FAILURE);
      }
   } /* end while */

   if (!(pbuf->fFlag & BFL_LZREAD))
      return(0);

   pbWork = (PBYTE) pbuf->pLzRdBitMap;

   /* DirtMask for lazy read is the inverse of that for lazy write.
    * A one bit signifies that the sector needs read I/O because
    * it has not been modified or has only been partially modified
    * while in cache.
    */

   // @130910 remove LzRdZeroBuf.
   // The next few lines of code do the following:
   //   Scan the LzRdBitMap for any sectors containing "free" bytes.
   //   A "free" byte is any byte that hasn't been modified by the
   //   partial write, and is represented by a '1' bit in the LzRd bitmap.
   //   If we find a "free" area, we set usDirtySect to identify
   //   which sector in the map the dirty bytes reside.
   //   The bDirtMask bit for that sector is marked, and then the
   //   pbWork pointer is moved to start the next scan in the bitmap starting
   //   at the next sector.  This quickly tells us what sectors in the cache
   //   block we need to read before the partial write can be merged.

   {
      USHORT usDirtySect = 0;               // current sector in block
      USHORT usDirtyBit;                    // bit offset of first unused byte

      while (SFB ( 1
                 , LZ_RD_BIT_MAP_SIZE - (usDirtySect * (LZ_RD_BIT_MAP_SIZE/SPB))
                 , pbWork
                 , &usDirtyBit))  // @130910
      {
         usDirtySect += (usDirtyBit / SECSIZE);  // convert from bit to sector
         bDirtMask |= (0x01 << usDirtySect);     // mark this sector dirty
         if (++usDirtySect >= SPB)               // if beyond last sector
            break;                               // we're done
         pbWork = (PBYTE) pbuf->pLzRdBitMap +
                  usDirtySect * (LZ_RD_BIT_MAP_SIZE/SPB);  // point to next sect
      }
   }

// @130910 ends.  Old code looked like the following
//
// if (memcmp(pbWork, pLzRdZeroBuf, LZ_RD_BIT_MAP_SIZE/SPB) != 0)
//   bDirtMask |= 0x01;
//
// if (memcmp(pbWork+LZ_RD_BIT_MAP_SIZE/SPB, pLzRdZeroBuf, LZ_RD_BIT_MAP_SIZE/SPB) != 0)
//   bDirtMask |= 0x02;
//
// if (memcmp(pbWork+((LZ_RD_BIT_MAP_SIZE/SPB)*2), pLzRdZeroBuf, LZ_RD_BIT_MAP_SIZE/SPB) != 0)
//   bDirtMask |= 0x04;
//
// if ((bDirtMask == 0) ||
//     (memcmp(pbWork+((LZ_RD_BIT_MAP_SIZE/SPB)*3), pLzRdZeroBuf, LZ_RD_BIT_MAP_SIZE/SPB)) !=0)
//   bDirtMask |= 0x08;

// @132506 BUGBUG - If the whole buf is touched, why doesn't the LR buffer
// @132506 get returned before we get here?  We should have caught that earlier.
// @132506 until we find out, we'll just skip the read if it's all dirty

   if (bDirtMask)           // @132506
   {
      cSecRead = aBufa2[bDirtMask].cSecToRead;

      usSecOff = aBufa2[bDirtMask].offus;
      usByteOff = usSecOff * SECSIZE;
      usLzRdBitMapOff = usByteOff / 8;

      LockBUF (pbuf);                // @114986

      if (((usRet = FSH_SEGALLOC ( SA_FRING0
                                 , (ULONG) SPB*SECSIZE
                                 , & sel))) == NO_ERROR)
      {

         pbufSave = pbuf;
         pblkDest = pbuf->pblkData;
         ulpblkPhys = pbuf->blkDataPhysAddr;

         pbuf->pblkData = MAKEP (sel, 0);
         VirtToPhys(pbuf->pblkData,&(pbuf->blkDataPhysAddr));

      }
      else
      {   /* Couldn't allocate space  */

         UnlockBUF (pbuf);                // @114986
         usRet1 = ERROR_NOT_ENOUGH_MEMORY;
         goto lzrRet;
      }

      if (SCR(pbuf,usSecOff,cSecRead,pfrm))
      {

        /* setup copy of unmodified bytes from pCacheSrcData */
         pbWork = (PBYTE)pbuf->pLzRdBitMap + usLzRdBitMapOff;
         pCacheSrcData = (PBYTE)pbuf->pblkData + usByteOff;
         pCacheDestData = (PBYTE)pblkDest + usByteOff;

        /* bitmap scan loop */
         for ( ui = usLzRdBitMapOff
             ; ui < LZ_RD_BIT_MAP_SIZE
             ; ui++, pbWork++, pCacheSrcData += 8, pCacheDestData += 8)
         {
            if (*pbWork)
            {

               pCacheSrcData2 = pCacheSrcData;
               pCacheDestData2 = pCacheDestData;
               ui2 = 0;

               if (*pbWork == 0xff)
               {
                  do
                  {
                     *pCacheDestData2++ = *pCacheSrcData2++;
                  } while (++ui2 < 8);

               }
               else
               {

                  for ( bMask = *pbWork
                      ; ui2 < 8
                      ; ui2++, bMask >>= 1, pCacheSrcData2++, pCacheDestData2++)
                  {

                     if (bMask & 0x01)
                        *pCacheDestData2 = *pCacheSrcData2;
                  }
               }
            }
         }

         usRet1 = NO_ERROR;

      }
      else
         usRet1 = ERROR_READ_FAULT;

      /* restore bufnode  */
      pbuf->pblkData = pblkDest;
      pbuf->blkDataPhysAddr = ulpblkPhys;

      usRet = FSH_SEGFREE (sel);       // @132506
      UnlockBUF (pbuf);                // @114986 @132506
   }

   RetHeap(pbuf->pLzRdBitMap);

   /* Lazy read flag no longer needed */
   pbuf->fFlag &= ~BFL_LZREAD;
   cBufLZRD--;

   if (pbuf->cLocked == 0)
   {
      if (pbuf->pWaitChain != 0)
         WakeupMisc2(&(pbuf->pWaitChain), LOB_BUFWAIT);
   }

lzrRet:
   return (GetHardErr(usRet1));
}
