📄 iopprocessor.cpp
字号:
// ProcessIorReadWrite processes an IOR_READ or an IOR_WRITE request
// asynchronously.
void
IopProcessor::ProcessIorReadWrite(PIOP pIop, PGPBoolean useAsync)
{
DualErr derr;
PDCB pDcb;
PGPBoolean doneWithRequest;
PGPdisk *pPGD;
PGPUInt8 drive, *buf;
PGPUInt16 blockSize, failSilentStatus;
PIOR pIor;
pgpAssertAddrValid(pIop, IOP);
pIor = &pIop->IOP_ior;
pgpAssertAddrValid(pIor, IOR);
pDcb = (PDCB) pIop->IOP_physical_dcb;
pgpAssertAddrValid(pDcb, DCB);
drive = pDcb->DCB_cmn.DCB_drive_lttr_equiv;
pgpAssert(IsLegalDriveNumber(drive));
pPGD = Driver->mPGPdisks.FindPGPdisk(drive);
pgpAssertAddrValid(pPGD, PGPdisk);
blockSize = ExtractBlockSize(pDcb);
pgpAssert(IsDriveBusy(drive));
// Reset the inactivity timer.
Driver->mSecondsInactive = 0;
// Verify that IO is enabled for this PGPdisk.
if (!pPGD->IsIOEnabled())
{
derr = kPGDMinorError_FailSilently;
failSilentStatus = IORS_NOT_READY;
}
// If this is a write, verify that the volume isn't write-protected.
if (derr.IsntError())
{
if (pIor->IOR_func == IOR_WRITE)
{
if (pPGD->IsReadOnly())
{
derr = kPGDMinorError_FailSilently;
failSilentStatus = IORS_WRITE_PROTECT;
}
}
}
// Prepare the request for execution.
if (derr.IsntError())
{
PGPUInt32 i, nBytes;
PGPUInt64 pos;
mIopReqs[drive].useAsync = useAsync;
mIopReqs[drive].pIop = pIop;
mIopReqs[drive].pIor = pIor;
mIopReqs[drive].downInfo.callback = IorReadWriteCallback;
mIopReqs[drive].downInfo.refData[0] = (PGPUInt32) this;
mIopReqs[drive].downInfo.refData[1] = drive;
// Mark all the mini-request stuctures as unused.
for (i=0; i<kIopProcMaxMinis; i++)
{
mIopReqs[drive].miniReqs[i].isInUse = FALSE;
}
// Calculate the byte offset on the volume where the request begins.
pos = pIor->IOR_start_addr[0] * blockSize;
// Initialize the list of miniReqs that describe the I/O transfers that
// make up this request.
if (!IsScatterGather(pIor)) // Just one 'piece'
{
nBytes = pIor->IOR_xfer_count;
// Translate to bytes
if (!IsInBytes(pIor))
{
nBytes *= blockSize;
}
buf = (PGPUInt8 *) pIor->IOR_buffer_ptr;
pgpAssertAddrValid(buf, PGPUInt8);
// Just one minireq at position 0 for this request.
mIopReqs[drive].miniReqs[0].isInUse = TRUE;
mIopReqs[drive].miniReqs[0].buf = buf;
mIopReqs[drive].miniReqs[0].pos = pos;
mIopReqs[drive].miniReqs[0].nBytes = nBytes;
}
else // More than one 'piece'
{
PGPUInt32 curMiniReq;
PSGD pSgd;
// We are dealing with scatter/gather requests. The pointer to
// the first S/G structure will be in IOR_buffer_ptr. Each SGD
// describes a number of bytes to transfer and provides a buffer.
pSgd = (PSGD) pIor->IOR_buffer_ptr;
pgpAssertAddrValid(pSgd, SGD);
curMiniReq = 0;
// Initialize a separate mini-request structure for each SGD.
while (derr.IsntError() && (nBytes = pSgd->bd.SG_buff_size))
{
if (curMiniReq >= kIopProcMaxMinis)
{
derr = DualErr(kPGDMinorError_MiniRequestOverflow);
}
if (derr.IsntError())
{
// Translate to bytes.
if (!IsInBytes(pIor))
{
nBytes *= blockSize;
}
buf = (PGPUInt8 *) pSgd->bd.SG_buff_ptr;
pgpAssertAddrValid(buf, PGPUInt8);
mIopReqs[drive].miniReqs[curMiniReq].isInUse = TRUE;
mIopReqs[drive].miniReqs[curMiniReq].buf = buf;
mIopReqs[drive].miniReqs[curMiniReq].pos = pos;
mIopReqs[drive].miniReqs[curMiniReq].nBytes = nBytes;
curMiniReq++;
pos += nBytes; // where the next read will begin
pSgd++; // move on to the next S/G structure
}
}
}
}
// Now begin executing the request.
if (derr.IsntError())
{
// ExecuteRequest won't fail on async.
if (useAsync)
ExecuteRequest(drive, &doneWithRequest);
else
derr = ExecuteRequest(drive, &doneWithRequest);
}
// If we are sync, then the request has been completed. If not, then
// doneWithRequest shouldn't be TRUE assuming we were passed valid params.
if (derr.IsntError())
{
if (doneWithRequest)
{
pgpAssert(!useAsync);
ScheduleAsyncCallback(pIop, IORS_SUCCESS);
}
}
// Call back errors now.
if (derr.IsError())
{
switch (derr.mMinorError)
{
case kPGDMinorError_IopRequestOverflow:
case kPGDMinorError_MiniRequestOverflow:
ScheduleAsyncCallback(pIop, IORS_BUSY);
break;
case kPGDMinorError_FailSilently:
ScheduleAsyncCallback(pIop, failSilentStatus);
break;
default:
if (IsntNull(pPGD))
{
pPGD->EnableIO(FALSE);
ScheduleAsyncCallback(pIop, IORS_MEDIA_ERROR);
// For I/O errors, user will be asked for options.
if (pIor->IOR_func == IOR_READ)
{
Driver->ReportError(kPGDMajorError_PGPdiskReadError,
derr, pPGD->GetDrive());
}
else
{
Driver->ReportError(kPGDMajorError_PGPdiskWriteError,
derr, pPGD->GetDrive());
}
}
else
{
ScheduleAsyncCallback(pIop, IORS_NO_DEVICE);
}
break;
}
}
}
// ExecuteRequest executes the next 'piece' of the request being processed on
// the given drive. If there nothing left to execute, 'doneWithRequest' is
// set to TRUE, otherwise FALSE.
DualErr
IopProcessor::ExecuteRequest(PGPUInt8 drive, PGPBoolean *doneWithRequest)
{
DualErr derr;
PGPBoolean foundMiniReq = FALSE;
PGPBoolean useAsync = FALSE;
PGPUInt32 i;
PDCB pDcb;
PGPdisk *pPGD;
PIOP pIop;
PIOR pIor;
pgpAssertAddrValid(doneWithRequest, PGPBoolean);
(* doneWithRequest) = FALSE;
pgpAssert(IsLegalDriveNumber(drive));
pgpAssert(IsDriveBusy(drive));
pIop = mIopReqs[drive].pIop;
pgpAssertAddrValid(pIop, IOP);
pIor = mIopReqs[drive].pIor;
pgpAssertAddrValid(pIor, IOR);
pDcb = (PDCB) pIop->IOP_physical_dcb;
pgpAssertAddrValid(pDcb, DCB);
pPGD = Driver->mPGPdisks.FindPGPdisk(drive);
pgpAssertAddrValid(pPGD, PGPdisk);
useAsync = mIopReqs[drive].useAsync;
// Look for the next piece we need to process, if any are left.
for (i=0; i<kIopProcMaxMinis; i++)
{
if (mIopReqs[drive].miniReqs[i].isInUse)
{
PGPUInt8 *buf;
PGPUInt32 nBytes;
PGPUInt64 pos;
foundMiniReq = TRUE;
buf = mIopReqs[drive].miniReqs[i].buf;
pos = mIopReqs[drive].miniReqs[i].pos;
nBytes = mIopReqs[drive].miniReqs[i].nBytes;
pgpAssertAddrValid(buf, PGPUInt8);
// Call it down. Don't ask for an error value on async calls since
// async errors will be returned using the callback, not here.
switch (pIor->IOR_func)
{
case IOR_READ:
if (useAsync)
pPGD->Read(buf, pos, nBytes, &mIopReqs[drive].downInfo);
else
derr = pPGD->Read(buf, pos, nBytes);
break;
case IOR_WRITE:
if (useAsync)
pPGD->Write(buf, pos, nBytes, &mIopReqs[drive].downInfo);
else
derr = pPGD->Write(buf, pos, nBytes);
break;
}
// If we're async we only process one piece at a time.
if (useAsync || derr.IsError())
break;
}
}
if (useAsync)
(* doneWithRequest) = !foundMiniReq;
else
(* doneWithRequest) = TRUE;
return derr;
}
// IorReadWriteCallback is called as a callback by the routines who executed
// our read and write requests. We extract the address of the PGPdisk object
// in question and pass the callback to it.
void
IopProcessor::IorReadWriteCallback(GenericCallbackInfo *downInfo)
{
IopProcessor *pIP;
PGPUInt8 drive;
pgpAssertAddrValid(downInfo, GenericCallbackInfo);
pIP = (IopProcessor *) downInfo->refData[0];
pgpAssertAddrValid(pIP, IopProcessor);
drive = (PGPUInt8) downInfo->refData[1];
pgpAssert(IsLegalDriveNumber(drive));
pIP->IorReadWriteCallbackAux(drive);
}
// IorReadWriteCallbackAux is called by the static callback function
// 'IorReadWriteCallback' so we don't have to type 'pIP' before every
// reference to an object member or method.
void
IopProcessor::IorReadWriteCallbackAux(PGPUInt8 drive)
{
DualErr derr;
PGPBoolean doneWithRequest;
PGPUInt32 i;
pgpAssert(IsLegalDriveNumber(drive));
pgpAssert(IsDriveBusy(drive));
derr = mIopReqs[drive].downInfo.derr;
if (derr.IsntError())
{
// Mark the mini-request structure we just completed as unused.
for (i=0; i<kIopProcMaxMinis; i++)
{
if (mIopReqs[drive].miniReqs[i].isInUse)
{
mIopReqs[drive].miniReqs[i].isInUse = FALSE;
break;
}
}
}
// Perform further processing on this request, if needed.
if (derr.IsntError())
{
derr = ExecuteRequest(drive, &doneWithRequest);
}
// Callback if we're done or on error.
if (doneWithRequest || derr.IsError())
{
PIOP pIop;
PIOR pIor;
pIop = mIopReqs[drive].pIop;
pgpAssertAddrValid(pIop, IOP);
pIor = &pIop->IOP_ior;
pgpAssertAddrValid(pIor, IOR);
if (derr.IsntError())
{
ScheduleAsyncCallback(pIop, IORS_SUCCESS);
}
else
{
PGPdisk *pPGD;
switch (derr.mMinorError)
{
case kPGDMinorError_IopRequestOverflow:
case kPGDMinorError_MiniRequestOverflow:
ScheduleAsyncCallback(pIop, IORS_BUSY);
break;
default:
pPGD = Driver->mPGPdisks.FindPGPdisk(drive);
pgpAssertAddrValid(pPGD, PGPdisk);
// Disable I/O to the PGPdisk.
pPGD->EnableIO(FALSE);
ScheduleAsyncCallback(pIop, IORS_MEDIA_ERROR);
// For I/O errors, user will be asked for options.
if (pIor->IOR_func == IOR_READ)
{
Driver->ReportError(kPGDMajorError_PGPdiskReadError,
DualErr::NoError, pPGD->GetDrive());
}
else
{
Driver->ReportError(kPGDMajorError_PGPdiskWriteError,
DualErr::NoError, pPGD->GetDrive());
}
break;
}
}
}
}
// ScheduleAsyncCallback schedules a windows event that calls our function
// that will call the asynchronous request up.
void
IopProcessor::ScheduleAsyncCallback(PIOP pIop, PGPUInt16 status)
{
PIOR pIor;
static RestrictedEvent_THUNK callbackThunk;
pgpAssertAddrValid(pIop, IOP);
pIor = &pIop->IOP_ior;
pgpAssertAddrValid(pIor, IOR);
pIor->IOR_status = status;
Call_Restricted_Event(0, NULL, PEF_ALWAYS_SCHED, (PVOID) pIop,
AsyncExecuteCallback, 0, &callbackThunk);
}
// AsyncExecuteCallback was scheduled by 'ScheduleAsyncCallback' for the
// purpose of calling back up the asynchronous request we received.
VOID
__stdcall
IopProcessor::AsyncExecuteCallback(
VMHANDLE hVM,
THREADHANDLE hThread,
PVOID Refdata,
PCLIENT_STRUCT pRegs)
{
IopProcessor *pIP;
PGPUInt8 drive;
PIOP pIop;
PIOR pIor;
pIop = (PIOP) Refdata;
pgpAssertAddrValid(pIop, IOP);
pIor = &pIop->IOP_ior;
pgpAssertAddrValid(pIor, IOR);
pIP = (IopProcessor *) pIor->IOR_private_port;
pgpAssertAddrValid(pIP, IopProcessor);
// If the IOR was a read or write request, we must check if there is more
// I/O from that PGPdisk to process. We do this by scheduling the IOP
// dispatch function as a callback.
PDCB pDcb;
switch (pIor->IOR_func)
{
case IOR_READ:
case IOR_WRITE:
pDcb = (PDCB) pIop->IOP_physical_dcb;
pgpAssertAddrValid(pDcb, DCB);
drive = pDcb->DCB_cmn.DCB_drive_lttr_equiv;
pgpAssert(IsLegalDriveNumber(drive));
--pIop->IOP_callback_ptr;
pIop->IOP_callback_ptr->IOP_CB_address(pIop);
pIP->ScheduleIorReadWriteDispatch(drive);
break;
default:
--pIop->IOP_callback_ptr;
pIop->IOP_callback_ptr->IOP_CB_address(pIop);
break;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -