aoe: jumbo frame support 1 of 2
authorEd L. Cashin <ecashin@coraid.com>
Wed, 20 Sep 2006 18:36:49 +0000 (14:36 -0400)
committerGreg Kroah-Hartman <gregkh@suse.de>
Wed, 18 Oct 2006 19:53:50 +0000 (12:53 -0700)
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>
drivers/block/aoe/aoe.h
drivers/block/aoe/aoechr.c
drivers/block/aoe/aoecmd.c

index fa2d804b266521bf35e083476b4c1e5166c00b09..1cec19986c40eafc08d8b692b5ead920587c1fad 100644 (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;
 };
 
index 0c543d3bfe58e8135d9beeb84a815390faacee3d..2b5256cc733db100dfa62fe33106480619ac48f9 100644 (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);
index 1aeb2969987f9539664ad4a48d3d00c181f2fb33..666797d646d6817b6340507ac1530f72bd94b68d 100644 (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)) {