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$");
43
44#include <sys/param.h>
45#include <sys/systm.h>
46#include <sys/endian.h>
47#include <sys/malloc.h>
48#include <sys/kernel.h>
49#include <sys/uio.h>
50#include <sys/conf.h>
51#include <sys/disk.h>
52#include <sys/stat.h>
53#include <sys/disklabel.h>
54#include <sys/sysctl.h>
55#include <machine/bus.h>
56
57#include <dev/iir/iir.h>
58
59/* Entry points and other prototypes */
60static struct gdt_softc *gdt_minor2softc(int minor_no);
61
62static d_open_t		iir_open;
63static d_close_t	iir_close;
64static d_write_t	iir_write;
65static d_read_t		iir_read;
66static d_ioctl_t	iir_ioctl;
67
68/* Normally, this is a static structure.  But we need it in pci/iir_pci.c */
69static struct cdevsw iir_cdevsw = {
70	.d_version =	D_VERSION,
71	.d_flags =	D_NEEDGIANT,
72	.d_open =	iir_open,
73	.d_close =	iir_close,
74	.d_read =	iir_read,
75	.d_write =	iir_write,
76	.d_ioctl =	iir_ioctl,
77	.d_name =	"iir",
78};
79
80/*
81static int iir_devsw_installed = 0;
82*/
83#ifndef SDEV_PER_HBA
84static int sdev_made = 0;
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(int unit)
95{
96    struct cdev *dev;
97
98#ifdef SDEV_PER_HBA
99    dev = make_dev(&iir_cdevsw, hba2minor(unit), UID_ROOT, GID_OPERATOR,
100                   S_IRUSR | S_IWUSR, "iir%d", unit);
101#else
102    if (sdev_made)
103        return (0);
104    dev = make_dev(&iir_cdevsw, 0, UID_ROOT, GID_OPERATOR,
105                   S_IRUSR | S_IWUSR, "iir");
106    sdev_made = 1;
107#endif
108    return (dev);
109}
110
111void
112gdt_destroy_dev(struct cdev *dev)
113{
114    if (dev != NULL)
115        destroy_dev(dev);
116}
117
118/*
119 * Given a minor device number,
120 * return the pointer to its softc structure
121 */
122static struct gdt_softc *
123gdt_minor2softc(int minor_no)
124{
125    struct gdt_softc *gdt;
126    int hanum;
127
128#ifdef SDEV_PER_HBA
129    hanum = minor2hba(minor_no);
130#else
131    hanum = minor_no;
132#endif
133
134    for (gdt = TAILQ_FIRST(&gdt_softcs);
135         gdt != NULL && gdt->sc_hanum != hanum;
136         gdt = TAILQ_NEXT(gdt, links));
137
138    return (gdt);
139}
140
141static int
142iir_open(struct cdev *dev, int flags, int fmt, struct thread * p)
143{
144    GDT_DPRINTF(GDT_D_DEBUG, ("iir_open()\n"));
145
146#ifdef SDEV_PER_HBA
147    int minor_no;
148    struct gdt_softc *gdt;
149
150    minor_no = dev2unit(dev);
151    gdt = gdt_minor2softc(minor_no);
152    if (gdt == NULL)
153        return (ENXIO);
154#endif
155
156    return (0);
157}
158
159static int
160iir_close(struct cdev *dev, int flags, int fmt, struct thread * p)
161{
162    GDT_DPRINTF(GDT_D_DEBUG, ("iir_close()\n"));
163
164#ifdef SDEV_PER_HBA
165    int minor_no;
166    struct gdt_softc *gdt;
167
168    minor_no = dev2unit(dev);
169    gdt = gdt_minor2softc(minor_no);
170    if (gdt == NULL)
171        return (ENXIO);
172#endif
173
174    return (0);
175}
176
177static int
178iir_write(struct cdev *dev, struct uio * uio, int ioflag)
179{
180    GDT_DPRINTF(GDT_D_DEBUG, ("iir_write()\n"));
181
182#ifdef SDEV_PER_HBA
183    int minor_no;
184    struct gdt_softc *gdt;
185
186    minor_no = dev2unit(dev);
187    gdt = gdt_minor2softc(minor_no);
188    if (gdt == NULL)
189        return (ENXIO);
190#endif
191
192    return (0);
193}
194
195static int
196iir_read(struct cdev *dev, struct uio * uio, int ioflag)
197{
198    GDT_DPRINTF(GDT_D_DEBUG, ("iir_read()\n"));
199
200#ifdef SDEV_PER_HBA
201    int minor_no;
202    struct gdt_softc *gdt;
203
204    minor_no = dev2unit(dev);
205    gdt = gdt_minor2softc(minor_no);
206    if (gdt == NULL)
207        return (ENXIO);
208#endif
209
210    return (0);
211}
212
213/**
214 * This is the control syscall interface.
215 * It should be binary compatible with UnixWare,
216 * if not totally syntatically so.
217 */
218
219static int
220iir_ioctl(struct cdev *dev, u_long cmd, caddr_t cmdarg, int flags, struct thread * p)
221{
222    GDT_DPRINTF(GDT_D_DEBUG, ("iir_ioctl() cmd 0x%lx\n",cmd));
223
224#ifdef SDEV_PER_HBA
225    int minor_no;
226    struct gdt_softc *gdt;
227
228    minor_no = dev2unit(dev);
229    gdt = gdt_minor2softc(minor_no);
230    if (gdt == NULL)
231        return (ENXIO);
232#endif
233    ++gdt_stat.io_count_act;
234    if (gdt_stat.io_count_act > gdt_stat.io_count_max)
235        gdt_stat.io_count_max = gdt_stat.io_count_act;
236
237    switch (cmd) {
238      case GDT_IOCTL_GENERAL:
239        {
240            gdt_ucmd_t *ucmd;
241            struct gdt_softc *gdt;
242            int lock;
243
244            ucmd = (gdt_ucmd_t *)cmdarg;
245            gdt = gdt_minor2softc(ucmd->io_node);
246            if (gdt == NULL)
247                return (ENXIO);
248            lock = splcam();
249            TAILQ_INSERT_TAIL(&gdt->sc_ucmd_queue, ucmd, links);
250            ucmd->complete_flag = FALSE;
251            splx(lock);
252            gdt_next(gdt);
253            if (!ucmd->complete_flag)
254                (void) tsleep((void *)ucmd, PCATCH | PRIBIO, "iirucw", 0);
255            break;
256        }
257
258      case GDT_IOCTL_DRVERS:
259      case GDT_IOCTL_DRVERS_OLD:
260        *(int *)cmdarg =
261            (IIR_DRIVER_VERSION << 8) | IIR_DRIVER_SUBVERSION;
262        break;
263
264      case GDT_IOCTL_CTRTYPE:
265      case GDT_IOCTL_CTRTYPE_OLD:
266        {
267            gdt_ctrt_t *p;
268            struct gdt_softc *gdt;
269
270            p = (gdt_ctrt_t *)cmdarg;
271            gdt = gdt_minor2softc(p->io_node);
272            if (gdt == NULL)
273                return (ENXIO);
274            /* only RP controllers */
275            p->ext_type = 0x6000 | gdt->sc_device;
276            if (gdt->sc_vendor == INTEL_VENDOR_ID_IIR) {
277                p->oem_id = OEM_ID_INTEL;
278                p->type = 0xfd;
279                /* new -> subdevice into ext_type */
280                if (gdt->sc_device >= 0x600)
281                    p->ext_type = 0x6000 | gdt->sc_subdevice;
282            } else {
283                p->oem_id = OEM_ID_ICP;
284                p->type = 0xfe;
285                /* new -> subdevice into ext_type */
286                if (gdt->sc_device >= 0x300)
287                    p->ext_type = 0x6000 | gdt->sc_subdevice;
288            }
289            p->info = (gdt->sc_bus << 8) | (gdt->sc_slot << 3);
290            p->device_id = gdt->sc_device;
291            p->sub_device_id = gdt->sc_subdevice;
292            break;
293        }
294
295      case GDT_IOCTL_OSVERS:
296        {
297            gdt_osv_t *p;
298
299            p = (gdt_osv_t *)cmdarg;
300            p->oscode = 10;
301            p->version = osrelease[0] - '0';
302            if (osrelease[1] == '.')
303                p->subversion = osrelease[2] - '0';
304            else
305                p->subversion = 0;
306            if (osrelease[3] == '.')
307                p->revision = osrelease[4] - '0';
308            else
309                p->revision = 0;
310            strcpy(p->name, ostype);
311            break;
312        }
313
314      case GDT_IOCTL_CTRCNT:
315        *(int *)cmdarg = gdt_cnt;
316        break;
317
318      case GDT_IOCTL_EVENT:
319        {
320            gdt_event_t *p;
321            int lock;
322
323            p = (gdt_event_t *)cmdarg;
324            if (p->erase == 0xff) {
325                if (p->dvr.event_source == GDT_ES_TEST)
326                    p->dvr.event_data.size = sizeof(p->dvr.event_data.eu.test);
327                else if (p->dvr.event_source == GDT_ES_DRIVER)
328                    p->dvr.event_data.size= sizeof(p->dvr.event_data.eu.driver);
329                else if (p->dvr.event_source == GDT_ES_SYNC)
330                    p->dvr.event_data.size = sizeof(p->dvr.event_data.eu.sync);
331                else
332                    p->dvr.event_data.size = sizeof(p->dvr.event_data.eu.async);
333                lock = splcam();
334                gdt_store_event(p->dvr.event_source, p->dvr.event_idx,
335                                &p->dvr.event_data);
336                splx(lock);
337            } else if (p->erase == 0xfe) {
338                lock = splcam();
339                gdt_clear_events();
340                splx(lock);
341            } else if (p->erase == 0) {
342                p->handle = gdt_read_event(p->handle, &p->dvr);
343            } else {
344                gdt_readapp_event((u_int8_t)p->erase, &p->dvr);
345            }
346            break;
347        }
348
349      case GDT_IOCTL_STATIST:
350        {
351            gdt_statist_t *p;
352
353            p = (gdt_statist_t *)cmdarg;
354            bcopy(&gdt_stat, p, sizeof(gdt_statist_t));
355            break;
356        }
357
358      default:
359        break;
360    }
361
362    --gdt_stat.io_count_act;
363    return (0);
364}
365
366/*
367static void
368iir_drvinit(void *unused)
369{
370    GDT_DPRINTF(GDT_D_DEBUG, ("iir_drvinit()\n"));
371
372    if (!iir_devsw_installed) {
373        cdevsw_add(&iir_cdevsw);
374        iir_devsw_installed = 1;
375    }
376}
377
378SYSINIT(iir_dev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, iir_drvinit, NULL)
379*/
380