974300f6a970b9a33ef84c527e8387fb01548920
[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.14 2006/12/28 21:23:58 dillon Exp $"
41
42 #include "opt_dpt.h"
43
44 #include <machine/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 <sys/thread2.h>
53 #include <vm/vm.h>
54 #include <vm/vm_kern.h>
55 #include <vm/vm_extern.h>
56 #include <vm/pmap.h>
57 #include <scsi/scsiconf.h>
58
59 #include "dpt.h"
60
61 #define INLINE __inline
62
63 extern char     osrelease[];
64
65 enum dpt_message dpt_message;
66 enum dpt_immediate_cmd dpt_immediate_cmd;
67
68 static dpt_sysinfo_t   dpt_sysinfo;
69
70 /* Entry points and other prototypes */
71 static vm_offset_t dpt_physmap(u_int32_t paddr, vm_size_t size);
72 static void     dpt_unphysmap(u_int8_t * vaddr, vm_size_t size);
73
74 static void     dpt_get_sysinfo(void);
75
76 static int      dpt_open(cdev_t dev, int flags, int fmt, struct proc * p);
77 static int      dpt_close(cdev_t dev, int flags, int fmt, struct proc * p);
78 static int      dpt_write(cdev_t dev, struct uio * uio, int ioflag);
79 static int      dpt_read(cdev_t dev, struct uio * uio, int ioflag);
80 static int      dpt_ioctl(cdev_t dev, u_long cmd, caddr_t cmdarg, int flags, struct proc * p);
81
82
83 /* This has to be modified as the processor and CPU are not known yet */
84 static dpt_sig_t dpt_sig = {
85         'd', 'P', 't', 'S', 'i', 'G',
86         SIG_VERSION, PROC_INTEL, PROC_386,
87         FT_HBADRVR, FTF_PROTECTED,
88         OEM_DPT, OS_FREEBSD,
89         CAP_PASS | CAP_OVERLAP | CAP_RAID0 | CAP_RAID1 | CAP_RAID5 | CAP_ASPI,
90         DEV_ALL, ADF_SC4_PCI | ADF_SC3_PCI, 0, 0,
91         DPT_RELEASE, DPT_VERSION, DPT_PATCH,
92         DPT_MONTH, DPT_DAY, DPT_YEAR,
93         "DPT FreeBSD Driver (c) 1997 Simon Shapiro"
94 };
95
96 #define CDEV_MAJOR          DPT_CDEV_MAJOR
97
98 /* Normally, this is a static structure.  But we need it in pci/dpt_pci.c */
99 static struct cdevsw dpt_cdevsw = {
100         /* name */      "dpt",
101         /* maj */       CDEV_MAJOR,
102         /* flags */     0,
103         /* port */      NULL,
104         /* clone */     NULL,
105
106         /* open */      dpt_open,
107         /* close */     dpt_close,
108         /* read */      dpt_read,
109         /* write */     dpt_write,
110         /* ioctl */     dpt_ioctl,
111         /* poll */      nopoll,
112         /* mmap */      nommap,
113         /* strategy */  nostrategy,
114         /* dump */      nodump,
115         /* psize */     nopsize
116 };
117
118 static struct buf *dpt_inbuf[DPT_MAX_ADAPTERS];
119 static char     dpt_rw_command[DPT_MAX_ADAPTERS][DPT_RW_CMD_LEN + 1];
120
121
122 /*
123  * Given a minor device number,
124  * return the pointer to its softc structure
125  */
126
127 dpt_softc_t *
128 dpt_minor2softc(int minor_no)
129 {
130         dpt_softc_t    *dpt;
131
132         if (dpt_minor2unit(minor_no & ~SCSI_CONTROL_MASK) == -1)
133                 return (NULL);
134
135         for (dpt = TAILQ_FIRST(&dpt_softc_list);
136              (dpt != NULL) && (dpt->unit != (minor_no & ~SCSI_CONTROL_MASK));
137              dpt = TAILQ_NEXT(dpt, links));
138
139         return (dpt);
140 }
141
142 /**
143  * Map a physical address to virtual one.
144  * This is a first cut, experimental thing
145  *
146  * Paddr is the physical address to map
147  * size is the size of the region, in bytes.
148  * Because of alignment problems, we actually round up the size requested to
149  * the next page count.
150  */
151
152 static          vm_offset_t
153 dpt_physmap(u_int32_t req_paddr, vm_size_t req_size)
154 {
155         vm_offset_t     va;
156         int             ndx;
157         vm_size_t       size;
158         u_int32_t       paddr;
159         u_int32_t       offset;
160
161
162
163         size = (req_size / PAGE_SIZE + 1) * PAGE_SIZE;
164         paddr = req_paddr & 0xfffff000;
165         offset = req_paddr - paddr;
166
167         va = kmem_alloc_pageable(&kernel_map, size);
168         if (va == (vm_offset_t) 0)
169                 return (va);
170
171         for (ndx = 0; ndx < size; ndx += PAGE_SIZE) {
172                 pmap_kenter(va + ndx, paddr + ndx);
173                 invltlb();
174         }
175
176         return (va + offset);
177 }
178
179
180 /*
181  * Release virtual space allocated by physmap We ASSUME that the correct
182  * start address and the correct LENGTH are given.
183  * 
184  * Disaster will follow if these assumptions are false!
185  */
186
187 static void
188 dpt_unphysmap(u_int8_t * vaddr, vm_size_t size)
189 {
190         int             ndx;
191
192         for (ndx = 0; ndx < size; ndx += PAGE_SIZE) {
193                 pmap_kremove((vm_offset_t) vaddr + ndx);
194         }
195
196         kmem_free(&kernel_map, (vm_offset_t) vaddr, size);
197 }
198
199 /**
200  * Collect interesting system information
201  * The following is one of the worst hacks I have ever allowed my
202  * name to be associated with.
203  * There MUST be a system structure that provides this data.
204  */
205
206 static void
207 dpt_get_sysinfo(void)
208 {
209         int             i;
210         int             j;
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         crit_enter();
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                 kprintf("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         crit_exit();
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(cdev_t dev, int flags, int fmt, struct proc * p)
412 {
413         int             minor_no;
414         dpt_softc_t    *dpt;
415
416         minor_no = minor(dev);
417
418         if (dpt_minor2unit(minor_no) == -1)
419                 return (ENXIO);
420         else
421                 dpt = dpt_minor2softc(minor_no);
422
423         if (dpt == NULL)
424                 return (ENXIO);
425
426         crit_enter();
427
428         if (dpt->state & DPT_HA_CONTROL_ACTIVE) {
429                 crit_exit();
430                 return (EBUSY);
431         } else {
432                 if ((dpt_inbuf[minor_no & ~SCSI_CONTROL_MASK] = geteblk(PAGE_SIZE))
433                     == NULL) {
434 #ifdef DPT_DEBUG_CONTROL
435                         kprintf("dpt%d: Failed to obtain an I/O buffer\n",
436                                minor_no & ~SCSI_CONTROL_MASK);
437 #endif
438                         crit_exit();
439                         return (EINVAL);
440                 }
441         }
442
443         dpt->state |= DPT_HA_CONTROL_ACTIVE;
444         crit_exit();
445         return (0);
446 }
447
448 static int
449 dpt_close(cdev_t dev, int flags, int fmt, struct proc * p)
450 {
451         int             minor_no;
452         dpt_softc_t    *dpt;
453
454         minor_no = minor(dev);
455         dpt = dpt_minor2softc(minor_no);
456
457         if ((dpt_minor2unit(minor_no) == -1) || (dpt == NULL))
458                 return (ENXIO);
459         else {
460                 brelse(dpt_inbuf[minor_no & ~SCSI_CONTROL_MASK]);
461                 dpt->state &= ~DPT_HA_CONTROL_ACTIVE;
462                 return (0);
463         }
464 }
465
466 static int
467 dpt_write(cdev_t dev, struct uio * uio, int ioflag)
468 {
469         int             minor_no;
470         int             unit;
471         int             error;
472
473         minor_no = minor(dev);
474
475         if (minor_no & SCSI_CONTROL_MASK) {
476 #ifdef DPT_DEBUG_CONTROL
477                 kprintf("dpt%d:  I/O attempted to control channel (%x)\n",
478                        dpt_minor2unit(minor_no), minor_no);
479 #endif
480                 return (ENXIO);
481         }
482         unit = dpt_minor2unit(minor_no);
483
484         if (unit == -1) {
485                 return (ENXIO);
486         } else if (uio->uio_resid > DPT_RW_CMD_LEN) {
487                 return (E2BIG);
488         } else {
489                 char           *cp;
490                 int             length;
491
492                 cp = dpt_inbuf[minor_no]->b_data;
493                 length = uio->uio_resid;        /* uiomove will change it! */
494
495                 if ((error = uiomove(cp, length, uio) != 0)) {
496 #ifdef DPT_DEBUG_CONTROL
497                         kprintf("dpt%d: uiomove(%x, %d, %x) failed (%d)\n",
498                                minor_no, cp, length, uio, error);
499 #endif
500                         return (error);
501                 } else {
502                         cp[length] = '\0';
503
504                         /* A real kludge, to allow plain echo(1) to work */
505                         if (cp[length - 1] == '\n')
506                                 cp[length - 1] = '\0';
507
508                         strncpy(dpt_rw_command[unit], cp, DPT_RW_CMD_LEN);
509 #ifdef DPT_DEBUG_CONTROL
510                         /**
511                          * For lack of anything better to do;
512                          * For now, dump the data so we can look at it and rejoice
513                          */
514                         kprintf("dpt%d: Command \"%s\" arrived\n",
515                                unit, dpt_rw_command[unit]);
516 #endif
517                 }
518         }
519
520         return (error);
521 }
522
523 static int
524 dpt_read(cdev_t dev, struct uio * uio, int ioflag)
525 {
526         dpt_softc_t    *dpt;
527         int             error;
528         int             minor_no;
529
530         minor_no = minor(dev);
531         error = 0;
532
533 #ifdef DPT_DEBUG_CONTROL
534         kprintf("dpt%d: read, count = %d, dev = %08x\n",
535                minor_no, uio->uio_resid, dev);
536 #endif
537
538         if (minor_no & SCSI_CONTROL_MASK) {
539 #ifdef DPT_DEBUG_CONTROL
540                 kprintf("dpt%d:  I/O attempted to control channel (%x)\n",
541                        dpt_minor2unit(minor_no), minor_no);
542 #endif
543                 return (ENXIO);
544         }
545         if (dpt_minor2unit(minor_no) == -1) {
546                 return (ENXIO);
547         }
548         /*
549          * else if ( uio->uio_resid > PAGE_SIZE ) { return(E2BIG); }
550          */ 
551         else {
552                 char           *work_buffer;
553                 char           *wbp;
554                 char           *command;
555                 int             work_size;
556                 int             ndx;
557                 int             x;
558
559                 if ((dpt = dpt_minor2softc(minor_no)) == NULL)
560                         return (ENXIO);
561
562                 work_buffer = (u_int8_t *) kmalloc(PAGE_SIZE, M_TEMP, M_WAITOK);
563                 wbp = work_buffer;
564                 work_size = 0;
565
566                 crit_enter();
567
568                 command = dpt_rw_command[dpt->unit];
569                 if (strcmp(command, DPT_RW_CMD_DUMP_SOFTC) == 0) {
570                         x = ksprintf(wbp, "dpt%d:%s:%s:%s:%s:%x\n",
571                                     dpt->unit,
572                                     dpt->board_data.vendor,
573                                     dpt->board_data.modelNum,
574                                     dpt->board_data.firmware,
575                                     dpt->board_data.protocol,
576                                     dpt->EATA_revision);
577                         work_size += x;
578                         wbp += x;
579
580                 } else if (strcmp(command, DPT_RW_CMD_DUMP_SYSINFO) == 0) {
581                         x = ksprintf(wbp, "dpt%d:%d:%d:%d:%d:%d:%d:%d:%d:%s:"
582                                     "%d:%d:%d:%d:%d:%d:%d:%d\n",
583                                     dpt->unit,
584                                     dpt_sysinfo.drive0CMOS,
585                                     dpt_sysinfo.drive1CMOS,
586                                     dpt_sysinfo.numDrives,
587                                     dpt_sysinfo.processorFamily,
588                                     dpt_sysinfo.processorType,
589                                     dpt_sysinfo.smartROMMajorVersion,
590                                     dpt_sysinfo.smartROMMinorVersion,
591                                     dpt_sysinfo.smartROMRevision,
592                                     i2bin(dpt_sysinfo.flags,
593                                           sizeof(dpt->queue_status) * 8),
594                                     dpt_sysinfo.conventionalMemSize,
595                                     dpt_sysinfo.extendedMemSize,
596                              dpt_sysinfo.osType, dpt_sysinfo.osMajorVersion,
597                          dpt_sysinfo.osMinorVersion, dpt_sysinfo.osRevision,
598                             dpt_sysinfo.osSubRevision, dpt_sysinfo.busType);
599                         work_size += x;
600                         wbp += x;
601
602                         for (ndx = 0; ndx < 16; ndx++) {
603                                 if (dpt_sysinfo.drives[ndx].cylinders != 0) {
604                                         x = ksprintf(wbp, "dpt%d:d%dc%dh%ds%d\n",
605                                                     dpt->unit,
606                                                     ndx,
607                                           dpt_sysinfo.drives[ndx].cylinders,
608                                               dpt_sysinfo.drives[ndx].heads,
609                                            dpt_sysinfo.drives[ndx].sectors);
610                                         work_size += x;
611                                         wbp += x;
612                                 }
613                         }
614                 } else if (strcmp(command, DPT_RW_CMD_DUMP_METRICS) == 0) {
615                         x = ksprintf(wbp,
616                                     "dpt%d: No metrics available.\n"
617                                     "Run the dpt_dm command, or use the\n"
618                            "DPT_IOCTL_INTERNAL_METRICS ioctl system call\n",
619                                     dpt->unit);
620                         work_size += x;
621                         wbp += x;
622                 } else if (strcmp(command, DPT_RW_CMD_CLEAR_METRICS) == 0) {
623 #ifdef DPT_MEASURE_PERFORMANCE
624                         dpt_reset_performance(dpt);
625 #endif                          /* DPT_MEASURE_PERFORMANCE */
626
627                         x = ksprintf(wbp, "dpt%d: Metrics have been cleared\n",
628                                     dpt->unit);
629                         work_size += x;
630                         wbp += x;
631                 } else if (strcmp(command, DPT_RW_CMD_SHOW_LED) == 0) {
632
633                         x = ksprintf(wbp, "dpt%d:%s\n",
634                                 dpt->unit, i2bin(dpt_blinking_led(dpt), 8));
635                         work_size += x;
636                         wbp += x;
637                 } else {
638 #ifdef DPT_DEBUG_CONTROL
639                         kprintf("dpt%d: Bad READ state (%s)\n", minor_no, command);
640 #endif
641                         crit_exit();
642                         error = EINVAL;
643                 }
644
645                 if (error == 0) {
646                         work_buffer[work_size++] = '\0';
647                         error = uiomove(work_buffer, work_size, uio);
648                         uio->uio_resid = 0;
649 #ifdef DPT_DEBUG_CONTROL
650                         if (error) {
651                                 kprintf("dpt%d: READ uimove failed (%d)\n", dpt->unit, error);
652                         }
653 #endif
654                 }
655         }
656         crit_exit();
657         return (error);
658 }
659
660 /**
661  * This is the control syscall interface.
662  * It should be binary compatible with UnixWare,
663  * if not totally syntatically so.
664  */
665
666 static int
667 dpt_ioctl(cdev_t dev, u_long cmd, caddr_t cmdarg, int flags, struct proc * p)
668 {
669         int             minor_no;
670         dpt_softc_t    *dpt;
671         dpt_user_softc_t udpt;
672         int             result;
673         int             ndx;
674         eata_pt_t      *eata_pass_thru;
675
676         minor_no = minor(dev);
677         result = 0;
678
679         if (!(minor_no & SCSI_CONTROL_MASK)) {
680 #ifdef DPT_DEBUG_CONTROL
681                 kprintf("dpt%d:  Control attempted to I/O channel (%x)\n",
682                        dpt_minor2unit(minor_no), minor_no);
683 #endif                          /* DEBUG */
684                 return (ENXIO);
685         } else
686                 minor_no &= ~SCSI_CONTROL_MASK;
687
688 #ifdef DPT_DEBUG_CONTROL
689         kprintf("dpt%d: IOCTL(%x, %x, %p, %x, %p)\n",
690                minor_no, dev, cmd, cmdarg, flags, p);
691 #endif                          /* DEBUG */
692
693         if ((dpt = dpt_minor2softc(minor_no)) == NULL)
694                 return (result);
695
696         switch (cmd) {
697 #ifdef DPT_MEASURE_PERFORMANCE
698         case DPT_IOCTL_INTERNAL_METRICS:            
699                 memcpy(cmdarg, &dpt->performance, sizeof(dpt->performance));
700                 return (0);
701 #endif                          /* DPT_MEASURE_PERFORMANCE */
702         case DPT_IOCTL_SOFTC:
703                 udpt.unit = dpt->unit;
704                 udpt.handle_interrupts = dpt->handle_interrupts;
705                 udpt.target_mode_enabled = dpt->target_mode_enabled;
706                 udpt.spare = dpt->spare;
707
708                 udpt.total_ccbs_count = dpt->total_ccbs_count;
709                 udpt.free_ccbs_count = dpt->free_ccbs_count;
710                 udpt.waiting_ccbs_count = dpt->waiting_ccbs_count;
711                 udpt.submitted_ccbs_count = dpt->submitted_ccbs_count;
712                 udpt.completed_ccbs_count = dpt->completed_ccbs_count;
713
714                 udpt.queue_status = dpt->queue_status;
715                 udpt.free_lock = dpt->free_lock;
716                 udpt.waiting_lock = dpt->waiting_lock;
717                 udpt.submitted_lock = dpt->submitted_lock;
718                 udpt.completed_lock = dpt->completed_lock;
719
720                 udpt.commands_processed = dpt->commands_processed;
721                 udpt.lost_interrupts = dpt->lost_interrupts;
722
723                 udpt.channels = dpt->channels;
724                 udpt.max_id = dpt->max_id;
725                 udpt.max_lun = dpt->max_lun;
726
727                 udpt.io_base = dpt->io_base;
728                 udpt.v_membase = (u_int8_t *) dpt->v_membase;
729                 udpt.p_membase = (u_int8_t *) dpt->p_membase;
730
731                 udpt.irq = dpt->irq;
732                 udpt.dma_channel = dpt->dma_channel;
733
734                 udpt.board_data = dpt->board_data;
735                 udpt.EATA_revision = dpt->EATA_revision;
736                 udpt.bustype = dpt->bustype;
737                 udpt.state = dpt->state;
738
739                 udpt.primary = dpt->primary;
740                 udpt.more_support = dpt->more_support;
741                 udpt.immediate_support = dpt->immediate_support;
742                 udpt.broken_INQUIRY = dpt->broken_INQUIRY;
743                 udpt.spare2 = dpt->spare2;
744
745                 for (ndx = 0; ndx < MAX_CHANNELS; ndx++) {
746                         udpt.resetlevel[ndx] = dpt->resetlevel[ndx];
747                         udpt.hostid[ndx] = dpt->hostid[ndx];
748                 }
749
750                 udpt.last_ccb = dpt->last_ccb;
751                 udpt.cplen = dpt->cplen;
752                 udpt.cppadlen = dpt->cppadlen;
753                 udpt.queuesize = dpt->queuesize;
754                 udpt.sgsize = dpt->sgsize;
755                 udpt.cache_type = dpt->cache_type;
756                 udpt.cache_size = dpt->cache_size;
757
758                 memcpy(cmdarg, &udpt, sizeof(dpt_user_softc_t));
759                 return (0);
760         case SDI_SEND:
761         case DPT_IOCTL_SEND:
762                 eata_pass_thru = (eata_pt_t *) cmdarg;
763
764                 if ((eata_pass_thru->eataID[0] != 'E')
765                     || (eata_pass_thru->eataID[1] != 'A')
766                     || (eata_pass_thru->eataID[2] != 'T')
767                     || (eata_pass_thru->eataID[3] != 'A')) {
768                         return (EFAULT);
769                 }
770                 switch (eata_pass_thru->command) {
771                 case DPT_SIGNATURE:
772                         return (copyout((char *) &dpt_sig,
773                                  (caddr_t *) eata_pass_thru->command_buffer,
774                                         sizeof(dpt_sig)));
775                 case DPT_NUMCTRLS:
776                         return (copyout((char *) &dpt_controllers_present,
777                                  (caddr_t *) eata_pass_thru->command_buffer,
778                                         sizeof(dpt_controllers_present)));
779                 case DPT_CTRLINFO:
780                         {
781                                 dpt_compat_ha_t compat_softc;
782                                 int             ndx;
783
784                                 compat_softc.ha_state = dpt->state;     /* Different Meaning! */
785                                 for (ndx = 0; ndx < MAX_CHANNELS; ndx++)
786                                         compat_softc.ha_id[ndx] = dpt->hostid[ndx];
787
788                                 compat_softc.ha_vect = dpt->irq;
789                                 compat_softc.ha_base = BaseRegister(dpt);
790                                 compat_softc.ha_max_jobs = dpt->total_ccbs_count;
791                                 compat_softc.ha_cache = dpt->cache_type;
792                                 compat_softc.ha_cachesize = dpt->cache_size;
793                                 compat_softc.ha_nbus = dpt->dma_channel + 1;
794                                 compat_softc.ha_ntargets = dpt->max_id + 1;
795                                 compat_softc.ha_nluns = dpt->max_lun + 1;
796                                 compat_softc.ha_tshift = (dpt->max_id == 7) ? 3 : 4;
797                                 compat_softc.ha_bshift = 2;
798                                 compat_softc.ha_npend = dpt->submitted_ccbs_count;
799                                 compat_softc.ha_active_jobs = dpt->waiting_ccbs_count;
800                                 strncpy(compat_softc.ha_fw_version,
801                                     dpt->board_data.firmware,
802                                     sizeof(compat_softc.ha_fw_version));
803                                 compat_softc.ha_ccb = NULL;
804                                 compat_softc.ha_cblist = NULL;
805                                 compat_softc.ha_dev = NULL;
806                                 compat_softc.ha_StPkt_lock = NULL;
807                                 compat_softc.ha_ccb_lock = NULL;
808                                 compat_softc.ha_LuQWaiting = NULL;
809                                 compat_softc.ha_QWait_lock = NULL;
810                                 compat_softc.ha_QWait_opri = NULL;
811
812                                 return (copyout((char *) &compat_softc,
813                                  (caddr_t *) eata_pass_thru->command_buffer,
814                                                 sizeof(dpt_compat_ha_t)));
815                         }
816                         break;
817
818                 case DPT_SYSINFO:
819                         return (copyout((char *) &dpt_sysinfo,
820                                  (caddr_t *) eata_pass_thru->command_buffer,
821                                         sizeof(dpt_sysinfo)));
822                 case EATAUSRCMD:
823                         result = dpt_user_cmd(dpt, eata_pass_thru, cmdarg, minor_no);
824                         return (result);
825                 case DPT_BLINKLED:
826                         result = dpt_blinking_led(dpt);
827                         return (copyout((caddr_t) & result,
828                                  (caddr_t *) eata_pass_thru->command_buffer,
829                                         sizeof(result)));
830                 default:
831                         kprintf("dpt%d: Invalid (%x) pass-throu command\n",
832                                dpt->unit, eata_pass_thru->command);
833                         result = EINVAL;
834                 }
835
836         default:
837                 kprintf("dpt%d: Invalid (%lx) IOCTL\n", dpt->unit, cmd);
838                 return (EINVAL);
839
840         }
841
842         return (result);
843 }
844
845 static          dpt_devsw_installed = 0;
846
847 static void
848 dpt_drvinit(void *unused)
849 {
850         if (!dpt_devsw_installed) {
851                 if (bootverbose)
852                         kprintf("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, 0, 0);
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 */