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#define FIREWIREPRIVATE
26#include <IOKit/firewire/IOFireWireController.h>
27#undef FIREWIREPRIVATE
28
29#include <IOKit/firewire/IOConfigDirectory.h>
30#include <IOKit/firewire/IOFireWireDevice.h>
31#include <IOKit/IODeviceTreeSupport.h>
32
33#include <IOKit/sbp2/IOFireWireSBP2LUN.h>
34#include <IOKit/sbp2/IOFireWireSBP2Target.h>
35#include "FWDebugging.h"
36
37const OSSymbol *gCommand_Set_Spec_ID_Symbol = NULL;
38const OSSymbol *gCommand_Set_Symbol = NULL;
39const OSSymbol *gModule_Vendor_ID_Symbol = NULL;
40const OSSymbol *gCommand_Set_Revision_Symbol = NULL;
41const OSSymbol *gIOUnit_Symbol = NULL;
42const OSSymbol *gFirmware_Revision_Symbol = NULL;
43const OSSymbol *gDevice_Type_Symbol = NULL;
44const OSSymbol *gGUID_Symbol = NULL;
45const OSSymbol *gUnit_Characteristics_Symbol = NULL;
46const OSSymbol *gManagement_Agent_Offset_Symbol = NULL;
47const OSSymbol *gFast_Start_Symbol = NULL;
48
49OSDefineMetaClassAndStructors(IOFireWireSBP2Target, IOService);
50
51OSMetaClassDefineReservedUnused(IOFireWireSBP2Target, 0);
52OSMetaClassDefineReservedUnused(IOFireWireSBP2Target, 1);
53OSMetaClassDefineReservedUnused(IOFireWireSBP2Target, 2);
54OSMetaClassDefineReservedUnused(IOFireWireSBP2Target, 3);
55OSMetaClassDefineReservedUnused(IOFireWireSBP2Target, 4);
56OSMetaClassDefineReservedUnused(IOFireWireSBP2Target, 5);
57OSMetaClassDefineReservedUnused(IOFireWireSBP2Target, 6);
58OSMetaClassDefineReservedUnused(IOFireWireSBP2Target, 7);
59OSMetaClassDefineReservedUnused(IOFireWireSBP2Target, 8);
60
61//
62// start / stop routines
63//
64
65bool IOFireWireSBP2Target::start( IOService *provider )
66{
67    fProviderUnit = OSDynamicCast(IOFireWireUnit, provider);
68    if (fProviderUnit == NULL)
69        return false;
70
71	fProviderUnit->retain();
72
73	// we want the expansion data member to be zeroed if it's available
74	// so create and zero in a local then assign to the member when were done
75
76	ExpansionData * exp_data = (ExpansionData*) IOMalloc( sizeof(ExpansionData) );
77	if( !exp_data )
78	{
79		return false;
80	}
81
82	bzero( exp_data, sizeof(ExpansionData) );
83
84	fExpansionData = exp_data;
85
86	fControl = fProviderUnit->getController();
87
88	// assume safe mode
89	fFlags = kIOFWSBP2FailsOnBusResetsDuringIO;
90
91    fOpenFromTarget = false;
92    fOpenFromLUNCount = 0;
93	fIOCriticalSectionCount = 0;
94
95	//
96	// create symbols
97	//
98
99	if( gCommand_Set_Spec_ID_Symbol == NULL )
100		gCommand_Set_Spec_ID_Symbol = OSSymbol::withCString("Command_Set_Spec_ID");
101
102	if( gCommand_Set_Symbol == NULL )
103		gCommand_Set_Symbol = OSSymbol::withCString("Command_Set");
104
105	if( gModule_Vendor_ID_Symbol == NULL )
106		gModule_Vendor_ID_Symbol = OSSymbol::withCString("Vendor_ID");
107
108	if( gCommand_Set_Revision_Symbol == NULL )
109		gCommand_Set_Revision_Symbol = OSSymbol::withCString("Command_Set_Revision");
110
111	if( gIOUnit_Symbol == NULL )
112		gIOUnit_Symbol = OSSymbol::withCString("IOUnit");
113
114	if( gFirmware_Revision_Symbol == NULL )
115		gFirmware_Revision_Symbol = OSSymbol::withCString("Firmware_Revision");
116
117	if( gDevice_Type_Symbol == NULL )
118		gDevice_Type_Symbol = OSSymbol::withCString("Device_Type");
119
120	if( gGUID_Symbol == NULL )
121		gGUID_Symbol = OSSymbol::withCString("GUID");
122
123	if( gUnit_Characteristics_Symbol == NULL )
124		gUnit_Characteristics_Symbol = OSSymbol::withCString("Unit_Characteristics");
125
126	if( gManagement_Agent_Offset_Symbol == NULL )
127		gManagement_Agent_Offset_Symbol = OSSymbol::withCString("Management_Agent_Offset");
128
129	if( gFast_Start_Symbol == NULL )
130		gFast_Start_Symbol = OSSymbol::withCString("Fast_Start");
131
132    if (IOService::start(provider))
133    {
134		IOFireWireController * 	controller = fProviderUnit->getController();
135        IOService * 			fwim = (IOService*)controller->getLink();
136		OSObject *				prop = NULL;
137		UInt32					byteCount1, byteCount2;
138
139		//
140		// read receive properties from registry
141		//
142
143		byteCount1 = 0;
144		prop = fwim->getProperty( "FWMaxAsyncReceiveBytes" );
145		if( prop )
146		{
147			byteCount1 = ((OSNumber*)prop)->unsigned32BitValue();
148			if( byteCount1 != 0 )
149			{
150				// minus 32 bytes for status block
151				byteCount1 -= 32;
152			}
153		}
154
155		byteCount2 = 0;
156		prop = fwim->getProperty( "FWMaxAsyncReceivePackets" );
157		if( prop )
158		{
159			UInt32 packetCount = ((OSNumber*)prop)->unsigned32BitValue();
160			if( packetCount != 0 )
161			{
162				// minus 1 for the status block
163				byteCount2 = (packetCount - 1) * 512; // 512 bytes is minimum packet size
164			}
165		}
166
167		// publish min byte size
168		UInt32 size = byteCount1 < byteCount2 ? byteCount1 : byteCount2;
169		if( size != 0)
170			setProperty( "SBP2ReceiveBufferByteCount", size, 32 );
171
172		// start scanning for LUNs
173        scanForLUNs();
174    }
175    else
176        return false;
177
178    FWKLOG( ( "IOFireWireSBP2Target<%p> : started\n", this ) );
179
180	fExpansionData->fStarted = true;
181
182    return true;
183}
184
185// stop
186//
187//
188
189void IOFireWireSBP2Target::stop( IOService *provider )
190{
191    FWKLOG( ( "IOFireWireSBP2Target<%p>::stop\n", this ) );
192
193    IOService::stop(provider);
194}
195
196// finalize
197//
198//
199
200bool IOFireWireSBP2Target::finalize( IOOptionBits options )
201{
202    // Nuke from device tree
203    detachAll( gIODTPlane );
204
205	return IOService::finalize( options );
206}
207
208// free
209//
210//
211
212void IOFireWireSBP2Target::free( void )
213{
214	FWKLOG( ( "IOFireWireSBP2Target<%p>::free\n", this ) );
215
216	if( fIOCriticalSectionCount != 0 )
217	{
218		IOLog( "IOFireWireSBP2Target<%p>::free - fIOCriticalSectionCount == %d!\n", this, fIOCriticalSectionCount );
219	}
220
221	while( fIOCriticalSectionCount != 0 )
222	{
223		fIOCriticalSectionCount--;
224		fControl->endIOCriticalSection();
225	}
226
227	if( fExpansionData )
228	{
229		if( fExpansionData->fPendingMgtAgentCommands )
230			fExpansionData->fPendingMgtAgentCommands->release() ;
231
232		IOFree( fExpansionData, sizeof(ExpansionData) );
233		fExpansionData = NULL;
234	}
235
236	if( fProviderUnit )
237	{
238		fProviderUnit->release();
239		fProviderUnit = NULL;
240	}
241
242	IOService::free();
243}
244
245////////////////////////////////////////////////////////////////////////
246
247//
248// message method
249//
250
251IOReturn IOFireWireSBP2Target::message( UInt32 type, IOService *nub, void *arg )
252{
253    IOReturn res = kIOReturnUnsupported;
254
255    FWKLOG( ("IOFireWireSBP2Target<%p> : message 0x%x, arg 0x%08lx\n", this, type, arg) );
256
257    res = IOService::message(type, nub, arg);
258    if( kIOReturnUnsupported == res )
259    {
260        switch (type)
261        {
262            case kIOMessageServiceIsTerminated:
263                FWKLOG( ( "IOFireWireSBP2Target<%p> : kIOMessageServiceIsTerminated\n", this ) );
264                res = kIOReturnSuccess;
265                break;
266
267            case kIOMessageServiceIsSuspended:
268                FWKLOG( ( "IOFireWireSBP2Target<%p> : kIOMessageServiceIsSuspended\n", this ) );
269                clearMgmtAgentAccess();
270                res = kIOReturnSuccess;
271                break;
272
273            case kIOMessageServiceIsResumed:
274                FWKLOG( ( "IOFireWireSBP2Target<%p> : kIOMessageServiceIsResumed\n", this ) );
275                configurePhysicalFilter();
276                res = kIOReturnSuccess;
277                break;
278
279            default: // default the action to return kIOReturnUnsupported
280                break;
281        }
282    }
283
284	if( type != kIOMessageServiceIsTerminated &&
285		type != (UInt32)kIOMessageFWSBP2ReconnectFailed &&
286		type != (UInt32)kIOMessageFWSBP2ReconnectComplete )
287	{
288		messageClients( type, arg );
289    }
290
291    return res;
292}
293
294// getFireWireUnit
295//
296// returns the FireWire unit for doing non-SBP2 work
297
298IOFireWireUnit * IOFireWireSBP2Target::getFireWireUnit( void )
299{
300	return (IOFireWireUnit*)getProvider();
301}
302
303////////////////////////////////////////////////////////////////////////
304// open / close internals
305
306//
307// handleOpen / handleClose
308//
309// we override these two methods to allow a reference counted open from
310// LUNs only.  Exculsive access is enforced for non-LUN clients
311//
312
313bool IOFireWireSBP2Target::handleOpen( IOService * forClient, IOOptionBits options, void * arg )
314{
315    bool ok = true;
316
317    FWKLOG(( "IOFireWireSBP2Target<%p::handleOpen entered fOpenFromLUNCount = %d, fOpenFromTarget = %d\n", this, fOpenFromLUNCount, fOpenFromTarget ));
318
319    IOFireWireSBP2LUN * lunClient = OSDynamicCast( IOFireWireSBP2LUN, forClient );
320    if( lunClient != NULL )
321    {
322        // bail if we're open from the target
323        if( fOpenFromTarget )
324            return false;
325
326        // if this is the first open call, actually do an open
327        if( fOpenFromLUNCount == 0 )
328        {
329            ok = fProviderUnit->open(this, options, arg);
330            if( ok )
331            {
332                fOpenFromLUNCount++;
333                ok = IOService::handleOpen( this, options, arg );
334                FWKLOG(( "IOFireWireSBP2Target<%p>::handleOpen called open\n", this ));
335            }
336        }
337        else
338        {
339            // otherwise just increase the reference count
340            fOpenFromLUNCount++;
341        }
342    }
343    else
344    {
345        // bail if we're open as a LUN
346        if( fOpenFromLUNCount != 0 )
347            return false;
348
349        // try to open
350        if( !fOpenFromTarget )  // extra safe
351        {
352            ok = fProviderUnit->open(this, options, arg);
353            if( ok )
354            {
355                fOpenFromTarget = true;
356                ok = IOService::handleOpen( forClient, options, arg );
357                FWKLOG(( "IOFireWireSBP2Target<%p>::handleOpen called open\n", this ));
358            }
359        }
360        else
361            ok = false;   // already open
362    }
363
364    FWKLOG(( "IOFireWireSBP2Target<%p>::handleOpen - exit handleOpen fOpenFromLUNCount = %d, fOpenFromTarget = %d\n", this, fOpenFromLUNCount, fOpenFromTarget ));
365
366    return ok;
367}
368
369void IOFireWireSBP2Target::handleClose( IOService * forClient, IOOptionBits options )
370{
371    FWKLOG(( "IOFireWireSBP2Target<%p>::handleClose enter handleClose fOpenFromLUNCount = %d, fOpenFromTarget = %d\n", this, fOpenFromLUNCount, fOpenFromTarget ));
372
373    IOFireWireSBP2LUN * lunClient = OSDynamicCast( IOFireWireSBP2LUN, forClient );
374    if( lunClient != NULL )
375    {
376        if( fOpenFromLUNCount != 0 ) // extra safe
377        {
378            fOpenFromLUNCount--;
379
380            if( fOpenFromLUNCount == 0 ) // close if we're down to zero
381            {
382                IOService::handleClose( this, options);
383                fProviderUnit->close(this, options);
384                FWKLOG(( "IOFireWireSBP2Target<%p>::handleClose - called close\n", this ));
385            }
386        }
387    }
388    else
389    {
390        if( fOpenFromTarget ) // if we were open from the target
391        {
392            fOpenFromTarget = false;
393            IOService::handleClose(forClient, options);
394            fProviderUnit->close(this, options);
395            FWKLOG(( "IOFireWireSBP2Target<%p::handleClose - called close\n", this ));
396        }
397    }
398
399    FWKLOG(( "IOFireWireSBP2Target<%p>::handleClose - exit handleClose fOpenFromLUNCount = %d, fOpenFromTarget = %d\n", this, fOpenFromLUNCount, fOpenFromTarget ));
400}
401
402//
403// handleIsOpen
404//
405// Default implementation is for single object access.  We use this when someone
406// has opened the target, but since multiple LUNs can open this object we override
407// the behavior in this case.
408
409bool IOFireWireSBP2Target::handleIsOpen( const IOService * forClient ) const
410{
411    // are we open from one or more LUNs?
412    if( fOpenFromLUNCount != 0 )
413    {
414        // is the client really a LUN?
415        IOFireWireSBP2LUN * lunClient = OSDynamicCast( IOFireWireSBP2LUN, forClient );
416        return (lunClient != NULL );
417    }
418
419    // are we open from the target
420    if( fOpenFromTarget )
421    {
422        // is the client the one who opened us?
423        return IOService::handleIsOpen( forClient );
424    }
425
426    // we're not open
427    return false;
428}
429
430////////////////////////////////////////////////////////////////////////
431// LUN discovery and creation
432
433// scanForLUNS
434//
435// look for LUNs, publish the information in the registry and initiate matching.
436
437void IOFireWireSBP2Target::scanForLUNs( void )
438{
439    IOReturn		status = kIOReturnSuccess;
440    IOReturn		tempStatus = kIOReturnSuccess;
441
442	LUNInfo info;
443
444	info.cmdSpecID 				= 0;
445	info.cmdSet 				= 0;
446	info.vendorID				= 0;
447	info.softwareRev 			= 0;
448	info.firmwareRev 			= 0;
449	info.lun					= 0;
450	info.devType				= 0;
451	info.unitCharacteristics 	= 0;
452	info.managementOffset 		= 0;
453	info.revision				= 0;
454	info.fastStartSupported 	= false;
455	info.fastStart				= 0;
456
457	//
458    // get root directory
459    //
460
461    IOConfigDirectory *		directory;
462
463    IOFireWireDevice *  device = NULL;
464    IOService *		providerService = fProviderUnit->getProvider();
465    if( providerService == NULL )
466        status = kIOReturnError;
467
468    if( status == kIOReturnSuccess )
469    {
470        device = OSDynamicCast( IOFireWireDevice, providerService );
471        if( device == NULL )
472            status = kIOReturnError;
473        FWKLOG( ("IOFireWireSBP2Target<%p> : unit = 0x%08lx, provider = 0x%08lx, device = 0x%08lx\n", this, fProviderUnit, providerService, device) );
474    }
475
476    if( status == kIOReturnSuccess )
477    {
478        status = device->getConfigDirectory( directory );
479        FWKLOG( ( "IOFireWireSBP2Target<%p> : status = %d\n", this, status ) );
480    }
481
482    //
483    // find vendor id
484    //
485
486    if( status == kIOReturnSuccess )
487        tempStatus = directory->getKeyValue( kConfigModuleVendorIdKey, info.vendorID );
488
489	//
490	// get unit directory
491    //
492
493    status = fProviderUnit->getConfigDirectory( directory );
494    FWKLOG( ( "IOFireWireSBP2Target<%p> : status = %d\n", this, status ) );
495
496	//
497	// find command spec id
498	//
499
500    if( status == kIOReturnSuccess )
501        status = directory->getKeyValue( kCmdSpecIDKey, info.cmdSpecID );
502
503	//
504	// find command set
505	//
506
507    if( status == kIOReturnSuccess )
508        status = directory->getKeyValue( kCmdSetKey, info.cmdSet );
509
510	//
511	// find unit characteristics
512	//
513
514	if( status == kIOReturnSuccess )
515        status = directory->getKeyValue( kUnitCharacteristicsKey, info.unitCharacteristics );
516
517	//
518	// find management agent offset
519    // and add ourselves to the DeviceTree with that location
520    // for OpenFirmware boot path generation.
521	//
522
523    status = directory->getKeyValue( kManagementAgentOffsetKey, info.managementOffset );
524    if( status == kIOReturnSuccess )
525    {
526        IOService *parent = this;
527        while(parent) {
528            if(parent->inPlane(gIODTPlane))
529                break;
530            parent = parent->getProvider();
531        }
532        if(parent) {
533            char location[9];
534            snprintf( location, sizeof(location), "%lx", info.managementOffset );
535            attachToParent(parent, gIODTPlane);
536            setLocation(location, gIODTPlane);
537            setName("sbp-2", gIODTPlane);
538        }
539    }
540
541    // failure to find one of the following is not fatal, hence the use of tempStatus
542
543	//
544	// find revision
545	//
546
547	if( status == kIOReturnSuccess )
548        tempStatus = directory->getKeyValue( kRevisionKey, info.revision );
549
550	//
551	// find fast start info
552	//
553
554	if( status == kIOReturnSuccess && info.revision != 0 )
555	{
556		tempStatus = directory->getKeyValue( kFastStartKey, info.fastStart );
557		if( tempStatus == kIOReturnSuccess )
558		{
559			info.fastStartSupported = true;
560		}
561	}
562
563	//
564	// find software rev
565	//
566
567    if( status == kIOReturnSuccess )
568         tempStatus = directory->getKeyValue( kSoftwareRevKey, info.softwareRev );
569
570    //
571	// find firmware rev
572	//
573
574    if( status == kIOReturnSuccess )
575        tempStatus = directory->getKeyValue( kFirmwareRevKey, info.firmwareRev );
576
577     FWKLOG( ( "IOFireWireSBP2Target<%p> : status = %d, cmdSpecID = %d, cmdSet = %d, vendorID = %d, softwareRev = %d, firmwareRev = %d\n",
578                             this, status, info.cmdSpecID, info.cmdSet, info.vendorID, info.softwareRev, info.firmwareRev ) );
579
580    //
581    // look for luns implemented as immediate values
582    //
583
584    if( status == kIOReturnSuccess )
585    {
586        // look at each entry
587        for( int pos = 0; pos < directory->getNumEntries(); pos++ )
588        {
589            // get index key
590            UInt32 key;
591            tempStatus = directory->getIndexEntry( pos, key );
592            FWKLOG( ( "IOFireWireSBP2Target<%p> : tempStatus = %d, pos = %d, key = %d\n",
593                             this, tempStatus, pos, key ) );
594
595            // if it was the LUN key
596            if( tempStatus == kIOReturnSuccess && key >> kConfigEntryKeyValuePhase == kLUNKey )
597            {
598                UInt32 data;
599                tempStatus = directory->getIndexValue( pos, data );
600                if( tempStatus == kIOReturnSuccess )
601                {
602                    info.lun = data  & 0x0000ffff;
603                    info.devType = (data & 0x001f0000) >> 16;
604
605                    FWKLOG( ( "IOFireWireSBP2Target<%p> : cmdSpecID = %d, cmdSet = %d, vendorID = %d, softwareRev = %d\n",
606                             this, info.cmdSpecID, info.cmdSet, info.vendorID, info.softwareRev ) );
607                    FWKLOG( ( "IOFireWireSBP2Target<%p> : firmwareRev = %d, lun = %d, devType = %d\n",
608                             this, info.firmwareRev, info.lun, info.devType ) );
609					FWKLOG( ( "IOFireWireSBP2Target<%p> : unitCharacteristics = %d, managementOffset = %d,\n",
610                             this, info.unitCharacteristics, info.managementOffset ) );
611					FWKLOG( ( "IOFireWireSBP2Target<%p> : revision = %d, fastStartSupported = %d, fastStart = 0x%08lx\n",
612                         this, info.revision, info.fastStartSupported, info.fastStart ) );
613
614                    // force vendors to use real values, (0, 0) is not legal
615                    if( (info.cmdSpecID & 0x00ffffff) || (info.cmdSet & 0x00ffffff) )
616                    {
617                    	fExpansionData->fNumLUNs++;
618                        createLUN( &info );
619                    }
620                }
621            }
622        }
623    }
624
625    //
626    // look for luns implemented as directories
627    //
628
629    if( status == kIOReturnSuccess )
630    {
631        OSIterator *			directoryIterator;
632        IOConfigDirectory *		lunDirectory;
633        UInt32 					lunValue;
634
635        status = directory->getKeySubdirectories( kLUNDirectoryKey, directoryIterator );
636
637        // iterate through directories
638        while( (lunDirectory = OSDynamicCast(IOConfigDirectory,directoryIterator->getNextObject())) != NULL )
639        {
640			//
641			// find fast start info
642			//
643
644			if( info.revision != 0 )
645			{
646				tempStatus = directory->getKeyValue( kFastStartKey, info.fastStart );
647				if( tempStatus == kIOReturnSuccess )
648				{
649					info.fastStartSupported = true;
650				}
651			}
652
653            // get lun value
654
655            tempStatus = lunDirectory->getKeyValue( kLUNKey, lunValue );
656            if( tempStatus == kIOReturnSuccess )
657            {
658                info.lun = lunValue  & 0x0000ffff;
659                info.devType = (lunValue & 0x001f0000) >> 16;
660
661                FWKLOG( ( "IOFireWireSBP2Target<%p> : cmdSpecID = %d, cmdSet = %d, vendorID = %d, softwareRev = %d\n",
662                         this, info.cmdSpecID, info.cmdSet, info.vendorID, info.softwareRev ) );
663                FWKLOG( ( "IOFireWireSBP2Target<%p> : firmwareRev = %d, lun = %d, devType = %d\n",
664                         this, info.firmwareRev, info.lun, info.devType ) );
665				FWKLOG( ( "IOFireWireSBP2Target<%p> : revision = %d, fastStartSupported = %d, fastStart = 0x%08lx\n",
666                         this, info.revision, info.fastStartSupported, info.fastStart ) );
667
668                // force vendors to use real values, (0, 0) is not legal
669                if( (info.cmdSpecID & 0x00ffffff) || (info.cmdSet & 0x00ffffff) )
670                {
671                	fExpansionData->fNumLUNs++;
672					createLUN( &info );
673                }
674            }
675        }
676
677        directoryIterator->release();
678    }
679
680	fExpansionData->fPendingMgtAgentCommands = OSArray::withCapacity( fExpansionData->fNumLUNs) ;
681
682    //
683    // we found all the luns so lets call registerService on ourselves
684    // for drivers that want to drive all luns
685    //
686
687    OSObject *prop;
688
689    if( status == kIOReturnSuccess )
690    {
691        // all of these values are 24 bits or less, even though we have specified 32 bits
692
693		prop = OSNumber::withNumber( info.cmdSpecID, 32 );
694        setProperty( gCommand_Set_Spec_ID_Symbol, prop );
695        prop->release();
696
697		prop = OSNumber::withNumber( info.cmdSet, 32 );
698        setProperty( gCommand_Set_Symbol, prop );
699        prop->release();
700
701        prop = OSNumber::withNumber( info.vendorID, 32 );
702        setProperty( gModule_Vendor_ID_Symbol, prop );
703        prop->release();
704
705        prop = OSNumber::withNumber( info.softwareRev, 32 );
706        setProperty( gCommand_Set_Revision_Symbol, prop );
707        prop->release();
708
709        prop = OSNumber::withNumber( info.firmwareRev, 32 );
710        setProperty( gFirmware_Revision_Symbol, prop );
711        prop->release();
712
713        prop = OSNumber::withNumber( info.devType, 32 );
714        setProperty( gDevice_Type_Symbol, prop );
715        prop->release();
716
717        prop = fProviderUnit->getProperty(gGUID_Symbol);
718        if( prop )
719            setProperty( gGUID_Symbol, prop );
720
721		prop = fProviderUnit->getProperty(gFireWireModel_ID);
722        if( prop )
723			setProperty( gFireWireModel_ID, prop );
724
725		prop = fProviderUnit->getProperty(gFireWireProduct_Name);
726        if( prop )
727            setProperty( gFireWireProduct_Name, prop );
728
729		prop = fProviderUnit->getProperty(gFireWireVendor_Name);
730        if( prop )
731            setProperty( gFireWireVendor_Name, prop );
732
733        registerService();
734    }
735}
736
737IOReturn IOFireWireSBP2Target::createLUN( LUNInfo * info )
738
739{
740    IOReturn	status = kIOReturnSuccess;
741
742    OSDictionary * propTable = OSDictionary::withCapacity(7);
743
744     OSObject *prop;
745
746    if( propTable )
747    {
748        // all of these values are 24 bits or less, even though we have specified 32 bits
749
750        prop = OSNumber::withNumber( info->cmdSpecID, 32 );
751        propTable->setObject( gCommand_Set_Spec_ID_Symbol, prop );
752        prop->release();
753
754		prop = OSNumber::withNumber( info->cmdSet, 32 );
755        propTable->setObject( gCommand_Set_Symbol, prop );
756        prop->release();
757
758		prop = OSNumber::withNumber( info->vendorID, 32 );
759        propTable->setObject( gModule_Vendor_ID_Symbol, prop );
760        prop->release();
761
762        prop = OSNumber::withNumber( info->softwareRev, 32 );
763        propTable->setObject( gCommand_Set_Revision_Symbol, prop );
764        prop->release();
765
766        prop = OSNumber::withNumber( info->firmwareRev, 32 );
767        propTable->setObject( gFirmware_Revision_Symbol, prop );
768        prop->release();
769
770        prop = OSNumber::withNumber( info->lun, 32 );
771        propTable->setObject( gIOUnit_Symbol, prop );
772        prop->release();
773
774        prop = OSNumber::withNumber( info->devType, 32 );
775        propTable->setObject( gDevice_Type_Symbol, prop );
776        prop->release();
777
778		prop = OSNumber::withNumber( info->unitCharacteristics, 32 );
779        propTable->setObject( gUnit_Characteristics_Symbol, prop );
780        prop->release();
781
782		prop = OSNumber::withNumber(info->managementOffset, 32 );
783        propTable->setObject( gManagement_Agent_Offset_Symbol, prop );
784        prop->release();
785
786		if( info->fastStartSupported )
787		{
788			prop = OSNumber::withNumber( info->fastStart, 32 );
789			propTable->setObject( gFast_Start_Symbol, prop );
790			prop->release();
791		}
792
793        prop = fProviderUnit->getProperty(gGUID_Symbol);
794        if( prop )
795            propTable->setObject( gGUID_Symbol, prop );
796
797		prop = fProviderUnit->getProperty(gFireWireModel_ID);
798        if( prop )
799            propTable->setObject( gFireWireModel_ID, prop );
800
801		prop = fProviderUnit->getProperty(gFireWireProduct_Name);
802        if( prop )
803            propTable->setObject( gFireWireProduct_Name, prop );
804
805		prop = fProviderUnit->getProperty(gFireWireVendor_Name);
806        if( prop )
807            propTable->setObject( gFireWireVendor_Name, prop );
808
809		//
810        // create lun
811        //
812
813        IOFireWireSBP2LUN * newLUN = new IOFireWireSBP2LUN;
814        if( newLUN != NULL )
815        {
816            bool success = true;
817
818            if( success )
819                success = newLUN->init(propTable);
820
821            if( success )
822                success = newLUN->attach(this);
823
824            if( success )
825                newLUN->registerService();
826
827            FWKLOG( ( "IOFireWireSBP2Target<%p> : created LUN object - success = %d\n", this, success ) );
828
829            if( !success )
830                status = kIOReturnError;
831
832            newLUN->release();
833        }
834
835        propTable->release();
836    }
837
838    return status;
839}
840
841// matchPropertyTable
842//
843//
844
845bool IOFireWireSBP2Target::matchPropertyTable(OSDictionary * table)
846{
847
848	//
849    // If the service object wishes to compare some of its properties in its
850    // property table against the supplied matching dictionary,
851    // it should do so in this method and return truth on success.
852    //
853
854    if( !IOService::matchPropertyTable(table) )
855		return false;
856
857    // We return success if the following expression is true -- individual
858    // comparisions evaluate to truth if the named property is not present
859    // in the supplied matching dictionary.
860
861    bool res = 	compareProperty(table, gCommand_Set_Spec_ID_Symbol) &&
862				compareProperty(table, gCommand_Set_Symbol) &&
863				compareProperty(table, gModule_Vendor_ID_Symbol) &&
864				compareProperty(table, gCommand_Set_Revision_Symbol) &&
865				compareProperty(table, gFirmware_Revision_Symbol) &&
866				compareProperty(table, gDevice_Type_Symbol) &&
867                compareProperty(table, gGUID_Symbol) &&
868                compareProperty(table, gFireWireModel_ID);
869
870    return res;
871}
872
873void IOFireWireSBP2Target::setTargetFlags( UInt32 flags )
874{
875	fFlags |= flags;
876
877	FWKLOG(( "IOFireWireSBP2Target<%p>::setTargetFlags 0x%08lx\n", this, fFlags ));
878
879    configurePhysicalFilter();
880}
881
882void IOFireWireSBP2Target::clearTargetFlags( UInt32 flags )
883{
884	fFlags &= ~flags;
885
886	FWKLOG(( "IOFireWireSBP2Target<%p>::clearTargetFlags 0x%08lx\n", this, fFlags ));
887
888    configurePhysicalFilter();
889}
890
891UInt32 IOFireWireSBP2Target::getTargetFlags( void )
892{
893    return fFlags;
894}
895
896void IOFireWireSBP2Target::configurePhysicalFilter( void )
897{
898    bool disablePhysicalAccess = false;
899
900	// sometimes message() gets called before start completes
901	// we shouldn't try to configure anything until start is done
902
903	if( fExpansionData == NULL )
904		return;
905
906	if( !fExpansionData->fStarted )
907		return;
908
909    //
910    // determine if we should turn off physical access
911    //
912
913    if( fFlags & kIOFWSBP2FailsOnAckBusy )
914    {
915        IOFireWireController * controller = fProviderUnit->getController();
916        IOService * fwim = (IOService*)controller->getLink();
917
918        UInt32 deviceCount = 0;
919
920        // get self id property
921        OSData * data = (OSData*)controller->getProperty( "FireWire Self IDs" );
922
923        // get self id data
924        UInt32 	numIDs = data->getLength() / sizeof(UInt32);
925        UInt32 	*IDs = (UInt32*)data->getBytesNoCopy();
926
927        // count nodes on bus
928        UInt32 	i;
929        for( i = 0; i < numIDs; i++ )
930        {
931            UInt32 current_id = IDs[i];
932            // count all type zero selfid with the linkon bit set
933            if( (current_id & kFWSelfIDPacketType) == 0 &&
934                (current_id & kFWSelfID0L) )
935            {
936                deviceCount++;
937            }
938        }
939
940		// if PhysicalUnitBlocksOnReads and more than one device on the bus,
941        // then turn off the physical unit for this node
942        if( (deviceCount > 2) && (fwim->getProperty( "PhysicalUnitBlocksOnReads" ) != NULL) )
943        {
944            disablePhysicalAccess = true;
945        }
946	}
947
948    //
949    // turn on or off physical access
950    //
951
952    if( disablePhysicalAccess )
953    {
954		FWKLOG(( "IOFireWireSBP2Target<%p>::configurePhysicalFilter disabling physical access for unit 0x%08lx\n", this, fProviderUnit ));
955        fProviderUnit->setNodeFlags( kIOFWDisableAllPhysicalAccess );
956    }
957    else
958    {
959		FWKLOG(( "IOFireWireSBP2Target<%p>::configurePhysicalFilter enabling physical access for unit 0x%08lx\n", this, fProviderUnit ));
960        fProviderUnit->clearNodeFlags( kIOFWDisableAllPhysicalAccess );
961    }
962
963}
964
965// beginIOCriticalSection
966//
967//
968
969IOReturn IOFireWireSBP2Target::beginIOCriticalSection( void )
970{
971	IOReturn status = kIOReturnSuccess;
972
973	FWKLOG(( "IOFireWireSBP2Target<%p>::beginIOCriticalSection\n", this ));
974
975	if( fFlags & kIOFWSBP2FailsOnBusResetsDuringIO )
976	{
977		FWKLOG(( "IOFireWireSBP2Target<%p>::beginIOCriticalSection fControl->disableSoftwareBusResets()\n", this ));
978		status = fControl->beginIOCriticalSection();
979		if( status == kIOReturnSuccess )
980		{
981			fIOCriticalSectionCount++;
982		}
983	}
984
985	FWKLOG(( "IOFireWireSBP2Target<%p>::beginIOCriticalSection status = 0x%08lx\n", this, (UInt32)status ));
986
987	return status;
988}
989
990// endIOCriticalSection
991//
992//
993
994void IOFireWireSBP2Target::endIOCriticalSection( void )
995{
996	FWKLOG(( "IOFireWireSBP2Target<%p>::endIOCriticalSection\n", this ));
997
998	if( fFlags & kIOFWSBP2FailsOnBusResetsDuringIO )
999	{
1000		FWKLOG(( "IOFireWireSBP2Target<%p>::endIOCriticalSection fControl->enableSoftwareBusResets()\n", this ));
1001
1002		if( fIOCriticalSectionCount != 0 )
1003		{
1004			fIOCriticalSectionCount--;
1005			fControl->endIOCriticalSection();
1006		}
1007		else
1008		{
1009#if __LP64__
1010			IOLog( "IOFireWireSBP2Target<0x%016llx>::endIOCriticalSection - fIOCriticalSectionCount == 0!\n", (UInt64)this );
1011#else
1012			IOLog( "IOFireWireSBP2Target<%p>::endIOCriticalSection - fIOCriticalSectionCount == 0!\n", this );
1013#endif
1014		}
1015	}
1016}
1017
1018// synchMgmtAgentAccess
1019//
1020//
1021
1022IOReturn IOFireWireSBP2Target::synchMgmtAgentAccess(
1023	IOFWCommand	*				mgmtOrbCommand
1024)
1025{
1026	if( fExpansionData->fNumLUNs > 1 )
1027	{
1028		FWKLOG(("IOFireWireSBP2Target::synchMgmtAgentAccess count %x\n",fExpansionData->fNumberPendingMgtAgentOrbs + 1));
1029
1030		if( fExpansionData->fNumberPendingMgtAgentOrbs++ )
1031		{
1032			FWKLOG(("IOFireWireSBP2Target::synchMgmtAgentAccess Mgmt Agent Busy, saving submit command %08x\n",mgmtOrbCommand));
1033			fExpansionData->fPendingMgtAgentCommands->setObject( mgmtOrbCommand );
1034		}
1035		else
1036			return( mgmtOrbCommand->submit() );
1037	}
1038	else
1039		return( mgmtOrbCommand->submit() );
1040
1041	return kIOReturnSuccess;
1042
1043}
1044
1045// completeMgmtAgentAccess
1046//
1047//
1048
1049void IOFireWireSBP2Target::completeMgmtAgentAccess( )
1050{
1051	IOFWAsyncCommand	*		mgmtOrbCommand;
1052	IOReturn 					status = kIOReturnSuccess;
1053
1054	if( fExpansionData->fNumLUNs > 1 )
1055	{
1056
1057		FWKLOG(("IOFireWireSBP2Target::completeMgmtAgentAccess >>  count %x\n",fExpansionData->fNumberPendingMgtAgentOrbs - 1));
1058		if( fExpansionData->fNumberPendingMgtAgentOrbs-- )
1059		{
1060			mgmtOrbCommand = (IOFWAsyncCommand *)fExpansionData->fPendingMgtAgentCommands->getObject( 0 ) ;
1061
1062			if( mgmtOrbCommand )
1063			{
1064				FWKLOG(("IOFireWireSBP2Target::completeMgmtAgentAccess, calling submit command %08x\n",mgmtOrbCommand));
1065				fExpansionData->fPendingMgtAgentCommands->removeObject( 0 ) ;
1066
1067				status = mgmtOrbCommand->submit() ;
1068
1069				if( status )
1070				{
1071					FWKLOG(("IOFireWireSBP2Target::completeMgmtAgentAccess, submit for command %08x failed with %08x\n",mgmtOrbCommand,status));
1072					mgmtOrbCommand->gotPacket( kFWResponseBusResetError, NULL, 0 );
1073				}
1074			}
1075		}
1076		FWKLOG(("IOFireWireSBP2Target::completeMgmtAgentAccess << count %x\n",fExpansionData->fNumberPendingMgtAgentOrbs));
1077	}
1078}
1079
1080// clearMgmtAgentAccess
1081//
1082//
1083
1084void IOFireWireSBP2Target::cancelMgmtAgentAccess( IOFWCommand * mgmtOrbCommand )
1085{
1086	// should only have one instance of a given command in this list, but I'll use a loop for good measure.
1087
1088	int index;
1089	while( (index = fExpansionData->fPendingMgtAgentCommands->getNextIndexOfObject( mgmtOrbCommand, 0 )) != -1 )
1090	{
1091		fExpansionData->fPendingMgtAgentCommands->removeObject( index );
1092	}
1093}
1094
1095// clearMgmtAgentAccess
1096//
1097//
1098
1099void IOFireWireSBP2Target::clearMgmtAgentAccess( )
1100{
1101	if( fExpansionData && fExpansionData->fPendingMgtAgentCommands )
1102	{
1103		IOFWAsyncCommand *				mgmtOrbCommand;
1104
1105		FWKLOG(("IOFireWireSBP2Target::clearMgmtAgentAccess\n",mgmtOrbCommand));
1106
1107		while( (mgmtOrbCommand = (IOFWAsyncCommand *)fExpansionData->fPendingMgtAgentCommands->getObject( 0 ))  )
1108		{
1109			mgmtOrbCommand->retain();
1110
1111			fExpansionData->fPendingMgtAgentCommands->removeObject( 0 ) ;
1112
1113			FWKLOG(("IOFireWireSBP2Target::clearMgmtAgentAccess, failing command %08x\n",mgmtOrbCommand));
1114			mgmtOrbCommand->gotPacket( kFWResponseBusResetError, NULL, 0 );
1115
1116			mgmtOrbCommand->release();
1117		}
1118
1119		fExpansionData->fNumberPendingMgtAgentOrbs = 0;
1120	}
1121}
1122