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