/*static char *SCCSID = "@(#)lsdbmerr.c 6.2 92/01/31";*/
#define _BTXT _BTXT
#define INCL_DOSERRORS
#include <os2def.h>
#include <bse.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 "superb.h"
#include "lw.h"
#include "frame.h"
#include "fsdata.h"
#include "pbmacros.h"
#include "log.h"                                                 // @76193

#include "pr_CACHE.h"
#include "pr_DEBUG.h"
#include "pr_FSINI.h"
#include "pr_MISC.h"


/*
 ***    LSDBMErr - Handle errors for LSDBM.
 *
 *      LSDBM is identical to LSD except instead of returning NULL
 *      for a single bad sector it checks the entire bitmap block
 *      (i.e, the cache block) for an error.  Any error sectors
 *      are zeroed, the "volume needs repair" flag is set, and
 *      offending sectors are zeroed.  The bandtab fields and the
 *      volume fields are adjusted as appropriate.
 *
 *      ENTRY   ppbuf = address of pbuf that's bad
 *
 *      EXIT    NONE
 *
 *      HISTORY
 *  @76193  23-Nov-1993 by D.Azzarito - Change holds for LOG support
 */

VOID far
LSDBMError (PBUFNODE pbuf, PFRAME pfrm)
{
    /* OK, we've got a hard error in the bitmap.  Locate the Volume
     * and the band involved - it could be that the bitmap only
     * occupies part of this cache block and that the error isn't
     * in the bitmap at all.
     */

    PVOLTAB pvol;
    USHORT i;
    PBANDTAB pbt;
    BYTE flag = 0;

#ifdef DEBUG
    dprintf ("LSDBMErr: handling hard error in the bitmap\n");
#endif

    pvol = VolPtr [IVOLFROMLSN ((pbuf)->lsnSec)];
#ifdef DEBUG
    if (pvol == NULL) {
        INTERR (__FILE__": NULL pVolTab");
    }
#endif
    {
        BOOL Found;


        /* We've got the volume.  See which band this is and we'll
         * adjust its counts
         */

        for (i=0; i < pvol->cBands; i++) {
            if (Found = (pvol->apbndList[i]->scpMap.lsn ==
                    pbuf->lsnSec)) {
                break;
            }
        }

        if (Found)
            pbt = pvol->apbndList[i];
        else {
            /* must be DirBlk */
            pbt = &pvol->bndDirBand;
#ifdef DEBUG
            if (pbt->scpMap.lsn != pbuf->lsnSec)
                INTERR (__FILE__": Can't find Bit Map");
#endif
        }
    }

    {
        USHORT cSecs;
        USHORT cerror = 0;

        /* Got the volume and bandtab.  Now check the bitmap sectors
         * in the cache block, looking for the bad ones.
         */

        cSecs = UNSAFE_ROUND_UP_DIV (pbt->cbMapLen, SECSIZE);
        for (i=0; i < cSecs; i++) {
            if ((pbuf->bBadMask & (1 << i)) != 0) {
                pbuf->bBadMask &= ~(1 << i);
                cerror++;
                memset (((PSECTOR) pbuf->pblkData + i), 0, SECSIZE);
            }
        }

        /* OK, we've zapped the bad sectors and marked them OK so that
         * we don't keep executing this code.  Now, compute the # of
         * bits that we've discarded and update the band and volume
         * table stuff.
         */

        if (cerror != 0) {

            USHORT cfree;
#ifdef DEBUG
            dprintf ("LSDBM: zapped bad sectors\n");
#endif

            cfree = pbt->csecFree;
            CountBit ((PBYTE) pbuf->pblkData, pbt->cbMapLen, pbt);

            /* Have zeroed the bad bits and removed their count from
             * the bandtab.  Now adjust the volume info for the reduced
             * number of bits.
             */
            pvol->csecSpace -= (cfree - pbt->csecFree);

            flag = SPF_BADBM;
        }

        /* We've zapped the bad bitmap sectors, if any, and adjusted
         * the counts.  Update the Spare block flags to show our
         * damage.
         */

        /* lbm50: */
#ifndef MINIFSD
        IncrHoldsBUF (pbuf);  // @76193

        WriteSparesFlag((BYTE)(flag | SPF_BADSEC), pfrm);

        DecrHoldsBUF (pbuf);  // @76193
#endif
        SETHARDERR (ERROR_READ_FAULT);
    }
}
