]> git.proxmox.com Git - ceph.git/blob - ceph/src/spdk/lib/nvme/nvme_uevent.c
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / spdk / lib / nvme / nvme_uevent.c
1 /*-
2 * BSD LICENSE
3 *
4 * Copyright (c) Intel Corporation.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * * Neither the name of Intel Corporation nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 #include "spdk/log.h"
35 #include "spdk/event.h"
36 #include "nvme_uevent.h"
37
38 #ifdef __linux__
39
40 #include <stdlib.h>
41 #include <stdint.h>
42 #include <inttypes.h>
43 #include <errno.h>
44 #include <stdio.h>
45 #include <string.h>
46 #include <unistd.h>
47 #include <sys/ioctl.h>
48 #include <sys/types.h>
49 #include <sys/socket.h>
50 #include <linux/netlink.h>
51
52 #define SPDK_UEVENT_MSG_LEN 4096
53 #define TRADDR_FMT "%.4" PRIx16 ":%.2" PRIx8 ":%.2" PRIx8 ".%" PRIx8
54
55 int
56 spdk_uevent_connect(void)
57 {
58 struct sockaddr_nl addr;
59 int ret;
60 int netlink_fd;
61 int size = 64 * 1024;
62 int nonblock = 1;
63
64 memset(&addr, 0, sizeof(addr));
65 addr.nl_family = AF_NETLINK;
66 addr.nl_pid = getpid();
67 addr.nl_groups = 0xffffffff;
68
69 netlink_fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
70 if (netlink_fd < 0)
71 return -1;
72
73 setsockopt(netlink_fd, SOL_SOCKET, SO_RCVBUFFORCE, &size, sizeof(size));
74
75 ret = ioctl(netlink_fd, FIONBIO, &nonblock);
76 if (ret != 0) {
77 SPDK_ERRLOG("ioctl(FIONBIO) failed\n");
78 close(netlink_fd);
79 return -1;
80 }
81
82 if (bind(netlink_fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
83 close(netlink_fd);
84 return -1;
85 }
86 return netlink_fd;
87 }
88
89 /* Note: We only parse the event from uio subsystem and will ignore
90 * all the event from other subsystem. the event from uio subsystem
91 * as below:
92 * action: "add" or "remove"
93 * subsystem: "uio"
94 * dev_path: "/devices/pci0000:80/0000:80:01.0/0000:81:00.0/uio/uio0"
95 */
96 static int
97 parse_event(const char *buf, struct spdk_uevent *event)
98 {
99 int ret;
100 char action[SPDK_UEVENT_MSG_LEN];
101 char subsystem[SPDK_UEVENT_MSG_LEN];
102 char dev_path[SPDK_UEVENT_MSG_LEN];
103
104 memset(action, 0, SPDK_UEVENT_MSG_LEN);
105 memset(subsystem, 0, SPDK_UEVENT_MSG_LEN);
106 memset(dev_path, 0, SPDK_UEVENT_MSG_LEN);
107
108 while (*buf) {
109 if (!strncmp(buf, "ACTION=", 7)) {
110 buf += 7;
111 snprintf(action, sizeof(action), "%s", buf);
112 } else if (!strncmp(buf, "DEVPATH=", 8)) {
113 buf += 8;
114 snprintf(dev_path, sizeof(dev_path), "%s", buf);
115 } else if (!strncmp(buf, "SUBSYSTEM=", 10)) {
116 buf += 10;
117 snprintf(subsystem, sizeof(subsystem), "%s", buf);
118 }
119 while (*buf++)
120 ;
121 }
122
123 if (!strncmp(subsystem, "uio", 3)) {
124 char *pci_address, *tmp;
125 unsigned int domain, bus, dev, func;
126
127 event->subsystem = SPDK_NVME_UEVENT_SUBSYSTEM_UIO;
128 if (!strncmp(action, "add", 3)) {
129 event->action = SPDK_NVME_UEVENT_ADD;
130 }
131 if (!strncmp(action, "remove", 6)) {
132 event->action = SPDK_NVME_UEVENT_REMOVE;
133 }
134 tmp = strstr(dev_path, "/uio/");
135
136 memset(tmp, 0, SPDK_UEVENT_MSG_LEN - (tmp - dev_path));
137
138 pci_address = strrchr(dev_path, '/');
139 pci_address++;
140 ret = sscanf(pci_address, "%x:%x:%x.%x", &domain, &bus, &dev, &func);
141 if (ret != 4) {
142 SPDK_ERRLOG("Invalid format for NVMe BDF: %s\n", pci_address);
143 }
144 snprintf(event->traddr, sizeof(event->traddr), TRADDR_FMT, domain, bus, dev, func);
145 return 1;
146 }
147 return -1;
148 }
149
150 int
151 spdk_get_uevent(int fd, struct spdk_uevent *uevent)
152 {
153 int ret;
154 char buf[SPDK_UEVENT_MSG_LEN];
155
156 memset(uevent, 0, sizeof(struct spdk_uevent));
157 memset(buf, 0, SPDK_UEVENT_MSG_LEN);
158
159 ret = recv(fd, buf, SPDK_UEVENT_MSG_LEN - 1, MSG_DONTWAIT);
160 if (ret > 0) {
161 return parse_event(buf, uevent);
162 }
163
164 if (ret < 0) {
165 if (errno == EAGAIN || errno == EWOULDBLOCK) {
166 return 0;
167 } else {
168 SPDK_ERRLOG("Socket read error(%d): %s\n", errno, strerror(errno));
169 return -1;
170 }
171 }
172
173 /* connection closed */
174 if (ret == 0) {
175 return -1;
176 }
177 return 0;
178 }
179
180 #else /* Not Linux */
181
182 int
183 spdk_uevent_connect(void)
184 {
185 return -1;
186 }
187
188 int
189 spdk_get_uevent(int fd, struct spdk_uevent *uevent)
190 {
191 return -1;
192 }
193 #endif