]>
Commit | Line | Data |
---|---|---|
1c79356b A |
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 | * IOSCSIParallelController.cpp | |
24 | * | |
25 | */ | |
26 | ||
27 | #include <IOKit/scsi/IOSCSIParallelInterface.h> | |
28 | #include <IOKit/IOSyncer.h> | |
29 | ||
30 | #undef super | |
31 | #define super IOService | |
32 | ||
33 | OSDefineMetaClass( IOSCSIParallelController, IOService ) | |
34 | OSDefineAbstractStructors( IOSCSIParallelController, IOService ); | |
35 | ||
36 | #define round(x,y) (((int)(x) + (y) - 1) & ~((y)-1)) | |
37 | ||
38 | /* | |
39 | * | |
40 | * | |
41 | */ | |
42 | bool IOSCSIParallelController::start( IOService *forProvider ) | |
43 | { | |
44 | provider = forProvider; | |
45 | ||
46 | if ( provider->open( this ) != true ) | |
47 | { | |
48 | return false; | |
49 | } | |
50 | ||
51 | if ( createWorkLoop() != true ) | |
52 | { | |
53 | return false; | |
54 | } | |
55 | ||
56 | if ( configureController() == false ) | |
57 | { | |
58 | provider->close( this ); | |
59 | return false; | |
60 | } | |
61 | ||
62 | initQueues(); | |
63 | ||
64 | if ( scanSCSIBus() == false ) | |
65 | { | |
66 | provider->close( this ); | |
67 | return false; | |
68 | } | |
69 | ||
70 | return true; | |
71 | } | |
72 | ||
73 | /* | |
74 | * | |
75 | * | |
76 | * | |
77 | */ | |
78 | bool IOSCSIParallelController::scanSCSIBus() | |
79 | { | |
80 | SCSITargetLun targetLun; | |
81 | UInt32 i; | |
82 | ||
83 | targetLun.lun = 0; | |
84 | ||
85 | for ( i=0; i < controllerInfo.maxTargetsSupported; i++ ) | |
86 | { | |
87 | targetLun.target = i; | |
88 | probeTarget( targetLun ); | |
89 | } | |
90 | ||
91 | return true; | |
92 | } | |
93 | ||
94 | /* | |
95 | * | |
96 | * | |
97 | * | |
98 | */ | |
99 | bool IOSCSIParallelController::probeTarget( SCSITargetLun targetLun ) | |
100 | { | |
101 | IOSCSIParallelDevice *device; | |
102 | UInt32 i; | |
103 | ||
104 | if ( targetLun.target == controllerInfo.initiatorId ) | |
105 | { | |
106 | return false; | |
107 | } | |
108 | ||
109 | if ( initTarget( targetLun ) == false ) | |
110 | { | |
111 | releaseTarget( targetLun ); | |
112 | return false; | |
113 | } | |
114 | ||
115 | for ( i=0; i < controllerInfo.maxLunsSupported; i++ ) | |
116 | { | |
117 | targetLun.lun = i; | |
118 | ||
119 | device = createDevice(); | |
120 | if ( device == 0 ) | |
121 | { | |
122 | break; | |
123 | } | |
124 | ||
125 | if ( device->init( this, targetLun ) == false ) | |
126 | { | |
127 | releaseDevice( device ); | |
128 | break; | |
129 | } | |
130 | ||
131 | if ( initDevice( device ) == false ) | |
132 | { | |
133 | releaseDevice( device ); | |
134 | continue; | |
135 | } | |
136 | ||
137 | if ( device->probeTargetLun() != kIOReturnSuccess ) | |
138 | { | |
139 | releaseDevice( device ); | |
140 | if ( i == 0 ) break; | |
141 | } | |
142 | } | |
143 | ||
144 | if ( i == 0 ) | |
145 | { | |
146 | releaseTarget( targetLun ); | |
147 | return false; | |
148 | } | |
149 | ||
150 | queue_iterate( &targets[targetLun.target].deviceList, device, IOSCSIParallelDevice *, nextDevice ) | |
151 | { | |
152 | device->setupTarget(); | |
153 | device->attach( this ); | |
154 | device->registerService(); | |
155 | } | |
156 | ||
157 | return true; | |
158 | } | |
159 | ||
160 | /* | |
161 | * | |
162 | * | |
163 | * | |
164 | */ | |
165 | bool IOSCSIParallelController::initTargetGated( SCSITargetLun *targetLun ) | |
166 | { | |
167 | return initTarget( *targetLun ); | |
168 | } | |
169 | ||
170 | bool IOSCSIParallelController::initTarget( SCSITargetLun targetLun ) | |
171 | { | |
172 | SCSITarget *target; | |
173 | UInt32 number; | |
174 | ||
175 | if ( getWorkLoop()->inGate() == false ) | |
176 | { | |
177 | return controllerGate->runAction( (IOCommandGate::Action)&IOSCSIParallelController::initTargetGated, (void *)&targetLun ); | |
178 | } | |
179 | ||
180 | target = &targets[targetLun.target]; | |
181 | ||
182 | target->clientSem = IORWLockAlloc(); | |
183 | target->targetSem = IORWLockAlloc(); | |
184 | if( (target->targetSem == 0) || (target->clientSem == 0)) | |
185 | { | |
186 | return false; | |
187 | } | |
188 | target->commandLimitSave = target->commandLimit = 1; | |
189 | ||
190 | target->targetParmsCurrent.transferWidth = 1; | |
191 | ||
192 | if ( controllerInfo.targetPrivateDataSize != 0 ) | |
193 | { | |
194 | target->targetPrivateData = IOMallocContiguous( controllerInfo.targetPrivateDataSize, 16, 0 ); | |
195 | if ( target->targetPrivateData == 0 ) | |
196 | { | |
197 | return false; | |
198 | } | |
199 | } | |
200 | ||
201 | if ( controllerInfo.tagAllocationMethod == kTagAllocationPerTarget ) | |
202 | { | |
203 | target->tagArray = (UInt32 *)IOMalloc( tagArraySize ); | |
204 | if ( target->tagArray == 0 ) | |
205 | { | |
206 | return false; | |
207 | } | |
208 | bzero( target->tagArray, tagArraySize ); | |
209 | } | |
210 | ||
211 | number = 0; | |
212 | target->regObjTransferPeriod = OSNumber::withNumber( number, 32 ); | |
213 | if ( target->regObjTransferPeriod == 0 ) | |
214 | { | |
215 | return false; | |
216 | } | |
217 | ||
218 | number = 0; | |
219 | target->regObjTransferOffset = OSNumber::withNumber( number, 32 ); | |
220 | if ( target->regObjTransferOffset == 0 ) | |
221 | { | |
222 | return false; | |
223 | } | |
224 | ||
225 | number = 1; | |
226 | target->regObjTransferWidth = OSNumber::withNumber( number, 32 ); | |
227 | if ( target->regObjTransferWidth == 0 ) | |
228 | { | |
229 | return false; | |
230 | } | |
231 | ||
232 | number = 0; | |
233 | target->regObjTransferOptions = OSNumber::withNumber( number, 32 ); | |
234 | if ( target->regObjTransferOptions == 0 ) | |
235 | { | |
236 | return false; | |
237 | } | |
238 | ||
239 | number = 0; | |
240 | target->regObjCmdQueue = OSNumber::withNumber( number, 32 ); | |
241 | if ( target->regObjCmdQueue == 0 ) | |
242 | { | |
243 | return false; | |
244 | } | |
245 | ||
246 | target->targetAllocated = allocateTarget( targetLun ); | |
247 | ||
248 | return target->targetAllocated; | |
249 | } | |
250 | ||
251 | /* | |
252 | * | |
253 | * | |
254 | * | |
255 | */ | |
256 | void IOSCSIParallelController::releaseTargetGated( SCSITargetLun *targetLun ) | |
257 | { | |
258 | releaseTarget( *targetLun ); | |
259 | } | |
260 | ||
261 | void IOSCSIParallelController::releaseTarget( SCSITargetLun targetLun ) | |
262 | { | |
263 | SCSITarget *target; | |
264 | ||
265 | if ( getWorkLoop()->inGate() == false ) | |
266 | { | |
267 | controllerGate->runAction( (IOCommandGate::Action)&IOSCSIParallelController::releaseTargetGated, (void *)&targetLun ); | |
268 | return; | |
269 | } | |
270 | ||
271 | target = &targets[targetLun.target]; | |
272 | ||
273 | if ( queue_empty( &target->deviceList ) != true ) | |
274 | { | |
275 | IOLog("IOSCSIParallelController()::Target %d deleted with lun(s) active!\n\r", | |
276 | targetLun.target ); | |
277 | } | |
278 | ||
279 | if ( target->targetAllocated == true ) | |
280 | { | |
281 | deallocateTarget( targetLun ); | |
282 | ||
283 | target->targetAllocated = false; | |
284 | } | |
285 | ||
286 | if ( target->tagArray != 0 ) | |
287 | { | |
288 | IOFree( target->tagArray, tagArraySize ); | |
289 | target->tagArray = 0; | |
290 | } | |
291 | ||
292 | if ( target->targetPrivateData != 0 ) | |
293 | { | |
294 | IOFreeContiguous( target->targetPrivateData, controllerInfo.targetPrivateDataSize ); | |
295 | target->targetPrivateData = 0; | |
296 | } | |
297 | ||
298 | if ( target->clientSem != 0 ) | |
299 | { | |
300 | IORWLockFree( target->clientSem ); | |
301 | } | |
302 | if ( target->targetSem != 0 ) | |
303 | { | |
304 | IORWLockFree( target->targetSem ); | |
305 | } | |
306 | ||
307 | if ( target->regObjTransferPeriod != 0 ) | |
308 | { | |
309 | target->regObjTransferPeriod->release(); | |
310 | target->regObjTransferPeriod = 0; | |
311 | } | |
312 | if ( target->regObjTransferOffset != 0 ) | |
313 | { | |
314 | target->regObjTransferOffset->release(); | |
315 | target->regObjTransferOffset = 0; | |
316 | } | |
317 | if ( target->regObjTransferWidth != 0 ) | |
318 | { | |
319 | target->regObjTransferWidth->release(); | |
320 | target->regObjTransferWidth = 0; | |
321 | } | |
322 | if ( target->regObjCmdQueue != 0 ) | |
323 | { | |
324 | target->regObjCmdQueue->release(); | |
325 | target->regObjCmdQueue = 0; | |
326 | } | |
327 | ||
328 | } | |
329 | ||
330 | /* | |
331 | * | |
332 | * | |
333 | * | |
334 | */ | |
335 | bool IOSCSIParallelController::initDeviceGated( IOSCSIParallelDevice *device ) | |
336 | { | |
337 | return initDevice( device ); | |
338 | } | |
339 | ||
340 | bool IOSCSIParallelController::initDevice( IOSCSIParallelDevice *device ) | |
341 | { | |
342 | if ( getWorkLoop()->inGate() == false ) | |
343 | { | |
344 | return controllerGate->runAction( (IOCommandGate::Action)&IOSCSIParallelController::initDeviceGated, (void *)device ); | |
345 | } | |
346 | ||
347 | addDevice( device ); | |
348 | device->lunAllocated = allocateLun( device->targetLun ); | |
349 | ||
350 | return device->lunAllocated; | |
351 | } | |
352 | ||
353 | /* | |
354 | * | |
355 | * | |
356 | * | |
357 | */ | |
358 | void IOSCSIParallelController::releaseDeviceGated( IOSCSIParallelDevice *device ) | |
359 | { | |
360 | releaseDevice( device ); | |
361 | return; | |
362 | } | |
363 | ||
364 | void IOSCSIParallelController::releaseDevice( IOSCSIParallelDevice *device ) | |
365 | { | |
366 | if ( getWorkLoop()->inGate() == false ) | |
367 | { | |
368 | controllerGate->runAction( (IOCommandGate::Action)&IOSCSIParallelController::releaseDeviceGated, (void *)device ); | |
369 | return; | |
370 | } | |
371 | ||
372 | deleteDevice( device ); | |
373 | if ( device->lunAllocated == true ) | |
374 | { | |
375 | deallocateLun( device->targetLun ); | |
376 | } | |
377 | ||
378 | device->release(); | |
379 | } | |
380 | ||
381 | ||
382 | /* | |
383 | * | |
384 | * | |
385 | * | |
386 | */ | |
387 | void IOSCSIParallelController::addDevice( IOSCSIParallelDevice *forDevice ) | |
388 | { | |
389 | UInt32 targetID; | |
390 | ||
391 | targetID = forDevice->targetLun.target; | |
392 | ||
393 | forDevice->target = &targets[targetID]; | |
394 | queue_enter( &targets[targetID].deviceList, forDevice, IOSCSIParallelDevice *, nextDevice ); | |
395 | } | |
396 | ||
397 | /* | |
398 | * | |
399 | * | |
400 | * | |
401 | */ | |
402 | void IOSCSIParallelController::deleteDevice( IOSCSIParallelDevice *forDevice ) | |
403 | { | |
404 | queue_head_t *deviceList; | |
405 | IOSCSIParallelDevice *device; | |
406 | UInt32 targetID; | |
407 | ||
408 | targetID = forDevice->targetLun.target; | |
409 | ||
410 | deviceList = &targets[targetID].deviceList; | |
411 | ||
412 | queue_iterate( deviceList, device, IOSCSIParallelDevice *, nextDevice ) | |
413 | { | |
414 | if ( device == forDevice ) | |
415 | { | |
416 | queue_remove( &targets[targetID].deviceList, device, IOSCSIParallelDevice *, nextDevice ); | |
417 | break; | |
418 | } | |
419 | } | |
420 | } | |
421 | ||
422 | /* | |
423 | * | |
424 | * | |
425 | * | |
426 | */ | |
427 | bool IOSCSIParallelController::allocateTarget( SCSITargetLun targetLun ) | |
428 | { | |
429 | return true; | |
430 | } | |
431 | ||
432 | /* | |
433 | * | |
434 | * | |
435 | * | |
436 | */ | |
437 | void IOSCSIParallelController::deallocateTarget( SCSITargetLun targetLun ) | |
438 | { | |
439 | } | |
440 | ||
441 | /* | |
442 | * | |
443 | * | |
444 | * | |
445 | */ | |
446 | bool IOSCSIParallelController::allocateLun( SCSITargetLun targetLun ) | |
447 | { | |
448 | return true; | |
449 | } | |
450 | ||
451 | /* | |
452 | * | |
453 | * | |
454 | * | |
455 | */ | |
456 | void IOSCSIParallelController::deallocateLun( SCSITargetLun targetLun ) | |
457 | { | |
458 | } | |
459 | ||
460 | ||
461 | /* | |
462 | * | |
463 | * | |
464 | * | |
465 | */ | |
466 | void *IOSCSIParallelController::getTargetData( SCSITargetLun targetLun ) | |
467 | { | |
468 | return targets[targetLun.target].targetPrivateData; | |
469 | } | |
470 | ||
471 | /* | |
472 | * | |
473 | * | |
474 | * | |
475 | */ | |
476 | void *IOSCSIParallelController::getLunData( SCSITargetLun targetLun ) | |
477 | { | |
478 | queue_head_t *deviceList; | |
479 | IOSCSIParallelDevice *device; | |
480 | ||
481 | deviceList = &targets[targetLun.target].deviceList; | |
482 | ||
483 | queue_iterate( deviceList, device, IOSCSIParallelDevice *, nextDevice ) | |
484 | { | |
485 | if ( device->targetLun.lun == targetLun.lun ) | |
486 | { | |
487 | return device->devicePrivateData; | |
488 | } | |
489 | } | |
490 | return 0; | |
491 | } | |
492 | ||
493 | ||
494 | ||
495 | /* | |
496 | * | |
497 | * | |
498 | * | |
499 | */ | |
500 | IOSCSIParallelDevice *IOSCSIParallelController::createDevice() | |
501 | { | |
502 | return new IOSCSIParallelDevice; | |
503 | } | |
504 | ||
505 | ||
506 | /* | |
507 | * | |
508 | * | |
509 | * | |
510 | */ | |
511 | void IOSCSIParallelController::initQueues() | |
512 | { | |
513 | UInt32 i; | |
514 | ||
515 | for ( i=0; i < controllerInfo.maxTargetsSupported; i++ ) | |
516 | { | |
517 | queue_init( &targets[i].deviceList ); | |
518 | } | |
519 | ||
520 | resetCmd = allocCommand( 0 ); | |
521 | resetCmd->cmdType = kSCSICommandBusReset; | |
522 | ||
523 | timer( timerEvent ); | |
524 | } | |
525 | ||
526 | /* | |
527 | * | |
528 | * | |
529 | * | |
530 | */ | |
531 | void IOSCSIParallelController::reset() | |
532 | { | |
533 | IOSCSIParallelDevice *device; | |
534 | UInt32 i; | |
535 | ||
536 | if ( busResetState != kStateIssue ) | |
537 | { | |
538 | return; | |
539 | } | |
540 | ||
541 | busResetState = kStateActive; | |
542 | ||
543 | for (i=0; i < controllerInfo.maxTargetsSupported; i++ ) | |
544 | { | |
545 | queue_iterate( &targets[i].deviceList, device, IOSCSIParallelDevice *, nextDevice ) | |
546 | { | |
547 | if ( device->client != 0 ) | |
548 | { | |
549 | device->client->message( kSCSIClientMsgBusReset, device ); | |
550 | } | |
551 | } | |
552 | } | |
553 | ||
554 | resetCommand( resetCmd ); | |
555 | } | |
556 | ||
557 | /* | |
558 | * | |
559 | * | |
560 | * | |
561 | */ | |
562 | bool IOSCSIParallelController::checkBusReset() | |
563 | { | |
564 | if ( busResetState == kStateIdle ) | |
565 | { | |
566 | return false; | |
567 | } | |
568 | if ( busResetState == kStateIssue ) | |
569 | { | |
570 | reset(); | |
571 | } | |
572 | return true; | |
573 | } | |
574 | ||
575 | ||
576 | /* | |
577 | * | |
578 | * | |
579 | * | |
580 | */ | |
581 | void IOSCSIParallelController::resetOccurred() | |
582 | { | |
583 | UInt32 i; | |
584 | IOSCSIParallelDevice *device; | |
585 | SCSITarget *target; | |
586 | SCSIClientMessage clientMsg; | |
587 | ||
588 | for (i=0; i < controllerInfo.maxTargetsSupported; i++ ) | |
589 | { | |
590 | target = &targets[i]; | |
591 | ||
592 | target->commandLimit = target->commandLimitSave; | |
593 | target->reqSenseCount = 0; | |
594 | target->reqSenseState = kStateIdle; | |
595 | target->negotiateState = kStateIssue; | |
596 | ||
597 | target->targetParmsCurrent.transferPeriodpS = 0; | |
598 | target->targetParmsCurrent.transferOffset = 0; | |
599 | target->targetParmsCurrent.transferWidth = 1; | |
600 | ||
601 | noDisconnectCmd = 0; | |
602 | ||
603 | clientMsg = ( busResetState != kStateActive ) ? kSCSIClientMsgBusReset : kSCSIClientMsgNone; | |
604 | ||
605 | queue_iterate( &target->deviceList, device, IOSCSIParallelDevice *, nextDevice ) | |
606 | { | |
607 | device->resetOccurred( clientMsg ); | |
608 | } | |
609 | } | |
610 | ||
611 | resetTimer = (kSCSIResetIntervalmS / kSCSITimerIntervalmS + 1); | |
612 | } | |
613 | ||
614 | ||
615 | /* | |
616 | * | |
617 | * | |
618 | */ | |
619 | void IOSCSIParallelController::timer( IOTimerEventSource * /* timer */ ) | |
620 | { | |
621 | UInt32 i; | |
622 | IOSCSIParallelDevice *device; | |
623 | ||
624 | ||
625 | if ( disableTimer ) | |
626 | { | |
627 | if ( !--disableTimer ) | |
628 | { | |
629 | disableTimeoutOccurred(); | |
630 | } | |
631 | } | |
632 | ||
633 | if ( resetTimer ) | |
634 | { | |
635 | if ( !--resetTimer ) | |
636 | { | |
637 | for (i=0; i < controllerInfo.maxTargetsSupported; i++ ) | |
638 | { | |
639 | queue_iterate( &targets[i].deviceList, device, IOSCSIParallelDevice *, nextDevice ) | |
640 | { | |
641 | device->resetComplete(); | |
642 | } | |
643 | } | |
644 | ||
645 | } | |
646 | } | |
647 | else | |
648 | { | |
649 | for (i=0; i < controllerInfo.maxTargetsSupported; i++ ) | |
650 | { | |
651 | queue_iterate( &targets[i].deviceList, device, IOSCSIParallelDevice *, nextDevice ) | |
652 | { | |
653 | device->timer(); | |
654 | } | |
655 | } | |
656 | } | |
657 | ||
658 | timerEvent->setTimeoutMS(kSCSITimerIntervalmS); | |
659 | } | |
660 | ||
661 | ||
662 | /* | |
663 | * | |
664 | * | |
665 | * | |
666 | */ | |
667 | void IOSCSIParallelController::completeCommand( IOSCSIParallelCommand *scsiCmd ) | |
668 | { | |
669 | switch ( scsiCmd->cmdType ) | |
670 | { | |
671 | case kSCSICommandBusReset: | |
672 | resetOccurred(); | |
673 | busResetState = kStateIdle; | |
674 | break; | |
675 | default: | |
676 | ; | |
677 | } | |
678 | } | |
679 | ||
680 | ||
681 | /* | |
682 | * | |
683 | * | |
684 | * | |
685 | */ | |
686 | bool IOSCSIParallelController::createWorkLoop() | |
687 | { | |
688 | workLoop = getWorkLoop(); | |
689 | if ( workLoop == 0 ) | |
690 | { | |
691 | workLoop = IOWorkLoop::workLoop(); | |
692 | if ( workLoop == 0 ) | |
693 | { | |
694 | return false; | |
695 | } | |
696 | } | |
697 | ||
698 | timerEvent = IOTimerEventSource::timerEventSource( this, (IOTimerEventSource::Action) &IOSCSIParallelController::timer ); | |
699 | if ( timerEvent == 0 ) | |
700 | { | |
701 | return false; | |
702 | } | |
703 | ||
704 | if ( workLoop->addEventSource( timerEvent ) != kIOReturnSuccess ) | |
705 | { | |
706 | return false; | |
707 | } | |
708 | ||
709 | ||
710 | dispatchEvent = IOInterruptEventSource::interruptEventSource( this, | |
711 | (IOInterruptEventAction) &IOSCSIParallelController::dispatch, | |
712 | 0 ); | |
713 | if ( dispatchEvent == 0 ) | |
714 | { | |
715 | return false; | |
716 | } | |
717 | ||
718 | if ( workLoop->addEventSource( dispatchEvent ) != kIOReturnSuccess ) | |
719 | { | |
720 | return false; | |
721 | } | |
722 | ||
723 | controllerGate = IOCommandGate::commandGate( this, (IOCommandGate::Action) 0 ); | |
724 | if ( controllerGate == 0 ) | |
725 | { | |
726 | return false; | |
727 | } | |
728 | ||
729 | if ( workLoop->addEventSource( controllerGate ) != kIOReturnSuccess ) | |
730 | { | |
731 | return false; | |
732 | } | |
733 | ||
734 | return true; | |
735 | } | |
736 | ||
737 | /* | |
738 | * | |
739 | * | |
740 | * | |
741 | */ | |
742 | IOSCSIParallelCommand *IOSCSIParallelController::findCommandWithNexus( SCSITargetLun targetLun, UInt32 tagValue = (UInt32)-1 ) | |
743 | { | |
744 | IOSCSIParallelDevice *device; | |
745 | ||
746 | device = findDeviceWithTargetLun( targetLun ); | |
747 | if ( device == 0 ) | |
748 | { | |
749 | return 0; | |
750 | } | |
751 | ||
752 | return device->findCommandWithNexus( tagValue ); | |
753 | } | |
754 | ||
755 | ||
756 | /* | |
757 | * | |
758 | * | |
759 | * | |
760 | */ | |
761 | IOSCSIParallelDevice *IOSCSIParallelController::findDeviceWithTargetLun( SCSITargetLun targetLun ) | |
762 | { | |
763 | IOSCSIParallelDevice *device; | |
764 | ||
765 | if ( targetLun.target > controllerInfo.maxTargetsSupported || targetLun.lun > controllerInfo.maxLunsSupported ) | |
766 | { | |
767 | return 0; | |
768 | } | |
769 | ||
770 | queue_iterate( &targets[targetLun.target].deviceList, device, IOSCSIParallelDevice *, nextDevice ) | |
771 | { | |
772 | if ( device->targetLun.lun == targetLun.lun ) | |
773 | { | |
774 | return device; | |
775 | } | |
776 | } | |
777 | return 0; | |
778 | } | |
779 | ||
780 | ||
781 | /* | |
782 | * | |
783 | * | |
784 | * | |
785 | */ | |
786 | bool IOSCSIParallelController::configureController() | |
787 | { | |
788 | UInt32 targetsSize; | |
789 | ||
790 | if ( configure( provider, &controllerInfo ) == false ) | |
791 | { | |
792 | return false; | |
793 | } | |
794 | ||
795 | controllerInfo.commandPrivateDataSize = round( controllerInfo.commandPrivateDataSize, 16 ); | |
796 | ||
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; | |
800 | ||
801 | targetsSize = controllerInfo.maxTargetsSupported * sizeof(SCSITarget); | |
802 | targets = (SCSITarget *)IOMalloc( targetsSize ); | |
803 | bzero( targets, targetsSize ); | |
804 | ||
805 | commandLimit = commandLimitSave = controllerInfo.maxCommandsPerController; | |
806 | ||
807 | tagArraySize = (controllerInfo.maxTags / 32 + ((controllerInfo.maxTags % 32) ? 1 : 0)) * sizeof(UInt32); | |
808 | ||
809 | if ( controllerInfo.tagAllocationMethod == kTagAllocationPerController ) | |
810 | { | |
811 | tagArray = (UInt32 *)IOMalloc( tagArraySize ); | |
812 | bzero( tagArray, tagArraySize ); | |
813 | } | |
814 | ||
815 | return true; | |
816 | } | |
817 | ||
818 | /* | |
819 | * | |
820 | * | |
821 | * | |
822 | */ | |
823 | void IOSCSIParallelController::setCommandLimit( UInt32 newCommandLimit ) | |
824 | { | |
825 | if ( newCommandLimit == 0 ) controllerInfo.maxCommandsPerController = (UInt32) -1; | |
826 | ||
827 | commandLimit = commandLimitSave = controllerInfo.maxCommandsPerController; | |
828 | } | |
829 | ||
830 | /* | |
831 | * | |
832 | * | |
833 | * | |
834 | */ | |
835 | IOWorkLoop *IOSCSIParallelController::getWorkLoop() const | |
836 | { | |
837 | return workLoop; | |
838 | } | |
839 | ||
840 | /* | |
841 | * | |
842 | * | |
843 | * | |
844 | */ | |
845 | void IOSCSIParallelController::disableCommands( UInt32 disableTimeoutmS ) | |
846 | { | |
847 | commandDisable = true; | |
848 | ||
849 | disableTimer = ( disableTimeoutmS != 0 ) ? (disableTimeoutmS / kSCSITimerIntervalmS + 1) : 0; | |
850 | } | |
851 | ||
852 | ||
853 | /* | |
854 | * | |
855 | * | |
856 | * | |
857 | */ | |
858 | void IOSCSIParallelController::disableCommands() | |
859 | { | |
860 | UInt32 disableTimeout; | |
861 | ||
862 | commandDisable = true; | |
863 | ||
864 | disableTimeout = kSCSIDisableTimeoutmS; | |
865 | ||
866 | if ( noDisconnectCmd != 0 ) | |
867 | { | |
868 | disableTimeout = noDisconnectCmd->getTimeout(); | |
869 | if ( disableTimeout != 0 ) disableTimeout += kSCSIDisableTimeoutmS; | |
870 | } | |
871 | ||
872 | disableTimer = ( disableTimeout != 0 ) ? (disableTimeout / kSCSITimerIntervalmS + 1) : 0; | |
873 | } | |
874 | ||
875 | /* | |
876 | * | |
877 | * | |
878 | * | |
879 | */ | |
880 | void IOSCSIParallelController::disableTimeoutOccurred() | |
881 | { | |
882 | busResetState = kStateIssue; | |
883 | dispatchRequest(); | |
884 | } | |
885 | ||
886 | /* | |
887 | * | |
888 | * | |
889 | * | |
890 | */ | |
891 | void IOSCSIParallelController::rescheduleCommand( IOSCSIParallelCommand *forSCSICmd ) | |
892 | { | |
893 | forSCSICmd->getDevice(kIOSCSIParallelDevice)->rescheduleCommand( forSCSICmd ); | |
894 | } | |
895 | ||
896 | /* | |
897 | * | |
898 | * | |
899 | * | |
900 | */ | |
901 | void IOSCSIParallelController::enableCommands() | |
902 | { | |
903 | commandDisable = false; | |
904 | ||
905 | disableTimer = 0; | |
906 | ||
907 | dispatchRequest(); | |
908 | } | |
909 | ||
910 | /* | |
911 | * | |
912 | * | |
913 | * | |
914 | */ | |
915 | void IOSCSIParallelController::dispatchRequest() | |
916 | { | |
917 | dispatchEvent->interruptOccurred(0, 0, 0); | |
918 | } | |
919 | ||
920 | ||
921 | /* | |
922 | * | |
923 | * | |
924 | * | |
925 | */ | |
926 | void IOSCSIParallelController::dispatch() | |
927 | { | |
928 | SCSITarget *target; | |
929 | IOSCSIParallelDevice *device; | |
930 | UInt32 dispatchAction; | |
931 | UInt32 lunsActive = 0; | |
932 | UInt32 i; | |
933 | ||
934 | if ( !targets || checkBusReset() ) | |
935 | { | |
936 | goto dispatch_Exit; | |
937 | } | |
938 | ||
939 | for ( i = 0; i < controllerInfo.maxTargetsSupported; i++ ) | |
940 | { | |
941 | target = &targets[i]; | |
942 | ||
943 | if ( target->state == kStateActive ) | |
944 | { | |
945 | lunsActive = 0; | |
946 | ||
947 | queue_iterate( &target->deviceList, device, IOSCSIParallelDevice *, nextDevice ) | |
948 | { | |
949 | if ( device->dispatch( &dispatchAction ) == true ) | |
950 | { | |
951 | lunsActive++; | |
952 | } | |
953 | ||
954 | switch ( dispatchAction ) | |
955 | { | |
956 | case kDispatchNextLun: | |
957 | ; | |
958 | case kDispatchNextTarget: | |
959 | break; | |
960 | case kDispatchStop: | |
961 | goto dispatch_Exit; | |
962 | } | |
963 | } | |
964 | if ( lunsActive == 0 ) | |
965 | { | |
966 | target->state = kStateIdle; | |
967 | } | |
968 | } | |
969 | } | |
970 | ||
971 | dispatch_Exit: | |
972 | ; | |
973 | } | |
974 | ||
975 | /* | |
976 | * | |
977 | * | |
978 | * | |
979 | */ | |
980 | IOSCSIParallelCommand *IOSCSIParallelController::allocCommand(UInt32 clientDataSize ) | |
981 | { | |
982 | IOSCSIParallelCommand *cmd; | |
983 | UInt32 size; | |
984 | ||
985 | size = controllerInfo.commandPrivateDataSize + round(clientDataSize, 16); | |
986 | ||
987 | cmd = new IOSCSIParallelCommand; | |
988 | if ( !cmd ) | |
989 | { | |
990 | return 0; | |
991 | } | |
992 | cmd->init(); | |
993 | ||
994 | if ( size ) | |
995 | { | |
996 | cmd->dataArea = (void *)IOMallocContiguous( (vm_size_t)size, 16, 0 ); | |
997 | if ( !cmd->dataArea ) | |
998 | { | |
999 | cmd->release(); | |
1000 | return 0; | |
1001 | } | |
1002 | ||
1003 | bzero( cmd->dataArea, size ); | |
1004 | ||
1005 | cmd->dataSize = size; | |
1006 | ||
1007 | if ( controllerInfo.commandPrivateDataSize ) | |
1008 | { | |
1009 | cmd->commandPrivateData = cmd->dataArea; | |
1010 | } | |
1011 | if ( clientDataSize ) | |
1012 | { | |
1013 | cmd->clientData = (void *)((UInt8 *)cmd->dataArea + controllerInfo.commandPrivateDataSize); | |
1014 | } | |
1015 | } | |
1016 | ||
1017 | cmd->controller = this; | |
1018 | ||
1019 | return cmd; | |
1020 | } | |
1021 | ||
1022 | /* | |
1023 | * | |
1024 | * | |
1025 | * | |
1026 | */ | |
1027 | void IOSCSIParallelController::free() | |
1028 | { | |
1029 | UInt32 targetsSize; | |
1030 | UInt32 i; | |
1031 | ||
1032 | if ( controllerGate != 0 ) | |
1033 | { | |
1034 | workLoop->removeEventSource( controllerGate ); | |
1035 | controllerGate->release(); | |
1036 | } | |
1037 | ||
1038 | if ( timerEvent != 0 ) timerEvent->release(); | |
1039 | ||
1040 | if ( dispatchEvent != 0 ) dispatchEvent->release(); | |
1041 | ||
1042 | if ( resetCmd != 0 ) resetCmd->release(); | |
1043 | ||
1044 | if ( workLoop != 0 ) workLoop->release(); | |
1045 | ||
1046 | if ( targets != 0 ) | |
1047 | { | |
1048 | for ( i=0; i < controllerInfo.maxTargetsSupported; i++ ) | |
1049 | { | |
1050 | if ( targets[i].targetPrivateData != 0 ) | |
1051 | { | |
1052 | IOFreeContiguous( targets[i].targetPrivateData, controllerInfo.targetPrivateDataSize ); | |
1053 | } | |
1054 | } | |
1055 | ||
1056 | targetsSize = controllerInfo.maxTargetsSupported * sizeof(SCSITarget); | |
1057 | IOFree( targets, targetsSize ); | |
1058 | } | |
1059 | ||
1060 | if ( tagArray != 0 ) IOFree( tagArray, tagArraySize ); | |
1061 | ||
1062 | super::free(); | |
1063 | } | |
1064 | ||
1065 | /* | |
1066 | * | |
1067 | * | |
1068 | * | |
1069 | */ | |
1070 | void IOSCSIParallelCommand::free() | |
1071 | { | |
1072 | if ( dataArea ) | |
1073 | { | |
1074 | IOFreeContiguous( dataArea, dataSize ); | |
1075 | } | |
1076 | ||
1077 | OSObject::free(); | |
1078 | } | |
1079 |