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 6483ae1c24eSEd L. Cashin ssize = d->gd->capacity; 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 */ 671*f885f8d1SHarvey Harrison n = get_unaligned_le16(&id[83 << 1]); 6721da177e4SLinus Torvalds 6731da177e4SLinus Torvalds /* word 86: command set/feature enabled */ 674*f885f8d1SHarvey 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 */ 680*f885f8d1SHarvey 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 */ 691*f885f8d1SHarvey Harrison ssize = get_unaligned_le32(&id[60 << 1]); 6921da177e4SLinus Torvalds 6931da177e4SLinus Torvalds /* NOTE: obsolete in ATA 6 */ 694*f885f8d1SHarvey Harrison d->geo.cylinders = get_unaligned_le16(&id[54 << 1]); 695*f885f8d1SHarvey Harrison d->geo.heads = get_unaligned_le16(&id[55 << 1]); 696*f885f8d1SHarvey 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) { 7101da177e4SLinus Torvalds d->gd->capacity = 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); 75868e0d42fSEd L. Cashin 75903054de1SLinus Torvalds all_stat_inc(disk, ios[rw], sector); 76003054de1SLinus Torvalds all_stat_add(disk, ticks[rw], duration, sector); 76103054de1SLinus Torvalds all_stat_add(disk, sectors[rw], n_sect, sector); 76203054de1SLinus Torvalds all_stat_add(disk, io_ticks, duration, sector); 76368e0d42fSEd L. Cashin } 76468e0d42fSEd L. Cashin 7651da177e4SLinus Torvalds void 7661da177e4SLinus Torvalds aoecmd_ata_rsp(struct sk_buff *skb) 7671da177e4SLinus Torvalds { 7681da177e4SLinus Torvalds struct aoedev *d; 769ddec63e8SEd L. Cashin struct aoe_hdr *hin, *hout; 7701da177e4SLinus Torvalds struct aoe_atahdr *ahin, *ahout; 7711da177e4SLinus Torvalds struct frame *f; 7721da177e4SLinus Torvalds struct buf *buf; 7731da177e4SLinus Torvalds struct sk_buff *sl; 77468e0d42fSEd L. Cashin struct aoetgt *t; 77568e0d42fSEd L. Cashin struct aoeif *ifp; 7761da177e4SLinus Torvalds register long n; 7771da177e4SLinus Torvalds ulong flags; 7781da177e4SLinus Torvalds char ebuf[128]; 77932465c65Secashin@coraid.com u16 aoemajor; 7801da177e4SLinus Torvalds 781abdbf94dSEd L. Cashin hin = (struct aoe_hdr *) skb_mac_header(skb); 782*f885f8d1SHarvey Harrison aoemajor = get_unaligned_be16(&hin->major); 78332465c65Secashin@coraid.com d = aoedev_by_aoeaddr(aoemajor, hin->minor); 7841da177e4SLinus Torvalds if (d == NULL) { 7851da177e4SLinus Torvalds snprintf(ebuf, sizeof ebuf, "aoecmd_ata_rsp: ata response " 7861da177e4SLinus Torvalds "for unknown device %d.%d\n", 78732465c65Secashin@coraid.com aoemajor, hin->minor); 7881da177e4SLinus Torvalds aoechr_error(ebuf); 7891da177e4SLinus Torvalds return; 7901da177e4SLinus Torvalds } 7911da177e4SLinus Torvalds 7921da177e4SLinus Torvalds spin_lock_irqsave(&d->lock, flags); 7931da177e4SLinus Torvalds 794*f885f8d1SHarvey Harrison n = get_unaligned_be32(&hin->tag); 79568e0d42fSEd L. Cashin t = gettgt(d, hin->src); 79668e0d42fSEd L. Cashin if (t == NULL) { 79768e0d42fSEd L. Cashin printk(KERN_INFO "aoe: can't find target e%ld.%d:%012llx\n", 7981eb0da4cSEd L. Cashin d->aoemajor, d->aoeminor, mac_addr(hin->src)); 79968e0d42fSEd L. Cashin spin_unlock_irqrestore(&d->lock, flags); 80068e0d42fSEd L. Cashin return; 80168e0d42fSEd L. Cashin } 80268e0d42fSEd L. Cashin f = getframe(t, n); 8031da177e4SLinus Torvalds if (f == NULL) { 804dced3a05SEd L. Cashin calc_rttavg(d, -tsince(n)); 8051da177e4SLinus Torvalds spin_unlock_irqrestore(&d->lock, flags); 8061da177e4SLinus Torvalds snprintf(ebuf, sizeof ebuf, 8071da177e4SLinus Torvalds "%15s e%d.%d tag=%08x@%08lx\n", 8081da177e4SLinus Torvalds "unexpected rsp", 809*f885f8d1SHarvey Harrison get_unaligned_be16(&hin->major), 8101da177e4SLinus Torvalds hin->minor, 811*f885f8d1SHarvey Harrison get_unaligned_be32(&hin->tag), 8121da177e4SLinus Torvalds jiffies); 8131da177e4SLinus Torvalds aoechr_error(ebuf); 8141da177e4SLinus Torvalds return; 8151da177e4SLinus Torvalds } 8161da177e4SLinus Torvalds 8171da177e4SLinus Torvalds calc_rttavg(d, tsince(f->tag)); 8181da177e4SLinus Torvalds 8191da177e4SLinus Torvalds ahin = (struct aoe_atahdr *) (hin+1); 820abdbf94dSEd L. Cashin hout = (struct aoe_hdr *) skb_mac_header(f->skb); 821ddec63e8SEd L. Cashin ahout = (struct aoe_atahdr *) (hout+1); 8221da177e4SLinus Torvalds buf = f->buf; 8231da177e4SLinus Torvalds 8241da177e4SLinus Torvalds if (ahin->cmdstat & 0xa9) { /* these bits cleared on success */ 825a12c93f0SEd L. Cashin printk(KERN_ERR 8261d75981aSEd L. Cashin "aoe: ata error cmd=%2.2Xh stat=%2.2Xh from e%ld.%d\n", 8271da177e4SLinus Torvalds ahout->cmdstat, ahin->cmdstat, 8281da177e4SLinus Torvalds d->aoemajor, d->aoeminor); 8291da177e4SLinus Torvalds if (buf) 8301da177e4SLinus Torvalds buf->flags |= BUFFL_FAIL; 8311da177e4SLinus Torvalds } else { 83268e0d42fSEd L. Cashin if (d->htgt && t == *d->htgt) /* I'll help myself, thank you. */ 83368e0d42fSEd L. Cashin d->htgt = NULL; 83419bf2635SEd L. Cashin n = ahout->scnt << 9; 8351da177e4SLinus Torvalds switch (ahout->cmdstat) { 8361da177e4SLinus Torvalds case WIN_READ: 8371da177e4SLinus Torvalds case WIN_READ_EXT: 8381da177e4SLinus Torvalds if (skb->len - sizeof *hin - sizeof *ahin < n) { 839a12c93f0SEd L. Cashin printk(KERN_ERR 84068e0d42fSEd L. Cashin "aoe: %s. skb->len=%d need=%ld\n", 84168e0d42fSEd L. Cashin "runt data size in read", skb->len, n); 8421da177e4SLinus Torvalds /* fail frame f? just returning will rexmit. */ 8431da177e4SLinus Torvalds spin_unlock_irqrestore(&d->lock, flags); 8441da177e4SLinus Torvalds return; 8451da177e4SLinus Torvalds } 8461da177e4SLinus Torvalds memcpy(f->bufaddr, ahin+1, n); 8471da177e4SLinus Torvalds case WIN_WRITE: 8481da177e4SLinus Torvalds case WIN_WRITE_EXT: 84968e0d42fSEd L. Cashin ifp = getif(t, skb->dev); 85068e0d42fSEd L. Cashin if (ifp) { 85168e0d42fSEd L. Cashin ifp->lost = 0; 85268e0d42fSEd L. Cashin if (n > DEFAULTBCNT) 85368e0d42fSEd L. Cashin ifp->lostjumbo = 0; 85468e0d42fSEd L. Cashin } 85519bf2635SEd L. Cashin if (f->bcnt -= n) { 85668e0d42fSEd L. Cashin f->lba += n >> 9; 85719bf2635SEd L. Cashin f->bufaddr += n; 85868e0d42fSEd L. Cashin resend(d, t, f); 85968e0d42fSEd L. Cashin goto xmit; 8604f51dc5eSEd L. Cashin } 8611da177e4SLinus Torvalds break; 8621da177e4SLinus Torvalds case WIN_IDENTIFY: 8631da177e4SLinus Torvalds if (skb->len - sizeof *hin - sizeof *ahin < 512) { 864a12c93f0SEd L. Cashin printk(KERN_INFO 865a12c93f0SEd L. Cashin "aoe: runt data size in ataid. skb->len=%d\n", 8666bb6285fSEd L. Cashin skb->len); 8671da177e4SLinus Torvalds spin_unlock_irqrestore(&d->lock, flags); 8681da177e4SLinus Torvalds return; 8691da177e4SLinus Torvalds } 87068e0d42fSEd L. Cashin ataid_complete(d, t, (char *) (ahin+1)); 8711da177e4SLinus Torvalds break; 8721da177e4SLinus Torvalds default: 873a12c93f0SEd L. Cashin printk(KERN_INFO 874a12c93f0SEd L. Cashin "aoe: unrecognized ata command %2.2Xh for %d.%d\n", 8751da177e4SLinus Torvalds ahout->cmdstat, 876*f885f8d1SHarvey Harrison get_unaligned_be16(&hin->major), 8771da177e4SLinus Torvalds hin->minor); 8781da177e4SLinus Torvalds } 8791da177e4SLinus Torvalds } 8801da177e4SLinus Torvalds 88168e0d42fSEd L. Cashin if (buf && --buf->nframesout == 0 && buf->resid == 0) { 88203054de1SLinus Torvalds diskstats(d->gd, buf->bio, jiffies - buf->stime, buf->sector); 8831da177e4SLinus Torvalds n = (buf->flags & BUFFL_FAIL) ? -EIO : 0; 8846712ecf8SNeilBrown bio_endio(buf->bio, n); 8851da177e4SLinus Torvalds mempool_free(buf, d->bufpool); 8861da177e4SLinus Torvalds } 8871da177e4SLinus Torvalds 8881da177e4SLinus Torvalds f->buf = NULL; 8891da177e4SLinus Torvalds f->tag = FREETAG; 89068e0d42fSEd L. Cashin t->nout--; 8911da177e4SLinus Torvalds 8921da177e4SLinus Torvalds aoecmd_work(d); 89368e0d42fSEd L. Cashin xmit: 894a4b38364Secashin@coraid.com sl = d->sendq_hd; 895a4b38364Secashin@coraid.com d->sendq_hd = d->sendq_tl = NULL; 8961da177e4SLinus Torvalds 8971da177e4SLinus Torvalds spin_unlock_irqrestore(&d->lock, flags); 8981da177e4SLinus Torvalds aoenet_xmit(sl); 8991da177e4SLinus Torvalds } 9001da177e4SLinus Torvalds 9011da177e4SLinus Torvalds void 9021da177e4SLinus Torvalds aoecmd_cfg(ushort aoemajor, unsigned char aoeminor) 9031da177e4SLinus Torvalds { 9043ae1c24eSEd L. Cashin struct sk_buff *sl; 9051da177e4SLinus Torvalds 9063ae1c24eSEd L. Cashin sl = aoecmd_cfg_pkts(aoemajor, aoeminor, NULL); 9071da177e4SLinus Torvalds 9081da177e4SLinus Torvalds aoenet_xmit(sl); 9091da177e4SLinus Torvalds } 9101da177e4SLinus Torvalds 91168e0d42fSEd L. Cashin struct sk_buff * 9121da177e4SLinus Torvalds aoecmd_ata_id(struct aoedev *d) 9131da177e4SLinus Torvalds { 9141da177e4SLinus Torvalds struct aoe_hdr *h; 9151da177e4SLinus Torvalds struct aoe_atahdr *ah; 9161da177e4SLinus Torvalds struct frame *f; 9171da177e4SLinus Torvalds struct sk_buff *skb; 91868e0d42fSEd L. Cashin struct aoetgt *t; 9191da177e4SLinus Torvalds 9204f51dc5eSEd L. Cashin f = freeframe(d); 92168e0d42fSEd L. Cashin if (f == NULL) 9221da177e4SLinus Torvalds return NULL; 92368e0d42fSEd L. Cashin 92468e0d42fSEd L. Cashin t = *d->tgt; 9251da177e4SLinus Torvalds 9261da177e4SLinus Torvalds /* initialize the headers & frame */ 927e407a7f6SEd L. Cashin skb = f->skb; 928abdbf94dSEd L. Cashin h = (struct aoe_hdr *) skb_mac_header(skb); 9291da177e4SLinus Torvalds ah = (struct aoe_atahdr *) (h+1); 93019900cdeSEd L. Cashin skb_put(skb, sizeof *h + sizeof *ah); 93119900cdeSEd L. Cashin memset(h, 0, skb->len); 93268e0d42fSEd L. Cashin f->tag = aoehdr_atainit(d, t, h); 93368e0d42fSEd L. Cashin t->nout++; 9341da177e4SLinus Torvalds f->waited = 0; 9351da177e4SLinus Torvalds 9361da177e4SLinus Torvalds /* set up ata header */ 9371da177e4SLinus Torvalds ah->scnt = 1; 9381da177e4SLinus Torvalds ah->cmdstat = WIN_IDENTIFY; 9391da177e4SLinus Torvalds ah->lba3 = 0xa0; 9401da177e4SLinus Torvalds 94168e0d42fSEd L. Cashin skb->dev = t->ifp->nd; 9421da177e4SLinus Torvalds 9433ae1c24eSEd L. Cashin d->rttavg = MAXTIMER; 9441da177e4SLinus Torvalds d->timer.function = rexmit_timer; 9451da177e4SLinus Torvalds 9464f51dc5eSEd L. Cashin return skb_clone(skb, GFP_ATOMIC); 9471da177e4SLinus Torvalds } 9481da177e4SLinus Torvalds 94968e0d42fSEd L. Cashin static struct aoetgt * 95068e0d42fSEd L. Cashin addtgt(struct aoedev *d, char *addr, ulong nframes) 95168e0d42fSEd L. Cashin { 95268e0d42fSEd L. Cashin struct aoetgt *t, **tt, **te; 95368e0d42fSEd L. Cashin struct frame *f, *e; 95468e0d42fSEd L. Cashin 95568e0d42fSEd L. Cashin tt = d->targets; 95668e0d42fSEd L. Cashin te = tt + NTARGETS; 95768e0d42fSEd L. Cashin for (; tt < te && *tt; tt++) 95868e0d42fSEd L. Cashin ; 95968e0d42fSEd L. Cashin 960578c4aa0SEd L. Cashin if (tt == te) { 961578c4aa0SEd L. Cashin printk(KERN_INFO 962578c4aa0SEd L. Cashin "aoe: device addtgt failure; too many targets\n"); 96368e0d42fSEd L. Cashin return NULL; 964578c4aa0SEd L. Cashin } 96568e0d42fSEd L. Cashin t = kcalloc(1, sizeof *t, GFP_ATOMIC); 96668e0d42fSEd L. Cashin f = kcalloc(nframes, sizeof *f, GFP_ATOMIC); 967578c4aa0SEd L. Cashin if (!t || !f) { 968578c4aa0SEd L. Cashin kfree(f); 9699bb237b6SEd L. Cashin kfree(t); 970578c4aa0SEd L. Cashin printk(KERN_INFO "aoe: cannot allocate memory to add target\n"); 9719bb237b6SEd L. Cashin return NULL; 9729bb237b6SEd L. Cashin } 9739bb237b6SEd L. Cashin 97468e0d42fSEd L. Cashin t->nframes = nframes; 97568e0d42fSEd L. Cashin t->frames = f; 97668e0d42fSEd L. Cashin e = f + nframes; 9779bb237b6SEd L. Cashin for (; f < e; f++) 97868e0d42fSEd L. Cashin f->tag = FREETAG; 97968e0d42fSEd L. Cashin memcpy(t->addr, addr, sizeof t->addr); 98068e0d42fSEd L. Cashin t->ifp = t->ifs; 98168e0d42fSEd L. Cashin t->maxout = t->nframes; 98268e0d42fSEd L. Cashin return *tt = t; 98368e0d42fSEd L. Cashin } 98468e0d42fSEd L. Cashin 9851da177e4SLinus Torvalds void 9861da177e4SLinus Torvalds aoecmd_cfg_rsp(struct sk_buff *skb) 9871da177e4SLinus Torvalds { 9881da177e4SLinus Torvalds struct aoedev *d; 9891da177e4SLinus Torvalds struct aoe_hdr *h; 9901da177e4SLinus Torvalds struct aoe_cfghdr *ch; 99168e0d42fSEd L. Cashin struct aoetgt *t; 99268e0d42fSEd L. Cashin struct aoeif *ifp; 99363e9cc5dSecashin@coraid.com ulong flags, sysminor, aoemajor; 9941da177e4SLinus Torvalds struct sk_buff *sl; 99519bf2635SEd L. Cashin u16 n; 9961da177e4SLinus Torvalds 997abdbf94dSEd L. Cashin h = (struct aoe_hdr *) skb_mac_header(skb); 9981da177e4SLinus Torvalds ch = (struct aoe_cfghdr *) (h+1); 9991da177e4SLinus Torvalds 10001da177e4SLinus Torvalds /* 10011da177e4SLinus Torvalds * Enough people have their dip switches set backwards to 10021da177e4SLinus Torvalds * warrant a loud message for this special case. 10031da177e4SLinus Torvalds */ 100443ecf529SDavid S. Miller aoemajor = be16_to_cpu(get_unaligned(&h->major)); 10051da177e4SLinus Torvalds if (aoemajor == 0xfff) { 1006a12c93f0SEd L. Cashin printk(KERN_ERR "aoe: Warning: shelf address is all ones. " 10076bb6285fSEd L. Cashin "Check shelf dip switches.\n"); 10081da177e4SLinus Torvalds return; 10091da177e4SLinus Torvalds } 10101da177e4SLinus Torvalds 10111da177e4SLinus Torvalds sysminor = SYSMINOR(aoemajor, h->minor); 1012fc458dcdSecashin@coraid.com if (sysminor * AOE_PARTITIONS + AOE_PARTITIONS > MINORMASK) { 1013a12c93f0SEd L. Cashin printk(KERN_INFO "aoe: e%ld.%d: minor number too large\n", 1014fc458dcdSecashin@coraid.com aoemajor, (int) h->minor); 10151da177e4SLinus Torvalds return; 10161da177e4SLinus Torvalds } 10171da177e4SLinus Torvalds 101819bf2635SEd L. Cashin n = be16_to_cpu(ch->bufcnt); 10197df620d8SEd L. Cashin if (n > aoe_maxout) /* keep it reasonable */ 10207df620d8SEd L. Cashin n = aoe_maxout; 10211da177e4SLinus Torvalds 102268e0d42fSEd L. Cashin d = aoedev_by_sysminor_m(sysminor); 10231da177e4SLinus Torvalds if (d == NULL) { 1024a12c93f0SEd L. Cashin printk(KERN_INFO "aoe: device sysminor_m failure\n"); 10251da177e4SLinus Torvalds return; 10261da177e4SLinus Torvalds } 10271da177e4SLinus Torvalds 10281da177e4SLinus Torvalds spin_lock_irqsave(&d->lock, flags); 10291da177e4SLinus Torvalds 103068e0d42fSEd L. Cashin t = gettgt(d, h->src); 103168e0d42fSEd L. Cashin if (!t) { 103268e0d42fSEd L. Cashin t = addtgt(d, h->src, n); 103368e0d42fSEd L. Cashin if (!t) { 103468e0d42fSEd L. Cashin spin_unlock_irqrestore(&d->lock, flags); 103568e0d42fSEd L. Cashin return; 103668e0d42fSEd L. Cashin } 103768e0d42fSEd L. Cashin } 103868e0d42fSEd L. Cashin ifp = getif(t, skb->dev); 103968e0d42fSEd L. Cashin if (!ifp) { 104068e0d42fSEd L. Cashin ifp = addif(t, skb->dev); 104168e0d42fSEd L. Cashin if (!ifp) { 104268e0d42fSEd L. Cashin printk(KERN_INFO 104368e0d42fSEd L. Cashin "aoe: device addif failure; " 104468e0d42fSEd L. Cashin "too many interfaces?\n"); 104568e0d42fSEd L. Cashin spin_unlock_irqrestore(&d->lock, flags); 104668e0d42fSEd L. Cashin return; 104768e0d42fSEd L. Cashin } 104868e0d42fSEd L. Cashin } 104968e0d42fSEd L. Cashin if (ifp->maxbcnt) { 105068e0d42fSEd L. Cashin n = ifp->nd->mtu; 105119bf2635SEd L. Cashin n -= sizeof (struct aoe_hdr) + sizeof (struct aoe_atahdr); 105219bf2635SEd L. Cashin n /= 512; 105319bf2635SEd L. Cashin if (n > ch->scnt) 105419bf2635SEd L. Cashin n = ch->scnt; 10554f51dc5eSEd L. Cashin n = n ? n * 512 : DEFAULTBCNT; 105668e0d42fSEd L. Cashin if (n != ifp->maxbcnt) { 1057a12c93f0SEd L. Cashin printk(KERN_INFO 105868e0d42fSEd L. Cashin "aoe: e%ld.%d: setting %d%s%s:%012llx\n", 105968e0d42fSEd L. Cashin d->aoemajor, d->aoeminor, n, 106068e0d42fSEd L. Cashin " byte data frames on ", ifp->nd->name, 10611eb0da4cSEd L. Cashin mac_addr(t->addr)); 106268e0d42fSEd L. Cashin ifp->maxbcnt = n; 10634f51dc5eSEd L. Cashin } 106419bf2635SEd L. Cashin } 10653ae1c24eSEd L. Cashin 10663ae1c24eSEd L. Cashin /* don't change users' perspective */ 106768e0d42fSEd L. Cashin if (d->nopen) { 10681da177e4SLinus Torvalds spin_unlock_irqrestore(&d->lock, flags); 10691da177e4SLinus Torvalds return; 10701da177e4SLinus Torvalds } 107163e9cc5dSecashin@coraid.com d->fw_ver = be16_to_cpu(ch->fwver); 10721da177e4SLinus Torvalds 107368e0d42fSEd L. Cashin sl = aoecmd_ata_id(d); 10741da177e4SLinus Torvalds 10751da177e4SLinus Torvalds spin_unlock_irqrestore(&d->lock, flags); 10761da177e4SLinus Torvalds 10771da177e4SLinus Torvalds aoenet_xmit(sl); 10781da177e4SLinus Torvalds } 10791da177e4SLinus Torvalds 108068e0d42fSEd L. Cashin void 108168e0d42fSEd L. Cashin aoecmd_cleanslate(struct aoedev *d) 108268e0d42fSEd L. Cashin { 108368e0d42fSEd L. Cashin struct aoetgt **t, **te; 108468e0d42fSEd L. Cashin struct aoeif *p, *e; 108568e0d42fSEd L. Cashin 108668e0d42fSEd L. Cashin d->mintimer = MINTIMER; 108768e0d42fSEd L. Cashin 108868e0d42fSEd L. Cashin t = d->targets; 108968e0d42fSEd L. Cashin te = t + NTARGETS; 109068e0d42fSEd L. Cashin for (; t < te && *t; t++) { 109168e0d42fSEd L. Cashin (*t)->maxout = (*t)->nframes; 109268e0d42fSEd L. Cashin p = (*t)->ifs; 109368e0d42fSEd L. Cashin e = p + NAOEIFS; 109468e0d42fSEd L. Cashin for (; p < e; p++) { 109568e0d42fSEd L. Cashin p->lostjumbo = 0; 109668e0d42fSEd L. Cashin p->lost = 0; 109768e0d42fSEd L. Cashin p->maxbcnt = DEFAULTBCNT; 109868e0d42fSEd L. Cashin } 109968e0d42fSEd L. Cashin } 110068e0d42fSEd L. Cashin } 1101