/* Copyright © 1993. Details in the file COPYRIGHT.txt */ #include "MacBSD.h" #include // For sprintf() prototype #ifndef MPW #include #endif static short read_ata (short ATAdev, short ATAbuss, u_long blknum, unsigned char *buf, u_long length); static short read_scsi (short SCSIid, u_long blknum, unsigned char *buf, u_long length); int read_disk (bDev dev, long blknum, unsigned char *buf, long length) { DebugPrintf(9, "Reading %ld bytes from block %ld of %s into %lx\n", length, blknum, disk_name(dev), buf); if (dev.devType == SCSI) return read_scsi (dev.id, blknum, buf, length); else return read_ata (dev.id, dev.buss, blknum, buf, length); } static char buff[50]; char * disk_name (bDev dev) { buff[0] = '\0'; if (dev.devType == SCSI) sprintf (buff, "SCSI buss %d, ID %d", dev.buss, dev.id); else sprintf (buff, "ATA buss %d, device %d", dev.buss, dev.id); return buff; } /* Stuff for IDE (ATA) disks */ #include "ATA.h" #define ATA_WAIT 600 /* Wait time before ATA timeout. */ typedef struct Identify /* Returned by kATAMgrDriveIdentify */ { short Signature; /* Word 00: Constant value */ short NumCyls; /* Word 01: Number of cylinders (default mode) */ short Reserved0; /* Word 02: Constant value of 0 */ short NumHds; /* Word 03: Number of heads (default mode) */ short TrkBytes; /* Word 04: Number of unformatted bytes/track */ short SecBytes; /* Word 05: Number of unformatted bytes/sector */ short NumSecs; /* Word 06: Number of sectors/track */ short VU[3]; /* Word 07-09: Vendor unique */ short Serial[10]; /* Word 10-19: Serial Number (right-justified) */ short BufType; /* Word 20: Buffer Type */ short BufSize; /* Word 21: Buffer size in 512 byte increments */ short NumECC; /* Word 22: Number of ECC bytes */ short FirmRev[4]; /* Word 23-26: Firmware revision (left-justified) */ short ModelNum[20]; /* Word 27-46: Model number (left-justified) */ short MultCmds; /* Word 47: R/W multiple commands not impl = 0 */ short DblXferFlag; /* Word 48: Double transfer flag */ short Capabilities; /* Word 49: LBA, DMA, IORDY support indicator */ short Reserved1; /* Word 50: Reserved */ short PIOTiming; /* Word 51: PIO transfer timing mode */ short DMATiming; /* Word 52: DMA transfer timing mode */ short Extension; /* Word 53: extended info support */ short CurCylinders; /* Word 54: number of current cylinders */ short CurHeads; /* Word 55: number of current heads */ short CurSPT; /* Word 56: number of current sectors per track */ long CurCapacity; /* Word 57-58: current capacity in sectors */ short MultSectors; /* Word 59: Multiple sector setting */ long LBACapacity; /* Word 60-61: total sectors in LBA mode */ short SWDMA; /* Word 62: single word DMA support */ short MWDMA; /* Word 63: multi word DMA support */ short APIOModes; /* Word 64: Advanced PIO Xfr mode supported */ short MDMATiming; /* Word 65: Minimum Multiword DMA Xfr Cycle */ short RDMATiming; /* Word 66: Recommended Multiword DMA Cycle */ short MPIOTiming; /* Word 67: Min PIO XFR Time W/O Flow Control */ short PIOwRDYTiming; /* Word 68: Min PIO XFR Time with IORDY flow ctrl */ short Reserved2[59]; /* Work 69-127: ? */ short Vendor[32]; /* Word 128-159: ? */ short Reserved3[96]; /* Word 160-255: ? */ } IdentifyBlock; IdentifyBlock info; #define LBA_CAPABLE 0x0200 /* In Capabilities */ static short read_ata (short ATAdev, short ATAbuss, u_long blknum, unsigned char *buf, u_long length) { ataDevConfiguration config; ataIdentify query; ataIOPB cmd; short lba; OSErr error; u_long bytes, cyl, head, id, sector, slave; unsigned char data[SECTOR_SIZE]; static bool reportConfigError = 1; /* Only report this error once */ if ( ! HasATA() ) { ErrorPrintf ("Computer does not have any ATA hardware and software\n"); return 0; } if ( debugLevel > 0 ) if ( sizeof(info) != 512 ) { ErrorPrintf ("IdentifyBlock has unexpected size - %d\n", sizeof(info) ); return 0; } id = (ATAdev && 0xFF) * 256 + (ATAbuss && 0xFF); memset((void *) &config, 0, sizeof(config)); config.ataPBDeviceID = id; config.ataPBFunctionCode = kATAMgrGetDrvConfiguration; config.ataPBVers = kATAPBVers2; error = ataManager((ataPB*) &config ); if ( error == noErr ) { if ( config.ataDeviceType == kATADeviceATAPI ) { Output("Cannot boot from ATAPI device\n"); } if ( config.ataDeviceType == kATADeviceUnknown ) { Output("Drive has unknown protocol\n"); } if ( config.ataDeviceType == kATADevicePCMCIA ) { Output("Cannot boot from PCMCIA device\n"); } if ( config.ataDeviceType != kATADeviceATA ) { return 0; } } else if ( reportConfigError ) { Output("Warning - cannot get configuration of ATA drive"); ErrorPrintf(" %ld, error %ld\n", id, error); reportConfigError = 0; } memset((void *) &query, 0, sizeof(query)); query.ataPBDeviceID = id; query.ataPBTimeOut = ATA_WAIT; query.ataPBFlags = mATAFlagIORead | mATAFlagByteSwap; query.ataPBFunctionCode = kATAMgrDriveIdentify; query.ataPBVers = kATAPBVers1; query.ataPBBuffer = (unsigned char *) &info; memset((void *) &info, 0, sizeof(info)); error = ataManager ((ataPB*) &query); if ( error != noErr ) { ErrorPrintf ("Cannot identify ATA drive %ld, error %ld\n", id, error); return 0; } DebugPrintf (10, "ATA dev %ld, ", id); if ( (info.Capabilities & LBA_CAPABLE) ) { DebugPrintf (10, "LBA capable - Size=%ld", info.LBACapacity); lba = 0x40; } else { DebugPrintf (10, "standard addressing - Size=%ld", info.CurCapacity); lba = 0; } DebugPrintf (10, ", Cylinders=%d, Heads=%d, Sectors/track=%d\n", info.NumCyls, info.NumHds, info.NumSecs); memset((void *) &cmd, 0, sizeof(cmd)); cmd.ataPBFunctionCode = kATAMgrExecIO; cmd.ataPBVers = kATAPBVers1; cmd.ataPBDeviceID = id; cmd.ataPBFlags = mATAFlagTFRead | mATAFlagIORead ; cmd.ataPBTimeOut = ATA_WAIT; if ( ATAdev ) slave = 0x10; else slave = 0x0; while ( length > 0 ) { if ( lba ) { sector = blknum & 0xFF; head = (blknum >> 24) & 0xF; cyl = (blknum >> 8) & 0xFFFF; } else { sector = (blknum % info.CurSPT) + 1; cyl = blknum / info.CurSPT; head = cyl % info.CurHeads; cyl = cyl / info.CurHeads; } cmd.ataPBBuffer = data; cmd.ataPBByteCount = SECTOR_SIZE; cmd.ataPBLogicalBlockSize = SECTOR_SIZE; cmd.ataPBTaskFile.ataTFCount = 1; cmd.ataPBTaskFile.ataTFSector = sector; cmd.ataPBTaskFile.ataTFCylinder = cyl; /* std | L/C | drive | head */ cmd.ataPBTaskFile.ataTFSDH = 0xA0 | lba | slave | head; cmd.ataPBTaskFile.ataTFCommand = kATAcmdRead; DebugPrintf (11, "Reading block %d ... ", blknum); error = ataManager((ataPB*) &cmd); if (error != noErr) { ErrorPrintf ("Cannot read from ATA drive %ld, error %ld\n", id, error); return 0; } if ( length < SECTOR_SIZE ) { bytes = length; DebugPrintf (11, "(using %d bytes of %d)\n", bytes, SECTOR_SIZE); } else { bytes = SECTOR_SIZE; length -= bytes; DebugPrintf (11, "%d bytes remaining\n", length); } memcpy(buf, data, bytes); buf += bytes; ++blknum; } return 1; } #include int read_Block0 (bDev dev) { Block0 ddMap; if ( ! read_disk (dev, 0, (unsigned char *) &ddMap, sizeof (Block0) ) ) { DebugPrintf (2, "Failed to read Block0 from disk.\n"); return -1; } if ( ddMap.sbSig != 0x4552 ) { DebugPrintf (2, "Device Descriptor Map signature invalid (%d). Is the disk formatted?\n", ddMap.sbSig); return -1; } if ( ddMap.sbBlkSize != SECTOR_SIZE ) { DebugPrintf (2, "BlockSize of disk (%d) is not that expected (%d)\n", ddMap.sbBlkSize, SECTOR_SIZE); return -1; } DebugPrintf (2, "Block count = %ld\n", ddMap.sbBlkCount); return 0; /* At the moment, I don't know how to count the valid partitions */ } static unsigned char cmd6[6]; static unsigned char cmd10[10]; #define SCSI_WAIT 600 /* Wait time before SCSI timeout. */ /* Can handle drives with # sectors no greater than 2^21, and sector size of 512 bytes */ static short read_scsi (short SCSIid, u_long blknum, unsigned char *buf, u_long length) { int error, cmdSize; short stat, msg; long num_blocks; struct SCSIInstr instrs[10]; Ptr cmdPtr; num_blocks = length / SECTOR_SIZE; if (num_blocks * SECTOR_SIZE < length ) num_blocks++; DebugPrintf(10, "Reading %ld blocks of %d bytes\n", num_blocks, SECTOR_SIZE); if ((error = SCSIGet()) != noErr) { ErrorPrintf("Error %d on SCSIGet()\n", error); return 0; } if ((error = SCSISelect(SCSIid)) != noErr) { ErrorPrintf ("Error %d on SCSISelect().\n", error); ErrorPrintf ("\n********** Is the SCSI ID (%d) wrong? **********\n\n", (int)SCSIid); return 0; } instrs[0].scOpcode = scInc; /* command scInc */ instrs[0].scParam1 = (long)buf; /* buffer pointer */ instrs[0].scParam2 = length; /* transfer size */ instrs[1].scOpcode = scStop; /* command stop */ instrs[1].scParam1 = 0; instrs[1].scParam2 = 0; if (blknum <= 0x1fffff) { cmd6[0] = 8; /* read */ cmd6[1] = (0 << 5) | ((blknum & 0x1f0000) >> 16) ; /* LUN and addr H */ cmd6[2] = (blknum & 0xff00) >> 8; /* addr M */ cmd6[3] = blknum & 0xff; /* addr L */ cmd6[4] = (unsigned char) (num_blocks & 0xff); /* num blocks to transfer */ cmd6[5] = 0; /* control bits (ignored) */ cmdSize = 6; cmdPtr = (Ptr)cmd6; } else { cmd10[0] = 0x28; /* read 10 */ cmd10[1] = 0; cmd10[2] = (blknum >> 24) & 0xff; cmd10[3] = (blknum >> 16) & 0xff; cmd10[4] = (blknum >> 8) & 0xff; cmd10[5] = blknum & 0xff; cmd10[6] = 0; cmd10[7] = (num_blocks >> 8) & 0xff; cmd10[8] = num_blocks & 0xff; cmd10[9] = 0; cmdSize = 10; cmdPtr = (Ptr)cmd10; } if ((error = SCSICmd(cmdPtr, cmdSize)) != noErr) { ErrorPrintf("Error %d on SCSICmd()\n", error); SCSIComplete(&stat, &msg, SCSI_WAIT); return 0; } if ((error = SCSIRead((Ptr) instrs)) != noErr) { ErrorPrintf ("Error %d on SCSIRead().\n", error); ErrorPrintf ("\n********** Is the disk in SCSI ID %d offline? **********\n\n", (int)SCSIid); SCSIComplete(&stat, &msg, SCSI_WAIT); return 0; } if ((error = SCSIComplete(&stat, &msg, SCSI_WAIT)) != noErr) { ErrorPrintf("Error %d on SCSIComplete()\n", error); return 0; } hex_dump (15, buf, length); return 1; }