2 * Intel MIC Platform Software Stack (MPSS)
4 * Copyright(c) 2013 Intel Corporation.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License, version 2, as
8 * published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * The full GNU General Public License is included in this distribution in
16 * the file called "COPYING".
18 * Intel MIC User Space Tools.
32 #include <sys/types.h>
35 #include <sys/socket.h>
36 #include <linux/virtio_ring.h>
37 #include <linux/virtio_net.h>
38 #include <linux/virtio_console.h>
39 #include <linux/virtio_blk.h>
40 #include <linux/version.h>
42 #include <linux/mic_ioctl.h>
43 #include <linux/mic_common.h>
45 static void init_mic(struct mic_info *mic);
48 static struct mic_info mic_list;
50 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
52 #define min_t(type, x, y) ({ \
55 __min1 < __min2 ? __min1 : __min2; })
57 /* align addr on a size boundary - adjust address up/down if needed */
58 #define _ALIGN_DOWN(addr, size) ((addr)&(~((size)-1)))
59 #define _ALIGN_UP(addr, size) _ALIGN_DOWN(addr + size - 1, size)
61 /* align addr on a size boundary - adjust address up if needed */
62 #define _ALIGN(addr, size) _ALIGN_UP(addr, size)
64 /* to align the pointer to the (next) page boundary */
65 #define PAGE_ALIGN(addr) _ALIGN(addr, PAGE_SIZE)
67 #define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))
70 #define MAX_GSO_SIZE (64 * 1024)
72 #define MAX_NET_PKT_SIZE (_ALIGN_UP(MAX_GSO_SIZE + ETH_H_LEN, 64))
73 #define MIC_DEVICE_PAGE_END 0x1000
75 #ifndef VIRTIO_NET_HDR_F_DATA_VALID
76 #define VIRTIO_NET_HDR_F_DATA_VALID 2 /* Csum is valid */
80 struct mic_device_desc dd;
81 struct mic_vqconfig vqconfig[2];
82 __u32 host_features, guest_acknowledgements;
83 struct virtio_console_config cons_config;
84 } virtcons_dev_page = {
86 .type = VIRTIO_ID_CONSOLE,
87 .num_vq = ARRAY_SIZE(virtcons_dev_page.vqconfig),
88 .feature_len = sizeof(virtcons_dev_page.host_features),
89 .config_len = sizeof(virtcons_dev_page.cons_config),
92 .num = htole16(MIC_VRING_ENTRIES),
95 .num = htole16(MIC_VRING_ENTRIES),
100 struct mic_device_desc dd;
101 struct mic_vqconfig vqconfig[2];
102 __u32 host_features, guest_acknowledgements;
103 struct virtio_net_config net_config;
104 } virtnet_dev_page = {
106 .type = VIRTIO_ID_NET,
107 .num_vq = ARRAY_SIZE(virtnet_dev_page.vqconfig),
108 .feature_len = sizeof(virtnet_dev_page.host_features),
109 .config_len = sizeof(virtnet_dev_page.net_config),
112 .num = htole16(MIC_VRING_ENTRIES),
115 .num = htole16(MIC_VRING_ENTRIES),
118 .host_features = htole32(
119 1 << VIRTIO_NET_F_CSUM |
120 1 << VIRTIO_NET_F_GSO |
121 1 << VIRTIO_NET_F_GUEST_TSO4 |
122 1 << VIRTIO_NET_F_GUEST_TSO6 |
123 1 << VIRTIO_NET_F_GUEST_ECN |
124 1 << VIRTIO_NET_F_GUEST_UFO),
130 static const char *mic_config_dir = "/etc/sysconfig/mic";
131 static const char *virtblk_backend = "VIRTBLK_BACKEND";
133 struct mic_device_desc dd;
134 struct mic_vqconfig vqconfig[1];
135 __u32 host_features, guest_acknowledgements;
136 struct virtio_blk_config blk_config;
137 } virtblk_dev_page = {
139 .type = VIRTIO_ID_BLOCK,
140 .num_vq = ARRAY_SIZE(virtblk_dev_page.vqconfig),
141 .feature_len = sizeof(virtblk_dev_page.host_features),
142 .config_len = sizeof(virtblk_dev_page.blk_config),
145 .num = htole16(MIC_VRING_ENTRIES),
148 htole32(1<<VIRTIO_BLK_F_SEG_MAX),
150 .seg_max = htole32(MIC_VRING_ENTRIES - 2),
151 .capacity = htole64(0),
158 tap_configure(struct mic_info *mic, char *dev)
162 char ipaddr[IFNAMSIZ];
173 mpsslog("Configuring %s\n", dev);
174 ret = execvp("ip", ifargv);
176 mpsslog("%s execvp failed errno %s\n",
177 mic->name, strerror(errno));
182 mpsslog("%s fork failed errno %s\n",
183 mic->name, strerror(errno));
187 ret = waitpid(pid, NULL, 0);
189 mpsslog("%s waitpid failed errno %s\n",
190 mic->name, strerror(errno));
194 snprintf(ipaddr, IFNAMSIZ, "172.31.%d.254/24", mic->id);
205 mpsslog("Configuring %s ipaddr %s\n", dev, ipaddr);
206 ret = execvp("ip", ifargv);
208 mpsslog("%s execvp failed errno %s\n",
209 mic->name, strerror(errno));
214 mpsslog("%s fork failed errno %s\n",
215 mic->name, strerror(errno));
219 ret = waitpid(pid, NULL, 0);
221 mpsslog("%s waitpid failed errno %s\n",
222 mic->name, strerror(errno));
225 mpsslog("MIC name %s %s %d DONE!\n",
226 mic->name, __func__, __LINE__);
230 static int tun_alloc(struct mic_info *mic, char *dev)
237 fd = open("/dev/net/tun", O_RDWR);
239 mpsslog("Could not open /dev/net/tun %s\n", strerror(errno));
243 memset(&ifr, 0, sizeof(ifr));
245 ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_VNET_HDR;
247 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
249 err = ioctl(fd, TUNSETIFF, (void *)&ifr);
251 mpsslog("%s %s %d TUNSETIFF failed %s\n",
252 mic->name, __func__, __LINE__, strerror(errno));
257 offload = TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6 |
258 TUN_F_TSO_ECN | TUN_F_UFO;
260 err = ioctl(fd, TUNSETOFFLOAD, offload);
262 mpsslog("%s %s %d TUNSETOFFLOAD failed %s\n",
263 mic->name, __func__, __LINE__, strerror(errno));
268 strcpy(dev, ifr.ifr_name);
269 mpsslog("Created TAP %s\n", dev);
274 #define NET_FD_VIRTIO_NET 0
278 static void set_dp(struct mic_info *mic, int type, void *dp)
281 case VIRTIO_ID_CONSOLE:
282 mic->mic_console.console_dp = dp;
285 mic->mic_net.net_dp = dp;
287 case VIRTIO_ID_BLOCK:
288 mic->mic_virtblk.block_dp = dp;
291 mpsslog("%s %s %d not found\n", mic->name, __func__, type);
295 static void *get_dp(struct mic_info *mic, int type)
298 case VIRTIO_ID_CONSOLE:
299 return mic->mic_console.console_dp;
301 return mic->mic_net.net_dp;
302 case VIRTIO_ID_BLOCK:
303 return mic->mic_virtblk.block_dp;
305 mpsslog("%s %s %d not found\n", mic->name, __func__, type);
310 static struct mic_device_desc *get_device_desc(struct mic_info *mic, int type)
312 struct mic_device_desc *d;
314 void *dp = get_dp(mic, type);
316 for (i = mic_aligned_size(struct mic_bootparam); i < PAGE_SIZE;
317 i += mic_total_desc_size(d)) {
327 mpsslog("%s %s d-> type %d d %p\n",
328 mic->name, __func__, d->type, d);
330 if (d->type == (__u8)type)
333 mpsslog("%s %s %d not found\n", mic->name, __func__, type);
338 /* See comments in vhost.c for explanation of next_desc() */
339 static unsigned next_desc(struct vring_desc *desc)
343 if (!(le16toh(desc->flags) & VRING_DESC_F_NEXT))
345 next = le16toh(desc->next);
349 /* Sum up all the IOVEC length */
351 sum_iovec_len(struct mic_copy_desc *copy)
356 for (i = 0; i < copy->iovcnt; i++)
357 sum += copy->iov[i].iov_len;
361 static inline void verify_out_len(struct mic_info *mic,
362 struct mic_copy_desc *copy)
364 if (copy->out_len != sum_iovec_len(copy)) {
365 mpsslog("%s %s %d BUG copy->out_len 0x%x len 0x%zx\n",
366 mic->name, __func__, __LINE__,
367 copy->out_len, sum_iovec_len(copy));
368 assert(copy->out_len == sum_iovec_len(copy));
372 /* Display an iovec */
374 disp_iovec(struct mic_info *mic, struct mic_copy_desc *copy,
375 const char *s, int line)
379 for (i = 0; i < copy->iovcnt; i++)
380 mpsslog("%s %s %d copy->iov[%d] addr %p len 0x%zx\n",
381 mic->name, s, line, i,
382 copy->iov[i].iov_base, copy->iov[i].iov_len);
385 static inline __u16 read_avail_idx(struct mic_vring *vr)
387 return ACCESS_ONCE(vr->info->avail_idx);
390 static inline void txrx_prepare(int type, bool tx, struct mic_vring *vr,
391 struct mic_copy_desc *copy, ssize_t len)
393 copy->vr_idx = tx ? 0 : 1;
394 copy->update_used = true;
395 if (type == VIRTIO_ID_NET)
396 copy->iov[1].iov_len = len - sizeof(struct virtio_net_hdr);
398 copy->iov[0].iov_len = len;
401 /* Central API which triggers the copies */
403 mic_virtio_copy(struct mic_info *mic, int fd,
404 struct mic_vring *vr, struct mic_copy_desc *copy)
408 ret = ioctl(fd, MIC_VIRTIO_COPY_DESC, copy);
410 mpsslog("%s %s %d errno %s ret %d\n",
411 mic->name, __func__, __LINE__,
412 strerror(errno), ret);
418 * This initialization routine requires at least one
419 * vring i.e. vr0. vr1 is optional.
422 init_vr(struct mic_info *mic, int fd, int type,
423 struct mic_vring *vr0, struct mic_vring *vr1, int num_vq)
428 vr_size = PAGE_ALIGN(vring_size(MIC_VRING_ENTRIES,
429 MIC_VIRTIO_RING_ALIGN) + sizeof(struct _mic_vring_info));
430 va = mmap(NULL, MIC_DEVICE_PAGE_END + vr_size * num_vq,
431 PROT_READ, MAP_SHARED, fd, 0);
432 if (MAP_FAILED == va) {
433 mpsslog("%s %s %d mmap failed errno %s\n",
434 mic->name, __func__, __LINE__,
438 set_dp(mic, type, va);
439 vr0->va = (struct mic_vring *)&va[MIC_DEVICE_PAGE_END];
440 vr0->info = vr0->va +
441 vring_size(MIC_VRING_ENTRIES, MIC_VIRTIO_RING_ALIGN);
443 MIC_VRING_ENTRIES, vr0->va, MIC_VIRTIO_RING_ALIGN);
444 mpsslog("%s %s vr0 %p vr0->info %p vr_size 0x%x vring 0x%x ",
445 __func__, mic->name, vr0->va, vr0->info, vr_size,
446 vring_size(MIC_VRING_ENTRIES, MIC_VIRTIO_RING_ALIGN));
447 mpsslog("magic 0x%x expected 0x%x\n",
448 vr0->info->magic, MIC_MAGIC + type);
449 assert(vr0->info->magic == MIC_MAGIC + type);
451 vr1->va = (struct mic_vring *)
452 &va[MIC_DEVICE_PAGE_END + vr_size];
453 vr1->info = vr1->va + vring_size(MIC_VRING_ENTRIES,
454 MIC_VIRTIO_RING_ALIGN);
456 MIC_VRING_ENTRIES, vr1->va, MIC_VIRTIO_RING_ALIGN);
457 mpsslog("%s %s vr1 %p vr1->info %p vr_size 0x%x vring 0x%x ",
458 __func__, mic->name, vr1->va, vr1->info, vr_size,
459 vring_size(MIC_VRING_ENTRIES, MIC_VIRTIO_RING_ALIGN));
460 mpsslog("magic 0x%x expected 0x%x\n",
461 vr1->info->magic, MIC_MAGIC + type + 1);
462 assert(vr1->info->magic == MIC_MAGIC + type + 1);
469 wait_for_card_driver(struct mic_info *mic, int fd, int type)
471 struct pollfd pollfd;
473 struct mic_device_desc *desc = get_device_desc(mic, type);
476 mpsslog("%s %s Waiting .... desc-> type %d status 0x%x\n",
477 mic->name, __func__, type, desc->status);
479 pollfd.events = POLLIN;
481 err = poll(&pollfd, 1, -1);
483 mpsslog("%s %s poll failed %s\n",
484 mic->name, __func__, strerror(errno));
488 if (pollfd.revents) {
489 mpsslog("%s %s Waiting... desc-> type %d status 0x%x\n",
490 mic->name, __func__, type, desc->status);
491 if (desc->status & VIRTIO_CONFIG_S_DRIVER_OK) {
492 mpsslog("%s %s poll.revents %d\n",
493 mic->name, __func__, pollfd.revents);
494 mpsslog("%s %s desc-> type %d status 0x%x\n",
495 mic->name, __func__, type,
503 /* Spin till we have some descriptors */
505 spin_for_descriptors(struct mic_info *mic, struct mic_vring *vr)
507 __u16 avail_idx = read_avail_idx(vr);
509 while (avail_idx == le16toh(ACCESS_ONCE(vr->vr.avail->idx))) {
511 mpsslog("%s %s waiting for desc avail %d info_avail %d\n",
513 le16toh(vr->vr.avail->idx), vr->info->avail_idx);
520 virtio_net(void *arg)
522 static __u8 vnet_hdr[2][sizeof(struct virtio_net_hdr)];
523 static __u8 vnet_buf[2][MAX_NET_PKT_SIZE] __aligned(64);
524 struct iovec vnet_iov[2][2] = {
525 { { .iov_base = vnet_hdr[0], .iov_len = sizeof(vnet_hdr[0]) },
526 { .iov_base = vnet_buf[0], .iov_len = sizeof(vnet_buf[0]) } },
527 { { .iov_base = vnet_hdr[1], .iov_len = sizeof(vnet_hdr[1]) },
528 { .iov_base = vnet_buf[1], .iov_len = sizeof(vnet_buf[1]) } },
530 struct iovec *iov0 = vnet_iov[0], *iov1 = vnet_iov[1];
531 struct mic_info *mic = (struct mic_info *)arg;
532 char if_name[IFNAMSIZ];
533 struct pollfd net_poll[MAX_NET_FD];
534 struct mic_vring tx_vr, rx_vr;
535 struct mic_copy_desc copy;
536 struct mic_device_desc *desc;
539 snprintf(if_name, IFNAMSIZ, "mic%d", mic->id);
540 mic->mic_net.tap_fd = tun_alloc(mic, if_name);
541 if (mic->mic_net.tap_fd < 0)
544 if (tap_configure(mic, if_name))
546 mpsslog("MIC name %s id %d\n", mic->name, mic->id);
548 net_poll[NET_FD_VIRTIO_NET].fd = mic->mic_net.virtio_net_fd;
549 net_poll[NET_FD_VIRTIO_NET].events = POLLIN;
550 net_poll[NET_FD_TUN].fd = mic->mic_net.tap_fd;
551 net_poll[NET_FD_TUN].events = POLLIN;
553 if (MAP_FAILED == init_vr(mic, mic->mic_net.virtio_net_fd,
554 VIRTIO_ID_NET, &tx_vr, &rx_vr,
555 virtnet_dev_page.dd.num_vq)) {
556 mpsslog("%s init_vr failed %s\n",
557 mic->name, strerror(errno));
562 desc = get_device_desc(mic, VIRTIO_ID_NET);
567 net_poll[NET_FD_VIRTIO_NET].revents = 0;
568 net_poll[NET_FD_TUN].revents = 0;
570 /* Start polling for data from tap and virtio net */
571 err = poll(net_poll, 2, -1);
573 mpsslog("%s poll failed %s\n",
574 __func__, strerror(errno));
577 if (!(desc->status & VIRTIO_CONFIG_S_DRIVER_OK))
578 wait_for_card_driver(mic, mic->mic_net.virtio_net_fd,
581 * Check if there is data to be read from TUN and write to
582 * virtio net fd if there is.
584 if (net_poll[NET_FD_TUN].revents & POLLIN) {
586 len = readv(net_poll[NET_FD_TUN].fd,
587 copy.iov, copy.iovcnt);
589 struct virtio_net_hdr *hdr
590 = (struct virtio_net_hdr *)vnet_hdr[0];
592 /* Disable checksums on the card since we are on
593 a reliable PCIe link */
594 hdr->flags |= VIRTIO_NET_HDR_F_DATA_VALID;
596 mpsslog("%s %s %d hdr->flags 0x%x ", mic->name,
597 __func__, __LINE__, hdr->flags);
598 mpsslog("copy.out_len %d hdr->gso_type 0x%x\n",
599 copy.out_len, hdr->gso_type);
602 disp_iovec(mic, copy, __func__, __LINE__);
603 mpsslog("%s %s %d read from tap 0x%lx\n",
604 mic->name, __func__, __LINE__,
607 spin_for_descriptors(mic, &tx_vr);
608 txrx_prepare(VIRTIO_ID_NET, 1, &tx_vr, ©,
611 err = mic_virtio_copy(mic,
612 mic->mic_net.virtio_net_fd, &tx_vr,
615 mpsslog("%s %s %d mic_virtio_copy %s\n",
616 mic->name, __func__, __LINE__,
620 verify_out_len(mic, ©);
622 disp_iovec(mic, copy, __func__, __LINE__);
623 mpsslog("%s %s %d wrote to net 0x%lx\n",
624 mic->name, __func__, __LINE__,
625 sum_iovec_len(©));
627 /* Reinitialize IOV for next run */
628 iov0[1].iov_len = MAX_NET_PKT_SIZE;
629 } else if (len < 0) {
630 disp_iovec(mic, ©, __func__, __LINE__);
631 mpsslog("%s %s %d read failed %s ", mic->name,
632 __func__, __LINE__, strerror(errno));
633 mpsslog("cnt %d sum %zd\n",
634 copy.iovcnt, sum_iovec_len(©));
639 * Check if there is data to be read from virtio net and
640 * write to TUN if there is.
642 if (net_poll[NET_FD_VIRTIO_NET].revents & POLLIN) {
643 while (rx_vr.info->avail_idx !=
644 le16toh(rx_vr.vr.avail->idx)) {
646 txrx_prepare(VIRTIO_ID_NET, 0, &rx_vr, ©,
648 + sizeof(struct virtio_net_hdr));
650 err = mic_virtio_copy(mic,
651 mic->mic_net.virtio_net_fd, &rx_vr,
655 struct virtio_net_hdr *hdr
656 = (struct virtio_net_hdr *)
659 mpsslog("%s %s %d hdr->flags 0x%x, ",
660 mic->name, __func__, __LINE__,
662 mpsslog("out_len %d gso_type 0x%x\n",
666 /* Set the correct output iov_len */
667 iov1[1].iov_len = copy.out_len -
668 sizeof(struct virtio_net_hdr);
669 verify_out_len(mic, ©);
671 disp_iovec(mic, copy, __func__,
674 mic->name, __func__, __LINE__);
675 mpsslog("read from net 0x%lx\n",
676 sum_iovec_len(copy));
678 len = writev(net_poll[NET_FD_TUN].fd,
679 copy.iov, copy.iovcnt);
680 if (len != sum_iovec_len(©)) {
681 mpsslog("Tun write failed %s ",
683 mpsslog("len 0x%zx ", len);
684 mpsslog("read_len 0x%zx\n",
685 sum_iovec_len(©));
688 disp_iovec(mic, ©, __func__,
693 mpsslog("wrote to tap 0x%lx\n",
698 mpsslog("%s %s %d mic_virtio_copy %s\n",
699 mic->name, __func__, __LINE__,
705 if (net_poll[NET_FD_VIRTIO_NET].revents & POLLERR)
706 mpsslog("%s: %s: POLLERR\n", __func__, mic->name);
713 #define VIRTIO_CONSOLE_FD 0
714 #define MONITOR_FD (VIRTIO_CONSOLE_FD + 1)
715 #define MAX_CONSOLE_FD (MONITOR_FD + 1) /* must be the last one + 1 */
716 #define MAX_BUFFER_SIZE PAGE_SIZE
719 virtio_console(void *arg)
721 static __u8 vcons_buf[2][PAGE_SIZE];
722 struct iovec vcons_iov[2] = {
723 { .iov_base = vcons_buf[0], .iov_len = sizeof(vcons_buf[0]) },
724 { .iov_base = vcons_buf[1], .iov_len = sizeof(vcons_buf[1]) },
726 struct iovec *iov0 = &vcons_iov[0], *iov1 = &vcons_iov[1];
727 struct mic_info *mic = (struct mic_info *)arg;
729 struct pollfd console_poll[MAX_CONSOLE_FD];
733 struct mic_vring tx_vr, rx_vr;
734 struct mic_copy_desc copy;
735 struct mic_device_desc *desc;
737 pty_fd = posix_openpt(O_RDWR);
739 mpsslog("can't open a pseudoterminal master device: %s\n",
743 pts_name = ptsname(pty_fd);
744 if (pts_name == NULL) {
745 mpsslog("can't get pts name\n");
748 printf("%s console message goes to %s\n", mic->name, pts_name);
749 mpsslog("%s console message goes to %s\n", mic->name, pts_name);
750 err = grantpt(pty_fd);
752 mpsslog("can't grant access: %s %s\n",
753 pts_name, strerror(errno));
756 err = unlockpt(pty_fd);
758 mpsslog("can't unlock a pseudoterminal: %s %s\n",
759 pts_name, strerror(errno));
762 console_poll[MONITOR_FD].fd = pty_fd;
763 console_poll[MONITOR_FD].events = POLLIN;
765 console_poll[VIRTIO_CONSOLE_FD].fd = mic->mic_console.virtio_console_fd;
766 console_poll[VIRTIO_CONSOLE_FD].events = POLLIN;
768 if (MAP_FAILED == init_vr(mic, mic->mic_console.virtio_console_fd,
769 VIRTIO_ID_CONSOLE, &tx_vr, &rx_vr,
770 virtcons_dev_page.dd.num_vq)) {
771 mpsslog("%s init_vr failed %s\n",
772 mic->name, strerror(errno));
777 desc = get_device_desc(mic, VIRTIO_ID_CONSOLE);
780 console_poll[MONITOR_FD].revents = 0;
781 console_poll[VIRTIO_CONSOLE_FD].revents = 0;
782 err = poll(console_poll, MAX_CONSOLE_FD, -1);
784 mpsslog("%s %d: poll failed: %s\n", __func__, __LINE__,
788 if (!(desc->status & VIRTIO_CONFIG_S_DRIVER_OK))
789 wait_for_card_driver(mic,
790 mic->mic_console.virtio_console_fd,
793 if (console_poll[MONITOR_FD].revents & POLLIN) {
795 len = readv(pty_fd, copy.iov, copy.iovcnt);
798 disp_iovec(mic, copy, __func__, __LINE__);
799 mpsslog("%s %s %d read from tap 0x%lx\n",
800 mic->name, __func__, __LINE__,
803 spin_for_descriptors(mic, &tx_vr);
804 txrx_prepare(VIRTIO_ID_CONSOLE, 1, &tx_vr,
807 err = mic_virtio_copy(mic,
808 mic->mic_console.virtio_console_fd,
811 mpsslog("%s %s %d mic_virtio_copy %s\n",
812 mic->name, __func__, __LINE__,
816 verify_out_len(mic, ©);
818 disp_iovec(mic, copy, __func__, __LINE__);
819 mpsslog("%s %s %d wrote to net 0x%lx\n",
820 mic->name, __func__, __LINE__,
821 sum_iovec_len(copy));
823 /* Reinitialize IOV for next run */
824 iov0->iov_len = PAGE_SIZE;
825 } else if (len < 0) {
826 disp_iovec(mic, ©, __func__, __LINE__);
827 mpsslog("%s %s %d read failed %s ",
828 mic->name, __func__, __LINE__,
830 mpsslog("cnt %d sum %zd\n",
831 copy.iovcnt, sum_iovec_len(©));
835 if (console_poll[VIRTIO_CONSOLE_FD].revents & POLLIN) {
836 while (rx_vr.info->avail_idx !=
837 le16toh(rx_vr.vr.avail->idx)) {
839 txrx_prepare(VIRTIO_ID_CONSOLE, 0, &rx_vr,
842 err = mic_virtio_copy(mic,
843 mic->mic_console.virtio_console_fd,
846 /* Set the correct output iov_len */
847 iov1->iov_len = copy.out_len;
848 verify_out_len(mic, ©);
850 disp_iovec(mic, copy, __func__,
853 mic->name, __func__, __LINE__);
854 mpsslog("read from net 0x%lx\n",
855 sum_iovec_len(copy));
858 copy.iov, copy.iovcnt);
859 if (len != sum_iovec_len(©)) {
860 mpsslog("Tun write failed %s ",
862 mpsslog("len 0x%zx ", len);
863 mpsslog("read_len 0x%zx\n",
864 sum_iovec_len(©));
867 disp_iovec(mic, copy, __func__,
872 mpsslog("wrote to tap 0x%lx\n",
877 mpsslog("%s %s %d mic_virtio_copy %s\n",
878 mic->name, __func__, __LINE__,
884 if (console_poll[NET_FD_VIRTIO_NET].revents & POLLERR)
885 mpsslog("%s: %s: POLLERR\n", __func__, mic->name);
894 add_virtio_device(struct mic_info *mic, struct mic_device_desc *dd)
899 snprintf(path, PATH_MAX, "/dev/mic%d", mic->id);
900 fd = open(path, O_RDWR);
902 mpsslog("Could not open %s %s\n", path, strerror(errno));
906 err = ioctl(fd, MIC_VIRTIO_ADD_DEVICE, dd);
908 mpsslog("Could not add %d %s\n", dd->type, strerror(errno));
914 mic->mic_net.virtio_net_fd = fd;
915 mpsslog("Added VIRTIO_ID_NET for %s\n", mic->name);
917 case VIRTIO_ID_CONSOLE:
918 mic->mic_console.virtio_console_fd = fd;
919 mpsslog("Added VIRTIO_ID_CONSOLE for %s\n", mic->name);
921 case VIRTIO_ID_BLOCK:
922 mic->mic_virtblk.virtio_block_fd = fd;
923 mpsslog("Added VIRTIO_ID_BLOCK for %s\n", mic->name);
929 set_backend_file(struct mic_info *mic)
932 char buff[PATH_MAX], *line, *evv, *p;
934 snprintf(buff, PATH_MAX, "%s/mpssd%03d.conf", mic_config_dir, mic->id);
935 config = fopen(buff, "r");
938 do { /* look for "virtblk_backend=XXXX" */
939 line = fgets(buff, PATH_MAX, config);
944 p = strchr(line, '\n');
947 } while (strncmp(line, virtblk_backend, strlen(virtblk_backend)) != 0);
951 evv = strchr(line, '=');
954 mic->mic_virtblk.backend_file = malloc(strlen(evv) + 1);
955 if (mic->mic_virtblk.backend_file == NULL) {
956 mpsslog("%s %d can't allocate memory\n", mic->name, mic->id);
959 strcpy(mic->mic_virtblk.backend_file, evv + 1);
963 #define SECTOR_SIZE 512
965 set_backend_size(struct mic_info *mic)
967 mic->mic_virtblk.backend_size = lseek(mic->mic_virtblk.backend, 0,
969 if (mic->mic_virtblk.backend_size < 0) {
970 mpsslog("%s: can't seek: %s\n",
971 mic->name, mic->mic_virtblk.backend_file);
974 virtblk_dev_page.blk_config.capacity =
975 mic->mic_virtblk.backend_size / SECTOR_SIZE;
976 if ((mic->mic_virtblk.backend_size % SECTOR_SIZE) != 0)
977 virtblk_dev_page.blk_config.capacity++;
979 virtblk_dev_page.blk_config.capacity =
980 htole64(virtblk_dev_page.blk_config.capacity);
986 open_backend(struct mic_info *mic)
988 if (!set_backend_file(mic))
990 mic->mic_virtblk.backend = open(mic->mic_virtblk.backend_file, O_RDWR);
991 if (mic->mic_virtblk.backend < 0) {
992 mpsslog("%s: can't open: %s\n", mic->name,
993 mic->mic_virtblk.backend_file);
996 if (!set_backend_size(mic))
998 mic->mic_virtblk.backend_addr = mmap(NULL,
999 mic->mic_virtblk.backend_size,
1000 PROT_READ|PROT_WRITE, MAP_SHARED,
1001 mic->mic_virtblk.backend, 0L);
1002 if (mic->mic_virtblk.backend_addr == MAP_FAILED) {
1003 mpsslog("%s: can't map: %s %s\n",
1004 mic->name, mic->mic_virtblk.backend_file,
1011 close(mic->mic_virtblk.backend);
1013 free(mic->mic_virtblk.backend_file);
1019 close_backend(struct mic_info *mic)
1021 munmap(mic->mic_virtblk.backend_addr, mic->mic_virtblk.backend_size);
1022 close(mic->mic_virtblk.backend);
1023 free(mic->mic_virtblk.backend_file);
1027 start_virtblk(struct mic_info *mic, struct mic_vring *vring)
1029 if (((unsigned long)&virtblk_dev_page.blk_config % 8) != 0) {
1030 mpsslog("%s: blk_config is not 8 byte aligned.\n",
1034 add_virtio_device(mic, &virtblk_dev_page.dd);
1035 if (MAP_FAILED == init_vr(mic, mic->mic_virtblk.virtio_block_fd,
1036 VIRTIO_ID_BLOCK, vring, NULL,
1037 virtblk_dev_page.dd.num_vq)) {
1038 mpsslog("%s init_vr failed %s\n",
1039 mic->name, strerror(errno));
1046 stop_virtblk(struct mic_info *mic)
1050 vr_size = PAGE_ALIGN(vring_size(MIC_VRING_ENTRIES,
1051 MIC_VIRTIO_RING_ALIGN) + sizeof(struct _mic_vring_info));
1052 ret = munmap(mic->mic_virtblk.block_dp,
1053 MIC_DEVICE_PAGE_END + vr_size * virtblk_dev_page.dd.num_vq);
1055 mpsslog("%s munmap errno %d\n", mic->name, errno);
1056 close(mic->mic_virtblk.virtio_block_fd);
1060 header_error_check(struct vring_desc *desc)
1062 if (le32toh(desc->len) != sizeof(struct virtio_blk_outhdr)) {
1063 mpsslog("%s() %d: length is not sizeof(virtio_blk_outhd)\n",
1064 __func__, __LINE__);
1067 if (!(le16toh(desc->flags) & VRING_DESC_F_NEXT)) {
1068 mpsslog("%s() %d: alone\n",
1069 __func__, __LINE__);
1072 if (le16toh(desc->flags) & VRING_DESC_F_WRITE) {
1073 mpsslog("%s() %d: not read\n",
1074 __func__, __LINE__);
1081 read_header(int fd, struct virtio_blk_outhdr *hdr, __u32 desc_idx)
1084 struct mic_copy_desc copy;
1086 iovec.iov_len = sizeof(*hdr);
1087 iovec.iov_base = hdr;
1090 copy.vr_idx = 0; /* only one vring on virtio_block */
1091 copy.update_used = false; /* do not update used index */
1092 return ioctl(fd, MIC_VIRTIO_COPY_DESC, ©);
1096 transfer_blocks(int fd, struct iovec *iovec, __u32 iovcnt)
1098 struct mic_copy_desc copy;
1101 copy.iovcnt = iovcnt;
1102 copy.vr_idx = 0; /* only one vring on virtio_block */
1103 copy.update_used = false; /* do not update used index */
1104 return ioctl(fd, MIC_VIRTIO_COPY_DESC, ©);
1108 status_error_check(struct vring_desc *desc)
1110 if (le32toh(desc->len) != sizeof(__u8)) {
1111 mpsslog("%s() %d: length is not sizeof(status)\n",
1112 __func__, __LINE__);
1119 write_status(int fd, __u8 *status)
1122 struct mic_copy_desc copy;
1124 iovec.iov_base = status;
1125 iovec.iov_len = sizeof(*status);
1128 copy.vr_idx = 0; /* only one vring on virtio_block */
1129 copy.update_used = true; /* Update used index */
1130 return ioctl(fd, MIC_VIRTIO_COPY_DESC, ©);
1134 virtio_block(void *arg)
1136 struct mic_info *mic = (struct mic_info *)arg;
1138 struct pollfd block_poll;
1139 struct mic_vring vring;
1142 struct vring_desc *desc;
1143 struct iovec *iovec, *piov;
1145 __u32 buffer_desc_idx;
1146 struct virtio_blk_outhdr hdr;
1149 for (;;) { /* forever */
1150 if (!open_backend(mic)) { /* No virtblk */
1151 for (mic->mic_virtblk.signaled = 0;
1152 !mic->mic_virtblk.signaled;)
1157 /* backend file is specified. */
1158 if (!start_virtblk(mic, &vring))
1159 goto _close_backend;
1160 iovec = malloc(sizeof(*iovec) *
1161 le32toh(virtblk_dev_page.blk_config.seg_max));
1163 mpsslog("%s: can't alloc iovec: %s\n",
1164 mic->name, strerror(ENOMEM));
1168 block_poll.fd = mic->mic_virtblk.virtio_block_fd;
1169 block_poll.events = POLLIN;
1170 for (mic->mic_virtblk.signaled = 0;
1171 !mic->mic_virtblk.signaled;) {
1172 block_poll.revents = 0;
1173 /* timeout in 1 sec to see signaled */
1174 ret = poll(&block_poll, 1, 1000);
1176 mpsslog("%s %d: poll failed: %s\n",
1182 if (!(block_poll.revents & POLLIN)) {
1184 mpsslog("%s %d: block_poll.revents=0x%x\n",
1185 __func__, __LINE__, block_poll.revents);
1191 while (vring.info->avail_idx !=
1192 le16toh(vring.vr.avail->idx)) {
1193 /* read header element */
1195 vring.info->avail_idx &
1198 vring.vr.avail->ring[avail_idx]);
1199 desc = &vring.vr.desc[desc_idx];
1201 mpsslog("%s() %d: avail_idx=%d ",
1203 vring.info->avail_idx);
1204 mpsslog("vring.vr.num=%d desc=%p\n",
1205 vring.vr.num, desc);
1207 status = header_error_check(desc);
1209 mic->mic_virtblk.virtio_block_fd,
1212 mpsslog("%s() %d %s: ret=%d %s\n",
1218 /* buffer element */
1221 fos = mic->mic_virtblk.backend_addr +
1222 (hdr.sector * SECTOR_SIZE);
1223 buffer_desc_idx = next_desc(desc);
1224 desc_idx = buffer_desc_idx;
1225 for (desc = &vring.vr.desc[buffer_desc_idx];
1226 desc->flags & VRING_DESC_F_NEXT;
1227 desc_idx = next_desc(desc),
1228 desc = &vring.vr.desc[desc_idx]) {
1229 piov->iov_len = desc->len;
1230 piov->iov_base = fos;
1234 /* Returning NULLs for VIRTIO_BLK_T_GET_ID. */
1235 if (hdr.type & ~(VIRTIO_BLK_T_OUT |
1236 VIRTIO_BLK_T_GET_ID)) {
1238 VIRTIO_BLK_T_IN - does not do
1239 anything. Probably for documenting.
1240 VIRTIO_BLK_T_SCSI_CMD - for
1242 VIRTIO_BLK_T_FLUSH - turned off in
1244 VIRTIO_BLK_T_BARRIER - defined but not
1247 mpsslog("%s() %d: type %x ",
1250 mpsslog("is not supported\n");
1254 ret = transfer_blocks(
1255 mic->mic_virtblk.virtio_block_fd,
1262 /* write status and update used pointer */
1264 status = status_error_check(desc);
1266 mic->mic_virtblk.virtio_block_fd,
1269 mpsslog("%s() %d: write status=%d on desc=%p\n",
1286 reset(struct mic_info *mic)
1288 #define RESET_TIMEOUT 120
1289 int i = RESET_TIMEOUT;
1290 setsysfs(mic->name, "state", "reset");
1293 state = readsysfs(mic->name, "state");
1296 mpsslog("%s: %s %d state %s\n",
1297 mic->name, __func__, __LINE__, state);
1300 * If the shutdown was initiated by OSPM, the state stays
1301 * in "suspended" which is also a valid condition for reset.
1303 if ((!strcmp(state, "offline")) ||
1304 (!strcmp(state, "suspended"))) {
1316 get_mic_shutdown_status(struct mic_info *mic, char *shutdown_status)
1318 if (!strcmp(shutdown_status, "nop"))
1320 if (!strcmp(shutdown_status, "crashed"))
1322 if (!strcmp(shutdown_status, "halted"))
1324 if (!strcmp(shutdown_status, "poweroff"))
1325 return MIC_POWER_OFF;
1326 if (!strcmp(shutdown_status, "restart"))
1328 mpsslog("%s: BUG invalid status %s\n", mic->name, shutdown_status);
1333 static int get_mic_state(struct mic_info *mic, char *state)
1335 if (!strcmp(state, "offline"))
1337 if (!strcmp(state, "online"))
1339 if (!strcmp(state, "shutting_down"))
1340 return MIC_SHUTTING_DOWN;
1341 if (!strcmp(state, "reset_failed"))
1342 return MIC_RESET_FAILED;
1343 if (!strcmp(state, "suspending"))
1344 return MIC_SUSPENDING;
1345 if (!strcmp(state, "suspended"))
1346 return MIC_SUSPENDED;
1347 mpsslog("%s: BUG invalid state %s\n", mic->name, state);
1352 static void mic_handle_shutdown(struct mic_info *mic)
1354 #define SHUTDOWN_TIMEOUT 60
1355 int i = SHUTDOWN_TIMEOUT, ret, stat = 0;
1356 char *shutdown_status;
1358 shutdown_status = readsysfs(mic->name, "shutdown_status");
1359 if (!shutdown_status)
1361 mpsslog("%s: %s %d shutdown_status %s\n",
1362 mic->name, __func__, __LINE__, shutdown_status);
1363 switch (get_mic_shutdown_status(mic, shutdown_status)) {
1369 free(shutdown_status);
1374 free(shutdown_status);
1379 ret = kill(mic->pid, SIGTERM);
1380 mpsslog("%s: %s %d kill pid %d ret %d\n",
1381 mic->name, __func__, __LINE__,
1384 ret = waitpid(mic->pid, &stat,
1386 mpsslog("%s: %s %d waitpid ret %d pid %d\n",
1387 mic->name, __func__, __LINE__,
1390 if (ret == mic->pid)
1395 mic_config(void *arg)
1397 struct mic_info *mic = (struct mic_info *)arg;
1399 char pathname[PATH_MAX];
1401 struct pollfd ufds[1];
1404 snprintf(pathname, PATH_MAX - 1, "%s/%s/%s",
1405 MICSYSFSDIR, mic->name, "state");
1407 fd = open(pathname, O_RDONLY);
1409 mpsslog("%s: opening file %s failed %s\n",
1410 mic->name, pathname, strerror(errno));
1415 ret = read(fd, value, sizeof(value));
1417 mpsslog("%s: Failed to read sysfs entry '%s': %s\n",
1418 mic->name, pathname, strerror(errno));
1422 state = readsysfs(mic->name, "state");
1425 mpsslog("%s: %s %d state %s\n",
1426 mic->name, __func__, __LINE__, state);
1427 switch (get_mic_state(mic, state)) {
1428 case MIC_SHUTTING_DOWN:
1429 mic_handle_shutdown(mic);
1431 case MIC_SUSPENDING:
1432 mic->boot_on_resume = 1;
1433 setsysfs(mic->name, "state", "suspend");
1434 mic_handle_shutdown(mic);
1437 if (mic->boot_on_resume) {
1438 setsysfs(mic->name, "state", "boot");
1439 mic->boot_on_resume = 0;
1448 ufds[0].events = POLLERR | POLLPRI;
1449 ret = poll(ufds, 1, -1);
1451 mpsslog("%s: poll failed %s\n",
1452 mic->name, strerror(errno));
1466 set_cmdline(struct mic_info *mic)
1468 char buffer[PATH_MAX];
1471 len = snprintf(buffer, PATH_MAX,
1472 "clocksource=tsc highres=off nohz=off ");
1473 len += snprintf(buffer + len, PATH_MAX,
1474 "cpufreq_on;corec6_off;pc3_off;pc6_off ");
1475 len += snprintf(buffer + len, PATH_MAX,
1476 "ifcfg=static;address,172.31.%d.1;netmask,255.255.255.0",
1479 setsysfs(mic->name, "cmdline", buffer);
1480 mpsslog("%s: Command line: \"%s\"\n", mic->name, buffer);
1481 snprintf(buffer, PATH_MAX, "172.31.%d.1", mic->id);
1482 mpsslog("%s: IPADDR: \"%s\"\n", mic->name, buffer);
1486 set_log_buf_info(struct mic_info *mic)
1490 char system_map[] = "/lib/firmware/mic/System.map";
1491 char *map, *temp, log_buf[17] = {'\0'};
1493 fd = open(system_map, O_RDONLY);
1495 mpsslog("%s: Opening System.map failed: %d\n",
1499 len = lseek(fd, 0, SEEK_END);
1501 mpsslog("%s: Reading System.map size failed: %d\n",
1506 map = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);
1507 if (map == MAP_FAILED) {
1508 mpsslog("%s: mmap of System.map failed: %d\n",
1513 temp = strstr(map, "__log_buf");
1515 mpsslog("%s: __log_buf not found: %d\n", mic->name, errno);
1520 strncpy(log_buf, temp - 19, 16);
1521 setsysfs(mic->name, "log_buf_addr", log_buf);
1522 mpsslog("%s: log_buf_addr: %s\n", mic->name, log_buf);
1523 temp = strstr(map, "log_buf_len");
1525 mpsslog("%s: log_buf_len not found: %d\n", mic->name, errno);
1530 strncpy(log_buf, temp - 19, 16);
1531 setsysfs(mic->name, "log_buf_len", log_buf);
1532 mpsslog("%s: log_buf_len: %s\n", mic->name, log_buf);
1537 static void init_mic(struct mic_info *mic);
1540 change_virtblk_backend(int x, siginfo_t *siginfo, void *p)
1542 struct mic_info *mic;
1544 for (mic = mic_list.next; mic != NULL; mic = mic->next)
1545 mic->mic_virtblk.signaled = 1/* true */;
1549 init_mic(struct mic_info *mic)
1551 struct sigaction ignore = {
1553 .sa_handler = SIG_IGN
1555 struct sigaction act = {
1556 .sa_flags = SA_SIGINFO,
1557 .sa_sigaction = change_virtblk_backend,
1559 char buffer[PATH_MAX];
1563 * Currently, one virtio block device is supported for each MIC card
1564 * at a time. Any user (or test) can send a SIGUSR1 to the MIC daemon.
1565 * The signal informs the virtio block backend about a change in the
1566 * configuration file which specifies the virtio backend file name on
1567 * the host. Virtio block backend then re-reads the configuration file
1568 * and switches to the new block device. This signalling mechanism may
1569 * not be required once multiple virtio block devices are supported by
1572 sigaction(SIGUSR1, &ignore, NULL);
1577 set_log_buf_info(mic);
1579 add_virtio_device(mic, &virtcons_dev_page.dd);
1580 add_virtio_device(mic, &virtnet_dev_page.dd);
1581 err = pthread_create(&mic->mic_console.console_thread, NULL,
1582 virtio_console, mic);
1584 mpsslog("%s virtcons pthread_create failed %s\n",
1585 mic->name, strerror(err));
1586 err = pthread_create(&mic->mic_net.net_thread, NULL,
1589 mpsslog("%s virtnet pthread_create failed %s\n",
1590 mic->name, strerror(err));
1591 err = pthread_create(&mic->mic_virtblk.block_thread, NULL,
1594 mpsslog("%s virtblk pthread_create failed %s\n",
1595 mic->name, strerror(err));
1596 sigemptyset(&act.sa_mask);
1597 err = sigaction(SIGUSR1, &act, NULL);
1599 mpsslog("%s sigaction SIGUSR1 failed %s\n",
1600 mic->name, strerror(errno));
1604 mpsslog("fork failed MIC name %s id %d errno %d\n",
1605 mic->name, mic->id, errno);
1609 snprintf(buffer, PATH_MAX, "boot");
1610 setsysfs(mic->name, "state", buffer);
1611 mpsslog("%s restarting mic %d\n",
1612 mic->name, mic->restart);
1615 pthread_create(&mic->config_thread, NULL, mic_config, mic);
1622 struct mic_info *mic;
1624 for (mic = mic_list.next; mic != NULL; mic = mic->next)
1634 struct mic_info *mic = &mic_list;
1635 struct dirent *file;
1639 dp = opendir(MICSYSFSDIR);
1643 while ((file = readdir(dp)) != NULL) {
1644 if (!strncmp(file->d_name, "mic", 3)) {
1645 mic->next = calloc(1, sizeof(struct mic_info));
1648 mic->id = atoi(&file->d_name[3]);
1649 mic->name = malloc(strlen(file->d_name) + 16);
1651 strcpy(mic->name, file->d_name);
1652 mpsslog("MIC name %s id %d\n", mic->name,
1664 mpsslog(char *format, ...)
1674 va_start(args, format);
1675 vsprintf(buffer, format, args);
1679 ts1 = ctime_r(&t, ts);
1680 ts1[strlen(ts1) - 1] = '\0';
1681 fprintf(logfp, "%s: %s", ts1, buffer);
1687 main(int argc, char *argv[])
1694 logfp = fopen(LOGFILE_NAME, "a+");
1696 fprintf(stderr, "cannot open logfile '%s'\n", LOGFILE_NAME);
1709 mpsslog("MIC Daemon start\n");
1711 cnt = init_mic_list();
1713 mpsslog("MIC module not loaded\n");
1716 mpsslog("MIC found %d devices\n", cnt);