4 * Copyright (c) Intel Corporation.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
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.
35 #include "spdk/event.h"
36 #include "nvme_uevent.h"
47 #include <sys/ioctl.h>
48 #include <sys/types.h>
49 #include <sys/socket.h>
50 #include <linux/netlink.h>
52 #define SPDK_UEVENT_MSG_LEN 4096
53 #define TRADDR_FMT "%.4" PRIx16 ":%.2" PRIx8 ":%.2" PRIx8 ".%" PRIx8
56 spdk_uevent_connect(void)
58 struct sockaddr_nl addr
;
64 memset(&addr
, 0, sizeof(addr
));
65 addr
.nl_family
= AF_NETLINK
;
66 addr
.nl_pid
= getpid();
67 addr
.nl_groups
= 0xffffffff;
69 netlink_fd
= socket(PF_NETLINK
, SOCK_DGRAM
, NETLINK_KOBJECT_UEVENT
);
73 setsockopt(netlink_fd
, SOL_SOCKET
, SO_RCVBUFFORCE
, &size
, sizeof(size
));
75 ret
= ioctl(netlink_fd
, FIONBIO
, &nonblock
);
77 SPDK_ERRLOG("ioctl(FIONBIO) failed\n");
82 if (bind(netlink_fd
, (struct sockaddr
*) &addr
, sizeof(addr
)) < 0) {
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
92 * action: "add" or "remove"
94 * dev_path: "/devices/pci0000:80/0000:80:01.0/0000:81:00.0/uio/uio0"
97 parse_event(const char *buf
, struct spdk_uevent
*event
)
100 char action
[SPDK_UEVENT_MSG_LEN
];
101 char subsystem
[SPDK_UEVENT_MSG_LEN
];
102 char dev_path
[SPDK_UEVENT_MSG_LEN
];
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
);
109 if (!strncmp(buf
, "ACTION=", 7)) {
111 snprintf(action
, sizeof(action
), "%s", buf
);
112 } else if (!strncmp(buf
, "DEVPATH=", 8)) {
114 snprintf(dev_path
, sizeof(dev_path
), "%s", buf
);
115 } else if (!strncmp(buf
, "SUBSYSTEM=", 10)) {
117 snprintf(subsystem
, sizeof(subsystem
), "%s", buf
);
123 if (!strncmp(subsystem
, "uio", 3)) {
124 char *pci_address
, *tmp
;
125 unsigned int domain
, bus
, dev
, func
;
127 event
->subsystem
= SPDK_NVME_UEVENT_SUBSYSTEM_UIO
;
128 if (!strncmp(action
, "add", 3)) {
129 event
->action
= SPDK_NVME_UEVENT_ADD
;
131 if (!strncmp(action
, "remove", 6)) {
132 event
->action
= SPDK_NVME_UEVENT_REMOVE
;
134 tmp
= strstr(dev_path
, "/uio/");
136 memset(tmp
, 0, SPDK_UEVENT_MSG_LEN
- (tmp
- dev_path
));
138 pci_address
= strrchr(dev_path
, '/');
140 ret
= sscanf(pci_address
, "%x:%x:%x.%x", &domain
, &bus
, &dev
, &func
);
142 SPDK_ERRLOG("Invalid format for NVMe BDF: %s\n", pci_address
);
144 snprintf(event
->traddr
, sizeof(event
->traddr
), TRADDR_FMT
, domain
, bus
, dev
, func
);
151 spdk_get_uevent(int fd
, struct spdk_uevent
*uevent
)
154 char buf
[SPDK_UEVENT_MSG_LEN
];
156 memset(uevent
, 0, sizeof(struct spdk_uevent
));
157 memset(buf
, 0, SPDK_UEVENT_MSG_LEN
);
159 ret
= recv(fd
, buf
, SPDK_UEVENT_MSG_LEN
- 1, MSG_DONTWAIT
);
161 return parse_event(buf
, uevent
);
165 if (errno
== EAGAIN
|| errno
== EWOULDBLOCK
) {
168 SPDK_ERRLOG("Socket read error(%d): %s\n", errno
, strerror(errno
));
173 /* connection closed */
180 #else /* Not Linux */
183 spdk_uevent_connect(void)
189 spdk_get_uevent(int fd
, struct spdk_uevent
*uevent
)