1/*
2 *  IOFWUserCommand.cpp
3 *  IOFireWireFamily
4 *
5 *  Created by noggin on Tue May 08 2001.
6 *  Copyright (c) 2001 Apple Computer, Inc. All rights reserved.
7 *
8 */
9
10// public
11#import <IOKit/firewire/IOFireWireDevice.h>
12#import <IOKit/firewire/IOFireWireFamilyCommon.h>
13#import <IOKit/firewire/IOFireWireController.h>
14
15// private
16#import "IOFWUserCommand.h"
17#import "IOFireWireLib.h"
18#import "IOFWUserVectorCommand.h"
19
20OSDefineMetaClassAndAbstractStructors(IOFWUserCommand, OSObject)
21OSDefineMetaClassAndStructors(IOFWUserReadCommand, IOFWUserCommand)
22OSDefineMetaClassAndStructors(IOFWUserWriteCommand, IOFWUserCommand)
23OSDefineMetaClassAndStructors(IOFWUserPHYCommand, IOFWUserCommand)
24OSDefineMetaClassAndStructors(IOFWUserCompareSwapCommand, IOFWUserCommand)
25OSDefineMetaClassAndStructors(IOFWUserAsyncStreamCommand, IOFWUserCommand)
26
27// ============================================================
28// IOFWUserCommand
29// ============================================================
30void
31IOFWUserCommand::free()
32{
33	if ( fCommand )
34	{
35		IOReturn	cmdStatus = fCommand->getStatus() ;
36		if ( cmdStatus == kIOReturnBusy || cmdStatus == kIOFireWirePending )
37		{
38			DebugLog("cancelling cmd %p\n", fCommand) ;
39			fCommand->cancel( kIOReturnAborted ) ;
40		}
41
42		fCommand->release() ;
43		fCommand = NULL;
44	}
45
46	if( fOutputArgs )
47	{
48		IOFree( fOutputArgs, fOutputArgsSize );
49		fOutputArgs = NULL;
50		fQuads = NULL ;
51		fNumQuads = 0 ;
52	}
53
54	if (fMem)
55	{
56		fMem->complete() ;
57		fMem->release() ;
58		fMem = NULL;
59	}
60
61	OSObject::free() ;
62}
63
64void
65IOFWUserCommand::setAsyncReference64(
66	OSAsyncReference64	inAsyncRef)
67{
68	bcopy(inAsyncRef, fAsyncRef, sizeof(OSAsyncReference64)) ;
69}
70
71IOFWUserCommand*
72IOFWUserCommand::withSubmitParams(
73	const CommandSubmitParams*	params,
74	const IOFireWireUserClient*			inUserClient)
75{
76	IOFWUserCommand*	result	= NULL ;
77
78	switch ( params->type )
79	{
80		case kFireWireCommandType_Read:
81			// fallthru
82		case kFireWireCommandType_ReadQuadlet:
83			result = OSTypeAlloc( IOFWUserReadCommand );
84			break ;
85
86		case kFireWireCommandType_Write:
87			// fallthru
88		case kFireWireCommandType_WriteQuadlet:
89			result = OSTypeAlloc( IOFWUserWriteCommand );
90			break ;
91
92		case kFireWireCommandType_CompareSwap:
93			result = OSTypeAlloc( IOFWUserCompareSwapCommand );
94			break ;
95
96		case kFireWireCommandType_PHY:
97			result = OSTypeAlloc( IOFWUserPHYCommand );
98			break ;
99
100		case kFireWireCommandType_AsyncStream:
101			result = OSTypeAlloc( IOFWUserAsyncStreamCommand );
102			break;
103
104		default:
105			DebugLog( "bad command type!\n" ) ;
106			break ;
107	}
108
109	if (result && !result->initWithSubmitParams( params, inUserClient ))
110	{
111		result->release() ;
112		result = NULL ;
113	}
114
115	return result ;
116}
117
118bool
119IOFWUserCommand::initWithSubmitParams(
120	const CommandSubmitParams*	params,
121	const IOFireWireUserClient*			inUserClient)
122{
123	fFlush = true;
124	fUserClient	= inUserClient ;
125	return true ;
126}
127
128
129void
130IOFWUserCommand::asyncReadWriteCommandCompletion(
131	void *					refcon,
132	IOReturn 				status,
133	IOFireWireNub *			device,
134	IOFWCommand *			fwCmd)
135{
136	IOFWUserCommand*	cmd = (IOFWUserCommand*) refcon ;
137
138	// tell the vector
139	if( cmd->fVectorCommand )
140	{
141		cmd->fVectorCommand->asyncCompletion( refcon, status, device, fwCmd );
142	}
143	else if ( refcon && cmd->fAsyncRef[0] )
144	{
145		io_user_reference_t args[3];
146		args[0] = cmd->fCommand->getBytesTransferred();
147		args[1] = cmd->fCommand->getAckCode();
148		args[2] = cmd->fCommand->getResponseCode();
149#if IOFIREWIREDEBUG > 0
150		IOReturn		error =
151#endif
152		IOFireWireUserClient::sendAsyncResult64( cmd->fAsyncRef, status, args, 3 );
153
154		DebugLogCond ( error, "IOFWUserCommand::asyncReadWriteCommandCompletion: sendAsyncResult64 returned error %x\n", error ) ;
155	}
156}
157
158void
159IOFWUserCommand::asyncReadQuadletCommandCompletion(
160	void *					refcon,
161	IOReturn 				status,
162	IOFireWireNub *			device,
163	IOFWCommand *			fwCmd)
164{
165	IOFWUserCommand*	cmd = (IOFWUserCommand*)refcon ;
166
167	if (refcon && cmd->fAsyncRef[0] )
168	{
169		cmd->fOutputArgs[0] = cmd->fCommand->getAckCode();
170		cmd->fOutputArgs[1] = cmd->fCommand->getResponseCode();
171		// quad data is already in fOutputArgs[3] and later
172
173#if IOFIREWIREDEBUG > 0
174		IOReturn result =
175#endif
176		IOFireWireUserClient::sendAsyncResult64( cmd->fAsyncRef, status, (io_user_reference_t *)cmd->fOutputArgs, ( cmd->fCommand->getBytesTransferred() >> 2) + 2 ) ;
177		DebugLogCond ( result, "IOFireWireUserClient::asyncReadQuadletCommandCompletion: sendAsyncResult64 returned error 0x%08x\n", result) ;
178	}
179}
180
181#pragma mark -
182// ============================================================
183// IOFWUserReadCommand
184// ============================================================
185
186bool
187IOFWUserReadCommand::initWithSubmitParams(
188	const CommandSubmitParams*	params,
189	const IOFireWireUserClient*			inUserClient)
190{
191	bool	result = true ;
192
193	result = (NULL != IOFWUserCommand::initWithSubmitParams(params, inUserClient)) ;
194
195	if (result)
196	{
197		fMem = IOMemoryDescriptor::withAddressRange( params->newBuffer, params->newBufferSize, kIODirectionIn, fUserClient->getOwningTask() ) ;
198		result = (NULL != fMem) ;
199	}
200
201	if (result)
202	{
203		IOReturn error = fMem->prepare() ;
204		result = ( kIOReturnSuccess == error ) ;
205	}
206
207	if (!result)
208	{
209		if (fMem)
210		{
211			fMem->release() ;
212			fMem = NULL;
213		}
214	}
215
216	return result ;
217}
218
219IOReturn
220IOFWUserReadCommand::submit(
221	CommandSubmitParams*	params,
222	CommandSubmitResult*	outResult)
223{
224	IOReturn	error		= kIOReturnSuccess ;
225	Boolean		syncFlag 	= ( params->flags & kFWCommandInterfaceSyncExecute ) != 0 ;
226	Boolean		copyFlag	= ( params->flags & kFireWireCommandUseCopy ) != 0;
227	Boolean		absFlag		= ( params->flags & kFireWireCommandAbsolute ) != 0 ;
228	bool		forceBlockFlag	= (params->flags & kFWCommandInterfaceForceBlockRequest) != 0;
229
230	FWAddress target_address;
231	target_address.addressLo = (UInt32)(params->newTarget & 0xffffffff);
232	target_address.addressHi = (UInt16)((params->newTarget >> 32) & 0x0000ffff);
233	target_address.nodeID = (UInt16)(params->newTarget >> 48);
234
235	if ( params->staleFlags & kFireWireCommandStale_Buffer )	// do we need reevaluate our buffers?
236	{
237		if ( fMem )	// whatever happens, we're going to need a new memory descriptor
238		{
239			fMem->complete() ;
240			fMem->release() ;
241			fMem = NULL;
242		}
243
244		if ( copyFlag )	// is this command using in-line data?
245		{
246			if( fQuads && (fNumQuads != params->newBufferSize) || syncFlag)	// if we're executing synchronously,
247																			// don't need quadlet buffer
248			{
249				IOFree( fOutputArgs, fOutputArgsSize );
250				fOutputArgs = NULL;
251				fQuads = NULL ;
252				fNumQuads = 0 ;
253			}
254
255			if (!syncFlag)
256			{
257				fNumQuads = params->newBufferSize ;
258				fOutputArgsSize = (params->newBufferSize + 2) * sizeof(UInt32);
259				fOutputArgs = (UInt32*)IOMalloc( fOutputArgsSize );
260				fQuads = fOutputArgs + 2;
261			}
262
263			fMem = NULL ;
264		}
265		else
266		{
267			if (fQuads)
268			{
269				IOFree( fOutputArgs, fOutputArgsSize );
270				fOutputArgs = NULL;
271				fQuads = NULL ;
272				fNumQuads = 0 ;
273			}
274
275			if (NULL == (fMem = IOMemoryDescriptor::withAddressRange( params->newBuffer,
276													params->newBufferSize,
277													kIODirectionIn,
278													fUserClient->getOwningTask())) )
279			{
280				error = kIOReturnNoMemory ;
281			}
282			else
283			{
284				error = fMem->prepare() ;
285
286				if ( error )
287				{
288					fMem->release() ;
289					fMem = NULL ;
290				}
291			}
292		}
293	}
294
295	if ( not error )
296	{
297		if (fCopyFlag != copyFlag)
298			if (fCommand)
299			{
300				fCommand->release() ;	// we had a normal command and need a quadlet command or vice-versa
301				fCommand = NULL ;
302			}
303
304		if (fCommand)
305		{
306			if ( copyFlag )
307				if (syncFlag)
308				{
309					if ( absFlag )
310					{
311						error = ((IOFWReadQuadCommand*)fCommand)->reinit( params->newGeneration, target_address, (UInt32*) params+1, params->newBufferSize, NULL, this ) ;
312					}
313					else
314						error = ((IOFWReadQuadCommand*)fCommand)->reinit( target_address, (UInt32*) params+1, params->newBufferSize, NULL, this, params->newFailOnReset) ;
315				}
316				else
317				{
318					error = ((IOFWReadQuadCommand*)fCommand)->reinit( target_address,
319																	   fQuads,
320																	   fNumQuads,
321																	   & IOFWUserCommand::asyncReadWriteCommandCompletion,
322																	   this,
323																	   params->newFailOnReset) ;
324				}
325			else
326				error = ((IOFWReadCommand*)fCommand)->reinit( target_address,
327															fMem,
328															syncFlag ? NULL : & IOFWUserCommand::asyncReadWriteCommandCompletion,
329															this,
330															params->newFailOnReset ) ;
331
332			fCommand->setGeneration(params->newGeneration) ;
333			DebugLogCond ( error, "IOFWUserReadCommand::submit: fCommand->reinit error=%08x\n", error) ;
334		}
335		else// if (params->staleFlags )
336		{
337			if ( copyFlag )
338			{
339				if (syncFlag)
340				{
341					if ( absFlag )
342					{
343						fCommand = fUserClient->createReadQuadCommand( params->newGeneration, target_address, (UInt32*) params+1, params->newBufferSize, NULL, this ) ;
344					}
345					else
346						fCommand = fUserClient->getOwner()->createReadQuadCommand( target_address, (UInt32*) params+1, params->newBufferSize, NULL, this, params->newFailOnReset ) ;
347				}
348				else
349				{
350					// create a quadlet command and copy in-line quads into it.
351					if ( absFlag )
352					{
353						fCommand = fUserClient->createReadQuadCommand( params->newGeneration, target_address, fQuads, fNumQuads, & IOFWUserCommand::asyncReadQuadletCommandCompletion, this ) ;
354					}
355					else
356					{
357						fCommand = fUserClient->getOwner()->createReadQuadCommand( target_address,
358																					fQuads,
359																					fNumQuads,
360																					& IOFWUserCommand::asyncReadQuadletCommandCompletion,
361																					this,
362																					params->newFailOnReset) ;
363						if ( fCommand )
364							fCommand->setGeneration( params->newGeneration ) ;
365					}
366				}
367			}
368			else
369			{
370				// create a read command -- memory descriptor based
371				if ( absFlag )
372				{
373					fCommand = fUserClient->createReadCommand( params->newGeneration, target_address, fMem, syncFlag ? NULL : & IOFWUserCommand::asyncReadWriteCommandCompletion, this ) ;
374				}
375				else
376				{
377					fCommand = fUserClient->getOwner()->createReadCommand( target_address,
378																			fMem,
379																			syncFlag ? NULL : & IOFWUserCommand::asyncReadWriteCommandCompletion,
380																			this,
381																			params->newFailOnReset ) ;
382					if ( fCommand )
383						fCommand->setGeneration( params->newGeneration ) ;
384				}
385			}
386
387			if (!fCommand)
388				error = kIOReturnNoMemory ;
389		}
390	}
391
392	if ( not error )
393	{
394		if (params->staleFlags & kFireWireCommandStale_MaxPacket)
395		{
396			fCommand->setMaxPacket(params->newMaxPacket) ;
397		}
398
399		if( params->staleFlags & kFireWireCommandStale_Timeout )
400		{
401			fCommand->setTimeout( params->timeoutDuration );
402		}
403
404		if( params->staleFlags & kFireWireCommandStale_Retries )
405		{
406			fCommand->setRetries( params->retryCount );
407		}
408
409		if( params->staleFlags & kFireWireCommandStale_Speed )
410		{
411			fCommand->setMaxSpeed( params->maxPacketSpeed );
412		}
413
414		// block or not
415		fCommand->setForceBlockRequests( forceBlockFlag );
416
417		// turn off flushing if requested
418		if( !fFlush )
419		{
420			fCommand->setFlush( fFlush );
421		}
422
423		error = fCommand->submit() ;
424
425		if( !fFlush )
426		{
427			fCommand->setFlush( true );
428		}
429
430		DebugLogCond ( error, "IOFWUserReadCommand::submit: fCommand->submit error=%08x\n", error ) ;
431	}
432
433	if( syncFlag && (outResult != NULL) )
434	{
435		outResult->result 			= fCommand->getStatus() ;
436		outResult->bytesTransferred	= fCommand->getBytesTransferred() ;
437		outResult->ackCode			= fCommand->getAckCode();
438		outResult->responseCode		= fCommand->getResponseCode();
439
440		// mach won't copy any of our result info out on an error, pretend everything is fine
441		error = kIOReturnSuccess;
442	}
443
444	return error ;
445}
446
447#pragma mark -
448// ============================================================
449// IOFWUserWriteCommand
450// ============================================================
451bool
452IOFWUserWriteCommand::initWithSubmitParams(
453	const CommandSubmitParams*	params,
454	const IOFireWireUserClient*			inUserClient)
455{
456	bool	result = true ;
457
458	result = (NULL != IOFWUserCommand::initWithSubmitParams(params, inUserClient)) ;
459
460	if (result)
461	{
462		fMem = IOMemoryDescriptor::withAddressRange( params->newBuffer, params->newBufferSize, kIODirectionOut, fUserClient->getOwningTask() ) ;
463		result = (NULL != fMem) ;
464	}
465
466	if (result)
467	{
468		IOReturn error = fMem->prepare() ;
469		result = (error == kIOReturnSuccess) ;
470	}
471
472	if (!result)
473	{
474		if (fMem)
475		{
476			fMem->release() ;
477			fMem = NULL;
478		}
479	}
480
481	return result ;
482}
483
484IOReturn
485IOFWUserWriteCommand::submit(
486	CommandSubmitParams*	params,
487	CommandSubmitResult*	outResult)
488{
489	IOReturn	result		= kIOReturnSuccess;
490	Boolean		syncFlag 	= (params->flags & kFWCommandInterfaceSyncExecute) != 0;
491	Boolean		copyFlag	= (params->flags & kFireWireCommandUseCopy) != 0;
492	Boolean		absFlag		= (params->flags & kFireWireCommandAbsolute) != 0;
493	bool		forceBlockFlag	= (params->flags & kFWCommandInterfaceForceBlockRequest) != 0;
494
495	FWAddress target_address;
496	target_address.addressLo = (UInt32)(params->newTarget & 0xffffffff);
497	target_address.addressHi = (UInt16)((params->newTarget >> 32) & 0x0000ffff);
498	target_address.nodeID = (UInt16)(params->newTarget >> 48);
499
500	if ( params->staleFlags & kFireWireCommandStale_Buffer )	// do we need reevaluate our buffers?
501	{
502		if ( fMem )	// whatever happens, we're going to need a new memory descriptor
503		{
504			fMem->complete() ;
505			fMem->release() ;
506		}
507
508		if ( copyFlag )	// is this command using in-line data?
509			fMem = NULL ;
510		else
511		{
512			if (NULL == (fMem = IOMemoryDescriptor::withAddressRange( params->newBuffer,
513													params->newBufferSize,
514													kIODirectionOut,
515													fUserClient->getOwningTask())) )
516			{
517				result = kIOReturnNoMemory ;
518			}
519			else
520			{
521				result = fMem->prepare() ;
522
523				if ( kIOReturnSuccess != result )
524				{
525					fMem->release() ;
526					fMem = NULL ;
527				}
528			}
529		}
530	}
531
532	if ( kIOReturnSuccess == result)
533	{
534		if (fCopyFlag != copyFlag)
535			if (fCommand)
536			{
537				fCommand->release() ;	// we had a normal command and need a quadlet command or vice-versa
538				fCommand = NULL ;
539			}
540
541		if (fCommand)
542		{
543			if ( copyFlag )
544			{
545				result = ((IOFWWriteQuadCommand*)fCommand)->reinit( target_address,
546																	(UInt32*) params+1,
547																	params->newBufferSize,
548																	syncFlag ? NULL : & IOFWUserCommand::asyncReadWriteCommandCompletion,
549																	this,
550																	params->newFailOnReset) ;
551			}
552			else
553			{
554				result = ((IOFWWriteCommand*)fCommand)->reinit( target_address,
555															    fMem,
556															    syncFlag ? NULL : & IOFWUserCommand::asyncReadWriteCommandCompletion,
557															    this,
558															    params->newFailOnReset ) ;
559			}
560
561			DebugLogCond ( result, "IOFWUserWriteCommand::submit: fCommand->reinit result=%08x\n", result) ;
562		}
563		else
564		{
565			if ( copyFlag )
566			{
567				if ( absFlag )
568					fCommand = fUserClient->createWriteQuadCommand( params->newGeneration, target_address, (UInt32*) params+1, params->newBufferSize, syncFlag ? NULL : & IOFWUserCommand::asyncReadWriteCommandCompletion, this ) ;
569				else
570				{
571					fCommand = fUserClient->getOwner()->createWriteQuadCommand( target_address,
572																				(UInt32*) params+1,
573																				params->newBufferSize,
574																				syncFlag ? NULL : & IOFWUserCommand::asyncReadWriteCommandCompletion,
575																				this,
576																				params->newFailOnReset ) ;
577					if ( fCommand )
578						fCommand->setGeneration( params->newGeneration ) ;
579				}
580			}
581			else
582			{
583				// create a read command -- memory descriptor based
584				if ( absFlag )
585					fCommand = fUserClient->createWriteCommand( params->newGeneration,
586																target_address,
587																fMem,
588																syncFlag ? NULL : & IOFWUserCommand::asyncReadWriteCommandCompletion,
589																this ) ;
590				else
591				{
592					fCommand = fUserClient->getOwner()->createWriteCommand( target_address,
593																			fMem,
594																			syncFlag ? NULL : & IOFWUserCommand::asyncReadWriteCommandCompletion,
595																			this,
596																			params->newFailOnReset ) ;
597					if ( fCommand )
598						fCommand->setGeneration( params->newGeneration ) ;
599				}
600			}
601
602			if (!fCommand)
603				result = kIOReturnNoMemory ;
604		}
605	}
606
607	if ( kIOReturnSuccess == result)
608	{
609		if (params->staleFlags & kFireWireCommandStale_MaxPacket)
610		{
611			fCommand->setMaxPacket(params->newMaxPacket) ;// zzz is there any reason for us to pay
612		}
613
614		if( params->staleFlags & kFireWireCommandStale_Timeout )
615		{
616			fCommand->setTimeout( params->timeoutDuration );
617		}
618
619		if( params->staleFlags & kFireWireCommandStale_Retries )
620		{
621			fCommand->setRetries( params->retryCount );
622		}
623
624		if( params->staleFlags & kFireWireCommandStale_Speed )
625		{
626			fCommand->setMaxSpeed( params->maxPacketSpeed );
627		}
628
629		// block or not
630		fCommand->setForceBlockRequests( forceBlockFlag );
631
632		// turn off flushing if requested
633		if( !fFlush )
634		{
635			fCommand->setFlush( fFlush );
636		}
637
638		result = fCommand->submit() ;
639
640		if( !fFlush )
641		{
642			fCommand->setFlush( true );
643		}
644
645		DebugLogCond ( result, "IOFWUserReadCommand::submit: fCommand->submit result=%08x\n", result);
646	}
647
648	if( syncFlag && (outResult != NULL) )
649	{
650		outResult->result 			= fCommand->getStatus();
651		outResult->bytesTransferred	= fCommand->getBytesTransferred();
652		outResult->ackCode			= fCommand->getAckCode();
653		outResult->responseCode		= fCommand->getResponseCode();
654
655		// mach won't copy any of our result info out on an error, pretend everything is fine
656		result = kIOReturnSuccess;
657	}
658
659	return result;
660}
661
662#pragma mark -
663// ============================================================
664// IOFWUserPHYCommand
665// ============================================================
666bool
667IOFWUserPHYCommand::initWithSubmitParams(
668	const CommandSubmitParams*	params,
669	const IOFireWireUserClient*			inUserClient)
670{
671	bool	result = true ;
672
673	result = (NULL != IOFWUserCommand::initWithSubmitParams(params, inUserClient));
674
675	return result;
676}
677
678IOReturn
679IOFWUserPHYCommand::submit(
680	CommandSubmitParams*	params,
681	CommandSubmitResult*	outResult)
682{
683	IOReturn	result		= kIOReturnSuccess;
684	Boolean		syncFlag 	= (params->flags & kFWCommandInterfaceSyncExecute) != 0;
685
686	if( kIOReturnSuccess == result)
687	{
688		if( fPHYCommand )
689		{
690			result = fPHYCommand->reinit(	params->newGeneration,
691											params->data1,
692											params->data2,
693											syncFlag ? NULL : & IOFWUserPHYCommand::asyncPHYCommandCompletion,
694											this,
695											params->newFailOnReset );
696
697			DebugLogCond ( result, "IOFWUserPHYCommand::submit: fCommand->reinit result=%08x\n", result) ;
698		}
699		else
700		{
701			IOFireWireController * control = fUserClient->getOwner()->getController();
702
703			fPHYCommand = control->createAsyncPHYCommand(	params->newGeneration,
704															params->data1,
705															params->data2,
706															syncFlag ? NULL : &IOFWUserPHYCommand::asyncPHYCommandCompletion,
707															this,
708															params->newFailOnReset );
709
710			if( !fPHYCommand )
711			{
712				result = kIOReturnNoMemory;
713			}
714		}
715	}
716
717	if( kIOReturnSuccess == result )
718	{
719		if( params->staleFlags & kFireWireCommandStale_Timeout )
720		{
721			fPHYCommand->setTimeout( params->timeoutDuration );
722		}
723
724		if( params->staleFlags & kFireWireCommandStale_Retries )
725		{
726			fPHYCommand->setRetries( params->retryCount );
727		}
728
729		// turn off flushing if requested
730		if( !fFlush )
731		{
732			fPHYCommand->setFlush( fFlush );
733		}
734
735		result = fPHYCommand->submit() ;
736
737		if( !fFlush )
738		{
739			fPHYCommand->setFlush( true );
740		}
741
742		DebugLogCond ( result, "IOFWUserPHYCommand::submit: fCommand->submit result=%08x\n", result);
743	}
744
745	if( syncFlag && (outResult != NULL) )
746	{
747		outResult->result 			= fPHYCommand->getStatus();
748		outResult->bytesTransferred	= 8;
749		outResult->ackCode			= fPHYCommand->getAckCode();
750		outResult->responseCode		= fPHYCommand->getResponseCode();
751
752		// mach won't copy any of our result info out on an error, pretend everything is fine
753		result = kIOReturnSuccess;
754
755	}
756
757	return result;
758}
759
760void
761IOFWUserPHYCommand::free()
762{
763	if( fPHYCommand )
764	{
765		IOReturn	cmdStatus = fPHYCommand->getStatus();
766		if ( cmdStatus == kIOReturnBusy || cmdStatus == kIOFireWirePending )
767		{
768			DebugLog("cancelling cmd %p\n", fCommand);
769			fPHYCommand->cancel( kIOReturnAborted );
770		}
771
772		fPHYCommand->release() ;
773		fCommand = NULL;
774	}
775
776	IOFWUserCommand::free();
777}
778
779void
780IOFWUserPHYCommand::asyncPHYCommandCompletion(
781	void *					refcon,
782	IOReturn 				status,
783	IOFireWireBus *			bus,
784	IOFWAsyncPHYCommand *	fwCmd )
785{
786	IOFWUserPHYCommand*	cmd = (IOFWUserPHYCommand*) refcon ;
787
788	// tell the vector
789	if( cmd->fVectorCommand )
790	{
791		cmd->fVectorCommand->asyncPHYCompletion( refcon, status, bus, fwCmd );
792	}
793	else if ( refcon && cmd->fAsyncRef[0] )
794	{
795		io_user_reference_t args[3];
796		args[0] = 8;
797		args[1] = cmd->fPHYCommand->getAckCode();
798		args[2] = cmd->fPHYCommand->getResponseCode();
799#if IOFIREWIREDEBUG > 0
800		IOReturn		error =
801#endif
802		IOFireWireUserClient::sendAsyncResult64( cmd->fAsyncRef, status, args, 3 );
803
804		DebugLogCond ( error, "IOFWUserCommand::asyncReadWriteCommandCompletion: sendAsyncResult64 returned error %x\n", error ) ;
805	}
806}
807
808#pragma mark -
809// ============================================================
810// IOFWUserCompareSwapCommand
811// ============================================================
812bool
813IOFWUserCompareSwapCommand::initWithSubmitParams(
814	const CommandSubmitParams*	params,
815	const IOFireWireUserClient*			inUserClient)
816{
817	bool	result = true ;
818
819	result = (NULL != IOFWUserCommand::initWithSubmitParams(params, inUserClient)) ;
820
821	return result ;
822}
823
824IOReturn
825IOFWUserCompareSwapCommand::submit ( CommandSubmitParams *	params, CommandSubmitResult * outResult )
826{
827	// cast to the right type:
828	// for compare swap commands we are really dealing with a 'CompareSwapSubmitResult'
829	// but we have to override submit() with a prototype matching our superclass submit()
830	CompareSwapSubmitResult* result = (CompareSwapSubmitResult*)outResult ;
831
832	IOReturn	error		= kIOReturnSuccess ;
833
834	if ( params->staleFlags & kFireWireCommandStale_Buffer )
835		fSize = params->newBufferSize ;
836
837	Boolean			syncFlag 	= ( params->flags & kFWCommandInterfaceSyncExecute ) != 0 ;
838	Boolean			absFlag		= ( params->flags & kFireWireCommandAbsolute ) != 0 ;
839
840	FWAddress target_address;
841	target_address.addressLo = (UInt32)(params->newTarget & 0xffffffff);
842	target_address.addressHi = (UInt16)((params->newTarget >> 32) & 0x0000ffff);
843	target_address.nodeID = (UInt16)(params->newTarget >> 48);
844
845	if ( params->staleFlags & kFireWireCommandStale )
846	{
847		if ( fCommand )
848		{
849			fCommand->release() ;
850			fCommand = NULL ;
851		}
852
853		if ( absFlag )
854			fCommand = fUserClient->createCompareAndSwapCommand(	params->newGeneration,
855																	target_address,
856																	(UInt32*)(params+1),// cmpVal past end of param struct
857																	(UInt32*)(params+1) + 2,// newVal past end of cmpVal
858																	fSize >> 2,
859																	syncFlag ? NULL : & IOFWUserCompareSwapCommand::asyncCompletion,
860																	this ) ;
861		else
862		{
863			fCommand = fUserClient->getOwner()->createCompareAndSwapCommand( target_address,
864																			(UInt32*)(params+1),// cmpVal past end of param struct
865																			(UInt32*)(params+1) + 2,// newVal past end of cmpVal
866																			fSize >> 2,
867																			syncFlag ? NULL : & IOFWUserCompareSwapCommand::asyncCompletion,
868																			this,
869																			params->newFailOnReset ) ;
870			if ( fCommand )
871				fCommand->setGeneration( params->newGeneration ) ;
872		}
873
874		if ( !fCommand )
875			error = kIOReturnNoMemory ;
876
877	}
878	else //if ( params->staleFlags )
879	{
880		if ( absFlag )
881			error =((IOFWCompareAndSwapCommand*)fCommand)->reinit( params->newGeneration,
882					target_address, (UInt32*)(params+1),// cmpVal past end of param struct
883					(UInt32*)(params+1) + 2,// newVal past end of cmpVal
884					fSize >> 2, syncFlag ? NULL : & IOFWUserCompareSwapCommand::asyncCompletion, this ) ;
885		else
886		{
887			error = ((IOFWCompareAndSwapCommand*)fCommand)->reinit( target_address,
888					(UInt32*)(params+1),// cmpVal past end of param struct
889					(UInt32*)(params+1) + 2,// newVal past end of cmpVal
890					fSize >> 2, syncFlag ? NULL : & IOFWUserCompareSwapCommand::asyncCompletion, this,
891					params->newFailOnReset ) ;
892			fCommand->setGeneration( params->newGeneration ) ;
893		}
894	}
895
896	if ( !error )
897	{
898		if( params->staleFlags & kFireWireCommandStale_Timeout )
899		{
900			fCommand->setTimeout( params->timeoutDuration );
901		}
902
903		if( params->staleFlags & kFireWireCommandStale_Retries )
904		{
905			fCommand->setRetries( params->retryCount );
906		}
907
908		if( params->staleFlags & kFireWireCommandStale_Speed )
909		{
910			fCommand->setMaxSpeed( params->maxPacketSpeed );
911		}
912
913		// turn off flushing if requested
914		if( !fFlush )
915		{
916			fCommand->setFlush( fFlush );
917		}
918
919		error = fCommand->submit() ;
920
921		if( !fFlush )
922		{
923			fCommand->setFlush( true );  // always restore command to true
924		}
925
926		if( syncFlag && (result != NULL) )
927		{
928			result->result 					= fCommand->getStatus() ;
929			result->bytesTransferred		= fCommand->getBytesTransferred() ;
930			result->lockInfo.didLock		= ((IOFWCompareAndSwapCommand*)fCommand)->locked( (UInt32*) & result->lockInfo.value ) ;
931			result->ackCode					= fCommand->getAckCode();
932			result->responseCode			= fCommand->getResponseCode();
933
934			// mach won't copy any of our result info out on an error, pretend everything is fine
935			error = kIOReturnSuccess;
936		}
937	}
938
939	return error ;
940}
941
942void
943IOFWUserCompareSwapCommand::asyncCompletion(
944	void *					refcon,
945	IOReturn 				status,
946	IOFireWireNub *			device,
947	IOFWCommand *			fwCmd)
948{
949	IOFWUserCompareSwapCommand*	cmd = (IOFWUserCompareSwapCommand*)refcon ;
950
951	if (refcon && cmd->fAsyncRef[0] )
952	{
953		UInt32 lock_value[2];
954		lock_value[0] = 0;
955		lock_value[1] = 0;
956		bool locked = ((IOFWCompareAndSwapCommand*)cmd->fCommand)->locked( lock_value );
957
958		UInt64 args[7];
959		args[0] = (UInt64)status;
960		args[1] = (UInt64)cmd->fCommand->getBytesTransferred();
961		args[2] = (UInt64)cmd->fCommand->getAckCode();
962		args[3] = (UInt64)cmd->fCommand->getResponseCode();
963		args[4] = (UInt64)locked;
964		args[5] = (UInt64)lock_value[0];
965		args[6] = (UInt64)lock_value[1];
966#if 0
967		int i = 0;
968		for( i = 0; i < 7; i++ )
969		{
970#ifdef __LP64__
971			IOLog( "IOFWUserCompareSwapCommand::asyncCompletion - args[%d] - %llx\n", i, args[i] );
972#else
973			IOLog( "IOFWUserCompareSwapCommand::asyncCompletion- args[%d] - %llx\n", i, args[i] );
974#endif
975		}
976#endif
977
978#if IOFIREWIREDEBUG > 0
979		IOReturn error =
980#endif
981		IOFireWireUserClient::sendAsyncResult64( cmd->fAsyncRef, status, args, 7 );
982		DebugLogCond ( error, "IOFireWireUserClient::asyncCompareSwapCommandCompletion: sendAsyncResult64 returned error 0x%08x\n", error ) ;
983
984
985#if 0
986		CompareSwapSubmitResult sendResult ;
987
988		sendResult.result = status ;
989		sendResult.bytesTransferred = cmd->fCommand->getBytesTransferred() ;
990		sendResult.lockInfo.didLock	= (Boolean)((IOFWCompareAndSwapCommand*)cmd->fCommand)->locked( (UInt32*) & sendResult.lockInfo.value ) ;
991		sendResult.ackCode = cmd->fCommand->getAckCode();
992		sendResult.responseCode = cmd->fCommand->getResponseCode();
993
994#if IOFIREWIREDEBUG > 0
995		IOReturn error =
996#endif
997		IOFireWireUserClient::sendAsyncResult64( cmd->fAsyncRef, status, (io_user_reference_t *)& sendResult, sizeof(sendResult)/sizeof(UInt32) ) ;	// +1 to round up
998		DebugLogCond ( error, "IOFireWireUserClient::asyncCompareSwapCommandCompletion: sendAsyncResult64 returned error 0x%08x\n", error ) ;
999#endif
1000
1001	}
1002}
1003
1004#pragma mark -
1005// ============================================================
1006// IOFWUserAsyncStreamCommand
1007// ============================================================
1008bool
1009IOFWUserAsyncStreamCommand::initWithSubmitParams(
1010	const CommandSubmitParams*	params,
1011	const IOFireWireUserClient*			inUserClient)
1012{
1013	bool	result = true ;
1014
1015	result = (NULL != IOFWUserCommand::initWithSubmitParams(params, inUserClient));
1016
1017	if (result)
1018	{
1019		fMem = IOMemoryDescriptor::withAddressRange( params->newBuffer, params->newBufferSize, kIODirectionOut, fUserClient->getOwningTask() ) ;
1020		result = (NULL != fMem) ;
1021	}
1022
1023	if (result)
1024	{
1025		IOReturn error = fMem->prepare() ;
1026		result = (error == kIOReturnSuccess) ;
1027	}
1028
1029	if (!result)
1030	{
1031		if (fMem)
1032		{
1033			fMem->release() ;
1034			fMem = NULL;
1035		}
1036	}
1037
1038	return result;
1039}
1040
1041IOReturn
1042IOFWUserAsyncStreamCommand::submit(
1043	CommandSubmitParams*	params,
1044	CommandSubmitResult*	outResult)
1045{
1046	IOReturn	result		= kIOReturnSuccess;
1047	Boolean		syncFlag 	= (params->flags & kFWCommandInterfaceSyncExecute) != 0;
1048
1049	if ( params->staleFlags & kFireWireCommandStale_Buffer )	// IOFWUserAsyncStreamCommand
1050	{
1051		if ( fMem )	// whatever happens, we're going to need a new memory descriptor
1052		{
1053			fMem->complete() ;
1054			fMem->release() ;
1055		}
1056
1057		if (NULL == (fMem = IOMemoryDescriptor::withAddressRange( params->newBuffer,
1058												params->newBufferSize,
1059												kIODirectionOut,
1060												fUserClient->getOwningTask())) )
1061		{
1062			result = kIOReturnNoMemory ;
1063		}
1064		else
1065		{
1066			result = fMem->prepare() ;
1067
1068			if ( kIOReturnSuccess != result )
1069			{
1070				fMem->release() ;
1071				fMem = NULL ;
1072			}
1073		}
1074	}
1075
1076	if ( kIOReturnSuccess == result)
1077	{
1078		if (fAsyncStreamCommand)
1079		{
1080			fAsyncStreamCommand->release() ;
1081			fAsyncStreamCommand = NULL ;
1082		}
1083
1084		if (fAsyncStreamCommand)
1085		{
1086			result = ((IOFWAsyncStreamCommand*)fAsyncStreamCommand)->reinit( params->newGeneration,
1087																			 params->data1,				// channel
1088																			 params->sync,
1089																			 params->tag,
1090																			 fMem,
1091																			 params->newBufferSize,
1092																			 params->maxPacketSpeed,
1093																			 syncFlag ? NULL : & IOFWUserAsyncStreamCommand::asyncStreamCommandCompletion,
1094																			 this,
1095																			 params->newFailOnReset) ;
1096			DebugLogCond ( result, "IOFWUserAsyncStreamCommand::submit: fCommand->reinit result=%08x\n", result) ;
1097		}
1098		else
1099		{
1100			IOFireWireController * control = fUserClient->getOwner()->getController();
1101
1102		    fAsyncStreamCommand = control->createAsyncStreamCommand( params->newGeneration,
1103																	 params->data1,						// channel
1104																	 params->sync,
1105																	 params->tag,
1106																	 fMem,
1107																	 params->newBufferSize,
1108																	 params->maxPacketSpeed,
1109																	 syncFlag ? NULL : & IOFWUserAsyncStreamCommand::asyncStreamCommandCompletion,
1110																	 this,
1111																	 params->newFailOnReset);
1112
1113			if (!fAsyncStreamCommand)
1114				result = kIOReturnNoMemory ;
1115		}
1116	}
1117
1118
1119	if ( kIOReturnSuccess == result)
1120	{
1121		if( params->staleFlags & kFireWireCommandStale_Timeout )
1122		{
1123			fAsyncStreamCommand->setTimeout( params->timeoutDuration );
1124		}
1125
1126		result = fAsyncStreamCommand->submit() ;
1127
1128		DebugLogCond ( result, "IOFWUserAsyncStreamCommand::submit: fCommand->submit result=%08x\n", result);
1129	}
1130
1131	if( syncFlag && (outResult != NULL) )
1132	{
1133		outResult->result 			= fAsyncStreamCommand->getStatus();
1134		outResult->responseCode		= 0;
1135
1136		// mach won't copy any of our result info out on an error, pretend everything is fine
1137		result = kIOReturnSuccess;
1138	}
1139
1140	return result;
1141}
1142
1143void
1144IOFWUserAsyncStreamCommand::free()
1145{
1146	if( fAsyncStreamCommand )
1147	{
1148		IOReturn	cmdStatus = fAsyncStreamCommand->getStatus();
1149		if ( cmdStatus == kIOReturnBusy || cmdStatus == kIOFireWirePending )
1150		{
1151			DebugLog("cancelling cmd %p\n", fAsyncStreamCommand);
1152			fAsyncStreamCommand->cancel( kIOReturnAborted );
1153		}
1154
1155		fAsyncStreamCommand->release() ;
1156		fAsyncStreamCommand = NULL;
1157	}
1158
1159	IOFWUserCommand::free();
1160}
1161
1162void
1163IOFWUserAsyncStreamCommand::asyncStreamCommandCompletion(void						*refcon,
1164														IOReturn					status,
1165														IOFireWireBus				*bus,
1166														IOFWAsyncStreamCommand		*fwCmd )
1167{
1168	IOFWUserAsyncStreamCommand*	cmd = (IOFWUserAsyncStreamCommand*) refcon ;
1169
1170	if ( refcon && cmd->fAsyncRef[0] )
1171	{
1172		io_user_reference_t args[3];
1173		args[0] = 8;
1174#if IOFIREWIREDEBUG > 0
1175		IOReturn		error =
1176#endif
1177		IOFireWireUserClient::sendAsyncResult64( cmd->fAsyncRef, status, args, 3 );
1178
1179		DebugLogCond ( error, "IOFWUserCommand::asyncStreamCommandCompletion: sendAsyncResult64 returned error %x\n", error ) ;
1180	}
1181}
1182