                .DO     External
                .LSTON
                .Page
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;>
;>      Module: Spare
;>
;>      This module contains all the routines that pertain 
;>      to the management of the spare table.
;>
;>      PROCEDURE SprBlock( SpareType : BIT { !r8/bit 7 } )
;>      PROCEDURE SpareBlock( BlockIsSpare : BOOLEAN { !r8/bit 4 } )
;>
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
                .LSTOFF
                .FIN
                .DO     External
                .LSTON
                .Page
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;>
;>      Procedure: SprBlock     { Spare A Block }
;>
;>      This procedure is responsible for relocating a logical
;>      block { note that the block type can be USER, or SPARETABLE }
;>      from either the user data area OR the spare area to
;>      some location within the spare area.
;>
;>      This procedure is capable of gobbling up ALL available spare
;>      block space and will ABORT if no space is available.
;>
;>      Inputs:
;>              SpareType : BIT { !rA/bit 4 }
;>
;>      Outputs: { none }
;>
;>      Algorithm:
;>
;>      BEGIN
;>       IF ( SpareType = Spare )
;>        THEN
;>         IF ( BlkStat.SpareCode = BadBlock )
;>          THEN 
;>              DeleteSpare
;>              SpareCount( Dec_BadCnt )
;>         BlockMove( WBuffer1, Buffer2 )
;>         IF NOT( WrVer_Common )
;>          THEN
;>           SpareBlock( SpareType )
;>        ELSE SpareBlock( BadBlockType )
;>       UpDate_SprTbl
;>       BlockMove( Buffer2, RBuffer1 )
;>      END
;>
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
                .LSTOFF
                .FIN
                .DO     Internal
                .LSTON
                .Page
                .FIN

SprBlock:
                Tm      !rA,#Spare ;IF SpareType = Spare
                Jr      Z,SprBlk_1
                
                Call    Get_Spr_Code
                Cp      !r0,#B_Block
                Jr      Nz,SprBlk_2
                
                Call    DeleteSpare
                 Ld     !r0,#Dec_BadCnt
                 Ld     !r2,#.HIBYTE. SpareCount
                 Ld     !r3,#.LOWBYTE. SpareCount
                Call    Bank_Call
                
SprBlk_2:       Call    ReSeek
                Ld      !r4,#10 ;bang on this block for a while
                Ld      !r5,#0 ;init error count

Spr_WrVer:       Ld     !r2,#.HIBYTE. Buf2_To_WrBuf
                 Ld     !r3,#.LOWBYTE. Buf2_To_WrBuf
                Call    Bank_Call

                 Ld     RdErrCnt,#10 ;assume failure
                Call    WrVer_Common
                Jr      Nz,SprWrV_1
                
                Or      WrStat,WrStat ;check for write error
                Jr      Nz,SprBlk_1
                
                Ld      !r0,RdErrCnt
                And     !r0,#$0F ;mask off status info
                Jr      Z,SprBlk_1  ;check for header failure
                
                Cp      !r0,#SprThresh
                Jr      Gt,SprBlk_1 ;spare the block if over threshold
                
                Add     !r5,!r0 ;bump cumulative error count
SprWrV_1:       Djnz    !r4,Spr_WrVer
                
                Cp      !r5,#SprThresh ;take a percentage of total reads
                Jr      Le,SprBlk_3
                
SprBlk_1:       Call    SpareBlock
                
SprBlk_3:        Ld     !r2,#.HIBYTE. UpDate_SprTbl
                 Ld     !r3,#.LOWBYTE. UpDate_SprTbl
                Call    Bank_Call
                 Ld     !r2,#.HIBYTE. Buf2_To_RBuf
                 Ld     !r3,#.LOWBYTE. Buf2_To_RBuf
                Call    Bank_Call

SprBlk_Ret:     Ret
                
                .LSTOFF
                .DO     External
                .LSTON
                .Page
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;>
;>      Procedure: SpareBlock
;>
;>      This function performs the actual sparing.
;>
;>      Inputs:
;>              SpareType          : BIT { !rA/bit 4 }
;>
;>      Outputs: { none }
;>
;>      Local Variables:
;>              SparingASpare : BOOLEAN { !r9 }
;>              SpareLocation : BYTE { !r4 }
;>              Error         : BOOLEAN { !r5 }
;>
;>      Algorithm:
;>
;>      BEGIN
;>       IF ( BlkStat.SpareCode = BadBlock )
;>        THEN 
;>              AddSpare( GetNewSpare( Load_Logical ), Load_Logical, BadBlock )
;>              SpareCount( Inc_BadCnt )
;>        ELSE
;>             REPEAT
;>              IF ( BlkStat.SpareCode = Spare )
;>               THEN
;>                Location := SrchSpTabl( Load_Logical )
;>                Ptr := Get_Ptr( Location )
;>                Ptr^.Useable := False
;>              SpareCount( Inc_SprCnt )
;>              BlkStat.SpareCode := SpareBlock
;>              Location := GetNewSpare( Load_Logical )
;>              AddSpare( Location, Load_Logical, SpareBlock )
;>              Seek_Type := Access_Offset
;>              Seek( Get_Cyl_H_S( MulR0_m( Location ) ) )
;>             UNTIL WrVer_Common
;>      END
;>
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
                .LSTOFF
                .FIN
                .DO     Internal
                .LSTON
                .Page
                .FIN
                
SpareBlock:
                 Ld     !r0,#1 ;byte 1
                 Ld     !r1,#Stat_Spare
                Call    SetStatus
                
                Tm      !rA,#Spare
                Jr      Nz,S_Blk_Rpt
                
                Call    Get_Spr_Code
                Cp      !r0,#B_Block
                Jr      Z,S_Blk_End
                
                Call    Load_Logical
                Call    GetNewSpare
                 Ld     !rF,!r0
                 Ld     !r8,#BadBlock
                Call    AddSpare
                 Ld     !r0,#Inc_BadCnt
                 Ld     !r2,#.HIBYTE. SpareCount
                 Ld     !r3,#.LOWBYTE. SpareCount
                Call    Bank_Call
                Jr      S_Blk_End
                
S_Blk_Rpt:      Call    Load_Logical
                Call    Spr_Enter
                Jr      Nz,S_Blk_End
                
                Cp      !r0,#Error+Ex_ReadErr ;check for sparing threshold
                Jr      Nz,S_Blk_Rpt
                
S_Blk_End:      Jp      Bank_Ret

                .Page

Spr_Enter:      Call    Get_Spr_Code
                 Cp     !r0,#S_Block
                Jr      Nz,S_Blk_New
                
                Call    ExtPush_Vector
                Call    SrchSpTabl
                 Push   !r1             ;save possible ptr to element
                 Push   Flags
                 Call   ExtPop_Vector
                 Pop    Flags
                 Pop    !r1
                Jr      Nz,S_Blk_Unuse
                
                Call    Abort
                
S_Blk_Unuse:     Ld     !r0,!r1
                Call    Get_Ptr
                Lde     !r0,@!!r2 ;Element.Useable := False
                And     !r0,#$FF-Useable
                Lde     @!!r2,!r0

S_Blk_New:       Ld     !r0,#Inc_SprCnt
                 Ld     !r2,#.HIBYTE. SpareCount
                 Ld     !r3,#.LOWBYTE. SpareCount
                Call    Bank_Call
                
                And     BlkStat,#$FC ;mask out the SpareCode stuff
                Or      BlkStat,#S_Block
                
                Call    GetNewSpare
                 Ld     !rF,!r0
                 Ld     !r8,#Spare
                Call    AddSpare
                
                Ld      Seek_Type,#Access_Offset
                 
                 Ld     !r0,!rF ;get Location back
                 Inc    !r0 ;count 1..76
                 Ld     !r2,#.HIBYTE. MulR0_m
                 Ld     !r3,#.LOWBYTE. MulR0_m
                Call    Bank_Call
                 Ld     !r2,#.HIBYTE. Get_Cyl_H_S
                 Ld     !r3,#.LOWBYTE. Get_Cyl_H_S
                Call    Bank_Call
                 Ld     !r0,!rF
                 Ld     !r2,#.HIBYTE. ReMap_Sector
                 Ld     !r3,#.LOWBYTE. ReMap_Sector
                Call    Bank_Call
                 Ld     !rF,!r0
                Call    Seek_Vector
                
                Cp      DataType,#User_type
                Jr      Z,Spr_LdBuf2
                
                 Ld     !r2,#.HIBYTE. SprChkSum ;calculate new checkbyte
                 Ld     !r3,#.LOWBYTE. SprChkSum
                Call    Bank_Call
                 Ld     !r2,#.HIBYTE. Spr_To_WrBuf
                 Ld     !r3,#.LOWBYTE. Spr_To_WrBuf
                Jr      Spr_LdWrBuf
                
Spr_LdBuf2:      Ld     !r2,#.HIBYTE. Buf2_To_WrBuf
                 Ld     !r3,#.LOWBYTE. Buf2_To_WrBuf
Spr_LdWrBuf:    Call    Bank_Call
                
                Call    WrVer_Common
                Jp      Bank_Ret
                
                .LSTOFF
                
