1/*
2 * Copyright (c) 1998-2002 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//#define IOASSERT 1	// Set to 1 to activate assert()
24
25// public
26#include <IOKit/firewire/IOFWCommand.h>
27#include <IOKit/firewire/IOFireWireController.h>
28#include <IOKit/firewire/IOFireWireNub.h>
29#include <IOKit/firewire/IOLocalConfigDirectory.h>
30
31// system
32#include <IOKit/assert.h>
33#include <IOKit/IOWorkLoop.h>
34#include <IOKit/IOCommand.h>
35
36OSDefineMetaClassAndStructors(IOFWWriteCommand, IOFWAsyncCommand)
37OSMetaClassDefineReservedUnused(IOFWWriteCommand, 0);
38OSMetaClassDefineReservedUnused(IOFWWriteCommand, 1);
39
40#pragma mark -
41
42// initWithController
43//
44//
45
46bool IOFWWriteCommand::initWithController(IOFireWireController *control)
47{
48	bool success = true;
49
50    fWrite = true;
51
52    success = IOFWAsyncCommand::initWithController(control);
53
54	// create member variables
55
56	if( success )
57	{
58		success = createMemberVariables();
59	}
60
61	return success;
62}
63
64// initAll
65//
66//
67
68bool IOFWWriteCommand::initAll(	IOFireWireNub *			device,
69								FWAddress 				devAddress,
70								IOMemoryDescriptor *	hostMem,
71								FWDeviceCallback 		completion,
72								void *					refcon,
73								bool 					failOnReset )
74{
75	bool success = true;
76
77    fWrite = true;
78
79    success = IOFWAsyncCommand::initAll( device, devAddress, hostMem,
80										 completion, refcon, failOnReset);
81
82	// create member variables
83
84	if( success )
85	{
86		success = createMemberVariables();
87	}
88
89	return success;
90}
91
92// initAll
93//
94//
95
96bool IOFWWriteCommand::initAll(	IOFireWireController *	control,
97								UInt32 					generation,
98								FWAddress 				devAddress,
99								IOMemoryDescriptor *	hostMem,
100								FWDeviceCallback 		completion,
101								void *					refcon )
102{
103	bool success = true;
104
105    fWrite = true;
106
107    success = IOFWAsyncCommand::initAll(control, generation, devAddress,
108										hostMem, completion, refcon);
109
110	// create member variables
111
112	if( success )
113	{
114		success = createMemberVariables();
115	}
116
117	return success;
118}
119
120// createMemberVariables
121//
122//
123
124bool IOFWWriteCommand::createMemberVariables( void )
125{
126	bool success = true;
127
128	if( fMembers == NULL )
129	{
130		success = IOFWAsyncCommand::createMemberVariables();
131	}
132
133	if( fMembers )
134	{
135		if( success )
136		{
137			fMembers->fSubclassMembers = IOMalloc( sizeof(MemberVariables) );
138			if( fMembers->fSubclassMembers == NULL )
139				success = false;
140		}
141
142		// zero member variables
143
144		if( success )
145		{
146			bzero( fMembers->fSubclassMembers, sizeof(MemberVariables) );
147		}
148
149		// clean up on failure
150
151		if( !success )
152		{
153			destroyMemberVariables();
154		}
155	}
156
157	return success;
158}
159
160// destroyMemberVariables
161//
162//
163
164void IOFWWriteCommand::destroyMemberVariables( void )
165{
166	if( fMembers->fSubclassMembers != NULL )
167	{
168		// free member variables
169
170		IOFree( fMembers->fSubclassMembers, sizeof(MemberVariables) );
171		fMembers->fSubclassMembers = NULL;
172	}
173}
174
175// free
176//
177//
178
179void IOFWWriteCommand::free()
180{
181	destroyMemberVariables();
182
183	IOFWAsyncCommand::free();
184}
185
186// reinit
187//
188//
189
190IOReturn IOFWWriteCommand::reinit(	FWAddress 				devAddress,
191									IOMemoryDescriptor *	hostMem,
192									FWDeviceCallback 		completion,
193									void *					refcon,
194									bool failOnReset )
195{
196    return IOFWAsyncCommand::reinit(	devAddress,
197										hostMem,
198										completion,
199										refcon,
200										failOnReset );
201}
202
203// reinit
204//
205//
206
207IOReturn IOFWWriteCommand::reinit(	UInt32 					generation,
208									FWAddress 				devAddress,
209									IOMemoryDescriptor *	hostMem,
210									FWDeviceCallback 		completion,
211									void *					refcon )
212{
213    return IOFWAsyncCommand::reinit(	generation,
214										devAddress,
215										hostMem,
216										completion,
217										refcon );
218}
219
220// execute
221//
222//
223
224IOReturn IOFWWriteCommand::execute()
225{
226    IOReturn result;
227    fStatus = kIOReturnBusy;
228
229    if( !fFailOnReset )
230	{
231        // Update nodeID and generation
232        fDevice->getNodeIDGeneration( fGeneration, fNodeID );
233		fSpeed = fControl->FWSpeed( fNodeID );
234		if( fMembers->fMaxSpeed < fSpeed )
235		{
236			fSpeed = fMembers->fMaxSpeed;
237		}
238    }
239
240    fPackSize = fSize;
241    if( fPackSize > fMaxPack )
242	{
243		fPackSize = fMaxPack;
244	}
245
246	int maxPack = (1 << fControl->maxPackLog(fWrite, fNodeID));
247	if( maxPack < fPackSize )
248	{
249		fPackSize = maxPack;
250	}
251
252    // Do this when we're in execute, not before,
253    // so that Reset handling knows which commands are waiting a response.
254    fTrans = fControl->allocTrans( this );
255    if( fTrans )
256	{
257		UInt32 flags = kIOFWWriteFlagsNone;
258
259		if( fMembers && fMembers->fSubclassMembers )
260		{
261			if( ((MemberVariables*)fMembers->fSubclassMembers)->fDeferredNotify )
262			{
263				flags |= kIOFWWriteFlagsDeferredNotify;
264			}
265
266			if( ((MemberVariables*)fMembers->fSubclassMembers)->fFastRetryOnBusy )
267			{
268				flags |= kIOFWWriteFastRetryOnBusy;
269			}
270
271			if( ((IOFWAsyncCommand::MemberVariables*)fMembers)->fForceBlockRequests )
272			{
273				flags |= kIOFWWriteBlockRequest;
274			}
275		}
276
277        result = fControl->asyncWrite(	fGeneration,
278										fNodeID,
279										fAddressHi,
280										fAddressLo,
281										fSpeed,
282										fTrans->fTCode,
283										fMemDesc,
284										fBytesTransferred,
285										fPackSize,
286										this,
287										(IOFWWriteFlags)flags );
288    }
289    else
290	{
291		//IOLog("IOFWWriteCommand::execute: Out of tLabels?\n");
292        result = kIOFireWireOutOfTLabels;
293    }
294
295	// complete could release us so protect fStatus with retain and release
296	IOReturn status = fStatus;
297    if( result != kIOReturnSuccess )
298	{
299		retain();
300        complete( result );
301		status = fStatus;
302		release();
303	}
304
305	return status;
306}
307
308// gotPacket
309//
310//
311
312void IOFWWriteCommand::gotPacket( int rcode, const void* data, int size )
313{
314	setResponseCode( rcode );
315
316    if( rcode != kFWResponseComplete )
317	{
318        complete( kIOFireWireResponseBase+rcode );
319        return;
320    }
321    else
322	{
323		fBytesTransferred += fPackSize;
324        fSize -= fPackSize;
325    }
326
327    if( fSize > 0 )
328	{
329        fAddressLo += fPackSize;
330
331        updateTimer();
332        fCurRetries = fMaxRetries;
333        fControl->freeTrans( fTrans );  // Free old tcode
334        execute();
335    }
336    else
337	{
338        complete( kIOReturnSuccess );
339    }
340}
341