1/* 2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * The contents of this file constitute Original Code as defined in and 7 * are subject to the Apple Public Source License Version 1.1 (the 8 * "License"). You may not use this file except in compliance with the 9 * License. Please obtain a copy of the License at 10 * http://www.apple.com/publicsource and read it before using this file. 11 * 12 * This Original Code and all software distributed under the License are 13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER 14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the 17 * License for the specific language governing rights and limitations 18 * under the License. 19 * 20 * @APPLE_LICENSE_HEADER_END@ 21 */ 22 23#if __ppc__ 24 25/*! 26 @header IOFireWireSBP2LSIWorkaroundDescriptor 27 Contains the class definition for IOFireWireSBP2LSIWorkaroundDescriptor. 28*/ 29 30#ifndef _IOKIT_IOFIREWIRESBP2LSIWORKAROUNDDESCRIPTOR_H 31#define _IOKIT_IOFIREWIRESBP2LSIWORKAROUNDDESCRIPTOR_H 32 33#include <IOKit/IOMemoryDescriptor.h> 34 35class IOFireWireSBP2LSIRange; 36 37/*! 38 @class IOFireWireSBP2LSIWorkaroundDescriptor 39 @abstract This is a subclass of IOGeneralMemoryDescriptor. It is designed to work around 40 a hardware problem in a common SBP2 target. It takes a memory descriptor as 41 an argument. It retains this descriptor and returns a new one with resegmented 42 physical segments and potentially some "unfixable" segments double buffered. 43 44 If the transfer will cause data to be sent from the Mac, syncBuffersForOutput 45 must be called before the transfer. 46 47 If the transfer will cause data to be recieve by the Mac, syncBuffersForInput 48 must be called after the transfer. 49 50 This class calculates the new segmentation only once when it is created. 51 Any changes to the structure of the original memory descriptor will render 52 this one useless. It must be released and a new IOFireWireSBP2LSIWorkaroundDescriptor 53 can be created. 54 55 LSI Bridge Workaround Algorithm Details 56 57 Goals: 58 1. Avoid LSI Logic "< 16 byte" bug - prevent any data packet smaller than 16 bytes 59 2. Minimize double-buffering 60 3. Support non-multiple-of-512-byte devices, e.g. CD Audio 61 62 Solution: 63 Write a page table such that the bridge will nor use packets smaller than 16 bytes. 64 In other words, rearrange the memory descriptor to avoid the bug, and do it such 65 that the SBP-2 layer will not break up a segment (du ro the 64k-1 limit) and 66 re-introduces the problem 67 68 SBP-2 defines the kFWSBP2MaxPageClusterSize constant. We simply make sure 69 none of our segments are larger than this size and SBP-2 will not break them 70 up when it writes the SBP-2 page table. 71 72 Notes: 73 - Some double buffering is unavoidable. Discontiguous pages may yield page 74 fragments at the start or end of the buffer (or both, with non-512x buffers). 75 solution uses less than 33 bytes of double-buffer per segment in original 76 memory descriptor. 77 - If driver must break up IO to meet ATA limit of 255 (250?) blocks, assume 78 the driver does this at a higher level (before applying workaround). 79 - It is expected that the original memory descriptor has been prepared (wired) 80*/ 81 82class IOFireWireSBP2LSIWorkaroundDescriptor : public IOGeneralMemoryDescriptor 83{ 84 OSDeclareDefaultStructors(IOFireWireSBP2LSIWorkaroundDescriptor) 85 86 friend class IOFireWireSBP2LSIRange; 87 88protected: 89 90 // reserved for future use 91 struct ExpansionData { }; 92 ExpansionData *reserved; 93 94 bool fFixedCapacity; // for both allocators 95 96 ////////////////////////////////////// 97 // for range allocator 98 99 OSArray * fPermanentRanges; 100 UInt32 fAllocatedRangesCount; 101 102 virtual IOReturn rangeAllocatorInitialize( UInt32 rangeCount ); 103 virtual void rangeAllocatorDeallocateAllRanges( void ); 104 virtual IOFireWireSBP2LSIRange * rangeAllocatorNewRange( void ); 105 virtual void rangeAllocatorFree( void ); 106 107 ////////////////////////////////////// 108 // for buffer allocator 109 110 OSArray * fBufferDescriptors; 111 UInt32 fPermanentPages; 112 IOByteCount fAllocatedBytesCount; 113 114 virtual IOReturn bufferAllocatorInitialize( IOByteCount requestedBufferSize ); 115 virtual void bufferAllocatorDeallocateAllBuffers( void ); 116 virtual void * bufferAllocatorNewBuffer( IOPhysicalAddress * address ); 117 virtual void bufferAllocatorFree( void ); 118 119 ////////////////////////////////////// 120 // for range table allocator 121 122 IOPhysicalRange * fRangeTable; 123 IOByteCount fRangeTableSize; 124 125 virtual IOReturn rangeTableAllocatorInitialize( UInt32 requestedBufferSize ); 126 virtual IOPhysicalRange * rangeTableAllocatorNewTable( UInt32 entries ); 127 virtual void rangeTableAllocatorFree( void ); 128 129 ////////////////////////////////////// 130 // for workaround 131 132 IOMemoryDescriptor * fOriginalDesc; 133 OSArray * fRanges; 134 IOByteCount fOffset; 135 IOByteCount fLength; 136 IODirection fDirection; 137 138 139 virtual bool initWithCapacity 140 ( UInt32 permanentRanges, IOByteCount permanentBufferSpace, bool fixedCapacity ); 141 142 virtual void free(); 143 144 virtual IOReturn resetToInitialCapacity( void ); 145 virtual IOReturn initializeRangesArray( void ); 146 virtual IOReturn recalculateSmallSegments( void ); 147 virtual IOReturn splitLargeSegments( void ); 148 virtual IOReturn resegmentOddLengthSegments( void ); 149 virtual IOReturn initializeBuffers( void ); 150 151 virtual bool initWithAddress( void * address, /* not supported */ 152 IOByteCount withLength, 153 IODirection withDirection ); 154 155 virtual bool initWithAddress( vm_address_t address, /* not supported */ 156 IOByteCount withLength, 157 IODirection withDirection, 158 task_t withTask ); 159 160 virtual bool initWithPhysicalAddress( 161 IOPhysicalAddress address, /* not supported */ 162 IOByteCount withLength, 163 IODirection withDirection ); 164 165 virtual bool initWithPhysicalRanges( 166 IOPhysicalRange * ranges, /* not supported */ 167 UInt32 withCount, 168 IODirection withDirection, 169 bool asReference = false ); 170 171 virtual bool initWithRanges( IOVirtualRange * ranges, /* not supported */ 172 UInt32 withCount, 173 IODirection withDirection, 174 task_t withTask, 175 bool asReference = false ); 176 177public: 178 179 // static factory methods and intializers 180 181 // 182 // create a new instance 183 // 184 185 186 /*! 187 @function withDescriptor 188 @abstract Creates a new IOFireWireSBP2LSIWorkaroundDescriptor. 189 @discussion Create a IOFireWireSBP2LSIWorkaroundDescriptor with no permanent capacity then 190 inits it the given descriptor. This is basicly a short cut for calling 191 withCapacity( 0, 0, false) and the initWithDescriptor() 192 @param desc Original memory descriptor. 193 @param offset Offset of data to "fix" in bytes from beginning of descriptor. 194 @param len Length of data in bytes to "fix" 195 @param direction IODirection of data transfer. 196 @result Returns a new IOFireWireSBP2LSIWorkaroundDescriptor if successful. 197 */ 198 199 static IOFireWireSBP2LSIWorkaroundDescriptor * withDescriptor 200 ( IOMemoryDescriptor * desc, IOByteCount offset = 0, 201 IOByteCount len = 0, IODirection direction = kIODirectionOutIn ); 202 203 // initialize with descriptor 204 205 /*! 206 @function initWithDescriptor 207 @abstract Initialize an IOFireWireSBP2LSIWorkaroundDescriptor with the given descriptor. 208 @discussion Initialize the workaround descriptor with the given descriptor. 209 @param desc Original memory descriptor. 210 @param offset Offset of data to "fix" in bytes from beginning of descriptor. 211 @param len Length of data in bytes to "fix" 212 @param direction IODirection of data transfer. 213 @result Returns true if the initialization was successful. 214 */ 215 216 virtual bool initWithDescriptor( IOMemoryDescriptor * desc, IOByteCount offset = 0, 217 IOByteCount len = 0, IODirection direction = kIODirectionOutIn ); 218 219 220 /////////////////////////////////// 221 222 223 /*! 224 @function withCapacity 225 @abstract Create a new descriptor with possibly a permanent capacity. 226 @discussion Create and IOFireWireSBP2LSIWorkaroundDescriptor with a permanent fixed capacity. 227 You should call initWithDescriptor afterward. permanentRanges is number of ranges to keep 228 permanently allocated for use by the algorithm. If fixedCapacity is false additional ranges 229 may be allocated and deallocated dyanmicly if needed. The algorithm may require more or less 230 ranges than either the original descriptor or the final fixed may decriptor contain. 231 permanentBufferSpace is the number of bytes of permanent buffer to keep arround. If fixedCapacity 232 is false additional buffer space may be allocated and deallocated dynamically. permanentBufferSpace 233 should generally be set to 32 * maximum number of ranges. fixedCapacity is a flag indicating 234 whether dynamic allocations are allowed. When making decisions about the maximum amount of 235 buffer space to keep around, it should be noted tha the maximum number of ranges maybe different 236 from permanentRanges if fixedCapcity is false. 237 @param permanentRanges Count of permanent ranges. 238 @param permanentBufferSpace Byte count of permanent buffers. 239 @param fixedCapacity bool indicating if dynamic allocations can be made. 240 @result Returns true if the initialization was successful. 241 */ 242 243 static IOFireWireSBP2LSIWorkaroundDescriptor * withCapacity 244 ( UInt32 permanentRanges, IOByteCount permanentBufferSpace, bool fixedCapacity ); 245 246 247 /////////////////////////////////// 248 249 // 250 // manipulate buffers for IO 251 // 252 253 /*! 254 @function syncBuffersForOutput 255 @abstract Synchronize the buffers for output. 256 @discussion Since double buffering may be invovled in the workaround. The driver needs to 257 indicate when these buffers should be syncronized with the original descriptor. For data 258 that will be output syncBuffersForOutput should be called before submiting the ORB. 259 @result Returns kIOReturnSuccess if sync was successful. 260 */ 261 262 virtual IOReturn syncBuffersForOutput( void ); // call before output 263 264 /*! 265 @function syncBuffersForInput 266 @abstract Synchronize the buffers for input. 267 @discussion Since double buffering may be invovled in the workaround. The driver needs to 268 indicate when these buffers should be syncronized with the original descriptor. For data 269 that will be input syncBuffersForOutput should be called after receiving completion status 270 for the ORB. 271 @result Returns kIOReturnSuccess if sync was successful. 272 */ 273 274 virtual IOReturn syncBuffersForInput( void ); // call after input 275 276private: 277 278 OSMetaClassDeclareReservedUnused(IOFireWireSBP2LSIWorkaroundDescriptor, 0); 279 OSMetaClassDeclareReservedUnused(IOFireWireSBP2LSIWorkaroundDescriptor, 1); 280 OSMetaClassDeclareReservedUnused(IOFireWireSBP2LSIWorkaroundDescriptor, 2); 281 OSMetaClassDeclareReservedUnused(IOFireWireSBP2LSIWorkaroundDescriptor, 3); 282 OSMetaClassDeclareReservedUnused(IOFireWireSBP2LSIWorkaroundDescriptor, 4); 283 OSMetaClassDeclareReservedUnused(IOFireWireSBP2LSIWorkaroundDescriptor, 5); 284 OSMetaClassDeclareReservedUnused(IOFireWireSBP2LSIWorkaroundDescriptor, 6); 285 OSMetaClassDeclareReservedUnused(IOFireWireSBP2LSIWorkaroundDescriptor, 7); 286 OSMetaClassDeclareReservedUnused(IOFireWireSBP2LSIWorkaroundDescriptor, 8); 287 288}; 289 290#endif 291 292#endif 293