NT4/private/ntos/dd/qic117/update.c
2020-09-30 17:12:29 +02:00

632 lines
12 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1993 - Colorado Memory Systems, Inc.
All Rights Reserved
Module Name:
update.c
Abstract:
Performs the various tape updating functions.
Revision History:
--*/
//
// include files
//
#include <ntddk.h>
#include <ntddtape.h>
#include "common.h"
#include "q117.h"
#include "protos.h"
#define FCT_ID 0x0124
dStatus
q117UpdateHeader(
IN PTAPE_HEADER Header,
IN PQ117_CONTEXT Context
)
/*++
Routine Description:
This routine updates the tape header.
Arguments:
Header -
Context -
Return Value:
--*/
{
dStatus ret;
PVOID scrbuf;
PSEGMENT_BUFFER bufferInfo;
//
// put saved logical part of header into transfer buffer
//
scrbuf = q117GetFreeBuffer(&bufferInfo,Context);
RtlMoveMemory(scrbuf, Header, sizeof(TAPE_HEADER));
//
// write out the TapeHeader structure
//
ret = q117FillTapeBlocks(
CMD_WRITE_DELETED_MARK,
(SEGMENT)0,
Header->DupHeaderSegment,
scrbuf,
Header->HeaderSegment,
Header->DupHeaderSegment,
bufferInfo,
Context);
return(ret);
}
dStatus
q117Update(
IN OUT PQ117_CONTEXT Context
)
/*++
Routine Description:
This routine updates tape directory with cur_vol.
Arguments:
Link -
Context -
Return Value:
--*/
{
dStatus ret; // Return value from other routines called.
Context->ActiveVolume.DataSize = Context->CurrentOperation.BytesOnTape;
//
// update volume table entry (to be written to tape directory)
//
Context->ActiveVolume.EndingSegment = (USHORT)Context->CurrentOperation.CurrentSegment-1;
if (Context->CurrentOperation.UpdateBadMap) {
if (ret = q117DoUpdateBad(Context))
return(ret);
}
//
// update volume directory
//
// thevoldir->endblock was set to 0 at StartBack().
//
ret=q117AppVolTD(&Context->ActiveVolume,Context);
if (ret==ERR_NO_ERR) {
Context->CurrentOperation.EndOfUsedTape = Context->ActiveVolume.EndingSegment;
#ifndef NO_MARKS
ret = q117DoUpdateMarks(Context);
#endif
} else {
Context->CurrentOperation.EndOfUsedTape=0;
}
//
// Set the tape status.
//
q117SetTpSt(Context);
return(ret);
}
dStatus
q117DoUpdateBad(
IN OUT PQ117_CONTEXT Context
)
/*++
Routine Description:
Arguments:
Context -
Return Value:
--*/
{
dStatus ret;
PVOID scrbuf;
PSEGMENT_BUFFER bufferInfo;
PTAPE_HEADER hdr;
//
//rdr - Beta fix
//
// return(BadTape);
CheckedDump(QIC117INFO,( "Q117i: Starting DoUpdateBad\n"));
//
// read the header segment in
//
//if (ret = q117ReadHeaderSegment(&hdr,Context)) {
//
// return(ret);
//
//}
hdr = Context->CurrentTape.TapeHeader;
//
// put in the new bad sector map
//
//RtlMoveMemory(&(hdr->BadMap),
// Context->CurrentTape.BadMapPtr,
// sizeof(BAD_MAP));
scrbuf = q117GetFreeBuffer(&bufferInfo,Context);
//
// put saved logical part of header into transfer buffer
//
RtlMoveMemory(scrbuf, hdr, sizeof(TAPE_HEADER));
//
// write out the TapeHeader structure
//
if ( ret = q117FillTapeBlocks(
CMD_WRITE_DELETED_MARK,
(SEGMENT)0,
hdr->DupHeaderSegment,
scrbuf,
hdr->HeaderSegment,
hdr->DupHeaderSegment,
bufferInfo,
Context) ) {
return ERROR_ENCODE(ERR_WRITE_FAILURE, FCT_ID, 1);
}
//
// tape directory potentialy corrupted by FillTapeBlocks(), so just
// re-read it
//
Context->tapedir = (PIO_REQUEST)NULL;
CheckedDump(QIC117INFO,( "Q117i: Ending DoUpdateBad (Success)\n"));
return(ERR_NO_ERR);
}
#ifndef NO_MARKS
dStatus
q117DoUpdateMarks(
IN OUT PQ117_CONTEXT Context
)
/*++
Routine Description:
Arguments:
Context -
Return Value:
--*/
{
dStatus ret;
PSEGMENT_BUFFER bufferInfo;
PVOID scrbuf;
PIO_REQUEST ioreq;
ULONG buf_size; // size in bytes of the buffer where mark array will go
ULONG mark_size; // size in bytes of the mark list (with overhead)
scrbuf = q117GetFreeBuffer(&bufferInfo,Context);
mark_size = (Context->MarkArray.TotalMarks+1)*sizeof(struct _MARKLIST);
buf_size = q117GoodDataBytes(
(SEGMENT)Context->ActiveVolume.DirectorySize, Context );
//
// Fill in the mark list
//
RtlZeroMemory(scrbuf, buf_size);
//
// Put in the mark count
//
*(ULONG *)scrbuf = Context->MarkArray.TotalMarks;
//
// Check to see if there is enough room for the whole mark table
//
if ( buf_size < mark_size + sizeof(ULONG) ) {
ret = ERROR_ENCODE(ERR_WRITE_FAILURE, FCT_ID, 2);
} else {
//
// Now write all active entries (includes the terminator) after the mark
// count
//
RtlMoveMemory((UBYTE *)scrbuf+sizeof(ULONG), Context->MarkArray.MarkEntry,
mark_size);
//
// Now, write out the map list
//
ret=q117IssIOReq(scrbuf,CMD_WRITE,
Context->ActiveVolume.DirectorySize * BLOCKS_PER_SEGMENT,bufferInfo,Context);
if (!ret) {
//
// Wait for data to be written
//
ioreq=q117Dequeue(WaitForItem,Context);
ret = ioreq->x.adi_hdr.status;
}
}
return(ret);
}
dBoolean
q117ValidMarkArray(
IN OUT PQ117_CONTEXT Context,
IN void *buffer
)
/*++
Routine Description:
Validates that the mark array is OK. The mark array should only
have correct mark types, and assending byte offsets on even 512
byte boundaries
Arguments:
Context -
Return Value:
--*/
{
dStatus ret;
ULONG total;
struct _MARKLIST *array;
dBoolean valid = TRUE;
dBoolean firsttime = TRUE;
ULONG last;
total = *(ULONG *)buffer;
array = (void *)((ULONG *)buffer+1);
//
// Calculate the maximum number of marks (based on (the number of
// actual bytes in the segment - count dword) / size of a mark entry)
//
Context->MarkArray.MaxMarks = (q117GoodDataBytes(
(SEGMENT)Context->ActiveVolume.DirectorySize, Context ) - sizeof(ULONG))
/ sizeof(struct _MARKLIST);
//
// Make sure the count is smaller than the buffer
//
if (total <= (ULONG)Context->MarkArray.MaxMarks) {
while (total-- && valid) {
//
// Make sure the list is ascending (except for first entry)
//
if (firsttime) {
firsttime = FALSE;
} else {
if (last > array->Offset)
valid = FALSE;
}
last = array->Offset;
//
// Make sure the Offset is an even block offset
//
//if (last % BLOCK_SIZE)
// valid = FALSE;
//
// Make sure the type is correct
//
if (array->Type != TAPE_SETMARKS &&
array->Type != TAPE_FILEMARKS)
valid = FALSE;
++array;
}
//
// Make sure the terminator is present
//
if (array->Offset != 0xffffffff)
valid = FALSE;
} else
valid = FALSE;
if (!valid) {
CheckedDump(QIC117INFO,( "QIC117: Invalid mark array. Ignoring\n"));
//
// If the mark array is invalid, make a null mark array
// and let the tape be corrupt
//
*(ULONG *)buffer = 0;
array = (void *)((ULONG *)buffer+1);
array->Offset = 0xffffffff;
}
return valid;
}
dStatus
q117GetMarks(
IN OUT PQ117_CONTEXT Context
)
/*++
Routine Description:
Arguments:
Context -
Return Value:
--*/
{
dStatus ret;
PSEGMENT_BUFFER bufferInfo;
PVOID scrbuf;
PIO_REQUEST ioreq;
NTSTATUS ntStatus;
scrbuf = q117GetFreeBuffer(&bufferInfo,Context);
//
// Read this data block into memory
//
ret=q117IssIOReq(scrbuf,CMD_READ,
Context->ActiveVolume.DirectorySize * BLOCKS_PER_SEGMENT,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);
}
if (!ret) {
//
// Get the mark count
//
Context->MarkArray.TotalMarks = *(ULONG *)scrbuf;
if (!q117ValidMarkArray(Context, scrbuf)) {
// ret = ERROR_ENCODE(ERR_INVALID_VOLUME, FCT_ID, 1);
//
// Just ignore the mark array. The backup software should
// see a bogus tape and error out on it's own.
//
Context->MarkArray.TotalMarks = 0;
}
// if there is not enough room to add the mark, make the array bigger
if (Context->MarkArray.TotalMarks+1 > Context->MarkArray.MarksAllocated) {
// Allocate room for the extra
ntStatus = q117MakeMarkArrayBigger(Context, (Context->MarkArray.TotalMarks+1)-Context->MarkArray.MarksAllocated);
// Must have run out of memory, so abort
if (!NT_SUCCESS( ntStatus))
ret = ERROR_ENCODE(ERR_NO_MEMORY, FCT_ID, 1);
}
if (!ret) {
//
// Now read all active entries (includes the terminator)
//
RtlMoveMemory(Context->MarkArray.MarkEntry,(UBYTE *)scrbuf+sizeof(ULONG),
(Context->MarkArray.TotalMarks+1)*sizeof(struct _MARKLIST));
}
}
}
return(ret);
}
#endif
dStatus
q117FillTapeBlocks(
IN OUT DRIVER_COMMAND Command,
IN SEGMENT CurrentSegment,
IN SEGMENT EndSegment,
IN OUT PVOID Buffer,
IN SEGMENT FirstGood,
IN SEGMENT SecondGood,
IN PSEGMENT_BUFFER BufferInfo,
IN PQ117_CONTEXT Context
)
/*++
Routine Description:
Arguments:
Command -
CurrentSegment -
EndSegment -
Buffer -
FirstGood -
SecondGood -
BufferInfo -
Context -
Return Value:
--*/
{
dStatus ret;
DRIVER_COMMAND iocmd;
PIO_REQUEST ioreq;
ULONG cur_seg = 0; // The current segment being processed
ULONG allbits;
//
// set queue into single buffer mode
//
q117QueueSingle(Context);
//
// get pointer to free buffer
//
if (Buffer == NULL) {
Buffer = q117GetFreeBuffer(&BufferInfo,Context);
}
do {
while(!q117QueueFull(Context) && CurrentSegment <= EndSegment) {
if (Command == CMD_WRITE_DELETED_MARK && (CurrentSegment == FirstGood || CurrentSegment == SecondGood)) {
iocmd = CMD_WRITE;
} else {
iocmd = Command;
}
//
// We need to skip segments with no data area (less than 4
// good segments)
//
while (q117GoodDataBytes(CurrentSegment,Context) <= 0) {
++CurrentSegment;
}
if (ret=q117IssIOReq(Buffer,iocmd,(LONG)CurrentSegment * BLOCKS_PER_SEGMENT,BufferInfo,Context)) {
return(ret);
}
++CurrentSegment;
}
ioreq = q117Dequeue(WaitForItem,Context);
if (ioreq->x.adi_hdr.status != ERR_NO_ERR &&
!(
Command == CMD_READ_VERIFY &&
ERROR_DECODE(ioreq->x.adi_hdr.status) == ERR_BAD_BLOCK_DETECTED
)) {
//
// Any Driver error except BadBlk.
//
return(ioreq->x.adi_hdr.status);
}
if (Command == CMD_READ_VERIFY) {
allbits = ioreq->x.ioDeviceIO.bsm|ioreq->x.ioDeviceIO.retrys|ioreq->x.ioDeviceIO.crc;
//
// Add bits to the bad sector list
//
ret = q117UpdateBadMap(
Context,
(USHORT)(ioreq->x.ioDeviceIO.starting_sector/BLOCKS_PER_SEGMENT),
allbits);
}
//
// Till nothing left in the queue.
//
} while (!q117QueueEmpty(Context) || CurrentSegment <= EndSegment);
q117QueueNormal(Context);
return(ERR_NO_ERR);
}