xref: /openbmc/linux/drivers/block/aoe/aoenet.c (revision 64c70b1c)
1 /* Copyright (c) 2006 Coraid, Inc.  See COPYING for GPL terms. */
2 /*
3  * aoenet.c
4  * Ethernet portion of AoE driver
5  */
6 
7 #include <linux/hdreg.h>
8 #include <linux/blkdev.h>
9 #include <linux/netdevice.h>
10 #include <linux/moduleparam.h>
11 #include <asm/unaligned.h>
12 #include "aoe.h"
13 
14 #define NECODES 5
15 
16 static char *aoe_errlist[] =
17 {
18 	"no such error",
19 	"unrecognized command code",
20 	"bad argument parameter",
21 	"device unavailable",
22 	"config string present",
23 	"unsupported version"
24 };
25 
26 enum {
27 	IFLISTSZ = 1024,
28 };
29 
30 static char aoe_iflist[IFLISTSZ];
31 module_param_string(aoe_iflist, aoe_iflist, IFLISTSZ, 0600);
32 MODULE_PARM_DESC(aoe_iflist, "aoe_iflist=\"dev1 [dev2 ...]\"\n");
33 
34 #ifndef MODULE
35 static int __init aoe_iflist_setup(char *str)
36 {
37 	strncpy(aoe_iflist, str, IFLISTSZ);
38 	aoe_iflist[IFLISTSZ - 1] = '\0';
39 	return 1;
40 }
41 
42 __setup("aoe_iflist=", aoe_iflist_setup);
43 #endif
44 
45 int
46 is_aoe_netif(struct net_device *ifp)
47 {
48 	register char *p, *q;
49 	register int len;
50 
51 	if (aoe_iflist[0] == '\0')
52 		return 1;
53 
54 	p = aoe_iflist + strspn(aoe_iflist, WHITESPACE);
55 	for (; *p; p = q + strspn(q, WHITESPACE)) {
56 		q = p + strcspn(p, WHITESPACE);
57 		if (q != p)
58 			len = q - p;
59 		else
60 			len = strlen(p); /* last token in aoe_iflist */
61 
62 		if (strlen(ifp->name) == len && !strncmp(ifp->name, p, len))
63 			return 1;
64 		if (q == p)
65 			break;
66 	}
67 
68 	return 0;
69 }
70 
71 int
72 set_aoe_iflist(const char __user *user_str, size_t size)
73 {
74 	if (size >= IFLISTSZ)
75 		return -EINVAL;
76 
77 	if (copy_from_user(aoe_iflist, user_str, size)) {
78 		printk(KERN_INFO "aoe: copy from user failed\n");
79 		return -EFAULT;
80 	}
81 	aoe_iflist[size] = 0x00;
82 	return 0;
83 }
84 
85 u64
86 mac_addr(char addr[6])
87 {
88 	__be64 n = 0;
89 	char *p = (char *) &n;
90 
91 	memcpy(p + 2, addr, 6);	/* (sizeof addr != 6) */
92 
93 	return __be64_to_cpu(n);
94 }
95 
96 void
97 aoenet_xmit(struct sk_buff *sl)
98 {
99 	struct sk_buff *skb;
100 
101 	while ((skb = sl)) {
102 		sl = sl->next;
103 		skb->next = skb->prev = NULL;
104 		dev_queue_xmit(skb);
105 	}
106 }
107 
108 /*
109  * (1) len doesn't include the header by default.  I want this.
110  */
111 static int
112 aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt, struct net_device *orig_dev)
113 {
114 	struct aoe_hdr *h;
115 	u32 n;
116 
117 	skb = skb_share_check(skb, GFP_ATOMIC);
118 	if (skb == NULL)
119 		return 0;
120 	if (skb_linearize(skb))
121 		goto exit;
122 	if (!is_aoe_netif(ifp))
123 		goto exit;
124 	skb_push(skb, ETH_HLEN);	/* (1) */
125 
126 	h = aoe_hdr(skb);
127 	n = be32_to_cpu(get_unaligned(&h->tag));
128 	if ((h->verfl & AOEFL_RSP) == 0 || (n & 1<<31))
129 		goto exit;
130 
131 	if (h->verfl & AOEFL_ERR) {
132 		n = h->err;
133 		if (n > NECODES)
134 			n = 0;
135 		if (net_ratelimit())
136 			printk(KERN_ERR "aoe: error packet from %d.%d; ecode=%d '%s'\n",
137 			       be16_to_cpu(get_unaligned(&h->major)), h->minor,
138 			       h->err, aoe_errlist[n]);
139 		goto exit;
140 	}
141 
142 	switch (h->cmd) {
143 	case AOECMD_ATA:
144 		aoecmd_ata_rsp(skb);
145 		break;
146 	case AOECMD_CFG:
147 		aoecmd_cfg_rsp(skb);
148 		break;
149 	default:
150 		printk(KERN_INFO "aoe: unknown cmd %d\n", h->cmd);
151 	}
152 exit:
153 	dev_kfree_skb(skb);
154 	return 0;
155 }
156 
157 static struct packet_type aoe_pt = {
158 	.type = __constant_htons(ETH_P_AOE),
159 	.func = aoenet_rcv,
160 };
161 
162 int __init
163 aoenet_init(void)
164 {
165 	dev_add_pack(&aoe_pt);
166 	return 0;
167 }
168 
169 void
170 aoenet_exit(void)
171 {
172 	dev_remove_pack(&aoe_pt);
173 }
174 
175