Merge from vendor branch GCC:
[dragonfly.git] / sys / dev / raid / dpt / dpt_control.c
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.7 2004/05/19 22:52:47 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         if (!dpt_devsw_installed) {
853                 if (bootverbose)
854                         printf("DPT:  RAID Manager driver, Version %d.%d.%d\n",
855                                DPT_CTL_RELEASE, DPT_CTL_VERSION, DPT_CTL_PATCH);
856
857                 /* Add the I/O (data) channel */
858                 cdevsw_add(&dpt_cdevsw, 0, 0);
859
860                 dpt_devsw_installed = 1;
861         }
862         dpt_get_sysinfo();
863 }
864
865 SYSINIT(dpt_dev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE + CDEV_MAJOR, dpt_drvinit, NULL)
866 /* End of the dpt_control driver */