1 | /* Copyright (c) 2013 Coraid, Inc. See COPYING for GPL terms. */ |
2 | /* |
3 | * aoenet.c |
4 | * Ethernet portion of AoE driver |
5 | */ |
6 | |
7 | #include <linux/gfp.h> |
8 | #include <linux/hdreg.h> |
9 | #include <linux/blkdev.h> |
10 | #include <linux/netdevice.h> |
11 | #include <linux/moduleparam.h> |
12 | #include <net/net_namespace.h> |
13 | #include <asm/unaligned.h> |
14 | #include "aoe.h" |
15 | |
16 | #define NECODES 5 |
17 | |
18 | static char *aoe_errlist[] = |
19 | { |
20 | "no such error" , |
21 | "unrecognized command code" , |
22 | "bad argument parameter" , |
23 | "device unavailable" , |
24 | "config string present" , |
25 | "unsupported version" |
26 | }; |
27 | |
28 | enum { |
29 | IFLISTSZ = 1024, |
30 | }; |
31 | |
32 | static char aoe_iflist[IFLISTSZ]; |
33 | module_param_string(aoe_iflist, aoe_iflist, IFLISTSZ, 0600); |
34 | MODULE_PARM_DESC(aoe_iflist, "aoe_iflist=dev1[,dev2...]" ); |
35 | |
36 | static wait_queue_head_t txwq; |
37 | static struct ktstate kts; |
38 | |
39 | #ifndef MODULE |
40 | static int __init aoe_iflist_setup(char *str) |
41 | { |
42 | strscpy(aoe_iflist, str, IFLISTSZ); |
43 | return 1; |
44 | } |
45 | |
46 | __setup("aoe_iflist=" , aoe_iflist_setup); |
47 | #endif |
48 | |
49 | static spinlock_t txlock; |
50 | static struct sk_buff_head skbtxq; |
51 | |
52 | /* enters with txlock held */ |
53 | static int |
54 | tx(int id) __must_hold(&txlock) |
55 | { |
56 | struct sk_buff *skb; |
57 | struct net_device *ifp; |
58 | |
59 | while ((skb = skb_dequeue(list: &skbtxq))) { |
60 | spin_unlock_irq(lock: &txlock); |
61 | ifp = skb->dev; |
62 | if (dev_queue_xmit(skb) == NET_XMIT_DROP && net_ratelimit()) |
63 | pr_warn("aoe: packet could not be sent on %s. %s\n" , |
64 | ifp ? ifp->name : "netif" , |
65 | "consider increasing tx_queue_len" ); |
66 | dev_put(dev: ifp); |
67 | spin_lock_irq(lock: &txlock); |
68 | } |
69 | return 0; |
70 | } |
71 | |
72 | int |
73 | is_aoe_netif(struct net_device *ifp) |
74 | { |
75 | register char *p, *q; |
76 | register int len; |
77 | |
78 | if (aoe_iflist[0] == '\0') |
79 | return 1; |
80 | |
81 | p = aoe_iflist + strspn(aoe_iflist, WHITESPACE); |
82 | for (; *p; p = q + strspn(q, WHITESPACE)) { |
83 | q = p + strcspn(p, WHITESPACE); |
84 | if (q != p) |
85 | len = q - p; |
86 | else |
87 | len = strlen(p); /* last token in aoe_iflist */ |
88 | |
89 | if (strlen(ifp->name) == len && !strncmp(ifp->name, p, len)) |
90 | return 1; |
91 | if (q == p) |
92 | break; |
93 | } |
94 | |
95 | return 0; |
96 | } |
97 | |
98 | int |
99 | set_aoe_iflist(const char __user *user_str, size_t size) |
100 | { |
101 | if (size >= IFLISTSZ) |
102 | return -EINVAL; |
103 | |
104 | if (copy_from_user(to: aoe_iflist, from: user_str, n: size)) { |
105 | printk(KERN_INFO "aoe: copy from user failed\n" ); |
106 | return -EFAULT; |
107 | } |
108 | aoe_iflist[size] = 0x00; |
109 | return 0; |
110 | } |
111 | |
112 | void |
113 | aoenet_xmit(struct sk_buff_head *queue) |
114 | { |
115 | struct sk_buff *skb, *tmp; |
116 | ulong flags; |
117 | |
118 | skb_queue_walk_safe(queue, skb, tmp) { |
119 | __skb_unlink(skb, list: queue); |
120 | spin_lock_irqsave(&txlock, flags); |
121 | skb_queue_tail(list: &skbtxq, newsk: skb); |
122 | spin_unlock_irqrestore(lock: &txlock, flags); |
123 | wake_up(&txwq); |
124 | } |
125 | } |
126 | |
127 | /* |
128 | * (1) len doesn't include the header by default. I want this. |
129 | */ |
130 | static int |
131 | aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt, struct net_device *orig_dev) |
132 | { |
133 | struct aoe_hdr *h; |
134 | struct aoe_atahdr *ah; |
135 | u32 n; |
136 | int sn; |
137 | |
138 | if (dev_net(dev: ifp) != &init_net) |
139 | goto exit; |
140 | |
141 | skb = skb_share_check(skb, GFP_ATOMIC); |
142 | if (skb == NULL) |
143 | return 0; |
144 | if (!is_aoe_netif(ifp)) |
145 | goto exit; |
146 | skb_push(skb, ETH_HLEN); /* (1) */ |
147 | sn = sizeof(*h) + sizeof(*ah); |
148 | if (skb->len >= sn) { |
149 | sn -= skb_headlen(skb); |
150 | if (sn > 0 && !__pskb_pull_tail(skb, delta: sn)) |
151 | goto exit; |
152 | } |
153 | h = (struct aoe_hdr *) skb->data; |
154 | n = get_unaligned_be32(p: &h->tag); |
155 | if ((h->verfl & AOEFL_RSP) == 0 || (n & 1<<31)) |
156 | goto exit; |
157 | |
158 | if (h->verfl & AOEFL_ERR) { |
159 | n = h->err; |
160 | if (n > NECODES) |
161 | n = 0; |
162 | if (net_ratelimit()) |
163 | printk(KERN_ERR |
164 | "%s%d.%d@%s; ecode=%d '%s'\n" , |
165 | "aoe: error packet from " , |
166 | get_unaligned_be16(&h->major), |
167 | h->minor, skb->dev->name, |
168 | h->err, aoe_errlist[n]); |
169 | goto exit; |
170 | } |
171 | |
172 | switch (h->cmd) { |
173 | case AOECMD_ATA: |
174 | /* ata_rsp may keep skb for later processing or give it back */ |
175 | skb = aoecmd_ata_rsp(skb); |
176 | break; |
177 | case AOECMD_CFG: |
178 | aoecmd_cfg_rsp(skb); |
179 | break; |
180 | default: |
181 | if (h->cmd >= AOECMD_VEND_MIN) |
182 | break; /* don't complain about vendor commands */ |
183 | pr_info("aoe: unknown AoE command type 0x%02x\n" , h->cmd); |
184 | break; |
185 | } |
186 | |
187 | if (!skb) |
188 | return 0; |
189 | exit: |
190 | dev_kfree_skb(skb); |
191 | return 0; |
192 | } |
193 | |
194 | static struct packet_type aoe_pt __read_mostly = { |
195 | .type = __constant_htons(ETH_P_AOE), |
196 | .func = aoenet_rcv, |
197 | }; |
198 | |
199 | int __init |
200 | aoenet_init(void) |
201 | { |
202 | skb_queue_head_init(list: &skbtxq); |
203 | init_waitqueue_head(&txwq); |
204 | spin_lock_init(&txlock); |
205 | kts.lock = &txlock; |
206 | kts.fn = tx; |
207 | kts.waitq = &txwq; |
208 | kts.id = 0; |
209 | snprintf(buf: kts.name, size: sizeof(kts.name), fmt: "aoe_tx%d" , kts.id); |
210 | if (aoe_ktstart(k: &kts)) |
211 | return -EAGAIN; |
212 | dev_add_pack(pt: &aoe_pt); |
213 | return 0; |
214 | } |
215 | |
216 | void |
217 | aoenet_exit(void) |
218 | { |
219 | aoe_ktstop(k: &kts); |
220 | skb_queue_purge(list: &skbtxq); |
221 | dev_remove_pack(pt: &aoe_pt); |
222 | } |
223 | |
224 | |