windows-nt/Source/XPSP1/NT/drivers/storage/tape/class/physlogi.c
2020-09-26 16:20:57 +08:00

288 lines
8.2 KiB
C

/*++
Copyright (C) Microsoft Corporation, 1992 - 1998
Module Name:
physlogi.c
Abstract:
This module contains functions used specifically by tape drivers.
It contains functions that do physical to pseudo-logical and pseudo-
logical to physical tape block address/position translation.
Environment:
kernel mode only
Revision History:
--*/
#include "ntddk.h"
#include "physlogi.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, TapeClassPhysicalBlockToLogicalBlock)
#pragma alloc_text(PAGE, TapeClassLogicalBlockToPhysicalBlock)
#endif
//
// defines for various QIC physical tape format constants
//
#define QIC_150_BOT_OFFSET 2
#define QIC_525_PSEUDO_PHYSICAL_BLOCK_SIZE 512
#define QIC_525_PHYSICAL_BLOCK_SIZE 1024
#define QIC_525_DATA_BLKS_PER_FRAME 14
#define QIC_525_ECC_BLKS_PER_FRAME 2
#define QIC_525_BLKS_PER_FRAME 16
#define QIC_525_BOT_OFFSET 16
#define QIC_1350_PHYSICAL_BLOCK_SIZE 512
#define QIC_1350_DATA_BLKS_PER_FRAME 52
#define QIC_1350_ECC_BLKS_PER_FRAME 12
#define QIC_1350_BLKS_PER_FRAME 64
#define QIC_1350_BOT_OFFSET 64
ULONG
TapeClassPhysicalBlockToLogicalBlock(
IN UCHAR DensityCode,
IN ULONG PhysicalBlockAddress,
IN ULONG BlockLength,
IN BOOLEAN FromBOT
)
/*++
Routine Description:
This routine will translate from a QIC physical tape format
specific physical/absolute block address to a pseudo-logical
block address.
Arguments:
DensityCode // tape media density code
PhysicalBlockAddress // tape format specific tape block address
BlockLength // mode select/sense block length setting
FromBOT // true/false - translate from BOT
Return Value:
ULONG
--*/
{
ULONG logicalBlockAddress;
ULONG frames;
PAGED_CODE();
logicalBlockAddress = PhysicalBlockAddress;
switch ( DensityCode ) {
case 0:
logicalBlockAddress = 0xFFFFFFFF;
break;
case QIC_24:
logicalBlockAddress--;
break;
case QIC_120:
logicalBlockAddress--;
break;
case QIC_150:
if (FromBOT) {
if (logicalBlockAddress > QIC_150_BOT_OFFSET) {
logicalBlockAddress -= QIC_150_BOT_OFFSET;
} else {
logicalBlockAddress = 0;
}
} else {
logicalBlockAddress--;
}
break;
case QIC_525:
case QIC_1000:
case QIC_2GB:
if (FromBOT && (logicalBlockAddress >= QIC_525_BOT_OFFSET)) {
logicalBlockAddress -= QIC_525_BOT_OFFSET;
}
if (logicalBlockAddress != 0) {
frames = logicalBlockAddress/QIC_525_BLKS_PER_FRAME;
logicalBlockAddress -= QIC_525_ECC_BLKS_PER_FRAME*frames;
switch (BlockLength) {
case QIC_525_PHYSICAL_BLOCK_SIZE:
break;
case QIC_525_PSEUDO_PHYSICAL_BLOCK_SIZE:
logicalBlockAddress *= 2;
break;
default:
if (BlockLength > QIC_525_PHYSICAL_BLOCK_SIZE) {
if ((BlockLength%QIC_525_PHYSICAL_BLOCK_SIZE) == 0) {
logicalBlockAddress /=
BlockLength/QIC_525_PHYSICAL_BLOCK_SIZE;
} else {
logicalBlockAddress /=
1+(BlockLength/QIC_525_PHYSICAL_BLOCK_SIZE);
}
}
break;
}
}
break;
case QIC_1350:
case QIC_2100:
if (FromBOT && (logicalBlockAddress >= QIC_1350_BOT_OFFSET)) {
logicalBlockAddress -= QIC_1350_BOT_OFFSET;
}
if (logicalBlockAddress != 0) {
frames = logicalBlockAddress/QIC_1350_BLKS_PER_FRAME;
logicalBlockAddress -= QIC_1350_ECC_BLKS_PER_FRAME*frames;
if (BlockLength > QIC_1350_PHYSICAL_BLOCK_SIZE) {
if ((BlockLength%QIC_1350_PHYSICAL_BLOCK_SIZE) == 0) {
logicalBlockAddress /=
BlockLength/QIC_1350_PHYSICAL_BLOCK_SIZE;
} else {
logicalBlockAddress /=
1+(BlockLength/QIC_1350_PHYSICAL_BLOCK_SIZE);
}
}
}
break;
}
return logicalBlockAddress;
} // end TapeClassPhysicalBlockToLogicalBlock()
TAPE_PHYS_POSITION
TapeClassLogicalBlockToPhysicalBlock(
IN UCHAR DensityCode,
IN ULONG LogicalBlockAddress,
IN ULONG BlockLength,
IN BOOLEAN FromBOT
)
/*++
Routine Description:
This routine will translate from a pseudo-logical block address
to a QIC physical tape format specific physical/absolute block
address and (space) block delta.
Arguments:
DensityCode // tape media density code
LogicalBlockAddress // pseudo-logical tape block address
BlockLength // mode select/sense block length setting
FromBOT // true/false - translate from BOT
Return Value:
TAPE_PHYS_POSITION info/structure
--*/
{
TAPE_PHYS_POSITION physPosition;
ULONG physicalBlockAddress;
ULONG remainder = 0;
ULONG frames;
PAGED_CODE();
physicalBlockAddress = LogicalBlockAddress;
switch ( DensityCode ) {
case 0:
physicalBlockAddress = 0xFFFFFFFF;
break;
case QIC_24:
physicalBlockAddress++;
break;
case QIC_120:
physicalBlockAddress++;
break;
case QIC_150:
if (FromBOT) {
physicalBlockAddress += QIC_150_BOT_OFFSET;
} else {
physicalBlockAddress++;
}
break;
case QIC_525:
case QIC_1000:
case QIC_2GB:
if (physicalBlockAddress != 0) {
switch (BlockLength) {
case QIC_525_PHYSICAL_BLOCK_SIZE:
break;
case QIC_525_PSEUDO_PHYSICAL_BLOCK_SIZE:
remainder = physicalBlockAddress & 0x00000001;
physicalBlockAddress >>= 1;
break;
default:
if (BlockLength > QIC_525_PHYSICAL_BLOCK_SIZE) {
if ((BlockLength%QIC_525_PHYSICAL_BLOCK_SIZE) == 0) {
physicalBlockAddress *=
BlockLength/QIC_525_PHYSICAL_BLOCK_SIZE;
} else {
physicalBlockAddress *=
1+(BlockLength/QIC_525_PHYSICAL_BLOCK_SIZE);
}
}
break;
}
frames = physicalBlockAddress/QIC_525_DATA_BLKS_PER_FRAME;
physicalBlockAddress += QIC_525_ECC_BLKS_PER_FRAME*frames;
}
if (FromBOT) {
physicalBlockAddress += QIC_525_BOT_OFFSET;
}
break;
case QIC_1350:
case QIC_2100:
if (physicalBlockAddress != 0) {
if (BlockLength > QIC_1350_PHYSICAL_BLOCK_SIZE) {
if ((BlockLength%QIC_1350_PHYSICAL_BLOCK_SIZE) == 0) {
physicalBlockAddress *=
BlockLength/QIC_1350_PHYSICAL_BLOCK_SIZE;
} else {
physicalBlockAddress *=
1+(BlockLength/QIC_1350_PHYSICAL_BLOCK_SIZE);
}
}
frames = physicalBlockAddress/QIC_1350_DATA_BLKS_PER_FRAME;
physicalBlockAddress += QIC_1350_ECC_BLKS_PER_FRAME*frames;
}
if (FromBOT) {
physicalBlockAddress += QIC_1350_BOT_OFFSET;
}
break;
}
physPosition.SeekBlockAddress = physicalBlockAddress;
physPosition.SpaceBlockCount = remainder;
return physPosition;
} // end TapeClassLogicalBlockToPhysicalBlock()