kprobes: Do not expose probe addresses to non-CAP_SYSLOG
[linux/fpc-iii.git] / samples / mic / mpssd / mpssd.c
bloba11bf6c5b53b4b21b910454c39bffd55e8829a61
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Intel MIC Platform Software Stack (MPSS)
5 * Copyright(c) 2013 Intel Corporation.
7 * Intel MIC User Space Tools.
8 */
10 #define _GNU_SOURCE
12 #include <stdlib.h>
13 #include <fcntl.h>
14 #include <getopt.h>
15 #include <assert.h>
16 #include <unistd.h>
17 #include <stdbool.h>
18 #include <signal.h>
19 #include <poll.h>
20 #include <features.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <sys/mman.h>
24 #include <sys/socket.h>
25 #include <linux/virtio_ring.h>
26 #include <linux/virtio_net.h>
27 #include <linux/virtio_console.h>
28 #include <linux/virtio_blk.h>
29 #include <linux/version.h>
30 #include "mpssd.h"
31 #include <linux/mic_ioctl.h>
32 #include <linux/mic_common.h>
33 #include <tools/endian.h>
35 static void *init_mic(void *arg);
37 static FILE *logfp;
38 static struct mic_info mic_list;
40 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
42 #define min_t(type, x, y) ({ \
43 type __min1 = (x); \
44 type __min2 = (y); \
45 __min1 < __min2 ? __min1 : __min2; })
47 /* align addr on a size boundary - adjust address up/down if needed */
48 #define _ALIGN_DOWN(addr, size) ((addr)&(~((size)-1)))
49 #define _ALIGN_UP(addr, size) _ALIGN_DOWN(addr + size - 1, size)
51 /* align addr on a size boundary - adjust address up if needed */
52 #define _ALIGN(addr, size) _ALIGN_UP(addr, size)
54 /* to align the pointer to the (next) page boundary */
55 #define PAGE_ALIGN(addr) _ALIGN(addr, PAGE_SIZE)
57 #define READ_ONCE(x) (*(volatile typeof(x) *)&(x))
59 #define GSO_ENABLED 1
60 #define MAX_GSO_SIZE (64 * 1024)
61 #define ETH_H_LEN 14
62 #define MAX_NET_PKT_SIZE (_ALIGN_UP(MAX_GSO_SIZE + ETH_H_LEN, 64))
63 #define MIC_DEVICE_PAGE_END 0x1000
65 #ifndef VIRTIO_NET_HDR_F_DATA_VALID
66 #define VIRTIO_NET_HDR_F_DATA_VALID 2 /* Csum is valid */
67 #endif
69 static struct {
70 struct mic_device_desc dd;
71 struct mic_vqconfig vqconfig[2];
72 __u32 host_features, guest_acknowledgements;
73 struct virtio_console_config cons_config;
74 } virtcons_dev_page = {
75 .dd = {
76 .type = VIRTIO_ID_CONSOLE,
77 .num_vq = ARRAY_SIZE(virtcons_dev_page.vqconfig),
78 .feature_len = sizeof(virtcons_dev_page.host_features),
79 .config_len = sizeof(virtcons_dev_page.cons_config),
81 .vqconfig[0] = {
82 .num = htole16(MIC_VRING_ENTRIES),
84 .vqconfig[1] = {
85 .num = htole16(MIC_VRING_ENTRIES),
89 static struct {
90 struct mic_device_desc dd;
91 struct mic_vqconfig vqconfig[2];
92 __u32 host_features, guest_acknowledgements;
93 struct virtio_net_config net_config;
94 } virtnet_dev_page = {
95 .dd = {
96 .type = VIRTIO_ID_NET,
97 .num_vq = ARRAY_SIZE(virtnet_dev_page.vqconfig),
98 .feature_len = sizeof(virtnet_dev_page.host_features),
99 .config_len = sizeof(virtnet_dev_page.net_config),
101 .vqconfig[0] = {
102 .num = htole16(MIC_VRING_ENTRIES),
104 .vqconfig[1] = {
105 .num = htole16(MIC_VRING_ENTRIES),
107 #if GSO_ENABLED
108 .host_features = htole32(
109 1 << VIRTIO_NET_F_CSUM |
110 1 << VIRTIO_NET_F_GSO |
111 1 << VIRTIO_NET_F_GUEST_TSO4 |
112 1 << VIRTIO_NET_F_GUEST_TSO6 |
113 1 << VIRTIO_NET_F_GUEST_ECN),
114 #else
115 .host_features = 0,
116 #endif
119 static const char *mic_config_dir = "/etc/mpss";
120 static const char *virtblk_backend = "VIRTBLK_BACKEND";
121 static struct {
122 struct mic_device_desc dd;
123 struct mic_vqconfig vqconfig[1];
124 __u32 host_features, guest_acknowledgements;
125 struct virtio_blk_config blk_config;
126 } virtblk_dev_page = {
127 .dd = {
128 .type = VIRTIO_ID_BLOCK,
129 .num_vq = ARRAY_SIZE(virtblk_dev_page.vqconfig),
130 .feature_len = sizeof(virtblk_dev_page.host_features),
131 .config_len = sizeof(virtblk_dev_page.blk_config),
133 .vqconfig[0] = {
134 .num = htole16(MIC_VRING_ENTRIES),
136 .host_features =
137 htole32(1<<VIRTIO_BLK_F_SEG_MAX),
138 .blk_config = {
139 .seg_max = htole32(MIC_VRING_ENTRIES - 2),
140 .capacity = htole64(0),
144 static char *myname;
146 static int
147 tap_configure(struct mic_info *mic, char *dev)
149 pid_t pid;
150 char *ifargv[7];
151 char ipaddr[IFNAMSIZ];
152 int ret = 0;
154 pid = fork();
155 if (pid == 0) {
156 ifargv[0] = "ip";
157 ifargv[1] = "link";
158 ifargv[2] = "set";
159 ifargv[3] = dev;
160 ifargv[4] = "up";
161 ifargv[5] = NULL;
162 mpsslog("Configuring %s\n", dev);
163 ret = execvp("ip", ifargv);
164 if (ret < 0) {
165 mpsslog("%s execvp failed errno %s\n",
166 mic->name, strerror(errno));
167 return ret;
170 if (pid < 0) {
171 mpsslog("%s fork failed errno %s\n",
172 mic->name, strerror(errno));
173 return ret;
176 ret = waitpid(pid, NULL, 0);
177 if (ret < 0) {
178 mpsslog("%s waitpid failed errno %s\n",
179 mic->name, strerror(errno));
180 return ret;
183 snprintf(ipaddr, IFNAMSIZ, "172.31.%d.254/24", mic->id + 1);
185 pid = fork();
186 if (pid == 0) {
187 ifargv[0] = "ip";
188 ifargv[1] = "addr";
189 ifargv[2] = "add";
190 ifargv[3] = ipaddr;
191 ifargv[4] = "dev";
192 ifargv[5] = dev;
193 ifargv[6] = NULL;
194 mpsslog("Configuring %s ipaddr %s\n", dev, ipaddr);
195 ret = execvp("ip", ifargv);
196 if (ret < 0) {
197 mpsslog("%s execvp failed errno %s\n",
198 mic->name, strerror(errno));
199 return ret;
202 if (pid < 0) {
203 mpsslog("%s fork failed errno %s\n",
204 mic->name, strerror(errno));
205 return ret;
208 ret = waitpid(pid, NULL, 0);
209 if (ret < 0) {
210 mpsslog("%s waitpid failed errno %s\n",
211 mic->name, strerror(errno));
212 return ret;
214 mpsslog("MIC name %s %s %d DONE!\n",
215 mic->name, __func__, __LINE__);
216 return 0;
219 static int tun_alloc(struct mic_info *mic, char *dev)
221 struct ifreq ifr;
222 int fd, err;
223 #if GSO_ENABLED
224 unsigned offload;
225 #endif
226 fd = open("/dev/net/tun", O_RDWR);
227 if (fd < 0) {
228 mpsslog("Could not open /dev/net/tun %s\n", strerror(errno));
229 goto done;
232 memset(&ifr, 0, sizeof(ifr));
234 ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_VNET_HDR;
235 if (*dev)
236 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
238 err = ioctl(fd, TUNSETIFF, (void *)&ifr);
239 if (err < 0) {
240 mpsslog("%s %s %d TUNSETIFF failed %s\n",
241 mic->name, __func__, __LINE__, strerror(errno));
242 close(fd);
243 return err;
245 #if GSO_ENABLED
246 offload = TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6 | TUN_F_TSO_ECN;
248 err = ioctl(fd, TUNSETOFFLOAD, offload);
249 if (err < 0) {
250 mpsslog("%s %s %d TUNSETOFFLOAD failed %s\n",
251 mic->name, __func__, __LINE__, strerror(errno));
252 close(fd);
253 return err;
255 #endif
256 strcpy(dev, ifr.ifr_name);
257 mpsslog("Created TAP %s\n", dev);
258 done:
259 return fd;
262 #define NET_FD_VIRTIO_NET 0
263 #define NET_FD_TUN 1
264 #define MAX_NET_FD 2
266 static void set_dp(struct mic_info *mic, int type, void *dp)
268 switch (type) {
269 case VIRTIO_ID_CONSOLE:
270 mic->mic_console.console_dp = dp;
271 return;
272 case VIRTIO_ID_NET:
273 mic->mic_net.net_dp = dp;
274 return;
275 case VIRTIO_ID_BLOCK:
276 mic->mic_virtblk.block_dp = dp;
277 return;
279 mpsslog("%s %s %d not found\n", mic->name, __func__, type);
280 assert(0);
283 static void *get_dp(struct mic_info *mic, int type)
285 switch (type) {
286 case VIRTIO_ID_CONSOLE:
287 return mic->mic_console.console_dp;
288 case VIRTIO_ID_NET:
289 return mic->mic_net.net_dp;
290 case VIRTIO_ID_BLOCK:
291 return mic->mic_virtblk.block_dp;
293 mpsslog("%s %s %d not found\n", mic->name, __func__, type);
294 assert(0);
295 return NULL;
298 static struct mic_device_desc *get_device_desc(struct mic_info *mic, int type)
300 struct mic_device_desc *d;
301 int i;
302 void *dp = get_dp(mic, type);
304 for (i = sizeof(struct mic_bootparam); i < PAGE_SIZE;
305 i += mic_total_desc_size(d)) {
306 d = dp + i;
308 /* End of list */
309 if (d->type == 0)
310 break;
312 if (d->type == -1)
313 continue;
315 mpsslog("%s %s d-> type %d d %p\n",
316 mic->name, __func__, d->type, d);
318 if (d->type == (__u8)type)
319 return d;
321 mpsslog("%s %s %d not found\n", mic->name, __func__, type);
322 return NULL;
325 /* See comments in vhost.c for explanation of next_desc() */
326 static unsigned next_desc(struct vring_desc *desc)
328 unsigned int next;
330 if (!(le16toh(desc->flags) & VRING_DESC_F_NEXT))
331 return -1U;
332 next = le16toh(desc->next);
333 return next;
336 /* Sum up all the IOVEC length */
337 static ssize_t
338 sum_iovec_len(struct mic_copy_desc *copy)
340 ssize_t sum = 0;
341 unsigned int i;
343 for (i = 0; i < copy->iovcnt; i++)
344 sum += copy->iov[i].iov_len;
345 return sum;
348 static inline void verify_out_len(struct mic_info *mic,
349 struct mic_copy_desc *copy)
351 if (copy->out_len != sum_iovec_len(copy)) {
352 mpsslog("%s %s %d BUG copy->out_len 0x%x len 0x%zx\n",
353 mic->name, __func__, __LINE__,
354 copy->out_len, sum_iovec_len(copy));
355 assert(copy->out_len == sum_iovec_len(copy));
359 /* Display an iovec */
360 static void
361 disp_iovec(struct mic_info *mic, struct mic_copy_desc *copy,
362 const char *s, int line)
364 unsigned int i;
366 for (i = 0; i < copy->iovcnt; i++)
367 mpsslog("%s %s %d copy->iov[%d] addr %p len 0x%zx\n",
368 mic->name, s, line, i,
369 copy->iov[i].iov_base, copy->iov[i].iov_len);
372 static inline __u16 read_avail_idx(struct mic_vring *vr)
374 return READ_ONCE(vr->info->avail_idx);
377 static inline void txrx_prepare(int type, bool tx, struct mic_vring *vr,
378 struct mic_copy_desc *copy, ssize_t len)
380 copy->vr_idx = tx ? 0 : 1;
381 copy->update_used = true;
382 if (type == VIRTIO_ID_NET)
383 copy->iov[1].iov_len = len - sizeof(struct virtio_net_hdr);
384 else
385 copy->iov[0].iov_len = len;
388 /* Central API which triggers the copies */
389 static int
390 mic_virtio_copy(struct mic_info *mic, int fd,
391 struct mic_vring *vr, struct mic_copy_desc *copy)
393 int ret;
395 ret = ioctl(fd, MIC_VIRTIO_COPY_DESC, copy);
396 if (ret) {
397 mpsslog("%s %s %d errno %s ret %d\n",
398 mic->name, __func__, __LINE__,
399 strerror(errno), ret);
401 return ret;
404 static inline unsigned _vring_size(unsigned int num, unsigned long align)
406 return ((sizeof(struct vring_desc) * num + sizeof(__u16) * (3 + num)
407 + align - 1) & ~(align - 1))
408 + sizeof(__u16) * 3 + sizeof(struct vring_used_elem) * num;
412 * This initialization routine requires at least one
413 * vring i.e. vr0. vr1 is optional.
415 static void *
416 init_vr(struct mic_info *mic, int fd, int type,
417 struct mic_vring *vr0, struct mic_vring *vr1, int num_vq)
419 int vr_size;
420 char *va;
422 vr_size = PAGE_ALIGN(_vring_size(MIC_VRING_ENTRIES,
423 MIC_VIRTIO_RING_ALIGN) +
424 sizeof(struct _mic_vring_info));
425 va = mmap(NULL, MIC_DEVICE_PAGE_END + vr_size * num_vq,
426 PROT_READ, MAP_SHARED, fd, 0);
427 if (MAP_FAILED == va) {
428 mpsslog("%s %s %d mmap failed errno %s\n",
429 mic->name, __func__, __LINE__,
430 strerror(errno));
431 goto done;
433 set_dp(mic, type, va);
434 vr0->va = (struct mic_vring *)&va[MIC_DEVICE_PAGE_END];
435 vr0->info = vr0->va +
436 _vring_size(MIC_VRING_ENTRIES, MIC_VIRTIO_RING_ALIGN);
437 vring_init(&vr0->vr,
438 MIC_VRING_ENTRIES, vr0->va, MIC_VIRTIO_RING_ALIGN);
439 mpsslog("%s %s vr0 %p vr0->info %p vr_size 0x%x vring 0x%x ",
440 __func__, mic->name, vr0->va, vr0->info, vr_size,
441 _vring_size(MIC_VRING_ENTRIES, MIC_VIRTIO_RING_ALIGN));
442 mpsslog("magic 0x%x expected 0x%x\n",
443 le32toh(vr0->info->magic), MIC_MAGIC + type);
444 assert(le32toh(vr0->info->magic) == MIC_MAGIC + type);
445 if (vr1) {
446 vr1->va = (struct mic_vring *)
447 &va[MIC_DEVICE_PAGE_END + vr_size];
448 vr1->info = vr1->va + _vring_size(MIC_VRING_ENTRIES,
449 MIC_VIRTIO_RING_ALIGN);
450 vring_init(&vr1->vr,
451 MIC_VRING_ENTRIES, vr1->va, MIC_VIRTIO_RING_ALIGN);
452 mpsslog("%s %s vr1 %p vr1->info %p vr_size 0x%x vring 0x%x ",
453 __func__, mic->name, vr1->va, vr1->info, vr_size,
454 _vring_size(MIC_VRING_ENTRIES, MIC_VIRTIO_RING_ALIGN));
455 mpsslog("magic 0x%x expected 0x%x\n",
456 le32toh(vr1->info->magic), MIC_MAGIC + type + 1);
457 assert(le32toh(vr1->info->magic) == MIC_MAGIC + type + 1);
459 done:
460 return va;
463 static int
464 wait_for_card_driver(struct mic_info *mic, int fd, int type)
466 struct pollfd pollfd;
467 int err;
468 struct mic_device_desc *desc = get_device_desc(mic, type);
469 __u8 prev_status;
471 if (!desc)
472 return -ENODEV;
473 prev_status = desc->status;
474 pollfd.fd = fd;
475 mpsslog("%s %s Waiting .... desc-> type %d status 0x%x\n",
476 mic->name, __func__, type, desc->status);
478 while (1) {
479 pollfd.events = POLLIN;
480 pollfd.revents = 0;
481 err = poll(&pollfd, 1, -1);
482 if (err < 0) {
483 mpsslog("%s %s poll failed %s\n",
484 mic->name, __func__, strerror(errno));
485 continue;
488 if (pollfd.revents) {
489 if (desc->status != prev_status) {
490 mpsslog("%s %s Waiting... desc-> type %d "
491 "status 0x%x\n",
492 mic->name, __func__, type,
493 desc->status);
494 prev_status = desc->status;
496 if (desc->status & VIRTIO_CONFIG_S_DRIVER_OK) {
497 mpsslog("%s %s poll.revents %d\n",
498 mic->name, __func__, pollfd.revents);
499 mpsslog("%s %s desc-> type %d status 0x%x\n",
500 mic->name, __func__, type,
501 desc->status);
502 break;
506 return 0;
509 /* Spin till we have some descriptors */
510 static void
511 spin_for_descriptors(struct mic_info *mic, struct mic_vring *vr)
513 __u16 avail_idx = read_avail_idx(vr);
515 while (avail_idx == le16toh(READ_ONCE(vr->vr.avail->idx))) {
516 #ifdef DEBUG
517 mpsslog("%s %s waiting for desc avail %d info_avail %d\n",
518 mic->name, __func__,
519 le16toh(vr->vr.avail->idx), vr->info->avail_idx);
520 #endif
521 sched_yield();
525 static void *
526 virtio_net(void *arg)
528 static __u8 vnet_hdr[2][sizeof(struct virtio_net_hdr)];
529 static __u8 vnet_buf[2][MAX_NET_PKT_SIZE] __attribute__ ((aligned(64)));
530 struct iovec vnet_iov[2][2] = {
531 { { .iov_base = vnet_hdr[0], .iov_len = sizeof(vnet_hdr[0]) },
532 { .iov_base = vnet_buf[0], .iov_len = sizeof(vnet_buf[0]) } },
533 { { .iov_base = vnet_hdr[1], .iov_len = sizeof(vnet_hdr[1]) },
534 { .iov_base = vnet_buf[1], .iov_len = sizeof(vnet_buf[1]) } },
536 struct iovec *iov0 = vnet_iov[0], *iov1 = vnet_iov[1];
537 struct mic_info *mic = (struct mic_info *)arg;
538 char if_name[IFNAMSIZ];
539 struct pollfd net_poll[MAX_NET_FD];
540 struct mic_vring tx_vr, rx_vr;
541 struct mic_copy_desc copy;
542 struct mic_device_desc *desc;
543 int err;
545 snprintf(if_name, IFNAMSIZ, "mic%d", mic->id);
546 mic->mic_net.tap_fd = tun_alloc(mic, if_name);
547 if (mic->mic_net.tap_fd < 0)
548 goto done;
550 if (tap_configure(mic, if_name))
551 goto done;
552 mpsslog("MIC name %s id %d\n", mic->name, mic->id);
554 net_poll[NET_FD_VIRTIO_NET].fd = mic->mic_net.virtio_net_fd;
555 net_poll[NET_FD_VIRTIO_NET].events = POLLIN;
556 net_poll[NET_FD_TUN].fd = mic->mic_net.tap_fd;
557 net_poll[NET_FD_TUN].events = POLLIN;
559 if (MAP_FAILED == init_vr(mic, mic->mic_net.virtio_net_fd,
560 VIRTIO_ID_NET, &tx_vr, &rx_vr,
561 virtnet_dev_page.dd.num_vq)) {
562 mpsslog("%s init_vr failed %s\n",
563 mic->name, strerror(errno));
564 goto done;
567 copy.iovcnt = 2;
568 desc = get_device_desc(mic, VIRTIO_ID_NET);
570 while (1) {
571 ssize_t len;
573 net_poll[NET_FD_VIRTIO_NET].revents = 0;
574 net_poll[NET_FD_TUN].revents = 0;
576 /* Start polling for data from tap and virtio net */
577 err = poll(net_poll, 2, -1);
578 if (err < 0) {
579 mpsslog("%s poll failed %s\n",
580 __func__, strerror(errno));
581 continue;
583 if (!(desc->status & VIRTIO_CONFIG_S_DRIVER_OK)) {
584 err = wait_for_card_driver(mic,
585 mic->mic_net.virtio_net_fd,
586 VIRTIO_ID_NET);
587 if (err) {
588 mpsslog("%s %s %d Exiting...\n",
589 mic->name, __func__, __LINE__);
590 break;
594 * Check if there is data to be read from TUN and write to
595 * virtio net fd if there is.
597 if (net_poll[NET_FD_TUN].revents & POLLIN) {
598 copy.iov = iov0;
599 len = readv(net_poll[NET_FD_TUN].fd,
600 copy.iov, copy.iovcnt);
601 if (len > 0) {
602 struct virtio_net_hdr *hdr
603 = (struct virtio_net_hdr *)vnet_hdr[0];
605 /* Disable checksums on the card since we are on
606 a reliable PCIe link */
607 hdr->flags |= VIRTIO_NET_HDR_F_DATA_VALID;
608 #ifdef DEBUG
609 mpsslog("%s %s %d hdr->flags 0x%x ", mic->name,
610 __func__, __LINE__, hdr->flags);
611 mpsslog("copy.out_len %d hdr->gso_type 0x%x\n",
612 copy.out_len, hdr->gso_type);
613 #endif
614 #ifdef DEBUG
615 disp_iovec(mic, copy, __func__, __LINE__);
616 mpsslog("%s %s %d read from tap 0x%lx\n",
617 mic->name, __func__, __LINE__,
618 len);
619 #endif
620 spin_for_descriptors(mic, &tx_vr);
621 txrx_prepare(VIRTIO_ID_NET, 1, &tx_vr, &copy,
622 len);
624 err = mic_virtio_copy(mic,
625 mic->mic_net.virtio_net_fd, &tx_vr,
626 &copy);
627 if (err < 0) {
628 mpsslog("%s %s %d mic_virtio_copy %s\n",
629 mic->name, __func__, __LINE__,
630 strerror(errno));
632 if (!err)
633 verify_out_len(mic, &copy);
634 #ifdef DEBUG
635 disp_iovec(mic, copy, __func__, __LINE__);
636 mpsslog("%s %s %d wrote to net 0x%lx\n",
637 mic->name, __func__, __LINE__,
638 sum_iovec_len(&copy));
639 #endif
640 /* Reinitialize IOV for next run */
641 iov0[1].iov_len = MAX_NET_PKT_SIZE;
642 } else if (len < 0) {
643 disp_iovec(mic, &copy, __func__, __LINE__);
644 mpsslog("%s %s %d read failed %s ", mic->name,
645 __func__, __LINE__, strerror(errno));
646 mpsslog("cnt %d sum %zd\n",
647 copy.iovcnt, sum_iovec_len(&copy));
652 * Check if there is data to be read from virtio net and
653 * write to TUN if there is.
655 if (net_poll[NET_FD_VIRTIO_NET].revents & POLLIN) {
656 while (rx_vr.info->avail_idx !=
657 le16toh(rx_vr.vr.avail->idx)) {
658 copy.iov = iov1;
659 txrx_prepare(VIRTIO_ID_NET, 0, &rx_vr, &copy,
660 MAX_NET_PKT_SIZE
661 + sizeof(struct virtio_net_hdr));
663 err = mic_virtio_copy(mic,
664 mic->mic_net.virtio_net_fd, &rx_vr,
665 &copy);
666 if (!err) {
667 #ifdef DEBUG
668 struct virtio_net_hdr *hdr
669 = (struct virtio_net_hdr *)
670 vnet_hdr[1];
672 mpsslog("%s %s %d hdr->flags 0x%x, ",
673 mic->name, __func__, __LINE__,
674 hdr->flags);
675 mpsslog("out_len %d gso_type 0x%x\n",
676 copy.out_len,
677 hdr->gso_type);
678 #endif
679 /* Set the correct output iov_len */
680 iov1[1].iov_len = copy.out_len -
681 sizeof(struct virtio_net_hdr);
682 verify_out_len(mic, &copy);
683 #ifdef DEBUG
684 disp_iovec(mic, copy, __func__,
685 __LINE__);
686 mpsslog("%s %s %d ",
687 mic->name, __func__, __LINE__);
688 mpsslog("read from net 0x%lx\n",
689 sum_iovec_len(copy));
690 #endif
691 len = writev(net_poll[NET_FD_TUN].fd,
692 copy.iov, copy.iovcnt);
693 if (len != sum_iovec_len(&copy)) {
694 mpsslog("Tun write failed %s ",
695 strerror(errno));
696 mpsslog("len 0x%zx ", len);
697 mpsslog("read_len 0x%zx\n",
698 sum_iovec_len(&copy));
699 } else {
700 #ifdef DEBUG
701 disp_iovec(mic, &copy, __func__,
702 __LINE__);
703 mpsslog("%s %s %d ",
704 mic->name, __func__,
705 __LINE__);
706 mpsslog("wrote to tap 0x%lx\n",
707 len);
708 #endif
710 } else {
711 mpsslog("%s %s %d mic_virtio_copy %s\n",
712 mic->name, __func__, __LINE__,
713 strerror(errno));
714 break;
718 if (net_poll[NET_FD_VIRTIO_NET].revents & POLLERR)
719 mpsslog("%s: %s: POLLERR\n", __func__, mic->name);
721 done:
722 pthread_exit(NULL);
725 /* virtio_console */
726 #define VIRTIO_CONSOLE_FD 0
727 #define MONITOR_FD (VIRTIO_CONSOLE_FD + 1)
728 #define MAX_CONSOLE_FD (MONITOR_FD + 1) /* must be the last one + 1 */
729 #define MAX_BUFFER_SIZE PAGE_SIZE
731 static void *
732 virtio_console(void *arg)
734 static __u8 vcons_buf[2][PAGE_SIZE];
735 struct iovec vcons_iov[2] = {
736 { .iov_base = vcons_buf[0], .iov_len = sizeof(vcons_buf[0]) },
737 { .iov_base = vcons_buf[1], .iov_len = sizeof(vcons_buf[1]) },
739 struct iovec *iov0 = &vcons_iov[0], *iov1 = &vcons_iov[1];
740 struct mic_info *mic = (struct mic_info *)arg;
741 int err;
742 struct pollfd console_poll[MAX_CONSOLE_FD];
743 int pty_fd;
744 char *pts_name;
745 ssize_t len;
746 struct mic_vring tx_vr, rx_vr;
747 struct mic_copy_desc copy;
748 struct mic_device_desc *desc;
750 pty_fd = posix_openpt(O_RDWR);
751 if (pty_fd < 0) {
752 mpsslog("can't open a pseudoterminal master device: %s\n",
753 strerror(errno));
754 goto _return;
756 pts_name = ptsname(pty_fd);
757 if (pts_name == NULL) {
758 mpsslog("can't get pts name\n");
759 goto _close_pty;
761 printf("%s console message goes to %s\n", mic->name, pts_name);
762 mpsslog("%s console message goes to %s\n", mic->name, pts_name);
763 err = grantpt(pty_fd);
764 if (err < 0) {
765 mpsslog("can't grant access: %s %s\n",
766 pts_name, strerror(errno));
767 goto _close_pty;
769 err = unlockpt(pty_fd);
770 if (err < 0) {
771 mpsslog("can't unlock a pseudoterminal: %s %s\n",
772 pts_name, strerror(errno));
773 goto _close_pty;
775 console_poll[MONITOR_FD].fd = pty_fd;
776 console_poll[MONITOR_FD].events = POLLIN;
778 console_poll[VIRTIO_CONSOLE_FD].fd = mic->mic_console.virtio_console_fd;
779 console_poll[VIRTIO_CONSOLE_FD].events = POLLIN;
781 if (MAP_FAILED == init_vr(mic, mic->mic_console.virtio_console_fd,
782 VIRTIO_ID_CONSOLE, &tx_vr, &rx_vr,
783 virtcons_dev_page.dd.num_vq)) {
784 mpsslog("%s init_vr failed %s\n",
785 mic->name, strerror(errno));
786 goto _close_pty;
789 copy.iovcnt = 1;
790 desc = get_device_desc(mic, VIRTIO_ID_CONSOLE);
792 for (;;) {
793 console_poll[MONITOR_FD].revents = 0;
794 console_poll[VIRTIO_CONSOLE_FD].revents = 0;
795 err = poll(console_poll, MAX_CONSOLE_FD, -1);
796 if (err < 0) {
797 mpsslog("%s %d: poll failed: %s\n", __func__, __LINE__,
798 strerror(errno));
799 continue;
801 if (!(desc->status & VIRTIO_CONFIG_S_DRIVER_OK)) {
802 err = wait_for_card_driver(mic,
803 mic->mic_console.virtio_console_fd,
804 VIRTIO_ID_CONSOLE);
805 if (err) {
806 mpsslog("%s %s %d Exiting...\n",
807 mic->name, __func__, __LINE__);
808 break;
812 if (console_poll[MONITOR_FD].revents & POLLIN) {
813 copy.iov = iov0;
814 len = readv(pty_fd, copy.iov, copy.iovcnt);
815 if (len > 0) {
816 #ifdef DEBUG
817 disp_iovec(mic, copy, __func__, __LINE__);
818 mpsslog("%s %s %d read from tap 0x%lx\n",
819 mic->name, __func__, __LINE__,
820 len);
821 #endif
822 spin_for_descriptors(mic, &tx_vr);
823 txrx_prepare(VIRTIO_ID_CONSOLE, 1, &tx_vr,
824 &copy, len);
826 err = mic_virtio_copy(mic,
827 mic->mic_console.virtio_console_fd,
828 &tx_vr, &copy);
829 if (err < 0) {
830 mpsslog("%s %s %d mic_virtio_copy %s\n",
831 mic->name, __func__, __LINE__,
832 strerror(errno));
834 if (!err)
835 verify_out_len(mic, &copy);
836 #ifdef DEBUG
837 disp_iovec(mic, copy, __func__, __LINE__);
838 mpsslog("%s %s %d wrote to net 0x%lx\n",
839 mic->name, __func__, __LINE__,
840 sum_iovec_len(copy));
841 #endif
842 /* Reinitialize IOV for next run */
843 iov0->iov_len = PAGE_SIZE;
844 } else if (len < 0) {
845 disp_iovec(mic, &copy, __func__, __LINE__);
846 mpsslog("%s %s %d read failed %s ",
847 mic->name, __func__, __LINE__,
848 strerror(errno));
849 mpsslog("cnt %d sum %zd\n",
850 copy.iovcnt, sum_iovec_len(&copy));
854 if (console_poll[VIRTIO_CONSOLE_FD].revents & POLLIN) {
855 while (rx_vr.info->avail_idx !=
856 le16toh(rx_vr.vr.avail->idx)) {
857 copy.iov = iov1;
858 txrx_prepare(VIRTIO_ID_CONSOLE, 0, &rx_vr,
859 &copy, PAGE_SIZE);
861 err = mic_virtio_copy(mic,
862 mic->mic_console.virtio_console_fd,
863 &rx_vr, &copy);
864 if (!err) {
865 /* Set the correct output iov_len */
866 iov1->iov_len = copy.out_len;
867 verify_out_len(mic, &copy);
868 #ifdef DEBUG
869 disp_iovec(mic, copy, __func__,
870 __LINE__);
871 mpsslog("%s %s %d ",
872 mic->name, __func__, __LINE__);
873 mpsslog("read from net 0x%lx\n",
874 sum_iovec_len(copy));
875 #endif
876 len = writev(pty_fd,
877 copy.iov, copy.iovcnt);
878 if (len != sum_iovec_len(&copy)) {
879 mpsslog("Tun write failed %s ",
880 strerror(errno));
881 mpsslog("len 0x%zx ", len);
882 mpsslog("read_len 0x%zx\n",
883 sum_iovec_len(&copy));
884 } else {
885 #ifdef DEBUG
886 disp_iovec(mic, copy, __func__,
887 __LINE__);
888 mpsslog("%s %s %d ",
889 mic->name, __func__,
890 __LINE__);
891 mpsslog("wrote to tap 0x%lx\n",
892 len);
893 #endif
895 } else {
896 mpsslog("%s %s %d mic_virtio_copy %s\n",
897 mic->name, __func__, __LINE__,
898 strerror(errno));
899 break;
903 if (console_poll[NET_FD_VIRTIO_NET].revents & POLLERR)
904 mpsslog("%s: %s: POLLERR\n", __func__, mic->name);
906 _close_pty:
907 close(pty_fd);
908 _return:
909 pthread_exit(NULL);
912 static void
913 add_virtio_device(struct mic_info *mic, struct mic_device_desc *dd)
915 char path[PATH_MAX];
916 int fd, err;
918 snprintf(path, PATH_MAX, "/dev/vop_virtio%d", mic->id);
919 fd = open(path, O_RDWR);
920 if (fd < 0) {
921 mpsslog("Could not open %s %s\n", path, strerror(errno));
922 return;
925 err = ioctl(fd, MIC_VIRTIO_ADD_DEVICE, dd);
926 if (err < 0) {
927 mpsslog("Could not add %d %s\n", dd->type, strerror(errno));
928 close(fd);
929 return;
931 switch (dd->type) {
932 case VIRTIO_ID_NET:
933 mic->mic_net.virtio_net_fd = fd;
934 mpsslog("Added VIRTIO_ID_NET for %s\n", mic->name);
935 break;
936 case VIRTIO_ID_CONSOLE:
937 mic->mic_console.virtio_console_fd = fd;
938 mpsslog("Added VIRTIO_ID_CONSOLE for %s\n", mic->name);
939 break;
940 case VIRTIO_ID_BLOCK:
941 mic->mic_virtblk.virtio_block_fd = fd;
942 mpsslog("Added VIRTIO_ID_BLOCK for %s\n", mic->name);
943 break;
947 static bool
948 set_backend_file(struct mic_info *mic)
950 FILE *config;
951 char buff[PATH_MAX], *line, *evv, *p;
953 snprintf(buff, PATH_MAX, "%s/mpssd%03d.conf", mic_config_dir, mic->id);
954 config = fopen(buff, "r");
955 if (config == NULL)
956 return false;
957 do { /* look for "virtblk_backend=XXXX" */
958 line = fgets(buff, PATH_MAX, config);
959 if (line == NULL)
960 break;
961 if (*line == '#')
962 continue;
963 p = strchr(line, '\n');
964 if (p)
965 *p = '\0';
966 } while (strncmp(line, virtblk_backend, strlen(virtblk_backend)) != 0);
967 fclose(config);
968 if (line == NULL)
969 return false;
970 evv = strchr(line, '=');
971 if (evv == NULL)
972 return false;
973 mic->mic_virtblk.backend_file = malloc(strlen(evv) + 1);
974 if (mic->mic_virtblk.backend_file == NULL) {
975 mpsslog("%s %d can't allocate memory\n", mic->name, mic->id);
976 return false;
978 strcpy(mic->mic_virtblk.backend_file, evv + 1);
979 return true;
982 #define SECTOR_SIZE 512
983 static bool
984 set_backend_size(struct mic_info *mic)
986 mic->mic_virtblk.backend_size = lseek(mic->mic_virtblk.backend, 0,
987 SEEK_END);
988 if (mic->mic_virtblk.backend_size < 0) {
989 mpsslog("%s: can't seek: %s\n",
990 mic->name, mic->mic_virtblk.backend_file);
991 return false;
993 virtblk_dev_page.blk_config.capacity =
994 mic->mic_virtblk.backend_size / SECTOR_SIZE;
995 if ((mic->mic_virtblk.backend_size % SECTOR_SIZE) != 0)
996 virtblk_dev_page.blk_config.capacity++;
998 virtblk_dev_page.blk_config.capacity =
999 htole64(virtblk_dev_page.blk_config.capacity);
1001 return true;
1004 static bool
1005 open_backend(struct mic_info *mic)
1007 if (!set_backend_file(mic))
1008 goto _error_exit;
1009 mic->mic_virtblk.backend = open(mic->mic_virtblk.backend_file, O_RDWR);
1010 if (mic->mic_virtblk.backend < 0) {
1011 mpsslog("%s: can't open: %s\n", mic->name,
1012 mic->mic_virtblk.backend_file);
1013 goto _error_free;
1015 if (!set_backend_size(mic))
1016 goto _error_close;
1017 mic->mic_virtblk.backend_addr = mmap(NULL,
1018 mic->mic_virtblk.backend_size,
1019 PROT_READ|PROT_WRITE, MAP_SHARED,
1020 mic->mic_virtblk.backend, 0L);
1021 if (mic->mic_virtblk.backend_addr == MAP_FAILED) {
1022 mpsslog("%s: can't map: %s %s\n",
1023 mic->name, mic->mic_virtblk.backend_file,
1024 strerror(errno));
1025 goto _error_close;
1027 return true;
1029 _error_close:
1030 close(mic->mic_virtblk.backend);
1031 _error_free:
1032 free(mic->mic_virtblk.backend_file);
1033 _error_exit:
1034 return false;
1037 static void
1038 close_backend(struct mic_info *mic)
1040 munmap(mic->mic_virtblk.backend_addr, mic->mic_virtblk.backend_size);
1041 close(mic->mic_virtblk.backend);
1042 free(mic->mic_virtblk.backend_file);
1045 static bool
1046 start_virtblk(struct mic_info *mic, struct mic_vring *vring)
1048 if (((unsigned long)&virtblk_dev_page.blk_config % 8) != 0) {
1049 mpsslog("%s: blk_config is not 8 byte aligned.\n",
1050 mic->name);
1051 return false;
1053 add_virtio_device(mic, &virtblk_dev_page.dd);
1054 if (MAP_FAILED == init_vr(mic, mic->mic_virtblk.virtio_block_fd,
1055 VIRTIO_ID_BLOCK, vring, NULL,
1056 virtblk_dev_page.dd.num_vq)) {
1057 mpsslog("%s init_vr failed %s\n",
1058 mic->name, strerror(errno));
1059 return false;
1061 return true;
1064 static void
1065 stop_virtblk(struct mic_info *mic)
1067 int vr_size, ret;
1069 vr_size = PAGE_ALIGN(_vring_size(MIC_VRING_ENTRIES,
1070 MIC_VIRTIO_RING_ALIGN) +
1071 sizeof(struct _mic_vring_info));
1072 ret = munmap(mic->mic_virtblk.block_dp,
1073 MIC_DEVICE_PAGE_END + vr_size * virtblk_dev_page.dd.num_vq);
1074 if (ret < 0)
1075 mpsslog("%s munmap errno %d\n", mic->name, errno);
1076 close(mic->mic_virtblk.virtio_block_fd);
1079 static __u8
1080 header_error_check(struct vring_desc *desc)
1082 if (le32toh(desc->len) != sizeof(struct virtio_blk_outhdr)) {
1083 mpsslog("%s() %d: length is not sizeof(virtio_blk_outhd)\n",
1084 __func__, __LINE__);
1085 return -EIO;
1087 if (!(le16toh(desc->flags) & VRING_DESC_F_NEXT)) {
1088 mpsslog("%s() %d: alone\n",
1089 __func__, __LINE__);
1090 return -EIO;
1092 if (le16toh(desc->flags) & VRING_DESC_F_WRITE) {
1093 mpsslog("%s() %d: not read\n",
1094 __func__, __LINE__);
1095 return -EIO;
1097 return 0;
1100 static int
1101 read_header(int fd, struct virtio_blk_outhdr *hdr, __u32 desc_idx)
1103 struct iovec iovec;
1104 struct mic_copy_desc copy;
1106 iovec.iov_len = sizeof(*hdr);
1107 iovec.iov_base = hdr;
1108 copy.iov = &iovec;
1109 copy.iovcnt = 1;
1110 copy.vr_idx = 0; /* only one vring on virtio_block */
1111 copy.update_used = false; /* do not update used index */
1112 return ioctl(fd, MIC_VIRTIO_COPY_DESC, &copy);
1115 static int
1116 transfer_blocks(int fd, struct iovec *iovec, __u32 iovcnt)
1118 struct mic_copy_desc copy;
1120 copy.iov = iovec;
1121 copy.iovcnt = iovcnt;
1122 copy.vr_idx = 0; /* only one vring on virtio_block */
1123 copy.update_used = false; /* do not update used index */
1124 return ioctl(fd, MIC_VIRTIO_COPY_DESC, &copy);
1127 static __u8
1128 status_error_check(struct vring_desc *desc)
1130 if (le32toh(desc->len) != sizeof(__u8)) {
1131 mpsslog("%s() %d: length is not sizeof(status)\n",
1132 __func__, __LINE__);
1133 return -EIO;
1135 return 0;
1138 static int
1139 write_status(int fd, __u8 *status)
1141 struct iovec iovec;
1142 struct mic_copy_desc copy;
1144 iovec.iov_base = status;
1145 iovec.iov_len = sizeof(*status);
1146 copy.iov = &iovec;
1147 copy.iovcnt = 1;
1148 copy.vr_idx = 0; /* only one vring on virtio_block */
1149 copy.update_used = true; /* Update used index */
1150 return ioctl(fd, MIC_VIRTIO_COPY_DESC, &copy);
1153 #ifndef VIRTIO_BLK_T_GET_ID
1154 #define VIRTIO_BLK_T_GET_ID 8
1155 #endif
1157 static void *
1158 virtio_block(void *arg)
1160 struct mic_info *mic = (struct mic_info *)arg;
1161 int ret;
1162 struct pollfd block_poll;
1163 struct mic_vring vring;
1164 __u16 avail_idx;
1165 __u32 desc_idx;
1166 struct vring_desc *desc;
1167 struct iovec *iovec, *piov;
1168 __u8 status;
1169 __u32 buffer_desc_idx;
1170 struct virtio_blk_outhdr hdr;
1171 void *fos;
1173 for (;;) { /* forever */
1174 if (!open_backend(mic)) { /* No virtblk */
1175 for (mic->mic_virtblk.signaled = 0;
1176 !mic->mic_virtblk.signaled;)
1177 sleep(1);
1178 continue;
1181 /* backend file is specified. */
1182 if (!start_virtblk(mic, &vring))
1183 goto _close_backend;
1184 iovec = malloc(sizeof(*iovec) *
1185 le32toh(virtblk_dev_page.blk_config.seg_max));
1186 if (!iovec) {
1187 mpsslog("%s: can't alloc iovec: %s\n",
1188 mic->name, strerror(ENOMEM));
1189 goto _stop_virtblk;
1192 block_poll.fd = mic->mic_virtblk.virtio_block_fd;
1193 block_poll.events = POLLIN;
1194 for (mic->mic_virtblk.signaled = 0;
1195 !mic->mic_virtblk.signaled;) {
1196 block_poll.revents = 0;
1197 /* timeout in 1 sec to see signaled */
1198 ret = poll(&block_poll, 1, 1000);
1199 if (ret < 0) {
1200 mpsslog("%s %d: poll failed: %s\n",
1201 __func__, __LINE__,
1202 strerror(errno));
1203 continue;
1206 if (!(block_poll.revents & POLLIN)) {
1207 #ifdef DEBUG
1208 mpsslog("%s %d: block_poll.revents=0x%x\n",
1209 __func__, __LINE__, block_poll.revents);
1210 #endif
1211 continue;
1214 /* POLLIN */
1215 while (vring.info->avail_idx !=
1216 le16toh(vring.vr.avail->idx)) {
1217 /* read header element */
1218 avail_idx =
1219 vring.info->avail_idx &
1220 (vring.vr.num - 1);
1221 desc_idx = le16toh(
1222 vring.vr.avail->ring[avail_idx]);
1223 desc = &vring.vr.desc[desc_idx];
1224 #ifdef DEBUG
1225 mpsslog("%s() %d: avail_idx=%d ",
1226 __func__, __LINE__,
1227 vring.info->avail_idx);
1228 mpsslog("vring.vr.num=%d desc=%p\n",
1229 vring.vr.num, desc);
1230 #endif
1231 status = header_error_check(desc);
1232 ret = read_header(
1233 mic->mic_virtblk.virtio_block_fd,
1234 &hdr, desc_idx);
1235 if (ret < 0) {
1236 mpsslog("%s() %d %s: ret=%d %s\n",
1237 __func__, __LINE__,
1238 mic->name, ret,
1239 strerror(errno));
1240 break;
1242 /* buffer element */
1243 piov = iovec;
1244 status = 0;
1245 fos = mic->mic_virtblk.backend_addr +
1246 (hdr.sector * SECTOR_SIZE);
1247 buffer_desc_idx = next_desc(desc);
1248 desc_idx = buffer_desc_idx;
1249 for (desc = &vring.vr.desc[buffer_desc_idx];
1250 desc->flags & VRING_DESC_F_NEXT;
1251 desc_idx = next_desc(desc),
1252 desc = &vring.vr.desc[desc_idx]) {
1253 piov->iov_len = desc->len;
1254 piov->iov_base = fos;
1255 piov++;
1256 fos += desc->len;
1258 /* Returning NULLs for VIRTIO_BLK_T_GET_ID. */
1259 if (hdr.type & ~(VIRTIO_BLK_T_OUT |
1260 VIRTIO_BLK_T_GET_ID)) {
1262 VIRTIO_BLK_T_IN - does not do
1263 anything. Probably for documenting.
1264 VIRTIO_BLK_T_SCSI_CMD - for
1265 virtio_scsi.
1266 VIRTIO_BLK_T_FLUSH - turned off in
1267 config space.
1268 VIRTIO_BLK_T_BARRIER - defined but not
1269 used in anywhere.
1271 mpsslog("%s() %d: type %x ",
1272 __func__, __LINE__,
1273 hdr.type);
1274 mpsslog("is not supported\n");
1275 status = -ENOTSUP;
1277 } else {
1278 ret = transfer_blocks(
1279 mic->mic_virtblk.virtio_block_fd,
1280 iovec,
1281 piov - iovec);
1282 if (ret < 0 &&
1283 status != 0)
1284 status = ret;
1286 /* write status and update used pointer */
1287 if (status != 0)
1288 status = status_error_check(desc);
1289 ret = write_status(
1290 mic->mic_virtblk.virtio_block_fd,
1291 &status);
1292 #ifdef DEBUG
1293 mpsslog("%s() %d: write status=%d on desc=%p\n",
1294 __func__, __LINE__,
1295 status, desc);
1296 #endif
1299 free(iovec);
1300 _stop_virtblk:
1301 stop_virtblk(mic);
1302 _close_backend:
1303 close_backend(mic);
1304 } /* forever */
1306 pthread_exit(NULL);
1309 static void
1310 reset(struct mic_info *mic)
1312 #define RESET_TIMEOUT 120
1313 int i = RESET_TIMEOUT;
1314 setsysfs(mic->name, "state", "reset");
1315 while (i) {
1316 char *state;
1317 state = readsysfs(mic->name, "state");
1318 if (!state)
1319 goto retry;
1320 mpsslog("%s: %s %d state %s\n",
1321 mic->name, __func__, __LINE__, state);
1323 if (!strcmp(state, "ready")) {
1324 free(state);
1325 break;
1327 free(state);
1328 retry:
1329 sleep(1);
1330 i--;
1334 static int
1335 get_mic_shutdown_status(struct mic_info *mic, char *shutdown_status)
1337 if (!strcmp(shutdown_status, "nop"))
1338 return MIC_NOP;
1339 if (!strcmp(shutdown_status, "crashed"))
1340 return MIC_CRASHED;
1341 if (!strcmp(shutdown_status, "halted"))
1342 return MIC_HALTED;
1343 if (!strcmp(shutdown_status, "poweroff"))
1344 return MIC_POWER_OFF;
1345 if (!strcmp(shutdown_status, "restart"))
1346 return MIC_RESTART;
1347 mpsslog("%s: BUG invalid status %s\n", mic->name, shutdown_status);
1348 /* Invalid state */
1349 assert(0);
1352 static int get_mic_state(struct mic_info *mic)
1354 char *state = NULL;
1355 enum mic_states mic_state;
1357 while (!state) {
1358 state = readsysfs(mic->name, "state");
1359 sleep(1);
1361 mpsslog("%s: %s %d state %s\n",
1362 mic->name, __func__, __LINE__, state);
1364 if (!strcmp(state, "ready")) {
1365 mic_state = MIC_READY;
1366 } else if (!strcmp(state, "booting")) {
1367 mic_state = MIC_BOOTING;
1368 } else if (!strcmp(state, "online")) {
1369 mic_state = MIC_ONLINE;
1370 } else if (!strcmp(state, "shutting_down")) {
1371 mic_state = MIC_SHUTTING_DOWN;
1372 } else if (!strcmp(state, "reset_failed")) {
1373 mic_state = MIC_RESET_FAILED;
1374 } else if (!strcmp(state, "resetting")) {
1375 mic_state = MIC_RESETTING;
1376 } else {
1377 mpsslog("%s: BUG invalid state %s\n", mic->name, state);
1378 assert(0);
1381 free(state);
1382 return mic_state;
1385 static void mic_handle_shutdown(struct mic_info *mic)
1387 #define SHUTDOWN_TIMEOUT 60
1388 int i = SHUTDOWN_TIMEOUT;
1389 char *shutdown_status;
1390 while (i) {
1391 shutdown_status = readsysfs(mic->name, "shutdown_status");
1392 if (!shutdown_status) {
1393 sleep(1);
1394 continue;
1396 mpsslog("%s: %s %d shutdown_status %s\n",
1397 mic->name, __func__, __LINE__, shutdown_status);
1398 switch (get_mic_shutdown_status(mic, shutdown_status)) {
1399 case MIC_RESTART:
1400 mic->restart = 1;
1401 case MIC_HALTED:
1402 case MIC_POWER_OFF:
1403 case MIC_CRASHED:
1404 free(shutdown_status);
1405 goto reset;
1406 default:
1407 break;
1409 free(shutdown_status);
1410 sleep(1);
1411 i--;
1413 reset:
1414 if (!i)
1415 mpsslog("%s: %s %d timing out waiting for shutdown_status %s\n",
1416 mic->name, __func__, __LINE__, shutdown_status);
1417 reset(mic);
1420 static int open_state_fd(struct mic_info *mic)
1422 char pathname[PATH_MAX];
1423 int fd;
1425 snprintf(pathname, PATH_MAX - 1, "%s/%s/%s",
1426 MICSYSFSDIR, mic->name, "state");
1428 fd = open(pathname, O_RDONLY);
1429 if (fd < 0)
1430 mpsslog("%s: opening file %s failed %s\n",
1431 mic->name, pathname, strerror(errno));
1432 return fd;
1435 static int block_till_state_change(int fd, struct mic_info *mic)
1437 struct pollfd ufds[1];
1438 char value[PAGE_SIZE];
1439 int ret;
1441 ufds[0].fd = fd;
1442 ufds[0].events = POLLERR | POLLPRI;
1443 ret = poll(ufds, 1, -1);
1444 if (ret < 0) {
1445 mpsslog("%s: %s %d poll failed %s\n",
1446 mic->name, __func__, __LINE__, strerror(errno));
1447 return ret;
1450 ret = lseek(fd, 0, SEEK_SET);
1451 if (ret < 0) {
1452 mpsslog("%s: %s %d Failed to seek to 0: %s\n",
1453 mic->name, __func__, __LINE__, strerror(errno));
1454 return ret;
1457 ret = read(fd, value, sizeof(value));
1458 if (ret < 0) {
1459 mpsslog("%s: %s %d Failed to read sysfs entry: %s\n",
1460 mic->name, __func__, __LINE__, strerror(errno));
1461 return ret;
1464 return 0;
1467 static void *
1468 mic_config(void *arg)
1470 struct mic_info *mic = (struct mic_info *)arg;
1471 int fd, ret, stat = 0;
1473 fd = open_state_fd(mic);
1474 if (fd < 0) {
1475 mpsslog("%s: %s %d open state fd failed %s\n",
1476 mic->name, __func__, __LINE__, strerror(errno));
1477 goto exit;
1480 do {
1481 ret = block_till_state_change(fd, mic);
1482 if (ret < 0) {
1483 mpsslog("%s: %s %d block_till_state_change error %s\n",
1484 mic->name, __func__, __LINE__, strerror(errno));
1485 goto close_exit;
1488 switch (get_mic_state(mic)) {
1489 case MIC_SHUTTING_DOWN:
1490 mic_handle_shutdown(mic);
1491 break;
1492 case MIC_READY:
1493 case MIC_RESET_FAILED:
1494 ret = kill(mic->pid, SIGTERM);
1495 mpsslog("%s: %s %d kill pid %d ret %d\n",
1496 mic->name, __func__, __LINE__,
1497 mic->pid, ret);
1498 if (!ret) {
1499 ret = waitpid(mic->pid, &stat,
1500 WIFSIGNALED(stat));
1501 mpsslog("%s: %s %d waitpid ret %d pid %d\n",
1502 mic->name, __func__, __LINE__,
1503 ret, mic->pid);
1505 if (mic->boot_on_resume) {
1506 setsysfs(mic->name, "state", "boot");
1507 mic->boot_on_resume = 0;
1509 goto close_exit;
1510 default:
1511 break;
1513 } while (1);
1515 close_exit:
1516 close(fd);
1517 exit:
1518 init_mic(mic);
1519 pthread_exit(NULL);
1522 static void
1523 set_cmdline(struct mic_info *mic)
1525 char buffer[PATH_MAX];
1526 int len;
1528 len = snprintf(buffer, PATH_MAX,
1529 "clocksource=tsc highres=off nohz=off ");
1530 len += snprintf(buffer + len, PATH_MAX - len,
1531 "cpufreq_on;corec6_off;pc3_off;pc6_off ");
1532 len += snprintf(buffer + len, PATH_MAX - len,
1533 "ifcfg=static;address,172.31.%d.1;netmask,255.255.255.0",
1534 mic->id + 1);
1536 setsysfs(mic->name, "cmdline", buffer);
1537 mpsslog("%s: Command line: \"%s\"\n", mic->name, buffer);
1538 snprintf(buffer, PATH_MAX, "172.31.%d.1", mic->id + 1);
1539 mpsslog("%s: IPADDR: \"%s\"\n", mic->name, buffer);
1542 static void
1543 set_log_buf_info(struct mic_info *mic)
1545 int fd;
1546 off_t len;
1547 char system_map[] = "/lib/firmware/mic/System.map";
1548 char *map, *temp, log_buf[17] = {'\0'};
1550 fd = open(system_map, O_RDONLY);
1551 if (fd < 0) {
1552 mpsslog("%s: Opening System.map failed: %d\n",
1553 mic->name, errno);
1554 return;
1556 len = lseek(fd, 0, SEEK_END);
1557 if (len < 0) {
1558 mpsslog("%s: Reading System.map size failed: %d\n",
1559 mic->name, errno);
1560 close(fd);
1561 return;
1563 map = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);
1564 if (map == MAP_FAILED) {
1565 mpsslog("%s: mmap of System.map failed: %d\n",
1566 mic->name, errno);
1567 close(fd);
1568 return;
1570 temp = strstr(map, "__log_buf");
1571 if (!temp) {
1572 mpsslog("%s: __log_buf not found: %d\n", mic->name, errno);
1573 munmap(map, len);
1574 close(fd);
1575 return;
1577 strncpy(log_buf, temp - 19, 16);
1578 setsysfs(mic->name, "log_buf_addr", log_buf);
1579 mpsslog("%s: log_buf_addr: %s\n", mic->name, log_buf);
1580 temp = strstr(map, "log_buf_len");
1581 if (!temp) {
1582 mpsslog("%s: log_buf_len not found: %d\n", mic->name, errno);
1583 munmap(map, len);
1584 close(fd);
1585 return;
1587 strncpy(log_buf, temp - 19, 16);
1588 setsysfs(mic->name, "log_buf_len", log_buf);
1589 mpsslog("%s: log_buf_len: %s\n", mic->name, log_buf);
1590 munmap(map, len);
1591 close(fd);
1594 static void
1595 change_virtblk_backend(int x, siginfo_t *siginfo, void *p)
1597 struct mic_info *mic;
1599 for (mic = mic_list.next; mic != NULL; mic = mic->next)
1600 mic->mic_virtblk.signaled = 1/* true */;
1603 static void
1604 set_mic_boot_params(struct mic_info *mic)
1606 set_log_buf_info(mic);
1607 set_cmdline(mic);
1610 static void *
1611 init_mic(void *arg)
1613 struct mic_info *mic = (struct mic_info *)arg;
1614 struct sigaction ignore = {
1615 .sa_flags = 0,
1616 .sa_handler = SIG_IGN
1618 struct sigaction act = {
1619 .sa_flags = SA_SIGINFO,
1620 .sa_sigaction = change_virtblk_backend,
1622 char buffer[PATH_MAX];
1623 int err, fd;
1626 * Currently, one virtio block device is supported for each MIC card
1627 * at a time. Any user (or test) can send a SIGUSR1 to the MIC daemon.
1628 * The signal informs the virtio block backend about a change in the
1629 * configuration file which specifies the virtio backend file name on
1630 * the host. Virtio block backend then re-reads the configuration file
1631 * and switches to the new block device. This signalling mechanism may
1632 * not be required once multiple virtio block devices are supported by
1633 * the MIC daemon.
1635 sigaction(SIGUSR1, &ignore, NULL);
1636 retry:
1637 fd = open_state_fd(mic);
1638 if (fd < 0) {
1639 mpsslog("%s: %s %d open state fd failed %s\n",
1640 mic->name, __func__, __LINE__, strerror(errno));
1641 sleep(2);
1642 goto retry;
1645 if (mic->restart) {
1646 snprintf(buffer, PATH_MAX, "boot");
1647 setsysfs(mic->name, "state", buffer);
1648 mpsslog("%s restarting mic %d\n",
1649 mic->name, mic->restart);
1650 mic->restart = 0;
1653 while (1) {
1654 while (block_till_state_change(fd, mic)) {
1655 mpsslog("%s: %s %d block_till_state_change error %s\n",
1656 mic->name, __func__, __LINE__, strerror(errno));
1657 sleep(2);
1658 continue;
1661 if (get_mic_state(mic) == MIC_BOOTING)
1662 break;
1665 mic->pid = fork();
1666 switch (mic->pid) {
1667 case 0:
1668 add_virtio_device(mic, &virtcons_dev_page.dd);
1669 add_virtio_device(mic, &virtnet_dev_page.dd);
1670 err = pthread_create(&mic->mic_console.console_thread, NULL,
1671 virtio_console, mic);
1672 if (err)
1673 mpsslog("%s virtcons pthread_create failed %s\n",
1674 mic->name, strerror(err));
1675 err = pthread_create(&mic->mic_net.net_thread, NULL,
1676 virtio_net, mic);
1677 if (err)
1678 mpsslog("%s virtnet pthread_create failed %s\n",
1679 mic->name, strerror(err));
1680 err = pthread_create(&mic->mic_virtblk.block_thread, NULL,
1681 virtio_block, mic);
1682 if (err)
1683 mpsslog("%s virtblk pthread_create failed %s\n",
1684 mic->name, strerror(err));
1685 sigemptyset(&act.sa_mask);
1686 err = sigaction(SIGUSR1, &act, NULL);
1687 if (err)
1688 mpsslog("%s sigaction SIGUSR1 failed %s\n",
1689 mic->name, strerror(errno));
1690 while (1)
1691 sleep(60);
1692 case -1:
1693 mpsslog("fork failed MIC name %s id %d errno %d\n",
1694 mic->name, mic->id, errno);
1695 break;
1696 default:
1697 err = pthread_create(&mic->config_thread, NULL,
1698 mic_config, mic);
1699 if (err)
1700 mpsslog("%s mic_config pthread_create failed %s\n",
1701 mic->name, strerror(err));
1704 return NULL;
1707 static void
1708 start_daemon(void)
1710 struct mic_info *mic;
1711 int err;
1713 for (mic = mic_list.next; mic; mic = mic->next) {
1714 set_mic_boot_params(mic);
1715 err = pthread_create(&mic->init_thread, NULL, init_mic, mic);
1716 if (err)
1717 mpsslog("%s init_mic pthread_create failed %s\n",
1718 mic->name, strerror(err));
1721 while (1)
1722 sleep(60);
1725 static int
1726 init_mic_list(void)
1728 struct mic_info *mic = &mic_list;
1729 struct dirent *file;
1730 DIR *dp;
1731 int cnt = 0;
1733 dp = opendir(MICSYSFSDIR);
1734 if (!dp)
1735 return 0;
1737 while ((file = readdir(dp)) != NULL) {
1738 if (!strncmp(file->d_name, "mic", 3)) {
1739 mic->next = calloc(1, sizeof(struct mic_info));
1740 if (mic->next) {
1741 mic = mic->next;
1742 mic->id = atoi(&file->d_name[3]);
1743 mic->name = malloc(strlen(file->d_name) + 16);
1744 if (mic->name)
1745 strcpy(mic->name, file->d_name);
1746 mpsslog("MIC name %s id %d\n", mic->name,
1747 mic->id);
1748 cnt++;
1753 closedir(dp);
1754 return cnt;
1757 void
1758 mpsslog(char *format, ...)
1760 va_list args;
1761 char buffer[4096];
1762 char ts[52], *ts1;
1763 time_t t;
1765 if (logfp == NULL)
1766 return;
1768 va_start(args, format);
1769 vsprintf(buffer, format, args);
1770 va_end(args);
1772 time(&t);
1773 ts1 = ctime_r(&t, ts);
1774 ts1[strlen(ts1) - 1] = '\0';
1775 fprintf(logfp, "%s: %s", ts1, buffer);
1777 fflush(logfp);
1781 main(int argc, char *argv[])
1783 int cnt;
1784 pid_t pid;
1786 myname = argv[0];
1788 logfp = fopen(LOGFILE_NAME, "a+");
1789 if (!logfp) {
1790 fprintf(stderr, "cannot open logfile '%s'\n", LOGFILE_NAME);
1791 exit(1);
1793 pid = fork();
1794 switch (pid) {
1795 case 0:
1796 break;
1797 case -1:
1798 exit(2);
1799 default:
1800 exit(0);
1803 mpsslog("MIC Daemon start\n");
1805 cnt = init_mic_list();
1806 if (cnt == 0) {
1807 mpsslog("MIC module not loaded\n");
1808 exit(3);
1810 mpsslog("MIC found %d devices\n", cnt);
1812 start_daemon();
1814 exit(0);