aoenet.c revision e730c15519d09ea528b4d2f1103681fa5937c0e6
12611464d7f36685fb1990275d3de1e72e6aff9d9Ed L. Cashin/* Copyright (c) 2006 Coraid, Inc.  See COPYING for GPL terms. */
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * aoenet.c
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Ethernet portion of AoE driver
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/hdreg.h>
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/blkdev.h>
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netdevice.h>
1003c41c434775c52092d17a5031ad8ebaaf555bc4Ed L. Cashin#include <linux/moduleparam.h>
11e730c15519d09ea528b4d2f1103681fa5937c0e6Eric W. Biederman#include <net/net_namespace.h>
1243ecf5295b622e9ec93f5b932949acf1c6e4150cDavid S. Miller#include <asm/unaligned.h>
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "aoe.h"
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define NECODES 5
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char *aoe_errlist[] =
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"no such error",
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"unrecognized command code",
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"bad argument parameter",
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"device unavailable",
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"config string present",
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"unsupported version"
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum {
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IFLISTSZ = 1024,
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char aoe_iflist[IFLISTSZ];
3203c41c434775c52092d17a5031ad8ebaaf555bc4Ed L. Cashinmodule_param_string(aoe_iflist, aoe_iflist, IFLISTSZ, 0600);
3303c41c434775c52092d17a5031ad8ebaaf555bc4Ed L. CashinMODULE_PARM_DESC(aoe_iflist, "aoe_iflist=\"dev1 [dev2 ...]\"\n");
3403c41c434775c52092d17a5031ad8ebaaf555bc4Ed L. Cashin
3503c41c434775c52092d17a5031ad8ebaaf555bc4Ed L. Cashin#ifndef MODULE
3603c41c434775c52092d17a5031ad8ebaaf555bc4Ed L. Cashinstatic int __init aoe_iflist_setup(char *str)
3703c41c434775c52092d17a5031ad8ebaaf555bc4Ed L. Cashin{
3803c41c434775c52092d17a5031ad8ebaaf555bc4Ed L. Cashin	strncpy(aoe_iflist, str, IFLISTSZ);
3903c41c434775c52092d17a5031ad8ebaaf555bc4Ed L. Cashin	aoe_iflist[IFLISTSZ - 1] = '\0';
4003c41c434775c52092d17a5031ad8ebaaf555bc4Ed L. Cashin	return 1;
4103c41c434775c52092d17a5031ad8ebaaf555bc4Ed L. Cashin}
4203c41c434775c52092d17a5031ad8ebaaf555bc4Ed L. Cashin
4303c41c434775c52092d17a5031ad8ebaaf555bc4Ed L. Cashin__setup("aoe_iflist=", aoe_iflist_setup);
4403c41c434775c52092d17a5031ad8ebaaf555bc4Ed L. Cashin#endif
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsis_aoe_netif(struct net_device *ifp)
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	register char *p, *q;
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	register int len;
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (aoe_iflist[0] == '\0')
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5503c41c434775c52092d17a5031ad8ebaaf555bc4Ed L. Cashin	p = aoe_iflist + strspn(aoe_iflist, WHITESPACE);
5603c41c434775c52092d17a5031ad8ebaaf555bc4Ed L. Cashin	for (; *p; p = q + strspn(q, WHITESPACE)) {
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		q = p + strcspn(p, WHITESPACE);
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (q != p)
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			len = q - p;
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			len = strlen(p); /* last token in aoe_iflist */
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (strlen(ifp->name) == len && !strncmp(ifp->name, p, len))
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 1;
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (q == p)
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsset_aoe_iflist(const char __user *user_str, size_t size)
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (size >= IFLISTSZ)
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (copy_from_user(aoe_iflist, user_str, size)) {
79a12c93f08b8fc83b7fcdabaf92b1adcea7489f5eEd L. Cashin		printk(KERN_INFO "aoe: copy from user failed\n");
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	aoe_iflist[size] = 0x00;
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsu64
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmac_addr(char addr[6])
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8963e9cc5d6fbe8b58ea1ee96439d356cbf726fbc0Ed L. Cashin	__be64 n = 0;
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char *p = (char *) &n;
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memcpy(p + 2, addr, 6);	/* (sizeof addr != 6) */
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return __be64_to_cpu(n);
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsaoenet_xmit(struct sk_buff *sl)
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sk_buff *skb;
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while ((skb = sl)) {
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sl = sl->next;
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		skb->next = skb->prev = NULL;
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_queue_xmit(skb);
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (1) len doesn't include the header by default.  I want this.
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
113f2ccd8fa06c8e302116e71df372f5c1f83432e03David S. Milleraoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt, struct net_device *orig_dev)
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct aoe_hdr *h;
11663e9cc5d6fbe8b58ea1ee96439d356cbf726fbc0Ed L. Cashin	u32 n;
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
118e730c15519d09ea528b4d2f1103681fa5937c0e6Eric W. Biederman	if (ifp->nd_net != &init_net)
119e730c15519d09ea528b4d2f1103681fa5937c0e6Eric W. Biederman		goto exit;
120e730c15519d09ea528b4d2f1103681fa5937c0e6Eric W. Biederman
1215dc401ee74c5d6a24867acd8302c55da9ae4f0ceEd L. Cashin	skb = skb_share_check(skb, GFP_ATOMIC);
1225dc401ee74c5d6a24867acd8302c55da9ae4f0ceEd L. Cashin	if (skb == NULL)
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
124364c6badde0dd62a0a38e5ed67f85d87d6665780Herbert Xu	if (skb_linearize(skb))
1255dc401ee74c5d6a24867acd8302c55da9ae4f0ceEd L. Cashin		goto exit;
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!is_aoe_netif(ifp))
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto exit;
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb_push(skb, ETH_HLEN);	/* (1) */
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
130029720f15dcd3c6c16824177cfc486083b229411Arnaldo Carvalho de Melo	h = aoe_hdr(skb);
13143ecf5295b622e9ec93f5b932949acf1c6e4150cDavid S. Miller	n = be32_to_cpu(get_unaligned(&h->tag));
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((h->verfl & AOEFL_RSP) == 0 || (n & 1<<31))
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto exit;
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (h->verfl & AOEFL_ERR) {
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		n = h->err;
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (n > NECODES)
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			n = 0;
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (net_ratelimit())
140a12c93f08b8fc83b7fcdabaf92b1adcea7489f5eEd L. Cashin			printk(KERN_ERR "aoe: error packet from %d.%d; ecode=%d '%s'\n",
14143ecf5295b622e9ec93f5b932949acf1c6e4150cDavid S. Miller			       be16_to_cpu(get_unaligned(&h->major)), h->minor,
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       h->err, aoe_errlist[n]);
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto exit;
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (h->cmd) {
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case AOECMD_ATA:
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		aoecmd_ata_rsp(skb);
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case AOECMD_CFG:
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		aoecmd_cfg_rsp(skb);
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
154a12c93f08b8fc83b7fcdabaf92b1adcea7489f5eEd L. Cashin		printk(KERN_INFO "aoe: unknown cmd %d\n", h->cmd);
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit:
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev_kfree_skb(skb);
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct packet_type aoe_pt = {
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.type = __constant_htons(ETH_P_AOE),
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.func = aoenet_rcv,
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint __init
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsaoenet_init(void)
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev_add_pack(&aoe_pt);
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsaoenet_exit(void)
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev_remove_pack(&aoe_pt);
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
179