vmod/vmodttl: fixed bug related to luns not ordered and/or not starting from zero.
[ht-drivers.git] / rawio / vmeio.c
blob50f705bcd43183f3deb54b3993a17901f686df3b
1 /**
2 * @file vmeio.c
4 * @brief VME bus DMA support through TSI148 chip
6 * @author Copyright (C) 2009-2010 CERN. Yury GEORGIEVSKIY <ygeorgie@cern.ch>
8 * @date Created on 02/12/2009
10 * @section license_sec License
11 * Released under the GPL
13 #define _GNU_SOURCE /* asprintf rocks */
14 #include <stdlib.h>
15 #include <stdio.h>
16 #include <stdarg.h>
17 #include <stdint.h>
18 #include <unistd.h>
19 #include <errno.h>
20 #include <string.h>
21 #include <signal.h>
22 #include <fcntl.h>
23 #include <ctype.h>
24 #include <sys/ioctl.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <vmebus.h>
29 /* error handling */
30 #define TSI148_LCSR_DSTA_VBE (1<<28) /* Error */
31 #define TSI148_LCSR_DSTA_ABT (1<<27) /* Abort */
32 #define TSI148_LCSR_DSTA_PAU (1<<26) /* Pause */
33 #define TSI148_LCSR_DSTA_DON (1<<25) /* Done */
34 #define TSI148_LCSR_DSTA_BSY (1<<24) /* Busy */
35 #define TSI148_LCSR_DSTA_ERRS (1<<20) /* Error Source */
36 #define TSI148_LCSR_DSTA_ERT (3<<16) /* Error Type */
37 #define TSI148_LCSR_DSTA_MASK 0x1f130000
39 unsigned int signum; /* current signal number */
41 void sighandler(unsigned int sig)
43 signum = sig;
45 if (signum != 0) {
46 printf("\nBus error\n");
47 exit(0);
51 /* swap bytes */
52 static __inline__ void __endian(const void *src, void *dest, unsigned int size)
54 unsigned int i;
55 for (i = 0; i < size; i++)
56 ((unsigned char*)dest)[i] = ((unsigned char*)src)[size - i - 1];
59 /* BE <-> LE convertion */
60 #define _ENDIAN(x) \
61 ({ \
62 typeof(x) __x; \
63 typeof(x) __val = (x); \
64 __endian(&(__val), &(__x), sizeof(__x)); \
65 __x; \
68 /**
69 * @brief Setup DMA description
71 * @param t -- operation type (r -- read, w -- write)
72 * @param ka -- VME address
73 * @param am -- VME address modifier
74 * @param dps -- Data Port Size (8, 16, 32, 64)
75 * @param buf -- user-space buffer to get/put data from/to
76 * @param eln -- number of elements to r/w
77 * @param d -- description table to init
79 static void setup_vme_desc(uint8_t t, void *ka, short am, uint8_t dps,
80 void *buf, int eln, struct vme_dma *d)
82 ulong vmeaddr = (ulong) ka;
83 memset(d, 0, sizeof(*d));
85 if (t == 'r') { /* read */
86 d->dir = VME_DMA_FROM_DEVICE;
87 d->src.data_width = dps;
88 d->src.am = am;
89 d->src.addrl = (unsigned int) vmeaddr;
90 d->dst.addrl = (unsigned int) buf;
91 } else { /* write */
92 d->dir = VME_DMA_TO_DEVICE;
93 d->dst.data_width = dps;
94 d->dst.am = am;
95 d->src.addrl = (unsigned int) buf;
96 d->dst.addrl = (unsigned int) vmeaddr;
98 d->length = eln * dps/8; /* number of bytes to r/w */
99 d->novmeinc = 0; /* FIFO r/w (1 -- yes, 0 -- no) */
101 d->ctrl.pci_block_size = VME_DMA_BSIZE_4096;
102 d->ctrl.pci_backoff_time = VME_DMA_BACKOFF_0;
103 d->ctrl.vme_block_size = VME_DMA_BSIZE_4096;
104 d->ctrl.vme_backoff_time = VME_DMA_BACKOFF_0;
108 * @brief BE <-> LE converter
110 * @param rd -- register description
111 * @param eln -- number of elements to swap
112 * @param buf -- data to be swapped
114 static void swap_bytes(uint8_t dps, void *buf, int eln)
116 uint16_t *w;
117 uint32_t *dw;
118 uint64_t *llw;
120 switch (dps) {
121 case 8:
122 break;
123 case 16:
124 w = (uint16_t *) buf;
125 while (eln--) { *w = _ENDIAN(*w); w++; }
126 break;
127 case 32:
128 dw = (uint32_t *) buf;
129 while (eln--) { *dw = _ENDIAN(*dw); dw++; }
130 break;
131 case 64:
132 llw = (uint64_t *) buf;
133 while (eln--) { *llw = _ENDIAN(*llw); llw++; }
134 break;
139 * @brief Decode TSI148 DMA errors. Should go into vmebus lib.
141 * @param desc -- VME DMA description table
142 * @param ptr -- if not NULL, error string will go here
144 * @note ptr (if not NULL) should be freed afterwards by the caller
146 * @return 0 -- no DMA error
147 * @return -1 -- DMA error occurs
149 static int vme_dma_error_decode(struct vme_dma *desc, char **ptr)
151 char str[256];
152 char *p = str;
153 int rc = 0, i;
154 /* Do not care about masked stuff */
155 int stat = desc->status & TSI148_LCSR_DSTA_MASK;
157 if (stat & TSI148_LCSR_DSTA_VBE) {
158 i = sprintf(p, "%s", "VME DMA error\n");
159 p += i;
160 rc = -1;
161 if ((stat & TSI148_LCSR_DSTA_ERRS) == 0) {
162 switch (stat & TSI148_LCSR_DSTA_ERT) {
163 case (0 << 16):
164 i = sprintf(p, "%s", "Bus error: SCT, BLT,"
165 " MBLT, 2eVME even data, 2eSST\n");
166 p += i;
167 break;
168 case (1 << 16):
169 i = sprintf(p, "%s",
170 "Bus error: 2eVME odd data\n");
171 p += i;
172 break;
173 case (2 << 16):
174 i = sprintf(p, "%s", "Slave termination:"
175 " 2eVME even data, 2eSST read\n");
176 p += i;
177 break;
178 case (3 << 16):
179 i = sprintf(p, "%s", "Slave termination:"
180 " 2eVME odd data, 2eSST read"
181 " last word invalid\n");
182 p += i;
183 break;
184 default:
185 break;
187 } else {
188 i = sprintf(p, "%s", "PCI/X Bus Error\n");
189 p += i;
193 if (stat & TSI148_LCSR_DSTA_ABT) {
194 i = sprintf(p, "%s", "VME DMA aborted\n");
195 p += i;
196 rc = -1;
199 if (stat & TSI148_LCSR_DSTA_PAU) {
200 i = sprintf(p, "%s", "DMA paused\n");
201 p += i;
202 rc = -1;
205 if (stat & TSI148_LCSR_DSTA_DON) {
206 i = sprintf(p, "%s", "DMA done\n");
207 p += i;
208 rc = 0;
211 if (stat & TSI148_LCSR_DSTA_BSY) {
212 i = sprintf(p, "%s", "DMA busy\n");
213 p += i;
214 rc = -1;
217 *p = '\0';
219 if (ptr)
220 asprintf(ptr, "%s", str);
222 return rc;
226 * @brief Perform DMA access
228 * @param t -- operation type (r -- read, w -- write)
229 * @param vmeaddr -- vme address to r/w
230 * @param am -- VME address modifier
231 * @param dps -- Data Port Size
232 * @param buf -- buffer to get/put data from/to
233 * @param eln -- number of elements to r/w
235 * @return -1 -- if FAILED
236 * @return 0 -- if OK
238 int do_dma(uint8_t t, void *vmeaddr, short am, uint8_t dps, void *buf, int eln)
240 struct vme_dma d;
241 char *errstr;
242 int f = open("/dev/vme_dma", O_RDWR);
244 if (!f)
245 return -1;
247 if (t == 'w')
248 /* should swap in case of write operation */
249 swap_bytes(dps, buf, eln);
251 setup_vme_desc(t, vmeaddr, am, dps, buf, eln, &d);
253 if (ioctl(f, VME_IOCTL_START_DMA, &d) < 0) {
254 perror("VME DMA access");
255 close(f);
256 return -1;
259 if (vme_dma_error_decode(&d, &errstr)) {
260 fprintf(stderr, "%s\n", errstr);
261 free(errstr);
262 close(f);
263 return -1;
266 free(errstr);
268 /* always swap data.
269 In case of read -- BE will come from VME
270 In case of write -- it was swapped by us at the beginning,
271 so swap it back */
272 swap_bytes(dps, buf, eln);
274 close(f);
275 return 0;
278 void get_obligitary_params(char *argv[], void **vmeaddr, int *am, int *dps)
280 sscanf(argv[2], "%p", vmeaddr);
281 sscanf(argv[3], "%x", am);
282 sscanf(argv[4], "%d", dps);
285 void do_read(int argc, char *argv[], char *envp[])
287 void *vmeaddr;
288 int am;
289 int dps;
290 int eln;
291 void *buf;
292 uint8_t *cp;
293 uint16_t *sp;
294 uint32_t *ip;
295 uint64_t *lp;
296 int i;
298 if (argc != 6) {
299 printf("Usage: r <VME Address> <Address Modifier>"
300 " <Data Port Size> <number of elements>\n");
301 exit(EXIT_FAILURE);
304 get_obligitary_params(argv, &vmeaddr, &am, &dps);
305 sscanf(argv[5], "%d", &eln);
307 if (!(buf = calloc(eln, dps/8))) {
308 perror("calloc");
309 exit(1);
312 do_dma('r', vmeaddr, am, dps, buf, eln);
314 printf("Read %d elements ", eln);
315 switch (dps) {
316 case 8:
317 printf("one byte long:\n");
318 cp = buf;
319 for (i = 0; i < eln; i++, cp++)
320 printf("[%d] --> %#x\n", i, *cp);
321 break;
322 case 16:
323 printf("2 bytes long:\n");
324 sp = buf;
325 for (i = 0; i < eln; i++, sp++)
326 printf("[%d] --> %#x\n", i, *sp);
327 break;
328 case 32:
329 printf("4 bytes long:\n");
330 ip = buf;
331 for (i = 0; i < eln; i++, ip++)
332 printf("[%d] --> %#x\n", i, *ip);
334 break;
335 case 64:
336 printf("8 bytes long:\n");
337 lp = buf;
338 for (i = 0; i < eln; i++, lp++)
339 printf("[%d] --> %#llx\n", i, *lp);
340 break;
341 default:
342 break;
345 free(buf);
349 void *get_data_from_file(char *fn)
351 printf("Should write data from '%s' file\n", fn);
352 printf("Not supported yet!\n");
353 return (void*)0;
356 void *get_data_from_cmd_line(char *argv[], int i, int dps, int eln)
358 uint8_t *cp;
359 uint16_t *sp;
360 uint32_t *ip;
361 uint64_t *lp;
362 void *buf = calloc(eln, dps/8);
364 switch (dps) {
365 case 8:
366 cp = buf;
367 while (eln--)
368 sscanf(argv[i++], "%x", (int*)cp++);
369 break;
370 case 16:
371 sp = buf;
372 while (eln--)
373 sscanf(argv[i++], "%hx", sp++);
374 break;
375 case 32:
376 ip = buf;
377 while (eln--)
378 sscanf(argv[i++], "%x", ip++);
379 break;
380 case 64:
381 lp = buf;
382 while (eln--)
383 sscanf(argv[i++], "%llx", lp++);
384 break;
387 return buf;
390 void do_write(int argc, char *argv[], char *envp[])
392 void *vmeaddr;
393 int am;
394 int dps;
395 int eln;
396 void *buf = NULL;
397 uint8_t *cp;
398 uint16_t *sp;
399 uint32_t *ip;
400 uint64_t *lp;
401 int i = 0;
403 if (argc < 6) {
404 usage:
405 printf("Usage: w <VME Address> <Address Modifier>"
406 " <Data Port Size> [-- <elements to write>] [<filename>]\n");
407 exit(EXIT_FAILURE);
410 while (strcmp(argv[i], "--")) {
411 if (i == 5) {
412 buf = get_data_from_file(argv[i]);
413 break;
415 ++i;
417 if (!(argc - (++i)) && !buf)
418 goto usage;
420 get_obligitary_params(argv, &vmeaddr, &am, &dps);
422 if (!buf) {
423 eln = argc - i;
424 buf = get_data_from_cmd_line(argv, i, dps, eln);
427 printf("Will write %d element(s)@%p ", eln, vmeaddr);
428 i = 0;
429 switch (dps) {
430 case 8:
431 printf("one byte long:\n");
432 cp = buf;
433 while (i < eln)
434 printf("[%d] --> %#x\n", i++, *cp++);
435 break;
436 case 16:
437 printf("2 bytes long:\n");
438 sp = buf;
439 while (i < eln)
440 printf("[%d] --> %#x\n", i++, *sp++);
441 break;
442 case 32:
443 printf("4 bytes long:\n");
444 ip = buf;
445 while (i < eln)
446 printf("[%d] --> %#x\n", i++, *ip++);
447 break;
448 case 64:
449 printf("8 bytes long:\n");
450 lp = buf;
451 while (i < eln)
452 printf("[%d] --> %#llx\n", i++, *lp++);
453 break;
456 do_dma('w', vmeaddr, am, dps, buf, eln);
459 int main(int argc, char *argv[], char *envp[])
461 char op;
462 struct sigaction sigact;
464 sigact.sa_handler = (void(*)(int))sighandler;
465 sigemptyset(&sigact.sa_mask);
466 sigact.sa_flags = 0;
467 if (sigaction(SIGBUS, &sigact, (struct sigaction *)NULL)) {
468 perror("sigaction(1)");
469 exit(1);
472 if (sigaction(SIGSEGV, &sigact, (struct sigaction *)NULL)) {
473 perror("sigaction(1)");
474 exit(1);
478 sscanf(argv[1], "%c", &op);
480 switch (op) {
481 case 'r':
482 do_read(argc, argv, envp);
483 break;
484 case 'w':
485 do_write(argc, argv, envp);
486 break;
487 default:
488 printf("Wrong optype (%c)\n", op);
489 exit(EXIT_FAILURE);
492 exit(EXIT_SUCCESS);