mirror of https://gitee.com/openkylin/linux.git
Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/aoe-2.6
* master.kernel.org:/pub/scm/linux/kernel/git/gregkh/aoe-2.6: [PATCH] aoe [3/3]: update version to 22 [PATCH] aoe [2/3]: don't request ATA device ID on ATA error [PATCH] aoe [1/3]: support multiple AoE listeners [PATCH] aoe: do not stop retransmit timer when device goes down [PATCH] aoe [8/8]: update driver version number [PATCH] aoe [7/8]: update driver compatibility string [PATCH] aoe [6/8]: update device information on last close [PATCH] aoe [5/8]: allow network interface migration on packet retransmit [PATCH] aoe [4/8]: use less confusing driver name [PATCH] aoe [3/8]: increase allowed outstanding packets [PATCH] aoe [2/8]: support dynamic resizing of AoE devices [PATCH] aoe [1/8]: zero packet data after skb allocation
This commit is contained in:
commit
3661f00e20
|
@ -27,6 +27,8 @@ rm -f $dir/discover
|
||||||
mknod -m 0200 $dir/discover c $MAJOR 3
|
mknod -m 0200 $dir/discover c $MAJOR 3
|
||||||
rm -f $dir/interfaces
|
rm -f $dir/interfaces
|
||||||
mknod -m 0200 $dir/interfaces c $MAJOR 4
|
mknod -m 0200 $dir/interfaces c $MAJOR 4
|
||||||
|
rm -f $dir/revalidate
|
||||||
|
mknod -m 0200 $dir/revalidate c $MAJOR 5
|
||||||
|
|
||||||
export n_partitions
|
export n_partitions
|
||||||
mkshelf=`echo $0 | sed 's!mkdevs!mkshelf!'`
|
mkshelf=`echo $0 | sed 's!mkdevs!mkshelf!'`
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
SUBSYSTEM="aoe", KERNEL="discover", NAME="etherd/%k", GROUP="disk", MODE="0220"
|
SUBSYSTEM="aoe", KERNEL="discover", NAME="etherd/%k", GROUP="disk", MODE="0220"
|
||||||
SUBSYSTEM="aoe", KERNEL="err", NAME="etherd/%k", GROUP="disk", MODE="0440"
|
SUBSYSTEM="aoe", KERNEL="err", NAME="etherd/%k", GROUP="disk", MODE="0440"
|
||||||
SUBSYSTEM="aoe", KERNEL="interfaces", NAME="etherd/%k", GROUP="disk", MODE="0220"
|
SUBSYSTEM="aoe", KERNEL="interfaces", NAME="etherd/%k", GROUP="disk", MODE="0220"
|
||||||
|
SUBSYSTEM="aoe", KERNEL="revalidate", NAME="etherd/%k", GROUP="disk", MODE="0220"
|
||||||
|
|
||||||
# aoe block devices
|
# aoe block devices
|
||||||
KERNEL="etherd*", NAME="%k", GROUP="disk"
|
KERNEL="etherd*", NAME="%k", GROUP="disk"
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/* Copyright (c) 2004 Coraid, Inc. See COPYING for GPL terms. */
|
/* Copyright (c) 2004 Coraid, Inc. See COPYING for GPL terms. */
|
||||||
#define VERSION "14"
|
#define VERSION "22"
|
||||||
#define AOE_MAJOR 152
|
#define AOE_MAJOR 152
|
||||||
#define DEVICE_NAME "aoe"
|
#define DEVICE_NAME "aoe"
|
||||||
|
|
||||||
|
@ -75,8 +75,9 @@ enum {
|
||||||
DEVFL_TKILL = (1<<1), /* flag for timer to know when to kill self */
|
DEVFL_TKILL = (1<<1), /* flag for timer to know when to kill self */
|
||||||
DEVFL_EXT = (1<<2), /* device accepts lba48 commands */
|
DEVFL_EXT = (1<<2), /* device accepts lba48 commands */
|
||||||
DEVFL_CLOSEWAIT = (1<<3), /* device is waiting for all closes to revalidate */
|
DEVFL_CLOSEWAIT = (1<<3), /* device is waiting for all closes to revalidate */
|
||||||
DEVFL_WC_UPDATE = (1<<4), /* this device needs to update write cache status */
|
DEVFL_GDALLOC = (1<<4), /* need to alloc gendisk */
|
||||||
DEVFL_WORKON = (1<<4),
|
DEVFL_PAUSE = (1<<5),
|
||||||
|
DEVFL_NEWSIZE = (1<<6), /* need to update dev size in block layer */
|
||||||
|
|
||||||
BUFFL_FAIL = 1,
|
BUFFL_FAIL = 1,
|
||||||
};
|
};
|
||||||
|
@ -152,16 +153,17 @@ void aoechr_exit(void);
|
||||||
void aoechr_error(char *);
|
void aoechr_error(char *);
|
||||||
|
|
||||||
void aoecmd_work(struct aoedev *d);
|
void aoecmd_work(struct aoedev *d);
|
||||||
void aoecmd_cfg(ushort, unsigned char);
|
void aoecmd_cfg(ushort aoemajor, unsigned char aoeminor);
|
||||||
void aoecmd_ata_rsp(struct sk_buff *);
|
void aoecmd_ata_rsp(struct sk_buff *);
|
||||||
void aoecmd_cfg_rsp(struct sk_buff *);
|
void aoecmd_cfg_rsp(struct sk_buff *);
|
||||||
|
void aoecmd_sleepwork(void *vp);
|
||||||
|
|
||||||
int aoedev_init(void);
|
int aoedev_init(void);
|
||||||
void aoedev_exit(void);
|
void aoedev_exit(void);
|
||||||
struct aoedev *aoedev_by_aoeaddr(int maj, int min);
|
struct aoedev *aoedev_by_aoeaddr(int maj, int min);
|
||||||
|
struct aoedev *aoedev_by_sysminor_m(ulong sysminor, ulong bufcnt);
|
||||||
void aoedev_downdev(struct aoedev *d);
|
void aoedev_downdev(struct aoedev *d);
|
||||||
struct aoedev *aoedev_set(ulong, unsigned char *, struct net_device *, ulong);
|
int aoedev_isbusy(struct aoedev *d);
|
||||||
int aoedev_busy(void);
|
|
||||||
|
|
||||||
int aoenet_init(void);
|
int aoenet_init(void);
|
||||||
void aoenet_exit(void);
|
void aoenet_exit(void);
|
||||||
|
|
|
@ -22,7 +22,9 @@ static ssize_t aoedisk_show_state(struct gendisk * disk, char *page)
|
||||||
return snprintf(page, PAGE_SIZE,
|
return snprintf(page, PAGE_SIZE,
|
||||||
"%s%s\n",
|
"%s%s\n",
|
||||||
(d->flags & DEVFL_UP) ? "up" : "down",
|
(d->flags & DEVFL_UP) ? "up" : "down",
|
||||||
(d->flags & DEVFL_CLOSEWAIT) ? ",closewait" : "");
|
(d->flags & DEVFL_PAUSE) ? ",paused" :
|
||||||
|
(d->nopen && !(d->flags & DEVFL_UP)) ? ",closewait" : "");
|
||||||
|
/* I'd rather see nopen exported so we can ditch closewait */
|
||||||
}
|
}
|
||||||
static ssize_t aoedisk_show_mac(struct gendisk * disk, char *page)
|
static ssize_t aoedisk_show_mac(struct gendisk * disk, char *page)
|
||||||
{
|
{
|
||||||
|
@ -107,8 +109,7 @@ aoeblk_release(struct inode *inode, struct file *filp)
|
||||||
|
|
||||||
spin_lock_irqsave(&d->lock, flags);
|
spin_lock_irqsave(&d->lock, flags);
|
||||||
|
|
||||||
if (--d->nopen == 0 && (d->flags & DEVFL_CLOSEWAIT)) {
|
if (--d->nopen == 0) {
|
||||||
d->flags &= ~DEVFL_CLOSEWAIT;
|
|
||||||
spin_unlock_irqrestore(&d->lock, flags);
|
spin_unlock_irqrestore(&d->lock, flags);
|
||||||
aoecmd_cfg(d->aoemajor, d->aoeminor);
|
aoecmd_cfg(d->aoemajor, d->aoeminor);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -158,14 +159,14 @@ aoeblk_make_request(request_queue_t *q, struct bio *bio)
|
||||||
}
|
}
|
||||||
|
|
||||||
list_add_tail(&buf->bufs, &d->bufq);
|
list_add_tail(&buf->bufs, &d->bufq);
|
||||||
aoecmd_work(d);
|
|
||||||
|
|
||||||
|
aoecmd_work(d);
|
||||||
sl = d->sendq_hd;
|
sl = d->sendq_hd;
|
||||||
d->sendq_hd = d->sendq_tl = NULL;
|
d->sendq_hd = d->sendq_tl = NULL;
|
||||||
|
|
||||||
spin_unlock_irqrestore(&d->lock, flags);
|
spin_unlock_irqrestore(&d->lock, flags);
|
||||||
|
|
||||||
aoenet_xmit(sl);
|
aoenet_xmit(sl);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,7 +206,7 @@ aoeblk_gdalloc(void *vp)
|
||||||
printk(KERN_ERR "aoe: aoeblk_gdalloc: cannot allocate disk "
|
printk(KERN_ERR "aoe: aoeblk_gdalloc: cannot allocate disk "
|
||||||
"structure for %ld.%ld\n", d->aoemajor, d->aoeminor);
|
"structure for %ld.%ld\n", d->aoemajor, d->aoeminor);
|
||||||
spin_lock_irqsave(&d->lock, flags);
|
spin_lock_irqsave(&d->lock, flags);
|
||||||
d->flags &= ~DEVFL_WORKON;
|
d->flags &= ~DEVFL_GDALLOC;
|
||||||
spin_unlock_irqrestore(&d->lock, flags);
|
spin_unlock_irqrestore(&d->lock, flags);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -218,7 +219,7 @@ aoeblk_gdalloc(void *vp)
|
||||||
"for %ld.%ld\n", d->aoemajor, d->aoeminor);
|
"for %ld.%ld\n", d->aoemajor, d->aoeminor);
|
||||||
put_disk(gd);
|
put_disk(gd);
|
||||||
spin_lock_irqsave(&d->lock, flags);
|
spin_lock_irqsave(&d->lock, flags);
|
||||||
d->flags &= ~DEVFL_WORKON;
|
d->flags &= ~DEVFL_GDALLOC;
|
||||||
spin_unlock_irqrestore(&d->lock, flags);
|
spin_unlock_irqrestore(&d->lock, flags);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -235,18 +236,13 @@ aoeblk_gdalloc(void *vp)
|
||||||
|
|
||||||
gd->queue = &d->blkq;
|
gd->queue = &d->blkq;
|
||||||
d->gd = gd;
|
d->gd = gd;
|
||||||
d->flags &= ~DEVFL_WORKON;
|
d->flags &= ~DEVFL_GDALLOC;
|
||||||
d->flags |= DEVFL_UP;
|
d->flags |= DEVFL_UP;
|
||||||
|
|
||||||
spin_unlock_irqrestore(&d->lock, flags);
|
spin_unlock_irqrestore(&d->lock, flags);
|
||||||
|
|
||||||
add_disk(gd);
|
add_disk(gd);
|
||||||
aoedisk_add_sysfs(d);
|
aoedisk_add_sysfs(d);
|
||||||
|
|
||||||
printk(KERN_INFO "aoe: %012llx e%lu.%lu v%04x has %llu "
|
|
||||||
"sectors\n", (unsigned long long)mac_addr(d->addr),
|
|
||||||
d->aoemajor, d->aoeminor,
|
|
||||||
d->fw_ver, (long long)d->ssize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -13,6 +13,7 @@ enum {
|
||||||
MINOR_ERR = 2,
|
MINOR_ERR = 2,
|
||||||
MINOR_DISCOVER,
|
MINOR_DISCOVER,
|
||||||
MINOR_INTERFACES,
|
MINOR_INTERFACES,
|
||||||
|
MINOR_REVALIDATE,
|
||||||
MSGSZ = 2048,
|
MSGSZ = 2048,
|
||||||
NARGS = 10,
|
NARGS = 10,
|
||||||
NMSG = 100, /* message backlog to retain */
|
NMSG = 100, /* message backlog to retain */
|
||||||
|
@ -41,6 +42,7 @@ static struct aoe_chardev chardevs[] = {
|
||||||
{ MINOR_ERR, "err" },
|
{ MINOR_ERR, "err" },
|
||||||
{ MINOR_DISCOVER, "discover" },
|
{ MINOR_DISCOVER, "discover" },
|
||||||
{ MINOR_INTERFACES, "interfaces" },
|
{ MINOR_INTERFACES, "interfaces" },
|
||||||
|
{ MINOR_REVALIDATE, "revalidate" },
|
||||||
};
|
};
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -62,6 +64,39 @@ interfaces(const char __user *str, size_t size)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
revalidate(const char __user *str, size_t size)
|
||||||
|
{
|
||||||
|
int major, minor, n;
|
||||||
|
ulong flags;
|
||||||
|
struct aoedev *d;
|
||||||
|
char buf[16];
|
||||||
|
|
||||||
|
if (size >= sizeof buf)
|
||||||
|
return -EINVAL;
|
||||||
|
buf[sizeof buf - 1] = '\0';
|
||||||
|
if (copy_from_user(buf, str, size))
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
/* should be e%d.%d format */
|
||||||
|
n = sscanf(buf, "e%d.%d", &major, &minor);
|
||||||
|
if (n != 2) {
|
||||||
|
printk(KERN_ERR "aoe: %s: invalid device specification\n",
|
||||||
|
__FUNCTION__);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
d = aoedev_by_aoeaddr(major, minor);
|
||||||
|
if (!d)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&d->lock, flags);
|
||||||
|
d->flags |= DEVFL_PAUSE;
|
||||||
|
spin_unlock_irqrestore(&d->lock, flags);
|
||||||
|
aoecmd_cfg(major, minor);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
aoechr_error(char *msg)
|
aoechr_error(char *msg)
|
||||||
{
|
{
|
||||||
|
@ -114,6 +149,8 @@ aoechr_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offp
|
||||||
case MINOR_INTERFACES:
|
case MINOR_INTERFACES:
|
||||||
ret = interfaces(buf, cnt);
|
ret = interfaces(buf, cnt);
|
||||||
break;
|
break;
|
||||||
|
case MINOR_REVALIDATE:
|
||||||
|
ret = revalidate(buf, cnt);
|
||||||
}
|
}
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
ret = cnt;
|
ret = cnt;
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include <linux/blkdev.h>
|
#include <linux/blkdev.h>
|
||||||
#include <linux/skbuff.h>
|
#include <linux/skbuff.h>
|
||||||
#include <linux/netdevice.h>
|
#include <linux/netdevice.h>
|
||||||
|
#include <linux/genhd.h>
|
||||||
#include <asm/unaligned.h>
|
#include <asm/unaligned.h>
|
||||||
#include "aoe.h"
|
#include "aoe.h"
|
||||||
|
|
||||||
|
@ -28,6 +29,7 @@ new_skb(struct net_device *if_dev, ulong len)
|
||||||
skb->protocol = __constant_htons(ETH_P_AOE);
|
skb->protocol = __constant_htons(ETH_P_AOE);
|
||||||
skb->priority = 0;
|
skb->priority = 0;
|
||||||
skb_put(skb, len);
|
skb_put(skb, len);
|
||||||
|
memset(skb->head, 0, len);
|
||||||
skb->next = skb->prev = NULL;
|
skb->next = skb->prev = NULL;
|
||||||
|
|
||||||
/* tell the network layer not to perform IP checksums
|
/* tell the network layer not to perform IP checksums
|
||||||
|
@ -188,12 +190,67 @@ aoecmd_ata_rw(struct aoedev *d, struct frame *f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* some callers cannot sleep, and they can call this function,
|
||||||
|
* transmitting the packets later, when interrupts are on
|
||||||
|
*/
|
||||||
|
static struct sk_buff *
|
||||||
|
aoecmd_cfg_pkts(ushort aoemajor, unsigned char aoeminor, struct sk_buff **tail)
|
||||||
|
{
|
||||||
|
struct aoe_hdr *h;
|
||||||
|
struct aoe_cfghdr *ch;
|
||||||
|
struct sk_buff *skb, *sl, *sl_tail;
|
||||||
|
struct net_device *ifp;
|
||||||
|
|
||||||
|
sl = sl_tail = NULL;
|
||||||
|
|
||||||
|
read_lock(&dev_base_lock);
|
||||||
|
for (ifp = dev_base; ifp; dev_put(ifp), ifp = ifp->next) {
|
||||||
|
dev_hold(ifp);
|
||||||
|
if (!is_aoe_netif(ifp))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
skb = new_skb(ifp, sizeof *h + sizeof *ch);
|
||||||
|
if (skb == NULL) {
|
||||||
|
printk(KERN_INFO "aoe: aoecmd_cfg: skb alloc failure\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (sl_tail == NULL)
|
||||||
|
sl_tail = skb;
|
||||||
|
h = (struct aoe_hdr *) skb->mac.raw;
|
||||||
|
memset(h, 0, sizeof *h + sizeof *ch);
|
||||||
|
|
||||||
|
memset(h->dst, 0xff, sizeof h->dst);
|
||||||
|
memcpy(h->src, ifp->dev_addr, sizeof h->src);
|
||||||
|
h->type = __constant_cpu_to_be16(ETH_P_AOE);
|
||||||
|
h->verfl = AOE_HVER;
|
||||||
|
h->major = cpu_to_be16(aoemajor);
|
||||||
|
h->minor = aoeminor;
|
||||||
|
h->cmd = AOECMD_CFG;
|
||||||
|
|
||||||
|
skb->next = sl;
|
||||||
|
sl = skb;
|
||||||
|
}
|
||||||
|
read_unlock(&dev_base_lock);
|
||||||
|
|
||||||
|
if (tail != NULL)
|
||||||
|
*tail = sl_tail;
|
||||||
|
return sl;
|
||||||
|
}
|
||||||
|
|
||||||
/* enters with d->lock held */
|
/* enters with d->lock held */
|
||||||
void
|
void
|
||||||
aoecmd_work(struct aoedev *d)
|
aoecmd_work(struct aoedev *d)
|
||||||
{
|
{
|
||||||
struct frame *f;
|
struct frame *f;
|
||||||
struct buf *buf;
|
struct buf *buf;
|
||||||
|
|
||||||
|
if (d->flags & DEVFL_PAUSE) {
|
||||||
|
if (!aoedev_isbusy(d))
|
||||||
|
d->sendq_hd = aoecmd_cfg_pkts(d->aoemajor,
|
||||||
|
d->aoeminor, &d->sendq_tl);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
loop:
|
loop:
|
||||||
f = getframe(d, FREETAG);
|
f = getframe(d, FREETAG);
|
||||||
if (f == NULL)
|
if (f == NULL)
|
||||||
|
@ -229,6 +286,8 @@ rexmit(struct aoedev *d, struct frame *f)
|
||||||
h = (struct aoe_hdr *) f->data;
|
h = (struct aoe_hdr *) f->data;
|
||||||
f->tag = n;
|
f->tag = n;
|
||||||
h->tag = cpu_to_be32(n);
|
h->tag = cpu_to_be32(n);
|
||||||
|
memcpy(h->dst, d->addr, sizeof h->dst);
|
||||||
|
memcpy(h->src, d->ifp->dev_addr, sizeof h->src);
|
||||||
|
|
||||||
skb = skb_prepare(d, f);
|
skb = skb_prepare(d, f);
|
||||||
if (skb) {
|
if (skb) {
|
||||||
|
@ -272,7 +331,7 @@ rexmit_timer(ulong vp)
|
||||||
spin_lock_irqsave(&d->lock, flags);
|
spin_lock_irqsave(&d->lock, flags);
|
||||||
|
|
||||||
if (d->flags & DEVFL_TKILL) {
|
if (d->flags & DEVFL_TKILL) {
|
||||||
tdie: spin_unlock_irqrestore(&d->lock, flags);
|
spin_unlock_irqrestore(&d->lock, flags);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
f = d->frames;
|
f = d->frames;
|
||||||
|
@ -283,7 +342,7 @@ tdie: spin_unlock_irqrestore(&d->lock, flags);
|
||||||
n /= HZ;
|
n /= HZ;
|
||||||
if (n > MAXWAIT) { /* waited too long. device failure. */
|
if (n > MAXWAIT) { /* waited too long. device failure. */
|
||||||
aoedev_downdev(d);
|
aoedev_downdev(d);
|
||||||
goto tdie;
|
break;
|
||||||
}
|
}
|
||||||
rexmit(d, f);
|
rexmit(d, f);
|
||||||
}
|
}
|
||||||
|
@ -305,6 +364,37 @@ tdie: spin_unlock_irqrestore(&d->lock, flags);
|
||||||
aoenet_xmit(sl);
|
aoenet_xmit(sl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* this function performs work that has been deferred until sleeping is OK
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
aoecmd_sleepwork(void *vp)
|
||||||
|
{
|
||||||
|
struct aoedev *d = (struct aoedev *) vp;
|
||||||
|
|
||||||
|
if (d->flags & DEVFL_GDALLOC)
|
||||||
|
aoeblk_gdalloc(d);
|
||||||
|
|
||||||
|
if (d->flags & DEVFL_NEWSIZE) {
|
||||||
|
struct block_device *bd;
|
||||||
|
unsigned long flags;
|
||||||
|
u64 ssize;
|
||||||
|
|
||||||
|
ssize = d->gd->capacity;
|
||||||
|
bd = bdget_disk(d->gd, 0);
|
||||||
|
|
||||||
|
if (bd) {
|
||||||
|
mutex_lock(&bd->bd_inode->i_mutex);
|
||||||
|
i_size_write(bd->bd_inode, (loff_t)ssize<<9);
|
||||||
|
mutex_unlock(&bd->bd_inode->i_mutex);
|
||||||
|
bdput(bd);
|
||||||
|
}
|
||||||
|
spin_lock_irqsave(&d->lock, flags);
|
||||||
|
d->flags |= DEVFL_UP;
|
||||||
|
d->flags &= ~DEVFL_NEWSIZE;
|
||||||
|
spin_unlock_irqrestore(&d->lock, flags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ataid_complete(struct aoedev *d, unsigned char *id)
|
ataid_complete(struct aoedev *d, unsigned char *id)
|
||||||
{
|
{
|
||||||
|
@ -339,21 +429,29 @@ ataid_complete(struct aoedev *d, unsigned char *id)
|
||||||
d->geo.heads = le16_to_cpu(get_unaligned((__le16 *) &id[55<<1]));
|
d->geo.heads = le16_to_cpu(get_unaligned((__le16 *) &id[55<<1]));
|
||||||
d->geo.sectors = le16_to_cpu(get_unaligned((__le16 *) &id[56<<1]));
|
d->geo.sectors = le16_to_cpu(get_unaligned((__le16 *) &id[56<<1]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (d->ssize != ssize)
|
||||||
|
printk(KERN_INFO "aoe: %012llx e%lu.%lu v%04x has %llu "
|
||||||
|
"sectors\n", (unsigned long long)mac_addr(d->addr),
|
||||||
|
d->aoemajor, d->aoeminor,
|
||||||
|
d->fw_ver, (long long)ssize);
|
||||||
d->ssize = ssize;
|
d->ssize = ssize;
|
||||||
d->geo.start = 0;
|
d->geo.start = 0;
|
||||||
if (d->gd != NULL) {
|
if (d->gd != NULL) {
|
||||||
d->gd->capacity = ssize;
|
d->gd->capacity = ssize;
|
||||||
d->flags |= DEVFL_UP;
|
d->flags |= DEVFL_NEWSIZE;
|
||||||
|
} else {
|
||||||
|
if (d->flags & DEVFL_GDALLOC) {
|
||||||
|
printk(KERN_INFO "aoe: %s: %s e%lu.%lu, %s\n",
|
||||||
|
__FUNCTION__,
|
||||||
|
"can't schedule work for",
|
||||||
|
d->aoemajor, d->aoeminor,
|
||||||
|
"it's already on! (This really shouldn't happen).\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (d->flags & DEVFL_WORKON) {
|
d->flags |= DEVFL_GDALLOC;
|
||||||
printk(KERN_INFO "aoe: ataid_complete: can't schedule work, it's already on! "
|
|
||||||
"(This really shouldn't happen).\n");
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
INIT_WORK(&d->work, aoeblk_gdalloc, d);
|
|
||||||
schedule_work(&d->work);
|
schedule_work(&d->work);
|
||||||
d->flags |= DEVFL_WORKON;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -419,6 +517,8 @@ aoecmd_ata_rsp(struct sk_buff *skb)
|
||||||
ahout = (struct aoe_atahdr *) (f->data + sizeof(struct aoe_hdr));
|
ahout = (struct aoe_atahdr *) (f->data + sizeof(struct aoe_hdr));
|
||||||
buf = f->buf;
|
buf = f->buf;
|
||||||
|
|
||||||
|
if (ahout->cmdstat == WIN_IDENTIFY)
|
||||||
|
d->flags &= ~DEVFL_PAUSE;
|
||||||
if (ahin->cmdstat & 0xa9) { /* these bits cleared on success */
|
if (ahin->cmdstat & 0xa9) { /* these bits cleared on success */
|
||||||
printk(KERN_CRIT "aoe: aoecmd_ata_rsp: ata error cmd=%2.2Xh "
|
printk(KERN_CRIT "aoe: aoecmd_ata_rsp: ata error cmd=%2.2Xh "
|
||||||
"stat=%2.2Xh from e%ld.%ld\n",
|
"stat=%2.2Xh from e%ld.%ld\n",
|
||||||
|
@ -451,7 +551,6 @@ aoecmd_ata_rsp(struct sk_buff *skb)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ataid_complete(d, (char *) (ahin+1));
|
ataid_complete(d, (char *) (ahin+1));
|
||||||
/* d->flags |= DEVFL_WC_UPDATE; */
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
printk(KERN_INFO "aoe: aoecmd_ata_rsp: unrecognized "
|
printk(KERN_INFO "aoe: aoecmd_ata_rsp: unrecognized "
|
||||||
|
@ -484,51 +583,19 @@ aoecmd_ata_rsp(struct sk_buff *skb)
|
||||||
f->tag = FREETAG;
|
f->tag = FREETAG;
|
||||||
|
|
||||||
aoecmd_work(d);
|
aoecmd_work(d);
|
||||||
|
|
||||||
sl = d->sendq_hd;
|
sl = d->sendq_hd;
|
||||||
d->sendq_hd = d->sendq_tl = NULL;
|
d->sendq_hd = d->sendq_tl = NULL;
|
||||||
|
|
||||||
spin_unlock_irqrestore(&d->lock, flags);
|
spin_unlock_irqrestore(&d->lock, flags);
|
||||||
|
|
||||||
aoenet_xmit(sl);
|
aoenet_xmit(sl);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
aoecmd_cfg(ushort aoemajor, unsigned char aoeminor)
|
aoecmd_cfg(ushort aoemajor, unsigned char aoeminor)
|
||||||
{
|
{
|
||||||
struct aoe_hdr *h;
|
struct sk_buff *sl;
|
||||||
struct aoe_cfghdr *ch;
|
|
||||||
struct sk_buff *skb, *sl;
|
|
||||||
struct net_device *ifp;
|
|
||||||
|
|
||||||
sl = NULL;
|
sl = aoecmd_cfg_pkts(aoemajor, aoeminor, NULL);
|
||||||
|
|
||||||
read_lock(&dev_base_lock);
|
|
||||||
for (ifp = dev_base; ifp; dev_put(ifp), ifp = ifp->next) {
|
|
||||||
dev_hold(ifp);
|
|
||||||
if (!is_aoe_netif(ifp))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
skb = new_skb(ifp, sizeof *h + sizeof *ch);
|
|
||||||
if (skb == NULL) {
|
|
||||||
printk(KERN_INFO "aoe: aoecmd_cfg: skb alloc failure\n");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
h = (struct aoe_hdr *) skb->mac.raw;
|
|
||||||
memset(h, 0, sizeof *h + sizeof *ch);
|
|
||||||
|
|
||||||
memset(h->dst, 0xff, sizeof h->dst);
|
|
||||||
memcpy(h->src, ifp->dev_addr, sizeof h->src);
|
|
||||||
h->type = __constant_cpu_to_be16(ETH_P_AOE);
|
|
||||||
h->verfl = AOE_HVER;
|
|
||||||
h->major = cpu_to_be16(aoemajor);
|
|
||||||
h->minor = aoeminor;
|
|
||||||
h->cmd = AOECMD_CFG;
|
|
||||||
|
|
||||||
skb->next = sl;
|
|
||||||
sl = skb;
|
|
||||||
}
|
|
||||||
read_unlock(&dev_base_lock);
|
|
||||||
|
|
||||||
aoenet_xmit(sl);
|
aoenet_xmit(sl);
|
||||||
}
|
}
|
||||||
|
@ -561,9 +628,6 @@ aoecmd_ata_id(struct aoedev *d)
|
||||||
f->waited = 0;
|
f->waited = 0;
|
||||||
f->writedatalen = 0;
|
f->writedatalen = 0;
|
||||||
|
|
||||||
/* this message initializes the device, so we reset the rttavg */
|
|
||||||
d->rttavg = MAXTIMER;
|
|
||||||
|
|
||||||
/* set up ata header */
|
/* set up ata header */
|
||||||
ah->scnt = 1;
|
ah->scnt = 1;
|
||||||
ah->cmdstat = WIN_IDENTIFY;
|
ah->cmdstat = WIN_IDENTIFY;
|
||||||
|
@ -571,12 +635,8 @@ aoecmd_ata_id(struct aoedev *d)
|
||||||
|
|
||||||
skb = skb_prepare(d, f);
|
skb = skb_prepare(d, f);
|
||||||
|
|
||||||
/* we now want to start the rexmit tracking */
|
d->rttavg = MAXTIMER;
|
||||||
d->flags &= ~DEVFL_TKILL;
|
|
||||||
d->timer.data = (ulong) d;
|
|
||||||
d->timer.function = rexmit_timer;
|
d->timer.function = rexmit_timer;
|
||||||
d->timer.expires = jiffies + TIMERTICK;
|
|
||||||
add_timer(&d->timer);
|
|
||||||
|
|
||||||
return skb;
|
return skb;
|
||||||
}
|
}
|
||||||
|
@ -590,7 +650,7 @@ aoecmd_cfg_rsp(struct sk_buff *skb)
|
||||||
ulong flags, sysminor, aoemajor;
|
ulong flags, sysminor, aoemajor;
|
||||||
u16 bufcnt;
|
u16 bufcnt;
|
||||||
struct sk_buff *sl;
|
struct sk_buff *sl;
|
||||||
enum { MAXFRAMES = 8 };
|
enum { MAXFRAMES = 16 };
|
||||||
|
|
||||||
h = (struct aoe_hdr *) skb->mac.raw;
|
h = (struct aoe_hdr *) skb->mac.raw;
|
||||||
ch = (struct aoe_cfghdr *) (h+1);
|
ch = (struct aoe_cfghdr *) (h+1);
|
||||||
|
@ -618,23 +678,28 @@ aoecmd_cfg_rsp(struct sk_buff *skb)
|
||||||
if (bufcnt > MAXFRAMES) /* keep it reasonable */
|
if (bufcnt > MAXFRAMES) /* keep it reasonable */
|
||||||
bufcnt = MAXFRAMES;
|
bufcnt = MAXFRAMES;
|
||||||
|
|
||||||
d = aoedev_set(sysminor, h->src, skb->dev, bufcnt);
|
d = aoedev_by_sysminor_m(sysminor, bufcnt);
|
||||||
if (d == NULL) {
|
if (d == NULL) {
|
||||||
printk(KERN_INFO "aoe: aoecmd_cfg_rsp: device set failure\n");
|
printk(KERN_INFO "aoe: aoecmd_cfg_rsp: device sysminor_m failure\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock_irqsave(&d->lock, flags);
|
spin_lock_irqsave(&d->lock, flags);
|
||||||
|
|
||||||
if (d->flags & (DEVFL_UP | DEVFL_CLOSEWAIT)) {
|
/* permit device to migrate mac and network interface */
|
||||||
|
d->ifp = skb->dev;
|
||||||
|
memcpy(d->addr, h->src, sizeof d->addr);
|
||||||
|
|
||||||
|
/* don't change users' perspective */
|
||||||
|
if (d->nopen && !(d->flags & DEVFL_PAUSE)) {
|
||||||
spin_unlock_irqrestore(&d->lock, flags);
|
spin_unlock_irqrestore(&d->lock, flags);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
d->flags |= DEVFL_PAUSE; /* force pause */
|
||||||
d->fw_ver = be16_to_cpu(ch->fwver);
|
d->fw_ver = be16_to_cpu(ch->fwver);
|
||||||
|
|
||||||
/* we get here only if the device is new */
|
/* check for already outstanding ataid */
|
||||||
sl = aoecmd_ata_id(d);
|
sl = aoedev_isbusy(d) == 0 ? aoecmd_ata_id(d) : NULL;
|
||||||
|
|
||||||
spin_unlock_irqrestore(&d->lock, flags);
|
spin_unlock_irqrestore(&d->lock, flags);
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,24 @@
|
||||||
static struct aoedev *devlist;
|
static struct aoedev *devlist;
|
||||||
static spinlock_t devlist_lock;
|
static spinlock_t devlist_lock;
|
||||||
|
|
||||||
|
int
|
||||||
|
aoedev_isbusy(struct aoedev *d)
|
||||||
|
{
|
||||||
|
struct frame *f, *e;
|
||||||
|
|
||||||
|
f = d->frames;
|
||||||
|
e = f + d->nframes;
|
||||||
|
do {
|
||||||
|
if (f->tag != FREETAG) {
|
||||||
|
printk(KERN_DEBUG "aoe: %ld.%ld isbusy\n",
|
||||||
|
d->aoemajor, d->aoeminor);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} while (++f < e);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
struct aoedev *
|
struct aoedev *
|
||||||
aoedev_by_aoeaddr(int maj, int min)
|
aoedev_by_aoeaddr(int maj, int min)
|
||||||
{
|
{
|
||||||
|
@ -28,6 +46,18 @@ aoedev_by_aoeaddr(int maj, int min)
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dummy_timer(ulong vp)
|
||||||
|
{
|
||||||
|
struct aoedev *d;
|
||||||
|
|
||||||
|
d = (struct aoedev *)vp;
|
||||||
|
if (d->flags & DEVFL_TKILL)
|
||||||
|
return;
|
||||||
|
d->timer.expires = jiffies + HZ;
|
||||||
|
add_timer(&d->timer);
|
||||||
|
}
|
||||||
|
|
||||||
/* called with devlist lock held */
|
/* called with devlist lock held */
|
||||||
static struct aoedev *
|
static struct aoedev *
|
||||||
aoedev_newdev(ulong nframes)
|
aoedev_newdev(ulong nframes)
|
||||||
|
@ -44,6 +74,8 @@ aoedev_newdev(ulong nframes)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
INIT_WORK(&d->work, aoecmd_sleepwork, d);
|
||||||
|
|
||||||
d->nframes = nframes;
|
d->nframes = nframes;
|
||||||
d->frames = f;
|
d->frames = f;
|
||||||
e = f + nframes;
|
e = f + nframes;
|
||||||
|
@ -52,6 +84,10 @@ aoedev_newdev(ulong nframes)
|
||||||
|
|
||||||
spin_lock_init(&d->lock);
|
spin_lock_init(&d->lock);
|
||||||
init_timer(&d->timer);
|
init_timer(&d->timer);
|
||||||
|
d->timer.data = (ulong) d;
|
||||||
|
d->timer.function = dummy_timer;
|
||||||
|
d->timer.expires = jiffies + HZ;
|
||||||
|
add_timer(&d->timer);
|
||||||
d->bufpool = NULL; /* defer to aoeblk_gdalloc */
|
d->bufpool = NULL; /* defer to aoeblk_gdalloc */
|
||||||
INIT_LIST_HEAD(&d->bufq);
|
INIT_LIST_HEAD(&d->bufq);
|
||||||
d->next = devlist;
|
d->next = devlist;
|
||||||
|
@ -67,9 +103,6 @@ aoedev_downdev(struct aoedev *d)
|
||||||
struct buf *buf;
|
struct buf *buf;
|
||||||
struct bio *bio;
|
struct bio *bio;
|
||||||
|
|
||||||
d->flags |= DEVFL_TKILL;
|
|
||||||
del_timer(&d->timer);
|
|
||||||
|
|
||||||
f = d->frames;
|
f = d->frames;
|
||||||
e = f + d->nframes;
|
e = f + d->nframes;
|
||||||
for (; f<e; f->tag = FREETAG, f->buf = NULL, f++) {
|
for (; f<e; f->tag = FREETAG, f->buf = NULL, f++) {
|
||||||
|
@ -92,16 +125,15 @@ aoedev_downdev(struct aoedev *d)
|
||||||
bio_endio(bio, bio->bi_size, -EIO);
|
bio_endio(bio, bio->bi_size, -EIO);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (d->nopen)
|
|
||||||
d->flags |= DEVFL_CLOSEWAIT;
|
|
||||||
if (d->gd)
|
if (d->gd)
|
||||||
d->gd->capacity = 0;
|
d->gd->capacity = 0;
|
||||||
|
|
||||||
d->flags &= ~DEVFL_UP;
|
d->flags &= ~(DEVFL_UP | DEVFL_PAUSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* find it or malloc it */
|
||||||
struct aoedev *
|
struct aoedev *
|
||||||
aoedev_set(ulong sysminor, unsigned char *addr, struct net_device *ifp, ulong bufcnt)
|
aoedev_by_sysminor_m(ulong sysminor, ulong bufcnt)
|
||||||
{
|
{
|
||||||
struct aoedev *d;
|
struct aoedev *d;
|
||||||
ulong flags;
|
ulong flags;
|
||||||
|
@ -112,25 +144,19 @@ aoedev_set(ulong sysminor, unsigned char *addr, struct net_device *ifp, ulong bu
|
||||||
if (d->sysminor == sysminor)
|
if (d->sysminor == sysminor)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (d == NULL && (d = aoedev_newdev(bufcnt)) == NULL) {
|
if (d == NULL) {
|
||||||
|
d = aoedev_newdev(bufcnt);
|
||||||
|
if (d == NULL) {
|
||||||
spin_unlock_irqrestore(&devlist_lock, flags);
|
spin_unlock_irqrestore(&devlist_lock, flags);
|
||||||
printk(KERN_INFO "aoe: aoedev_set: aoedev_newdev failure.\n");
|
printk(KERN_INFO "aoe: aoedev_set: aoedev_newdev failure.\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
} /* if newdev, (d->flags & DEVFL_UP) == 0 for below */
|
}
|
||||||
|
|
||||||
spin_unlock_irqrestore(&devlist_lock, flags);
|
|
||||||
spin_lock_irqsave(&d->lock, flags);
|
|
||||||
|
|
||||||
d->ifp = ifp;
|
|
||||||
memcpy(d->addr, addr, sizeof d->addr);
|
|
||||||
if ((d->flags & DEVFL_UP) == 0) {
|
|
||||||
aoedev_downdev(d); /* flushes outstanding frames */
|
|
||||||
d->sysminor = sysminor;
|
d->sysminor = sysminor;
|
||||||
d->aoemajor = AOEMAJOR(sysminor);
|
d->aoemajor = AOEMAJOR(sysminor);
|
||||||
d->aoeminor = AOEMINOR(sysminor);
|
d->aoeminor = AOEMINOR(sysminor);
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_unlock_irqrestore(&d->lock, flags);
|
spin_unlock_irqrestore(&devlist_lock, flags);
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,6 +187,7 @@ aoedev_exit(void)
|
||||||
|
|
||||||
spin_lock_irqsave(&d->lock, flags);
|
spin_lock_irqsave(&d->lock, flags);
|
||||||
aoedev_downdev(d);
|
aoedev_downdev(d);
|
||||||
|
d->flags |= DEVFL_TKILL;
|
||||||
spin_unlock_irqrestore(&d->lock, flags);
|
spin_unlock_irqrestore(&d->lock, flags);
|
||||||
|
|
||||||
del_timer_sync(&d->timer);
|
del_timer_sync(&d->timer);
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
MODULE_AUTHOR("Sam Hopkins <sah@coraid.com>");
|
MODULE_AUTHOR("Sam Hopkins <sah@coraid.com>");
|
||||||
MODULE_DESCRIPTION("AoE block/char driver for 2.6.[0-9]+");
|
MODULE_DESCRIPTION("AoE block/char driver for 2.6.2 and newer 2.6 kernels");
|
||||||
MODULE_VERSION(VERSION);
|
MODULE_VERSION(VERSION);
|
||||||
|
|
||||||
enum { TINIT, TRUN, TKILL };
|
enum { TINIT, TRUN, TKILL };
|
||||||
|
@ -89,7 +89,7 @@ aoe_init(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
printk(KERN_INFO
|
printk(KERN_INFO
|
||||||
"aoe: aoe_init: AoE v2.6-%s initialised.\n",
|
"aoe: aoe_init: AoE v%s initialised.\n",
|
||||||
VERSION);
|
VERSION);
|
||||||
discover_timer(TINIT);
|
discover_timer(TINIT);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -92,18 +92,6 @@ mac_addr(char addr[6])
|
||||||
return __be64_to_cpu(n);
|
return __be64_to_cpu(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct sk_buff *
|
|
||||||
skb_check(struct sk_buff *skb)
|
|
||||||
{
|
|
||||||
if (skb_is_nonlinear(skb))
|
|
||||||
if ((skb = skb_share_check(skb, GFP_ATOMIC)))
|
|
||||||
if (skb_linearize(skb, GFP_ATOMIC) < 0) {
|
|
||||||
dev_kfree_skb(skb);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return skb;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
aoenet_xmit(struct sk_buff *sl)
|
aoenet_xmit(struct sk_buff *sl)
|
||||||
{
|
{
|
||||||
|
@ -125,14 +113,14 @@ aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt,
|
||||||
struct aoe_hdr *h;
|
struct aoe_hdr *h;
|
||||||
u32 n;
|
u32 n;
|
||||||
|
|
||||||
skb = skb_check(skb);
|
skb = skb_share_check(skb, GFP_ATOMIC);
|
||||||
if (!skb)
|
if (skb == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
if (skb_is_nonlinear(skb))
|
||||||
|
if (skb_linearize(skb, GFP_ATOMIC) < 0)
|
||||||
|
goto exit;
|
||||||
if (!is_aoe_netif(ifp))
|
if (!is_aoe_netif(ifp))
|
||||||
goto exit;
|
goto exit;
|
||||||
|
|
||||||
//skb->len += ETH_HLEN; /* (1) */
|
|
||||||
skb_push(skb, ETH_HLEN); /* (1) */
|
skb_push(skb, ETH_HLEN); /* (1) */
|
||||||
|
|
||||||
h = (struct aoe_hdr *) skb->mac.raw;
|
h = (struct aoe_hdr *) skb->mac.raw;
|
||||||
|
|
Loading…
Reference in New Issue