/*++ 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()