Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
Src/ContinueTesting.c
/* ContinueTesting.c */ |
/* |
* ContinueTesting.c |
* Copyright © 93 Apple Computer Inc. All Rights Reserved. |
* |
* Run the dialog until the user has had enough. |
*/ |
#include "SCSIAsyncSample.h" |
#include "SCSIDefinitions.h" |
pascal void |
PerformTestIOCompletion( |
void *ioPtr |
); |
#define INFO (*infoPtr) |
void ComputeTestParameters( |
register InfoPtr infoPtr |
); |
void PerformTest( |
register InfoPtr infoPtr |
); |
void |
StartTesting(void) |
{ |
InfoPtr infoPtr; |
for (infoPtr = (InfoPtr) infoPtrQueue.qHead; |
infoPtr != NULL; |
infoPtr = (InfoPtr) infoPtr->link) { |
if (INFO.validDevice) { |
INFO.sampleSum = INFO.sampleSumSquare = 0.0; |
INFO.deviceActive = TRUE; |
Microseconds(&INFO.testStartTime); |
if (INFO.enableAsync) { |
/* |
* This loop is entered once when we start the actual test. |
* It is only called for asychronous threads. |
*/ |
ComputeTestParameters(infoPtr); |
PerformTest(infoPtr); |
} |
} |
} |
} |
void |
ContinueTesting(void) |
{ |
InfoPtr infoPtr; |
Boolean somethingIsBusy; |
static Boolean stoppedYet = FALSE; |
somethingIsBusy = FALSE; |
for (infoPtr = (InfoPtr) infoPtrQueue.qHead; |
infoPtr != NULL; |
infoPtr = (InfoPtr) infoPtr->link) { |
if (INFO.deviceActive && INFO.testCompleted == FALSE) { |
somethingIsBusy = TRUE; |
if (INFO.enableAsync == FALSE) { |
/* |
* This loop is entered each time through the event loop to |
* read one request from a synchronous test thread. It is not |
* called for asychronous threads. |
*/ |
ComputeTestParameters(infoPtr); |
PerformTest(infoPtr); |
} |
} |
} |
if (somethingIsBusy == FALSE) { |
InitCursor(); |
if (stoppedYet == FALSE) { |
stoppedYet = TRUE; |
DisplayTestResults(); |
} |
} |
} |
void VMStartMarker(void) { } |
/* |
* These may be called from an I/O completion routine |
*/ |
void |
PerformTest( |
register InfoPtr infoPtr |
) |
{ |
short commandLength; |
OSErr status; |
register short i; |
register SCSIExecIOPB *pb; |
register RequestMemoryPtr requestMemoryPtr; |
#define PB (*pb) |
ClearMemory((Ptr) INFO.vmHoldInfo, sizeof INFO.vmHoldInfo); |
CLEAR(INFO.command); |
if (INFO.transferSizeBlocks <= 256 |
&& INFO.blockCount <= 0x001FFFFFL) { |
INFO.command.scsi6.opcode = kScsiCmdRead6; |
INFO.command.scsi6.lbn3 = (INFO.blockNumber >> 16) & 0xFF; |
INFO.command.scsi6.lbn2 = (INFO.blockNumber >> 8) & 0xFF; |
INFO.command.scsi6.lbn1 = (INFO.blockNumber ) & 0xFF; |
INFO.command.scsi6.len = INFO.transferSizeBlocks & 0xFF; |
INFO.command.scsi6.lbn3 |= (INFO.deviceIdent.LUN << 5) & 0xE0; |
commandLength = sizeof INFO.command.scsi6; |
} |
else { |
INFO.command.scsi10.opcode = kScsiCmdRead6; |
INFO.command.scsi10.lbn4 = (INFO.blockNumber >> 24) & 0xFF; |
INFO.command.scsi10.lbn3 = (INFO.blockNumber >> 16) & 0xFF; |
INFO.command.scsi10.lbn2 = (INFO.blockNumber >> 8) & 0xFF; |
INFO.command.scsi10.lbn1 = (INFO.blockNumber ) & 0xFF; |
INFO.command.scsi10.len2 = (INFO.transferSizeBlocks >> 8) & 0xFF; |
INFO.command.scsi10.len1 = (INFO.transferSizeBlocks ) & 0xFF; |
INFO.command.scsi10.lun |= (INFO.deviceIdent.LUN << 5) & 0xE0; |
commandLength = sizeof INFO.command.scsi10; |
} |
/* |
* Plug the parameters into the SCSI command block. |
*/ |
pb = INFO.pb; |
PB.scsiPBLength = INFO.pbSize; |
PB.scsiFunctionCode = SCSIExecIO; |
/* |
* Use the private pointer in the SCSI command block to link the |
* SCSI parameter block to the InfoRecord. |
*/ |
PB.scsiDriverStorage = (unsigned char *) infoPtr; |
PB.scsiCompletion = (INFO.enableAsync) ? PerformTestIOCompletion : NULL; |
PB.scsiTimeout = INFO.completionTimeout; |
PB.scsiSelectTimeout = INFO.completionTimeout; |
PB.scsiDevice = INFO.deviceIdent; |
PB.scsiCDBLength = commandLength; |
PB.scsiCDB.cdbPtr = (unsigned char *) &INFO.command; |
PB.scsiFlags = (scsiCDBIsPointer | scsiSIMQNoFreeze); |
PB.scsiFlags |= (INFO.enableDisconnect) |
? scsiDoDisconnect |
: scsiDontDisconnect; |
if (INFO.bufferPtr == NULL || INFO.bufferLength == 0) |
PB.scsiFlags |= scsiDirectionNone; |
else { |
/* |
* If the user specified the transfer quantum == 1, select "polled" |
* transfers, otherwise, select "blind." |
*/ |
PB.scsiTransferType = (INFO.transferQuantum == 1) |
? scsiTransferPolled |
: scsiTransferBlind; |
PB.scsiDataPtr = (unsigned char *) INFO.bufferPtr; |
PB.scsiDataLength = INFO.bufferLength; |
PB.scsiDataType = scsiDataBuffer; |
PB.scsiFlags |= scsiDirectionIn; |
PB.scsiHandshake[0] = 512; |
PB.scsiHandshake[1] = 0; |
} |
INFO.senseData.errorCode = 0; |
PB.scsiSensePtr = (unsigned char *) &INFO.senseData; |
PB.scsiSenseLength = sizeof INFO.senseData; |
if (gVirtualMemoryEnabled) { |
/* Function */ |
/* Param block */ |
INFO.vmHoldInfo[kVMParam].ptr = INFO.pb; |
INFO.vmHoldInfo[kVMParam].size = INFO.pbSize; |
/* Data buffer */ |
INFO.vmHoldInfo[kVMBuffer].ptr = PB.scsiDataPtr; |
INFO.vmHoldInfo[kVMBuffer].size = PB.scsiDataLength; |
/* Info record (has command and sense buffer) */ |
INFO.vmHoldInfo[kVMSense].ptr = PB.scsiSensePtr; |
INFO.vmHoldInfo[kVMSense].size = PB.scsiSenseLength; |
for (i = 0; i < kVMSize; i++) { |
if (INFO.vmHoldInfo[i].ptr != NULL) { |
status = HoldMemory( |
INFO.vmHoldInfo[i].ptr, |
INFO.vmHoldInfo[i].size |
); |
if (status != noErr) { |
while (i < kVMSize) |
INFO.vmHoldInfo[i++].ptr = NULL; |
break; |
} |
} |
} |
if (status != noErr) { |
/* |
* Something failed. Unwind before exiting. |
*/ |
for (i = 0; i < kVMSize; i++) { |
if (INFO.vmHoldInfo[i].ptr != NULL) { |
(void) UnholdMemory( |
INFO.vmHoldInfo[i].ptr, |
INFO.vmHoldInfo[i].size |
); |
} |
} |
} |
} |
/* |
* What ho, here we go! |
*/ |
requestMemoryPtr = &INFO.requestMemory[INFO.transfersAttempted % kRequestMemory]; |
INFO.requestMemoryPtr = requestMemoryPtr; |
requestMemoryPtr->blockNumber = INFO.blockNumber; |
++INFO.transfersAttempted; |
Microseconds(&requestMemoryPtr->startTime); |
status = SCSIAction((SCSI_PB *) pb); |
if (PB.scsiResult == scsiRequestInProgress) |
++INFO.asynchRequests; |
if (status != noErr) { |
if (PB.scsiCompletion == NULL && PB.scsiResult == noErr) |
PB.scsiResult = status; |
if (INFO.finalStatus == noErr) |
INFO.finalStatus = status; |
} |
/* |
* If we're asychronous, just exit - the I/O completion routine will |
* clean up the mess. If we're synchronous, we're done, so call the |
* I/O completion routine ourself. |
*/ |
if (PB.scsiCompletion == NULL) |
PerformTestIOCompletion(pb); |
} |
/* |
* This is called by I/O completion. |
*/ |
pascal void |
PerformTestIOCompletion( |
void *ioPtr |
) |
{ |
register SCSIExecIOPB *pb; |
register InfoPtr infoPtr; |
short i; |
double sampleTime; |
UnsignedWide difference; |
pb = (SCSIExecIOPB *) ioPtr; |
infoPtr = (InfoPtr) PB.scsiDriverStorage; |
Microseconds(&INFO.requestMemoryPtr->endTime); |
MicrosecondDelta( |
&INFO.requestMemoryPtr->startTime, |
&INFO.requestMemoryPtr->endTime, |
&difference |
); |
sampleTime = MicrosecondToDouble(&difference) / 1000000.0; |
INFO.sampleSum += sampleTime; |
INFO.sampleSumSquare += (sampleTime * sampleTime); |
/* |
* Release virtual memory |
*/ |
for (i = 0; i < kVMSize; i++) { |
if (INFO.vmHoldInfo[i].ptr != NULL) { |
(void) UnholdMemory( |
INFO.vmHoldInfo[i].ptr, |
INFO.vmHoldInfo[i].size |
); |
} |
} |
++INFO.transfersCompleted; |
/* |
* If an error occurred, set the global "stop" flag to prevent |
* errors from cascading. |
*/ |
if (PB.scsiResult != noErr && INFO.finalStatus == noErr) |
INFO.finalStatus = PB.scsiResult; |
if (INFO.finalStatus != noErr) |
INFO.testCompleted = TRUE; |
else if (INFO.totalTransfers != 0 |
&& INFO.transfersCompleted >= INFO.totalTransfers) |
INFO.testCompleted = TRUE; |
/* |
* If we're running asychronously and are still alive, start the |
* next transfer. |
*/ |
if (INFO.testCompleted) { |
INFO.testEndTime = INFO.requestMemoryPtr->endTime; |
INFO.deviceActive = FALSE; |
} |
else if (INFO.enableAsync) { |
ComputeTestParameters(infoPtr); |
PerformTest(infoPtr); |
} |
} |
void VMEndMarker(void) { } |
void |
ComputeTestParameters( |
register InfoPtr infoPtr |
) |
{ |
if (INFO.finalStatus != noErr |
|| (INFO.totalTransfers != 0 |
&& INFO.transfersCompleted >= INFO.totalTransfers)) |
INFO.testCompleted = TRUE; |
else if (INFO.enableRandomSeek) { |
INFO.randomSeed = (INFO.randomSeed * 1103515245L) + 12345L; |
INFO.nextBlockNumber = INFO.randomSeed % INFO.totalLogicalBlocks; |
goto computeByteCount; |
} |
else { |
if (INFO.nextBlockNumber >= INFO.totalLogicalBlocks) |
INFO.nextBlockNumber = 0; |
computeByteCount: |
INFO.blockNumber = INFO.nextBlockNumber; |
INFO.blockCount = INFO.transferSizeBlocks; |
if (INFO.blockNumber + INFO.blockCount >= INFO.totalLogicalBlocks) |
INFO.blockCount = INFO.totalLogicalBlocks - INFO.blockNumber; |
INFO.byteCount = INFO.transferSizeBlocks * INFO.logicalBlockLength; |
INFO.nextBlockNumber = INFO.blockNumber + INFO.blockCount; |
} |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14