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#include <IOKit/sbp2/IOFireWireSBP2ORB.h>
24#include <IOKit/sbp2/IOFireWireSBP2Login.h>
25#include <IOKit/sbp2/IOFireWireSBP2LUN.h>
26#include "FWDebugging.h"
27
28#define FIREWIREPRIVATE
29#include <IOKit/firewire/IOFireWireController.h>
30#undef FIREWIREPRIVATE
31
32#include <IOKit/firewire/IOFWSimpleContiguousPhysicalAddressSpace.h>
33
34OSDefineMetaClassAndStructors( IOFireWireSBP2ORB, IOCommand );
35
36OSMetaClassDefineReservedUnused(IOFireWireSBP2ORB, 0);
37OSMetaClassDefineReservedUnused(IOFireWireSBP2ORB, 1);
38OSMetaClassDefineReservedUnused(IOFireWireSBP2ORB, 2);
39OSMetaClassDefineReservedUnused(IOFireWireSBP2ORB, 3);
40OSMetaClassDefineReservedUnused(IOFireWireSBP2ORB, 4);
41OSMetaClassDefineReservedUnused(IOFireWireSBP2ORB, 5);
42OSMetaClassDefineReservedUnused(IOFireWireSBP2ORB, 6);
43OSMetaClassDefineReservedUnused(IOFireWireSBP2ORB, 7);
44OSMetaClassDefineReservedUnused(IOFireWireSBP2ORB, 8);
45
46enum
47{
48	kFWSBP2CommandMaxPacketSizeOverride			= (1 << 12)
49};
50
51// initWithLogin
52//
53// initializer
54
55bool IOFireWireSBP2ORB::initWithLogin( IOFireWireSBP2Login * login )
56{
57    bool res 			= true;
58    fLogin 				= login;
59    fLUN				= getFireWireLUN();
60    fUnit 				= getFireWireUnit();
61    fControl			= fUnit->getController();
62
63    // these should already be zeroed
64
65    fTimeoutTimerSet				= false;
66    fRefCon							= NULL;
67    fBufferAddressSpaceAllocated 	= false;
68    fBufferDescriptor 				= NULL;
69    fMaxPayloadSize					= 0;
70    fCommandFlags					= 0;
71    fTimeoutDuration				= 0;
72	fDMACommand						= NULL;
73	fConstraintOptions				= 0;
74    // init super
75   if( !IOCommand::init() )
76        return false;
77
78    IOReturn status = allocateResources();
79    if( status != kIOReturnSuccess )
80        res = false;
81
82    return res;
83}
84
85// allocateResources
86//
87// create orb and pageTable
88
89IOReturn IOFireWireSBP2ORB::allocateResources( void )
90{
91     IOReturn status = kIOReturnSuccess;
92
93	status = setBufferConstraints( kFWSBP2MaxPageClusterSize, 1, 0 );
94
95//	IOLog("IOFireWireSBP2ORB::allocateResources - setBufferConstraints, status = 0x%08lx\n", status );
96    //
97    // create ORB
98    //
99
100	if( status == kIOReturnSuccess )
101    {
102		// calculate orb size
103		UInt32 orbSize = sizeof(FWSBP2ORB) - 4 + fLogin->getMaxCommandBlockSize();
104		status = allocateORB( orbSize );
105	}
106
107//	IOLog("IOFireWireSBP2ORB::allocateResources - allocateORB, status = 0x%08lx\n", status );
108
109	//
110	// create page table
111	//
112
113	if( status == kIOReturnSuccess )
114    {
115        status = allocatePageTable( PAGE_SIZE / sizeof(FWSBP2PTE) );  // default size
116	}
117
118//	IOLog("IOFireWireSBP2ORB::allocateResources - allocatePageTable, status = 0x%08lx\n", status );
119
120	//
121	// create timer
122	//
123
124	if( status == kIOReturnSuccess )
125	{
126        status = allocateTimer();
127    }
128
129    //
130    // clean up on error
131    //
132
133    if( status != kIOReturnSuccess )
134    {
135        deallocateTimer();
136        deallocateORB();
137        deallocatePageTable();
138    }
139
140//	IOLog("IOFireWireSBP2ORB::allocateResources - status = 0x%08lx\n", status );
141
142    return status;
143}
144
145void IOFireWireSBP2ORB::release() const
146{
147	if( getRetainCount() >= 2 )
148		IOCommand::release(2);
149}
150
151void IOFireWireSBP2ORB::free( void )
152{
153    FWKLOG(( "IOFireWireSBP2ORB<%p> : free\n", this ));
154
155    removeORB( this );
156
157    deallocateTimer();
158    deallocatePageTable();
159    deallocateBufferAddressSpace();
160	deallocateORB();
161
162    IOCommand::free();
163}
164
165//////////////////////////////////////////////////////////////////////
166// ORB
167//
168
169// allocateORB
170//
171//
172
173IOReturn IOFireWireSBP2ORB::allocateORB( UInt32 orbSize )
174{
175	IOReturn	status = kIOReturnSuccess;
176
177	IOFWSimpleContiguousPhysicalAddressSpace * physical_space;
178	if( status == kIOReturnSuccess )
179    {
180        physical_space = fUnit->createSimpleContiguousPhysicalAddressSpace( orbSize, kIODirectionOut );
181     	if( physical_space == NULL )
182        	status = kIOReturnNoMemory;
183    }
184
185//	IOLog( "IOFireWireSBP2ORB::allocateORB - 1 status = 0x%08lx\n", status );
186
187	if( status == kIOReturnSuccess )
188	{
189		fORBPhysicalAddressSpace = (IOFWAddressSpace*)physical_space;
190		fORBDescriptor = physical_space->getMemoryDescriptor();
191		fORBPhysicalAddress = physical_space->getFWAddress();
192		fORBBuffer = (FWSBP2ORB *)physical_space->getVirtualAddress();
193	}
194
195//	IOLog( "IOFireWireSBP2ORB::allocateORB - 2 status = 0x%08lx\n", status );
196
197	if( status == kIOReturnSuccess )
198    {
199        status = fORBPhysicalAddressSpace->activate();
200    }
201
202//	IOLog( "IOFireWireSBP2ORB::allocateORB - 3 status = 0x%08lx\n", status );
203
204    if( status == kIOReturnSuccess )
205    {
206		//zzz shouldn't be able to write to ORBs
207		//zzz of course when running via the physical unit there's nothing to stop writes anyway
208
209        fORBPseudoAddressSpace = IOFWPseudoAddressSpace::simpleRW( fControl, &fORBPseudoAddress, fORBDescriptor );
210       	if ( fORBPseudoAddressSpace == NULL )
211        	status = kIOReturnNoMemory;
212    }
213
214//	IOLog( "IOFireWireSBP2ORB::allocateORB - 4 status = 0x%08lx\n", status );
215
216    if( status == kIOReturnSuccess )
217    {
218        status = fORBPseudoAddressSpace->activate();
219
220		FWKLOG( ( "IOFireWireSBP2ORB<%p> : created orb at phys: 0x%04lx.%08lx psuedo: 0x%04lx.%08lx of size %d\n",
221				this, fORBPhysicalAddress.addressHi, fORBPhysicalAddress.addressLo, fORBPseudoAddress.addressHi, fORBPseudoAddress.addressLo, orbSize ) );
222    }
223
224//	IOLog( "IOFireWireSBP2ORB::allocateORB - 5 status = 0x%08lx\n", status );
225
226	if( status != kIOReturnSuccess )
227	{
228		deallocateORB();
229	}
230
231	return status;
232}
233
234void IOFireWireSBP2ORB::deallocateORB( void )
235{
236    IOReturn status = kIOReturnSuccess;
237
238	// deallocate physical address space
239    if( fORBPhysicalAddressSpace != NULL && status == kIOReturnSuccess )
240    {
241        fORBPhysicalAddressSpace->deactivate();
242        fORBPhysicalAddressSpace->release();
243		fORBPhysicalAddressSpace = NULL;
244    }
245
246	// deallocate pseudo address space
247    if( fORBPseudoAddressSpace != NULL && status == kIOReturnSuccess )
248    {
249        fORBPseudoAddressSpace->deactivate();
250        fORBPseudoAddressSpace->release();
251		fORBPseudoAddressSpace = NULL;
252	}
253}
254
255
256////////////////////////////////////////////////////////////////////
257// command execution
258//
259
260// calculateTransferSizeLog
261//
262//
263
264UInt32 IOFireWireSBP2ORB::calculateTransferSizeLog( bool * clipping )
265{
266    //
267    // calculate transfer size
268    //
269
270	UInt32  transferSizeBytes;
271    *clipping = false;
272    transferSizeBytes = 4096; // start at max packet size
273
274	bool size_override = (fCommandFlags & kFWSBP2CommandMaxPacketSizeOverride);
275
276	if( !size_override )
277	{
278		// clip by ARMDMAMax for performance
279		UInt32 ARDMAMax = fLogin->getARDMMax();
280		if( (fCommandFlags & kFWSBP2CommandTransferDataFromTarget) &&	// if this is a read
281			(ARDMAMax != 0) )											// and we've got an ARDMA clip
282		{
283			transferSizeBytes = ARDMAMax;
284			*clipping = true;
285		}
286	}
287
288    // trim by max payload sizes
289    UInt32 loginMaxPayloadSize = fLogin->getMaxPayloadSize();
290    if( loginMaxPayloadSize != 0 && loginMaxPayloadSize < transferSizeBytes )
291        transferSizeBytes = loginMaxPayloadSize;
292
293    if( fMaxPayloadSize != 0 && fMaxPayloadSize < transferSizeBytes )
294        transferSizeBytes = fMaxPayloadSize;
295
296    // find the largest power of two less than or equal to transferSizeBytes/4
297    UInt32 transferSizeLog = 0;
298    while( (transferSizeBytes >= 8) && (transferSizeLog < 15) )
299    {
300        transferSizeBytes >>= 1;
301        transferSizeLog++;
302    }
303
304	if( !size_override )
305	{
306		// trim by maxPackLog
307		UInt32 maxPackLog = fUnit->maxPackLog(!(fCommandFlags & kFWSBP2CommandTransferDataFromTarget));
308		maxPackLog -= 2; // convert to quads
309		if( maxPackLog < transferSizeLog )
310		{
311			*clipping = true;
312			transferSizeLog = maxPackLog;
313		}
314	}
315	else
316	{
317		UInt32 maxPackLog = 7;
318
319		IOFWSpeed speed = fUnit->FWSpeed();
320		switch( speed )
321		{
322			case kFWSpeed800MBit:
323				maxPackLog = 10;
324				break;
325
326			case kFWSpeed400MBit:
327				maxPackLog = 9;
328				 break;
329
330			case kFWSpeed200MBit:
331				maxPackLog = 8;
332				break;
333
334			default:
335				break;
336		 }
337
338		if( maxPackLog < transferSizeLog )
339			transferSizeLog = maxPackLog;
340	}
341
342
343	return transferSizeLog;
344}
345
346// prepareORBForExecution
347//
348//
349
350void IOFireWireSBP2ORB::prepareORBForExecution( void )
351{
352
353    // make sure orb points nowhere
354    fORBBuffer->nextORBAddressHi = OSSwapHostToBigInt32(0x80000000);
355    fORBBuffer->nextORBAddressLo = OSSwapHostToBigInt32(0x00000000);
356
357    // update data descriptor with local node ID
358    UInt32 generation;	// Hmm, shouldn't this be checked?
359    UInt16 unitNode;
360    UInt16 localNode;
361    fUnit->getNodeIDGeneration( generation, unitNode, localNode );
362    fORBBuffer->dataDescriptorHi &= OSSwapHostToBigInt32(0x0000ffff);
363    fORBBuffer->dataDescriptorHi |= OSSwapHostToBigInt32(((UInt32)localNode) << 16);
364
365    // clear options
366    fORBBuffer->options &= OSSwapHostToBigInt16(0x000f);
367
368    // mark for notify if requested
369    if( fCommandFlags & kFWSBP2CommandCompleteNotify )
370        fORBBuffer->options |= OSSwapHostToBigInt16(0x8000);
371
372    // mark ORB rq_fmt. if kFWSBP2CommandNormalORB is set, the zero is already in place.
373    // the driver is not supposed to set more than one of these flags
374    if( fCommandFlags & kFWSBP2CommandReservedORB )
375        fORBBuffer->options |= OSSwapHostToBigInt16(0x2000);
376
377    if( fCommandFlags & kFWSBP2CommandVendorORB )
378        fORBBuffer->options |= OSSwapHostToBigInt16(0x4000);
379
380    if( fCommandFlags & kFWSBP2CommandDummyORB )
381        fORBBuffer->options |= OSSwapHostToBigInt16(0x6000);
382
383    // mark as "read" if requested
384    if( fCommandFlags & kFWSBP2CommandTransferDataFromTarget )
385        fORBBuffer->options |= OSSwapHostToBigInt16(0x0800);
386
387    //
388    // set speed
389    //
390
391    IOFWSpeed speed = fUnit->FWSpeed();
392    switch( speed )
393    {
394		case kFWSpeed800MBit:
395			fORBBuffer->options |= OSSwapHostToBigInt16(0x0300);
396			break;
397
398        case kFWSpeed400MBit:
399            fORBBuffer->options |= OSSwapHostToBigInt16(0x0200);
400             break;
401
402        case kFWSpeed200MBit:
403            fORBBuffer->options |= OSSwapHostToBigInt16(0x0100);
404            break;
405
406        default:
407            // default options is |= 0x0000
408            break;
409     }
410
411	 UInt32 transferSizeLog;
412	 bool clipping;
413
414	transferSizeLog = calculateTransferSizeLog( &clipping );
415
416	// set transfer size, actual max is 2 ^ (size + 2) bytes (or 2 ^ size quads)
417	fORBBuffer->options |= OSSwapHostToBigInt16(transferSizeLog << 4);
418}
419
420// prepareFastStartPacket
421//
422//
423
424void IOFireWireSBP2ORB::prepareFastStartPacket( IOBufferMemoryDescriptor * descriptor )
425{
426	UInt32 offset = 16;
427	UInt32 length = descriptor->getLength();
428
429	//
430	// write orb
431	//
432
433	UInt32 orbLength = fORBDescriptor->getLength();
434	if( length < (offset + orbLength) )
435	{
436		IOLog( "IOFireWireSBP2ORB<0x%08lx>::prepareFastStartPacket - fast start packet length (%d) < orblength (%d) + 16\n", this, length, orbLength );
437	}
438	descriptor->writeBytes( offset, fORBBuffer, orbLength );
439
440	offset += orbLength;
441
442	//
443	// write page table
444	//
445
446	FWSBP2PTE pte;
447	UInt32 pageTableOffset = 0;
448	UInt32 pageTableSize = fPTECount * sizeof(FWSBP2PTE);
449
450	while( offset < length && pageTableOffset < pageTableSize )
451	{
452		if( (length - offset) < sizeof(FWSBP2PTE) )
453		{
454			IOLog( "IOFireWireSBP2ORB<0x%08lx>::prepareFastStartPacket - fast start packet not full, yet pte doesn't fit\n", this );
455			break;
456		}
457
458		fPageTableDescriptor->readBytes( pageTableOffset, &pte, sizeof(FWSBP2PTE) );
459		descriptor->writeBytes( offset, &pte, sizeof(FWSBP2PTE) );
460
461
462		offset += sizeof(FWSBP2PTE);
463		pageTableOffset += sizeof(FWSBP2PTE);
464	}
465
466	if( offset > length )
467	{
468		IOLog( "IOFireWireSBP2ORB<0x%08lx>::prepareFastStartPacket - offset > length\n", this );
469	}
470
471	//
472	// trim descriptor size if necessary
473	//
474
475	descriptor->setLength( offset );
476}
477
478#if 0
479IOReturn checkMemoryInRange( IOMemoryDescriptor * memory, UInt64 mask, IODMACommand * dma_command_arg )
480{
481	IOReturn status = kIOReturnSuccess;
482
483	if( memory == NULL )
484	{
485		status = kIOReturnBadArgument;
486	}
487
488	//
489	// setup
490	//
491
492	bool memory_prepared = false;
493	if( dma_command_arg == NULL )
494	{
495		if( status == kIOReturnSuccess )
496		{
497			status = memory->prepare( kIODirectionInOut );
498		}
499
500		if( status == kIOReturnSuccess )
501		{
502			memory_prepared = true;
503		}
504	}
505
506
507	UInt64 length = 0;
508
509	if( status == kIOReturnSuccess )
510	{
511		length = memory->getLength();
512	}
513
514	IODMACommand * dma_command = dma_command_arg;
515	bool dma_command_prepared = false;
516	if( dma_command == NULL )
517	{
518		if( status == kIOReturnSuccess )
519		{
520			dma_command = IODMACommand::withSpecification(
521													kIODMACommandOutputHost64,		// segment function
522													64,								// max address bits
523													0,								// max segment size
524													(IODMACommand::MappingOptions)(IODMACommand::kMapped | IODMACommand::kIterateOnly),		// IO mapped & don't bounce buffer
525													0,							// max transfer size
526													0,								// page alignment
527													NULL,							// mapper
528													NULL );							// refcon
529			if( dma_command == NULL )
530				status = kIOReturnError;
531
532		}
533
534		if( status == kIOReturnSuccess )
535		{
536			// set memory descriptor and don't prepare it
537			status = dma_command->setMemoryDescriptor( memory, false );
538		}
539
540		if( status == kIOReturnSuccess )
541		{
542			status = dma_command->prepare( 0, length, true );
543		}
544
545		if( status == kIOReturnSuccess )
546		{
547			dma_command_prepared = true;
548		}
549	}
550	else
551	{
552#if 0
553	dma_command->setMemoryDescriptor( memory, false );
554	dma_command->prepare( 0, length, true );
555	dma_command_prepared = true;
556#endif
557	}
558	//
559	// check ranges
560	//
561
562	if( status == kIOReturnSuccess )
563	{
564		IOLog( "checkSegments - length = %d\n", length  );
565
566		UInt64 offset = 0;
567		while( (offset < length) && (status == kIOReturnSuccess) )
568		{
569			IODMACommand::Segment64 segments[10];
570			UInt32 num_segments = 10;
571			status = dma_command->gen64IOVMSegments( &offset, segments, &num_segments );
572			if( status == kIOReturnSuccess )
573			{
574				for( UInt32 i = 0; i < num_segments; i++ )
575				{
576					IOLog( "checkSegments - offset = 0x%016llx segments[%d].fIOVMAddr = 0x%016llx, fLength = %d\n", offset, i, segments[i].fIOVMAddr, segments[i].fLength  );
577
578					if( (segments[i].fIOVMAddr & (~mask)) )
579					{
580						IOLog( "checkSegmentsFailed - 0x%016llx & 0x%016llx\n", segments[i].fIOVMAddr, mask );
581						status = kIOReturnNotPermitted;
582					//	break;
583					}
584				}
585			}
586			else
587			{
588				IOLog( "checkSegments - offset = %lld 0x%08lx\n", offset, status  );
589			}
590		}
591	}
592
593	//
594	// clean up
595	//
596
597	if( dma_command_prepared )
598	{
599		dma_command->complete();
600		dma_command_prepared = false;
601	}
602
603	if( dma_command && (dma_command_arg == NULL) )
604	{
605		dma_command->release();
606		dma_command = NULL;
607	}
608
609	if( memory_prepared )
610	{
611		memory->complete();
612		memory_prepared = false;
613	}
614
615	return status;
616}
617
618#endif
619
620//////////////////////////////////////////////////////////////////////////////////////////
621// timeouts
622//
623
624IOReturn IOFireWireSBP2ORB::allocateTimer( void )
625{
626    IOReturn status = kIOReturnSuccess;
627
628    if( status == kIOReturnSuccess )
629	{
630		fTimeoutCommand = (IOFWDelayCommand*)fControl->createDelayedCmd( fTimeoutDuration * 1000,
631																		 IOFireWireSBP2ORB::orbTimeoutStatic,
632																		 this );
633		if( fTimeoutCommand == NULL )
634			status = kIOReturnError;
635	}
636
637	if( status != kIOReturnSuccess )
638	{
639		deallocateTimer();
640	}
641
642    return status;
643}
644
645void IOFireWireSBP2ORB::deallocateTimer( void )
646{
647    // cancel timer
648    if( fTimeoutTimerSet )
649        cancelTimer();
650
651	if( fTimeoutCommand )
652	{
653		fTimeoutCommand->release();
654		fTimeoutCommand = NULL;
655    }
656}
657
658// startTimer
659//
660//
661
662void IOFireWireSBP2ORB::startTimer( void )
663{
664    //
665    // set timeout if necessary
666    //
667
668    if( fCommandFlags & kFWSBP2CommandCompleteNotify )
669	{
670		fInProgress = true;
671
672		if( fTimeoutDuration != 0 )
673		{
674			IOReturn ORBtimeoutSubmitStatus;
675
676			FWKLOG( ( "IOFireWireSBP2ORB<%p> : set timeout\n", this ) );
677
678			fTimeoutTimerSet = true;
679			ORBtimeoutSubmitStatus = fTimeoutCommand->submit();
680
681			FWPANICASSERT( ORBtimeoutSubmitStatus == kIOReturnSuccess );
682		}
683	}
684}
685
686// isTimerSet
687//
688//
689
690bool IOFireWireSBP2ORB::isTimerSet( void )
691{
692    return fInProgress;
693}
694
695// cancelTimer
696//
697//
698
699void IOFireWireSBP2ORB::cancelTimer( void )
700{
701    FWKLOG( ( "IOFireWireSBP2ORB<%p> : cancel timer\n", this ) );
702
703    // cancel timer
704    if( fTimeoutTimerSet )
705	{
706        fTimeoutCommand->cancel( kIOReturnAborted );
707	}
708	else
709	{
710		fInProgress = false;
711	}
712}
713
714// orb timeout handler
715//
716// static wrapper & virtual method
717
718void IOFireWireSBP2ORB::orbTimeoutStatic( void *refcon, IOReturn status, IOFireWireBus *bus, IOFWBusCommand *fwCmd )
719{
720    ((IOFireWireSBP2ORB*)refcon)->orbTimeout( status, bus, fwCmd );
721}
722
723void IOFireWireSBP2ORB::orbTimeout( IOReturn status, IOFireWireBus *bus, IOFWBusCommand *fwCmd )
724{
725    fTimeoutTimerSet = false;
726    fInProgress = false;
727
728    if( status == kIOReturnTimeout )
729    {
730        FWKLOG( ( "IOFireWireSBP2ORB<%p> : orb timeout\n", this ) );
731		sendTimeoutNotification( this );
732    }
733    else
734    {
735        FWKLOG( ( "IOFireWireSBP2ORB<%p> : orb timeout cancelled\n", this ) );
736    }
737}
738
739//////////////////////////////////////////////////////////////////////
740// page table
741//
742
743// allocatePageTable
744//
745//
746
747IOReturn IOFireWireSBP2ORB::allocatePageTable( UInt32 entryCount )
748{
749	IOReturn	status = kIOReturnSuccess;
750
751	deallocatePageTable();
752
753	//
754    // create page table
755    //
756
757    // allocate mem for page table
758    fPageTableSize = sizeof(FWSBP2PTE) * entryCount;
759	UInt64 phys_mask = fControl->getFireWirePhysicalAddressMask();
760	fPageTableDescriptor = IOBufferMemoryDescriptor::inTaskWithPhysicalMask( kernel_task, kIODirectionOutIn, fPageTableSize, phys_mask );
761    if( fPageTableDescriptor == NULL )
762        status =  kIOReturnNoMemory;
763
764    if( status == kIOReturnSuccess )
765    {
766        fPageTableDescriptor->setLength( fPageTableSize );
767	}
768
769	bool dma_command_prepared = false;
770	IODMACommand * dma_command = NULL;
771	if( status == kIOReturnSuccess )
772    {
773		dma_command = IODMACommand::withSpecification(
774												kIODMACommandOutputHost64,		// segment function
775												48,								// max address bits
776												fPageTableSize,					// max segment size
777												(IODMACommand::MappingOptions)(IODMACommand::kMapped | IODMACommand::kIterateOnly),		// IO mapped & don't bounce buffer
778												fPageTableSize,					// max transfer size
779												0,								// no alignment
780												NULL,							// mapper
781												NULL );							// refcon
782		if( dma_command == NULL )
783			status = kIOReturnNoMemory;
784	}
785
786//	IOLog( "IOFireWireSBP2ORB::allocatePageTable (1) - status = 0x%08lx\n", status );
787
788	if( status == kIOReturnSuccess )
789	{
790		// set memory descriptor and don't prepare it
791		status = dma_command->setMemoryDescriptor( fPageTableDescriptor, false );
792	}
793
794	if( status == kIOReturnSuccess )
795	{
796		status = dma_command->prepare( 0, fPageTableSize, true );
797	}
798
799	if( status == kIOReturnSuccess )
800	{
801		dma_command_prepared = true;
802	}
803
804//	IOLog( "IOFireWireSBP2ORB::allocatePageTable (2) - status = 0x%08lx\n", status );
805
806	IODMACommand::Segment64 segment;
807	UInt32 numSegments = 1;
808	if( status == kIOReturnSuccess )
809	{
810		UInt64 offset = 0;
811		status = dma_command->gen64IOVMSegments( &offset, &segment, &numSegments );
812	}
813
814	if( status == kIOReturnSuccess )
815	{
816		if( numSegments != 1 )
817		{
818			status = kIOReturnNoMemory;
819		}
820	}
821
822//	IOLog( "IOFireWireSBP2ORB::allocatePageTable (3) - status = 0x%08lx\n", status );
823
824	if( status == kIOReturnSuccess )
825	{
826		fPageTablePhysicalLength = segment.fLength;
827		fPageTablePhysicalAddress.nodeID = 0x0000;		// invalid node id
828		fPageTablePhysicalAddress.addressHi = (segment.fIOVMAddr >> 32) & 0x000000000000ffffULL;
829		fPageTablePhysicalAddress.addressLo = segment.fIOVMAddr & 0x00000000ffffffffULL;
830	}
831
832	if( dma_command_prepared )
833	{
834		dma_command->complete();
835		dma_command_prepared = false;
836	}
837
838	if( dma_command )
839	{
840		dma_command->release();
841		dma_command = NULL;
842	}
843
844//	IOLog( "IOFireWireSBP2ORB::allocatePageTable (1) - status = 0x%08lx segment = 0x%016llx len = %d\n", status, segment.fIOVMAddr, segment.fLength );
845
846    // allocate and register a physical address space for the page table
847
848    if( status == kIOReturnSuccess )
849    {
850        fPageTablePhysicalAddressSpace = fUnit->createPhysicalAddressSpace( fPageTableDescriptor );
851       	if ( fPageTablePhysicalAddressSpace == NULL )
852        	status = kIOReturnNoMemory;
853    }
854
855    if( status == kIOReturnSuccess )
856    {
857        status = fPageTablePhysicalAddressSpace->activate();
858    }
859
860    // allocate and register a pseudo address space for the page table
861
862    if( status == kIOReturnSuccess )
863    {
864		//zzz shouldn't be able to write to the page table
865		//zzz of course when run physically there's nothing to stop writes anyway
866
867        fPageTablePseudoAddressSpace = IOFWPseudoAddressSpace::simpleRW( fControl, &fPageTablePseudoAddress, fPageTableDescriptor );
868       	if ( fPageTablePseudoAddressSpace == NULL )
869        	status = kIOReturnNoMemory;
870    }
871
872    if( status == kIOReturnSuccess )
873    {
874        status = fPageTablePseudoAddressSpace->activate();
875    }
876
877	if( status != kIOReturnSuccess )
878	{
879		deallocatePageTable();
880	}
881
882	return status;
883}
884
885// deallocatePageTable
886//
887//
888
889void IOFireWireSBP2ORB::deallocatePageTable( void )
890{
891    IOReturn status = kIOReturnSuccess;
892
893	// deallocate physical address space
894    if( fPageTablePhysicalAddressSpace != NULL && status == kIOReturnSuccess )
895    {
896        fPageTablePhysicalAddressSpace->deactivate();
897        fPageTablePhysicalAddressSpace->release();
898		fPageTablePhysicalAddressSpace = NULL;
899    }
900
901	// deallocate pseudo address space
902    if( fPageTablePseudoAddressSpace != NULL && status == kIOReturnSuccess )
903    {
904        fPageTablePseudoAddressSpace->deactivate();
905        fPageTablePseudoAddressSpace->release();
906		fPageTablePseudoAddressSpace = NULL;
907	}
908
909    // free mem
910    if( fPageTableDescriptor != NULL )
911	{
912        fPageTableDescriptor->release();
913		fPageTableDescriptor = NULL;
914	}
915
916	fPageTableSize = 0;
917}
918
919// setBufferConstraints
920//
921//
922
923IOReturn IOFireWireSBP2ORB::setBufferConstraints( UInt64 maxSegmentSize, UInt32 alignment, UInt32 options )
924{
925	IOReturn status = kIOReturnSuccess;
926
927	if( fBufferAddressSpaceAllocated )
928	{
929		status = kIOReturnBusy;
930	}
931
932	if( status == kIOReturnSuccess )
933	{
934		fConstraintOptions = options;
935
936		deallocateBufferAddressSpace();
937
938		//
939		// create DMACommand
940		//
941
942		if( status == kIOReturnSuccess )
943		{
944			UInt32 address_bits = fControl->getFireWirePhysicalAddressBits();
945#if 0
946		// testing
947		//	address_bits = 29;
948#endif
949
950			UInt64 segment_size = maxSegmentSize;
951			if( (segment_size > kFWSBP2MaxPageClusterSize) || (segment_size == 0) )
952				segment_size = kFWSBP2MaxPageClusterSize;
953
954			fDMACommand = IODMACommand::withSpecification(
955													kIODMACommandOutputHost64,		// segment function
956													address_bits,					// max address bits
957													segment_size,					// max segment size
958													IODMACommand::kMapped,			// IO mapped & allow bounce buffering
959													0,								// max transfer size
960													alignment,						// alignment
961													NULL,							// mapper
962													NULL );							// refcon
963			if( fDMACommand == NULL )
964				status = kIOReturnError;
965		}
966	}
967
968	// allocate and register an address space for the buffers
969
970//	IOLog( "IOFireWireSBP2ORB::setBufferConstraints - (1) status = 0x%08lx\n", status );
971
972	if( status == kIOReturnSuccess )
973	{
974		fBufferAddressSpace = fUnit->createPhysicalAddressSpace( NULL );
975		if( fBufferAddressSpace == NULL )
976		{
977			status = kIOReturnNoMemory;
978		}
979	}
980
981//	IOLog( "IOFireWireSBP2ORB::setBufferConstraints - (2) status = 0x%08lx\n", status );
982
983	if( status == kIOReturnSuccess )
984	{
985		((IOFWPhysicalAddressSpace*)fBufferAddressSpace)->setDMACommand( fDMACommand );
986	}
987
988	return status;
989}
990
991// prepareBufferAddressSpace
992//
993//
994
995IOReturn IOFireWireSBP2ORB::prepareBufferAddressSpace( IOMemoryDescriptor * memoryDescriptor )
996{
997	if( fBufferAddressSpaceAllocated )
998	{
999		completeBufferAddressSpace();
1000	}
1001
1002	fBufferDescriptor = memoryDescriptor;
1003	fBufferDescriptor->retain();
1004
1005	((IOFWPhysicalAddressSpace*)fBufferAddressSpace)->setMemoryDescriptor( fBufferDescriptor );
1006	fBufferAddressSpace->activate();
1007
1008	if( fConstraintOptions & kFWSBP2ConstraintForceDoubleBuffer )
1009	{
1010		((IOFWPhysicalAddressSpace*)fBufferAddressSpace)->synchronize( IODMACommand::kForceDoubleBuffer | kIODirectionOut );
1011	}
1012
1013	fBufferAddressSpaceAllocated = true;
1014
1015	return kIOReturnSuccess;
1016}
1017
1018// completeBufferAddressSpace
1019//
1020//
1021
1022IOReturn IOFireWireSBP2ORB::completeBufferAddressSpace( void )
1023{
1024	if( fBufferAddressSpace )
1025	{
1026		fBufferAddressSpace->deactivate();
1027		((IOFWPhysicalAddressSpace*)fBufferAddressSpace)->setMemoryDescriptor( NULL );
1028	}
1029
1030	if( fBufferDescriptor )
1031	{
1032		fBufferDescriptor->release();
1033		fBufferDescriptor = NULL;
1034	}
1035
1036	fBufferAddressSpaceAllocated = false;
1037
1038	if( fORBBuffer )
1039	{
1040		fORBBuffer->dataDescriptorHi = 0;
1041		fORBBuffer->dataDescriptorLo = 0;
1042		fORBBuffer->options &= OSSwapHostToBigInt16(0xfff0); // no page table
1043		fORBBuffer->dataSize = 0;
1044	}
1045
1046	return kIOReturnSuccess;
1047}
1048
1049// deallocateBufferAddressSpace
1050//
1051//
1052
1053void IOFireWireSBP2ORB::deallocateBufferAddressSpace( void )
1054{
1055    fControl->closeGate();
1056
1057	fPTECount = 0;
1058
1059    if( fBufferAddressSpaceAllocated )
1060    {
1061		completeBufferAddressSpace();
1062	}
1063
1064	if( fBufferAddressSpace )
1065	{
1066		fBufferAddressSpace->release();
1067		fBufferAddressSpace = NULL;
1068	}
1069
1070	if( fDMACommand )
1071	{
1072		fDMACommand->release();
1073		fDMACommand = NULL;
1074	}
1075
1076	// no page table
1077	if( fORBBuffer )
1078	{
1079		fORBBuffer->dataDescriptorHi	= 0;
1080		fORBBuffer->dataDescriptorLo	= 0;
1081		fORBBuffer->options				&= OSSwapHostToBigInt16(0xfff0);
1082	// no page table
1083		fORBBuffer->dataSize			= 0;
1084	}
1085
1086	fPTECount = 0;
1087
1088    fControl->openGate();
1089}
1090
1091// setCommandBuffersAsRanges
1092//
1093// allocates and prepares a memory descriptor from given virtual ranges
1094// and then calls setCommandBuffers with the descriptor
1095
1096IOReturn IOFireWireSBP2ORB::setCommandBuffersAsRanges(  IOVirtualRange * ranges,
1097                                                        UInt32           withCount,
1098                                                        IODirection      withDirection,
1099                                                        task_t           withTask,
1100                                                        UInt32	         offset,
1101                                                        UInt32	         length )
1102{
1103    IOReturn			status = kIOReturnSuccess;
1104    IOMemoryDescriptor *	memory = NULL;
1105
1106	if( withCount == 0 )
1107	{
1108		status = kIOReturnBadArgument;
1109	}
1110
1111	IOAddressRange * address_ranges = NULL;
1112    if( status == kIOReturnSuccess )
1113	{
1114		IOAddressRange * address_ranges = IONew( IOAddressRange, withCount );
1115		if( address_ranges == NULL )
1116		{
1117			status = kIOReturnNoMemory;
1118		}
1119	}
1120
1121	if( status == kIOReturnSuccess )
1122	{
1123		for( uint32_t i = 0; i < withCount; i++ )
1124		{
1125			address_ranges[i].address = ranges[i].address;
1126			address_ranges[i].length = ranges[i].length;
1127		}
1128
1129		memory = IOMemoryDescriptor::withAddressRanges( address_ranges, withCount, withDirection, withTask );
1130        if( !memory )
1131            status = kIOReturnNoMemory;
1132    }
1133
1134	if( address_ranges )
1135	{
1136		IODelete( address_ranges, IOAddressRange, withCount );
1137		address_ranges = NULL;
1138	}
1139
1140    if( status == kIOReturnSuccess )
1141    {
1142        status = memory->prepare( withDirection );
1143    }
1144
1145    if( status == kIOReturnSuccess )
1146    {
1147        status = setCommandBuffers( memory, offset, length );
1148    }
1149
1150	if( memory )
1151	{
1152		memory->release();
1153	}
1154
1155    return status;
1156}
1157
1158// setCommandBuffersAsRanges64
1159//
1160//
1161
1162IOReturn IOFireWireSBP2ORB::setCommandBuffersAsRanges64(	IOAddressRange *	ranges,
1163															uint64_t			withCount,
1164															IODirection			withDirection,
1165															task_t				withTask,
1166															uint64_t			offset,
1167															uint64_t			length )
1168{
1169    IOReturn			status = kIOReturnSuccess;
1170    IOMemoryDescriptor *	memory = NULL;
1171
1172    if( status == kIOReturnSuccess )
1173    {
1174        memory = IOMemoryDescriptor::withAddressRanges( ranges, withCount, withDirection, withTask );
1175        if( !memory )
1176            status = kIOReturnNoMemory;
1177    }
1178
1179    if( status == kIOReturnSuccess )
1180    {
1181        status = memory->prepare( withDirection );
1182    }
1183
1184    if( status == kIOReturnSuccess )
1185    {
1186        status = setCommandBuffers( memory, offset, length );
1187    }
1188
1189	if( memory )
1190	{
1191		memory->release();
1192	}
1193
1194    return status;
1195
1196}
1197
1198// releaseCommandBuffers
1199//
1200// tell SBP2 that the IO is done and command buffers can be released
1201
1202IOReturn IOFireWireSBP2ORB::releaseCommandBuffers( void )
1203{
1204    return setCommandBuffers( NULL );
1205}
1206
1207// setCommandBuffers
1208//
1209// write a page table from the given memoryDecriptor
1210
1211IOReturn IOFireWireSBP2ORB::setCommandBuffers( IOMemoryDescriptor * memoryDescriptor, UInt32 offset, UInt32 length )
1212{
1213    IOReturn status = kIOReturnSuccess;
1214
1215	fControl->closeGate();
1216
1217    //
1218    // deallocate previous mapping
1219    //
1220
1221    // I obsolete the old address space even if we fail at mapping a new one
1222    // that seems like it would be the more expected behavior
1223
1224	completeBufferAddressSpace();
1225
1226	//
1227	// bail if no memory descriptor
1228	//
1229
1230    if( memoryDescriptor == NULL )
1231    {
1232		fControl->openGate();
1233
1234	//	IOLog( "IOFireWireSBP2ORB::setCommandBuffers status = 0x%08lx\n", status );
1235
1236		return kIOReturnSuccess;
1237	}
1238
1239#if 0
1240   	// memoryDescriptor is valid from here on
1241
1242	IOReturn check_status = checkMemoryInRange( memoryDescriptor, 0x000000001fffffff, NULL );
1243#endif
1244
1245	//
1246	// map buffers
1247	//
1248
1249	// allocate and register an address space for the buffers
1250
1251	if( status == kIOReturnSuccess )
1252	{
1253		status = prepareBufferAddressSpace( memoryDescriptor );
1254	}
1255
1256#if 0
1257	if( check_status != kIOReturnSuccess )
1258	{
1259		IOLog( "After prepare\n" );
1260		check_status = checkMemoryInRange( memoryDescriptor, 0x000000001fffffff, fDMACommand );
1261		IOLog( "After prepare = 0x%08lx\n", check_status );
1262	}
1263#endif
1264
1265   	//
1266   	// fix up length if necessary
1267   	//
1268
1269    if( status == kIOReturnSuccess )
1270    {
1271        // use memory descriptor's length if length = 0
1272
1273        if( length == 0 )
1274        {
1275            length = fDMACommand->getMemoryDescriptor()->getLength();
1276		}
1277
1278#if FWLOGGING
1279        // I occasionally get memory descriptors with bogus lengths
1280
1281        UInt32 tempLength = fDMACommand->getMemoryDescriptor()->getLength();
1282
1283		if(length != tempLength)
1284		{
1285        	FWKLOG( ( "IOFireWireSBP2ORB<%p> : ### buffer length = %d, memDescriptor length = %d ###\n", this, length, tempLength  ) );
1286        // length = tempLength;
1287		}
1288#endif
1289
1290	}
1291
1292    //
1293    // write page table
1294    //
1295
1296	UInt32 		pte = 0;
1297	UInt32		maxPageClipSize = kFWSBP2MaxPageClusterSize;
1298	UInt32		maxPackLog;
1299	bool clipping;
1300	UInt32 targetFlags = fLogin->fTarget->getTargetFlags();
1301
1302	maxPackLog = calculateTransferSizeLog( &clipping );
1303
1304	if( !(targetFlags & kIOFWSBP2DontUsePTPacketLimit) && clipping )
1305	{
1306		switch( maxPackLog )
1307		{
1308			case 10:
1309				maxPageClipSize = 4096;
1310				break;
1311
1312			case 9:
1313				maxPageClipSize = 2048;
1314				break;
1315
1316			case 8:
1317				maxPageClipSize = 1024;
1318				break;
1319
1320			default:
1321				maxPageClipSize = 512;
1322				break;
1323		}
1324
1325	}
1326
1327
1328	if( status == kIOReturnSuccess )
1329	{
1330		UInt32 	ptes_allocated = 0;
1331		bool 	done = false;
1332
1333		// algorithm is usually 1 pass, but may take 2
1334		// passes if we need to grow the page table
1335
1336		// we never shrink the page table
1337
1338		while( !done )
1339		{
1340			ptes_allocated = fPageTableSize / sizeof(FWSBP2PTE);
1341
1342			vm_size_t pos = offset;
1343
1344 			pte = 0;
1345
1346			while( pos < (length + offset) )
1347			{
1348	    		UInt64 	phys = 0;
1349   				UInt64 	lengthOfSegment = 0;
1350
1351				// get next segment
1352
1353				IODMACommand::Segment64 segment;
1354				UInt32 numSegments = 1;
1355				if( status == kIOReturnSuccess )
1356				{
1357					UInt64 dma_pos = pos;  // don't mangle pos
1358					status = fDMACommand->gen64IOVMSegments( &dma_pos, &segment, &numSegments );
1359				//	IOLog( "IOFireWireSBP2ORB::setCommandBuffers - pos = %d, status = 0x%08lx\n", pos, status );
1360				//	IOSleep( 10 );
1361				}
1362
1363				if( status == kIOReturnSuccess )
1364				{
1365					if( numSegments != 1 )
1366					{
1367						status = kIOReturnNoMemory;
1368					}
1369				}
1370
1371				if( status == kIOReturnSuccess )
1372				{
1373					phys = segment.fIOVMAddr;
1374					lengthOfSegment = segment.fLength;
1375				}
1376
1377				// nothing more to map
1378
1379				if( phys == 0 )
1380				{
1381					status = kIOReturnBadArgument;  // buffer not large enough
1382					done = true;
1383					break;
1384				}
1385
1386				// map until we are done or we run out of segment
1387
1388				// DMA command constraints should make this code unnecessary
1389
1390				while( (pos < (length + offset)) && (lengthOfSegment != 0) )
1391				{
1392					UInt32 		step = 0;
1393    				UInt32		toMap = 0;
1394
1395					// 64k max page table entry, so we do it in chunks
1396
1397					if( lengthOfSegment > maxPageClipSize )
1398						step = maxPageClipSize;
1399					else
1400						step = lengthOfSegment;
1401
1402					lengthOfSegment -= step;
1403
1404					// clip mapping by length if necessary
1405
1406					if( (pos + step) > (length + offset) )
1407						toMap = length + offset - pos;
1408					else
1409						toMap = step;
1410
1411					// map it if we've got anything to map
1412
1413					if( toMap != 0 )
1414					{
1415						pte++;
1416
1417						if( pte <= ptes_allocated )
1418						{
1419							FWSBP2PTE entry;
1420
1421							entry.segmentLength = OSSwapHostToBigInt16( toMap );
1422							entry.segmentBaseAddressHi = OSSwapHostToBigInt16( ((phys >> 32) & 0x000000000000ffffULL) );
1423							entry.segmentBaseAddressLo = OSSwapHostToBigInt32( (phys & 0x00000000ffffffffULL) );
1424
1425							fPageTableDescriptor->writeBytes( (pte-1) * sizeof(FWSBP2PTE), &entry, sizeof(FWSBP2PTE) );
1426
1427						//	IOLog( "IOFireWireSBP2ORB<%p> : PTE = %d, size = %d\n", this, pte-1, toMap  );
1428
1429		 //                  FWKLOG( ( "IOFireWireSBP2ORB<%p> : PTE = %d, size = %d\n", this, pte-1, toMap  ) );
1430						}
1431
1432						// move to new page table entry and beginning of unmapped memory
1433						phys += toMap;
1434						pos += toMap;
1435					}
1436				}
1437			}
1438
1439			FWKLOG( ( "IOFireWireSBP2ORB<%p> : number of required PTE's = %d\n", this, pte ) );
1440
1441			if( pte <= ptes_allocated )
1442			{
1443				done = true;
1444			}
1445			else
1446			{
1447				if( fCommandFlags & kFWSBP2CommandFixedSize )
1448				{
1449					status = kIOReturnNoMemory;
1450					done = true;
1451				}
1452				else
1453				{
1454					// reallocate
1455					status = allocatePageTable( pte );
1456					if( status != kIOReturnSuccess )
1457					{
1458						status = kIOReturnNoMemory;
1459						done = true;
1460					}
1461				}
1462			}
1463		}
1464	}
1465
1466    //
1467    // fill in orb
1468    //
1469
1470    if( status == kIOReturnSuccess )
1471    {
1472        if( pte == 0 )
1473        {
1474			// no page table
1475            fORBBuffer->dataDescriptorHi	= 0;
1476            fORBBuffer->dataDescriptorLo	= 0;
1477            fORBBuffer->options				&= OSSwapHostToBigInt16(0xfff0);	// no page table
1478            fORBBuffer->dataSize			= 0;
1479			fPTECount = 0;
1480        }
1481        else
1482		{
1483			FWSBP2PTE firstEntry;
1484
1485			fPageTableDescriptor->readBytes( 0, &firstEntry, sizeof(FWSBP2PTE) );
1486
1487			// very strictly speaking, if we don't use a page table, the buffer
1488			// must be quadlet-aligned.  SBP-2 is vague about this.  We'll enforce it.
1489
1490			if( pte == 1 && !(firstEntry.segmentBaseAddressLo & OSSwapHostToBigInt32(0x00000003)) )  // make sure quadlet aligned
1491			{
1492				// directly addressed buffer
1493				fORBBuffer->dataDescriptorHi	= 0;			// tbd later
1494				fORBBuffer->dataDescriptorLo	= firstEntry.segmentBaseAddressLo;
1495				fORBBuffer->options				&= OSSwapHostToBigInt16(0xfff0);		// no page table
1496				fORBBuffer->dataSize			= firstEntry.segmentLength;
1497				fPTECount = 0;
1498			}
1499			else if( pte * sizeof(FWSBP2PTE) <= fPageTablePhysicalLength )
1500			{
1501				// use physical unit
1502				fORBBuffer->dataDescriptorHi	= OSSwapHostToBigInt32(fPageTablePhysicalAddress.addressHi);			// tbd later
1503				fORBBuffer->dataDescriptorLo	= OSSwapHostToBigInt32(fPageTablePhysicalAddress.addressLo);
1504				fORBBuffer->options				&= OSSwapHostToBigInt16(0xfff0);
1505				fORBBuffer->options				|= OSSwapHostToBigInt16(0x0008);		// unrestricted page table
1506				fORBBuffer->dataSize			= OSSwapHostToBigInt16(pte);
1507				fPTECount = pte;
1508			}
1509			else
1510			{
1511				// use software address space
1512				fORBBuffer->dataDescriptorHi	= OSSwapHostToBigInt32(fPageTablePseudoAddress.addressHi);			// tbd later
1513				fORBBuffer->dataDescriptorLo	= OSSwapHostToBigInt32(fPageTablePseudoAddress.addressLo);
1514				fORBBuffer->options				&= OSSwapHostToBigInt16(0xfff0);
1515				fORBBuffer->options				|= OSSwapHostToBigInt16(0x0008);		// unrestricted page table
1516				fORBBuffer->dataSize			= OSSwapHostToBigInt16(pte);
1517				fPTECount = pte;
1518			}
1519		}
1520    }
1521
1522	if( status != kIOReturnSuccess )
1523	{
1524		completeBufferAddressSpace();
1525	}
1526
1527    fControl->openGate();
1528
1529//	IOLog( "IOFireWireSBP2ORB::setCommandBuffers return status = 0x%08lx\n", status );
1530
1531    return status;
1532}
1533
1534// getCommandBufferDesceiptor
1535//
1536//
1537
1538IOMemoryDescriptor * IOFireWireSBP2ORB::getCommandBufferDescriptor( void )
1539{
1540	return fBufferDescriptor;
1541}
1542
1543/////////////////////////////////////////////////////////////////////
1544// command block
1545//
1546
1547// setCommandBlock
1548//
1549// set the command block portion of the orb with buffer and length
1550
1551IOReturn IOFireWireSBP2ORB::setCommandBlock( void * buffer, UInt32 length )
1552{
1553    fControl->closeGate();
1554
1555    UInt32 maxCommandBlockSize = fLogin->getMaxCommandBlockSize();
1556
1557    if( length > maxCommandBlockSize )
1558        return kIOReturnNoMemory;
1559
1560    bzero( &fORBBuffer->commandBlock[0], maxCommandBlockSize );
1561    bcopy( buffer, &fORBBuffer->commandBlock[0], length );
1562
1563    fControl->openGate();
1564
1565    return kIOReturnSuccess;
1566}
1567
1568// setCommandBlock
1569//
1570// set the command block portion of the orb with memory descriptor
1571
1572IOReturn IOFireWireSBP2ORB::setCommandBlock( IOMemoryDescriptor * memory )
1573{
1574    fControl->closeGate();
1575
1576    UInt32 maxCommandBlockSize = fLogin->getMaxCommandBlockSize();
1577    IOByteCount length = memory->getLength();
1578
1579    if( length > maxCommandBlockSize )
1580        return kIOReturnNoMemory;
1581
1582    bzero( &fORBBuffer->commandBlock[0], maxCommandBlockSize );
1583    memory->readBytes(0, &fORBBuffer->commandBlock[0], length );
1584
1585    fControl->openGate();
1586
1587    return kIOReturnSuccess;
1588}
1589
1590/////////////////////////////////////////////////////////////////////
1591// accessors
1592//
1593
1594void IOFireWireSBP2ORB::setCommandFlags( UInt32 flags )
1595{
1596    fCommandFlags = flags;
1597}
1598
1599UInt32 IOFireWireSBP2ORB::getCommandFlags( void )
1600{
1601    return fCommandFlags;
1602}
1603
1604// get / set refCon
1605
1606void IOFireWireSBP2ORB::setRefCon( void * refCon )
1607{
1608    fRefCon = (UInt64)refCon;
1609}
1610
1611void * IOFireWireSBP2ORB::getRefCon( void )
1612{
1613    return (void*)fRefCon;
1614}
1615
1616// get / set refCon 64
1617
1618void IOFireWireSBP2ORB::setRefCon64( UInt64 refCon )
1619{
1620    fRefCon = refCon;
1621}
1622
1623UInt64 IOFireWireSBP2ORB::getRefCon64( void )
1624{
1625    return fRefCon;
1626}
1627
1628// get / set max payload size
1629
1630void IOFireWireSBP2ORB::setMaxPayloadSize( UInt32 maxPayloadSize )
1631{
1632    fMaxPayloadSize = maxPayloadSize;
1633}
1634
1635UInt32 IOFireWireSBP2ORB::getMaxPayloadSize( void )
1636{
1637    return fMaxPayloadSize;
1638}
1639
1640// get / set command timeout
1641
1642void IOFireWireSBP2ORB::setCommandTimeout( UInt32 timeout )
1643{
1644    IOReturn ORBTimeoutReinitStatus;
1645
1646    fControl->closeGate();
1647
1648    fTimeoutDuration = timeout;
1649	ORBTimeoutReinitStatus = fTimeoutCommand->reinit( fTimeoutDuration * 1000, IOFireWireSBP2ORB::orbTimeoutStatic, this );
1650
1651    //zzz perhaps this should pass error back to user
1652    FWPANICASSERT( ORBTimeoutReinitStatus == kIOReturnSuccess );
1653
1654    fControl->openGate();
1655}
1656
1657UInt32 IOFireWireSBP2ORB::getCommandTimeout( void )
1658{
1659    return fTimeoutDuration;
1660}
1661
1662// get / set command generation
1663
1664void IOFireWireSBP2ORB::setCommandGeneration( UInt32 gen )
1665{
1666    fGeneration = gen;
1667}
1668
1669UInt32 IOFireWireSBP2ORB::getCommandGeneration( void )
1670{
1671     return fGeneration;
1672}
1673
1674// returns the ORB address
1675
1676void IOFireWireSBP2ORB::getORBAddress( FWAddress * address )
1677{
1678	if( fCommandFlags & kFWSBP2CommandVirtualORBs )
1679	{
1680		*address = fORBPseudoAddress;
1681	}
1682	else
1683	{
1684		*address = fORBPhysicalAddress;
1685	}
1686}
1687
1688// sets the address of the next ORB field
1689void IOFireWireSBP2ORB::setNextORBAddress( FWAddress address )
1690{
1691    fORBBuffer->nextORBAddressHi = OSSwapHostToBigInt32((UInt32)address.addressHi);
1692    fORBBuffer->nextORBAddressLo = OSSwapHostToBigInt32(address.addressLo);
1693}
1694
1695// get login
1696IOFireWireSBP2Login * IOFireWireSBP2ORB::getLogin( void )
1697{
1698    return fLogin;
1699}
1700
1701void IOFireWireSBP2ORB::setToDummy( void )
1702{
1703    // set rq_fmt to 3 (NOP) in case it wasn't fetched yet
1704    fORBBuffer->options |= OSSwapHostToBigInt16(0x6000);
1705}
1706
1707bool IOFireWireSBP2ORB::isAppended( void )
1708{
1709	return fIsAppended;
1710}
1711
1712void IOFireWireSBP2ORB::setIsAppended( bool state )
1713{
1714	fIsAppended = state;
1715}
1716
1717UInt32 IOFireWireSBP2ORB::getFetchAgentWriteRetries( void )
1718{
1719    return fFetchAgentWriteRetries;
1720}
1721
1722void IOFireWireSBP2ORB::setFetchAgentWriteRetries( UInt32 retries )
1723{
1724    fFetchAgentWriteRetries = retries;
1725}
1726
1727// getFetchAgentWriteRetryInterval
1728//
1729//
1730
1731UInt32 IOFireWireSBP2ORB::getFetchAgentWriteRetryInterval( void )
1732{
1733	return fFetchAgentWriteRetryInterval;
1734}
1735
1736// setFetchAgentWriteRetryInterval
1737//
1738//
1739
1740void IOFireWireSBP2ORB::setFetchAgentWriteRetryInterval( UInt32 interval )
1741{
1742	fFetchAgentWriteRetryInterval = interval;
1743}
1744
1745//////////////////////////////////////////////////////////////////////////////////////////
1746// friend class wrappers
1747
1748// login friend class wrappers
1749
1750IOFireWireUnit * IOFireWireSBP2ORB::getFireWireUnit( void )
1751{
1752	return fLogin->getFireWireUnit();
1753}
1754
1755IOFireWireSBP2LUN * IOFireWireSBP2ORB::getFireWireLUN( void )
1756{
1757	return fLogin->getFireWireLUN();
1758}
1759
1760IOReturn IOFireWireSBP2ORB::removeORB( IOFireWireSBP2ORB * orb )
1761{
1762	return fLogin->removeORB( orb );
1763}
1764
1765void IOFireWireSBP2ORB::sendTimeoutNotification( IOFireWireSBP2ORB * orb )
1766{
1767	fLogin->sendTimeoutNotification( orb );
1768}
1769