152e112b3ab6b2b35a144565c8ea3bdda1e2845f2Ed L. Cashin/* Copyright (c) 2007 Coraid, Inc. See COPYING for GPL terms. */ 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * aoenet.c 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Ethernet portion of AoE driver 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 75a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/gfp.h> 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/hdreg.h> 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/blkdev.h> 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netdevice.h> 1103c41c434775c52092d17a5031ad8ebaaf555bc4Ed L. Cashin#include <linux/moduleparam.h> 12e730c15519d09ea528b4d2f1103681fa5937c0e6Eric W. Biederman#include <net/net_namespace.h> 1343ecf5295b622e9ec93f5b932949acf1c6e4150cDavid S. Miller#include <asm/unaligned.h> 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "aoe.h" 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define NECODES 5 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char *aoe_errlist[] = 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "no such error", 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "unrecognized command code", 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "bad argument parameter", 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "device unavailable", 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "config string present", 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "unsupported version" 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum { 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IFLISTSZ = 1024, 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char aoe_iflist[IFLISTSZ]; 3303c41c434775c52092d17a5031ad8ebaaf555bc4Ed L. Cashinmodule_param_string(aoe_iflist, aoe_iflist, IFLISTSZ, 0600); 3461a2d07d3fb1ac34d142b9b62d4cd60a0f8c229eNiels de VosMODULE_PARM_DESC(aoe_iflist, "aoe_iflist=\"dev1 [dev2 ...]\""); 3503c41c434775c52092d17a5031ad8ebaaf555bc4Ed L. Cashin 3603c41c434775c52092d17a5031ad8ebaaf555bc4Ed L. Cashin#ifndef MODULE 3703c41c434775c52092d17a5031ad8ebaaf555bc4Ed L. Cashinstatic int __init aoe_iflist_setup(char *str) 3803c41c434775c52092d17a5031ad8ebaaf555bc4Ed L. Cashin{ 3903c41c434775c52092d17a5031ad8ebaaf555bc4Ed L. Cashin strncpy(aoe_iflist, str, IFLISTSZ); 4003c41c434775c52092d17a5031ad8ebaaf555bc4Ed L. Cashin aoe_iflist[IFLISTSZ - 1] = '\0'; 4103c41c434775c52092d17a5031ad8ebaaf555bc4Ed L. Cashin return 1; 4203c41c434775c52092d17a5031ad8ebaaf555bc4Ed L. Cashin} 4303c41c434775c52092d17a5031ad8ebaaf555bc4Ed L. Cashin 4403c41c434775c52092d17a5031ad8ebaaf555bc4Ed L. Cashin__setup("aoe_iflist=", aoe_iflist_setup); 4503c41c434775c52092d17a5031ad8ebaaf555bc4Ed L. Cashin#endif 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsis_aoe_netif(struct net_device *ifp) 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds register char *p, *q; 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds register int len; 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (aoe_iflist[0] == '\0') 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5603c41c434775c52092d17a5031ad8ebaaf555bc4Ed L. Cashin p = aoe_iflist + strspn(aoe_iflist, WHITESPACE); 5703c41c434775c52092d17a5031ad8ebaaf555bc4Ed L. Cashin for (; *p; p = q + strspn(q, WHITESPACE)) { 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds q = p + strcspn(p, WHITESPACE); 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (q != p) 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = q - p; 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = strlen(p); /* last token in aoe_iflist */ 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (strlen(ifp->name) == len && !strncmp(ifp->name, p, len)) 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (q == p) 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsset_aoe_iflist(const char __user *user_str, size_t size) 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (size >= IFLISTSZ) 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_from_user(aoe_iflist, user_str, size)) { 80a12c93f08b8fc83b7fcdabaf92b1adcea7489f5eEd L. Cashin printk(KERN_INFO "aoe: copy from user failed\n"); 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds aoe_iflist[size] = 0x00; 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid 88e9bb8fb0b6d61a822201537b25206a0ca34b9d1dDavid S. Milleraoenet_xmit(struct sk_buff_head *queue) 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 90e9bb8fb0b6d61a822201537b25206a0ca34b9d1dDavid S. Miller struct sk_buff *skb, *tmp; 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 92d87798450a7635ab1bcc80271a13ce4a53b016a9David S. Miller skb_queue_walk_safe(queue, skb, tmp) { 93d87798450a7635ab1bcc80271a13ce4a53b016a9David S. Miller __skb_unlink(skb, queue); 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_queue_xmit(skb); 95d87798450a7635ab1bcc80271a13ce4a53b016a9David S. Miller } 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (1) len doesn't include the header by default. I want this. 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 102f2ccd8fa06c8e302116e71df372f5c1f83432e03David S. Milleraoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt, struct net_device *orig_dev) 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct aoe_hdr *h; 10563e9cc5d6fbe8b58ea1ee96439d356cbf726fbc0Ed L. Cashin u32 n; 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 107c346dca10840a874240c78efe3f39acf4312a1f2YOSHIFUJI Hideaki if (dev_net(ifp) != &init_net) 108e730c15519d09ea528b4d2f1103681fa5937c0e6Eric W. Biederman goto exit; 109e730c15519d09ea528b4d2f1103681fa5937c0e6Eric W. Biederman 1105dc401ee74c5d6a24867acd8302c55da9ae4f0ceEd L. Cashin skb = skb_share_check(skb, GFP_ATOMIC); 1115dc401ee74c5d6a24867acd8302c55da9ae4f0ceEd L. Cashin if (skb == NULL) 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 113364c6badde0dd62a0a38e5ed67f85d87d6665780Herbert Xu if (skb_linearize(skb)) 1145dc401ee74c5d6a24867acd8302c55da9ae4f0ceEd L. Cashin goto exit; 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!is_aoe_netif(ifp)) 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_push(skb, ETH_HLEN); /* (1) */ 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 119abdbf94d7c6f1fcb2931d5cb7562a6159323b704Ed L. Cashin h = (struct aoe_hdr *) skb_mac_header(skb); 120f885f8d127665e784a8071755243bd4e18f594d5Harvey Harrison n = get_unaligned_be32(&h->tag); 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((h->verfl & AOEFL_RSP) == 0 || (n & 1<<31)) 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (h->verfl & AOEFL_ERR) { 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds n = h->err; 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (n > NECODES) 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds n = 0; 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (net_ratelimit()) 12968e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin printk(KERN_ERR 13068e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin "%s%d.%d@%s; ecode=%d '%s'\n", 13168e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin "aoe: error packet from ", 132f885f8d127665e784a8071755243bd4e18f594d5Harvey Harrison get_unaligned_be16(&h->major), 13368e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin h->minor, skb->dev->name, 13468e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin h->err, aoe_errlist[n]); 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (h->cmd) { 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case AOECMD_ATA: 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds aoecmd_ata_rsp(skb); 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case AOECMD_CFG: 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds aoecmd_cfg_rsp(skb); 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 146b6d6c5175809934e04a606d9193ef04924a7a7d9Ed L. Cashin if (h->cmd >= AOECMD_VEND_MIN) 147b6d6c5175809934e04a606d9193ef04924a7a7d9Ed L. Cashin break; /* don't complain about vendor commands */ 148a12c93f08b8fc83b7fcdabaf92b1adcea7489f5eEd L. Cashin printk(KERN_INFO "aoe: unknown cmd %d\n", h->cmd); 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit: 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_kfree_skb(skb); 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1557546dd97d27306d939c13e03318aae695badaa88Stephen Hemmingerstatic struct packet_type aoe_pt __read_mostly = { 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .type = __constant_htons(ETH_P_AOE), 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .func = aoenet_rcv, 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint __init 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsaoenet_init(void) 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_add_pack(&aoe_pt); 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsaoenet_exit(void) 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_remove_pack(&aoe_pt); 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 173