/*++

Copyright (c) 1993 - Colorado Memory Systems, Inc.
All Rights Reserved

Module Name:

    ntalloc.c

Abstract:

    routines to provide storage allocation for cached information and
    queues.

Revision History:




--*/

#include <ntddk.h>
#include <ntddtape.h>
#include "common.h"
#include "q117.h"
#include "protos.h"

#define FCT_ID 0x0111

NTSTATUS
q117AllocatePermanentMemory(
    PQ117_CONTEXT   Context,
    PADAPTER_OBJECT AdapterObject,
    ULONG           NumberOfMapRegisters
    )

/*++

Routine Description:

    Allocates track buffers at init time.

Arguments:

    Context - Current context of the driver

Return Value:

    NT Status

--*/

{
    Context->AdapterInfo = ExAllocatePool(NonPagedPool,
				sizeof(*Context->AdapterInfo));

    if (Context->AdapterInfo == NULL) {
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    Context->AdapterInfo->AdapterObject = AdapterObject;
    Context->AdapterInfo->NumberOfMapRegisters = NumberOfMapRegisters;

    //
    // Initialize state information
    //
    Context->CurrentOperation.Type = NoOperation;
    Context->CurrentTape.State = NeedInfoLoaded;
    Context->DriverOpened = FALSE;
    Context->CurrentTape.TapeHeader = NULL;
    Context->IoRequest = NULL;
    Context->CurrentTape.MediaInfo = NULL;

    if (!Context->Parameters.DetectOnly) {

        if (q117AllocateBuffers(Context)) {
            return STATUS_INSUFFICIENT_RESOURCES;
        }

    }

    return STATUS_SUCCESS;
}

dStatus
q117GetTemporaryMemory (
    PQ117_CONTEXT Context
    )

/*++

Routine Description:

Allocates memory for the bad sector map, the IORequest array
at driver open time.

Arguments:

    Context - Current context of the driver

Return Value:

    NT Status

--*/

{
    NTSTATUS ntStatus;

    //
    // Allocate I/O Request array for packets sent to q117i
    //
    Context->IoRequest = ExAllocatePool(
	NonPagedPool,
	UNIX_MAXBFS * sizeof(IO_REQUEST));

    //
    // Allocate current header info
    //

    Context->CurrentTape.TapeHeader = ExAllocatePool(
					NonPagedPool,
					sizeof(TAPE_HEADER));

    //
    // Init the bad sector map pointer to the old QIC40 location
    // This will be changed to the proper location by format.c or
    // init.c when a tape is formatted, or read.
    //
    Context->CurrentTape.BadMapPtr = &(Context->CurrentTape.TapeHeader->BadMap);
    Context->CurrentTape.BadSectorMapSize = sizeof(BAD_MAP);
    Context->CurrentTape.CurBadListIndex = 0;

    //
    // Allocate tape info structure
    //
    Context->CurrentTape.MediaInfo = ExAllocatePool(
					NonPagedPool,
					sizeof(*Context->CurrentTape.MediaInfo));

	 // Zero media info buffer and init block size.  This should not be
	 // necessary,  but HCT tests rely on info here to be valid even in
	 // error case.
	 RtlZeroMemory(Context->CurrentTape.MediaInfo, sizeof(*Context->CurrentTape.MediaInfo));
	 Context->CurrentTape.MediaInfo->BlockSize = BLOCK_SIZE;

    // Create the minimum mark table
    Context->MarkArray.MarksAllocated = 0;
    Context->MarkArray.TotalMarks = 0;
    Context->MarkArray.MarkEntry = NULL;
    ntStatus = q117MakeMarkArrayBigger(Context, 0);

    if ( Context->CurrentTape.TapeHeader == NULL ||
	    Context->IoRequest == NULL ||
	    Context->CurrentTape.MediaInfo == NULL || !NT_SUCCESS(ntStatus)) {

	//
	// Free anything that was allocated
	//
	q117FreeTemporaryMemory(Context);
	return ERROR_ENCODE(ERR_NO_MEMORY, FCT_ID, 1);

    }

    return(ERR_NO_ERR);
}

VOID
q117FreeTemporaryMemory (
    PQ117_CONTEXT Context
    )

/*++

Routine Description:

Frees memory allocated for the bad sector map, the IORequest
array driver open time.  This
routine is called at driver close time or in the event of a
drive error.

Arguments:

    Context - Current context of the driver

Return Value:

    NT Status

--*/

{
    //
    // Free I/O request buffer array
    //
    if (Context->IoRequest) {
	ExFreePool(Context->IoRequest);
	Context->IoRequest = NULL;
    }

    //
    // Free tape header buffer
    //
    if (Context->CurrentTape.TapeHeader) {
	ExFreePool(Context->CurrentTape.TapeHeader);
	Context->CurrentTape.TapeHeader = NULL;
    }

    //
    // Free tape information buffer
    //
    if (Context->CurrentTape.MediaInfo) {
	ExFreePool(Context->CurrentTape.MediaInfo);
	Context->CurrentTape.MediaInfo = NULL;
    }

    //
    // Free the mark array
    //
    Context->MarkArray.MarksAllocated = 0;
    if (Context->MarkArray.MarkEntry) {
	ExFreePool(Context->MarkArray.MarkEntry);
	Context->MarkArray.MarkEntry = NULL;
    }

    //
    // Flag the need to re-load the tape information
    //
    Context->CurrentOperation.Type = NoOperation;
    Context->CurrentTape.State = NeedInfoLoaded;
}

dStatus
q117AllocateBuffers (
    PQ117_CONTEXT Context
    )
{
    ULONG i;
    ULONG totalBuffs;

    //
    // Allocate DMA buffers in physically contiguous memory.
    // NOTE: HalAllocateCommonBuffer is really for BUS MASTERS ONLY
    // but this is the only way we can guarantee that IoMapTransfer
    // doesn't copy our buffer somewhere else.  This would stop the
    // tape from streaming.
    //

    totalBuffs = 0;
    for (i = 0; i < UNIX_MAXBFS; i++) {

        if ((Context->SegmentBuffer[i].logical =
            HalAllocateCommonBuffer(Context->AdapterInfo->AdapterObject,
                        BLOCKS_PER_SEGMENT * BYTES_PER_SECTOR,
                        &Context->SegmentBuffer[i].physical,
                        FALSE)) == NULL) {
            break;
        }

        ++totalBuffs;

        CheckedDump(QIC117INFO,("q117:  buffer %x ",i,Context->SegmentBuffer[i].logical));

        CheckedDump(QIC117INFO,("Logical: %x%08x   Virtual: %x\n",
                Context->SegmentBuffer[i].physical, Context->SegmentBuffer[i].logical));

    }

    Context->SegmentBuffersAvailable = totalBuffs;

    //
    // We need at least two buffers to stream
    //
    if (totalBuffs < 2) {

        CheckedDump(QIC117DBGP,("Fatal error - Insufficient buffers available from HalAllocateCommonBuffer()\n"));

        q117FreeTemporaryMemory(Context);
        return ERROR_ENCODE(ERR_NO_MEMORY, FCT_ID, 2);

    }

    return ERR_NO_ERR;

}