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/IOMessage.h>
24
25#include <IOKit/sbp2/IOFireWireSBP2Login.h>
26#include <IOKit/sbp2/IOFireWireSBP2LUN.h>
27#include <IOKit/sbp2/IOFireWireSBP2Target.h>
28
29#define FIREWIREPRIVATE
30#include <IOKit/firewire/IOFireWireController.h>
31#undef FIREWIREPRIVATE
32
33#include <IOKit/firewire/IOConfigDirectory.h>
34
35#include "FWDebugging.h"
36#include "IOFireWireSBP2Diagnostics.h"
37#include "IOFWSBP2PseudoAddressSpace.h"
38
39#define kFetchAgentSplitTimeout (3*125*1000)		// 275 milliseconds
40#define kFetchAgentRetryInterval (125*1000)			// 125 milliseconds
41
42extern const OSSymbol *gUnit_Characteristics_Symbol;
43extern const OSSymbol *gManagement_Agent_Offset_Symbol;
44extern const OSSymbol *gFast_Start_Symbol;
45
46OSDefineMetaClassAndStructors( IOFireWireSBP2Login, OSObject );
47
48OSMetaClassDefineReservedUnused(IOFireWireSBP2Login, 0);
49OSMetaClassDefineReservedUnused(IOFireWireSBP2Login, 1);
50OSMetaClassDefineReservedUnused(IOFireWireSBP2Login, 2);
51OSMetaClassDefineReservedUnused(IOFireWireSBP2Login, 3);
52OSMetaClassDefineReservedUnused(IOFireWireSBP2Login, 4);
53OSMetaClassDefineReservedUnused(IOFireWireSBP2Login, 5);
54OSMetaClassDefineReservedUnused(IOFireWireSBP2Login, 6);
55OSMetaClassDefineReservedUnused(IOFireWireSBP2Login, 7);
56OSMetaClassDefineReservedUnused(IOFireWireSBP2Login, 8);
57
58#if   defined(__BIG_ENDIAN__)
59#define SBP2SwapHostToBigInt32Array(array, bytes)
60#define SBP2SwapBigToHostInt32Array(array, bytes)
61#elif defined(__LITTLE_ENDIAN__)
62static void SBP2SwapInt32Array(void * array, int bytes)
63{
64    if ( array && bytes )
65    {
66        UInt32 * quads = (UInt32 *) array;
67        bytes >>= 2;
68        while (bytes--)
69            quads[bytes] = OSSwapInt32(quads[bytes]);
70    }
71}
72static inline void SBP2SwapHostToBigInt32Array(void * array, int bytes)
73{ SBP2SwapInt32Array(array, bytes); }
74static inline void SBP2SwapBigToHostInt32Array(void * array, int bytes)
75{ SBP2SwapInt32Array(array, bytes); }
76#else
77#error Unknown endianess
78#endif
79
80#pragma mark -
81
82// initWithLUN
83//
84// initializer
85
86bool IOFireWireSBP2Login::initWithLUN( IOFireWireSBP2LUN * lun )
87{
88	IOReturn status = kIOReturnSuccess;
89
90    // store LUN & Unit
91    fLUN 	= lun;
92	fTarget = getTarget();
93    fUnit 	= fLUN->getFireWireUnit();
94	fControl = fUnit->getController();
95
96    fRefCon	= NULL;
97
98    fLoginGeneration 		= 0;
99	fLoginNodeID			= 0;
100    fLoginFlags				= 0;
101    fMaxPayloadSize			= 4;
102
103    // NULL out fields we may allocate
104	fStatusBlockAddressSpace 			= NULL;
105	fStatusNotifyCallback				= NULL;
106    fStatusNotifyRefCon					= NULL;
107    fUnsolicitedStatusNotifyCallback 	= NULL;
108    fUnsolicitedStatusNotifyRefCon	 	= NULL;
109
110    fLoginORBAddressSpace 			= NULL;
111	fLoginResponseAddressSpace 		= NULL;
112	fLoginTimeoutTimerSet			= false;
113    fLoginWriteCommand 				= NULL;
114    fLoginWriteCommandMemory 		= NULL;
115    fLoginWriteInProgress			= false;
116	fLoginCompletionCallback 		= NULL;
117    fLoginCompletionRefCon 			= NULL;
118
119    fReconnectORBAddressSpace 			= NULL;
120    fReconnectStatusBlockAddressSpace 	= NULL;
121	fReconnectTime						= 0;
122	fReconnectTimeoutTimerSet			= false;
123	fReconnectWriteCommand 				= NULL;
124    fReconnectWriteCommandMemory 		= NULL;
125    fReconnectWriteInProgress 			= false;
126    fReconnectWriteInterrupted			= false;
127
128	fLogoutORBAddressSpace 			= NULL;
129	fLogoutTimeoutTimerSet			= false;
130	fLogoutWriteInProgress			= false;
131	fLogoutWriteCommand 			= NULL;
132    fLogoutWriteCommandMemory 		= NULL;
133	fLogoutCompletionCallback		= NULL;
134    fLogoutCompletionRefCon			= NULL;
135
136	fLoginRetryMax = 32;
137	fLoginRetryDelay = 1000000;
138
139	fUnsolicitedStatusEnableRequested = false;
140
141	fFetchAgentWriteCommandInUse 	= false;
142	fFetchAgentWriteCommand			= NULL;
143    fFetchAgentWriteCommandMemory	= NULL;
144	fFetchAgentWriteCompletion 		= NULL;
145
146	fFetchAgentResetInProgress		= false;
147	fFetchAgentResetCommand 		= NULL;
148	fFetchAgentResetRefCon 			= NULL;
149	fFetchAgentResetCompletion		= NULL;
150
151	fDoorbellInProgress		= false;
152	fDoorbellRingAgain		= false;
153	fDoorbellCommand 		= NULL;
154
155	fUnsolicitedStatusEnableInProgress		= false;
156	fUnsolicitedStatusEnableCommand 		= NULL;
157
158	fSetBusyTimeoutBuffer = OSSwapHostToBigInt32(0x0000000f);
159	fSetBusyTimeoutInProgress = false;
160	fSetBusyTimeoutAddress = FWAddress( 0x0000FFFF, 0xF0000210 );
161	fSetBusyTimeoutCommand = NULL;
162
163    fPasswordBuf = NULL;
164    fPasswordLen = 0;
165    fPasswordAddressSpace = NULL;
166    fPasswordAddress = NULL;
167	fPasswordDescriptor = NULL;
168	fSuspended = false;
169
170	fARDMAMax = 0;
171
172	fLastORBAddress = FWAddress(0,0);
173
174	//
175	// set up command gate
176	//
177
178	IOWorkLoop * workLoop = NULL;
179	if( status == kIOReturnSuccess )
180	{
181		workLoop = fLUN->getWorkLoop();
182		if( !workLoop )
183			status = kIOReturnNoResources;
184	}
185
186	if( status == kIOReturnSuccess )
187	{
188		fGate = IOCommandGate::commandGate( this );
189		if( !fGate )
190			status = kIOReturnNoMemory;
191	}
192
193	if( status == kIOReturnSuccess )
194	{
195		workLoop->retain();
196		workLoop->addEventSource( fGate );
197	}
198
199	if( status == kIOReturnSuccess )
200	{
201		// init state machine
202		fLoginState = kLoginStateIdle;
203
204		// scan unit
205		status = getUnitInformation();
206		FWKLOG( ( "IOFireWireSBP2Login<%p> : fManagementOffset = 0x%lx, fMaxORBSize = %d, fMaxCommandBlockSize = %d\n", this, fManagementOffset, fMaxORBSize, fMaxCommandBlockSize ) );
207	}
208
209	if( status == kIOReturnSuccess )
210	{
211		status = allocateResources();
212	}
213
214    if( status == kIOReturnSuccess )
215    {
216        fORBSet = OSSet::withCapacity(1);
217		if( fORBSet == NULL )
218			status = kIOReturnNoMemory;
219	}
220
221	if( status == kIOReturnSuccess )
222	{
223		fORBSetIterator = OSCollectionIterator::withCollection( fORBSet );
224    }
225
226	if( status == kIOReturnSuccess )
227	{
228		OSObject * prop = fLUN->getProperty( "FWARDMAMax", gIOServicePlane );
229		if( prop != NULL )
230		{
231			fARDMAMax = ((OSNumber*)prop)->unsigned32BitValue();
232		}
233	}
234
235    // the LUN that's creating us will call release() on a non-successful init
236    // we'll clean up there from what ever half-allocated state we are in
237
238    return (status == kIOReturnSuccess);
239}
240
241/////////////////////////////////////////////////////////////////////
242// getUnitInformation
243//
244// gathers SBP2 specific information from unit's ROM
245// specifically it reads, the management agent, and unit dependent
246// characteristics
247
248IOReturn IOFireWireSBP2Login::getUnitInformation( void )
249{
250    IOReturn			status = kIOReturnSuccess;
251    UInt32				unitCharacteristics = 0;
252	OSObject *			prop = NULL;
253
254	//
255	// get management agent info
256	//
257
258	prop = fLUN->getProperty( gManagement_Agent_Offset_Symbol );
259	if( prop == NULL )
260		status = kIOReturnError;
261
262	if( status == kIOReturnSuccess )
263	{
264		fManagementOffset = ((OSNumber*)prop)->unsigned32BitValue();
265	}
266
267    FWKLOG( ("IOFireWireSBP2Login<%p> : status = %d, fManagementOffset = %d\n", this, status, fManagementOffset) );
268
269    //
270    // get unit characteristics
271    //
272
273	if( status == kIOReturnSuccess )
274	{
275		prop = fLUN->getProperty( gUnit_Characteristics_Symbol );
276		if( prop == NULL )
277			status = kIOReturnError;
278	}
279
280	if( status == kIOReturnSuccess )
281	{
282		unitCharacteristics = ((OSNumber*)prop)->unsigned32BitValue();
283
284        // extract management timeout, max ORB size, max command block size
285
286        fManagementTimeout = ((unitCharacteristics >> 8) & 0xff) * 500;   // in milliseconds
287		UInt32 orbSize = (unitCharacteristics & 0xff) * 4;
288        if( orbSize < 32 )
289            orbSize = 32;
290        fMaxORBSize = orbSize;
291        fMaxCommandBlockSize = orbSize - (sizeof(IOFireWireSBP2ORB::FWSBP2ORB) - 4);
292    }
293
294	//
295	// get fast start info
296	//
297
298	if( status == kIOReturnSuccess )
299	{
300		prop = fLUN->getProperty( gFast_Start_Symbol );
301		if( prop != NULL )
302		{
303			UInt32 fastStartInfo = ((OSNumber*)prop)->unsigned32BitValue();
304
305			fFastStartSupported = true;
306			fFastStartOffset = fastStartInfo & 0x000000ff;
307			fFastStartMaxPayload = (fastStartInfo >> 8) & 0x000000ff;
308		}
309	}
310
311    FWKLOG( ("IOFireWireSBP2Login<%p> : fFastStartSupported = %d, fFastStartOffset = 0x%02lx, fFastStartMaxPayload = %d\n", this, fFastStartSupported, fFastStartOffset, fFastStartMaxPayload ) );
312
313    return status;
314}
315
316// allocateResources
317//
318// allocate addressSpaces (ORBs, status registers, response registers)
319// and command objects for writing registers, etc.
320
321IOReturn IOFireWireSBP2Login::allocateResources( void )
322{
323    IOReturn					status = kIOReturnSuccess;
324
325    //
326    // allocate and register an address space for the login ORB
327    //
328
329	FWAddress host_address;
330    if( status == kIOReturnSuccess )
331    {
332        fLoginORBAddressSpace = IOFWSBP2PseudoAddressSpace::simpleRead( fControl, &host_address, sizeof(FWSBP2LoginORB), &fLoginORB );
333    	if ( fLoginORBAddressSpace == NULL )
334        	status = kIOReturnNoMemory;
335    }
336
337    if( status == kIOReturnSuccess )
338    {
339		fLoginORBAddress.nodeID = OSSwapHostToBigInt16( host_address.nodeID );
340		fLoginORBAddress.addressHi = OSSwapHostToBigInt16( host_address.addressHi );
341		fLoginORBAddress.addressLo = OSSwapHostToBigInt32( host_address.addressLo );
342
343        status = fLoginORBAddressSpace->activate();
344    }
345
346    //
347    // allocate and register an address space for the login response
348    //
349
350    if( status == kIOReturnSuccess )
351    {
352        fLoginResponseAddressSpace = IOFWSBP2PseudoAddressSpace::simpleRW( 	fControl, &fLoginResponseAddress,
353																			sizeof(FWSBP2LoginResponse),
354																			&fLoginResponse );
355        if ( fLoginResponseAddressSpace == NULL )
356            status = kIOReturnNoMemory;
357    }
358
359    if( status == kIOReturnSuccess )
360    {
361        status = fLoginResponseAddressSpace->activate();
362    }
363
364    //
365    // allocate and register an address space for the reconnect ORB
366    //
367
368    if( status == kIOReturnSuccess )
369    {
370        fReconnectORBAddressSpace = IOFWPseudoAddressSpace::simpleRead( fControl, &host_address,
371																		sizeof(FWSBP2ReconnectORB),
372                                                                        &fReconnectORB );
373    	if ( fReconnectORBAddressSpace == NULL )
374            status = kIOReturnNoMemory;
375    }
376
377    if( status == kIOReturnSuccess )
378    {
379        fReconnectORBAddress.nodeID = OSSwapHostToBigInt16( host_address.nodeID );
380		fReconnectORBAddress.addressHi = OSSwapHostToBigInt16( host_address.addressHi );
381		fReconnectORBAddress.addressLo = OSSwapHostToBigInt32( host_address.addressLo );
382
383        status = fReconnectORBAddressSpace->activate();
384    }
385
386    //
387    // allocate and register an address space for the status block
388    //
389
390    if( status == kIOReturnSuccess )
391    {
392        fStatusBlockAddressSpace = fUnit->createPseudoAddressSpace(	&fStatusBlockAddress,
393																	sizeof(FWSBP2StatusBlock),
394																	NULL,
395																	IOFireWireSBP2Login::statusBlockWriteStatic,
396																	this );
397        if ( fStatusBlockAddressSpace == NULL )
398            status = kIOReturnNoMemory;
399    }
400
401    if( status == kIOReturnSuccess )
402    {
403        status = fStatusBlockAddressSpace->activate();
404    }
405
406    //
407    // allocate and register an address space for the reconnect status block
408    //
409
410    if( status == kIOReturnSuccess )
411    {
412        fReconnectStatusBlockAddressSpace =
413            fUnit->createPseudoAddressSpace( &fReconnectStatusBlockAddress, sizeof(FWSBP2StatusBlock),
414                                             NULL, IOFireWireSBP2Login::reconnectStatusBlockWriteStatic, this );
415
416        if ( fReconnectStatusBlockAddressSpace == NULL )
417            status = kIOReturnNoMemory;
418    }
419
420    if( status == kIOReturnSuccess )
421    {
422        status = fReconnectStatusBlockAddressSpace->activate();
423    }
424
425    //
426    // allocate and register an address space for the logout ORB
427    //
428
429    if( status == kIOReturnSuccess )
430    {
431        fLogoutORBAddressSpace = IOFWPseudoAddressSpace::simpleRead( fControl, &host_address, sizeof(FWSBP2LogoutORB),
432                                                                     &fLogoutORB );
433    	if ( fLogoutORBAddressSpace == NULL )
434        	status = kIOReturnNoMemory;
435    }
436
437    if( status == kIOReturnSuccess )
438    {
439		fLogoutORBAddress.nodeID = OSSwapHostToBigInt16( host_address.nodeID );
440		fLogoutORBAddress.addressHi = OSSwapHostToBigInt16( host_address.addressHi );
441		fLogoutORBAddress.addressLo = OSSwapHostToBigInt32( host_address.addressLo );
442
443        status = fLogoutORBAddressSpace->activate();
444    }
445
446    //
447    // prepare parts of the ORBs
448    //
449
450    fLoginORB.loginResponseAddressHi = OSSwapHostToBigInt32((fLoginResponseAddress.nodeID << 16) | fLoginResponseAddress.addressHi);
451    fLoginORB.loginResponseAddressLo = OSSwapHostToBigInt32(fLoginResponseAddress.addressLo);
452    fLoginORB.loginResponseLength = OSSwapHostToBigInt16(sizeof( FWSBP2LoginResponse ));
453    fLoginORB.lun = OSSwapHostToBigInt16(fLUN->getLUNumber());
454    FWKLOG( ("IOFireWireSBP2Login<%p>::allocateResources lun number = %d\n", this, OSSwapBigToHostInt16(fLoginORB.lun)) );
455    fLoginORB.statusFIFOAddressHi = OSSwapHostToBigInt32((fStatusBlockAddress.nodeID << 16) | fStatusBlockAddress.addressHi);
456    fLoginORB.statusFIFOAddressLo = OSSwapHostToBigInt32(fStatusBlockAddress.addressLo);
457
458    fReconnectORB.options = OSSwapHostToBigInt16(3 |  0x8000);   // reconnect | notify
459    fReconnectORB.statusFIFOAddressHi = OSSwapHostToBigInt32((fReconnectStatusBlockAddress.nodeID << 16) | fReconnectStatusBlockAddress.addressHi);
460    fReconnectORB.statusFIFOAddressLo = OSSwapHostToBigInt32(fReconnectStatusBlockAddress.addressLo);
461
462    fLogoutORB.options = OSSwapHostToBigInt16(7 | 0x8000);  	// logout | notify
463    fLogoutORB.statusFIFOAddressHi = OSSwapHostToBigInt32((fStatusBlockAddress.nodeID << 16) | fStatusBlockAddress.addressHi);
464    fLogoutORB.statusFIFOAddressLo = OSSwapHostToBigInt32(fStatusBlockAddress.addressLo);
465
466	//
467    // create command for writing the management agent
468    //
469
470    if( status == kIOReturnSuccess )
471    {
472        fLoginWriteCommandMemory = IOMemoryDescriptor::withAddress( &fLoginORBAddress, 8, kIODirectionOut);
473    	if( fLoginWriteCommandMemory == NULL )
474    		status = kIOReturnNoMemory;
475    }
476
477    if( status == kIOReturnSuccess )
478    {
479        fLoginWriteCommand = fUnit->createWriteCommand( FWAddress(0x0000ffff, 0xf0000000 + (fManagementOffset << 2)),
480                                                        fLoginWriteCommandMemory,
481                                                        IOFireWireSBP2Login::loginWriteCompleteStatic, this, true );
482        if( fLoginWriteCommand == NULL )
483        	status = kIOReturnNoMemory;
484    }
485
486    if( status == kIOReturnSuccess )
487    {
488		fLoginTimeoutCommand = fControl->createDelayedCmd( fManagementTimeout * 1000,
489                                                           IOFireWireSBP2Login::loginTimeoutStatic, this);
490	}
491
492
493    if( status == kIOReturnSuccess )
494    {
495		fLoginRetryTimeoutCommand = fControl->createDelayedCmd( 1000000, // 1 second
496                                                                IOFireWireSBP2Login::loginRetryTimeoutStatic, this);
497	}
498
499	if( status == kIOReturnSuccess )
500    {
501		fReconnectRetryTimeoutCommand = fControl->createDelayedCmd( 100000, // 1/10th of a second
502                                                                IOFireWireSBP2Login::reconnectRetryTimeoutStatic, this);
503	}
504
505    //
506    // create command for writing the management agent during reconnect
507    //
508
509    if( status == kIOReturnSuccess )
510    {
511        fReconnectWriteCommandMemory = IOMemoryDescriptor::withAddress( &fReconnectORBAddress, 8, kIODirectionOut);
512    	if( fReconnectWriteCommandMemory == NULL )
513    		status = kIOReturnNoMemory;
514    }
515
516    if( status == kIOReturnSuccess )
517    {
518        fReconnectWriteCommand = fUnit->createWriteCommand( FWAddress(0x0000ffff, 0xf0000000 + (fManagementOffset << 2)),
519                                                            fReconnectWriteCommandMemory,
520                                                            IOFireWireSBP2Login::reconnectWriteCompleteStatic, this, true );
521        if( fReconnectWriteCommand == NULL )
522        	status = kIOReturnNoMemory;
523    }
524
525   if( status == kIOReturnSuccess )
526    {
527		fReconnectTimeoutCommand = (IOFWDelayCommand*)fControl->createDelayedCmd( ((fManagementTimeout + 1000) * 1000),
528                                                                IOFireWireSBP2Login::reconnectTimeoutStatic, this);
529		if( !fReconnectTimeoutCommand )
530			status = kIOReturnNoMemory;
531	}
532
533    //
534    // create command for writing the management agent during logout
535    //
536
537    if( status == kIOReturnSuccess )
538    {
539        fLogoutWriteCommandMemory = IOMemoryDescriptor::withAddress( &fLogoutORBAddress, 8, kIODirectionOut);
540    	if( fLogoutWriteCommandMemory == NULL )
541    		status = kIOReturnNoMemory;
542    }
543
544    if( status == kIOReturnSuccess )
545    {
546        fLogoutWriteCommand = fUnit->createWriteCommand( FWAddress(0x0000ffff, 0xf0000000 + (fManagementOffset << 2)),
547                                                         fLogoutWriteCommandMemory,
548                                                         IOFireWireSBP2Login::logoutWriteCompleteStatic, this, true );
549        if( fLogoutWriteCommand == NULL )
550        	status = kIOReturnNoMemory;
551    }
552
553	//
554	// create command timeout during logout
555	//
556
557    if( status == kIOReturnSuccess )
558    {
559		fLogoutTimeoutCommand = fControl->createDelayedCmd( fManagementTimeout * 1000,
560                                                            IOFireWireSBP2Login::logoutTimeoutStatic, this);
561	}
562
563	//
564	// create command for fetch agent write retries
565	//
566
567    if( status == kIOReturnSuccess )
568    {
569		fFetchAgentRetryTimerCommand = fControl->createDelayedCmd( kFetchAgentRetryInterval,
570                                                            IOFireWireSBP2Login::fetchAgentRetryTimerStatic, this);
571	}
572
573    //
574    // create command for writing the fetch agent
575    //
576
577	//
578    // create command for writing the fast start register
579    //
580
581	if( fFastStartSupported )
582	{
583		if( status == kIOReturnSuccess )
584		{
585			UInt32 size = fFastStartMaxPayload * 4;
586			if( size == 0 )
587				size = 4096;
588			fFetchAgentWriteCommandMemory = IOBufferMemoryDescriptor::withOptions( kIODirectionOutIn | kIOMemoryUnshared, size, PAGE_SIZE );
589			if( fFetchAgentWriteCommandMemory == NULL )
590				status = kIOReturnNoMemory;
591		}
592
593		if( status == kIOReturnSuccess )
594		{
595			fFetchAgentWriteCommand = fUnit->createWriteCommand( FWAddress(0,0),  // tbd later
596																fFetchAgentWriteCommandMemory,
597																IOFireWireSBP2Login::fetchAgentWriteCompleteStatic, this, true );
598			if( fFetchAgentWriteCommand == NULL )
599				status = kIOReturnNoMemory;
600		}
601
602        if( status == kIOReturnSuccess )
603        {
604            // extra long timeout to support a slow to respond still camera
605            fFetchAgentWriteCommand->setTimeout( kFetchAgentSplitTimeout );
606			fFetchAgentWriteCommand->setRetries( 0 );
607        }
608	}
609    else
610	{
611		if( status == kIOReturnSuccess )
612		{
613			fFetchAgentWriteCommandMemory = IOMemoryDescriptor::withAddress( &fLastORBAddress, 8, kIODirectionOut );
614			if( fFetchAgentWriteCommandMemory == NULL )
615				status = kIOReturnNoMemory;
616		}
617
618		if( status == kIOReturnSuccess )
619		{
620			fFetchAgentWriteCommand = fUnit->createWriteCommand( FWAddress(0,0),  // tbd later
621																fFetchAgentWriteCommandMemory,
622																IOFireWireSBP2Login::fetchAgentWriteCompleteStatic, this, true );
623			if( fFetchAgentWriteCommand == NULL )
624				status = kIOReturnNoMemory;
625		}
626
627        if( status == kIOReturnSuccess )
628        {
629            // extra long timeout to support a slow to respond still camera
630            fFetchAgentWriteCommand->setTimeout( kFetchAgentSplitTimeout );
631			fFetchAgentWriteCommand->setRetries( 0 );
632		}
633	}
634
635	//
636    // create command for reseting the fetch agent
637    //
638
639    if( status == kIOReturnSuccess )
640    {
641        fFetchAgentResetCommand = fUnit->createWriteQuadCommand( FWAddress(0,0),  // tbd later
642                                                             &fFetchAgentResetBuffer, 1,
643                                                             IOFireWireSBP2Login::fetchAgentResetCompleteStatic,
644															 this, true );
645        if( fFetchAgentResetCommand == NULL )
646        	status = kIOReturnNoMemory;
647    }
648
649	//
650    // create command for ringing the doorbell
651    //
652
653    if( status == kIOReturnSuccess )
654    {
655        fDoorbellCommand = fUnit->createWriteQuadCommand( FWAddress(0,0),  // tbd later
656                                                             &fDoorbellBuffer, 1,
657                                                             IOFireWireSBP2Login::doorbellCompleteStatic,
658															 this, true );
659        if( fDoorbellCommand == NULL )
660        	status = kIOReturnNoMemory;
661    }
662
663	//
664    // create command for setting busy timeout
665    //
666
667    if( status == kIOReturnSuccess )
668    {
669        fSetBusyTimeoutCommand = fUnit->createWriteQuadCommand( fSetBusyTimeoutAddress,
670                                                             &fSetBusyTimeoutBuffer, 1,
671                                                             IOFireWireSBP2Login::setBusyTimeoutCompleteStatic,
672															 this, true );
673        if( fSetBusyTimeoutCommand == NULL )
674        	status = kIOReturnNoMemory;
675    }
676
677	//
678    // create command for enabling unsolicited status
679    //
680
681    if( status == kIOReturnSuccess )
682    {
683        fUnsolicitedStatusEnableCommand = fUnit->createWriteQuadCommand( FWAddress(0,0),  // tbd later
684                                                             &fUnsolicitedStatusEnableBuffer, 1,
685                                                             IOFireWireSBP2Login::unsolicitedStatusEnableCompleteStatic,
686															 this, true );
687        if( fUnsolicitedStatusEnableCommand == NULL )
688        	status = kIOReturnNoMemory;
689    }
690
691    return status;
692}
693
694void IOFireWireSBP2Login::release() const
695{
696	if( getRetainCount() >= 2 )
697		OSObject::release(2);
698}
699
700void IOFireWireSBP2Login::free( void )
701{
702    IOReturn						status = kIOReturnSuccess;
703
704    FWKLOG( ( "IOFireWireSBP2Login<%p> : free called\n", this ) );
705
706	if( fControl && fTarget )
707	{
708		fControl->closeGate();
709
710		if( fReconnectWriteCommand )
711		{
712			fTarget->cancelMgmtAgentAccess( fReconnectWriteCommand );
713		}
714
715		if( fLoginWriteCommand )
716		{
717			fTarget->cancelMgmtAgentAccess( fLoginWriteCommand );
718		}
719
720		fControl->openGate();
721	}
722
723    // disconnect from lun
724    removeLogin();
725
726	///////////////////////////////////////////
727
728	//
729	// release command for reseting fetch agent
730	//
731
732	if( fFetchAgentResetInProgress )
733		fFetchAgentResetCommand->cancel( kIOReturnAborted );
734
735	if( fFetchAgentResetCommand )
736		fFetchAgentResetCommand->release();
737
738	//
739	// release command for ringing the doorbell
740	//
741
742	if( fDoorbellInProgress )
743		fDoorbellCommand->cancel( kIOReturnAborted );
744
745	if( fDoorbellCommand )
746		fDoorbellCommand->release();
747
748	//
749	// release command for enabling unsolicited status
750	//
751
752	if( fUnsolicitedStatusEnableInProgress )
753		fUnsolicitedStatusEnableCommand->cancel( kIOReturnAborted );
754
755	if( fUnsolicitedStatusEnableCommand )
756		fUnsolicitedStatusEnableCommand->release();
757
758	//
759	// release command for setting busy timeout
760	//
761
762	if( fSetBusyTimeoutInProgress )
763		fSetBusyTimeoutCommand->cancel( kIOReturnAborted );
764
765	if( fSetBusyTimeoutCommand )
766		fSetBusyTimeoutCommand->release();
767
768    //
769    // release command for writing the management agent
770    //
771
772    if( fLoginWriteInProgress )
773        fLoginWriteCommand->cancel( kIOReturnAborted );
774
775    if( fLoginWriteCommand != NULL )
776        fLoginWriteCommand->release();
777
778    if( fLoginWriteCommandMemory != NULL )
779        fLoginWriteCommandMemory->release();
780
781    // cancel timer
782    if( fLoginTimeoutTimerSet )
783        fLoginTimeoutCommand->cancel(kIOReturnAborted);
784
785	if( fLoginTimeoutCommand )
786		fLoginTimeoutCommand->release();
787
788	// cancel timer
789	stopLoginRetryTimer();
790
791	if( fLoginRetryTimeoutCommand )
792		fLoginRetryTimeoutCommand->release();
793
794	// cancel timer
795	stopReconnectRetryTimer();
796
797	if( fReconnectRetryTimeoutCommand )
798		fReconnectRetryTimeoutCommand->release();
799
800    //
801    // deallocate login orb address space
802    //
803
804    if( fLoginORBAddressSpace != NULL && status == kIOReturnSuccess )
805    {
806        fLoginORBAddressSpace->deactivate();
807        fLoginORBAddressSpace->release();
808    }
809
810    //
811    // deallocate login response address space
812    //
813
814    if( fLoginResponseAddressSpace != NULL && status == kIOReturnSuccess )
815    {
816        fLoginResponseAddressSpace->deactivate();
817        fLoginResponseAddressSpace->release();
818    }
819
820	///////////////////////////////////////////
821
822    //
823    // release command for writing the management agent during reconnect
824    //
825
826    if( fReconnectWriteInProgress )
827        fReconnectWriteCommand->cancel(kIOReturnAborted);
828
829    if( fReconnectWriteCommand != NULL )
830        fReconnectWriteCommand->release();
831
832    if( fReconnectWriteCommandMemory != NULL )
833        fReconnectWriteCommandMemory->release();
834
835    // cancel timer
836    if( fReconnectTimeoutTimerSet )
837        fReconnectTimeoutCommand->cancel(kIOReturnAborted);
838
839	if( fReconnectTimeoutCommand )
840		fReconnectTimeoutCommand->release();
841
842    //
843    // deallocate reconnect orb address space
844    //
845
846    if( fReconnectORBAddressSpace != NULL && status == kIOReturnSuccess )
847    {
848        fReconnectORBAddressSpace->deactivate();
849        fReconnectORBAddressSpace->release();
850     }
851
852    //
853    // deallocate reconnect status block address space
854    //
855
856    if( fReconnectStatusBlockAddressSpace != NULL && status == kIOReturnSuccess )
857    {
858        fReconnectStatusBlockAddressSpace->deactivate();
859        fReconnectStatusBlockAddressSpace->release();
860    }
861
862  	///////////////////////////////////////////
863
864    //
865    // release command for writing the management agent during logout
866    //
867
868    if( fLogoutWriteInProgress )
869        fLogoutWriteCommand->cancel(kIOReturnAborted);
870
871    if( fLogoutWriteCommand != NULL )
872        fLogoutWriteCommand->release();
873
874    if( fLogoutWriteCommandMemory != NULL )
875        fLogoutWriteCommandMemory->release();
876
877	// cancel timer
878    if( fLogoutTimeoutTimerSet )
879        fLogoutTimeoutCommand->cancel(kIOReturnAborted);
880
881	// release logout timer
882	if( fLogoutTimeoutCommand )
883		fLogoutTimeoutCommand->release();
884
885    //
886    // deallocate logout orb address space
887    //
888
889    if( fLogoutORBAddressSpace != NULL && status == kIOReturnSuccess )
890    {
891        fLogoutORBAddressSpace->deactivate();
892        fLogoutORBAddressSpace->release();
893     }
894
895	///////////////////////////////////////////
896
897    //
898    // release command for writing the fetch agent
899    //
900
901	// cancel timer
902	stopFetchAgentRetryTimer();
903
904	if( fFetchAgentRetryTimerCommand )
905	{
906		fFetchAgentRetryTimerCommand->release();
907		fFetchAgentRetryTimerCommand = NULL;
908	}
909
910    if( fFetchAgentWriteCommandInUse )
911    {
912	    fFetchAgentWriteCommand->cancel(kIOReturnAborted);
913	}
914
915    if( fFetchAgentWriteCommand != NULL )
916    {
917	    fFetchAgentWriteCommand->release();
918		fFetchAgentWriteCommand = NULL;
919	}
920
921    if( fFetchAgentWriteCommandMemory != NULL )
922    {
923	    fFetchAgentWriteCommandMemory->release();
924		fFetchAgentWriteCommandMemory = NULL;
925    }
926
927    //
928    // deallocate status block address space
929    //
930
931    if( fStatusBlockAddressSpace != NULL && status == kIOReturnSuccess )
932    {
933        fStatusBlockAddressSpace->deactivate();
934        fStatusBlockAddressSpace->release();
935    }
936
937    //
938    // deallocate old password address space
939    //
940
941    if( fPasswordAddressSpace != NULL )
942    {
943        fPasswordAddressSpace->deactivate();
944        fPasswordAddressSpace->release();
945        fPasswordBuf = NULL;
946        fPasswordLen = 0;
947    }
948
949	if( fPasswordDescriptor != NULL )
950	{
951		fPasswordDescriptor->release();
952		fPasswordDescriptor = NULL;
953	}
954
955	//
956	// free unreleased orbs
957	//
958
959	if( fORBSetIterator )
960	{
961		IOFireWireSBP2ORB * item = NULL;
962		do
963		{
964            fORBSetIterator->reset();
965			item = (IOFireWireSBP2ORB *)fORBSetIterator->getNextObject();
966			if( item )
967				item->release();
968		} while( item );
969
970		fORBSetIterator->release();
971	}
972
973	if( fORBSet )
974		fORBSet->release();
975
976	// clean up any dangling critical section disables
977	for( int i = 0; i < fCriticalSectionCount; i++ )
978	{
979		fTarget->endIOCriticalSection();
980	}
981
982	//
983	// destroy command gate
984	//
985
986	if( fGate != NULL )
987	{
988		IOWorkLoop * workLoop = NULL;
989
990		workLoop = fGate->getWorkLoop();
991		workLoop->removeEventSource( fGate );
992		workLoop->release();
993
994		fGate->release();
995		fGate = NULL;
996	}
997
998	OSObject::free();
999}
1000
1001#pragma mark -
1002/////////////////////////////////////////////////////////////////////
1003// accessors
1004//
1005
1006// get unit
1007
1008IOFireWireUnit * IOFireWireSBP2Login::getFireWireUnit( void )
1009{
1010    return fUnit;
1011}
1012
1013// get lun
1014
1015IOFireWireSBP2LUN * IOFireWireSBP2Login::getFireWireLUN( void )
1016{
1017    return fLUN;
1018}
1019
1020// get command block size
1021
1022UInt32 IOFireWireSBP2Login::getMaxCommandBlockSize( void )
1023{
1024    return fMaxCommandBlockSize;
1025}
1026
1027UInt32 IOFireWireSBP2Login::getLoginID( void )
1028{
1029    return fLoginID;
1030}
1031
1032// get / set refCon
1033
1034void IOFireWireSBP2Login::setRefCon( void * refCon )
1035{
1036    fRefCon = refCon;
1037}
1038
1039void * IOFireWireSBP2Login::getRefCon( void )
1040{
1041    return fRefCon;
1042}
1043
1044// get / set login flags
1045
1046void IOFireWireSBP2Login::setLoginFlags( UInt32 loginFlags )
1047{
1048    fLoginFlags = loginFlags;
1049    FWKLOG(( "IOFireWireSBP2Login<%p> : setLoginFlags : 0x%08lx\n", this, fLoginFlags ));
1050}
1051
1052UInt32 IOFireWireSBP2Login::getLoginFlags( void )
1053{
1054    return fLoginFlags;
1055}
1056
1057// set login and logout completion routines
1058
1059void IOFireWireSBP2Login::setLoginCompletion( void * refCon, FWSBP2LoginCallback completion )
1060{
1061    fLoginCompletionRefCon = refCon;
1062    fLoginCompletionCallback = completion;
1063}
1064
1065void IOFireWireSBP2Login::setLogoutCompletion( void * refCon, FWSBP2LogoutCallback completion )
1066{
1067    fLogoutCompletionRefCon = refCon;
1068    fLogoutCompletionCallback = completion;
1069}
1070
1071// get / set reconnect time
1072
1073void IOFireWireSBP2Login::setReconnectTime( UInt32 reconnectTime )
1074{
1075    fReconnectTime = reconnectTime & 0x0000000f;
1076}
1077
1078UInt32 IOFireWireSBP2Login::getReconnectTime( void )
1079{
1080    return fReconnectTime;
1081}
1082
1083// get / set status notify proc
1084
1085void IOFireWireSBP2Login::setStatusNotifyProc( void * refCon, FWSBP2NotifyCallback callback )
1086{
1087    fStatusNotifyCallback = callback;
1088    fStatusNotifyRefCon = refCon;
1089}
1090
1091void IOFireWireSBP2Login::getStatusNotifyProc( void ** refCon, FWSBP2NotifyCallback * callback )
1092{
1093    *callback = fStatusNotifyCallback;
1094    *refCon = fStatusNotifyRefCon;
1095}
1096
1097// get / set status notify proc
1098
1099void IOFireWireSBP2Login::setUnsolicitedStatusNotifyProc( void * refCon, FWSBP2NotifyCallback callback )
1100{
1101    fUnsolicitedStatusNotifyCallback = callback;
1102    fUnsolicitedStatusNotifyRefCon = refCon;
1103}
1104
1105void IOFireWireSBP2Login::getUnsolicitedStatusNotifyProc( void ** refCon, FWSBP2NotifyCallback * callback )
1106{
1107    *callback = fStatusNotifyCallback;
1108    *refCon = fStatusNotifyRefCon;
1109}
1110
1111// get / set max payload size
1112
1113void IOFireWireSBP2Login::setMaxPayloadSize( UInt32 maxPayloadSize )
1114{
1115    fMaxPayloadSize = maxPayloadSize;
1116}
1117
1118UInt32 IOFireWireSBP2Login::getMaxPayloadSize( void )
1119{
1120    return fMaxPayloadSize;
1121}
1122
1123void IOFireWireSBP2Login::setLoginRetryCountAndDelayTime( UInt32 retryCount, UInt32 uSecs )
1124{
1125	fLoginRetryMax = retryCount;
1126	fLoginRetryDelay = uSecs;
1127
1128	if( fLoginRetryTimeoutCommand )
1129	{
1130		fLoginRetryTimeoutCommand->reinit( fLoginRetryDelay, IOFireWireSBP2Login::loginRetryTimeoutStatic, this );
1131	}
1132}
1133
1134
1135// set password
1136//
1137//
1138
1139IOReturn IOFireWireSBP2Login::setPassword( IOMemoryDescriptor * memory )
1140{
1141    IOReturn status = kIOReturnSuccess;
1142	IOByteCount len = 0;
1143
1144    //
1145    // deallocate old password address space
1146    //
1147
1148    if( fPasswordAddressSpace != NULL )
1149    {
1150        fPasswordAddressSpace->deactivate();
1151        fPasswordAddressSpace->release();
1152        fPasswordBuf = NULL;
1153        fPasswordLen = 0;
1154    }
1155
1156	if( fPasswordDescriptor != NULL )
1157	{
1158		fPasswordDescriptor->release();
1159		fPasswordDescriptor = NULL;
1160	}
1161
1162	if( status == kIOReturnSuccess )
1163	{
1164		fPasswordDescriptor = memory;
1165		if( memory == NULL )
1166			status = kIOReturnError;
1167	}
1168
1169	if( status == kIOReturnSuccess )
1170	{
1171		fPasswordDescriptor->retain();
1172		len = fPasswordDescriptor->getLength();
1173		status = fPasswordDescriptor->prepare();  // for readBytes
1174	}
1175
1176	if( status == kIOReturnSuccess )
1177	{
1178		if( len <= 8 )
1179		{
1180			fLoginORB.password[0] = 0;
1181			fLoginORB.password[1] = 0;
1182			fLoginORB.passwordLength = 0;
1183			status = memory->readBytes( 0, &(fLoginORB.password), len );
1184		}
1185		else
1186		{
1187
1188			//
1189			// allocate and register an address space for the password
1190			//
1191
1192			if( status == kIOReturnSuccess )
1193			{
1194				fPasswordAddressSpace = IOFWPseudoAddressSpace::simpleRW( fControl, &fPasswordAddress, memory );
1195				if( fPasswordAddressSpace == NULL )
1196					status = kIOReturnNoMemory;
1197			}
1198
1199			if( status == kIOReturnSuccess )
1200			{
1201				status = fPasswordAddressSpace->activate();
1202			}
1203
1204			if( status == kIOReturnSuccess )
1205			{
1206				fLoginORB.passwordLength = OSSwapHostToBigInt16(len);
1207				fLoginORB.password[0] = OSSwapHostToBigInt32(0x0000ffff & fPasswordAddress.addressHi);
1208				fLoginORB.password[1] = OSSwapHostToBigInt32(fPasswordAddress.addressLo);
1209			}
1210
1211		}
1212    }
1213
1214    return status;
1215}
1216
1217// set password
1218//
1219//
1220
1221IOReturn IOFireWireSBP2Login::setPassword( void * buf, UInt32 len )
1222{
1223    IOReturn						status 			= kIOReturnSuccess;
1224
1225    //
1226    // deallocate old password address space
1227    //
1228
1229
1230    if( fPasswordAddressSpace != NULL )
1231    {
1232        fPasswordAddressSpace->deactivate();
1233        fPasswordAddressSpace->release();
1234        fPasswordBuf = NULL;
1235        fPasswordLen = 0;
1236    }
1237
1238	if( fPasswordDescriptor != NULL )
1239	{
1240		fPasswordDescriptor->release();
1241		fPasswordDescriptor = NULL;
1242	}
1243
1244    if( len <= 8 )
1245    {
1246        fPasswordBuf = buf;
1247        fPasswordLen = len;
1248
1249		fLoginORB.password[0] = 0;
1250		fLoginORB.password[1] = 0;
1251
1252        bcopy( buf, &(fLoginORB.password), len );
1253        fLoginORB.passwordLength = 0;
1254    }
1255    else
1256    {
1257
1258        //
1259        // allocate and register an address space for the password
1260        //
1261
1262        if( status == kIOReturnSuccess )
1263        {
1264			fPasswordAddressSpace = IOFWPseudoAddressSpace::simpleRW( fControl, &fPasswordAddress, len, buf );
1265			if( fPasswordAddressSpace == NULL )
1266				status = kIOReturnNoMemory;
1267        }
1268
1269        if( status == kIOReturnSuccess )
1270        {
1271            status = fPasswordAddressSpace->activate();
1272        }
1273
1274        if( status == kIOReturnSuccess )
1275        {
1276            fPasswordBuf = buf;
1277            fPasswordLen = len;
1278            fLoginORB.passwordLength = OSSwapHostToBigInt16(len);
1279            fLoginORB.password[0] = OSSwapHostToBigInt32(0x0000ffff & fPasswordAddress.addressHi);
1280            fLoginORB.password[1] = OSSwapHostToBigInt32(fPasswordAddress.addressLo);
1281        }
1282
1283    }
1284
1285    return status;
1286}
1287
1288// setLoginGeneration
1289//
1290//
1291
1292void IOFireWireSBP2Login::setLoginGeneration( UInt32 generation )
1293{
1294	fUserLoginGeneration = generation;
1295	fUserLoginGenerationSet = true;
1296}
1297
1298// clearLoginGeneration
1299//
1300//
1301
1302void IOFireWireSBP2Login::clearLoginGeneration( void )
1303{
1304	fUserLoginGenerationSet = false;
1305}
1306
1307#pragma mark -
1308/////////////////////////////////////////////////////////////////////
1309//
1310// login path
1311//
1312
1313// submitLogin
1314//
1315//
1316
1317IOReturn IOFireWireSBP2Login::submitLogin( void )
1318{
1319    IOReturn status = kIOReturnSuccess;
1320
1321	status = fGate->runAction( staticExecuteLogin );
1322
1323	return status;
1324}
1325
1326IOReturn IOFireWireSBP2Login::staticExecuteLogin( OSObject *self, void *, void *, void *, void * )
1327{
1328	return ((IOFireWireSBP2Login *)self)->initialExecuteLogin();
1329}
1330
1331IOReturn IOFireWireSBP2Login::initialExecuteLogin( void )
1332{
1333	IOReturn status = kIOReturnSuccess;
1334
1335	if( fLoginState != kLoginStateIdle || fLoginRetryTimeoutTimerSet )
1336	{
1337		return kIOReturnExclusiveAccess;
1338	}
1339
1340	fLoginRetryCount = fLoginRetryMax;
1341
1342	status = executeLogin();
1343	if( status != kIOReturnSuccess &&
1344	    ((status != kIOFireWireBusReset) || !fUserLoginGenerationSet) &&
1345		fLoginRetryCount != 0 )
1346	{
1347		fLoginRetryCount--;
1348		startLoginRetryTimer();
1349		status = kIOReturnSuccess;
1350	}
1351
1352	return status;
1353}
1354
1355IOReturn IOFireWireSBP2Login::executeLogin( void )
1356{
1357    IOReturn status = kIOReturnSuccess;
1358
1359	FWKLOG( ( "IOFireWireSBP2Login<%p> : executeLogin\n", this ) );
1360
1361	if( fSuspended )
1362	{
1363		return kIOFireWireBusReset;
1364	}
1365
1366	if( fLoginState != kLoginStateIdle )
1367	{
1368		return kIOReturnExclusiveAccess;
1369	}
1370
1371    fLoginState = kLoginStateLoggingIn;  		// set state
1372
1373    if( fLastORB )
1374    {
1375        fLastORB->release();
1376        fLastORB = NULL;
1377    }
1378
1379	fLastORBAddress = FWAddress(0,0);
1380
1381	// to quote sbp-2 : ... truncated login response data
1382	// shall be interpreted as if the omitted fields
1383	// had been stored as zeros. ...
1384
1385    fLoginResponse.reserved = 0;
1386    fLoginResponse.reconnectHold = 0;
1387
1388    // set options
1389    FWKLOG(( "IOFireWireSBP2Login<%p> : fLoginFlags : 0x%08lx\n", this, fLoginFlags ));
1390
1391    fLoginORB.options = OSSwapHostToBigInt16(0x0000 | 0x8000);		// login | notify
1392    fLoginORB.options |= OSSwapHostToBigInt16(fReconnectTime << 4);
1393    if( fLoginFlags & kFWSBP2ExclusiveLogin )
1394        fLoginORB.options |= OSSwapHostToBigInt16(0x1000);
1395
1396    // set to correct generation
1397    fLoginWriteCommand->reinit( FWAddress(0x0000ffff, 0xf0000000 + (fManagementOffset << 2)),
1398                                fLoginWriteCommandMemory, IOFireWireSBP2Login::loginWriteCompleteStatic,
1399                                this, true );
1400
1401    // get local node and generation
1402    // note: these two are latched affter command gen is set and before submit is called
1403    // if these are old command will fail
1404    fUnit->getNodeIDGeneration(fLoginGeneration, fLoginNodeID, fLocalNodeID);
1405
1406	if( fUserLoginGenerationSet && fUserLoginGeneration != fLoginGeneration )
1407	{
1408		status = kIOFireWireBusReset;
1409	}
1410
1411	if( status == kIOReturnSuccess )
1412	{
1413		fLoginWriteInProgress = true;
1414		fLoginStatusReceived = false;
1415		status = fTarget->beginIOCriticalSection();
1416	}
1417
1418	if( status == kIOReturnSuccess )
1419	{
1420		fInCriticalSection = true;
1421		fCriticalSectionCount++;
1422
1423		if( fLoginFlags & kFWSBP2DontSynchronizeMgmtAgent )
1424			fLoginWriteCommand->submit();
1425		else
1426			fTarget->synchMgmtAgentAccess( fLoginWriteCommand );
1427	}
1428
1429	if( status != kIOReturnSuccess )
1430	{
1431		fLoginWriteInProgress = false;
1432		fLoginState = kLoginStateIdle;
1433    }
1434
1435    return status;
1436}
1437
1438//
1439// login write completion
1440//
1441
1442void IOFireWireSBP2Login::loginWriteCompleteStatic( void *refcon, IOReturn status, IOFireWireNub *device,
1443                                                    IOFWCommand *fwCmd )
1444{
1445    ((IOFireWireSBP2Login*)refcon)->loginWriteComplete( status, device, fwCmd );
1446}
1447
1448void IOFireWireSBP2Login::loginWriteComplete( IOReturn status, IOFireWireNub *device, IOFWCommand *fwCmd )
1449{
1450    FWKLOG( ("IOFireWireSBP2Login<%p> : login write complete\n", this) );
1451
1452    fLoginWriteInProgress = false;
1453
1454	if( fLoginStatusReceived )
1455	{
1456		processLoginWrite();
1457	}
1458    else
1459	{
1460		if( status == kIOReturnSuccess )
1461		{
1462			// we wrote the management agent, now set a timer and wait for response & status
1463			fLoginTimeoutTimerSet = true;
1464			if( fLoginTimeoutCommand->submit() != kIOReturnSuccess )
1465				fLoginTimeoutTimerSet = false;
1466		}
1467		else
1468		{
1469			fLoginState = kLoginStateIdle;
1470			completeLogin( status );  // complete with error
1471		}
1472	}
1473}
1474
1475//
1476// login timeout
1477//
1478
1479void IOFireWireSBP2Login::loginTimeoutStatic( void *refcon, IOReturn status,
1480                                               IOFireWireBus *bus, IOFWBusCommand *fwCmd)
1481{
1482    ((IOFireWireSBP2Login*)refcon)->loginTimeout( status, bus, fwCmd );
1483}
1484
1485void IOFireWireSBP2Login::loginTimeout( IOReturn status, IOFireWireBus *bus, IOFWBusCommand *fwCmd)
1486{
1487    fLoginTimeoutTimerSet = false;
1488    if( status != kIOReturnSuccess )
1489    {
1490        FWKLOG( ("IOFireWireSBP2Login<%p> : login timed out\n", this) );
1491
1492        // init state machine
1493        fLoginState = kLoginStateIdle;
1494        completeLogin( kIOReturnTimeout );
1495    }
1496}
1497
1498// login retry timeout
1499//
1500//
1501
1502void IOFireWireSBP2Login::startLoginRetryTimer( void )
1503{
1504	stopLoginRetryTimer();
1505
1506	fLoginRetryTimeoutTimerSet = true;
1507	if( fLoginRetryTimeoutCommand->submit() != kIOReturnSuccess )
1508		fLoginRetryTimeoutTimerSet = false;
1509}
1510
1511void IOFireWireSBP2Login::stopLoginRetryTimer( void )
1512{
1513	// cancel timeout
1514    if( fLoginRetryTimeoutTimerSet )
1515        fLoginRetryTimeoutCommand->cancel( kIOReturnAborted );
1516}
1517
1518void IOFireWireSBP2Login::loginRetryTimeoutStatic( void *refcon, IOReturn status,
1519                                                   IOFireWireBus *bus, IOFWBusCommand *fwCmd)
1520{
1521    ((IOFireWireSBP2Login*)refcon)->loginRetryTimeout( status, bus, fwCmd );
1522}
1523
1524void IOFireWireSBP2Login::loginRetryTimeout( IOReturn status, IOFireWireBus *bus, IOFWBusCommand *fwCmd)
1525{
1526    fLoginRetryTimeoutTimerSet = false;
1527    if( status == kIOReturnTimeout )
1528    {
1529        FWKLOG( ("IOFireWireSBP2Login<%p> : login retry timer fired\n", this) );
1530
1531		IOReturn login_status = executeLogin();
1532		if( login_status != kIOReturnSuccess )
1533		{
1534			completeLogin( login_status );
1535		}
1536	}
1537}
1538
1539void IOFireWireSBP2Login::abortLogin( void )
1540{
1541    // if we're in the middle of a login write, we need to cancel it
1542    // before aborting the command
1543    if( fLoginWriteInProgress )
1544        fLoginWriteCommand->cancel( kIOReturnAborted );
1545
1546    // cancel timeout
1547    if( fLoginTimeoutTimerSet )
1548        fLoginTimeoutCommand->cancel( kIOReturnAborted );
1549
1550    // set state
1551    fLoginState = kLoginStateIdle;
1552
1553    // complete command
1554//    completeLogin( kIOReturnTimeout );  //zzz is this a good error?, this is what OS9 returns
1555}
1556
1557void IOFireWireSBP2Login::completeLogin( IOReturn state, const void *buf, UInt32 len, void * buf2 )
1558{
1559	FWKLOG( ( "IOFireWireSBP2Login<%p> : completeLogin\n", this ) );
1560
1561	if( (fLoginFlags & kFWSBP2DontSynchronizeMgmtAgent) == 0 )
1562		fTarget->completeMgmtAgentAccess(  );
1563
1564	if( fInCriticalSection )
1565	{
1566		fInCriticalSection = false;
1567		if( fCriticalSectionCount > 0 )
1568		{
1569			fCriticalSectionCount--;
1570		}
1571		fTarget->endIOCriticalSection();
1572	}
1573
1574	if( (state != kIOReturnSuccess) &&
1575		((state != kIOFireWireBusReset) || !fUserLoginGenerationSet) &&
1576		(state != kIOReturnNotAttached) &&
1577		(fLoginRetryCount != 0) )
1578	{
1579		fLoginRetryCount--;
1580		startLoginRetryTimer();
1581	}
1582	else if( fLoginCompletionCallback != NULL )
1583    {
1584        FWSBP2LoginCompleteParams		params;
1585
1586		// try enabling unsolicited status now
1587		if( fUnsolicitedStatusEnableRequested )
1588		{
1589			fUnsolicitedStatusEnableRequested = false;
1590			executeUnsolicitedStatusEnable();
1591		}
1592
1593        params.login = this;
1594        params.generation = fLoginGeneration;
1595
1596        params.status = state;
1597        params.loginResponse = (FWSBP2LoginResponsePtr)buf2;
1598        params.statusBlock = (FWSBP2StatusBlock*)buf;
1599        params.statusBlockLength = len;
1600
1601         (*fLoginCompletionCallback)(fLoginCompletionRefCon, &params);
1602    }
1603}
1604
1605//
1606// status block handlers
1607//
1608
1609UInt32 IOFireWireSBP2Login::statusBlockWriteStatic(void *refcon, UInt16 nodeID, IOFWSpeed &speed,
1610                FWAddress addr, UInt32 len, const void *buf, IOFWRequestRefCon lockRead)
1611{
1612   	return ((IOFireWireSBP2Login*)refcon)->statusBlockWrite( nodeID, speed, addr, len, buf, lockRead );
1613}
1614
1615UInt32 IOFireWireSBP2Login::statusBlockWrite( UInt16 nodeID, IOFWSpeed &speed, FWAddress addr, UInt32 len,
1616                                              const void *buf, IOFWRequestRefCon lockRead )
1617{
1618    FWKLOG( ( "IOFireWireSBP2Login<%p> : status block write\n", this ) );
1619
1620
1621	if( len < 8 )
1622	{
1623	//	IOLog( "IOFireWireSBP2Login<0x%08lx> : illegal status block length = %d\n", this, len );
1624		return kFWResponseComplete;
1625	}
1626
1627    bzero( &fStatusBlock, sizeof(fStatusBlock) );
1628
1629    //�����������������
1630    if( len < sizeof(fStatusBlock) )
1631        bcopy( buf, &fStatusBlock, len);
1632    else
1633        bcopy( buf, &fStatusBlock, sizeof(fStatusBlock));
1634
1635	const void * client_status_block = &fStatusBlock;
1636
1637#if 0
1638	// compatibility hack for Craig's layer
1639
1640	FWSBP2StatusBlock host_status_block;
1641
1642	bzero( &host_status_block, sizeof(host_status_block) );
1643	bcopy( &fStatusBlock, &host_status_block, sizeof(host_status_block));
1644
1645    host_status_block.orbOffsetHi = OSSwapBigToHostInt16(fStatusBlock.orbOffsetHi);
1646    host_status_block.orbOffsetLo = OSSwapBigToHostInt32(fStatusBlock.orbOffsetLo);
1647
1648    SBP2SwapBigToHostInt32Array( &host_status_block.status, sizeof(host_status_block.status) );
1649
1650	client_status_block = &host_status_block;
1651#endif
1652
1653    switch( fLoginState )
1654    {
1655        case kLoginStateLoggingIn:
1656
1657            // complete login
1658
1659            // cancel timeout
1660            if( fLoginTimeoutTimerSet )
1661            {
1662                fLoginTimeoutCommand->cancel(kIOReturnSuccess);
1663            }
1664
1665			if( !fLoginStatusReceived )
1666			{
1667				bzero( &fLoginStatusBlock, sizeof(fLoginStatusBlock) );
1668
1669				//�����������������
1670				if( len < sizeof(fLoginStatusBlock) )
1671					bcopy( buf, &fLoginStatusBlock, len);
1672				else
1673					bcopy( buf, &fLoginStatusBlock, sizeof(fLoginStatusBlock));
1674
1675				fLoginStatusBlockLen = len;
1676
1677				if( fLoginWriteInProgress )
1678				{
1679					fLoginStatusReceived = true;
1680				}
1681				else
1682				{
1683					processLoginWrite();
1684				}
1685			}
1686
1687            break;
1688
1689        case kLoginStateConnected:
1690            // orb related or unsolicited
1691
1692            if( (fStatusBlock.details & 0xc0) == 0x80 )
1693            {
1694                // send unsolicited status
1695                if( fUnsolicitedStatusNotifyCallback != NULL )
1696                {
1697                    FWSBP2NotifyParams		params;
1698
1699                    params.message = client_status_block;
1700                    params.length = len;
1701                    params.notificationEvent = kFWSBP2UnsolicitedStatus;
1702                    params.generation = fLoginGeneration;
1703                    (*fUnsolicitedStatusNotifyCallback)(fUnsolicitedStatusNotifyRefCon, &params );
1704                }
1705
1706            }
1707            else
1708            {
1709                // normal command orb
1710
1711                // find ORB
1712                bool found = false;
1713
1714                FWAddress notificationAddress;
1715				notificationAddress.nodeID = 0x0000;
1716				notificationAddress.addressHi = OSSwapBigToHostInt16(fStatusBlock.orbOffsetHi);
1717				notificationAddress.addressLo = OSSwapBigToHostInt32(fStatusBlock.orbOffsetLo);
1718
1719                IOFireWireSBP2ORB * item = NULL;
1720                fORBSetIterator->reset();
1721                while( (found != true) && (item = (IOFireWireSBP2ORB *) fORBSetIterator->getNextObject())  )
1722                {
1723                    FWAddress address;
1724                    item->getORBAddress( &address );
1725                    if( (notificationAddress.addressHi & 0x0000ffff) == (address.addressHi & 0x0000ffff) &&
1726                         notificationAddress.addressLo == address.addressLo )
1727                    {
1728                        found = true;
1729                    }
1730                }
1731
1732                FWKLOG( ( "IOFireWireSBP2Login<%p> : solicited found = %d\n", this, found ) );
1733
1734				bool deadBitIsSet = fStatusBlock.details & 0x08;
1735
1736                if( found )
1737                {
1738					UInt32 flags = item->getCommandFlags();
1739
1740                    // cancel timer if set
1741                    if( isORBTimerSet( item ) )
1742                    {
1743                        cancelORBTimer( item);
1744
1745						if( isORBAppended( item ) )
1746						{
1747							setORBIsAppended( item, false );
1748							if( fCriticalSectionCount > 0 )
1749							{
1750								fCriticalSectionCount--;
1751							}
1752							fTarget->endIOCriticalSection();
1753						}
1754					}
1755                    else if( flags & kFWSBP2CommandCompleteNotify )
1756                    {
1757                        // if timer went off and then we get status, just ignore status.
1758                        // late arriving status will be discarded unless timeout duration is changed to zero
1759                        // at which point we can't tell that there ever was a timer running
1760                        break;
1761                    }
1762
1763					// send solicited status
1764
1765                    if( fStatusNotifyCallback != NULL )
1766                    {
1767                        FWSBP2NotifyParams		params;
1768
1769                        params.message = client_status_block;
1770                        params.length = len;
1771                        params.notificationEvent = kFWSBP2NormalCommandStatus;
1772                        params.generation = fLoginGeneration;
1773                        params.commandObject = item;
1774                        (*fStatusNotifyCallback)(fStatusNotifyRefCon, &params );
1775                    }
1776                }
1777
1778				if( deadBitIsSet )
1779				{
1780					// all tasks are aborted
1781					clearAllTasksInSet();
1782				}
1783            }
1784
1785            break;
1786
1787        case kLoginStateLoggingOut:
1788
1789            // cancel timeout
1790            if( fLogoutTimeoutTimerSet )
1791            {
1792                fLogoutTimeoutCommand->cancel(kIOReturnSuccess);
1793             }
1794
1795            // success or not
1796            if( ((fStatusBlock.details >> 4) & 3) == kFWSBP2RequestComplete &&
1797                fStatusBlock.sbpStatus == kFWSBP2NoSense )
1798            {
1799                FWKLOG( ( "IOFireWireSBP2Login<%p> : successful logout\n", this ) );
1800                fLoginState = kLoginStateIdle;
1801				fUnsolicitedStatusEnableRequested = false;
1802
1803                // get login ID and fetch agent address
1804                fLoginID = OSSwapBigToHostInt16(fLoginResponse.loginID);
1805                completeLogout( kIOReturnSuccess, client_status_block, len );
1806            }
1807            else
1808            {
1809                FWKLOG( ( "IOFireWireSBP2Login<%p> : logout failed!?\n", this ) );
1810                fLoginState = kLoginStateIdle;
1811				completeLogout( kIOReturnError, client_status_block, len );
1812            }
1813
1814			// all tasks are aborted
1815			clearAllTasksInSet();
1816
1817            break;
1818
1819        case kLoginStateReconnect:
1820        case kLoginStateIdle:
1821        default:
1822            FWKLOG( ( "IOFireWireSBP2Login<%p> : status block write on illegal state\n", this ) );
1823            break;
1824    }
1825
1826    return kFWResponseComplete;
1827}
1828
1829// processLoginWrite
1830//
1831//
1832
1833void IOFireWireSBP2Login::processLoginWrite( void )
1834{
1835	// success or not
1836	if( ((fLoginStatusBlock.details >> 4) & 3) == kFWSBP2RequestComplete &&
1837		fLoginStatusBlock.sbpStatus == kFWSBP2NoSense )
1838	{
1839		FWKLOG( ( "IOFireWireSBP2Login<%p> : successful login\n", this ) );
1840
1841		// get login ID and fetch agent address
1842		fLoginID = OSSwapBigToHostInt16(fLoginResponse.loginID);
1843		fReconnectORB.loginID = OSSwapHostToBigInt16(fLoginID);  // set id for reconnect;
1844
1845		// set reconnect_hold, some devices indicate it
1846		if( OSSwapBigToHostInt16(fLoginResponse.length) >= 16 )
1847			fReconnectHold = (OSSwapBigToHostInt16(fLoginResponse.reconnectHold) & 0x7fff) + 1;
1848		else
1849			fReconnectHold = 1;
1850
1851		UInt32 commandBlockAgentAddressHi = OSSwapBigToHostInt32(fLoginResponse.commandBlockAgentAddressHi);
1852		UInt32 commandBlockAgentAddressLo = OSSwapBigToHostInt32(fLoginResponse.commandBlockAgentAddressLo);
1853
1854		// set fetch agent reset address
1855		fFetchAgentResetAddress = FWAddress( commandBlockAgentAddressHi & 0x0000ffff,
1856											 commandBlockAgentAddressLo + 0x00000004 );
1857
1858		fFetchAgentResetCommand->reinit( fFetchAgentResetAddress,
1859										&fFetchAgentResetBuffer, 1,
1860										IOFireWireSBP2Login::fetchAgentResetCompleteStatic,
1861										this, true );
1862		fFetchAgentResetCommand->updateNodeID( fLoginGeneration, fLoginNodeID );
1863
1864		// set fetch agent address
1865		if( fFastStartSupported )
1866		{
1867			fFetchAgentAddress = FWAddress( commandBlockAgentAddressHi & 0x0000ffff,
1868											commandBlockAgentAddressLo + (fFastStartOffset << 2));
1869		}
1870		else
1871		{
1872			fFetchAgentAddress = FWAddress( commandBlockAgentAddressHi & 0x0000ffff,
1873											commandBlockAgentAddressLo + 0x00000008);
1874		}
1875
1876		fFetchAgentWriteCommand->reinit( fFetchAgentAddress,  // tis determined
1877										 fFetchAgentWriteCommandMemory,
1878										 IOFireWireSBP2Login::fetchAgentWriteCompleteStatic, this, true );
1879		fFetchAgentWriteCommand->updateNodeID( fLoginGeneration, fLoginNodeID );
1880		fFetchAgentWriteCommand->setRetries( 0 );
1881
1882		// set doorbell reset address
1883		fDoorbellAddress = FWAddress( commandBlockAgentAddressHi & 0x0000ffff,
1884									  commandBlockAgentAddressLo + 0x00000010 );
1885
1886		fDoorbellCommand->reinit( fDoorbellAddress,
1887								  &fDoorbellBuffer, 1,
1888								  IOFireWireSBP2Login::doorbellCompleteStatic,
1889								  this, true );
1890		fDoorbellCommand->updateNodeID( fLoginGeneration, fLoginNodeID );
1891
1892		// set unsolicited status enable address
1893		fUnsolicitedStatusEnableAddress = FWAddress( commandBlockAgentAddressHi & 0x0000ffff,
1894													 commandBlockAgentAddressLo + 0x00000014 );
1895
1896		fUnsolicitedStatusEnableCommand->reinit( fUnsolicitedStatusEnableAddress,
1897												 &fUnsolicitedStatusEnableBuffer, 1,
1898												 IOFireWireSBP2Login::unsolicitedStatusEnableCompleteStatic,
1899												 this, true );
1900		fUnsolicitedStatusEnableCommand->updateNodeID( fLoginGeneration, fLoginNodeID );
1901
1902		fLoginState = kLoginStateConnected;
1903
1904		completeLogin( kIOReturnSuccess, &fLoginStatusBlock, fLoginStatusBlockLen, &fLoginResponse );
1905	}
1906	else
1907	{
1908		FWKLOG( ( "IOFireWireSBP2Login<%p> : login failed\n", this ) );
1909		fLoginState = kLoginStateIdle;
1910
1911		completeLogin( kIOReturnError, &fLoginStatusBlock, fLoginStatusBlockLen, NULL );
1912	}
1913}
1914
1915#pragma mark -
1916/////////////////////////////////////////////////////////////////////
1917//
1918// reconnect path
1919//
1920
1921//
1922// suspendedNotify method
1923//
1924// called when a suspended message is received
1925
1926void IOFireWireSBP2Login::suspendedNotify( void )
1927{
1928    FWKLOG( ( "IOFireWireSBP2Login<%p> : suspendedNotify\n", this ) );
1929
1930	fSuspended = true;
1931
1932    UInt32 generation = fControl->getGeneration();
1933
1934	stopFetchAgentRetryTimer();		// better stop fetch agent retry timer on a bus reset
1935
1936    switch( fLoginState )
1937    {
1938        case kLoginStateConnected:
1939            // start/restart timer
1940            startReconnectTimer();
1941            break;
1942
1943        case kLoginStateReconnect:
1944			// cancel any pending reconnect retries
1945			stopReconnectRetryTimer();
1946
1947			// start/restart timer
1948			startReconnectTimer();
1949            break;
1950
1951        case kLoginStateLoggingIn:
1952			// login is valid until generation changes
1953			if( fLoginGeneration != generation )
1954			{
1955				abortLogin();
1956            }
1957			break;
1958
1959        case kLoginStateIdle:
1960        case kLoginStateLoggingOut:
1961        default:
1962            FWKLOG( ("IOFireWireSBP2Login<%p> : suspended notify, nothing to do\n", this) );
1963            break;
1964    }
1965}
1966
1967//
1968// resumeNotify method
1969//
1970// called when a resume message is received
1971
1972void IOFireWireSBP2Login::resumeNotify( void )
1973{
1974    FWKLOG( ( "IOFireWireSBP2Login<%p> : resume notify\n", this ) );
1975
1976    UInt32 generation = fControl->getGeneration();
1977	fPhysicalAccessEnabled = fUnit->isPhysicalAccessEnabled();
1978
1979	fSuspended = false;
1980
1981	executeSetBusyTimeout(); //can handle interruption
1982
1983	if( fLogoutPending )
1984	{
1985		fLogoutPending = false;
1986		executeLogout();
1987	}
1988	else
1989	{
1990		switch( fLoginState )
1991		{
1992			case kLoginStateReconnect:
1993				if( fLoginGeneration != generation )
1994				{
1995					// start/restart reconnect
1996					restartReconnect();
1997				}
1998				else
1999				{
2000					// already logged in this generation
2001					fLoginState = kLoginStateConnected;
2002					if( fReconnectTimeoutTimerSet )
2003						fReconnectTimeoutCommand->cancel(kIOReturnAborted);
2004				}
2005				break;
2006
2007			case kLoginStateLoggingIn:
2008				// login is valid until generation changes
2009				if( fLoginGeneration != generation)
2010				{
2011					abortLogin();
2012				}
2013				break;
2014
2015			case kLoginStateIdle:
2016			case kLoginStateLoggingOut:
2017			case kLoginStateConnected:
2018			default:
2019				FWKLOG( ("IOFireWireSBP2Login<%p> : resume notify, nothing to do\n", this) );
2020				break;
2021		}
2022	}
2023}
2024
2025// terminateNotify method
2026//
2027// called when a terminated message is received
2028
2029void IOFireWireSBP2Login::terminateNotify( void )
2030{
2031    FWKLOG( ( "IOFireWireSBP2Login<%p> : terminate notify\n", this ) );
2032
2033	if( fLogoutPending )
2034	{
2035		fLogoutPending = false;
2036	}
2037	else
2038	{
2039		switch( fLoginState )
2040		{
2041			case kLoginStateReconnect:
2042				if( fReconnectTimeoutTimerSet )
2043					fReconnectTimeoutCommand->cancel(kIOReturnAborted);
2044				break;
2045
2046			case kLoginStateLoggingIn:
2047				abortLogin();
2048				break;
2049
2050			case kLoginStateIdle:
2051			case kLoginStateLoggingOut:
2052			case kLoginStateConnected:
2053			case kLoginStateTerminated:
2054			default:
2055				FWKLOG( ("IOFireWireSBP2Login<%p> : terminate notify, nothing to do\n", this) );
2056				break;
2057		}
2058
2059		// cancel timeout
2060		if( fLoginRetryTimeoutTimerSet )
2061		{
2062			fLoginRetryTimeoutCommand->cancel( kIOReturnAborted );
2063			fLoginState = kLoginStateTerminated;
2064			completeLogin( kIOReturnNotAttached );
2065		}
2066	}
2067}
2068
2069// startReconnectTimer
2070//
2071//
2072
2073void IOFireWireSBP2Login::startReconnectTimer( void )
2074{
2075	IOReturn status = kIOReturnSuccess;
2076
2077	fLoginState = kLoginStateReconnect;
2078
2079    if( fReconnectTimeoutTimerSet )
2080         fReconnectTimeoutCommand->cancel(kIOReturnAborted);
2081
2082    FWKLOGASSERT( status == kIOReturnSuccess );
2083
2084    // start a reconnect timer
2085
2086    // even if a device went away
2087    // we want to keep trying for up to the reconnect timeout. maybe we'll get
2088    // another bus reset and the device will be back, and still willing to reconnect
2089
2090    // this assumes that transient errors might cause us to loose sight of the device
2091    // for short periods (shorter than the timeout).  if the reconnect timeout is
2092    // really large (several seconds) then maybe we'll wait too long.
2093
2094    // zzz some devices wait until the end of the reconnect interval before they
2095    // acknowledge a reconnect.  that seems bad, but for now add one second of fudge
2096    // factor so we can tolerate this.
2097
2098	// reconnect hold is in seconds, createDelayed cmd expects microseconds
2099
2100	fReconnectTimeoutCommand->reinit( ((fManagementTimeout + 1000) * 1000),
2101									  IOFireWireSBP2Login::reconnectTimeoutStatic, this);
2102
2103    // we wrote the management agent, now set a timer and wait for response & status
2104    fReconnectTimeoutTimerSet = true;
2105
2106	status = fReconnectTimeoutCommand->submit();
2107	if( status != kIOReturnSuccess )
2108	{
2109		fReconnectTimeoutTimerSet = false;
2110	}
2111
2112#if FWLOGGING
2113    if( fReconnectTimeoutTimerSet )
2114    FWKLOG( ("IOFireWireSBP2Login<%p> : reconnect timeout set for %d microseconds \n", this, ((fManagementTimeout + 1000) * 1000)) );
2115#endif
2116
2117}
2118
2119// doReconnect
2120//
2121// called when we recieve bus reset notification while we're logged in
2122// also called if we get a second reset while reconnecting, but only after
2123// the first reconnect attempt has been cleaned up.
2124//
2125// starts reconnect processs by writing a reconnect ORB to the target
2126// the remainder of the process occurs after the write command complete
2127
2128void IOFireWireSBP2Login::doReconnect( void )
2129{
2130    FWKLOG( ("IOFireWireSBP2Login<%p> : reconnect\n", this) );
2131
2132	IOReturn status = fTarget->beginIOCriticalSection();
2133	if( status != kIOReturnSuccess )
2134	{
2135		IOLog( "IOFireWireSBP2Login<0x%08lx>::doReconnect fTarget->beginIOCriticalSection() returned 0x%08lx\n", (UInt32)status);
2136		return;
2137	}
2138
2139	fInCriticalSection = true;
2140	fCriticalSectionCount++;
2141
2142    // set to correct generation
2143    fReconnectWriteCommand->reinit( FWAddress(0x0000ffff, 0xf0000000 + (fManagementOffset << 2)),
2144                                    fReconnectWriteCommandMemory, IOFireWireSBP2Login::reconnectWriteCompleteStatic,
2145                                    this, true );
2146
2147    // get local node and generation
2148    // note: these two are latched after command gen is set and before submit is called
2149    // if these are old command will fail
2150    fUnit->getNodeIDGeneration(fLoginGeneration, fLoginNodeID, fLocalNodeID);
2151
2152    fReconnectWriteInProgress = true;
2153
2154	if( fLoginFlags & kFWSBP2DontSynchronizeMgmtAgent )
2155		status = fReconnectWriteCommand->submit();
2156	else
2157		status = fTarget->synchMgmtAgentAccess( fReconnectWriteCommand );
2158
2159	if( status == kIOFireWireBusReset )
2160	{
2161		fReconnectWriteInProgress = false;
2162    }
2163	else if( status != kIOReturnSuccess )
2164    {
2165        fLoginState = kLoginStateIdle;
2166        fReconnectWriteInProgress = false;
2167		sendReconnectNotification( kIOMessageFWSBP2ReconnectFailed );
2168    }
2169
2170}
2171
2172// restartReconnect
2173//
2174// Called if we get a bus reset while we are already trying to reconnect.
2175// Per sbp-2, the entire reconnect process (and timer) starts over again.
2176// So we clean up the in-progress reconnect attempt and try again.
2177
2178void IOFireWireSBP2Login::restartReconnect( void )
2179{
2180    // we may be in two possible states
2181    // (1) we are waiting for the reconnect write to complete
2182    // (2) we are waiting for either the timer to go off or a response from the target
2183
2184    // case (1)
2185
2186    if( fReconnectWriteInProgress )
2187    {
2188        // the write will fail with a bus reset error, unless it is already
2189        // complete and waiting for completion to happen.
2190        // (can that happen? does completion get called immediately, or is it q'd?)
2191        //
2192        // in any case, we know that it has not run yet, so we just make a note about this
2193        // new reset, so that when it does run, it can continue to work.  That way, even if
2194        // it thought the write completed, it can immediately start over.
2195        // the reset makes even a completed write pointless.
2196
2197        fReconnectWriteInterrupted = true;
2198    }
2199    else
2200    {
2201        // case (2)
2202
2203        // we already wrote the reconnect ORB to the target and we are waiting for either a
2204        // timeout or a response from the target.
2205        //
2206
2207        // restart reconnect
2208        doReconnect();
2209
2210        //zzz what if timer has gone off but not run?
2211    }
2212}
2213
2214//
2215// reconnect write completion handler
2216//
2217
2218void IOFireWireSBP2Login::reconnectWriteCompleteStatic( void *refcon, IOReturn status, IOFireWireNub *device,
2219                                                        IOFWCommand *fwCmd )
2220{
2221    ((IOFireWireSBP2Login*)refcon)->reconnectWriteComplete( status, device, fwCmd );
2222}
2223
2224void IOFireWireSBP2Login::reconnectWriteComplete( IOReturn status, IOFireWireNub *device, IOFWCommand *fwCmd )
2225{
2226    FWKLOG( ("IOFireWireSBP2Login<%p> : reconnectWriteComplete \n", this) );
2227
2228    fReconnectWriteInProgress = false;
2229
2230	if( fReconnectWriteInterrupted )
2231    {
2232        fReconnectWriteInterrupted = false;
2233        doReconnect();
2234    }
2235	else if( status == kIOFireWireResponseBase+kFWResponseConflictError )
2236	{
2237		// retry reconnect
2238		startReconnectRetryTimer();
2239	}
2240}
2241
2242//
2243// reconnect timeout handler
2244//
2245
2246void IOFireWireSBP2Login::reconnectTimeoutStatic( void *refcon, IOReturn status, IOFireWireBus *bus,
2247                                                  IOFWBusCommand *fwCmd )
2248{
2249    ((IOFireWireSBP2Login*)refcon)->reconnectTimeout( status, bus, fwCmd );
2250}
2251
2252void IOFireWireSBP2Login::reconnectTimeout( IOReturn status, IOFireWireBus *bus, IOFWBusCommand *fwCmd )
2253{
2254    fReconnectTimeoutTimerSet = false;
2255    FWKLOG( ("IOFireWireSBP2Login<%p> : reconnect timeout proc, status = 0x%08lx\n", this, status) );
2256
2257	if( fInCriticalSection )
2258	{
2259		fInCriticalSection = false;
2260		if( fCriticalSectionCount > 0 )
2261		{
2262			fCriticalSectionCount--;
2263		}
2264		fTarget->endIOCriticalSection();
2265	}
2266
2267    if(status == kIOReturnTimeout)
2268    {
2269        FWKLOG( ("IOFireWireSBP2Login<0x%08lx> : reconnect timeout\n") );
2270
2271        // only send failure notification if we really failed
2272        // zzz is this necessary
2273        if( fLoginState == kLoginStateReconnect )
2274        {
2275            // reset state machine
2276            fLoginState = kLoginStateIdle;
2277
2278			// stop any retries that might have been in progress
2279			stopReconnectRetryTimer();
2280
2281			if( fLogoutPending )
2282				executeLogout();
2283			else
2284				sendReconnectNotification( kIOMessageFWSBP2ReconnectFailed );
2285        }
2286     }
2287}
2288
2289//
2290// reconnect status block handler
2291//
2292
2293UInt32 IOFireWireSBP2Login::reconnectStatusBlockWriteStatic(void *refcon, UInt16 nodeID, IOFWSpeed &speed,
2294                                                            FWAddress addr, UInt32 len, const void *buf,
2295                                                            IOFWRequestRefCon lockRead)
2296{
2297    return ((IOFireWireSBP2Login*)refcon)->reconnectStatusBlockWrite( nodeID, speed, addr, len, buf, lockRead );
2298}
2299
2300UInt32 IOFireWireSBP2Login::reconnectStatusBlockWrite( UInt16 nodeID, IOFWSpeed &speed, FWAddress addr,
2301                                                       UInt32 len, const void *buf, IOFWRequestRefCon lockRead )
2302{
2303    FWKLOG( ("IOFireWireSBP2Login<%p> : reconnect status block write\n", this) );
2304
2305//IOLog("length %ld contents %08lx %08lx\n", len, *((UInt32 *)buf),  *(1+(UInt32 *)buf) );
2306
2307    // this is possibly a belated reconnect acknowledgement. if so ignore it
2308    if( !fReconnectTimeoutTimerSet )
2309    {
2310        FWKLOG( ("IOFireWireSBP2Login<%p> : reconnect status block write after timer went off\n", this) );
2311        return kFWResponseComplete;
2312    }
2313
2314    // this is possibly a write that came in before the most recent bus reset
2315    // if so ignore it
2316    if( fLoginGeneration != fControl->getGeneration() )
2317    {
2318        FWKLOG( ("IOFireWireSBP2Login<%p> : reconnect status block write for wrong generation\n", this) );
2319        return kFWResponseComplete;
2320    }
2321
2322    bzero( &fReconnectStatusBlock, sizeof(fReconnectStatusBlock) );
2323
2324    if( len < sizeof(fReconnectStatusBlock) )
2325        bcopy( buf, &fReconnectStatusBlock, len);
2326    else
2327        bcopy( buf, &fReconnectStatusBlock, sizeof(fReconnectStatusBlock));
2328
2329    // erfolgreich �der nicht?
2330    if( ( ( ( fReconnectStatusBlock.details >> 4 ) & 3 ) == kFWSBP2RequestComplete ) &&
2331        ( fReconnectStatusBlock.sbpStatus == kFWSBP2NoSense ) )
2332    {
2333        FWKLOG( ( "IOFireWireSBP2Login<%p> : successful reconnect\n", this ) );
2334
2335		// cancel timer, won't get here if its not set
2336		fReconnectTimeoutCommand->cancel(kIOReturnAborted);
2337
2338        if( fLastORB )
2339        {
2340            fLastORB->release();
2341            fLastORB = NULL;
2342        }
2343		fLastORBAddress = FWAddress(0,0);
2344        fLoginState = kLoginStateConnected;
2345
2346        // set generation
2347        fFetchAgentWriteCommand->reinit( fFetchAgentAddress,
2348                                         fFetchAgentWriteCommandMemory,
2349                                         IOFireWireSBP2Login::fetchAgentWriteCompleteStatic, this, true );
2350		fFetchAgentWriteCommand->updateNodeID( fLoginGeneration, fLoginNodeID );
2351		fFetchAgentWriteCommand->setRetries( 0 );
2352
2353		// try enabling unsolicited status now
2354		if( fUnsolicitedStatusEnableRequested )
2355		{
2356			fUnsolicitedStatusEnableRequested = false;
2357			executeUnsolicitedStatusEnable();
2358		}
2359
2360		if( fLogoutPending )
2361		{
2362			fLogoutPending = false;
2363			executeLogout();
2364		}
2365		else
2366			sendReconnectNotificationWithStatusBlock( kIOMessageFWSBP2ReconnectComplete );
2367	}
2368	else if( ( ( ( fReconnectStatusBlock.details >> 4 ) & 3 ) == kFWSBP2RequestComplete ) &&
2369			 ( fReconnectStatusBlock.sbpStatus == kFWSBP2UnspecifiedError ) )
2370	{
2371		// retry reconnect
2372		startReconnectRetryTimer();
2373	}
2374    else
2375    {
2376        FWKLOG( ( "IOFireWireSBP2Login<%p> : reconnect failed\n", this ) );
2377
2378		// cancel timer, won't get here if its not set
2379		fReconnectTimeoutCommand->cancel(kIOReturnAborted);
2380
2381        fLoginState = kLoginStateIdle;
2382		if( fLogoutPending )
2383		{
2384			fLogoutPending = false;
2385			executeLogout();
2386		}
2387		else
2388			sendReconnectNotificationWithStatusBlock( kIOMessageFWSBP2ReconnectFailed );
2389    }
2390
2391    return kFWResponseComplete;
2392}
2393
2394// reconnect retry timeout
2395//
2396//
2397
2398void IOFireWireSBP2Login::startReconnectRetryTimer( void )
2399{
2400	stopReconnectRetryTimer();
2401
2402	fReconnectRetryTimeoutTimerSet = true;
2403	if( fReconnectRetryTimeoutCommand->submit() != kIOReturnSuccess )
2404		fReconnectRetryTimeoutTimerSet = false;
2405}
2406
2407void IOFireWireSBP2Login::stopReconnectRetryTimer( void )
2408{
2409	// cancel timeout
2410    if( fReconnectRetryTimeoutTimerSet )
2411        fReconnectRetryTimeoutCommand->cancel( kIOReturnAborted );
2412}
2413
2414void IOFireWireSBP2Login::reconnectRetryTimeoutStatic( void *refcon, IOReturn status,
2415                                                   IOFireWireBus *bus, IOFWBusCommand *fwCmd)
2416{
2417    ((IOFireWireSBP2Login*)refcon)->reconnectRetryTimeout( status, bus, fwCmd );
2418}
2419
2420void IOFireWireSBP2Login::reconnectRetryTimeout( IOReturn status, IOFireWireBus *bus, IOFWBusCommand *fwCmd)
2421{
2422    fReconnectRetryTimeoutTimerSet = false;
2423    if( status == kIOReturnTimeout )
2424    {
2425        FWKLOG( ("IOFireWireSBP2Login<%p> : reconnect retry timer fired\n", this) );
2426
2427		doReconnect();
2428	}
2429}
2430
2431//
2432// send reconnect notification
2433//
2434
2435void IOFireWireSBP2Login::sendReconnectNotification( UInt32 event )
2436{
2437    FWSBP2ReconnectParams		params;
2438
2439   	if( (fLoginFlags & kFWSBP2DontSynchronizeMgmtAgent) == 0 )
2440		fTarget->completeMgmtAgentAccess(  );
2441
2442    params.login = this;
2443    params.generation = fLoginGeneration;
2444
2445    params.reconnectStatusBlock = NULL;
2446    params.reconnectStatusBlockLength = 0;
2447
2448    FWKLOG( ( "IOFireWireSBP2Login<%p> : arg address 0x%08lx\n", this, &params ) );
2449
2450    FWKLOG( ( "IOFireWireSBP2Login<%p> : reconnectStatusBlock 0x%08lx, reconnectStatusBlockLength 0x%08lx\n", this, params.reconnectStatusBlock, params.reconnectStatusBlockLength ) );
2451
2452    fTarget->messageClients( event, &params );
2453	fLUN->messageClients( event, &params );
2454}
2455
2456void IOFireWireSBP2Login::sendReconnectNotificationWithStatusBlock( UInt32 event )
2457{
2458    FWSBP2ReconnectParams		params;
2459
2460     if( (fLoginFlags & kFWSBP2DontSynchronizeMgmtAgent) == 0 )
2461		fTarget->completeMgmtAgentAccess(  );
2462
2463    params.login = this;
2464    params.generation = fLoginGeneration;
2465
2466    params.reconnectStatusBlock = &fReconnectStatusBlock;
2467    params.reconnectStatusBlockLength = sizeof(FWSBP2StatusBlock);
2468
2469    FWKLOG( ( "IOFireWireSBP2Login<%p> : arg address 0x%08lx\n", this, &params ) );
2470    FWKLOG( ( "IOFireWireSBP2Login<%p> : reconnectStatusBlock 0x%08lx, reconnectStatusBlockLength 0x%08lx\n", this, params.reconnectStatusBlock, params.reconnectStatusBlockLength ) );
2471    fTarget->messageClients( event, &params );
2472	fLUN->messageClients( event, &params );
2473}
2474
2475#pragma mark -
2476/////////////////////////////////////////////////////////////////////
2477//
2478// logout path
2479//
2480
2481// submitLogout
2482//
2483//
2484
2485IOReturn IOFireWireSBP2Login::submitLogout( void )
2486{
2487    IOReturn status = kIOReturnSuccess;
2488
2489	status = fGate->runAction( staticExecuteLogout );
2490
2491	return status;
2492}
2493
2494IOReturn IOFireWireSBP2Login::staticExecuteLogout( OSObject *self, void *, void *, void *, void * )
2495{
2496	return ((IOFireWireSBP2Login *)self)->executeLogout();
2497}
2498
2499IOReturn IOFireWireSBP2Login::executeLogout( void )
2500{
2501    FWKLOG( ( "IOFireWireSBP2Login<%p> : executeLogout\n", this ) );
2502
2503	// are we already processing a logout
2504	if( fLoginState == kLoginStateLoggingOut || fLogoutPending )
2505	{
2506		return kIOReturnBusy;
2507	}
2508
2509	// logout while suspended
2510	if( fSuspended )
2511	{
2512		fLogoutPending = true;
2513	}
2514
2515	// logout during login
2516	if( fLoginState == kLoginStateLoggingIn )
2517	{
2518		return kIOReturnBusy;
2519	}
2520
2521	// logout during reconnect
2522	if( fLoginState == kLoginStateReconnect )
2523	{
2524		fLogoutPending = true;
2525	}
2526
2527	if( fLoginState == kLoginStateIdle )
2528	{
2529//		completeLogout( kIOReturnSuccess );
2530// zzz what do I do here?
2531		return kIOReturnSuccess;
2532	}
2533
2534	if( fLoginState == kLoginStateConnected )
2535	{
2536		fLoginState = kLoginStateLoggingOut;
2537		fLogoutORB.loginID = OSSwapHostToBigInt16(fLoginID);
2538
2539		// set to correct generation
2540		fLogoutWriteCommand->reinit( FWAddress(0x0000ffff, 0xf0000000 + (fManagementOffset << 2)),
2541									fLogoutWriteCommandMemory, IOFireWireSBP2Login::logoutWriteCompleteStatic,
2542									this, true );
2543		fLogoutWriteCommand->updateNodeID( fLoginGeneration, fLoginNodeID );
2544
2545		IOReturn status = fTarget->beginIOCriticalSection();
2546
2547		if( status == kIOReturnSuccess )
2548		{
2549			fInCriticalSection = true;
2550			fCriticalSectionCount++;
2551			fLogoutWriteInProgress = true;
2552			status = fLogoutWriteCommand->submit();
2553		}
2554
2555		if( status != kIOReturnSuccess )
2556		{
2557			// fLoginState = kLoginStateIdle;   //zzz what do I do here?
2558			fLogoutWriteInProgress = false;
2559
2560			if( fInCriticalSection )
2561			{
2562				fInCriticalSection = false;
2563				if( fCriticalSectionCount > 0 )
2564				{
2565					fCriticalSectionCount--;
2566				}
2567				fTarget->endIOCriticalSection();
2568			}
2569
2570			return status;
2571		}
2572	}
2573
2574    return kIOReturnSuccess;
2575}
2576
2577//
2578// logout write complete handler
2579//
2580
2581void IOFireWireSBP2Login::logoutWriteCompleteStatic( void *refcon, IOReturn status, IOFireWireNub *device,
2582                                                     IOFWCommand *fwCmd )
2583{
2584    ((IOFireWireSBP2Login*)refcon)->logoutWriteComplete( status, device, fwCmd );
2585}
2586
2587void IOFireWireSBP2Login::logoutWriteComplete( IOReturn status, IOFireWireNub *device, IOFWCommand *fwCmd )
2588{
2589    FWKLOG( ( "IOFireWireSBP2Login<%p> : logoutWriteComplete \n", this ) );
2590
2591    fLogoutWriteInProgress = false;
2592
2593    if( status == kIOReturnSuccess )
2594    {
2595        // we wrote the management agent, now set a timer and wait for response & status
2596        fLogoutTimeoutTimerSet = true;
2597		if( fLogoutTimeoutCommand->submit() != kIOReturnSuccess )
2598			fLogoutTimeoutTimerSet = false;
2599    }
2600    else
2601    {
2602        fLoginState = kLoginStateIdle;
2603        completeLogout( status );  // complete with error
2604    }
2605}
2606
2607//
2608// logout timeout handler
2609//
2610
2611void IOFireWireSBP2Login::logoutTimeoutStatic( void *refcon, IOReturn status, IOFireWireBus *bus, IOFWBusCommand *fwCmd )
2612{
2613    ((IOFireWireSBP2Login*)refcon)->logoutTimeout( status, bus, fwCmd );
2614}
2615
2616void IOFireWireSBP2Login::logoutTimeout( IOReturn status, IOFireWireBus *bus, IOFWBusCommand *fwCmd )
2617{
2618    FWKLOG( ( "IOFireWireSBP2Login<%p> : logoutTimeout \n", this ) );
2619
2620    fLogoutTimeoutTimerSet = false;
2621    if( status != kIOReturnSuccess )
2622    {
2623        FWKLOG( ("IOFireWireSBP2Login<%p> : logout timed out\n", this) );
2624
2625        // back to idle
2626        fLoginState = kLoginStateIdle;
2627        completeLogout( status );
2628     }
2629}
2630
2631void IOFireWireSBP2Login::completeLogout( IOReturn state, const void *buf, UInt32 len )
2632{
2633	FWKLOG( ( "IOFireWireSBP2Login<%p> : completeLogout\n", this ) );
2634
2635	if( fInCriticalSection )
2636	{
2637		fInCriticalSection = false;
2638		if( fCriticalSectionCount > 0 )
2639		{
2640			fCriticalSectionCount--;
2641		}
2642		fTarget->endIOCriticalSection();
2643	}
2644
2645    if( fLogoutCompletionCallback != NULL )
2646    {
2647        FWSBP2LogoutCompleteParams		params;
2648
2649        params.login = this;
2650        params.generation = fLoginGeneration;
2651
2652        params.status = state;
2653        params.statusBlock = (FWSBP2StatusBlock*)buf;
2654        params.statusBlockLength = len;
2655
2656        (*fLogoutCompletionCallback)(fLogoutCompletionRefCon, &params);
2657    }
2658}
2659
2660void IOFireWireSBP2Login::clearAllTasksInSet( void )
2661{
2662	stopFetchAgentRetryTimer();
2663
2664	// send reset notification for each orb
2665	// find ORB
2666	IOFireWireSBP2ORB * item;
2667	fORBSetIterator->reset();
2668	while( (item = (IOFireWireSBP2ORB *) fORBSetIterator->getNextObject()) )
2669	{
2670		if( isORBTimerSet( item ) )
2671		{
2672			cancelORBTimer( item );
2673
2674			if( isORBAppended( item ) )
2675			{
2676				setORBIsAppended( item, false );
2677				if( fCriticalSectionCount > 0 )
2678				{
2679					fCriticalSectionCount--;
2680				}
2681                fTarget->endIOCriticalSection();
2682            }
2683
2684			// send solicited status
2685			if( fStatusNotifyCallback != NULL )
2686			{
2687				FWSBP2NotifyParams		params;
2688
2689				params.message = 0;
2690				params.length = 0;
2691				params.notificationEvent = kFWSBP2NormalCommandReset;
2692				params.generation = fLoginGeneration;
2693				params.commandObject = item;
2694				(*fStatusNotifyCallback)(fStatusNotifyRefCon, &params );
2695			}
2696		}
2697	}
2698
2699	// if we've set aside an orb we have not set its timer yet
2700	if( fORBToWrite )
2701	{
2702		item = fORBToWrite;
2703		fORBToWrite = 0;
2704
2705		if( item->getCommandTimeout() != 0 )
2706		{
2707			// send solicited status
2708			if( fStatusNotifyCallback != NULL )
2709			{
2710				FWSBP2NotifyParams		params;
2711
2712				params.message = 0;
2713				params.length = 0;
2714				params.notificationEvent = kFWSBP2NormalCommandReset;
2715				params.generation = fLoginGeneration;
2716				params.commandObject = item;
2717				(*fStatusNotifyCallback)(fStatusNotifyRefCon, &params );
2718			}
2719		}
2720	}
2721
2722    if( fLastORB )
2723    {
2724        fLastORB->release();
2725        fLastORB = NULL;
2726    }
2727	fLastORBAddress = FWAddress(0,0);
2728}
2729
2730#pragma mark -
2731/////////////////////////////////////////////////////////////////////
2732//
2733// command block ORB routines
2734
2735// createORB
2736//
2737// create an orb object
2738
2739IOFireWireSBP2ORB * IOFireWireSBP2Login::createORB( void )
2740{
2741    IOFireWireSBP2ORB * orb  = new IOFireWireSBP2ORB;
2742    if( orb != NULL && !initORBWithLogin( orb, this ) )
2743    {
2744    	orb->release();
2745    	orb = NULL;
2746    }
2747	else
2748	{
2749		addORB( orb );
2750    }
2751
2752    return orb;
2753}
2754
2755// addORB
2756//
2757//
2758
2759IOReturn IOFireWireSBP2Login::addORB( IOFireWireSBP2ORB * orb )
2760{
2761    IOReturn status = kIOReturnSuccess;
2762
2763	status = fGate->runAction( staticExecuteAddORB, (void*)orb );
2764
2765	return status;
2766}
2767
2768IOReturn IOFireWireSBP2Login::staticExecuteAddORB( OSObject *self, void * orb, void *, void *, void * )
2769{
2770	return ((IOFireWireSBP2Login *)self)->executeAddORB( (IOFireWireSBP2ORB*)orb );
2771}
2772
2773IOReturn IOFireWireSBP2Login::executeAddORB( IOFireWireSBP2ORB * orb )
2774{
2775	return fORBSet->setObject( orb );
2776}
2777
2778// removeORB
2779//
2780//
2781
2782IOReturn IOFireWireSBP2Login::removeORB( IOFireWireSBP2ORB * orb )
2783{
2784    IOReturn status = kIOReturnSuccess;
2785
2786	status = fGate->runAction( staticExecuteRemoveORB, (void*)orb );
2787
2788	return status;
2789}
2790
2791IOReturn IOFireWireSBP2Login::staticExecuteRemoveORB( OSObject *self, void * orb, void *, void *, void * )
2792{
2793	return ((IOFireWireSBP2Login *)self)->executeRemoveORB( (IOFireWireSBP2ORB*)orb );
2794}
2795
2796IOReturn IOFireWireSBP2Login::executeRemoveORB( IOFireWireSBP2ORB * orb )
2797{
2798	fORBSet->removeObject( orb );
2799
2800	return kIOReturnSuccess;
2801}
2802
2803// submitORB
2804//
2805//
2806
2807IOReturn IOFireWireSBP2Login::submitORB( IOFireWireSBP2ORB * orb )
2808{
2809    IOReturn status = kIOReturnSuccess;
2810
2811	status = fGate->runAction( staticExecuteORB, (void*)orb );
2812
2813    return status;
2814}
2815
2816IOReturn IOFireWireSBP2Login::staticExecuteORB( OSObject *self, void * orb, void *, void *, void * )
2817{
2818	return ((IOFireWireSBP2Login *)self)->executeORB( ( IOFireWireSBP2ORB *)orb );
2819}
2820
2821IOReturn IOFireWireSBP2Login::executeORB( IOFireWireSBP2ORB * orb )
2822{
2823	IOReturn 	status = kIOReturnSuccess;
2824	UInt32		commandFlags = 0;
2825
2826	if( !isConnected() )
2827    {
2828		status = kIOFireWireBusReset; //zzz better error
2829	}
2830
2831    if( status == kIOReturnSuccess )
2832    {
2833        commandFlags = orb->getCommandFlags();
2834    }
2835
2836    if( status == kIOReturnSuccess )
2837    {
2838        if( (fFetchAgentWriteCommandInUse || fFetchAgentRetryTimerSet) &&	// if we're still writing the fetch agent
2839			( commandFlags & kFWSBP2CommandImmediate ) &&					// and this is an immediate orb
2840			fORBToWrite )													// and we've already got another orb
2841        {
2842            FWKLOG(("IOFireWireSBP2Login<%p> : fetchAgentWriteCommand still in use\n", this ));
2843            status = kIOReturnNoResources;
2844        }
2845    }
2846
2847    if( status == kIOReturnSuccess )
2848    {
2849        UInt32 generation = orb->getCommandGeneration();
2850
2851        // check generation
2852        if( commandFlags & kFWSBP2CommandCheckGeneration && !fControl->checkGeneration(generation) )
2853            status = kIOFireWireBusReset;
2854    }
2855
2856	if( status == kIOReturnSuccess )
2857	{
2858		UInt32 targetFlags = fTarget->getTargetFlags();
2859		if( targetFlags & kIOFWSBP2FailsOnBusResetsDuringIO )
2860		{
2861			// sorry, no silent orbs if your device
2862			// can't handle bus resets at any time
2863			UInt32 orbFlags = orb->getCommandFlags();
2864			orb->setCommandFlags( orbFlags | kFWSBP2CommandCompleteNotify );
2865		}
2866	}
2867
2868    if( status == kIOReturnSuccess )
2869    {
2870        // retries failed fetch agent writes up to four times
2871        orb->setFetchAgentWriteRetries( 20 );
2872		orb->setFetchAgentWriteRetryInterval( 1000 );
2873        prepareORBForExecution(orb);
2874    }
2875
2876	if( status == kIOReturnSuccess && fFastStartSupported )
2877	{
2878		// setup fast start data
2879
2880		//
2881		// set fast start write length
2882		//
2883
2884		UInt32 maxPacketBytes = 1 << fUnit->maxPackLog(true,fFetchAgentAddress);
2885		UInt32 fastStartPacketBytes = fFastStartMaxPayload << 2;
2886		if( fastStartPacketBytes == 0 )
2887		{
2888			fastStartPacketBytes = maxPacketBytes;
2889		}
2890		else if( maxPacketBytes < fastStartPacketBytes )
2891		{
2892			fastStartPacketBytes = maxPacketBytes;
2893		}
2894
2895		IOBufferMemoryDescriptor * descriptor = OSDynamicCast(IOBufferMemoryDescriptor, fFetchAgentWriteCommandMemory);
2896
2897		if( descriptor == NULL )
2898		{
2899			panic( "IOFireWireSBP2Login<0x%08lx>::executeORB() - fFetchAgentWriteCommandMemory is not an IOBufferMemoryDescriptor!\n", this );
2900		}
2901
2902		descriptor->setLength( fastStartPacketBytes );
2903
2904		//
2905		// write previous orb
2906		//
2907
2908		{
2909			FWAddress orbAddress(0,0);
2910			if( commandFlags & kFWSBP2CommandImmediate )
2911			{
2912				orbAddress = FWAddress(0,0);
2913			}
2914			else
2915			{
2916				orbAddress = fLastORBAddress;
2917			}
2918
2919			if( orbAddress.addressHi == 0 && orbAddress.addressLo == 0 )
2920			{
2921				orbAddress.nodeID = OSSwapHostToBigInt16(0x8000);
2922			}
2923			else
2924			{
2925				orbAddress.nodeID = OSSwapHostToBigInt16(fLocalNodeID);
2926			}
2927			descriptor->writeBytes( 0, &orbAddress, sizeof(FWAddress) );
2928		}
2929
2930		//
2931		// write this orb
2932		//
2933		{
2934			FWAddress orbAddress(0,0);
2935			orb->getORBAddress( &orbAddress );
2936
2937			orbAddress.nodeID = OSSwapHostToBigInt16(fLocalNodeID);
2938			orbAddress.addressHi = OSSwapHostToBigInt16(orbAddress.addressHi);
2939			orbAddress.addressLo = OSSwapHostToBigInt32(orbAddress.addressLo);
2940
2941			descriptor->writeBytes( 8, &orbAddress, sizeof(FWAddress) );
2942		}
2943
2944		//
2945		// prepare orb and page table
2946		//
2947
2948		orb->prepareFastStartPacket( descriptor );
2949
2950		fastStartPacketBytes = descriptor->getLength();
2951	}
2952
2953#if FWDIAGNOSTICS
2954	((IOFireWireSBP2Diagnostics*)(fLUN->getDiagnostics()))->incrementExecutedORBCount();
2955#endif
2956
2957    if( status == kIOReturnSuccess )
2958    {
2959        if( commandFlags & kFWSBP2CommandImmediate )
2960        {
2961            if( fLastORB )
2962            {
2963                fLastORB->release();
2964                fLastORB = NULL;
2965            }
2966
2967			FWAddress orbAddress(0,0);
2968			orb->getORBAddress( &orbAddress );
2969
2970			fLastORBAddress.nodeID = OSSwapHostToBigInt16(orbAddress.nodeID);
2971			fLastORBAddress.addressHi = OSSwapHostToBigInt16(orbAddress.addressHi);
2972			fLastORBAddress.addressLo = OSSwapHostToBigInt32(orbAddress.addressLo);
2973            orb->retain();
2974			fLastORB = orb;
2975
2976			if( fFetchAgentWriteCommandInUse )
2977			{
2978				fORBToWrite = orb;
2979		//		IOLog( "IOFireWireSBP2Login : fetch agent write command busy, putting aside orb 0x%08lx\n", orb );
2980			}
2981			else
2982			{
2983				startORBTimer(orb);
2984				if( fTarget->beginIOCriticalSection() == kIOReturnSuccess )
2985				{
2986#if PANIC_ON_DOUBLE_APPEND
2987					if( isORBAppended( orb ) )
2988					{
2989						panic( "IOFireWireSBP2Login::executeORB - double appending orb!\n" );
2990					}
2991#endif
2992					fCriticalSectionCount++;
2993					setORBIsAppended( orb, true );
2994					status = appendORBImmediate( orb );
2995				}
2996			}
2997		}
2998        else
2999        {
3000			startORBTimer(orb);
3001            if( fTarget->beginIOCriticalSection() == kIOReturnSuccess )
3002			{
3003#if PANIC_ON_DOUBLE_APPEND
3004					if( isORBAppended( orb ) )
3005					{
3006						panic( "IOFireWireSBP2Login::executeORB - double appending orb!\n" );
3007					}
3008#endif
3009
3010				fCriticalSectionCount++;
3011				setORBIsAppended( orb, true );
3012
3013				status = appendORB( orb );
3014
3015				// clean up if there are no ORBs to chain to or if we
3016				// tried to chain to ourselves
3017
3018				if( status != kIOReturnSuccess )
3019				{
3020					cancelORBTimer( orb );
3021					setORBIsAppended( orb, false );
3022					if( fCriticalSectionCount > 0 )
3023					{
3024						fCriticalSectionCount--;
3025					}
3026					fTarget->endIOCriticalSection();
3027				}
3028			}
3029		}
3030    }
3031
3032    return status;
3033}
3034
3035
3036// are we connected?
3037bool IOFireWireSBP2Login::isConnected( void )
3038{
3039    return (fLoginState == kLoginStateConnected);
3040}
3041
3042void IOFireWireSBP2Login::setFetchAgentWriteCompletion( void * refCon, FWSBP2FetchAgentWriteCallback completion )
3043{
3044	fFetchAgentWriteCompletion = completion;
3045	fFetchAgentWriteRefCon = refCon;
3046}
3047
3048//
3049// fetchAgentWrite completion handler
3050//
3051
3052void IOFireWireSBP2Login::fetchAgentWriteCompleteStatic( void *refcon, IOReturn status, IOFireWireNub *device, IOFWCommand *fwCmd )
3053{
3054    ((IOFireWireSBP2Login*)refcon)->fetchAgentWriteComplete( status, device, fwCmd );
3055}
3056
3057void IOFireWireSBP2Login::fetchAgentWriteComplete( IOReturn status, IOFireWireNub *device, IOFWCommand *fwCmd )
3058{
3059	IOFireWireSBP2ORB * orb = fORBToWrite;
3060
3061	fFetchAgentWriteCommandInUse = false;
3062
3063	if( fLastORB != NULL )
3064	{
3065
3066		UInt32 retries = fLastORB->getFetchAgentWriteRetries();
3067		int ack = fFetchAgentWriteCommand->getAckCode();
3068		int rcode = fFetchAgentWriteCommand->getResponseCode();
3069
3070		if(  status != kIOReturnSuccess &&
3071			 status != kIOFireWireBusReset &&
3072			 retries != 0 )
3073		{
3074			if( (ack == kFWAckBusyX) ||
3075				(ack == kFWAckBusyA) ||
3076				(ack == kFWAckBusyB) )
3077			{
3078
3079	//			IOLog( "IOFireWireSBP2Login::fetchAgentWriteComplete fetch agent write failed! retrying\n" );
3080
3081	#if PANIC_ON_DOUBLE_APPEND
3082				panic( "IOFireWireSBP2Login::fetchAgentWriteComplete fetch agent write failed!\n" );
3083	#endif
3084
3085				// retry
3086				retries--;
3087				fLastORB->setFetchAgentWriteRetries( retries );
3088
3089				// on busy family already delays for split timeout
3090
3091				if( kFetchAgentRetryInterval > kFetchAgentSplitTimeout )
3092				{
3093					// wait a bit logner
3094					startFetchAgentRetryTimer( kFetchAgentRetryInterval - kFetchAgentSplitTimeout );
3095				}
3096				else
3097				{
3098					// waited long enough, append
3099					appendORBImmediate( fLastORB );
3100				}
3101
3102				return;
3103			}
3104			else if ( (ack == kFWAckDataError) ||
3105					  (rcode == kFWResponseConflictError) ||
3106					  (rcode == kFWResponseDataError) )
3107			{
3108
3109	//			IOLog( "IOFireWireSBP2Login::fetchAgentWriteComplete fetch agent write failed! retrying\n" );
3110	#if PANIC_ON_DOUBLE_APPEND
3111				panic( "IOFireWireSBP2Login::fetchAgentWriteComplete fetch agent write failed!\n" );
3112	#endif
3113
3114				// retry
3115				retries--;
3116				fLastORB->setFetchAgentWriteRetries( retries );
3117
3118				// arithmetic increase in retry time
3119				UInt32 interval = fLastORB->getFetchAgentWriteRetryInterval();
3120				fLastORB->setFetchAgentWriteRetryInterval( interval + 1000 );
3121
3122				// family does not delay on these acks and rcodes
3123				startFetchAgentRetryTimer( interval );
3124
3125				return;
3126			}
3127		}
3128    }
3129
3130	//
3131	// check if we have an orb waiting to be appended
3132	//
3133
3134	fORBToWrite = 0; // no more orb pending a fetch agent write
3135
3136	// theoretically fORBToWrite should already be cleared to zero
3137	// before this fails with kIOFireWireBusReset
3138
3139	if( orb && status != kIOFireWireBusReset )
3140	{
3141	//	IOLog( "IOFireWireSBP2Login : fetch agent write command free, submitting orb 0x%08lx\n", orb );
3142
3143		// actually do the write if this completed for normal reasons
3144		startORBTimer( orb );
3145		if( fTarget->beginIOCriticalSection() == kIOReturnSuccess )
3146		{
3147#if PANIC_ON_DOUBLE_APPEND
3148			if( isORBAppended( orb ) )
3149			{
3150				panic( "IOFireWireSBP2Login::fetchAgentWriteComplete - double appending orb!\n" );
3151			}
3152#endif
3153			fCriticalSectionCount++;
3154			setORBIsAppended( orb, true );
3155			appendORBImmediate( orb );
3156		}
3157	}
3158
3159	// send complete notification here
3160	if( fFetchAgentWriteCompletion != NULL )
3161        (*fFetchAgentWriteCompletion)( fFetchAgentWriteRefCon, status, fLastORB );
3162}
3163
3164//
3165// fetch agent retry timer
3166//
3167
3168// startFetchAgentRetryTimer
3169//
3170//
3171
3172void IOFireWireSBP2Login::startFetchAgentRetryTimer( UInt32 duration )
3173{
3174	// shouldn't already be set
3175    FWKLOGASSERT( fFetchAgentRetryTimerSet == false );
3176
3177	// stop it if it is
3178	stopFetchAgentRetryTimer();
3179
3180	fFetchAgentRetryTimerCommand->reinit( duration,
3181									  IOFireWireSBP2Login::fetchAgentRetryTimerStatic, this );
3182
3183    // wait a little bit before retrying
3184    fFetchAgentRetryTimerSet = true;
3185
3186	IOReturn status = fFetchAgentRetryTimerCommand->submit();
3187	if( status != kIOReturnSuccess )
3188	{
3189		fFetchAgentRetryTimerSet = false;
3190	}
3191}
3192
3193// stopFetchAgentRetryTimer
3194//
3195//
3196
3197void IOFireWireSBP2Login::stopFetchAgentRetryTimer( void )
3198{
3199	if( fFetchAgentRetryTimerSet )
3200	{
3201		fFetchAgentRetryTimerCommand->cancel(kIOReturnAborted);
3202	}
3203}
3204
3205// fetchAgentRetryTimer
3206//
3207//
3208
3209void IOFireWireSBP2Login::fetchAgentRetryTimerStatic( void *refcon, IOReturn status, IOFireWireBus *bus, IOFWBusCommand *fwCmd )
3210{
3211    ((IOFireWireSBP2Login*)refcon)->fetchAgentRetryTimer( status, bus, fwCmd );
3212}
3213
3214void IOFireWireSBP2Login::fetchAgentRetryTimer( IOReturn status, IOFireWireBus *bus, IOFWBusCommand *fwCmd )
3215{
3216    FWKLOG( ( "IOFireWireSBP2Login<%p>IOFireWireSBP2Login::fetchAgentRetryTimer\n", this ) );
3217
3218    fFetchAgentRetryTimerSet = false;
3219
3220	if( status == kIOReturnTimeout )
3221    {
3222		appendORBImmediate( fLastORB );
3223	}
3224}
3225
3226// isFetchAgentWriteInProgress
3227//
3228// do we have a fetch agent write in progress
3229
3230bool IOFireWireSBP2Login::isFetchAgentWriteInProgress( void )
3231{
3232    return (fFetchAgentWriteCommandInUse || fFetchAgentRetryTimerSet);
3233}
3234
3235// fetch agent reset
3236//
3237//
3238
3239void IOFireWireSBP2Login::setFetchAgentResetCompletion( void * refCon, FWSBP2StatusCallback completion )
3240{
3241	fFetchAgentResetCompletion = completion;
3242	fFetchAgentResetRefCon = refCon;
3243}
3244
3245IOReturn IOFireWireSBP2Login::submitFetchAgentReset( void )
3246{
3247    IOReturn status = kIOReturnSuccess;
3248
3249	status = fGate->runAction( staticExecuteFetchAgentReset );
3250
3251	return status;
3252}
3253
3254IOReturn IOFireWireSBP2Login::staticExecuteFetchAgentReset( OSObject *self, void *, void *, void *, void * )
3255{
3256	return ((IOFireWireSBP2Login *)self)->executeFetchAgentReset();
3257}
3258
3259IOReturn IOFireWireSBP2Login::executeFetchAgentReset( void )
3260{
3261	IOReturn status = kIOReturnSuccess;
3262
3263	switch( fLoginState )
3264	{
3265		case kLoginStateConnected:
3266			if( fFetchAgentResetInProgress )
3267				fFetchAgentResetCommand->cancel( kIOReturnAborted );
3268
3269			fFetchAgentResetInProgress = true;
3270			fFetchAgentResetCommand->reinit( fFetchAgentResetAddress,
3271											&fFetchAgentResetBuffer, 1,
3272											IOFireWireSBP2Login::fetchAgentResetCompleteStatic,
3273											this, true );
3274			fFetchAgentResetCommand->updateNodeID( fLoginGeneration, fLoginNodeID );
3275
3276			fFetchAgentResetCommand->submit();
3277			break;
3278
3279		case kLoginStateLoggingIn:
3280		case kLoginStateReconnect:
3281		case kLoginStateIdle:
3282		case kLoginStateLoggingOut:
3283		default:
3284			status = kIOReturnError;
3285			break;
3286	}
3287
3288	return status;
3289}
3290
3291void IOFireWireSBP2Login::fetchAgentResetCompleteStatic( void *refcon, IOReturn status, IOFireWireNub *device, IOFWCommand *fwCmd )
3292{
3293    ((IOFireWireSBP2Login*)refcon)->fetchAgentResetComplete( status, device, fwCmd );
3294}
3295
3296void IOFireWireSBP2Login::fetchAgentResetComplete( IOReturn status, IOFireWireNub *device, IOFWCommand *fwCmd )
3297{
3298    FWKLOG( ("IOFireWireSBP2Login<%p> : fetch agent reset complete\n", this) );
3299
3300    fFetchAgentResetInProgress = false;
3301
3302	if( status == kIOReturnSuccess )
3303	{
3304		clearAllTasksInSet();
3305	}
3306
3307	if( status != kIOReturnAborted )
3308	{
3309		if( fFetchAgentResetCompletion )
3310			(*fFetchAgentResetCompletion)( fFetchAgentResetRefCon, status );
3311	}
3312}
3313
3314// ringDoorbell
3315//
3316//
3317
3318IOReturn IOFireWireSBP2Login::ringDoorbell( void )
3319{
3320    IOReturn status = kIOReturnSuccess;
3321
3322	status = fGate->runAction( staticExecuteDoorbell );
3323
3324	return status;
3325}
3326
3327IOReturn IOFireWireSBP2Login::staticExecuteDoorbell( OSObject *self, void *, void *, void *, void * )
3328{
3329	return ((IOFireWireSBP2Login *)self)->executeDoorbell();
3330}
3331
3332IOReturn IOFireWireSBP2Login::executeDoorbell( void )
3333{
3334	// must be logged to ring the doorbell
3335	if( isConnected() )
3336	{
3337		if( fDoorbellInProgress )
3338		{
3339			fDoorbellRingAgain = true;
3340			return kIOReturnSuccess;
3341		}
3342
3343		fDoorbellInProgress = true;
3344		fDoorbellCommand->reinit( fDoorbellAddress,
3345								  &fDoorbellBuffer, 1,
3346								  IOFireWireSBP2Login::doorbellCompleteStatic,
3347								  this, true );
3348		fDoorbellCommand->updateNodeID( fLoginGeneration, fLoginNodeID );
3349
3350		fDoorbellCommand->submit();
3351	}
3352	else
3353		return kIOReturnError;
3354
3355	return kIOReturnSuccess;
3356}
3357
3358void IOFireWireSBP2Login::doorbellCompleteStatic( void *refcon, IOReturn status, IOFireWireNub *device, IOFWCommand *fwCmd )
3359{
3360    ((IOFireWireSBP2Login*)refcon)->doorbellComplete( status, device, fwCmd );
3361}
3362
3363void IOFireWireSBP2Login::doorbellComplete( IOReturn status, IOFireWireNub *device, IOFWCommand *fwCmd )
3364{
3365    FWKLOG( ("IOFireWireSBP2Login<%p> : doorbell complete\n", this) );
3366
3367    fDoorbellInProgress = false;
3368
3369	if( fDoorbellRingAgain )
3370	{
3371		fDoorbellRingAgain = false;
3372		executeDoorbell();
3373	}
3374}
3375
3376// enableUnsolicitedStatus
3377//
3378//
3379
3380IOReturn IOFireWireSBP2Login::enableUnsolicitedStatus( void )
3381{
3382    IOReturn status = kIOReturnSuccess;
3383
3384	status = fGate->runAction( staticExecuteUnsolicitedStatusEnable );
3385
3386	return status;
3387}
3388
3389IOReturn IOFireWireSBP2Login::staticExecuteUnsolicitedStatusEnable( OSObject *self, void *, void *, void *, void * )
3390{
3391	return ((IOFireWireSBP2Login *)self)->executeUnsolicitedStatusEnable();
3392}
3393
3394IOReturn IOFireWireSBP2Login::executeUnsolicitedStatusEnable( void )
3395{
3396	IOReturn status = kIOReturnSuccess;
3397
3398	switch( fLoginState )
3399	{
3400		case kLoginStateConnected:
3401			if( fUnsolicitedStatusEnableInProgress )
3402				fUnsolicitedStatusEnableCommand->cancel( kIOReturnAborted );
3403
3404			fUnsolicitedStatusEnableInProgress = true;
3405			fUnsolicitedStatusEnableCommand->reinit( fUnsolicitedStatusEnableAddress,
3406									&fUnsolicitedStatusEnableBuffer, 1,
3407									IOFireWireSBP2Login::unsolicitedStatusEnableCompleteStatic,
3408									this, true );
3409			fUnsolicitedStatusEnableCommand->updateNodeID( fLoginGeneration, fLoginNodeID );
3410
3411			fUnsolicitedStatusEnableCommand->submit();
3412			break;
3413
3414		case kLoginStateLoggingIn:
3415		case kLoginStateReconnect:
3416			fUnsolicitedStatusEnableRequested = true;	// try again after we're logged in
3417			break;
3418
3419		case kLoginStateIdle:
3420		case kLoginStateLoggingOut:
3421		default:
3422			status = kIOReturnError;
3423			break;
3424	}
3425
3426	return status;
3427}
3428
3429void IOFireWireSBP2Login::unsolicitedStatusEnableCompleteStatic( void *refcon, IOReturn status, IOFireWireNub *device, IOFWCommand *fwCmd )
3430{
3431    ((IOFireWireSBP2Login*)refcon)->unsolicitedStatusEnableComplete( status, device, fwCmd );
3432}
3433
3434void IOFireWireSBP2Login::unsolicitedStatusEnableComplete( IOReturn status, IOFireWireNub *device, IOFWCommand *fwCmd )
3435{
3436    FWKLOG( ("IOFireWireSBP2Login<%p> : unsolicitedStatusEnableComplete complete\n", this) );
3437
3438    fUnsolicitedStatusEnableInProgress = false;
3439
3440	if( status == kIOFireWireBusReset )
3441	{
3442		fUnsolicitedStatusEnableRequested = true; 	// try again after we're logged in
3443	}
3444}
3445
3446// set busy timeout
3447//
3448//
3449
3450void IOFireWireSBP2Login::setBusyTimeoutRegisterValue( UInt32 timeout )
3451{
3452	fSetBusyTimeoutBuffer = OSSwapHostToBigInt32(timeout);
3453	executeSetBusyTimeout();
3454}
3455
3456IOReturn IOFireWireSBP2Login::executeSetBusyTimeout( void )
3457{
3458	if( fSetBusyTimeoutInProgress )
3459		fSetBusyTimeoutCommand->cancel( kIOReturnAborted );
3460
3461	fSetBusyTimeoutInProgress = true;
3462	fSetBusyTimeoutCommand->reinit( fSetBusyTimeoutAddress,
3463								    &fSetBusyTimeoutBuffer, 1,
3464								    IOFireWireSBP2Login::setBusyTimeoutCompleteStatic,
3465								    this, true );
3466
3467	fSetBusyTimeoutCommand->submit();
3468
3469	return kIOReturnSuccess;
3470}
3471
3472void IOFireWireSBP2Login::setBusyTimeoutCompleteStatic( void *refcon, IOReturn status, IOFireWireNub *device, IOFWCommand *fwCmd )
3473{
3474    ((IOFireWireSBP2Login*)refcon)->setBusyTimeoutComplete( status, device, fwCmd );
3475}
3476
3477void IOFireWireSBP2Login::setBusyTimeoutComplete( IOReturn status, IOFireWireNub *device, IOFWCommand *fwCmd )
3478{
3479    FWKLOG( ("IOFireWireSBP2Login<%p> : setBusyTimeoutComplete\n", this) );
3480
3481    fSetBusyTimeoutInProgress = false;
3482}
3483
3484// appendORBImmediate
3485//
3486//
3487
3488IOReturn IOFireWireSBP2Login::appendORBImmediate( IOFireWireSBP2ORB * orb )
3489{
3490	if( fFetchAgentWriteCommandInUse )
3491		 fFetchAgentWriteCommand->cancel( kIOReturnAborted );
3492
3493    fFetchAgentWriteCommandInUse = true;
3494
3495	fFetchAgentWriteCommand->reinit( fFetchAgentAddress,
3496										fFetchAgentWriteCommandMemory,
3497										IOFireWireSBP2Login::fetchAgentWriteCompleteStatic, this, true );
3498
3499	fFetchAgentWriteCommand->setRetries( 0 );
3500	fFetchAgentWriteCommand->updateNodeID( fLoginGeneration, fLoginNodeID );
3501
3502    return fFetchAgentWriteCommand->submit();
3503}
3504
3505// appendORB
3506//
3507//
3508
3509IOReturn IOFireWireSBP2Login::appendORB( IOFireWireSBP2ORB * orb )
3510{
3511    IOReturn status = kIOReturnSuccess;
3512    if( fLastORB != NULL && fLastORB != orb )
3513    {
3514		FWAddress orb_address(0,0);
3515        orb->getORBAddress( &orb_address );
3516        setNextORBAddress( fLastORB, orb_address );
3517
3518		fLastORBAddress.nodeID = OSSwapHostToBigInt16(orb_address.nodeID);
3519		fLastORBAddress.addressHi = OSSwapHostToBigInt16(orb_address.addressHi);
3520		fLastORBAddress.addressLo = OSSwapHostToBigInt32(orb_address.addressLo);
3521        orb->retain();
3522
3523        if( fLastORB )
3524        {
3525            fLastORB->release();
3526            fLastORB = NULL;
3527        }
3528
3529        fLastORB = orb;
3530    }
3531    else
3532        status = kIOReturnError;
3533
3534    return status;
3535}
3536
3537// sendTimeoutNotification
3538//
3539//
3540
3541void IOFireWireSBP2Login::sendTimeoutNotification( IOFireWireSBP2ORB * orb )
3542{
3543	if( isORBAppended( orb ) )
3544	{
3545		setORBIsAppended( orb, false );
3546		if( fCriticalSectionCount > 0 )
3547		{
3548			fCriticalSectionCount--;
3549		}
3550		fTarget->endIOCriticalSection();
3551	}
3552
3553    // send solicited status
3554    if( fStatusNotifyCallback != NULL )
3555    {
3556        FWSBP2NotifyParams		params;
3557
3558        params.message = 0;
3559        params.length = 0;
3560        params.notificationEvent = kFWSBP2NormalCommandTimeout;
3561        params.generation = fLoginGeneration;
3562        params.commandObject = orb;
3563        (*fStatusNotifyCallback)(fStatusNotifyRefCon, &params );
3564    }
3565}
3566
3567// setAddressLoForLoginORBAndResponse
3568//
3569//
3570
3571void IOFireWireSBP2Login::setAddressLoForLoginORBAndResponse( UInt32 addressLoORB, UInt32 addressLoResponse )
3572{
3573	IOFWSBP2PseudoAddressSpace * space;
3574	UInt32 addressLoORBMasked = addressLoORB & 0xfffffff0;
3575	UInt32 addressLoResponseMasked = addressLoResponse & 0xfffffff0;
3576
3577	fControl->closeGate();
3578
3579	FWKLOG(( "IOFireWireSBP2Login::setAddressLoForLoginORBAndResponse<%p> - set ORB addressLo to 0x%08lx, set Response addressLo to 0x%08lx\n", this, addressLoORBMasked, addressLoResponseMasked ));
3580
3581	space = OSDynamicCast( IOFWSBP2PseudoAddressSpace, fLoginORBAddressSpace );
3582	if( space != NULL )
3583	{
3584		fLoginORBAddress.addressLo = OSSwapHostToBigInt32(addressLoORBMasked);
3585		space->setAddressLo( addressLoORBMasked );
3586	}
3587
3588	space = OSDynamicCast( IOFWSBP2PseudoAddressSpace, fLoginResponseAddressSpace );
3589	if( space != NULL )
3590	{
3591		fLoginResponseAddress.addressLo = addressLoResponseMasked;
3592		fLoginORB.loginResponseAddressLo = OSSwapHostToBigInt32(fLoginResponseAddress.addressLo);
3593		space->setAddressLo( addressLoResponseMasked );
3594	}
3595
3596	fControl->openGate();
3597}
3598
3599// isPhysicalAccessEnabled
3600//
3601//
3602
3603bool IOFireWireSBP2Login::isPhysicalAccessEnabled( void )
3604{
3605	return fPhysicalAccessEnabled;
3606}
3607
3608// getARDMMax
3609//
3610//
3611
3612UInt32 IOFireWireSBP2Login::getARDMMax( void )
3613{
3614	return fARDMAMax;
3615}
3616
3617#pragma mark -
3618//////////////////////////////////////////////////////////////////////////////////////////
3619// friend class wrappers
3620
3621//
3622// IOFireWireSBP2ORB friend class wrappers
3623//
3624
3625bool IOFireWireSBP2Login::initORBWithLogin( IOFireWireSBP2ORB * orb, IOFireWireSBP2Login * login )
3626{
3627	return orb->initWithLogin( login );
3628}
3629
3630void IOFireWireSBP2Login::setNextORBAddress( IOFireWireSBP2ORB * orb, FWAddress address )
3631{
3632	orb->setNextORBAddress( address );
3633}
3634
3635void IOFireWireSBP2Login::fetchAgentWriteComplete( IOFireWireSBP2ORB * orb, IOReturn status )
3636{
3637	// orb->fetchAgentWriteComplete( status );
3638}
3639
3640bool IOFireWireSBP2Login::isORBTimerSet( IOFireWireSBP2ORB * orb )
3641{
3642	return orb->isTimerSet();
3643}
3644
3645void IOFireWireSBP2Login::cancelORBTimer( IOFireWireSBP2ORB * orb )
3646{
3647	orb->cancelTimer();
3648}
3649
3650void IOFireWireSBP2Login::startORBTimer( IOFireWireSBP2ORB * orb )
3651{
3652	orb->startTimer();
3653}
3654
3655void IOFireWireSBP2Login::prepareORBForExecution( IOFireWireSBP2ORB * orb )
3656{
3657	orb->prepareORBForExecution();
3658}
3659
3660bool IOFireWireSBP2Login::isORBAppended( IOFireWireSBP2ORB * orb )
3661{
3662	return orb->isAppended();
3663}
3664
3665void IOFireWireSBP2Login::setORBIsAppended( IOFireWireSBP2ORB * orb, bool state )
3666{
3667	orb->setIsAppended( state );
3668}
3669
3670//
3671// IOFireWireSBP2LUN friend class wrappers
3672//
3673
3674void IOFireWireSBP2Login::removeLogin( void )
3675{
3676	fLUN->removeLogin( this);
3677}
3678
3679IOFireWireSBP2Target * IOFireWireSBP2Login::getTarget( void )
3680{
3681	return fLUN->getTarget();
3682}
3683