aoe: jumbo frame support 1 of 2

Add support for jumbo ethernet frames.
(This patch depends on patch 7 to follow.)

Signed-off-by: "Ed L. Cashin" <ecashin@coraid.com>
Acked-by: Alan Cox <alan@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
Ed L. Cashin 2006-09-20 14:36:49 -04:00 committed by Greg Kroah-Hartman
parent e407a7f6cd
commit 19bf26353c
3 changed files with 72 additions and 17 deletions

View File

@ -65,7 +65,7 @@ struct aoe_atahdr {
struct aoe_cfghdr {
__be16 bufcnt;
__be16 fwver;
unsigned char res;
unsigned char scnt;
unsigned char aoeccmd;
unsigned char cslen[2];
};
@ -78,12 +78,13 @@ enum {
DEVFL_GDALLOC = (1<<4), /* need to alloc gendisk */
DEVFL_PAUSE = (1<<5),
DEVFL_NEWSIZE = (1<<6), /* need to update dev size in block layer */
DEVFL_MAXBCNT = (1<<7), /* d->maxbcnt is not changeable */
BUFFL_FAIL = 1,
};
enum {
MAXATADATA = 1024,
DEFAULTBCNT = 2 * 512, /* 2 sectors */
NPERSHELF = 16, /* number of slots per shelf address */
FREETAG = -1,
MIN_BUFS = 8,
@ -107,6 +108,8 @@ struct frame {
ulong waited;
struct buf *buf;
char *bufaddr;
ulong bcnt;
sector_t lba;
struct sk_buff *skb;
};
@ -120,6 +123,7 @@ struct aoedev {
ulong nopen; /* (bd_openers isn't available without sleeping) */
ulong rttavg; /* round trip average of requests/responses */
u16 fw_ver; /* version of blade's firmware */
u16 maxbcnt;
struct work_struct work;/* disk create work struct */
struct gendisk *gd;
request_queue_t blkq;
@ -134,7 +138,8 @@ struct aoedev {
struct list_head bufq; /* queue of bios to work on */
struct buf *inprocess; /* the one we're currently working on */
ulong lasttag; /* last tag sent */
ulong nframes; /* number of frames below */
ushort lostjumbo;
ushort nframes; /* number of frames below */
struct frame *frames;
};

View File

@ -89,6 +89,7 @@ revalidate(const char __user *str, size_t size)
return -EINVAL;
spin_lock_irqsave(&d->lock, flags);
d->flags &= ~DEVFL_MAXBCNT;
d->flags |= DEVFL_PAUSE;
spin_unlock_irqrestore(&d->lock, flags);
aoecmd_cfg(major, minor);

View File

@ -83,6 +83,17 @@ aoehdr_atainit(struct aoedev *d, struct aoe_hdr *h)
return host_tag;
}
static inline void
put_lba(struct aoe_atahdr *ah, sector_t lba)
{
ah->lba0 = lba;
ah->lba1 = lba >>= 8;
ah->lba2 = lba >>= 8;
ah->lba3 = lba >>= 8;
ah->lba4 = lba >>= 8;
ah->lba5 = lba >>= 8;
}
static void
aoecmd_ata_rw(struct aoedev *d, struct frame *f)
{
@ -101,8 +112,8 @@ aoecmd_ata_rw(struct aoedev *d, struct frame *f)
sector = buf->sector;
bcnt = buf->bv_resid;
if (bcnt > MAXATADATA)
bcnt = MAXATADATA;
if (bcnt > d->maxbcnt)
bcnt = d->maxbcnt;
/* initialize the headers & frame */
skb = f->skb;
@ -114,17 +125,14 @@ aoecmd_ata_rw(struct aoedev *d, struct frame *f)
f->waited = 0;
f->buf = buf;
f->bufaddr = buf->bufaddr;
f->bcnt = bcnt;
f->lba = sector;
/* set up ata header */
ah->scnt = bcnt >> 9;
ah->lba0 = sector;
ah->lba1 = sector >>= 8;
ah->lba2 = sector >>= 8;
ah->lba3 = sector >>= 8;
put_lba(ah, sector);
if (d->flags & DEVFL_EXT) {
ah->aflags |= AOEAFL_EXT;
ah->lba4 = sector >>= 8;
ah->lba5 = sector >>= 8;
} else {
extbit = 0;
ah->lba3 &= 0x0f;
@ -251,6 +259,7 @@ rexmit(struct aoedev *d, struct frame *f)
{
struct sk_buff *skb;
struct aoe_hdr *h;
struct aoe_atahdr *ah;
char buf[128];
u32 n;
@ -264,11 +273,27 @@ rexmit(struct aoedev *d, struct frame *f)
skb = f->skb;
h = (struct aoe_hdr *) skb->mac.raw;
ah = (struct aoe_atahdr *) (h+1);
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);
n = DEFAULTBCNT / 512;
if (ah->scnt > n) {
ah->scnt = n;
if (ah->aflags & AOEAFL_WRITE)
skb_fill_page_desc(skb, 0, virt_to_page(f->bufaddr),
offset_in_page(f->bufaddr), DEFAULTBCNT);
if (++d->lostjumbo > (d->nframes << 1))
if (d->maxbcnt != DEFAULTBCNT) {
printk(KERN_INFO "aoe: rexmit: too many lost jumbo. "
"dropping back to 1KB frames.\n");
d->maxbcnt = DEFAULTBCNT;
d->flags |= DEVFL_MAXBCNT;
}
}
skb->dev = d->ifp;
skb_get(skb);
skb->next = NULL;
@ -506,10 +531,10 @@ aoecmd_ata_rsp(struct sk_buff *skb)
if (buf)
buf->flags |= BUFFL_FAIL;
} else {
n = ahout->scnt << 9;
switch (ahout->cmdstat) {
case WIN_READ:
case WIN_READ_EXT:
n = ahout->scnt << 9;
if (skb->len - sizeof *hin - sizeof *ahin < n) {
printk(KERN_CRIT "aoe: aoecmd_ata_rsp: runt "
"ata data size in read. skb->len=%d\n",
@ -521,6 +546,22 @@ aoecmd_ata_rsp(struct sk_buff *skb)
memcpy(f->bufaddr, ahin+1, n);
case WIN_WRITE:
case WIN_WRITE_EXT:
if (f->bcnt -= n) {
f->bufaddr += n;
put_lba(ahout, f->lba += ahout->scnt);
n = f->bcnt > DEFAULTBCNT ? DEFAULTBCNT : f->bcnt;
ahout->scnt = n >> 9;
if (ahout->aflags & AOEAFL_WRITE)
skb_fill_page_desc(f->skb, 0, virt_to_page(f->bufaddr),
offset_in_page(f->bufaddr), n);
skb_get(f->skb);
f->skb->next = NULL;
spin_unlock_irqrestore(&d->lock, flags);
aoenet_xmit(f->skb);
return;
}
if (n > DEFAULTBCNT)
d->lostjumbo = 0;
break;
case WIN_IDENTIFY:
if (skb->len - sizeof *hin - sizeof *ahin < 512) {
@ -628,9 +669,9 @@ aoecmd_cfg_rsp(struct sk_buff *skb)
struct aoe_hdr *h;
struct aoe_cfghdr *ch;
ulong flags, sysminor, aoemajor;
u16 bufcnt;
struct sk_buff *sl;
enum { MAXFRAMES = 16 };
u16 n;
h = (struct aoe_hdr *) skb->mac.raw;
ch = (struct aoe_cfghdr *) (h+1);
@ -654,11 +695,11 @@ aoecmd_cfg_rsp(struct sk_buff *skb)
return;
}
bufcnt = be16_to_cpu(ch->bufcnt);
if (bufcnt > MAXFRAMES) /* keep it reasonable */
bufcnt = MAXFRAMES;
n = be16_to_cpu(ch->bufcnt);
if (n > MAXFRAMES) /* keep it reasonable */
n = MAXFRAMES;
d = aoedev_by_sysminor_m(sysminor, bufcnt);
d = aoedev_by_sysminor_m(sysminor, n);
if (d == NULL) {
printk(KERN_INFO "aoe: aoecmd_cfg_rsp: device sysminor_m failure\n");
return;
@ -669,6 +710,14 @@ aoecmd_cfg_rsp(struct sk_buff *skb)
/* permit device to migrate mac and network interface */
d->ifp = skb->dev;
memcpy(d->addr, h->src, sizeof d->addr);
if (!(d->flags & DEVFL_MAXBCNT)) {
n = d->ifp->mtu;
n -= sizeof (struct aoe_hdr) + sizeof (struct aoe_atahdr);
n /= 512;
if (n > ch->scnt)
n = ch->scnt;
d->maxbcnt = n ? n * 512 : DEFAULTBCNT;
}
/* don't change users' perspective */
if (d->nopen && !(d->flags & DEVFL_PAUSE)) {