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#include <IOKit/IOWorkLoop.h>
25
26#include <IOKit/sbp2/IOFireWireSBP2Target.h>
27#include <IOKit/sbp2/IOFireWireSBP2LUN.h>
28#include <IOKit/sbp2/IOFireWireSBP2UserClient.h>
29#include "FWDebugging.h"
30#include "IOFireWireSBP2Diagnostics.h"
31
32extern const OSSymbol *gCommand_Set_Spec_ID_Symbol;
33extern const OSSymbol *gCommand_Set_Symbol;
34extern const OSSymbol *gModule_Vendor_ID_Symbol;
35extern const OSSymbol *gCommand_Set_Revision_Symbol;
36extern const OSSymbol *gIOUnit_Symbol;
37extern const OSSymbol *gFirmware_Revision_Symbol;
38extern const OSSymbol *gDevice_Type_Symbol;
39extern const OSSymbol *gGUID_Symbol;
40
41const OSSymbol *gDiagnostics_Symbol;
42
43OSDefineMetaClassAndStructors( IOFireWireSBP2LUN, IOService );
44
45OSMetaClassDefineReservedUnused(IOFireWireSBP2LUN, 0);
46OSMetaClassDefineReservedUnused(IOFireWireSBP2LUN, 1);
47OSMetaClassDefineReservedUnused(IOFireWireSBP2LUN, 2);
48OSMetaClassDefineReservedUnused(IOFireWireSBP2LUN, 3);
49OSMetaClassDefineReservedUnused(IOFireWireSBP2LUN, 4);
50OSMetaClassDefineReservedUnused(IOFireWireSBP2LUN, 5);
51OSMetaClassDefineReservedUnused(IOFireWireSBP2LUN, 6);
52OSMetaClassDefineReservedUnused(IOFireWireSBP2LUN, 7);
53OSMetaClassDefineReservedUnused(IOFireWireSBP2LUN, 8);
54
55bool IOFireWireSBP2LUN::attach(IOService *provider)
56{
57	IOReturn status = kIOReturnSuccess;
58
59	// init fields
60	fProviderTarget = NULL;
61	fGate 			= NULL;
62	fLUNumber 		= 0;
63	fORBSet 		= NULL;
64	fORBSetIterator = NULL;
65
66    FWKLOG( ( "IOFireWireSBP2LUN<%p> : attach\n", this ) );
67
68	//
69	// attach to provider
70	//
71
72	if( status == kIOReturnSuccess )
73	{
74		fProviderTarget = OSDynamicCast( IOFireWireSBP2Target, provider );
75		if( !fProviderTarget )
76			status = kIOReturnError;
77	}
78
79	if( status == kIOReturnSuccess )
80	{
81		fProviderTarget->retain();
82		if( !IOService::attach(provider) )
83        	status = kIOReturnError;
84	}
85
86#if FWDIAGNOSTICS
87
88	if( gDiagnostics_Symbol == NULL )
89		gDiagnostics_Symbol = OSSymbol::withCString("SBP2 Diagnostics");
90
91	fDiagnostics = IOFireWireSBP2Diagnostics::createDiagnostics();
92	if( fDiagnostics )
93	{
94		setProperty( gDiagnostics_Symbol, fDiagnostics );
95	}
96
97#endif
98
99	//
100	// get lun number
101	//
102
103	if( status == kIOReturnSuccess )
104	{
105		OSObject *prop;
106
107		// read lun number from registry
108		prop = getProperty( gIOUnit_Symbol );
109		fLUNumber = ((OSNumber*)prop)->unsigned32BitValue();
110	}
111
112    //
113    // create login set
114    //
115
116	if( status == kIOReturnSuccess )
117	{
118		fLoginSet = OSSet::withCapacity(1);
119		if( fLoginSet == NULL )
120			status = kIOReturnNoMemory;
121	}
122
123	if( status == kIOReturnSuccess )
124	{
125		if( fLoginSet )
126            fLoginSetIterator = OSCollectionIterator::withCollection( fLoginSet );
127	}
128
129
130	//
131	// create management orb set
132	//
133
134	if( status == kIOReturnSuccess )
135	{
136		fORBSet = OSSet::withCapacity(1);
137		if( fORBSet == NULL )
138			status = kIOReturnNoMemory;
139	}
140
141	if( status == kIOReturnSuccess )
142	{
143		if( fORBSet )
144            fORBSetIterator = OSCollectionIterator::withCollection( fORBSet );
145	}
146
147	//
148	// set up command gate
149	//
150
151	IOWorkLoop * workLoop = NULL;
152	if( status == kIOReturnSuccess )
153	{
154		workLoop = getWorkLoop();
155		if( !workLoop )
156			status = kIOReturnNoResources;
157	}
158
159	if( status == kIOReturnSuccess )
160	{
161		fGate = IOCommandGate::commandGate( this );
162		if( !fGate )
163			status = kIOReturnNoMemory;
164	}
165
166	if( status == kIOReturnSuccess )
167	{
168		workLoop->retain();
169		workLoop->addEventSource( fGate );
170	}
171
172    return (status == kIOReturnSuccess);
173}
174
175// finalize
176//
177//
178
179bool IOFireWireSBP2LUN::finalize( IOOptionBits options )
180{
181	FWKLOG( ( "IOFireWireSBP2LUN<%p> : finalize\n", this ) );
182
183	return IOService::finalize( options );
184}
185
186//
187// free
188//
189
190void IOFireWireSBP2LUN::free( void )
191{
192	FWKLOG( ( "IOFireWireSBP2LUN<%p> : free\n", this ) );
193
194	//
195	// free unreleased orbs
196	//
197
198//	flushAllManagementORBs();
199
200	if( fORBSetIterator )
201		fORBSetIterator->release();
202
203	if( fORBSet )
204		fORBSet->release();
205
206    //
207    // release login set
208    //
209
210	if( fLoginSetIterator )
211		fLoginSetIterator->release();
212
213	if( fLoginSet )
214		fLoginSet->release();
215
216	//
217	// destroy command gate
218	//
219
220	if( fGate != NULL )
221	{
222		IOWorkLoop * workLoop = NULL;
223
224		workLoop = fGate->getWorkLoop();
225		workLoop->removeEventSource( fGate );
226		workLoop->release();
227
228		fGate->release();
229		fGate = NULL;
230	}
231
232	if( fProviderTarget )
233	{
234		fProviderTarget->release();
235		fProviderTarget = NULL;
236	}
237
238	IOService::free();
239}
240
241// flushAllManagementORBs
242//
243//
244
245void IOFireWireSBP2LUN::flushAllManagementORBs( void )
246{
247	IOReturn status = kIOReturnSuccess;
248
249	status = fGate->runAction( staticExecuteFlushAllMgmtORBs);
250}
251
252IOReturn IOFireWireSBP2LUN::staticExecuteFlushAllMgmtORBs( OSObject * self, void *,
253										void *, void *, void * )
254{
255	return ((IOFireWireSBP2LUN *)self)->executeFlushAllMgmtORBs();
256}
257
258IOReturn IOFireWireSBP2LUN::executeFlushAllMgmtORBs( void )
259{
260	//
261	// free unreleased orbs
262	//
263
264	if( fORBSetIterator )
265	{
266		IOFireWireSBP2ManagementORB * item = NULL;
267		do
268		{
269            fORBSetIterator->reset();
270			item = (IOFireWireSBP2ManagementORB *)fORBSetIterator->getNextObject();
271			if( item )
272				item->release();
273		} while( item );
274	}
275
276	return kIOReturnSuccess;
277}
278
279////////////////////////////////////////////////////////////////////
280
281//
282// handleOpen / handleClose
283//
284
285bool IOFireWireSBP2LUN::handleOpen( IOService * forClient, IOOptionBits options, void * arg )
286{
287    FWKLOG(( "IOFireWireSBP2LUN<%p> (%d) : handleOpen\n", this, fLUNumber ));
288
289	bool ok = false;
290
291	if( !isOpen() )
292	{
293		ok = fProviderTarget->open(this, options, arg);
294		if(ok)
295			ok = IOService::handleOpen(forClient, options, arg);
296	}
297
298	return ok;
299}
300
301void IOFireWireSBP2LUN::handleClose( IOService * forClient, IOOptionBits options )
302{
303    FWKLOG(( "IOFireWireSBP2LUN<%p> (%d) : handleClose\n", this, fLUNumber ));
304
305	if( isOpen( forClient ) )
306	{
307		IOService::handleClose(forClient, options);
308		fProviderTarget->close(this, options);
309	}
310}
311
312//
313// message method
314//
315
316IOReturn IOFireWireSBP2LUN::message( UInt32 type, IOService *nub, void *arg )
317{
318    IOReturn res = kIOReturnUnsupported;
319
320    //IOLog("IOFireWireSBP2LUN, message 0x%x\n", type);
321
322    res = IOService::message(type, nub, arg);
323
324    if( kIOReturnUnsupported == res )
325    {
326        switch (type)
327        {
328            case kIOMessageServiceIsTerminated:
329				terminateNotify();
330                FWKLOG( ( "IOFireWireSBP2LUN<%p> : kIOMessageServiceIsTerminated\n", this ) );
331                res = kIOReturnSuccess;
332                break;
333
334            case kIOMessageServiceIsSuspended:
335				FWKLOG( ( "IOFireWireSBP2LUN<%p> : kIOMessageServiceIsSuspended\n", this ) );
336                suspendedNotify();
337                res = kIOReturnSuccess;
338                break;
339
340            case kIOMessageServiceIsResumed:
341				FWKLOG( ( "IOFireWireSBP2LUN<%p> : kIOMessageServiceIsResumed\n", this ) );
342                resumeNotify();
343                res = kIOReturnSuccess;
344                break;
345
346            default: // default the action to return kIOReturnUnsupported
347                break;
348        }
349   }
350
351    // we must send resumeNotify and/or suspendNotify before messaging clients
352	if( type != kIOMessageServiceIsTerminated &&
353		type != (UInt32)kIOMessageFWSBP2ReconnectFailed &&
354		type != (UInt32)kIOMessageFWSBP2ReconnectComplete )
355	{
356		messageClients( type, arg );
357    }
358
359	// send reset notification for all busy orbs
360	// we must send orb reset notification after messaging clients
361	if( type == kIOMessageServiceIsSuspended )
362		clearAllTasksInSet();
363
364    return res;
365}
366
367////////////////////////////////////////////////////////////////////
368
369// getFireWireUnit
370//
371// returns the FireWire unit for doing non-SBP2 work
372
373IOFireWireUnit * IOFireWireSBP2LUN::getFireWireUnit( void )
374{
375	IOService * unit = NULL;
376
377	IOService * provider = getProvider();
378	if( provider )
379	{
380		unit = provider->getProvider();
381	}
382
383    return (IOFireWireUnit*)unit;
384}
385
386// getLUNumber
387//
388// lun number accessor
389
390UInt32 IOFireWireSBP2LUN::getLUNumber( void )
391{
392    return fLUNumber;
393}
394
395// getTarget
396//
397// target accessor
398
399IOFireWireSBP2Target * IOFireWireSBP2LUN::getTarget( void )
400{
401	return (IOFireWireSBP2Target*)getProvider();
402}
403
404////////////////////////////////////////////////////////////////////
405
406// createLogin
407//
408// create a login object
409
410IOFireWireSBP2Login * IOFireWireSBP2LUN::createLogin( void )
411{
412	IOReturn 				status = kIOReturnSuccess;
413	IOFireWireSBP2Login *	login;
414
415	status = fGate->runAction( staticCreateLogin, &login );
416
417	return login;
418}
419
420IOReturn IOFireWireSBP2LUN::staticCreateLogin( OSObject *self, void * login, void *, void *, void * )
421{
422	return ((IOFireWireSBP2LUN *)self)->createLoginAction( (IOFireWireSBP2Login **)login );
423}
424
425IOReturn IOFireWireSBP2LUN::createLoginAction( IOFireWireSBP2Login ** login )
426{
427	IOFireWireSBP2Login *	newLogin;
428    newLogin  = new IOFireWireSBP2Login;
429	if( newLogin != NULL && !initLoginWithLUN( newLogin, this ) )
430    {
431    	newLogin->release();
432    	newLogin = NULL;
433    }
434
435	*login = newLogin;
436
437	fLoginSet->setObject( *login );
438
439    return kIOReturnSuccess;
440}
441
442//
443// remove login
444//
445
446// removeManagementORB
447//
448// remove management orb from LUN's set
449
450void IOFireWireSBP2LUN::removeLogin( IOFireWireSBP2Login * login )
451{
452	IOReturn status = kIOReturnSuccess;
453
454	status = fGate->runAction( (IOCommandGate::Action)staticRemoveLoginAction, (void*)login );
455}
456
457IOReturn IOFireWireSBP2LUN::staticRemoveLoginAction( OSObject *self, void * login, void *, void *, void * )
458{
459	return ((IOFireWireSBP2LUN*)self)->removeLoginAction( (IOFireWireSBP2Login *)login );
460}
461
462IOReturn IOFireWireSBP2LUN::removeLoginAction( IOFireWireSBP2Login * login )
463{
464	fLoginSet->removeObject( login );
465	return kIOReturnSuccess;
466}
467
468// clearAllTasksInSet
469//
470// send reset notification for all busy orbs
471
472void IOFireWireSBP2LUN::clearAllTasksInSet( void )
473{
474	if( fORBSetIterator )
475	{
476		IOFireWireSBP2ManagementORB * item = NULL;
477		fORBSetIterator->reset();
478		do
479		{
480			item = (IOFireWireSBP2ManagementORB *)fORBSetIterator->getNextObject();
481			if( item )
482				item->suspendedNotify();
483		} while( item );
484	}
485
486 	if( fLoginSetIterator )
487	{
488		IOFireWireSBP2Login * item = NULL;
489        fLoginSetIterator->reset();
490        do
491		{
492			item = (IOFireWireSBP2Login *)fLoginSetIterator->getNextObject();
493			if( item )
494				item->clearAllTasksInSet();
495		} while( item );
496	}
497}
498
499////////////////////////////////////////////////////////////////////
500
501// createManagementORB
502//
503// create a management object
504
505IOFireWireSBP2ManagementORB * IOFireWireSBP2LUN::createManagementORB( void * refCon, FWSBP2ManagementCallback completion )
506{
507	IOReturn status = kIOReturnSuccess;
508	IOFireWireSBP2ManagementORB * orb;
509
510	status = fGate->runAction( staticCreateManagementORBAction, refCon, (void*)completion, &orb );
511
512	return orb;
513}
514
515IOReturn IOFireWireSBP2LUN::staticCreateManagementORBAction( OSObject *self,
516								void * refCon, void * completion,
517								void * orb, void * )
518{
519	return ((IOFireWireSBP2LUN *)self)->createManagementORBAction(  refCon, (FWSBP2ManagementCallback)completion, (IOFireWireSBP2ManagementORB **)orb );
520}
521
522IOReturn IOFireWireSBP2LUN::createManagementORBAction(
523								void * refCon, FWSBP2ManagementCallback completion,
524								IOFireWireSBP2ManagementORB ** orb )
525{
526    IOFireWireSBP2ManagementORB * newORB = new IOFireWireSBP2ManagementORB;
527    if( newORB != NULL && !initMgmtORBWithLUN( newORB, this, refCon, completion ) )
528    {
529    	newORB->release();
530    	newORB = NULL;
531    }
532
533	*orb = newORB;
534
535	fORBSet->setObject( *orb );
536
537    return kIOReturnSuccess;
538}
539
540// removeManagementORB
541//
542// remove management orb from LUN's set
543
544void IOFireWireSBP2LUN::removeManagementORB( IOFireWireSBP2ManagementORB * orb )
545{
546	IOReturn status = kIOReturnSuccess;
547
548	status = fGate->runAction( (IOCommandGate::Action)staticRemoveManagementORBAction, (void*)orb );
549}
550
551IOReturn IOFireWireSBP2LUN::staticRemoveManagementORBAction( OSObject *self, void * orb,
552																void *, void *, void * )
553{
554	return ((IOFireWireSBP2LUN*)self)->removeManagementORBAction( (IOFireWireSBP2ManagementORB *)orb );
555}
556
557IOReturn IOFireWireSBP2LUN::removeManagementORBAction(
558								IOFireWireSBP2ManagementORB * orb )
559{
560	fORBSet->removeObject( orb );
561
562	return kIOReturnSuccess;
563}
564
565////////////////////////////////////////////////////////////////////
566
567// matchPropertyTable
568//
569//
570
571bool IOFireWireSBP2LUN::matchPropertyTable(OSDictionary * table)
572{
573
574	//
575    // If the service object wishes to compare some of its properties in its
576    // property table against the supplied matching dictionary,
577    // it should do so in this method and return truth on success.
578    //
579
580    if( !IOService::matchPropertyTable(table) )
581		return false;
582
583    // We return success if the following expression is true -- individual
584    // comparisions evaluate to truth if the named property is not present
585    // in the supplied matching dictionary.
586
587    bool res = 	compareProperty(table, gCommand_Set_Spec_ID_Symbol) &&
588				compareProperty(table, gCommand_Set_Symbol) &&
589				compareProperty(table, gModule_Vendor_ID_Symbol) &&
590				compareProperty(table, gCommand_Set_Revision_Symbol) &&
591				compareProperty(table, gIOUnit_Symbol) &&
592				compareProperty(table, gFirmware_Revision_Symbol) &&
593				compareProperty(table, gDevice_Type_Symbol) &&
594                compareProperty(table, gGUID_Symbol) &&
595                compareProperty(table, gFireWireModel_ID);
596
597    return res;
598}
599
600////////////////////////////////////////////////////////////////////
601
602//
603// IOFireWireSBP2ManagementORB friend class wrappers
604//
605
606bool IOFireWireSBP2LUN::initMgmtORBWithLUN( IOFireWireSBP2ManagementORB * orb, IOFireWireSBP2LUN * lun,
607									 void * refCon,
608									 FWSBP2ManagementCallback completion )
609{
610	return orb->initWithLUN( lun, refCon, completion );
611}
612
613//
614// IOFireWireSBP2Login friend class wrappers
615//
616
617bool IOFireWireSBP2LUN::initLoginWithLUN( IOFireWireSBP2Login * login, IOFireWireSBP2LUN * lun )
618{
619	return login->initWithLUN( lun );
620}
621
622void IOFireWireSBP2LUN::suspendedNotify( void )
623{
624    if( fLoginSetIterator )
625	{
626		IOFireWireSBP2Login * item = NULL;
627		fLoginSetIterator->reset();
628		do
629		{
630			item = (IOFireWireSBP2Login *)fLoginSetIterator->getNextObject();
631			if( item )
632				item->suspendedNotify();
633		} while( item );
634	}
635}
636
637void IOFireWireSBP2LUN::resumeNotify( void )
638{
639    if( fLoginSetIterator )
640	{
641		IOFireWireSBP2Login * item = NULL;
642		fLoginSetIterator->reset();
643        do
644		{
645			item = (IOFireWireSBP2Login *)fLoginSetIterator->getNextObject();
646			if( item )
647				item->resumeNotify();
648		} while( item );
649	}
650}
651
652void IOFireWireSBP2LUN::terminateNotify( void )
653{
654    if( fLoginSetIterator )
655	{
656		IOFireWireSBP2Login * item = NULL;
657		fLoginSetIterator->reset();
658		do
659		{
660			item = (IOFireWireSBP2Login *)fLoginSetIterator->getNextObject();
661			if( item )
662				item->terminateNotify();
663		} while( item );
664	}
665}
666
667
668// getDiagnostics
669//
670// return a pointer to the diagnostics object
671
672OSObject * IOFireWireSBP2LUN::getDiagnostics( void )
673{
674	return fDiagnostics;
675}
676