summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEd L. Cashin <ecashin@coraid.com>2006-09-20 22:36:49 +0400
committerGreg Kroah-Hartman <gregkh@suse.de>2006-10-18 23:53:50 +0400
commit19bf26353c50bc2be375109ec73f2f0bbd616ed1 (patch)
tree5bcdf714d67d573885d2f42a7c0a79586de77c25
parente407a7f6cd143b3ab4eb3d7e1cf882e96b710eb5 (diff)
downloadlinux-19bf26353c50bc2be375109ec73f2f0bbd616ed1.tar.xz
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>
-rw-r--r--drivers/block/aoe/aoe.h11
-rw-r--r--drivers/block/aoe/aoechr.c1
-rw-r--r--drivers/block/aoe/aoecmd.c77
3 files changed, 72 insertions, 17 deletions
diff --git a/drivers/block/aoe/aoe.h b/drivers/block/aoe/aoe.h
index fa2d804b2665..1cec19986c40 100644
--- a/drivers/block/aoe/aoe.h
+++ b/drivers/block/aoe/aoe.h
@@ -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;
};
diff --git a/drivers/block/aoe/aoechr.c b/drivers/block/aoe/aoechr.c
index 0c543d3bfe58..2b5256cc733d 100644
--- a/drivers/block/aoe/aoechr.c
+++ b/drivers/block/aoe/aoechr.c
@@ -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);
diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c
index 1aeb2969987f..666797d646d6 100644
--- a/drivers/block/aoe/aoecmd.c
+++ b/drivers/block/aoe/aoecmd.c
@@ -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)) {