/* * ATA_media.c - * * Written by Eryk Vershen */ /* * Copyright 1997,1998 by Apple Computer, Inc. * All Rights Reserved * * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose and without fee is hereby granted, * provided that the above copyright notice appears in all copies and * that both the copyright notice and this permission notice appear in * supporting documentation. * * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE. * * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ // for printf() #include // for malloc() & free() #include #include // for SCSI command structures #include "MacSCSICommand.h" #include "ATA_media.h" #include "util.h" /* * Defines */ #define RESULT_OFFSET(type) \ ((sizeof(type) == 1) ? 3 : ((sizeof(type) == 2) ? 1 : 0)) #define TBTrapTableAddress(trapNum) (((trapNum & 0x03FF) << 2) + 0xE00) #define SWAP_SHORTS(x) ((((x) & 0xFFFF) << 16) | (((x) >> 16) & 0xFFFF)) #define LBA_CAPABLE 0x0200 /* * Types */ typedef struct ATA_info *ATA_INFO; struct ATA_info { long lba; long heads; long sectors; }; typedef struct ATA_media *ATA_MEDIA; struct ATA_media { struct media m; long id; struct ATA_info info; }; struct ATA_manager { long exists; long kind; struct { char major; char minor; } version; short busCount; long *bus_list; }; typedef struct ATA_media_iterator *ATA_MEDIA_ITERATOR; struct ATA_media_iterator { struct media_iterator m; long bus_index; long bus; long id; }; struct ATA_identify_drive_info { /* word */ uint16_t config_bits; /* 0 */ uint16_t num_cylinders; /* 1 */ uint16_t reserved2; /* 2 */ uint16_t num_heads; /* 3 */ uint16_t bytes_per_track; /* 4 */ uint16_t bytes_per_sector; /* 5 */ uint16_t sectors_per_track; /* 6 */ uint16_t vendor7[3]; /* 7-9 */ char serial_number[20]; /* 10-19 */ uint16_t buffer_type; /* 20 */ uint16_t buffer_size; /* 21 */ uint16_t num_of_ecc_bytes; /* 22 */ char firmware_rev[8]; /* 23-26 */ char model_number[40]; /* 27-46 */ uint16_t word47; /* 47 */ uint16_t double_word_io; /* 48 */ uint16_t capabilities; /* 49 */ uint16_t reserved50; /* 50 */ uint16_t pio_timing; /* 51 */ uint16_t dma_timing; /* 52 */ uint16_t current_is_valid; /* 53 */ uint16_t cur_cylinders; /* 54 */ uint16_t cur_heads; /* 55 */ uint16_t cur_sec_per_track; /* 56 */ uint32_t total_sectors; /* 57-58 */ uint16_t multiple_sectors; /* 59 */ uint32_t lba_sectors; /* 60-61 */ uint16_t singleword_dma; /* 62 */ uint16_t multiword_dma; /* 63 */ uint16_t reserved64[64]; /* 64-127 */ uint16_t vendor128[32]; /* 128-159 */ uint16_t reserved160[96]; /* 160-255 */ }; struct ATAPI_identify_drive_info { /* word */ uint16_t config_bits; /* 0 */ uint16_t retired1[9]; /* 1-9 */ char serial_number[20]; /* 10-19 */ uint16_t retired20[3]; /* 20-22 */ char firmware_rev[8]; /* 23-26 */ char model_number[40]; /* 27-46 */ uint16_t retired47[2]; /* 47-48 */ uint16_t capabilities; /* 49 */ uint16_t reserved50; /* 50 */ uint16_t pio_timing; /* 51 */ uint16_t dma_timing; /* 52 */ uint16_t current_is_valid; /* 53 */ uint16_t retired54[8]; /* 54-61 */ uint16_t singleword_dma; /* 62 */ uint16_t multiword_dma; /* 63 */ uint16_t pio_transfer; /* 64 */ uint16_t min_cycle_time; /* 65 */ uint16_t rec_cycle_time; /* 66 */ uint16_t min_wo_flow; /* 67 */ uint16_t min_with_flow; /* 68 */ uint16_t reserved69[2]; /* 69-70 */ uint16_t release_over; /* 71 */ uint16_t release_service; /* 72 */ uint16_t major_rev; /* 73 */ uint16_t minor_rev; /* 74 */ uint16_t reserved75[53]; /* 75-127 */ uint16_t vendor128[32]; /* 128-159 */ uint16_t reserved160[96]; /* 160-255 */ }; /* Identifies the bus protocol type. */ enum { kDevUnknown = 0, kDevATA = 1, kDevATAPI = 2, kDevPCMCIA = 3 }; /* * Global Constants */ enum { kNoDevice = 0x00FF, kATAtimeout = 3000, kATAcmdATAPIPacket = 0x00A0 /* ATAPI packet command */ }; /* * Global Variables */ static long ata_inited = 0; static struct ATA_manager ata_mgr; /* * Forward declarations */ int ATAManagerPresent(void); int ATAHardwarePresent(void); pascal SInt16 ataManager(ataPB *pb); void ata_init(void); ATA_MEDIA new_ata_media(void); long read_ata_media(MEDIA m, long long offset, uint32_t count, void *address); long write_ata_media(MEDIA m, long long offset, uint32_t count, void *address); long close_ata_media(MEDIA m); long os_reload_ata_media(MEDIA m); long compute_id(long bus, long device); pascal SInt16 ataManager(ataPB *pb); int ATA_ReadBlock(UInt32 deviceID, ATA_INFO info, UInt32 block_size, UInt32 block, UInt8 *address); int ATA_WriteBlock(UInt32 deviceID, ATA_INFO info, UInt32 block_size, UInt32 block, UInt8 *address); long get_info(long id, struct ATA_identify_drive_info *ip); long get_pi_info(long id, struct ATAPI_identify_drive_info *ip); long is_atapi(long id); long read_atapi_media(MEDIA m, long long offset, uint32_t count, void *address); long write_atapi_media(MEDIA m, long long offset, uint32_t count, void *address); int ATAPI_ReadBlock(UInt32 deviceID, UInt32 block_size, UInt32 block, UInt8 *address); int ATAPI_TestUnitReady(UInt32 deviceID); int ATAPI_ReadCapacity(UInt32 deviceID, uint32_t *block_size, uint32_t *blocks); ATA_MEDIA_ITERATOR new_ata_iterator(void); void reset_ata_iterator(MEDIA_ITERATOR m); char *step_ata_iterator(MEDIA_ITERATOR m); void delete_ata_iterator(MEDIA_ITERATOR m); int ata_bus_present(int num); /* * Routines */ #if GENERATINGPOWERPC 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 int ATAHardwarePresent(void) { UInt16 configFlags; // Hardware configuration flags configFlags = LMGetHWCfgFlags(); return ((configFlags & 0x0080) != 0); } int ATAManagerPresent(void) { if (ATAHardwarePresent()) { return (TrapAvailable(kATATrap)); } else { return 0; } } void ata_init(void) { ataMgrInquiry pb; OSErr status; int i; int j; if (ata_inited != 0) { return; } ata_inited = 1; if (ATAManagerPresent() == 0) { ata_mgr.exists = 0; return; } ata_mgr.exists = 1; ata_mgr.kind = allocate_media_kind(); clear_memory((void *)&pb, sizeof(pb)); pb.ataPBFunctionCode = kATAMgrManagerInquiry; pb.ataPBVers = kATAPBVers1; status = ataManager((ataPB*) &pb ); if (status != noErr) { ata_mgr.exists = 0; return; } ata_mgr.version.major = pb.ataMgrVersion.majorRev; ata_mgr.version.minor = pb.ataMgrVersion.minorAndBugRev >> 4; ata_mgr.busCount = pb.ataBusCnt; ata_mgr.bus_list = (long *) calloc(ata_mgr.busCount, sizeof(long)); if (ata_mgr.bus_list == 0) { ata_mgr.busCount = 0; } else { for (i = 0, j = 0; j < ata_mgr.busCount; i++) { if (ata_bus_present(i)) { ata_mgr.bus_list[j] = i; j++; } } } } int ata_bus_present(int num) { ataBusInquiry pb; OSErr status; clear_memory((void *)&pb, sizeof(pb)); pb.ataPBFunctionCode = kATAMgrBusInquiry; pb.ataPBVers = kATAPBVers1; pb.ataPBDeviceID = num; status = ataManager((ataPB*) &pb ); if (status == noErr) { return 1; } else { //printf("status = %d\n", status); return 0; } } ATA_MEDIA new_ata_media(void) { return (ATA_MEDIA) new_media(sizeof(struct ATA_media)); } #pragma mark - long compute_id(long bus, long device) { long id; int i; id = -1; for (i = 0; i < ata_mgr.busCount; i++) { if (bus == ata_mgr.bus_list[i]) { break; } } if (i >= ata_mgr.busCount) { /* bad bus id */ } else if (ata_mgr.version.major < 3) { if (device != 0) { /* bad device id */ } else { id = bus & 0xFF; } } else { if (device < 0 || device > 1) { /* bad device id */ } else { id = ((device & 0xFF) << 8) | (bus & 0xFF); } } return id; } static long get_info(long id, struct ATA_identify_drive_info *ip) { ataIdentify pb; ataDevConfiguration pb2; OSErr status; long rtn_value; long atapi; if (sizeof(struct ATA_identify_drive_info) < 512) { return 0; } clear_memory((void *)ip, sizeof(struct ATA_identify_drive_info)); clear_memory((void *)&pb, sizeof(pb)); pb.ataPBFunctionCode = kATAMgrDriveIdentify; pb.ataPBVers = kATAPBVers1; pb.ataPBDeviceID = id; pb.ataPBFlags = mATAFlagIORead | mATAFlagByteSwap; pb.ataPBTimeOut = kATAtimeout; pb.ataPBBuffer = (void*) ip; status = ataManager((ataPB*) &pb ); if (status != noErr) { //printf("get info status = %d\n", status); rtn_value = 0; } else { ip->total_sectors = SWAP_SHORTS(ip->total_sectors); ip->lba_sectors = SWAP_SHORTS(ip->lba_sectors); rtn_value = 1; } return rtn_value; } static long is_atapi(long id) { ataDevConfiguration pb; OSErr status; long atapi; atapi = 0; if (ata_mgr.version.major >= 2) { clear_memory((void *)&pb, sizeof(pb)); pb.ataPBFunctionCode = kATAMgrGetDrvConfiguration; pb.ataPBVers = kATAPBVers2; pb.ataPBDeviceID = id; pb.ataPBTimeOut = kATAtimeout; status = ataManager((ataPB*) &pb ); if (status != noErr) { //printf("is atatpi status = %d\n", status); } else if (pb.ataDeviceType == kDevATAPI) { atapi = 1; /* the drive can be asleep or something in which case this doesn't work */ /* how do we do reads */ } } return atapi; } MEDIA open_ata_as_media(long bus, long device) { ATA_MEDIA a; long id; struct ATA_identify_drive_info info; uint8_t *buf; uint32_t total; if (ata_inited == 0) { ata_init(); } if (ata_mgr.exists == 0) { //printf("ATA manager does not exist\n"); return 0; } id = compute_id(bus, device); if (id < 0) { return 0; } else if (is_atapi(id)) { a = (ATA_MEDIA) open_atapi_as_media(bus, device); } else { a = 0; if (get_info(id, &info) != 0) { a = new_ata_media(); if (a != 0) { a->m.kind = ata_mgr.kind; if ((info.capabilities & LBA_CAPABLE) != 0) { total = info.lba_sectors; a->info.lba = 1; a->info.heads = 0; a->info.sectors = 0; } else { /* Only CHS - Cylinder Head Sector addressing */ total = info.total_sectors; a->info.lba = 0; a->info.heads = info.cur_heads; a->info.sectors = info.cur_sec_per_track; } { /* XXX this should be a loop in a subroutine */ buf = malloc(2048); if (ATA_ReadBlock(id, &a->info, 512, 0, buf)) { a->m.grain = 512; } else if (ATA_ReadBlock(id, &a->info, 1024, 0, buf)) { a->m.grain = 1024; } else if (ATA_ReadBlock(id, &a->info, 2048, 0, buf)) { a->m.grain = 2048; } else { a->m.grain = 512; /* XXX should really return failure here */ } free(buf); } if (total == 0) { a->m.size_in_bytes = ((long long)1000) * a->m.grain; /* XXX not right */ } else { a->m.size_in_bytes = ((long long)total) * a->m.grain; } a->m.do_read = read_ata_media; a->m.do_write = write_ata_media; a->m.do_close = close_ata_media; a->m.do_os_reload = os_reload_ata_media; a->id = id; } } else { printf("ATA - couldn't get info\n"); } } return (MEDIA) a; } long read_ata_media(MEDIA m, long long offset, uint32_t count, void *address) { ATA_MEDIA a; ataIOPB pb; OSErr status; long rtn_value; long block; long block_count; long block_size; uint8_t *buffer; int i; a = (ATA_MEDIA) m; rtn_value = 0; if (a == 0) { /* no media */ } else if (a->m.kind != ata_mgr.kind) { /* wrong kind - XXX need to error here - this is an internal problem */ } else if (count <= 0 || count % a->m.grain != 0) { /* can't handle size */ } else if (offset < 0 || offset % a->m.grain != 0) { /* can't handle offset */ } else if (offset + count > a->m.size_in_bytes) { /* check for offset (and offset+count) too large */ } else { /* do a read on the physical device */ block_size = a->m.grain; block = offset / block_size; block_count = count / block_size; buffer = address; rtn_value = 1; for (i = 0; i < block_count; i++) { if (ATA_ReadBlock(a->id, &a->info, block_size, block, buffer) == 0) { rtn_value = 0; break; } buffer += block_size; block += 1; } } return rtn_value; } long write_ata_media(MEDIA m, long long offset, uint32_t count, void *address) { ATA_MEDIA a; long rtn_value; long block; long block_count; long block_size; uint8_t *buffer; int i; a = (ATA_MEDIA) m; rtn_value = 0; if (a == 0) { /* no media */ } else if (a->m.kind != ata_mgr.kind) { /* XXX need to error here - this is an internal problem */ } else if (count <= 0 || count % a->m.grain != 0) { /* can't handle size */ } else if (offset < 0 || offset % a->m.grain != 0) { /* can't handle offset */ } else if (offset + count > a->m.size_in_bytes) { /* check for offset (and offset+count) too large */ } else { /* do a write on the physical device */ block_size = a->m.grain; block = offset / block_size; block_count = count / block_size; buffer = address; rtn_value = 1; for (i = 0; i < block_count; i++) { if (ATA_WriteBlock(a->id, &a->info, block_size, block, buffer) == 0) { rtn_value = 0; break; } buffer += block_size; block += 1; } } return rtn_value; } long close_ata_media(MEDIA m) { ATA_MEDIA a; a = (ATA_MEDIA) m; if (a == 0) { return 0; } else if (a->m.kind != ata_mgr.kind) { /* XXX need to error here - this is an internal problem */ return 0; } /* XXX nothing to do - I think? */ return 1; } long os_reload_ata_media(MEDIA m) { printf("Reboot your system so the partition table will be reread.\n"); return 1; } int ATA_ReadBlock(UInt32 deviceID, ATA_INFO info, UInt32 block_size, UInt32 block, UInt8 *address) { ataIOPB pb; OSErr status; long slave; long lba, cyl, head, sector; clear_memory((void *)&pb, sizeof(pb)); pb.ataPBFunctionCode = kATAMgrExecIO; pb.ataPBVers = kATAPBVers1; pb.ataPBDeviceID = deviceID; pb.ataPBFlags = mATAFlagTFRead | mATAFlagIORead ; pb.ataPBTimeOut = kATAtimeout; pb.ataPBLogicalBlockSize = block_size; pb.ataPBBuffer = address; pb.ataPBByteCount = block_size; if (info->lba) { lba = 0x40; sector = block & 0xFF; head = (block >> 24) & 0xF; cyl = (block >> 8) & 0xFFFF; } else { lba = 0x00; sector = (block % info->sectors) + 1; cyl = block / info->sectors; head = cyl % info->heads; cyl = cyl / info->heads; } pb.ataPBTaskFile.ataTFCount = 1; pb.ataPBTaskFile.ataTFSector = sector; pb.ataPBTaskFile.ataTFCylinder = cyl; if (deviceID & 0x0FF00) { slave = 0x10; } else { slave = 0x0; } /* std | L/C | Drive | head */ pb.ataPBTaskFile.ataTFSDH = 0xA0 | lba | slave | head; pb.ataPBTaskFile.ataTFCommand = kATAcmdRead; status = ataManager((ataPB*) &pb ); if (status != noErr) { /* failure */ //printf(" ATA read status = %d\n", status); return 0; } else { return 1; } } int ATA_WriteBlock(UInt32 deviceID, ATA_INFO info, UInt32 block_size, UInt32 block, UInt8 *address) { ataIOPB pb; OSErr status; long slave; long lba, cyl, head, sector; clear_memory((void *)&pb, sizeof(pb)); pb.ataPBFunctionCode = kATAMgrExecIO; pb.ataPBVers = kATAPBVers1; pb.ataPBDeviceID = deviceID; pb.ataPBFlags = mATAFlagTFRead | mATAFlagIOWrite ; pb.ataPBTimeOut = kATAtimeout; pb.ataPBLogicalBlockSize = block_size; pb.ataPBBuffer = address; pb.ataPBByteCount = block_size; if (info->lba) { lba = 0x40; sector = block & 0xFF; head = (block >> 24) & 0xF; cyl = (block >> 8) & 0xFFFF; } else { lba = 0x00; sector = (block % info->sectors) + 1; cyl = block / info->sectors; head = cyl % info->heads; cyl = cyl / info->heads; } pb.ataPBTaskFile.ataTFCount = 1; pb.ataPBTaskFile.ataTFSector = sector; pb.ataPBTaskFile.ataTFCylinder = cyl; if (deviceID & 0x0FF00) { slave = 0x10; } else { slave = 0x0; } /* std | L/C | Drive | head */ pb.ataPBTaskFile.ataTFSDH = 0xA0 | lba | slave | head; pb.ataPBTaskFile.ataTFCommand = kATAcmdWrite; status = ataManager((ataPB*) &pb ); if (status != noErr) { /* failure */ return 0; } else { return 1; } } #pragma mark - /* * ATAPI stuff */ static long get_pi_info(long id, struct ATAPI_identify_drive_info *ip) { ataIdentify pb; OSErr status; long rtn_value; if (sizeof(struct ATAPI_identify_drive_info) < 512) { return 0; } clear_memory((void *)ip, sizeof(struct ATAPI_identify_drive_info)); clear_memory((void *)&pb, sizeof(pb)); pb.ataPBFunctionCode = kATAMgrDriveIdentify; pb.ataPBVers = kATAPBVers1; pb.ataPBDeviceID = id; pb.ataPBFlags = mATAFlagIORead | mATAFlagByteSwap | mATAFlagProtocol1; pb.ataPBTimeOut = kATAtimeout; pb.ataPBBuffer = (void*) ip; status = ataManager((ataPB*) &pb ); if (status != noErr) { //printf("get pi info status = %d\n", status); rtn_value = 0; } else { rtn_value = 1; } return rtn_value; } MEDIA open_atapi_as_media(long bus, long device) { ATA_MEDIA a; long id; struct ATAPI_identify_drive_info info; uint8_t *buf; uint32_t block_size; uint32_t blocks; if (ata_inited == 0) { ata_init(); } if (ata_mgr.exists == 0) { return 0; } id = compute_id(bus, device); if (!is_atapi(id)) { a = 0; } else { a = 0; if (get_pi_info(id, &info) != 0 && (info.capabilities & LBA_CAPABLE) != 0) { if (ATAPI_TestUnitReady(id) != 0) { a = new_ata_media(); if (a != 0) { a->m.kind = ata_mgr.kind; if (ATAPI_ReadCapacity(id, &block_size, &blocks) == 0) { block_size = 2048; blocks = 1000; } a->m.grain = block_size; a->m.size_in_bytes = ((long long)blocks) * a->m.grain; a->m.do_read = read_atapi_media; a->m.do_write = write_atapi_media; a->m.do_close = close_ata_media; a->m.do_os_reload = os_reload_ata_media; a->id = id; } } else { printf("ATAPI - unit not ready\n"); } } else { printf("ATAPI - couldn't get info or not LBA capable\n"); } } return (MEDIA) a; } long read_atapi_media(MEDIA m, long long offset, uint32_t count, void *address) { ATA_MEDIA a; ataIOPB pb; OSErr status; long rtn_value; long block; long block_count; long block_size; uint8_t *buffer; int i; a = (ATA_MEDIA) m; rtn_value = 0; if (a == 0) { /* no media */ } else if (a->m.kind != ata_mgr.kind) { /* wrong kind - XXX need to error here - this is an internal problem */ } else if (count <= 0 || count % a->m.grain != 0) { /* can't handle size */ } else if (offset < 0 || offset % a->m.grain != 0) { /* can't handle offset */ } else if (offset + count > a->m.size_in_bytes) { /* check for offset (and offset+count) too large */ } else { /* XXX do a read on the physical device */ block_size = a->m.grain; block = offset / block_size; block_count = count / block_size; buffer = address; rtn_value = 1; for (i = 0; i < block_count; i++) { if (ATAPI_ReadBlock(a->id, block_size, block, buffer) == 0) { rtn_value = 0; break; } buffer += block_size; block += 1; } } return rtn_value; } long write_atapi_media(MEDIA m, long long offset, uint32_t count, void *address) { return 0; } int ATAPI_ReadBlock(UInt32 deviceID, UInt32 block_size, UInt32 block, UInt8 *address) { ataIOPB pb; OSErr status; long slave; ATAPICmdPacket cmdPacket; SCSI_10_Byte_Command *gRead; long count; clear_memory((void *)&pb, sizeof(pb)); pb.ataPBFunctionCode = kATAMgrExecIO; pb.ataPBVers = kATAPBVers1; pb.ataPBDeviceID = deviceID; pb.ataPBFlags = mATAFlagTFRead | mATAFlagIORead | mATAFlagProtocol1; pb.ataPBTimeOut = kATAtimeout; pb.ataPBBuffer = address; pb.ataPBByteCount = block_size; pb.ataPBTaskFile.ataTFCylinder = block_size; if (deviceID & 0x0FF00) { slave = 0x10; } else { slave = 0x0; } /* std | L/C | Drive | head */ pb.ataPBTaskFile.ataTFSDH = 0xA0 | 0x40 | slave; pb.ataPBTaskFile.ataTFCommand = kATAcmdATAPIPacket; pb.ataPBPacketPtr = &cmdPacket; cmdPacket.atapiPacketSize = 16; clear_memory((void *)&cmdPacket.atapiCommandByte, 16); gRead = (SCSI_10_Byte_Command *) &cmdPacket.atapiCommandByte[0]; gRead->opcode = kScsiCmdRead10; gRead->lbn4 = (block >> 24) & 0xFF; gRead->lbn3 = (block >> 16) & 0xFF; gRead->lbn2 = (block >> 8) & 0xFF; gRead->lbn1 = block & 0xFF; count = 1; gRead->len2 = (count >> 8) & 0xFF; gRead->len1 = count & 0xFF; status = ataManager((ataPB*) &pb ); if (status != noErr) { /* failure */ //printf("ATAPI read status = %d\n", status); return 0; } else { return 1; } } int ATAPI_TestUnitReady(UInt32 deviceID) { ataIOPB pb; OSErr status; long slave; ATAPICmdPacket cmdPacket; SCSI_10_Byte_Command *gTestUnit; clear_memory((void *)&pb, sizeof(pb)); pb.ataPBFunctionCode = kATAMgrExecIO; pb.ataPBVers = kATAPBVers1; pb.ataPBDeviceID = deviceID; pb.ataPBFlags = mATAFlagTFRead | mATAFlagIORead | mATAFlagProtocol1; pb.ataPBTimeOut = kATAtimeout; if (deviceID & 0x0FF00) { slave = 0x10; } else { slave = 0x0; } /* std | L/C | Drive | head */ pb.ataPBTaskFile.ataTFSDH = 0xA0 | 0x40 | slave; pb.ataPBTaskFile.ataTFCommand = kATAcmdATAPIPacket; pb.ataPBPacketPtr = &cmdPacket; cmdPacket.atapiPacketSize = 16; clear_memory((void *)&cmdPacket.atapiCommandByte, 16); gTestUnit = (SCSI_10_Byte_Command *) &cmdPacket.atapiCommandByte[0]; gTestUnit->opcode = kScsiCmdTestUnitReady; status = ataManager((ataPB*) &pb ); if (status != noErr) { /* failure */ //printf("ATAPI test unit ready status = %d\n", status); return 0; } else { return 1; } } int ATAPI_ReadCapacity(UInt32 deviceID, uint32_t *block_size, uint32_t *blocks) { ataIOPB pb; OSErr status; long slave; ATAPICmdPacket cmdPacket; SCSI_10_Byte_Command *gReadCap; struct read_cap_data { long addr; long size; } rcd; clear_memory((void *)&pb, sizeof(pb)); pb.ataPBFunctionCode = kATAMgrExecIO; pb.ataPBVers = kATAPBVers1; pb.ataPBDeviceID = deviceID; pb.ataPBFlags = mATAFlagTFRead | mATAFlagIORead | mATAFlagProtocol1; pb.ataPBTimeOut = kATAtimeout; pb.ataPBBuffer = (uint8_t *)&rcd; pb.ataPBByteCount = 8; pb.ataPBTaskFile.ataTFCylinder = 8; if (deviceID & 0x0FF00) { slave = 0x10; } else { slave = 0x0; } /* std | L/C | Drive | head */ pb.ataPBTaskFile.ataTFSDH = 0xA0 | 0x40 | slave; pb.ataPBTaskFile.ataTFCommand = kATAcmdATAPIPacket; pb.ataPBPacketPtr = &cmdPacket; cmdPacket.atapiPacketSize = 16; clear_memory((void *)&cmdPacket.atapiCommandByte, 16); gReadCap = (SCSI_10_Byte_Command *) &cmdPacket.atapiCommandByte[0]; gReadCap->opcode = kScsiCmdReadCapacity; status = ataManager((ataPB*) &pb ); if (status != noErr) { /* failure */ //printf("ATAPI read capacity status = %d\n", status); return 0; } else { *blocks = rcd.addr; *block_size = rcd.size; return 1; } } MEDIA ATA_FindDevice(long dRefNum) { ataDrvrRegister pb; OSErr status; if (ATAManagerPresent()) { clear_memory((void *)&pb, sizeof(pb)); pb.ataPBFunctionCode = kATAMgrFindDriverRefnum; pb.ataPBVers = kATAPBVers1; pb.ataPBDeviceID = 0xFFFF; pb.ataPBTimeOut = kATAtimeout; pb.ataDeviceNextID = 1; do { status = ataManager((ataPB*) &pb); if (status != noErr) { break; } else if (pb.ataDrvrRefNum == dRefNum && pb.ataPBDeviceID != kNoDevice) { return open_ata_as_media(pb.ataPBDeviceID & 0xFF, (pb.ataPBDeviceID >> 8) & 0xFF); } else { pb.ataPBDeviceID = pb.ataDeviceNextID; } } while (pb.ataPBDeviceID != kNoDevice); } return 0; } #pragma mark - ATA_MEDIA_ITERATOR new_ata_iterator(void) { return (ATA_MEDIA_ITERATOR) new_media_iterator(sizeof(struct ATA_media_iterator)); } MEDIA_ITERATOR create_ata_iterator(void) { ATA_MEDIA_ITERATOR a; if (ata_inited == 0) { ata_init(); } if (ata_mgr.exists == 0) { return 0; } a = new_ata_iterator(); if (a != 0) { a->m.kind = ata_mgr.kind; a->m.state = kInit; a->m.do_reset = reset_ata_iterator; a->m.do_step = step_ata_iterator; a->m.do_delete = delete_ata_iterator; a->bus_index = 0; a->bus = 0; a->id = 0; } return (MEDIA_ITERATOR) a; } void reset_ata_iterator(MEDIA_ITERATOR m) { ATA_MEDIA_ITERATOR a; a = (ATA_MEDIA_ITERATOR) m; if (a == 0) { /* no media */ } else if (a->m.kind != ata_mgr.kind) { /* wrong kind - XXX need to error here - this is an internal problem */ } else if (a->m.state != kInit) { a->m.state = kReset; } } char * step_ata_iterator(MEDIA_ITERATOR m) { ATA_MEDIA_ITERATOR a; char *result; a = (ATA_MEDIA_ITERATOR) m; if (a == 0) { /* no media */ } else if (a->m.kind != ata_mgr.kind) { /* wrong kind - XXX need to error here - this is an internal problem */ } else { switch (a->m.state) { case kInit: /* find # of buses (done in ata_init) */ a->m.state = kReset; /* fall through to reset */ case kReset: a->bus_index = 0 /* low bus id */; a->bus = ata_mgr.bus_list[a->bus_index]; a->id = 0 /* low device id */; a->m.state = kIterating; /* fall through to iterate */ case kIterating: while (1) { if (a->bus_index >= ata_mgr.busCount/* max bus id */) { break; } if (a->id > 1 /*max id for bus */) { a->bus_index += 1; a->bus = ata_mgr.bus_list[a->bus_index]; a->id = 0 /* low device id */; continue; /* try again */ } if (a->bus > 9) { // insure that name creation works break; } /* generate result */ result = (char *) malloc(20); if (result != NULL) { snprintf(result, 20, "/dev/ata%c.%c", '0'+a->bus, '0'+a->id); } a->id += 1; /* next id */ return result; } a->m.state = kEnd; /* fall through to end */ case kEnd: default: break; } } return 0 /* no entry */; } void delete_ata_iterator(MEDIA_ITERATOR m) { return; } #pragma mark - #ifdef notdef MEDIA open_linux_ata_as_media(long index) { long bus; long id; long i; i = index / 2; if (i >= ata_mgr.busCount) { // set bogus id bus = 0; id = 2; } else { bus = ata_mgr.bus_list[index / 2]; id = index % 2; } return open_ata_as_media(bus, id); } #else MEDIA open_linux_ata_as_media(long index) { long bus; long id; bus = index / 2; id = index % 2; return open_ata_as_media(bus, id); } #endif char * linux_ata_name(long bus, long id) { char *result; if (bus >= 13) { // a bus >= 13 would be a bogus character return NULL; } result = (char *) malloc(20); if (result != NULL) { /* name is hda, hdb, hdc, hdd, ... * in order (0,0) (0,1) (1,0) (1,1) ... */ snprintf(result, 20, "/dev/hd%c", 'a' + (bus*2 + id)); } return result; }