1/*
2 * Copyright (c) 1998-2001 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#define FIREWIREPRIVATE
23
24#include <IOKit/firewire/IOFireWireController.h>
25#include <IOKit/firewire/IOFireWireNub.h>
26#include <IOKit/IOSyncer.h>
27
28#include "IOFireWireIPCommand.h"
29#include "IOFWIPBusInterface.h"
30
31#define BCOPY(s, d, l) do { bcopy((void *) s, (void *) d, l); } while(0)
32
33#pragma mark -
34#pragma mark ��� IOFWIPAsyncWriteCommand methods ���
35
36/************************************************************************************
37	IOFWIPAsyncWriteCommand - Asynchronous write command class
38 ***********************************************************************************/
39
40OSDefineMetaClassAndStructors(IOFWIPAsyncWriteCommand, IOFWWriteCommand);
41OSMetaClassDefineReservedUnused(IOFWIPAsyncWriteCommand, 0);
42OSMetaClassDefineReservedUnused(IOFWIPAsyncWriteCommand, 1);
43OSMetaClassDefineReservedUnused(IOFWIPAsyncWriteCommand, 2);
44OSMetaClassDefineReservedUnused(IOFWIPAsyncWriteCommand, 3);
45
46/*!
47    @function initAll
48	Initializes the Asynchronous write command object
49	@result true if successfull.
50*/
51bool IOFWIPAsyncWriteCommand::initAll(IOFireWireIP *networkObject, IOFWIPBusInterface *fwIPBusIfObject, UInt32 cmdLen, FWAddress devAddress, FWDeviceCallback completion, void *refcon, bool failOnReset)
52{
53	fIPLocalNode = networkObject;
54
55	if(!fIPLocalNode)
56		return false;
57
58	IOFireWireNub *device = fIPLocalNode->getDevice();
59
60    if(!IOFWWriteCommand::initWithController(device->getController()))
61        return false;
62
63    // Create a buffer descriptor that will hold something more than MTU
64	fBuffer		= IOBufferMemoryDescriptor::inTaskWithOptions( kernel_task, 0, cmdLen, 1 );
65    if(fBuffer == NULL)
66        return false;
67
68    // Create a Memory descriptor that will hold the buffer descriptor's memory pointer
69	fMem = NULL;
70
71	fCursorBuf = (UInt8*)getBufferFromDescriptor();
72
73    // Initialize the maxBufLen with current max configuration
74    maxBufLen = cmdLen;
75
76    fMaxRetries = 2;
77    fCurRetries = fMaxRetries;
78    fMemDesc = fMem;
79    fComplete = completion;
80    fSync = completion == NULL;
81    fRefCon = refcon;
82    fTimeout = 1000*125;
83
84    if(fMem)
85        fSize = fMem->getLength();
86    fBytesTransferred = 0;
87	fLinkFragmentType = UNFRAGMENTED;
88
89    fDevice = device;
90    device->getNodeIDGeneration(fGeneration, fNodeID);
91    fAddressHi = devAddress.addressHi;
92    fAddressLo = devAddress.addressLo;
93    fMaxPack = 1 << device->maxPackLog(fWrite, devAddress);
94    fSpeed = fControl->FWSpeed(fNodeID);
95    fFailOnReset = failOnReset;
96
97	if(fwIPBusIfObject)
98	{
99		fIPBusIf = fwIPBusIfObject;
100		fIPBusIf->retain();
101	}
102
103    return true;
104}
105
106/*!
107	@function free
108	@abstract releases the buffer and the command object.
109	@param None.
110	@result void.
111*/
112void IOFWIPAsyncWriteCommand::free()
113{
114	if(fIPBusIf)
115	{
116		fIPBusIf->release();
117		fIPBusIf = NULL;
118	}
119
120    // Release the buffer descriptor
121    if(fBuffer){
122        fBuffer->release();
123        fBuffer = NULL;
124    }
125
126    // Release the memory descriptor
127    if(fMem){
128        fMem->release();
129        fMem = NULL;
130    }
131
132    // Should we free the command
133    IOFWWriteCommand::free();
134}
135
136void IOFWIPAsyncWriteCommand::wait()
137{
138	IODelay(fTimeout);
139}
140
141/*!
142	@function reinit
143	@abstract reinit will re-initialize all the variables for this command object, good
144			  when we have to reconfigure our outgoing command objects.
145	@result kIOReturnSuccess if successfull.
146*/
147IOReturn IOFWIPAsyncWriteCommand::reinit(IOFireWireNub *device, UInt32 cmdLen,
148                FWAddress devAddress, FWDeviceCallback completion, void *refcon,
149				bool failOnReset, bool deferNotify)
150{
151	// Check the cmd len less than the pre-allocated buffer
152    if(cmdLen > maxBufLen)
153        return kIOFireWireIPNoResources;
154
155    fComplete = completion;
156    fRefCon = refcon;
157
158	fSize = cmdLen;
159    fBytesTransferred = 0;
160
161    fDevice = device;
162    device->getNodeIDGeneration(fGeneration, fNodeID);
163    fAddressHi = devAddress.addressHi;
164    fAddressLo = devAddress.addressLo;
165    fMaxPack = 1 << device->maxPackLog(fWrite, devAddress);
166    fSpeed = fControl->FWSpeed(fNodeID);
167    fFailOnReset = failOnReset;
168    fMaxRetries = 2;
169    fCurRetries = fMaxRetries;
170    fTimeout = 1000*125;
171
172	setDeferredNotify(deferNotify);
173
174	IOFWWriteCommand::setFastRetryOnBusy(fIPLocalNode->fIPoFWDiagnostics.fDoFastRetry);
175
176    return kIOReturnSuccess;
177}
178
179IOReturn IOFWIPAsyncWriteCommand::transmit(IOFireWireNub *device, UInt32 cmdLen,
180											FWAddress devAddress, FWDeviceCallback completion, void *refcon,
181											bool failOnReset, bool deferNotify, bool doQueue, FragmentType fragmentType)
182{
183	fLinkFragmentType = fragmentType;
184	return transmit(device, cmdLen, devAddress, completion, refcon, failOnReset, deferNotify, doQueue);
185}
186
187IOReturn IOFWIPAsyncWriteCommand::transmit(IOFireWireNub *device, UInt32 cmdLen,
188											FWAddress devAddress, FWDeviceCallback completion, void *refcon,
189											bool failOnReset, bool deferNotify, bool doQueue)
190{
191	fMBufCommand->retain();		// released in resetDescriptor
192
193	IOReturn status = initDescriptor(cmdLen);
194
195	// Initialize the command with new values of device object
196	if(status == kIOReturnSuccess)
197		status = reinit(device, cmdLen+fHeaderSize, devAddress, completion, refcon, failOnReset, deferNotify);
198
199	if(status == kIOReturnSuccess)
200	{
201		reInitCount = 0;
202		resetCount = 0;
203		reInitCount++;
204		submit(doQueue);
205		status = getStatus();
206	}
207
208	switch (status)
209	{
210		case kIOFireWireOutOfTLabels:
211			fIPLocalNode->fIPoFWDiagnostics.fSubmitErrs++;
212			break;
213
214		case kIOFireWireIPNoResources:
215			resetDescriptor(status);
216			((IOFWIPBusInterface*)refcon)->returnAsyncCommand(this);
217			fIPLocalNode->fIPoFWDiagnostics.fNoResources++;
218			status = kIOReturnSuccess;
219			break;
220
221		default: // kIOReturnNoResources || kIOReturnBusy || kIOReturnSuccess
222			status = kIOReturnSuccess;
223			break;
224	}
225
226	return status;
227}
228
229/*!
230	@function createFragmentedDescriptors
231	@abstract creates IOVirtual ranges for fragmented Mbuf packets.
232	@param none.
233	@result 0 if copied successfully else non-negative value
234*/
235IOReturn IOFWIPAsyncWriteCommand::createFragmentedDescriptors()
236{
237	mbuf_t	m		=	fMBufCommand->getMBuf();
238	mbuf_t	srcm	=	m;
239
240	SInt32	srcLen = mbuf_len(srcm);
241	vm_address_t src = (vm_offset_t)mbuf_data(srcm);
242
243	// Mbuf manipulated to point at the correct offset
244	SInt32 tempOffset = fOffset;
245
246	((IOFWIPBusInterface*)fRefCon)->moveMbufWithOffset(tempOffset, &srcm, &src, &srcLen);
247
248	SInt32 dstLen = fLength;
249    SInt32 copylen = dstLen;
250
251    mbuf_t temp = NULL;
252
253    for (;;)
254	{
255        if (fIndex > (MAX_ALLOWED_SEGS-3))
256		{
257			fTailMbuf  = NULL;
258			fCursorBuf = fCursorBuf + fHeaderSize;
259			// Just copy the remaining length
260			fLength = copylen;
261			UInt32  residual   = copyToBufferDescriptors();
262			if(residual != 0)
263				return kIOFireWireIPNoResources;
264
265			fVirtualRange[fIndex].address = (IOVirtualAddress)(fCursorBuf);
266			fVirtualRange[fIndex].length = fLength;
267			fIndex++;
268			return kIOReturnSuccess;
269		}
270
271        if (srcLen < dstLen)
272		{
273			// Set the remainder of src mbuf to current virtual range.
274			fVirtualRange[fIndex].address = (IOVirtualAddress)(src);
275			fVirtualRange[fIndex].length = srcLen;
276			fIndex++;
277
278			dstLen -= srcLen;
279			copylen -= srcLen;
280			// set the offset
281			fOffset = fOffset + srcLen;
282
283			if(copylen == 0)
284			{
285				// set the new mbuf to point to the new chain
286				temp = mbuf_next(srcm);
287				srcm = temp;
288				break;
289			}
290            // Move on to the next source mbuf.
291            temp = mbuf_next(srcm); assert(temp);
292            srcm = temp;
293            srcLen = mbuf_len(srcm);
294            src = (vm_offset_t)mbuf_data(srcm);
295        }
296        else if (srcLen > dstLen)
297		{
298            // set some of src mbuf to the next virtual range.
299			fVirtualRange[fIndex].address = (IOVirtualAddress)(src);
300			fVirtualRange[fIndex].length = dstLen;
301			fIndex++;
302
303            src += dstLen;
304            srcLen -= dstLen;
305            copylen -= dstLen;
306
307			// set the offset
308			fOffset = fOffset + dstLen;
309
310            // Move on to the next destination mbuf.
311			if(copylen == 0)
312				break;// set the new mbuf to point to the new chain
313        }
314        else
315		{
316			// srcLen == dstLen
317            // set remainder of src into the available virtual range
318			fVirtualRange[fIndex].address = (IOVirtualAddress)(src);
319			fVirtualRange[fIndex].length = srcLen;
320			fIndex++;
321
322			copylen -= srcLen;
323
324			if(copylen == 0)
325			{
326				// set the offset
327				fOffset = 0;
328				// set the new mbuf to point to the new chain
329				temp = mbuf_next(srcm);
330				srcm = temp;
331				break;
332			}
333            // Free current mbuf and move the current onto the next
334            srcm = mbuf_next(srcm);
335
336            // Do we have any data left to copy?
337            if (dstLen == 0)
338				break;
339
340            srcLen = mbuf_len(srcm);
341            src = (vm_offset_t)mbuf_data(srcm);
342        }
343    }
344
345	return copylen;
346}
347
348/*!
349	@function createUnFragmentedDescriptors
350	@abstract creates IOVirtual ranges for fragmented Mbuf packets.
351	@param none.
352	@result kIOReturnSuccess if successfull, else kIOFireWireIPNoResources.
353*/
354IOReturn IOFWIPAsyncWriteCommand::createUnFragmentedDescriptors()
355{
356	mbuf_t	m			= fMBufCommand->getMBuf();
357	mbuf_t	n			= 0;
358	UInt32	totalLength = 0;
359	UInt32	residual	= 0;
360	UInt32	pktLen		= 0;
361	UInt32	offset		= 0;
362
363	fIndex = 0;
364
365	if (mbuf_flags(m) & MBUF_PKTHDR)
366	{
367		pktLen = mbuf_pkthdr_len(m);
368		offset = fOffset;
369	}
370
371	while (m)
372	{
373
374		if(mbuf_data(m) != NULL)
375		{
376			fVirtualRange[fIndex].address = (IOVirtualAddress)((UInt8*)mbuf_data(m) + offset);
377			fVirtualRange[fIndex].length = mbuf_len(m) - offset;
378			totalLength += fVirtualRange[fIndex].length;
379			fIndex++;
380		}
381
382		offset = 0;
383
384        m = mbuf_next(m);
385
386		//
387		// If Mbuf chain gets to the last segment
388		// it will be copied into the available buffer area
389		//
390		if ((fIndex > MAX_ALLOWED_SEGS-3) && (m != NULL))
391		{
392			n = mbuf_next(m);
393			// If last mbuf, then use it in segment directly
394			if(n == NULL)
395			{
396				fVirtualRange[fIndex].address = (IOVirtualAddress)(mbuf_data(m));
397				fVirtualRange[fIndex].length = mbuf_len(m);
398			}
399			// unlucky, so lets copy rest into the pre-allocated buffer
400			else
401			{
402				fTailMbuf 	= m;
403				// Just copy the remaining length
404				fLength = fLength - totalLength + fHeaderSize;
405				fCursorBuf = (UInt8*)getBufferFromDescriptor();
406
407				residual = copyToBufferDescriptors();
408				if(residual != 0)
409					return kIOFireWireIPNoResources;
410
411				fVirtualRange[fIndex].address = (IOVirtualAddress)(fCursorBuf);
412				fVirtualRange[fIndex].length = fLength;
413			}
414			fIndex++;
415			return kIOReturnSuccess;
416		}
417    }
418
419	return kIOReturnSuccess;
420}
421
422/*!
423	@function copyToBufferDescriptors
424	@abstract copies mbuf data into the buffer pointed by IOMemoryDescriptor.
425	@param none.
426	@result 0 if copied successfully else non-negative value
427*/
428IOReturn IOFWIPAsyncWriteCommand::copyToBufferDescriptors()
429{
430	// Get the source
431	mbuf_t	srcm		= fMBufCommand->getMBuf();
432	SInt32	srcLen		= mbuf_len(srcm);
433    vm_address_t src	= (vm_offset_t)mbuf_data(srcm);
434
435	//
436	// Mbuf manipulated to point at the correct offset
437	// If its last segment copy, to form the scatter gather list
438	// we don't need to move the cursor to the offset position
439	//
440	SInt32 tempOffset = 0;
441	if(fTailMbuf != NULL)
442	{
443		srcm = fTailMbuf;
444		srcLen = mbuf_len(srcm);
445		src = (vm_offset_t)mbuf_data(srcm);
446	}
447	else
448	{
449		tempOffset = fOffset;
450		((IOFWIPBusInterface*)fRefCon)->moveMbufWithOffset(tempOffset, &srcm, &src, &srcLen);
451	}
452
453	SInt32 dstLen = fLength;
454    SInt32 copylen = dstLen;
455	vm_address_t dst = (vm_address_t)fCursorBuf;
456
457    mbuf_t temp = NULL;
458
459	UInt32 totalLen = 0;
460
461    for (;;)
462	{
463
464        if (srcLen < dstLen)
465		{
466            // Copy remainder of src mbuf to current dst.
467            BCOPY(src, dst, srcLen);
468			totalLen += srcLen;
469            dst += srcLen;
470            dstLen -= srcLen;
471			copylen -= srcLen;
472			// set the offset
473			fOffset = fOffset + srcLen;
474
475			if(copylen == 0)
476			{
477				// set the new mbuf to point to the new chain
478				temp = mbuf_next(srcm);
479				srcm = temp;
480				break;
481			}
482            // Move on to the next source mbuf.
483            temp = mbuf_next(srcm);
484			if(temp == NULL)
485				break;
486
487			assert(temp);
488            srcm = temp;
489            srcLen = mbuf_len(srcm);
490            src = (vm_offset_t)mbuf_data(srcm);
491        }
492        else if (srcLen > dstLen)
493		{
494            // Copy some of src mbuf to remaining space in dst mbuf.
495            BCOPY(src, dst, dstLen);
496			totalLen += dstLen;
497            src += dstLen;
498            srcLen -= dstLen;
499            copylen -= dstLen;
500			// set the offset
501			fOffset = fOffset + dstLen;
502
503            // Move on to the next destination mbuf.
504			if(copylen == 0)
505				break;
506        }
507        else
508		{
509		    /* (srcLen == dstLen) */
510            // copy remainder of src into remaining space of current dst
511            BCOPY(src, dst, srcLen);
512			totalLen += srcLen;
513			copylen -= srcLen;
514
515			if(copylen == 0)
516			{
517				// set the offset
518				fOffset = 0;
519				// set the new mbuf to point to the new chain
520				temp = mbuf_next(srcm);
521				srcm = temp;
522				break;
523			}
524            // Free current mbuf and move the current onto the next
525            srcm = mbuf_next(srcm);
526
527            // Do we have any data left to copy?
528            if (dstLen == 0)
529				break;
530
531            srcLen = mbuf_len(srcm);
532            src = (vm_offset_t)mbuf_data(srcm);
533        }
534    }
535
536	return copylen;
537}
538
539/*!
540	@function initDescriptor
541	@abstract copies mbuf data into the buffer pointed by IOMemoryDescriptor.
542	@param unfragmented - indicates whether the packet is fragmented or unfragmented.
543	@param length - length to copy.
544	@result kIOReturnSuccess, if successfull.
545*/
546IOReturn IOFWIPAsyncWriteCommand::initDescriptor(UInt32 length)
547{
548	fLength = length;
549
550	// if we copy the payload
551	if(fCopy == true)
552	{
553		// Increment the buffer pointer for the unfrag or frag header
554		fVirtualRange[fIndex].address	= (IOVirtualAddress)fCursorBuf;
555		fVirtualRange[fIndex].length	= fLength + fHeaderSize;
556		fIndex++;
557
558		fCursorBuf = fCursorBuf + fHeaderSize;
559
560		if(copyToBufferDescriptors() != 0)
561			return kIOFireWireIPNoResources;
562	}
563	// if we don't copy the payload
564	else
565	{
566		// if packets are unfragmented
567		if(((fLinkFragmentType == UNFRAGMENTED) ?  createUnFragmentedDescriptors() : createFragmentedDescriptors()) != kIOReturnSuccess)
568			return kIOFireWireIPNoResources;
569	}
570
571	fMem = IOMemoryDescriptor::withAddressRanges(fVirtualRange,
572												  fIndex,
573												  kIODirectionOut,
574												  kernel_task);
575
576    if(!fMem)
577        return kIOFireWireIPNoResources;
578
579	fMemDesc = fMem;
580	fMemDesc->prepare();
581
582	return kIOReturnSuccess;
583}
584
585/*!
586	@function resetDescriptor
587	@abstract resets the IOMemoryDescriptor & reinitializes the cursorbuf.
588	@result void.
589*/
590void IOFWIPAsyncWriteCommand::resetDescriptor(IOReturn status)
591{
592	if( fMem ){
593		fMem->complete();
594		fMem->release();
595		fMem = NULL;
596		fMemDesc = fMem;
597	}
598
599	memset(fVirtualRange, 0, sizeof(IOVirtualRange)*MAX_ALLOWED_SEGS);
600	fTailMbuf	= NULL;
601	fCursorBuf	= (UInt8*)getBufferFromDescriptor();
602
603	if( status == kIOReturnSuccess || status == kIOReturnBusy )
604			fIPLocalNode->fIPoFWDiagnostics.fFastRetryBusyAcks += getFastRetryCount();
605
606	fMBufCommand->releaseWithStatus(status);
607
608	// reset the link fragment type
609	fLinkFragmentType	= UNFRAGMENTED;
610	fDevice				= NULL;
611	fMBufCommand		= NULL;
612
613	resetCount++;
614}
615
616/*!
617	@function initPacketHeader
618	@abstract returns a descriptor header based on fragmentation and copying
619			  of payload.
620	@result void.
621*/
622void* IOFWIPAsyncWriteCommand::initPacketHeader(IOFWIPMBufCommand *mBufCommand, bool doCopy, FragmentType unfragmented, UInt32 headerSize, UInt32 offset)
623{
624	fMBufCommand		= mBufCommand;
625	fCopy				= doCopy;
626	fOffset				= offset;
627	fHeaderSize			= headerSize;
628	fLinkFragmentType	= unfragmented;
629	fIndex				= 0;
630
631	if(fCopy == false)
632	{
633		// If we don't copy then return the starting point of the Mbuf
634		if(unfragmented == UNFRAGMENTED)
635		{
636			fOffset = fOffset - fHeaderSize;
637			return (void*)((UInt8*)mbuf_data(fMBufCommand->getMBuf()) + fOffset);
638		}
639		else
640		{
641			fVirtualRange[fIndex].address = (IOVirtualAddress)(getCursorBuf());
642			fVirtualRange[fIndex].length = fHeaderSize;
643			fIndex++;
644			return getCursorBuf();
645		}
646	}
647
648	// else return the buffer pointer
649	return getBufferFromDescriptor();
650}
651
652void IOFWIPAsyncWriteCommand::gotAck(int ackCode)
653{
654	if ( (ackCode == kFWAckBusyX) || (ackCode == kFWAckBusyA) || (ackCode == kFWAckBusyB) )
655		fIPLocalNode->fIPoFWDiagnostics.fBusyAcks++;
656
657	IOFWWriteCommand::gotAck(ackCode);
658}
659
660/*!
661	@function getCursorBuf
662	@abstract returns the pointer from the current position of fBuffer.
663	@result void* - pre-allocated buffer pointer
664*/
665void* IOFWIPAsyncWriteCommand::getCursorBuf()
666{
667    return fCursorBuf;
668}
669
670/*!
671	@function getBufferFromDescriptor
672	@abstract returns the head pointer position of fBuffer.
673	@result void* - pre-allocated buffer pointer
674*/
675void* IOFWIPAsyncWriteCommand::getBufferFromDescriptor()
676{
677    return fBuffer->getBytesNoCopy();
678}
679
680/*!
681    @function getMaxBufLen
682	@abstract Usefull when MTU changes to a greater value and we need to
683	          accomodate more data in the buffer without a 1394 fragmentation
684	@result UInt32 - size of the pre-allocated buffer
685*/
686UInt32 IOFWIPAsyncWriteCommand::getMaxBufLen()
687{
688    return maxBufLen;
689}
690
691bool IOFWIPAsyncWriteCommand::notDoubleComplete()
692{
693	return (reInitCount == resetCount);
694}
695
696#pragma mark -
697#pragma mark ��� IOFWIPAsyncStreamTxCommand methods ���
698
699/************************************************************************************
700	IOFWIPAsyncStreamTxCommand - AsynStream Trasmit command class
701 ***********************************************************************************/
702
703OSDefineMetaClassAndStructors(IOFWIPAsyncStreamTxCommand, IOFWAsyncStreamCommand);
704OSMetaClassDefineReservedUnused(IOFWIPAsyncStreamTxCommand, 0);
705OSMetaClassDefineReservedUnused(IOFWIPAsyncStreamTxCommand, 1);
706OSMetaClassDefineReservedUnused(IOFWIPAsyncStreamTxCommand, 2);
707OSMetaClassDefineReservedUnused(IOFWIPAsyncStreamTxCommand, 3);
708
709
710/*!
711    @function initAll
712	Initializes the Asynchronous write command object
713	@result true if successfull.
714*/
715bool IOFWIPAsyncStreamTxCommand::initAll(
716										IOFireWireIP			*networkObject,
717										IOFireWireController 	*control,
718										IOFWIPBusInterface		*fwIPBusIfObject,
719										UInt32					generation,
720										UInt32					channel,
721										UInt32					sync,
722										UInt32 					tag,
723										UInt32					cmdLen,
724										int						speed,
725										FWAsyncStreamCallback	completion,
726										void					*refcon)
727
728{
729    if(!IOFWAsyncStreamCommand::initWithController(control))
730        return false;
731
732	fIPLocalNode = networkObject;
733
734	if(!fIPLocalNode)
735		return false;
736
737    // Create a buffer descriptor that will hold something more than MTU
738	fBuffer	= IOBufferMemoryDescriptor::inTaskWithOptions( kernel_task, 0, cmdLen, 1 );
739    if(fBuffer == NULL)
740        return false;
741
742    // Create a Memory descriptor that will hold the buffer descriptor's memory pointer
743    fMem = IOMemoryDescriptor::withAddress((void *)fBuffer->getBytesNoCopy(), cmdLen,
744                                          kIODirectionOut);
745    if(!fMem) {
746        return false;
747    }
748
749    // Initialize the maxBufLen with current max configuration
750    maxBufLen = cmdLen;
751
752    fMaxRetries = 0;
753    fCurRetries = fMaxRetries;
754    fMemDesc = fMem;
755    fComplete = completion;
756    fSync = completion == NULL;
757    fRefCon = refcon;
758    fTimeout = 1000*125;
759
760    if(fMem)
761        fSize = fMem->getLength();
762
763    fGeneration = generation;
764    fChannel = channel;
765    fSyncBits = sync;
766    fTag = tag;
767    fSpeed = speed;
768    fFailOnReset = true;
769
770	if(fwIPBusIfObject)
771	{
772		fIPBusIf = fwIPBusIfObject;
773		fIPBusIf->retain();
774	}
775
776    return true;
777}
778
779void IOFWIPAsyncStreamTxCommand::wait()
780{
781	IODelay(fTimeout);
782}
783
784void IOFWIPAsyncStreamTxCommand::free()
785{
786	if(fIPBusIf)
787	{
788		fIPBusIf->release();
789		fIPBusIf = NULL;
790	}
791
792    // Release the buffer descriptor
793    if(fBuffer){
794        fBuffer->release();
795        fBuffer = NULL;
796    }
797
798    // Release the memory descriptor
799    if(fMem){
800        fMem->release();
801        fMem = NULL;
802    }
803
804    // Should we free the command
805    IOFWAsyncStreamCommand::free();
806}
807
808/*!
809	@function reinit
810	reinit will re-initialize all the variables for this command object, good
811	when we have to reconfigure our outgoing command objects.
812	@result true if successfull.
813*/
814IOReturn IOFWIPAsyncStreamTxCommand::reinit(
815								UInt32 					generation,
816                                UInt32 					channel,
817                                UInt32					cmdLen,
818                                int						speed,
819                                FWAsyncStreamCallback 	completion,
820                                void 					*refcon)
821{
822    if(fStatus == kIOReturnBusy || fStatus == kIOFireWirePending)
823		return fStatus;
824
825    // Check the cmd len less than the pre-allocated buffer
826    if(cmdLen > maxBufLen)
827        return kIOReturnNoResources;
828
829    fComplete = completion;
830    fRefCon = refcon;
831
832    if(fMem)
833        fSize = cmdLen;
834
835    fMaxRetries = 0;
836    fCurRetries = fMaxRetries;
837    fGeneration = generation;
838    fChannel = channel;
839    fSpeed = speed;
840	fTimeout = 1000*125;
841
842    return fStatus = kIOReturnSuccess;
843}
844
845/*!
846	@function getBufferFromDescriptor
847	Usefull for copying data from the mbuf
848	@result void* - pre-allocated buffer pointer
849*/
850void* IOFWIPAsyncStreamTxCommand::getBufferFromDesc()
851{
852    return fBuffer->getBytesNoCopy();
853}
854
855/*!
856    @function getMaxBufLen
857	Usefull when MTU changes to a greater value and we need to
858	accomodate more data in the buffer without a 1394 fragmentation
859	@result UInt32 - size of the pre-allocated buffer
860*/
861UInt32 IOFWIPAsyncStreamTxCommand::getMaxBufLen()
862{
863    return maxBufLen;
864}
865