iir_ctrl.c revision 330897
1/*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 *       Copyright (c) 2000-03 ICP vortex GmbH
5 *       Copyright (c) 2002-03 Intel Corporation
6 *       Copyright (c) 2003    Adaptec Inc.
7 *       All Rights Reserved
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions, and the following disclaimer,
14 *    without modification, immediately at the beginning of the file.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 * 3. The name of the author may not be used to endorse or promote products
19 *    derived from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
25 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34/*
35 * iir_ctrl.c: Control functions and /dev entry points for /dev/iir*
36 *
37 * Written by: Achim Leubner <achim_leubner@adaptec.com>
38 * Fixes/Additions: Boji Tony Kannanthanam <boji.t.kannanthanam@intel.com>
39 *
40 * $Id: iir_ctrl.c 1.3 2003/08/26 12:31:15 achim Exp $"
41 */
42
43#include <sys/cdefs.h>
44__FBSDID("$FreeBSD: stable/11/sys/dev/iir/iir_ctrl.c 330897 2018-03-14 03:19:51Z eadler $");
45
46#include <sys/param.h>
47#include <sys/systm.h>
48#include <sys/bus.h>
49#include <sys/endian.h>
50#include <sys/malloc.h>
51#include <sys/kernel.h>
52#include <sys/uio.h>
53#include <sys/conf.h>
54#include <sys/disk.h>
55#include <sys/stat.h>
56#include <sys/disklabel.h>
57#include <sys/sysctl.h>
58#include <sys/sx.h>
59#include <machine/bus.h>
60
61#include <dev/iir/iir.h>
62
63/* Entry points and other prototypes */
64static struct gdt_softc *gdt_minor2softc(struct cdev *dev, int minor_no);
65
66static d_open_t		iir_open;
67static d_close_t	iir_close;
68static d_write_t	iir_write;
69static d_read_t		iir_read;
70static d_ioctl_t	iir_ioctl;
71
72/* Normally, this is a static structure.  But we need it in pci/iir_pci.c */
73static struct cdevsw iir_cdevsw = {
74	.d_version =	D_VERSION,
75	.d_open =	iir_open,
76	.d_close =	iir_close,
77	.d_read =	iir_read,
78	.d_write =	iir_write,
79	.d_ioctl =	iir_ioctl,
80	.d_name =	"iir",
81};
82
83#ifndef SDEV_PER_HBA
84static int sdev_made = 0;
85static struct sx sdev_lock;
86SX_SYSINIT(iir_sdev_lock, &sdev_lock, "iir sdev");
87#endif
88extern int gdt_cnt;
89extern gdt_statist_t gdt_stat;
90
91/*
92 * Given a controller number,
93 * make a special device and return the dev_t
94 */
95struct cdev *
96gdt_make_dev(struct gdt_softc *gdt)
97{
98    struct cdev *dev;
99
100#ifdef SDEV_PER_HBA
101    dev = make_dev(&iir_cdevsw, 0, UID_ROOT, GID_OPERATOR,
102                   S_IRUSR | S_IWUSR, "iir%d", unit);
103    dev->si_drv1 = gdt;
104#else
105    sx_xlock(&sdev_lock);
106    if (sdev_made)
107        return (NULL);
108    dev = make_dev(&iir_cdevsw, 0, UID_ROOT, GID_OPERATOR,
109                   S_IRUSR | S_IWUSR, "iir");
110    sdev_made = 1;
111    sx_xunlock(&sdev_lock);
112#endif
113    return (dev);
114}
115
116void
117gdt_destroy_dev(struct cdev *dev)
118{
119    if (dev != NULL)
120        destroy_dev(dev);
121}
122
123/*
124 * Given a minor device number,
125 * return the pointer to its softc structure
126 */
127static struct gdt_softc *
128gdt_minor2softc(struct cdev *dev, int minor_no)
129{
130#ifdef SDEV_PER_HBA
131
132    return (dev->si_drv1);
133#else
134    devclass_t dc;
135    device_t child;
136
137    dc = devclass_find("iir");
138    if (dc == NULL)
139	return (NULL);
140    child = devclass_get_device(dc, minor_no);
141    if (child == NULL)
142	return (NULL);
143    return (device_get_softc(child));
144#endif
145}
146
147static int
148iir_open(struct cdev *dev, int flags, int fmt, struct thread * p)
149{
150    GDT_DPRINTF(GDT_D_DEBUG, ("iir_open()\n"));
151
152    return (0);
153}
154
155static int
156iir_close(struct cdev *dev, int flags, int fmt, struct thread * p)
157{
158    GDT_DPRINTF(GDT_D_DEBUG, ("iir_close()\n"));
159
160    return (0);
161}
162
163static int
164iir_write(struct cdev *dev, struct uio * uio, int ioflag)
165{
166    GDT_DPRINTF(GDT_D_DEBUG, ("iir_write()\n"));
167
168    return (0);
169}
170
171static int
172iir_read(struct cdev *dev, struct uio * uio, int ioflag)
173{
174    GDT_DPRINTF(GDT_D_DEBUG, ("iir_read()\n"));
175
176    return (0);
177}
178
179/**
180 * This is the control syscall interface.
181 * It should be binary compatible with UnixWare,
182 * if not totally syntatically so.
183 */
184
185static int
186iir_ioctl(struct cdev *dev, u_long cmd, caddr_t cmdarg, int flags, struct thread * p)
187{
188    GDT_DPRINTF(GDT_D_DEBUG, ("iir_ioctl() cmd 0x%lx\n",cmd));
189
190    ++gdt_stat.io_count_act;
191    if (gdt_stat.io_count_act > gdt_stat.io_count_max)
192        gdt_stat.io_count_max = gdt_stat.io_count_act;
193
194    switch (cmd) {
195      case GDT_IOCTL_GENERAL:
196        {
197            gdt_ucmd_t *ucmd;
198            struct gdt_softc *gdt;
199
200            ucmd = (gdt_ucmd_t *)cmdarg;
201            gdt = gdt_minor2softc(dev, ucmd->io_node);
202            if (gdt == NULL)
203                return (ENXIO);
204	    mtx_lock(&gdt->sc_lock);
205            TAILQ_INSERT_TAIL(&gdt->sc_ucmd_queue, ucmd, links);
206            ucmd->complete_flag = FALSE;
207            gdt_next(gdt);
208            if (!ucmd->complete_flag)
209                (void) mtx_sleep(ucmd, &gdt->sc_lock, PCATCH | PRIBIO, "iirucw",
210		    0);
211	    mtx_unlock(&gdt->sc_lock);
212            break;
213        }
214
215      case GDT_IOCTL_DRVERS:
216      case GDT_IOCTL_DRVERS_OLD:
217        *(int *)cmdarg =
218            (IIR_DRIVER_VERSION << 8) | IIR_DRIVER_SUBVERSION;
219        break;
220
221      case GDT_IOCTL_CTRTYPE:
222      case GDT_IOCTL_CTRTYPE_OLD:
223        {
224            gdt_ctrt_t *p;
225            struct gdt_softc *gdt;
226
227            p = (gdt_ctrt_t *)cmdarg;
228            gdt = gdt_minor2softc(dev, p->io_node);
229            if (gdt == NULL)
230                return (ENXIO);
231            /* only RP controllers */
232            p->ext_type = 0x6000 | gdt->sc_device;
233            if (gdt->sc_vendor == INTEL_VENDOR_ID_IIR) {
234                p->oem_id = OEM_ID_INTEL;
235                p->type = 0xfd;
236                /* new -> subdevice into ext_type */
237                if (gdt->sc_device >= 0x600)
238                    p->ext_type = 0x6000 | gdt->sc_subdevice;
239            } else {
240                p->oem_id = OEM_ID_ICP;
241                p->type = 0xfe;
242                /* new -> subdevice into ext_type */
243                if (gdt->sc_device >= 0x300)
244                    p->ext_type = 0x6000 | gdt->sc_subdevice;
245            }
246            p->info = (gdt->sc_bus << 8) | (gdt->sc_slot << 3);
247            p->device_id = gdt->sc_device;
248            p->sub_device_id = gdt->sc_subdevice;
249            break;
250        }
251
252      case GDT_IOCTL_OSVERS:
253        {
254            gdt_osv_t *p;
255
256            p = (gdt_osv_t *)cmdarg;
257            p->oscode = 10;
258	    p->version = osreldate / 100000;
259	    p->subversion = osreldate / 1000 % 100;
260	    p->revision = 0;
261            strcpy(p->name, ostype);
262            break;
263        }
264
265      case GDT_IOCTL_CTRCNT:
266        *(int *)cmdarg = gdt_cnt;
267        break;
268
269      case GDT_IOCTL_EVENT:
270        {
271            gdt_event_t *p;
272
273            p = (gdt_event_t *)cmdarg;
274            if (p->erase == 0xff) {
275                if (p->dvr.event_source == GDT_ES_TEST)
276                    p->dvr.event_data.size = sizeof(p->dvr.event_data.eu.test);
277                else if (p->dvr.event_source == GDT_ES_DRIVER)
278                    p->dvr.event_data.size= sizeof(p->dvr.event_data.eu.driver);
279                else if (p->dvr.event_source == GDT_ES_SYNC)
280                    p->dvr.event_data.size = sizeof(p->dvr.event_data.eu.sync);
281                else
282                    p->dvr.event_data.size = sizeof(p->dvr.event_data.eu.async);
283                gdt_store_event(p->dvr.event_source, p->dvr.event_idx,
284                                &p->dvr.event_data);
285            } else if (p->erase == 0xfe) {
286                gdt_clear_events();
287            } else if (p->erase == 0) {
288                p->handle = gdt_read_event(p->handle, &p->dvr);
289            } else {
290                gdt_readapp_event((u_int8_t)p->erase, &p->dvr);
291            }
292            break;
293        }
294
295      case GDT_IOCTL_STATIST:
296        {
297            gdt_statist_t *p;
298
299            p = (gdt_statist_t *)cmdarg;
300            bcopy(&gdt_stat, p, sizeof(gdt_statist_t));
301            break;
302        }
303
304      default:
305        break;
306    }
307
308    --gdt_stat.io_count_act;
309    return (0);
310}
311