2 * Copyright (c) 1997 by Simon Shapiro
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
32 * dpt_control.c: Control Functions and /dev entry points for /dev/dpt*
34 * Caveat Emptor! This is work in progress. The interfaces and
35 * functionality of this code will change (possibly radically) in the
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.2 2003/06/17 04:28:23 dillon Exp $"
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>
53 #include <vm/vm_kern.h>
54 #include <vm/vm_extern.h>
56 #include <scsi/scsiconf.h>
58 #include <dev/dpt/dpt.h>
60 #define INLINE __inline
62 extern char osrelease[];
64 static dpt_sysinfo_t dpt_sysinfo;
66 /* Entry points and other prototypes */
67 static vm_offset_t dpt_physmap(u_int32_t paddr, vm_size_t size);
68 static void dpt_unphysmap(u_int8_t * vaddr, vm_size_t size);
70 static void dpt_get_sysinfo(void);
72 static int dpt_open(dev_t dev, int flags, int fmt, struct proc * p);
73 static int dpt_close(dev_t dev, int flags, int fmt, struct proc * p);
74 static int dpt_write(dev_t dev, struct uio * uio, int ioflag);
75 static int dpt_read(dev_t dev, struct uio * uio, int ioflag);
76 static int dpt_ioctl(dev_t dev, u_long cmd, caddr_t cmdarg, int flags, struct proc * p);
79 /* This has to be modified as the processor and CPU are not known yet */
80 static dpt_sig_t dpt_sig = {
81 'd', 'P', 't', 'S', 'i', 'G',
82 SIG_VERSION, PROC_INTEL, PROC_386,
83 FT_HBADRVR, FTF_PROTECTED,
85 CAP_PASS | CAP_OVERLAP | CAP_RAID0 | CAP_RAID1 | CAP_RAID5 | CAP_ASPI,
86 DEV_ALL, ADF_SC4_PCI | ADF_SC3_PCI, 0, 0,
87 DPT_RELEASE, DPT_VERSION, DPT_PATCH,
88 DPT_MONTH, DPT_DAY, DPT_YEAR,
89 "DPT FreeBSD Driver (c) 1997 Simon Shapiro"
92 #define CDEV_MAJOR DPT_CDEV_MAJOR
94 /* Normally, this is a static structure. But we need it in pci/dpt_pci.c */
95 static struct cdevsw dpt_cdevsw = {
97 /* close */ dpt_close,
99 /* write */ dpt_write,
100 /* ioctl */ dpt_ioctl,
103 /* strategy */ nostrategy,
105 /* maj */ CDEV_MAJOR,
112 static struct buf *dpt_inbuf[DPT_MAX_ADAPTERS];
113 static char dpt_rw_command[DPT_MAX_ADAPTERS][DPT_RW_CMD_LEN + 1];
117 * Given a minor device number,
118 * return the pointer to its softc structure
122 dpt_minor2softc(int minor_no)
126 if (dpt_minor2unit(minor_no & ~SCSI_CONTROL_MASK) == -1)
129 for (dpt = TAILQ_FIRST(&dpt_softc_list);
130 (dpt != NULL) && (dpt->unit != (minor_no & ~SCSI_CONTROL_MASK));
131 dpt = TAILQ_NEXT(dpt, links));
137 * Map a physical address to virtual one.
138 * This is a first cut, experimental thing
140 * Paddr is the physical address to map
141 * size is the size of the region, in bytes.
142 * Because of alignment problems, we actually round up the size requested to
143 * the next page count.
147 dpt_physmap(u_int32_t req_paddr, vm_size_t req_size)
157 size = (req_size / PAGE_SIZE + 1) * PAGE_SIZE;
158 paddr = req_paddr & 0xfffff000;
159 offset = req_paddr - paddr;
161 va = kmem_alloc_pageable(kernel_map, size);
162 if (va == (vm_offset_t) 0)
165 for (ndx = 0; ndx < size; ndx += PAGE_SIZE) {
166 pmap_kenter(va + ndx, paddr + ndx);
170 return (va + offset);
175 * Release virtual space allocated by physmap We ASSUME that the correct
176 * start address and the correct LENGTH are given.
178 * Disaster will follow if these assumptions are false!
182 dpt_unphysmap(u_int8_t * vaddr, vm_size_t size)
186 for (ndx = 0; ndx < size; ndx += PAGE_SIZE) {
187 pmap_kremove((vm_offset_t) vaddr + ndx);
190 kmem_free(kernel_map, (vm_offset_t) vaddr, size);
194 * Collect interesting system information
195 * The following is one of the worst hacks I have ever allowed my
196 * name to be associated with.
197 * There MUST be a system structure that provides this data.
201 dpt_get_sysinfo(void)
208 bzero(&dpt_sysinfo, sizeof(dpt_sysinfo_t));
211 * This is really silly, but we better run this in splhigh as we
212 * have no clue what we bump into.
213 * Let's hope anyone else who does this sort of things protects them
220 dpt_sig.Processor = dpt_sysinfo.processorType = PROC_386;
223 dpt_sig.Processor = dpt_sysinfo.processorType = PROC_486;
226 dpt_sig.Processor = dpt_sysinfo.processorType = PROC_PENTIUM;
229 dpt_sig.Processor = dpt_sysinfo.processorType = PROC_P6;
232 dpt_sig.Processor = dpt_sysinfo.flags &= ~SI_ProcessorValid;
236 /* Get The First Drive Type From CMOS */
245 dpt_sysinfo.drive0CMOS = j;
247 /* Get The Second Drive Type From CMOS */
253 dpt_sysinfo.drive1CMOS = j;
255 /* Get The Number Of Drives From The Bios Data Area */
256 if ((addr = (char *) dpt_physmap(0x0475, 1024)) == NULL) {
257 printf("DPT: Cannot map BIOS address 0x0475. No sysinfo... :-(\n");
260 dpt_sysinfo.numDrives = *addr;
261 dpt_unphysmap(addr, 1024);
263 /* Get the processor fields from the SIG structure, and set the flags */
264 dpt_sysinfo.processorFamily = dpt_sig.ProcessorFamily;
265 dpt_sysinfo.flags = SI_CMOS_Valid | SI_NumDrivesValid;
267 /* Go out and look for SmartROM */
268 for (i = 0; i < 3; ++i) {
271 addr = (char *) dpt_physmap(0xC8000, 1024);
273 addr = (char *) dpt_physmap(0xD8000, 1024);
275 addr = (char *) dpt_physmap(0xDC000, 1024);
281 if (*((u_int16_t *) addr) == 0xaa55) {
282 if ((*((u_int32_t *) (addr + 6)) == 0x00202053)
283 && (*((u_int32_t *) (addr + 10)) == 0x00545044)) {
287 dpt_unphysmap(addr, 1024);
292 * If i < 3, we founday it so set up a pointer to the starting
293 * version digit by searching for it.
297 for (i = 0; i < 64; ++i)
298 if ((addr[i] == ' ') && (addr[i + 1] == 'v'))
303 dpt_unphysmap(addr, 1024);
307 /* If all is well, set up the SmartROM version fields */
309 dpt_sysinfo.smartROMMajorVersion = *addr - '0'; /* Assumes ASCII */
310 dpt_sysinfo.smartROMMinorVersion = *(addr + 2);
311 dpt_sysinfo.smartROMRevision = *(addr + 3);
312 dpt_sysinfo.flags |= SI_SmartROMverValid;
314 dpt_sysinfo.flags |= SI_NO_SmartROM;
317 /* Get the conventional memory size from CMOS */
323 dpt_sysinfo.conventionalMemSize = j;
326 * Get the extended memory found at power on from CMOS
333 dpt_sysinfo.extendedMemSize = j;
334 dpt_sysinfo.flags |= SI_MemorySizeValid;
336 /* If there is 1 or 2 drives found, set up the drive parameters */
337 if (dpt_sysinfo.numDrives > 0) {
338 /* Get the pointer from int 41 for the first drive parameters */
339 addr = (char *) dpt_physmap(0x0104, 1024);
342 j = *((ushort *) (addr + 2));
344 j += *((ushort *) (addr));
345 dpt_unphysmap(addr, 1024);
346 addr = (char *) dpt_physmap(j, 1024);
349 dpt_sysinfo.drives[0].cylinders = *((ushort *) addr);
350 dpt_sysinfo.drives[0].heads = *(addr + 2);
351 dpt_sysinfo.drives[0].sectors = *(addr + 14);
352 dpt_unphysmap(addr, 1024);
355 if (dpt_sysinfo.numDrives > 1) {
357 * Get the pointer from Int 46 for the second drive
360 addr = (char *) dpt_physmap(0x01118, 1024);
361 j = *((ushort *) (addr + 2));
363 j += *((ushort *) (addr));
364 dpt_unphysmap(addr, 1024);
365 addr = (char *) dpt_physmap(j, 1024);
368 dpt_sysinfo.drives[1].cylinders = *((ushort *) addr);
369 dpt_sysinfo.drives[1].heads = *(addr + 2);
370 dpt_sysinfo.drives[1].sectors = *(addr + 14);
371 dpt_unphysmap(addr, 1024);
374 dpt_sysinfo.flags |= SI_DriveParamsValid;
378 /* Get the processor information */
379 dpt_sysinfo.flags |= SI_ProcessorValid;
381 /* Get the bus I/O bus information */
382 dpt_sysinfo.flags |= SI_BusTypeValid;
383 dpt_sysinfo.busType = HBA_BUS_PCI;
385 /* XXX Use _FreeBSD_Version_ */
386 dpt_sysinfo.osType = OS_FREEBSD;
387 dpt_sysinfo.osMajorVersion = osrelease[0] - '0';
388 if (osrelease[1] == '.')
389 dpt_sysinfo.osMinorVersion = osrelease[2] - '0';
391 dpt_sysinfo.osMinorVersion = 0;
392 if (osrelease[3] == '.')
393 dpt_sysinfo.osRevision = osrelease[4] - '0';
395 dpt_sysinfo.osMinorVersion = 0;
396 if (osrelease[5] == '.')
397 dpt_sysinfo.osSubRevision = osrelease[6] - '0';
399 dpt_sysinfo.osMinorVersion = 0;
402 dpt_sysinfo.flags |= SI_OSversionValid;
406 dpt_open(dev_t dev, int flags, int fmt, struct proc * p)
412 minor_no = minor(dev);
414 if (dpt_minor2unit(minor_no) == -1)
417 dpt = dpt_minor2softc(minor_no);
424 if (dpt->state & DPT_HA_CONTROL_ACTIVE) {
428 if ((dpt_inbuf[minor_no & ~SCSI_CONTROL_MASK] = geteblk(PAGE_SIZE))
430 #ifdef DPT_DEBUG_CONTROL
431 printf("dpt%d: Failed to obtain an I/O buffer\n",
432 minor_no & ~SCSI_CONTROL_MASK);
439 dpt->state |= DPT_HA_CONTROL_ACTIVE;
445 dpt_close(dev_t dev, int flags, int fmt, struct proc * p)
450 minor_no = minor(dev);
451 dpt = dpt_minor2softc(minor_no);
453 if ((dpt_minor2unit(minor_no) == -1) || (dpt == NULL))
456 brelse(dpt_inbuf[minor_no & ~SCSI_CONTROL_MASK]);
457 dpt->state &= ~DPT_HA_CONTROL_ACTIVE;
463 dpt_write(dev_t dev, struct uio * uio, int ioflag)
469 minor_no = minor(dev);
471 if (minor_no & SCSI_CONTROL_MASK) {
472 #ifdef DPT_DEBUG_CONTROL
473 printf("dpt%d: I/O attempted to control channel (%x)\n",
474 dpt_minor2unit(minor_no), minor_no);
478 unit = dpt_minor2unit(minor_no);
482 } else if (uio->uio_resid > DPT_RW_CMD_LEN) {
488 cp = dpt_inbuf[minor_no]->b_data;
489 length = uio->uio_resid; /* uiomove will change it! */
491 if ((error = uiomove(cp, length, uio) != 0)) {
492 #ifdef DPT_DEBUG_CONTROL
493 printf("dpt%d: uiomove(%x, %d, %x) failed (%d)\n",
494 minor_no, cp, length, uio, error);
500 /* A real kludge, to allow plain echo(1) to work */
501 if (cp[length - 1] == '\n')
502 cp[length - 1] = '\0';
504 strncpy(dpt_rw_command[unit], cp, DPT_RW_CMD_LEN);
505 #ifdef DPT_DEBUG_CONTROL
507 * For lack of anything better to do;
508 * For now, dump the data so we can look at it and rejoice
510 printf("dpt%d: Command \"%s\" arrived\n",
511 unit, dpt_rw_command[unit]);
520 dpt_read(dev_t dev, struct uio * uio, int ioflag)
527 minor_no = minor(dev);
530 #ifdef DPT_DEBUG_CONTROL
531 printf("dpt%d: read, count = %d, dev = %08x\n",
532 minor_no, uio->uio_resid, dev);
535 if (minor_no & SCSI_CONTROL_MASK) {
536 #ifdef DPT_DEBUG_CONTROL
537 printf("dpt%d: I/O attempted to control channel (%x)\n",
538 dpt_minor2unit(minor_no), minor_no);
542 if (dpt_minor2unit(minor_no) == -1) {
546 * else if ( uio->uio_resid > PAGE_SIZE ) { return(E2BIG); }
556 if ((dpt = dpt_minor2softc(minor_no)) == NULL)
559 work_buffer = (u_int8_t *) malloc(PAGE_SIZE, M_TEMP, M_WAITOK);
565 command = dpt_rw_command[dpt->unit];
566 if (strcmp(command, DPT_RW_CMD_DUMP_SOFTC) == 0) {
567 x = sprintf(wbp, "dpt%d:%s:%s:%s:%s:%x\n",
569 dpt->board_data.vendor,
570 dpt->board_data.modelNum,
571 dpt->board_data.firmware,
572 dpt->board_data.protocol,
577 } else if (strcmp(command, DPT_RW_CMD_DUMP_SYSINFO) == 0) {
578 x = sprintf(wbp, "dpt%d:%d:%d:%d:%d:%d:%d:%d:%d:%s:"
579 "%d:%d:%d:%d:%d:%d:%d:%d\n",
581 dpt_sysinfo.drive0CMOS,
582 dpt_sysinfo.drive1CMOS,
583 dpt_sysinfo.numDrives,
584 dpt_sysinfo.processorFamily,
585 dpt_sysinfo.processorType,
586 dpt_sysinfo.smartROMMajorVersion,
587 dpt_sysinfo.smartROMMinorVersion,
588 dpt_sysinfo.smartROMRevision,
589 i2bin(dpt_sysinfo.flags,
590 sizeof(dpt->queue_status) * 8),
591 dpt_sysinfo.conventionalMemSize,
592 dpt_sysinfo.extendedMemSize,
593 dpt_sysinfo.osType, dpt_sysinfo.osMajorVersion,
594 dpt_sysinfo.osMinorVersion, dpt_sysinfo.osRevision,
595 dpt_sysinfo.osSubRevision, dpt_sysinfo.busType);
599 for (ndx = 0; ndx < 16; ndx++) {
600 if (dpt_sysinfo.drives[ndx].cylinders != 0) {
601 x = sprintf(wbp, "dpt%d:d%dc%dh%ds%d\n",
604 dpt_sysinfo.drives[ndx].cylinders,
605 dpt_sysinfo.drives[ndx].heads,
606 dpt_sysinfo.drives[ndx].sectors);
611 } else if (strcmp(command, DPT_RW_CMD_DUMP_METRICS) == 0) {
613 "dpt%d: No metrics available.\n"
614 "Run the dpt_dm command, or use the\n"
615 "DPT_IOCTL_INTERNAL_METRICS ioctl system call\n",
619 } else if (strcmp(command, DPT_RW_CMD_CLEAR_METRICS) == 0) {
620 #ifdef DPT_MEASURE_PERFORMANCE
621 dpt_reset_performance(dpt);
622 #endif /* DPT_MEASURE_PERFORMANCE */
624 x = sprintf(wbp, "dpt%d: Metrics have been cleared\n",
628 } else if (strcmp(command, DPT_RW_CMD_SHOW_LED) == 0) {
630 x = sprintf(wbp, "dpt%d:%s\n",
631 dpt->unit, i2bin(dpt_blinking_led(dpt), 8));
635 #ifdef DPT_DEBUG_CONTROL
636 printf("dpt%d: Bad READ state (%s)\n", minor_no, command);
643 work_buffer[work_size++] = '\0';
644 error = uiomove(work_buffer, work_size, uio);
646 #ifdef DPT_DEBUG_CONTROL
648 printf("dpt%d: READ uimove failed (%d)\n", dpt->unit, error);
658 * This is the control syscall interface.
659 * It should be binary compatible with UnixWare,
660 * if not totally syntatically so.
664 dpt_ioctl(dev_t dev, u_long cmd, caddr_t cmdarg, int flags, struct proc * p)
668 dpt_user_softc_t udpt;
671 eata_pt_t *eata_pass_thru;
673 minor_no = minor(dev);
676 if (!(minor_no & SCSI_CONTROL_MASK)) {
677 #ifdef DPT_DEBUG_CONTROL
678 printf("dpt%d: Control attempted to I/O channel (%x)\n",
679 dpt_minor2unit(minor_no), minor_no);
683 minor_no &= ~SCSI_CONTROL_MASK;
685 #ifdef DPT_DEBUG_CONTROL
686 printf("dpt%d: IOCTL(%x, %x, %p, %x, %p)\n",
687 minor_no, dev, cmd, cmdarg, flags, p);
690 if ((dpt = dpt_minor2softc(minor_no)) == NULL)
694 #ifdef DPT_MEASURE_PERFORMANCE
695 case DPT_IOCTL_INTERNAL_METRICS:
696 memcpy(cmdarg, &dpt->performance, sizeof(dpt->performance));
698 #endif /* DPT_MEASURE_PERFORMANCE */
699 case DPT_IOCTL_SOFTC:
700 udpt.unit = dpt->unit;
701 udpt.handle_interrupts = dpt->handle_interrupts;
702 udpt.target_mode_enabled = dpt->target_mode_enabled;
703 udpt.spare = dpt->spare;
705 udpt.total_ccbs_count = dpt->total_ccbs_count;
706 udpt.free_ccbs_count = dpt->free_ccbs_count;
707 udpt.waiting_ccbs_count = dpt->waiting_ccbs_count;
708 udpt.submitted_ccbs_count = dpt->submitted_ccbs_count;
709 udpt.completed_ccbs_count = dpt->completed_ccbs_count;
711 udpt.queue_status = dpt->queue_status;
712 udpt.free_lock = dpt->free_lock;
713 udpt.waiting_lock = dpt->waiting_lock;
714 udpt.submitted_lock = dpt->submitted_lock;
715 udpt.completed_lock = dpt->completed_lock;
717 udpt.commands_processed = dpt->commands_processed;
718 udpt.lost_interrupts = dpt->lost_interrupts;
720 udpt.channels = dpt->channels;
721 udpt.max_id = dpt->max_id;
722 udpt.max_lun = dpt->max_lun;
724 udpt.io_base = dpt->io_base;
725 udpt.v_membase = (u_int8_t *) dpt->v_membase;
726 udpt.p_membase = (u_int8_t *) dpt->p_membase;
729 udpt.dma_channel = dpt->dma_channel;
731 udpt.board_data = dpt->board_data;
732 udpt.EATA_revision = dpt->EATA_revision;
733 udpt.bustype = dpt->bustype;
734 udpt.state = dpt->state;
736 udpt.primary = dpt->primary;
737 udpt.more_support = dpt->more_support;
738 udpt.immediate_support = dpt->immediate_support;
739 udpt.broken_INQUIRY = dpt->broken_INQUIRY;
740 udpt.spare2 = dpt->spare2;
742 for (ndx = 0; ndx < MAX_CHANNELS; ndx++) {
743 udpt.resetlevel[ndx] = dpt->resetlevel[ndx];
744 udpt.hostid[ndx] = dpt->hostid[ndx];
747 udpt.last_ccb = dpt->last_ccb;
748 udpt.cplen = dpt->cplen;
749 udpt.cppadlen = dpt->cppadlen;
750 udpt.queuesize = dpt->queuesize;
751 udpt.sgsize = dpt->sgsize;
752 udpt.cache_type = dpt->cache_type;
753 udpt.cache_size = dpt->cache_size;
755 memcpy(cmdarg, &udpt, sizeof(dpt_user_softc_t));
759 eata_pass_thru = (eata_pt_t *) cmdarg;
761 if ((eata_pass_thru->eataID[0] != 'E')
762 || (eata_pass_thru->eataID[1] != 'A')
763 || (eata_pass_thru->eataID[2] != 'T')
764 || (eata_pass_thru->eataID[3] != 'A')) {
767 switch (eata_pass_thru->command) {
769 return (copyout((char *) &dpt_sig,
770 (caddr_t *) eata_pass_thru->command_buffer,
773 return (copyout((char *) &dpt_controllers_present,
774 (caddr_t *) eata_pass_thru->command_buffer,
775 sizeof(dpt_controllers_present)));
778 dpt_compat_ha_t compat_softc;
781 compat_softc.ha_state = dpt->state; /* Different Meaning! */
782 for (ndx = 0; ndx < MAX_CHANNELS; ndx++)
783 compat_softc.ha_id[ndx] = dpt->hostid[ndx];
785 compat_softc.ha_vect = dpt->irq;
786 compat_softc.ha_base = BaseRegister(dpt);
787 compat_softc.ha_max_jobs = dpt->total_ccbs_count;
788 compat_softc.ha_cache = dpt->cache_type;
789 compat_softc.ha_cachesize = dpt->cache_size;
790 compat_softc.ha_nbus = dpt->dma_channel + 1;
791 compat_softc.ha_ntargets = dpt->max_id + 1;
792 compat_softc.ha_nluns = dpt->max_lun + 1;
793 compat_softc.ha_tshift = (dpt->max_id == 7) ? 3 : 4;
794 compat_softc.ha_bshift = 2;
795 compat_softc.ha_npend = dpt->submitted_ccbs_count;
796 compat_softc.ha_active_jobs = dpt->waiting_ccbs_count;
797 strncpy(compat_softc.ha_fw_version,
798 dpt->board_data.firmware,
799 sizeof(compat_softc.ha_fw_version));
800 compat_softc.ha_ccb = NULL;
801 compat_softc.ha_cblist = NULL;
802 compat_softc.ha_dev = NULL;
803 compat_softc.ha_StPkt_lock = NULL;
804 compat_softc.ha_ccb_lock = NULL;
805 compat_softc.ha_LuQWaiting = NULL;
806 compat_softc.ha_QWait_lock = NULL;
807 compat_softc.ha_QWait_opri = NULL;
809 return (copyout((char *) &compat_softc,
810 (caddr_t *) eata_pass_thru->command_buffer,
811 sizeof(dpt_compat_ha_t)));
816 return (copyout((char *) &dpt_sysinfo,
817 (caddr_t *) eata_pass_thru->command_buffer,
818 sizeof(dpt_sysinfo)));
820 result = dpt_user_cmd(dpt, eata_pass_thru, cmdarg, minor_no);
823 result = dpt_blinking_led(dpt);
824 return (copyout((caddr_t) & result,
825 (caddr_t *) eata_pass_thru->command_buffer,
828 printf("dpt%d: Invalid (%x) pass-throu command\n",
829 dpt->unit, eata_pass_thru->command);
834 printf("dpt%d: Invalid (%lx) IOCTL\n", dpt->unit, cmd);
842 static dpt_devsw_installed = 0;
845 dpt_drvinit(void *unused)
848 if (!dpt_devsw_installed) {
850 printf("DPT: RAID Manager driver, Version %d.%d.%d\n",
851 DPT_CTL_RELEASE, DPT_CTL_VERSION, DPT_CTL_PATCH);
853 /* Add the I/O (data) channel */
854 cdevsw_add(&dpt_cdevsw);
856 dpt_devsw_installed = 1;
861 SYSINIT(dpt_dev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE + CDEV_MAJOR, dpt_drvinit, NULL)
862 /* End of the dpt_control driver */