blob: f9ddfda4d9cb5945e3800e4a6865691e6069765f [file] [log] [blame]
Ed L. Cashin26114642006-09-20 14:36:48 -04001/* Copyright (c) 2006 Coraid, Inc. See COPYING for GPL terms. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002/*
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>
Ed L Cashin03c41c42005-04-29 10:24:03 -040010#include <linux/moduleparam.h>
David S. Miller43ecf522007-03-01 18:30:08 -080011#include <asm/unaligned.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070012#include "aoe.h"
13
14#define NECODES 5
15
16static 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
26enum {
27 IFLISTSZ = 1024,
28};
29
30static char aoe_iflist[IFLISTSZ];
Ed L Cashin03c41c42005-04-29 10:24:03 -040031module_param_string(aoe_iflist, aoe_iflist, IFLISTSZ, 0600);
32MODULE_PARM_DESC(aoe_iflist, "aoe_iflist=\"dev1 [dev2 ...]\"\n");
33
34#ifndef MODULE
35static 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
Linus Torvalds1da177e2005-04-16 15:20:36 -070044
45int
46is_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
Ed L Cashin03c41c42005-04-29 10:24:03 -040054 p = aoe_iflist + strspn(aoe_iflist, WHITESPACE);
55 for (; *p; p = q + strspn(q, WHITESPACE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070056 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
71int
72set_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)) {
Ed L. Cashina12c93f2006-09-20 14:36:51 -040078 printk(KERN_INFO "aoe: copy from user failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -070079 return -EFAULT;
80 }
81 aoe_iflist[size] = 0x00;
82 return 0;
83}
84
85u64
86mac_addr(char addr[6])
87{
ecashin@coraid.com63e9cc52005-04-18 22:00:20 -070088 __be64 n = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070089 char *p = (char *) &n;
90
91 memcpy(p + 2, addr, 6); /* (sizeof addr != 6) */
92
93 return __be64_to_cpu(n);
94}
95
Linus Torvalds1da177e2005-04-16 15:20:36 -070096void
97aoenet_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 */
111static int
David S. Millerf2ccd8f2005-08-09 19:34:12 -0700112aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt, struct net_device *orig_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113{
114 struct aoe_hdr *h;
ecashin@coraid.com63e9cc52005-04-18 22:00:20 -0700115 u32 n;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116
Ed L. Cashin5dc401e2006-02-07 11:26:39 -0500117 skb = skb_share_check(skb, GFP_ATOMIC);
118 if (skb == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119 return 0;
Herbert Xu364c6ba2006-06-09 16:10:40 -0700120 if (skb_linearize(skb))
Ed L. Cashin5dc401e2006-02-07 11:26:39 -0500121 goto exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122 if (!is_aoe_netif(ifp))
123 goto exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124 skb_push(skb, ETH_HLEN); /* (1) */
125
Arnaldo Carvalho de Melo029720f2007-03-10 11:20:07 -0300126 h = aoe_hdr(skb);
David S. Miller43ecf522007-03-01 18:30:08 -0800127 n = be32_to_cpu(get_unaligned(&h->tag));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128 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())
Ed L. Cashina12c93f2006-09-20 14:36:51 -0400136 printk(KERN_ERR "aoe: error packet from %d.%d; ecode=%d '%s'\n",
David S. Miller43ecf522007-03-01 18:30:08 -0800137 be16_to_cpu(get_unaligned(&h->major)), h->minor,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138 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:
Ed L. Cashina12c93f2006-09-20 14:36:51 -0400150 printk(KERN_INFO "aoe: unknown cmd %d\n", h->cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151 }
152exit:
153 dev_kfree_skb(skb);
154 return 0;
155}
156
157static struct packet_type aoe_pt = {
158 .type = __constant_htons(ETH_P_AOE),
159 .func = aoenet_rcv,
160};
161
162int __init
163aoenet_init(void)
164{
165 dev_add_pack(&aoe_pt);
166 return 0;
167}
168
169void
170aoenet_exit(void)
171{
172 dev_remove_pack(&aoe_pt);
173}
174