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