Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

import pdisk utility from Eryk Vershen:

  http://cantaforda.com/cfcl/eryk/linux/pdisk/index.html
this is the utility provided by mklinux and osX to manipulate
the Apple Partition map.
  • Loading branch information...
commit 0885043f1cde5fa0e76212e919ea98b5eb52690f 1 parent a2bca40
dbj authored
Showing with 13,275 additions and 0 deletions.
  1. +1,239 −0 dist/pdisk/ATA_media.c
  2. +64 −0 dist/pdisk/ATA_media.h
  3. +649 −0 dist/pdisk/DoSCSICommand.c
  4. +130 −0 dist/pdisk/DoSCSICommand.h
  5. +68 −0 dist/pdisk/HISTORY
  6. +420 −0 dist/pdisk/MacSCSICommand.h
  7. +147 −0 dist/pdisk/README
  8. +1,108 −0 dist/pdisk/SCSI_media.c
  9. +65 −0 dist/pdisk/SCSI_media.h
  10. +101 −0 dist/pdisk/bitfield.c
  11. +72 −0 dist/pdisk/bitfield.h
  12. +204 −0 dist/pdisk/convert.c
  13. +65 −0 dist/pdisk/convert.h
  14. +208 −0 dist/pdisk/cvt_pt.c
  15. +334 −0 dist/pdisk/deblock_media.c
  16. +59 −0 dist/pdisk/deblock_media.h
  17. +219 −0 dist/pdisk/dpme.h
  18. +917 −0 dist/pdisk/dump.c
  19. +72 −0 dist/pdisk/dump.h
  20. +173 −0 dist/pdisk/errors.c
  21. +62 −0 dist/pdisk/errors.h
  22. +574 −0 dist/pdisk/file_media.c
  23. +60 −0 dist/pdisk/file_media.h
  24. +253 −0 dist/pdisk/hfs_misc.c
  25. +41 −0 dist/pdisk/hfs_misc.h
  26. +463 −0 dist/pdisk/io.c
  27. +67 −0 dist/pdisk/io.h
  28. +180 −0 dist/pdisk/layout_dump.c
  29. +78 −0 dist/pdisk/layout_dump.h
  30. +212 −0 dist/pdisk/makefile
  31. +228 −0 dist/pdisk/media.c
  32. +139 −0 dist/pdisk/media.h
  33. +1,319 −0 dist/pdisk/partition_map.c
  34. +119 −0 dist/pdisk/partition_map.h
  35. +247 −0 dist/pdisk/pathname.c
  36. +62 −0 dist/pdisk/pathname.h
  37. +222 −0 dist/pdisk/pdisk.8
  38. +1,072 −0 dist/pdisk/pdisk.c
  39. +57 −0 dist/pdisk/pdisk.h
  40. +406 −0 dist/pdisk/pdisk.html
  41. +234 −0 dist/pdisk/pdisk.r
  42. +164 −0 dist/pdisk/util.c
  43. +62 −0 dist/pdisk/util.h
  44. +499 −0 dist/pdisk/validate.c
  45. +59 −0 dist/pdisk/validate.h
  46. +82 −0 dist/pdisk/version.h
View
1,239 dist/pdisk/ATA_media.c
@@ -0,0 +1,1239 @@
+/*
+ * 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 <stdio.h>
+// for malloc() & free()
+#include <stdlib.h>
+#include <ATA.h>
+// 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 */
+ unsigned short config_bits; /* 0 */
+ unsigned short num_cylinders; /* 1 */
+ unsigned short reserved2; /* 2 */
+ unsigned short num_heads; /* 3 */
+ unsigned short bytes_per_track; /* 4 */
+ unsigned short bytes_per_sector; /* 5 */
+ unsigned short sectors_per_track; /* 6 */
+ unsigned short vendor7[3]; /* 7-9 */
+ char serial_number[20]; /* 10-19 */
+ unsigned short buffer_type; /* 20 */
+ unsigned short buffer_size; /* 21 */
+ unsigned short num_of_ecc_bytes; /* 22 */
+ char firmware_rev[8]; /* 23-26 */
+ char model_number[40]; /* 27-46 */
+ unsigned short word47; /* 47 */
+ unsigned short double_word_io; /* 48 */
+ unsigned short capabilities; /* 49 */
+ unsigned short reserved50; /* 50 */
+ unsigned short pio_timing; /* 51 */
+ unsigned short dma_timing; /* 52 */
+ unsigned short current_is_valid; /* 53 */
+ unsigned short cur_cylinders; /* 54 */
+ unsigned short cur_heads; /* 55 */
+ unsigned short cur_sec_per_track; /* 56 */
+ unsigned long total_sectors; /* 57-58 */
+ unsigned short multiple_sectors; /* 59 */
+ unsigned long lba_sectors; /* 60-61 */
+ unsigned short singleword_dma; /* 62 */
+ unsigned short multiword_dma; /* 63 */
+ unsigned short reserved64[64]; /* 64-127 */
+ unsigned short vendor128[32]; /* 128-159 */
+ unsigned short reserved160[96]; /* 160-255 */
+};
+
+struct ATAPI_identify_drive_info { /* word */
+ unsigned short config_bits; /* 0 */
+ unsigned short retired1[9]; /* 1-9 */
+ char serial_number[20]; /* 10-19 */
+ unsigned short retired20[3]; /* 20-22 */
+ char firmware_rev[8]; /* 23-26 */
+ char model_number[40]; /* 27-46 */
+ unsigned short retired47[2]; /* 47-48 */
+ unsigned short capabilities; /* 49 */
+ unsigned short reserved50; /* 50 */
+ unsigned short pio_timing; /* 51 */
+ unsigned short dma_timing; /* 52 */
+ unsigned short current_is_valid; /* 53 */
+ unsigned short retired54[8]; /* 54-61 */
+ unsigned short singleword_dma; /* 62 */
+ unsigned short multiword_dma; /* 63 */
+ unsigned short pio_transfer; /* 64 */
+ unsigned short min_cycle_time; /* 65 */
+ unsigned short rec_cycle_time; /* 66 */
+ unsigned short min_wo_flow; /* 67 */
+ unsigned short min_with_flow; /* 68 */
+ unsigned short reserved69[2]; /* 69-70 */
+ unsigned short release_over; /* 71 */
+ unsigned short release_service; /* 72 */
+ unsigned short major_rev; /* 73 */
+ unsigned short minor_rev; /* 74 */
+ unsigned short reserved75[53]; /* 75-127 */
+ unsigned short vendor128[32]; /* 128-159 */
+ unsigned short 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, unsigned long count, void *address);
+long write_ata_media(MEDIA m, long long offset, unsigned long 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, unsigned long count, void *address);
+long write_atapi_media(MEDIA m, long long offset, unsigned long 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, unsigned long *block_size, unsigned long *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;
+ unsigned char *buf;
+ unsigned long 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, unsigned long count, void *address)
+{
+ ATA_MEDIA a;
+ ataIOPB pb;
+ OSErr status;
+ long rtn_value;
+ long block;
+ long block_count;
+ long block_size;
+ unsigned char *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, unsigned long count, void *address)
+{
+ ATA_MEDIA a;
+ long rtn_value;
+ long block;
+ long block_count;
+ long block_size;
+ unsigned char *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;
+ unsigned char *buf;
+ unsigned long block_size;
+ unsigned long 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, unsigned long count, void *address)
+{
+ ATA_MEDIA a;
+ ataIOPB pb;
+ OSErr status;
+ long rtn_value;
+ long block;
+ long block_count;
+ long block_size;
+ unsigned char *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, unsigned long 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, unsigned long *block_size, unsigned long *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 = (unsigned char *)&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) {
+ sprintf(result, "/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) ...
+ */
+ sprintf(result, "/dev/hd%c", 'a' + (bus*2 + id));
+ }
+ return result;
+}
View
64 dist/pdisk/ATA_media.h
@@ -0,0 +1,64 @@
+/*
+ * ATA_media.h -
+ *
+ * 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.
+ */
+
+#ifndef __ATA_media__
+#define __ATA_media__
+
+#include "media.h"
+
+
+/*
+ * Defines
+ */
+
+
+/*
+ * Types
+ */
+
+
+/*
+ * Global Constants
+ */
+
+
+/*
+ * Global Variables
+ */
+
+
+/*
+ * Forward declarations
+ */
+MEDIA ATA_FindDevice(long dRefNum);
+MEDIA open_ata_as_media(long bus, long device);
+MEDIA open_atapi_as_media(long bus, long device);
+MEDIA_ITERATOR create_ata_iterator(void);
+MEDIA open_linux_ata_as_media(long index);
+char *linux_ata_name(long bus, long id);
+
+#endif /* __ATA_media__ */
View
649 dist/pdisk/DoSCSICommand.c
@@ -0,0 +1,649 @@
+/*
+ * DoScsiCommand.c
+ *
+ * This is the common entry to the original and asynchronous SCSI Manager calls:
+ * if the asynchronous SCSI Manager is requested, it calls it. Otherwise, it
+ * calls the original SCSI Manager and executes Request Sense if necessary.
+ *
+ * This function returns "autosense" in the SCSI_Sense_Data area. This will
+ * be formatted in the senseMessage string.
+ */
+
+/*
+ * Copyright 1992, 1993, 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.
+ */
+
+#include "DoScsiCommand.h"
+#include "util.h"
+
+
+//
+// Defines
+//
+#define kSCSICommandTimeout (5 * 1000L) /* Five seconds */
+/*
+ * This is the maximum number of times we try to grab the SCSI Bus
+ */
+#define kMaxSCSIRetries 40 /* 10 seconds, 4 times/sec */
+/*
+ * This test is TRUE if the SCSI bus status indicates "busy" (which is the case
+ * if either the BSY or SEL bit is set).
+ */
+#ifndef kScsiStatBSY
+#define kScsiStatBSY (1 << 6)
+#endif
+#ifndef kScsiStatSEL
+#define kScsiStatSEL (1 << 1)
+#endif
+#define ScsiBusBusy() ((SCSIStat() & (kScsiStatBSY | kScsiStatSEL)) != 0)
+
+
+//
+// Types
+//
+
+
+//
+// Global Constants
+//
+
+
+//
+// Global Variables
+//
+int gSCSIHiBusID;
+SCSIExecIOPB *gSCSIExecIOPBPtr;
+UInt32 gSCSIExecIOPBPtrLen;
+
+
+//
+// Forward declarations
+//
+UInt16 GetCommandLength(const SCSI_CommandPtr cmdPtr);
+Boolean IsVirtualMemoryRunning(void);
+
+OSErr OriginalSCSI(
+ DeviceIdent scsiDevice,
+ const SCSI_CommandPtr scsiCommand,
+ UInt8 scsiCommandLen,
+ Ptr dataBuffer,
+ ByteCount dataLength,
+ UInt32 scsiFlags,
+ ByteCount *actualTransferCount,
+ UInt8 *scsiStatusByte
+);
+
+OSErr DoOriginalSCSICommand(
+ DeviceIdent scsiDevice,
+ const SCSI_CommandPtr theSCSICommand,
+ unsigned short cmdBlockLength,
+ Ptr dataBuffer,
+ ByteCount dataLength,
+ UInt32 scsiFlags,
+ ByteCount *actualTransferCount,
+ SCSI_Sense_Data *sensePtr
+);
+
+
+//
+// Routines
+//
+
+/*
+ * This returns TRUE if the command failed with "Illegal Request." We need this
+ * so we can ignore LogSense or ReadDefectData if the device doesn't support
+ * these functions.
+ */
+Boolean
+IsIllegalRequest(
+ OSErr scsiStatus,
+ const SCSI_Sense_Data *senseDataPtr
+ )
+{
+ Boolean result;
+#define SENSE (*senseDataPtr)
+
+ result = FALSE;
+ if (scsiStatus == scsiNonZeroStatus
+ && (SENSE.senseKey & kScsiSenseKeyMask) == kScsiSenseIllegalReq
+ && SENSE.additionalSenseLength >= 4) {
+ switch ((SENSE.additionalSenseCode << 8) | SENSE.additionalSenseQualifier) {
+ case 0x0000:
+ case 0x2000:
+ case 0x2022: /* Obsolete */
+ result = TRUE;
+ break;
+ default:
+ break;
+ }
+ }
+ return (result);
+#undef SENSE
+}
+
+
+/*
+ * This returns TRUE if the command failed with Device Not Ready (No Media Present)
+ */
+Boolean
+IsNoMedia(
+ OSErr scsiStatus,
+ const SCSI_Sense_Data *senseDataPtr
+ )
+{
+ Boolean result;
+#define SENSE (*senseDataPtr)
+
+ result = FALSE;
+ if (scsiStatus == scsiNonZeroStatus
+ && (SENSE.senseKey & kScsiSenseKeyMask) == kScsiSenseNotReady
+ && SENSE.additionalSenseLength >= 4) {
+ switch ((SENSE.additionalSenseCode << 8) | SENSE.additionalSenseQualifier) {
+ case 0x0000:
+ case 0x3A00:
+ result = TRUE;
+ break;
+ default:
+ break;
+ }
+ }
+ return (result);
+#undef SENSE
+}
+
+
+/*
+ * Do one SCSI Command. If the device returns Check Condition, issue Request Sense
+ * (original SCSI Manager only) and interpret the sense data. The original SCSI
+ * command status is in SCB.status. If it is statusErr or scsiNonZeroStatus,
+ * the sense data is in SCB.sense and the Request Sense status is in
+ * SCB.requestSenseStatus.
+ *
+ * If sensePtr[0] is non-zero, there is a message.
+ */
+OSErr
+DoSCSICommand(
+ DeviceIdent scsiDevice,
+ ConstStr255Param currentAction,
+ const SCSI_CommandPtr callerSCSICommand,
+ Ptr dataBuffer,
+ ByteCount dataLength,
+ UInt32 scsiFlags,
+ ByteCount *actualTransferCount,
+ SCSI_Sense_Data *sensePtr,
+ StringPtr senseMessage
+ )
+{
+ OSErr status;
+ SCSI_Command theSCSICommand;
+ unsigned short cmdBlockLength;
+
+// SpinSpinner(&gCurrentInfoPtr->spinnerRecord);
+// ShowProgressAction(currentAction);
+ /*
+ * Store the LUN information in the command block - this is needed
+ * for devices that only examine the command block for LUN values.
+ * (On SCSI-II, the asynchronous SCSI Manager also includes the
+ * LUN in the identify message).
+ */
+ theSCSICommand = *callerSCSICommand;
+ theSCSICommand.scsi[1] &= ~0xE0;
+ theSCSICommand.scsi[1] |= (scsiDevice.LUN & 0x03) << 5;
+ cmdBlockLength = GetCommandLength(&theSCSICommand);
+ if (senseMessage != NULL)
+ senseMessage[0] = 0;
+ if (sensePtr != NULL)
+ sensePtr->errorCode = 0;
+ if (scsiDevice.bus == kOriginalSCSIBusAdaptor) {
+ status = DoOriginalSCSICommand(
+ scsiDevice,
+ &theSCSICommand,
+ cmdBlockLength,
+ dataBuffer,
+ dataLength,
+ scsiFlags,
+ actualTransferCount,
+ sensePtr
+ );
+ }
+ else {
+ clear_memory(gSCSIExecIOPBPtr, gSCSIExecIOPBPtrLen);
+#define PB (*gSCSIExecIOPBPtr)
+ PB.scsiPBLength = gSCSIExecIOPBPtrLen;
+ PB.scsiFunctionCode = SCSIExecIO;
+ PB.scsiDevice = scsiDevice;
+ PB.scsiTimeout = kSCSICommandTimeout;
+ /*
+ * Fiddle the flags so they're the least disruptive possible.
+ */
+ PB.scsiFlags = scsiFlags | (scsiSIMQNoFreeze | scsiDontDisconnect);
+ if (sensePtr != NULL) {
+ PB.scsiSensePtr = (UInt8 *) sensePtr;
+ PB.scsiSenseLength = sizeof *sensePtr;
+ }
+ BlockMoveData(&theSCSICommand, &PB.scsiCDB.cdbBytes[0], cmdBlockLength);
+ PB.scsiCDBLength = cmdBlockLength;
+ if (dataBuffer != NULL) {
+ PB.scsiDataPtr = (UInt8 *) dataBuffer;
+ PB.scsiDataLength = dataLength;
+ PB.scsiDataType = scsiDataBuffer;
+ PB.scsiTransferType = scsiTransferPolled;
+ }
+ status = SCSIAction((SCSI_PB *) &PB);
+ if (status == noErr)
+ status = PB.scsiResult;
+ if (status == scsiSelectTimeout)
+ status = scsiDeviceNotThere;
+ if (actualTransferCount != NULL) {
+ /*
+ * Make sure that the actual transfer count does not exceed
+ * the allocation count (some devices spit extra data at us!)
+ */
+ *actualTransferCount = dataLength - PB.scsiDataResidual;
+ if (*actualTransferCount > dataLength)
+ *actualTransferCount = dataLength;
+ }
+#undef PB
+ }
+ if (status == scsiNonZeroStatus
+ && sensePtr != NULL
+ && sensePtr->errorCode != 0
+ && senseMessage != NULL) {
+// FormatSenseMessage(sensePtr, senseMessage);
+// ShowProgressAction(senseMessage);
+ }
+ return (status);
+}
+
+
+/*
+ * Do a command with autosense using the original SCSI manager.
+ */
+OSErr
+DoOriginalSCSICommand(
+ DeviceIdent scsiDevice,
+ const SCSI_CommandPtr theSCSICommand,
+ unsigned short cmdBlockLength,
+ Ptr dataBuffer,
+ ByteCount dataLength,
+ UInt32 scsiFlags,
+ ByteCount *actualTransferCount,
+ SCSI_Sense_Data *sensePtr
+ )
+{
+ OSErr status;
+ UInt8 scsiStatusByte;
+ SCSI_Command scsiStatusCommand;
+
+ status = OriginalSCSI(
+ scsiDevice,
+ theSCSICommand,
+ cmdBlockLength,
+ dataBuffer,
+ dataLength,
+ scsiFlags,
+ actualTransferCount,
+ &scsiStatusByte
+ );
+ if (status == scsiNonZeroStatus
+ && scsiStatusByte == kScsiStatusCheckCondition
+ && sensePtr != NULL) {
+ CLEAR(scsiStatusCommand);
+ CLEAR(*sensePtr);
+ scsiStatusCommand.scsi6.opcode = kScsiCmdRequestSense;
+ scsiStatusCommand.scsi[1] |= (scsiDevice.LUN & 0x03) << 5;
+ scsiStatusCommand.scsi6.len = sizeof *sensePtr;
+ status = OriginalSCSI(
+ scsiDevice,
+ &scsiStatusCommand,
+ sizeof scsiStatusCommand.scsi6,
+ (Ptr) sensePtr,
+ sizeof *sensePtr,
+ scsiDirectionIn,
+ NULL,
+ &scsiStatusByte
+ );
+ if (status != noErr && status != scsiDataRunError) {
+#ifdef notdef
+ if (gDebugOnError && scsiStatusByte != kScsiStatusCheckCondition) {
+ Str255 work;
+
+ pstrcpy(work, "\pAutosense failed ");
+ AppendSigned(work, status);
+ AppendChar(work, ' ');
+ AppendHexLeadingZeros(work, scsiStatusByte, 2);
+ DebugStr(work);
+ }
+#endif
+ sensePtr->errorCode = 0;
+ status = scsiAutosenseFailed;
+ }
+ else {
+ status = scsiNonZeroStatus;
+ }
+ }
+ return (status);
+}
+
+
+OSErr
+OriginalSCSI(
+ DeviceIdent scsiDevice,
+ const SCSI_CommandPtr scsiCommand,
+ UInt8 scsiCommandLen,
+ Ptr dataBuffer,
+ ByteCount dataLength,
+ UInt32 scsiFlags,
+ ByteCount *actualTransferCount,
+ UInt8 *scsiStatusBytePtr
+ )
+{
+ OSErr status; /* Final status */
+ OSErr completionStatus; /* Status from ScsiComplete */
+ short totalTries; /* Get/Select retries */
+ short getTries; /* Get retries */
+ short iCount; /* Bus free counter */
+ unsigned long watchdog; /* Timeout after this */
+ unsigned long myTransferCount; /* Gets TIB loop counter */
+ short scsiStatusByte; /* Gets SCSIComplete result */
+ short scsiMsgByte; /* Gets SCSIComplete result */
+ Boolean bufferHoldFlag;
+ /*
+ * The TIB has the following format:
+ * [0] scInc user buffer transferQuantum or transferSize
+ * [1] scAdd &theTransferCount 1
+ * [2] scLoop -> tib[0] transferSize / transferQuantum
+ * [3] scStop
+ * The intent of this is to return, in actualTransferCount, the number
+ * of times we cycled through the tib[] loop. This will be the actual
+ * transfer count if transferQuantum equals one, or the number of
+ * "blocks" if transferQuantum is the length of one sector.
+ */
+ SCSIInstr tib[4]; /* Current TIB */
+
+ status = noErr;
+ bufferHoldFlag = FALSE;
+ scsiStatusByte = 0xFF;
+ scsiMsgByte = 0xFF;
+ myTransferCount = 0;
+ /*
+ * If there is a data transfer, setup the tib.
+ */
+ if (dataBuffer != NULL) {
+ tib[0].scOpcode = scInc;
+ tib[0].scParam1 = (unsigned long) dataBuffer;
+ tib[0].scParam2 = 1;
+ tib[1].scOpcode = scAdd;
+ tib[1].scParam1 = (unsigned long) &myTransferCount;
+ tib[1].scParam2 = 1;
+ tib[2].scOpcode = scLoop;
+ tib[2].scParam1 = (-2 * sizeof (SCSIInstr));
+ tib[2].scParam2 = dataLength / tib[0].scParam2;
+ tib[3].scOpcode = scStop;
+ tib[3].scParam1 = 0;
+ tib[3].scParam2 = 0;
+ }
+ if (IsVirtualMemoryRunning() && dataBuffer != NULL) {
+ /*
+ * Lock down the user buffer, if any. In a real-world application
+ * or driver, this would be done before calling the SCSI interface.
+ */
+#ifdef notdef
+ FailOSErr(
+ HoldMemory(dataBuffer, dataLength),
+ "\pCan't lock data buffer in physical memory"
+ );
+#else
+ HoldMemory(dataBuffer, dataLength);
+#endif
+ bufferHoldFlag = TRUE;
+ }
+ /*
+ * Arbitrate for the scsi bus. This will fail if some other device is
+ * accessing the bus at this time (which is unlikely).
+ *
+ *** Do not set breakpoints or call any functions that may require device
+ *** I/O (such as display code that accesses font resources between
+ *** SCSIGet and SCSIComplete,
+ *
+ */
+ for (totalTries = 0; totalTries < kMaxSCSIRetries; totalTries++) {
+ for (getTries = 0; getTries < 4; getTries++) {
+ /*
+ * Wait for the bus to go free.
+ */
+ watchdog = TickCount() + 300; /* 5 second timeout */
+ while (ScsiBusBusy()) {
+ if (/*gStopNow || StopNow() ||*/ TickCount() > watchdog) {
+ status = scsiBusy;
+ goto exit;
+ }
+ }
+ /*
+ * The bus is free, try to grab it
+ */
+ for (iCount = 0; iCount < 4; iCount++) {
+ if ((status = SCSIGet()) == noErr)
+ break;
+ }
+ if (status == noErr) {
+ break; /* Success: we have the bus */
+ }
+ /*
+ * The bus became busy again. Try to wait for it to go free.
+ */
+ for (iCount = 0;
+ /*gStopNow == FALSE && StopNow() == FALSE &&*/ iCount < 100 && ScsiBusBusy();
+ iCount++)
+ ;
+ } /* The getTries loop */
+ if (status != noErr) {
+ /*
+ * The SCSI Manager thinks the bus is not busy and not selected,
+ * but "someone" has set its internal semaphore that signals
+ * that the SCSI Manager itself is busy. The application will have
+ * to handle this problem. (We tried getTries * 4 times).
+ */
+ status = scsiBusy;
+ goto exit;
+ }
+ /*
+ * We now own the SCSI bus. Try to select the device.
+ */
+ if ((status = SCSISelect(scsiDevice.targetID)) != noErr) {
+ switch (status) {
+ /*
+ * We get scBadParmsErr if we try to arbitrate for the initiator.
+ */
+ case scBadParmsErr: status = scsiTIDInvalid; break;
+ case scCommErr: status = scsiDeviceNotThere; break;
+ case scArbNBErr: status = scsiBusy; break;
+ case scSequenceErr: status = scsiRequestInvalid; break;
+ }
+ goto exit;
+ }
+ /*
+ * From this point on, we must exit through SCSIComplete() even if an
+ * error is detected. Send a command to the selected device. There are
+ * several failure modes, including an illegal command (such as a
+ * write to a read-only device). If the command failed because of
+ * "device busy", we will try it again.
+ */
+ status = SCSICmd((Ptr) scsiCommand, scsiCommandLen);
+ if (status != noErr) {
+ switch (status) {
+ case scCommErr: status = scsiCommandTimeout; break;
+ case scPhaseErr: status = scsiSequenceFailed; break;
+ }
+ }
+ if (status == noErr && dataBuffer != NULL) {
+ /*
+ * This command requires a data transfer.
+ */
+ if (scsiFlags == scsiDirectionOut) {
+ status = SCSIWrite((Ptr) tib);
+ } else {
+ status = SCSIRead((Ptr) tib);
+ }
+ switch (status) {
+ case scCommErr: status = scsiCommandTimeout; break;
+ case scBadParmsErr: status = scsiRequestInvalid; break;
+ case scPhaseErr: status = noErr; /* Don't care */ break;
+ case scCompareErr: /* Can't happen */ break;
+ }
+ }
+ /*
+ * SCSIComplete "runs" the bus-phase algorithm until the bitter end,
+ * returning the status and command-completion message bytes..
+ */
+ completionStatus = SCSIComplete(
+ &scsiStatusByte,
+ &scsiMsgByte,
+ 5 * 60L
+ );
+ if (status == noErr && completionStatus != noErr) {
+ switch (completionStatus) {
+ case scCommErr: status = scsiCommandTimeout; break;
+ case scPhaseErr: status = scsiSequenceFailed; break;
+ case scComplPhaseErr: status = scsiSequenceFailed; break;
+ }
+ }
+ if (completionStatus == noErr && scsiStatusByte == kScsiStatusBusy) {
+ /*
+ * ScsiComplete is happy. If the device is busy,
+ * pause for 1/4 second and try again.
+ */
+ watchdog = TickCount() + 15;
+ while (TickCount() < watchdog)
+ ;
+ continue; /* Do next totalTries attempt */
+ }
+ /*
+ * This is the normal exit (success) or final failure exit.
+ */
+ break;
+ } /* totalTries loop */
+exit:
+
+ if (bufferHoldFlag) {
+ (void) UnholdMemory(dataBuffer, dataLength);
+ }
+ /*
+ * Return the number of bytes transferred to the caller. If the caller
+ * supplied an actual count and the count is no greater than the maximum,
+ * ignore any phase errors.
+ */
+ if (actualTransferCount != NULL) {
+ *actualTransferCount = myTransferCount;
+ if (*actualTransferCount > dataLength) {
+ *actualTransferCount = dataLength;
+ }
+ }
+ /*
+ * Also, there is a bug in the combination of System 7.0.1 and the 53C96
+ * that may cause the real SCSI Status Byte to be in the Message byte.
+ */
+ if (scsiStatusByte == kScsiStatusGood
+ && scsiMsgByte == kScsiStatusCheckCondition) {
+ scsiStatusByte = kScsiStatusCheckCondition;
+ }
+ if (status == noErr) {
+ switch (scsiStatusByte) {
+ case kScsiStatusGood: break;
+ case kScsiStatusBusy: status = scsiBusy; break;
+ case 0xFF: status = scsiProvideFail; break;
+ default: status = scsiNonZeroStatus; break;
+ }
+ }
+ if (status == noErr
+ && (scsiFlags & scsiDirectionMask) != scsiDirectionNone
+ && myTransferCount != dataLength) {
+ status = scsiDataRunError;
+ }
+ if (scsiStatusBytePtr != NULL) {
+ *scsiStatusBytePtr = scsiStatusByte;
+ }
+ return (status);
+}
+
+
+UInt16
+GetCommandLength(
+ const SCSI_CommandPtr cmdPtr
+ )
+{
+ unsigned short result;
+ /*
+ * Look at the "group code" in the command operation. Return zero
+ * error for the reserved (3, 4) and vendor-specific command (6, 7)
+ * command groups. Otherwise, set the command length from the group code
+ * value as specified in the SCSI-II spec.
+ */
+ switch (cmdPtr->scsi6.opcode & 0xE0) {
+ case (0 << 5): result = 6; break;
+ case (1 << 5):
+ case (2 << 5): result = 10; break;
+ case (5 << 5): result = 12; break;
+ default: result = 0; break;
+ }
+ return (result);
+}
+
+
+Boolean
+IsVirtualMemoryRunning(void)
+{
+ OSErr status;
+ long response;
+
+ status = Gestalt(gestaltVMAttr, &response);
+ /*
+ * VM is active iff Gestalt succeeded and the response is appropriate.
+ */
+ return (status == noErr && ((response & (1 << gestaltVMPresent)) != 0));
+}
+
+
+void
+AllocatePB()
+{
+ OSErr status;
+ SCSIBusInquiryPB busInquiryPB;
+#define PB (busInquiryPB)
+
+ if (gSCSIExecIOPBPtr == NULL) {
+ CLEAR(PB);
+ PB.scsiPBLength = sizeof PB;
+ PB.scsiFunctionCode = SCSIBusInquiry;
+ PB.scsiDevice.bus = 0xFF; /* Get info about the XPT */
+ status = SCSIAction((SCSI_PB *) &PB);
+ if (status == noErr)
+ status = PB.scsiResult;
+ if (PB.scsiHiBusID == 0xFF) {
+ gSCSIHiBusID = -1;
+ } else {
+ gSCSIHiBusID = PB.scsiHiBusID;
+ }
+ gSCSIExecIOPBPtrLen = PB.scsiMaxIOpbSize;
+ if (gSCSIExecIOPBPtrLen != 0)
+ gSCSIExecIOPBPtr = (SCSIExecIOPB *) NewPtrClear(gSCSIExecIOPBPtrLen);
+ }
+#undef PB
+}
View
130 dist/pdisk/DoSCSICommand.h
@@ -0,0 +1,130 @@
+/*
+ * DoScsiCommand.h -
+ *
+ * Modifed by Eryk Vershen
+ * from an original by Martin Minow
+ */
+
+/*
+ * Copyright 1993-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.
+ */
+
+#ifndef __DoScsiCommand__
+#define __DoScsiCommand__
+
+#include <SCSI.h>
+#include "MacSCSICommand.h"
+
+
+/*
+ * Defines
+ */
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#define kOriginalSCSIBusAdaptor (0xFF)
+
+#define SameSCSIDevice(a, b) ((*((UInt32 *) &a)) == (*((UInt32 *) &b)))
+
+/*
+ * Cheap 'n dirty memory clear routine.
+ */
+#define CLEAR(dst) clear_memory((void *) &dst, sizeof dst)
+
+
+/*
+ * Types
+ */
+#if !defined(__NewTypesDefined__)
+#define __NewTypesDefined__
+typedef signed char SInt8;
+typedef signed short SInt16;
+typedef signed long SInt32;
+typedef unsigned char UInt8;
+typedef unsigned short UInt16;
+typedef unsigned long UInt32;
+typedef unsigned long ItemCount;
+typedef unsigned long ByteCount;
+#endif
+
+
+/*
+ * Global Constants
+ */
+enum {
+ bit0 = (1 << 0),
+ bit1 = (1 << 1),
+ bit2 = (1 << 2),
+ bit3 = (1 << 3),
+ bit4 = (1 << 4),
+ bit5 = (1 << 5),
+ bit6 = (1 << 6),
+ bit7 = (1 << 7)
+};
+
+
+/*
+ * Global Variables
+ */
+EXTERN int gSCSIHiBusID;
+EXTERN SCSIExecIOPB *gSCSIExecIOPBPtr;
+EXTERN UInt32 gSCSIExecIOPBPtrLen;
+
+
+/*
+ * Forward declarations
+ */
+void AllocatePB();
+Boolean IsIllegalRequest(OSErr scsiStatus, const SCSI_Sense_Data *senseDataPtr);
+Boolean IsNoMedia(OSErr scsiStatus, const SCSI_Sense_Data *senseDataPtr);
+/*
+ * All SCSI Commands come here.
+ * if scsiDevice.busID == kOriginalSCSIBusAdaptor, IM-IV SCSI will be called.
+ * scsiFlags should be scsiDirectionNone, scsiDirectionIn, or scsiDirectionOut
+ * actualTransferCount may be NULL if you don't care.
+ * Both old and new SCSI return SCSI Manager 4.3 errors.
+ *
+ * DoSCSICommand throws really serious errors, but returns SCSI errors such
+ * as dataRunError and scsiDeviceNotThere.
+ */
+OSErr DoSCSICommand(
+ DeviceIdent scsiDevice,
+ ConstStr255Param currentAction,
+ const SCSI_CommandPtr callerSCSICommand,
+ Ptr dataBuffer,
+ ByteCount dataLength,
+ UInt32 scsiFlags,
+ ByteCount *actualTransferCount,
+ SCSI_Sense_Data *sensePtr,
+ StringPtr senseMessage
+);
+
+
+#endif /* __DoScsiCommand__ */
View
68 dist/pdisk/HISTORY
@@ -0,0 +1,68 @@
+A short history of pdisk
+------------------------
+11/1996 - Spent a week to create a minimal partitioner
+ that reads maps, initializes maps, can add and delete partitions.
+ Released as version 0.1 to MkLinux team
+
+12/1996 - Spent three weeks adding more commands, writing
+ documentation, fixing bugs and making it prettier.
+ Released version 0.2 to Gilbert
+ Fixed a few more bugs.
+ Released as version 0.3
+
+01/1997 - Spent two weeks creating MacOS version and fixing
+ a few more bugs.
+ Released as version 0.4
+
+03/1997 - Spent an evening adding device driver deletion
+ and a couple of flags to private version.
+
+07/1997 - Some one else ported it to Rhapsody.
+ Spent a couple of weeks adding variable block
+ size support to Rhapsody version.
+ Took the time to stop using rich man's source code control
+ (multiple copies) in linux/mac and put sources under RCS.
+ Folded linux/mac version changes into Rhapsody and
+ brought some of the Rhapsody changes into linux/mac
+
+09/1997 - Fixed bugs in MacOS version of variable block size.
+ Added new dump routines.
+ Added case-insensitive string matching.
+ Released one copy of version 0.5a3 source internally.
+
+10/1997 - Wrote MacOS documentation
+ Minor fixes
+
+11/1997 - A few more fixes
+ Released as version 0.5
+
+12/1997 - Integrated new media abstraction
+ (includes support for ATA and ATAPI on MacOS)
+
+01/1998 - Added media iterators (to fix grunge in dump.c)
+ Added os_reload_media (to get rid of ioctl's in write_partition_map)
+ Added rename partition command ('n' in edit mode)
+ Added /dev/hd? and /dev/scd? to MkLinux list all disks
+ Added 68k target to CW project
+
+02/1998 - Released version 0.6
+ Added support for ATA/IDE disks without LBA capability
+ Fixed bug - create partition with unmodified size failed
+ Added support for new (DR3) MkLinux names - show MkLinux
+ name when displaying under another name and allow the
+ MkLinux name to be used on input.
+ Released version 0.7
+
+02-04/2000 - Clean up sources - fix naming, delete old email addresses
+ Added support for display of Mac volume names
+ Added cvt_pt target (for LinuxPPC team)
+ Fix block 0 display to show logical offset of drivers
+ Require confimation of quit without write
+ Fix iteration to not complain about missing devices
+ Warn when creating/writing a map with more than 15 entries
+ Make initial window larger in Mac version
+ Fix ATA support to scan buses correctly
+ Fix linux names (in MacOS) to work right when many devices
+ Change so WORM devices are considered 'CDs'
+
+05/2000 - Released version 0.8
View
420 dist/pdisk/MacSCSICommand.h
@@ -0,0 +1,420 @@
+/*
+ File: MacSCSICommand.h
+
+ Contains: SCSI specific definitions.
+
+ Written by: Martin Minow
+
+*/
+
+/*
+ * Copyright 1995, 1997 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.
+ */
+
+/*
+ * Scsi-specific definitions.
+ */
+#ifndef __MacSCSICommand__
+#define __MacSCSICommand__
+
+/*
+ * The 6-byte commands are used for most simple
+ * I/O requests.
+ */
+struct SCSI_6_Byte_Command { /* Six-byte command */
+ unsigned char opcode; /* 0 */
+ unsigned char lbn3; /* 1 lbn in low 5 */
+ unsigned char lbn2; /* 2 */
+ unsigned char lbn1; /* 3 */
+ unsigned char len; /* 4 */
+ unsigned char ctrl; /* 5 */
+};
+typedef struct SCSI_6_Byte_Command SCSI_6_Byte_Command;
+
+struct SCSI_10_Byte_Command { /* Ten-byte command */
+ unsigned char opcode; /* 0 */
+ unsigned char lun; /* 1 */
+ unsigned char lbn4; /* 2 */
+ unsigned char lbn3; /* 3 */
+ unsigned char lbn2; /* 4 */
+ unsigned char lbn1; /* 5 */
+ unsigned char pad; /* 6 */
+ unsigned char len2; /* 7 */
+ unsigned char len1; /* 8 */
+ unsigned char ctrl; /* 9 */
+};
+typedef struct SCSI_10_Byte_Command SCSI_10_Byte_Command;
+
+struct SCSI_12_Byte_Command { /* Twelve-byte command */
+ unsigned char opcode; /* 0 */
+ unsigned char lun; /* 1 */
+ unsigned char lbn4; /* 2 */
+ unsigned char lbn3; /* 3 */
+ unsigned char lbn2; /* 4 */
+ unsigned char lbn1; /* 5 */
+ unsigned char len4; /* 6 */
+ unsigned char len3; /* 7 */
+ unsigned char len2; /* 8 */
+ unsigned char len1; /* 9 */
+ unsigned char pad; /* 10 */
+ unsigned char ctrl; /* 11 */
+};
+typedef struct SCSI_12_Byte_Command SCSI_12_Byte_Command;
+
+/*
+ * This union defines all scsi commands.
+ */
+union SCSI_Command {
+ SCSI_6_Byte_Command scsi6;
+ SCSI_10_Byte_Command scsi10;
+ SCSI_12_Byte_Command scsi12;
+ unsigned char scsi[12];
+};
+typedef union SCSI_Command SCSI_Command, *SCSI_CommandPtr;
+
+/*
+ * Returned by a read-capacity command.
+ */
+struct SCSI_Capacity_Data {
+ unsigned char lbn4; /* Number */
+ unsigned char lbn3; /* of */
+ unsigned char lbn2; /* logical */
+ unsigned char lbn1; /* blocks */
+ unsigned char len4; /* Length */
+ unsigned char len3; /* of each */
+ unsigned char len2; /* logical block */
+ unsigned char len1; /* in bytes */
+};
+typedef struct SCSI_Capacity_Data SCSI_Capacity_Data;
+
+struct SCSI_Inquiry_Data { /* Inquiry returns this */
+ unsigned char devType; /* 0 Device type, */
+ unsigned char devTypeMod; /* 1 Device type modifier */
+ unsigned char version; /* 2 ISO/ECMA/ANSI version */
+ unsigned char format; /* 3 Response data format */
+ unsigned char length; /* 4 Additional Length */
+ unsigned char reserved5; /* 5 Reserved */
+ unsigned char reserved6; /* 6 Reserved */
+ unsigned char flags; /* 7 Capability flags */
+ unsigned char vendor[8]; /* 8-15 Vendor-specific */
+ unsigned char product[16]; /* 16-31 Product id */
+ unsigned char revision[4]; /* 32-35 Product revision */
+ unsigned char vendorSpecific[20]; /* 36-55 Vendor stuff */
+ unsigned char moreReserved[40]; /* 56-95 Reserved */
+};
+typedef struct SCSI_Inquiry_Data SCSI_Inquiry_Data;
+
+/*
+ * This bit may be set in SCSI_Inquiry_Data.devTypeMod
+ */
+enum {
+ kScsiInquiryRMB = 0x80 /* Removable medium if set */
+};
+/*
+ * These bits may be set in SCSI_Inquiry_Data.flags
+ */
+enum {
+ kScsiInquiryRelAdr = 0x80, /* Has relative addressing */
+ kScsiInquiryWBus32 = 0x40, /* Wide (32-bit) transfers */
+ kScsiInquiryWBus16 = 0x20, /* Wide (16-bit) transfers */
+ kScsiInquirySync = 0x10, /* Synchronous transfers */
+ kScsiInquiryLinked = 0x08, /* Linked commands ok */
+ kScsiInquiryReserved = 0x04,
+ kScsiInquiryCmdQue = 0x02, /* Tagged cmd queuing ok */
+ kScsiInquirySftRe = 0x01 /* Soft reset alternative */
+};
+
+/*
+ * These bits may be set in SCSI_Inquiry_Data.devType
+ */
+enum {
+ kScsiDevTypeDirect = 0,
+ kScsiDevTypeSequential,
+ kScsiDevTypePrinter,
+ kScsiDevTypeProcessor,
+ kScsiDevTypeWorm, /* Write-once, read mult */
+ kScsiDevTypeCDROM,
+ kScsiDevTypeScanner,
+ kScsiDevTypeOptical,
+ kScsiDevTypeChanger,
+ kScsiDevTypeComm,
+ kScsiDevTypeGraphicArts0A,
+ kScsiDevTypeGraphicArts0B,
+ kScsiDevTypeFirstReserved, /* Reserved sequence start */
+ kScsiDevTypeUnknownOrMissing = 0x1F,
+ kScsiDevTypeMask = 0x1F
+};
+/*
+ * These are device type qualifiers. We need them to distinguish between "unknown"
+ * and "missing" devices.
+ */
+enum {
+ kScsiDevTypeQualifierConnected = 0x00, /* Exists and is connected */
+ kScsiDevTypeQualifierNotConnected = 0x20, /* Logical unit exists */
+ kScsiDevTypeQualifierReserved = 0x40,
+ kScsiDevTypeQualifierMissing = 0x60, /* No such logical unit */
+ kScsiDevTypeQualifierVendorSpecific = 0x80, /* Other bits are unspecified */
+ kScsiDevTypeQualifierMask = 0xE0
+};
+#define kScsiDevTypeMissing \
+ (kScsiDevTypeUnknownOrMissing | kScsiDevTypeQualifierMissing)
+
+/*
+ * This is the data that is returned after a GetExtendedStatus
+ * request. The errorCode gives a general indication of the error,
+ * which may be qualified by the additionalSenseCode and
+ * additionalSenseQualifier fields. These may be device (vendor)
+ * specific values, however. The info[] field contains additional
+ * information. For a media error, it contains the failing
+ * logical block number (most-significant byte first).
+ */
+struct SCSI_Sense_Data { /* Request Sense result */
+ unsigned char errorCode; /* 0 Class code, valid lbn */
+ unsigned char segmentNumber; /* 1 Segment number */
+ unsigned char senseKey; /* 2 Sense key and flags */
+ unsigned char info[4];
+ unsigned char additionalSenseLength;
+ unsigned char reservedForCopy[4];
+ unsigned char additionalSenseCode;
+ unsigned char additionalSenseQualifier;
+ unsigned char fruCode; /* Field replacable unit code */
+ unsigned char senseKeySpecific[2];
+ unsigned char additional[101];
+};
+typedef struct SCSI_Sense_Data SCSI_Sense_Data;
+/*
+ * The high-bit of errorCode signals whether there is a logical
+ * block. The low value signals whether there is a valid sense
+ */
+#define kScsiSenseHasLBN 0x80 /* Logical block number set */
+#define kScsiSenseInfoValid 0x70 /* Is sense key valid? */
+#define kScsiSenseInfoMask 0x70 /* Mask for sense info */
+/*
+ * These bits may be set in the sense key
+ */
+#define kScsiSenseKeyMask 0x0F
+#define kScsiSenseILI 0x20 /* Illegal logical Length */
+#define kScsiSenseEOM 0x40 /* End of media */
+#define kScsiSenseFileMark 0x80 /* End of file mark */
+
+/*
+ * SCSI sense codes. (Returned after request sense).
+ */
+#define kScsiSenseNone 0x00 /* No error */
+#define kScsiSenseRecoveredErr 0x01 /* Warning */
+#define kScsiSenseNotReady 0x02 /* Device not ready */
+#define kScsiSenseMediumErr 0x03 /* Device medium error */
+#define kScsiSenseHardwareErr 0x04 /* Device hardware error */
+#define kScsiSenseIllegalReq 0x05 /* Illegal request for dev. */
+#define kScsiSenseUnitAtn 0x06 /* Unit attention (not err) */
+#define kScsiSenseDataProtect 0x07 /* Data protection */
+#define kScsiSenseBlankCheck 0x08 /* Tape-specific error */
+#define kScsiSenseVendorSpecific 0x09 /* Vendor-specific error */
+#define kScsiSenseCopyAborted 0x0a /* Copy request cancelled */
+#define kScsiSenseAbortedCmd 0x0b /* Initiator aborted cmd. */
+#define kScsiSenseEqual 0x0c /* Comparison equal */
+#define kScsiSenseVolumeOverflow 0x0d /* Write past end mark */
+#define kScsiSenseMiscompare 0x0e /* Comparison failed */
+#define kScsiSenseCurrentErr 0x70
+#define kScsiSenseDeferredErr 0x71
+
+/*
+ * Mode sense parameter header
+ */
+struct SCSI_ModeParamHeader {
+ unsigned char modeDataLength;
+ unsigned char mediumType;
+ unsigned char deviceSpecific;
+ unsigned char blockDescriptorLength;
+};
+typedef struct SCSI_ModeParamHeader SCSI_ModeParamHeader;
+
+struct SCSI_ModeParamBlockDescriptor {
+ unsigned char densityCode;
+ unsigned char numberOfBlocks[3];
+ unsigned char reserved;
+ unsigned char blockLength[3];
+};
+typedef struct SCSI_ModeParamBlockDescriptor SCSI_ModeParamBlockDescriptor;
+
+union SCSI_ModeParamPage {
+ unsigned char data[1];
+ struct {
+ unsigned char code;
+ unsigned char length;
+ } page;
+};
+typedef union SCSI_ModeParamPage SCSI_ModeParamPage;
+
+/*
+ * LogSense parameter header
+ */
+struct SCSI_LogSenseParamHeader {
+ unsigned char pageCode;
+ unsigned char reserved;
+ unsigned char pageLength[2];
+};
+typedef struct SCSI_LogSenseParamHeader SCSI_LogSenseParamHeader;
+
+/*
+ * Log parameter pages are variable-length with a fixed length header.
+ */
+union SCSI_LogSenseParamPage {
+ unsigned char data[1];
+ struct {
+ unsigned char parameterCode[2];
+ unsigned char flags;
+ unsigned char parameterLength;
+ } page;
+};
+typedef union SCSI_LogSenseParamPage SCSI_LogSenseParamPage;
+
+/*
+ * SCSI command status (from status phase)
+ */
+#define kScsiStatusGood 0x00 /* Normal completion */
+#define kScsiStatusCheckCondition 0x02 /* Need GetExtendedStatus */
+#define kScsiStatusConditionMet 0x04
+#define kScsiStatusBusy 0x08 /* Device busy (self-test?) */
+#define kScsiStatusIntermediate 0x10 /* Intermediate status */
+#define kScsiStatusResConflict 0x18 /* Reservation conflict */
+#define kScsiStatusQueueFull 0x28 /* Target can't do command */
+#define kScsiStatusReservedMask 0x3e /* Vendor specific? */
+
+/*
+ * SCSI command codes. Commands defined as ...6, ...10, ...12, are
+ * six-byte, ten-byte, and twelve-byte variants of the indicated command.
+ */
+/*
+ * These commands are supported for all devices.
+ */
+#define kScsiCmdChangeDefinition 0x40
+#define kScsiCmdCompare 0x39
+#define kScsiCmdCopy 0x18
+#define kScsiCmdCopyAndVerify 0x3a
+#define kScsiCmdInquiry 0x12
+#define kScsiCmdLogSelect 0x4c
+#define kScsiCmdLogSense 0x4d
+#define kScsiCmdModeSelect10 0x55
+#define kScsiCmdModeSelect6 0x15
+#define kScsiCmdModeSense10 0x5a
+#define kScsiCmdModeSense6 0x1a
+#define kScsiCmdReadBuffer 0x3c
+#define kScsiCmdRecvDiagResult 0x1c
+#define kScsiCmdRequestSense 0x03
+#define kScsiCmdSendDiagnostic 0x1d
+#define kScsiCmdTestUnitReady 0x00
+#define kScsiCmdWriteBuffer 0x3b
+
+/*
+ * These commands are supported by direct-access devices only.
+ */
+#define kScsiCmdFormatUnit 0x04
+#define kSCSICmdCopy 0x18
+#define kSCSICmdCopyAndVerify 0x3a
+#define kScsiCmdLockUnlockCache 0x36
+#define kScsiCmdPrefetch 0x34
+#define kScsiCmdPreventAllowRemoval 0x1e
+#define kScsiCmdRead6 0x08
+#define kScsiCmdRead10 0x28
+#define kScsiCmdReadCapacity 0x25
+#define kScsiCmdReadDefectData 0x37
+#define kScsiCmdReadLong 0x3e
+#define kScsiCmdReassignBlocks 0x07
+#define kScsiCmdRelease 0x17
+#define kScsiCmdReserve 0x16
+#define kScsiCmdRezeroUnit 0x01
+#define kScsiCmdSearchDataEql 0x31
+#define kScsiCmdSearchDataHigh 0x30
+#define kScsiCmdSearchDataLow 0x32
+#define kScsiCmdSeek6 0x0b
+#define kScsiCmdSeek10 0x2b
+#define kScsiCmdSetLimits 0x33
+#define kScsiCmdStartStopUnit 0x1b
+#define kScsiCmdSynchronizeCache 0x35
+#define kScsiCmdVerify 0x2f
+#define kScsiCmdWrite6 0x0a
+#define kScsiCmdWrite10 0x2a
+#define kScsiCmdWriteAndVerify 0x2e
+#define kScsiCmdWriteLong 0x3f
+#define kScsiCmdWriteSame 0x41
+
+/*
+ * These commands are supported by sequential devices.
+ */
+#define kScsiCmdRewind 0x01
+#define kScsiCmdWriteFilemarks 0x10
+#define kScsiCmdSpace 0x11
+#define kScsiCmdLoadUnload 0x1B
+/*
+ * ANSI SCSI-II for CD-ROM devices.
+ */
+#define kScsiCmdReadCDTableOfContents 0x43
+
+/*
+ * Message codes (for Msg In and Msg Out phases).
+ */
+#define kScsiMsgAbort 0x06
+#define kScsiMsgAbortTag 0x0d
+#define kScsiMsgBusDeviceReset 0x0c
+#define kScsiMsgClearQueue 0x0e
+#define kScsiMsgCmdComplete 0x00
+#define kScsiMsgDisconnect 0x04
+#define kScsiMsgIdentify 0x80
+#define kScsiMsgIgnoreWideResdue 0x23
+#define kScsiMsgInitiateRecovery 0x0f
+#define kScsiMsgInitiatorDetectedErr 0x05
+#define kScsiMsgLinkedCmdComplete 0x0a
+#define kScsiMsgLinkedCmdCompleteFlag 0x0b
+#define kScsiMsgParityErr 0x09
+#define kScsiMsgRejectMsg 0x07
+#define kScsiMsgModifyDataPtr 0x00 /* Extended msg */
+#define kScsiMsgNop 0x08
+#define kScsiMsgHeadOfQueueTag 0x21 /* Two byte msg */
+#define kScsiMsgOrderedQueueTag 0x22 /* Two byte msg */
+#define kScsiMsgSimpleQueueTag 0x20 /* Two byte msg */
+#define kScsiMsgReleaseRecovery 0x10
+#define kScsiMsgRestorePointers 0x03
+#define kScsiMsgSaveDataPointers 0x02
+#define kScsiMsgSyncXferReq 0x01 /* Extended msg */
+#define kScsiMsgWideDataXferReq 0x03 /* Extended msg */
+#define kScsiMsgTerminateIOP 0x11
+#define kScsiMsgExtended 0x01
+#define kScsiMsgEnableDisconnectMask 0x40
+
+#define kScsiMsgTwoByte 0x20
+#define kScsiMsgTwoByteMin 0x20
+#define kScsiMsgTwoByteMax 0x2f
+
+/*
+ * Default timeout times for SCSI commands (times are in Msec).
+ */
+#define kScsiNormalCompletionTime (500L) /* 1/2 second */
+/*
+ * Dratted DAT tape.
+ */
+#define kScsiDATCompletionTime (60L * 1000L); /* One minute */
+/*
+ * Yes, we do allow 90 seconds for spin-up of those dratted tape drives.
+ */
+#define kScsiSpinUpCompletionTime (90L * 1000L)
+
+
+#endif /* __MacSCSICommand__ */
View
147 dist/pdisk/README
@@ -0,0 +1,147 @@
+Product name: pdisk
+Version: 0.8
+Ship date: 16 May 2000
+Company name: n/a
+Author name: Eryk Vershen
+
+Description: A low-level Apple partition table editor for Linux.
+ A MacOS version exists for "standalone" use.
+
+What's New: Clean up sources - fix naming, delete old email addresses
+ Added support for display of Mac volume names
+ Added cvt_pt target (for LinuxPPC team)
+ Fix block 0 display to show logical offset of drivers
+ Require confimation of quit without write
+ Fix iteration to not complain about missing devices
+ Warn when creating/writing a map with more than 15 entries
+ Make initial window larger in Mac version
+ Fix ATA support to scan buses correctly
+ Fix linux names (in MacOS) to work right when many devices
+ Change so WORM devices are considered 'CDs'
+
+Last time: Added support for ATA/IDE disks without LBA capability
+ Fixed bug - create partition with unmodified size failed
+ Added support for new (DR3) MkLinux names - show MkLinux
+ name when displaying under another name and allow the
+ MkLinux name to be used on input.
+
+Requirements: Linux PPC - just run the binary
+ MacOS - Distributed binaries for PowerPC or 68000
+ I haven't tried it except on 7.6.1 and 8.0
+
+Price: Free
+
+Legalese:
+ Modifications copyright 2000 by Eryk Vershen
+
+ Copyright 1996,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.
+
+
+Contact Info: You can send mail to the author. There is no guarantee of
+ a response, but it is your best hope of getting a bug fixed
+ or a feature added.
+
+
+Other info:
+
+
+READ the html file or the man page.
+
+
+Finding out about apple partitioning
+------------------------------------
+The best curently available documentation on the Apple disk partitioning scheme
+is "Technote 1189: The Monster Disk Drive Technote". This release is not
+completely in sync with that technote. Maybe next time.
+
+
+Building the macintosh application
+----------------------------------
+I have only built this under Code Warrior Pro. The project file is included.
+Thanks to Martin Minow for the SCSI support code.
+
+
+Some notes on the apple partitioning
+------------------------------------
+The apple disk partitioning scheme was developed in 1986. It attempted to
+be forward thinking as it was intended to handle drives of sizes up to several
+hundred megabytes. There was a design document, but like most such documents
+it was neither complete nor unambiguous.
+
+While the original intent was to handle various block sizes, in practice
+most devices use a partitioning block size of 512 bytes.
+Since the various address fields are 32 bits unsigned this means the format
+can handle disks up to 2 Terabytes in size. (32bits + 9 bits = 41 bits)
+Because the format was designed around SCSI, there is no knowledge of
+cylinders or heads, all block address are in absolute sector form.
+A correct map should describe every block on the disk except for block zero.
+
+An aside on CDROMs. Most old apple CDROMs have incorrect data in block zero.
+Since the HFS file-system could only handle 512 byte blocks, apple drives had
+a special mode where they would do deblocking (i.e. converting 2k blocks
+into four 512byte blocks and accepting 512byte block addresses.) The partition
+maps laid down on these disks are for the deblocked form. In many cases the
+partition maps they contain have only the minimum number of fields correct.
+At least one CDROM I have seen doesn't even contain a partition map at all,
+but is simply an HFS volume.
+Bootable CD-ROMs have even stranger partition maps since two are laid down:
+one at 2K offsets and one at 512-byte offsets. If you notice that these
+overlap then you begin to get an idea of how wierd these maps can be.
+Apple refers to this "technique" as ghost partitioning.
+
+The documentation in Inside Macintosh is only partially correct.
+The boot-arguments field was left out. A/UX used the boot arguments field
+for something that was called the bzb (block zero block - don't ask me why).
+This structure evolved over the course of A/UX. I have recapitulated this
+in the dpme.h header file.
+
+
+Making a disk with Apple & Intel partitioning
+---------------------------------------------
+Don't cringe. I know it is an awful hack, but sometimes...
+While I don't recommend doing this, it can be useful.
+The procedure below is what we did.
+
+The intel map can contain NO MORE THAN FOUR PRIMARY PARTITIONS.
+You can't have any extended or logical partitions. (Well, you might get it
+to work but I wouldn't want to try it.) The disk will NOT BE INTEL BOOTABLE.
+
+1) Use pdisk to initialize an apple partition map. Don't add any partitions
+ yet, just write the map out and quit.
+
+2) Use fdisk to create the primary partitions. Go into the expert 'x' menu
+ in fdisk and print out the table with the sector addresses. Write the
+ start and lengths down some where. Write the table out.
+
+3) Use pdisk again. Shrink the partition map down, if necessary, so it
+ does not overlap any intel partition. Create an apple partition for each
+ intel partition using the start and length value you got from fdisk.
+ Write out the map and quit.
+
+At present file systems are not compatible between Linux & MkLinux, but you
+can tar stuff into these partitions and tar them out on another machine.
+
+
+
+Good luck,
+
+-eryk vershen
+ software mechanic
+ eryk@cfcl.com