Bump version to 0.3.5next
[archipelago] / xseg / drivers / user / xseg_segdev.c
1 /*
2  * Copyright 2012 GRNET S.A. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or
5  * without modification, are permitted provided that the following
6  * conditions are met:
7  *
8  *   1. Redistributions of source code must retain the above
9  *      copyright notice, this list of conditions and the following
10  *      disclaimer.
11  *   2. Redistributions in binary form must reproduce the above
12  *      copyright notice, this list of conditions and the following
13  *      disclaimer in the documentation and/or other materials
14  *      provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  *
29  * The views and conclusions contained in the software and
30  * documentation are those of the authors and should not be
31  * interpreted as representing official policies, either expressed
32  * or implied, of GRNET S.A.
33  */
34
35 #define _GNU_SOURCE
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <unistd.h>
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <sys/ioctl.h>
42 #include <sys/mman.h>
43 #include <sys/syscall.h>
44 #include <fcntl.h>
45 #include <errno.h>
46 #include <string.h>
47 #include <signal.h>
48 #include <xseg/xseg.h>
49 #include <sys/util.h>
50 #include <sys/kernel/segdev.h>
51 #include <drivers/xseg_segdev.h>
52
53 #define ERRSIZE 512
54 static char errbuf[ERRSIZE];
55
56 #define SEGDEV_DEVICE "/dev/segdev"
57 static int fdev = -1;
58
59 static int opendev(void)
60 {
61         if (fdev >= 0)
62                 return fdev;
63
64         fdev = open(SEGDEV_DEVICE, O_RDWR);
65         if (fdev < 0) {
66                 XSEGLOG("Cannot open %s: %s\n", SEGDEV_DEVICE,
67                         strerror_r(errno, errbuf, ERRSIZE));
68                 fdev = -1;
69         }
70         return fdev;
71 }
72
73 static int closedev(void)
74 {
75         int r;
76         if (fdev < 0)
77                 return 0;
78
79         r = close(fdev);
80         if (r < 0) {
81                 XSEGLOG("Cannot close %s: %s\n", SEGDEV_DEVICE,
82                         strerror_r(errno, errbuf, ERRSIZE));
83                 return -1;
84         } else
85                 fdev = -1;
86
87         return 0;
88 }
89
90 static long segdev_allocate(const char *name, uint64_t size)
91 {
92         int fd;
93         long oldsize;
94
95         fd = opendev();
96         if (fd < 0)
97                 return fd;
98
99         oldsize = ioctl(fd, SEGDEV_IOC_SEGSIZE, 0);
100         if (oldsize >= 0) {
101                 XSEGLOG("Failed to create new segment. Destroy the old one first");
102                 return -2;
103         }
104
105         XSEGLOG("creating segment of size %llu\n", size);
106
107         if (ioctl(fd, SEGDEV_IOC_CREATESEG, size)) {
108                 XSEGLOG("Failed to create segment");
109                 closedev();
110                 return -3;
111         }
112
113         return 0;
114 }
115
116 static long segdev_deallocate(const char *name)
117 {
118         int fd;
119         fd = open(SEGDEV_DEVICE, O_RDWR);
120         if (fd < 0) {
121                 XSEGLOG("Cannot open %s: %s\n", SEGDEV_DEVICE,
122                         strerror_r(errno, errbuf, ERRSIZE));
123                 return -1;
124         }
125
126         if (ioctl(fd, SEGDEV_IOC_DESTROYSEG, 0)) {
127                 XSEGLOG("Failed to destroy old segment");
128                 return -2;
129         }
130         close(fd);
131         closedev();
132         return 0;
133 }
134
135 static void *segdev_map(const char *name, uint64_t size, struct xseg *seg)
136 {
137         struct xseg *xseg;
138         int fd;
139
140         if (seg)
141                 //XSEGLOG("struct xseg * not NULL. Ignoring...\n");
142                 ;
143
144         fd = opendev();
145         if (fd < 0)
146                 return NULL;
147
148         xseg = mmap (   XSEG_BASE_AS_PTR,
149                         size,
150                         PROT_READ | PROT_WRITE,
151                         MAP_SHARED | MAP_FIXED /* | MAP_LOCKED */,
152                         fd, 0   );
153
154         if (xseg == MAP_FAILED) {
155                 XSEGLOG("Could not map segment: %s\n",
156                         strerror_r(errno, errbuf, ERRSIZE));
157                 closedev();
158                 return NULL;
159         }
160
161         return xseg;
162 }
163
164 static void segdev_unmap(void *ptr, uint64_t size)
165 {
166         struct xseg *xseg = ptr;
167         (void)munmap(xseg, xseg->segment_size);
168         closedev();
169 }
170
171
172 static struct xseg_type xseg_segdev = {
173         /* xseg_operations */
174         {
175                 .allocate       = segdev_allocate,
176                 .deallocate     = segdev_deallocate,
177                 .map            = segdev_map,
178                 .unmap          = segdev_unmap
179         },
180         /* name */
181         "segdev"
182 };
183
184 static int segdev_local_signal_init(struct xseg *xseg, xport portno)
185 {
186         return -1;
187 }
188
189 static void segdev_local_signal_quit(struct xseg *xseg, xport portno)
190 {
191         return;
192 }
193
194 static int segdev_remote_signal_init(void)
195 {
196         return 0;
197 }
198
199 static void segdev_remote_signal_quit(void)
200 {
201         return;
202 }
203
204 static int segdev_prepare_wait(struct xseg *xseg, uint32_t portno)
205 {
206         return -1;
207 }
208
209 static int segdev_cancel_wait(struct xseg *xseg, uint32_t portno)
210 {
211         return -1;
212 }
213
214 static int segdev_wait_signal(struct xseg *xseg, void *sd, uint32_t timeout)
215 {
216         return -1;
217 }
218
219 static int segdev_signal(struct xseg *xseg, uint32_t portno)
220 {
221         struct xseg_port *port = xseg_get_port(xseg, portno);
222         if (!port)
223                 return -1;
224         struct segdev_signal_desc *ssd = xseg_get_signal_desc(xseg, port);
225         if (!ssd)
226                 return -1;
227
228         if (!ssd->waitcue){
229                 return 0;
230         }
231         else
232                 return write(opendev(), &portno, sizeof(portno));
233 }
234
235 static void *segdev_malloc(uint64_t size)
236 {
237         return NULL;
238 }
239
240 static void *segdev_realloc(void *mem, uint64_t size)
241 {
242         return NULL;
243 }
244
245 static void segdev_mfree(void *mem) { }
246
247 static int segdev_init_signal_desc(struct xseg *xseg, void *sd)
248 {
249         return -1;
250 }
251
252 static void segdev_quit_signal_desc(struct xseg *xseg, void *sd)
253 {
254         return;
255 }
256
257 static void *segdev_alloc_data(struct xseg *xseg)
258 {
259         return NULL;
260 }
261
262 static void segdev_free_data(struct xseg *xseg, void *data)
263 {
264         return;
265 }
266
267 static void *segdev_alloc_signal_desc(struct xseg *xseg, void *data)
268 {
269         return NULL;
270 }
271
272 static void segdev_free_signal_desc(struct xseg *xseg, void *data, void *sd)
273 {
274         return;
275 }
276
277 static struct xseg_peer xseg_peer_segdev = {
278         /* xseg signal operations */
279         {
280                 .init_signal_desc   = segdev_init_signal_desc,
281                 .quit_signal_desc   = segdev_quit_signal_desc,
282                 .alloc_data         = segdev_alloc_data,
283                 .free_data          = segdev_free_data,
284                 .alloc_signal_desc  = segdev_alloc_signal_desc,
285                 .free_signal_desc   = segdev_free_signal_desc,
286                 .local_signal_init  = segdev_local_signal_init,
287                 .local_signal_quit  = segdev_local_signal_quit,
288                 .remote_signal_init = segdev_remote_signal_init,
289                 .remote_signal_quit = segdev_remote_signal_quit,
290                 .prepare_wait = segdev_prepare_wait,
291                 .cancel_wait = segdev_cancel_wait,
292                 .wait_signal = segdev_wait_signal,
293                 .signal = segdev_signal,
294                 .malloc = segdev_malloc,
295                 .realloc = segdev_realloc,
296                 .mfree = segdev_mfree
297         },
298         /* name */
299         "segdev"
300 };
301
302 void xseg_segdev_init(void)
303 {
304         xseg_register_type(&xseg_segdev);
305         xseg_register_peer(&xseg_peer_segdev);
306 }
307