]> git.saurik.com Git - apple/xnu.git/blob - iokit/Families/IOSCSIParallel/IOSCSIParallelDevice.cpp
dc8c2593ca3ab112626026a79f1699acef115973
[apple/xnu.git] / iokit / Families / IOSCSIParallel / IOSCSIParallelDevice.cpp
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 * IOSCSIParallelDevice.cpp
24 *
25 */
26
27 #include <IOKit/IOSyncer.h>
28 #include <IOKit/scsi/IOSCSIParallelInterface.h>
29
30 #include <IOKit/IOKitKeys.h>
31 #include <IOKit/system.h>
32
33 #undef super
34 #define super IOSCSIDevice
35
36 #ifndef MIN
37 #define MIN(a,b) ((a <= b) ? a : b)
38 #endif
39
40 OSDefineMetaClassAndAbstractStructors( IOCDBDevice, IOService )
41 OSDefineMetaClassAndAbstractStructors( IOSCSIDevice, IOCDBDevice )
42 OSDefineMetaClassAndStructors( IOSCSIParallelDevice, IOSCSIDevice )
43
44 /*
45 *
46 *
47 *
48 */
49 bool IOSCSIParallelDevice::init( IOSCSIParallelController *forController, SCSITargetLun forTargetLun )
50 {
51 SCSICDBInfo scsiCDB;
52
53 controller = forController;
54 targetLun = forTargetLun;
55
56 target = &controller->targets[targetLun.target];
57
58 queue_init( &deviceList );
59 queue_init( &bypassList );
60 queue_init( &activeList );
61 queue_init( &abortList );
62 queue_init( &cancelList );
63
64 clientSem = IORWLockAlloc();
65 if ( clientSem == 0 )
66 {
67 return false;
68 }
69
70 if ( super::init() == false )
71 {
72 return false;
73 }
74
75 if ( controller->controllerInfo.lunPrivateDataSize != 0 )
76 {
77 devicePrivateData = IOMallocContiguous( controller->controllerInfo.lunPrivateDataSize, 16, 0 );
78 if ( devicePrivateData == 0 )
79 {
80 return false;
81 }
82 }
83
84 bzero( &scsiCDB, sizeof(scsiCDB) );
85
86 abortCmd = allocCommand(kIOSCSIParallelDevice, 0);
87 if ( abortCmd == 0 )
88 {
89 return false;
90 }
91 abortCmd->setTimeout( kSCSIAbortTimeoutmS );
92
93 cancelCmd = allocCommand(kIOSCSIParallelDevice, 0);
94 if ( cancelCmd == 0 )
95 {
96 return false;
97 }
98 cancelCmd->setTimeout( 0 );
99 cancelCmd->cmdType = kSCSICommandCancel;
100
101 reqSenseCmd = allocCommand(kIOSCSIParallelDevice, 0);
102 if ( reqSenseCmd == 0 )
103 {
104 return false;
105 }
106 scsiCDB.cdbLength = 6;
107 scsiCDB.cdb[0] = kSCSICmdRequestSense;
108 scsiCDB.cdb[1] = targetLun.lun << 4;
109 scsiCDB.cdbTag = (UInt32) -1;
110
111 reqSenseCmd->setTimeout( kSCSIReqSenseTimeoutmS );
112 reqSenseCmd->cmdType = kSCSICommandReqSense;
113 reqSenseCmd->setCDB( &scsiCDB );
114
115 if ( controller->controllerInfo.tagAllocationMethod == kTagAllocationPerLun )
116 {
117 tagArray = (UInt32 *)IOMalloc( controller->tagArraySize );
118 bzero( tagArray, controller->tagArraySize );
119 }
120
121 deviceGate = IOCommandGate::commandGate( this, (IOCommandGate::Action) &IOSCSIParallelDevice::receiveCommand );
122 if ( deviceGate == 0 )
123 {
124 return false;
125 }
126
127 if ( controller->workLoop->addEventSource( deviceGate ) != kIOReturnSuccess )
128 {
129 return false;
130 }
131
132 commandLimitSave = commandLimit = controller->controllerInfo.maxCommandsPerLun;
133
134 idleNotifyActive = false;
135
136 normalQHeld = false;
137 bypassQHeld = false;
138
139 return true;
140 }
141
142 /*
143 *
144 *
145 *
146 */
147 IOReturn IOSCSIParallelDevice::probeTargetLun()
148 {
149 SCSICDBInfo cdb;
150 SCSIResults result;
151 IOReturn rc;
152 IOMemoryDescriptor *desc = 0;
153 SCSIInquiry *inqData = 0;
154 UInt32 size = 0;
155 OSDictionary *propTable;
156
157 probeCmd = allocCommand(kIOSCSIParallelDevice, 0);
158
159 if ( probeCmd == 0 )
160 {
161 rc = kIOReturnNoMemory;
162 goto probeError;
163 }
164
165 size = sizeof(SCSIInquiry);
166
167 if ( !(inqData = (SCSIInquiry *)IOMalloc(size)) )
168 {
169 rc = kIOReturnNoMemory;
170 goto probeError;
171 }
172
173 desc = IOMemoryDescriptor::withAddress( (void *)inqData, size, kIODirectionIn );
174 if ( desc == 0 )
175 {
176 rc = kIOReturnNoMemory;
177 goto probeError;
178 }
179
180 if ( open( this ) == false )
181 {
182 rc = kIOReturnError;
183 goto probeError;
184 }
185
186 bzero( (void *)&cdb, sizeof(cdb) );
187
188 cdb.cdbLength = 6;
189 cdb.cdb[0] = kSCSICmdInquiry;
190 cdb.cdb[4] = size;
191 probeCmd->setCDB( &cdb );
192
193 probeCmd->setPointers( desc, size, false );
194
195 probeCmd->setTimeout( kSCSIProbeTimeoutmS );
196 probeCmd->setCallback();
197
198 probeCmd->execute();
199
200 rc = probeCmd->getResults( &result );
201
202 switch ( rc )
203 {
204 case kIOReturnSuccess:
205 break;
206
207 case kIOReturnUnderrun:
208 rc = kIOReturnSuccess;
209 break;
210
211 default:
212 goto probeError;
213 }
214
215 if ( result.bytesTransferred <= (UInt32)(&inqData->flags - &inqData->devType) )
216 {
217 rc = kIOReturnDeviceError;
218 goto probeError;
219 }
220
221 switch ( inqData->devType & kSCSIDevTypeQualifierMask )
222 {
223 case kSCSIDevTypeQualifierConnected:
224 case kSCSIDevTypeQualifierNotConnected:
225 break;
226 case kSCSIDevTypeQualifierReserved:
227 case kSCSIDevTypeQualifierMissing:
228 rc = kIOReturnNotAttached;
229 break;
230 default:
231 break;
232 }
233
234 if ( rc != kIOReturnSuccess )
235 {
236 goto probeError;
237 }
238
239 inquiryData = inqData;
240 inquiryDataSize = result.bytesTransferred;
241
242 propTable = createProperties();
243 if ( !propTable ) goto probeError;
244
245 setPropertyTable( propTable );
246
247 propTable->release();
248
249 probeError: ;
250
251 if ( desc )
252 {
253 desc->release();
254 }
255
256 if ( inqData )
257 {
258 if ( rc != kIOReturnSuccess )
259 {
260 IOFree( inqData, size );
261 }
262 }
263
264 return rc;
265 }
266
267 /*
268 *
269 *
270 *
271 */
272 void IOSCSIParallelDevice::setupTarget()
273 {
274 SCSITargetParms targetParms;
275 UInt32 transferWidth;
276
277 if ( targetLun.lun != 0 )
278 {
279 close( this );
280 return;
281 }
282
283 getTargetParms( &targetParms );
284
285 if ( ((inquiryData->flags & kSCSIDevCapCmdQue) != 0) && (checkCmdQueEnabled() == true) )
286 {
287 targetParms.enableTagQueuing = true;
288 }
289
290 if ( inquiryData->flags & kSCSIDevCapSync )
291 {
292 targetParms.transferPeriodpS = controller->controllerInfo.minTransferPeriodpS;
293 targetParms.transferOffset = controller->controllerInfo.maxTransferOffset;
294 }
295
296 if ( inquiryData->flags & kSCSIDevCapWBus32 )
297 {
298 transferWidth = 4;
299 }
300 else if ( inquiryData->flags & kSCSIDevCapWBus16 )
301 {
302 transferWidth = 2;
303 }
304 else
305 {
306 transferWidth = 1;
307 }
308
309 targetParms.transferWidth = MIN( transferWidth, controller->controllerInfo.maxTransferWidth );
310
311 if ( ((inquiryData->version & 0x07) >= kSCSIInqVersionSCSI3)
312 && (inquiryDataSize > (UInt32)(&inquiryData->scsi3Options - &inquiryData->devType)) )
313 {
314 if ( inquiryData->scsi3Options & kSCSI3InqOptionClockDT )
315 {
316 targetParms.transferOptions |= kSCSITransferOptionClockDT;
317
318 /* If it's a SCSI-3 target that handles DT clocking,
319 * assume the HBA can try using the PPR message.
320 */
321 targetParms.transferOptions |= kSCSITransferOptionPPR;
322
323 if ( inquiryData->scsi3Options & kSCSI3InqOptionIUS )
324 {
325 targetParms.transferOptions |= kSCSITransferOptionIUS;
326
327 if ( inquiryData->scsi3Options & kSCSI3InqOptionQAS )
328 {
329 targetParms.transferOptions |= kSCSITransferOptionQAS;
330 }
331 }
332 }
333 }
334
335 setTargetParms( &targetParms );
336
337 close( this );
338 }
339
340 /*
341 *
342 *
343 *
344 */
345 bool IOSCSIParallelDevice::checkCmdQueEnabled()
346 {
347 SCSICDBInfo scsiCDB;
348 SCSIResults scsiResult;
349 IOMemoryDescriptor *desc;
350 UInt32 size;
351 UInt8 controlModePage[32];
352 IOReturn cmdRc;
353 bool rc = false;
354
355 bzero( (void *)&scsiCDB, sizeof(scsiCDB) );
356
357 size = sizeof(controlModePage);
358
359 scsiCDB.cdbLength = 6;
360 scsiCDB.cdb[0] = kSCSICmdModeSense6;
361 scsiCDB.cdb[1] = 0x08;
362 scsiCDB.cdb[2] = 0x0a; // Control Mode Page
363 scsiCDB.cdb[4] = size;
364
365 probeCmd->setCDB( &scsiCDB );
366
367 desc = IOMemoryDescriptor::withAddress( (void *)controlModePage, size, kIODirectionIn );
368 if ( desc == 0 )
369 {
370 return rc;
371 }
372
373 probeCmd->setPointers( desc, size, false );
374
375 probeCmd->setTimeout( kSCSIProbeTimeoutmS );
376 probeCmd->setCallback();
377
378 probeCmd->execute();
379
380 cmdRc = probeCmd->getResults( &scsiResult );
381
382 if ( (cmdRc == kIOReturnUnderrun) && (scsiResult.bytesTransferred > 7) )
383 {
384 cmdRc = kIOReturnSuccess;
385 }
386
387 /* Check DQue bit on ControlMode Page (0x0A) */
388 if ( (cmdRc == kIOReturnSuccess) && ((controlModePage[7] & 0x01) == 0) )
389 {
390 rc = true;
391 }
392
393 desc->release();
394
395 return rc;
396 }
397
398 /*
399 *
400 *
401 *
402 */
403 void IOSCSIParallelDevice::getInquiryData( void *clientBuf, UInt32 clientBufSize, UInt32 *clientDataSize )
404 {
405 UInt32 len;
406
407 bzero( clientBuf, clientBufSize );
408
409 len = MIN( clientBufSize, inquiryDataSize );
410
411 bcopy( inquiryData, clientBuf, len );
412
413 *clientDataSize = len;
414 }
415
416 /*
417 *
418 *
419 *
420 */
421 void IOSCSIParallelDevice::abort()
422 {
423 submitCommand( kSCSICommandAbortAll, 0 );
424 }
425
426 /*
427 *
428 *
429 *
430 */
431 void IOSCSIParallelDevice::reset()
432 {
433 submitCommand( kSCSICommandDeviceReset, 0 );
434 }
435
436 /*
437 *
438 *
439 *
440 */
441 void IOSCSIParallelDevice::holdQueue( UInt32 queueType )
442 {
443 if ( getWorkLoop()->inGate() == false )
444 {
445 IOPanic( "IOSCSIParallelDevice::holdQueue() - must be called from workloop!!\n\r");
446 }
447
448 if ( queueType == kQTypeBypassQ )
449 {
450 bypassQHeld = true;
451 }
452 else if ( queueType == kQTypeNormalQ )
453 {
454 normalQHeld = true;
455 }
456 }
457
458 /*
459 *
460 *
461 *
462 */
463 void IOSCSIParallelDevice::releaseQueue( UInt32 queueType )
464 {
465 if ( getWorkLoop()->inGate() == false )
466 {
467 IOPanic( "IOSCSIParallelDevice::releaseQueue() - must be called from workloop!!\n\r");
468 }
469
470 if ( queueType == kQTypeBypassQ )
471 {
472 bypassQHeld = false;
473 }
474 else if ( queueType == kQTypeNormalQ )
475 {
476 normalQHeld = false;
477 }
478
479 dispatchRequest();
480 }
481
482 /*
483 *
484 *
485 *
486 */
487 void IOSCSIParallelDevice::notifyIdle( void *target = 0, CallbackFn callback = 0, void *refcon = 0 )
488 {
489 if ( getWorkLoop()->inGate() == false )
490 {
491 IOPanic( "IOSCSIParallelDevice:::notifyIdle() - must be called from workloop!!\n\r");
492 }
493
494 if ( callback == 0 )
495 {
496 idleNotifyActive = false;
497 return;
498 }
499
500 if ( idleNotifyActive == true )
501 {
502 IOPanic( "IOSCSIParallelDevice:::notifyIdle() - only one idle notify may be active\n\r");
503 }
504
505 idleNotifyActive = true;
506 idleNotifyTarget = target;
507 idleNotifyCallback = callback;
508 idleNotifyRefcon = refcon;
509
510 checkIdleNotify();
511 }
512
513
514 /*
515 *
516 *
517 *
518 */
519 void IOSCSIParallelDevice::submitCommand( UInt32 cmdType, IOSCSIParallelCommand *scsiCmd, UInt32 cmdSequenceNumber )
520 {
521 deviceGate->runCommand( (void *)cmdType, (void *)scsiCmd, (void *) cmdSequenceNumber, (void *) 0 );
522 }
523
524 /*
525 *
526 *
527 *
528 */
529 void IOSCSIParallelDevice::receiveCommand( UInt32 cmdType, IOSCSIParallelCommand *scsiCmd, UInt32 cmdSequenceNumber, void *p3 )
530 {
531 queue_head_t *queue;
532
533 switch ( cmdType )
534 {
535 case kSCSICommandExecute:
536 scsiCmd->cmdType = (SCSICommandType) cmdType;
537
538 scsiCmd->scsiCmd.cdbFlags &= (kCDBFNoDisconnect);
539
540 queue = (scsiCmd->queueType == kQTypeBypassQ) ? &bypassList : &deviceList;
541
542 if ( scsiCmd->queuePosition == kQPositionHead )
543 {
544 stackCommand( queue, scsiCmd );
545 }
546 else
547 {
548 addCommand( queue, scsiCmd );
549 }
550
551 dispatchRequest();
552 break;
553
554 case kSCSICommandAbortAll:
555 abortAllCommands( kSCSICommandAbortAll );
556 break;
557
558 case kSCSICommandAbort:
559 abortCommand( scsiCmd, cmdSequenceNumber );
560 break;
561
562 case kSCSICommandDeviceReset:
563 abortAllCommands( kSCSICommandDeviceReset );
564 break;
565
566 default:
567 /* ??? */
568 break;
569 }
570 }
571
572 /*
573 *
574 *
575 *
576 */
577 void IOSCSIParallelDevice::abortCommand( IOSCSIParallelCommand *scsiCmd, UInt32 sequenceNumber )
578 {
579 if ( scsiCmd->list == (queue_head_t *)deviceGate )
580 {
581 if ( scsiCmd->sequenceNumber != sequenceNumber )
582 {
583 return;
584 }
585 scsiCmd->results.returnCode = kIOReturnAborted;
586 }
587 else if ( scsiCmd->list == &deviceList )
588 {
589 if ( scsiCmd->sequenceNumber != sequenceNumber )
590 {
591 return;
592 }
593
594 deleteCommand( &deviceList, scsiCmd );
595 scsiCmd->results.returnCode = kIOReturnAborted;
596 finishCommand( scsiCmd );
597 }
598 else if ( scsiCmd->list == &activeList )
599 {
600 if ( scsiCmd->sequenceNumber != sequenceNumber )
601 {
602 return;
603 }
604
605 moveCommand( &activeList, &abortList, scsiCmd );
606
607 dispatchRequest();
608 }
609 }
610
611
612 /*
613 *
614 *
615 *
616 */
617 void IOSCSIParallelDevice::abortAllCommands( SCSICommandType cmdType )
618 {
619 IOSCSIParallelDevice *abortDev;
620
621 abortCmdPending = cmdType;
622
623 if ( abortCmdPending == kSCSICommandAbortAll )
624 {
625 if ( client != 0 )
626 {
627 client->message( kSCSIClientMsgDeviceAbort, this );
628 }
629 }
630 else if ( abortCmdPending == kSCSICommandDeviceReset )
631 {
632 queue_iterate( &target->deviceList, abortDev, IOSCSIParallelDevice *, nextDevice )
633 {
634 if ( abortDev->client != 0 )
635 {
636 abortDev->client->message( kSCSIClientMsgDeviceReset, abortDev );
637 }
638 }
639 }
640
641 dispatchRequest();
642 }
643
644 /*
645 *
646 *
647 *
648 */
649 void IOSCSIParallelDevice::resetOccurred( SCSIClientMessage clientMsg )
650 {
651 if ( client != 0 && clientMsg != kSCSIClientMsgNone )
652 {
653 client->message( clientMsg, this );
654 }
655
656 moveAllCommands( &activeList, &cancelList, kIOReturnAborted );
657 moveAllCommands( &abortList, &cancelList, kIOReturnAborted );
658
659 abortState = kStateIdle;
660 reqSenseState = kStateIdle;
661 commandLimit = commandLimitSave;
662 negotiateState = kStateIdle;
663
664 dispatchRequest();
665 }
666
667 void IOSCSIParallelDevice::resetComplete()
668 {
669 if ( client != 0 )
670 {
671 client->message( kSCSIClientMsgBusReset | kSCSIClientMsgDone, this );
672 }
673 }
674
675
676 /*
677 *
678 *
679 *
680 */
681 bool IOSCSIParallelDevice::checkAbortQueue()
682 {
683 IOSCSIParallelCommand *origCmd;
684
685 if ( abortState == kStateActive )
686 {
687 return true;
688 }
689
690 if ( abortCmdPending != kSCSICommandNone )
691 {
692 abortCmd->origCommand = 0;
693
694 abortCmd->scsiCmd.cdbTagMsg = 0;
695 abortCmd->scsiCmd.cdbTag = (UInt32) -1;
696
697
698 abortCmd->cmdType = abortCmdPending;
699 abortCmd->scsiCmd.cdbAbortMsg = (abortCmdPending == kSCSICommandAbortAll)
700 ? kSCSIMsgAbort : kSCSIMsgBusDeviceReset;
701
702 if ( disableDisconnect == true )
703 {
704 abortCmd->scsiCmd.cdbFlags |= kCDBFlagsNoDisconnect;
705 }
706 else
707 {
708 abortCmd->scsiCmd.cdbFlags &= ~kCDBFlagsNoDisconnect;
709 }
710
711
712 abortCmd->timer = ( abortCmd->timeout != 0 ) ?
713 abortCmd->timeout / kSCSITimerIntervalmS + 1 : 0;
714
715 bzero( &abortCmd->results, sizeof(SCSIResults) );
716
717 abortCmdPending = kSCSICommandNone;
718 abortState = kStateActive;
719
720 addCommand( &activeList, abortCmd );
721 controller->executeCommand( abortCmd );
722 }
723 else if ( queue_empty( &abortList ) == false )
724 {
725 origCmd = (IOSCSIParallelCommand *)queue_first( &abortList );
726 abortCmd->origCommand = origCmd;
727
728 abortCmd->cmdType = kSCSICommandAbort;
729 abortCmd->scsiCmd.cdbTagMsg = origCmd->scsiCmd.cdbTagMsg;
730 abortCmd->scsiCmd.cdbTag = origCmd->scsiCmd.cdbTag;
731 abortCmd->scsiCmd.cdbAbortMsg = (abortCmd->scsiCmd.cdbTagMsg != 0)
732 ? kSCSIMsgAbortTag : kSCSIMsgAbort;
733
734 abortCmd->timer = ( abortCmd->timeout != 0 ) ?
735 abortCmd->timeout / kSCSITimerIntervalmS + 1 : 0;
736
737 bzero( &abortCmd->results, sizeof(SCSIResults) );
738
739 abortState = kStateActive;
740
741 addCommand( &activeList, abortCmd );
742 controller->executeCommand( abortCmd );
743 }
744 else
745 {
746 return false;
747 }
748
749 return true;
750 }
751
752 /*
753 *
754 *
755 *
756 */
757 void IOSCSIParallelDevice::checkCancelQueue()
758 {
759 if ( cancelState != kStateIdle )
760 {
761 return;
762 }
763
764 if ( queue_empty( &cancelList ) == true )
765 {
766 return;
767 }
768
769 if ( controller->controllerInfo.disableCancelCommands == true )
770 {
771 return;
772 }
773
774 cancelCmd->origCommand = (IOSCSIParallelCommand *)queue_first( &cancelList );
775 bzero( &cancelCmd->results, sizeof(SCSIResults) );
776
777 cancelState = kStateActive;
778 controller->cancelCommand( cancelCmd );
779 }
780
781 /*
782 *
783 *
784 *
785 */
786 bool IOSCSIParallelDevice::checkReqSense()
787 {
788 IOMemoryDescriptor *senseData;
789 UInt32 senseLength;
790 SCSITargetParms *tpCur;
791
792 if ( target->reqSenseState == kStateActive )
793 {
794 return true;
795 }
796
797 if ( reqSenseState == kStateIssue )
798 {
799 reqSenseCmd->origCommand = reqSenseOrigCmd;
800 bzero( &reqSenseCmd->results, sizeof(SCSIResults) );
801
802 reqSenseOrigCmd->getPointers( &senseData, &senseLength, 0, true );
803 reqSenseCmd->setPointers( senseData, senseLength, false );
804
805 reqSenseCmd->scsiCmd.cdbFlags = 0;
806
807 if ( disableDisconnect == true )
808 {
809 reqSenseCmd->scsiCmd.cdbFlags |= kCDBFlagsNoDisconnect;
810 }
811 else
812 {
813 reqSenseCmd->scsiCmd.cdbFlags &= ~kCDBFlagsNoDisconnect;
814 }
815
816 tpCur = &target->targetParmsCurrent;
817
818 if ( tpCur->transferWidth > 1 )
819 {
820 reqSenseCmd->scsiCmd.cdbFlags |= kCDBFlagsNegotiateWDTR;
821 if (tpCur->transferOptions & kSCSITransferOptionPPR) {
822 reqSenseCmd->scsiCmd.cdbFlags |= kCDBFlagsNegotiatePPR;
823 }
824 }
825
826 if ( tpCur->transferOffset != 0 )
827 {
828 reqSenseCmd->scsiCmd.cdbFlags |= kCDBFlagsNegotiateSDTR;
829 if (tpCur->transferOptions & kSCSITransferOptionPPR) {
830 reqSenseCmd->scsiCmd.cdbFlags |= kCDBFlagsNegotiatePPR;
831 }
832
833 }
834
835 reqSenseCmd->timer = ( reqSenseCmd->timeout != 0 ) ?
836 reqSenseCmd->timeout / kSCSITimerIntervalmS + 1 : 0;
837
838 reqSenseCmd->scsiCmd.cdb[3] = (senseLength >> 8) & 0xff;
839 reqSenseCmd->scsiCmd.cdb[4] = senseLength & 0xff;
840
841 reqSenseState = kStatePending;
842 }
843
844 if ( reqSenseState == kStatePending )
845 {
846 target->reqSenseState = reqSenseState = kStateActive;
847
848 addCommand( &activeList, reqSenseCmd );
849
850 commandCount++;
851 controller->commandCount++;
852
853 controller->executeCommand( reqSenseCmd );
854 }
855
856 return (target->reqSenseCount > 0);
857 }
858
859
860 /*
861 *
862 *
863 *
864 */
865 bool IOSCSIParallelDevice::checkDeviceQueue( UInt32 *dispatchAction )
866 {
867 IOSCSIParallelCommand *scsiCmd = 0;
868 queue_head_t *queue;
869 UInt32 i;
870 bool rc = true;
871 bool queueHeld;
872
873 do
874 {
875 if ( controller->commandCount >= controller->commandLimit )
876 {
877 *dispatchAction = kDispatchStop;
878 break;
879 }
880
881 if ( target->commandCount >= target->commandLimit )
882 {
883 *dispatchAction = kDispatchNextTarget;
884 break;
885 }
886
887 *dispatchAction = kDispatchNextLun;
888
889 if ( commandCount >= commandLimit )
890 {
891 break;
892 }
893
894 for ( i=0; i < 2; i++ )
895 {
896 queueHeld = (i == 0) ? bypassQHeld : normalQHeld;
897 queue = (i == 0) ? &bypassList : &deviceList;
898
899 if ( queueHeld == true )
900 {
901 continue;
902 }
903
904 scsiCmd = checkCommand( queue );
905 if ( scsiCmd != 0 )
906 {
907 *dispatchAction = kDispatchNextCommand;
908 break;
909 }
910 }
911
912 if ( i == 2 )
913 {
914 rc = false;
915 break;
916 }
917
918 if ( disableDisconnect == true || (scsiCmd->scsiCmd.cdbFlags & kCDBFNoDisconnect) )
919 {
920 scsiCmd->scsiCmd.cdbFlags |= kCDBFlagsNoDisconnect;
921
922 if ( controller->commandCount != 0 )
923 {
924 *dispatchAction = kDispatchNextLun;
925 break;
926 }
927
928 controller->noDisconnectCmd = scsiCmd;
929 controller->commandLimitSave = controller->commandLimit;
930 controller->commandLimit = 1;
931 }
932
933 else if ( checkTag( scsiCmd ) == false )
934 {
935 switch ( controller->controllerInfo.tagAllocationMethod )
936 {
937 case kTagAllocationPerTarget:
938 *dispatchAction = kDispatchNextTarget;
939 break;
940 case kTagAllocationPerController:
941 *dispatchAction = kDispatchStop;
942 break;
943 case kTagAllocationPerLun:
944 ;
945 default:
946 *dispatchAction = kDispatchNextLun;
947 }
948 break;
949 }
950
951 getCommand( queue );
952
953 checkNegotiate( scsiCmd );
954
955 scsiCmd->timer = ( scsiCmd->timeout != 0 ) ? scsiCmd->timeout / kSCSITimerIntervalmS + 1 : 0;
956
957 commandCount++;
958 target->commandCount++;
959 controller->commandCount++;
960
961 addCommand( &activeList, scsiCmd );
962
963 controller->executeCommand( scsiCmd );
964
965 } while ( 0 );
966
967 return rc;
968 }
969
970 /*
971 *
972 *
973 *
974 */
975 void IOSCSIParallelDevice::rescheduleCommand( IOSCSIParallelCommand *scsiCmd )
976 {
977 if ( scsiCmd->list != &activeList )
978 {
979 IOLog( "IOSCSIParallelController::rescheduleCommand() - Command not active. Cmd = %08x\n\r", (int)scsiCmd );
980 return;
981 }
982
983 deleteCommand( &activeList, scsiCmd );
984
985 switch ( scsiCmd->cmdType )
986 {
987 case kSCSICommandExecute:
988 if ( scsiCmd->scsiCmd.cdbTagMsg != 0 )
989 {
990 freeTag( scsiCmd->scsiCmd.cdbTag );
991 scsiCmd->scsiCmd.cdbTag = (UInt32) -1;
992 }
993
994 stackCommand( &deviceList, scsiCmd );
995
996 if ( scsiCmd->scsiCmd.cdbFlags & kCDBFlagsNoDisconnect )
997 {
998 controller->commandLimit = controller->commandLimitSave;
999 controller->noDisconnectCmd = 0;
1000 }
1001
1002 controller->commandCount--;
1003 target->commandCount--;
1004 commandCount--;
1005 break;
1006
1007 case kSCSICommandReqSense:
1008 reqSenseState = kStatePending;
1009 target->reqSenseState = kStateIdle;
1010 commandCount--;
1011 controller->commandCount--;
1012 break;
1013
1014 case kSCSICommandAbortAll:
1015 case kSCSICommandDeviceReset:
1016 abortCmdPending = scsiCmd->cmdType;
1017
1018 case kSCSICommandAbort:
1019 abortState = kStateIdle;
1020 break;
1021
1022 default:
1023 ;
1024 }
1025
1026 dispatchRequest();
1027
1028 }
1029
1030 /*
1031 *
1032 *
1033 *
1034 */
1035 bool IOSCSIParallelDevice::setTargetParms( SCSITargetParms *targetParms )
1036 {
1037 IOSCSIParallelCommand *scsiCmd;
1038 SCSICDBInfo scsiCDB;
1039 bool fTagEnable;
1040 bool rc = true;
1041
1042 IOMemoryDescriptor *senseDesc;
1043 UInt8 senseBuffer[14];
1044
1045
1046 if ( getWorkLoop()->inGate() == true )
1047 {
1048 IOPanic( "IOSCSIParallelDevice:::setTargetParms() - must not be called from workloop!!\n\r");
1049 }
1050
1051 IOWriteLock( target->clientSem );
1052 IOWriteLock( target->targetSem );
1053
1054 while ( target->negotiateState == kStateActive )
1055 {
1056 IOSleep( 100 );
1057 }
1058
1059 target->targetParmsNew = *targetParms;
1060
1061 if ( targetParms->transferPeriodpS < controller->controllerInfo.minTransferPeriodpS )
1062 {
1063 target->targetParmsNew.transferPeriodpS = controller->controllerInfo.minTransferPeriodpS;
1064 }
1065
1066 if ( target->targetParmsNew.transferPeriodpS == 0
1067 || target->targetParmsNew.transferOffset == 0
1068 || controller->controllerInfo.minTransferPeriodpS == 0 )
1069 {
1070 target->targetParmsNew.transferPeriodpS = 0;
1071 target->targetParmsNew.transferOffset = 0;
1072 }
1073
1074 target->commandLimit = 1;
1075
1076 fTagEnable = (targetParms->enableTagQueuing == true)
1077 && (controller->controllerInfo.tagAllocationMethod != kTagAllocationNone)
1078 && (controller->controllerInfo.maxTags != 0);
1079
1080 regObjCmdQueue->setValue( (UInt32)fTagEnable );
1081
1082 if ( fTagEnable == true )
1083 {
1084 target->commandLimitSave = controller->controllerInfo.maxCommandsPerTarget;
1085 }
1086 else
1087 {
1088 target->commandLimitSave = 1;
1089 target->targetParmsNew.enableTagQueuing = false;
1090 }
1091
1092 scsiCmd = allocCommand(kIOSCSIParallelDevice, 0);
1093
1094 bzero( &scsiCDB, sizeof( SCSICDBInfo ) );
1095
1096 scsiCDB.cdbLength = 6;
1097 scsiCDB.cdb[0] = kSCSICmdTestUnitReady;
1098 scsiCDB.cdb[1] = targetLun.lun << 4;
1099 scsiCmd->setCDB( &scsiCDB );
1100
1101 senseDesc = IOMemoryDescriptor::withAddress(senseBuffer, sizeof(senseBuffer), kIODirectionIn);
1102 if ( senseDesc == 0 ) return false;
1103 scsiCmd->setPointers( senseDesc, sizeof(senseBuffer), false, true );
1104
1105 target->negotiateState = kStateIssue;
1106
1107 scsiCmd->execute();
1108
1109 IOWriteLock( target->targetSem );
1110 IORWUnlock( target->targetSem );
1111
1112 scsiCmd->release();
1113 senseDesc->release();
1114
1115 rc = (target->negotiationResult.returnCode == kIOReturnSuccess);
1116
1117 IORWUnlock( target->clientSem );
1118
1119 return rc;
1120 }
1121
1122 /*
1123 *
1124 *
1125 *
1126 */
1127 void IOSCSIParallelDevice::getTargetParms( SCSITargetParms *targetParms )
1128 {
1129 *targetParms = target->targetParmsCurrent;
1130 }
1131
1132 /*
1133 *
1134 *
1135 *
1136 */
1137 bool IOSCSIParallelDevice::setLunParms( SCSILunParms *lunParms )
1138 {
1139 IOSCSIParallelCommand *scsiCmd;
1140 SCSICDBInfo scsiCDB;
1141
1142 IOMemoryDescriptor *senseDesc;
1143 UInt8 senseBuffer[14];
1144
1145 if ( getWorkLoop()->inGate() == true )
1146 {
1147 IOPanic( "IOSCSIParallelDevice:::setLunParms() - must not be called from workloop!!\n\r");
1148 }
1149
1150 IOWriteLock( clientSem );
1151
1152 lunParmsNew = *lunParms;
1153 commandLimitSave = commandLimit;
1154 commandLimit = 1;
1155
1156 scsiCmd = allocCommand(kIOSCSIParallelDevice, 0);
1157
1158 bzero( &scsiCDB, sizeof( SCSICDBInfo ) );
1159
1160 scsiCDB.cdbLength = 6;
1161 scsiCDB.cdb[0] = kSCSICmdTestUnitReady;
1162 scsiCDB.cdb[1] = targetLun.lun << 4;
1163 scsiCmd->setCDB( &scsiCDB );
1164
1165 senseDesc = IOMemoryDescriptor::withAddress(senseBuffer, sizeof(senseBuffer), kIODirectionIn);
1166 if ( senseDesc == 0 ) return false;
1167 scsiCmd->setPointers( senseDesc, sizeof(senseBuffer), false, true );
1168
1169 negotiateState = kStateIssue;
1170
1171 scsiCmd->execute();
1172
1173 scsiCmd->release();
1174 senseDesc->release();
1175
1176 while ( negotiateState != kStateIdle )
1177 {
1178 IOSleep( 100 );
1179 }
1180
1181 IORWUnlock( clientSem );
1182
1183 return true;
1184 }
1185
1186 /*
1187 *
1188 *
1189 *
1190 */
1191 void IOSCSIParallelDevice::getLunParms( SCSILunParms *lunParms )
1192 {
1193 lunParms->disableDisconnect = disableDisconnect;
1194 }
1195
1196 /*
1197 *
1198 *
1199 *
1200 */
1201 void IOSCSIParallelDevice::checkNegotiate( IOSCSIParallelCommand *scsiCmd )
1202 {
1203 SCSITargetParms *tpCur, *tpNew;
1204
1205 if ( target->negotiateState == kStateIssue )
1206 {
1207 if ( target->commandCount == 0 )
1208 {
1209 target->negotiateState = kStateActive;
1210
1211 tpNew = &target->targetParmsNew;
1212 tpCur = &target->targetParmsCurrent;
1213
1214 target->negotiationResult.returnCode = kIOReturnError;
1215
1216 if ((tpCur->transferPeriodpS != tpNew->transferPeriodpS) ||
1217 (tpCur->transferOffset != tpNew->transferOffset) ||
1218 ((tpCur->transferOptions ^ tpNew->transferOptions) & kSCSITransferOptionsSCSI3) )
1219 {
1220 scsiCmd->scsiCmd.cdbFlags |= kCDBFlagsNegotiateSDTR;
1221
1222 if (tpNew->transferOptions & kSCSITransferOptionPPR) {
1223 scsiCmd->scsiCmd.cdbFlags |= kCDBFlagsNegotiatePPR;
1224 }
1225 }
1226
1227 if ( tpCur->transferWidth != tpNew->transferWidth )
1228 {
1229 scsiCmd->scsiCmd.cdbFlags |= kCDBFlagsNegotiateWDTR;
1230 }
1231
1232 if ( tpCur->enableTagQueuing != tpNew->enableTagQueuing )
1233 {
1234 scsiCmd->scsiCmd.cdbFlags |= kCDBFlagsEnableTagQueuing;
1235 }
1236
1237 if ( (scsiCmd->scsiCmd.cdbFlags &
1238 (kCDBFlagsNegotiateSDTR |
1239 kCDBFlagsNegotiateWDTR |
1240 kCDBFlagsNegotiatePPR |
1241 kCDBFlagsEnableTagQueuing)) == 0 )
1242 {
1243 IORWUnlock( target->targetSem );
1244 target->negotiateState = kStateIdle;
1245 target->commandLimit = target->commandLimitSave;
1246 }
1247
1248 *tpCur = *tpNew;
1249 }
1250 }
1251
1252 if ( negotiateState == kStateIssue )
1253 {
1254 if ( commandCount == 0 )
1255 {
1256 disableDisconnect = lunParmsNew.disableDisconnect;
1257 negotiateState = kStateIdle;
1258 }
1259 }
1260 }
1261
1262 /*
1263 *
1264 *
1265 *
1266 */
1267 void IOSCSIParallelDevice::negotiationComplete()
1268 {
1269 SCSITargetParms *tpCur, *tpNew;
1270
1271 tpNew = &target->targetParmsNew;
1272 tpCur = &target->targetParmsCurrent;
1273
1274 if ( target->negotiationResult.returnCode == kIOReturnSuccess )
1275 {
1276 tpCur->transferPeriodpS = tpNew->transferPeriodpS = target->negotiationResult.transferPeriodpS;
1277 tpCur->transferOffset = tpNew->transferOffset = target->negotiationResult.transferOffset;
1278 tpCur->transferWidth = tpNew->transferWidth = target->negotiationResult.transferWidth;
1279 tpCur->transferOptions = tpNew->transferOptions = target->negotiationResult.transferOptions;
1280
1281 target->commandLimit = target->commandLimitSave;
1282 }
1283 else
1284 {
1285 tpNew->transferPeriodpS = 0;
1286 tpNew->transferOffset = 0;
1287 tpNew->transferWidth = 1;
1288 }
1289
1290 target->regObjTransferPeriod->setValue( tpNew->transferPeriodpS );
1291 target->regObjTransferOffset->setValue( tpNew->transferOffset );
1292 target->regObjTransferWidth->setValue( tpNew->transferWidth );
1293 target->regObjTransferOptions->setValue( tpNew->transferOptions );
1294
1295 target->negotiateState = kStateIdle;
1296 }
1297
1298 /*
1299 *
1300 *
1301 *
1302 */
1303 bool IOSCSIParallelDevice::checkTag( IOSCSIParallelCommand *scsiCmd )
1304 {
1305 SCSICDBInfo scsiCDB;
1306 bool rc = true;
1307
1308 scsiCmd->getCDB( &scsiCDB );
1309
1310 scsiCDB.cdbTagMsg = 0;
1311 scsiCDB.cdbTag = (UInt32)-1;
1312
1313 do
1314 {
1315 if ( scsiCmd->device->target->targetParmsCurrent.enableTagQueuing == false )
1316 {
1317 break;
1318 }
1319
1320 /* If the command is untagged, then don't allocate a tag nor
1321 * send the untagged command as a simple-tagged command.
1322 */
1323 if ( scsiCDB.cdbTagMsg == 0 )
1324 {
1325 break;
1326 }
1327
1328 if ( allocTag( &scsiCDB.cdbTag ) == false )
1329 {
1330 rc = false;
1331 break;
1332 }
1333 }
1334 while ( 0 );
1335
1336 scsiCmd->setCDB( &scsiCDB );
1337
1338 return rc;
1339 }
1340
1341 /*
1342 *
1343 *
1344 *
1345 */
1346 bool IOSCSIParallelDevice::allocTag( UInt32 *tagId )
1347 {
1348 UInt32 i;
1349 UInt32 tagIndex;
1350 UInt32 tagMask;
1351 UInt32 *tags = 0;
1352
1353 switch ( controller->controllerInfo.tagAllocationMethod )
1354 {
1355 case kTagAllocationPerLun:
1356 tags = tagArray;
1357 break;
1358 case kTagAllocationPerTarget:
1359 tags = target->tagArray;
1360 break;
1361 case kTagAllocationPerController:
1362 tags = controller->tagArray;
1363 break;
1364 default:
1365 ;
1366 }
1367
1368 if ( tags == 0 ) return false;
1369
1370 for ( i = 0; i < controller->controllerInfo.maxTags; i++ )
1371 {
1372 tagIndex = i / 32;
1373 tagMask = 1 << (i % 32);
1374 if ( !(tags[tagIndex] & tagMask) )
1375 {
1376 tags[tagIndex] |= tagMask;
1377 *tagId = i;
1378 return true;
1379 }
1380 }
1381 return false;
1382 }
1383
1384 /*
1385 *
1386 *
1387 *
1388 */
1389 void IOSCSIParallelDevice::freeTag( UInt32 tagId )
1390 {
1391 UInt32 *tags = 0;
1392
1393 switch ( controller->controllerInfo.tagAllocationMethod )
1394 {
1395 case kTagAllocationPerLun:
1396 tags = tagArray;
1397 break;
1398 case kTagAllocationPerTarget:
1399 tags = target->tagArray;
1400 break;
1401 case kTagAllocationPerController:
1402 tags = controller->tagArray;
1403 break;
1404 default:
1405 ;
1406 }
1407
1408 if ( tags == 0 ) return;
1409
1410 tags[tagId/32] &= ~(1 << (tagId % 32));
1411 }
1412
1413 /*
1414 *
1415 *
1416 *
1417 */
1418 IOSCSIParallelCommand *IOSCSIParallelDevice::findCommandWithNexus( UInt32 tagValue )
1419 {
1420 IOSCSIParallelCommand *scsiCmd;
1421
1422 queue_iterate( &activeList, scsiCmd, IOSCSIParallelCommand *, nextCommand )
1423 {
1424 switch ( scsiCmd->cmdType )
1425 {
1426 case kSCSICommandExecute:
1427 case kSCSICommandReqSense:
1428 if ( scsiCmd->scsiCmd.cdbTag == tagValue )
1429 {
1430 return scsiCmd;
1431 }
1432 break;
1433 default:
1434 ;
1435 }
1436 }
1437
1438 queue_iterate( &abortList, scsiCmd, IOSCSIParallelCommand *, nextCommand )
1439 {
1440 switch ( scsiCmd->cmdType )
1441 {
1442 case kSCSICommandExecute:
1443 case kSCSICommandReqSense:
1444 if ( scsiCmd->scsiCmd.cdbTag == tagValue )
1445 {
1446 return scsiCmd;
1447 }
1448 break;
1449 default:
1450 ;
1451 }
1452 }
1453
1454 return 0;
1455 }
1456
1457 /*
1458 *
1459 *
1460 *
1461 */
1462 void IOSCSIParallelDevice::timer()
1463 {
1464 IOSCSIParallelCommand *scsiCmd, *tmp = 0;
1465 SCSITargetLun scsiTargetLun;
1466
1467 queue_iterate( &activeList, scsiCmd, IOSCSIParallelCommand *, nextCommand )
1468 {
1469 tmp = (IOSCSIParallelCommand *)queue_prev( &scsiCmd->nextCommand );
1470
1471 if ( scsiCmd->timer )
1472 {
1473 if ( !--scsiCmd->timer )
1474 {
1475 scsiCmd->getTargetLun( &scsiTargetLun );
1476 IOLog("Timeout: T/L = %d:%d Cmd = %08x Cmd Type = %d\n\r",
1477 scsiTargetLun.target, scsiTargetLun.lun, (int)scsiCmd, scsiCmd->cmdType );
1478
1479 switch ( scsiCmd->cmdType )
1480 {
1481 case kSCSICommandExecute:
1482 moveCommand( &activeList, &abortList, scsiCmd, kIOReturnTimeout );
1483 scsiCmd = tmp;
1484 break;
1485
1486 case kSCSICommandReqSense:
1487 reqSenseState = kStateIdle;
1488 moveCommand( &activeList, &abortList, scsiCmd, kIOReturnTimeout );
1489 scsiCmd = tmp;
1490 break;
1491
1492 case kSCSICommandAbort:
1493 case kSCSICommandAbortAll:
1494 case kSCSICommandDeviceReset:
1495 controller->busResetState = kStateIssue;
1496 break;
1497
1498 default:
1499 ;
1500 }
1501
1502 dispatchRequest();
1503 }
1504 }
1505
1506 if ( queue_end( &activeList, (queue_head_t *)scsiCmd ) == true )
1507 {
1508 break;
1509 }
1510 }
1511 }
1512
1513 /*
1514 *
1515 *
1516 *
1517 */
1518 void IOSCSIParallelDevice::dispatchRequest()
1519 {
1520 target->state = kStateActive;
1521 controller->dispatchRequest();
1522 }
1523
1524 /*
1525 *
1526 *
1527 *
1528 */
1529 bool IOSCSIParallelDevice::dispatch( UInt32 *dispatchAction )
1530 {
1531 bool rc;
1532
1533 checkCancelQueue();
1534
1535 if ( controller->checkBusReset() == true )
1536 {
1537 *dispatchAction = kDispatchStop;
1538 return true;
1539 }
1540
1541 if ( (rc = controller->commandDisable) == true )
1542 {
1543 *dispatchAction = kDispatchNextTarget;
1544 return true;
1545 }
1546
1547 if ( checkAbortQueue() == true )
1548 {
1549 *dispatchAction = kDispatchNextTarget;
1550 return true;
1551 }
1552
1553 do
1554 {
1555 if ( (rc = controller->commandDisable) == true )
1556 {
1557 *dispatchAction = kDispatchStop;
1558 break;
1559 }
1560
1561 if ( (rc = checkReqSense()) == true )
1562 {
1563 *dispatchAction = kDispatchNextTarget;
1564 break;
1565 }
1566
1567 rc = checkDeviceQueue( dispatchAction );
1568
1569 } while ( *dispatchAction == kDispatchNextCommand );
1570
1571 return rc;
1572 }
1573
1574
1575 /*
1576 *
1577 *
1578 *
1579 */
1580 void IOSCSIParallelDevice::completeCommand( IOSCSIParallelCommand *scsiCmd )
1581 {
1582 SCSICommandType cmdType;
1583
1584 cmdType = scsiCmd->cmdType;
1585 switch ( cmdType )
1586 {
1587 case kSCSICommandExecute:
1588 executeCommandDone( scsiCmd );
1589 break;
1590
1591 case kSCSICommandReqSense:
1592 executeReqSenseDone( scsiCmd );
1593 break;
1594
1595 case kSCSICommandAbort:
1596 case kSCSICommandAbortAll:
1597 case kSCSICommandDeviceReset:
1598 abortCommandDone( scsiCmd );
1599 break;
1600
1601 case kSCSICommandCancel:
1602 cancelCommandDone( scsiCmd );
1603 break;
1604
1605 default:
1606 ;
1607 }
1608
1609 checkIdleNotify();
1610
1611 dispatchRequest();
1612 }
1613
1614 /*
1615 *
1616 *
1617 *
1618 */
1619 void IOSCSIParallelDevice::checkIdleNotify()
1620 {
1621 if ( idleNotifyActive == false )
1622 {
1623 return;
1624 }
1625
1626 if ( (queue_empty( &activeList ) == true)
1627 && (queue_empty( &abortList ) == true)
1628 && (queue_empty( &cancelList ) == true)
1629 && (target->reqSenseCount == 0) )
1630 {
1631 idleNotifyActive = false;
1632 (idleNotifyCallback)( idleNotifyTarget, idleNotifyRefcon );
1633 }
1634 }
1635
1636 /*
1637 *
1638 *
1639 *
1640 */
1641 void IOSCSIParallelDevice::flushQueue( UInt32 queueType, IOReturn rc )
1642 {
1643 queue_head_t *queue;
1644
1645 queue = (queueType == kQTypeBypassQ) ? &bypassList : &deviceList;
1646 purgeAllCommands( queue, rc );
1647 }
1648
1649 /*
1650 *
1651 *
1652 *
1653 */
1654 void IOSCSIParallelDevice::executeCommandDone( IOSCSIParallelCommand *scsiCmd )
1655 {
1656 deleteCommand( scsiCmd->list, scsiCmd );
1657
1658 commandCount--;
1659 controller->commandCount--;
1660 target->commandCount--;
1661
1662 if ( scsiCmd->scsiCmd.cdbTagMsg != 0 )
1663 {
1664 freeTag( scsiCmd->scsiCmd.cdbTag );
1665 scsiCmd->scsiCmd.cdbTag = (UInt32) -1;
1666 }
1667
1668 if ( scsiCmd->scsiCmd.cdbFlags & (kCDBFlagsNegotiateSDTR |
1669 kCDBFlagsNegotiateWDTR |
1670 kCDBFlagsNegotiatePPR |
1671 kCDBFlagsEnableTagQueuing) )
1672 {
1673 if ( scsiCmd->scsiCmd.cdbFlags & (kCDBFlagsNegotiateSDTR |
1674 kCDBFlagsNegotiateWDTR |
1675 kCDBFlagsNegotiatePPR) )
1676 {
1677 negotiationComplete();
1678 }
1679 else
1680 {
1681 target->negotiationResult.returnCode = kIOReturnSuccess;
1682 }
1683
1684 IORWUnlock( target->targetSem );
1685 }
1686
1687 if ( scsiCmd->scsiCmd.cdbFlags & kCDBFlagsNoDisconnect )
1688 {
1689 controller->commandLimit = controller->commandLimitSave;
1690 controller->noDisconnectCmd = 0;
1691 }
1692
1693 if ( scsiCmd->results.scsiStatus == kSCSIStatusCheckCondition
1694 && scsiCmd->results.requestSenseDone == false
1695 && scsiCmd->senseData != 0 )
1696 {
1697 reqSenseOrigCmd = scsiCmd;
1698 reqSenseState = kStateIssue;
1699 target->reqSenseCount++;
1700 return;
1701 }
1702
1703 if ( scsiCmd->results.scsiStatus == kSCSIStatusQueueFull )
1704 {
1705 if ( commandCount > 4 )
1706 {
1707 // IOLog( "IOSCSI: Q-full - commandCount = %d commandLimit = %d\n\r", commandCount, commandLimit );
1708 commandLimit = commandCount;
1709 }
1710
1711 stackCommand( &deviceList, scsiCmd );
1712 return;
1713 }
1714
1715 finishCommand( scsiCmd );
1716 }
1717
1718 /*
1719 *
1720 *
1721 *
1722 */
1723 void IOSCSIParallelDevice::executeReqSenseDone( IOSCSIParallelCommand *scsiCmd )
1724 {
1725 IOSCSIParallelCommand *origCommand;
1726
1727 deleteCommand( scsiCmd->list, scsiCmd );
1728
1729 target->reqSenseState = reqSenseState = kStateIdle;
1730 target->reqSenseCount--;
1731
1732 commandCount--;
1733 controller->commandCount--;
1734
1735 reqSenseOrigCmd = 0;
1736
1737 origCommand = scsiCmd->origCommand;
1738
1739 if ( (scsiCmd->results.returnCode == kIOReturnSuccess) || (scsiCmd->results.returnCode == kIOReturnUnderrun) )
1740 {
1741 origCommand->results.requestSenseDone = true;
1742 origCommand->results.requestSenseLength = scsiCmd->results.bytesTransferred;
1743 }
1744 else
1745 {
1746 origCommand->results.requestSenseDone = false;
1747 origCommand->results.requestSenseLength = 0;
1748 }
1749
1750 finishCommand( scsiCmd->origCommand );
1751 }
1752
1753 /*
1754 *
1755 *
1756 *
1757 */
1758 void IOSCSIParallelDevice::abortCommandDone( IOSCSIParallelCommand *scsiCmd )
1759 {
1760 IOSCSIParallelCommand *origSCSICmd;
1761 IOSCSIParallelDevice *abortDev;
1762
1763 deleteCommand( scsiCmd->list, scsiCmd );
1764
1765 abortState = kStateIdle;
1766
1767 if ( scsiCmd->cmdType == kSCSICommandAbortAll )
1768 {
1769 moveAllCommands( &activeList, &cancelList, kIOReturnAborted );
1770 moveAllCommands( &abortList, &cancelList, kIOReturnAborted );
1771
1772 if ( client != 0 )
1773 {
1774 client->message( kSCSIClientMsgDeviceAbort | kSCSIClientMsgDone, this );
1775 }
1776 }
1777 if ( scsiCmd->cmdType == kSCSICommandDeviceReset )
1778 {
1779 target->commandLimit = target->commandLimitSave;
1780 target->reqSenseCount = 0;
1781 target->reqSenseState = kStateIdle;
1782 target->negotiateState = kStateIssue;
1783
1784 target->targetParmsCurrent.transferPeriodpS = 0;
1785 target->targetParmsCurrent.transferOffset = 0;
1786 target->targetParmsCurrent.transferWidth = 1;
1787
1788 queue_iterate( &target->deviceList, abortDev, IOSCSIParallelDevice *, nextDevice )
1789 {
1790 abortDev->resetOccurred( (SCSIClientMessage)(kSCSIClientMsgDeviceReset | kSCSIClientMsgDone) );
1791 }
1792 }
1793 else if ( scsiCmd->cmdType == kSCSICommandAbort )
1794 {
1795 origSCSICmd = scsiCmd->origCommand;
1796
1797 if ( findCommand( &abortList, origSCSICmd ) == true )
1798 {
1799 moveCommand( &abortList, &cancelList, origSCSICmd, kIOReturnAborted );
1800 }
1801 }
1802
1803 return;
1804 }
1805
1806 /*
1807 *
1808 *
1809 *
1810 */
1811 void IOSCSIParallelDevice::cancelCommandDone( IOSCSIParallelCommand *scsiCmd )
1812 {
1813 IOSCSIParallelCommand *origSCSICmd;
1814
1815 cancelState = kStateIdle;
1816
1817 origSCSICmd = scsiCmd->origCommand;
1818
1819 if ( findCommand( &cancelList, origSCSICmd ) == true )
1820 {
1821 IOLog( "IOSCSIParallelDevice::cancelCommandDone - Cancelled command not completed - scsiCmd = %08x\n\r", (int)origSCSICmd );
1822 deleteCommand( &cancelList, origSCSICmd );
1823 }
1824 }
1825
1826 /*
1827 *
1828 *
1829 *
1830 */
1831 void IOSCSIParallelDevice::finishCommand( IOSCSIParallelCommand *scsiCmd )
1832 {
1833 if ( scsiCmd->completionInfo.async.callback )
1834 {
1835 (*scsiCmd->completionInfo.async.callback)( scsiCmd->completionInfo.async.target,
1836 scsiCmd->completionInfo.async.refcon );
1837 }
1838 else
1839 {
1840 scsiCmd->completionInfo.sync.lock->signal();
1841 }
1842 }
1843
1844
1845 /*
1846 *
1847 *
1848 */
1849 OSDictionary *IOSCSIParallelDevice::createProperties()
1850 {
1851 OSDictionary *propTable = 0;
1852 OSObject *regObj;
1853 char tmpbuf[81];
1854 char *d;
1855 char unit[10];
1856
1857 propTable = OSDictionary::withCapacity(kSCSIMaxProperties);
1858 if ( propTable == NULL )
1859 {
1860 return NULL;
1861 }
1862
1863 regObj = (OSObject *)OSNumber::withNumber(targetLun.target,32);
1864 if ( addToRegistry( propTable, regObj, kSCSIPropertyTarget ) != true )
1865 {
1866 goto createprop_error;
1867 }
1868
1869 regObj = (OSObject *)OSNumber::withNumber(targetLun.target,32);
1870 if ( addToRegistry( propTable, regObj, kSCSIPropertyIOUnit ) != true )
1871 {
1872 goto createprop_error;
1873 }
1874
1875 sprintf(unit,"%x",targetLun.target);
1876 setLocation(unit);
1877
1878 regObj = (OSObject *)OSNumber::withNumber(targetLun.lun,32);
1879 if ( addToRegistry( propTable, regObj, kSCSIPropertyLun ) != true )
1880 {
1881 goto createprop_error;
1882 }
1883
1884 d= tmpbuf;
1885
1886 stripBlanks( d, (char *)inquiryData->vendorName, sizeof(inquiryData->vendorName) );
1887 regObj = (OSObject *)OSString::withCString( d );
1888 if ( addToRegistry( propTable, regObj, kSCSIPropertyVendorName ) != true )
1889 {
1890 goto createprop_error;
1891 }
1892
1893 stripBlanks( d, (char *)inquiryData->productName, sizeof(inquiryData->productName) );
1894 regObj = (OSObject *)OSString::withCString( d );
1895 if ( addToRegistry( propTable, regObj, kSCSIPropertyProductName ) != true )
1896 {
1897 goto createprop_error;
1898 }
1899
1900 stripBlanks( d, (char *)inquiryData->productRevision, sizeof(inquiryData->productRevision) );
1901 regObj = (OSObject *)OSString::withCString( d );
1902 if ( addToRegistry( propTable, regObj, kSCSIPropertyProductRevision ) != true )
1903 {
1904 goto createprop_error;
1905 }
1906
1907 regObj = (OSObject *)OSBoolean::withBoolean( (inquiryData->devTypeMod & kSCSIDevTypeModRemovable) != 0 );
1908 if ( addToRegistry( propTable, regObj, kSCSIPropertyRemovableMedia ) != true )
1909 {
1910 goto createprop_error;
1911 }
1912
1913 regObj = (OSObject *)OSNumber::withNumber( inquiryData->devType & kSCSIDevTypeMask, 32 );
1914 if ( addToRegistry( propTable, regObj, kSCSIPropertyDeviceTypeID ) != true )
1915 {
1916 goto createprop_error;
1917 }
1918
1919 regObj = (OSObject *)target->regObjTransferPeriod;
1920 if ( addToRegistry( propTable, regObj, kSCSIPropertyTransferPeriod, false ) != true )
1921 {
1922 goto createprop_error;
1923 }
1924 regObjTransferPeriod = (OSNumber *)regObj;
1925
1926 regObj = (OSObject *)target->regObjTransferOffset;
1927 if ( addToRegistry( propTable, regObj, kSCSIPropertyTransferOffset, false ) != true )
1928 {
1929 goto createprop_error;
1930 }
1931 regObjTransferOffset = (OSNumber *)regObj;
1932
1933
1934 regObj = (OSObject *)target->regObjTransferWidth;
1935 if ( addToRegistry( propTable, regObj, kSCSIPropertyTransferWidth, false ) != true )
1936 {
1937 goto createprop_error;
1938 }
1939 regObjTransferWidth = (OSNumber *)regObj;
1940
1941 regObj = (OSObject *)target->regObjTransferOptions;
1942 if ( addToRegistry( propTable, regObj, kSCSIPropertyTransferOptions, false ) != true )
1943 {
1944 goto createprop_error;
1945 }
1946 regObjTransferOptions = (OSNumber *)regObj;
1947
1948 regObj = (OSObject *)target->regObjCmdQueue;
1949 if ( addToRegistry( propTable, regObj, kSCSIPropertyCmdQueue, false ) != true )
1950 {
1951 goto createprop_error;
1952 }
1953 regObjCmdQueue = (OSNumber *)regObj;
1954
1955 return propTable;
1956
1957 createprop_error: ;
1958 propTable->release();
1959 return NULL;
1960 }
1961
1962
1963 /*
1964 *
1965 *
1966 */
1967 bool IOSCSIParallelDevice::addToRegistry( OSDictionary *propTable, OSObject *regObj, char *key,
1968 bool doRelease = true )
1969 {
1970 bool rc;
1971
1972 if ( regObj == NULL )
1973 {
1974 return false;
1975 }
1976
1977 rc = propTable->setObject( key, regObj );
1978
1979 if ( doRelease )
1980 {
1981 // If 'doRelease' is true, then a reference count is consumed.
1982 regObj->release();
1983 }
1984
1985 return rc;
1986 }
1987
1988
1989 /*
1990 *
1991 *
1992 *
1993 */
1994 bool IOSCSIParallelDevice::matchPropertyTable(OSDictionary * table)
1995 {
1996 bool match;
1997
1998 match = compareProperty( table, kSCSIPropertyIOUnit ) &&
1999 compareProperty( table, kSCSIPropertyDeviceTypeID ) &&
2000 compareProperty( table, kSCSIPropertyRemovableMedia ) &&
2001 compareProperty( table, kSCSIPropertyVendorName ) &&
2002 compareProperty( table, kSCSIPropertyProductName ) &&
2003 compareProperty( table, kSCSIPropertyProductRevision );
2004
2005 if ( match == true )
2006 {
2007 match = super::matchPropertyTable(table);
2008 }
2009
2010 return match;
2011 }
2012
2013
2014 /*
2015 *
2016 *
2017 *
2018 */
2019 IOService *IOSCSIParallelDevice::matchLocation(IOService * client)
2020 {
2021 return this;
2022 }
2023
2024
2025 /*
2026 *
2027 *
2028 *
2029 */
2030 void IOSCSIParallelDevice::stripBlanks( char *d, char *s, UInt32 l )
2031 {
2032 char *p, c;
2033
2034 for ( p = d, c = *s; l && c ; l--)
2035 {
2036 c = (*d++ = *s++);
2037 if ( c != ' ' )
2038 {
2039 p = d;
2040 }
2041 }
2042 *p = 0;
2043 }
2044
2045 /*
2046 *
2047 *
2048 *
2049 */
2050 IOSCSICommand *IOSCSIParallelDevice::allocCommand( IOSCSIDevice *, UInt32 clientDataSize )
2051 {
2052
2053 return (IOSCSICommand *) allocCommand( kIOSCSIParallelDevice, clientDataSize );
2054 }
2055
2056 IOSCSIParallelCommand *IOSCSIParallelDevice::allocCommand( IOSCSIParallelDevice *, UInt32 clientDataSize )
2057 {
2058 IOSCSIParallelCommand *cmd;
2059
2060 if ( (cmd = controller->allocCommand( clientDataSize )) )
2061 {
2062 cmd->device = this;
2063 }
2064 return cmd;
2065 }
2066
2067 IOCDBCommand *IOSCSIParallelDevice::allocCommand( IOCDBDevice *, UInt32 clientDataSize )
2068 {
2069 return (IOCDBCommand *) allocCommand( kIOSCSIDevice, clientDataSize );
2070 }
2071
2072
2073 /*
2074 *
2075 *
2076 */
2077 IOWorkLoop *IOSCSIParallelDevice::getWorkLoop() const
2078 {
2079 return controller->workLoop;
2080 }
2081
2082
2083 /*
2084 *
2085 *
2086 *
2087 */
2088 bool IOSCSIParallelDevice::open( IOService *forClient, IOOptionBits options, void *arg )
2089 {
2090 if ( client != 0 ) return false;
2091
2092 client = forClient;
2093
2094 return super::open( forClient, options, arg );
2095 }
2096
2097 /*
2098 *
2099 *
2100 *
2101 */
2102 void IOSCSIParallelDevice::close( IOService *forClient, IOOptionBits options )
2103 {
2104 client = 0;
2105
2106 return super::close( forClient, options );
2107 }
2108
2109 /*
2110 *
2111 *
2112 *
2113 */
2114 IOReturn IOSCSIParallelDevice::message( UInt32 forMsg, IOService *forProvider, void *forArg )
2115 {
2116 IOReturn rc = kIOReturnSuccess;
2117 SCSIClientMessage clientMsg;
2118
2119 clientMsg = (SCSIClientMessage) forMsg;
2120
2121 // IOLog( "IOSCSIParallelDevice::message() - clientMsg = %08x\n\r", clientMsg );
2122
2123 switch( clientMsg )
2124 {
2125 case kSCSIClientMsgBusReset:
2126 holdQueue( kQTypeNormalQ );
2127 break;
2128 case kSCSIClientMsgBusReset | kSCSIClientMsgDone:
2129 releaseQueue( kQTypeNormalQ );
2130 break;
2131 default:
2132 rc = super::message( clientMsg, forProvider, forArg );
2133 }
2134
2135 return rc;
2136 }
2137
2138 /*
2139 *
2140 *
2141 *
2142 */
2143 void IOSCSIParallelDevice::free()
2144 {
2145 if ( deviceGate != 0 )
2146 {
2147 controller->workLoop->removeEventSource( deviceGate );
2148 deviceGate->release();
2149 }
2150
2151 if ( reqSenseCmd != 0 ) reqSenseCmd->release();
2152 if ( abortCmd != 0 ) abortCmd->release();
2153 if ( cancelCmd != 0 ) cancelCmd->release();
2154 if ( probeCmd != 0 ) probeCmd->release();
2155
2156 if ( tagArray != 0 ) IOFree( tagArray, controller->tagArraySize );
2157 if ( inquiryData != 0 ) IOFree( inquiryData, inquiryDataSize );
2158 if ( devicePrivateData != 0 ) IOFreeContiguous( devicePrivateData, controller->controllerInfo.lunPrivateDataSize );
2159 if ( clientSem != 0 ) IORWLockFree( clientSem );
2160
2161 super::free();
2162 }
2163
2164