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