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