Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
ATA Error Detection.c
/* |
File: ATA Error Detection.c |
Description:Sample code demonstrating how to test for certain kinds of ATA hard |
drives which would cause problems for some PowerBooks in SCSI disk mode. |
Demonstrates using the ATA inquiry command and the fields returned by this |
command to determine information about an ATA drive. Detects an error documented |
in the technote "PowerBook HD Upgrades and SCSI Disk Mode Compatibility". |
Requires: PowerBook with ATA manager (190, 2300, 5300, 1400, 3400, 2400). |
Later PowerBooks are not affected by these bugs, but the test will run. |
Author: by BB based on the ATA Manager Sample by VM, |
Copyright: Copyright: © 1997,1999 by Apple Computer, Inc. |
all rights reserved. |
Disclaimer: You may incorporate this sample code into your applications without |
restriction, though the sample code has been provided "AS IS" and the |
responsibility for its operation is 100% yours. However, what you are |
not permitted to do is to redistribute the source as "DSC Sample Code" |
after having made changes. If you're going to re-distribute the source, |
we require that you make it clear in the source that the code was |
descended from Apple Sample Code, but that you've made changes. |
Change History (most recent first): |
6/23/99 Updated for Metrowerks Codewarrior Pro 2.1(KG) |
*/ |
//----------------------------------------------------------------------- |
#pragma mark Includes |
//--------------------------------------------------------------------------- |
#include <stdio.h> |
#include <stdlib.h> |
#include <ATA.h> |
#ifdef __MWERKS__ |
#include <SIOUX.h> |
#endif |
#include <LowMem.h> |
#include <Traps.h> |
#include <Devices.h> |
//---------------------------------------------------------------------------- |
#pragma mark Defines |
//---------------------------------------------------------------------------- |
// |
// Identifies the bus protocol type. |
// |
enum |
{ |
kDevUnknown = 0, |
kDevATA = 1, |
kDevATAPI = 2, |
kDevPCMCIA = 3 |
}; |
// |
// Identifies the Socket type. |
// |
enum |
{ |
kSocketUnknown = 0, |
kSocketInternal = 1, |
kSocketMediaBay = 2, |
kkSocketPCMCIA = 3 |
}; |
//------------------------------------------------------------------------------------ |
#pragma mark Macros |
//------------------------------------------------------------------------------------ |
#define CLEAR(what) do { \ |
register Ptr _ptr = (Ptr) &what; \ |
register Size _len = sizeof what; \ |
for (; _len > 0; --_len) \ |
*_ptr++ = 0; \ |
} while (0) |
#define RETURN_IF_ERROR(_err_,_str_) if (_err_ != noErr) \ |
{ printf(_str_, _err_); return (_err_); } |
// |
// This is returned by the device in response to an IDENTIFY command (512 bytes). |
// |
typedef struct IdentifyBlock |
{ /* Structure of Identify data */ |
UInt16 Signature; /* Word 00: Constant value */ |
UInt16 NumCyls; /* Word 01: # of cylinders (default mode) */ |
UInt16 RSVD0; /* Word 02: Constant value of 0 */ |
UInt16 NumHds; /* Word 03: # of heads (default mode) */ |
UInt16 TrkBytes; /* Word 04: # of unformatted bytes/track */ |
UInt16 SecBytes; /* Word 05: # of unformatted bytes/sector */ |
UInt16 NumSecs; /* Word 06: # of sectors/track */ |
UInt16 VU0; /* Word 07: Vendor unique */ |
UInt16 VU1; /* Word 08: Vendor unique */ |
UInt16 VU2; /* Word 09: Vendor unique */ |
UInt16 Serial[10]; /* Word 10-19: Serial Number (right-justified) */ |
UInt16 BufType; /* Word 20: Buffer Type */ |
UInt16 BufSize; /* Word 21: Buffer size,512 byte increments */ |
UInt16 NumECC; /* Word 22: # of ECC bytes */ |
/* these next 2 fields are left justified */ |
UInt16 FirmRev[4]; /* Word 23-26:Firmware revision */ |
UInt16 ModelNum[20];/* Word 27-46: Model number */ |
UInt16 MultCmds; /* Word 47: R/W multiple commands not impl = 0 */ |
UInt16 DblXferFlag;/* Word 48: Double transfer flag */ |
UInt16 Capabilities;/* Word 49: LBA, DMA, IORDY support indicator */ |
UInt16 Reserved1; /* Word 50: Reserved */ |
UInt16 PIOTiming; /* Word 51: PIO transfer timing mode */ |
UInt16 DMATiming; /* Word 52: DMA transfer timing mode */ |
UInt16 Extension; /* Word 53: extended info support */ |
UInt16 CurCylinders;/* Word 54: # of current cylinders */ |
UInt16 CurHeads; /* Word 55: # of current heads */ |
UInt16 CurSPT; /* Word 56: # of current sectors per track */ |
UInt16 CurCapacity[2];/* Word 57-58: current capacity in sectors */ |
UInt16 MultSectors;/* Word 59: Multiple sector setting */ |
UInt16 LBACapacity[2];/* Word 60-61: total sectors in LBA mode */ |
UInt16 SWDMA; /* Word 62: single word DMA support */ |
UInt16 MWDMA; /* Word 63: multi word DMA support */ |
UInt16 APIOModes; /* Word 64: Advanced PIO Xfr mode supported */ |
UInt16 MDMATiming; /* Word 65: Minimum Multiword DMA Xfr Cycle */ |
UInt16 RDMATiming; /* Word 66: Recommended Multiword DMA Cycle */ |
UInt16 MPIOTiming; /* Word 67: Min PIO XFR Time W/O Flow Control */ |
UInt16 PIOwRDYTiming;/* Word 68: Min PIO XFR Time with IORDY flow ctrl */ |
UInt16 Reserved[187];/* Word 69-255: Reserved */ |
} IdentifyBlock; |
//------------------------------------------------------------------------------------ |
#pragma mark Prototypes |
//------------------------------------------------------------------------------------ |
Boolean ATAManagerPresent (void); |
Boolean ATAHardwarePresent (void); |
Boolean TrapAvailable (short theTrap); |
void PrintNumVersion (char *label, NumVersion version ); |
OSErr DisplayATAManagerInquiryInfo (void); |
OSErr ScanATABusses (void); |
OSErr DisplayATADriveIdentity (UInt32 deviceID ); |
void DumpRawBuffer ( UInt8 *bufferPtr, int length ); |
char* DrvrRefToName (short refNum); |
Boolean CheckBug1(IdentifyBlock *ibPtr); |
Boolean CheckBug2(IdentifyBlock *ibPtr); |
// --------------------------------------------------------------------------- |
// |
// This is the mixed mode stuff needed to call the ATA manager |
// if you are generating CFM code (i.e. if you are compiling for |
// Power PC). The 'ataManager' call is not a publicly exported |
// symbol in InterfaceLib. |
// |
#if GENERATINGCFM |
pascal SInt16 ataManager(ataPB *pb); |
#define RESULT_OFFSET(type) \ |
((sizeof(type) == 1) ? 3 : ((sizeof(type) == 2) ? 1 : 0)) |
#define TBTrapTableAddress(trapNum) (((trapNum & 0x03FF) << 2) + 0xE00) |
pascal SInt16 ataManager(ataPB *pb) |
{ |
#ifdef applec |
#if sizeof(SInt16) > 4 |
#error "Result types larger than 4 bytes are not supported." |
#endif |
#endif |
long private_result; |
private_result = CallUniversalProc( |
*(UniversalProcPtr*)TBTrapTableAddress(0xAAF1), |
kPascalStackBased |
| RESULT_SIZE(SIZE_CODE(sizeof(SInt16))) |
| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(pb))), |
pb); |
return *(((SInt16*)&private_result) + RESULT_OFFSET(SInt16)); |
} |
#endif |
// --------------------------------------------------------------------------- |
// |
// Display information about the ATA Busses |
// |
OSErr ScanATABusses (void) |
{ |
ataDrvrRegister pb; |
OSErr status; |
// Get first device ID (yes you have to do this once) |
CLEAR(pb); |
pb.ataPBFunctionCode = kATAMgrFindDriverRefnum; |
pb.ataPBVers = kATAPBVers1; |
pb.ataPBDeviceID = (UInt32)0x0000ffff; |
status = ataManager((ataPB*) &pb ); |
// loop through devices |
for (pb.ataPBDeviceID = (UInt32) pb.ataDeviceNextID; |
pb.ataPBDeviceID != 0xff; |
pb.ataPBDeviceID = (UInt32) pb.ataDeviceNextID) |
{ |
status = ataManager((ataPB*) &pb ); |
RETURN_IF_ERROR(status, |
"ATA Find Driver failed with status 0x%04x\n") |
printf("\n-----------------------------------------\n\n"); |
printf("Device %d %#s\n", |
pb.ataPBDeviceID, DrvrRefToName(pb.ataDrvrRefNum) ); |
DisplayATADriveIdentity(pb.ataPBDeviceID); |
}; |
return (status); |
} |
// --------------------------------------------------------------------------- |
void main (void) |
// --------------------------------------------------------------------------- |
{ |
OSErr status; |
#if __MWERKS__ |
SIOUXSettings.asktosaveonclose = false; |
#endif |
printf("Program to detect potential problems with SCSI disk mode\n\n"); |
printf("This program looks at your ATA hard disk inside your PowerBook.\n"); |
printf("It does not alter the disk or any data in any way.\n"); |
printf("See the technote \"PowerBook HD Upgrades and SCSI Disk Mode\n"); |
printf("Compatibility\" for details on the conditions this code tests.\n\n"); |
printf("Listing devices on your ATA bus ... \n\n"); |
// Check for ATA Hardware |
// you should do this before calling the ATAManager, since some |
// early ROMS could indicate an ATA manager without the proper |
// HW, thus causing a crash. |
if (ATAHardwarePresent() == false) |
{ |
printf("ATA Hardware is not present on this system\n"); |
exit(EXIT_FAILURE); |
} |
// Check for ATA Manager |
if (ATAManagerPresent() == false) |
{ |
printf("ATA Manager is not present on this system\n"); |
exit(EXIT_FAILURE); |
} |
// Display ATA Device Info |
status = ScanATABusses(); |
if (status != noErr) |
{ |
printf("Cannot access ATA Manager: 0x%04x\n", (int) status); |
exit(EXIT_FAILURE); |
} |
} |
// --------------------------------------------------------------------------- |
OSErr DisplayATADriveIdentity (UInt32 deviceID) |
// --------------------------------------------------------------------------- |
// |
// Display information about the ATA Identify Info |
// |
{ |
ataIdentify pb; |
ataDevConfiguration pb1; |
IdentifyBlock buffer; |
OSErr status; |
Boolean bugsExist; |
UInt32 capacity; |
// Get Driver Configuration |
CLEAR(pb1); |
pb1.ataPBFunctionCode = kATAMgrGetDrvConfiguration; |
pb1.ataPBVers = kATAPBVers2; |
pb1.ataPBDeviceID = deviceID; |
status = ataManager((ataPB*) &pb1 ); |
RETURN_IF_ERROR(status, |
"ATA GetDrvConfiguration failed with status 0x%04x\n") |
// Setup Identify block; |
CLEAR(pb); |
pb.ataPBFunctionCode = kATAMgrDriveIdentify; |
pb.ataPBVers = kATAPBVers1; |
pb.ataPBDeviceID = deviceID; |
pb.ataPBFlags = mATAFlagIORead + mATAFlagByteSwap ; |
if (pb1.ataDeviceType == kDevATAPI) |
pb.ataPBFlags += mATAFlagProtocol1; |
pb.ataPBTimeOut = 100; |
pb.ataPBBuffer = (void*) &buffer; |
status = ataManager((ataPB*) &pb ); |
if (noErr == status) |
{ |
switch(pb1.ataDeviceType){ |
case kDevATA: |
case kDevATAPI: |
capacity = (buffer.CurCapacity[1] << 16) | |
buffer.CurCapacity[0]; |
printf("This disk has %lu sectors of 512 bytes (0x%08lX in hexadecimal).\n", |
capacity, capacity); |
printf("This is roughly equivalent to %lu000 bytes.", capacity/2); |
bugsExist = CheckBug1(&buffer); |
if (!bugsExist) |
bugsExist = CheckBug2(&buffer); |
if (!bugsExist) |
{ |
printf("This drive may be safely used in SCSI\n"); |
printf("in SCSI disk mode on a PowerBook 3400,\n"); |
printf("2400, 5300, 1400, 190, or Duo 2300.\n"); |
} |
break; |
default: |
break; |
} |
} |
return status; |
} |
// --------------------------------------------------------------------------- |
Boolean ATAManagerPresent (void) |
// --------------------------------------------------------------------------- |
// |
// returns true if this machine has the ata manager |
// |
{ |
return (TrapAvailable(kATATrap)); |
} |
// --------------------------------------------------------------------------- |
Boolean ATAHardwarePresent (void) |
// --------------------------------------------------------------------------- |
// |
// returns true if this machine has ata hardware |
// |
{ |
UInt16 configFlags; |
// Hardware configuration flags |
configFlags = LMGetHWCfgFlags(); |
return (configFlags & 0x0080); |
} |
//------------------------------------------------------------------------------------ |
#pragma mark - |
#define NumToolboxTraps() ( \ |
(NGetTrapAddress(_InitGraf, ToolTrap) \ |
== NGetTrapAddress(0xAA6E, ToolTrap)) \ |
? 0x200 : 0x400 \ |
) |
#define GetTrapType(theTrap) ( \ |
(((theTrap) & 0x800) != 0) ? ToolTrap : OSTrap \ |
) |
// --------------------------------------------------------------------------- |
Boolean TrapAvailable (short theTrap) |
// --------------------------------------------------------------------------- |
// (see Inside Mac VI 3-8) |
{ |
TrapType trapType; |
trapType = GetTrapType(theTrap); |
if (trapType == ToolTrap) |
{ |
theTrap &= 0x07FF; |
if (theTrap >= NumToolboxTraps()) |
theTrap = _Unimplemented; |
} |
return ( |
NGetTrapAddress(theTrap, trapType) |
!= NGetTrapAddress(_Unimplemented, ToolTrap) |
); |
} |
// --------------------------------------------------------------------------- |
char* DrvrRefToName(short refNum) |
// --------------------------------------------------------------------------- |
// |
// lookup driver name in table |
// |
{ |
AuxDCEHandle* UTable = |
(AuxDCEHandle*) LMGetUTableBase(); |
DCtlPtr dctl; |
Ptr p; |
if(!refNum) |
return ((char*) "\p<none>"); |
dctl = (DCtlPtr) *UTable[~refNum]; |
p = dctl->dCtlDriver; |
if( dctl->dCtlFlags & 0x0040) |
p = (void*) *p; |
return ( p?(char*) (p+18):(char*)"\p-Purged-"); |
} |
// --------------------------------------------------------------------------- |
Boolean CheckBug1(IdentifyBlock *ibPtr) |
// --------------------------------------------------------------------------- |
// |
// Check for the first of the two bugs. If a drive reports a capacity that |
// is greater than 4 gigabytes, then you should not use that drive in SCSI |
// disk mode on a 190/2300/1400/5300/3400/2400. Return false if no bug |
// conditions found. |
// |
{ |
UInt32 capacity; |
Boolean result = false; // assume no bug |
capacity = (ibPtr->CurCapacity[1] << 16) | |
ibPtr->CurCapacity[0]; |
if (capacity >= (UInt32)0x00800000) |
{ |
printf("\n\n******************************************\n"); |
printf("* Warning! This drive is too large to be *\n"); |
printf("* used in SCSI disk mode on a PowerBook *\n"); |
printf("* 3400, 2400, 5300, 1400, 190, or 2300! *\n"); |
printf("******************************************\n\n"); |
result = true; |
} |
return result; |
} |
// --------------------------------------------------------------------------- |
Boolean CheckBug2(IdentifyBlock *ibPtr) |
// --------------------------------------------------------------------------- |
// |
// Check for the second of the two bugs. If a drive reports a capacity that |
// has a lower word with the top bit set, the last 16 Mb of that drive won't |
// work correctly on the 5300/190/1400/2300. Return false if no bug |
// conditions found. |
// |
{ |
Boolean result = false; // assume no bug |
if (ibPtr->CurCapacity[0] & 0x8000) |
{ |
printf("\n\n******************************************\n"); |
printf("* Warning! This drive should not be used *\n"); |
printf("* in SCSI disk mode on a PowerBook 5300, *\n"); |
printf("* 1400, 190, or Duo 2300! *\n"); |
printf("* This drive is safe on a 3400 or 2400. *\n"); |
printf("******************************************\n"); |
result = true; |
} |
return result; |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14