]> err.no Git - linux-2.6/blobdiff - drivers/block/aoe/aoecmd.c
pci: VT3336 can't do MSI either
[linux-2.6] / drivers / block / aoe / aoecmd.c
index 5e7daa1ff6f668eb9b066e27798fff9b72d27acb..41f818be2f7ec8c4c737acaa16ecfeddc94f42b4 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2006 Coraid, Inc.  See COPYING for GPL terms. */
+/* Copyright (c) 2007 Coraid, Inc.  See COPYING for GPL terms. */
 /*
  * aoecmd.c
  * Filesystem request handling methods
@@ -18,6 +18,11 @@ static int aoe_deadsecs = 60 * 3;
 module_param(aoe_deadsecs, int, 0644);
 MODULE_PARM_DESC(aoe_deadsecs, "After aoe_deadsecs seconds, give up and fail dev.");
 
+static int aoe_maxout = 16;
+module_param(aoe_maxout, int, 0644);
+MODULE_PARM_DESC(aoe_maxout,
+       "Only aoe_maxout outstanding packets for every MAC on eX.Y.");
+
 static struct sk_buff *
 new_skb(ulong len)
 {
@@ -106,45 +111,104 @@ ifrotate(struct aoetgt *t)
        }
 }
 
+static void
+skb_pool_put(struct aoedev *d, struct sk_buff *skb)
+{
+       if (!d->skbpool_hd)
+               d->skbpool_hd = skb;
+       else
+               d->skbpool_tl->next = skb;
+       d->skbpool_tl = skb;
+}
+
+static struct sk_buff *
+skb_pool_get(struct aoedev *d)
+{
+       struct sk_buff *skb;
+
+       skb = d->skbpool_hd;
+       if (skb && atomic_read(&skb_shinfo(skb)->dataref) == 1) {
+               d->skbpool_hd = skb->next;
+               skb->next = NULL;
+               return skb;
+       }
+       if (d->nskbpool < NSKBPOOLMAX
+       && (skb = new_skb(ETH_ZLEN))) {
+               d->nskbpool++;
+               return skb;
+       }
+       return NULL;
+}
+
+/* freeframe is where we do our load balancing so it's a little hairy. */
 static struct frame *
 freeframe(struct aoedev *d)
 {
-       struct frame *f, *e;
+       struct frame *f, *e, *rf;
        struct aoetgt **t;
-       ulong n;
+       struct sk_buff *skb;
 
        if (d->targets[0] == NULL) {    /* shouldn't happen, but I'm paranoid */
                printk(KERN_ERR "aoe: NULL TARGETS!\n");
                return NULL;
        }
-       t = d->targets;
-       do {
-               if (t != d->htgt
-               && (*t)->ifp->nd
-               && (*t)->nout < (*t)->maxout) {
-                       n = (*t)->nframes;
+       t = d->tgt;
+       t++;
+       if (t >= &d->targets[NTARGETS] || !*t)
+               t = d->targets;
+       for (;;) {
+               if ((*t)->nout < (*t)->maxout
+               && t != d->htgt
+               && (*t)->ifp->nd) {
+                       rf = NULL;
                        f = (*t)->frames;
-                       e = f + n;
+                       e = f + (*t)->nframes;
                        for (; f < e; f++) {
                                if (f->tag != FREETAG)
                                        continue;
-                               if (atomic_read(&skb_shinfo(f->skb)->dataref)
+                               skb = f->skb;
+                               if (!skb
+                               && !(f->skb = skb = new_skb(ETH_ZLEN)))
+                                       continue;
+                               if (atomic_read(&skb_shinfo(skb)->dataref)
                                        != 1) {
-                                       n--;
+                                       if (!rf)
+                                               rf = f;
                                        continue;
                                }
-                               skb_shinfo(f->skb)->nr_frags = 0;
-                               f->skb->data_len = 0;
-                               skb_trim(f->skb, 0);
+gotone:                                skb_shinfo(skb)->nr_frags = skb->data_len = 0;
+                               skb_trim(skb, 0);
                                d->tgt = t;
                                ifrotate(*t);
                                return f;
                        }
-                       if (n == 0)     /* slow polling network card */
+                       /* Work can be done, but the network layer is
+                          holding our precious packets.  Try to grab
+                          one from the pool. */
+                       f = rf;
+                       if (f == NULL) {        /* more paranoia */
+                               printk(KERN_ERR
+                                       "aoe: freeframe: %s.\n",
+                                       "unexpected null rf");
+                               d->flags |= DEVFL_KICKME;
+                               return NULL;
+                       }
+                       skb = skb_pool_get(d);
+                       if (skb) {
+                               skb_pool_put(d, f->skb);
+                               f->skb = skb;
+                               goto gotone;
+                       }
+                       (*t)->dataref++;
+                       if ((*t)->nout == 0)
                                d->flags |= DEVFL_KICKME;
                }
+               if (t == d->tgt)        /* we've looped and found nada */
+                       break;
                t++;
-       } while (t < &d->targets[NTARGETS] && *t);
+               if (t >= &d->targets[NTARGETS] || !*t)
+                       t = d->targets;
+       }
        return NULL;
 }
 
@@ -309,7 +373,8 @@ resend(struct aoedev *d, struct aoetgt *t, struct frame *f)
                "%15s e%ld.%d oldtag=%08x@%08lx newtag=%08x "
                "s=%012llx d=%012llx nout=%d\n",
                "retransmit", d->aoemajor, d->aoeminor, f->tag, jiffies, n,
-               mac_addr(h->src), mac_addr(h->dst), t->nout);
+               mac_addr(h->src),
+               mac_addr(h->dst), t->nout);
        aoechr_error(buf);
 
        f->tag = n;
@@ -603,16 +668,16 @@ ataid_complete(struct aoedev *d, struct aoetgt *t, unsigned char *id)
        u16 n;
 
        /* word 83: command set supported */
-       n = le16_to_cpu(get_unaligned((__le16 *) &id[83<<1]));
+       n = get_unaligned_le16(&id[83 << 1]);
 
        /* word 86: command set/feature enabled */
-       n |= le16_to_cpu(get_unaligned((__le16 *) &id[86<<1]));
+       n |= get_unaligned_le16(&id[86 << 1]);
 
        if (n & (1<<10)) {      /* bit 10: LBA 48 */
                d->flags |= DEVFL_EXT;
 
                /* word 100: number lba48 sectors */
-               ssize = le64_to_cpu(get_unaligned((__le64 *) &id[100<<1]));
+               ssize = get_unaligned_le64(&id[100 << 1]);
 
                /* set as in ide-disk.c:init_idedisk_capacity */
                d->geo.cylinders = ssize;
@@ -623,21 +688,24 @@ ataid_complete(struct aoedev *d, struct aoetgt *t, unsigned char *id)
                d->flags &= ~DEVFL_EXT;
 
                /* number lba28 sectors */
-               ssize = le32_to_cpu(get_unaligned((__le32 *) &id[60<<1]));
+               ssize = get_unaligned_le32(&id[60 << 1]);
 
                /* NOTE: obsolete in ATA 6 */
-               d->geo.cylinders = le16_to_cpu(get_unaligned((__le16 *) &id[54<<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.cylinders = get_unaligned_le16(&id[54 << 1]);
+               d->geo.heads = get_unaligned_le16(&id[55 << 1]);
+               d->geo.sectors = 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(t->addr),
+               printk(KERN_INFO
+                       "aoe: %012llx e%ld.%d v%04x has %llu sectors\n",
+                       mac_addr(t->addr),
                        d->aoemajor, d->aoeminor,
                        d->fw_ver, (long long)ssize);
        d->ssize = ssize;
        d->geo.start = 0;
+       if (d->flags & (DEVFL_GDALLOC|DEVFL_NEWSIZE))
+               return;
        if (d->gd != NULL) {
                d->gd->capacity = ssize;
                d->flags |= DEVFL_NEWSIZE;
@@ -683,15 +751,17 @@ gettgt(struct aoedev *d, char *addr)
 }
 
 static inline void
-diskstats(struct gendisk *disk, struct bio *bio, ulong duration)
+diskstats(struct gendisk *disk, struct bio *bio, ulong duration, sector_t sector)
 {
        unsigned long n_sect = bio->bi_size >> 9;
        const int rw = bio_data_dir(bio);
+       struct hd_struct *part;
 
-       disk_stat_inc(disk, ios[rw]);
-       disk_stat_add(disk, ticks[rw], duration);
-       disk_stat_add(disk, sectors[rw], n_sect);
-       disk_stat_add(disk, io_ticks, duration);
+       part = get_part(disk, sector);
+       all_stat_inc(disk, part, ios[rw], sector);
+       all_stat_add(disk, part, ticks[rw], duration, sector);
+       all_stat_add(disk, part, sectors[rw], n_sect, sector);
+       all_stat_add(disk, part, io_ticks, duration, sector);
 }
 
 void
@@ -711,7 +781,7 @@ aoecmd_ata_rsp(struct sk_buff *skb)
        u16 aoemajor;
 
        hin = (struct aoe_hdr *) skb_mac_header(skb);
-       aoemajor = be16_to_cpu(get_unaligned(&hin->major));
+       aoemajor = get_unaligned_be16(&hin->major);
        d = aoedev_by_aoeaddr(aoemajor, hin->minor);
        if (d == NULL) {
                snprintf(ebuf, sizeof ebuf, "aoecmd_ata_rsp: ata response "
@@ -723,12 +793,11 @@ aoecmd_ata_rsp(struct sk_buff *skb)
 
        spin_lock_irqsave(&d->lock, flags);
 
-       n = be32_to_cpu(get_unaligned(&hin->tag));
+       n = get_unaligned_be32(&hin->tag);
        t = gettgt(d, hin->src);
        if (t == NULL) {
                printk(KERN_INFO "aoe: can't find target e%ld.%d:%012llx\n",
-                       d->aoemajor, d->aoeminor,
-                       (unsigned long long) mac_addr(hin->src));
+                       d->aoemajor, d->aoeminor, mac_addr(hin->src));
                spin_unlock_irqrestore(&d->lock, flags);
                return;
        }
@@ -739,9 +808,9 @@ aoecmd_ata_rsp(struct sk_buff *skb)
                snprintf(ebuf, sizeof ebuf,
                        "%15s e%d.%d    tag=%08x@%08lx\n",
                        "unexpected rsp",
-                       be16_to_cpu(get_unaligned(&hin->major)),
+                       get_unaligned_be16(&hin->major),
                        hin->minor,
-                       be32_to_cpu(get_unaligned(&hin->tag)),
+                       get_unaligned_be32(&hin->tag),
                        jiffies);
                aoechr_error(ebuf);
                return;
@@ -756,7 +825,7 @@ aoecmd_ata_rsp(struct sk_buff *skb)
 
        if (ahin->cmdstat & 0xa9) {     /* these bits cleared on success */
                printk(KERN_ERR
-                       "aoe: ata error cmd=%2.2Xh stat=%2.2Xh from e%ld.%ld\n",
+                       "aoe: ata error cmd=%2.2Xh stat=%2.2Xh from e%ld.%d\n",
                        ahout->cmdstat, ahin->cmdstat,
                        d->aoemajor, d->aoeminor);
                if (buf)
@@ -806,13 +875,13 @@ aoecmd_ata_rsp(struct sk_buff *skb)
                        printk(KERN_INFO
                                "aoe: unrecognized ata command %2.2Xh for %d.%d\n",
                                ahout->cmdstat,
-                               be16_to_cpu(get_unaligned(&hin->major)),
+                               get_unaligned_be16(&hin->major),
                                hin->minor);
                }
        }
 
        if (buf && --buf->nframesout == 0 && buf->resid == 0) {
-               diskstats(d->gd, buf->bio, jiffies - buf->stime);
+               diskstats(d->gd, buf->bio, jiffies - buf->stime, buf->sector);
                n = (buf->flags & BUFFL_FAIL) ? -EIO : 0;
                bio_endio(buf->bio, n);
                mempool_free(buf, d->bufpool);
@@ -890,37 +959,29 @@ addtgt(struct aoedev *d, char *addr, ulong nframes)
        for (; tt < te && *tt; tt++)
                ;
 
-       if (tt == te)
+       if (tt == te) {
+               printk(KERN_INFO
+                       "aoe: device addtgt failure; too many targets\n");
                return NULL;
-
+       }
        t = kcalloc(1, sizeof *t, GFP_ATOMIC);
        f = kcalloc(nframes, sizeof *f, GFP_ATOMIC);
-       if (!t || !f)
-               goto bail;
+       if (!t || !f) {
+               kfree(f);
+               kfree(t);
+               printk(KERN_INFO "aoe: cannot allocate memory to add target\n");
+               return NULL;
+       }
+
        t->nframes = nframes;
        t->frames = f;
        e = f + nframes;
-       for (; f < e; f++) {
+       for (; f < e; f++)
                f->tag = FREETAG;
-               f->skb = new_skb(ETH_ZLEN);
-               if (!f->skb)
-                       break;
-       }
-       if (f != e) {
-               while (f > t->frames) {
-                       f--;
-                       dev_kfree_skb(f->skb);
-               }
-               goto bail;
-       }
        memcpy(t->addr, addr, sizeof t->addr);
        t->ifp = t->ifs;
        t->maxout = t->nframes;
        return *tt = t;
-bail:
-       kfree(t);
-       kfree(f);
-       return NULL;
 }
 
 void
@@ -933,7 +994,6 @@ aoecmd_cfg_rsp(struct sk_buff *skb)
        struct aoeif *ifp;
        ulong flags, sysminor, aoemajor;
        struct sk_buff *sl;
-       enum { MAXFRAMES = 16 };
        u16 n;
 
        h = (struct aoe_hdr *) skb_mac_header(skb);
@@ -958,8 +1018,8 @@ aoecmd_cfg_rsp(struct sk_buff *skb)
        }
 
        n = be16_to_cpu(ch->bufcnt);
-       if (n > MAXFRAMES)      /* keep it reasonable */
-               n = MAXFRAMES;
+       if (n > aoe_maxout)     /* keep it reasonable */
+               n = aoe_maxout;
 
        d = aoedev_by_sysminor_m(sysminor);
        if (d == NULL) {
@@ -973,9 +1033,6 @@ aoecmd_cfg_rsp(struct sk_buff *skb)
        if (!t) {
                t = addtgt(d, h->src, n);
                if (!t) {
-                       printk(KERN_INFO
-                               "aoe: device addtgt failure; "
-                               "too many targets?\n");
                        spin_unlock_irqrestore(&d->lock, flags);
                        return;
                }
@@ -1003,7 +1060,7 @@ aoecmd_cfg_rsp(struct sk_buff *skb)
                                "aoe: e%ld.%d: setting %d%s%s:%012llx\n",
                                d->aoemajor, d->aoeminor, n,
                                " byte data frames on ", ifp->nd->name,
-                               (unsigned long long) mac_addr(t->addr));
+                               mac_addr(t->addr));
                        ifp->maxbcnt = n;
                }
        }