nrelease - fix/improve livecd
[dragonfly.git] / sys / dev / raid / ips / ips_ioctl.c
1 /*-
2  * Written by: David Jeffery
3  * Copyright (c) 2002 Adaptec Inc.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
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  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  * $FreeBSD: src/sys/dev/ips/ips_ioctl.c,v 1.5 2004/05/30 04:01:29 scottl Exp $
28  */
29
30 #include <dev/raid/ips/ips.h>
31 #include <dev/raid/ips/ips_ioctl.h>
32
33 static void
34 ips_ioctl_finish(ips_command_t *command)
35 {
36         ips_ioctl_t *ioctl_cmd = command->arg;
37
38         if (ioctl_cmd->readwrite & IPS_IOCTL_READ) {
39                 bus_dmamap_sync(ioctl_cmd->dmatag, ioctl_cmd->dmamap,
40                     BUS_DMASYNC_POSTREAD);
41         } else if (ioctl_cmd->readwrite & IPS_IOCTL_WRITE) {
42                 bus_dmamap_sync(ioctl_cmd->dmatag, ioctl_cmd->dmamap,
43                     BUS_DMASYNC_POSTWRITE);
44         }
45         bus_dmamap_sync(command->sc->command_dmatag, command->command_dmamap,
46             BUS_DMASYNC_POSTWRITE);
47         bus_dmamap_unload(ioctl_cmd->dmatag, ioctl_cmd->dmamap);
48         ioctl_cmd->status.value = command->status.value;
49         ips_insert_free_cmd(command->sc, command);
50 }
51
52 static void
53 ips_ioctl_callback(void *cmdptr, bus_dma_segment_t *segments,
54     int segnum, int error)
55 {
56         ips_command_t *command;
57         ips_ioctl_t *ioctl_cmd;
58         ips_generic_cmd *command_buffer;
59
60         command = cmdptr;
61         ioctl_cmd = command->arg;
62         command_buffer = command->command_buffer;
63         if (error) {
64                 ioctl_cmd->status.value = IPS_ERROR_STATUS;
65                 ips_insert_free_cmd(command->sc, command);
66                 return;
67         }
68         command_buffer->id = command->id;
69         command_buffer->buffaddr = segments[0].ds_addr;
70         if (ioctl_cmd->readwrite & IPS_IOCTL_WRITE) {
71                 bus_dmamap_sync(ioctl_cmd->dmatag, ioctl_cmd->dmamap,
72                     BUS_DMASYNC_PREWRITE);
73         } else if (ioctl_cmd->readwrite & IPS_IOCTL_READ) {
74                 bus_dmamap_sync(ioctl_cmd->dmatag, ioctl_cmd->dmamap,
75                     BUS_DMASYNC_PREREAD);
76         }
77         bus_dmamap_sync(command->sc->command_dmatag, command->command_dmamap,
78             BUS_DMASYNC_PREWRITE);
79         command->sc->ips_issue_cmd(command);
80 }
81
82 static int
83 ips_ioctl_start(ips_command_t *command)
84 {
85         ips_ioctl_t *ioctl_cmd = command->arg;
86
87         memcpy(command->command_buffer, ioctl_cmd->command_buffer,
88             sizeof(ips_generic_cmd));
89         command->callback = ips_ioctl_finish;
90         bus_dmamap_load(ioctl_cmd->dmatag, ioctl_cmd->dmamap,
91             ioctl_cmd->data_buffer, ioctl_cmd->datasize, ips_ioctl_callback,
92             command, 0);
93         return 0;
94 }
95
96 static int
97 ips_ioctl_cmd(ips_softc_t *sc, ips_ioctl_t *ioctl_cmd,
98     ips_user_request *user_request)
99 {
100         ips_command_t *command;
101         int error = EINVAL;
102
103         if (bus_dma_tag_create(
104                         /* parent    */ sc->adapter_dmatag,
105                         /* alignment */ 1,
106                         /* boundary  */ 0,
107                         /* lowaddr   */ BUS_SPACE_MAXADDR_32BIT,
108                         /* highaddr  */ BUS_SPACE_MAXADDR,
109                         /* maxsize   */ ioctl_cmd->datasize,
110                         /* numsegs   */ 1,
111                         /* maxsegsize*/ ioctl_cmd->datasize,
112                         /* flags     */ 0,
113                         &ioctl_cmd->dmatag) != 0) {
114                 return ENOMEM;
115         }
116         if (bus_dmamem_alloc(ioctl_cmd->dmatag, &ioctl_cmd->data_buffer,
117             0, &ioctl_cmd->dmamap)) {
118                 error = ENOMEM;
119                 goto exit;
120         }
121         if (copyin(user_request->data_buffer, ioctl_cmd->data_buffer,
122             ioctl_cmd->datasize))
123                 goto exit;
124         ioctl_cmd->status.value = 0xffffffff;
125         lockmgr(&sc->queue_lock, LK_EXCLUSIVE|LK_RETRY);
126         if ((error = ips_get_free_cmd(sc, &command, 0)) > 0) {
127                 error = ENOMEM;
128                 lockmgr(&sc->queue_lock, LK_RELEASE);
129                 goto exit;
130         }
131         command->arg = ioctl_cmd;
132         ips_ioctl_start(command);
133         while (ioctl_cmd->status.value == 0xffffffff)
134                 tsleep(ioctl_cmd, 0, "ips", hz / 10);
135         if (COMMAND_ERROR(&ioctl_cmd->status))
136                 error = EIO;
137         else
138                 error = 0;
139         lockmgr(&sc->queue_lock, LK_RELEASE);
140
141         if (copyout(ioctl_cmd->data_buffer, user_request->data_buffer,
142             ioctl_cmd->datasize))
143                 error = EINVAL;
144 exit:
145         bus_dmamem_free(ioctl_cmd->dmatag, ioctl_cmd->data_buffer,
146             ioctl_cmd->dmamap);
147         bus_dma_tag_destroy(ioctl_cmd->dmatag);
148         return error;
149 }
150
151 int
152 ips_ioctl_request(ips_softc_t *sc, u_long ioctl_request, caddr_t addr,
153     int32_t flags)
154 {
155         ips_ioctl_t *ioctl_cmd;
156         ips_user_request *user_request;
157         int error = EINVAL;
158
159         switch (ioctl_request) {
160         case IPS_USER_CMD:
161                 user_request = (ips_user_request *)addr;
162                 ioctl_cmd = kmalloc(sizeof(ips_ioctl_t), M_IPSBUF, M_WAITOK);
163                 ioctl_cmd->command_buffer = kmalloc(sizeof(ips_generic_cmd),
164                     M_IPSBUF, M_WAITOK);
165                 if (copyin(user_request->command_buffer,
166                     ioctl_cmd->command_buffer, sizeof(ips_generic_cmd))) {
167                         kfree(ioctl_cmd->command_buffer, M_IPSBUF);
168                         kfree(ioctl_cmd, M_IPSBUF);
169                         break;
170                 }
171                 ioctl_cmd->readwrite = IPS_IOCTL_READ | IPS_IOCTL_WRITE;
172                 ioctl_cmd->datasize = IPS_IOCTL_BUFFER_SIZE;
173                 error = ips_ioctl_cmd(sc, ioctl_cmd, user_request);
174                 kfree(ioctl_cmd->command_buffer, M_IPSBUF);
175                 kfree(ioctl_cmd, M_IPSBUF);
176                 break;
177         }
178         return error;
179 }