344 lines
8.2 KiB
C
344 lines
8.2 KiB
C
/*++
|
||
|
||
Copyright (c) 1993 - Colorado Memory Systems, Inc.
|
||
All Rights Reserved
|
||
|
||
Module Name:
|
||
|
||
stbk.c
|
||
|
||
Abstract:
|
||
|
||
These routines setup all of the global variables for appending
|
||
to current tape.
|
||
|
||
|
||
Revision History:
|
||
|
||
|
||
|
||
|
||
--*/
|
||
|
||
//
|
||
// include files
|
||
//
|
||
|
||
#include <ntddk.h>
|
||
#include <ntddtape.h>
|
||
#include "common.h"
|
||
#include "q117.h"
|
||
#include "protos.h"
|
||
|
||
#define FCT_ID 0x0123
|
||
|
||
dStatus
|
||
q117StartBack(
|
||
IN OUT PVOLUME_TABLE_ENTRY TheVolumeTable,
|
||
IN PQ117_CONTEXT Context
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine gets the necessry information for backing up to the
|
||
end of the current tape.
|
||
|
||
Arguments:
|
||
|
||
TheVolumeTable - volume table entry to be used for updating the tape
|
||
directory and for tape linking.
|
||
|
||
Return value:
|
||
|
||
Error in return value.
|
||
|
||
--*/
|
||
|
||
{
|
||
dStatus ret = ERR_NO_ERR; // Return value from other routines called
|
||
LONG i; // Loop variable.
|
||
VOLUME_TABLE_ENTRY temp;
|
||
|
||
//
|
||
// Check to see if anyone has read the last
|
||
// volume entry since Init was called
|
||
//
|
||
|
||
if (Context->CurrentOperation.EndOfUsedTape==0) {
|
||
|
||
//
|
||
// read tape directory (this sets CurrentOperation.EndOfUsedTape)
|
||
//
|
||
if (ret=q117GetEndBlock(&temp,&i,Context))
|
||
|
||
return(ret);
|
||
}
|
||
|
||
//if (Context->ActiveVolumeNumber == Context->CurrentTape.MaximumVolumes) {
|
||
// return(VolFull);
|
||
//}
|
||
|
||
if (Context->CurrentOperation.EndOfUsedTape ==
|
||
Context->CurrentTape.LastSegment) {
|
||
|
||
return ERROR_ENCODE(ERR_TAPE_FULL, FCT_ID, 1);
|
||
|
||
}
|
||
|
||
//
|
||
// fill in the appropriate information in
|
||
// the volume entry
|
||
//
|
||
TheVolumeTable->Signature=VolumeTableSig;
|
||
TheVolumeTable->CreationTime = 0; // lbt_qictime()
|
||
TheVolumeTable->NotVerified = TRUE; // set if volume not verified yet
|
||
TheVolumeTable->NoNewName = FALSE; // set if new file names (redirection) disallowed
|
||
TheVolumeTable->SequenceNumber = 1; // multi-cartridge sequence number
|
||
|
||
ret = q117StartComm(TheVolumeTable,Context);
|
||
|
||
//
|
||
// do common initialization (start or link)
|
||
//
|
||
|
||
return(ret);
|
||
}
|
||
|
||
|
||
dStatus
|
||
q117StartAppend(
|
||
IN OUT ULONG BytesAlreadyThere,
|
||
IN PVOLUME_TABLE_ENTRY TheVolumeTable,
|
||
IN OUT PQ117_CONTEXT Context
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
|
||
|
||
Arguments:
|
||
|
||
BytesAlreadyThere -
|
||
|
||
TheVolumeTable -
|
||
|
||
Context -
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
dStatus ret = ERR_NO_ERR; // Return value from other routines called.
|
||
PSEGMENT_BUFFER bufferInfo;
|
||
PIO_REQUEST ioreq;
|
||
int queuePointer;
|
||
|
||
|
||
//
|
||
// Set up as if we were starting a backup from scratch
|
||
//
|
||
|
||
ret = q117StartBack(TheVolumeTable,Context);
|
||
|
||
if (!ret) {
|
||
|
||
//
|
||
// Now advance past the existing data
|
||
//
|
||
|
||
//
|
||
// Walk through the previous backup
|
||
// to find the ending data and segment
|
||
//
|
||
|
||
while (BytesAlreadyThere >=
|
||
(ULONG)Context->CurrentOperation.SegmentBytesRemaining) {
|
||
|
||
//
|
||
// Adjust counters as if we had backed up the data
|
||
//
|
||
BytesAlreadyThere -=
|
||
Context->CurrentOperation.SegmentBytesRemaining;
|
||
|
||
Context->CurrentOperation.BytesOnTape +=
|
||
Context->CurrentOperation.SegmentBytesRemaining;
|
||
|
||
++Context->CurrentOperation.CurrentSegment;
|
||
|
||
Context->CurrentOperation.SegmentBytesRemaining =
|
||
q117GoodDataBytes(
|
||
Context->CurrentOperation.CurrentSegment,
|
||
Context);
|
||
}
|
||
|
||
//
|
||
// If there is data in the segment we are going to append to
|
||
//
|
||
if (BytesAlreadyThere) {
|
||
Context->CurrentOperation.BytesOnTape += BytesAlreadyThere;
|
||
|
||
//
|
||
// Get pointer to current buffer and buffer info
|
||
//
|
||
Context->CurrentOperation.SegmentPointer =
|
||
q117GetFreeBuffer(&bufferInfo,Context);
|
||
|
||
queuePointer = q117GetQueueIndex(Context);
|
||
|
||
//
|
||
// Read this data block into memory
|
||
//
|
||
ret=q117IssIOReq(
|
||
Context->CurrentOperation.SegmentPointer,
|
||
CMD_READ,
|
||
SEGMENT_TO_BLOCK( Context->CurrentOperation.CurrentSegment),
|
||
bufferInfo,
|
||
Context);
|
||
|
||
if (!ret) {
|
||
|
||
//
|
||
// Wait for data to be read
|
||
//
|
||
ioreq=q117Dequeue(WaitForItem,Context);
|
||
|
||
if (ERROR_DECODE(ioreq->x.adi_hdr.status) != ERR_BAD_BLOCK_DETECTED && ioreq->x.adi_hdr.status) {
|
||
ret = ioreq->x.adi_hdr.status;
|
||
} else {
|
||
|
||
//
|
||
// correct data segment with Reed-Solomon and
|
||
// Heroic retries
|
||
//
|
||
ret = q117ReconstructSegment(ioreq,Context);
|
||
}
|
||
}
|
||
|
||
//
|
||
// Setup queue to write this buffer back out
|
||
//
|
||
q117SetQueueIndex(queuePointer,Context);
|
||
|
||
//
|
||
// Now adjust pointer into buffer to point pass data
|
||
// that is already there.
|
||
//
|
||
(UCHAR *)Context->CurrentOperation.SegmentPointer +=
|
||
BytesAlreadyThere;
|
||
|
||
Context->CurrentOperation.SegmentBytesRemaining -=
|
||
(USHORT)BytesAlreadyThere;
|
||
|
||
}
|
||
}
|
||
|
||
return(ret);
|
||
|
||
}
|
||
|
||
|
||
dStatus
|
||
q117StartComm(
|
||
OUT PVOLUME_TABLE_ENTRY TheVolumeTable,
|
||
IN OUT PQ117_CONTEXT Context
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine gets the necessary information for backing up to the end
|
||
of the current tape.
|
||
|
||
Arguments:
|
||
|
||
TheVolumeTable - volume table entry to be used for updating the tape
|
||
directory and for tape linking.
|
||
|
||
Return Value:
|
||
|
||
Error in return value.
|
||
|
||
--*/
|
||
|
||
{
|
||
LONG ret = ERR_NO_ERR;
|
||
|
||
//
|
||
// zero out appropriate information
|
||
//
|
||
TheVolumeTable->MultiCartridge = FALSE; // set if volume spans another tape
|
||
TheVolumeTable->DirectorySize = 0; // number of bytes reserved for directory
|
||
TheVolumeTable->DataSize = 0; // size of data area (includes other cartridges)
|
||
TheVolumeTable->EndingSegment = 0;
|
||
TheVolumeTable->NoNewName = FALSE; // allow restoring to new name (re-direction)
|
||
TheVolumeTable->reserved = 0; // QIC-40 spec. says to zero this out
|
||
|
||
//
|
||
// set global variables
|
||
//
|
||
Context->CurrentOperation.CurrentSegment =
|
||
Context->CurrentOperation.EndOfUsedTape+1;
|
||
|
||
Context->CurrentOperation.LastSegment = Context->CurrentTape.LastSegment;
|
||
|
||
// clear out the flag for update of bad map
|
||
Context->CurrentOperation.UpdateBadMap = FALSE;
|
||
|
||
Context->CurrentOperation.BytesZeroFilled = 0;
|
||
Context->CurrentOperation.BytesOnTape = 0;
|
||
Context->CurrentOperation.SegmentPointer = q117GetFreeBuffer(NULL, Context);
|
||
|
||
#ifndef NO_MARKS
|
||
|
||
//
|
||
// We need to skip segments with no data area (too many bad sectors)
|
||
//
|
||
while ((Context->CurrentOperation.SegmentBytesRemaining =
|
||
q117GoodDataBytes(
|
||
Context->CurrentOperation.CurrentSegment,
|
||
Context)
|
||
) <= 0) {
|
||
|
||
++Context->CurrentOperation.CurrentSegment;
|
||
}
|
||
|
||
|
||
//
|
||
// Use the directorySize field to store the segment that has marks
|
||
//
|
||
TheVolumeTable->DirectorySize =
|
||
(ULONG)Context->CurrentOperation.CurrentSegment++;
|
||
|
||
//
|
||
// Calculate the maximum number of marks (based on (the number of
|
||
// actual bytes in the segment - count dword) / size of a mark entry)
|
||
// NOTE: This value is only useful, and valid, for a backup.
|
||
//
|
||
Context->MarkArray.MaxMarks = (q117GoodDataBytes(
|
||
(SEGMENT)Context->ActiveVolume.DirectorySize, Context ) - sizeof(ULONG))
|
||
/ sizeof(struct _MARKLIST);
|
||
|
||
|
||
#endif
|
||
|
||
//
|
||
// We need to skip segments with no data area (too many bad sectors)
|
||
//
|
||
while ((Context->CurrentOperation.SegmentBytesRemaining = q117GoodDataBytes(
|
||
Context->CurrentOperation.CurrentSegment,
|
||
Context)) <= 0) {
|
||
++Context->CurrentOperation.CurrentSegment;
|
||
}
|
||
|
||
TheVolumeTable->StartSegment = Context->CurrentOperation.CurrentSegment;
|
||
return(ret);
|
||
}
|