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