ACPI: Make _OSI(Linux) a special case
[pv_ops_mirror.git] / drivers / block / aoe / aoenet.c
blobf9ddfda4d9cb5945e3800e4a6865691e6069765f
1 /* Copyright (c) 2006 Coraid, Inc. See COPYING for GPL terms. */
2 /*
3 * aoenet.c
4 * Ethernet portion of AoE driver
5 */
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"
14 #define NECODES 5
16 static char *aoe_errlist[] =
18 "no such error",
19 "unrecognized command code",
20 "bad argument parameter",
21 "device unavailable",
22 "config string present",
23 "unsupported version"
26 enum {
27 IFLISTSZ = 1024,
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");
34 #ifndef MODULE
35 static int __init aoe_iflist_setup(char *str)
37 strncpy(aoe_iflist, str, IFLISTSZ);
38 aoe_iflist[IFLISTSZ - 1] = '\0';
39 return 1;
42 __setup("aoe_iflist=", aoe_iflist_setup);
43 #endif
45 int
46 is_aoe_netif(struct net_device *ifp)
48 register char *p, *q;
49 register int len;
51 if (aoe_iflist[0] == '\0')
52 return 1;
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 */
62 if (strlen(ifp->name) == len && !strncmp(ifp->name, p, len))
63 return 1;
64 if (q == p)
65 break;
68 return 0;
71 int
72 set_aoe_iflist(const char __user *user_str, size_t size)
74 if (size >= IFLISTSZ)
75 return -EINVAL;
77 if (copy_from_user(aoe_iflist, user_str, size)) {
78 printk(KERN_INFO "aoe: copy from user failed\n");
79 return -EFAULT;
81 aoe_iflist[size] = 0x00;
82 return 0;
85 u64
86 mac_addr(char addr[6])
88 __be64 n = 0;
89 char *p = (char *) &n;
91 memcpy(p + 2, addr, 6); /* (sizeof addr != 6) */
93 return __be64_to_cpu(n);
96 void
97 aoenet_xmit(struct sk_buff *sl)
99 struct sk_buff *skb;
101 while ((skb = sl)) {
102 sl = sl->next;
103 skb->next = skb->prev = NULL;
104 dev_queue_xmit(skb);
109 * (1) len doesn't include the header by default. I want this.
111 static int
112 aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt, struct net_device *orig_dev)
114 struct aoe_hdr *h;
115 u32 n;
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) */
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;
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;
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);
152 exit:
153 dev_kfree_skb(skb);
154 return 0;
157 static struct packet_type aoe_pt = {
158 .type = __constant_htons(ETH_P_AOE),
159 .func = aoenet_rcv,
162 int __init
163 aoenet_init(void)
165 dev_add_pack(&aoe_pt);
166 return 0;
169 void
170 aoenet_exit(void)
172 dev_remove_pack(&aoe_pt);