|
|
#include "arccodes.h"
#include "bootx86.h"
#include "flop.h"
#ifdef FLOPPY_CACHE
//#define FLOPPY_CACHE_DEBUG
#ifdef FLOPPY_CACHE_DEBUG
#define DBGOUT(x) BlPrint x
#else
#define DBGOUT(x)
#endif
#define MAX_FLOPPY_LEN 1474560
UCHAR CachedDiskImage[MAX_FLOPPY_LEN]; UCHAR CachedDiskBadSectorMap[(MAX_FLOPPY_LEN/512)]; UCHAR CachedDiskCylinderMap[80]; USHORT CachedDiskBytesPerSector; USHORT CachedDiskSectorsPerTrack; USHORT CachedDiskSectorsPerCylinder; USHORT CachedDiskBytesPerTrack; ULONG CachedDiskLastSector;
BOOLEAN DiskInCache = FALSE;
VOID FcpCacheOneCylinder( IN USHORT Cylinder ) { PUCHAR pCache; unsigned track,sector; ULONG AbsoluteSector; ARC_STATUS Status; unsigned retry;
//
// Calculate the location in the cache image where this cylinder should go.
//
AbsoluteSector = Cylinder * CachedDiskSectorsPerCylinder; pCache = CachedDiskImage + (AbsoluteSector * CachedDiskBytesPerSector);
//
// Read track 0 and 1 of this cylinder.
//
for(track=0; track<2; track++) {
DBGOUT(("FcCacheFloppyDisk: Cylinder %u head %u: ",Cylinder,track));
retry = 0;
do {
Status = GET_SECTOR( 2, // int13 request = read
0, // disk number (a:)
(USHORT)track, // head (0 or 1)
Cylinder, // track (usually 0-79)
1, // sector number (1-based)
CachedDiskSectorsPerTrack, // number of sectors to read
LocalBuffer // buffer
);
if(Status) { retry++; RESET_DISK(0,0,0,0,0,0,0); }
} while(Status && (retry <= 3));
if(Status) {
DBGOUT(("Error!\n"));
//
// One or more sectors in the track were bad -- read individually.
//
for(sector=1; sector<=CachedDiskSectorsPerTrack; sector++) { DBGOUT((" Sector %u: ",sector));
retry = 0;
do {
Status = GET_SECTOR( 2, // int13 request = read
0, // disk number (a:)
(USHORT)track, // head (0 or 1)
Cylinder, // cylinder (usually 0-79)
(USHORT)sector, // sector number (1-based)
1, // number of sectors to read
LocalBuffer // buffer
);
if(Status) { retry++; RESET_DISK(0,0,0,0,0,0,0); }
} while(Status && (retry <= 2));
if(Status) {
//
// Sector is bad.
//
CachedDiskBadSectorMap[AbsoluteSector] = TRUE;
DBGOUT(("bad\n"));
} else {
//
// Sector is good. Transfer the data into the cache buffer.
//
RtlMoveMemory(pCache,LocalBuffer,CachedDiskBytesPerSector);
DBGOUT(("OK\n")); }
//
// Advance to the next sector in the cache buffer.
//
pCache += CachedDiskBytesPerSector; AbsoluteSector++; }
} else { //
// Transfer the whole track we just successfully read
// into the cached disk buffer.
//
RtlMoveMemory(pCache,LocalBuffer,CachedDiskBytesPerTrack); pCache += CachedDiskBytesPerTrack; AbsoluteSector += CachedDiskSectorsPerTrack;
DBGOUT(("OK\n")); } }
CachedDiskCylinderMap[Cylinder] = TRUE; }
BOOLEAN FcIsThisFloppyCached( IN PUCHAR Buffer ) { if(!DiskInCache) { return(FALSE); }
//
// Compare the first 512 bytes of the cached disk
// to the buffer passed in. If they are equal,
// then the disk is already cached.
//
if(RtlCompareMemory(CachedDiskImage,Buffer,512) == 512) { return(TRUE); }
//
// Disk is not cached.
//
return(FALSE); }
VOID FcUncacheFloppyDisk( VOID ) { DiskInCache = FALSE; }
VOID FcCacheFloppyDisk( PBIOS_PARAMETER_BLOCK Bpb ) { //
// Indicate that the cache is invalid.
//
DiskInCache = FALSE;
//
// Sanity check the bpb.
// Ensure it's a standard 1.2 meg or 1.44 meg disk.
//
if((Bpb->Heads != 2) || (Bpb->BytesPerSector != 512) || ((Bpb->SectorsPerTrack != 15) && (Bpb->SectorsPerTrack != 18)) || ((Bpb->Sectors != 2880) && (Bpb->Sectors != 2400))) { DBGOUT(("FcCacheFloppyDisk: floppy not standard 1.2 or 1.44 meg disk\n")); return; }
//
// Grab a buffer under the 1 meg line.
// The buffer must be big enough to hold one whole track of
// a 1.44 meg floppy.
//
if(LocalBuffer == NULL) { LocalBuffer = FwAllocateHeap(18 * 512); if(LocalBuffer == NULL) { DBGOUT(("FcCacheFloppyDisk: Couldn't allocate local buffer\n")); return; } }
DBGOUT(("FcCacheFloppyDisk: LocalBuffer @ %lx\n",LocalBuffer));
//
// The disk is one we can cache. Indicate that a disk is cached
// and mark all sectors good and all tracks not present.
//
DiskInCache = TRUE; RtlZeroMemory(CachedDiskBadSectorMap,sizeof(CachedDiskBadSectorMap)); RtlZeroMemory(CachedDiskCylinderMap,sizeof(CachedDiskCylinderMap)); CachedDiskSectorsPerTrack = Bpb->SectorsPerTrack; CachedDiskSectorsPerCylinder = Bpb->Heads * Bpb->SectorsPerTrack; CachedDiskBytesPerSector = Bpb->BytesPerSector;
//
// Calculate the number of bytes in a Track on the floppy.
//
CachedDiskBytesPerTrack = CachedDiskSectorsPerTrack * Bpb->BytesPerSector;
//
// Calculate the number of tracks.
//
CachedDiskLastSector = Bpb->Sectors-1;
DBGOUT(("FcCacheFloppyDisk: Caching disk, %u sectors per track\n",CachedDiskSectorsPerTrack));
FcpCacheOneCylinder(0); }
ARC_STATUS FcReadFromCache( IN ULONG Offset, IN ULONG Length, OUT PUCHAR Buffer ) { ULONG FirstSector,LastSector,Sector; ULONG FirstCyl,LastCyl,cyl;
if(!Length) { return(ESUCCESS); }
if(!DiskInCache) { return(EINVAL); }
//
// Determine the first sector in the transfer.
//
FirstSector = Offset / 512;
//
// Determine and validate the last sector in the transfer.
//
LastSector = FirstSector + ((Length-1)/512);
if(LastSector > CachedDiskLastSector) { return(E2BIG); }
//
// Determine the first and last cylinders involved in the transfer.
//
FirstCyl = FirstSector / CachedDiskSectorsPerCylinder; LastCyl = LastSector / CachedDiskSectorsPerCylinder;
//
// Make sure all these cylinders are cached.
//
for(cyl=FirstCyl; cyl<=LastCyl; cyl++) { if(!CachedDiskCylinderMap[cyl]) { FcpCacheOneCylinder((USHORT)cyl); } }
//
// Determine if any of the sectors in the transfer range
// are marked bad in the sector map.
//
// If so, return an i/o error.
//
for(Sector=FirstSector; Sector<=LastSector; Sector++) { if(CachedDiskBadSectorMap[Sector]) { return(EIO); } }
//
// Transfer the data into the caller's buffer.
//
RtlMoveMemory(Buffer,CachedDiskImage+Offset,Length);
return(ESUCCESS); }
#endif // def FLOPPY_CACHE
|