File:  [Apple Darwin 0.x] / driverkit / libDriver / IODiskPartition.m
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 17:37:51 2018 UTC (8 years, 3 months ago) by root
Branches: MAIN, Apple
CVS tags: HEAD, Darwin03, Darwin02
Darwin 0.2 Driver Kit

/*
 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 * 
 * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
 * Reserved.  This file contains Original Code and/or Modifications of
 * Original Code as defined in and that are subject to the Apple Public
 * Source License Version 1.1 (the "License").  You may not use this file
 * except in compliance with the License.  Please obtain a copy of the
 * License at http://www.apple.com/publicsource and read it before using
 * this file.
 * 
 * The Original Code and all software distributed under the License are
 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT.  Please see the
 * License for the specific language governing rights and limitations
 * under the License.
 * 
 * @APPLE_LICENSE_HEADER_END@
 */
/* 	Copyright (c) 1991 NeXT Computer, Inc.  All rights reserved. 
 *
 * IODiskPartition.m - implementation of NeXT-style logical disk.
 *
 * HISTORY
 * 22-Jan-98	radar 1669467 - ISO 9660 CD support - jwc
 * 15-Dec-92	Sam Streeper (sam) at NeXT
 *	Added support for a NeXT disk on a MS-DOS partition
 * 01-May-91    Doug Mitchell at NeXT
 *      Created.
 */

#define DRIVER_PRIVATE 1

#import <driverkit/return.h>
#import <driverkit/IODiskPartition.h>
#import <driverkit/generalFuncs.h>
#import <bsd/dev/disk_label.h>
#import <bsd/sys/disktab.h>
#ifdef	KERNEL
#import <kernserv/prototypes.h>
#import <driverkit/kernelDiskMethods.h>
#import <driverkit/kernelDiskMethodsPrivate.h>
#import <driverkit/kernelDriver.h>
#import <machkit/NXLock.h>
#else	KERNEL
#import <bsd/libc.h>
#endif	KERNEL
#import <kern/time_stamp.h>
#import <driverkit/Device_ddm.h>
#import <mach/vm_param.h>
#import <driverkit/disk_label.h>
#import <driverkit/diskstruct.h>
#ifdef	i386
#import <bsd/dev/i386/disk.h>
#endif	i386
#import <architecture/byte_order.h>
#import "label_subr.h"
#import <driverkit/IODeviceDescription.h>
#import <bsd/dev/voldev.h>
#ifdef	ppc
#import <bsd/dev/ppc/disk.h>
#endif

/* Define GROK_DOS if scsi driver is to understand MS-DOS partitions.
 * It only finds the partition with the NeXT name.  Live partition is
 * not affected.  -sam
 *
 * define GROK_APPLE if we want to look to a Rhapsody partition on a
 * Apple Partitioned disk
 */
#ifdef i386
#define	GROK_DOS
#endif

#ifdef ppc
#define GROK_APPLE 1
#endif

// seconds to wait for disk ready at probe time
#define DELAY_AT_PROBE	0

#ifdef GROK_APPLE //bknight - 12/3/97 - Radar #2004660

#define HFS_PART_TYPE "Apple_HFS"

#endif //bknight - 12/3/97 - Radar #2004660


@interface IODiskPartition(Private)

/*
 * Private methods.
 */				  
/*
 * Examine a known good label, initialize LogicalDisk parameters for the
 * raw device (on which this method is invoked) and create block devices
 * as appropriate.
 *
 * Invoked by LogicalDisk +probe, upon disk insertion, and when a new label
 * is written.
 */
- (void) _probeLabel		: (disk_label_t *)labelp;

/*
 * Assign logical disk parameters for a partition instance.
 */
- (void)_initPartition		: (int)partNum
              physicalPartition : (int)physNum	
                        disktab : (struct disktab *)dtp;
				  
/*
 * Free all partition instances other than partition 0.
 */
- (IOReturn)_freePartitions;

/*
 * Determine if any block devices in the logicalDisk chain are open.
 */
- (BOOL)isAnyBlockDevOpen;

/*
 * Verify that it's safe to do an operation which will result in a call
 * to _freePartitions.
 */
- (IOReturn)checkSafeConfig	: (const char *)op;

#ifdef GROK_APPLE //bknight - 12/3/97 - Radar #2004660

/*
 * IODiskPartition knows how to
 * Create HFS Devices From Apple Partition Map.
 */
+ (void)CreateHFSDevicesFromApplePartitionMap : (id)physicalDisk;

/*
 * Assign logical disk parameters for a partition instance.
 */

- (void)	_initHFSPartition : (int) partitionNum
			physicalPartNum : (int) physNum
			diskSize : (int) diskSize
			partitionBase : (int) partitionBase;

#endif GROK_APPLE //bknight - 12/3/97 - Radar #2004660
				  
@end


@implementation IODiskPartition

+ (IODeviceStyle)deviceStyle
{
	return IO_IndirectDevice;
}

/*
 * The protocol we need as an indirect device.
 */
static Protocol *protocols[] = {
	@protocol(IOPhysicalDiskMethods),
	@protocol(IODiskReadingAndWriting),
	nil
};

+ (Protocol **)requiredProtocols
{
	return protocols;
}

/*
 * Attempt to read label of physical device. If valid label, create an 
 * instance of LogicalDisk for each valid partition as well as for the 
 * Unix raw device. Returns YES if any instances were created. 
 */
+ (BOOL)probe : deviceDescription
{
	id		physDisk = [deviceDescription directDevice];
	int 		try;
	IODiskReadyState 	ready;
	IOReturn 	rtn;
	disk_label_t 	*labelp = NULL;
	IODiskPartition *part0p;
	BOOL 		frtn = YES;	// when would this be NO?
	char 		name[30];
	id 		ld;
	const char 	*physName = [physDisk name];
	unsigned	physBlockSize = 0;
	unsigned	physDiskSize = 0;
	unsigned	formattedFlag;
	BOOL		logParams = NO;
	BOOL		logLabel = NO;
	IODiskReadyState	oldReady;
	
	xpr_disk("IODiskPartition probe\n", 1,2,3,4,5);
	/*
	 * First of all, we're only interested in physical disks.
	 * (Shouldn't this be covered by our requiredProtocols values?)
	 */
	if(![physDisk isPhysical]) {
		return NO;
	}
	
	/*
	 * Create a partition 0 instance if there isn't already one; attach 
	 * it to physDisk. There will already be a partition 0 instance if 
	 * this probe is in response to a disk insertion as opposed to 
	 * initial device configuration.
	 */
	ld = [physDisk nextLogicalDisk];
	if(ld != nil) {
		part0p = (IODiskPartition *)ld;
		
		/*
		 * Update physical parameters.
		 */
		[part0p connectToPhysicalDisk:physDisk];
		part0p->_labelValid = 0;    
        	part0p->_physicalPartition = 0;

#ifdef GROK_APPLE //bknight - 12/3/97 - Radar #2004660
		part0p->_hfsValid = 0;    
#endif GROK_APPLE //bknight - 12/3/97 - Radar #2004660
		part0p->_blockDeviceOpen = 0;
		part0p->_rawDeviceOpen = 0;
		IOLog("\n");
	}
	else {
		part0p = [IODiskPartition new];
		sprintf(name, "%sa", physName);
		[part0p setName:name];
		[part0p setDeviceKind:"IODiskPartition"];
		[part0p setDriveName:"IODiskPartition Partition"]; 
		[part0p setLocation:NULL];
                part0p->_partitionWaitLock = [[NXConditionLock alloc] init];
		IOGetTimestamp( &part0p->_probeTime);
		[part0p init];
		[part0p connectToPhysicalDisk:physDisk];
                [part0p setDeviceDescription:deviceDescription];
		[physDisk setLogicalDisk:part0p];
		part0p->_labelValid = 0;    
#ifdef GROK_APPLE //bknight - 12/3/97 - Radar #2004660
		part0p->_hfsValid = 0;    
#endif GROK_APPLE //bknight - 12/3/97 - Radar #2004660
		part0p->_blockDeviceOpen = 0;
		part0p->_rawDeviceOpen = 0;
	
#ifdef	KERNEL
		/*
		 * Register both physDisk and partition 0 with Unix 
		 * level owner.
		 */
		[physDisk registerUnixDisk:0];
		[part0p registerUnixDisk:0];
#endif	KERNEL
	}
	
	/*
	 * Give the drive a chance to spin up.
	 */
	oldReady = [physDisk lastReadyState];

#if DELAY_AT_PROBE
	if( (physName[0] == 'f') && (physName[1] == 'd'))
	    ready = [physDisk updateReadyState];
	else {
	    for(try = 0; try < DELAY_AT_PROBE; try++) {
		ready = [physDisk updateReadyState];
		switch(ready) {
		    case IO_Ready: 	
		    	goto goOn;		/* go for it */
		    case IO_NotReady:
		    	break;			/* try again */
		    case IO_NoDisk:
		    	if (try > 0)
			    IOLog("\n");
			goto done;		/* forget it */
		    case IO_Ejecting:	
			break;			/* try again */
		}
		if(try == 0)
			IOLog("%s: Waiting for drive to come ready", physName);
		else
			IOLog(".");
		IOSleep(1000);
	    }
	  goOn:
	    if (try > 0)
		IOLog("\n");
	}
#else
        ready = [physDisk updateReadyState];
#endif
	[physDisk setLastReadyState:ready];
	if(ready != IO_Ready) {
		IOLog("%s: Disk Not Ready\n", physName);
		xpr_disk("IODiskPartition probe: Disk Not Ready\n", 1,2,3,4,5);
		goto done;
	}

	/*
	 * If the disk just came ready, have driver update its physical 
	 * parameters.
	 */
	if(oldReady != IO_Ready) {
		[physDisk updatePhysicalParameters];
	}
		
	/*
	 * If disk is not formatted, forget the rest of this.
	 */
	formattedFlag = [physDisk isFormatted];
	if(!formattedFlag) {
		IOLog("%s: Disk Unformatted\n", physName);
		xpr_disk("IODiskPartitionProbe: physDisk %s not formatted\n", 
			physName, 2,3,4,5);
		goto done;
	}

	physDiskSize = [physDisk diskSize];
	physBlockSize = [physDisk blockSize];

	[part0p setPhysicalBlockSize:physBlockSize];

	logParams = YES;

	/*
	 * Try to read a label.
	 */
	labelp = IOMalloc(sizeof(disk_label_t));
	rtn = [part0p readLabel:labelp];
	if(rtn) {		
		xpr_disk("IODiskPartition probe: No Label\n", 1,2,3,4,5);
		IOLog("%s: No Valid Disk Label\n", physName);
		
		/*
		 * Set up blockSize and diskSize of partition A
		 * to be the same as our physicalDisk's for now.
		 */
		[part0p setBlockSize:physBlockSize];
		[part0p setDiskSize:[physDisk diskSize]];

		/* Remember to reset the partition base to zero,
		 * since we don't yet have any recognizable
		 * partitioning information.
		 */
		[part0p setPartitionBase:0];
	}
	else {
		logLabel = YES;
	
		/*
		 * Initialize remaining device parameters and create 
		 * additional partition instances as appropriate.
		 */
		[part0p _probeLabel:labelp];
	}

#ifdef GROK_APPLE //bknight - 12/3/97 - Radar #2004660

	[self CreateHFSDevicesFromApplePartitionMap:deviceDescription];

#endif GROK_APPLE //bknight - 12/3/97 - Radar #2004660

	if( part0p->_partitionWaitLock) {
            [part0p->_partitionWaitLock lock];
            [part0p->_partitionWaitLock unlockWith:YES];
	}
done:
	if(logParams) {
		unsigned kbytes;
		
		IOLog("%s: Device Block Size: %u bytes\n",
			physName, physBlockSize);
		kbytes = (physDiskSize / 1024) * physBlockSize;
		if(kbytes > (10 * 1024)) {
			IOLog("%s: Device Capacity:   %u MB\n", 
				physName, kbytes / 1024);
		}
		else {
			IOLog("%s: Device Capacity:   %u KB\n", 
				physName, physDiskSize * physBlockSize / 
				1024);
		}
	}
	if(logLabel) {
		IOLog("%s: Disk Label:        %s\n", 
			physName, labelp->dl_label);
	}
	if(labelp != NULL) {
		IOFree(labelp, sizeof(disk_label_t));
	}

	if(ld == nil)
		[part0p registerDevice];

	return(frtn);
}

#ifdef GROK_DOS
/* returns the offset to the NeXT partition of an MSDOS partitioned
 * hard disk (0 if it isn't a DOS disk), or a (negative) IOReturn.  
 */
- (int) NeXTpartitionOffset
{
	IOReturn 		frtn = 0;
	IOReturn 		rtn;
	unsigned		bytesXfr;
	id 			physDisk = [self physicalDisk];
	/*
	 * Force page alignment...
	 */
	unsigned char		*blk= IOMalloc(PAGE_SIZE);
	struct disk_blk0	*blk0;
	struct fdisk_part	*fd;
	int			n;
	BOOL			validPart = NO;
	
	if ([self physicalBlockSize] != DISK_BLK0SZ) {
		frtn = 0;
		goto out;
	}
	// fixme - can I really transfer to unwired, unaligned buffer?
        rtn = [[super class] commonReadWrite
		    : physDisk
		    : YES			/* read */
		    : (unsigned long long)DISK_BLK0 * [physDisk blockSize]
		    : DISK_BLK0SZ 	/* bytes */
		    : blk
		    : IOVmTaskSelf()
		    : (void *)NULL
		    : &bytesXfr];

	if (rtn) {
		frtn = IO_R_NO_BLOCK_ZERO;
		goto out;
	}

	// Check for a valid DOS boot block.
	blk0 = (struct disk_blk0 *)blk;
	if (blk0->signature != DISK_SIGNATURE) {
		goto out;
	}

	// Check to see if the disk has been partitioned with FDISK
	// to allow DOS and ufs filesystems to exist on the same disk
	fd = (struct fdisk_part *)blk0->parts;    
	for (n = 0; n < FDISK_NPART; n++, fd++) {
		switch(fd->systid) {
		    case 0:
		    	/*
			 * Not valid partition, meaningless.
			 */
			break;
		    case FDISK_NEXTNAME:
		    	/*
			 * Valid NeXT partition.
			 */
			frtn = fd->relsect;
                        _physicalPartition = n;
			goto out;
		    default:
		    	/*
			 * Not what we're looking for, but this means that
			 * we can't use partition 0.
			 */
			validPart = YES;
			break;
		}
	}
	if(validPart) {
		frtn = IO_R_NO_NEXT_PART;
	}
	else {
		/*
		 * No valid partitions; treat same as "no valid block 0".
		 */
	}
out:
	IOFree(blk, PAGE_SIZE);
	return frtn;
}
#endif	GROK_DOS

#ifdef GROK_APPLE
/*
 * Check for an apple partition:
 *
 */
#define BLOCKSIZE_512_BYTES	512

- (int) NeXTpartitionOffset
{
	unsigned char *		blk;
	Block0 *		blk0;
	unsigned long 		blocksize = [self physicalBlockSize];
	unsigned		bytesXfr;
	IOReturn 		frtn = 0;
	id	 		physDisk = [self physicalDisk];
	IOReturn 		rtn;

	blk = IOMalloc(PAGE_SIZE); /* force page alignment */
	blk0 = (Block0 *)blk;

	/* check block 0 for valid Apple partition signature */

        rtn = [[super class] commonReadWrite
            			: physDisk
				: YES			/* read */
				: (unsigned long long)0 /* byte offset */
				: PAGE_SIZE 	/* bytes */
				: blk
				: IOVmTaskSelf()
				: (void *)NULL
				: &bytesXfr];
        
        /* scan for the rhapsody apple ufs partition */
	if (rtn)
	    frtn = IO_R_NO_BLOCK_ZERO;
	else {
	    unsigned int		block = 1;
	    unsigned int		entry_within_block = 0;
	    int				n;
	    unsigned int		nentries_per_block = 1;
	    unsigned int		numPartBlocks;
	    DPME *			partEntry;
	    int				physNum;

	    /* check if there is a valid map at 512 offset */
	    partEntry = (DPME *)(blk + BLOCKSIZE_512_BYTES);
	    if (blocksize > BLOCKSIZE_512_BYTES) {
		if (NXSwapBigShortToHost(partEntry->dpme_signature) 
		    == DPME_SIGNATURE) {
		    /* there is a valid map, and the device blocksize
		     * is > 512, which means we probably have a CDROM
		     * using 2K, but having valid 512 map
		     */
		    block = 0;
		    nentries_per_block = blocksize / BLOCKSIZE_512_BYTES;
		    entry_within_block = 1;
		}
		else
		    partEntry = (DPME *)(blk + blocksize);
	    }
	  if (NXSwapBigShortToHost(partEntry->dpme_signature) == DPME_SIGNATURE) {
	    numPartBlocks = NXSwapBigLongToHost(partEntry->dpme_map_entries);
#ifdef PRINT_APT
	    IOLog("Apple Partition table (%d entries)...\n", numPartBlocks);
#endif PRINT_APT

            physNum = 1;
	    for (n = 0; n < numPartBlocks; n++) {
		int ufs_partition_set = 0;

		if (NXSwapBigShortToHost(partEntry->dpme_signature) 
		    != DPME_SIGNATURE) {
		    break;
		}
		if (strcmp(partEntry->dpme_type, RHAPSODY_PART_TYPE) == 0
		    && ufs_partition_set == 0) {
		    unsigned long part_offset;

		    part_offset 
			= NXSwapBigLongToHost(partEntry->dpme_pblock_start);
		    if ((part_offset / nentries_per_block * nentries_per_block)
			!= part_offset) {
			IOLog("IODiskPartition: " RHAPSODY_PART_TYPE
			      " partition base (%ld x 512) is not"
			      " a multiple of the devblksize %ld\n",
			      part_offset, blocksize);
			frtn = IO_R_NO_NEXT_PART;
			break;
		    }
	
		    part_offset = part_offset / nentries_per_block;
#ifdef PRINT_APT
		    IOLog("%s: UFS partition at offset %ld\n",
			  [physDisk name], part_offset);
#endif PRINT_APT
		    frtn = (IOReturn)part_offset;
		    ufs_partition_set = 1;
                    _physicalPartition = physNum;
		}
#ifdef PRINT_APT
		IOLog("Apple Partition entry %d:\n", n + 1);
		IOLog("  Name: %s, Type %s, size: %d\n", 
		       partEntry->dpme_name, partEntry->dpme_type,
		       partEntry->dpme_pblocks);
		IOLog("block %d entry %d (of %d) blocksize %d\n", 
		       block, entry_within_block + 1,
		       nentries_per_block, blocksize);
#endif PRINT_APT
		partEntry++;
                physNum++;
		if (++entry_within_block == nentries_per_block) {
		    block++;
		    entry_within_block = 0;
		    partEntry = (DPME *)blk;

		    rtn = [[super class] commonReadWrite
            			: physDisk
 				: YES			/* read */
		    : (unsigned long long)block * blocksize /* byte offset */
				: blocksize 	/* bytes */
				: blk
				: IOVmTaskSelf()
				: (void *)NULL
				: &bytesXfr];
                   
		    if (rtn) {
			frtn = IO_R_NO_NEXT_PART;
			break;
		    }
		}
	    }
	  } /* DPME signature validation */
	} /* scan for Apple rhapsody ufs partitions */
	IOFree(blk, PAGE_SIZE);
	return frtn;
}

- getDevicePath:(char *)path maxLength:(int)maxLen useAlias:(BOOL)doAlias
{
    if( [[self physicalDisk] 
	getDevicePath:path maxLength:maxLen useAlias:doAlias]) {

	char partStr[ 12 ];

	sprintf( partStr, ":%x", _physicalPartition);
	strcat( path, partStr);
	return( self);
    }
    return( nil);
}

#endif GROK_APPLE

/*
 * Read disk label. label_p must does not have to be aligned; we do a
 * page-aligned read to satisfy any possible DMA requirements.
 *
 * This is only invoked on the raw device. This can be invoked on a 
 * drive with no disk present; we'll do a 'isDiskReady:YES" to get a 
 * disk if necessary.
 *
 * This reads labels as raw m68k disk_label_t's. On successful return,
 * *label_p contains a label which is valid for the current architecture;
 * the transformation is performed per the API in <driverkit/disk_label.h>.
 */

- (IOReturn) readLabel	: (disk_label_t *)label_p
{
	int 			label_num;
	IOReturn 		rtn;
	int 			found = 0;
	int 			blocksInLabel;
	int 			bytesInLabel;
	unsigned		bytesXfr;
	char			*raw_label;
	int 			labelBufSize;
	id 			physDisk = [self physicalDisk];
	unsigned		physBlockSize = [self physicalBlockSize];
	unsigned		physFormatted;
        unsigned		blocksize;
	const char 		*disk_name = [self name];
	/* offset of NeXT disk on dos or Apple partition */
	int			part_offset = 0;
	
	xpr_disk("IODiskPartition readLabel\n", 1,2,3,4,5);
	
	/*
	 * Note we have to 'fault in' a possible non-present disk in 
	 * order to get its physical parameters...
	 */
	rtn = [physDisk isDiskReady:YES];
	switch(rtn) {
	    case IO_R_SUCCESS:
	    	break;
	    case IO_R_NO_DISK:
		xpr_err("%s readLabel: disk not present\n", disk_name, 
			2,3,4,5);
		return(rtn);
	    default:
	    	IOLog("%s readLabel: bogus return from isDiskReady (%s)\n",
			disk_name, [self stringFromReturn:rtn]);
		return(rtn);
	}
	
	physFormatted = [physDisk isFormatted];
	if((physBlockSize == 0) || !physFormatted) {
		xpr_err("%s readLabel: physDisk UNFORMATTED\n", 
			disk_name, 2,3,4,5);
		return(IO_R_UNFORMATTED);
	}
	
#if defined(GROK_DOS) || defined(GROK_APPLE)
	part_offset = [self NeXTpartitionOffset];
	if (part_offset < 0) {
		return part_offset;
	}
#ifdef	DEBUG
	if (part_offset > 0) {
		printf("found NeXT disk partition at offset"
			", offset = %d sectors\n", part_offset);
	}
#endif	DEBUG
#endif defined(GROK_DOS) || defined(GROK_APPLE)

	/*
	 * Careful, we're reading in an m68k-style label...
	 */
	blocksInLabel = howmany(SIZEOF_DISK_LABEL_T, physBlockSize);
	bytesInLabel = blocksInLabel * physBlockSize;
	labelBufSize = round_page(bytesInLabel);
	
	/*
	 * This assumes that the memory allocator used by IOMalloc will 
	 * return one physically contiguous page if we ask it for one
	 * page...should be OK, right?
	 * This used to be vm_allocate(), but can't DMA to IOTask's
	 * virtual memory.
	 */
	raw_label = IOMalloc(labelBufSize);
	for(label_num=0; label_num<NLABELS; label_num++) {

	/* To read a disk label, we *should* use the blocksize of the
	 * enclosing partition, but we don't know what that is.
	 *
	 * As a workaround, we can use the *physical* blocksize. By
	 * doing so, we will always compute the proper offset for
	 * fixed disks using Mac, FDISK, or *no* partitioning scheme,
	 * since all these schemes assume a 512 byte blocksize.
	 * (It is possible for a Mac partition map to imply a non-512
	 * blocksize, but in practice this is rare).
	 *
	 * Using the physical blocksize would not iterate properly
	 * through all four labels on a Mac-partitioned CD-ROM, because
	 * we'd be using 2K blocks instead of the Mac partition's 512.
	 * This, however, *still* luckily works because the first label
	 * is at offset zero: offset zero is always the same no matter
	 * what you're multiplying by to get that zero!
	 *
	 * Once we find a valid label (often the one at offset zero),
	 * we immediately reset our logical blocksize, so after that
	 * point things work normally.
	 */

	blocksize = [physDisk blockSize];

       		rtn = [[super class] commonReadWrite
                    		: physDisk
				: YES			/* read */
				: ((unsigned long long)part_offset + 
					(label_num * blocksInLabel))
					    * blocksize /* byte offset */
				: bytesInLabel 	/* bytes */
				: raw_label
				: IOVmTaskSelf()
				: (void *)NULL
				: &bytesXfr];
            if((rtn == IO_R_SUCCESS) &&
		   (bytesXfr == bytesInLabel)) {
			
			/*
			 * Is it a valid disk label?
			 */
			const char *rtn;
			
			rtn = check_label(raw_label, 
				part_offset + (label_num*blocksInLabel));
			if(rtn == NULL) {
				found++;
				break;
			}
#ifdef	DEBUG
			else {
				IOLog("%s\n", rtn);
			}
#endif	DEBUG
		}
		
		/*
		 * there is one fatal error here - disk not present.
		 */
		if(rtn == IO_R_NO_DISK)
			break;
	}

	if(found) {
		/*
		 * Success. 
		 */
		xpr_disk("readLabel: Valid Label\n", 1,2,3,4,5);
		_labelValid = 1;
#ifdef GROK_APPLE //bknight - 12/3/97 - Radar #2004660
		_hfsValid = 0;			// bek - 12/14/97 - Is this redundant?
#endif GROK_APPLE //bknight - 12/3/97 - Radar #2004660
		get_disk_label(raw_label, label_p);
		rtn = IO_R_SUCCESS;
	}
	else {
		xpr_disk("readLabel: NO LABEL\n", 1,2,3,4,5);
		if(rtn != IO_R_NO_DISK)
			rtn = IO_R_NO_LABEL;
	}
	IOFree(raw_label, labelBufSize);
	return(rtn);
}

/*
 * Write disk label. Label is passed in as an actual native label per 
 * current architecture and is written as an m68k-style label.
 */

static inline void put_short(unsigned short s, void *dest)
{
	*((unsigned short *)dest) = NXSwapHostShortToBig(s);
}

- (IOReturn) writeLabel : (disk_label_t *)label_p
{
	unsigned 		size;
	unsigned short 		*cksum_p;
	unsigned short		cksum;
	ns_time_t 		timestamp;
	int 			label_num;
	unsigned		bytesXfr;
	int 			goodLabel = 0;
	IOReturn 		rtn;
	int 			blocksInLabel;
	int 			bytesInLabel;
	id 			physDisk = [self physicalDisk];
	unsigned		physBlockSize = [self physicalBlockSize];
	char		 	*raw_label = NULL;
	int 			labelBufSize = 0;	/* compiler quirk */
	unsigned		formattedFlag = 0;
	const char 		*lrtn;
	int			cksum_offset;
	/* offset of NeXT disk on dos or Apple partition */
	int			part_offset = 0;
#ifdef	i386
	/*
	 * Avoid writing first label over block 0.
	 */
	int			firstLabel = 1;
#else	i386
	int			firstLabel = 0;
#endif	i386

	xpr_disk("IODiskPartition writeLabel\n", 1,2,3,4,5);
	
	/*
	 * We can't do this if any block devices, or any other logical disk, 
	 * are currently open. Also, we can only do this on partition 0
	 * because we're going to blow away all IODiskPartitions other than the
	 * one for partition 0 before we're thru.
	 */
	rtn = [self checkSafeConfig:"writeLabel"];
	if(rtn) {
		return rtn;
	}

	/*
	 * Lock out similar destructive actions...
	 */
	[physDisk lockLogicalDisks];
	
	formattedFlag = [physDisk isFormatted];
	if(!formattedFlag) {
		xpr_disk("IODiskPartition writeLabel: UNFORMATTED DISK\n",
			1,2,3,4,5);
		rtn = IO_R_IO;
		goto done;
	}
	
	/*
	 * OK, here we go. All other partitions are now invalid. Let's
	 * get rid of them.
	 */
	[self _freePartitions];
	_labelValid = 0;			// until we're thru
#ifdef GROK_APPLE //bknight - 12/3/97 - Radar #2004660
	_hfsValid = 0;			// until we're thru
#endif GROK_APPLE //bknight - 12/3/97 - Radar #2004660
	
	if(label_p->dl_version == DL_V1 || label_p->dl_version == DL_V2) {
		size = SIZEOF_DISK_LABEL_T;
		cksum_p = &label_p->dl_checksum;
		cksum_offset = DISK_LABEL_DL_CHECKSUM;
	} else if(label_p->dl_version == DL_V3) {
		size = SIZEOF_DISK_LABEL_T - SIZEOF_DL_UN_T;
		cksum_p = &label_p->dl_v3_checksum;
		cksum_offset = DISK_LABEL_DL_UN;
	}
	else {
		IOLog("%s writeLabel: BAD LABEL\n", [self name]);
		rtn = IO_R_INVALID_ARG;
		goto done;
	}
		
	/*
	 * tag label with time.
	 */
	IOGetTimestamp(&timestamp);
	label_p->dl_tag = (unsigned)timestamp;
	
	/*
	 * prepare to validate (before converting to m68k-style label).
	 */
	label_p->dl_label_blkno = 0;
	*cksum_p = 0;
	
	/*
	 * Get an m68k-style label for validation (and which we'll eventually
	 * write to disk). We do page alignment here to satisfy the most 
	 * stringent DMA requirements downstream.
	 */
	blocksInLabel = howmany(SIZEOF_DISK_LABEL_T, physBlockSize);
	bytesInLabel = blocksInLabel * physBlockSize;
	labelBufSize = round_page(bytesInLabel);
	raw_label = IOMalloc(labelBufSize);
	put_disk_label(label_p, raw_label);

	/*
	 * Get checksum and validate. Careful, put the checksum in the 
	 * raw m68k-style label in a machine-independent manner...
	 */
	cksum = checksum16((unsigned short *)raw_label, size >> 1);
	put_short(cksum, raw_label + cksum_offset);
	if(lrtn = check_label(raw_label, 0)) {
		IOLog("%s writeLabel: BAD LABEL : %s\n", 
			[self name], lrtn);
		rtn = IO_R_INVALID_ARG;
		goto done;
	}
		
#if defined(GROK_DOS) || defined(GROK_APPLE)
	part_offset = [self NeXTpartitionOffset];
	if (part_offset < 0) {
		rtn = part_offset;
		goto done;
	}
#endif defined(GROK_DOS) || defined(GROK_APPLE)

	/*
	 * OK, the caller gave us a good label. Write NLABEL copies.
	 */
	for(label_num=firstLabel; label_num<NLABELS; label_num++) {
		*(int *)(raw_label + DISK_LABEL_DL_LABEL_BLKNO ) = 
			NXSwapHostIntToBig(part_offset + 
				(label_num * blocksInLabel));

       		rtn = [[super class] commonReadWrite
                    		: physDisk
				: NO			/* write */
				: ((unsigned long long)part_offset + 
					(label_num * blocksInLabel))
					    * physBlockSize /* byte offset */
				: bytesInLabel 	/* bytes */
				: raw_label
				: IOVmTaskSelf()
				: (void *)NULL
				: &bytesXfr];

            if((rtn == IO_R_SUCCESS) && (bytesXfr == bytesInLabel)) {
		   	goodLabel++;
		}
		/*
		 * there is one fatal error here - disk not present.
		 */
		if(rtn == IO_R_NO_DISK)
			break;
	}
	if(goodLabel) {
		_labelValid = 1;
#ifdef GROK_APPLE //bknight - 12/3/97 - Radar #2004660
		_hfsValid = 0;			// bek - 12/14/97 - Is this redundant?
#endif GROK_APPLE //bknight - 12/3/97 - Radar #2004660
		rtn = IO_R_SUCCESS;
	}
	else {
		xpr_disk("IODiskPartition writeLabel: Couldn\'t write label\n",
			1,2,3,4,5);
		if(rtn != IO_R_NO_DISK)
			rtn = IO_R_IO;
		goto done;
	}
	
	/*
	 * One more thing - update our own parameters and see if we
	 * need to create any block devices.
	 */
	[self _probeLabel: label_p];
done:
	[physDisk unlockLogicalDisks];
	if(raw_label) {
		IOFree(raw_label, labelBufSize);
	}
	return(rtn);
}


/*
 * Before we die, tell owner about this. LogicalDisk takes care of freeing
 * chained logicalDisks.
 */
- free
{
#ifdef	KERNEL
	[self unregisterUnixDisk: _partition];
#endif	KERNEL

	if( _partitionWaitLock) {
	    [_partitionWaitLock free];
	    _partitionWaitLock = nil;
	}
	return([super free]);
}
		  
/*
 * Handle Disk Eject request. Overrides IODisk's method of same name. 
 * Invoked upon the partition 0 instance by DiskObject's eject. This 
 * will be rejected at the DiskObject level if any block devices are open. 
 * We require this to be done only on partition 0 since we're going to blow
 * away all of the other partitions.
 */
- (IOReturn)eject
{
	IOReturn rtn;
	id phys = [self physicalDisk];
	
	xpr_disk("IODiskPartition eject\n", 1,2,3,4,5);

	/*
	 * We can't do this if any block devices, or any other logical disk, 
	 * are currently open. Also, we can only do this on partition 0
	 * because we're going to blow away all IODiskPartitions other than the
	 * one for partition 0 before we're thru.
	 */
	rtn = [self checkSafeConfig:"eject"];
	if(rtn) {
		return rtn;
	}

	/*
	 * Kill all other partitions. Have IODisk clear our
	 * "formatted" flag.
	 */
	[self _freePartitions];
	_labelValid = 0;
#ifdef GROK_APPLE //bknight - 12/3/97 - Radar #2004660
	_hfsValid = 0;
#endif GROK_APPLE //bknight - 12/3/97 - Radar #2004660
	[super setFormattedInternal:0];

	/*
	 * Cancel possible outstanding "manual poll" request. This covers
	 * the case in which the open() performed immediately preceeding
	 * this eject command did an implied vol_check_set_poll() in the
	 * driver's open() routine.
	 */
	if([phys needsManualPolling]) {
		vol_check_manual_poll();
	}
	
	/*
	 * Pass this down to physDisk using the internal versions to avoid
	 * getting callbacks.
	 */
	return([phys ejectPhysical]);
}

- (IOReturn) requestRelease
{
	IOReturn rtn;
	
	/*
	 * We can't do this if any block devices, or any other logical disk, 
	 * are currently open. Also, we can only do this on partition 0
	 * because we're going to blow away all IODiskPartitions other than the
	 * one for partition 0 before we're thru.
	 */

	rtn = [self checkSafeConfig:"disown"];
	if(rtn) {
		return rtn;
	}

	/*
	 * Kill all other partitions. Have IODisk clear our
	 * "formatted" flag.
	 */
	[self _freePartitions];
	_labelValid = 0;
#ifdef GROK_APPLE
	_hfsValid = 0;
#endif GROK_APPLE
	[super setFormattedInternal:0];

	return(rtn);
}

/*
 * read/write methods. These are illegal if _labelValid is false, otherwise
 * they're just passed up to LogicalDisk.
 */
#ifdef	KERNEL
- (IOReturn) readAt		: (unsigned)offset 
				  length : (unsigned)length 
				  buffer : (unsigned char *)buffer
				  actualLength : (out unsigned *)actualLength
				  client : (vm_task_t)client
{
	xpr_disk("IODiskPartition read\n", 1,2,3,4,5);
	
#if 0 // radar 1669467 - ISO 9660 CD support
// Read is NOT illegal if _labelValid is false - ISO 9660 CDs do not have 
// standard disk label.  In order to get read-only ISO 9660 CDROM support
// working, we have disabled the check for a valid label on the read path 
// only.  However, the ISO 9660 file system will not attempt to write to 
// the device and no other client should be able to open the device for 
// writing while the file system has it open, so the above scenario should 
// not occur.  bknight.
//
#ifdef GROK_APPLE //bknight - 12/3/97 - Radar #2004660
	if( ! ( _labelValid || _hfsValid ) ) {
#else GROK_APPLE //bknight - 12/3/97 - Radar #2004660
	if( ! _labelValid ) {
#endif GROK_APPLE //bknight - 12/3/97 - Radar #2004660
		IOLog("%s: Read attempt with no valid label\n", 
			[self name]);
		return(IO_R_INVALID_ARG);
	}
#endif // radar 1669467 - ISO 9660 CD support

	return([super readAt : offset 
		      length : length 
		      buffer : buffer
		      actualLength : actualLength
		      client : client]);
}
				  
- (IOReturn) readAsyncAt	: (unsigned)offset 
				  length : (unsigned)length 
				  buffer : (unsigned char *)buffer
				  pending : (void *)pending
				  client : (vm_task_t)client
{
	xpr_disk("IODiskPartition readAsync\n", 1,2,3,4,5);
#if 0 // radar 1669467 - ISO 9660 CD support
// Read is NOT illegal if _labelValid is false - ISO 9660 CDs do not have 
// standard disk label.  In order to get read-only ISO 9660 CDROM support
// working, we have disabled the check for a valid label on the read path 
// only.  However, the ISO 9660 file system will not attempt to write to 
// the device and no other client should be able to open the device for 
// writing while the file system has it open, so the above scenario should 
// not occur.  bknight.
//
#ifdef GROK_APPLE //bknight - 12/3/97 - Radar #2004660
	if( ! ( _labelValid || _hfsValid ) ) {
#else GROK_APPLE //bknight - 12/3/97 - Radar #2004660
	if( ! _labelValid ) {
#endif GROK_APPLE //bknight - 12/3/97 - Radar #2004660
		IOLog("%s: Read attempt with no valid label\n", 
			[self name]);
		return(IO_R_INVALID_ARG);
	}
#endif // radar 1669467 - ISO 9660 CD support

	return([super readAsyncAt : offset 
		      length : length 
		      buffer : buffer
		      pending: pending
		      client : client]);
}
				  
- (IOReturn) writeAt		: (unsigned)offset 
				  length : (unsigned)length 
				  buffer : (unsigned char *)buffer
				  actualLength : (out unsigned *)actualLength
				  client : (vm_task_t)client
{
	xpr_disk("IODiskPartition writeAt\n", 1,2,3,4,5);
#ifdef GROK_APPLE //bknight - 12/3/97 - Radar #2004660
	if( ! ( _labelValid || _hfsValid ) ) {
#else GROK_APPLE //bknight - 12/3/97 - Radar #2004660
	if( ! _labelValid ) {
#endif GROK_APPLE //bknight - 12/3/97 - Radar #2004660
		IOLog("%s: Write attempt with no valid label\n", 
			[self name]);
		return(IO_R_INVALID_ARG);
	}
	return([super writeAt : offset 
		      length : length 
		      buffer : buffer
		      actualLength : actualLength
		      client : client]);
}
				  	
- (IOReturn) writeAsyncAt	: (unsigned)offset 
				  length : (unsigned)length 
				  buffer : (unsigned char *)buffer
				  pending : (void *)pending
				  client : (vm_task_t)client
{
	xpr_disk("IODiskPartition writeAsync\n", 1,2,3,4,5);
#ifdef GROK_APPLE //bknight - 12/3/97 - Radar #2004660
	if( ! ( _labelValid || _hfsValid ) ) {
#else GROK_APPLE //bknight - 12/3/97 - Radar #2004660
	if( ! _labelValid ) {
#endif GROK_APPLE //bknight - 12/3/97 - Radar #2004660
		IOLog("%s: Write attempt with no valid label\n", 
			[self name]);
		return(IO_R_INVALID_ARG);
	}
	return([super writeAsyncAt : offset 
		      length : length 
		      buffer : buffer
		      pending: pending
		      client : client]);
}

#else	KERNEL

- (IOReturn) readAt		: (unsigned)offset 
				  length : (unsigned)length 
				  buffer : (unsigned char *)buffer
				  actualLength : (out unsigned *)actualLength
{
	xpr_disk("IODiskPartition read\n", 1,2,3,4,5);
#ifdef GROK_APPLE //bknight - 12/3/97 - Radar #2004660
	if( ! ( _labelValid || _hfsValid ) ) {
#else GROK_APPLE //bknight - 12/3/97 - Radar #2004660
	if( ! _labelValid ) {
#endif GROK_APPLE //bknight - 12/3/97 - Radar #2004660
		IOLog("%s: Read attempt with no valid label\n", 
			[self name]);
		return(IO_R_INVALID_ARG);
	}
	return([super readAt : offset 
		      length : length 
		      buffer : buffer
		      actualLength : actualLength]);
}
				  
- (IOReturn) readAsyncAt	: (unsigned)offset 
				  length : (unsigned)length 
				  buffer : (unsigned char *)buffer
				  pending : (void *)pending
{
	xpr_disk("IODiskPartition readAsync\n", 1,2,3,4,5);
#ifdef GROK_APPLE //bknight - 12/3/97 - Radar #2004660
	if( ! ( _labelValid || _hfsValid ) ) {
#else GROK_APPLE //bknight - 12/3/97 - Radar #2004660
	if( ! _labelValid ) {
#endif GROK_APPLE //bknight - 12/3/97 - Radar #2004660
		IOLog("%s: Read attempt with no valid label\n", 
			[self name]);
		return(IO_R_INVALID_ARG);
	}
	return([super readAsyncAt : offset 
		      length : length 
		      buffer : buffer
		      pending: pending]);
}
				  
- (IOReturn) writeAt		: (unsigned)offset 
				  length : (unsigned)length 
				  buffer : (unsigned char *)buffer
				  actualLength : (unsigned *)actualLength
{
	xpr_disk("IODiskPartition writeAt\n", 1,2,3,4,5);
#ifdef GROK_APPLE //bknight - 12/3/97 - Radar #2004660
	if( ! ( _labelValid || _hfsValid ) ) {
#else GROK_APPLE //bknight - 12/3/97 - Radar #2004660
	if( ! _labelValid ) {
#endif GROK_APPLE //bknight - 12/3/97 - Radar #2004660
		IOLog("%s: Write attempt with no valid label\n", 
			[self name]);
		return(IO_R_INVALID_ARG);
	}
	return([super writeAt : offset 
		      length : length 
		      buffer : buffer
		      actualLength : actualLength]);
}
				  	
- (IOReturn) writeAsyncAt	: (unsigned)offset 
				  length : (unsigned)length 
				  buffer : (unsigned char *)buffer
				  pending : (void *)pending
{
	xpr_disk("IODiskPartition writeAsync\n", 1,2,3,4,5);
#ifdef GROK_APPLE //bknight - 12/3/97 - Radar #2004660
	if( ! ( _labelValid || _hfsValid ) ) {
#else GROK_APPLE //bknight - 12/3/97 - Radar #2004660
	if( ! _labelValid ) {
#endif GROK_APPLE //bknight - 12/3/97 - Radar #2004660
		IOLog("%s: Write attempt with no valid label\n", 
			[self name]);
		return(IO_R_INVALID_ARG);
	}
	return([super writeAsyncAt : offset 
		      length : length 
		      buffer : buffer
		      pending: pending]);
}
#endif	KERNEL

/*
 * Public setFormatted, overrides the same method in IODisk.
 * This is the normal way a setFormatted operation is done in a 
 * Unix environment.
 */
- (IOReturn)setFormatted : (BOOL)formattedFlag
{
	id physDisk;
	IOReturn rtn;
	
	/*
	 * We can't do this if any block devices, or any other logical disk, 
	 * are currently open. Also, we can only do this on partition 0
	 * because we're going to blow away all IODiskPartitions other than the
	 * one for partition 0 before we're thru.
	 */
	rtn = [self checkSafeConfig:"setFormatted"];
	if(rtn) {
		return rtn;
	}

	/*
	 * Pass this down to physDisk using the internal versions to avoid
	 * getting callbacks.
	 */
	physDisk = [self physicalDisk];
	[physDisk setFormattedInternal:formattedFlag];
	if(formattedFlag) {
		/*
		 * Going to a newly formatted state; have physical
		 * device update block size and so forth.
		 */
		[physDisk updatePhysicalParameters];
	}
	
	/*
	 * Strange, but we'll set the internal formatted flag again in case 
	 * physical device driver disagrees with what our caller is saying.
	 * The caller wins in this case.
	 */
	[physDisk setFormattedInternal:formattedFlag];
	[self setFormattedInternal:formattedFlag];
	return IO_R_SUCCESS;
}

/*
 * internal setFormatted - avoids logical disk interaction. Called by
 * the exported setFormatted method both here (for normal Unix use) and
 * from physicalDisk.
 */
- (void)setFormattedInternal:(BOOL)formattedFlag
{
	xpr_disk("%s: setFormattedInternal %d\n", [self name], 
		formattedFlag, 3,4,5);
	[self _freePartitions];
	_labelValid = 0;

	/*
	 * Finally, the low-impact "just set the flag" method in
	 * IODisk...
	 */
	[super setFormattedInternal:formattedFlag];
}


/*
 * Get/set "device open" flags.
 */
- (BOOL)isBlockDeviceOpen
{
	return _blockDeviceOpen;
}

- (void)setBlockDeviceOpen		: (BOOL)openFlag
{
   	 _blockDeviceOpen = openFlag ? YES : NO;
	[self setInstanceOpen: (_blockDeviceOpen || _rawDeviceOpen)];
}

- (BOOL)isRawDeviceOpen
{
	return _rawDeviceOpen;
}

- (void)setRawDeviceOpen		: (BOOL)openFlag
{
	_rawDeviceOpen = openFlag ? YES : NO;
	[self setInstanceOpen: (_blockDeviceOpen || _rawDeviceOpen)];
}

- waitForProbe:(int) seconds
{
    int		attempts;
    BOOL	ready;
    ns_time_t	now;

    if( nil == _partitionWaitLock)
	return( nil);

    [_partitionWaitLock lock];
    ready = [_partitionWaitLock condition];
    [_partitionWaitLock unlock];

    if( NO == ready) do {
        IOGetTimestamp( &now);
        attempts = seconds - (int)((now - _probeTime) / 1000 / 1000 / 1000);
        if( attempts <= 0)
	    continue;

        IOLog( "%s: Waiting for drive to come ready", [self name]);
        for( ; (NO == ready) && attempts; attempts--) {
            IOLog( ".");
            IOSleep( 1000);
            [_partitionWaitLock lock];
            ready = [_partitionWaitLock condition];
            [_partitionWaitLock unlock];
        }
        IOLog( "\n");
        if( NO == ready)
            IOLog( "%s: Disk Not Ready\n", [self name]);

    } while( NO);

    return( ready ? self : nil);
}

@end

@implementation IODiskPartition(Private)


/*
 * Examine a known good label, initialize LogicalDisk parameters for the
 * partition '0' instance (on which this method is invoked) and create 
 * additional partition instances as appropriate.
 *
 * Invoked by LogicalDisk +probe, upon disk insertion, and when a new label
 * is written.
 */
- (void) _probeLabel : (disk_label_t *)labelp
{
	IODiskPartition *partInst;
	int part;
	struct partition *partition_p;
	id physDisk = [self physicalDisk];
	id lastIODiskPartition = self;
	
	xpr_disk("IODiskPartition  _probeLabel\n", 1,2,3,4,5);
	
	if(_partition != 0) {
		IOLog("%s:  _probeLabel on partition != 0\n", 
			[self name]);
		return;
	}
	
	/*
	 * Update internal state for partition 0.
	 */
	[self 	_initPartition:0 
		physicalPartition:_physicalPartition
		disktab:&labelp->dl_dt];
	
	/*
	 * Create & init an additional IODiskPartition instance per valid 
	 * partition. Partition NPART-1 is never used by convention (it's 
	 * the live partition).
	 */
	for(part=1; part<NPART-1; part++) {
		partition_p = &labelp->dl_dt.d_partitions[part];
		if(partition_p->p_size > 0) {
		
			/*
			 * A valid logical disk partition.
			 */
			partInst = [IODiskPartition new];
			[partInst connectToPhysicalDisk:physDisk];
			[partInst _initPartition : part
				physicalPartition: _physicalPartition
				disktab : &labelp->dl_dt];
			[partInst init];
			[partInst registerDevice];
				
			/*
			 * Link to logical disk chain, and notify 
			 * physDisk as well.
			 */
			[lastIODiskPartition setLogicalDisk:partInst];
			[[self physicalDisk] setLogicalDisk:partInst];
			lastIODiskPartition = partInst;
		}
	}
	return;
}

/*
 * Assign logical disk parameters for an IODiskPartition instance based on
 * specified partition number on disktab. Caller must have already 
 * done a connectToPhysicalDisk on this instance, and specified partition
 * is known to be valid.
 */
- (void)_initPartition		: (int)partNum
              physicalPartition : (int)physNum	
                        disktab : (struct disktab *)dtp;
{
	struct partition *pp = &dtp->d_partitions[partNum];
	int partBase;
	char name[30];
	id physDisk = [self physicalDisk];

	/*
	 * Set IODevice-class instance variables.
	 */
	sprintf(name, "%s%c", [physDisk name], 'a' + partNum);
	[self setName:name];
	[self setDriveName:"IODiskPartition Partition"];
	[self setLocation:NULL];
	xpr_disk("%s: _initPartition\n", IOCopyString(name), 2,3,4,5);
	[self setDiskSize:pp->p_size];
	[self setBlockSize:dtp->d_secsize];
	[self setUnit:[physDisk unit]];		// probably unnecessary

	// Ensure partition 0 always has the correct value
	// for this instance variable, since connectToPhysicalDisk
	// is only called once for that partition.
	[self setWriteProtected:[physDisk isWriteProtected]];

	/*
	 * LogicalDisk instance variables are taken care of in
	 * connectToPhysicalDisk.
	 * Set up local instance variables.
	 *
	 * Careful, partitionBase is not necessarily in physical blocksize;
	 * for old disks, it's in d_secsize (usually DEV_BSIZE) from 
	 * disktab...
	 */
	partBase = pp->p_base + dtp->d_front;
	partBase *= dtp->d_secsize / [self physicalBlockSize];
	[self setPartitionBase:partBase];
	_partition =  partNum;
	_physicalPartition = physNum;
	
	/*
	 * The low-impact "just set the flag" method in IODisk...Our
	 * override of this method frees partitions.
	 */
	[super setFormattedInternal:1];
	_labelValid = 1;
#ifdef GROK_APPLE //bknight - 12/3/97 - Radar #2004660
	_hfsValid = 0;			// bek - 12/14/97 - Is this redundant?
#endif GROK_APPLE //bknight - 12/3/97 - Radar #2004660
	
#ifdef	KERNEL
	/*
	 * Let Unix layer know about us.
	 */
	[self registerUnixDisk : partNum];
#endif	KERNEL
	return;
}				  
		
/*
 * Free all partition instances other than partition 0. The others must
 * not be open, and this must be invoked on partition 0.
 */
- (IOReturn)_freePartitions;
{
	id nextPart = [self nextLogicalDisk];
	
	if(_partition != 0) {
		IOLog("%s: _freePartitions on partition != 0\n",
			[self name]);
		return IO_R_BUSY;	
	}	
	if(nextPart == nil)
		return IO_R_SUCCESS;
	if([nextPart isOpen]) {
		/* 
		 * this shouldn't happen - this was already checked
		 * in checkSafeConfig.
		 */
		IOLog("%s: _freePartitions with open partitions\n",
			[self name]);
		return IO_R_BUSY;
	}
	[nextPart free];
	[self setLogicalDisk:nil];
	return IO_R_SUCCESS;
}

/*
 * Determine if any block devices in the logicalDisk chain are open.
 */
- (BOOL)isAnyBlockDevOpen
{
	id logDisk = [[self physicalDisk] nextLogicalDisk];
	
	while(logDisk) {
		if([logDisk isBlockDeviceOpen]) {
			return YES;
		}
		logDisk = [logDisk nextLogicalDisk];
	}
	return NO;
}


/*
 * Verify that it's safe to do an operation which will result in a call
 * to _freePartitions.
 */
- (IOReturn)checkSafeConfig	: (const char *)op
{
	if(_partition != 0) {
		return IO_R_BUSY;
	}
	if([self isAnyBlockDevOpen]) {
		return IO_R_BUSY;
	}
	if([self isAnyOtherOpen]) {
		return IO_R_BUSY;
	}
	return IO_R_SUCCESS;
}


#ifdef GROK_APPLE //bknight - 12/3/97 - Radar #2004660

/*
 * Check for an apple partition:
 *
 */
#define BLOCKSIZE_512_BYTES	512

+ (void)CreateHFSDevicesFromApplePartitionMap: (id) devDesc
{
	id			physicalDisk = [devDesc directDevice];
	unsigned char	*	blk;
	Block0			*	blk0;
	unsigned long 		blocksize;
	unsigned			bytesXfr;
	IOReturn	 		rtn;
	
    unsigned int		block = 1;
    unsigned int		entry_within_block = 0;
    int					n;
    unsigned int		nentries_per_block = 1;
    unsigned int		numPartBlocks;
    DPME			*	partEntry;
    int				physNum;

	IODiskPartition	*	partitionInstance;
	IODiskPartition	*	lastIODiskPartition = nil; // mandatory initialization
	unsigned			part = 0;

	blocksize = 512;

	blk = IOMalloc(PAGE_SIZE); /* force page alignment */
	blk0 = (Block0 *)blk;

	/* check block 0 for valid Apple partition signature */

	rtn = [[super class] commonReadWrite
            			: physicalDisk
				: YES			/* read */
				: (unsigned long long)0	/* byte offset */
				: PAGE_SIZE 	/* bytes */
				: blk
				: IOVmTaskSelf()
				: (void *)NULL
				: &bytesXfr];

        if (rtn)
	{
	    goto Return;
	}
	
	/* scan for apple hfs partitions */

    /* check if there is a valid map at 512 offset */

    partEntry = (DPME *)(blk + BLOCKSIZE_512_BYTES);

    if (blocksize > BLOCKSIZE_512_BYTES)
    {
		if (NXSwapBigShortToHost(partEntry->dpme_signature) == DPME_SIGNATURE)
		{
		    /* there is a valid map, and the device blocksize
		     * is > 512, which means we probably have a CDROM
		     * using 2K, but having valid 512 map
		     */
		    block = 0;
		    nentries_per_block = blocksize / BLOCKSIZE_512_BYTES;
		    entry_within_block = 1;
		}
		else
		{
		    partEntry = (DPME *)(blk + blocksize);
		}
    }

    if (NXSwapBigShortToHost(partEntry->dpme_signature) != DPME_SIGNATURE)
    {
#if 1 // bknight - 7/2/98 - Radar #2240631
	/* Make a single giant "_hfs_a" partition to support floppies, DOS disks, ISO9660 CDs. */

	partitionInstance = [IODiskPartition new];
	[partitionInstance connectToPhysicalDisk: physicalDisk];
	[partitionInstance setDeviceDescription: devDesc];
	[partitionInstance _initHFSPartition: 0
		physicalPartNum: 0 // bknight - intentionally illegal phys part num
		diskSize: ( [physicalDisk diskSize] * ([physicalDisk blockSize] / BLOCKSIZE_512_BYTES) )
		partitionBase: 0];
	[partitionInstance init]; //bknight - [super init] all the way up to Object
	[partitionInstance registerDevice]; //bknight - doesn't do anything since (!_isPhysical)
			
	/* No need to link onto the end of nonexistent chain of logical partitions.
	   Just notify the physical disk. */
		 
	[physicalDisk setLogicalDisk: partitionInstance]; //bknight - doesn't override if already set
#endif // bknight - 7/2/98 - Radar #2240631
	goto Return;
    }

    numPartBlocks = NXSwapBigLongToHost(partEntry->dpme_map_entries);
    physNum = 1;
    for (n = 0; n < numPartBlocks; n++)
    {
		if (NXSwapBigShortToHost(partEntry->dpme_signature) != DPME_SIGNATURE)
		{
		    break;
		}

		if ( strcmp(partEntry->dpme_type, HFS_PART_TYPE) == 0 )
		{
		    /*
		     * Mount HFS volume only if this isn't "MOSX_OF3_Booter" partition.
		     */
		    if ( strcmp(partEntry->dpme_name, "MOSX_OF3_Booter") != 0 )
		    {
			    unsigned long part_offset;
	
			    part_offset = NXSwapBigLongToHost(partEntry->dpme_pblock_start);
			    if ((part_offset / nentries_per_block * nentries_per_block) != part_offset)
			    {
					IOLog("IODiskPartition: " HFS_PART_TYPE
					      " partition base (%ld x 512) is not"
					      " a multiple of the devblksize %ld\n",
					      part_offset, blocksize);
					break;
			    }
	
		    part_offset = part_offset / nentries_per_block;

			/* A valid logical disk partition. */

			partitionInstance = [IODiskPartition new];
			[partitionInstance connectToPhysicalDisk: physicalDisk];
			[partitionInstance setDeviceDescription:devDesc];
			[partitionInstance
				_initHFSPartition: part
				physicalPartNum: physNum
				diskSize: partEntry->dpme_pblocks
				partitionBase: partEntry->dpme_pblock_start];
			[partitionInstance init]; //bknight - [super init] all the way up to Object
			[partitionInstance registerDevice]; //bknight - doesn't do anything since (!_isPhysical)
				
			/* Link to logical disk chain, and notify the physicalDisk. */
			 
			if ( lastIODiskPartition != nil )
			{
				[lastIODiskPartition setLogicalDisk: partitionInstance];
			}
			lastIODiskPartition = partitionInstance;
			[physicalDisk setLogicalDisk: partitionInstance]; //bknight - doesn't override if already set
			
			/* Increment our partition counter. */
			
			part++;
		    } // if not "MOSX_OF3_Booter" partition flag set
		} // if HFS_PART_TYPE

                physNum++;
		partEntry++;
		if (++entry_within_block == nentries_per_block)
		{
		    block++;
		    entry_within_block = 0;
		    partEntry = (DPME *)blk;
       		    rtn = [[super class] commonReadWrite
                        	: physicalDisk
				: YES			/* read */
		    : (unsigned long long)block * blocksize /* byte offset */
				: blocksize 	/* bytes */
				: blk
				: IOVmTaskSelf()
				: (void *)NULL
				: &bytesXfr];
                    if (rtn)
		    {
				break;
		    }

		} // if

    } // for

Return:

	IOFree(blk, PAGE_SIZE);
	return;

} // CreateHFSDevicesFromApplePartitionMap

#endif GROK_APPLE //bknight - 12/3/97 - Radar #2004660

#if GROK_APPLE //bknight - 12/3/97 - Radar #2004660

/*
 * Assign logical disk parameters for an IODiskPartition instance based on
 * specified partition number on disktab. Caller must have already 
 * done a connectToPhysicalDisk on this instance, and specified partition
 * is known to be valid.
 */
- (void)	_initHFSPartition	: (int) partitionNum
			physicalPartNum	: (int) physNum
			diskSize	: (int) diskSize
			partitionBase : (int) partitionBase;
{
	int						hfsPartitionNum = partitionNum + NPART;
	char					name[30]; //bknight - hardcoded
	id						physicalDisk = [self physicalDisk];

	/* IODevice initialization */

	sprintf(name, "%s_hfs_%c", [physicalDisk name], 'a' + partitionNum);
	[self setUnit: [physicalDisk unit]]; // IODevice //bknight - probably unnecessary ???
	[self setName: name];
	[self setLocation: NULL];

	/* IODisk initialization */

	[self setDriveName: "IODiskPartition Partition"];

	// always measured in 512-byte blocks, regardless of the device block size

	[self setDiskSize: diskSize]; //bknight - in 512-byte blocks

	// hardcoded per Radar #2211264

	[self setBlockSize: 512]; 

	/* bknight - WHAT DOES THIS COMMENT / LINE MEAN ??? */

	// Ensure partition 0 always has the correct value
	// for this instance variable, since connectToPhysicalDisk
	// is only called once for that partition.
	[self setWriteProtected:[physicalDisk isWriteProtected]];

	/*
	 * IOLogicalDisk instance variables are taken care of in connectToPhysicalDisk.
	 * Set up IODiskPartition instance variables.
	 *
	 */
	[self setPartitionBase: partitionBase];
	_partition = hfsPartitionNum;
        _physicalPartition = physNum;

	/*
	 * The low-impact "just set the flag" method in IODisk...Our
	 * override of this method frees partitions.
	 */
	[super setFormattedInternal:1];
	_hfsValid = 1;
	_labelValid = 0;
	
#ifdef	KERNEL
	/*
	 * Let Unix layer know about us.
	 */
	[self registerUnixDisk: hfsPartitionNum];
#endif	KERNEL

Return:

	return;

} // _initHFSPartition
		
#endif GROK_APPLE //bknight - 12/3/97 - Radar #2004660

- property_IODeviceType:(char *)types length:(unsigned int *)maxLen
{
#if GROK_APPLE
    if( _hfsValid)
        strcat( types, " "IOTypeHFS);
    else
#endif GROK_APPLE
        strcat( types, " "IOTypeUFS);
    return( self);
}

- property_IODeviceClass:(char *)classes length:(unsigned int *)maxLen
{
    [super property_IODeviceClass:classes length:maxLen];
    strcat( classes, " "IOClassDiskPartition);
    return( self);
}

- property_IOPartitionNumber:(char *)result length:(unsigned int *)maxLen
{
    sprintf( result, "0x%x", _physicalPartition);
    return( self);
}

- registerLoudly
{
    return( nil);
}

@end

#ifndef	KERNEL
/*
 * Ripped off from kernel's next/checksum16.c
 */
#define	ADDCARRY(x)  (x > 65535 ? x -= 65535 : x)
#define	REDUCE { 				\
	l_util.l = sum; 			\
	sum = l_util.s[0] + l_util.s[1];	\
	ADDCARRY(sum);				\
}

u_short checksum_16(u_short *wp, int num_shorts)
{
	int sum = 0;
	union {
		u_short s[2];
		long	l;
	} l_util;

	while (num_shorts--)
		sum += *wp++;
	REDUCE;
	return (sum);
}
#endif	KERNEL

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.