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
|
||||
rm -f $dir/interfaces
|
||||
mknod -m 0200 $dir/interfaces c $MAJOR 4
|
||||
rm -f $dir/revalidate
|
||||
mknod -m 0200 $dir/revalidate c $MAJOR 5
|
||||
|
||||
export n_partitions
|
||||
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="err", NAME="etherd/%k", GROUP="disk", MODE="0440"
|
||||
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
|
||||
KERNEL="etherd*", NAME="%k", GROUP="disk"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* Copyright (c) 2004 Coraid, Inc. See COPYING for GPL terms. */
|
||||
#define VERSION "14"
|
||||
#define VERSION "22"
|
||||
#define AOE_MAJOR 152
|
||||
#define DEVICE_NAME "aoe"
|
||||
|
||||
|
@ -75,8 +75,9 @@ enum {
|
|||
DEVFL_TKILL = (1<<1), /* flag for timer to know when to kill self */
|
||||
DEVFL_EXT = (1<<2), /* device accepts lba48 commands */
|
||||
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_WORKON = (1<<4),
|
||||
DEVFL_GDALLOC = (1<<4), /* need to alloc gendisk */
|
||||
DEVFL_PAUSE = (1<<5),
|
||||
DEVFL_NEWSIZE = (1<<6), /* need to update dev size in block layer */
|
||||
|
||||
BUFFL_FAIL = 1,
|
||||
};
|
||||
|
@ -152,16 +153,17 @@ void aoechr_exit(void);
|
|||
void aoechr_error(char *);
|
||||
|
||||
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_cfg_rsp(struct sk_buff *);
|
||||
void aoecmd_sleepwork(void *vp);
|
||||
|
||||
int aoedev_init(void);
|
||||
void aoedev_exit(void);
|
||||
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);
|
||||
struct aoedev *aoedev_set(ulong, unsigned char *, struct net_device *, ulong);
|
||||
int aoedev_busy(void);
|
||||
int aoedev_isbusy(struct aoedev *d);
|
||||
|
||||
int aoenet_init(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,
|
||||
"%s%s\n",
|
||||
(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)
|
||||
{
|
||||
|
@ -107,8 +109,7 @@ aoeblk_release(struct inode *inode, struct file *filp)
|
|||
|
||||
spin_lock_irqsave(&d->lock, flags);
|
||||
|
||||
if (--d->nopen == 0 && (d->flags & DEVFL_CLOSEWAIT)) {
|
||||
d->flags &= ~DEVFL_CLOSEWAIT;
|
||||
if (--d->nopen == 0) {
|
||||
spin_unlock_irqrestore(&d->lock, flags);
|
||||
aoecmd_cfg(d->aoemajor, d->aoeminor);
|
||||
return 0;
|
||||
|
@ -158,14 +159,14 @@ aoeblk_make_request(request_queue_t *q, struct bio *bio)
|
|||
}
|
||||
|
||||
list_add_tail(&buf->bufs, &d->bufq);
|
||||
aoecmd_work(d);
|
||||
|
||||
aoecmd_work(d);
|
||||
sl = d->sendq_hd;
|
||||
d->sendq_hd = d->sendq_tl = NULL;
|
||||
|
||||
spin_unlock_irqrestore(&d->lock, flags);
|
||||
|
||||
aoenet_xmit(sl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -205,7 +206,7 @@ aoeblk_gdalloc(void *vp)
|
|||
printk(KERN_ERR "aoe: aoeblk_gdalloc: cannot allocate disk "
|
||||
"structure for %ld.%ld\n", d->aoemajor, d->aoeminor);
|
||||
spin_lock_irqsave(&d->lock, flags);
|
||||
d->flags &= ~DEVFL_WORKON;
|
||||
d->flags &= ~DEVFL_GDALLOC;
|
||||
spin_unlock_irqrestore(&d->lock, flags);
|
||||
return;
|
||||
}
|
||||
|
@ -218,7 +219,7 @@ aoeblk_gdalloc(void *vp)
|
|||
"for %ld.%ld\n", d->aoemajor, d->aoeminor);
|
||||
put_disk(gd);
|
||||
spin_lock_irqsave(&d->lock, flags);
|
||||
d->flags &= ~DEVFL_WORKON;
|
||||
d->flags &= ~DEVFL_GDALLOC;
|
||||
spin_unlock_irqrestore(&d->lock, flags);
|
||||
return;
|
||||
}
|
||||
|
@ -235,18 +236,13 @@ aoeblk_gdalloc(void *vp)
|
|||
|
||||
gd->queue = &d->blkq;
|
||||
d->gd = gd;
|
||||
d->flags &= ~DEVFL_WORKON;
|
||||
d->flags &= ~DEVFL_GDALLOC;
|
||||
d->flags |= DEVFL_UP;
|
||||
|
||||
spin_unlock_irqrestore(&d->lock, flags);
|
||||
|
||||
add_disk(gd);
|
||||
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
|
||||
|
|
|
@ -13,6 +13,7 @@ enum {
|
|||
MINOR_ERR = 2,
|
||||
MINOR_DISCOVER,
|
||||
MINOR_INTERFACES,
|
||||
MINOR_REVALIDATE,
|
||||
MSGSZ = 2048,
|
||||
NARGS = 10,
|
||||
NMSG = 100, /* message backlog to retain */
|
||||
|
@ -41,6 +42,7 @@ static struct aoe_chardev chardevs[] = {
|
|||
{ MINOR_ERR, "err" },
|
||||
{ MINOR_DISCOVER, "discover" },
|
||||
{ MINOR_INTERFACES, "interfaces" },
|
||||
{ MINOR_REVALIDATE, "revalidate" },
|
||||
};
|
||||
|
||||
static int
|
||||
|
@ -62,6 +64,39 @@ interfaces(const char __user *str, size_t size)
|
|||
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
|
||||
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:
|
||||
ret = interfaces(buf, cnt);
|
||||
break;
|
||||
case MINOR_REVALIDATE:
|
||||
ret = revalidate(buf, cnt);
|
||||
}
|
||||
if (ret == 0)
|
||||
ret = cnt;
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <linux/blkdev.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/genhd.h>
|
||||
#include <asm/unaligned.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->priority = 0;
|
||||
skb_put(skb, len);
|
||||
memset(skb->head, 0, len);
|
||||
skb->next = skb->prev = NULL;
|
||||
|
||||
/* 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 */
|
||||
void
|
||||
aoecmd_work(struct aoedev *d)
|
||||
{
|
||||
struct frame *f;
|
||||
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:
|
||||
f = getframe(d, FREETAG);
|
||||
if (f == NULL)
|
||||
|
@ -229,6 +286,8 @@ rexmit(struct aoedev *d, struct frame *f)
|
|||
h = (struct aoe_hdr *) f->data;
|
||||
f->tag = 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);
|
||||
if (skb) {
|
||||
|
@ -272,7 +331,7 @@ rexmit_timer(ulong vp)
|
|||
spin_lock_irqsave(&d->lock, flags);
|
||||
|
||||
if (d->flags & DEVFL_TKILL) {
|
||||
tdie: spin_unlock_irqrestore(&d->lock, flags);
|
||||
spin_unlock_irqrestore(&d->lock, flags);
|
||||
return;
|
||||
}
|
||||
f = d->frames;
|
||||
|
@ -283,7 +342,7 @@ tdie: spin_unlock_irqrestore(&d->lock, flags);
|
|||
n /= HZ;
|
||||
if (n > MAXWAIT) { /* waited too long. device failure. */
|
||||
aoedev_downdev(d);
|
||||
goto tdie;
|
||||
break;
|
||||
}
|
||||
rexmit(d, f);
|
||||
}
|
||||
|
@ -305,6 +364,37 @@ tdie: spin_unlock_irqrestore(&d->lock, flags);
|
|||
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
|
||||
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.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->geo.start = 0;
|
||||
if (d->gd != NULL) {
|
||||
d->gd->capacity = ssize;
|
||||
d->flags |= DEVFL_UP;
|
||||
return;
|
||||
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;
|
||||
}
|
||||
d->flags |= DEVFL_GDALLOC;
|
||||
}
|
||||
if (d->flags & DEVFL_WORKON) {
|
||||
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);
|
||||
d->flags |= DEVFL_WORKON;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -419,6 +517,8 @@ aoecmd_ata_rsp(struct sk_buff *skb)
|
|||
ahout = (struct aoe_atahdr *) (f->data + sizeof(struct aoe_hdr));
|
||||
buf = f->buf;
|
||||
|
||||
if (ahout->cmdstat == WIN_IDENTIFY)
|
||||
d->flags &= ~DEVFL_PAUSE;
|
||||
if (ahin->cmdstat & 0xa9) { /* these bits cleared on success */
|
||||
printk(KERN_CRIT "aoe: aoecmd_ata_rsp: ata error cmd=%2.2Xh "
|
||||
"stat=%2.2Xh from e%ld.%ld\n",
|
||||
|
@ -451,7 +551,6 @@ aoecmd_ata_rsp(struct sk_buff *skb)
|
|||
return;
|
||||
}
|
||||
ataid_complete(d, (char *) (ahin+1));
|
||||
/* d->flags |= DEVFL_WC_UPDATE; */
|
||||
break;
|
||||
default:
|
||||
printk(KERN_INFO "aoe: aoecmd_ata_rsp: unrecognized "
|
||||
|
@ -484,51 +583,19 @@ aoecmd_ata_rsp(struct sk_buff *skb)
|
|||
f->tag = FREETAG;
|
||||
|
||||
aoecmd_work(d);
|
||||
|
||||
sl = d->sendq_hd;
|
||||
d->sendq_hd = d->sendq_tl = NULL;
|
||||
|
||||
spin_unlock_irqrestore(&d->lock, flags);
|
||||
|
||||
aoenet_xmit(sl);
|
||||
}
|
||||
|
||||
void
|
||||
aoecmd_cfg(ushort aoemajor, unsigned char aoeminor)
|
||||
{
|
||||
struct aoe_hdr *h;
|
||||
struct aoe_cfghdr *ch;
|
||||
struct sk_buff *skb, *sl;
|
||||
struct net_device *ifp;
|
||||
struct sk_buff *sl;
|
||||
|
||||
sl = 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);
|
||||
sl = aoecmd_cfg_pkts(aoemajor, aoeminor, NULL);
|
||||
|
||||
aoenet_xmit(sl);
|
||||
}
|
||||
|
@ -561,9 +628,6 @@ aoecmd_ata_id(struct aoedev *d)
|
|||
f->waited = 0;
|
||||
f->writedatalen = 0;
|
||||
|
||||
/* this message initializes the device, so we reset the rttavg */
|
||||
d->rttavg = MAXTIMER;
|
||||
|
||||
/* set up ata header */
|
||||
ah->scnt = 1;
|
||||
ah->cmdstat = WIN_IDENTIFY;
|
||||
|
@ -571,12 +635,8 @@ aoecmd_ata_id(struct aoedev *d)
|
|||
|
||||
skb = skb_prepare(d, f);
|
||||
|
||||
/* we now want to start the rexmit tracking */
|
||||
d->flags &= ~DEVFL_TKILL;
|
||||
d->timer.data = (ulong) d;
|
||||
d->rttavg = MAXTIMER;
|
||||
d->timer.function = rexmit_timer;
|
||||
d->timer.expires = jiffies + TIMERTICK;
|
||||
add_timer(&d->timer);
|
||||
|
||||
return skb;
|
||||
}
|
||||
|
@ -590,7 +650,7 @@ aoecmd_cfg_rsp(struct sk_buff *skb)
|
|||
ulong flags, sysminor, aoemajor;
|
||||
u16 bufcnt;
|
||||
struct sk_buff *sl;
|
||||
enum { MAXFRAMES = 8 };
|
||||
enum { MAXFRAMES = 16 };
|
||||
|
||||
h = (struct aoe_hdr *) skb->mac.raw;
|
||||
ch = (struct aoe_cfghdr *) (h+1);
|
||||
|
@ -618,23 +678,28 @@ aoecmd_cfg_rsp(struct sk_buff *skb)
|
|||
if (bufcnt > MAXFRAMES) /* keep it reasonable */
|
||||
bufcnt = MAXFRAMES;
|
||||
|
||||
d = aoedev_set(sysminor, h->src, skb->dev, bufcnt);
|
||||
d = aoedev_by_sysminor_m(sysminor, bufcnt);
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
||||
d->flags |= DEVFL_PAUSE; /* force pause */
|
||||
d->fw_ver = be16_to_cpu(ch->fwver);
|
||||
|
||||
/* we get here only if the device is new */
|
||||
sl = aoecmd_ata_id(d);
|
||||
/* check for already outstanding ataid */
|
||||
sl = aoedev_isbusy(d) == 0 ? aoecmd_ata_id(d) : NULL;
|
||||
|
||||
spin_unlock_irqrestore(&d->lock, flags);
|
||||
|
||||
|
|
|
@ -12,6 +12,24 @@
|
|||
static struct aoedev *devlist;
|
||||
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 *
|
||||
aoedev_by_aoeaddr(int maj, int min)
|
||||
{
|
||||
|
@ -28,6 +46,18 @@ aoedev_by_aoeaddr(int maj, int min)
|
|||
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 */
|
||||
static struct aoedev *
|
||||
aoedev_newdev(ulong nframes)
|
||||
|
@ -44,6 +74,8 @@ aoedev_newdev(ulong nframes)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
INIT_WORK(&d->work, aoecmd_sleepwork, d);
|
||||
|
||||
d->nframes = nframes;
|
||||
d->frames = f;
|
||||
e = f + nframes;
|
||||
|
@ -52,6 +84,10 @@ aoedev_newdev(ulong nframes)
|
|||
|
||||
spin_lock_init(&d->lock);
|
||||
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 */
|
||||
INIT_LIST_HEAD(&d->bufq);
|
||||
d->next = devlist;
|
||||
|
@ -67,9 +103,6 @@ aoedev_downdev(struct aoedev *d)
|
|||
struct buf *buf;
|
||||
struct bio *bio;
|
||||
|
||||
d->flags |= DEVFL_TKILL;
|
||||
del_timer(&d->timer);
|
||||
|
||||
f = d->frames;
|
||||
e = f + d->nframes;
|
||||
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);
|
||||
}
|
||||
|
||||
if (d->nopen)
|
||||
d->flags |= DEVFL_CLOSEWAIT;
|
||||
if (d->gd)
|
||||
d->gd->capacity = 0;
|
||||
|
||||
d->flags &= ~DEVFL_UP;
|
||||
d->flags &= ~(DEVFL_UP | DEVFL_PAUSE);
|
||||
}
|
||||
|
||||
/* find it or malloc it */
|
||||
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;
|
||||
ulong flags;
|
||||
|
@ -112,25 +144,19 @@ aoedev_set(ulong sysminor, unsigned char *addr, struct net_device *ifp, ulong bu
|
|||
if (d->sysminor == sysminor)
|
||||
break;
|
||||
|
||||
if (d == NULL && (d = aoedev_newdev(bufcnt)) == NULL) {
|
||||
spin_unlock_irqrestore(&devlist_lock, flags);
|
||||
printk(KERN_INFO "aoe: aoedev_set: aoedev_newdev failure.\n");
|
||||
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 */
|
||||
if (d == NULL) {
|
||||
d = aoedev_newdev(bufcnt);
|
||||
if (d == NULL) {
|
||||
spin_unlock_irqrestore(&devlist_lock, flags);
|
||||
printk(KERN_INFO "aoe: aoedev_set: aoedev_newdev failure.\n");
|
||||
return NULL;
|
||||
}
|
||||
d->sysminor = sysminor;
|
||||
d->aoemajor = AOEMAJOR(sysminor);
|
||||
d->aoeminor = AOEMINOR(sysminor);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&d->lock, flags);
|
||||
spin_unlock_irqrestore(&devlist_lock, flags);
|
||||
return d;
|
||||
}
|
||||
|
||||
|
@ -161,6 +187,7 @@ aoedev_exit(void)
|
|||
|
||||
spin_lock_irqsave(&d->lock, flags);
|
||||
aoedev_downdev(d);
|
||||
d->flags |= DEVFL_TKILL;
|
||||
spin_unlock_irqrestore(&d->lock, flags);
|
||||
|
||||
del_timer_sync(&d->timer);
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
MODULE_LICENSE("GPL");
|
||||
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);
|
||||
|
||||
enum { TINIT, TRUN, TKILL };
|
||||
|
@ -89,7 +89,7 @@ aoe_init(void)
|
|||
}
|
||||
|
||||
printk(KERN_INFO
|
||||
"aoe: aoe_init: AoE v2.6-%s initialised.\n",
|
||||
"aoe: aoe_init: AoE v%s initialised.\n",
|
||||
VERSION);
|
||||
discover_timer(TINIT);
|
||||
return 0;
|
||||
|
|
|
@ -92,18 +92,6 @@ mac_addr(char addr[6])
|
|||
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
|
||||
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;
|
||||
u32 n;
|
||||
|
||||
skb = skb_check(skb);
|
||||
if (!skb)
|
||||
skb = skb_share_check(skb, GFP_ATOMIC);
|
||||
if (skb == NULL)
|
||||
return 0;
|
||||
|
||||
if (skb_is_nonlinear(skb))
|
||||
if (skb_linearize(skb, GFP_ATOMIC) < 0)
|
||||
goto exit;
|
||||
if (!is_aoe_netif(ifp))
|
||||
goto exit;
|
||||
|
||||
//skb->len += ETH_HLEN; /* (1) */
|
||||
skb_push(skb, ETH_HLEN); /* (1) */
|
||||
|
||||
h = (struct aoe_hdr *) skb->mac.raw;
|
||||
|
|
Loading…
Reference in New Issue