2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
20 * @APPLE_LICENSE_HEADER_END@
23 * IOSCSIParallelController.cpp
27 #include <IOKit/scsi/IOSCSIParallelInterface.h>
28 #include <IOKit/IOSyncer.h>
31 #define super IOService
33 OSDefineMetaClass( IOSCSIParallelController
, IOService
)
34 OSDefineAbstractStructors( IOSCSIParallelController
, IOService
);
36 #define round(x,y) (((int)(x) + (y) - 1) & ~((y)-1))
42 bool IOSCSIParallelController::start( IOService
*forProvider
)
44 provider
= forProvider
;
46 if ( provider
->open( this ) != true )
51 if ( createWorkLoop() != true )
56 if ( configureController() == false )
58 provider
->close( this );
64 if ( scanSCSIBus() == false )
66 provider
->close( this );
78 bool IOSCSIParallelController::scanSCSIBus()
80 SCSITargetLun targetLun
;
85 for ( i
=0; i
< controllerInfo
.maxTargetsSupported
; i
++ )
88 probeTarget( targetLun
);
99 bool IOSCSIParallelController::probeTarget( SCSITargetLun targetLun
)
101 IOSCSIParallelDevice
*device
;
104 if ( targetLun
.target
== controllerInfo
.initiatorId
)
109 if ( initTarget( targetLun
) == false )
111 releaseTarget( targetLun
);
115 for ( i
=0; i
< controllerInfo
.maxLunsSupported
; i
++ )
119 device
= createDevice();
125 if ( device
->init( this, targetLun
) == false )
127 releaseDevice( device
);
131 if ( initDevice( device
) == false )
133 releaseDevice( device
);
137 if ( device
->probeTargetLun() != kIOReturnSuccess
)
139 releaseDevice( device
);
146 releaseTarget( targetLun
);
150 queue_iterate( &targets
[targetLun
.target
].deviceList
, device
, IOSCSIParallelDevice
*, nextDevice
)
152 device
->setupTarget();
153 device
->attach( this );
154 device
->registerService();
165 bool IOSCSIParallelController::initTargetGated( SCSITargetLun
*targetLun
)
167 return initTarget( *targetLun
);
170 bool IOSCSIParallelController::initTarget( SCSITargetLun targetLun
)
175 if ( getWorkLoop()->inGate() == false )
177 return controllerGate
->runAction( (IOCommandGate::Action
)&IOSCSIParallelController::initTargetGated
, (void *)&targetLun
);
180 target
= &targets
[targetLun
.target
];
182 target
->clientSem
= IORWLockAlloc();
183 target
->targetSem
= IORWLockAlloc();
184 if( (target
->targetSem
== 0) || (target
->clientSem
== 0))
188 target
->commandLimitSave
= target
->commandLimit
= 1;
190 target
->targetParmsCurrent
.transferWidth
= 1;
192 if ( controllerInfo
.targetPrivateDataSize
!= 0 )
194 target
->targetPrivateData
= IOMallocContiguous( controllerInfo
.targetPrivateDataSize
, 16, 0 );
195 if ( target
->targetPrivateData
== 0 )
201 if ( controllerInfo
.tagAllocationMethod
== kTagAllocationPerTarget
)
203 target
->tagArray
= (UInt32
*)IOMalloc( tagArraySize
);
204 if ( target
->tagArray
== 0 )
208 bzero( target
->tagArray
, tagArraySize
);
212 target
->regObjTransferPeriod
= OSNumber::withNumber( number
, 32 );
213 if ( target
->regObjTransferPeriod
== 0 )
219 target
->regObjTransferOffset
= OSNumber::withNumber( number
, 32 );
220 if ( target
->regObjTransferOffset
== 0 )
226 target
->regObjTransferWidth
= OSNumber::withNumber( number
, 32 );
227 if ( target
->regObjTransferWidth
== 0 )
233 target
->regObjTransferOptions
= OSNumber::withNumber( number
, 32 );
234 if ( target
->regObjTransferOptions
== 0 )
240 target
->regObjCmdQueue
= OSNumber::withNumber( number
, 32 );
241 if ( target
->regObjCmdQueue
== 0 )
246 target
->targetAllocated
= allocateTarget( targetLun
);
248 return target
->targetAllocated
;
256 void IOSCSIParallelController::releaseTargetGated( SCSITargetLun
*targetLun
)
258 releaseTarget( *targetLun
);
261 void IOSCSIParallelController::releaseTarget( SCSITargetLun targetLun
)
265 if ( getWorkLoop()->inGate() == false )
267 controllerGate
->runAction( (IOCommandGate::Action
)&IOSCSIParallelController::releaseTargetGated
, (void *)&targetLun
);
271 target
= &targets
[targetLun
.target
];
273 if ( queue_empty( &target
->deviceList
) != true )
275 IOLog("IOSCSIParallelController()::Target %d deleted with lun(s) active!\n\r",
279 if ( target
->targetAllocated
== true )
281 deallocateTarget( targetLun
);
283 target
->targetAllocated
= false;
286 if ( target
->tagArray
!= 0 )
288 IOFree( target
->tagArray
, tagArraySize
);
289 target
->tagArray
= 0;
292 if ( target
->targetPrivateData
!= 0 )
294 IOFreeContiguous( target
->targetPrivateData
, controllerInfo
.targetPrivateDataSize
);
295 target
->targetPrivateData
= 0;
298 if ( target
->clientSem
!= 0 )
300 IORWLockFree( target
->clientSem
);
302 if ( target
->targetSem
!= 0 )
304 IORWLockFree( target
->targetSem
);
307 if ( target
->regObjTransferPeriod
!= 0 )
309 target
->regObjTransferPeriod
->release();
310 target
->regObjTransferPeriod
= 0;
312 if ( target
->regObjTransferOffset
!= 0 )
314 target
->regObjTransferOffset
->release();
315 target
->regObjTransferOffset
= 0;
317 if ( target
->regObjTransferWidth
!= 0 )
319 target
->regObjTransferWidth
->release();
320 target
->regObjTransferWidth
= 0;
322 if ( target
->regObjCmdQueue
!= 0 )
324 target
->regObjCmdQueue
->release();
325 target
->regObjCmdQueue
= 0;
335 bool IOSCSIParallelController::initDeviceGated( IOSCSIParallelDevice
*device
)
337 return initDevice( device
);
340 bool IOSCSIParallelController::initDevice( IOSCSIParallelDevice
*device
)
342 if ( getWorkLoop()->inGate() == false )
344 return controllerGate
->runAction( (IOCommandGate::Action
)&IOSCSIParallelController::initDeviceGated
, (void *)device
);
348 device
->lunAllocated
= allocateLun( device
->targetLun
);
350 return device
->lunAllocated
;
358 void IOSCSIParallelController::releaseDeviceGated( IOSCSIParallelDevice
*device
)
360 releaseDevice( device
);
364 void IOSCSIParallelController::releaseDevice( IOSCSIParallelDevice
*device
)
366 if ( getWorkLoop()->inGate() == false )
368 controllerGate
->runAction( (IOCommandGate::Action
)&IOSCSIParallelController::releaseDeviceGated
, (void *)device
);
372 deleteDevice( device
);
373 if ( device
->lunAllocated
== true )
375 deallocateLun( device
->targetLun
);
387 void IOSCSIParallelController::addDevice( IOSCSIParallelDevice
*forDevice
)
391 targetID
= forDevice
->targetLun
.target
;
393 forDevice
->target
= &targets
[targetID
];
394 queue_enter( &targets
[targetID
].deviceList
, forDevice
, IOSCSIParallelDevice
*, nextDevice
);
402 void IOSCSIParallelController::deleteDevice( IOSCSIParallelDevice
*forDevice
)
404 queue_head_t
*deviceList
;
405 IOSCSIParallelDevice
*device
;
408 targetID
= forDevice
->targetLun
.target
;
410 deviceList
= &targets
[targetID
].deviceList
;
412 queue_iterate( deviceList
, device
, IOSCSIParallelDevice
*, nextDevice
)
414 if ( device
== forDevice
)
416 queue_remove( &targets
[targetID
].deviceList
, device
, IOSCSIParallelDevice
*, nextDevice
);
427 bool IOSCSIParallelController::allocateTarget( SCSITargetLun targetLun
)
437 void IOSCSIParallelController::deallocateTarget( SCSITargetLun targetLun
)
446 bool IOSCSIParallelController::allocateLun( SCSITargetLun targetLun
)
456 void IOSCSIParallelController::deallocateLun( SCSITargetLun targetLun
)
466 void *IOSCSIParallelController::getTargetData( SCSITargetLun targetLun
)
468 return targets
[targetLun
.target
].targetPrivateData
;
476 void *IOSCSIParallelController::getLunData( SCSITargetLun targetLun
)
478 queue_head_t
*deviceList
;
479 IOSCSIParallelDevice
*device
;
481 deviceList
= &targets
[targetLun
.target
].deviceList
;
483 queue_iterate( deviceList
, device
, IOSCSIParallelDevice
*, nextDevice
)
485 if ( device
->targetLun
.lun
== targetLun
.lun
)
487 return device
->devicePrivateData
;
500 IOSCSIParallelDevice
*IOSCSIParallelController::createDevice()
502 return new IOSCSIParallelDevice
;
511 void IOSCSIParallelController::initQueues()
515 for ( i
=0; i
< controllerInfo
.maxTargetsSupported
; i
++ )
517 queue_init( &targets
[i
].deviceList
);
520 resetCmd
= allocCommand( 0 );
521 resetCmd
->cmdType
= kSCSICommandBusReset
;
531 void IOSCSIParallelController::reset()
533 IOSCSIParallelDevice
*device
;
536 if ( busResetState
!= kStateIssue
)
541 busResetState
= kStateActive
;
543 for (i
=0; i
< controllerInfo
.maxTargetsSupported
; i
++ )
545 queue_iterate( &targets
[i
].deviceList
, device
, IOSCSIParallelDevice
*, nextDevice
)
547 if ( device
->client
!= 0 )
549 device
->client
->message( kSCSIClientMsgBusReset
, device
);
554 resetCommand( resetCmd
);
562 bool IOSCSIParallelController::checkBusReset()
564 if ( busResetState
== kStateIdle
)
568 if ( busResetState
== kStateIssue
)
581 void IOSCSIParallelController::resetOccurred()
584 IOSCSIParallelDevice
*device
;
586 SCSIClientMessage clientMsg
;
588 for (i
=0; i
< controllerInfo
.maxTargetsSupported
; i
++ )
590 target
= &targets
[i
];
592 target
->commandLimit
= target
->commandLimitSave
;
593 target
->reqSenseCount
= 0;
594 target
->reqSenseState
= kStateIdle
;
595 target
->negotiateState
= kStateIssue
;
597 target
->targetParmsCurrent
.transferPeriodpS
= 0;
598 target
->targetParmsCurrent
.transferOffset
= 0;
599 target
->targetParmsCurrent
.transferWidth
= 1;
603 clientMsg
= ( busResetState
!= kStateActive
) ? kSCSIClientMsgBusReset
: kSCSIClientMsgNone
;
605 queue_iterate( &target
->deviceList
, device
, IOSCSIParallelDevice
*, nextDevice
)
607 device
->resetOccurred( clientMsg
);
611 resetTimer
= (kSCSIResetIntervalmS
/ kSCSITimerIntervalmS
+ 1);
619 void IOSCSIParallelController::timer( IOTimerEventSource
* /* timer */ )
622 IOSCSIParallelDevice
*device
;
627 if ( !--disableTimer
)
629 disableTimeoutOccurred();
637 for (i
=0; i
< controllerInfo
.maxTargetsSupported
; i
++ )
639 queue_iterate( &targets
[i
].deviceList
, device
, IOSCSIParallelDevice
*, nextDevice
)
641 device
->resetComplete();
649 for (i
=0; i
< controllerInfo
.maxTargetsSupported
; i
++ )
651 queue_iterate( &targets
[i
].deviceList
, device
, IOSCSIParallelDevice
*, nextDevice
)
658 timerEvent
->setTimeoutMS(kSCSITimerIntervalmS
);
667 void IOSCSIParallelController::completeCommand( IOSCSIParallelCommand
*scsiCmd
)
669 switch ( scsiCmd
->cmdType
)
671 case kSCSICommandBusReset
:
673 busResetState
= kStateIdle
;
686 bool IOSCSIParallelController::createWorkLoop()
688 workLoop
= getWorkLoop();
691 workLoop
= IOWorkLoop::workLoop();
698 timerEvent
= IOTimerEventSource::timerEventSource( this, (IOTimerEventSource::Action
) &IOSCSIParallelController::timer
);
699 if ( timerEvent
== 0 )
704 if ( workLoop
->addEventSource( timerEvent
) != kIOReturnSuccess
)
710 dispatchEvent
= IOInterruptEventSource::interruptEventSource( this,
711 (IOInterruptEventAction
) &IOSCSIParallelController::dispatch
,
713 if ( dispatchEvent
== 0 )
718 if ( workLoop
->addEventSource( dispatchEvent
) != kIOReturnSuccess
)
723 controllerGate
= IOCommandGate::commandGate( this, (IOCommandGate::Action
) 0 );
724 if ( controllerGate
== 0 )
729 if ( workLoop
->addEventSource( controllerGate
) != kIOReturnSuccess
)
742 IOSCSIParallelCommand
*IOSCSIParallelController::findCommandWithNexus( SCSITargetLun targetLun
, UInt32 tagValue
= (UInt32
)-1 )
744 IOSCSIParallelDevice
*device
;
746 device
= findDeviceWithTargetLun( targetLun
);
752 return device
->findCommandWithNexus( tagValue
);
761 IOSCSIParallelDevice
*IOSCSIParallelController::findDeviceWithTargetLun( SCSITargetLun targetLun
)
763 IOSCSIParallelDevice
*device
;
765 if ( targetLun
.target
> controllerInfo
.maxTargetsSupported
|| targetLun
.lun
> controllerInfo
.maxLunsSupported
)
770 queue_iterate( &targets
[targetLun
.target
].deviceList
, device
, IOSCSIParallelDevice
*, nextDevice
)
772 if ( device
->targetLun
.lun
== targetLun
.lun
)
786 bool IOSCSIParallelController::configureController()
790 if ( configure( provider
, &controllerInfo
) == false )
795 controllerInfo
.commandPrivateDataSize
= round( controllerInfo
.commandPrivateDataSize
, 16 );
797 if ( controllerInfo
.maxCommandsPerController
== 0 ) controllerInfo
.maxCommandsPerController
= (UInt32
) -1;
798 if ( controllerInfo
.maxCommandsPerTarget
== 0 ) controllerInfo
.maxCommandsPerTarget
= (UInt32
) -1;
799 if ( controllerInfo
.maxCommandsPerLun
== 0 ) controllerInfo
.maxCommandsPerLun
= (UInt32
) -1;
801 targetsSize
= controllerInfo
.maxTargetsSupported
* sizeof(SCSITarget
);
802 targets
= (SCSITarget
*)IOMalloc( targetsSize
);
803 bzero( targets
, targetsSize
);
805 commandLimit
= commandLimitSave
= controllerInfo
.maxCommandsPerController
;
807 tagArraySize
= (controllerInfo
.maxTags
/ 32 + ((controllerInfo
.maxTags
% 32) ? 1 : 0)) * sizeof(UInt32
);
809 if ( controllerInfo
.tagAllocationMethod
== kTagAllocationPerController
)
811 tagArray
= (UInt32
*)IOMalloc( tagArraySize
);
812 bzero( tagArray
, tagArraySize
);
823 void IOSCSIParallelController::setCommandLimit( UInt32 newCommandLimit
)
825 if ( newCommandLimit
== 0 ) controllerInfo
.maxCommandsPerController
= (UInt32
) -1;
827 commandLimit
= commandLimitSave
= controllerInfo
.maxCommandsPerController
;
835 IOWorkLoop
*IOSCSIParallelController::getWorkLoop() const
845 void IOSCSIParallelController::disableCommands( UInt32 disableTimeoutmS
)
847 commandDisable
= true;
849 disableTimer
= ( disableTimeoutmS
!= 0 ) ? (disableTimeoutmS
/ kSCSITimerIntervalmS
+ 1) : 0;
858 void IOSCSIParallelController::disableCommands()
860 UInt32 disableTimeout
;
862 commandDisable
= true;
864 disableTimeout
= kSCSIDisableTimeoutmS
;
866 if ( noDisconnectCmd
!= 0 )
868 disableTimeout
= noDisconnectCmd
->getTimeout();
869 if ( disableTimeout
!= 0 ) disableTimeout
+= kSCSIDisableTimeoutmS
;
872 disableTimer
= ( disableTimeout
!= 0 ) ? (disableTimeout
/ kSCSITimerIntervalmS
+ 1) : 0;
880 void IOSCSIParallelController::disableTimeoutOccurred()
882 busResetState
= kStateIssue
;
891 void IOSCSIParallelController::rescheduleCommand( IOSCSIParallelCommand
*forSCSICmd
)
893 forSCSICmd
->getDevice(kIOSCSIParallelDevice
)->rescheduleCommand( forSCSICmd
);
901 void IOSCSIParallelController::enableCommands()
903 commandDisable
= false;
915 void IOSCSIParallelController::dispatchRequest()
917 dispatchEvent
->interruptOccurred(0, 0, 0);
926 void IOSCSIParallelController::dispatch()
929 IOSCSIParallelDevice
*device
;
930 UInt32 dispatchAction
;
931 UInt32 lunsActive
= 0;
934 if ( !targets
|| checkBusReset() )
939 for ( i
= 0; i
< controllerInfo
.maxTargetsSupported
; i
++ )
941 target
= &targets
[i
];
943 if ( target
->state
== kStateActive
)
947 queue_iterate( &target
->deviceList
, device
, IOSCSIParallelDevice
*, nextDevice
)
949 if ( device
->dispatch( &dispatchAction
) == true )
954 switch ( dispatchAction
)
956 case kDispatchNextLun
:
958 case kDispatchNextTarget
:
964 if ( lunsActive
== 0 )
966 target
->state
= kStateIdle
;
980 IOSCSIParallelCommand
*IOSCSIParallelController::allocCommand(UInt32 clientDataSize
)
982 IOSCSIParallelCommand
*cmd
;
985 size
= controllerInfo
.commandPrivateDataSize
+ round(clientDataSize
, 16);
987 cmd
= new IOSCSIParallelCommand
;
996 cmd
->dataArea
= (void *)IOMallocContiguous( (vm_size_t
)size
, 16, 0 );
997 if ( !cmd
->dataArea
)
1003 bzero( cmd
->dataArea
, size
);
1005 cmd
->dataSize
= size
;
1007 if ( controllerInfo
.commandPrivateDataSize
)
1009 cmd
->commandPrivateData
= cmd
->dataArea
;
1011 if ( clientDataSize
)
1013 cmd
->clientData
= (void *)((UInt8
*)cmd
->dataArea
+ controllerInfo
.commandPrivateDataSize
);
1017 cmd
->controller
= this;
1027 void IOSCSIParallelController::free()
1032 if ( controllerGate
!= 0 )
1034 workLoop
->removeEventSource( controllerGate
);
1035 controllerGate
->release();
1038 if ( timerEvent
!= 0 ) timerEvent
->release();
1040 if ( dispatchEvent
!= 0 ) dispatchEvent
->release();
1042 if ( resetCmd
!= 0 ) resetCmd
->release();
1044 if ( workLoop
!= 0 ) workLoop
->release();
1048 for ( i
=0; i
< controllerInfo
.maxTargetsSupported
; i
++ )
1050 if ( targets
[i
].targetPrivateData
!= 0 )
1052 IOFreeContiguous( targets
[i
].targetPrivateData
, controllerInfo
.targetPrivateDataSize
);
1056 targetsSize
= controllerInfo
.maxTargetsSupported
* sizeof(SCSITarget
);
1057 IOFree( targets
, targetsSize
);
1060 if ( tagArray
!= 0 ) IOFree( tagArray
, tagArraySize
);
1070 void IOSCSIParallelCommand::free()
1074 IOFreeContiguous( dataArea
, dataSize
);