AMD64 - Refactor uio_resid and size_t assumptions.
[dragonfly.git] / sys / dev / raid / dpt / dpt_control.c
CommitLineData
984263bc
MD
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 $"
e4846942 40#ident "$DragonFly: src/sys/dev/raid/dpt/dpt_control.c,v 1.14 2006/12/28 21:23:58 dillon Exp $"
984263bc
MD
41
42#include "opt_dpt.h"
43
f8334305 44#include <machine/cputypes.h>
984263bc
MD
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>
73c4645c 52#include <sys/thread2.h>
984263bc
MD
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
1f2de5d4 59#include "dpt.h"
984263bc
MD
60
61#define INLINE __inline
62
63extern char osrelease[];
64
ac40735c
MD
65enum dpt_message dpt_message;
66enum dpt_immediate_cmd dpt_immediate_cmd;
67
984263bc
MD
68static dpt_sysinfo_t dpt_sysinfo;
69
70/* Entry points and other prototypes */
71static vm_offset_t dpt_physmap(u_int32_t paddr, vm_size_t size);
72static void dpt_unphysmap(u_int8_t * vaddr, vm_size_t size);
73
74static void dpt_get_sysinfo(void);
75
b13267a5
MD
76static int dpt_open(cdev_t dev, int flags, int fmt, struct proc * p);
77static int dpt_close(cdev_t dev, int flags, int fmt, struct proc * p);
78static int dpt_write(cdev_t dev, struct uio * uio, int ioflag);
79static int dpt_read(cdev_t dev, struct uio * uio, int ioflag);
80static int dpt_ioctl(cdev_t dev, u_long cmd, caddr_t cmdarg, int flags, struct proc * p);
984263bc
MD
81
82
83/* This has to be modified as the processor and CPU are not known yet */
84static 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 */
99static struct cdevsw dpt_cdevsw = {
fabb8ceb
MD
100 /* name */ "dpt",
101 /* maj */ CDEV_MAJOR,
102 /* flags */ 0,
103 /* port */ NULL,
455fcd7e 104 /* clone */ NULL,
fabb8ceb 105
984263bc
MD
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,
984263bc 114 /* dump */ nodump,
fabb8ceb 115 /* psize */ nopsize
984263bc
MD
116};
117
118static struct buf *dpt_inbuf[DPT_MAX_ADAPTERS];
119static 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
127dpt_softc_t *
128dpt_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
152static vm_offset_t
153dpt_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
e4846942 167 va = kmem_alloc_pageable(&kernel_map, size);
984263bc
MD
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
187static void
188dpt_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
e4846942 196 kmem_free(&kernel_map, (vm_offset_t) vaddr, size);
984263bc
MD
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
206static void
207dpt_get_sysinfo(void)
208{
209 int i;
210 int j;
984263bc
MD
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 */
73c4645c 221 crit_enter();
984263bc
MD
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) {
e3869ec7 262 kprintf("DPT: Cannot map BIOS address 0x0475. No sysinfo... :-(\n");
984263bc
MD
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 }
73c4645c 381 crit_exit();
984263bc
MD
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
410static int
b13267a5 411dpt_open(cdev_t dev, int flags, int fmt, struct proc * p)
984263bc
MD
412{
413 int minor_no;
984263bc
MD
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
73c4645c 426 crit_enter();
984263bc
MD
427
428 if (dpt->state & DPT_HA_CONTROL_ACTIVE) {
73c4645c 429 crit_exit();
984263bc
MD
430 return (EBUSY);
431 } else {
432 if ((dpt_inbuf[minor_no & ~SCSI_CONTROL_MASK] = geteblk(PAGE_SIZE))
433 == NULL) {
434#ifdef DPT_DEBUG_CONTROL
e3869ec7 435 kprintf("dpt%d: Failed to obtain an I/O buffer\n",
984263bc
MD
436 minor_no & ~SCSI_CONTROL_MASK);
437#endif
73c4645c 438 crit_exit();
984263bc
MD
439 return (EINVAL);
440 }
441 }
442
443 dpt->state |= DPT_HA_CONTROL_ACTIVE;
73c4645c 444 crit_exit();
984263bc
MD
445 return (0);
446}
447
448static int
b13267a5 449dpt_close(cdev_t dev, int flags, int fmt, struct proc * p)
984263bc
MD
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
466static int
b13267a5 467dpt_write(cdev_t dev, struct uio * uio, int ioflag)
984263bc
MD
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
e3869ec7 477 kprintf("dpt%d: I/O attempted to control channel (%x)\n",
984263bc
MD
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 {
e54488bb
MD
489 char *cp;
490 size_t length;
984263bc
MD
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
e3869ec7 497 kprintf("dpt%d: uiomove(%x, %d, %x) failed (%d)\n",
984263bc
MD
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 */
e3869ec7 514 kprintf("dpt%d: Command \"%s\" arrived\n",
984263bc
MD
515 unit, dpt_rw_command[unit]);
516#endif
517 }
518 }
519
520 return (error);
521}
522
523static int
b13267a5 524dpt_read(cdev_t dev, struct uio * uio, int ioflag)
984263bc
MD
525{
526 dpt_softc_t *dpt;
527 int error;
528 int minor_no;
984263bc
MD
529
530 minor_no = minor(dev);
531 error = 0;
532
533#ifdef DPT_DEBUG_CONTROL
e3869ec7 534 kprintf("dpt%d: read, count = %d, dev = %08x\n",
984263bc
MD
535 minor_no, uio->uio_resid, dev);
536#endif
537
538 if (minor_no & SCSI_CONTROL_MASK) {
539#ifdef DPT_DEBUG_CONTROL
e3869ec7 540 kprintf("dpt%d: I/O attempted to control channel (%x)\n",
984263bc
MD
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
efda3bd0 562 work_buffer = (u_int8_t *) kmalloc(PAGE_SIZE, M_TEMP, M_WAITOK);
984263bc
MD
563 wbp = work_buffer;
564 work_size = 0;
565
73c4645c 566 crit_enter();
984263bc
MD
567
568 command = dpt_rw_command[dpt->unit];
569 if (strcmp(command, DPT_RW_CMD_DUMP_SOFTC) == 0) {
f8c7a42d 570 x = ksprintf(wbp, "dpt%d:%s:%s:%s:%s:%x\n",
984263bc
MD
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) {
f8c7a42d 581 x = ksprintf(wbp, "dpt%d:%d:%d:%d:%d:%d:%d:%d:%d:%s:"
984263bc
MD
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) {
f8c7a42d 604 x = ksprintf(wbp, "dpt%d:d%dc%dh%ds%d\n",
984263bc
MD
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) {
f8c7a42d 615 x = ksprintf(wbp,
984263bc
MD
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
f8c7a42d 627 x = ksprintf(wbp, "dpt%d: Metrics have been cleared\n",
984263bc
MD
628 dpt->unit);
629 work_size += x;
630 wbp += x;
631 } else if (strcmp(command, DPT_RW_CMD_SHOW_LED) == 0) {
632
f8c7a42d 633 x = ksprintf(wbp, "dpt%d:%s\n",
984263bc
MD
634 dpt->unit, i2bin(dpt_blinking_led(dpt), 8));
635 work_size += x;
636 wbp += x;
637 } else {
638#ifdef DPT_DEBUG_CONTROL
e3869ec7 639 kprintf("dpt%d: Bad READ state (%s)\n", minor_no, command);
984263bc 640#endif
73c4645c 641 crit_exit();
984263bc
MD
642 error = EINVAL;
643 }
644
645 if (error == 0) {
646 work_buffer[work_size++] = '\0';
e54488bb 647 error = uiomove(work_buffer, (size_t)work_size, uio);
984263bc
MD
648 uio->uio_resid = 0;
649#ifdef DPT_DEBUG_CONTROL
650 if (error) {
e3869ec7 651 kprintf("dpt%d: READ uimove failed (%d)\n", dpt->unit, error);
984263bc
MD
652 }
653#endif
654 }
655 }
73c4645c 656 crit_exit();
984263bc
MD
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
666static int
b13267a5 667dpt_ioctl(cdev_t dev, u_long cmd, caddr_t cmdarg, int flags, struct proc * p)
984263bc
MD
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
e3869ec7 681 kprintf("dpt%d: Control attempted to I/O channel (%x)\n",
984263bc
MD
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
e3869ec7 689 kprintf("dpt%d: IOCTL(%x, %x, %p, %x, %p)\n",
984263bc
MD
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:
e3869ec7 831 kprintf("dpt%d: Invalid (%x) pass-throu command\n",
984263bc
MD
832 dpt->unit, eata_pass_thru->command);
833 result = EINVAL;
834 }
835
836 default:
e3869ec7 837 kprintf("dpt%d: Invalid (%lx) IOCTL\n", dpt->unit, cmd);
984263bc
MD
838 return (EINVAL);
839
840 }
841
842 return (result);
843}
844
845static dpt_devsw_installed = 0;
846
847static void
848dpt_drvinit(void *unused)
849{
984263bc
MD
850 if (!dpt_devsw_installed) {
851 if (bootverbose)
e3869ec7 852 kprintf("DPT: RAID Manager driver, Version %d.%d.%d\n",
984263bc
MD
853 DPT_CTL_RELEASE, DPT_CTL_VERSION, DPT_CTL_PATCH);
854
855 /* Add the I/O (data) channel */
e4c9c0c8 856 cdevsw_add(&dpt_cdevsw, 0, 0);
984263bc
MD
857
858 dpt_devsw_installed = 1;
859 }
860 dpt_get_sysinfo();
861}
862
863SYSINIT(dpt_dev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE + CDEV_MAJOR, dpt_drvinit, NULL)
864/* End of the dpt_control driver */