File:  [Apple Darwin 0.x] / drvEIDE / EIDE.drvproj / EIDE.lksproj / IdeKernel.m
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 17:40:59 2018 UTC (8 years, 1 month ago) by root
Branches: MAIN, Apple
CVS tags: HEAD, Darwin03
Darwin 0.3 EIDE device driver

/*
 * 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.0 (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 1997-1998 by Apple Computer, Inc., All rights reserved.
 * Copyright 1994-1997 NeXT Software, Inc., All rights reserved.
 *
 * IdeKern.m - UNIX front end for kernel IDE Disk driver.
 *
 * HISTORY 
 * 07-Jul-1994	 Rakesh Dubey at NeXT
 *	Created from original driver written by David Somayajulu.
 * 19-Jun-97	Dieter Siegmund at Apple
 *	Updated to use the BSD4.4 ioctl interface that copies user
 *	buffer in/out of kernel automatically.
 */
 
#if (IO_DRIVERKIT_VERSION == 400)
#define _POSIX_SOURCE
#endif

/*
 * Note that this file builds with KERNEL_PRIVATE and !MACH_USER_API.
 */
#import <sys/types.h>
#import <sys/ttycom.h>
#import <sys/ucred.h>
#import <driverkit/kernelDiskMethods.h> 
#import <driverkit/generalFuncs.h>
#import "IdeCnt.h"
#import "IdeDiskInternal.h"
#import "IdeDisk.h"
#import <driverkit/kernelDriver.h>
#import <driverkit/IODiskPartition.h>
#import <sys/buf.h>
#import <sys/uio.h>
#import <bsd/dev/ldd.h>
#import <sys/errno.h>
#import <sys/proc.h>
#if (IO_DRIVERKIT_VERSION == 330)
#import <vm/vm_kern.h>
#endif
#import <sys/fcntl.h>
#import <sys/systm.h>
#import "IdeKernel.h"

#if (IO_DRIVERKIT_VERSION != 330)
extern struct vm_map *kernel_map;
#endif

IONamedValue iderValues[] = {

	{IDER_SUCCESS,		"Success"			},
	{IDER_TIMEOUT,		"Timeout occured"		},
	{IDER_MEMALLOC,		"Couldn't allocate memory"	},
	{IDER_MEMFAIL,		"Memory transfer error"		},
	{IDER_REJECT,		"Bad field in ide_ioreq"	},
	{IDER_BADDRV,		"Drive not present"		},
	{IDER_CMD_ERROR,	"Command Failed"		},
	{IDER_VOLUNAVAIL,	"Requested Volume not available"},
	{IDER_SPURIOUS,		"Spurious Interrupt"		},
	{IDER_CNTRL_REJECT,	"Controller Reject" 		},
	{0,			NULL				},
};


/*
 * dev-to-id map array. Instances of DiskObject register their IDs in
 * this array via registerUnixDisk:.
 */
IODevAndIdInfo IdeIdMap[NUM_IDE_DEV];

/*
 * Private per-unit data.
 */
static Ide_dev_t ide_dev[NUM_IDE_DEV] = {
	{NULL},
	{NULL},
	{NULL},
	{NULL},
};

/*
 * Indices of our entries in devsw's.
 */
static int ide_block_major;
static int ide_raw_major;

/*
 * prototypes for internal functions
 */
static unsigned ideminphys(struct buf *bp); 
static id ide_dev_to_id(dev_t dev);

/*
 * Initialize id map and Ide_dev. Currently invoked by Ide probe:.
 */
__private_extern__ void ide_init_idmap(id self)
{
    IODevAndIdInfo *idMap = IdeIdMap;
    Ide_dev_t *ide_devp = ide_dev;
    int unit;
    
    /* 
     * figure out our major device numbers.
     */
    ide_block_major = [self blockMajor];
    ide_raw_major = [self characterMajor];

    bzero((char *)idMap, sizeof(IODevAndIdInfo) * NUM_IDE_DEV);
    for (unit = 0; unit < NUM_IDE_DEV; unit++) {
	idMap->rawDev   = makedev(ide_raw_major, (unit << 3));
	idMap->blockDev = makedev(ide_block_major, (unit << 3));
	idMap++;
	ide_devp->physbuf = (struct buf *)IOMalloc(sizeof(struct buf));
	ide_devp->physbuf->b_flags = 0;
	ide_devp++;
    }
}

__private_extern__ IODevAndIdInfo *ide_idmap()
{
    return IdeIdMap;
}

__private_extern__ int
ideopen(dev_t dev, int flag, int devtype, struct proc * pp)
{
    id diskObj = ide_dev_to_id(dev);
    
    if(diskObj == nil)
	return(ENXIO);

    if([diskObj isDiskReady:NO])
	return(ENXIO);
		
    /*
     * Register this 'Unix-level open' event for IODiskPartitions.
     */
    if(IO_DISK_PART(dev) != IDE_LIVE_PART) {
	if(major(dev) == ide_block_major) {
	    [diskObj setBlockDeviceOpen:YES];
	}
	else {
	    [diskObj setRawDeviceOpen:YES];
	}
    }
    return(0);	
} /* ideopen() */

__private_extern__ int
ideclose(dev_t dev, int flag, int devtype, struct proc * pp)
{
    id diskObj = ide_dev_to_id(dev);
    
    if(diskObj == nil)
	return(ENXIO);
    if(IO_DISK_PART(dev) == IDE_LIVE_PART) { 
	return 0;
    } else 	{
	if(![diskObj isInstanceOpen])
	    return(ENXIO);
    }
	    
    /*
     * Register this 'Unix-level close' event. We won't be called unless
     * this is the last close.
     */
    if(major(dev) == ide_block_major) {
	[diskObj setBlockDeviceOpen:NO];
    }
    else {
	[diskObj setRawDeviceOpen:NO];
    }
    
    return(0);	
} /* ideclose() */

/*
 * Raw I/O uses standard UNIX physio routine, resulting in async I/O requests
 * via idestrategy().
 */

__private_extern__ int
ideread(dev_t dev, struct uio *uiop, int ioflag)
{
    id 		diskObj = ide_dev_to_id(dev);
    int 	unit = IO_DISK_UNIT(dev);
    int 	rtn;

    if(diskObj == nil) {
	return(ENXIO);
    }


    rtn = physio(idestrategy, 
	ide_dev[unit].physbuf, 
	dev, 
	B_READ, 
	ideminphys, 
	uiop, 
	[diskObj blockSize]);
	    
    return rtn;
} /* ideread() */

__private_extern__ int
idewrite(dev_t dev, struct uio *uiop, int ioflag)
{
    id 		diskObj = ide_dev_to_id(dev);
    int 	unit = IO_DISK_UNIT(dev);
    int 	rtn;
	    
    if(diskObj == nil)
	return(ENXIO);
    

    rtn = physio(idestrategy, 
	ide_dev[unit].physbuf, 
	dev, 
	B_WRITE, 
	ideminphys, 
	uiop, 
	[diskObj blockSize]);
	    
    return rtn;
} /* idewrite() */

__private_extern__ void
idestrategy(struct buf *bp)
{
    id diskObj = ide_dev_to_id(bp->b_dev);
    u_int offset;
    u_int bytes_req;
    void *bufp;
    u_int block_size;
    IOReturn rtn;
    vm_task_t client;
	
    if(diskObj == nil) {
	bp->b_error = ENXIO;
	goto bad;
    }
    
    if((bp->b_flags & (B_PHYS|B_KERNSPACE)) == B_PHYS) {
	/*
	 * Physical I/O to user space.
	 */
	client = IOVmTaskForBuf(bp);
    }
    else {
	/*
	 * Either block I/O (always kernel space) or physical I/O
	 * to kernel space (e.g., loadable file system).
	 */
	client = IOVmTaskSelf();
    }
    
    block_size = [diskObj blockSize];
    if (block_size == 0) {
	bp->b_error = ENXIO;
	goto bad;
    }
    offset = bp->b_blkno;
    bytes_req = bp->b_bcount;
    bufp = bp->b_un.b_addr;

    if (bp->b_flags & B_READ) {
	rtn = [diskObj readAsyncAt:offset
		length:bytes_req
		buffer:bufp
		pending:bp
		client:client];
    }
    else {
	rtn = [diskObj writeAsyncAt:offset
		length:bytes_req
		buffer:bufp
		pending:bp
		client:client];
    }

    if (rtn) {
	bp->b_error = [diskObj errnoFromReturn:rtn];
	goto bad;
    }
    return;

bad:
    bp->b_flags |= B_ERROR;
    biodone(bp);
} /* fdstrategy() */

/*
 * Ops which are common to all IODiskPartitions are done on the raw device; 
 * Ide-specific ioctls are done directly to the live Ide object.
 */
__private_extern__ int
ideioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc * pp)
{
    int     unit = IO_DISK_UNIT(dev);
    id      diskObj;
    IODevAndIdInfo *idmap;
    int     rtn = 0;
    IOReturn irtn = IO_R_SUCCESS;
    struct ucred cred;
    u_short acflags;

    // user src/dest
    int     i;
    int     nblk;
    ideIoReq_t *ideIoReq;
    int     error;
    void   *userPtr;

    // in ideIoReq_t
    BOOL wrFlag = NO;
    unsigned bSize = 0;
    unsigned char *alignedPtr;

    if (unit > NUM_IDE_DEV)
	return (ENXIO);
#if 0
    if ((major(dev) != ide_raw_major) ||
	(IO_DISK_PART(dev) >= NUM_IDE_PART)) {
	return (ENXIO);
    }
#endif

    idmap = &IdeIdMap[unit];

    /*
     * First verify valid device. 
     */
    switch (cmd) {
      case DKIOCSFORMAT:
      case DKIOCGFORMAT:
      case DKIOCGLABEL:
      case DKIOCSLABEL:

	/*
	 * Raw device, whatever the caller asked for. 
	 */
	diskObj = idmap->partitionId[0];
	break;

      case IDEDIOCREQ:
      case IDEDIOCINFO:
      case DKIOCINFO:
      case DKIOCBLKSIZE:
      case DKIOCNUMBLKS:

	diskObj = idmap->liveId;
	break;

      default:
	return (EINVAL);
    }
    if (diskObj == nil)
	goto nodev;

    switch (cmd) {
      case DKIOCSFORMAT:

	/*
	 * This can fail if block devices attached to this disk are open. 
	 */
	irtn = [diskObj setFormatted:(*(u_int *) data)];
	break;

      case DKIOCGFORMAT:
	{
	    *(int *)data = [diskObj isFormatted];
	    break;
	}

      case DKIOCGLABEL:
	{
	    struct disk_label *labelp;

	    labelp = (struct disk_label *)IOMalloc(sizeof(*labelp));
	    irtn = [diskObj readLabel:labelp];
	    if (irtn == IO_R_SUCCESS) {
		*(struct disk_label *)data = *labelp;
	    }
	    IOFree(labelp, sizeof(*labelp));
	    break;
	}

      case DKIOCSLABEL:
	{
	    struct disk_label *labelp;

		//IOLog("DKIOCSLABEL called\n");

	    labelp = (struct disk_label *)IOMalloc(sizeof(*labelp));
	    *labelp = *(struct disk_label *)data;
	    irtn = [diskObj writeLabel:labelp];
	    IOFree(labelp, sizeof(*labelp));
	    break;
	}

      case DKIOCINFO:
	{
	    struct drive_info info;

	    bzero(&info, sizeof(info));
	    strcpy(info.di_name,[diskObj driveName]);
	    info.di_devblklen = [diskObj blockSize];
	    info.di_maxbcount = IDE_MAX_PHYS_IO;
	    if (info.di_devblklen) {
		nblk = howmany(sizeof(struct disk_label),
			       info.di_devblklen);
	    } else {
		nblk = 0;
	    }
	    for (i = 0; i < NLABELS; i++)
		info.di_label_blkno[i] = nblk * i;
	    *(struct drive_info *) data = info;
	    break;
	}

      case DKIOCBLKSIZE:
	*(int *)data = [diskObj blockSize];
	break;

      case DKIOCNUMBLKS:
	*(int *)data = [diskObj diskSize];
	break;

      case IDEDIOCREQ:

	/*
	 * Perform specified I/O.
	 */
	ideIoReq = (ideIoReq_t *) data;
//	if (!suser() && (ideIoReq->cmd != IDE_IDENTIFY_DRIVE))
	if (!suser(&cred, &acflags) && (ideIoReq->cmd != IDE_IDENTIFY_DRIVE))	{
//	    return (u.u_error);
	    return (EINVAL);
	}
	
	if ((ideIoReq->cmd == IDE_WRITE_DMA) ||
	    (ideIoReq->cmd == IDE_READ_DMA)) {
	    if ([[diskObj cntrlr] isDmaSupported:[diskObj driveNum]] != TRUE)
		return (EINVAL);
	}
        if (ideIoReq->cmd == IDE_IDENTIFY_DRIVE)
	    ideIoReq->blkcnt = 1;

	userPtr = (void *)ideIoReq->addr;

	alignedPtr = ideIoReq->addr;
	if ((ideIoReq->cmd == IDE_WRITE) ||
	    (ideIoReq->cmd == IDE_READ) ||
	    (ideIoReq->cmd == IDE_READ_MULTIPLE) ||
	    (ideIoReq->cmd == IDE_WRITE_MULTIPLE) ||
	    (ideIoReq->cmd == IDE_READ_DMA) ||
	    (ideIoReq->cmd == IDE_WRITE_DMA) ||
	    (ideIoReq->cmd == IDE_IDENTIFY_DRIVE)) {
	    if (ideIoReq->blkcnt != 0) {
		bSize = [diskObj blockSize];
		wrFlag = ((ideIoReq->cmd == IDE_WRITE) ||
			  (ideIoReq->cmd == IDE_WRITE_MULTIPLE) ||
			  (ideIoReq->cmd == IDE_WRITE_DMA));

		alignedPtr = (unsigned char *)
		    IOMalloc(ideIoReq->blkcnt * bSize);
		if (alignedPtr == 0) {
		    ideIoReq->status = IDER_MEMALLOC;
		    return (ENOMEM);
		}
		if (wrFlag) {
		    error = copyin(ideIoReq->addr,
				   alignedPtr,
				   ideIoReq->blkcnt * bSize);
		    if (error) {
			ideIoReq->status = IDER_MEMFAIL;
			goto err_exit;
		    }
		}
	    }
	    ideIoReq->addr = (caddr_t) alignedPtr;
	    ideIoReq->map = (struct vm_map *)IOVmTaskSelf();
	}


	[diskObj ideXfrIoReq:ideIoReq];

	/*
	 * Note if we got this far, we'll return 0; any errors are in
	 * ideIoReq->status. 
	 */
	if ((ideIoReq->cmd == IDE_WRITE) ||
	    (ideIoReq->cmd == IDE_READ) ||
	    (ideIoReq->cmd == IDE_READ_MULTIPLE) ||
	    (ideIoReq->cmd == IDE_WRITE_MULTIPLE) ||
	    (ideIoReq->cmd == IDE_READ_DMA) ||
	    (ideIoReq->cmd == IDE_WRITE_DMA) ||
	    (ideIoReq->cmd == IDE_IDENTIFY_DRIVE)) {

	    ideIoReq->addr = userPtr;
	    if (((ideIoReq->cmd == IDE_READ) ||
		 (ideIoReq->cmd == IDE_READ_MULTIPLE) ||
		 (ideIoReq->cmd == IDE_IDENTIFY_DRIVE) ||
		 (ideIoReq->cmd == IDE_READ_DMA)) &&
		(ideIoReq->blocks_xfered != 0)) {
		error = copyout(alignedPtr,
				userPtr,
				ideIoReq->blocks_xfered * bSize);
		if (error) {
		    ideIoReq->status = IDER_MEMFAIL;
		}
	    }
    err_exit:

	    /*
	     * if we malloc'd any memory, free it. 
	     */
	    if (ideIoReq->blkcnt != 0)
		IOFree(alignedPtr, ideIoReq->blkcnt * bSize);
	}
	break;

      case IDEDIOCINFO:
	{
	    ideDriveInfo_t *idep = (ideDriveInfo_t *) data;

	    *idep = (ideDriveInfo_t)[diskObj ideGetDriveInfo];
	    break;
	}
      default:
	return (EINVAL);
    }

    if (irtn)
	rtn = [diskObj errnoFromReturn:irtn];
    return (rtn);

nodev:
    return (ENXIO);

} /* ideioctl() */

/*
 * Obtain physical block size.
 */
__private_extern__ int
idesize(dev_t dev)
{
    id diskObj = ide_dev_to_id(dev);
    
    if(diskObj == nil) {
	return -1;
    }
    return [diskObj blockSize];
}

/*
 * Returns block and char major nums. This is used so that the PostLoad
 * program can create block and character nodes for IDE. 
 */
__private_extern__ void
ide_block_char_majors(int *blockmajor, int *charmajor)
{
    *blockmajor = ide_block_major;
    *charmajor = ide_raw_major;
}

static unsigned ideminphys(struct buf *bp)
{
    if (bp->b_bcount > IDE_MAX_PHYS_IO)
	bp->b_bcount = IDE_MAX_PHYS_IO;
    return(bp->b_bcount);
}

/*
 * Map dev_t to id. A nil return indicates ENXIO.
 */
static id ide_dev_to_id(dev_t dev)
{
    id rtn;
    int unit = IO_DISK_UNIT(dev);
    IODevAndIdInfo *idmap;
    int part = IO_DISK_PART(dev);
    
    if((unit >= NUM_IDE_DEV) || (part >= NUM_IDE_PART)) {
	return nil;
    }
    idmap = &IdeIdMap[unit];
    if(part == IDE_LIVE_PART) {
	if(major(dev) == ide_block_major) {
	    rtn = nil;  
	}
	else {
	    rtn = idmap->liveId;
	}
    }
    else {
	rtn = idmap->partitionId[part];
    }
    return rtn;
}

/* end of IdeKern.m */

unix.superglobalmegacorp.com

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