📄 iopprocessor.cpp
字号:
//////////////////////////////////////////////////////////////////////////////
// IopProcessor.cpp
//
// Implementation of class IopProcessor.
//////////////////////////////////////////////////////////////////////////////
// $Id: IopProcessor.cpp,v 1.7 1999/02/13 04:24:35 nryan Exp $
// Copyright (C) 1998 by Network Associates, Inc.
// All rights reserved.
#include <vtoolscp.h>
#include "Required.h"
#include "CPGPdiskDrv.h"
#include "Globals.h"
#include "IopProcessor.h"
#include "PGPdisk.h"
/////////////////////////////////////////////
// Class IopProcessor public member functions
/////////////////////////////////////////////
// The IopProcessor constructor.
IopProcessor::IopProcessor()
{
mUseAsyncIO = kDefaultUseAsyncIO;
for (PGPUInt32 i=0; i<kMaxDrives; i++)
{
mIopReqs[i].isBusy = FALSE;
}
}
// IsDriveBusy returns TRUE if the PGPdisk represented by the given drive
// number is busy processing I/O.
PGPBoolean
IopProcessor::IsDriveBusy(PGPUInt8 drive)
{
pgpAssert(IsLegalDriveNumber(drive));
return mIopReqs[drive].isBusy;
}
// SetDriveBusy marks the given drive as busy or not busy.
void
IopProcessor::SetDriveBusy(PGPUInt8 drive, PGPBoolean isBusy)
{
pgpAssert(IsLegalDriveNumber(drive));
mIopReqs[drive].isBusy = isBusy;
}
// IsIOAsync returns TRUE if I/O is currently being processed asynchronously,
// FALSE otherwise.
PGPBoolean
IopProcessor::IsIOAsync()
{
return mUseAsyncIO;
}
// SetIOAsync specifies that I/O be processed either async or sync.
void
IopProcessor::SetIOAsync(PGPBoolean isIOAsync)
{
mUseAsyncIO = isIOAsync;
}
// ProcessIop schedules later processing, at a safe time, of the given IOP
// request. Validate the IOP and fail silently if validation fails.
void
IopProcessor::ProcessIop(PIOP pIop)
{
PDCB pDcb;
PGPBoolean failThisRequest = FALSE;
PGPUInt8 drive;
PGPUInt16 failStatus;
PIOR pIor;
pgpAssertAddrValid(pIop, IOP);
pIor = &pIop->IOP_ior;
pgpAssertAddrValid(pIor, IOR);
DebugOut("PGPdisk: Saw an %s\n",
Driver->GetIORFunctionName(pIor->IOR_func));
// Store a pointer to this object in the IOP itself.
pIor->IOR_private_port = (PGPUInt32) this;
switch (pIor->IOR_func)
{
case IOR_GEN_IOCTL:
// NEVER SCHEDULE IOCTL REQUESTS. ALWAYS PROCESS IN SAME CONTEXT IN
// WHICH THEY ARE RECEIVED.
IorGenIoctlDispatcher(pIop);
break;
case IOR_READ:
case IOR_WRITE:
// Queue the request.
pDcb = (PDCB) pIop->IOP_physical_dcb;
pgpAssertAddrValid(pDcb, DCB);
// Validate the drive letter.
drive = pDcb->DCB_cmn.DCB_drive_lttr_equiv;
if (!IsLegalDriveNumber(drive) ||
IsNull(Driver->mPGPdisks.FindPGPdisk(drive)))
{
failThisRequest = TRUE;
failStatus = IORS_NO_DEVICE;
}
if (!failThisRequest)
{
IlbEnqueueIop(pIop, pDcb);
// We must determine whether or not to schedule dispatching.
// If I/O is in process, we don't schedule another callback -
// this will be done later on when that I/O is finished.
// Otherwise we schedule a callback right now.
if (!IsDriveBusy(drive))
{
SetDriveBusy(drive, TRUE);
ScheduleIorReadWriteDispatch(drive);
}
}
break;
default:
failThisRequest = TRUE;
failStatus = IORS_INVALID_COMMAND;
break;
}
if (failThisRequest)
{
pIor->IOR_status = failStatus;
--pIop->IOP_callback_ptr;
pIop->IOP_callback_ptr->IOP_CB_address(pIop);
}
}
//////////////////////////////////////////////
// Class IopProcessor private member functions
//////////////////////////////////////////////
// ScheduleIorReadWriteDispatch asks the system to schedule our IOR_READ and
// IOR_WRITE dispatching function for execution at a safer time.
void
IopProcessor::ScheduleIorReadWriteDispatch(PGPUInt8 drive)
{
static RestrictedEvent_THUNK iopThunk;
pgpAssert(IsLegalDriveNumber(drive));
Call_Restricted_Event(0, NULL, PEF_ALWAYS_SCHED, (PVOID) drive,
IorReadWriteDispatcher, 0, &iopThunk);
}
// IorGenIoctlDispatcher is called in order to dispatch IOR_GEN_IOCTL
// requests.
void
IopProcessor::IorGenIoctlDispatcher(PIOP pIop)
{
PIOR pIor;
pgpAssertAddrValid(pIop, IOP);
pIor = &pIop->IOP_ior;
pgpAssertAddrValid(pIor, IOR);
DebugOut("PGPdisk: %s initiated\n",
Driver->GetIORFunctionName(pIor->IOR_func));
// Switch on the IOR function.
switch (pIor->IOR_func)
{
case IOR_GEN_IOCTL: // an ioctl request
Driver->mIopProcessor.ProcessIorGenIoctl(pIop);
break;
default: // otherwise fail
pgpAssert(FALSE);
break;
}
}
// IorReadWriteDispatcher is the event callback that is scheduled by the
// I/O request routine in order to dispatch IOR_READ and IOR_WRITE requests.
VOID
__stdcall
IopProcessor::IorReadWriteDispatcher(
VMHANDLE hVM,
THREADHANDLE hThread,
PVOID Refdata,
PCLIENT_STRUCT pRegs)
{
PDCB pDcb;
PGPBoolean foundIop = FALSE;
PGPdisk *pPGD;
PGPUInt8 drive;
PIOP pIop;
drive = (PGPUInt8) Refdata;
pgpAssert(IsLegalDriveNumber(drive));
pPGD = Driver->mPGPdisks.FindPGPdisk(drive);
pgpAssertAddrValid(pPGD, PGPdisk);
pDcb = pPGD->GetDcb();
pgpAssertAddrValid(pDcb, DCB);
// Any outstanding I/O for this PGPdisk?
if (pIop = IlbDequeueIop(pDcb))
{
PIOR pIor;
pgpAssertAddrValid(pIop, IOP);
pIor = &pIop->IOP_ior;
pgpAssertAddrValid(pIor, IOR);
DebugOut("PGPdisk: %s initiated\n",
Driver->GetIORFunctionName(pIor->IOR_func));
// Switch on the IOR function.
switch (pIor->IOR_func)
{
case IOR_READ: // a read request
case IOR_WRITE: // a write request
Driver->mIopProcessor.ProcessIorReadWrite(pIop,
Driver->mIopProcessor.mUseAsyncIO);
break;
default: // otherwise fail
pgpAssert(FALSE);
break;
}
}
else
{
// Allow I/O to the PGPdisk.
Driver->mIopProcessor.SetDriveBusy(drive, FALSE);
}
}
// ProcessIorGenIoctl processes an IOR_GEN_IOCTL request synchronously. We
// need to process these so formatting will work on PGPdisks.
void
IopProcessor::ProcessIorGenIoctl(PIOP pIop)
{
DualErr derr;
PGPUInt8 drive;
PGPUInt16 iorsResult;
PGPUInt32 ioctlResult;
PIOR pIor;
PGPdisk *pPGD;
pgpAssertAddrValid(pIop, IOP);
pIor = &pIop->IOP_ior;
pgpAssertAddrValid(pIor, IOR);
drive = pIor->IOR_ioctl_drive - 1;
// Check for invalid drive.
if ((drive == 0) || !IsLegalDriveNumber(drive) ||
IsNull(Driver->mPGPdisks.FindPGPdisk(drive)))
{
ioctlResult = ERROR_INVALID_DRIVE;
iorsResult = IORS_INVALID_COMMAND;
}
else
{
pPGD = Driver->mPGPdisks.FindPGPdisk(drive);
pgpAssertAddrValid(pPGD, PGPdisk);
DebugOut("PGPdisk: Ioctl - drive=%c function=%x minor %x\n",
DriveNumToLet(drive), pIor->IOR_ioctl_function,
pIor->IOR_ioctl_control_param & 0xff);
// Now process the IOCTL request. We only process some 440D functions
// and the 4411 function.
switch (pIor->IOR_ioctl_function)
{
case 0x440D:
switch (GetLowByte((PGPUInt16) pIor->IOR_ioctl_control_param))
{
case 0x40: // Set Device Parameters
{
// We don't actually have to 'do' anything here. The system
// will set these parameters when it writes the boot block,
// which is where we get them from anyways.
ioctlResult = ERROR_SUCCESS;
iorsResult = IORS_SUCCESS;
break;
}
case 0x41: // Write Track on Logical Drive
{
PGPUInt8 *buf;
PGPUInt16 offset, segment;
PGPUInt32 nBlocks;
PGPUInt64 pos;
RwBlock *pRWB;
pRWB = (RwBlock *) pIor->IOR_ioctl_buffer_ptr;
// Calculate the starting sector.
pos = pRWB->rwCylinder * kSizeCyl;
pos += pRWB->rwHead * kSizeHead;
pos += pRWB->rwFirstSector;
// Calculate the number of blocks to read.
nBlocks = pRWB->rwSectors;
// Calculate the buffer address.
segment = GetHighWord(pRWB->rwBuffer);
offset = GetLowWord(pRWB->rwBuffer);
buf = (PGPUInt8 *) Get_Cur_VM_Handle()->CB_High_Linear +
(segment << 4) + offset;
// Perform the write.
derr = pPGD->Read(buf, pos*kDefaultBlockSize,
nBlocks*kDefaultBlockSize);
ioctlResult = (derr.IsntError() ? ERROR_SUCCESS :
ERROR_INVALID_FUNCTION);
iorsResult = IORS_SUCCESS;
break;
}
case 0x42: // Format Track on Logical Drive
{
FvBlock *pFVB;
// Don't actually do anything, since PGPdisks aren't physical
// drives that need any special treatment of sectors before
// being written to.
pFVB = (FvBlock *) pIor->IOR_ioctl_buffer_ptr;
if (pFVB->fvSpecFunc == 1)
{
pFVB->fvSpecFunc = 0;
}
ioctlResult = ERROR_SUCCESS;
iorsResult = IORS_SUCCESS;
break;
}
case 0x60: // Get Device Parameters
{
switch (
GetHighByte((PGPUInt16) pIor->IOR_ioctl_control_param))
{
case 0x08:
derr = pPGD->GetDevParams16(
(DevParams16 *) pIor->IOR_ioctl_buffer_ptr);
break;
case 0x48:
derr = pPGD->GetDevParams32(
(DevParams32 *) pIor->IOR_ioctl_buffer_ptr);
break;
}
ioctlResult = (derr.IsntError() ? ERROR_SUCCESS :
ERROR_INVALID_FUNCTION);
iorsResult = IORS_SUCCESS;
break;
}
case 0x61: // Read Track on Logical Drive
{
PGPUInt8 *buf;
PGPUInt16 offset, segment;
PGPUInt32 nBlocks;
PGPUInt64 pos;
RwBlock *pRWB;
pRWB = (RwBlock *) pIor->IOR_ioctl_buffer_ptr;
// Calculate the starting sector.
pos = pRWB->rwCylinder * kSizeCyl;
pos += pRWB->rwHead * kSizeHead;
pos += pRWB->rwFirstSector;
// Calculate the number of blocks to read.
nBlocks = pRWB->rwSectors;
// Calculate the buffer address.
segment = GetHighWord(pRWB->rwBuffer);
offset = GetLowWord(pRWB->rwBuffer);
buf = (PGPUInt8 *) Get_Cur_VM_Handle()->CB_High_Linear +
(segment << 4) + offset;
// Perform the read.
derr = pPGD->Read(buf, pos*kDefaultBlockSize,
nBlocks*kDefaultBlockSize);
ioctlResult = (derr.IsntError() ? ERROR_SUCCESS :
ERROR_INVALID_FUNCTION);
iorsResult = IORS_SUCCESS;
break;
}
case 0x66: // Get Media ID
{
derr = pPGD->GetMediaId((MID *) pIor->IOR_ioctl_buffer_ptr);
ioctlResult = (derr.IsntError() ? ERROR_SUCCESS :
ERROR_INVALID_FUNCTION);
iorsResult = IORS_SUCCESS;
break;
}
default:
ioctlResult = ERROR_INVALID_FUNCTION;
iorsResult = IORS_INVALID_COMMAND;
break;
}
break;
case 0x4411: // Query if we handle specified 440D code
switch (GetLowByte((PGPUInt16) pIor->IOR_ioctl_control_param))
{
case 0x40:
case 0x41:
case 0x42:
case 0x60:
case 0x61:
case 0x66:
ioctlResult = ERROR_SUCCESS;
iorsResult = IORS_SUCCESS;
break;
default:
ioctlResult = ERROR_INVALID_FUNCTION;
iorsResult = IORS_SUCCESS;
break;
}
break;
default:
ioctlResult = ERROR_INVALID_FUNCTION;
iorsResult = IORS_INVALID_COMMAND;
break;
}
}
pIor->IOR_ioctl_return = ioctlResult;
ScheduleAsyncCallback(pIop, iorsResult);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -