File:  [DragonFly] / src / sys / dev / raid / dpt / dpt_control.c
Revision 1.6: download - view: text, annotated - select for diffs
Thu May 13 23:49:18 2004 UTC (10 years, 6 months ago) by dillon
Branches: MAIN
CVS tags: HEAD
device switch 1/many: Remove d_autoq, add d_clone (where d_autoq was).

d_autoq was used to allow the device port dispatch to mix old-style synchronous
calls with new style messaging calls within a particular device.  It was never
used for that purpose.

d_clone will be more fully implemented as work continues.  We are going to
install d_port in the dev_t (struct specinfo) structure itself and d_clone
will be needed to allow devices to 'revector' the port on a minor-number
by minor-number basis, in particular allowing minor numbers to be directly
dispatched to distinct threads.  This is something we will be needing later
on.

    1: /**
    2:  *       Copyright (c) 1997 by Simon Shapiro
    3:  *       All Rights Reserved
    4:  *
    5:  * Redistribution and use in source and binary forms, with or without
    6:  * modification, are permitted provided that the following conditions
    7:  * are met:
    8:  * 1. Redistributions of source code must retain the above copyright
    9:  *    notice, this list of conditions, and the following disclaimer,
   10:  *    without modification, immediately at the beginning of the file.
   11:  * 2. Redistributions in binary form must reproduce the above copyright
   12:  *    notice, this list of conditions and the following disclaimer in the
   13:  *    documentation and/or other materials provided with the distribution.
   14:  * 3. The name of the author may not be used to endorse or promote products
   15:  *    derived from this software without specific prior written permission.
   16:  *
   17:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   18:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20:  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
   21:  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   22:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   23:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   24:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   25:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   26:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   27:  * SUCH DAMAGE.
   28:  *
   29:  */
   30: 
   31: /**
   32:  * dpt_control.c: Control Functions and /dev entry points for /dev/dpt*
   33:  *
   34:  * Caveat Emptor!	This is work in progress.	The interfaces and
   35:  * functionality of this code will change (possibly radically) in the
   36:  * future.
   37:  */
   38: 
   39: #ident "$FreeBSD: src/sys/dev/dpt/dpt_control.c,v 1.16 1999/09/25 18:23:48 phk Exp $"
   40: #ident "$DragonFly: src/sys/dev/raid/dpt/dpt_control.c,v 1.6 2004/05/13 23:49:18 dillon Exp $"
   41: 
   42: #include "opt_dpt.h"
   43: 
   44: #include <i386/include/cputypes.h>
   45: #include <sys/param.h>
   46: #include <sys/systm.h>
   47: #include <sys/malloc.h>
   48: #include <sys/kernel.h>
   49: #include <sys/buf.h>
   50: #include <sys/uio.h>
   51: #include <sys/conf.h>
   52: #include <vm/vm.h>
   53: #include <vm/vm_kern.h>
   54: #include <vm/vm_extern.h>
   55: #include <vm/pmap.h>
   56: #include <scsi/scsiconf.h>
   57: 
   58: #include "dpt.h"
   59: 
   60: #define INLINE __inline
   61: 
   62: extern char     osrelease[];
   63: 
   64: enum dpt_message dpt_message;
   65: enum dpt_immediate_cmd dpt_immediate_cmd;
   66: 
   67: static dpt_sysinfo_t   dpt_sysinfo;
   68: 
   69: /* Entry points and other prototypes */
   70: static vm_offset_t dpt_physmap(u_int32_t paddr, vm_size_t size);
   71: static void     dpt_unphysmap(u_int8_t * vaddr, vm_size_t size);
   72: 
   73: static void     dpt_get_sysinfo(void);
   74: 
   75: static int      dpt_open(dev_t dev, int flags, int fmt, struct proc * p);
   76: static int      dpt_close(dev_t dev, int flags, int fmt, struct proc * p);
   77: static int      dpt_write(dev_t dev, struct uio * uio, int ioflag);
   78: static int      dpt_read(dev_t dev, struct uio * uio, int ioflag);
   79: static int      dpt_ioctl(dev_t dev, u_long cmd, caddr_t cmdarg, int flags, struct proc * p);
   80: 
   81: 
   82: /* This has to be modified as the processor and CPU are not known yet */
   83: static dpt_sig_t dpt_sig = {
   84: 	'd', 'P', 't', 'S', 'i', 'G',
   85: 	SIG_VERSION, PROC_INTEL, PROC_386,
   86: 	FT_HBADRVR, FTF_PROTECTED,
   87: 	OEM_DPT, OS_FREEBSD,
   88: 	CAP_PASS | CAP_OVERLAP | CAP_RAID0 | CAP_RAID1 | CAP_RAID5 | CAP_ASPI,
   89: 	DEV_ALL, ADF_SC4_PCI | ADF_SC3_PCI, 0, 0,
   90: 	DPT_RELEASE, DPT_VERSION, DPT_PATCH,
   91: 	DPT_MONTH, DPT_DAY, DPT_YEAR,
   92: 	"DPT FreeBSD Driver (c) 1997 Simon Shapiro"
   93: };
   94: 
   95: #define CDEV_MAJOR	    DPT_CDEV_MAJOR
   96: 
   97: /* Normally, this is a static structure.  But we need it in pci/dpt_pci.c */
   98: static struct cdevsw dpt_cdevsw = {
   99: 	/* name */	"dpt",
  100: 	/* maj */	CDEV_MAJOR,
  101: 	/* flags */	0,
  102: 	/* port */      NULL,
  103: 	/* clone */	NULL,
  104: 
  105: 	/* open */	dpt_open,
  106: 	/* close */	dpt_close,
  107: 	/* read */	dpt_read,
  108: 	/* write */	dpt_write,
  109: 	/* ioctl */	dpt_ioctl,
  110: 	/* poll */	nopoll,
  111: 	/* mmap */	nommap,
  112: 	/* strategy */	nostrategy,
  113: 	/* dump */	nodump,
  114: 	/* psize */	nopsize
  115: };
  116: 
  117: static struct buf *dpt_inbuf[DPT_MAX_ADAPTERS];
  118: static char     dpt_rw_command[DPT_MAX_ADAPTERS][DPT_RW_CMD_LEN + 1];
  119: 
  120: 
  121: /*
  122:  * Given a minor device number,
  123:  * return the pointer to its softc structure
  124:  */
  125: 
  126: dpt_softc_t *
  127: dpt_minor2softc(int minor_no)
  128: {
  129: 	dpt_softc_t    *dpt;
  130: 
  131: 	if (dpt_minor2unit(minor_no & ~SCSI_CONTROL_MASK) == -1)
  132: 		return (NULL);
  133: 
  134: 	for (dpt = TAILQ_FIRST(&dpt_softc_list);
  135: 	     (dpt != NULL) && (dpt->unit != (minor_no & ~SCSI_CONTROL_MASK));
  136: 	     dpt = TAILQ_NEXT(dpt, links));
  137: 
  138: 	return (dpt);
  139: }
  140: 
  141: /**
  142:  * Map a physical address to virtual one.
  143:  * This is a first cut, experimental thing
  144:  *
  145:  * Paddr is the physical address to map
  146:  * size is the size of the region, in bytes.
  147:  * Because of alignment problems, we actually round up the size requested to
  148:  * the next page count.
  149:  */
  150: 
  151: static          vm_offset_t
  152: dpt_physmap(u_int32_t req_paddr, vm_size_t req_size)
  153: {
  154: 	vm_offset_t     va;
  155: 	int             ndx;
  156: 	vm_size_t       size;
  157: 	u_int32_t       paddr;
  158: 	u_int32_t       offset;
  159: 
  160: 
  161: 
  162: 	size = (req_size / PAGE_SIZE + 1) * PAGE_SIZE;
  163: 	paddr = req_paddr & 0xfffff000;
  164: 	offset = req_paddr - paddr;
  165: 
  166: 	va = kmem_alloc_pageable(kernel_map, size);
  167: 	if (va == (vm_offset_t) 0)
  168: 		return (va);
  169: 
  170: 	for (ndx = 0; ndx < size; ndx += PAGE_SIZE) {
  171: 		pmap_kenter(va + ndx, paddr + ndx);
  172: 		invltlb();
  173: 	}
  174: 
  175: 	return (va + offset);
  176: }
  177: 
  178: 
  179: /*
  180:  * Release virtual space allocated by physmap We ASSUME that the correct
  181:  * start address and the correct LENGTH are given.
  182:  * 
  183:  * Disaster will follow if these assumptions are false!
  184:  */
  185: 
  186: static void
  187: dpt_unphysmap(u_int8_t * vaddr, vm_size_t size)
  188: {
  189: 	int             ndx;
  190: 
  191: 	for (ndx = 0; ndx < size; ndx += PAGE_SIZE) {
  192: 		pmap_kremove((vm_offset_t) vaddr + ndx);
  193: 	}
  194: 
  195: 	kmem_free(kernel_map, (vm_offset_t) vaddr, size);
  196: }
  197: 
  198: /**
  199:  * Collect interesting system information
  200:  * The following is one of the worst hacks I have ever allowed my
  201:  * name to be associated with.
  202:  * There MUST be a system structure that provides this data.
  203:  */
  204: 
  205: static void
  206: dpt_get_sysinfo(void)
  207: {
  208: 	int             i;
  209: 	int             j;
  210: 	int             ospl;
  211: 	char           *addr;
  212: 
  213: 	bzero(&dpt_sysinfo, sizeof(dpt_sysinfo_t));
  214: 
  215: 	/**
  216:          * This is really silly, but we better run this in splhigh as we
  217:          * have no clue what we bump into.
  218:          * Let's hope anyone else who does this sort of things protects them
  219:          * with splhigh too.
  220:          */
  221: 	ospl = splhigh();
  222: 
  223: 	switch (cpu_class) {
  224: 	case CPUCLASS_386:
  225: 		dpt_sig.Processor = dpt_sysinfo.processorType = PROC_386;
  226: 		break;
  227: 	case CPUCLASS_486:
  228: 		dpt_sig.Processor = dpt_sysinfo.processorType = PROC_486;
  229: 		break;
  230: 	case CPUCLASS_586:
  231: 		dpt_sig.Processor = dpt_sysinfo.processorType = PROC_PENTIUM;
  232: 		break;
  233: 	case CPUCLASS_686:
  234: 		dpt_sig.Processor = dpt_sysinfo.processorType = PROC_P6;
  235: 		break;
  236: 	default:
  237: 		dpt_sig.Processor = dpt_sysinfo.flags &= ~SI_ProcessorValid;
  238: 		break;
  239: 	}
  240: 
  241: 	/* Get The First Drive Type From CMOS */
  242: 	outb(0x70, 0x12);
  243: 	i = inb(0x71);
  244: 	j = i >> 4;
  245: 
  246: 	if (i == 0x0f) {
  247: 		outb(0x70, 0x19);
  248: 		j = inb(0x71);
  249: 	}
  250: 	dpt_sysinfo.drive0CMOS = j;
  251: 
  252: 	/* Get The Second Drive Type From CMOS */
  253: 	j = i & 0x0f;
  254: 	if (i == 0x0f) {
  255: 		outb(0x70, 0x1a);
  256: 		j = inb(0x71);
  257: 	}
  258: 	dpt_sysinfo.drive1CMOS = j;
  259: 
  260: 	/* Get The Number Of Drives From The Bios Data Area */
  261: 	if ((addr = (char *) dpt_physmap(0x0475, 1024)) == NULL) {
  262: 		printf("DPT:  Cannot map BIOS address 0x0475.  No sysinfo... :-(\n");
  263: 		return;
  264: 	}
  265: 	dpt_sysinfo.numDrives = *addr;
  266: 	dpt_unphysmap(addr, 1024);
  267: 
  268: 	/* Get the processor fields from the SIG structure, and set the flags */
  269: 	dpt_sysinfo.processorFamily = dpt_sig.ProcessorFamily;
  270: 	dpt_sysinfo.flags = SI_CMOS_Valid | SI_NumDrivesValid;
  271: 
  272: 	/* Go out and look for SmartROM */
  273: 	for (i = 0; i < 3; ++i) {
  274: 		switch (i) {
  275: 		case 0:
  276: 			addr = (char *) dpt_physmap(0xC8000, 1024);
  277: 		case 1:
  278: 			addr = (char *) dpt_physmap(0xD8000, 1024);
  279: 		default:
  280: 			addr = (char *) dpt_physmap(0xDC000, 1024);
  281: 		}
  282: 
  283: 		if (addr == NULL)
  284: 			continue;
  285: 
  286: 		if (*((u_int16_t *) addr) == 0xaa55) {
  287: 			if ((*((u_int32_t *) (addr + 6)) == 0x00202053)
  288: 			  && (*((u_int32_t *) (addr + 10)) == 0x00545044)) {
  289: 				break;
  290: 			}
  291: 		}
  292: 		dpt_unphysmap(addr, 1024);
  293: 		addr = NULL;
  294: 	}
  295: 
  296: 	/**
  297:          * If i < 3, we founday it so set up a pointer to the starting
  298:          * version digit by searching for it.
  299:          */
  300: 	if (addr != NULL) {
  301: 		addr += 0x15;
  302: 		for (i = 0; i < 64; ++i)
  303: 			if ((addr[i] == ' ') && (addr[i + 1] == 'v'))
  304: 				break;
  305: 		if (i < 64) {
  306: 			addr += (i + 4);
  307: 		} else {
  308: 			dpt_unphysmap(addr, 1024);
  309: 			addr = NULL;
  310: 		}
  311: 	}
  312: 	/* If all is well, set up the SmartROM version fields */
  313: 	if (addr != NULL) {
  314: 		dpt_sysinfo.smartROMMajorVersion = *addr - '0';	/* Assumes ASCII */
  315: 		dpt_sysinfo.smartROMMinorVersion = *(addr + 2);
  316: 		dpt_sysinfo.smartROMRevision = *(addr + 3);
  317: 		dpt_sysinfo.flags |= SI_SmartROMverValid;
  318: 	} else {
  319: 		dpt_sysinfo.flags |= SI_NO_SmartROM;
  320: 	}
  321: 
  322: 	/* Get the conventional memory size from CMOS */
  323: 	outb(0x70, 0x16);
  324: 	j = inb(0x71);
  325: 	j <<= 8;
  326: 	outb(0x70, 0x15);
  327: 	j |= inb(0x71);
  328: 	dpt_sysinfo.conventionalMemSize = j;
  329: 
  330: 	/**
  331:          * Get the extended memory found at power on from CMOS
  332:          */
  333: 	outb(0x70, 0x31);
  334: 	j = inb(0x71);
  335: 	j <<= 8;
  336: 	outb(0x70, 0x30);
  337: 	j |= inb(0x71);
  338: 	dpt_sysinfo.extendedMemSize = j;
  339: 	dpt_sysinfo.flags |= SI_MemorySizeValid;
  340: 
  341: 	/* If there is 1 or 2 drives found, set up the drive parameters */
  342: 	if (dpt_sysinfo.numDrives > 0) {
  343: 		/* Get the pointer from int 41 for the first drive parameters */
  344: 		addr = (char *) dpt_physmap(0x0104, 1024);
  345: 
  346: 		if (addr != NULL) {
  347: 			j = *((ushort *) (addr + 2));
  348: 			j *= 16;
  349: 			j += *((ushort *) (addr));
  350: 			dpt_unphysmap(addr, 1024);
  351: 			addr = (char *) dpt_physmap(j, 1024);
  352: 
  353: 			if (addr != NULL) {
  354: 				dpt_sysinfo.drives[0].cylinders = *((ushort *) addr);
  355: 				dpt_sysinfo.drives[0].heads = *(addr + 2);
  356: 				dpt_sysinfo.drives[0].sectors = *(addr + 14);
  357: 				dpt_unphysmap(addr, 1024);
  358: 			}
  359: 		}
  360: 		if (dpt_sysinfo.numDrives > 1) {
  361: 			/*
  362: 			 * Get the pointer from Int 46 for the second drive
  363: 			 * parameters
  364: 			 */
  365: 			addr = (char *) dpt_physmap(0x01118, 1024);
  366: 			j = *((ushort *) (addr + 2));
  367: 			j *= 16;
  368: 			j += *((ushort *) (addr));
  369: 			dpt_unphysmap(addr, 1024);
  370: 			addr = (char *) dpt_physmap(j, 1024);
  371: 
  372: 			if (addr != NULL) {
  373: 				dpt_sysinfo.drives[1].cylinders = *((ushort *) addr);
  374: 				dpt_sysinfo.drives[1].heads = *(addr + 2);
  375: 				dpt_sysinfo.drives[1].sectors = *(addr + 14);
  376: 				dpt_unphysmap(addr, 1024);
  377: 			}
  378: 		}
  379: 		dpt_sysinfo.flags |= SI_DriveParamsValid;
  380: 	}
  381: 	splx(ospl);
  382: 
  383: 	/* Get the processor information */
  384: 	dpt_sysinfo.flags |= SI_ProcessorValid;
  385: 
  386: 	/* Get the bus I/O bus information */
  387: 	dpt_sysinfo.flags |= SI_BusTypeValid;
  388: 	dpt_sysinfo.busType = HBA_BUS_PCI;
  389: 
  390: 	/* XXX Use _FreeBSD_Version_ */
  391: 	dpt_sysinfo.osType = OS_FREEBSD;
  392: 	dpt_sysinfo.osMajorVersion = osrelease[0] - '0';
  393: 	if (osrelease[1] == '.')
  394: 		dpt_sysinfo.osMinorVersion = osrelease[2] - '0';
  395: 	else
  396: 		dpt_sysinfo.osMinorVersion = 0;
  397: 	if (osrelease[3] == '.')
  398: 		dpt_sysinfo.osRevision = osrelease[4] - '0';
  399: 	else
  400: 		dpt_sysinfo.osMinorVersion = 0;
  401: 	if (osrelease[5] == '.')
  402: 		dpt_sysinfo.osSubRevision = osrelease[6] - '0';
  403: 	else
  404: 		dpt_sysinfo.osMinorVersion = 0;
  405: 
  406: 
  407: 	dpt_sysinfo.flags |= SI_OSversionValid;
  408: }
  409: 
  410: static int
  411: dpt_open(dev_t dev, int flags, int fmt, struct proc * p)
  412: {
  413: 	int             minor_no;
  414: 	int             ospl;
  415: 	dpt_softc_t    *dpt;
  416: 
  417: 	minor_no = minor(dev);
  418: 
  419: 	if (dpt_minor2unit(minor_no) == -1)
  420: 		return (ENXIO);
  421: 	else
  422: 		dpt = dpt_minor2softc(minor_no);
  423: 
  424: 	if (dpt == NULL)
  425: 		return (ENXIO);
  426: 
  427: 	ospl = splbio();
  428: 
  429: 	if (dpt->state & DPT_HA_CONTROL_ACTIVE) {
  430: 		splx(ospl);
  431: 		return (EBUSY);
  432: 	} else {
  433: 		if ((dpt_inbuf[minor_no & ~SCSI_CONTROL_MASK] = geteblk(PAGE_SIZE))
  434: 		    == NULL) {
  435: #ifdef DPT_DEBUG_CONTROL
  436: 			printf("dpt%d: Failed to obtain an I/O buffer\n",
  437: 			       minor_no & ~SCSI_CONTROL_MASK);
  438: #endif
  439: 			splx(ospl);
  440: 			return (EINVAL);
  441: 		}
  442: 	}
  443: 
  444: 	dpt->state |= DPT_HA_CONTROL_ACTIVE;
  445: 	splx(ospl);
  446: 	return (0);
  447: }
  448: 
  449: static int
  450: dpt_close(dev_t dev, int flags, int fmt, struct proc * p)
  451: {
  452: 	int             minor_no;
  453: 	dpt_softc_t    *dpt;
  454: 
  455: 	minor_no = minor(dev);
  456: 	dpt = dpt_minor2softc(minor_no);
  457: 
  458: 	if ((dpt_minor2unit(minor_no) == -1) || (dpt == NULL))
  459: 		return (ENXIO);
  460: 	else {
  461: 		brelse(dpt_inbuf[minor_no & ~SCSI_CONTROL_MASK]);
  462: 		dpt->state &= ~DPT_HA_CONTROL_ACTIVE;
  463: 		return (0);
  464: 	}
  465: }
  466: 
  467: static int
  468: dpt_write(dev_t dev, struct uio * uio, int ioflag)
  469: {
  470: 	int             minor_no;
  471: 	int             unit;
  472: 	int             error;
  473: 
  474: 	minor_no = minor(dev);
  475: 
  476: 	if (minor_no & SCSI_CONTROL_MASK) {
  477: #ifdef DPT_DEBUG_CONTROL
  478: 		printf("dpt%d:  I/O attempted to control channel (%x)\n",
  479: 		       dpt_minor2unit(minor_no), minor_no);
  480: #endif
  481: 		return (ENXIO);
  482: 	}
  483: 	unit = dpt_minor2unit(minor_no);
  484: 
  485: 	if (unit == -1) {
  486: 		return (ENXIO);
  487: 	} else if (uio->uio_resid > DPT_RW_CMD_LEN) {
  488: 		return (E2BIG);
  489: 	} else {
  490: 		char           *cp;
  491: 		int             length;
  492: 
  493: 		cp = dpt_inbuf[minor_no]->b_data;
  494: 		length = uio->uio_resid;	/* uiomove will change it! */
  495: 
  496: 		if ((error = uiomove(cp, length, uio) != 0)) {
  497: #ifdef DPT_DEBUG_CONTROL
  498: 			printf("dpt%d: uiomove(%x, %d, %x) failed (%d)\n",
  499: 			       minor_no, cp, length, uio, error);
  500: #endif
  501: 			return (error);
  502: 		} else {
  503: 			cp[length] = '\0';
  504: 
  505: 			/* A real kludge, to allow plain echo(1) to work */
  506: 			if (cp[length - 1] == '\n')
  507: 				cp[length - 1] = '\0';
  508: 
  509: 			strncpy(dpt_rw_command[unit], cp, DPT_RW_CMD_LEN);
  510: #ifdef DPT_DEBUG_CONTROL
  511: 			/**
  512: 			 * For lack of anything better to do;
  513: 			 * For now, dump the data so we can look at it and rejoice
  514: 			 */
  515: 			printf("dpt%d: Command \"%s\" arrived\n",
  516: 			       unit, dpt_rw_command[unit]);
  517: #endif
  518: 		}
  519: 	}
  520: 
  521: 	return (error);
  522: }
  523: 
  524: static int
  525: dpt_read(dev_t dev, struct uio * uio, int ioflag)
  526: {
  527: 	dpt_softc_t    *dpt;
  528: 	int             error;
  529: 	int             minor_no;
  530: 	int             ospl;
  531: 
  532: 	minor_no = minor(dev);
  533: 	error = 0;
  534: 
  535: #ifdef DPT_DEBUG_CONTROL
  536: 	printf("dpt%d: read, count = %d, dev = %08x\n",
  537: 	       minor_no, uio->uio_resid, dev);
  538: #endif
  539: 
  540: 	if (minor_no & SCSI_CONTROL_MASK) {
  541: #ifdef DPT_DEBUG_CONTROL
  542: 		printf("dpt%d:  I/O attempted to control channel (%x)\n",
  543: 		       dpt_minor2unit(minor_no), minor_no);
  544: #endif
  545: 		return (ENXIO);
  546: 	}
  547: 	if (dpt_minor2unit(minor_no) == -1) {
  548: 		return (ENXIO);
  549: 	}
  550: 	/*
  551: 	 * else if ( uio->uio_resid > PAGE_SIZE ) { return(E2BIG); }
  552: 	 */ 
  553: 	else {
  554: 		char           *work_buffer;
  555: 		char           *wbp;
  556: 		char           *command;
  557: 		int             work_size;
  558: 		int             ndx;
  559: 		int             x;
  560: 
  561: 		if ((dpt = dpt_minor2softc(minor_no)) == NULL)
  562: 			return (ENXIO);
  563: 
  564: 		work_buffer = (u_int8_t *) malloc(PAGE_SIZE, M_TEMP, M_WAITOK);
  565: 		wbp = work_buffer;
  566: 		work_size = 0;
  567: 
  568: 		ospl = splbio();
  569: 
  570: 		command = dpt_rw_command[dpt->unit];
  571: 		if (strcmp(command, DPT_RW_CMD_DUMP_SOFTC) == 0) {
  572: 			x = sprintf(wbp, "dpt%d:%s:%s:%s:%s:%x\n",
  573: 				    dpt->unit,
  574: 				    dpt->board_data.vendor,
  575: 				    dpt->board_data.modelNum,
  576: 				    dpt->board_data.firmware,
  577: 				    dpt->board_data.protocol,
  578: 				    dpt->EATA_revision);
  579: 			work_size += x;
  580: 			wbp += x;
  581: 
  582: 		} else if (strcmp(command, DPT_RW_CMD_DUMP_SYSINFO) == 0) {
  583: 			x = sprintf(wbp, "dpt%d:%d:%d:%d:%d:%d:%d:%d:%d:%s:"
  584: 				    "%d:%d:%d:%d:%d:%d:%d:%d\n",
  585: 				    dpt->unit,
  586: 				    dpt_sysinfo.drive0CMOS,
  587: 				    dpt_sysinfo.drive1CMOS,
  588: 				    dpt_sysinfo.numDrives,
  589: 				    dpt_sysinfo.processorFamily,
  590: 				    dpt_sysinfo.processorType,
  591: 				    dpt_sysinfo.smartROMMajorVersion,
  592: 				    dpt_sysinfo.smartROMMinorVersion,
  593: 				    dpt_sysinfo.smartROMRevision,
  594: 				    i2bin(dpt_sysinfo.flags,
  595: 					  sizeof(dpt->queue_status) * 8),
  596: 				    dpt_sysinfo.conventionalMemSize,
  597: 				    dpt_sysinfo.extendedMemSize,
  598: 			     dpt_sysinfo.osType, dpt_sysinfo.osMajorVersion,
  599: 			 dpt_sysinfo.osMinorVersion, dpt_sysinfo.osRevision,
  600: 			    dpt_sysinfo.osSubRevision, dpt_sysinfo.busType);
  601: 			work_size += x;
  602: 			wbp += x;
  603: 
  604: 			for (ndx = 0; ndx < 16; ndx++) {
  605: 				if (dpt_sysinfo.drives[ndx].cylinders != 0) {
  606: 					x = sprintf(wbp, "dpt%d:d%dc%dh%ds%d\n",
  607: 						    dpt->unit,
  608: 						    ndx,
  609: 					  dpt_sysinfo.drives[ndx].cylinders,
  610: 					      dpt_sysinfo.drives[ndx].heads,
  611: 					   dpt_sysinfo.drives[ndx].sectors);
  612: 					work_size += x;
  613: 					wbp += x;
  614: 				}
  615: 			}
  616: 		} else if (strcmp(command, DPT_RW_CMD_DUMP_METRICS) == 0) {
  617: 			x = sprintf(wbp,
  618: 				    "dpt%d: No metrics available.\n"
  619: 				    "Run the dpt_dm command, or use the\n"
  620: 			   "DPT_IOCTL_INTERNAL_METRICS ioctl system call\n",
  621: 				    dpt->unit);
  622: 			work_size += x;
  623: 			wbp += x;
  624: 		} else if (strcmp(command, DPT_RW_CMD_CLEAR_METRICS) == 0) {
  625: #ifdef DPT_MEASURE_PERFORMANCE
  626: 			dpt_reset_performance(dpt);
  627: #endif				/* DPT_MEASURE_PERFORMANCE */
  628: 
  629: 			x = sprintf(wbp, "dpt%d: Metrics have been cleared\n",
  630: 				    dpt->unit);
  631: 			work_size += x;
  632: 			wbp += x;
  633: 		} else if (strcmp(command, DPT_RW_CMD_SHOW_LED) == 0) {
  634: 
  635: 			x = sprintf(wbp, "dpt%d:%s\n",
  636: 				dpt->unit, i2bin(dpt_blinking_led(dpt), 8));
  637: 			work_size += x;
  638: 			wbp += x;
  639: 		} else {
  640: #ifdef DPT_DEBUG_CONTROL
  641: 			printf("dpt%d: Bad READ state (%s)\n", minor_no, command);
  642: #endif
  643: 			splx(ospl);
  644: 			error = EINVAL;
  645: 		}
  646: 
  647: 		if (error == 0) {
  648: 			work_buffer[work_size++] = '\0';
  649: 			error = uiomove(work_buffer, work_size, uio);
  650: 			uio->uio_resid = 0;
  651: #ifdef DPT_DEBUG_CONTROL
  652: 			if (error) {
  653: 				printf("dpt%d: READ uimove failed (%d)\n", dpt->unit, error);
  654: 			}
  655: #endif
  656: 		}
  657: 	}
  658: 	splx(ospl);
  659: 	return (error);
  660: }
  661: 
  662: /**
  663:  * This is the control syscall interface.
  664:  * It should be binary compatible with UnixWare,
  665:  * if not totally syntatically so.
  666:  */
  667: 
  668: static int
  669: dpt_ioctl(dev_t dev, u_long cmd, caddr_t cmdarg, int flags, struct proc * p)
  670: {
  671: 	int             minor_no;
  672: 	dpt_softc_t    *dpt;
  673: 	dpt_user_softc_t udpt;
  674: 	int             result;
  675: 	int             ndx;
  676: 	eata_pt_t      *eata_pass_thru;
  677: 
  678: 	minor_no = minor(dev);
  679: 	result = 0;
  680: 
  681: 	if (!(minor_no & SCSI_CONTROL_MASK)) {
  682: #ifdef DPT_DEBUG_CONTROL
  683: 		printf("dpt%d:  Control attempted to I/O channel (%x)\n",
  684: 		       dpt_minor2unit(minor_no), minor_no);
  685: #endif				/* DEBUG */
  686: 		return (ENXIO);
  687: 	} else
  688: 		minor_no &= ~SCSI_CONTROL_MASK;
  689: 
  690: #ifdef DPT_DEBUG_CONTROL
  691: 	printf("dpt%d: IOCTL(%x, %x, %p, %x, %p)\n",
  692: 	       minor_no, dev, cmd, cmdarg, flags, p);
  693: #endif				/* DEBUG */
  694: 
  695: 	if ((dpt = dpt_minor2softc(minor_no)) == NULL)
  696: 		return (result);
  697: 
  698: 	switch (cmd) {
  699: #ifdef DPT_MEASURE_PERFORMANCE
  700: 	case DPT_IOCTL_INTERNAL_METRICS:	    
  701: 		memcpy(cmdarg, &dpt->performance, sizeof(dpt->performance));
  702: 		return (0);
  703: #endif				/* DPT_MEASURE_PERFORMANCE */
  704: 	case DPT_IOCTL_SOFTC:
  705: 		udpt.unit = dpt->unit;
  706: 		udpt.handle_interrupts = dpt->handle_interrupts;
  707: 		udpt.target_mode_enabled = dpt->target_mode_enabled;
  708: 		udpt.spare = dpt->spare;
  709: 
  710: 		udpt.total_ccbs_count = dpt->total_ccbs_count;
  711: 		udpt.free_ccbs_count = dpt->free_ccbs_count;
  712: 		udpt.waiting_ccbs_count = dpt->waiting_ccbs_count;
  713: 		udpt.submitted_ccbs_count = dpt->submitted_ccbs_count;
  714: 		udpt.completed_ccbs_count = dpt->completed_ccbs_count;
  715: 
  716: 		udpt.queue_status = dpt->queue_status;
  717: 		udpt.free_lock = dpt->free_lock;
  718: 		udpt.waiting_lock = dpt->waiting_lock;
  719: 		udpt.submitted_lock = dpt->submitted_lock;
  720: 		udpt.completed_lock = dpt->completed_lock;
  721: 
  722: 		udpt.commands_processed = dpt->commands_processed;
  723: 		udpt.lost_interrupts = dpt->lost_interrupts;
  724: 
  725: 		udpt.channels = dpt->channels;
  726: 		udpt.max_id = dpt->max_id;
  727: 		udpt.max_lun = dpt->max_lun;
  728: 
  729: 		udpt.io_base = dpt->io_base;
  730: 		udpt.v_membase = (u_int8_t *) dpt->v_membase;
  731: 		udpt.p_membase = (u_int8_t *) dpt->p_membase;
  732: 
  733: 		udpt.irq = dpt->irq;
  734: 		udpt.dma_channel = dpt->dma_channel;
  735: 
  736: 		udpt.board_data = dpt->board_data;
  737: 		udpt.EATA_revision = dpt->EATA_revision;
  738: 		udpt.bustype = dpt->bustype;
  739: 		udpt.state = dpt->state;
  740: 
  741: 		udpt.primary = dpt->primary;
  742: 		udpt.more_support = dpt->more_support;
  743: 		udpt.immediate_support = dpt->immediate_support;
  744: 		udpt.broken_INQUIRY = dpt->broken_INQUIRY;
  745: 		udpt.spare2 = dpt->spare2;
  746: 
  747: 		for (ndx = 0; ndx < MAX_CHANNELS; ndx++) {
  748: 			udpt.resetlevel[ndx] = dpt->resetlevel[ndx];
  749: 			udpt.hostid[ndx] = dpt->hostid[ndx];
  750: 		}
  751: 
  752: 		udpt.last_ccb = dpt->last_ccb;
  753: 		udpt.cplen = dpt->cplen;
  754: 		udpt.cppadlen = dpt->cppadlen;
  755: 		udpt.queuesize = dpt->queuesize;
  756: 		udpt.sgsize = dpt->sgsize;
  757: 		udpt.cache_type = dpt->cache_type;
  758: 		udpt.cache_size = dpt->cache_size;
  759: 
  760: 		memcpy(cmdarg, &udpt, sizeof(dpt_user_softc_t));
  761: 		return (0);
  762: 	case SDI_SEND:
  763: 	case DPT_IOCTL_SEND:
  764: 		eata_pass_thru = (eata_pt_t *) cmdarg;
  765: 
  766: 		if ((eata_pass_thru->eataID[0] != 'E')
  767: 		    || (eata_pass_thru->eataID[1] != 'A')
  768: 		    || (eata_pass_thru->eataID[2] != 'T')
  769: 		    || (eata_pass_thru->eataID[3] != 'A')) {
  770: 			return (EFAULT);
  771: 		}
  772: 		switch (eata_pass_thru->command) {
  773: 		case DPT_SIGNATURE:
  774: 			return (copyout((char *) &dpt_sig,
  775: 				 (caddr_t *) eata_pass_thru->command_buffer,
  776: 					sizeof(dpt_sig)));
  777: 		case DPT_NUMCTRLS:
  778: 			return (copyout((char *) &dpt_controllers_present,
  779: 				 (caddr_t *) eata_pass_thru->command_buffer,
  780: 					sizeof(dpt_controllers_present)));
  781: 		case DPT_CTRLINFO:
  782: 			{
  783: 				dpt_compat_ha_t compat_softc;
  784: 				int             ndx;
  785: 
  786: 				compat_softc.ha_state = dpt->state;	/* Different Meaning! */
  787: 				for (ndx = 0; ndx < MAX_CHANNELS; ndx++)
  788: 					compat_softc.ha_id[ndx] = dpt->hostid[ndx];
  789: 
  790: 				compat_softc.ha_vect = dpt->irq;
  791: 				compat_softc.ha_base = BaseRegister(dpt);
  792: 				compat_softc.ha_max_jobs = dpt->total_ccbs_count;
  793: 				compat_softc.ha_cache = dpt->cache_type;
  794: 				compat_softc.ha_cachesize = dpt->cache_size;
  795: 				compat_softc.ha_nbus = dpt->dma_channel + 1;
  796: 				compat_softc.ha_ntargets = dpt->max_id + 1;
  797: 				compat_softc.ha_nluns = dpt->max_lun + 1;
  798: 				compat_softc.ha_tshift = (dpt->max_id == 7) ? 3 : 4;
  799: 				compat_softc.ha_bshift = 2;
  800: 				compat_softc.ha_npend = dpt->submitted_ccbs_count;
  801: 				compat_softc.ha_active_jobs = dpt->waiting_ccbs_count;
  802: 				strncpy(compat_softc.ha_fw_version,
  803: 				    dpt->board_data.firmware,
  804: 				    sizeof(compat_softc.ha_fw_version));
  805: 				compat_softc.ha_ccb = NULL;
  806: 				compat_softc.ha_cblist = NULL;
  807: 				compat_softc.ha_dev = NULL;
  808: 				compat_softc.ha_StPkt_lock = NULL;
  809: 				compat_softc.ha_ccb_lock = NULL;
  810: 				compat_softc.ha_LuQWaiting = NULL;
  811: 				compat_softc.ha_QWait_lock = NULL;
  812: 				compat_softc.ha_QWait_opri = NULL;
  813: 
  814: 				return (copyout((char *) &compat_softc,
  815: 				 (caddr_t *) eata_pass_thru->command_buffer,
  816: 						sizeof(dpt_compat_ha_t)));
  817: 			}
  818: 			break;
  819: 
  820: 		case DPT_SYSINFO:
  821: 			return (copyout((char *) &dpt_sysinfo,
  822: 				 (caddr_t *) eata_pass_thru->command_buffer,
  823: 					sizeof(dpt_sysinfo)));
  824: 		case EATAUSRCMD:
  825: 			result = dpt_user_cmd(dpt, eata_pass_thru, cmdarg, minor_no);
  826: 			return (result);
  827: 		case DPT_BLINKLED:
  828: 			result = dpt_blinking_led(dpt);
  829: 			return (copyout((caddr_t) & result,
  830: 				 (caddr_t *) eata_pass_thru->command_buffer,
  831: 					sizeof(result)));
  832: 		default:
  833: 			printf("dpt%d: Invalid (%x) pass-throu command\n",
  834: 			       dpt->unit, eata_pass_thru->command);
  835: 			result = EINVAL;
  836: 		}
  837: 
  838: 	default:
  839: 		printf("dpt%d: Invalid (%lx) IOCTL\n", dpt->unit, cmd);
  840: 		return (EINVAL);
  841: 
  842: 	}
  843: 
  844: 	return (result);
  845: }
  846: 
  847: static          dpt_devsw_installed = 0;
  848: 
  849: static void
  850: dpt_drvinit(void *unused)
  851: {
  852: 
  853: 	if (!dpt_devsw_installed) {
  854: 		if (bootverbose)
  855: 			printf("DPT:  RAID Manager driver, Version %d.%d.%d\n",
  856: 			       DPT_CTL_RELEASE, DPT_CTL_VERSION, DPT_CTL_PATCH);
  857: 
  858: 		/* Add the I/O (data) channel */
  859: 		cdevsw_add(&dpt_cdevsw);
  860: 
  861: 		dpt_devsw_installed = 1;
  862: 	}
  863: 	dpt_get_sysinfo();
  864: }
  865: 
  866: SYSINIT(dpt_dev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE + CDEV_MAJOR, dpt_drvinit, NULL)
  867: /* End of the dpt_control driver */