152e112b3SEd L. Cashin /* Copyright (c) 2007 Coraid, Inc. See COPYING for GPL terms. */ 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * aoecmd.c 41da177e4SLinus Torvalds * Filesystem request handling methods 51da177e4SLinus Torvalds */ 61da177e4SLinus Torvalds 71da177e4SLinus Torvalds #include <linux/hdreg.h> 81da177e4SLinus Torvalds #include <linux/blkdev.h> 91da177e4SLinus Torvalds #include <linux/skbuff.h> 101da177e4SLinus Torvalds #include <linux/netdevice.h> 113ae1c24eSEd L. Cashin #include <linux/genhd.h> 1268e0d42fSEd L. Cashin #include <linux/moduleparam.h> 13881d966bSEric W. Biederman #include <net/net_namespace.h> 14475172fbSEd L. Cashin #include <asm/unaligned.h> 151da177e4SLinus Torvalds #include "aoe.h" 161da177e4SLinus Torvalds 17b751e8b6SEd L. Cashin static int aoe_deadsecs = 60 * 3; 18b751e8b6SEd L. Cashin module_param(aoe_deadsecs, int, 0644); 19b751e8b6SEd L. Cashin MODULE_PARM_DESC(aoe_deadsecs, "After aoe_deadsecs seconds, give up and fail dev."); 201da177e4SLinus Torvalds 217df620d8SEd L. Cashin static int aoe_maxout = 16; 227df620d8SEd L. Cashin module_param(aoe_maxout, int, 0644); 237df620d8SEd L. Cashin MODULE_PARM_DESC(aoe_maxout, 247df620d8SEd L. Cashin "Only aoe_maxout outstanding packets for every MAC on eX.Y."); 257df620d8SEd L. Cashin 2668e0d42fSEd L. Cashin static struct sk_buff * 27e407a7f6SEd L. Cashin new_skb(ulong len) 281da177e4SLinus Torvalds { 291da177e4SLinus Torvalds struct sk_buff *skb; 301da177e4SLinus Torvalds 311da177e4SLinus Torvalds skb = alloc_skb(len, GFP_ATOMIC); 321da177e4SLinus Torvalds if (skb) { 33459a98edSArnaldo Carvalho de Melo skb_reset_mac_header(skb); 34c1d2bbe1SArnaldo Carvalho de Melo skb_reset_network_header(skb); 351da177e4SLinus Torvalds skb->protocol = __constant_htons(ETH_P_AOE); 361da177e4SLinus Torvalds skb->priority = 0; 371da177e4SLinus Torvalds skb->next = skb->prev = NULL; 381da177e4SLinus Torvalds 391da177e4SLinus Torvalds /* tell the network layer not to perform IP checksums 401da177e4SLinus Torvalds * or to get the NIC to do it 411da177e4SLinus Torvalds */ 421da177e4SLinus Torvalds skb->ip_summed = CHECKSUM_NONE; 431da177e4SLinus Torvalds } 441da177e4SLinus Torvalds return skb; 451da177e4SLinus Torvalds } 461da177e4SLinus Torvalds 471da177e4SLinus Torvalds static struct frame * 4868e0d42fSEd L. Cashin getframe(struct aoetgt *t, int tag) 491da177e4SLinus Torvalds { 501da177e4SLinus Torvalds struct frame *f, *e; 511da177e4SLinus Torvalds 5268e0d42fSEd L. Cashin f = t->frames; 5368e0d42fSEd L. Cashin e = f + t->nframes; 541da177e4SLinus Torvalds for (; f<e; f++) 551da177e4SLinus Torvalds if (f->tag == tag) 561da177e4SLinus Torvalds return f; 571da177e4SLinus Torvalds return NULL; 581da177e4SLinus Torvalds } 591da177e4SLinus Torvalds 601da177e4SLinus Torvalds /* 611da177e4SLinus Torvalds * Leave the top bit clear so we have tagspace for userland. 621da177e4SLinus Torvalds * The bottom 16 bits are the xmit tick for rexmit/rttavg processing. 631da177e4SLinus Torvalds * This driver reserves tag -1 to mean "unused frame." 641da177e4SLinus Torvalds */ 651da177e4SLinus Torvalds static int 6668e0d42fSEd L. Cashin newtag(struct aoetgt *t) 671da177e4SLinus Torvalds { 681da177e4SLinus Torvalds register ulong n; 691da177e4SLinus Torvalds 701da177e4SLinus Torvalds n = jiffies & 0xffff; 7168e0d42fSEd L. Cashin return n |= (++t->lasttag & 0x7fff) << 16; 721da177e4SLinus Torvalds } 731da177e4SLinus Torvalds 741da177e4SLinus Torvalds static int 7568e0d42fSEd L. Cashin aoehdr_atainit(struct aoedev *d, struct aoetgt *t, struct aoe_hdr *h) 761da177e4SLinus Torvalds { 7768e0d42fSEd L. Cashin u32 host_tag = newtag(t); 781da177e4SLinus Torvalds 7968e0d42fSEd L. Cashin memcpy(h->src, t->ifp->nd->dev_addr, sizeof h->src); 8068e0d42fSEd L. Cashin memcpy(h->dst, t->addr, sizeof h->dst); 8163e9cc5dSecashin@coraid.com h->type = __constant_cpu_to_be16(ETH_P_AOE); 821da177e4SLinus Torvalds h->verfl = AOE_HVER; 8363e9cc5dSecashin@coraid.com h->major = cpu_to_be16(d->aoemajor); 841da177e4SLinus Torvalds h->minor = d->aoeminor; 851da177e4SLinus Torvalds h->cmd = AOECMD_ATA; 8663e9cc5dSecashin@coraid.com h->tag = cpu_to_be32(host_tag); 871da177e4SLinus Torvalds 881da177e4SLinus Torvalds return host_tag; 891da177e4SLinus Torvalds } 901da177e4SLinus Torvalds 9119bf2635SEd L. Cashin static inline void 9219bf2635SEd L. Cashin put_lba(struct aoe_atahdr *ah, sector_t lba) 9319bf2635SEd L. Cashin { 9419bf2635SEd L. Cashin ah->lba0 = lba; 9519bf2635SEd L. Cashin ah->lba1 = lba >>= 8; 9619bf2635SEd L. Cashin ah->lba2 = lba >>= 8; 9719bf2635SEd L. Cashin ah->lba3 = lba >>= 8; 9819bf2635SEd L. Cashin ah->lba4 = lba >>= 8; 9919bf2635SEd L. Cashin ah->lba5 = lba >>= 8; 10019bf2635SEd L. Cashin } 10119bf2635SEd L. Cashin 1021da177e4SLinus Torvalds static void 10368e0d42fSEd L. Cashin ifrotate(struct aoetgt *t) 1041da177e4SLinus Torvalds { 10568e0d42fSEd L. Cashin t->ifp++; 10668e0d42fSEd L. Cashin if (t->ifp >= &t->ifs[NAOEIFS] || t->ifp->nd == NULL) 10768e0d42fSEd L. Cashin t->ifp = t->ifs; 10868e0d42fSEd L. Cashin if (t->ifp->nd == NULL) { 10968e0d42fSEd L. Cashin printk(KERN_INFO "aoe: no interface to rotate to\n"); 11068e0d42fSEd L. Cashin BUG(); 11168e0d42fSEd L. Cashin } 11268e0d42fSEd L. Cashin } 11368e0d42fSEd L. Cashin 1149bb237b6SEd L. Cashin static void 1159bb237b6SEd L. Cashin skb_pool_put(struct aoedev *d, struct sk_buff *skb) 1169bb237b6SEd L. Cashin { 1179bb237b6SEd L. Cashin if (!d->skbpool_hd) 1189bb237b6SEd L. Cashin d->skbpool_hd = skb; 1199bb237b6SEd L. Cashin else 1209bb237b6SEd L. Cashin d->skbpool_tl->next = skb; 1219bb237b6SEd L. Cashin d->skbpool_tl = skb; 1229bb237b6SEd L. Cashin } 1239bb237b6SEd L. Cashin 1249bb237b6SEd L. Cashin static struct sk_buff * 1259bb237b6SEd L. Cashin skb_pool_get(struct aoedev *d) 1269bb237b6SEd L. Cashin { 1279bb237b6SEd L. Cashin struct sk_buff *skb; 1289bb237b6SEd L. Cashin 1299bb237b6SEd L. Cashin skb = d->skbpool_hd; 1309bb237b6SEd L. Cashin if (skb && atomic_read(&skb_shinfo(skb)->dataref) == 1) { 1319bb237b6SEd L. Cashin d->skbpool_hd = skb->next; 1329bb237b6SEd L. Cashin skb->next = NULL; 1339bb237b6SEd L. Cashin return skb; 1349bb237b6SEd L. Cashin } 1359bb237b6SEd L. Cashin if (d->nskbpool < NSKBPOOLMAX 1369bb237b6SEd L. Cashin && (skb = new_skb(ETH_ZLEN))) { 1379bb237b6SEd L. Cashin d->nskbpool++; 1389bb237b6SEd L. Cashin return skb; 1399bb237b6SEd L. Cashin } 1409bb237b6SEd L. Cashin return NULL; 1419bb237b6SEd L. Cashin } 1429bb237b6SEd L. Cashin 1439bb237b6SEd L. Cashin /* freeframe is where we do our load balancing so it's a little hairy. */ 14468e0d42fSEd L. Cashin static struct frame * 14568e0d42fSEd L. Cashin freeframe(struct aoedev *d) 14668e0d42fSEd L. Cashin { 1479bb237b6SEd L. Cashin struct frame *f, *e, *rf; 14868e0d42fSEd L. Cashin struct aoetgt **t; 1499bb237b6SEd L. Cashin struct sk_buff *skb; 15068e0d42fSEd L. Cashin 15168e0d42fSEd L. Cashin if (d->targets[0] == NULL) { /* shouldn't happen, but I'm paranoid */ 15268e0d42fSEd L. Cashin printk(KERN_ERR "aoe: NULL TARGETS!\n"); 15368e0d42fSEd L. Cashin return NULL; 15468e0d42fSEd L. Cashin } 1559bb237b6SEd L. Cashin t = d->tgt; 1569bb237b6SEd L. Cashin t++; 1579bb237b6SEd L. Cashin if (t >= &d->targets[NTARGETS] || !*t) 15868e0d42fSEd L. Cashin t = d->targets; 1599bb237b6SEd L. Cashin for (;;) { 1609bb237b6SEd L. Cashin if ((*t)->nout < (*t)->maxout 1619bb237b6SEd L. Cashin && t != d->htgt 1629bb237b6SEd L. Cashin && (*t)->ifp->nd) { 1639bb237b6SEd L. Cashin rf = NULL; 16468e0d42fSEd L. Cashin f = (*t)->frames; 1659bb237b6SEd L. Cashin e = f + (*t)->nframes; 16668e0d42fSEd L. Cashin for (; f < e; f++) { 16768e0d42fSEd L. Cashin if (f->tag != FREETAG) 16868e0d42fSEd L. Cashin continue; 1699bb237b6SEd L. Cashin skb = f->skb; 1709bb237b6SEd L. Cashin if (!skb 1719bb237b6SEd L. Cashin && !(f->skb = skb = new_skb(ETH_ZLEN))) 1729bb237b6SEd L. Cashin continue; 1739bb237b6SEd L. Cashin if (atomic_read(&skb_shinfo(skb)->dataref) 17468e0d42fSEd L. Cashin != 1) { 1759bb237b6SEd L. Cashin if (!rf) 1769bb237b6SEd L. Cashin rf = f; 17768e0d42fSEd L. Cashin continue; 17868e0d42fSEd L. Cashin } 1799bb237b6SEd L. Cashin gotone: skb_shinfo(skb)->nr_frags = skb->data_len = 0; 1809bb237b6SEd L. Cashin skb_trim(skb, 0); 18168e0d42fSEd L. Cashin d->tgt = t; 18268e0d42fSEd L. Cashin ifrotate(*t); 18368e0d42fSEd L. Cashin return f; 18468e0d42fSEd L. Cashin } 1859bb237b6SEd L. Cashin /* Work can be done, but the network layer is 1869bb237b6SEd L. Cashin holding our precious packets. Try to grab 1879bb237b6SEd L. Cashin one from the pool. */ 1889bb237b6SEd L. Cashin f = rf; 1899bb237b6SEd L. Cashin if (f == NULL) { /* more paranoia */ 1909bb237b6SEd L. Cashin printk(KERN_ERR 1919bb237b6SEd L. Cashin "aoe: freeframe: %s.\n", 1929bb237b6SEd L. Cashin "unexpected null rf"); 1939bb237b6SEd L. Cashin d->flags |= DEVFL_KICKME; 1949bb237b6SEd L. Cashin return NULL; 1959bb237b6SEd L. Cashin } 1969bb237b6SEd L. Cashin skb = skb_pool_get(d); 1979bb237b6SEd L. Cashin if (skb) { 1989bb237b6SEd L. Cashin skb_pool_put(d, f->skb); 1999bb237b6SEd L. Cashin f->skb = skb; 2009bb237b6SEd L. Cashin goto gotone; 2019bb237b6SEd L. Cashin } 2029bb237b6SEd L. Cashin (*t)->dataref++; 2039bb237b6SEd L. Cashin if ((*t)->nout == 0) 20468e0d42fSEd L. Cashin d->flags |= DEVFL_KICKME; 20568e0d42fSEd L. Cashin } 2069bb237b6SEd L. Cashin if (t == d->tgt) /* we've looped and found nada */ 2079bb237b6SEd L. Cashin break; 20868e0d42fSEd L. Cashin t++; 2099bb237b6SEd L. Cashin if (t >= &d->targets[NTARGETS] || !*t) 2109bb237b6SEd L. Cashin t = d->targets; 2119bb237b6SEd L. Cashin } 21268e0d42fSEd L. Cashin return NULL; 21368e0d42fSEd L. Cashin } 21468e0d42fSEd L. Cashin 21568e0d42fSEd L. Cashin static int 21668e0d42fSEd L. Cashin aoecmd_ata_rw(struct aoedev *d) 21768e0d42fSEd L. Cashin { 21868e0d42fSEd L. Cashin struct frame *f; 2191da177e4SLinus Torvalds struct aoe_hdr *h; 2201da177e4SLinus Torvalds struct aoe_atahdr *ah; 2211da177e4SLinus Torvalds struct buf *buf; 22268e0d42fSEd L. Cashin struct bio_vec *bv; 22368e0d42fSEd L. Cashin struct aoetgt *t; 2241da177e4SLinus Torvalds struct sk_buff *skb; 2251da177e4SLinus Torvalds ulong bcnt; 2261da177e4SLinus Torvalds char writebit, extbit; 2271da177e4SLinus Torvalds 2281da177e4SLinus Torvalds writebit = 0x10; 2291da177e4SLinus Torvalds extbit = 0x4; 2301da177e4SLinus Torvalds 23168e0d42fSEd L. Cashin f = freeframe(d); 23268e0d42fSEd L. Cashin if (f == NULL) 23368e0d42fSEd L. Cashin return 0; 23468e0d42fSEd L. Cashin t = *d->tgt; 2351da177e4SLinus Torvalds buf = d->inprocess; 23668e0d42fSEd L. Cashin bv = buf->bv; 23768e0d42fSEd L. Cashin bcnt = t->ifp->maxbcnt; 23868e0d42fSEd L. Cashin if (bcnt == 0) 23968e0d42fSEd L. Cashin bcnt = DEFAULTBCNT; 24068e0d42fSEd L. Cashin if (bcnt > buf->bv_resid) 2411da177e4SLinus Torvalds bcnt = buf->bv_resid; 2421da177e4SLinus Torvalds /* initialize the headers & frame */ 243e407a7f6SEd L. Cashin skb = f->skb; 244abdbf94dSEd L. Cashin h = (struct aoe_hdr *) skb_mac_header(skb); 2451da177e4SLinus Torvalds ah = (struct aoe_atahdr *) (h+1); 24619900cdeSEd L. Cashin skb_put(skb, sizeof *h + sizeof *ah); 24719900cdeSEd L. Cashin memset(h, 0, skb->len); 24868e0d42fSEd L. Cashin f->tag = aoehdr_atainit(d, t, h); 24968e0d42fSEd L. Cashin t->nout++; 2501da177e4SLinus Torvalds f->waited = 0; 2511da177e4SLinus Torvalds f->buf = buf; 25268e0d42fSEd L. Cashin f->bufaddr = page_address(bv->bv_page) + buf->bv_off; 25319bf2635SEd L. Cashin f->bcnt = bcnt; 25468e0d42fSEd L. Cashin f->lba = buf->sector; 2551da177e4SLinus Torvalds 2561da177e4SLinus Torvalds /* set up ata header */ 2571da177e4SLinus Torvalds ah->scnt = bcnt >> 9; 25868e0d42fSEd L. Cashin put_lba(ah, buf->sector); 2591da177e4SLinus Torvalds if (d->flags & DEVFL_EXT) { 2601da177e4SLinus Torvalds ah->aflags |= AOEAFL_EXT; 2611da177e4SLinus Torvalds } else { 2621da177e4SLinus Torvalds extbit = 0; 2631da177e4SLinus Torvalds ah->lba3 &= 0x0f; 2641da177e4SLinus Torvalds ah->lba3 |= 0xe0; /* LBA bit + obsolete 0xa0 */ 2651da177e4SLinus Torvalds } 2661da177e4SLinus Torvalds if (bio_data_dir(buf->bio) == WRITE) { 26768e0d42fSEd L. Cashin skb_fill_page_desc(skb, 0, bv->bv_page, buf->bv_off, bcnt); 2681da177e4SLinus Torvalds ah->aflags |= AOEAFL_WRITE; 2694f51dc5eSEd L. Cashin skb->len += bcnt; 2704f51dc5eSEd L. Cashin skb->data_len = bcnt; 27168e0d42fSEd L. Cashin t->wpkts++; 2721da177e4SLinus Torvalds } else { 27368e0d42fSEd L. Cashin t->rpkts++; 2741da177e4SLinus Torvalds writebit = 0; 2751da177e4SLinus Torvalds } 2761da177e4SLinus Torvalds 2771da177e4SLinus Torvalds ah->cmdstat = WIN_READ | writebit | extbit; 2781da177e4SLinus Torvalds 2791da177e4SLinus Torvalds /* mark all tracking fields and load out */ 2801da177e4SLinus Torvalds buf->nframesout += 1; 28168e0d42fSEd L. Cashin buf->bv_off += bcnt; 2821da177e4SLinus Torvalds buf->bv_resid -= bcnt; 2831da177e4SLinus Torvalds buf->resid -= bcnt; 2841da177e4SLinus Torvalds buf->sector += bcnt >> 9; 2851da177e4SLinus Torvalds if (buf->resid == 0) { 2861da177e4SLinus Torvalds d->inprocess = NULL; 2871da177e4SLinus Torvalds } else if (buf->bv_resid == 0) { 28868e0d42fSEd L. Cashin buf->bv = ++bv; 28968e0d42fSEd L. Cashin buf->bv_resid = bv->bv_len; 29068e0d42fSEd L. Cashin WARN_ON(buf->bv_resid == 0); 29168e0d42fSEd L. Cashin buf->bv_off = bv->bv_offset; 2921da177e4SLinus Torvalds } 2931da177e4SLinus Torvalds 29468e0d42fSEd L. Cashin skb->dev = t->ifp->nd; 2954f51dc5eSEd L. Cashin skb = skb_clone(skb, GFP_ATOMIC); 29668e0d42fSEd L. Cashin if (skb) { 297a4b38364Secashin@coraid.com if (d->sendq_hd) 298a4b38364Secashin@coraid.com d->sendq_tl->next = skb; 299a4b38364Secashin@coraid.com else 300a4b38364Secashin@coraid.com d->sendq_hd = skb; 301a4b38364Secashin@coraid.com d->sendq_tl = skb; 3021da177e4SLinus Torvalds } 30368e0d42fSEd L. Cashin return 1; 30468e0d42fSEd L. Cashin } 3051da177e4SLinus Torvalds 3063ae1c24eSEd L. Cashin /* some callers cannot sleep, and they can call this function, 3073ae1c24eSEd L. Cashin * transmitting the packets later, when interrupts are on 3083ae1c24eSEd L. Cashin */ 3093ae1c24eSEd L. Cashin static struct sk_buff * 3103ae1c24eSEd L. Cashin aoecmd_cfg_pkts(ushort aoemajor, unsigned char aoeminor, struct sk_buff **tail) 3113ae1c24eSEd L. Cashin { 3123ae1c24eSEd L. Cashin struct aoe_hdr *h; 3133ae1c24eSEd L. Cashin struct aoe_cfghdr *ch; 3143ae1c24eSEd L. Cashin struct sk_buff *skb, *sl, *sl_tail; 3153ae1c24eSEd L. Cashin struct net_device *ifp; 3163ae1c24eSEd L. Cashin 3173ae1c24eSEd L. Cashin sl = sl_tail = NULL; 3183ae1c24eSEd L. Cashin 3193ae1c24eSEd L. Cashin read_lock(&dev_base_lock); 320881d966bSEric W. Biederman for_each_netdev(&init_net, ifp) { 3213ae1c24eSEd L. Cashin dev_hold(ifp); 3223ae1c24eSEd L. Cashin if (!is_aoe_netif(ifp)) 3237562f876SPavel Emelianov goto cont; 3243ae1c24eSEd L. Cashin 325e407a7f6SEd L. Cashin skb = new_skb(sizeof *h + sizeof *ch); 3263ae1c24eSEd L. Cashin if (skb == NULL) { 327a12c93f0SEd L. Cashin printk(KERN_INFO "aoe: skb alloc failure\n"); 3287562f876SPavel Emelianov goto cont; 3293ae1c24eSEd L. Cashin } 33019900cdeSEd L. Cashin skb_put(skb, sizeof *h + sizeof *ch); 331e407a7f6SEd L. Cashin skb->dev = ifp; 3323ae1c24eSEd L. Cashin if (sl_tail == NULL) 3333ae1c24eSEd L. Cashin sl_tail = skb; 334abdbf94dSEd L. Cashin h = (struct aoe_hdr *) skb_mac_header(skb); 3353ae1c24eSEd L. Cashin memset(h, 0, sizeof *h + sizeof *ch); 3363ae1c24eSEd L. Cashin 3373ae1c24eSEd L. Cashin memset(h->dst, 0xff, sizeof h->dst); 3383ae1c24eSEd L. Cashin memcpy(h->src, ifp->dev_addr, sizeof h->src); 3393ae1c24eSEd L. Cashin h->type = __constant_cpu_to_be16(ETH_P_AOE); 3403ae1c24eSEd L. Cashin h->verfl = AOE_HVER; 3413ae1c24eSEd L. Cashin h->major = cpu_to_be16(aoemajor); 3423ae1c24eSEd L. Cashin h->minor = aoeminor; 3433ae1c24eSEd L. Cashin h->cmd = AOECMD_CFG; 3443ae1c24eSEd L. Cashin 3453ae1c24eSEd L. Cashin skb->next = sl; 3463ae1c24eSEd L. Cashin sl = skb; 3477562f876SPavel Emelianov cont: 3487562f876SPavel Emelianov dev_put(ifp); 3493ae1c24eSEd L. Cashin } 3503ae1c24eSEd L. Cashin read_unlock(&dev_base_lock); 3513ae1c24eSEd L. Cashin 3523ae1c24eSEd L. Cashin if (tail != NULL) 3533ae1c24eSEd L. Cashin *tail = sl_tail; 3543ae1c24eSEd L. Cashin return sl; 3553ae1c24eSEd L. Cashin } 3563ae1c24eSEd L. Cashin 3571da177e4SLinus Torvalds static void 35868e0d42fSEd L. Cashin resend(struct aoedev *d, struct aoetgt *t, struct frame *f) 3591da177e4SLinus Torvalds { 3601da177e4SLinus Torvalds struct sk_buff *skb; 3611da177e4SLinus Torvalds struct aoe_hdr *h; 36219bf2635SEd L. Cashin struct aoe_atahdr *ah; 3631da177e4SLinus Torvalds char buf[128]; 3641da177e4SLinus Torvalds u32 n; 3651da177e4SLinus Torvalds 36668e0d42fSEd L. Cashin ifrotate(t); 36768e0d42fSEd L. Cashin n = newtag(t); 368e407a7f6SEd L. Cashin skb = f->skb; 369abdbf94dSEd L. Cashin h = (struct aoe_hdr *) skb_mac_header(skb); 37019bf2635SEd L. Cashin ah = (struct aoe_atahdr *) (h+1); 37168e0d42fSEd L. Cashin 37268e0d42fSEd L. Cashin snprintf(buf, sizeof buf, 37368e0d42fSEd L. Cashin "%15s e%ld.%d oldtag=%08x@%08lx newtag=%08x " 37468e0d42fSEd L. Cashin "s=%012llx d=%012llx nout=%d\n", 37568e0d42fSEd L. Cashin "retransmit", d->aoemajor, d->aoeminor, f->tag, jiffies, n, 3761eb0da4cSEd L. Cashin mac_addr(h->src), 3771eb0da4cSEd L. Cashin mac_addr(h->dst), t->nout); 37868e0d42fSEd L. Cashin aoechr_error(buf); 37968e0d42fSEd L. Cashin 3801da177e4SLinus Torvalds f->tag = n; 38163e9cc5dSecashin@coraid.com h->tag = cpu_to_be32(n); 38268e0d42fSEd L. Cashin memcpy(h->dst, t->addr, sizeof h->dst); 38368e0d42fSEd L. Cashin memcpy(h->src, t->ifp->nd->dev_addr, sizeof h->src); 3841da177e4SLinus Torvalds 38568e0d42fSEd L. Cashin switch (ah->cmdstat) { 38668e0d42fSEd L. Cashin default: 38768e0d42fSEd L. Cashin break; 38868e0d42fSEd L. Cashin case WIN_READ: 38968e0d42fSEd L. Cashin case WIN_READ_EXT: 39068e0d42fSEd L. Cashin case WIN_WRITE: 39168e0d42fSEd L. Cashin case WIN_WRITE_EXT: 39268e0d42fSEd L. Cashin put_lba(ah, f->lba); 39368e0d42fSEd L. Cashin 39468e0d42fSEd L. Cashin n = f->bcnt; 39568e0d42fSEd L. Cashin if (n > DEFAULTBCNT) 39668e0d42fSEd L. Cashin n = DEFAULTBCNT; 39768e0d42fSEd L. Cashin ah->scnt = n >> 9; 3984f51dc5eSEd L. Cashin if (ah->aflags & AOEAFL_WRITE) { 39919bf2635SEd L. Cashin skb_fill_page_desc(skb, 0, virt_to_page(f->bufaddr), 40068e0d42fSEd L. Cashin offset_in_page(f->bufaddr), n); 40168e0d42fSEd L. Cashin skb->len = sizeof *h + sizeof *ah + n; 40268e0d42fSEd L. Cashin skb->data_len = n; 40319bf2635SEd L. Cashin } 40419bf2635SEd L. Cashin } 40568e0d42fSEd L. Cashin skb->dev = t->ifp->nd; 4064f51dc5eSEd L. Cashin skb = skb_clone(skb, GFP_ATOMIC); 4074f51dc5eSEd L. Cashin if (skb == NULL) 4084f51dc5eSEd L. Cashin return; 409a4b38364Secashin@coraid.com if (d->sendq_hd) 410a4b38364Secashin@coraid.com d->sendq_tl->next = skb; 411a4b38364Secashin@coraid.com else 412a4b38364Secashin@coraid.com d->sendq_hd = skb; 413a4b38364Secashin@coraid.com d->sendq_tl = skb; 4141da177e4SLinus Torvalds } 4151da177e4SLinus Torvalds 4161da177e4SLinus Torvalds static int 4171da177e4SLinus Torvalds tsince(int tag) 4181da177e4SLinus Torvalds { 4191da177e4SLinus Torvalds int n; 4201da177e4SLinus Torvalds 4211da177e4SLinus Torvalds n = jiffies & 0xffff; 4221da177e4SLinus Torvalds n -= tag & 0xffff; 4231da177e4SLinus Torvalds if (n < 0) 4241da177e4SLinus Torvalds n += 1<<16; 4251da177e4SLinus Torvalds return n; 4261da177e4SLinus Torvalds } 4271da177e4SLinus Torvalds 42868e0d42fSEd L. Cashin static struct aoeif * 42968e0d42fSEd L. Cashin getif(struct aoetgt *t, struct net_device *nd) 43068e0d42fSEd L. Cashin { 43168e0d42fSEd L. Cashin struct aoeif *p, *e; 43268e0d42fSEd L. Cashin 43368e0d42fSEd L. Cashin p = t->ifs; 43468e0d42fSEd L. Cashin e = p + NAOEIFS; 43568e0d42fSEd L. Cashin for (; p < e; p++) 43668e0d42fSEd L. Cashin if (p->nd == nd) 43768e0d42fSEd L. Cashin return p; 43868e0d42fSEd L. Cashin return NULL; 43968e0d42fSEd L. Cashin } 44068e0d42fSEd L. Cashin 44168e0d42fSEd L. Cashin static struct aoeif * 44268e0d42fSEd L. Cashin addif(struct aoetgt *t, struct net_device *nd) 44368e0d42fSEd L. Cashin { 44468e0d42fSEd L. Cashin struct aoeif *p; 44568e0d42fSEd L. Cashin 44668e0d42fSEd L. Cashin p = getif(t, NULL); 44768e0d42fSEd L. Cashin if (!p) 44868e0d42fSEd L. Cashin return NULL; 44968e0d42fSEd L. Cashin p->nd = nd; 45068e0d42fSEd L. Cashin p->maxbcnt = DEFAULTBCNT; 45168e0d42fSEd L. Cashin p->lost = 0; 45268e0d42fSEd L. Cashin p->lostjumbo = 0; 45368e0d42fSEd L. Cashin return p; 45468e0d42fSEd L. Cashin } 45568e0d42fSEd L. Cashin 45668e0d42fSEd L. Cashin static void 45768e0d42fSEd L. Cashin ejectif(struct aoetgt *t, struct aoeif *ifp) 45868e0d42fSEd L. Cashin { 45968e0d42fSEd L. Cashin struct aoeif *e; 46068e0d42fSEd L. Cashin ulong n; 46168e0d42fSEd L. Cashin 46268e0d42fSEd L. Cashin e = t->ifs + NAOEIFS - 1; 46368e0d42fSEd L. Cashin n = (e - ifp) * sizeof *ifp; 46468e0d42fSEd L. Cashin memmove(ifp, ifp+1, n); 46568e0d42fSEd L. Cashin e->nd = NULL; 46668e0d42fSEd L. Cashin } 46768e0d42fSEd L. Cashin 46868e0d42fSEd L. Cashin static int 46968e0d42fSEd L. Cashin sthtith(struct aoedev *d) 47068e0d42fSEd L. Cashin { 47168e0d42fSEd L. Cashin struct frame *f, *e, *nf; 47268e0d42fSEd L. Cashin struct sk_buff *skb; 47368e0d42fSEd L. Cashin struct aoetgt *ht = *d->htgt; 47468e0d42fSEd L. Cashin 47568e0d42fSEd L. Cashin f = ht->frames; 47668e0d42fSEd L. Cashin e = f + ht->nframes; 47768e0d42fSEd L. Cashin for (; f < e; f++) { 47868e0d42fSEd L. Cashin if (f->tag == FREETAG) 47968e0d42fSEd L. Cashin continue; 48068e0d42fSEd L. Cashin nf = freeframe(d); 48168e0d42fSEd L. Cashin if (!nf) 48268e0d42fSEd L. Cashin return 0; 48368e0d42fSEd L. Cashin skb = nf->skb; 48468e0d42fSEd L. Cashin *nf = *f; 48568e0d42fSEd L. Cashin f->skb = skb; 48668e0d42fSEd L. Cashin f->tag = FREETAG; 48768e0d42fSEd L. Cashin nf->waited = 0; 48868e0d42fSEd L. Cashin ht->nout--; 48968e0d42fSEd L. Cashin (*d->tgt)->nout++; 49068e0d42fSEd L. Cashin resend(d, *d->tgt, nf); 49168e0d42fSEd L. Cashin } 49268e0d42fSEd L. Cashin /* he's clean, he's useless. take away his interfaces */ 49368e0d42fSEd L. Cashin memset(ht->ifs, 0, sizeof ht->ifs); 49468e0d42fSEd L. Cashin d->htgt = NULL; 49568e0d42fSEd L. Cashin return 1; 49668e0d42fSEd L. Cashin } 49768e0d42fSEd L. Cashin 49868e0d42fSEd L. Cashin static inline unsigned char 49968e0d42fSEd L. Cashin ata_scnt(unsigned char *packet) { 50068e0d42fSEd L. Cashin struct aoe_hdr *h; 50168e0d42fSEd L. Cashin struct aoe_atahdr *ah; 50268e0d42fSEd L. Cashin 50368e0d42fSEd L. Cashin h = (struct aoe_hdr *) packet; 50468e0d42fSEd L. Cashin ah = (struct aoe_atahdr *) (h+1); 50568e0d42fSEd L. Cashin return ah->scnt; 50668e0d42fSEd L. Cashin } 50768e0d42fSEd L. Cashin 5081da177e4SLinus Torvalds static void 5091da177e4SLinus Torvalds rexmit_timer(ulong vp) 5101da177e4SLinus Torvalds { 5111da177e4SLinus Torvalds struct aoedev *d; 51268e0d42fSEd L. Cashin struct aoetgt *t, **tt, **te; 51368e0d42fSEd L. Cashin struct aoeif *ifp; 5141da177e4SLinus Torvalds struct frame *f, *e; 5151da177e4SLinus Torvalds struct sk_buff *sl; 5161da177e4SLinus Torvalds register long timeout; 5171da177e4SLinus Torvalds ulong flags, n; 5181da177e4SLinus Torvalds 5191da177e4SLinus Torvalds d = (struct aoedev *) vp; 5201da177e4SLinus Torvalds sl = NULL; 5211da177e4SLinus Torvalds 5221da177e4SLinus Torvalds /* timeout is always ~150% of the moving average */ 5231da177e4SLinus Torvalds timeout = d->rttavg; 5241da177e4SLinus Torvalds timeout += timeout >> 1; 5251da177e4SLinus Torvalds 5261da177e4SLinus Torvalds spin_lock_irqsave(&d->lock, flags); 5271da177e4SLinus Torvalds 5281da177e4SLinus Torvalds if (d->flags & DEVFL_TKILL) { 5291c6f3fcaSEd L. Cashin spin_unlock_irqrestore(&d->lock, flags); 5301da177e4SLinus Torvalds return; 5311da177e4SLinus Torvalds } 53268e0d42fSEd L. Cashin tt = d->targets; 53368e0d42fSEd L. Cashin te = tt + NTARGETS; 53468e0d42fSEd L. Cashin for (; tt < te && *tt; tt++) { 53568e0d42fSEd L. Cashin t = *tt; 53668e0d42fSEd L. Cashin f = t->frames; 53768e0d42fSEd L. Cashin e = f + t->nframes; 5381da177e4SLinus Torvalds for (; f < e; f++) { 53968e0d42fSEd L. Cashin if (f->tag == FREETAG 54068e0d42fSEd L. Cashin || tsince(f->tag) < timeout) 54168e0d42fSEd L. Cashin continue; 5421da177e4SLinus Torvalds n = f->waited += timeout; 5431da177e4SLinus Torvalds n /= HZ; 54468e0d42fSEd L. Cashin if (n > aoe_deadsecs) { 54568e0d42fSEd L. Cashin /* waited too long. device failure. */ 5461da177e4SLinus Torvalds aoedev_downdev(d); 5471c6f3fcaSEd L. Cashin break; 5481da177e4SLinus Torvalds } 54968e0d42fSEd L. Cashin 55068e0d42fSEd L. Cashin if (n > HELPWAIT /* see if another target can help */ 55168e0d42fSEd L. Cashin && (tt != d->targets || d->targets[1])) 55268e0d42fSEd L. Cashin d->htgt = tt; 55368e0d42fSEd L. Cashin 55468e0d42fSEd L. Cashin if (t->nout == t->maxout) { 55568e0d42fSEd L. Cashin if (t->maxout > 1) 55668e0d42fSEd L. Cashin t->maxout--; 55768e0d42fSEd L. Cashin t->lastwadj = jiffies; 55868e0d42fSEd L. Cashin } 55968e0d42fSEd L. Cashin 56068e0d42fSEd L. Cashin ifp = getif(t, f->skb->dev); 56168e0d42fSEd L. Cashin if (ifp && ++ifp->lost > (t->nframes << 1) 56268e0d42fSEd L. Cashin && (ifp != t->ifs || t->ifs[1].nd)) { 56368e0d42fSEd L. Cashin ejectif(t, ifp); 56468e0d42fSEd L. Cashin ifp = NULL; 56568e0d42fSEd L. Cashin } 56668e0d42fSEd L. Cashin 56768e0d42fSEd L. Cashin if (ata_scnt(skb_mac_header(f->skb)) > DEFAULTBCNT / 512 56868e0d42fSEd L. Cashin && ifp && ++ifp->lostjumbo > (t->nframes << 1) 56968e0d42fSEd L. Cashin && ifp->maxbcnt != DEFAULTBCNT) { 57068e0d42fSEd L. Cashin printk(KERN_INFO 57168e0d42fSEd L. Cashin "aoe: e%ld.%d: " 57268e0d42fSEd L. Cashin "too many lost jumbo on " 57368e0d42fSEd L. Cashin "%s:%012llx - " 57468e0d42fSEd L. Cashin "falling back to %d frames.\n", 57568e0d42fSEd L. Cashin d->aoemajor, d->aoeminor, 57668e0d42fSEd L. Cashin ifp->nd->name, mac_addr(t->addr), 57768e0d42fSEd L. Cashin DEFAULTBCNT); 57868e0d42fSEd L. Cashin ifp->maxbcnt = 0; 57968e0d42fSEd L. Cashin } 58068e0d42fSEd L. Cashin resend(d, t, f); 58168e0d42fSEd L. Cashin } 58268e0d42fSEd L. Cashin 58368e0d42fSEd L. Cashin /* window check */ 58468e0d42fSEd L. Cashin if (t->nout == t->maxout 58568e0d42fSEd L. Cashin && t->maxout < t->nframes 58668e0d42fSEd L. Cashin && (jiffies - t->lastwadj)/HZ > 10) { 58768e0d42fSEd L. Cashin t->maxout++; 58868e0d42fSEd L. Cashin t->lastwadj = jiffies; 5891da177e4SLinus Torvalds } 5901da177e4SLinus Torvalds } 59168e0d42fSEd L. Cashin 59268e0d42fSEd L. Cashin if (d->sendq_hd) { 59368e0d42fSEd L. Cashin n = d->rttavg <<= 1; 59468e0d42fSEd L. Cashin if (n > MAXTIMER) 59568e0d42fSEd L. Cashin d->rttavg = MAXTIMER; 59668e0d42fSEd L. Cashin } 59768e0d42fSEd L. Cashin 59868e0d42fSEd L. Cashin if (d->flags & DEVFL_KICKME || d->htgt) { 5994f51dc5eSEd L. Cashin d->flags &= ~DEVFL_KICKME; 6004f51dc5eSEd L. Cashin aoecmd_work(d); 6014f51dc5eSEd L. Cashin } 6021da177e4SLinus Torvalds 603a4b38364Secashin@coraid.com sl = d->sendq_hd; 604a4b38364Secashin@coraid.com d->sendq_hd = d->sendq_tl = NULL; 6051da177e4SLinus Torvalds 6061da177e4SLinus Torvalds d->timer.expires = jiffies + TIMERTICK; 6071da177e4SLinus Torvalds add_timer(&d->timer); 6081da177e4SLinus Torvalds 6091da177e4SLinus Torvalds spin_unlock_irqrestore(&d->lock, flags); 6101da177e4SLinus Torvalds 6111da177e4SLinus Torvalds aoenet_xmit(sl); 6121da177e4SLinus Torvalds } 6131da177e4SLinus Torvalds 61468e0d42fSEd L. Cashin /* enters with d->lock held */ 61568e0d42fSEd L. Cashin void 61668e0d42fSEd L. Cashin aoecmd_work(struct aoedev *d) 61768e0d42fSEd L. Cashin { 61868e0d42fSEd L. Cashin struct buf *buf; 61968e0d42fSEd L. Cashin loop: 62068e0d42fSEd L. Cashin if (d->htgt && !sthtith(d)) 62168e0d42fSEd L. Cashin return; 62268e0d42fSEd L. Cashin if (d->inprocess == NULL) { 62368e0d42fSEd L. Cashin if (list_empty(&d->bufq)) 62468e0d42fSEd L. Cashin return; 62568e0d42fSEd L. Cashin buf = container_of(d->bufq.next, struct buf, bufs); 62668e0d42fSEd L. Cashin list_del(d->bufq.next); 62768e0d42fSEd L. Cashin d->inprocess = buf; 62868e0d42fSEd L. Cashin } 62968e0d42fSEd L. Cashin if (aoecmd_ata_rw(d)) 63068e0d42fSEd L. Cashin goto loop; 63168e0d42fSEd L. Cashin } 63268e0d42fSEd L. Cashin 6333ae1c24eSEd L. Cashin /* this function performs work that has been deferred until sleeping is OK 6343ae1c24eSEd L. Cashin */ 6353ae1c24eSEd L. Cashin void 636c4028958SDavid Howells aoecmd_sleepwork(struct work_struct *work) 6373ae1c24eSEd L. Cashin { 638c4028958SDavid Howells struct aoedev *d = container_of(work, struct aoedev, work); 6393ae1c24eSEd L. Cashin 6403ae1c24eSEd L. Cashin if (d->flags & DEVFL_GDALLOC) 6413ae1c24eSEd L. Cashin aoeblk_gdalloc(d); 6423ae1c24eSEd L. Cashin 6433ae1c24eSEd L. Cashin if (d->flags & DEVFL_NEWSIZE) { 6443ae1c24eSEd L. Cashin struct block_device *bd; 6453ae1c24eSEd L. Cashin unsigned long flags; 6463ae1c24eSEd L. Cashin u64 ssize; 6473ae1c24eSEd L. Cashin 64880795aefSTejun Heo ssize = get_capacity(d->gd); 6493ae1c24eSEd L. Cashin bd = bdget_disk(d->gd, 0); 6503ae1c24eSEd L. Cashin 6513ae1c24eSEd L. Cashin if (bd) { 6523ae1c24eSEd L. Cashin mutex_lock(&bd->bd_inode->i_mutex); 6533ae1c24eSEd L. Cashin i_size_write(bd->bd_inode, (loff_t)ssize<<9); 6543ae1c24eSEd L. Cashin mutex_unlock(&bd->bd_inode->i_mutex); 6553ae1c24eSEd L. Cashin bdput(bd); 6563ae1c24eSEd L. Cashin } 6573ae1c24eSEd L. Cashin spin_lock_irqsave(&d->lock, flags); 6583ae1c24eSEd L. Cashin d->flags |= DEVFL_UP; 6593ae1c24eSEd L. Cashin d->flags &= ~DEVFL_NEWSIZE; 6603ae1c24eSEd L. Cashin spin_unlock_irqrestore(&d->lock, flags); 6613ae1c24eSEd L. Cashin } 6623ae1c24eSEd L. Cashin } 6633ae1c24eSEd L. Cashin 6641da177e4SLinus Torvalds static void 66568e0d42fSEd L. Cashin ataid_complete(struct aoedev *d, struct aoetgt *t, unsigned char *id) 6661da177e4SLinus Torvalds { 6671da177e4SLinus Torvalds u64 ssize; 6681da177e4SLinus Torvalds u16 n; 6691da177e4SLinus Torvalds 6701da177e4SLinus Torvalds /* word 83: command set supported */ 671f885f8d1SHarvey Harrison n = get_unaligned_le16(&id[83 << 1]); 6721da177e4SLinus Torvalds 6731da177e4SLinus Torvalds /* word 86: command set/feature enabled */ 674f885f8d1SHarvey Harrison n |= get_unaligned_le16(&id[86 << 1]); 6751da177e4SLinus Torvalds 6761da177e4SLinus Torvalds if (n & (1<<10)) { /* bit 10: LBA 48 */ 6771da177e4SLinus Torvalds d->flags |= DEVFL_EXT; 6781da177e4SLinus Torvalds 6791da177e4SLinus Torvalds /* word 100: number lba48 sectors */ 680f885f8d1SHarvey Harrison ssize = get_unaligned_le64(&id[100 << 1]); 6811da177e4SLinus Torvalds 6821da177e4SLinus Torvalds /* set as in ide-disk.c:init_idedisk_capacity */ 6831da177e4SLinus Torvalds d->geo.cylinders = ssize; 6841da177e4SLinus Torvalds d->geo.cylinders /= (255 * 63); 6851da177e4SLinus Torvalds d->geo.heads = 255; 6861da177e4SLinus Torvalds d->geo.sectors = 63; 6871da177e4SLinus Torvalds } else { 6881da177e4SLinus Torvalds d->flags &= ~DEVFL_EXT; 6891da177e4SLinus Torvalds 6901da177e4SLinus Torvalds /* number lba28 sectors */ 691f885f8d1SHarvey Harrison ssize = get_unaligned_le32(&id[60 << 1]); 6921da177e4SLinus Torvalds 6931da177e4SLinus Torvalds /* NOTE: obsolete in ATA 6 */ 694f885f8d1SHarvey Harrison d->geo.cylinders = get_unaligned_le16(&id[54 << 1]); 695f885f8d1SHarvey Harrison d->geo.heads = get_unaligned_le16(&id[55 << 1]); 696f885f8d1SHarvey Harrison d->geo.sectors = get_unaligned_le16(&id[56 << 1]); 6971da177e4SLinus Torvalds } 6983ae1c24eSEd L. Cashin 6993ae1c24eSEd L. Cashin if (d->ssize != ssize) 7001d75981aSEd L. Cashin printk(KERN_INFO 7011d75981aSEd L. Cashin "aoe: %012llx e%ld.%d v%04x has %llu sectors\n", 7021eb0da4cSEd L. Cashin mac_addr(t->addr), 7033ae1c24eSEd L. Cashin d->aoemajor, d->aoeminor, 7043ae1c24eSEd L. Cashin d->fw_ver, (long long)ssize); 7051da177e4SLinus Torvalds d->ssize = ssize; 7061da177e4SLinus Torvalds d->geo.start = 0; 7076b9699bbSEd L. Cashin if (d->flags & (DEVFL_GDALLOC|DEVFL_NEWSIZE)) 7086b9699bbSEd L. Cashin return; 7091da177e4SLinus Torvalds if (d->gd != NULL) { 71080795aefSTejun Heo set_capacity(d->gd, ssize); 7113ae1c24eSEd L. Cashin d->flags |= DEVFL_NEWSIZE; 71268e0d42fSEd L. Cashin } else 7133ae1c24eSEd L. Cashin d->flags |= DEVFL_GDALLOC; 7141da177e4SLinus Torvalds schedule_work(&d->work); 7151da177e4SLinus Torvalds } 7161da177e4SLinus Torvalds 7171da177e4SLinus Torvalds static void 7181da177e4SLinus Torvalds calc_rttavg(struct aoedev *d, int rtt) 7191da177e4SLinus Torvalds { 7201da177e4SLinus Torvalds register long n; 7211da177e4SLinus Torvalds 7221da177e4SLinus Torvalds n = rtt; 723dced3a05SEd L. Cashin if (n < 0) { 724dced3a05SEd L. Cashin n = -rtt; 7251da177e4SLinus Torvalds if (n < MINTIMER) 7261da177e4SLinus Torvalds n = MINTIMER; 7271da177e4SLinus Torvalds else if (n > MAXTIMER) 7281da177e4SLinus Torvalds n = MAXTIMER; 729dced3a05SEd L. Cashin d->mintimer += (n - d->mintimer) >> 1; 730dced3a05SEd L. Cashin } else if (n < d->mintimer) 731dced3a05SEd L. Cashin n = d->mintimer; 732dced3a05SEd L. Cashin else if (n > MAXTIMER) 733dced3a05SEd L. Cashin n = MAXTIMER; 7341da177e4SLinus Torvalds 7351da177e4SLinus Torvalds /* g == .25; cf. Congestion Avoidance and Control, Jacobson & Karels; 1988 */ 7361da177e4SLinus Torvalds n -= d->rttavg; 7371da177e4SLinus Torvalds d->rttavg += n >> 2; 7381da177e4SLinus Torvalds } 7391da177e4SLinus Torvalds 74068e0d42fSEd L. Cashin static struct aoetgt * 74168e0d42fSEd L. Cashin gettgt(struct aoedev *d, char *addr) 74268e0d42fSEd L. Cashin { 74368e0d42fSEd L. Cashin struct aoetgt **t, **e; 74468e0d42fSEd L. Cashin 74568e0d42fSEd L. Cashin t = d->targets; 74668e0d42fSEd L. Cashin e = t + NTARGETS; 74768e0d42fSEd L. Cashin for (; t < e && *t; t++) 74868e0d42fSEd L. Cashin if (memcmp((*t)->addr, addr, sizeof((*t)->addr)) == 0) 74968e0d42fSEd L. Cashin return *t; 75068e0d42fSEd L. Cashin return NULL; 75168e0d42fSEd L. Cashin } 75268e0d42fSEd L. Cashin 75368e0d42fSEd L. Cashin static inline void 75403054de1SLinus Torvalds diskstats(struct gendisk *disk, struct bio *bio, ulong duration, sector_t sector) 75568e0d42fSEd L. Cashin { 75668e0d42fSEd L. Cashin unsigned long n_sect = bio->bi_size >> 9; 75768e0d42fSEd L. Cashin const int rw = bio_data_dir(bio); 75828f13702SJens Axboe struct hd_struct *part; 759c9959059STejun Heo int cpu; 76068e0d42fSEd L. Cashin 761*074a7acaSTejun Heo cpu = part_stat_lock(); 762e71bf0d0STejun Heo part = disk_map_sector_rcu(disk, sector); 763e71bf0d0STejun Heo 764*074a7acaSTejun Heo part_stat_inc(cpu, part, ios[rw]); 765*074a7acaSTejun Heo part_stat_add(cpu, part, ticks[rw], duration); 766*074a7acaSTejun Heo part_stat_add(cpu, part, sectors[rw], n_sect); 767*074a7acaSTejun Heo part_stat_add(cpu, part, io_ticks, duration); 768c9959059STejun Heo 769*074a7acaSTejun Heo part_stat_unlock(); 77068e0d42fSEd L. Cashin } 77168e0d42fSEd L. Cashin 7721da177e4SLinus Torvalds void 7731da177e4SLinus Torvalds aoecmd_ata_rsp(struct sk_buff *skb) 7741da177e4SLinus Torvalds { 7751da177e4SLinus Torvalds struct aoedev *d; 776ddec63e8SEd L. Cashin struct aoe_hdr *hin, *hout; 7771da177e4SLinus Torvalds struct aoe_atahdr *ahin, *ahout; 7781da177e4SLinus Torvalds struct frame *f; 7791da177e4SLinus Torvalds struct buf *buf; 7801da177e4SLinus Torvalds struct sk_buff *sl; 78168e0d42fSEd L. Cashin struct aoetgt *t; 78268e0d42fSEd L. Cashin struct aoeif *ifp; 7831da177e4SLinus Torvalds register long n; 7841da177e4SLinus Torvalds ulong flags; 7851da177e4SLinus Torvalds char ebuf[128]; 78632465c65Secashin@coraid.com u16 aoemajor; 7871da177e4SLinus Torvalds 788abdbf94dSEd L. Cashin hin = (struct aoe_hdr *) skb_mac_header(skb); 789f885f8d1SHarvey Harrison aoemajor = get_unaligned_be16(&hin->major); 79032465c65Secashin@coraid.com d = aoedev_by_aoeaddr(aoemajor, hin->minor); 7911da177e4SLinus Torvalds if (d == NULL) { 7921da177e4SLinus Torvalds snprintf(ebuf, sizeof ebuf, "aoecmd_ata_rsp: ata response " 7931da177e4SLinus Torvalds "for unknown device %d.%d\n", 79432465c65Secashin@coraid.com aoemajor, hin->minor); 7951da177e4SLinus Torvalds aoechr_error(ebuf); 7961da177e4SLinus Torvalds return; 7971da177e4SLinus Torvalds } 7981da177e4SLinus Torvalds 7991da177e4SLinus Torvalds spin_lock_irqsave(&d->lock, flags); 8001da177e4SLinus Torvalds 801f885f8d1SHarvey Harrison n = get_unaligned_be32(&hin->tag); 80268e0d42fSEd L. Cashin t = gettgt(d, hin->src); 80368e0d42fSEd L. Cashin if (t == NULL) { 80468e0d42fSEd L. Cashin printk(KERN_INFO "aoe: can't find target e%ld.%d:%012llx\n", 8051eb0da4cSEd L. Cashin d->aoemajor, d->aoeminor, mac_addr(hin->src)); 80668e0d42fSEd L. Cashin spin_unlock_irqrestore(&d->lock, flags); 80768e0d42fSEd L. Cashin return; 80868e0d42fSEd L. Cashin } 80968e0d42fSEd L. Cashin f = getframe(t, n); 8101da177e4SLinus Torvalds if (f == NULL) { 811dced3a05SEd L. Cashin calc_rttavg(d, -tsince(n)); 8121da177e4SLinus Torvalds spin_unlock_irqrestore(&d->lock, flags); 8131da177e4SLinus Torvalds snprintf(ebuf, sizeof ebuf, 8141da177e4SLinus Torvalds "%15s e%d.%d tag=%08x@%08lx\n", 8151da177e4SLinus Torvalds "unexpected rsp", 816f885f8d1SHarvey Harrison get_unaligned_be16(&hin->major), 8171da177e4SLinus Torvalds hin->minor, 818f885f8d1SHarvey Harrison get_unaligned_be32(&hin->tag), 8191da177e4SLinus Torvalds jiffies); 8201da177e4SLinus Torvalds aoechr_error(ebuf); 8211da177e4SLinus Torvalds return; 8221da177e4SLinus Torvalds } 8231da177e4SLinus Torvalds 8241da177e4SLinus Torvalds calc_rttavg(d, tsince(f->tag)); 8251da177e4SLinus Torvalds 8261da177e4SLinus Torvalds ahin = (struct aoe_atahdr *) (hin+1); 827abdbf94dSEd L. Cashin hout = (struct aoe_hdr *) skb_mac_header(f->skb); 828ddec63e8SEd L. Cashin ahout = (struct aoe_atahdr *) (hout+1); 8291da177e4SLinus Torvalds buf = f->buf; 8301da177e4SLinus Torvalds 8311da177e4SLinus Torvalds if (ahin->cmdstat & 0xa9) { /* these bits cleared on success */ 832a12c93f0SEd L. Cashin printk(KERN_ERR 8331d75981aSEd L. Cashin "aoe: ata error cmd=%2.2Xh stat=%2.2Xh from e%ld.%d\n", 8341da177e4SLinus Torvalds ahout->cmdstat, ahin->cmdstat, 8351da177e4SLinus Torvalds d->aoemajor, d->aoeminor); 8361da177e4SLinus Torvalds if (buf) 8371da177e4SLinus Torvalds buf->flags |= BUFFL_FAIL; 8381da177e4SLinus Torvalds } else { 83968e0d42fSEd L. Cashin if (d->htgt && t == *d->htgt) /* I'll help myself, thank you. */ 84068e0d42fSEd L. Cashin d->htgt = NULL; 84119bf2635SEd L. Cashin n = ahout->scnt << 9; 8421da177e4SLinus Torvalds switch (ahout->cmdstat) { 8431da177e4SLinus Torvalds case WIN_READ: 8441da177e4SLinus Torvalds case WIN_READ_EXT: 8451da177e4SLinus Torvalds if (skb->len - sizeof *hin - sizeof *ahin < n) { 846a12c93f0SEd L. Cashin printk(KERN_ERR 84768e0d42fSEd L. Cashin "aoe: %s. skb->len=%d need=%ld\n", 84868e0d42fSEd L. Cashin "runt data size in read", skb->len, n); 8491da177e4SLinus Torvalds /* fail frame f? just returning will rexmit. */ 8501da177e4SLinus Torvalds spin_unlock_irqrestore(&d->lock, flags); 8511da177e4SLinus Torvalds return; 8521da177e4SLinus Torvalds } 8531da177e4SLinus Torvalds memcpy(f->bufaddr, ahin+1, n); 8541da177e4SLinus Torvalds case WIN_WRITE: 8551da177e4SLinus Torvalds case WIN_WRITE_EXT: 85668e0d42fSEd L. Cashin ifp = getif(t, skb->dev); 85768e0d42fSEd L. Cashin if (ifp) { 85868e0d42fSEd L. Cashin ifp->lost = 0; 85968e0d42fSEd L. Cashin if (n > DEFAULTBCNT) 86068e0d42fSEd L. Cashin ifp->lostjumbo = 0; 86168e0d42fSEd L. Cashin } 86219bf2635SEd L. Cashin if (f->bcnt -= n) { 86368e0d42fSEd L. Cashin f->lba += n >> 9; 86419bf2635SEd L. Cashin f->bufaddr += n; 86568e0d42fSEd L. Cashin resend(d, t, f); 86668e0d42fSEd L. Cashin goto xmit; 8674f51dc5eSEd L. Cashin } 8681da177e4SLinus Torvalds break; 8691da177e4SLinus Torvalds case WIN_IDENTIFY: 8701da177e4SLinus Torvalds if (skb->len - sizeof *hin - sizeof *ahin < 512) { 871a12c93f0SEd L. Cashin printk(KERN_INFO 872a12c93f0SEd L. Cashin "aoe: runt data size in ataid. skb->len=%d\n", 8736bb6285fSEd L. Cashin skb->len); 8741da177e4SLinus Torvalds spin_unlock_irqrestore(&d->lock, flags); 8751da177e4SLinus Torvalds return; 8761da177e4SLinus Torvalds } 87768e0d42fSEd L. Cashin ataid_complete(d, t, (char *) (ahin+1)); 8781da177e4SLinus Torvalds break; 8791da177e4SLinus Torvalds default: 880a12c93f0SEd L. Cashin printk(KERN_INFO 881a12c93f0SEd L. Cashin "aoe: unrecognized ata command %2.2Xh for %d.%d\n", 8821da177e4SLinus Torvalds ahout->cmdstat, 883f885f8d1SHarvey Harrison get_unaligned_be16(&hin->major), 8841da177e4SLinus Torvalds hin->minor); 8851da177e4SLinus Torvalds } 8861da177e4SLinus Torvalds } 8871da177e4SLinus Torvalds 88868e0d42fSEd L. Cashin if (buf && --buf->nframesout == 0 && buf->resid == 0) { 88903054de1SLinus Torvalds diskstats(d->gd, buf->bio, jiffies - buf->stime, buf->sector); 8901da177e4SLinus Torvalds n = (buf->flags & BUFFL_FAIL) ? -EIO : 0; 8916712ecf8SNeilBrown bio_endio(buf->bio, n); 8921da177e4SLinus Torvalds mempool_free(buf, d->bufpool); 8931da177e4SLinus Torvalds } 8941da177e4SLinus Torvalds 8951da177e4SLinus Torvalds f->buf = NULL; 8961da177e4SLinus Torvalds f->tag = FREETAG; 89768e0d42fSEd L. Cashin t->nout--; 8981da177e4SLinus Torvalds 8991da177e4SLinus Torvalds aoecmd_work(d); 90068e0d42fSEd L. Cashin xmit: 901a4b38364Secashin@coraid.com sl = d->sendq_hd; 902a4b38364Secashin@coraid.com d->sendq_hd = d->sendq_tl = NULL; 9031da177e4SLinus Torvalds 9041da177e4SLinus Torvalds spin_unlock_irqrestore(&d->lock, flags); 9051da177e4SLinus Torvalds aoenet_xmit(sl); 9061da177e4SLinus Torvalds } 9071da177e4SLinus Torvalds 9081da177e4SLinus Torvalds void 9091da177e4SLinus Torvalds aoecmd_cfg(ushort aoemajor, unsigned char aoeminor) 9101da177e4SLinus Torvalds { 9113ae1c24eSEd L. Cashin struct sk_buff *sl; 9121da177e4SLinus Torvalds 9133ae1c24eSEd L. Cashin sl = aoecmd_cfg_pkts(aoemajor, aoeminor, NULL); 9141da177e4SLinus Torvalds 9151da177e4SLinus Torvalds aoenet_xmit(sl); 9161da177e4SLinus Torvalds } 9171da177e4SLinus Torvalds 91868e0d42fSEd L. Cashin struct sk_buff * 9191da177e4SLinus Torvalds aoecmd_ata_id(struct aoedev *d) 9201da177e4SLinus Torvalds { 9211da177e4SLinus Torvalds struct aoe_hdr *h; 9221da177e4SLinus Torvalds struct aoe_atahdr *ah; 9231da177e4SLinus Torvalds struct frame *f; 9241da177e4SLinus Torvalds struct sk_buff *skb; 92568e0d42fSEd L. Cashin struct aoetgt *t; 9261da177e4SLinus Torvalds 9274f51dc5eSEd L. Cashin f = freeframe(d); 92868e0d42fSEd L. Cashin if (f == NULL) 9291da177e4SLinus Torvalds return NULL; 93068e0d42fSEd L. Cashin 93168e0d42fSEd L. Cashin t = *d->tgt; 9321da177e4SLinus Torvalds 9331da177e4SLinus Torvalds /* initialize the headers & frame */ 934e407a7f6SEd L. Cashin skb = f->skb; 935abdbf94dSEd L. Cashin h = (struct aoe_hdr *) skb_mac_header(skb); 9361da177e4SLinus Torvalds ah = (struct aoe_atahdr *) (h+1); 93719900cdeSEd L. Cashin skb_put(skb, sizeof *h + sizeof *ah); 93819900cdeSEd L. Cashin memset(h, 0, skb->len); 93968e0d42fSEd L. Cashin f->tag = aoehdr_atainit(d, t, h); 94068e0d42fSEd L. Cashin t->nout++; 9411da177e4SLinus Torvalds f->waited = 0; 9421da177e4SLinus Torvalds 9431da177e4SLinus Torvalds /* set up ata header */ 9441da177e4SLinus Torvalds ah->scnt = 1; 9451da177e4SLinus Torvalds ah->cmdstat = WIN_IDENTIFY; 9461da177e4SLinus Torvalds ah->lba3 = 0xa0; 9471da177e4SLinus Torvalds 94868e0d42fSEd L. Cashin skb->dev = t->ifp->nd; 9491da177e4SLinus Torvalds 9503ae1c24eSEd L. Cashin d->rttavg = MAXTIMER; 9511da177e4SLinus Torvalds d->timer.function = rexmit_timer; 9521da177e4SLinus Torvalds 9534f51dc5eSEd L. Cashin return skb_clone(skb, GFP_ATOMIC); 9541da177e4SLinus Torvalds } 9551da177e4SLinus Torvalds 95668e0d42fSEd L. Cashin static struct aoetgt * 95768e0d42fSEd L. Cashin addtgt(struct aoedev *d, char *addr, ulong nframes) 95868e0d42fSEd L. Cashin { 95968e0d42fSEd L. Cashin struct aoetgt *t, **tt, **te; 96068e0d42fSEd L. Cashin struct frame *f, *e; 96168e0d42fSEd L. Cashin 96268e0d42fSEd L. Cashin tt = d->targets; 96368e0d42fSEd L. Cashin te = tt + NTARGETS; 96468e0d42fSEd L. Cashin for (; tt < te && *tt; tt++) 96568e0d42fSEd L. Cashin ; 96668e0d42fSEd L. Cashin 967578c4aa0SEd L. Cashin if (tt == te) { 968578c4aa0SEd L. Cashin printk(KERN_INFO 969578c4aa0SEd L. Cashin "aoe: device addtgt failure; too many targets\n"); 97068e0d42fSEd L. Cashin return NULL; 971578c4aa0SEd L. Cashin } 97268e0d42fSEd L. Cashin t = kcalloc(1, sizeof *t, GFP_ATOMIC); 97368e0d42fSEd L. Cashin f = kcalloc(nframes, sizeof *f, GFP_ATOMIC); 974578c4aa0SEd L. Cashin if (!t || !f) { 975578c4aa0SEd L. Cashin kfree(f); 9769bb237b6SEd L. Cashin kfree(t); 977578c4aa0SEd L. Cashin printk(KERN_INFO "aoe: cannot allocate memory to add target\n"); 9789bb237b6SEd L. Cashin return NULL; 9799bb237b6SEd L. Cashin } 9809bb237b6SEd L. Cashin 98168e0d42fSEd L. Cashin t->nframes = nframes; 98268e0d42fSEd L. Cashin t->frames = f; 98368e0d42fSEd L. Cashin e = f + nframes; 9849bb237b6SEd L. Cashin for (; f < e; f++) 98568e0d42fSEd L. Cashin f->tag = FREETAG; 98668e0d42fSEd L. Cashin memcpy(t->addr, addr, sizeof t->addr); 98768e0d42fSEd L. Cashin t->ifp = t->ifs; 98868e0d42fSEd L. Cashin t->maxout = t->nframes; 98968e0d42fSEd L. Cashin return *tt = t; 99068e0d42fSEd L. Cashin } 99168e0d42fSEd L. Cashin 9921da177e4SLinus Torvalds void 9931da177e4SLinus Torvalds aoecmd_cfg_rsp(struct sk_buff *skb) 9941da177e4SLinus Torvalds { 9951da177e4SLinus Torvalds struct aoedev *d; 9961da177e4SLinus Torvalds struct aoe_hdr *h; 9971da177e4SLinus Torvalds struct aoe_cfghdr *ch; 99868e0d42fSEd L. Cashin struct aoetgt *t; 99968e0d42fSEd L. Cashin struct aoeif *ifp; 100063e9cc5dSecashin@coraid.com ulong flags, sysminor, aoemajor; 10011da177e4SLinus Torvalds struct sk_buff *sl; 100219bf2635SEd L. Cashin u16 n; 10031da177e4SLinus Torvalds 1004abdbf94dSEd L. Cashin h = (struct aoe_hdr *) skb_mac_header(skb); 10051da177e4SLinus Torvalds ch = (struct aoe_cfghdr *) (h+1); 10061da177e4SLinus Torvalds 10071da177e4SLinus Torvalds /* 10081da177e4SLinus Torvalds * Enough people have their dip switches set backwards to 10091da177e4SLinus Torvalds * warrant a loud message for this special case. 10101da177e4SLinus Torvalds */ 1011823ed72eSHarvey Harrison aoemajor = get_unaligned_be16(&h->major); 10121da177e4SLinus Torvalds if (aoemajor == 0xfff) { 1013a12c93f0SEd L. Cashin printk(KERN_ERR "aoe: Warning: shelf address is all ones. " 10146bb6285fSEd L. Cashin "Check shelf dip switches.\n"); 10151da177e4SLinus Torvalds return; 10161da177e4SLinus Torvalds } 10171da177e4SLinus Torvalds 10181da177e4SLinus Torvalds sysminor = SYSMINOR(aoemajor, h->minor); 1019fc458dcdSecashin@coraid.com if (sysminor * AOE_PARTITIONS + AOE_PARTITIONS > MINORMASK) { 1020a12c93f0SEd L. Cashin printk(KERN_INFO "aoe: e%ld.%d: minor number too large\n", 1021fc458dcdSecashin@coraid.com aoemajor, (int) h->minor); 10221da177e4SLinus Torvalds return; 10231da177e4SLinus Torvalds } 10241da177e4SLinus Torvalds 102519bf2635SEd L. Cashin n = be16_to_cpu(ch->bufcnt); 10267df620d8SEd L. Cashin if (n > aoe_maxout) /* keep it reasonable */ 10277df620d8SEd L. Cashin n = aoe_maxout; 10281da177e4SLinus Torvalds 102968e0d42fSEd L. Cashin d = aoedev_by_sysminor_m(sysminor); 10301da177e4SLinus Torvalds if (d == NULL) { 1031a12c93f0SEd L. Cashin printk(KERN_INFO "aoe: device sysminor_m failure\n"); 10321da177e4SLinus Torvalds return; 10331da177e4SLinus Torvalds } 10341da177e4SLinus Torvalds 10351da177e4SLinus Torvalds spin_lock_irqsave(&d->lock, flags); 10361da177e4SLinus Torvalds 103768e0d42fSEd L. Cashin t = gettgt(d, h->src); 103868e0d42fSEd L. Cashin if (!t) { 103968e0d42fSEd L. Cashin t = addtgt(d, h->src, n); 104068e0d42fSEd L. Cashin if (!t) { 104168e0d42fSEd L. Cashin spin_unlock_irqrestore(&d->lock, flags); 104268e0d42fSEd L. Cashin return; 104368e0d42fSEd L. Cashin } 104468e0d42fSEd L. Cashin } 104568e0d42fSEd L. Cashin ifp = getif(t, skb->dev); 104668e0d42fSEd L. Cashin if (!ifp) { 104768e0d42fSEd L. Cashin ifp = addif(t, skb->dev); 104868e0d42fSEd L. Cashin if (!ifp) { 104968e0d42fSEd L. Cashin printk(KERN_INFO 105068e0d42fSEd L. Cashin "aoe: device addif failure; " 105168e0d42fSEd L. Cashin "too many interfaces?\n"); 105268e0d42fSEd L. Cashin spin_unlock_irqrestore(&d->lock, flags); 105368e0d42fSEd L. Cashin return; 105468e0d42fSEd L. Cashin } 105568e0d42fSEd L. Cashin } 105668e0d42fSEd L. Cashin if (ifp->maxbcnt) { 105768e0d42fSEd L. Cashin n = ifp->nd->mtu; 105819bf2635SEd L. Cashin n -= sizeof (struct aoe_hdr) + sizeof (struct aoe_atahdr); 105919bf2635SEd L. Cashin n /= 512; 106019bf2635SEd L. Cashin if (n > ch->scnt) 106119bf2635SEd L. Cashin n = ch->scnt; 10624f51dc5eSEd L. Cashin n = n ? n * 512 : DEFAULTBCNT; 106368e0d42fSEd L. Cashin if (n != ifp->maxbcnt) { 1064a12c93f0SEd L. Cashin printk(KERN_INFO 106568e0d42fSEd L. Cashin "aoe: e%ld.%d: setting %d%s%s:%012llx\n", 106668e0d42fSEd L. Cashin d->aoemajor, d->aoeminor, n, 106768e0d42fSEd L. Cashin " byte data frames on ", ifp->nd->name, 10681eb0da4cSEd L. Cashin mac_addr(t->addr)); 106968e0d42fSEd L. Cashin ifp->maxbcnt = n; 10704f51dc5eSEd L. Cashin } 107119bf2635SEd L. Cashin } 10723ae1c24eSEd L. Cashin 10733ae1c24eSEd L. Cashin /* don't change users' perspective */ 107468e0d42fSEd L. Cashin if (d->nopen) { 10751da177e4SLinus Torvalds spin_unlock_irqrestore(&d->lock, flags); 10761da177e4SLinus Torvalds return; 10771da177e4SLinus Torvalds } 107863e9cc5dSecashin@coraid.com d->fw_ver = be16_to_cpu(ch->fwver); 10791da177e4SLinus Torvalds 108068e0d42fSEd L. Cashin sl = aoecmd_ata_id(d); 10811da177e4SLinus Torvalds 10821da177e4SLinus Torvalds spin_unlock_irqrestore(&d->lock, flags); 10831da177e4SLinus Torvalds 10841da177e4SLinus Torvalds aoenet_xmit(sl); 10851da177e4SLinus Torvalds } 10861da177e4SLinus Torvalds 108768e0d42fSEd L. Cashin void 108868e0d42fSEd L. Cashin aoecmd_cleanslate(struct aoedev *d) 108968e0d42fSEd L. Cashin { 109068e0d42fSEd L. Cashin struct aoetgt **t, **te; 109168e0d42fSEd L. Cashin struct aoeif *p, *e; 109268e0d42fSEd L. Cashin 109368e0d42fSEd L. Cashin d->mintimer = MINTIMER; 109468e0d42fSEd L. Cashin 109568e0d42fSEd L. Cashin t = d->targets; 109668e0d42fSEd L. Cashin te = t + NTARGETS; 109768e0d42fSEd L. Cashin for (; t < te && *t; t++) { 109868e0d42fSEd L. Cashin (*t)->maxout = (*t)->nframes; 109968e0d42fSEd L. Cashin p = (*t)->ifs; 110068e0d42fSEd L. Cashin e = p + NAOEIFS; 110168e0d42fSEd L. Cashin for (; p < e; p++) { 110268e0d42fSEd L. Cashin p->lostjumbo = 0; 110368e0d42fSEd L. Cashin p->lost = 0; 110468e0d42fSEd L. Cashin p->maxbcnt = DEFAULTBCNT; 110568e0d42fSEd L. Cashin } 110668e0d42fSEd L. Cashin } 110768e0d42fSEd L. Cashin } 1108