/*static char *SCCSID = "@(#)initseg.c  6.2 91/01/14";*/
#define SCCSID "@(#)initseg.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 :  INITSEG.C
 *
 *
 *  DESCRIPTION
 *
 *      Memory initialization routines called only once.  These allocate
 *      the first segment in the heap and the sector cache.
 *
 *
 *  FUNCTIONS DEFINED
 *
 *      InitSegments () -- Initial allocation of segments
 *
 *
 *  REVISION HISTORY (in reverse chronological order)
 *  -----------------------------------------------------------------------
 *  9/26/92     Frank Schroeder Initialized raw directory record (prdrGlobalRDR)
 *                              pointer and (sRawDirRec) semaphore for MSCDEX
 *                              support.
 *
 *  4/19/90     Brian Andrew    Initialized the LIST_SEM_BLK global and
 *                              semaphore.
 *
 *  4/5/90      Brian Andrew    Rewrite of original functions in
 *                              'meminit.c'.
 *
 *
 *  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"

#include "pr_heap.h"
#include "pr_memin.h"
#include "pr_strng.h"
#include "pr_misc.h"

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

/***    InitSegments () --  Initial allocation of segments.
 *
 *  DESCRIPTION
 *
 *      This routine is called after the first entry into the FSD other
 *      than FS_INIT.  This is where the sector cache is allocated and
 *      the initial heap is allocated.  The initial heap is allocated
 *      first, this will provide the BUF structures for the sectors.
 *
 *      We then try to allocate all the requested sector cache structures
 *      and attach BUF structures to them.  If there is an error while
 *      allocating and attaching BUF's to the first segment for the cache,
 *      we return and error and generate a popup.  If there is an error
 *      in allocating or attaching BUF's to the any subsequent cache
 *      segment, we generate a popup but don't return an error.
 *
 *      The BUF's for each segment are linked together and not linked to
 *      the BUF free list until the segment is completely processed.
 *
 *
 *  ENTRY   (Arguements passed to function)
 *
 *      NONE
 *
 *
 *  GLOBAL  (Global variables accessed by this function)
 *
 *      phHeapStart     --  Pointer to first segment in heap.
 *      pbFreeSec       --  Pointer to first BUF in free list.
 *      pbFirstPT       --  Pointer to most recently used PT sector.
 *      pbLastPT        --  Pointer to least recently PT sector.
 *      pbFirstSec      --  Pointer to most recently used data sector.
 *      pbLastSec       --  Pointer to least recently used data sector.
 *      pblGlobalBL     --  Pointer to start of free BUF_LIST structs.
 *      pbGlobalBuf     --  Pointer to start of free BUF structs.
 *      ppeGlobalPE     --  Pointer to start of free PATH_ENTRY structs.
 *      pptGlobalPT     --  Pointer to start of free PATH_TABLE structs.
 *      pdeGlobalDE     --  Pointer to start of free DIR_ENTRY structs.
 *      prdrGlobalRDR   --  Pointer to start of free RAW_DIR_REC structs.
 *      pvdGlobalVD     --  Pointer to start of free VOL_DESC structs.
 *      pssGlobalSS     --  Pointer to start of free SEARCH_STRING structs.
 *      prpiGlobalRPI   --  Pointer to start of free RAW_PATH_ISO structs.
 *      pfblGlobalFBL   --  Pointer to start of free FIND_BUF_LOC structs.
 *      pmpGlobalMP     --  Pointer to start of free MOUNT_PARAMS structs.
 *      pffpGlobalFFP   --  Pointer to start of free FIND_FIRST_PARMS structs.
 *      psbGlobalSB     --  Pointer to start of free STRING_BUFFER structs.
 *      plsbGlobalLSB   --  Pointer to start of free LIST_SEM_BLK structs.
 *      cBufSegs        --  Count of segments to use for cache.
 *      sBuf            --  Semaphore for BUF structures.
 *      sSearchArray    --  Semaphore for SEARCH_STRING structures.
 *      sBufList        --  Semaphore for BUF_LIST structures.
 *      sPathEntry      --  Semaphore for PATH_ENTRY structures.
 *      sVolDesc        --  Semaphore for VOL_DESC structures.
 *      sDirEntry       --  Semaphore for DIR_ENTRY structures.
 *      sPathTable      --  Semaphore for PATH_TABLE structures.
 *      sRawPathISO     --  Semaphore for RAW_PATH_ISO structures.
 *      sFindBufLoc     --  Semaphore for FIND_BUF_LOC structures.
 *      sMountParams    --  Semaphore for MOUNT_PARAMS structures.
 *      sFFrstParams    --  Semaphore for FFRST_PARAMS structures.
 *      sStringBuf      --  Semaphore for STRING_BUFFER structures.
 *      sHeap           --  Semaphore for HEAP structures.
 *      sFreeSec        --  Semaphore for accessing free BUF list.
 *      sBLSec          --  Semaphore for accessing in-use BUF_LIST sectors.
 *      sPTSec          --  Semaphore for accessing in-use PATH_TABLE sectors.
 *      sSemBlk         --  Semaphore for accessing LIST_SEM_BLK structures.
 *
 *
 *  GOTO    (Jump targets)
 *
 *      InitSegments_FreeHeap_ErrMsg    --  Common point if failure in
 *                                          in initial cache segment.
 *
 *      InitSegments_WarnMsg_ClrErr     --  Common point if failure in
 *                                          subsequent cache segment.
 *
 *
 *  RETURN  (Values returned by this function)
 *
 *      Return value from FSH_SEGALLOC.
 *      Return value from GetBuf.
 *      Return value from GetHeapChunk.
 *      NO_ERROR if partial or successful allocation.
 *
 *  EXIT    (Changes to variables seen outside this function)
 *
 *      Debug version uses 'pszMsgArray'
 *
 *
 *  LOCAL   (Variables declared within this function)
 *
 *      sSel            --  Selector used for allocation.
 *      phHeap          --  Pointer to heap structure.
 *      usRet           --  Return value.
 *      cSegments       --  Count through allocated cache segments.
 *      sThisSector     --  Pointer to current sector in segment.
 *      pbPrevBuf       --  Pointer to last BUF allocated.
 *      pbThisBuf       --  Pointer to this BUF allocated.
 *      cSectors        --  Count through sectors in segment.
 *      acNumbers       --  Array of buffers to store numbers.
 *      apcNumbersASCII --  Array of pointers to number arrays.
 *      psbStringBuf    --  Used for storage of string message.
 */

USHORT InitSegments ()
{
        /* Local variables */
        SEL     sSel;
        PHEAP   phHeap;
        USHORT  usRet;
        USHORT  cSegments;
        SECTOR  sThisSector;
        PBUF    pbPrevBuf;
        PBUF    pbThisBuf;
        USHORT  cSectors;

        /* Initialize global variables */
        phHeapStart = NULL;
        pbFreeSec = NULL;
        pbFirstPT = NULL;
        pbLastPT = NULL;
        pbFirstSec = NULL;
        pbLastSec = NULL;
        pblGlobalBL = NULL;
        pbGlobalBuf = NULL;
        ppeGlobalPE = NULL;
        pptGlobalPT = NULL;
        pdeGlobalDE = NULL;
        prdrGlobalRDR = NULL;
        pvdGlobalVD = NULL;
        pssGlobalSS = NULL;
        prpiGlobalRPI = NULL;
        pfblGlobalFBL = NULL;
        pmpGlobalMP = NULL;
        pffpGlobalFFP = NULL;
        psbGlobalSB = NULL;
        plsbGlobalLSB = NULL;

        /* Clear all the semaphores */
        SEM_CLEAR (sBuf);
        SEM_CLEAR (sSearchArray);
        SEM_CLEAR (sBufList);
        SEM_CLEAR (sPathEntry);
        SEM_CLEAR (sVolDesc);
        SEM_CLEAR (sDirEntry);
        SEM_CLEAR (sRawDirRec);
        SEM_CLEAR (sPathTable);
        SEM_CLEAR (sRawPathISO);
        SEM_CLEAR (sFindBufLoc);
        SEM_CLEAR (sMountParams);
        SEM_CLEAR (sFFrstParams);
        SEM_CLEAR (sStringBuf);
        SEM_CLEAR (sHeap);
        SEM_CLEAR (sFreeSec);
        SEM_CLEAR (sBLSec);
        SEM_CLEAR (sPTSec);
        SEM_CLEAR (sSemBlk);

        /* Attempt allocation of original heap segment */
        if (!(usRet = FSH_SEGALLOC (SWAP_ALLOC, INIT_HEAP_SIZE, &sSel)))
        {
                /* Attach this heap structure to the FSD heap */
                phHeap = MAKEP (sSel, 0);
                phHeap->cbHeapSize = INIT_HEAP_SIZE;
                phHeap->phNextHeap = NULL;
                phHeapStart = phHeap;

                /*
                 *  for loop :
                 *
                 *      This loop is entered for each segment in the sector
                 *      cache.  Ideally, a segment is allocated and divided
                 *      up into 2k blocks.  A BUF structure is attached to
                 *      each block and linked with the other BUF's for this
                 *      segment.  When a chain has been constructed of all the
                 *      sectors in this segment, the entire chain is added to
                 *      the list of free sectors.
                 *
                 *      If an error occurs while processing the first cache
                 *      segment, we free any segments allocated and generate
                 *      a popup indicating memory allocation failure.
                 *
                 *      If an error occurs while processing a cache segment
                 *      other than the first, we deallocate the segment that
                 *      caused the error.  A popup is generated indicating that
                 *      the cache is smaller than the expected size but is
                 *      present.  The error code is then cleared.
                 */
                for (cSegments = cBufSegs; cSegments--;)
                {
                        /* Attempt to allocate next cache segment */
                        if (!(usRet = FSH_SEGALLOC (SWAP_ALLOC, SEC_ALLOC_LEN,
                                                                        &sSel)))
                        {
                                /* Convert selector to pointer */
                                sThisSector = MAKEP (sSel, 0);

                                /* Set previous BUF pointer to NULL */
                                pbPrevBuf = NULL;

                                /*
                                *  for loop :
                                *
                                *      This loop walks through the sectors in a
                                *      single segment.  For each sector a BUF structure
                                *      is requested and the sector is attached to it.
                                *
                                *      The BUF are linked together in a circular list
                                *      where we point to the current BUF and it points
                                *      to both the previous BUF and the first BUF in
                                *      the chain.
                                *
                                *      If an error occurs while allocating BUF structs,
                                *      we walk through the chain, freeing the BUF
                                *      structures in the chain.  We also attach the
                                *      the sector segment to the heap, since the
                                *      BUF failure could only come from a memory
                                *      allocation problem.
                                *
                                *      If the error occurs during the processing of
                                *      the first cache segment.  There is no way the
                                *      FSD can function.  In that case, we simply
                                *      free all allocated segments and return an
                                *      error.
                                */
                                for (cSectors = SEC_PER_SEG; cSectors--;)
                                {
                                        /* Attempt to get a BUF structure */
                                        if (!(usRet = AllocBuf (&pbThisBuf)))
                                        {
                                                /* Attach sector to BUF */
                                                pbThisBuf->sSector = sThisSector;

                                                /* Step forward in sector */
                                                sThisSector += SECTOR_SIZE;

                                                /* If previous BUF exists, attach to it */
                                                if (pbPrevBuf)
                                                {
                                                        pbThisBuf->pbNextBUF = pbPrevBuf->pbNextBUF;
                                                        pbPrevBuf->pbNextBUF = pbThisBuf;

                                                } /* end if previous BUF exists */

                                                /* Else create a circle of one */
                                                else
                                                {
                                                        pbThisBuf->pbNextBUF = pbThisBuf;
                                                }

                                                /* Connect the new BUF to its predecessor */
                                                pbThisBuf->pbPrevBUF = pbPrevBuf;

                                                /* Current BUF is now previous BUF */
                                                pbPrevBuf = pbThisBuf;

                                        } /* end if successful allocation of BUF struct */

                                        /* Else BUF allocation failure */
                                        else
                                        {
                                                /* If this is the first cache segment */
                                                if (cSegments == cBufSegs - 1)
                                                {
                                                        /* Free the cache segment via selector */
                                                        FSH_SEGFREE (sSel);

                                                        /*
                                                                * Jump to common point to free heap segment
                                                                * and generate error popup message.
                                                                */
                                                        goto InitSegments_FreeHeap_ErrMsg;

                                                } /* end if first cache segment */

                                                /* Else this is a later segment */
                                                else
                                                {
                                                        /*
                                                        *  while loop :
                                                        *
                                                        *      This loop walks from the end
                                                        *      of the linked list of BUF
                                                        *      structs and puts them on the
                                                        *      free list.  We take advantage
                                                        *      of the fact that FREE_BUF only
                                                        *      modifies the 'next' pointer
                                                        *      in the BUF so we can still
                                                        *      access the 'prev' pointer even
                                                        *      after we have freed the struct.
                                                        */
                                                        /* While any BUF's in list */
                                                        while (pbPrevBuf)
                                                        {
                                                                /* Free the current BUF */
                                                                FREE_BUF (pbPrevBuf);

                                                                /* Make previous BUF current */
                                                                pbPrevBuf = pbPrevBuf->pbPrevBUF;

                                                        } /* end while more BUF's */

                                                        /* Recover a pointer to the cache segment */
                                                        phHeap = MAKEP (sSel, 0);

                                                        /* Attach this pointer into the heap */
                                                        phHeap->cbHeapSize = SEC_ALLOC_LEN;
                                                        phHeap->phNextHeap = phHeapStart;
                                                        phHeapStart = phHeap;

                                                        /*
                                                        * Jump to common code to generate a warning
                                                        * popup and clear the error code.
                                                        */
                                                        goto InitSegments_WarnMsg_ClrErr;

                                                } /* end else a later segment */

                                        } /* end else BUF allocation failure */

                                } /* end for loop for each sector in segment */

                                /* Attach circular sector list to free list */
                                /* Remember the first in the list */
                                pbThisBuf = pbPrevBuf->pbNextBUF;

                                /* Connect end of circular to top of free list */
                                pbPrevBuf->pbNextBUF = pbFreeSec;

                                /* Set the top of the free list to circle head */
                                pbFreeSec = pbThisBuf;

                        } /* end if allocation of cache segment */

                        /* Else cache segment allocation failed */
                        else
                        {
                                /* If this is the first segment */
                                if (cSegments == cBufSegs - 1)
                                {

/* Jump point for failure on first segment */
InitSegments_FreeHeap_ErrMsg:

                                        /* De-allocate heap segment */
                                        FSH_SEGFREE (SELECTOROF (phHeapStart));

                                        /* Generate error popup */
                                        /* BUGBUG send message to debug screen for now */
#ifdef DEBUG
                                        dprintf ("\tInitSegments : Initial allocation failed -- %d\n",
                                                                usRet);
#endif

                                } /* end if first cache segment */

                                /* Else generate non-fatal popup */
                                else
                                {
/* Jump point for failure on subsequent segment */
InitSegments_WarnMsg_ClrErr:

                                        /* Generate warning pop-up */
                                        /* BUGBUG This is simply to the debug screen now */
#ifdef DEBUG
                                        {
                                                UCHAR       acNumbers[2][10];
                                                PCHAR       apcNumbersASCII[2];
                                                PSTRING_BUF psbStringBuf;

                                                /* Point to the separate buffers */
                                                apcNumbersASCII[0] = acNumbers[0];
                                                apcNumbersASCII[1] = acNumbers[1];

                                                /* Try to allocate a message buffer */
                                                if (!GetStringBuf (&psbStringBuf))
                                                {
                                                        /* Fill in the parameter buffers */
                                                        DecimalToASCII (acNumbers[0],
                                                                                        (ULONG) (cBufSegs - cSegments + 1),
                                                                                        TRUE);

                                                        DecimalToASCII (acNumbers[1],
                                                                                        (ULONG) cBufSegs,
                                                                                        TRUE);

                                                        /* Put this into a message buffer */
                                                        ParmMsg (
                                                                (PMESSAGE) &(_TXT_MSG_CDFS_PARTIAL_MEM_FAIL),
                                                                psbStringBuf,
                                                                apcNumbersASCII);

                                                        dprintf ("\t%Fs",psbStringBuf);

                                                } /* End if successful allocation of string buffer */

                                        } /* end of block for variables */
#endif

                                        /* Clear error code */
                                        usRet = NO_ERROR;

                                } /* end else not the first segment */

                                /* Break out of 'for' loop */
                                break;

                        } /* end else cache segment allocation failed */

                } /* end for loop for each cache segment */

        } /* end if successful allocation of initial heap segment */

#ifdef DEBUG
        /* Else generate error popup */
        else
        {
                /* BUGBUG send message to debug screen for now */
                dprintf ("\tInitSegments : Initial allocation failed -- %d\n",
                                        usRet);

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

        /* Return the error code */
        return usRet;

} /* end InitSegments */


