1fea05a26SEd Cashin /* Copyright (c) 2012 Coraid, Inc. See COPYING for GPL terms. */ 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * aoecmd.c 41da177e4SLinus Torvalds * Filesystem request handling methods 51da177e4SLinus Torvalds */ 61da177e4SLinus Torvalds 704b3ab52SBartlomiej Zolnierkiewicz #include <linux/ata.h> 85a0e3ad6STejun Heo #include <linux/slab.h> 91da177e4SLinus Torvalds #include <linux/hdreg.h> 101da177e4SLinus Torvalds #include <linux/blkdev.h> 111da177e4SLinus Torvalds #include <linux/skbuff.h> 121da177e4SLinus Torvalds #include <linux/netdevice.h> 133ae1c24eSEd L. Cashin #include <linux/genhd.h> 1468e0d42fSEd L. Cashin #include <linux/moduleparam.h> 15896831f5SEd Cashin #include <linux/workqueue.h> 16896831f5SEd Cashin #include <linux/kthread.h> 17881d966bSEric W. Biederman #include <net/net_namespace.h> 18475172fbSEd L. Cashin #include <asm/unaligned.h> 19896831f5SEd Cashin #include <linux/uio.h> 201da177e4SLinus Torvalds #include "aoe.h" 211da177e4SLinus Torvalds 22896831f5SEd Cashin #define MAXIOC (8192) /* default meant to avoid most soft lockups */ 23896831f5SEd Cashin 24896831f5SEd Cashin static void ktcomplete(struct frame *, struct sk_buff *); 25896831f5SEd Cashin 2669cf2d85SEd Cashin static struct buf *nextbuf(struct aoedev *); 2769cf2d85SEd Cashin 28b751e8b6SEd L. Cashin static int aoe_deadsecs = 60 * 3; 29b751e8b6SEd L. Cashin module_param(aoe_deadsecs, int, 0644); 30b751e8b6SEd L. Cashin MODULE_PARM_DESC(aoe_deadsecs, "After aoe_deadsecs seconds, give up and fail dev."); 311da177e4SLinus Torvalds 327df620d8SEd L. Cashin static int aoe_maxout = 16; 337df620d8SEd L. Cashin module_param(aoe_maxout, int, 0644); 347df620d8SEd L. Cashin MODULE_PARM_DESC(aoe_maxout, 357df620d8SEd L. Cashin "Only aoe_maxout outstanding packets for every MAC on eX.Y."); 367df620d8SEd L. Cashin 37896831f5SEd Cashin static wait_queue_head_t ktiowq; 38896831f5SEd Cashin static struct ktstate kts; 39896831f5SEd Cashin 40896831f5SEd Cashin /* io completion queue */ 41896831f5SEd Cashin static struct { 42896831f5SEd Cashin struct list_head head; 43896831f5SEd Cashin spinlock_t lock; 44896831f5SEd Cashin } iocq; 45896831f5SEd Cashin 4668e0d42fSEd L. Cashin static struct sk_buff * 47e407a7f6SEd L. Cashin new_skb(ulong len) 481da177e4SLinus Torvalds { 491da177e4SLinus Torvalds struct sk_buff *skb; 501da177e4SLinus Torvalds 511da177e4SLinus Torvalds skb = alloc_skb(len, GFP_ATOMIC); 521da177e4SLinus Torvalds if (skb) { 53459a98edSArnaldo Carvalho de Melo skb_reset_mac_header(skb); 54c1d2bbe1SArnaldo Carvalho de Melo skb_reset_network_header(skb); 551da177e4SLinus Torvalds skb->protocol = __constant_htons(ETH_P_AOE); 568babe8ccSEd Cashin skb_checksum_none_assert(skb); 571da177e4SLinus Torvalds } 581da177e4SLinus Torvalds return skb; 591da177e4SLinus Torvalds } 601da177e4SLinus Torvalds 611da177e4SLinus Torvalds static struct frame * 623a0c40d2SEd Cashin getframe_deferred(struct aoedev *d, u32 tag) 633a0c40d2SEd Cashin { 643a0c40d2SEd Cashin struct list_head *head, *pos, *nx; 653a0c40d2SEd Cashin struct frame *f; 663a0c40d2SEd Cashin 673a0c40d2SEd Cashin head = &d->rexmitq; 683a0c40d2SEd Cashin list_for_each_safe(pos, nx, head) { 693a0c40d2SEd Cashin f = list_entry(pos, struct frame, head); 703a0c40d2SEd Cashin if (f->tag == tag) { 713a0c40d2SEd Cashin list_del(pos); 723a0c40d2SEd Cashin return f; 733a0c40d2SEd Cashin } 743a0c40d2SEd Cashin } 753a0c40d2SEd Cashin return NULL; 763a0c40d2SEd Cashin } 773a0c40d2SEd Cashin 783a0c40d2SEd Cashin static struct frame * 7964a80f5aSEd Cashin getframe(struct aoedev *d, u32 tag) 801da177e4SLinus Torvalds { 81896831f5SEd Cashin struct frame *f; 82896831f5SEd Cashin struct list_head *head, *pos, *nx; 83896831f5SEd Cashin u32 n; 841da177e4SLinus Torvalds 85896831f5SEd Cashin n = tag % NFACTIVE; 8664a80f5aSEd Cashin head = &d->factive[n]; 87896831f5SEd Cashin list_for_each_safe(pos, nx, head) { 88896831f5SEd Cashin f = list_entry(pos, struct frame, head); 89896831f5SEd Cashin if (f->tag == tag) { 90896831f5SEd Cashin list_del(pos); 911da177e4SLinus Torvalds return f; 92896831f5SEd Cashin } 93896831f5SEd Cashin } 941da177e4SLinus Torvalds return NULL; 951da177e4SLinus Torvalds } 961da177e4SLinus Torvalds 971da177e4SLinus Torvalds /* 981da177e4SLinus Torvalds * Leave the top bit clear so we have tagspace for userland. 991da177e4SLinus Torvalds * The bottom 16 bits are the xmit tick for rexmit/rttavg processing. 1001da177e4SLinus Torvalds * This driver reserves tag -1 to mean "unused frame." 1011da177e4SLinus Torvalds */ 1021da177e4SLinus Torvalds static int 10364a80f5aSEd Cashin newtag(struct aoedev *d) 1041da177e4SLinus Torvalds { 1051da177e4SLinus Torvalds register ulong n; 1061da177e4SLinus Torvalds 1071da177e4SLinus Torvalds n = jiffies & 0xffff; 10864a80f5aSEd Cashin return n |= (++d->lasttag & 0x7fff) << 16; 1091da177e4SLinus Torvalds } 1101da177e4SLinus Torvalds 111896831f5SEd Cashin static u32 11268e0d42fSEd L. Cashin aoehdr_atainit(struct aoedev *d, struct aoetgt *t, struct aoe_hdr *h) 1131da177e4SLinus Torvalds { 11464a80f5aSEd Cashin u32 host_tag = newtag(d); 1151da177e4SLinus Torvalds 11668e0d42fSEd L. Cashin memcpy(h->src, t->ifp->nd->dev_addr, sizeof h->src); 11768e0d42fSEd L. Cashin memcpy(h->dst, t->addr, sizeof h->dst); 11863e9cc5dSecashin@coraid.com h->type = __constant_cpu_to_be16(ETH_P_AOE); 1191da177e4SLinus Torvalds h->verfl = AOE_HVER; 12063e9cc5dSecashin@coraid.com h->major = cpu_to_be16(d->aoemajor); 1211da177e4SLinus Torvalds h->minor = d->aoeminor; 1221da177e4SLinus Torvalds h->cmd = AOECMD_ATA; 12363e9cc5dSecashin@coraid.com h->tag = cpu_to_be32(host_tag); 1241da177e4SLinus Torvalds 1251da177e4SLinus Torvalds return host_tag; 1261da177e4SLinus Torvalds } 1271da177e4SLinus Torvalds 12819bf2635SEd L. Cashin static inline void 12919bf2635SEd L. Cashin put_lba(struct aoe_atahdr *ah, sector_t lba) 13019bf2635SEd L. Cashin { 13119bf2635SEd L. Cashin ah->lba0 = lba; 13219bf2635SEd L. Cashin ah->lba1 = lba >>= 8; 13319bf2635SEd L. Cashin ah->lba2 = lba >>= 8; 13419bf2635SEd L. Cashin ah->lba3 = lba >>= 8; 13519bf2635SEd L. Cashin ah->lba4 = lba >>= 8; 13619bf2635SEd L. Cashin ah->lba5 = lba >>= 8; 13719bf2635SEd L. Cashin } 13819bf2635SEd L. Cashin 1393f0f0133SEd Cashin static struct aoeif * 14068e0d42fSEd L. Cashin ifrotate(struct aoetgt *t) 1411da177e4SLinus Torvalds { 1423f0f0133SEd Cashin struct aoeif *ifp; 1433f0f0133SEd Cashin 1443f0f0133SEd Cashin ifp = t->ifp; 1453f0f0133SEd Cashin ifp++; 1463f0f0133SEd Cashin if (ifp >= &t->ifs[NAOEIFS] || ifp->nd == NULL) 1473f0f0133SEd Cashin ifp = t->ifs; 1483f0f0133SEd Cashin if (ifp->nd == NULL) 1493f0f0133SEd Cashin return NULL; 1503f0f0133SEd Cashin return t->ifp = ifp; 15168e0d42fSEd L. Cashin } 15268e0d42fSEd L. Cashin 1539bb237b6SEd L. Cashin static void 1549bb237b6SEd L. Cashin skb_pool_put(struct aoedev *d, struct sk_buff *skb) 1559bb237b6SEd L. Cashin { 156e9bb8fb0SDavid S. Miller __skb_queue_tail(&d->skbpool, skb); 1579bb237b6SEd L. Cashin } 1589bb237b6SEd L. Cashin 1599bb237b6SEd L. Cashin static struct sk_buff * 1609bb237b6SEd L. Cashin skb_pool_get(struct aoedev *d) 1619bb237b6SEd L. Cashin { 162e9bb8fb0SDavid S. Miller struct sk_buff *skb = skb_peek(&d->skbpool); 1639bb237b6SEd L. Cashin 1649bb237b6SEd L. Cashin if (skb && atomic_read(&skb_shinfo(skb)->dataref) == 1) { 165e9bb8fb0SDavid S. Miller __skb_unlink(skb, &d->skbpool); 1669bb237b6SEd L. Cashin return skb; 1679bb237b6SEd L. Cashin } 168e9bb8fb0SDavid S. Miller if (skb_queue_len(&d->skbpool) < NSKBPOOLMAX && 169e9bb8fb0SDavid S. Miller (skb = new_skb(ETH_ZLEN))) 1709bb237b6SEd L. Cashin return skb; 171e9bb8fb0SDavid S. Miller 1729bb237b6SEd L. Cashin return NULL; 1739bb237b6SEd L. Cashin } 1749bb237b6SEd L. Cashin 175896831f5SEd Cashin void 176896831f5SEd Cashin aoe_freetframe(struct frame *f) 17768e0d42fSEd L. Cashin { 178896831f5SEd Cashin struct aoetgt *t; 179896831f5SEd Cashin 180896831f5SEd Cashin t = f->t; 181896831f5SEd Cashin f->buf = NULL; 182896831f5SEd Cashin f->bv = NULL; 183896831f5SEd Cashin f->r_skb = NULL; 184896831f5SEd Cashin list_add(&f->head, &t->ffree); 185896831f5SEd Cashin } 186896831f5SEd Cashin 187896831f5SEd Cashin static struct frame * 188896831f5SEd Cashin newtframe(struct aoedev *d, struct aoetgt *t) 189896831f5SEd Cashin { 190896831f5SEd Cashin struct frame *f; 1919bb237b6SEd L. Cashin struct sk_buff *skb; 192896831f5SEd Cashin struct list_head *pos; 193896831f5SEd Cashin 194896831f5SEd Cashin if (list_empty(&t->ffree)) { 195896831f5SEd Cashin if (t->falloc >= NSKBPOOLMAX*2) 196896831f5SEd Cashin return NULL; 197896831f5SEd Cashin f = kcalloc(1, sizeof(*f), GFP_ATOMIC); 198896831f5SEd Cashin if (f == NULL) 199896831f5SEd Cashin return NULL; 200896831f5SEd Cashin t->falloc++; 201896831f5SEd Cashin f->t = t; 202896831f5SEd Cashin } else { 203896831f5SEd Cashin pos = t->ffree.next; 204896831f5SEd Cashin list_del(pos); 205896831f5SEd Cashin f = list_entry(pos, struct frame, head); 206896831f5SEd Cashin } 207896831f5SEd Cashin 208896831f5SEd Cashin skb = f->skb; 209896831f5SEd Cashin if (skb == NULL) { 210896831f5SEd Cashin f->skb = skb = new_skb(ETH_ZLEN); 211896831f5SEd Cashin if (!skb) { 212896831f5SEd Cashin bail: aoe_freetframe(f); 213896831f5SEd Cashin return NULL; 214896831f5SEd Cashin } 215896831f5SEd Cashin } 216896831f5SEd Cashin 217896831f5SEd Cashin if (atomic_read(&skb_shinfo(skb)->dataref) != 1) { 218896831f5SEd Cashin skb = skb_pool_get(d); 219896831f5SEd Cashin if (skb == NULL) 220896831f5SEd Cashin goto bail; 221896831f5SEd Cashin skb_pool_put(d, f->skb); 222896831f5SEd Cashin f->skb = skb; 223896831f5SEd Cashin } 224896831f5SEd Cashin 225896831f5SEd Cashin skb->truesize -= skb->data_len; 226896831f5SEd Cashin skb_shinfo(skb)->nr_frags = skb->data_len = 0; 227896831f5SEd Cashin skb_trim(skb, 0); 228896831f5SEd Cashin return f; 229896831f5SEd Cashin } 230896831f5SEd Cashin 231896831f5SEd Cashin static struct frame * 232896831f5SEd Cashin newframe(struct aoedev *d) 233896831f5SEd Cashin { 234896831f5SEd Cashin struct frame *f; 235896831f5SEd Cashin struct aoetgt *t, **tt; 236896831f5SEd Cashin int totout = 0; 23768e0d42fSEd L. Cashin 23868e0d42fSEd L. Cashin if (d->targets[0] == NULL) { /* shouldn't happen, but I'm paranoid */ 23968e0d42fSEd L. Cashin printk(KERN_ERR "aoe: NULL TARGETS!\n"); 24068e0d42fSEd L. Cashin return NULL; 24168e0d42fSEd L. Cashin } 242896831f5SEd Cashin tt = d->tgt; /* last used target */ 2439bb237b6SEd L. Cashin for (;;) { 244896831f5SEd Cashin tt++; 245896831f5SEd Cashin if (tt >= &d->targets[NTARGETS] || !*tt) 246896831f5SEd Cashin tt = d->targets; 247896831f5SEd Cashin t = *tt; 248896831f5SEd Cashin totout += t->nout; 249896831f5SEd Cashin if (t->nout < t->maxout 2509bb237b6SEd L. Cashin && t != d->htgt 251896831f5SEd Cashin && t->ifp->nd) { 252896831f5SEd Cashin f = newtframe(d, t); 253896831f5SEd Cashin if (f) { 254896831f5SEd Cashin ifrotate(t); 2553f0f0133SEd Cashin d->tgt = tt; 25668e0d42fSEd L. Cashin return f; 25768e0d42fSEd L. Cashin } 2589bb237b6SEd L. Cashin } 259896831f5SEd Cashin if (tt == d->tgt) /* we've looped and found nada */ 2609bb237b6SEd L. Cashin break; 261896831f5SEd Cashin } 262896831f5SEd Cashin if (totout == 0) { 263896831f5SEd Cashin d->kicked++; 264896831f5SEd Cashin d->flags |= DEVFL_KICKME; 2659bb237b6SEd L. Cashin } 26668e0d42fSEd L. Cashin return NULL; 26768e0d42fSEd L. Cashin } 26868e0d42fSEd L. Cashin 2693d5b0605SEd Cashin static void 2703d5b0605SEd Cashin skb_fillup(struct sk_buff *skb, struct bio_vec *bv, ulong off, ulong cnt) 2713d5b0605SEd Cashin { 2723d5b0605SEd Cashin int frag = 0; 2733d5b0605SEd Cashin ulong fcnt; 2743d5b0605SEd Cashin loop: 2753d5b0605SEd Cashin fcnt = bv->bv_len - (off - bv->bv_offset); 2763d5b0605SEd Cashin if (fcnt > cnt) 2773d5b0605SEd Cashin fcnt = cnt; 2783d5b0605SEd Cashin skb_fill_page_desc(skb, frag++, bv->bv_page, off, fcnt); 2793d5b0605SEd Cashin cnt -= fcnt; 2803d5b0605SEd Cashin if (cnt <= 0) 2813d5b0605SEd Cashin return; 2823d5b0605SEd Cashin bv++; 2833d5b0605SEd Cashin off = bv->bv_offset; 2843d5b0605SEd Cashin goto loop; 2853d5b0605SEd Cashin } 2863d5b0605SEd Cashin 287896831f5SEd Cashin static void 288896831f5SEd Cashin fhash(struct frame *f) 289896831f5SEd Cashin { 29064a80f5aSEd Cashin struct aoedev *d = f->t->d; 291896831f5SEd Cashin u32 n; 292896831f5SEd Cashin 293896831f5SEd Cashin n = f->tag % NFACTIVE; 29464a80f5aSEd Cashin list_add_tail(&f->head, &d->factive[n]); 295896831f5SEd Cashin } 296896831f5SEd Cashin 29768e0d42fSEd L. Cashin static int 29868e0d42fSEd L. Cashin aoecmd_ata_rw(struct aoedev *d) 29968e0d42fSEd L. Cashin { 30068e0d42fSEd L. Cashin struct frame *f; 3011da177e4SLinus Torvalds struct aoe_hdr *h; 3021da177e4SLinus Torvalds struct aoe_atahdr *ah; 3031da177e4SLinus Torvalds struct buf *buf; 30468e0d42fSEd L. Cashin struct aoetgt *t; 3051da177e4SLinus Torvalds struct sk_buff *skb; 30669cf2d85SEd Cashin struct sk_buff_head queue; 3073d5b0605SEd Cashin ulong bcnt, fbcnt; 3081da177e4SLinus Torvalds char writebit, extbit; 3091da177e4SLinus Torvalds 3101da177e4SLinus Torvalds writebit = 0x10; 3111da177e4SLinus Torvalds extbit = 0x4; 3121da177e4SLinus Torvalds 31369cf2d85SEd Cashin buf = nextbuf(d); 31469cf2d85SEd Cashin if (buf == NULL) 31569cf2d85SEd Cashin return 0; 316896831f5SEd Cashin f = newframe(d); 31768e0d42fSEd L. Cashin if (f == NULL) 31868e0d42fSEd L. Cashin return 0; 31968e0d42fSEd L. Cashin t = *d->tgt; 3203f0f0133SEd Cashin bcnt = d->maxbcnt; 32168e0d42fSEd L. Cashin if (bcnt == 0) 32268e0d42fSEd L. Cashin bcnt = DEFAULTBCNT; 3233d5b0605SEd Cashin if (bcnt > buf->resid) 3243d5b0605SEd Cashin bcnt = buf->resid; 3253d5b0605SEd Cashin fbcnt = bcnt; 3263d5b0605SEd Cashin f->bv = buf->bv; 3273d5b0605SEd Cashin f->bv_off = f->bv->bv_offset + (f->bv->bv_len - buf->bv_resid); 3283d5b0605SEd Cashin do { 3293d5b0605SEd Cashin if (fbcnt < buf->bv_resid) { 3303d5b0605SEd Cashin buf->bv_resid -= fbcnt; 3313d5b0605SEd Cashin buf->resid -= fbcnt; 3323d5b0605SEd Cashin break; 3333d5b0605SEd Cashin } 3343d5b0605SEd Cashin fbcnt -= buf->bv_resid; 3353d5b0605SEd Cashin buf->resid -= buf->bv_resid; 3363d5b0605SEd Cashin if (buf->resid == 0) { 33769cf2d85SEd Cashin d->ip.buf = NULL; 3383d5b0605SEd Cashin break; 3393d5b0605SEd Cashin } 3403d5b0605SEd Cashin buf->bv++; 3413d5b0605SEd Cashin buf->bv_resid = buf->bv->bv_len; 3423d5b0605SEd Cashin WARN_ON(buf->bv_resid == 0); 3433d5b0605SEd Cashin } while (fbcnt); 3443d5b0605SEd Cashin 3451da177e4SLinus Torvalds /* initialize the headers & frame */ 346e407a7f6SEd L. Cashin skb = f->skb; 347abdbf94dSEd L. Cashin h = (struct aoe_hdr *) skb_mac_header(skb); 3481da177e4SLinus Torvalds ah = (struct aoe_atahdr *) (h+1); 34919900cdeSEd L. Cashin skb_put(skb, sizeof *h + sizeof *ah); 35019900cdeSEd L. Cashin memset(h, 0, skb->len); 35168e0d42fSEd L. Cashin f->tag = aoehdr_atainit(d, t, h); 352896831f5SEd Cashin fhash(f); 35368e0d42fSEd L. Cashin t->nout++; 3541da177e4SLinus Torvalds f->waited = 0; 3553fc9b032SEd Cashin f->waited_total = 0; 3561da177e4SLinus Torvalds f->buf = buf; 35719bf2635SEd L. Cashin f->bcnt = bcnt; 35868e0d42fSEd L. Cashin f->lba = buf->sector; 3591da177e4SLinus Torvalds 3601da177e4SLinus Torvalds /* set up ata header */ 3611da177e4SLinus Torvalds ah->scnt = bcnt >> 9; 36268e0d42fSEd L. Cashin put_lba(ah, buf->sector); 3631da177e4SLinus Torvalds if (d->flags & DEVFL_EXT) { 3641da177e4SLinus Torvalds ah->aflags |= AOEAFL_EXT; 3651da177e4SLinus Torvalds } else { 3661da177e4SLinus Torvalds extbit = 0; 3671da177e4SLinus Torvalds ah->lba3 &= 0x0f; 3681da177e4SLinus Torvalds ah->lba3 |= 0xe0; /* LBA bit + obsolete 0xa0 */ 3691da177e4SLinus Torvalds } 3701da177e4SLinus Torvalds if (bio_data_dir(buf->bio) == WRITE) { 3713d5b0605SEd Cashin skb_fillup(skb, f->bv, f->bv_off, bcnt); 3721da177e4SLinus Torvalds ah->aflags |= AOEAFL_WRITE; 3734f51dc5eSEd L. Cashin skb->len += bcnt; 3744f51dc5eSEd L. Cashin skb->data_len = bcnt; 3753d5b0605SEd Cashin skb->truesize += bcnt; 37668e0d42fSEd L. Cashin t->wpkts++; 3771da177e4SLinus Torvalds } else { 37868e0d42fSEd L. Cashin t->rpkts++; 3791da177e4SLinus Torvalds writebit = 0; 3801da177e4SLinus Torvalds } 3811da177e4SLinus Torvalds 38204b3ab52SBartlomiej Zolnierkiewicz ah->cmdstat = ATA_CMD_PIO_READ | writebit | extbit; 3831da177e4SLinus Torvalds 3841da177e4SLinus Torvalds /* mark all tracking fields and load out */ 3851da177e4SLinus Torvalds buf->nframesout += 1; 3861da177e4SLinus Torvalds buf->sector += bcnt >> 9; 3871da177e4SLinus Torvalds 38868e0d42fSEd L. Cashin skb->dev = t->ifp->nd; 3894f51dc5eSEd L. Cashin skb = skb_clone(skb, GFP_ATOMIC); 39069cf2d85SEd Cashin if (skb) { 3915f0c9c48SEd Cashin do_gettimeofday(&f->sent); 3925f0c9c48SEd Cashin f->sent_jiffs = (u32) jiffies; 39369cf2d85SEd Cashin __skb_queue_head_init(&queue); 39469cf2d85SEd Cashin __skb_queue_tail(&queue, skb); 39569cf2d85SEd Cashin aoenet_xmit(&queue); 39669cf2d85SEd Cashin } 39768e0d42fSEd L. Cashin return 1; 39868e0d42fSEd L. Cashin } 3991da177e4SLinus Torvalds 4003ae1c24eSEd L. Cashin /* some callers cannot sleep, and they can call this function, 4013ae1c24eSEd L. Cashin * transmitting the packets later, when interrupts are on 4023ae1c24eSEd L. Cashin */ 403e9bb8fb0SDavid S. Miller static void 404e9bb8fb0SDavid S. Miller aoecmd_cfg_pkts(ushort aoemajor, unsigned char aoeminor, struct sk_buff_head *queue) 4053ae1c24eSEd L. Cashin { 4063ae1c24eSEd L. Cashin struct aoe_hdr *h; 4073ae1c24eSEd L. Cashin struct aoe_cfghdr *ch; 408e9bb8fb0SDavid S. Miller struct sk_buff *skb; 4093ae1c24eSEd L. Cashin struct net_device *ifp; 4103ae1c24eSEd L. Cashin 411840a185dSEric Dumazet rcu_read_lock(); 412840a185dSEric Dumazet for_each_netdev_rcu(&init_net, ifp) { 4133ae1c24eSEd L. Cashin dev_hold(ifp); 4143ae1c24eSEd L. Cashin if (!is_aoe_netif(ifp)) 4157562f876SPavel Emelianov goto cont; 4163ae1c24eSEd L. Cashin 417e407a7f6SEd L. Cashin skb = new_skb(sizeof *h + sizeof *ch); 4183ae1c24eSEd L. Cashin if (skb == NULL) { 419a12c93f0SEd L. Cashin printk(KERN_INFO "aoe: skb alloc failure\n"); 4207562f876SPavel Emelianov goto cont; 4213ae1c24eSEd L. Cashin } 42219900cdeSEd L. Cashin skb_put(skb, sizeof *h + sizeof *ch); 423e407a7f6SEd L. Cashin skb->dev = ifp; 424e9bb8fb0SDavid S. Miller __skb_queue_tail(queue, skb); 425abdbf94dSEd L. Cashin h = (struct aoe_hdr *) skb_mac_header(skb); 4263ae1c24eSEd L. Cashin memset(h, 0, sizeof *h + sizeof *ch); 4273ae1c24eSEd L. Cashin 4283ae1c24eSEd L. Cashin memset(h->dst, 0xff, sizeof h->dst); 4293ae1c24eSEd L. Cashin memcpy(h->src, ifp->dev_addr, sizeof h->src); 4303ae1c24eSEd L. Cashin h->type = __constant_cpu_to_be16(ETH_P_AOE); 4313ae1c24eSEd L. Cashin h->verfl = AOE_HVER; 4323ae1c24eSEd L. Cashin h->major = cpu_to_be16(aoemajor); 4333ae1c24eSEd L. Cashin h->minor = aoeminor; 4343ae1c24eSEd L. Cashin h->cmd = AOECMD_CFG; 4353ae1c24eSEd L. Cashin 4367562f876SPavel Emelianov cont: 4377562f876SPavel Emelianov dev_put(ifp); 4383ae1c24eSEd L. Cashin } 439840a185dSEric Dumazet rcu_read_unlock(); 4403ae1c24eSEd L. Cashin } 4413ae1c24eSEd L. Cashin 4421da177e4SLinus Torvalds static void 443896831f5SEd Cashin resend(struct aoedev *d, struct frame *f) 4441da177e4SLinus Torvalds { 4451da177e4SLinus Torvalds struct sk_buff *skb; 44669cf2d85SEd Cashin struct sk_buff_head queue; 4471da177e4SLinus Torvalds struct aoe_hdr *h; 44819bf2635SEd L. Cashin struct aoe_atahdr *ah; 449896831f5SEd Cashin struct aoetgt *t; 4501da177e4SLinus Torvalds char buf[128]; 4511da177e4SLinus Torvalds u32 n; 4521da177e4SLinus Torvalds 453896831f5SEd Cashin t = f->t; 45464a80f5aSEd Cashin n = newtag(d); 455e407a7f6SEd L. Cashin skb = f->skb; 4563f0f0133SEd Cashin if (ifrotate(t) == NULL) { 4573f0f0133SEd Cashin /* probably can't happen, but set it up to fail anyway */ 4583f0f0133SEd Cashin pr_info("aoe: resend: no interfaces to rotate to.\n"); 4593f0f0133SEd Cashin ktcomplete(f, NULL); 4603f0f0133SEd Cashin return; 4613f0f0133SEd Cashin } 462abdbf94dSEd L. Cashin h = (struct aoe_hdr *) skb_mac_header(skb); 46319bf2635SEd L. Cashin ah = (struct aoe_atahdr *) (h+1); 46468e0d42fSEd L. Cashin 46568e0d42fSEd L. Cashin snprintf(buf, sizeof buf, 466411c41eeSHarvey Harrison "%15s e%ld.%d oldtag=%08x@%08lx newtag=%08x s=%pm d=%pm nout=%d\n", 46768e0d42fSEd L. Cashin "retransmit", d->aoemajor, d->aoeminor, f->tag, jiffies, n, 468411c41eeSHarvey Harrison h->src, h->dst, t->nout); 46968e0d42fSEd L. Cashin aoechr_error(buf); 47068e0d42fSEd L. Cashin 4711da177e4SLinus Torvalds f->tag = n; 472896831f5SEd Cashin fhash(f); 47363e9cc5dSecashin@coraid.com h->tag = cpu_to_be32(n); 47468e0d42fSEd L. Cashin memcpy(h->dst, t->addr, sizeof h->dst); 47568e0d42fSEd L. Cashin memcpy(h->src, t->ifp->nd->dev_addr, sizeof h->src); 4761da177e4SLinus Torvalds 47768e0d42fSEd L. Cashin skb->dev = t->ifp->nd; 4784f51dc5eSEd L. Cashin skb = skb_clone(skb, GFP_ATOMIC); 4794f51dc5eSEd L. Cashin if (skb == NULL) 4804f51dc5eSEd L. Cashin return; 4815f0c9c48SEd Cashin do_gettimeofday(&f->sent); 4825f0c9c48SEd Cashin f->sent_jiffs = (u32) jiffies; 48369cf2d85SEd Cashin __skb_queue_head_init(&queue); 48469cf2d85SEd Cashin __skb_queue_tail(&queue, skb); 48569cf2d85SEd Cashin aoenet_xmit(&queue); 4861da177e4SLinus Torvalds } 4871da177e4SLinus Torvalds 4881da177e4SLinus Torvalds static int 4895f0c9c48SEd Cashin tsince_hr(struct frame *f) 4905f0c9c48SEd Cashin { 4915f0c9c48SEd Cashin struct timeval now; 4925f0c9c48SEd Cashin int n; 4935f0c9c48SEd Cashin 4945f0c9c48SEd Cashin do_gettimeofday(&now); 4955f0c9c48SEd Cashin n = now.tv_usec - f->sent.tv_usec; 4965f0c9c48SEd Cashin n += (now.tv_sec - f->sent.tv_sec) * USEC_PER_SEC; 4975f0c9c48SEd Cashin 4985f0c9c48SEd Cashin if (n < 0) 4995f0c9c48SEd Cashin n = -n; 5005f0c9c48SEd Cashin 5015f0c9c48SEd Cashin /* For relatively long periods, use jiffies to avoid 5025f0c9c48SEd Cashin * discrepancies caused by updates to the system time. 5035f0c9c48SEd Cashin * 5045f0c9c48SEd Cashin * On system with HZ of 1000, 32-bits is over 49 days 5055f0c9c48SEd Cashin * worth of jiffies, or over 71 minutes worth of usecs. 5065f0c9c48SEd Cashin * 5075f0c9c48SEd Cashin * Jiffies overflow is handled by subtraction of unsigned ints: 5085f0c9c48SEd Cashin * (gdb) print (unsigned) 2 - (unsigned) 0xfffffffe 5095f0c9c48SEd Cashin * $3 = 4 5105f0c9c48SEd Cashin * (gdb) 5115f0c9c48SEd Cashin */ 5125f0c9c48SEd Cashin if (n > USEC_PER_SEC / 4) { 5135f0c9c48SEd Cashin n = ((u32) jiffies) - f->sent_jiffs; 5145f0c9c48SEd Cashin n *= USEC_PER_SEC / HZ; 5155f0c9c48SEd Cashin } 5165f0c9c48SEd Cashin 5175f0c9c48SEd Cashin return n; 5185f0c9c48SEd Cashin } 5195f0c9c48SEd Cashin 5205f0c9c48SEd Cashin static int 521896831f5SEd Cashin tsince(u32 tag) 5221da177e4SLinus Torvalds { 5231da177e4SLinus Torvalds int n; 5241da177e4SLinus Torvalds 5251da177e4SLinus Torvalds n = jiffies & 0xffff; 5261da177e4SLinus Torvalds n -= tag & 0xffff; 5271da177e4SLinus Torvalds if (n < 0) 5281da177e4SLinus Torvalds n += 1<<16; 5295f0c9c48SEd Cashin return jiffies_to_usecs(n + 1); 5301da177e4SLinus Torvalds } 5311da177e4SLinus Torvalds 53268e0d42fSEd L. Cashin static struct aoeif * 53368e0d42fSEd L. Cashin getif(struct aoetgt *t, struct net_device *nd) 53468e0d42fSEd L. Cashin { 53568e0d42fSEd L. Cashin struct aoeif *p, *e; 53668e0d42fSEd L. Cashin 53768e0d42fSEd L. Cashin p = t->ifs; 53868e0d42fSEd L. Cashin e = p + NAOEIFS; 53968e0d42fSEd L. Cashin for (; p < e; p++) 54068e0d42fSEd L. Cashin if (p->nd == nd) 54168e0d42fSEd L. Cashin return p; 54268e0d42fSEd L. Cashin return NULL; 54368e0d42fSEd L. Cashin } 54468e0d42fSEd L. Cashin 54568e0d42fSEd L. Cashin static void 54668e0d42fSEd L. Cashin ejectif(struct aoetgt *t, struct aoeif *ifp) 54768e0d42fSEd L. Cashin { 54868e0d42fSEd L. Cashin struct aoeif *e; 5491b86fda9SEd Cashin struct net_device *nd; 55068e0d42fSEd L. Cashin ulong n; 55168e0d42fSEd L. Cashin 5521b86fda9SEd Cashin nd = ifp->nd; 55368e0d42fSEd L. Cashin e = t->ifs + NAOEIFS - 1; 55468e0d42fSEd L. Cashin n = (e - ifp) * sizeof *ifp; 55568e0d42fSEd L. Cashin memmove(ifp, ifp+1, n); 55668e0d42fSEd L. Cashin e->nd = NULL; 5571b86fda9SEd Cashin dev_put(nd); 55868e0d42fSEd L. Cashin } 55968e0d42fSEd L. Cashin 5603fc9b032SEd Cashin static struct frame * 5613fc9b032SEd Cashin reassign_frame(struct list_head *pos) 56268e0d42fSEd L. Cashin { 5633fc9b032SEd Cashin struct frame *f; 5643fc9b032SEd Cashin struct frame *nf; 56568e0d42fSEd L. Cashin struct sk_buff *skb; 56668e0d42fSEd L. Cashin 567896831f5SEd Cashin f = list_entry(pos, struct frame, head); 5683fc9b032SEd Cashin nf = newframe(f->t->d); 56968e0d42fSEd L. Cashin if (!nf) 5703fc9b032SEd Cashin return NULL; 571896831f5SEd Cashin 572896831f5SEd Cashin list_del(pos); 573896831f5SEd Cashin 57468e0d42fSEd L. Cashin skb = nf->skb; 575896831f5SEd Cashin nf->skb = f->skb; 576896831f5SEd Cashin nf->buf = f->buf; 577896831f5SEd Cashin nf->bcnt = f->bcnt; 578896831f5SEd Cashin nf->lba = f->lba; 579896831f5SEd Cashin nf->bv = f->bv; 580896831f5SEd Cashin nf->bv_off = f->bv_off; 58168e0d42fSEd L. Cashin nf->waited = 0; 5823fc9b032SEd Cashin nf->waited_total = f->waited_total; 5833fc9b032SEd Cashin nf->sent = f->sent; 584*fe7252bfSEd Cashin nf->sent_jiffs = f->sent_jiffs; 585896831f5SEd Cashin f->skb = skb; 586896831f5SEd Cashin aoe_freetframe(f); 5873fc9b032SEd Cashin f->t->nout--; 588896831f5SEd Cashin nf->t->nout++; 5893fc9b032SEd Cashin 5903fc9b032SEd Cashin return nf; 5913fc9b032SEd Cashin } 5923fc9b032SEd Cashin 5933fc9b032SEd Cashin static int 5943fc9b032SEd Cashin sthtith(struct aoedev *d) 5953fc9b032SEd Cashin { 5963fc9b032SEd Cashin struct frame *f, *nf; 5973fc9b032SEd Cashin struct list_head *nx, *pos, *head; 5983fc9b032SEd Cashin struct aoetgt *ht = d->htgt; 5993fc9b032SEd Cashin int i; 6003fc9b032SEd Cashin 6013fc9b032SEd Cashin /* look through the active and pending retransmit frames */ 6023fc9b032SEd Cashin for (i = 0; i < NFACTIVE; i++) { 6033fc9b032SEd Cashin head = &d->factive[i]; 6043fc9b032SEd Cashin list_for_each_safe(pos, nx, head) { 6053fc9b032SEd Cashin f = list_entry(pos, struct frame, head); 6063fc9b032SEd Cashin if (f->t != ht) 6073fc9b032SEd Cashin continue; 6083fc9b032SEd Cashin nf = reassign_frame(pos); 6093fc9b032SEd Cashin if (!nf) 6103fc9b032SEd Cashin return 0; 611896831f5SEd Cashin resend(d, nf); 612896831f5SEd Cashin } 61368e0d42fSEd L. Cashin } 6143fc9b032SEd Cashin head = &d->rexmitq; 6153fc9b032SEd Cashin list_for_each_safe(pos, nx, head) { 6163fc9b032SEd Cashin f = list_entry(pos, struct frame, head); 6173fc9b032SEd Cashin if (f->t != ht) 6183fc9b032SEd Cashin continue; 6193fc9b032SEd Cashin nf = reassign_frame(pos); 6203fc9b032SEd Cashin if (!nf) 6213fc9b032SEd Cashin return 0; 6223fc9b032SEd Cashin resend(d, nf); 6233fc9b032SEd Cashin } 6243f0f0133SEd Cashin /* We've cleaned up the outstanding so take away his 6253f0f0133SEd Cashin * interfaces so he won't be used. We should remove him from 6263f0f0133SEd Cashin * the target array here, but cleaning up a target is 6273f0f0133SEd Cashin * involved. PUNT! 6283f0f0133SEd Cashin */ 62968e0d42fSEd L. Cashin memset(ht->ifs, 0, sizeof ht->ifs); 63068e0d42fSEd L. Cashin d->htgt = NULL; 63168e0d42fSEd L. Cashin return 1; 63268e0d42fSEd L. Cashin } 63368e0d42fSEd L. Cashin 6341da177e4SLinus Torvalds static void 6353a0c40d2SEd Cashin rexmit_deferred(struct aoedev *d) 6363a0c40d2SEd Cashin { 6373a0c40d2SEd Cashin struct aoetgt *t; 6383a0c40d2SEd Cashin struct frame *f; 6393a0c40d2SEd Cashin struct list_head *pos, *nx, *head; 6403fc9b032SEd Cashin int since; 6413a0c40d2SEd Cashin 6423a0c40d2SEd Cashin head = &d->rexmitq; 6433a0c40d2SEd Cashin list_for_each_safe(pos, nx, head) { 6443a0c40d2SEd Cashin f = list_entry(pos, struct frame, head); 6453a0c40d2SEd Cashin t = f->t; 6463a0c40d2SEd Cashin if (t->nout >= t->maxout) 6473a0c40d2SEd Cashin continue; 6483a0c40d2SEd Cashin list_del(pos); 6493a0c40d2SEd Cashin t->nout++; 6503fc9b032SEd Cashin since = tsince_hr(f); 6513fc9b032SEd Cashin f->waited += since; 6523fc9b032SEd Cashin f->waited_total += since; 6533a0c40d2SEd Cashin resend(d, f); 6543a0c40d2SEd Cashin } 6553a0c40d2SEd Cashin } 6563a0c40d2SEd Cashin 6573a0c40d2SEd Cashin static void 6581da177e4SLinus Torvalds rexmit_timer(ulong vp) 6591da177e4SLinus Torvalds { 6601da177e4SLinus Torvalds struct aoedev *d; 6613a0c40d2SEd Cashin struct aoetgt *t; 66268e0d42fSEd L. Cashin struct aoeif *ifp; 663896831f5SEd Cashin struct frame *f; 664896831f5SEd Cashin struct list_head *head, *pos, *nx; 665896831f5SEd Cashin LIST_HEAD(flist); 6661da177e4SLinus Torvalds register long timeout; 6671da177e4SLinus Torvalds ulong flags, n; 668896831f5SEd Cashin int i; 6693fc9b032SEd Cashin int since; 6701da177e4SLinus Torvalds 6711da177e4SLinus Torvalds d = (struct aoedev *) vp; 6721da177e4SLinus Torvalds 6730d555ecfSEd Cashin spin_lock_irqsave(&d->lock, flags); 6740d555ecfSEd Cashin 6753a0c40d2SEd Cashin /* timeout based on observed timings and variations */ 6763a0c40d2SEd Cashin timeout = 2 * d->rttavg >> RTTSCALE; 6773a0c40d2SEd Cashin timeout += 8 * d->rttdev >> RTTDSCALE; 6783a0c40d2SEd Cashin if (timeout == 0) 6793a0c40d2SEd Cashin timeout = 1; 6801da177e4SLinus Torvalds 6811da177e4SLinus Torvalds if (d->flags & DEVFL_TKILL) { 6821c6f3fcaSEd L. Cashin spin_unlock_irqrestore(&d->lock, flags); 6831da177e4SLinus Torvalds return; 6841da177e4SLinus Torvalds } 685896831f5SEd Cashin 686896831f5SEd Cashin /* collect all frames to rexmit into flist */ 687896831f5SEd Cashin for (i = 0; i < NFACTIVE; i++) { 68864a80f5aSEd Cashin head = &d->factive[i]; 689896831f5SEd Cashin list_for_each_safe(pos, nx, head) { 690896831f5SEd Cashin f = list_entry(pos, struct frame, head); 6915f0c9c48SEd Cashin if (tsince_hr(f) < timeout) 69264a80f5aSEd Cashin break; /* end of expired frames */ 693896831f5SEd Cashin /* move to flist for later processing */ 694896831f5SEd Cashin list_move_tail(pos, &flist); 695896831f5SEd Cashin } 696896831f5SEd Cashin } 69769cf2d85SEd Cashin 698896831f5SEd Cashin /* process expired frames */ 699896831f5SEd Cashin while (!list_empty(&flist)) { 700896831f5SEd Cashin pos = flist.next; 701896831f5SEd Cashin f = list_entry(pos, struct frame, head); 7023fc9b032SEd Cashin since = tsince_hr(f); 7033fc9b032SEd Cashin n = f->waited_total + since; 7045f0c9c48SEd Cashin n /= USEC_PER_SEC; 70568e0d42fSEd L. Cashin if (n > aoe_deadsecs) { 706896831f5SEd Cashin /* Waited too long. Device failure. 707896831f5SEd Cashin * Hang all frames on first hash bucket for downdev 708896831f5SEd Cashin * to clean up. 709896831f5SEd Cashin */ 71064a80f5aSEd Cashin list_splice(&flist, &d->factive[0]); 7111da177e4SLinus Torvalds aoedev_downdev(d); 7123a0c40d2SEd Cashin goto out; 7131da177e4SLinus Torvalds } 71468e0d42fSEd L. Cashin 715896831f5SEd Cashin t = f->t; 716d54d35acSEd Cashin if (n > aoe_deadsecs/2) 717d54d35acSEd Cashin d->htgt = t; /* see if another target can help */ 718d54d35acSEd Cashin 7193a0c40d2SEd Cashin if (t->maxout != 1) { 7203a0c40d2SEd Cashin t->ssthresh = t->maxout / 2; 7213a0c40d2SEd Cashin t->maxout = 1; 72268e0d42fSEd L. Cashin } 72368e0d42fSEd L. Cashin 72468e0d42fSEd L. Cashin ifp = getif(t, f->skb->dev); 72568e0d42fSEd L. Cashin if (ifp && ++ifp->lost > (t->nframes << 1) 72668e0d42fSEd L. Cashin && (ifp != t->ifs || t->ifs[1].nd)) { 72768e0d42fSEd L. Cashin ejectif(t, ifp); 72868e0d42fSEd L. Cashin ifp = NULL; 72968e0d42fSEd L. Cashin } 7303a0c40d2SEd Cashin list_move_tail(pos, &d->rexmitq); 7313a0c40d2SEd Cashin t->nout--; 7321da177e4SLinus Torvalds } 7333a0c40d2SEd Cashin rexmit_deferred(d); 73468e0d42fSEd L. Cashin 7353a0c40d2SEd Cashin out: 73669cf2d85SEd Cashin if ((d->flags & DEVFL_KICKME || d->htgt) && d->blkq) { 7374f51dc5eSEd L. Cashin d->flags &= ~DEVFL_KICKME; 73869cf2d85SEd Cashin d->blkq->request_fn(d->blkq); 7394f51dc5eSEd L. Cashin } 7401da177e4SLinus Torvalds 7411da177e4SLinus Torvalds d->timer.expires = jiffies + TIMERTICK; 7421da177e4SLinus Torvalds add_timer(&d->timer); 7431da177e4SLinus Torvalds 7441da177e4SLinus Torvalds spin_unlock_irqrestore(&d->lock, flags); 74569cf2d85SEd Cashin } 7461da177e4SLinus Torvalds 74769cf2d85SEd Cashin static unsigned long 74869cf2d85SEd Cashin rqbiocnt(struct request *r) 74969cf2d85SEd Cashin { 75069cf2d85SEd Cashin struct bio *bio; 75169cf2d85SEd Cashin unsigned long n = 0; 75269cf2d85SEd Cashin 75369cf2d85SEd Cashin __rq_for_each_bio(bio, r) 75469cf2d85SEd Cashin n++; 75569cf2d85SEd Cashin return n; 75669cf2d85SEd Cashin } 75769cf2d85SEd Cashin 75869cf2d85SEd Cashin /* This can be removed if we are certain that no users of the block 75969cf2d85SEd Cashin * layer will ever use zero-count pages in bios. Otherwise we have to 76069cf2d85SEd Cashin * protect against the put_page sometimes done by the network layer. 76169cf2d85SEd Cashin * 76269cf2d85SEd Cashin * See http://oss.sgi.com/archives/xfs/2007-01/msg00594.html for 76369cf2d85SEd Cashin * discussion. 76469cf2d85SEd Cashin * 76569cf2d85SEd Cashin * We cannot use get_page in the workaround, because it insists on a 76669cf2d85SEd Cashin * positive page count as a precondition. So we use _count directly. 76769cf2d85SEd Cashin */ 76869cf2d85SEd Cashin static void 76969cf2d85SEd Cashin bio_pageinc(struct bio *bio) 77069cf2d85SEd Cashin { 77169cf2d85SEd Cashin struct bio_vec *bv; 77269cf2d85SEd Cashin struct page *page; 77369cf2d85SEd Cashin int i; 77469cf2d85SEd Cashin 77569cf2d85SEd Cashin bio_for_each_segment(bv, bio, i) { 77669cf2d85SEd Cashin page = bv->bv_page; 77769cf2d85SEd Cashin /* Non-zero page count for non-head members of 77869cf2d85SEd Cashin * compound pages is no longer allowed by the kernel, 77969cf2d85SEd Cashin * but this has never been seen here. 78069cf2d85SEd Cashin */ 78169cf2d85SEd Cashin if (unlikely(PageCompound(page))) 78269cf2d85SEd Cashin if (compound_trans_head(page) != page) { 78369cf2d85SEd Cashin pr_crit("page tail used for block I/O\n"); 78469cf2d85SEd Cashin BUG(); 78569cf2d85SEd Cashin } 78669cf2d85SEd Cashin atomic_inc(&page->_count); 78769cf2d85SEd Cashin } 78869cf2d85SEd Cashin } 78969cf2d85SEd Cashin 79069cf2d85SEd Cashin static void 79169cf2d85SEd Cashin bio_pagedec(struct bio *bio) 79269cf2d85SEd Cashin { 79369cf2d85SEd Cashin struct bio_vec *bv; 79469cf2d85SEd Cashin int i; 79569cf2d85SEd Cashin 79669cf2d85SEd Cashin bio_for_each_segment(bv, bio, i) 79769cf2d85SEd Cashin atomic_dec(&bv->bv_page->_count); 79869cf2d85SEd Cashin } 79969cf2d85SEd Cashin 80069cf2d85SEd Cashin static void 80169cf2d85SEd Cashin bufinit(struct buf *buf, struct request *rq, struct bio *bio) 80269cf2d85SEd Cashin { 80369cf2d85SEd Cashin struct bio_vec *bv; 80469cf2d85SEd Cashin 80569cf2d85SEd Cashin memset(buf, 0, sizeof(*buf)); 80669cf2d85SEd Cashin buf->rq = rq; 80769cf2d85SEd Cashin buf->bio = bio; 80869cf2d85SEd Cashin buf->resid = bio->bi_size; 80969cf2d85SEd Cashin buf->sector = bio->bi_sector; 81069cf2d85SEd Cashin bio_pageinc(bio); 81169cf2d85SEd Cashin buf->bv = bv = &bio->bi_io_vec[bio->bi_idx]; 81269cf2d85SEd Cashin buf->bv_resid = bv->bv_len; 81369cf2d85SEd Cashin WARN_ON(buf->bv_resid == 0); 81469cf2d85SEd Cashin } 81569cf2d85SEd Cashin 81669cf2d85SEd Cashin static struct buf * 81769cf2d85SEd Cashin nextbuf(struct aoedev *d) 81869cf2d85SEd Cashin { 81969cf2d85SEd Cashin struct request *rq; 82069cf2d85SEd Cashin struct request_queue *q; 82169cf2d85SEd Cashin struct buf *buf; 82269cf2d85SEd Cashin struct bio *bio; 82369cf2d85SEd Cashin 82469cf2d85SEd Cashin q = d->blkq; 82569cf2d85SEd Cashin if (q == NULL) 82669cf2d85SEd Cashin return NULL; /* initializing */ 82769cf2d85SEd Cashin if (d->ip.buf) 82869cf2d85SEd Cashin return d->ip.buf; 82969cf2d85SEd Cashin rq = d->ip.rq; 83069cf2d85SEd Cashin if (rq == NULL) { 83169cf2d85SEd Cashin rq = blk_peek_request(q); 83269cf2d85SEd Cashin if (rq == NULL) 83369cf2d85SEd Cashin return NULL; 83469cf2d85SEd Cashin blk_start_request(rq); 83569cf2d85SEd Cashin d->ip.rq = rq; 83669cf2d85SEd Cashin d->ip.nxbio = rq->bio; 83769cf2d85SEd Cashin rq->special = (void *) rqbiocnt(rq); 83869cf2d85SEd Cashin } 83969cf2d85SEd Cashin buf = mempool_alloc(d->bufpool, GFP_ATOMIC); 84069cf2d85SEd Cashin if (buf == NULL) { 84169cf2d85SEd Cashin pr_err("aoe: nextbuf: unable to mempool_alloc!\n"); 84269cf2d85SEd Cashin return NULL; 84369cf2d85SEd Cashin } 84469cf2d85SEd Cashin bio = d->ip.nxbio; 84569cf2d85SEd Cashin bufinit(buf, rq, bio); 84669cf2d85SEd Cashin bio = bio->bi_next; 84769cf2d85SEd Cashin d->ip.nxbio = bio; 84869cf2d85SEd Cashin if (bio == NULL) 84969cf2d85SEd Cashin d->ip.rq = NULL; 85069cf2d85SEd Cashin return d->ip.buf = buf; 8511da177e4SLinus Torvalds } 8521da177e4SLinus Torvalds 85368e0d42fSEd L. Cashin /* enters with d->lock held */ 85468e0d42fSEd L. Cashin void 85568e0d42fSEd L. Cashin aoecmd_work(struct aoedev *d) 85668e0d42fSEd L. Cashin { 85768e0d42fSEd L. Cashin if (d->htgt && !sthtith(d)) 85868e0d42fSEd L. Cashin return; 8593a0c40d2SEd Cashin rexmit_deferred(d); 86069cf2d85SEd Cashin while (aoecmd_ata_rw(d)) 86169cf2d85SEd Cashin ; 86268e0d42fSEd L. Cashin } 86368e0d42fSEd L. Cashin 8643ae1c24eSEd L. Cashin /* this function performs work that has been deferred until sleeping is OK 8653ae1c24eSEd L. Cashin */ 8663ae1c24eSEd L. Cashin void 867c4028958SDavid Howells aoecmd_sleepwork(struct work_struct *work) 8683ae1c24eSEd L. Cashin { 869c4028958SDavid Howells struct aoedev *d = container_of(work, struct aoedev, work); 870b21faa25SEd Cashin struct block_device *bd; 871b21faa25SEd Cashin u64 ssize; 8723ae1c24eSEd L. Cashin 8733ae1c24eSEd L. Cashin if (d->flags & DEVFL_GDALLOC) 8743ae1c24eSEd L. Cashin aoeblk_gdalloc(d); 8753ae1c24eSEd L. Cashin 8763ae1c24eSEd L. Cashin if (d->flags & DEVFL_NEWSIZE) { 87780795aefSTejun Heo ssize = get_capacity(d->gd); 8783ae1c24eSEd L. Cashin bd = bdget_disk(d->gd, 0); 8793ae1c24eSEd L. Cashin if (bd) { 8803ae1c24eSEd L. Cashin mutex_lock(&bd->bd_inode->i_mutex); 8813ae1c24eSEd L. Cashin i_size_write(bd->bd_inode, (loff_t)ssize<<9); 8823ae1c24eSEd L. Cashin mutex_unlock(&bd->bd_inode->i_mutex); 8833ae1c24eSEd L. Cashin bdput(bd); 8843ae1c24eSEd L. Cashin } 885b21faa25SEd Cashin spin_lock_irq(&d->lock); 8863ae1c24eSEd L. Cashin d->flags |= DEVFL_UP; 8873ae1c24eSEd L. Cashin d->flags &= ~DEVFL_NEWSIZE; 888b21faa25SEd Cashin spin_unlock_irq(&d->lock); 8893ae1c24eSEd L. Cashin } 8903ae1c24eSEd L. Cashin } 8913ae1c24eSEd L. Cashin 8921da177e4SLinus Torvalds static void 893667be1e7SEd Cashin ata_ident_fixstring(u16 *id, int ns) 894667be1e7SEd Cashin { 895667be1e7SEd Cashin u16 s; 896667be1e7SEd Cashin 897667be1e7SEd Cashin while (ns-- > 0) { 898667be1e7SEd Cashin s = *id; 899667be1e7SEd Cashin *id++ = s >> 8 | s << 8; 900667be1e7SEd Cashin } 901667be1e7SEd Cashin } 902667be1e7SEd Cashin 903667be1e7SEd Cashin static void 90468e0d42fSEd L. Cashin ataid_complete(struct aoedev *d, struct aoetgt *t, unsigned char *id) 9051da177e4SLinus Torvalds { 9061da177e4SLinus Torvalds u64 ssize; 9071da177e4SLinus Torvalds u16 n; 9081da177e4SLinus Torvalds 9091da177e4SLinus Torvalds /* word 83: command set supported */ 910f885f8d1SHarvey Harrison n = get_unaligned_le16(&id[83 << 1]); 9111da177e4SLinus Torvalds 9121da177e4SLinus Torvalds /* word 86: command set/feature enabled */ 913f885f8d1SHarvey Harrison n |= get_unaligned_le16(&id[86 << 1]); 9141da177e4SLinus Torvalds 9151da177e4SLinus Torvalds if (n & (1<<10)) { /* bit 10: LBA 48 */ 9161da177e4SLinus Torvalds d->flags |= DEVFL_EXT; 9171da177e4SLinus Torvalds 9181da177e4SLinus Torvalds /* word 100: number lba48 sectors */ 919f885f8d1SHarvey Harrison ssize = get_unaligned_le64(&id[100 << 1]); 9201da177e4SLinus Torvalds 9211da177e4SLinus Torvalds /* set as in ide-disk.c:init_idedisk_capacity */ 9221da177e4SLinus Torvalds d->geo.cylinders = ssize; 9231da177e4SLinus Torvalds d->geo.cylinders /= (255 * 63); 9241da177e4SLinus Torvalds d->geo.heads = 255; 9251da177e4SLinus Torvalds d->geo.sectors = 63; 9261da177e4SLinus Torvalds } else { 9271da177e4SLinus Torvalds d->flags &= ~DEVFL_EXT; 9281da177e4SLinus Torvalds 9291da177e4SLinus Torvalds /* number lba28 sectors */ 930f885f8d1SHarvey Harrison ssize = get_unaligned_le32(&id[60 << 1]); 9311da177e4SLinus Torvalds 9321da177e4SLinus Torvalds /* NOTE: obsolete in ATA 6 */ 933f885f8d1SHarvey Harrison d->geo.cylinders = get_unaligned_le16(&id[54 << 1]); 934f885f8d1SHarvey Harrison d->geo.heads = get_unaligned_le16(&id[55 << 1]); 935f885f8d1SHarvey Harrison d->geo.sectors = get_unaligned_le16(&id[56 << 1]); 9361da177e4SLinus Torvalds } 9373ae1c24eSEd L. Cashin 938667be1e7SEd Cashin ata_ident_fixstring((u16 *) &id[10<<1], 10); /* serial */ 939667be1e7SEd Cashin ata_ident_fixstring((u16 *) &id[23<<1], 4); /* firmware */ 940667be1e7SEd Cashin ata_ident_fixstring((u16 *) &id[27<<1], 20); /* model */ 941667be1e7SEd Cashin memcpy(d->ident, id, sizeof(d->ident)); 942667be1e7SEd Cashin 9433ae1c24eSEd L. Cashin if (d->ssize != ssize) 9441d75981aSEd L. Cashin printk(KERN_INFO 945411c41eeSHarvey Harrison "aoe: %pm e%ld.%d v%04x has %llu sectors\n", 946411c41eeSHarvey Harrison t->addr, 9473ae1c24eSEd L. Cashin d->aoemajor, d->aoeminor, 9483ae1c24eSEd L. Cashin d->fw_ver, (long long)ssize); 9491da177e4SLinus Torvalds d->ssize = ssize; 9501da177e4SLinus Torvalds d->geo.start = 0; 9516b9699bbSEd L. Cashin if (d->flags & (DEVFL_GDALLOC|DEVFL_NEWSIZE)) 9526b9699bbSEd L. Cashin return; 9531da177e4SLinus Torvalds if (d->gd != NULL) { 95480795aefSTejun Heo set_capacity(d->gd, ssize); 9553ae1c24eSEd L. Cashin d->flags |= DEVFL_NEWSIZE; 95668e0d42fSEd L. Cashin } else 9573ae1c24eSEd L. Cashin d->flags |= DEVFL_GDALLOC; 9581da177e4SLinus Torvalds schedule_work(&d->work); 9591da177e4SLinus Torvalds } 9601da177e4SLinus Torvalds 9611da177e4SLinus Torvalds static void 9623a0c40d2SEd Cashin calc_rttavg(struct aoedev *d, struct aoetgt *t, int rtt) 9631da177e4SLinus Torvalds { 9641da177e4SLinus Torvalds register long n; 9651da177e4SLinus Torvalds 9661da177e4SLinus Torvalds n = rtt; 9671da177e4SLinus Torvalds 9683a0c40d2SEd Cashin /* cf. Congestion Avoidance and Control, Jacobson & Karels, 1988 */ 9693a0c40d2SEd Cashin n -= d->rttavg >> RTTSCALE; 9703a0c40d2SEd Cashin d->rttavg += n; 9713a0c40d2SEd Cashin if (n < 0) 9723a0c40d2SEd Cashin n = -n; 9733a0c40d2SEd Cashin n -= d->rttdev >> RTTDSCALE; 9743a0c40d2SEd Cashin d->rttdev += n; 9753a0c40d2SEd Cashin 9763a0c40d2SEd Cashin if (!t || t->maxout >= t->nframes) 9773a0c40d2SEd Cashin return; 9783a0c40d2SEd Cashin if (t->maxout < t->ssthresh) 9793a0c40d2SEd Cashin t->maxout += 1; 9803a0c40d2SEd Cashin else if (t->nout == t->maxout && t->next_cwnd-- == 0) { 9813a0c40d2SEd Cashin t->maxout += 1; 9823a0c40d2SEd Cashin t->next_cwnd = t->maxout; 9833a0c40d2SEd Cashin } 9841da177e4SLinus Torvalds } 9851da177e4SLinus Torvalds 98668e0d42fSEd L. Cashin static struct aoetgt * 98768e0d42fSEd L. Cashin gettgt(struct aoedev *d, char *addr) 98868e0d42fSEd L. Cashin { 98968e0d42fSEd L. Cashin struct aoetgt **t, **e; 99068e0d42fSEd L. Cashin 99168e0d42fSEd L. Cashin t = d->targets; 99268e0d42fSEd L. Cashin e = t + NTARGETS; 99368e0d42fSEd L. Cashin for (; t < e && *t; t++) 99468e0d42fSEd L. Cashin if (memcmp((*t)->addr, addr, sizeof((*t)->addr)) == 0) 99568e0d42fSEd L. Cashin return *t; 99668e0d42fSEd L. Cashin return NULL; 99768e0d42fSEd L. Cashin } 99868e0d42fSEd L. Cashin 9993d5b0605SEd Cashin static void 1000896831f5SEd Cashin bvcpy(struct bio_vec *bv, ulong off, struct sk_buff *skb, long cnt) 10013d5b0605SEd Cashin { 10023d5b0605SEd Cashin ulong fcnt; 10033d5b0605SEd Cashin char *p; 10043d5b0605SEd Cashin int soff = 0; 10053d5b0605SEd Cashin loop: 10063d5b0605SEd Cashin fcnt = bv->bv_len - (off - bv->bv_offset); 10073d5b0605SEd Cashin if (fcnt > cnt) 10083d5b0605SEd Cashin fcnt = cnt; 10093d5b0605SEd Cashin p = page_address(bv->bv_page) + off; 10103d5b0605SEd Cashin skb_copy_bits(skb, soff, p, fcnt); 10113d5b0605SEd Cashin soff += fcnt; 10123d5b0605SEd Cashin cnt -= fcnt; 10133d5b0605SEd Cashin if (cnt <= 0) 10143d5b0605SEd Cashin return; 10153d5b0605SEd Cashin bv++; 10163d5b0605SEd Cashin off = bv->bv_offset; 10173d5b0605SEd Cashin goto loop; 10183d5b0605SEd Cashin } 10193d5b0605SEd Cashin 102069cf2d85SEd Cashin void 102169cf2d85SEd Cashin aoe_end_request(struct aoedev *d, struct request *rq, int fastfail) 102269cf2d85SEd Cashin { 102369cf2d85SEd Cashin struct bio *bio; 102469cf2d85SEd Cashin int bok; 102569cf2d85SEd Cashin struct request_queue *q; 102669cf2d85SEd Cashin 102769cf2d85SEd Cashin q = d->blkq; 102869cf2d85SEd Cashin if (rq == d->ip.rq) 102969cf2d85SEd Cashin d->ip.rq = NULL; 103069cf2d85SEd Cashin do { 103169cf2d85SEd Cashin bio = rq->bio; 103269cf2d85SEd Cashin bok = !fastfail && test_bit(BIO_UPTODATE, &bio->bi_flags); 103369cf2d85SEd Cashin } while (__blk_end_request(rq, bok ? 0 : -EIO, bio->bi_size)); 103469cf2d85SEd Cashin 103569cf2d85SEd Cashin /* cf. http://lkml.org/lkml/2006/10/31/28 */ 103669cf2d85SEd Cashin if (!fastfail) 103711cfb6ffSEd Cashin __blk_run_queue(q); 103869cf2d85SEd Cashin } 103969cf2d85SEd Cashin 104069cf2d85SEd Cashin static void 104169cf2d85SEd Cashin aoe_end_buf(struct aoedev *d, struct buf *buf) 104269cf2d85SEd Cashin { 104369cf2d85SEd Cashin struct request *rq; 104469cf2d85SEd Cashin unsigned long n; 104569cf2d85SEd Cashin 104669cf2d85SEd Cashin if (buf == d->ip.buf) 104769cf2d85SEd Cashin d->ip.buf = NULL; 104869cf2d85SEd Cashin rq = buf->rq; 104969cf2d85SEd Cashin bio_pagedec(buf->bio); 105069cf2d85SEd Cashin mempool_free(buf, d->bufpool); 105169cf2d85SEd Cashin n = (unsigned long) rq->special; 105269cf2d85SEd Cashin rq->special = (void *) --n; 105369cf2d85SEd Cashin if (n == 0) 105469cf2d85SEd Cashin aoe_end_request(d, rq, 0); 105569cf2d85SEd Cashin } 105669cf2d85SEd Cashin 10573d5b0605SEd Cashin static void 1058896831f5SEd Cashin ktiocomplete(struct frame *f) 10593d5b0605SEd Cashin { 1060ddec63e8SEd L. Cashin struct aoe_hdr *hin, *hout; 10611da177e4SLinus Torvalds struct aoe_atahdr *ahin, *ahout; 10621da177e4SLinus Torvalds struct buf *buf; 1063896831f5SEd Cashin struct sk_buff *skb; 106468e0d42fSEd L. Cashin struct aoetgt *t; 106568e0d42fSEd L. Cashin struct aoeif *ifp; 1066896831f5SEd Cashin struct aoedev *d; 1067896831f5SEd Cashin long n; 1068896831f5SEd Cashin 1069896831f5SEd Cashin if (f == NULL) 1070896831f5SEd Cashin return; 1071896831f5SEd Cashin 1072896831f5SEd Cashin t = f->t; 1073896831f5SEd Cashin d = t->d; 1074896831f5SEd Cashin 1075896831f5SEd Cashin hout = (struct aoe_hdr *) skb_mac_header(f->skb); 1076896831f5SEd Cashin ahout = (struct aoe_atahdr *) (hout+1); 1077896831f5SEd Cashin buf = f->buf; 1078896831f5SEd Cashin skb = f->r_skb; 1079896831f5SEd Cashin if (skb == NULL) 1080896831f5SEd Cashin goto noskb; /* just fail the buf. */ 1081896831f5SEd Cashin 1082896831f5SEd Cashin hin = (struct aoe_hdr *) skb->data; 1083896831f5SEd Cashin skb_pull(skb, sizeof(*hin)); 1084896831f5SEd Cashin ahin = (struct aoe_atahdr *) skb->data; 1085896831f5SEd Cashin skb_pull(skb, sizeof(*ahin)); 1086896831f5SEd Cashin if (ahin->cmdstat & 0xa9) { /* these bits cleared on success */ 1087896831f5SEd Cashin pr_err("aoe: ata error cmd=%2.2Xh stat=%2.2Xh from e%ld.%d\n", 1088896831f5SEd Cashin ahout->cmdstat, ahin->cmdstat, 1089896831f5SEd Cashin d->aoemajor, d->aoeminor); 1090896831f5SEd Cashin noskb: if (buf) 109169cf2d85SEd Cashin clear_bit(BIO_UPTODATE, &buf->bio->bi_flags); 1092896831f5SEd Cashin goto badrsp; 1093896831f5SEd Cashin } 1094896831f5SEd Cashin 1095896831f5SEd Cashin n = ahout->scnt << 9; 1096896831f5SEd Cashin switch (ahout->cmdstat) { 1097896831f5SEd Cashin case ATA_CMD_PIO_READ: 1098896831f5SEd Cashin case ATA_CMD_PIO_READ_EXT: 1099896831f5SEd Cashin if (skb->len < n) { 1100896831f5SEd Cashin pr_err("aoe: runt data size in read. skb->len=%d need=%ld\n", 1101896831f5SEd Cashin skb->len, n); 110269cf2d85SEd Cashin clear_bit(BIO_UPTODATE, &buf->bio->bi_flags); 1103896831f5SEd Cashin break; 1104896831f5SEd Cashin } 1105896831f5SEd Cashin bvcpy(f->bv, f->bv_off, skb, n); 1106896831f5SEd Cashin case ATA_CMD_PIO_WRITE: 1107896831f5SEd Cashin case ATA_CMD_PIO_WRITE_EXT: 1108896831f5SEd Cashin spin_lock_irq(&d->lock); 1109896831f5SEd Cashin ifp = getif(t, skb->dev); 11103f0f0133SEd Cashin if (ifp) 1111896831f5SEd Cashin ifp->lost = 0; 1112896831f5SEd Cashin if (d->htgt == t) /* I'll help myself, thank you. */ 1113896831f5SEd Cashin d->htgt = NULL; 1114896831f5SEd Cashin spin_unlock_irq(&d->lock); 1115896831f5SEd Cashin break; 1116896831f5SEd Cashin case ATA_CMD_ID_ATA: 1117896831f5SEd Cashin if (skb->len < 512) { 1118896831f5SEd Cashin pr_info("aoe: runt data size in ataid. skb->len=%d\n", 1119896831f5SEd Cashin skb->len); 1120896831f5SEd Cashin break; 1121896831f5SEd Cashin } 1122896831f5SEd Cashin if (skb_linearize(skb)) 1123896831f5SEd Cashin break; 1124896831f5SEd Cashin spin_lock_irq(&d->lock); 1125896831f5SEd Cashin ataid_complete(d, t, skb->data); 1126896831f5SEd Cashin spin_unlock_irq(&d->lock); 1127896831f5SEd Cashin break; 1128896831f5SEd Cashin default: 1129896831f5SEd Cashin pr_info("aoe: unrecognized ata command %2.2Xh for %d.%d\n", 1130896831f5SEd Cashin ahout->cmdstat, 1131896831f5SEd Cashin be16_to_cpu(get_unaligned(&hin->major)), 1132896831f5SEd Cashin hin->minor); 1133896831f5SEd Cashin } 1134896831f5SEd Cashin badrsp: 1135896831f5SEd Cashin spin_lock_irq(&d->lock); 1136896831f5SEd Cashin 1137896831f5SEd Cashin aoe_freetframe(f); 1138896831f5SEd Cashin 113969cf2d85SEd Cashin if (buf && --buf->nframesout == 0 && buf->resid == 0) 114069cf2d85SEd Cashin aoe_end_buf(d, buf); 1141896831f5SEd Cashin 114269cf2d85SEd Cashin aoecmd_work(d); 114369cf2d85SEd Cashin 1144896831f5SEd Cashin spin_unlock_irq(&d->lock); 114569cf2d85SEd Cashin aoedev_put(d); 1146896831f5SEd Cashin dev_kfree_skb(skb); 1147896831f5SEd Cashin } 1148896831f5SEd Cashin 1149896831f5SEd Cashin /* Enters with iocq.lock held. 1150896831f5SEd Cashin * Returns true iff responses needing processing remain. 1151896831f5SEd Cashin */ 1152896831f5SEd Cashin static int 1153896831f5SEd Cashin ktio(void) 1154896831f5SEd Cashin { 1155896831f5SEd Cashin struct frame *f; 1156896831f5SEd Cashin struct list_head *pos; 1157896831f5SEd Cashin int i; 1158896831f5SEd Cashin 1159896831f5SEd Cashin for (i = 0; ; ++i) { 1160896831f5SEd Cashin if (i == MAXIOC) 1161896831f5SEd Cashin return 1; 1162896831f5SEd Cashin if (list_empty(&iocq.head)) 1163896831f5SEd Cashin return 0; 1164896831f5SEd Cashin pos = iocq.head.next; 1165896831f5SEd Cashin list_del(pos); 1166896831f5SEd Cashin spin_unlock_irq(&iocq.lock); 1167896831f5SEd Cashin f = list_entry(pos, struct frame, head); 1168896831f5SEd Cashin ktiocomplete(f); 1169896831f5SEd Cashin spin_lock_irq(&iocq.lock); 1170896831f5SEd Cashin } 1171896831f5SEd Cashin } 1172896831f5SEd Cashin 1173896831f5SEd Cashin static int 1174896831f5SEd Cashin kthread(void *vp) 1175896831f5SEd Cashin { 1176896831f5SEd Cashin struct ktstate *k; 1177896831f5SEd Cashin DECLARE_WAITQUEUE(wait, current); 1178896831f5SEd Cashin int more; 1179896831f5SEd Cashin 1180896831f5SEd Cashin k = vp; 1181896831f5SEd Cashin current->flags |= PF_NOFREEZE; 1182896831f5SEd Cashin set_user_nice(current, -10); 1183896831f5SEd Cashin complete(&k->rendez); /* tell spawner we're running */ 1184896831f5SEd Cashin do { 1185896831f5SEd Cashin spin_lock_irq(k->lock); 1186896831f5SEd Cashin more = k->fn(); 1187896831f5SEd Cashin if (!more) { 1188896831f5SEd Cashin add_wait_queue(k->waitq, &wait); 1189896831f5SEd Cashin __set_current_state(TASK_INTERRUPTIBLE); 1190896831f5SEd Cashin } 1191896831f5SEd Cashin spin_unlock_irq(k->lock); 1192896831f5SEd Cashin if (!more) { 1193896831f5SEd Cashin schedule(); 1194896831f5SEd Cashin remove_wait_queue(k->waitq, &wait); 1195896831f5SEd Cashin } else 1196896831f5SEd Cashin cond_resched(); 1197896831f5SEd Cashin } while (!kthread_should_stop()); 1198896831f5SEd Cashin complete(&k->rendez); /* tell spawner we're stopping */ 1199896831f5SEd Cashin return 0; 1200896831f5SEd Cashin } 1201896831f5SEd Cashin 1202eb086ec5SEd Cashin void 1203896831f5SEd Cashin aoe_ktstop(struct ktstate *k) 1204896831f5SEd Cashin { 1205896831f5SEd Cashin kthread_stop(k->task); 1206896831f5SEd Cashin wait_for_completion(&k->rendez); 1207896831f5SEd Cashin } 1208896831f5SEd Cashin 1209eb086ec5SEd Cashin int 1210896831f5SEd Cashin aoe_ktstart(struct ktstate *k) 1211896831f5SEd Cashin { 1212896831f5SEd Cashin struct task_struct *task; 1213896831f5SEd Cashin 1214896831f5SEd Cashin init_completion(&k->rendez); 1215896831f5SEd Cashin task = kthread_run(kthread, k, k->name); 1216896831f5SEd Cashin if (task == NULL || IS_ERR(task)) 1217896831f5SEd Cashin return -ENOMEM; 1218896831f5SEd Cashin k->task = task; 1219896831f5SEd Cashin wait_for_completion(&k->rendez); /* allow kthread to start */ 1220896831f5SEd Cashin init_completion(&k->rendez); /* for waiting for exit later */ 1221896831f5SEd Cashin return 0; 1222896831f5SEd Cashin } 1223896831f5SEd Cashin 1224896831f5SEd Cashin /* pass it off to kthreads for processing */ 1225896831f5SEd Cashin static void 1226896831f5SEd Cashin ktcomplete(struct frame *f, struct sk_buff *skb) 1227896831f5SEd Cashin { 1228896831f5SEd Cashin ulong flags; 1229896831f5SEd Cashin 1230896831f5SEd Cashin f->r_skb = skb; 1231896831f5SEd Cashin spin_lock_irqsave(&iocq.lock, flags); 1232896831f5SEd Cashin list_add_tail(&f->head, &iocq.head); 1233896831f5SEd Cashin spin_unlock_irqrestore(&iocq.lock, flags); 1234896831f5SEd Cashin wake_up(&ktiowq); 1235896831f5SEd Cashin } 1236896831f5SEd Cashin 1237896831f5SEd Cashin struct sk_buff * 1238896831f5SEd Cashin aoecmd_ata_rsp(struct sk_buff *skb) 1239896831f5SEd Cashin { 1240896831f5SEd Cashin struct aoedev *d; 1241896831f5SEd Cashin struct aoe_hdr *h; 1242896831f5SEd Cashin struct frame *f; 1243896831f5SEd Cashin u32 n; 12441da177e4SLinus Torvalds ulong flags; 12451da177e4SLinus Torvalds char ebuf[128]; 124632465c65Secashin@coraid.com u16 aoemajor; 12471da177e4SLinus Torvalds 1248896831f5SEd Cashin h = (struct aoe_hdr *) skb->data; 1249896831f5SEd Cashin aoemajor = be16_to_cpu(get_unaligned(&h->major)); 12500c966214SEd Cashin d = aoedev_by_aoeaddr(aoemajor, h->minor, 0); 12511da177e4SLinus Torvalds if (d == NULL) { 12521da177e4SLinus Torvalds snprintf(ebuf, sizeof ebuf, "aoecmd_ata_rsp: ata response " 12531da177e4SLinus Torvalds "for unknown device %d.%d\n", 1254896831f5SEd Cashin aoemajor, h->minor); 12551da177e4SLinus Torvalds aoechr_error(ebuf); 1256896831f5SEd Cashin return skb; 12571da177e4SLinus Torvalds } 12581da177e4SLinus Torvalds 12591da177e4SLinus Torvalds spin_lock_irqsave(&d->lock, flags); 12601da177e4SLinus Torvalds 1261896831f5SEd Cashin n = be32_to_cpu(get_unaligned(&h->tag)); 126264a80f5aSEd Cashin f = getframe(d, n); 12633a0c40d2SEd Cashin if (f) { 12645f0c9c48SEd Cashin calc_rttavg(d, f->t, tsince_hr(f)); 12653a0c40d2SEd Cashin f->t->nout--; 12663a0c40d2SEd Cashin } else { 12673a0c40d2SEd Cashin f = getframe_deferred(d, n); 12683a0c40d2SEd Cashin if (f) { 12695f0c9c48SEd Cashin calc_rttavg(d, NULL, tsince_hr(f)); 12703a0c40d2SEd Cashin } else { 12713a0c40d2SEd Cashin calc_rttavg(d, NULL, tsince(n)); 12721da177e4SLinus Torvalds spin_unlock_irqrestore(&d->lock, flags); 127369cf2d85SEd Cashin aoedev_put(d); 12743a0c40d2SEd Cashin snprintf(ebuf, sizeof(ebuf), 12752292a7e1SEd Cashin "%15s e%d.%d tag=%08x@%08lx s=%pm d=%pm\n", 12761da177e4SLinus Torvalds "unexpected rsp", 1277896831f5SEd Cashin get_unaligned_be16(&h->major), 1278896831f5SEd Cashin h->minor, 1279896831f5SEd Cashin get_unaligned_be32(&h->tag), 12802292a7e1SEd Cashin jiffies, 12812292a7e1SEd Cashin h->src, 12822292a7e1SEd Cashin h->dst); 12831da177e4SLinus Torvalds aoechr_error(ebuf); 1284896831f5SEd Cashin return skb; 12851da177e4SLinus Torvalds } 12863a0c40d2SEd Cashin } 12871da177e4SLinus Torvalds aoecmd_work(d); 12881da177e4SLinus Torvalds 12891da177e4SLinus Torvalds spin_unlock_irqrestore(&d->lock, flags); 1290896831f5SEd Cashin 1291896831f5SEd Cashin ktcomplete(f, skb); 1292896831f5SEd Cashin 1293896831f5SEd Cashin /* 1294896831f5SEd Cashin * Note here that we do not perform an aoedev_put, as we are 1295896831f5SEd Cashin * leaving this reference for the ktio to release. 1296896831f5SEd Cashin */ 1297896831f5SEd Cashin return NULL; 12981da177e4SLinus Torvalds } 12991da177e4SLinus Torvalds 13001da177e4SLinus Torvalds void 13011da177e4SLinus Torvalds aoecmd_cfg(ushort aoemajor, unsigned char aoeminor) 13021da177e4SLinus Torvalds { 1303e9bb8fb0SDavid S. Miller struct sk_buff_head queue; 13041da177e4SLinus Torvalds 1305e9bb8fb0SDavid S. Miller __skb_queue_head_init(&queue); 1306e9bb8fb0SDavid S. Miller aoecmd_cfg_pkts(aoemajor, aoeminor, &queue); 1307e9bb8fb0SDavid S. Miller aoenet_xmit(&queue); 13081da177e4SLinus Torvalds } 13091da177e4SLinus Torvalds 131068e0d42fSEd L. Cashin struct sk_buff * 13111da177e4SLinus Torvalds aoecmd_ata_id(struct aoedev *d) 13121da177e4SLinus Torvalds { 13131da177e4SLinus Torvalds struct aoe_hdr *h; 13141da177e4SLinus Torvalds struct aoe_atahdr *ah; 13151da177e4SLinus Torvalds struct frame *f; 13161da177e4SLinus Torvalds struct sk_buff *skb; 131768e0d42fSEd L. Cashin struct aoetgt *t; 13181da177e4SLinus Torvalds 1319896831f5SEd Cashin f = newframe(d); 132068e0d42fSEd L. Cashin if (f == NULL) 13211da177e4SLinus Torvalds return NULL; 132268e0d42fSEd L. Cashin 132368e0d42fSEd L. Cashin t = *d->tgt; 13241da177e4SLinus Torvalds 13251da177e4SLinus Torvalds /* initialize the headers & frame */ 1326e407a7f6SEd L. Cashin skb = f->skb; 1327abdbf94dSEd L. Cashin h = (struct aoe_hdr *) skb_mac_header(skb); 13281da177e4SLinus Torvalds ah = (struct aoe_atahdr *) (h+1); 132919900cdeSEd L. Cashin skb_put(skb, sizeof *h + sizeof *ah); 133019900cdeSEd L. Cashin memset(h, 0, skb->len); 133168e0d42fSEd L. Cashin f->tag = aoehdr_atainit(d, t, h); 1332896831f5SEd Cashin fhash(f); 133368e0d42fSEd L. Cashin t->nout++; 13341da177e4SLinus Torvalds f->waited = 0; 13353fc9b032SEd Cashin f->waited_total = 0; 13361da177e4SLinus Torvalds 13371da177e4SLinus Torvalds /* set up ata header */ 13381da177e4SLinus Torvalds ah->scnt = 1; 133904b3ab52SBartlomiej Zolnierkiewicz ah->cmdstat = ATA_CMD_ID_ATA; 13401da177e4SLinus Torvalds ah->lba3 = 0xa0; 13411da177e4SLinus Torvalds 134268e0d42fSEd L. Cashin skb->dev = t->ifp->nd; 13431da177e4SLinus Torvalds 13443a0c40d2SEd Cashin d->rttavg = RTTAVG_INIT; 13453a0c40d2SEd Cashin d->rttdev = RTTDEV_INIT; 13461da177e4SLinus Torvalds d->timer.function = rexmit_timer; 13471da177e4SLinus Torvalds 13485f0c9c48SEd Cashin skb = skb_clone(skb, GFP_ATOMIC); 13495f0c9c48SEd Cashin if (skb) { 13505f0c9c48SEd Cashin do_gettimeofday(&f->sent); 13515f0c9c48SEd Cashin f->sent_jiffs = (u32) jiffies; 13525f0c9c48SEd Cashin } 13535f0c9c48SEd Cashin 13545f0c9c48SEd Cashin return skb; 13551da177e4SLinus Torvalds } 13561da177e4SLinus Torvalds 135768e0d42fSEd L. Cashin static struct aoetgt * 135868e0d42fSEd L. Cashin addtgt(struct aoedev *d, char *addr, ulong nframes) 135968e0d42fSEd L. Cashin { 136068e0d42fSEd L. Cashin struct aoetgt *t, **tt, **te; 136168e0d42fSEd L. Cashin 136268e0d42fSEd L. Cashin tt = d->targets; 136368e0d42fSEd L. Cashin te = tt + NTARGETS; 136468e0d42fSEd L. Cashin for (; tt < te && *tt; tt++) 136568e0d42fSEd L. Cashin ; 136668e0d42fSEd L. Cashin 1367578c4aa0SEd L. Cashin if (tt == te) { 1368578c4aa0SEd L. Cashin printk(KERN_INFO 1369578c4aa0SEd L. Cashin "aoe: device addtgt failure; too many targets\n"); 137068e0d42fSEd L. Cashin return NULL; 1371578c4aa0SEd L. Cashin } 1372896831f5SEd Cashin t = kzalloc(sizeof(*t), GFP_ATOMIC); 1373896831f5SEd Cashin if (!t) { 1374578c4aa0SEd L. Cashin printk(KERN_INFO "aoe: cannot allocate memory to add target\n"); 13759bb237b6SEd L. Cashin return NULL; 13769bb237b6SEd L. Cashin } 13779bb237b6SEd L. Cashin 1378896831f5SEd Cashin d->ntargets++; 137968e0d42fSEd L. Cashin t->nframes = nframes; 1380896831f5SEd Cashin t->d = d; 138168e0d42fSEd L. Cashin memcpy(t->addr, addr, sizeof t->addr); 138268e0d42fSEd L. Cashin t->ifp = t->ifs; 13833a0c40d2SEd Cashin aoecmd_wreset(t); 1384896831f5SEd Cashin INIT_LIST_HEAD(&t->ffree); 138568e0d42fSEd L. Cashin return *tt = t; 138668e0d42fSEd L. Cashin } 138768e0d42fSEd L. Cashin 13883f0f0133SEd Cashin static void 13893f0f0133SEd Cashin setdbcnt(struct aoedev *d) 13903f0f0133SEd Cashin { 13913f0f0133SEd Cashin struct aoetgt **t, **e; 13923f0f0133SEd Cashin int bcnt = 0; 13933f0f0133SEd Cashin 13943f0f0133SEd Cashin t = d->targets; 13953f0f0133SEd Cashin e = t + NTARGETS; 13963f0f0133SEd Cashin for (; t < e && *t; t++) 13973f0f0133SEd Cashin if (bcnt == 0 || bcnt > (*t)->minbcnt) 13983f0f0133SEd Cashin bcnt = (*t)->minbcnt; 13993f0f0133SEd Cashin if (bcnt != d->maxbcnt) { 14003f0f0133SEd Cashin d->maxbcnt = bcnt; 14013f0f0133SEd Cashin pr_info("aoe: e%ld.%d: setting %d byte data frames\n", 14023f0f0133SEd Cashin d->aoemajor, d->aoeminor, bcnt); 14033f0f0133SEd Cashin } 14043f0f0133SEd Cashin } 14053f0f0133SEd Cashin 14063f0f0133SEd Cashin static void 14073f0f0133SEd Cashin setifbcnt(struct aoetgt *t, struct net_device *nd, int bcnt) 14083f0f0133SEd Cashin { 14093f0f0133SEd Cashin struct aoedev *d; 14103f0f0133SEd Cashin struct aoeif *p, *e; 14113f0f0133SEd Cashin int minbcnt; 14123f0f0133SEd Cashin 14133f0f0133SEd Cashin d = t->d; 14143f0f0133SEd Cashin minbcnt = bcnt; 14153f0f0133SEd Cashin p = t->ifs; 14163f0f0133SEd Cashin e = p + NAOEIFS; 14173f0f0133SEd Cashin for (; p < e; p++) { 14183f0f0133SEd Cashin if (p->nd == NULL) 14193f0f0133SEd Cashin break; /* end of the valid interfaces */ 14203f0f0133SEd Cashin if (p->nd == nd) { 14213f0f0133SEd Cashin p->bcnt = bcnt; /* we're updating */ 14223f0f0133SEd Cashin nd = NULL; 14233f0f0133SEd Cashin } else if (minbcnt > p->bcnt) 14243f0f0133SEd Cashin minbcnt = p->bcnt; /* find the min interface */ 14253f0f0133SEd Cashin } 14263f0f0133SEd Cashin if (nd) { 14273f0f0133SEd Cashin if (p == e) { 14283f0f0133SEd Cashin pr_err("aoe: device setifbcnt failure; too many interfaces.\n"); 14293f0f0133SEd Cashin return; 14303f0f0133SEd Cashin } 14311b86fda9SEd Cashin dev_hold(nd); 14323f0f0133SEd Cashin p->nd = nd; 14333f0f0133SEd Cashin p->bcnt = bcnt; 14343f0f0133SEd Cashin } 14353f0f0133SEd Cashin t->minbcnt = minbcnt; 14363f0f0133SEd Cashin setdbcnt(d); 14373f0f0133SEd Cashin } 14383f0f0133SEd Cashin 14391da177e4SLinus Torvalds void 14401da177e4SLinus Torvalds aoecmd_cfg_rsp(struct sk_buff *skb) 14411da177e4SLinus Torvalds { 14421da177e4SLinus Torvalds struct aoedev *d; 14431da177e4SLinus Torvalds struct aoe_hdr *h; 14441da177e4SLinus Torvalds struct aoe_cfghdr *ch; 144568e0d42fSEd L. Cashin struct aoetgt *t; 14460c966214SEd Cashin ulong flags, aoemajor; 14471da177e4SLinus Torvalds struct sk_buff *sl; 144869cf2d85SEd Cashin struct sk_buff_head queue; 144919bf2635SEd L. Cashin u16 n; 14501da177e4SLinus Torvalds 145169cf2d85SEd Cashin sl = NULL; 1452abdbf94dSEd L. Cashin h = (struct aoe_hdr *) skb_mac_header(skb); 14531da177e4SLinus Torvalds ch = (struct aoe_cfghdr *) (h+1); 14541da177e4SLinus Torvalds 14551da177e4SLinus Torvalds /* 14561da177e4SLinus Torvalds * Enough people have their dip switches set backwards to 14571da177e4SLinus Torvalds * warrant a loud message for this special case. 14581da177e4SLinus Torvalds */ 1459823ed72eSHarvey Harrison aoemajor = get_unaligned_be16(&h->major); 14601da177e4SLinus Torvalds if (aoemajor == 0xfff) { 1461a12c93f0SEd L. Cashin printk(KERN_ERR "aoe: Warning: shelf address is all ones. " 14626bb6285fSEd L. Cashin "Check shelf dip switches.\n"); 14631da177e4SLinus Torvalds return; 14641da177e4SLinus Torvalds } 14657159e969SEd Cashin if (aoemajor == 0xffff) { 14667159e969SEd Cashin pr_info("aoe: e%ld.%d: broadcast shelf number invalid\n", 14670c966214SEd Cashin aoemajor, (int) h->minor); 14686583303cSEd Cashin return; 14696583303cSEd Cashin } 14707159e969SEd Cashin if (h->minor == 0xff) { 14717159e969SEd Cashin pr_info("aoe: e%ld.%d: broadcast slot number invalid\n", 14727159e969SEd Cashin aoemajor, (int) h->minor); 14731da177e4SLinus Torvalds return; 14741da177e4SLinus Torvalds } 14751da177e4SLinus Torvalds 147619bf2635SEd L. Cashin n = be16_to_cpu(ch->bufcnt); 14777df620d8SEd L. Cashin if (n > aoe_maxout) /* keep it reasonable */ 14787df620d8SEd L. Cashin n = aoe_maxout; 14791da177e4SLinus Torvalds 14807159e969SEd Cashin d = aoedev_by_aoeaddr(aoemajor, h->minor, 1); 14817159e969SEd Cashin if (d == NULL) { 14827159e969SEd Cashin pr_info("aoe: device allocation failure\n"); 14837159e969SEd Cashin return; 14847159e969SEd Cashin } 14857159e969SEd Cashin 14861da177e4SLinus Torvalds spin_lock_irqsave(&d->lock, flags); 14871da177e4SLinus Torvalds 148868e0d42fSEd L. Cashin t = gettgt(d, h->src); 14891b8a1636SEd Cashin if (t) { 14901b8a1636SEd Cashin t->nframes = n; 14911b8a1636SEd Cashin if (n < t->maxout) 14923a0c40d2SEd Cashin aoecmd_wreset(t); 14931b8a1636SEd Cashin } else { 149468e0d42fSEd L. Cashin t = addtgt(d, h->src, n); 149569cf2d85SEd Cashin if (!t) 149669cf2d85SEd Cashin goto bail; 149768e0d42fSEd L. Cashin } 14983f0f0133SEd Cashin n = skb->dev->mtu; 149919bf2635SEd L. Cashin n -= sizeof(struct aoe_hdr) + sizeof(struct aoe_atahdr); 150019bf2635SEd L. Cashin n /= 512; 150119bf2635SEd L. Cashin if (n > ch->scnt) 150219bf2635SEd L. Cashin n = ch->scnt; 15034f51dc5eSEd L. Cashin n = n ? n * 512 : DEFAULTBCNT; 15043f0f0133SEd Cashin setifbcnt(t, skb->dev, n); 15053ae1c24eSEd L. Cashin 15063ae1c24eSEd L. Cashin /* don't change users' perspective */ 150769cf2d85SEd Cashin if (d->nopen == 0) { 150863e9cc5dSecashin@coraid.com d->fw_ver = be16_to_cpu(ch->fwver); 150968e0d42fSEd L. Cashin sl = aoecmd_ata_id(d); 151069cf2d85SEd Cashin } 151169cf2d85SEd Cashin bail: 15121da177e4SLinus Torvalds spin_unlock_irqrestore(&d->lock, flags); 151369cf2d85SEd Cashin aoedev_put(d); 1514e9bb8fb0SDavid S. Miller if (sl) { 1515e9bb8fb0SDavid S. Miller __skb_queue_head_init(&queue); 1516e9bb8fb0SDavid S. Miller __skb_queue_tail(&queue, sl); 1517e9bb8fb0SDavid S. Miller aoenet_xmit(&queue); 1518e9bb8fb0SDavid S. Miller } 15191da177e4SLinus Torvalds } 15201da177e4SLinus Torvalds 152168e0d42fSEd L. Cashin void 15223a0c40d2SEd Cashin aoecmd_wreset(struct aoetgt *t) 15233a0c40d2SEd Cashin { 15243a0c40d2SEd Cashin t->maxout = 1; 15253a0c40d2SEd Cashin t->ssthresh = t->nframes / 2; 15263a0c40d2SEd Cashin t->next_cwnd = t->nframes; 15273a0c40d2SEd Cashin } 15283a0c40d2SEd Cashin 15293a0c40d2SEd Cashin void 153068e0d42fSEd L. Cashin aoecmd_cleanslate(struct aoedev *d) 153168e0d42fSEd L. Cashin { 153268e0d42fSEd L. Cashin struct aoetgt **t, **te; 153368e0d42fSEd L. Cashin 15343a0c40d2SEd Cashin d->rttavg = RTTAVG_INIT; 15353a0c40d2SEd Cashin d->rttdev = RTTDEV_INIT; 15363f0f0133SEd Cashin d->maxbcnt = 0; 153768e0d42fSEd L. Cashin 153868e0d42fSEd L. Cashin t = d->targets; 153968e0d42fSEd L. Cashin te = t + NTARGETS; 15403f0f0133SEd Cashin for (; t < te && *t; t++) 15413a0c40d2SEd Cashin aoecmd_wreset(*t); 154268e0d42fSEd L. Cashin } 1543896831f5SEd Cashin 154469cf2d85SEd Cashin void 154569cf2d85SEd Cashin aoe_failbuf(struct aoedev *d, struct buf *buf) 154669cf2d85SEd Cashin { 154769cf2d85SEd Cashin if (buf == NULL) 154869cf2d85SEd Cashin return; 154969cf2d85SEd Cashin buf->resid = 0; 155069cf2d85SEd Cashin clear_bit(BIO_UPTODATE, &buf->bio->bi_flags); 155169cf2d85SEd Cashin if (buf->nframesout == 0) 155269cf2d85SEd Cashin aoe_end_buf(d, buf); 155369cf2d85SEd Cashin } 155469cf2d85SEd Cashin 155569cf2d85SEd Cashin void 155669cf2d85SEd Cashin aoe_flush_iocq(void) 1557896831f5SEd Cashin { 1558896831f5SEd Cashin struct frame *f; 1559896831f5SEd Cashin struct aoedev *d; 1560896831f5SEd Cashin LIST_HEAD(flist); 1561896831f5SEd Cashin struct list_head *pos; 1562896831f5SEd Cashin struct sk_buff *skb; 1563896831f5SEd Cashin ulong flags; 1564896831f5SEd Cashin 1565896831f5SEd Cashin spin_lock_irqsave(&iocq.lock, flags); 1566896831f5SEd Cashin list_splice_init(&iocq.head, &flist); 1567896831f5SEd Cashin spin_unlock_irqrestore(&iocq.lock, flags); 1568896831f5SEd Cashin while (!list_empty(&flist)) { 1569896831f5SEd Cashin pos = flist.next; 1570896831f5SEd Cashin list_del(pos); 1571896831f5SEd Cashin f = list_entry(pos, struct frame, head); 1572896831f5SEd Cashin d = f->t->d; 1573896831f5SEd Cashin skb = f->r_skb; 1574896831f5SEd Cashin spin_lock_irqsave(&d->lock, flags); 1575896831f5SEd Cashin if (f->buf) { 1576896831f5SEd Cashin f->buf->nframesout--; 1577896831f5SEd Cashin aoe_failbuf(d, f->buf); 1578896831f5SEd Cashin } 1579896831f5SEd Cashin aoe_freetframe(f); 1580896831f5SEd Cashin spin_unlock_irqrestore(&d->lock, flags); 1581896831f5SEd Cashin dev_kfree_skb(skb); 158269cf2d85SEd Cashin aoedev_put(d); 1583896831f5SEd Cashin } 1584896831f5SEd Cashin } 1585896831f5SEd Cashin 1586896831f5SEd Cashin int __init 1587896831f5SEd Cashin aoecmd_init(void) 1588896831f5SEd Cashin { 1589896831f5SEd Cashin INIT_LIST_HEAD(&iocq.head); 1590896831f5SEd Cashin spin_lock_init(&iocq.lock); 1591896831f5SEd Cashin init_waitqueue_head(&ktiowq); 1592896831f5SEd Cashin kts.name = "aoe_ktio"; 1593896831f5SEd Cashin kts.fn = ktio; 1594896831f5SEd Cashin kts.waitq = &ktiowq; 1595896831f5SEd Cashin kts.lock = &iocq.lock; 1596896831f5SEd Cashin return aoe_ktstart(&kts); 1597896831f5SEd Cashin } 1598896831f5SEd Cashin 1599896831f5SEd Cashin void 1600896831f5SEd Cashin aoecmd_exit(void) 1601896831f5SEd Cashin { 1602896831f5SEd Cashin aoe_ktstop(&kts); 160369cf2d85SEd Cashin aoe_flush_iocq(); 1604896831f5SEd Cashin } 1605