/** * 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.1 1998/01/26 06:11:17 julian Exp $" #include "opt_dpt.h" #include /* #include */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define INLINE __inline extern 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 INLINE dpt_softc_t *dpt_minor2softc(int minor_no); static INLINE int dpt_minor2unit(int minor_no); 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, int 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]; /** * 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_t dpt_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 * srart address and the correct LENGTH are given. * * Disaster will follow if these assumptions are false! */ static void dpt_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); } /** * Given a minor device number, get its SCSI Unit. */ static INLINE int dpt_minor2unit(int minor) { int unit; unit = minor2hba(minor & ~SCSI_CONTROL_MASK); return (unit); } /** * Given a minor device number, * return the pointer to it's softc structure */ static INLINE 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); } /** * 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 void dpt_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; #warning "O/S Version determination is an ugly hack" 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 int dpt_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 return (EINVAL); } } dpt->state |= DPT_HA_CONTROL_ACTIVE; splx(ospl); return (0); } static int dpt_close(dev_t dev, int flags, int fmt, struct proc * p) { int minor_no; dpt_softc_t *dpt; minor_no = minor(dev); dpt = dpt_minor2softc(minor_no); if ((dpt_minor2unit(minor_no) == -1) || (dpt == NULL)) return (ENXIO); else { brelse(dpt_inbuf[minor_no & ~SCSI_CONTROL_MASK]); dpt->state &= ~DPT_HA_CONTROL_ACTIVE; return (0); } } static int dpt_write(dev_t dev, struct uio * uio, int ioflag) { int minor_no; int unit; int error; minor_no = minor(dev); if (minor_no & SCSI_CONTROL_MASK) { #ifdef DPT_DEBUG_CONTROL printf("dpt%d: I/O attempted to control channel (%x)\n", dpt_minor2unit(minor_no), minor_no); #endif return (ENXIO); } unit = dpt_minor2unit(minor_no); if (unit == -1) { return (ENXIO); } else if (uio->uio_resid > DPT_RW_CMD_LEN) { return (E2BIG); } else { char *cp; int length; cp = dpt_inbuf[minor_no]->b_data; length = uio->uio_resid; /* uiomove will change it! */ if ((error = uiomove(cp, length, uio) != 0)) { #ifdef DPT_DEBUG_CONTROL printf("dpt%d: uiomove(%x, %d, %x) failed (%d)\n", minor_no, cp, length, uio, error); #endif return (error); } else { cp[length] = '\0'; /* A real kludge, to allow plain echo(1) to work */ if (cp[length - 1] == '\n') cp[length - 1] = '\0'; strncpy(dpt_rw_command[unit], cp, DPT_RW_CMD_LEN); #ifdef DPT_DEBUG_CONTROL /** * For lack of anything better to do; * For now, dump the data so we can look at it and rejoice */ printf("dpt%d: Command \"%s\" arrived\n", unit, dpt_rw_command[unit]); #endif } } return (error); } static int dpt_read(dev_t dev, struct uio * uio, int ioflag) { dpt_softc_t *dpt; int error; int minor_no; int ospl; minor_no = minor(dev); error = 0; #ifdef DPT_DEBUG_CONTROL printf("dpt%d: read, count = %d, dev = %08x\n", minor_no, uio->uio_resid, dev); #endif if (minor_no & SCSI_CONTROL_MASK) { #ifdef DPT_DEBUG_CONTROL printf("dpt%d: I/O attempted to control channel (%x)\n", dpt_minor2unit(minor_no), minor_no); #endif return (ENXIO); } if (dpt_minor2unit(minor_no) == -1) { return (ENXIO); } /* * else if ( uio->uio_resid > PAGE_SIZE ) { return(E2BIG); } */ else { char *work_buffer; char *wbp; char *command; int work_size; int ndx; int x; if ((dpt = dpt_minor2softc(minor_no)) == NULL) return (ENXIO); work_buffer = (u_int8_t *) malloc(PAGE_SIZE, M_TEMP, M_WAITOK); wbp = work_buffer; work_size = 0; ospl = splbio(); command = dpt_rw_command[dpt->unit]; if (strcmp(command, DPT_RW_CMD_DUMP_SOFTC) == 0) { x = sprintf(wbp, "dpt%d:%s:%s:%s:%s:%x\n", dpt->unit, dpt->board_data.vendor, dpt->board_data.modelNum, dpt->board_data.firmware, dpt->board_data.protocol, dpt->EATA_revision); work_size += x; wbp += x; } else if (strcmp(command, DPT_RW_CMD_DUMP_SYSINFO) == 0) { x = sprintf(wbp, "dpt%d:%d:%d:%d:%d:%d:%d:%d:%d:%s:" "%d:%d:%d:%d:%d:%d:%d:%d\n", dpt->unit, dpt_sysinfo.drive0CMOS, dpt_sysinfo.drive1CMOS, dpt_sysinfo.numDrives, dpt_sysinfo.processorFamily, dpt_sysinfo.processorType, dpt_sysinfo.smartROMMajorVersion, dpt_sysinfo.smartROMMinorVersion, dpt_sysinfo.smartROMRevision, i2bin(dpt_sysinfo.flags, sizeof(dpt->queue_status) * 8), dpt_sysinfo.conventionalMemSize, dpt_sysinfo.extendedMemSize, dpt_sysinfo.osType, dpt_sysinfo.osMajorVersion, dpt_sysinfo.osMinorVersion, dpt_sysinfo.osRevision, dpt_sysinfo.osSubRevision, dpt_sysinfo.busType); work_size += x; wbp += x; for (ndx = 0; ndx < 16; ndx++) { if (dpt_sysinfo.drives[ndx].cylinders != 0) { x = sprintf(wbp, "dpt%d:d%dc%dh%ds%d\n", dpt->unit, ndx, dpt_sysinfo.drives[ndx].cylinders, dpt_sysinfo.drives[ndx].heads, dpt_sysinfo.drives[ndx].sectors); work_size += x; wbp += x; } } } else if (strcmp(command, DPT_RW_CMD_DUMP_METRICS) == 0) { x = sprintf(wbp, "dpt%d: No metrics available.\n" "Run the dpt_dm command, or use the\n" "DPT_IOCTL_INTERNAL_METRICS ioctl system call\n", dpt->unit); work_size += x; wbp += x; } else if (strcmp(command, DPT_RW_CMD_CLEAR_METRICS) == 0) { #ifdef DPT_MEASURE_PERFORMANCE bzero(&dpt->performance, sizeof(dpt->performance)); #endif /* DPT_MEASURE_PERFORMANCE */ x = sprintf(wbp, "dpt%d: Metrics have been cleared\n", dpt->unit); work_size += x; wbp += x; } else if (strcmp(command, DPT_RW_CMD_SHOW_LED) == 0) { #ifdef DPT_MEASURE_PERFORMANCE bzero(&dpt->performance, sizeof(dpt->performance)); #endif /* DPT_MEASURE_PERFORMANCE */ x = sprintf(wbp, "dpt%d:%s\n", dpt->unit, i2bin(dpt_blinking_led(dpt), 8)); work_size += x; wbp += x; } else { #ifdef DPT_DEBUG_CONTROL printf("dpt%d: Bad READ state (%s)\n", minor_no, command); #endif splx(ospl); error = EINVAL; } if (error == 0) { work_buffer[work_size++] = '\0'; error = uiomove(work_buffer, work_size, uio); uio->uio_resid = 0; #ifdef DPT_DEBUG_CONTROL if (error) { printf("dpt%d: READ uimove failed (%d)\n", dpt->unit, error); } #endif } } splx(ospl); return (error); } /** * This is the control syscall interface. * It should be binary compatible with UnixWare, * if not totally syntatically so. */ static int dpt_ioctl(dev_t dev, int cmd, caddr_t cmdarg, int flags, struct proc * p) { int minor_no; dpt_softc_t *dpt; dpt_user_softc_t udpt; int result; int ndx; eata_pt_t *eata_pass_thru; minor_no = minor(dev); result = 0; if (!(minor_no & SCSI_CONTROL_MASK)) { #ifdef DPT_DEBUG_CONTROL printf("dpt%d: Control attempted to I/O channel (%x)\n", dpt_minor2unit(minor_no), minor_no); #endif /* DEBUG */ return (ENXIO); } else minor_no &= ~SCSI_CONTROL_MASK; #ifdef DPT_DEBUG_CONTROL printf("dpt%d: IOCTL(%x, %x, %p, %x, %p)\n", minor_no, dev, cmd, cmdarg, flags, p); #endif /* DEBUG */ if ((dpt = dpt_minor2softc(minor_no)) == NULL) return (result); switch (cmd) { #ifdef DPT_MEASURE_PERFORMANCE case DPT_IOCTL_INTERNAL_METRICS: (void) memcpy(cmdarg, (char *) &dpt->performance, sizeof(dpt_perf_t)); return (0); #endif /* DPT_MEASURE_PERFORMANCE */ case DPT_IOCTL_SOFTC: udpt.unit = dpt->unit; udpt.handle_interrupts = dpt->handle_interrupts; udpt.target_mode_enabled = dpt->target_mode_enabled; udpt.spare = dpt->spare; udpt.total_ccbs_count = dpt->total_ccbs_count; udpt.free_ccbs_count = dpt->free_ccbs_count; udpt.waiting_ccbs_count = dpt->waiting_ccbs_count; udpt.submitted_ccbs_count = dpt->submitted_ccbs_count; udpt.completed_ccbs_count = dpt->completed_ccbs_count; udpt.queue_status = dpt->queue_status; udpt.free_lock = dpt->free_lock; udpt.waiting_lock = dpt->waiting_lock; udpt.submitted_lock = dpt->submitted_lock; udpt.completed_lock = dpt->completed_lock; udpt.commands_processed = dpt->commands_processed; udpt.lost_interrupts = dpt->lost_interrupts; udpt.channels = dpt->channels; udpt.max_id = dpt->max_id; udpt.max_lun = dpt->max_lun; udpt.io_base = dpt->io_base; udpt.v_membase = (u_int8_t *) dpt->v_membase; udpt.p_membase = (u_int8_t *) dpt->p_membase; udpt.irq = dpt->irq; udpt.dma_channel = dpt->dma_channel; udpt.board_data = dpt->board_data; udpt.EATA_revision = dpt->EATA_revision; udpt.bustype = dpt->bustype; udpt.state = dpt->state; udpt.primary = dpt->primary; udpt.more_support = dpt->more_support; udpt.immediate_support = dpt->immediate_support; udpt.broken_INQUIRY = dpt->broken_INQUIRY; udpt.spare2 = dpt->spare2; for (ndx = 0; ndx < MAX_CHANNELS; ndx++) { udpt.resetlevel[ndx] = dpt->resetlevel[ndx]; udpt.hostid[ndx] = dpt->hostid[ndx]; } udpt.last_ccb = dpt->last_ccb; udpt.cplen = dpt->cplen; udpt.cppadlen = dpt->cppadlen; udpt.queuesize = dpt->queuesize; udpt.sgsize = dpt->sgsize; udpt.cache_type = dpt->cache_type; udpt.cache_size = dpt->cache_size; (void) memcpy(cmdarg, (char *) &udpt, sizeof(dpt_user_softc_t)); return (0); case SDI_SEND: case DPT_IOCTL_SEND: eata_pass_thru = (eata_pt_t *) cmdarg; if ((eata_pass_thru->eataID[0] != 'E') || (eata_pass_thru->eataID[1] != 'A') || (eata_pass_thru->eataID[2] != 'T') || (eata_pass_thru->eataID[3] != 'A')) { return (EFAULT); } switch (eata_pass_thru->command) { case DPT_SIGNATURE: return (copyout((char *) &dpt_sig, (caddr_t *) eata_pass_thru->command_buffer, sizeof(dpt_sig))); case DPT_NUMCTRLS: return (copyout((char *) &dpt_controllers_present, (caddr_t *) eata_pass_thru->command_buffer, sizeof(dpt_controllers_present))); case DPT_CTRLINFO: { dpt_compat_ha_t compat_softc; int ndx; compat_softc.ha_state = dpt->state; /* Different Meaning! */ for (ndx = 0; ndx < MAX_CHANNELS; ndx++) compat_softc.ha_id[ndx] = dpt->hostid[ndx]; compat_softc.ha_vect = dpt->irq; compat_softc.ha_base = BaseRegister(dpt); compat_softc.ha_max_jobs = dpt->total_ccbs_count; compat_softc.ha_cache = dpt->cache_type; compat_softc.ha_cachesize = dpt->cache_size; compat_softc.ha_nbus = dpt->dma_channel + 1; compat_softc.ha_ntargets = dpt->max_id + 1; compat_softc.ha_nluns = dpt->max_lun + 1; compat_softc.ha_tshift = (dpt->max_id == 7) ? 3 : 4; compat_softc.ha_bshift = 2; compat_softc.ha_npend = dpt->submitted_ccbs_count; compat_softc.ha_active_jobs = dpt->waiting_ccbs_count; strncpy(compat_softc.ha_fw_version, dpt->board_data.firmware, 4); compat_softc.ha_ccb = NULL; compat_softc.ha_cblist = NULL; compat_softc.ha_dev = NULL; compat_softc.ha_StPkt_lock = NULL; compat_softc.ha_ccb_lock = NULL; compat_softc.ha_LuQWaiting = NULL; compat_softc.ha_QWait_lock = NULL; compat_softc.ha_QWait_opri = NULL; return (copyout((char *) &compat_softc, (caddr_t *) eata_pass_thru->command_buffer, sizeof(dpt_compat_ha_t))); } break; case DPT_SYSINFO: return (copyout((char *) &dpt_sysinfo, (caddr_t *) eata_pass_thru->command_buffer, sizeof(dpt_sysinfo))); case EATAUSRCMD: printf("%d\n", __LINE__); result = dpt_user_cmd(dpt, eata_pass_thru, cmdarg, minor_no); printf("%d\n", __LINE__); return (result); case DPT_BLINKLED: result = dpt_blinking_led(dpt); return (copyout((caddr_t) & result, (caddr_t *) eata_pass_thru->command_buffer, sizeof(result))); default: printf("dpt%d: Invalid (%x) pass-throu command\n", dpt->unit, eata_pass_thru->command); result = EINVAL; } default: printf("dpt%d: Invalid (%x) IOCTL\n", dpt->unit, cmd); return (EINVAL); } return (result); } static dpt_devsw_installed = 0; static void dpt_drvinit(void *unused) { dev_t dev; if (!dpt_devsw_installed) { printf("DPT: RAID Manager driver, Version %d.%d.%d\n", DPT_CTL_RELEASE, DPT_CTL_VERSION, DPT_CTL_PATCH); /* Add the I/O (data) channel */ dev = makedev(CDEV_MAJOR, 0); cdevsw_add(&dev, &dpt_cdevsw, NULL); /* Add the Control (IOCTL) channel */ dev = makedev(CDEV_MAJOR, SCSI_CONTROL_MASK); cdevsw_add(&dev, &dpt_cdevsw, NULL); dpt_devsw_installed = 1; } dpt_get_sysinfo(); } SYSINIT(dpt_dev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE + CDEV_MAJOR, dpt_drvinit, NULL) /* End of the dpt_control driver */