home *** CD-ROM | disk | FTP | other *** search
Text File | 2000-04-25 | 27.7 KB | 782 lines | [TEXT/CWIE] |
- /*
- File: UnitTableReadWriteSupport.c
-
- Contains: Handles read and write requests. Also handles all filesystem
- to device block conversions.
-
- Version: 1.0
-
- Copyright: © 1999 by Apple Computer, Inc., all rights reserved.
-
- */
-
- // All system header includes
- #include <Devices.h>
- #include <DriverServices.h>
- #include <Errors.h>
-
- // Unit Table Driver specific headers
- #include "UnitTableReadWriteSupport.h"
- #include "UnitTableDeviceAccess.h"
- #include "UnitTableDriveQSupport.h"
-
- typedef struct IntReadWritePB
- {
- UInt32 userData;
- ReadWriteCompletionProcPtr userCompletion;
- volatile OSStatus status;
- UInt32 startBlock;
- UInt32 blockCount;
- Boolean convertToSystemBlocks;
- UInt32 reqCount;
- Ptr userBuffer;
- UInt16 retryCount;
- UInt32 blockSize;
- Boolean doWrite;
- UInt8 currentExecutionState;
- SGList theSGList;
- SGElement sgElements[4];
- UInt32 leadDataStart;
- UInt32 leadDataEnd;
- UInt32 trailDataCount;
- } IntReadWritePB, *IntReadWritePBPtr;
-
- static IntReadWritePB gReadWritePB;
-
- enum
- {
- kMaxSupportedBlocksize = 2048
- };
-
- enum
- {
- kReadWriteRetryCount = 5
- };
-
- static OSStatus ConvertSystemBlocksToDriveBlocks( IntReadWritePBPtr readWritePB );
-
- static void ReadScatterGatherCompletion( UInt32 userData,
- OSStatus status );
-
- static void WriteReadTrailingOnlyCompletion( UInt32 userData,
- OSStatus status );
-
- static void WriteReadLeadingCompletion( UInt32 userData,
- OSStatus status );
-
- static void WriteReadTrailingCompletion( UInt32 userData,
- OSStatus status );
-
- static void ReadWriteCompletion( UInt32 userData,
- OSStatus status );
-
- /* ---------------------Supporting Functions below this point -------------------------- */
- //------------------------------------------------------------------------------
- // Function: DoReadWriteCommand
- // Description: This is the entry point for all Read and Write
- // requests passed through DoDriverIO.
- //
- // Input: ioPB = Pointer to caller's I/O parameter block
- //
- // Output: A status code is returned (status is equal to 1
- // if command is pending completion).
- //-------------------------------------------------------------------------------
- OSStatus DoReadWriteCommand( UInt32 userData, IOParamPtr iopb, UInt16 driveNum, Boolean doWrite, ReadWriteCompletionProcPtr callback )
- {
- OSStatus err;
- UInt32 startingBlock, numBlocks;
- UInt32 standardBlockSize = kFileSystemRequestBlockSize;
- DriveQRecPtr drive;
-
- // Save the parameters ino our internal parameter block
- BlockZero( &gReadWritePB, sizeof( IntReadWritePB ));
- gReadWritePB.userData = userData;
- gReadWritePB.userCompletion = callback;
- gReadWritePB.doWrite = doWrite;
-
- // Find the associated volume and drive records required for the request.
- drive = FindDriveQRecForDriveNum( driveNum ); // Get the volume record requested
-
- if ( drive == nil ) // Abort if we can't find a valid drive
- {
- return( nsDrvErr );
- }
-
- gReadWritePB.blockSize = drive->blockSize;
-
- // Make sure that the request is converted from native blocks to system blocks if necessary.
- gReadWritePB.convertToSystemBlocks = true;
- //................................................................................
- // A usable drive and volume exists. Continue processing the request…
-
- // Compute the starting block address for the request. We accept either
- // the new 'Large Volume (64 bit) Addressing' or the normal 32 bit address.
- if (iopb->ioPosMode & kUseWidePositioning) // If 'wide' address is used
- {
- XIOParam *widePB;
-
- widePB = (XIOParam *) iopb;
-
- startingBlock = (widePB->ioWPosOffset.hi & 0XFC00); // Verify whether a valid 52 bit address
- if (startingBlock != 0)
- return(paramErr); // address too large
-
- // The address is a 64 bit big-endian integer (only 52 bits are used for now).
- // Divide by 512 to get a 32 bit block address. This translates as follows:
- // byte address bits 00-31 = block address bits 00-22
- // byte address bits 32-51 = block address bits 23-31
- startingBlock = (widePB->ioWPosOffset.hi << 23); // block address bits 23-31
- startingBlock |= (widePB->ioWPosOffset.lo >> 9); // block address bits 00-23
- }
- else
- {
- // traditional 32 bit address
- startingBlock = (UInt32)((iopb->ioPosOffset)/(standardBlockSize));
- }
-
- numBlocks = (iopb->ioReqCount)/(standardBlockSize);
-
- if (doWrite && drive->driveStatus.writeProt)
- {
- // check for write protect
- err = wPrErr;
- }
- else if (iopb->ioReqCount & ((standardBlockSize) - 1))
- {
- // Verify if request is a multiple of the file system request blocksize
- err = paramErr;
- }
- else if ( ( startingBlock + numBlocks ) > ((drive->curoffset) ? drive->partblks : drive->capacity))
- {
- // Verify if request is within range with respect to doing physical or logical I/O.
- // Access is limited to partition range (logical I/O) if curoffset is non-zero.
- err = paramErr;
- }
- else if ((iopb->ioPosMode & rdVerify) && !doWrite)
- {
- // If Read-Verify mode, this is not efficient with disks so we simply pretend we did it.
- iopb->ioActCount = iopb->ioReqCount;
- iopb->ioPosOffset += iopb->ioActCount;
- err = noErr;
- }
- else // Do the read or write
- {
- startingBlock += drive->curoffset; // add in the partition offset
-
- gReadWritePB.startBlock = startingBlock;
- gReadWritePB.blockCount = numBlocks;
- gReadWritePB.userBuffer = iopb->ioBuffer;
- gReadWritePB.reqCount = iopb->ioReqCount;
- err = ConvertSystemBlocksToDriveBlocks( &gReadWritePB );
- }
-
- return err;
- }
-
- OSStatus DoReadWritePhysicalBlocks ( UInt32 userData,
- UInt32 startBlock,
- UInt32 blockCount,
- UInt32 blockSize,
- Boolean convertToSystemBlocks,
- Ptr buffer,
- UInt32 byteCount,
- Boolean doWrite,
- ReadWriteCompletionProcPtr callBack)
- {
- OSStatus err;
-
- // Save the parameters ino our internal parameter block
- BlockZero( &gReadWritePB, sizeof( IntReadWritePB ));
- gReadWritePB.userData = userData;
- gReadWritePB.userCompletion = callBack;
- gReadWritePB.blockSize = blockSize;
- gReadWritePB.doWrite = doWrite;
- gReadWritePB.startBlock = startBlock;
- gReadWritePB.blockCount = blockCount;
- gReadWritePB.userBuffer = buffer;
- gReadWritePB.reqCount = byteCount;
- gReadWritePB.convertToSystemBlocks = convertToSystemBlocks;
-
- // Check to make sure that if we are not converting to system
- // blocks, that the request is actually a multiple of the
- // native block size of the device.
- if (( convertToSystemBlocks == false ) && (( byteCount % blockSize ) != 0 ))
- {
- err = ioErr;
- }
- else
- {
- err = ConvertSystemBlocksToDriveBlocks( &gReadWritePB );
- }
-
- return err;
- }
-
- // Our buffers for deblocking the requests
- static UInt8 LeadingBlockBuffer[kMaxSupportedBlocksize];
- static UInt8 TrailingBlockBuffer[kMaxSupportedBlocksize];
-
- OSStatus ConvertSystemBlocksToDriveBlocks( IntReadWritePBPtr readWritePB )
- {
- OSStatus err;
- UInt32 startingDriveBlock, numDriveBlocks;
- UInt32 standardBlockSize = kFileSystemRequestBlockSize;
-
- if (( readWritePB->blockSize == standardBlockSize ) || ( readWritePB->convertToSystemBlocks == false ))
- {
- // The drive's blocksize is the same as the system's or we are ask not to do th conversion,
- // we do not need to do anything else, but send this request.
- err = ReadWriteSingleBuffer( (UInt32) readWritePB,
- readWritePB->startBlock,
- readWritePB->blockCount,
- readWritePB->userBuffer,
- readWritePB->reqCount,
- readWritePB->doWrite,
- &ReadWriteCompletion );
- }
- else
- {
- // The drive's block size is greater than the system defaut block size.
- // Each request needs to be examined to see if it can be completed as a single
- // buffer command, a scatter-gather command or if it requires additional read
- // commands to complete
- UInt8 sysBlksPrDriveBlk;
-
- sysBlksPrDriveBlk = (readWritePB->blockSize)/standardBlockSize;
- if (( ( readWritePB->startBlock % sysBlksPrDriveBlk) == 0 )
- && ( (readWritePB->blockCount % sysBlksPrDriveBlk) == 0 ))
- {
- // The starting block is on a drive block boundary and
- // the blockCount is a multiple of drive blocks
- // modify the start block and block count and send as
- // a single buffer request.
- startingDriveBlock = (readWritePB->startBlock)/sysBlksPrDriveBlk;
- numDriveBlocks = (readWritePB->blockCount)/sysBlksPrDriveBlk;
- err = ReadWriteSingleBuffer( (UInt32) readWritePB,
- startingDriveBlock,
- numDriveBlocks,
- readWritePB->userBuffer,
- readWritePB->reqCount,
- readWritePB->doWrite,
- &ReadWriteCompletion );
- return err;
- }
- else if ( readWritePB->doWrite == true )
- {
- // Request is a write, handle all reading and blockcopy commands needed
- // to complete the write request.
- /*
- Write Flow:
- Read Lead
- Read Trail
- BlockCopy A
- BlockCopy B
- 1 Write S-G
- Write Lead
- Write X
- Write Trail
- */
- if ( ( readWritePB->startBlock % sysBlksPrDriveBlk) == 0 )
- {
- //The starting block is on a drive block boundary
- if (readWritePB->blockCount < sysBlksPrDriveBlk)
- {
- // The total data to be transferred is smaller than a drive block
- // Read the one drive block that has all the system blocks in it
- startingDriveBlock = (readWritePB->startBlock)/sysBlksPrDriveBlk;
- }
- else
- {
- // The total data to be transferred crosses a drive block boundary
- // Read the last drive block that this request touches.
- startingDriveBlock = (readWritePB->startBlock + readWritePB->blockCount)/sysBlksPrDriveBlk;
- }
-
- // We need to read just the trailing block at this point
- err = ReadWriteSingleBuffer( (UInt32) readWritePB,
- startingDriveBlock,
- 1, // We only want to read one block
- (Ptr) TrailingBlockBuffer, // Read into the trailing buffer
- readWritePB->blockSize, // We need to read one block
- false, // We want to read this block
- &WriteReadTrailingOnlyCompletion );
- return err;
- }
- else
- {
- // The starting block is not on a drive block boundary
- // The leading block needs to be read before anything can be written
- // We need to read just the leading block at this point
- startingDriveBlock = (readWritePB->startBlock)/sysBlksPrDriveBlk;
- err = ReadWriteSingleBuffer( (UInt32) readWritePB,
- startingDriveBlock,
- 1, // We only want to read one block
- (Ptr) LeadingBlockBuffer, // Read into the Leading buffer
- readWritePB->blockSize, // We need to read one block
- false, // We want to read this block
- &WriteReadLeadingCompletion );
- }
- }
- else
- {
- /*
- Read flow:
- 1 Read S-G:
- Read Lead
- Read X
- Read Trail
- Blockcopy A
- BlockCopy B
- */
- if ( ( readWritePB->startBlock % sysBlksPrDriveBlk) == 0 )
- {
- //The starting block is on a drive block boundary
- startingDriveBlock = (readWritePB->startBlock)/sysBlksPrDriveBlk;
-
- if (readWritePB->blockCount <= sysBlksPrDriveBlk)
- {
- // The total data to be transferred is smaller than a drive block
- readWritePB->sgElements[0].SGAddr = (Ptr) TrailingBlockBuffer;
- readWritePB->sgElements[0].SGCount = readWritePB->blockSize;
-
- readWritePB->theSGList.sgNumberElements = 1;
- readWritePB->leadDataStart = 0;
- readWritePB->leadDataEnd = 0;
- readWritePB->trailDataCount = ( readWritePB->blockCount * kFileSystemRequestBlockSize );
-
- // The number of blocks to read is just one
- numDriveBlocks = 1;
- }
- else
- {
- // The total data to be transferred crosses a drive block boundary
- readWritePB->sgElements[0].SGAddr = readWritePB->userBuffer;
- readWritePB->sgElements[0].SGCount = ((readWritePB->blockCount / sysBlksPrDriveBlk) * readWritePB->blockSize);
-
- readWritePB->sgElements[1].SGAddr = (Ptr) TrailingBlockBuffer;
- readWritePB->sgElements[1].SGCount = readWritePB->blockSize;
-
- readWritePB->theSGList.sgNumberElements = 2;
- readWritePB->leadDataStart = 0;
- readWritePB->leadDataEnd = 0;
- readWritePB->trailDataCount = ((readWritePB->blockCount % sysBlksPrDriveBlk) * kFileSystemRequestBlockSize);
-
- // The number of blocks to read will be the total number of drive blocks, plus the trailing block
- numDriveBlocks = (readWritePB->blockCount/sysBlksPrDriveBlk) + 1;
- }
- }
- else
- {
- // The starting block is not on a drive block boundary
- UInt32 blocksInLeading;
-
- blocksInLeading = sysBlksPrDriveBlk - (readWritePB->startBlock % sysBlksPrDriveBlk);
- startingDriveBlock = (readWritePB->startBlock)/sysBlksPrDriveBlk;
- if ( blocksInLeading > readWritePB->blockCount )
- {
- blocksInLeading = readWritePB->blockCount;
- }
-
- readWritePB->sgElements[0].SGAddr = (Ptr) LeadingBlockBuffer;
- readWritePB->sgElements[0].SGCount = readWritePB->blockSize;
- readWritePB->leadDataStart = ((readWritePB->startBlock % sysBlksPrDriveBlk) * kFileSystemRequestBlockSize);
- readWritePB->leadDataEnd = readWritePB->leadDataStart + ( blocksInLeading * kFileSystemRequestBlockSize );
- if ( readWritePB->blockCount <= blocksInLeading )
- {
- // All the data to be transferred is in the LeadingBlockBuffer
- readWritePB->trailDataCount = 0;
- readWritePB->theSGList.sgNumberElements = 1;
- numDriveBlocks = 1;
- }
- else
- {
- UInt32 numSystemBlksRemaining = readWritePB->blockCount - blocksInLeading;
-
- if ( numSystemBlksRemaining < sysBlksPrDriveBlk )
- {
- // We don not have another complete block, read trailing block
- readWritePB->sgElements[1].SGAddr = (Ptr) TrailingBlockBuffer;
- readWritePB->sgElements[1].SGCount = readWritePB->blockSize;
-
- readWritePB->trailDataCount = ((numSystemBlksRemaining % sysBlksPrDriveBlk) * kFileSystemRequestBlockSize);
- readWritePB->theSGList.sgNumberElements = 2;
-
- // Number of blocks will be the leading + the trailing block
- numDriveBlocks = 1 + 1;
- }
- else
- {
- readWritePB->sgElements[1].SGAddr = readWritePB->userBuffer + (blocksInLeading * kFileSystemRequestBlockSize);
- readWritePB->sgElements[1].SGCount = ((numSystemBlksRemaining / sysBlksPrDriveBlk) * readWritePB->blockSize);
-
- if( (numSystemBlksRemaining % sysBlksPrDriveBlk) == 0 )
- {
- // The rest of the data will be in one segment
- readWritePB->theSGList.sgNumberElements = 2;
-
- // Number of blocks will be the leading plus the number of whole drive blocks
- numDriveBlocks = 1 + (numSystemBlksRemaining / sysBlksPrDriveBlk );
- }
- else
- {
- // We also need to read a trailing block
- readWritePB->sgElements[2].SGAddr = (Ptr) TrailingBlockBuffer;
- readWritePB->sgElements[2].SGCount = readWritePB->blockSize;
-
- readWritePB->trailDataCount = ((numSystemBlksRemaining % sysBlksPrDriveBlk) * kFileSystemRequestBlockSize);
- readWritePB->theSGList.sgNumberElements = 3;
-
- // Number of blocks will be the leading plus the number of whole drive blocks + the trailing block
- numDriveBlocks = 1 + ( numSystemBlksRemaining / sysBlksPrDriveBlk ) +1;
- }
- }
- }
- }
-
- readWritePB->theSGList.sgElementList = readWritePB->sgElements;
- err = ReadWriteScatterGatherList(
- (UInt32) readWritePB,
- startingDriveBlock,
- numDriveBlocks,
- &readWritePB->theSGList,
- numDriveBlocks * ( readWritePB->blockSize),
- readWritePB->doWrite,
- &ReadScatterGatherCompletion );
- }
- }
-
- return err;
- }
-
- #pragma mark --
- #pragma mark SG Completion Routines
- void ReadScatterGatherCompletion( UInt32 userData, OSStatus status )
- {
- if ( status == noErr )
- {
- IntReadWritePBPtr ourPB = (IntReadWritePBPtr) userData;
-
- if (( ourPB->leadDataStart != 0 ) || ( ourPB->leadDataEnd != 0 ))
- {
- // Copy the data from the leading buffer to the user's buffer
- BlockCopy( LeadingBlockBuffer + ourPB->leadDataStart, ourPB->userBuffer, ourPB->leadDataEnd - ourPB->leadDataStart );
- }
-
- if ( ourPB->trailDataCount != 0 )
- {
- // Copy the data from the trailing buffer to the user's buffer
- UInt32 bufferOffset;
-
- bufferOffset = ourPB->reqCount - ourPB->trailDataCount;
- BlockCopy( TrailingBlockBuffer, ourPB->userBuffer + bufferOffset, ourPB->trailDataCount );
- }
- }
-
- ReadWriteCompletion( userData, status );
- }
-
- void WriteReadTrailingOnlyCompletion( UInt32 userData, OSStatus status )
- {
- OSStatus err = status;
-
- // This is the completion routine after reading the trailing block for
- // requests that start on a drive boundary.
- if ( err == noErr )
- {
- UInt32 startingDriveBlock, numDriveBlocks;
- UInt32 standardBlockSize = kFileSystemRequestBlockSize;
- IntReadWritePBPtr ourPB = (IntReadWritePBPtr) userData;
- UInt8 sysBlksPrDriveBlk;
-
- sysBlksPrDriveBlk = (ourPB->blockSize)/standardBlockSize;
- startingDriveBlock = (ourPB->startBlock)/sysBlksPrDriveBlk;
-
- // Handle all copies from our buffers to the request buffers
- if ( ourPB->blockCount < sysBlksPrDriveBlk )
- {
- // All the data is in one drive block
- // Copy the data from the user buffer into the start of the trailing buffer
- BlockCopy( ourPB->userBuffer, TrailingBlockBuffer, ourPB->reqCount );
-
- // Now write the block out as a single buffer
- err = ReadWriteSingleBuffer( (UInt32) ourPB,
- startingDriveBlock,
- 1, // Write just one drive block
- (Ptr) TrailingBlockBuffer, // The Trailing Buffer has the data to write
- ourPB->blockSize, // We are writing one complete drive block
- ourPB->doWrite,
- &ReadWriteCompletion );
- }
- else
- {
- // The data is in multiple drive blocks
- UInt32 bufferOffset;
-
- //bufferOffset = ((ourPB->blockCount) - (ourPB->blockCount % sysBlksPrDriveBlk)) * standardBlockSize;
- bufferOffset = (ourPB->blockCount/sysBlksPrDriveBlk) * ourPB->blockSize;
-
- // Copy the data from the user buffer into the start of the trailing buffer
- BlockCopy( ourPB->userBuffer + bufferOffset, TrailingBlockBuffer, ourPB->reqCount - bufferOffset );
- // Write all complete drive blocks plus the trailing buffer
- ourPB->sgElements[0].SGAddr = ourPB->userBuffer;
- ourPB->sgElements[0].SGCount = ((ourPB->blockCount / sysBlksPrDriveBlk) * ourPB->blockSize);
-
- ourPB->sgElements[1].SGAddr = (Ptr) TrailingBlockBuffer;
- ourPB->sgElements[1].SGCount = ourPB->blockSize;
-
- ourPB->theSGList.sgNumberElements = 2;
-
- // The number of blocks to write will be the total number of drive blocks, plus the trailing block
- // Use the standard completion routine because the request will be finished when this write completes.
- numDriveBlocks = (ourPB->blockCount/sysBlksPrDriveBlk) + 1;
- ourPB->theSGList.sgElementList = ourPB->sgElements;
- err = ReadWriteScatterGatherList(
- (UInt32) ourPB,
- startingDriveBlock,
- numDriveBlocks,
- &ourPB->theSGList,
- numDriveBlocks * ( ourPB->blockSize),
- ourPB->doWrite,
- &ReadWriteCompletion );
- }
- }
-
- if ( err != kRequestPending )
- {
- // An error occurred, let the standard completion routine
- // determine if it should be retried, or if an error should
- // be returned back to the system.
- ReadWriteCompletion( userData, err );
- }
- }
-
- void WriteReadLeadingCompletion( UInt32 userData, OSStatus status )
- {
- OSStatus err = status;
-
- // This is the completion routine after reading the leading block for
- // requests that do not start on a drive boundary.
- if ( err == noErr )
- {
- UInt32 startingDriveBlock, numDriveBlocks;
- UInt32 standardBlockSize = kFileSystemRequestBlockSize;
- IntReadWritePBPtr ourPB = (IntReadWritePBPtr) userData;
- UInt8 sysBlksPrDriveBlk;
- UInt32 blocksInLeading;
- UInt32 leadingBufferOffset;
-
- sysBlksPrDriveBlk = (ourPB->blockSize)/standardBlockSize;
- startingDriveBlock = (ourPB->startBlock)/sysBlksPrDriveBlk;
-
- blocksInLeading = sysBlksPrDriveBlk - (ourPB->startBlock % sysBlksPrDriveBlk);
- if ( blocksInLeading > ourPB->blockCount )
- {
- blocksInLeading = ourPB->blockCount;
- }
-
- // Copy the data from the user buffer into the leading buffer at the calculated offset.
- leadingBufferOffset = ((ourPB->startBlock % sysBlksPrDriveBlk) * standardBlockSize);
- BlockCopy( ourPB->userBuffer, (LeadingBlockBuffer + leadingBufferOffset), ( blocksInLeading * standardBlockSize ));
-
- // Handle all copies from our buffers to the request buffers
- if ( ourPB->blockCount <= blocksInLeading )
- {
- // All the data to be transferred will be in the LeadingBlockBuffer
- // Now write the block out as a single buffer
- err = ReadWriteSingleBuffer( (UInt32) ourPB,
- startingDriveBlock,
- 1, // Write just one drive block
- (Ptr) LeadingBlockBuffer, // The Leading Buffer has all the data to write
- ourPB->blockSize, // We are writing one complete drive block
- ourPB->doWrite,
- &ReadWriteCompletion ); // This completes the request, use the standard completion
- }
- else
- {
- UInt32 numSystemBlksRemaining = ourPB->blockCount - blocksInLeading;
-
- if( (numSystemBlksRemaining % sysBlksPrDriveBlk) == 0 )
- {
- // The rest of the data will be in one segment
- // Build Scatter-Gather list with the Leading block
- // and the remainder of the user buffer.
- ourPB->sgElements[0].SGAddr = (Ptr) LeadingBlockBuffer;
- ourPB->sgElements[0].SGCount = ourPB->blockSize;
-
- ourPB->sgElements[1].SGAddr = ourPB->userBuffer + (blocksInLeading * standardBlockSize);
- ourPB->sgElements[1].SGCount = (numSystemBlksRemaining/sysBlksPrDriveBlk) * ourPB->blockSize;
-
- ourPB->theSGList.sgNumberElements = 2;
-
- // The number of blocks to write will be the leading block + total number of remaining drive blocks
- numDriveBlocks = 1 + (numSystemBlksRemaining/sysBlksPrDriveBlk);
- ourPB->theSGList.sgElementList = ourPB->sgElements;
- err = ReadWriteScatterGatherList(
- (UInt32) ourPB,
- startingDriveBlock,
- numDriveBlocks, // Write the total number of system blocks
- &ourPB->theSGList, // Use the SG List to for buffer and bytes to write
- numDriveBlocks * ( ourPB->blockSize),
- ourPB->doWrite,
- &ReadWriteCompletion ); // This completes the request, use the standard completion
- }
- else
- {
- // We also need to read a trailing block before anything can be written
- // We need to read just the trailing block at this point
-
- // Modify the starting block to be the starting block for the trailing buffer
- startingDriveBlock += (( numSystemBlksRemaining / sysBlksPrDriveBlk ) +1 );
- err = ReadWriteSingleBuffer( (UInt32) ourPB,
- startingDriveBlock,
- 1, // We only want to read one block
- (Ptr) TrailingBlockBuffer, // Read into the Trailing buffer
- ourPB->blockSize, // We need to read one block
- false, // We want to read this block
- &WriteReadTrailingCompletion );
- }
- }
- }
-
- if ( err != kRequestPending )
- {
- // An error occurred, let the standard completion routine
- // determine if it should be retried, or if an error should
- // be returned back to the system.
- ReadWriteCompletion( userData, err );
- }
- }
-
- void WriteReadTrailingCompletion( UInt32 userData, OSStatus status )
- {
- OSStatus err = status;
-
- // This is the completion routine after reading the trailing block for
- // requests that do not start on a drive block boundary and do not end
- // on a drive block boundary.
- if ( err == noErr )
- {
- UInt32 startingDriveBlock, numDriveBlocks;
- UInt32 standardBlockSize = kFileSystemRequestBlockSize;
- IntReadWritePBPtr ourPB = (IntReadWritePBPtr) userData;
- UInt8 sysBlksPrDriveBlk;
- UInt32 blocksInLeading;
- UInt32 userBufferOffset;
- UInt32 numSystemBlksRemaining;
-
- sysBlksPrDriveBlk = (ourPB->blockSize)/standardBlockSize;
- startingDriveBlock = (ourPB->startBlock)/sysBlksPrDriveBlk;
-
- // Copy the data from the user buffer to the Trailing block
- blocksInLeading = sysBlksPrDriveBlk - (ourPB->startBlock % sysBlksPrDriveBlk);
- if ( blocksInLeading > ourPB->blockCount )
- {
- blocksInLeading = ourPB->blockCount;
- }
-
- numSystemBlksRemaining = ourPB->blockCount - blocksInLeading;
- userBufferOffset = ( ( blocksInLeading * standardBlockSize ) + ((numSystemBlksRemaining/sysBlksPrDriveBlk) * ourPB->blockSize));
- BlockCopy( (ourPB->userBuffer + userBufferOffset), TrailingBlockBuffer, (ourPB->reqCount - userBufferOffset));
-
- if ( numSystemBlksRemaining < sysBlksPrDriveBlk )
- {
- // We do not have another complete block,
- // The SG List will be just the leading and trailing buffers
- ourPB->sgElements[0].SGAddr = (Ptr) LeadingBlockBuffer;
- ourPB->sgElements[0].SGCount = ourPB->blockSize;
-
- ourPB->sgElements[1].SGAddr = (Ptr) TrailingBlockBuffer;
- ourPB->sgElements[1].SGCount = ourPB->blockSize;
-
- ourPB->theSGList.sgNumberElements = 2;
-
- // The number of blocks to write will be the leading block + the trailing block
- numDriveBlocks = 1 + 1;
- }
- else
- {
- // The SG List will be the leading buffer, all complete drive blocks
- // from the user buffer, and the trailing buffer
- ourPB->sgElements[0].SGAddr = (Ptr) LeadingBlockBuffer;
- ourPB->sgElements[0].SGCount = ourPB->blockSize;
-
- ourPB->sgElements[1].SGAddr = ourPB->userBuffer + (blocksInLeading * standardBlockSize);
- ourPB->sgElements[1].SGCount = (numSystemBlksRemaining/sysBlksPrDriveBlk) * ourPB->blockSize;
-
- ourPB->sgElements[2].SGAddr = (Ptr) TrailingBlockBuffer;
- ourPB->sgElements[2].SGCount = ourPB->blockSize;
-
- ourPB->theSGList.sgNumberElements = 3;
-
- // The number of blocks to write will be the leading block + total number of remaining drive blocks
- // + the trailing buffer
- numDriveBlocks = 1 + (numSystemBlksRemaining/sysBlksPrDriveBlk) + 1;
- }
-
- ourPB->theSGList.sgElementList = ourPB->sgElements;
- err = ReadWriteScatterGatherList(
- (UInt32) ourPB,
- startingDriveBlock,
- numDriveBlocks, // Write the total number of system blocks
- &ourPB->theSGList, // Use the SG List for buffer and bytes to write
- numDriveBlocks * ( ourPB->blockSize),
- ourPB->doWrite,
- &ReadWriteCompletion ); // This completes the request, use the standard completion
- }
-
- if ( err != kRequestPending )
- {
- // An error occurred, let the standard completion routine
- // determine if it should be retried, or if an error should
- // be returned back to the system.
- ReadWriteCompletion( userData, err );
- }
- }
-
- #pragma mark --
- #pragma mark Standard Completion Routines
- void ReadWriteCompletion( UInt32 userData,
- OSStatus status )
- {
- IntReadWritePBPtr ourPB = (IntReadWritePBPtr) userData;
- Boolean wasWrite;
- OSStatus returnStatus;
-
- returnStatus = status;
- wasWrite = ourPB->doWrite;
-
- if( returnStatus == noErr )
- {
- // This was a read command, and no errors occurred, finish the IO request and
- // return to the system.
- returnStatus = noErr;
- }
- else
- {
- // An error occurred on the initial command, check to see if it should be retried.
- //if ((ourPB->retryCount < kReadWriteRetryCount) && ( returnStatus == kDeviceAccessDataTransferErrorOccurred ))
- if (ourPB->retryCount < kReadWriteRetryCount)
- {
- // We have not yet exceeded the retry count, so try the operation again
- // Increment our retry counter
- ourPB->retryCount += 1;
-
- // Send the command out again
- returnStatus = ConvertSystemBlocksToDriveBlocks( ourPB );
- }
- else
- {
- // Since we only get here if an error occurrs on the command,
- // and so the request couldn't be completed, report back an ioErr to the system.
- returnStatus = ioErr;
- }
- }
-
- if( returnStatus != kRequestPending)
- {
- // The request is either finished, or got an error on the retry;
- // therefore, signal completion of the command to the client
- (*ourPB->userCompletion) ( ourPB->userData, returnStatus );
- }
- }
-