IB:usnic: Add UDP support to usnic_transport.[hc]
[linux.git] / drivers / infiniband / hw / usnic / usnic_transport.c
1 /*
2  * Copyright (c) 2013, Cisco Systems, Inc. All rights reserved.
3  *
4  * This program is free software; you may redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; version 2 of the License.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
9  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
10  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
11  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
12  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
13  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
15  * SOFTWARE.
16  *
17  */
18 #include <linux/bitmap.h>
19 #include <linux/file.h>
20 #include <linux/module.h>
21 #include <linux/slab.h>
22 #include <net/inet_sock.h>
23
24 #include "usnic_transport.h"
25 #include "usnic_log.h"
26
27 /* ROCE */
28 static unsigned long *roce_bitmap;
29 static u16 roce_next_port = 1;
30 #define ROCE_BITMAP_SZ ((1 << (8 /*CHAR_BIT*/ * sizeof(u16)))/8 /*CHAR BIT*/)
31 static DEFINE_SPINLOCK(roce_bitmap_lock);
32
33 const char *usnic_transport_to_str(enum usnic_transport_type type)
34 {
35         switch (type) {
36         case USNIC_TRANSPORT_UNKNOWN:
37                 return "Unknown";
38         case USNIC_TRANSPORT_ROCE_CUSTOM:
39                 return "roce custom";
40         case USNIC_TRANSPORT_IPV4_UDP:
41                 return "IPv4 UDP";
42         case USNIC_TRANSPORT_MAX:
43                 return "Max?";
44         default:
45                 return "Not known";
46         }
47 }
48
49 int usnic_transport_sock_to_str(char *buf, int buf_sz,
50                                         struct socket *sock)
51 {
52         int err;
53         uint32_t addr;
54         uint16_t port;
55         int proto;
56
57         memset(buf, 0, buf_sz);
58         err = usnic_transport_sock_get_addr(sock, &proto, &addr, &port);
59         if (err)
60                 return 0;
61
62         addr = htonl(addr);
63         return scnprintf(buf, buf_sz, "Proto:%u Addr:%pI4 Port:%hu",
64                         proto, &addr, port);
65 }
66
67 /*
68  * reserve a port number.  if "0" specified, we will try to pick one
69  * starting at roce_next_port.  roce_next_port will take on the values
70  * 1..4096
71  */
72 u16 usnic_transport_rsrv_port(enum usnic_transport_type type, u16 port_num)
73 {
74         if (type == USNIC_TRANSPORT_ROCE_CUSTOM) {
75                 spin_lock(&roce_bitmap_lock);
76                 if (!port_num) {
77                         port_num = bitmap_find_next_zero_area(roce_bitmap,
78                                                 ROCE_BITMAP_SZ,
79                                                 roce_next_port /* start */,
80                                                 1 /* nr */,
81                                                 0 /* align */);
82                         roce_next_port = (port_num & 4095) + 1;
83                 } else if (test_bit(port_num, roce_bitmap)) {
84                         usnic_err("Failed to allocate port for %s\n",
85                                         usnic_transport_to_str(type));
86                         spin_unlock(&roce_bitmap_lock);
87                         goto out_fail;
88                 }
89                 bitmap_set(roce_bitmap, port_num, 1);
90                 spin_unlock(&roce_bitmap_lock);
91         } else {
92                 usnic_err("Failed to allocate port - transport %s unsupported\n",
93                                 usnic_transport_to_str(type));
94                 goto out_fail;
95         }
96
97         usnic_dbg("Allocating port %hu for %s\n", port_num,
98                         usnic_transport_to_str(type));
99         return port_num;
100
101 out_fail:
102         return 0;
103 }
104
105 void usnic_transport_unrsrv_port(enum usnic_transport_type type, u16 port_num)
106 {
107         if (type == USNIC_TRANSPORT_ROCE_CUSTOM) {
108                 spin_lock(&roce_bitmap_lock);
109                 if (!port_num) {
110                         usnic_err("Unreserved unvalid port num 0 for %s\n",
111                                         usnic_transport_to_str(type));
112                         goto out_roce_custom;
113                 }
114
115                 if (!test_bit(port_num, roce_bitmap)) {
116                         usnic_err("Unreserving invalid %hu for %s\n",
117                                         port_num,
118                                         usnic_transport_to_str(type));
119                         goto out_roce_custom;
120                 }
121                 bitmap_clear(roce_bitmap, port_num, 1);
122                 usnic_dbg("Freeing port %hu for %s\n", port_num,
123                                 usnic_transport_to_str(type));
124 out_roce_custom:
125                 spin_unlock(&roce_bitmap_lock);
126         } else {
127                 usnic_err("Freeing invalid port %hu for %d\n", port_num, type);
128         }
129 }
130
131 struct socket *usnic_transport_get_socket(int sock_fd)
132 {
133         struct socket *sock;
134         int err;
135         char buf[25];
136
137         /* sockfd_lookup will internally do a fget */
138         sock = sockfd_lookup(sock_fd, &err);
139         if (!sock) {
140                 usnic_err("Unable to lookup socket for fd %d with err %d\n",
141                                 sock_fd, err);
142                 return ERR_PTR(-ENOENT);
143         }
144
145         usnic_transport_sock_to_str(buf, sizeof(buf), sock);
146         usnic_dbg("Get sock %s\n", buf);
147
148         return sock;
149 }
150
151 void usnic_transport_put_socket(struct socket *sock)
152 {
153         char buf[100];
154
155         usnic_transport_sock_to_str(buf, sizeof(buf), sock);
156         usnic_dbg("Put sock %s\n", buf);
157         sockfd_put(sock);
158 }
159
160 int usnic_transport_sock_get_addr(struct socket *sock, int *proto,
161                                         uint32_t *addr, uint16_t *port)
162 {
163         int len;
164         int err;
165         struct sockaddr_in sock_addr;
166
167         err = sock->ops->getname(sock,
168                                 (struct sockaddr *)&sock_addr,
169                                 &len, 0);
170         if (err)
171                 return err;
172
173         if (sock_addr.sin_family != AF_INET)
174                 return -EINVAL;
175
176         if (proto)
177                 *proto = sock->sk->sk_protocol;
178         if (port)
179                 *port = ntohs(((struct sockaddr_in *)&sock_addr)->sin_port);
180         if (addr)
181                 *addr = ntohl(((struct sockaddr_in *)
182                                         &sock_addr)->sin_addr.s_addr);
183
184         return 0;
185 }
186
187
188 int usnic_transport_init(void)
189 {
190         roce_bitmap = kzalloc(ROCE_BITMAP_SZ, GFP_KERNEL);
191         if (!roce_bitmap) {
192                 usnic_err("Failed to allocate bit map");
193                 return -ENOMEM;
194         }
195
196         /* Do not ever allocate bit 0, hence set it here */
197         bitmap_set(roce_bitmap, 0, 1);
198         return 0;
199 }
200
201 void usnic_transport_fini(void)
202 {
203         kfree(roce_bitmap);
204 }