2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 #include <IOKit/IOLib.h>
24 #include <IOKit/IOReturn.h>
25 #include <IOKit/scsi/IOSCSIDeviceInterface.h>
26 #include <IOKit/scsi/scsi-device/SCSIDevice.h>
27 #include <IOKit/storage/scsi/IOBasicSCSI.h>
29 #define super IOService
30 OSDefineMetaClass(IOBasicSCSI
,IOService
)
31 OSDefineAbstractStructors(IOBasicSCSI
,IOService
)
33 void IOBasicSCSI_gc_glue(void *object
,void *param
);
35 /* Allocate a new context struct. A return of NULL means we couldn't
36 * allocate either the context itself or one of its members.
38 struct IOBasicSCSI::context
*
39 IOBasicSCSI::allocateContext(void)
43 //xxx IOLog("allocateContext entered\n");
45 /* First, the context structure itself. */
47 cx
= IONew(struct context
,1);
52 bzero(cx
,sizeof(struct context
));
54 /* Allocate all the structs and objects we need. If any allocation
55 * fails, we can simply call deleteContext() to free anything
59 cx
->scsireq
= _provider
->allocCommand(kIOSCSIDevice
, 0);
60 if (cx
->scsireq
== NULL
) {
66 /* Preset the completion parameters, which are the same for
67 * all SCSI requests we issue. Only the target function changes.
70 cx
->senseData
= (SCSISenseData
*)IOMalloc(256);
71 if (cx
-> senseData
== NULL
) {
76 bzero(cx
->senseData
, 256 );
78 cx
->senseDataDesc
= IOMemoryDescriptor::withAddress(cx
->senseData
,
83 cx
->sync
= IOSyncer::create(false);
84 if (cx
->sync
== NULL
) {
89 cx
->retryInProgress
= false;
91 /* We defer allocation of the Memory Descriptor till later;
92 * it will be allocated where it's needed.
95 // IOLog("allocateContext returning cx = %08x\n",(unsigned int)cx);
101 IOBasicSCSI::allocateInquiryBuffer(UInt8
**buf
,UInt32 size
)
103 *buf
= (UInt8
*)IOMalloc(size
);
105 return(kIOReturnNoMemory
);
110 return(kIOReturnSuccess
);
114 IOBasicSCSI::allocateTempBuffer(UInt8
**buf
,UInt32 size
)
116 *buf
= (UInt8
*)IOMalloc(size
);
118 return(kIOReturnNoMemory
);
123 return(kIOReturnSuccess
);
127 IOBasicSCSI::allocateReadCapacityBuffer(UInt8
**buf
,UInt8 size
)
129 *buf
= (UInt8
*)IOMalloc(size
);
131 return(kIOReturnNoMemory
);
136 return(kIOReturnSuccess
);
140 IOBasicSCSI::createReadCdb(UInt8
*cdb
,UInt32
*cdbLength
,
141 UInt32 block
,UInt32 nblks
,
142 UInt32
*maxAutoSenseLength
,
143 UInt32
*timeoutSeconds
)
147 c
= (struct IORWcdb
*)cdb
;
149 c
->opcode
= SOP_READ10
;
152 c
->lba_3
= block
>> 24;
153 c
->lba_2
= block
>> 16;
154 c
->lba_1
= block
>> 8;
155 c
->lba_0
= block
& 0xff;
159 c
->count_msb
= nblks
>> 8;
160 c
->count_lsb
= nblks
& 0xff;
165 *maxAutoSenseLength
= 8; /* do the sense */
166 *timeoutSeconds
= 60;
171 IOBasicSCSI::createWriteCdb(UInt8
*cdb
,UInt32
*cdbLength
,
172 UInt32 block
,UInt32 nblks
,
173 UInt32
*maxAutoSenseLength
,
174 UInt32
*timeoutSeconds
)
178 c
= (struct IORWcdb
*)cdb
;
180 c
->opcode
= SOP_WRITE10
;
183 c
->lba_3
= block
>> 24;
184 c
->lba_2
= block
>> 16;
185 c
->lba_1
= block
>> 8;
186 c
->lba_0
= block
& 0xff;
190 c
->count_msb
= nblks
>> 8;
191 c
->count_lsb
= nblks
& 0xff;
196 *maxAutoSenseLength
= sizeof( SCSISenseData
); /* do the sense */
197 *timeoutSeconds
= 60;
202 IOBasicSCSI::deleteContext(struct context
*cx
)
204 // IOLog("deleteContext %08x\n",(unsigned int)cx);
207 cx
->scsireq
->release();
210 // if (cx->scsiresult) {
211 // IODelete(cx->scsiresult,struct IOSCSIResult,1);
216 IOFree( cx
->senseData
, 256 );
219 if ( cx
->senseDataDesc
)
221 cx
->senseDataDesc
->release();
225 cx
->memory
->release();
232 IODelete(cx
,struct context
,1);
236 IOBasicSCSI::deleteInquiryBuffer(UInt8
*buf
,UInt32 size
)
238 IOFree((void *)buf
,size
);
242 IOBasicSCSI::deleteTempBuffer(UInt8
*buf
,UInt32 len
)
244 IOFree((void *)buf
,len
);
248 IOBasicSCSI::deleteReadCapacityBuffer(UInt8
*buf
,UInt32 len
)
250 IOFree((void *)buf
,len
);
254 IOBasicSCSI::doInquiry(UInt8
*inqBuf
,UInt32 maxLen
,UInt32
*actualLen
)
256 _provider
->getInquiryData( inqBuf
, maxLen
, actualLen
);
257 return kIOReturnSuccess
;
261 IOBasicSCSI::doReadCapacity(UInt64
*blockSize
,UInt64
*maxBlock
)
264 struct IOReadCapcdb
*c
;
270 cx
= allocateContext();
272 return(kIOReturnNoMemory
);
277 bzero( &scsiCDB
, sizeof(SCSICDBInfo
) );
279 c
= (struct IOReadCapcdb
*)&scsiCDB
.cdb
;
280 c
->opcode
= SOP_READCAP
;
291 scsiCDB
.cdbLength
= 10;
293 req
->setCDB( &scsiCDB
);
294 req
->setPointers( cx
->senseDataDesc
, sizeof(SCSISenseData
), false, true );
296 req
->setTimeout( 30000 );
301 result
= allocateReadCapacityBuffer(&buf
,kReadCapSize
);
303 if (result
== kIOReturnSuccess
) {
305 cx
->memory
= IOMemoryDescriptor::withAddress((void *)buf
,
309 req
->setPointers( cx
->memory
, kReadCapSize
, false );
311 /* We force the drive to be completely powered-up, including the mechanical
312 * components, because some drives (e.g. CDs) access the media.
315 queueCommand(cx
,kSync
,getReadCapacityPowerState()); /* queue the operation, sleep awaiting power */
317 result
= simpleSynchIO(cx
);
319 if (result
== kIOReturnSuccess
) {
321 *blockSize
= (buf
[4] << 24) | /* endian-neutral */
326 *maxBlock
= (buf
[0] << 24) | /* endian-neutral */
332 deleteReadCapacityBuffer(buf
,kReadCapSize
);
341 IOBasicSCSI::free(void)
344 deleteInquiryBuffer(_inqBuf
,_inqBufSize
);
349 if (_powerQueue
.lock
) {
350 IOLockFree(_powerQueue
.lock
);
354 if (_busResetContext
) {
355 deleteContext(_busResetContext
);
357 if (_unitAttentionContext
) {
358 deleteContext(_unitAttentionContext
);
364 /* The Callback (C) entry from the SCSI provider. We just glue
369 IOBasicSCSI_gc_glue(void *object
,void *param
)
372 struct IOBasicSCSI::context
*cx
;
374 self
= (IOBasicSCSI
*)object
;
375 cx
= (struct IOBasicSCSI::context
*)param
;
376 self
->genericCompletion(cx
); /* do it in C++ */
380 IOBasicSCSI::setupBusResetRecovery(void)
382 IOLog("%s[IOBasicSCSI]: SCSI bus reset occurred; begin recovery.\n",getName());
384 _busResetContext
->step
= 1;
385 _busResetRecoveryInProgress
= true;
386 _provider
->holdQueue(kQTypeNormalQ
);
387 // _provider->flushQueue(kQTypeNormalQ,kIOReturnAborted);
391 IOBasicSCSI::beginBusResetRecovery(void)
393 /* In this method, we issue the first command necessary to recover
394 * from the Bus Reset condition. Its completion will call
395 * busResetRecoveryCommandComplete, which is respnsible for starting
396 * the next command, until all have been executed.
398 * The default implementation of this method does nothing, except
399 * to call finishBusResetRecovery immediately.
402 // IOLog("%s[IOBasicSCSI]: beginBusReset\n",getName());
403 finishBusResetRecovery();
407 IOBasicSCSI::busResetRecoveryCommandComplete(struct IOBasicSCSI::context
*cx
)
409 /* We are entered for each command completion during bus reset recovery.
411 * Do whatever we have to upon completion of one of our commands.
413 * Typically we would increment "step" then start another asynchronous
414 * command. When we have finished running off the whole set of required
415 * operations then we call finishBusResetRecovery.
417 * The default implementation does nothing.
422 IOBasicSCSI::finishBusResetRecovery(void)
424 /* Release the IO queue so that any pending commands can start. */
426 IOLog("%s[IOBasicSCSI]: SCSI bus reset recovery complete.\n",getName());
427 _provider
->releaseQueue(kQTypeNormalQ
);
428 _busResetRecoveryInProgress
= false;
432 IOBasicSCSI::unitAttentionDetected(struct IOBasicSCSI::context
*cx
)
434 SCSIResults scsiResults
;
436 /* We're not currently handling a Unit Attention: see if
437 * we just got a one to handle. Note that we do NOT have to
438 * detect Bus Reset here, because we receive notification of
439 * that event asynchronously via the message() method.
442 cx
->scsireq
->getResults(&scsiResults
);
444 /* A special case is Unit Attention, which can happen at any time. We begin
445 * the Unit Attention recovery procedure which issues multiple asynch commands
446 * to restore the device condition. After the recovery procedure completes,
447 * it causes a retry of the original command.
450 if (scsiResults
.requestSenseDone
== true) { /* an error occurred */
452 // IOLog("%s[IOBasicSCSI]::unitAttentionDetected: sense code %02x\n",
453 // getName(),cx->scsiresult->scsiSense[02]);
455 if ((cx
->senseData
->senseKey
& 0x0f) == kUnitAttention
) { /* it's a UA */
457 // IOLog("%s[IOBasicSCSI]::unitAttentionDetected: detected UnitAttention\n",
463 } /* no sense data, therefore NOT a Unit Attention */
469 IOBasicSCSI::setupUnitAttentionRecovery(struct IOBasicSCSI::context
*cx
)
471 if (!_unitAttentionRecoveryInProgress
) {
473 /* Save original IO context and set step. */
475 _unitAttentionContext
->originalIOContext
= cx
;
477 _unitAttentionContext
->step
= 1;
479 _unitAttentionRecoveryInProgress
= true;
481 beginUnitAttentionRecovery();
486 IOBasicSCSI::beginUnitAttentionRecovery(void)
488 /* In this method, we issue the first command necessary to recover
489 * from the Unit Attention condition. Its completion will call
490 * unitAttentionCommandComplete, which is respnsible for starting
491 * the next command, until all have been executed.
493 * The default implementation of this method does nothing, except
494 * to call finishUnitAttentionRecovery immediately.
497 finishUnitAttentionRecovery();
501 IOBasicSCSI::unitAttentionRecoveryCommandComplete(struct IOBasicSCSI::context
*cx
)
503 /* We are entered for each command completion during Unit Attention recovery.
505 * Do whatever we have to upon completion of one of our commands.
507 * Typically we would increment "step" then start another asynchronous
508 * command. When we have finished running off the whole set of required
509 * operations then we call finishUnitAttentionRecovery.
511 * The default implementation does nothing.
516 IOBasicSCSI::finishUnitAttentionRecovery(void)
518 /* When we're done, we reissue the command that caught the Unit Attention. */
520 _unitAttentionRecoveryInProgress
= false;
521 _unitAttentionContext
->originalIOContext
->scsireq
->execute();
525 IOBasicSCSI::automaticRetry(struct IOBasicSCSI::context
*cx
)
527 SCSIResults scsiResults
;
529 if (unitAttentionDetected(cx
)) { /* do an automatic retry for Unit Attention */
530 setupUnitAttentionRecovery(cx
);
534 cx
->scsireq
->getResults(&scsiResults
);
536 if (scsiResults
.returnCode
!= kIOReturnSuccess
&&
537 scsiResults
.returnCode
!= kIOReturnError
) {
539 IOLog("%s[IOBasicSCSI]: retcode = %08lx / %s\n",
540 getName(),scsiResults.returnCode,stringFromReturn(scsiResults.returnCode));
544 if (scsiResults
.returnCode
== kIOReturnAborted
||
545 scsiResults
.returnCode
== kIOReturnTimeout
) { /* must be a Bus Reset abort */
546 if (!cx
->retryInProgress
) { /* start a retry if not already doing one */
547 cx
->retryInProgress
= true;
548 cx
->retryCount
= kMaxRetries
;
550 if (cx
->retryCount
> 0) { /* OK to continue retrying */
551 IOLog("%s[IOBasicSCSI]: AutoRetry cx @ %08lx, cmd @ %08lx; %ld retries to go.\n",
552 getName(),(unsigned long)cx
,(unsigned long)cx
->scsireq
,cx
->retryCount
);
554 cx
->scsireq
->execute();
557 cx
->retryInProgress
= false;
562 return(customAutomaticRetry(cx
));
566 IOBasicSCSI::customAutomaticRetry(struct IOBasicSCSI::context
*cx
)
568 return(false); /* the default does nothing special */
572 IOBasicSCSI::genericCompletion(struct IOBasicSCSI::context
*cx
)
575 /* We dispatch the completion depending on our state. */
577 // IOLog("%s[IOBasicSCSI]::genericCompletion: dispatching, state = %s\n",
578 // getName(),stringFromState(cx->state));
582 case kSimpleSynchIO
:
583 if (!automaticRetry(cx
)) {
584 cx
->sync
->signal(kIOReturnSuccess
,false); /* Just wake up the waiting thread: */
588 case kAsyncReadWrite
: /* normal r/w completion */
589 if (!automaticRetry(cx
)) {
595 case kHandlingRecoveryAfterBusReset
: /* still handling recovery after reset */
596 if (!automaticRetry(cx
)) {
597 busResetRecoveryCommandComplete(cx
);
599 break; /* just wait for next completion */
601 case kHandlingUnitAttention
: /* still handling UA */
602 unitAttentionRecoveryCommandComplete(cx
);
603 break; /* just wait for next completion */
605 case kNone
: /* undefined */
606 case kMaxStateValue
:
607 case kAwaitingPower
:
615 IOBasicSCSI::getAdditionalDeviceInfoString(void)
621 IOBasicSCSI::getBlockSize(void)
627 IOBasicSCSI::getProductString(void)
633 IOBasicSCSI::getRevisionString(void)
639 IOBasicSCSI::getVendorString(void)
645 IOBasicSCSI::init(OSDictionary
* properties
)
655 _readCapDone
= false;
661 _powerQueue
.head
= NULL
;
662 _powerQueue
.tail
= NULL
;
663 _powerQueue
.lock
= IOLockAlloc();
664 if (_powerQueue
.lock
== NULL
) {
669 return(super::init(properties
));
673 IOBasicSCSI::message(UInt32 type
,IOService
* provider
,void * argument
)
675 // IOLog("%s[IOBasicSCSI]: message: type = %lx\n",getName(),type);
677 case kSCSIClientMsgBusReset
: /* Bus Reset has begun */
678 if (!_busResetRecoveryInProgress
) { /* try to avoid reset-within-reset recovery */
679 setupBusResetRecovery(); /* indicate recovery will be in progress */
681 break; /* now wait till reset is done */
683 case (kSCSIClientMsgBusReset
| kSCSIClientMsgDone
) : /* Bus Reset is finished */
684 beginBusResetRecovery(); /* now start the actual recovery process */
688 return(super::message(type
,provider
,argument
)); /* not one of ours */
691 return(kIOReturnSuccess
);
695 IOBasicSCSI::probe(IOService
* provider
,SInt32
* score
)
700 if (!super::probe(provider
,score
)) {
704 _provider
= (IOSCSIDevice
*)provider
;
706 /* Do an inquiry to get the device type. The inquiry buffer will
707 * be deleted by free().
710 _inqBufSize
= kMaxInqSize
;
711 result
= allocateInquiryBuffer(&_inqBuf
,_inqBufSize
);
712 if (result
!= kIOReturnSuccess
) {
716 result
= doInquiry(_inqBuf
,_inqBufSize
,&_inqLen
);
717 if (result
!= kIOReturnSuccess
) {
722 // xxx NEVER match for ID=0, the boot disk. This lets us
723 // test this driver on other disk drives.
725 if (_provider
->getTarget() == 0) {
726 IOLog("**%s[IOBasicSCSI]:probe; ignoring SCSI ID %d\n",
727 getName(),(int)_provider
->getTarget());
732 // Fetch SCSI device information from the nub.
734 string
= OSDynamicCast(OSString
,
735 _provider
->getProperty(kSCSIPropertyVendorName
));
737 strncpy(_vendor
, string
->getCStringNoCopy(), 8);
741 string
= OSDynamicCast(OSString
,
742 _provider
->getProperty(kSCSIPropertyProductName
));
744 strncpy(_product
, string
->getCStringNoCopy(), 16);
748 string
= OSDynamicCast(OSString
,
749 _provider
->getProperty(kSCSIPropertyProductRevision
));
751 strncpy(_rev
, string
->getCStringNoCopy(), 4);
755 if (deviceTypeMatches(_inqBuf
,_inqLen
,score
)) {
758 IOLog("**%s[IOBasicSCSI]::probe; accepting %s, %s, %s, %s; SCSI ID %d\n",
759 getName(),getVendorString(),getProductString(),getRevisionString(),
760 getAdditionalDeviceInfoString(),
761 (int)_provider->getTarget());
771 IOBasicSCSI::dequeueCommands(void)
781 /* Dequeue and execute all requests for which we have the proper power level. */
785 if (pm_vars
->myCurrentState
!= cx
->desiredPower
) {
788 q
->head
= cx
->next
; /* remove command from the queue */
789 if (q
->head
== NULL
) {
795 /* If the queued request was synchronous, all we have to do is wake it up. */
798 cx
->sync
->signal(kIOReturnSuccess
, false); /* Just wake up the waiting thread: */
800 } else { /* it's async; fire it off! */
801 result
= standardAsyncReadWriteExecute(cx
); /* execute the async IO */
802 if (result
!= kIOReturnSuccess
) { /* provider didn't accept it! */
803 RWCompletion(cx
); /* force a completion */
808 IOLockUnlock(q
->lock
);
813 IOBasicSCSI::queueCommand(struct context
*cx
,bool isSync
,UInt32 desiredPower
)
815 #ifndef DISKPM //for now, just return immediately without queueing
816 /* If we're ifdefed out, we have to start async requests. Sync requests
817 * will just return immediately without any delay for power.
819 if (isSync
== kAsync
) {
820 (void)standardAsyncReadWriteExecute(cx
); /* execute the async IO */
825 /* First, we enqueue the request to ensure sequencing with respect
826 * to other commands that may already be in the queue.
832 cx
->state
= kAwaitingPower
;
836 if (q
->head
== NULL
) { /* empty queue */
840 } else { /* not empty; add after tail */
845 /* If the command is synchronous, start by assuming we'll have to sleep
846 * awaiting power (and subsequent dequeuing). If, however, power is already
847 * right, then dequeuCommands will unlock the lock and we will continue,
848 * returning inline to the call site, exactly as if we were awakened.
850 * An async request will call dequeueCommands and always return immediately.
853 IOLockUnlock(q
->lock
);
855 /* Now we try to dequeue pending commands if the power's right. */
859 /* If we're synchronous, we'll wait here till dequeued. If we were
860 * dequeued above (and unlocked), then we'll return to allow the
861 * caller to continue with the command execution.
865 cx
->sync
->wait(false); /* waits here till awakened */
871 IOBasicSCSI::reportBlockSize(UInt64
*blockSize
)
876 result
= kIOReturnSuccess
;
878 if (_readCapDone
== false) {
879 result
= doReadCapacity(&_blockSize
,&_maxBlock
);
883 if (result
== kIOReturnSuccess
) {
884 *blockSize
= _blockSize
;
891 IOBasicSCSI::reportEjectability(bool *isEjectable
)
893 *isEjectable
= true; /* default: if it's removable, it's ejectable */
894 return(kIOReturnSuccess
);
898 IOBasicSCSI::reportLockability(bool *isLockable
)
900 *isLockable
= true; /* default: if it's removable, it's lockable */
901 return(kIOReturnSuccess
);
905 IOBasicSCSI::reportMaxReadTransfer (UInt64 blocksize
,UInt64
*max
)
907 *max
= blocksize
* 65536; /* max blocks in a SCSI transfer */
908 return(kIOReturnSuccess
);
912 IOBasicSCSI::reportMaxValidBlock(UInt64
*maxBlock
)
917 result
= kIOReturnSuccess
;
919 if (_readCapDone
== false) {
920 result
= doReadCapacity(&_blockSize
,&_maxBlock
);
924 if (result
== kIOReturnSuccess
) {
925 *maxBlock
= _maxBlock
;
931 IOBasicSCSI::reportMaxWriteTransfer(UInt64 blocksize
,UInt64
*max
)
933 *max
= blocksize
* 65536; /* max blocks in a SCSI transfer */
934 return(kIOReturnSuccess
);
938 IOBasicSCSI::reportPollRequirements(bool *pollRequired
,bool *pollIsExpensive
)
940 *pollIsExpensive
= false;
941 *pollRequired
= _removable
; /* for now, all removables need polling */
942 return(kIOReturnSuccess
);
946 IOBasicSCSI::reportRemovability(bool *isRemovable
)
948 if (_inqLen
> 0) { /* inquiry byte exists to check */
949 if (_inqBuf
[1] & 0x80) { /* it's removable */
952 } else { /* it's not removable */
953 *isRemovable
= false;
956 } else { /* no byte? call it nonremovable */
957 *isRemovable
= false;
960 return(kIOReturnSuccess
);
963 /* Issue a Mode Sense to get the Mode Parameter Header but no pages.
964 * Since we're only interested in the Mode Parameter Header, we just
965 * issue a standard SCSI-1 6-byte command, nothing fancy.
968 IOBasicSCSI::reportWriteProtection(bool *writeProtected
)
971 struct IOModeSensecdb
*c
;
974 SCSIResults scsiResults
;
978 cx
= allocateContext();
980 return(kIOReturnNoMemory
);
985 bzero( &scsiCDB
, sizeof(SCSICDBInfo
) );
987 c
= (struct IOModeSensecdb
*)&scsiCDB
.cdb
;
988 c
->opcode
= SOP_MODESENSE
;
990 c
->pagecode
= 0 | 0x01; /* get current settings; any page will work */
992 c
->len
= kModeSenseSize
;
995 scsiCDB
.cdbLength
= 6;
997 req
->setCDB( &scsiCDB
);
998 req
->setPointers( cx
->senseDataDesc
, sizeof(SCSISenseData
), false, true );
1000 req
->setTimeout( 30000 );
1002 result
= allocateTempBuffer(&buf
,kModeSenseSize
);
1004 if (result
== kIOReturnSuccess
) {
1006 cx
->memory
= IOMemoryDescriptor::withAddress((void *)buf
,
1010 req
->setPointers( cx
->memory
, kModeSenseSize
, false );
1012 queueCommand(cx
,kSync
,getReportWriteProtectionPowerState()); /* queue the op, sleep awaiting power */
1014 result
= simpleSynchIO(cx
);
1016 if (result
== kIOReturnUnderrun
) {
1017 cx
->scsireq
->getResults( &scsiResults
);
1018 if (scsiResults
.bytesTransferred
>= 4)
1019 result
= kIOReturnSuccess
;
1022 if (result
== kIOReturnSuccess
) {
1023 if (buf
[2] & 0x80) {
1024 *writeProtected
= true;
1026 *writeProtected
= false;
1030 deleteTempBuffer(buf
,kModeSenseSize
);
1038 /* Issue a simple, asynchronous SCSI operation. The caller's supplied context
1039 * contains a SCSI command and Memory Descriptor. The caller is responsible
1040 * for deleting the context.
1044 IOBasicSCSI::simpleAsynchIO(struct IOBasicSCSI::context
*cx
)
1049 if (cx
== NULL
) { /* safety check */
1050 return(kIOReturnNoMemory
);
1053 /* Set completion to return to genericCompletion: */
1056 req
->setCallback( (void *)this, (CallbackFn
)IOBasicSCSI_gc_glue
, (void *)cx
);
1058 cx
->state
= kSimpleSynchIO
;
1060 /* Start the scsi request: */
1062 result
= req
->execute();
1064 if (result
== true ) {
1065 result
= req
->getResults((SCSIResults
*) 0);
1071 /* Issue a simple, synchronous SCSI operation. The caller's supplied context
1072 * contains a SCSI command and Memory Descriptor. The caller is responsible
1073 * for deleting the context.
1077 IOBasicSCSI::simpleSynchIO(struct context
*cx
)
1082 if (cx
== NULL
) { /* safety check */
1083 return(kIOReturnNoMemory
);
1086 /* Set completion to return to genericCompletion: */
1089 req
->setCallback( (void *)this, (CallbackFn
)IOBasicSCSI_gc_glue
, (void *)cx
);
1091 cx
->state
= kSimpleSynchIO
;
1094 IOLog("%s[IOBasicSCSI]::simpleSynchIO; issuing SCSI cmd %02x\n",
1095 getName(),req->cdb.byte[0]);
1097 /* Start the scsi request: */
1099 //IOLog("IOBasicSCSI::simpleSynchIO, lock initted, calling SCSI\n");
1101 result
= req
->execute();
1103 if (result
== true ) {
1105 // IOLog("IOBasicSCSI::simpleSynchIO, SCSI req accepted\n");
1107 /* Wait for it to complete by attempting to acquire a read-lock, which
1108 * will block until the write-lock is released by the completion routine.
1111 cx
->sync
->wait(false); /* waits here till unlocked at completion */
1115 result
= req
->getResults((SCSIResults
*) 0);
1118 if ((result != kIOReturnSuccess) ) {
1119 IOLog("%s[IOBasicSCSI]::simpleSynchIO; err '%s' from completed req\n",
1120 getName(),stringFromReturn(result));
1125 IOLog("%s[IOBasicSCSI]:simpleSynchIO; err '%s' queueing SCSI req\n",
1126 getName(),stringFromReturn(result));
1130 // IOLog("IOBasicSCSI: completed; result '%s'\n",stringFromReturn(result));
1136 IOBasicSCSI::standardAsyncReadWrite(IOMemoryDescriptor
*buffer
,
1137 UInt32 block
,UInt32 nblks
,
1138 IOStorageCompletion completion
)
1142 SCSICDBInfo scsiCDB
;
1143 UInt32 reqSenseLength
;
1144 UInt32 timeoutSeconds
;
1148 cx
= allocateContext();
1151 return(kIOReturnNoMemory
);
1154 buffer
->retain(); /* bump the retain count */
1156 cx
->memory
= buffer
;
1157 if (buffer
->getDirection() == kIODirectionOut
) {
1164 IOLog("%s[IOBasicSCSI]::standardAsyncReadWrite; (%s) blk %ld nblks %ld\n",
1165 getName(),(isWrite ? "write" : "read"),block,nblks);
1169 /* Set completion to return to rwCompletion: */
1170 cx
->completion
= completion
;
1172 bzero( &scsiCDB
, sizeof(scsiCDB
) );
1174 req
->setPointers( buffer
, nblks
* getBlockSize(), isWrite
);
1176 req
->setCallback( this, IOBasicSCSI_gc_glue
, cx
);
1178 cx
->state
= kAsyncReadWrite
;
1180 cdb
= (UInt8
*) &scsiCDB
.cdb
;
1182 /* Allow a subclass to override the creation of the cdb and specify
1183 * other parameters for the operation.
1187 scsiCDB
.cdbFlags
|= createWriteCdb(cdb
,&scsiCDB
.cdbLength
,
1194 scsiCDB
.cdbFlags
|= createReadCdb(cdb
,&scsiCDB
.cdbLength
,
1200 req
->setCDB( &scsiCDB
);
1201 req
->setPointers( cx
->senseDataDesc
, reqSenseLength
, false, true );
1202 req
->setTimeout( timeoutSeconds
* 1000 );
1204 /* Queue the request awaiting power and return. When power comes up,
1205 * the request will be passed to standardAsyncReadWriteExecute.
1207 queueCommand(cx
,kAsync
,getReadWritePowerState()); /* queue and possibly wait for power */
1209 return(kIOReturnSuccess
);
1213 IOBasicSCSI::standardAsyncReadWriteExecute(struct context
*cx
)
1215 return(cx
->scsireq
->execute());
1219 IOBasicSCSI::standardSyncReadWrite(IOMemoryDescriptor
*buffer
,UInt32 block
,UInt32 nblks
)
1223 SCSICDBInfo scsiCDB
;
1224 UInt32 reqSenseLength
;
1225 UInt32 reqTimeoutSeconds
;
1230 cx
= allocateContext();
1233 return(kIOReturnNoMemory
);
1236 cx
->memory
= buffer
;
1237 buffer
->retain(); /* bump the retain count */
1239 if (buffer
->getDirection() == kIODirectionOut
) {
1246 IOLog("%s[IOBasicSCSI]::standardSyncReadWrite; (%s) blk %ld nblks %ld\n",
1247 getName(),(isWrite ? "write" : "read"),block,nblks);
1250 bzero(&scsiCDB
,sizeof(scsiCDB
));
1253 req
->setPointers(buffer
,(nblks
* getBlockSize()),isWrite
);
1255 cdb
= (UInt8
*)&scsiCDB
.cdb
;
1257 /* Allow a subclass to override the creation of the cdb and specify
1258 * other parameters for the operation.
1262 scsiCDB
.cdbFlags
|= createWriteCdb(cdb
,&scsiCDB
.cdbLength
,
1265 &reqTimeoutSeconds
);
1269 scsiCDB
.cdbFlags
|= createReadCdb(cdb
,&scsiCDB
.cdbLength
,
1272 &reqTimeoutSeconds
);
1276 req
->setCDB(&scsiCDB
);
1277 req
->setPointers(cx
->senseDataDesc
,reqSenseLength
,false,true);
1278 req
->setTimeout(reqTimeoutSeconds
* 1000);
1280 queueCommand(cx
,kSync
,getReadWritePowerState()); /* queue the operation, sleep awaiting power */
1282 result
= simpleSynchIO(cx
); /* issue a simple command */
1289 IOBasicSCSI::start(IOService
*provider
)
1293 _busResetContext
= allocateContext();
1294 if (_busResetContext
== NULL
) {
1297 _busResetContext
->state
= kHandlingRecoveryAfterBusReset
;
1298 _busResetRecoveryInProgress
= false;
1300 _unitAttentionContext
= allocateContext();
1301 if (_unitAttentionContext
== NULL
) {
1304 _unitAttentionContext
->state
= kHandlingUnitAttention
;
1305 _unitAttentionRecoveryInProgress
= false;
1307 result
= provider
->open(this,0,0); /* set up to receive message() notifications */
1308 if (result
!= true) {
1309 IOLog("open result is false\n");
1316 IOBasicSCSI::stringFromState(stateValue state
)
1318 static char *stateNames
[] = {
1322 "kHandlingUnitAttention",
1323 "khandlingRecoveryAfterBusReset"
1326 if (state
< 0 || state
> kMaxValidState
) {
1330 return(stateNames
[state
]);