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