dpt_control.c

来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 856 行 · 第 1/2 页

C
856
字号
/** *       Copyright (c) 1997 by Simon Shapiro *       All Rights Reserved * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions, and the following disclaimer, *    without modification, immediately at the beginning of the file. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products *    derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * *//** * dpt_control.c: Control Functions and /dev entry points for /dev/dpt* * * Caveat Emptor!	This is work in progress.	The interfaces and * functionality of this code will change (possibly radically) in the * future. */#ident "$Id: dpt_control.c,v 1.10.2.2 1999/05/13 05:25:21 jkh Exp $"#include "opt_dpt.h"#include <i386/include/cputypes.h>#include <sys/param.h>#include <sys/systm.h>#include <sys/malloc.h>#include <sys/kernel.h>#include <sys/buf.h>#include <sys/uio.h>#include <sys/conf.h>#include <vm/vm.h>#include <vm/vm_kern.h>#include <vm/vm_extern.h>#include <vm/pmap.h>#include <scsi/scsiconf.h>#include <dev/dpt/dpt.h>#define INLINE __inlineextern char     osrelease[];static dpt_sysinfo_t   dpt_sysinfo;/* Entry points and other prototypes */static vm_offset_t dpt_physmap(u_int32_t paddr, vm_size_t size);static void     dpt_unphysmap(u_int8_t * vaddr, vm_size_t size);static void     dpt_get_sysinfo(void);static int      dpt_open(dev_t dev, int flags, int fmt, struct proc * p);static int      dpt_close(dev_t dev, int flags, int fmt, struct proc * p);static int      dpt_write(dev_t dev, struct uio * uio, int ioflag);static int      dpt_read(dev_t dev, struct uio * uio, int ioflag);static int      dpt_ioctl(dev_t dev, u_long cmd, caddr_t cmdarg, int flags, struct proc * p);/* This has to be modified as the processor and CPU are not known yet */static dpt_sig_t dpt_sig = {	'd', 'P', 't', 'S', 'i', 'G',	SIG_VERSION, PROC_INTEL, PROC_386,	FT_HBADRVR, FTF_PROTECTED,	OEM_DPT, OS_FREEBSD,	CAP_PASS | CAP_OVERLAP | CAP_RAID0 | CAP_RAID1 | CAP_RAID5 | CAP_ASPI,	DEV_ALL, ADF_SC4_PCI | ADF_SC3_PCI, 0, 0,	DPT_RELEASE, DPT_VERSION, DPT_PATCH,	DPT_MONTH, DPT_DAY, DPT_YEAR,	"DPT FreeBSD Driver (c) 1997 Simon Shapiro"};#define CDEV_MAJOR	    DPT_CDEV_MAJOR/* Normally, this is a static structure.  But we need it in pci/dpt_pci.c */struct cdevsw   dpt_cdevsw = {	dpt_open, dpt_close, dpt_read, dpt_write,	dpt_ioctl, nostop, nullreset, nodevtotty,	seltrue, nommap, NULL, "dpt",NULL, -1};static struct buf *dpt_inbuf[DPT_MAX_ADAPTERS];static char     dpt_rw_command[DPT_MAX_ADAPTERS][DPT_RW_CMD_LEN + 1];/* * Given a minor device number, * return the pointer to its softc structure */dpt_softc_t *dpt_minor2softc(int minor_no){	dpt_softc_t    *dpt;	if (dpt_minor2unit(minor_no & ~SCSI_CONTROL_MASK) == -1)		return (NULL);	for (dpt = TAILQ_FIRST(&dpt_softc_list);	     (dpt != NULL) && (dpt->unit != (minor_no & ~SCSI_CONTROL_MASK));	     dpt = TAILQ_NEXT(dpt, links));	return (dpt);}/** * Map a physical address to virtual one. * This is a first cut, experimental thing * * Paddr is the physical address to map * size is the size of the region, in bytes. * Because of alignment problems, we actually round up the size requested to * the next page count. */static          vm_offset_tdpt_physmap(u_int32_t req_paddr, vm_size_t req_size){	vm_offset_t     va;	int             ndx;	vm_size_t       size;	u_int32_t       paddr;	u_int32_t       offset;	size = (req_size / PAGE_SIZE + 1) * PAGE_SIZE;	paddr = req_paddr & 0xfffff000;	offset = req_paddr - paddr;	va = kmem_alloc_pageable(kernel_map, size);	if (va == (vm_offset_t) 0)		return (va);	for (ndx = 0; ndx < size; ndx += PAGE_SIZE) {		pmap_kenter(va + ndx, paddr + ndx);		invltlb();	}	return (va + offset);}/* * Release virtual space allocated by physmap We ASSUME that the correct * start address and the correct LENGTH are given. *  * Disaster will follow if these assumptions are false! */static voiddpt_unphysmap(u_int8_t * vaddr, vm_size_t size){	int             ndx;	for (ndx = 0; ndx < size; ndx += PAGE_SIZE) {		pmap_kremove((vm_offset_t) vaddr + ndx);	}	kmem_free(kernel_map, (vm_offset_t) vaddr, size);}/** * Collect interesting system information * The following is one of the worst hacks I have ever allowed my * name to be associated with. * There MUST be a system structure that provides this data. */static voiddpt_get_sysinfo(void){	int             i;	int             j;	int             ospl;	char           *addr;	bzero(&dpt_sysinfo, sizeof(dpt_sysinfo_t));	/**         * This is really silly, but we better run this in splhigh as we         * have no clue what we bump into.         * Let's hope anyone else who does this sort of things protects them         * with splhigh too.         */	ospl = splhigh();	switch (cpu_class) {	case CPUCLASS_386:		dpt_sig.Processor = dpt_sysinfo.processorType = PROC_386;		break;	case CPUCLASS_486:		dpt_sig.Processor = dpt_sysinfo.processorType = PROC_486;		break;	case CPUCLASS_586:		dpt_sig.Processor = dpt_sysinfo.processorType = PROC_PENTIUM;		break;	case CPUCLASS_686:		dpt_sig.Processor = dpt_sysinfo.processorType = PROC_P6;		break;	default:		dpt_sig.Processor = dpt_sysinfo.flags &= ~SI_ProcessorValid;		break;	}	/* Get The First Drive Type From CMOS */	outb(0x70, 0x12);	i = inb(0x71);	j = i >> 4;	if (i == 0x0f) {		outb(0x70, 0x19);		j = inb(0x71);	}	dpt_sysinfo.drive0CMOS = j;	/* Get The Second Drive Type From CMOS */	j = i & 0x0f;	if (i == 0x0f) {		outb(0x70, 0x1a);		j = inb(0x71);	}	dpt_sysinfo.drive1CMOS = j;	/* Get The Number Of Drives From The Bios Data Area */	if ((addr = (char *) dpt_physmap(0x0475, 1024)) == NULL) {		printf("DPT:  Cannot map BIOS address 0x0475.  No sysinfo... :-(\n");		return;	}	dpt_sysinfo.numDrives = *addr;	dpt_unphysmap(addr, 1024);	/* Get the processor fields from the SIG structure, and set the flags */	dpt_sysinfo.processorFamily = dpt_sig.ProcessorFamily;	dpt_sysinfo.flags = SI_CMOS_Valid | SI_NumDrivesValid;	/* Go out and look for SmartROM */	for (i = 0; i < 3; ++i) {		switch (i) {		case 0:			addr = (char *) dpt_physmap(0xC8000, 1024);		case 1:			addr = (char *) dpt_physmap(0xD8000, 1024);		default:			addr = (char *) dpt_physmap(0xDC000, 1024);		}		if (addr == NULL)			continue;		if (*((u_int16_t *) addr) == 0xaa55) {			if ((*((u_int32_t *) (addr + 6)) == 0x00202053)			  && (*((u_int32_t *) (addr + 10)) == 0x00545044)) {				break;			}		}		dpt_unphysmap(addr, 1024);		addr = NULL;	}	/**         * If i < 3, we founday it so set up a pointer to the starting         * version digit by searching for it.         */	if (addr != NULL) {		addr += 0x15;		for (i = 0; i < 64; ++i)			if ((addr[i] == ' ') && (addr[i + 1] == 'v'))				break;		if (i < 64) {			addr += (i + 4);		} else {			dpt_unphysmap(addr, 1024);			addr = NULL;		}	}	/* If all is well, set up the SmartROM version fields */	if (addr != NULL) {		dpt_sysinfo.smartROMMajorVersion = *addr - '0';	/* Assumes ASCII */		dpt_sysinfo.smartROMMinorVersion = *(addr + 2);		dpt_sysinfo.smartROMRevision = *(addr + 3);		dpt_sysinfo.flags |= SI_SmartROMverValid;	} else {		dpt_sysinfo.flags |= SI_NO_SmartROM;	}	/* Get the conventional memory size from CMOS */	outb(0x70, 0x16);	j = inb(0x71);	j <<= 8;	outb(0x70, 0x15);	j |= inb(0x71);	dpt_sysinfo.conventionalMemSize = j;	/**         * Get the extended memory found at power on from CMOS         */	outb(0x70, 0x31);	j = inb(0x71);	j <<= 8;	outb(0x70, 0x30);	j |= inb(0x71);	dpt_sysinfo.extendedMemSize = j;	dpt_sysinfo.flags |= SI_MemorySizeValid;	/* If there is 1 or 2 drives found, set up the drive parameters */	if (dpt_sysinfo.numDrives > 0) {		/* Get the pointer from int 41 for the first drive parameters */		addr = (char *) dpt_physmap(0x0104, 1024);		if (addr != NULL) {			j = *((ushort *) (addr + 2));			j *= 16;			j += *((ushort *) (addr));			dpt_unphysmap(addr, 1024);			addr = (char *) dpt_physmap(j, 1024);			if (addr != NULL) {				dpt_sysinfo.drives[0].cylinders = *((ushort *) addr);				dpt_sysinfo.drives[0].heads = *(addr + 2);				dpt_sysinfo.drives[0].sectors = *(addr + 14);				dpt_unphysmap(addr, 1024);			}		}		if (dpt_sysinfo.numDrives > 1) {			/*			 * Get the pointer from Int 46 for the second drive			 * parameters			 */			addr = (char *) dpt_physmap(0x01118, 1024);			j = *((ushort *) (addr + 2));			j *= 16;			j += *((ushort *) (addr));			dpt_unphysmap(addr, 1024);			addr = (char *) dpt_physmap(j, 1024);			if (addr != NULL) {				dpt_sysinfo.drives[1].cylinders = *((ushort *) addr);				dpt_sysinfo.drives[1].heads = *(addr + 2);				dpt_sysinfo.drives[1].sectors = *(addr + 14);				dpt_unphysmap(addr, 1024);			}		}		dpt_sysinfo.flags |= SI_DriveParamsValid;	}	splx(ospl);	/* Get the processor information */	dpt_sysinfo.flags |= SI_ProcessorValid;	/* Get the bus I/O bus information */	dpt_sysinfo.flags |= SI_BusTypeValid;	dpt_sysinfo.busType = HBA_BUS_PCI;	/* XXX Use _FreeBSD_Version_ */	dpt_sysinfo.osType = OS_FREEBSD;	dpt_sysinfo.osMajorVersion = osrelease[0] - '0';	if (osrelease[1] == '.')		dpt_sysinfo.osMinorVersion = osrelease[2] - '0';	else		dpt_sysinfo.osMinorVersion = 0;	if (osrelease[3] == '.')		dpt_sysinfo.osRevision = osrelease[4] - '0';	else		dpt_sysinfo.osMinorVersion = 0;	if (osrelease[5] == '.')		dpt_sysinfo.osSubRevision = osrelease[6] - '0';	else		dpt_sysinfo.osMinorVersion = 0;	dpt_sysinfo.flags |= SI_OSversionValid;}static intdpt_open(dev_t dev, int flags, int fmt, struct proc * p){	int             minor_no;	int             ospl;	dpt_softc_t    *dpt;	minor_no = minor(dev);	if (dpt_minor2unit(minor_no) == -1)		return (ENXIO);	else		dpt = dpt_minor2softc(minor_no);	if (dpt == NULL)		return (ENXIO);	ospl = splbio();	if (dpt->state & DPT_HA_CONTROL_ACTIVE) {		splx(ospl);		return (EBUSY);	} else {		if ((dpt_inbuf[minor_no & ~SCSI_CONTROL_MASK] = geteblk(PAGE_SIZE))		    == NULL) {#ifdef DPT_DEBUG_CONTROL			printf("dpt%d: Failed to obtain an I/O buffer\n",			       minor_no & ~SCSI_CONTROL_MASK);#endif			splx(ospl);			return (EINVAL);		}	}	dpt->state |= DPT_HA_CONTROL_ACTIVE;	splx(ospl);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?