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 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 * 62896831f5SEd Cashin getframe(struct aoetgt *t, u32 tag) 631da177e4SLinus Torvalds { 64896831f5SEd Cashin struct frame *f; 65896831f5SEd Cashin struct list_head *head, *pos, *nx; 66896831f5SEd Cashin u32 n; 671da177e4SLinus Torvalds 68896831f5SEd Cashin n = tag % NFACTIVE; 69896831f5SEd Cashin head = &t->factive[n]; 70896831f5SEd Cashin list_for_each_safe(pos, nx, head) { 71896831f5SEd Cashin f = list_entry(pos, struct frame, head); 72896831f5SEd Cashin if (f->tag == tag) { 73896831f5SEd Cashin list_del(pos); 741da177e4SLinus Torvalds return f; 75896831f5SEd Cashin } 76896831f5SEd Cashin } 771da177e4SLinus Torvalds return NULL; 781da177e4SLinus Torvalds } 791da177e4SLinus Torvalds 801da177e4SLinus Torvalds /* 811da177e4SLinus Torvalds * Leave the top bit clear so we have tagspace for userland. 821da177e4SLinus Torvalds * The bottom 16 bits are the xmit tick for rexmit/rttavg processing. 831da177e4SLinus Torvalds * This driver reserves tag -1 to mean "unused frame." 841da177e4SLinus Torvalds */ 851da177e4SLinus Torvalds static int 8668e0d42fSEd L. Cashin newtag(struct aoetgt *t) 871da177e4SLinus Torvalds { 881da177e4SLinus Torvalds register ulong n; 891da177e4SLinus Torvalds 901da177e4SLinus Torvalds n = jiffies & 0xffff; 9168e0d42fSEd L. Cashin return n |= (++t->lasttag & 0x7fff) << 16; 921da177e4SLinus Torvalds } 931da177e4SLinus Torvalds 94896831f5SEd Cashin static u32 9568e0d42fSEd L. Cashin aoehdr_atainit(struct aoedev *d, struct aoetgt *t, struct aoe_hdr *h) 961da177e4SLinus Torvalds { 9768e0d42fSEd L. Cashin u32 host_tag = newtag(t); 981da177e4SLinus Torvalds 9968e0d42fSEd L. Cashin memcpy(h->src, t->ifp->nd->dev_addr, sizeof h->src); 10068e0d42fSEd L. Cashin memcpy(h->dst, t->addr, sizeof h->dst); 10163e9cc5dSecashin@coraid.com h->type = __constant_cpu_to_be16(ETH_P_AOE); 1021da177e4SLinus Torvalds h->verfl = AOE_HVER; 10363e9cc5dSecashin@coraid.com h->major = cpu_to_be16(d->aoemajor); 1041da177e4SLinus Torvalds h->minor = d->aoeminor; 1051da177e4SLinus Torvalds h->cmd = AOECMD_ATA; 10663e9cc5dSecashin@coraid.com h->tag = cpu_to_be32(host_tag); 1071da177e4SLinus Torvalds 1081da177e4SLinus Torvalds return host_tag; 1091da177e4SLinus Torvalds } 1101da177e4SLinus Torvalds 11119bf2635SEd L. Cashin static inline void 11219bf2635SEd L. Cashin put_lba(struct aoe_atahdr *ah, sector_t lba) 11319bf2635SEd L. Cashin { 11419bf2635SEd L. Cashin ah->lba0 = lba; 11519bf2635SEd L. Cashin ah->lba1 = lba >>= 8; 11619bf2635SEd L. Cashin ah->lba2 = lba >>= 8; 11719bf2635SEd L. Cashin ah->lba3 = lba >>= 8; 11819bf2635SEd L. Cashin ah->lba4 = lba >>= 8; 11919bf2635SEd L. Cashin ah->lba5 = lba >>= 8; 12019bf2635SEd L. Cashin } 12119bf2635SEd L. Cashin 122*3f0f0133SEd Cashin static struct aoeif * 12368e0d42fSEd L. Cashin ifrotate(struct aoetgt *t) 1241da177e4SLinus Torvalds { 125*3f0f0133SEd Cashin struct aoeif *ifp; 126*3f0f0133SEd Cashin 127*3f0f0133SEd Cashin ifp = t->ifp; 128*3f0f0133SEd Cashin ifp++; 129*3f0f0133SEd Cashin if (ifp >= &t->ifs[NAOEIFS] || ifp->nd == NULL) 130*3f0f0133SEd Cashin ifp = t->ifs; 131*3f0f0133SEd Cashin if (ifp->nd == NULL) 132*3f0f0133SEd Cashin return NULL; 133*3f0f0133SEd Cashin return t->ifp = ifp; 13468e0d42fSEd L. Cashin } 13568e0d42fSEd L. Cashin 1369bb237b6SEd L. Cashin static void 1379bb237b6SEd L. Cashin skb_pool_put(struct aoedev *d, struct sk_buff *skb) 1389bb237b6SEd L. Cashin { 139e9bb8fb0SDavid S. Miller __skb_queue_tail(&d->skbpool, skb); 1409bb237b6SEd L. Cashin } 1419bb237b6SEd L. Cashin 1429bb237b6SEd L. Cashin static struct sk_buff * 1439bb237b6SEd L. Cashin skb_pool_get(struct aoedev *d) 1449bb237b6SEd L. Cashin { 145e9bb8fb0SDavid S. Miller struct sk_buff *skb = skb_peek(&d->skbpool); 1469bb237b6SEd L. Cashin 1479bb237b6SEd L. Cashin if (skb && atomic_read(&skb_shinfo(skb)->dataref) == 1) { 148e9bb8fb0SDavid S. Miller __skb_unlink(skb, &d->skbpool); 1499bb237b6SEd L. Cashin return skb; 1509bb237b6SEd L. Cashin } 151e9bb8fb0SDavid S. Miller if (skb_queue_len(&d->skbpool) < NSKBPOOLMAX && 152e9bb8fb0SDavid S. Miller (skb = new_skb(ETH_ZLEN))) 1539bb237b6SEd L. Cashin return skb; 154e9bb8fb0SDavid S. Miller 1559bb237b6SEd L. Cashin return NULL; 1569bb237b6SEd L. Cashin } 1579bb237b6SEd L. Cashin 158896831f5SEd Cashin void 159896831f5SEd Cashin aoe_freetframe(struct frame *f) 16068e0d42fSEd L. Cashin { 161896831f5SEd Cashin struct aoetgt *t; 162896831f5SEd Cashin 163896831f5SEd Cashin t = f->t; 164896831f5SEd Cashin f->buf = NULL; 165896831f5SEd Cashin f->bv = NULL; 166896831f5SEd Cashin f->r_skb = NULL; 167896831f5SEd Cashin list_add(&f->head, &t->ffree); 168896831f5SEd Cashin } 169896831f5SEd Cashin 170896831f5SEd Cashin static struct frame * 171896831f5SEd Cashin newtframe(struct aoedev *d, struct aoetgt *t) 172896831f5SEd Cashin { 173896831f5SEd Cashin struct frame *f; 1749bb237b6SEd L. Cashin struct sk_buff *skb; 175896831f5SEd Cashin struct list_head *pos; 176896831f5SEd Cashin 177896831f5SEd Cashin if (list_empty(&t->ffree)) { 178896831f5SEd Cashin if (t->falloc >= NSKBPOOLMAX*2) 179896831f5SEd Cashin return NULL; 180896831f5SEd Cashin f = kcalloc(1, sizeof(*f), GFP_ATOMIC); 181896831f5SEd Cashin if (f == NULL) 182896831f5SEd Cashin return NULL; 183896831f5SEd Cashin t->falloc++; 184896831f5SEd Cashin f->t = t; 185896831f5SEd Cashin } else { 186896831f5SEd Cashin pos = t->ffree.next; 187896831f5SEd Cashin list_del(pos); 188896831f5SEd Cashin f = list_entry(pos, struct frame, head); 189896831f5SEd Cashin } 190896831f5SEd Cashin 191896831f5SEd Cashin skb = f->skb; 192896831f5SEd Cashin if (skb == NULL) { 193896831f5SEd Cashin f->skb = skb = new_skb(ETH_ZLEN); 194896831f5SEd Cashin if (!skb) { 195896831f5SEd Cashin bail: aoe_freetframe(f); 196896831f5SEd Cashin return NULL; 197896831f5SEd Cashin } 198896831f5SEd Cashin } 199896831f5SEd Cashin 200896831f5SEd Cashin if (atomic_read(&skb_shinfo(skb)->dataref) != 1) { 201896831f5SEd Cashin skb = skb_pool_get(d); 202896831f5SEd Cashin if (skb == NULL) 203896831f5SEd Cashin goto bail; 204896831f5SEd Cashin skb_pool_put(d, f->skb); 205896831f5SEd Cashin f->skb = skb; 206896831f5SEd Cashin } 207896831f5SEd Cashin 208896831f5SEd Cashin skb->truesize -= skb->data_len; 209896831f5SEd Cashin skb_shinfo(skb)->nr_frags = skb->data_len = 0; 210896831f5SEd Cashin skb_trim(skb, 0); 211896831f5SEd Cashin return f; 212896831f5SEd Cashin } 213896831f5SEd Cashin 214896831f5SEd Cashin static struct frame * 215896831f5SEd Cashin newframe(struct aoedev *d) 216896831f5SEd Cashin { 217896831f5SEd Cashin struct frame *f; 218896831f5SEd Cashin struct aoetgt *t, **tt; 219896831f5SEd Cashin int totout = 0; 22068e0d42fSEd L. Cashin 22168e0d42fSEd L. Cashin if (d->targets[0] == NULL) { /* shouldn't happen, but I'm paranoid */ 22268e0d42fSEd L. Cashin printk(KERN_ERR "aoe: NULL TARGETS!\n"); 22368e0d42fSEd L. Cashin return NULL; 22468e0d42fSEd L. Cashin } 225896831f5SEd Cashin tt = d->tgt; /* last used target */ 2269bb237b6SEd L. Cashin for (;;) { 227896831f5SEd Cashin tt++; 228896831f5SEd Cashin if (tt >= &d->targets[NTARGETS] || !*tt) 229896831f5SEd Cashin tt = d->targets; 230896831f5SEd Cashin t = *tt; 231896831f5SEd Cashin totout += t->nout; 232896831f5SEd Cashin if (t->nout < t->maxout 2339bb237b6SEd L. Cashin && t != d->htgt 234896831f5SEd Cashin && t->ifp->nd) { 235896831f5SEd Cashin f = newtframe(d, t); 236896831f5SEd Cashin if (f) { 237896831f5SEd Cashin ifrotate(t); 238*3f0f0133SEd Cashin d->tgt = tt; 23968e0d42fSEd L. Cashin return f; 24068e0d42fSEd L. Cashin } 2419bb237b6SEd L. Cashin } 242896831f5SEd Cashin if (tt == d->tgt) /* we've looped and found nada */ 2439bb237b6SEd L. Cashin break; 244896831f5SEd Cashin } 245896831f5SEd Cashin if (totout == 0) { 246896831f5SEd Cashin d->kicked++; 247896831f5SEd Cashin d->flags |= DEVFL_KICKME; 2489bb237b6SEd L. Cashin } 24968e0d42fSEd L. Cashin return NULL; 25068e0d42fSEd L. Cashin } 25168e0d42fSEd L. Cashin 2523d5b0605SEd Cashin static void 2533d5b0605SEd Cashin skb_fillup(struct sk_buff *skb, struct bio_vec *bv, ulong off, ulong cnt) 2543d5b0605SEd Cashin { 2553d5b0605SEd Cashin int frag = 0; 2563d5b0605SEd Cashin ulong fcnt; 2573d5b0605SEd Cashin loop: 2583d5b0605SEd Cashin fcnt = bv->bv_len - (off - bv->bv_offset); 2593d5b0605SEd Cashin if (fcnt > cnt) 2603d5b0605SEd Cashin fcnt = cnt; 2613d5b0605SEd Cashin skb_fill_page_desc(skb, frag++, bv->bv_page, off, fcnt); 2623d5b0605SEd Cashin cnt -= fcnt; 2633d5b0605SEd Cashin if (cnt <= 0) 2643d5b0605SEd Cashin return; 2653d5b0605SEd Cashin bv++; 2663d5b0605SEd Cashin off = bv->bv_offset; 2673d5b0605SEd Cashin goto loop; 2683d5b0605SEd Cashin } 2693d5b0605SEd Cashin 270896831f5SEd Cashin static void 271896831f5SEd Cashin fhash(struct frame *f) 272896831f5SEd Cashin { 273896831f5SEd Cashin struct aoetgt *t = f->t; 274896831f5SEd Cashin u32 n; 275896831f5SEd Cashin 276896831f5SEd Cashin n = f->tag % NFACTIVE; 277896831f5SEd Cashin list_add_tail(&f->head, &t->factive[n]); 278896831f5SEd Cashin } 279896831f5SEd Cashin 28068e0d42fSEd L. Cashin static int 28168e0d42fSEd L. Cashin aoecmd_ata_rw(struct aoedev *d) 28268e0d42fSEd L. Cashin { 28368e0d42fSEd L. Cashin struct frame *f; 2841da177e4SLinus Torvalds struct aoe_hdr *h; 2851da177e4SLinus Torvalds struct aoe_atahdr *ah; 2861da177e4SLinus Torvalds struct buf *buf; 28768e0d42fSEd L. Cashin struct bio_vec *bv; 28868e0d42fSEd L. Cashin struct aoetgt *t; 2891da177e4SLinus Torvalds struct sk_buff *skb; 29069cf2d85SEd Cashin struct sk_buff_head queue; 2913d5b0605SEd Cashin ulong bcnt, fbcnt; 2921da177e4SLinus Torvalds char writebit, extbit; 2931da177e4SLinus Torvalds 2941da177e4SLinus Torvalds writebit = 0x10; 2951da177e4SLinus Torvalds extbit = 0x4; 2961da177e4SLinus Torvalds 29769cf2d85SEd Cashin buf = nextbuf(d); 29869cf2d85SEd Cashin if (buf == NULL) 29969cf2d85SEd Cashin return 0; 300896831f5SEd Cashin f = newframe(d); 30168e0d42fSEd L. Cashin if (f == NULL) 30268e0d42fSEd L. Cashin return 0; 30368e0d42fSEd L. Cashin t = *d->tgt; 30468e0d42fSEd L. Cashin bv = buf->bv; 305*3f0f0133SEd Cashin bcnt = d->maxbcnt; 30668e0d42fSEd L. Cashin if (bcnt == 0) 30768e0d42fSEd L. Cashin bcnt = DEFAULTBCNT; 3083d5b0605SEd Cashin if (bcnt > buf->resid) 3093d5b0605SEd Cashin bcnt = buf->resid; 3103d5b0605SEd Cashin fbcnt = bcnt; 3113d5b0605SEd Cashin f->bv = buf->bv; 3123d5b0605SEd Cashin f->bv_off = f->bv->bv_offset + (f->bv->bv_len - buf->bv_resid); 3133d5b0605SEd Cashin do { 3143d5b0605SEd Cashin if (fbcnt < buf->bv_resid) { 3153d5b0605SEd Cashin buf->bv_resid -= fbcnt; 3163d5b0605SEd Cashin buf->resid -= fbcnt; 3173d5b0605SEd Cashin break; 3183d5b0605SEd Cashin } 3193d5b0605SEd Cashin fbcnt -= buf->bv_resid; 3203d5b0605SEd Cashin buf->resid -= buf->bv_resid; 3213d5b0605SEd Cashin if (buf->resid == 0) { 32269cf2d85SEd Cashin d->ip.buf = NULL; 3233d5b0605SEd Cashin break; 3243d5b0605SEd Cashin } 3253d5b0605SEd Cashin buf->bv++; 3263d5b0605SEd Cashin buf->bv_resid = buf->bv->bv_len; 3273d5b0605SEd Cashin WARN_ON(buf->bv_resid == 0); 3283d5b0605SEd Cashin } while (fbcnt); 3293d5b0605SEd Cashin 3301da177e4SLinus Torvalds /* initialize the headers & frame */ 331e407a7f6SEd L. Cashin skb = f->skb; 332abdbf94dSEd L. Cashin h = (struct aoe_hdr *) skb_mac_header(skb); 3331da177e4SLinus Torvalds ah = (struct aoe_atahdr *) (h+1); 33419900cdeSEd L. Cashin skb_put(skb, sizeof *h + sizeof *ah); 33519900cdeSEd L. Cashin memset(h, 0, skb->len); 33668e0d42fSEd L. Cashin f->tag = aoehdr_atainit(d, t, h); 337896831f5SEd Cashin fhash(f); 33868e0d42fSEd L. Cashin t->nout++; 3391da177e4SLinus Torvalds f->waited = 0; 3401da177e4SLinus Torvalds f->buf = buf; 34119bf2635SEd L. Cashin f->bcnt = bcnt; 34268e0d42fSEd L. Cashin f->lba = buf->sector; 3431da177e4SLinus Torvalds 3441da177e4SLinus Torvalds /* set up ata header */ 3451da177e4SLinus Torvalds ah->scnt = bcnt >> 9; 34668e0d42fSEd L. Cashin put_lba(ah, buf->sector); 3471da177e4SLinus Torvalds if (d->flags & DEVFL_EXT) { 3481da177e4SLinus Torvalds ah->aflags |= AOEAFL_EXT; 3491da177e4SLinus Torvalds } else { 3501da177e4SLinus Torvalds extbit = 0; 3511da177e4SLinus Torvalds ah->lba3 &= 0x0f; 3521da177e4SLinus Torvalds ah->lba3 |= 0xe0; /* LBA bit + obsolete 0xa0 */ 3531da177e4SLinus Torvalds } 3541da177e4SLinus Torvalds if (bio_data_dir(buf->bio) == WRITE) { 3553d5b0605SEd Cashin skb_fillup(skb, f->bv, f->bv_off, bcnt); 3561da177e4SLinus Torvalds ah->aflags |= AOEAFL_WRITE; 3574f51dc5eSEd L. Cashin skb->len += bcnt; 3584f51dc5eSEd L. Cashin skb->data_len = bcnt; 3593d5b0605SEd Cashin skb->truesize += bcnt; 36068e0d42fSEd L. Cashin t->wpkts++; 3611da177e4SLinus Torvalds } else { 36268e0d42fSEd L. Cashin t->rpkts++; 3631da177e4SLinus Torvalds writebit = 0; 3641da177e4SLinus Torvalds } 3651da177e4SLinus Torvalds 36604b3ab52SBartlomiej Zolnierkiewicz ah->cmdstat = ATA_CMD_PIO_READ | writebit | extbit; 3671da177e4SLinus Torvalds 3681da177e4SLinus Torvalds /* mark all tracking fields and load out */ 3691da177e4SLinus Torvalds buf->nframesout += 1; 3701da177e4SLinus Torvalds buf->sector += bcnt >> 9; 3711da177e4SLinus Torvalds 37268e0d42fSEd L. Cashin skb->dev = t->ifp->nd; 3734f51dc5eSEd L. Cashin skb = skb_clone(skb, GFP_ATOMIC); 37469cf2d85SEd Cashin if (skb) { 37569cf2d85SEd Cashin __skb_queue_head_init(&queue); 37669cf2d85SEd Cashin __skb_queue_tail(&queue, skb); 37769cf2d85SEd Cashin aoenet_xmit(&queue); 37869cf2d85SEd Cashin } 37968e0d42fSEd L. Cashin return 1; 38068e0d42fSEd L. Cashin } 3811da177e4SLinus Torvalds 3823ae1c24eSEd L. Cashin /* some callers cannot sleep, and they can call this function, 3833ae1c24eSEd L. Cashin * transmitting the packets later, when interrupts are on 3843ae1c24eSEd L. Cashin */ 385e9bb8fb0SDavid S. Miller static void 386e9bb8fb0SDavid S. Miller aoecmd_cfg_pkts(ushort aoemajor, unsigned char aoeminor, struct sk_buff_head *queue) 3873ae1c24eSEd L. Cashin { 3883ae1c24eSEd L. Cashin struct aoe_hdr *h; 3893ae1c24eSEd L. Cashin struct aoe_cfghdr *ch; 390e9bb8fb0SDavid S. Miller struct sk_buff *skb; 3913ae1c24eSEd L. Cashin struct net_device *ifp; 3923ae1c24eSEd L. Cashin 393840a185dSEric Dumazet rcu_read_lock(); 394840a185dSEric Dumazet for_each_netdev_rcu(&init_net, ifp) { 3953ae1c24eSEd L. Cashin dev_hold(ifp); 3963ae1c24eSEd L. Cashin if (!is_aoe_netif(ifp)) 3977562f876SPavel Emelianov goto cont; 3983ae1c24eSEd L. Cashin 399e407a7f6SEd L. Cashin skb = new_skb(sizeof *h + sizeof *ch); 4003ae1c24eSEd L. Cashin if (skb == NULL) { 401a12c93f0SEd L. Cashin printk(KERN_INFO "aoe: skb alloc failure\n"); 4027562f876SPavel Emelianov goto cont; 4033ae1c24eSEd L. Cashin } 40419900cdeSEd L. Cashin skb_put(skb, sizeof *h + sizeof *ch); 405e407a7f6SEd L. Cashin skb->dev = ifp; 406e9bb8fb0SDavid S. Miller __skb_queue_tail(queue, skb); 407abdbf94dSEd L. Cashin h = (struct aoe_hdr *) skb_mac_header(skb); 4083ae1c24eSEd L. Cashin memset(h, 0, sizeof *h + sizeof *ch); 4093ae1c24eSEd L. Cashin 4103ae1c24eSEd L. Cashin memset(h->dst, 0xff, sizeof h->dst); 4113ae1c24eSEd L. Cashin memcpy(h->src, ifp->dev_addr, sizeof h->src); 4123ae1c24eSEd L. Cashin h->type = __constant_cpu_to_be16(ETH_P_AOE); 4133ae1c24eSEd L. Cashin h->verfl = AOE_HVER; 4143ae1c24eSEd L. Cashin h->major = cpu_to_be16(aoemajor); 4153ae1c24eSEd L. Cashin h->minor = aoeminor; 4163ae1c24eSEd L. Cashin h->cmd = AOECMD_CFG; 4173ae1c24eSEd L. Cashin 4187562f876SPavel Emelianov cont: 4197562f876SPavel Emelianov dev_put(ifp); 4203ae1c24eSEd L. Cashin } 421840a185dSEric Dumazet rcu_read_unlock(); 4223ae1c24eSEd L. Cashin } 4233ae1c24eSEd L. Cashin 4241da177e4SLinus Torvalds static void 425896831f5SEd Cashin resend(struct aoedev *d, struct frame *f) 4261da177e4SLinus Torvalds { 4271da177e4SLinus Torvalds struct sk_buff *skb; 42869cf2d85SEd Cashin struct sk_buff_head queue; 4291da177e4SLinus Torvalds struct aoe_hdr *h; 43019bf2635SEd L. Cashin struct aoe_atahdr *ah; 431896831f5SEd Cashin struct aoetgt *t; 4321da177e4SLinus Torvalds char buf[128]; 4331da177e4SLinus Torvalds u32 n; 4341da177e4SLinus Torvalds 435896831f5SEd Cashin t = f->t; 43668e0d42fSEd L. Cashin n = newtag(t); 437e407a7f6SEd L. Cashin skb = f->skb; 438*3f0f0133SEd Cashin if (ifrotate(t) == NULL) { 439*3f0f0133SEd Cashin /* probably can't happen, but set it up to fail anyway */ 440*3f0f0133SEd Cashin pr_info("aoe: resend: no interfaces to rotate to.\n"); 441*3f0f0133SEd Cashin ktcomplete(f, NULL); 442*3f0f0133SEd Cashin return; 443*3f0f0133SEd Cashin } 444abdbf94dSEd L. Cashin h = (struct aoe_hdr *) skb_mac_header(skb); 44519bf2635SEd L. Cashin ah = (struct aoe_atahdr *) (h+1); 44668e0d42fSEd L. Cashin 44768e0d42fSEd L. Cashin snprintf(buf, sizeof buf, 448411c41eeSHarvey Harrison "%15s e%ld.%d oldtag=%08x@%08lx newtag=%08x s=%pm d=%pm nout=%d\n", 44968e0d42fSEd L. Cashin "retransmit", d->aoemajor, d->aoeminor, f->tag, jiffies, n, 450411c41eeSHarvey Harrison h->src, h->dst, t->nout); 45168e0d42fSEd L. Cashin aoechr_error(buf); 45268e0d42fSEd L. Cashin 4531da177e4SLinus Torvalds f->tag = n; 454896831f5SEd Cashin fhash(f); 45563e9cc5dSecashin@coraid.com h->tag = cpu_to_be32(n); 45668e0d42fSEd L. Cashin memcpy(h->dst, t->addr, sizeof h->dst); 45768e0d42fSEd L. Cashin memcpy(h->src, t->ifp->nd->dev_addr, sizeof h->src); 4581da177e4SLinus Torvalds 45968e0d42fSEd L. Cashin skb->dev = t->ifp->nd; 4604f51dc5eSEd L. Cashin skb = skb_clone(skb, GFP_ATOMIC); 4614f51dc5eSEd L. Cashin if (skb == NULL) 4624f51dc5eSEd L. Cashin return; 46369cf2d85SEd Cashin __skb_queue_head_init(&queue); 46469cf2d85SEd Cashin __skb_queue_tail(&queue, skb); 46569cf2d85SEd Cashin aoenet_xmit(&queue); 4661da177e4SLinus Torvalds } 4671da177e4SLinus Torvalds 4681da177e4SLinus Torvalds static int 469896831f5SEd Cashin tsince(u32 tag) 4701da177e4SLinus Torvalds { 4711da177e4SLinus Torvalds int n; 4721da177e4SLinus Torvalds 4731da177e4SLinus Torvalds n = jiffies & 0xffff; 4741da177e4SLinus Torvalds n -= tag & 0xffff; 4751da177e4SLinus Torvalds if (n < 0) 4761da177e4SLinus Torvalds n += 1<<16; 4771da177e4SLinus Torvalds return n; 4781da177e4SLinus Torvalds } 4791da177e4SLinus Torvalds 48068e0d42fSEd L. Cashin static struct aoeif * 48168e0d42fSEd L. Cashin getif(struct aoetgt *t, struct net_device *nd) 48268e0d42fSEd L. Cashin { 48368e0d42fSEd L. Cashin struct aoeif *p, *e; 48468e0d42fSEd L. Cashin 48568e0d42fSEd L. Cashin p = t->ifs; 48668e0d42fSEd L. Cashin e = p + NAOEIFS; 48768e0d42fSEd L. Cashin for (; p < e; p++) 48868e0d42fSEd L. Cashin if (p->nd == nd) 48968e0d42fSEd L. Cashin return p; 49068e0d42fSEd L. Cashin return NULL; 49168e0d42fSEd L. Cashin } 49268e0d42fSEd L. Cashin 49368e0d42fSEd L. Cashin static void 49468e0d42fSEd L. Cashin ejectif(struct aoetgt *t, struct aoeif *ifp) 49568e0d42fSEd L. Cashin { 49668e0d42fSEd L. Cashin struct aoeif *e; 49768e0d42fSEd L. Cashin ulong n; 49868e0d42fSEd L. Cashin 49968e0d42fSEd L. Cashin e = t->ifs + NAOEIFS - 1; 50068e0d42fSEd L. Cashin n = (e - ifp) * sizeof *ifp; 50168e0d42fSEd L. Cashin memmove(ifp, ifp+1, n); 50268e0d42fSEd L. Cashin e->nd = NULL; 50368e0d42fSEd L. Cashin } 50468e0d42fSEd L. Cashin 50568e0d42fSEd L. Cashin static int 50668e0d42fSEd L. Cashin sthtith(struct aoedev *d) 50768e0d42fSEd L. Cashin { 508896831f5SEd Cashin struct frame *f, *nf; 509896831f5SEd Cashin struct list_head *nx, *pos, *head; 51068e0d42fSEd L. Cashin struct sk_buff *skb; 511896831f5SEd Cashin struct aoetgt *ht = d->htgt; 512896831f5SEd Cashin int i; 51368e0d42fSEd L. Cashin 514896831f5SEd Cashin for (i = 0; i < NFACTIVE; i++) { 515896831f5SEd Cashin head = &ht->factive[i]; 516896831f5SEd Cashin list_for_each_safe(pos, nx, head) { 517896831f5SEd Cashin f = list_entry(pos, struct frame, head); 518896831f5SEd Cashin nf = newframe(d); 51968e0d42fSEd L. Cashin if (!nf) 52068e0d42fSEd L. Cashin return 0; 521896831f5SEd Cashin 522896831f5SEd Cashin /* remove frame from active list */ 523896831f5SEd Cashin list_del(pos); 524896831f5SEd Cashin 525896831f5SEd Cashin /* reassign all pertinent bits to new outbound frame */ 52668e0d42fSEd L. Cashin skb = nf->skb; 527896831f5SEd Cashin nf->skb = f->skb; 528896831f5SEd Cashin nf->buf = f->buf; 529896831f5SEd Cashin nf->bcnt = f->bcnt; 530896831f5SEd Cashin nf->lba = f->lba; 531896831f5SEd Cashin nf->bv = f->bv; 532896831f5SEd Cashin nf->bv_off = f->bv_off; 53368e0d42fSEd L. Cashin nf->waited = 0; 534896831f5SEd Cashin f->skb = skb; 535896831f5SEd Cashin aoe_freetframe(f); 53668e0d42fSEd L. Cashin ht->nout--; 537896831f5SEd Cashin nf->t->nout++; 538896831f5SEd Cashin resend(d, nf); 539896831f5SEd Cashin } 54068e0d42fSEd L. Cashin } 541*3f0f0133SEd Cashin /* We've cleaned up the outstanding so take away his 542*3f0f0133SEd Cashin * interfaces so he won't be used. We should remove him from 543*3f0f0133SEd Cashin * the target array here, but cleaning up a target is 544*3f0f0133SEd Cashin * involved. PUNT! 545*3f0f0133SEd Cashin */ 54668e0d42fSEd L. Cashin memset(ht->ifs, 0, sizeof ht->ifs); 54768e0d42fSEd L. Cashin d->htgt = NULL; 54868e0d42fSEd L. Cashin return 1; 54968e0d42fSEd L. Cashin } 55068e0d42fSEd L. Cashin 55168e0d42fSEd L. Cashin static inline unsigned char 55268e0d42fSEd L. Cashin ata_scnt(unsigned char *packet) { 55368e0d42fSEd L. Cashin struct aoe_hdr *h; 55468e0d42fSEd L. Cashin struct aoe_atahdr *ah; 55568e0d42fSEd L. Cashin 55668e0d42fSEd L. Cashin h = (struct aoe_hdr *) packet; 55768e0d42fSEd L. Cashin ah = (struct aoe_atahdr *) (h+1); 55868e0d42fSEd L. Cashin return ah->scnt; 55968e0d42fSEd L. Cashin } 56068e0d42fSEd L. Cashin 5611da177e4SLinus Torvalds static void 5621da177e4SLinus Torvalds rexmit_timer(ulong vp) 5631da177e4SLinus Torvalds { 5641da177e4SLinus Torvalds struct aoedev *d; 56568e0d42fSEd L. Cashin struct aoetgt *t, **tt, **te; 56668e0d42fSEd L. Cashin struct aoeif *ifp; 567896831f5SEd Cashin struct frame *f; 568896831f5SEd Cashin struct list_head *head, *pos, *nx; 569896831f5SEd Cashin LIST_HEAD(flist); 5701da177e4SLinus Torvalds register long timeout; 5711da177e4SLinus Torvalds ulong flags, n; 572896831f5SEd Cashin int i; 5731da177e4SLinus Torvalds 5741da177e4SLinus Torvalds d = (struct aoedev *) vp; 5751da177e4SLinus Torvalds 5761da177e4SLinus Torvalds /* timeout is always ~150% of the moving average */ 5771da177e4SLinus Torvalds timeout = d->rttavg; 5781da177e4SLinus Torvalds timeout += timeout >> 1; 5791da177e4SLinus Torvalds 5801da177e4SLinus Torvalds spin_lock_irqsave(&d->lock, flags); 5811da177e4SLinus Torvalds 5821da177e4SLinus Torvalds if (d->flags & DEVFL_TKILL) { 5831c6f3fcaSEd L. Cashin spin_unlock_irqrestore(&d->lock, flags); 5841da177e4SLinus Torvalds return; 5851da177e4SLinus Torvalds } 586896831f5SEd Cashin 587896831f5SEd Cashin /* collect all frames to rexmit into flist */ 58868e0d42fSEd L. Cashin tt = d->targets; 58968e0d42fSEd L. Cashin te = tt + NTARGETS; 59068e0d42fSEd L. Cashin for (; tt < te && *tt; tt++) { 59168e0d42fSEd L. Cashin t = *tt; 592896831f5SEd Cashin for (i = 0; i < NFACTIVE; i++) { 593896831f5SEd Cashin head = &t->factive[i]; 594896831f5SEd Cashin list_for_each_safe(pos, nx, head) { 595896831f5SEd Cashin f = list_entry(pos, struct frame, head); 596896831f5SEd Cashin if (tsince(f->tag) < timeout) 59768e0d42fSEd L. Cashin continue; 598896831f5SEd Cashin /* move to flist for later processing */ 599896831f5SEd Cashin list_move_tail(pos, &flist); 600896831f5SEd Cashin } 601896831f5SEd Cashin } 602896831f5SEd Cashin 603896831f5SEd Cashin /* window check */ 604896831f5SEd Cashin if (t->nout == t->maxout 605896831f5SEd Cashin && t->maxout < t->nframes 606896831f5SEd Cashin && (jiffies - t->lastwadj)/HZ > 10) { 607896831f5SEd Cashin t->maxout++; 608896831f5SEd Cashin t->lastwadj = jiffies; 609896831f5SEd Cashin } 610896831f5SEd Cashin } 611896831f5SEd Cashin 61269cf2d85SEd Cashin if (!list_empty(&flist)) { /* retransmissions necessary */ 61369cf2d85SEd Cashin n = d->rttavg <<= 1; 61469cf2d85SEd Cashin if (n > MAXTIMER) 61569cf2d85SEd Cashin d->rttavg = MAXTIMER; 61669cf2d85SEd Cashin } 61769cf2d85SEd Cashin 618896831f5SEd Cashin /* process expired frames */ 619896831f5SEd Cashin while (!list_empty(&flist)) { 620896831f5SEd Cashin pos = flist.next; 621896831f5SEd Cashin f = list_entry(pos, struct frame, head); 6221da177e4SLinus Torvalds n = f->waited += timeout; 6231da177e4SLinus Torvalds n /= HZ; 62468e0d42fSEd L. Cashin if (n > aoe_deadsecs) { 625896831f5SEd Cashin /* Waited too long. Device failure. 626896831f5SEd Cashin * Hang all frames on first hash bucket for downdev 627896831f5SEd Cashin * to clean up. 628896831f5SEd Cashin */ 629896831f5SEd Cashin list_splice(&flist, &f->t->factive[0]); 6301da177e4SLinus Torvalds aoedev_downdev(d); 6311c6f3fcaSEd L. Cashin break; 6321da177e4SLinus Torvalds } 633896831f5SEd Cashin list_del(pos); 63468e0d42fSEd L. Cashin 635896831f5SEd Cashin t = f->t; 636896831f5SEd Cashin if (n > HELPWAIT) { 637896831f5SEd Cashin /* see if another target can help */ 638896831f5SEd Cashin if (d->ntargets > 1) 639896831f5SEd Cashin d->htgt = t; 640896831f5SEd Cashin } 64168e0d42fSEd L. Cashin if (t->nout == t->maxout) { 64268e0d42fSEd L. Cashin if (t->maxout > 1) 64368e0d42fSEd L. Cashin t->maxout--; 64468e0d42fSEd L. Cashin t->lastwadj = jiffies; 64568e0d42fSEd L. Cashin } 64668e0d42fSEd L. Cashin 64768e0d42fSEd L. Cashin ifp = getif(t, f->skb->dev); 64868e0d42fSEd L. Cashin if (ifp && ++ifp->lost > (t->nframes << 1) 64968e0d42fSEd L. Cashin && (ifp != t->ifs || t->ifs[1].nd)) { 65068e0d42fSEd L. Cashin ejectif(t, ifp); 65168e0d42fSEd L. Cashin ifp = NULL; 65268e0d42fSEd L. Cashin } 653896831f5SEd Cashin resend(d, f); 6541da177e4SLinus Torvalds } 65568e0d42fSEd L. Cashin 65669cf2d85SEd Cashin if ((d->flags & DEVFL_KICKME || d->htgt) && d->blkq) { 6574f51dc5eSEd L. Cashin d->flags &= ~DEVFL_KICKME; 65869cf2d85SEd Cashin d->blkq->request_fn(d->blkq); 6594f51dc5eSEd L. Cashin } 6601da177e4SLinus Torvalds 6611da177e4SLinus Torvalds d->timer.expires = jiffies + TIMERTICK; 6621da177e4SLinus Torvalds add_timer(&d->timer); 6631da177e4SLinus Torvalds 6641da177e4SLinus Torvalds spin_unlock_irqrestore(&d->lock, flags); 66569cf2d85SEd Cashin } 6661da177e4SLinus Torvalds 66769cf2d85SEd Cashin static unsigned long 66869cf2d85SEd Cashin rqbiocnt(struct request *r) 66969cf2d85SEd Cashin { 67069cf2d85SEd Cashin struct bio *bio; 67169cf2d85SEd Cashin unsigned long n = 0; 67269cf2d85SEd Cashin 67369cf2d85SEd Cashin __rq_for_each_bio(bio, r) 67469cf2d85SEd Cashin n++; 67569cf2d85SEd Cashin return n; 67669cf2d85SEd Cashin } 67769cf2d85SEd Cashin 67869cf2d85SEd Cashin /* This can be removed if we are certain that no users of the block 67969cf2d85SEd Cashin * layer will ever use zero-count pages in bios. Otherwise we have to 68069cf2d85SEd Cashin * protect against the put_page sometimes done by the network layer. 68169cf2d85SEd Cashin * 68269cf2d85SEd Cashin * See http://oss.sgi.com/archives/xfs/2007-01/msg00594.html for 68369cf2d85SEd Cashin * discussion. 68469cf2d85SEd Cashin * 68569cf2d85SEd Cashin * We cannot use get_page in the workaround, because it insists on a 68669cf2d85SEd Cashin * positive page count as a precondition. So we use _count directly. 68769cf2d85SEd Cashin */ 68869cf2d85SEd Cashin static void 68969cf2d85SEd Cashin bio_pageinc(struct bio *bio) 69069cf2d85SEd Cashin { 69169cf2d85SEd Cashin struct bio_vec *bv; 69269cf2d85SEd Cashin struct page *page; 69369cf2d85SEd Cashin int i; 69469cf2d85SEd Cashin 69569cf2d85SEd Cashin bio_for_each_segment(bv, bio, i) { 69669cf2d85SEd Cashin page = bv->bv_page; 69769cf2d85SEd Cashin /* Non-zero page count for non-head members of 69869cf2d85SEd Cashin * compound pages is no longer allowed by the kernel, 69969cf2d85SEd Cashin * but this has never been seen here. 70069cf2d85SEd Cashin */ 70169cf2d85SEd Cashin if (unlikely(PageCompound(page))) 70269cf2d85SEd Cashin if (compound_trans_head(page) != page) { 70369cf2d85SEd Cashin pr_crit("page tail used for block I/O\n"); 70469cf2d85SEd Cashin BUG(); 70569cf2d85SEd Cashin } 70669cf2d85SEd Cashin atomic_inc(&page->_count); 70769cf2d85SEd Cashin } 70869cf2d85SEd Cashin } 70969cf2d85SEd Cashin 71069cf2d85SEd Cashin static void 71169cf2d85SEd Cashin bio_pagedec(struct bio *bio) 71269cf2d85SEd Cashin { 71369cf2d85SEd Cashin struct bio_vec *bv; 71469cf2d85SEd Cashin int i; 71569cf2d85SEd Cashin 71669cf2d85SEd Cashin bio_for_each_segment(bv, bio, i) 71769cf2d85SEd Cashin atomic_dec(&bv->bv_page->_count); 71869cf2d85SEd Cashin } 71969cf2d85SEd Cashin 72069cf2d85SEd Cashin static void 72169cf2d85SEd Cashin bufinit(struct buf *buf, struct request *rq, struct bio *bio) 72269cf2d85SEd Cashin { 72369cf2d85SEd Cashin struct bio_vec *bv; 72469cf2d85SEd Cashin 72569cf2d85SEd Cashin memset(buf, 0, sizeof(*buf)); 72669cf2d85SEd Cashin buf->rq = rq; 72769cf2d85SEd Cashin buf->bio = bio; 72869cf2d85SEd Cashin buf->resid = bio->bi_size; 72969cf2d85SEd Cashin buf->sector = bio->bi_sector; 73069cf2d85SEd Cashin bio_pageinc(bio); 73169cf2d85SEd Cashin buf->bv = bv = &bio->bi_io_vec[bio->bi_idx]; 73269cf2d85SEd Cashin buf->bv_resid = bv->bv_len; 73369cf2d85SEd Cashin WARN_ON(buf->bv_resid == 0); 73469cf2d85SEd Cashin } 73569cf2d85SEd Cashin 73669cf2d85SEd Cashin static struct buf * 73769cf2d85SEd Cashin nextbuf(struct aoedev *d) 73869cf2d85SEd Cashin { 73969cf2d85SEd Cashin struct request *rq; 74069cf2d85SEd Cashin struct request_queue *q; 74169cf2d85SEd Cashin struct buf *buf; 74269cf2d85SEd Cashin struct bio *bio; 74369cf2d85SEd Cashin 74469cf2d85SEd Cashin q = d->blkq; 74569cf2d85SEd Cashin if (q == NULL) 74669cf2d85SEd Cashin return NULL; /* initializing */ 74769cf2d85SEd Cashin if (d->ip.buf) 74869cf2d85SEd Cashin return d->ip.buf; 74969cf2d85SEd Cashin rq = d->ip.rq; 75069cf2d85SEd Cashin if (rq == NULL) { 75169cf2d85SEd Cashin rq = blk_peek_request(q); 75269cf2d85SEd Cashin if (rq == NULL) 75369cf2d85SEd Cashin return NULL; 75469cf2d85SEd Cashin blk_start_request(rq); 75569cf2d85SEd Cashin d->ip.rq = rq; 75669cf2d85SEd Cashin d->ip.nxbio = rq->bio; 75769cf2d85SEd Cashin rq->special = (void *) rqbiocnt(rq); 75869cf2d85SEd Cashin } 75969cf2d85SEd Cashin buf = mempool_alloc(d->bufpool, GFP_ATOMIC); 76069cf2d85SEd Cashin if (buf == NULL) { 76169cf2d85SEd Cashin pr_err("aoe: nextbuf: unable to mempool_alloc!\n"); 76269cf2d85SEd Cashin return NULL; 76369cf2d85SEd Cashin } 76469cf2d85SEd Cashin bio = d->ip.nxbio; 76569cf2d85SEd Cashin bufinit(buf, rq, bio); 76669cf2d85SEd Cashin bio = bio->bi_next; 76769cf2d85SEd Cashin d->ip.nxbio = bio; 76869cf2d85SEd Cashin if (bio == NULL) 76969cf2d85SEd Cashin d->ip.rq = NULL; 77069cf2d85SEd Cashin return d->ip.buf = buf; 7711da177e4SLinus Torvalds } 7721da177e4SLinus Torvalds 77368e0d42fSEd L. Cashin /* enters with d->lock held */ 77468e0d42fSEd L. Cashin void 77568e0d42fSEd L. Cashin aoecmd_work(struct aoedev *d) 77668e0d42fSEd L. Cashin { 77768e0d42fSEd L. Cashin if (d->htgt && !sthtith(d)) 77868e0d42fSEd L. Cashin return; 77969cf2d85SEd Cashin while (aoecmd_ata_rw(d)) 78069cf2d85SEd Cashin ; 78168e0d42fSEd L. Cashin } 78268e0d42fSEd L. Cashin 7833ae1c24eSEd L. Cashin /* this function performs work that has been deferred until sleeping is OK 7843ae1c24eSEd L. Cashin */ 7853ae1c24eSEd L. Cashin void 786c4028958SDavid Howells aoecmd_sleepwork(struct work_struct *work) 7873ae1c24eSEd L. Cashin { 788c4028958SDavid Howells struct aoedev *d = container_of(work, struct aoedev, work); 7893ae1c24eSEd L. Cashin 7903ae1c24eSEd L. Cashin if (d->flags & DEVFL_GDALLOC) 7913ae1c24eSEd L. Cashin aoeblk_gdalloc(d); 7923ae1c24eSEd L. Cashin 7933ae1c24eSEd L. Cashin if (d->flags & DEVFL_NEWSIZE) { 7943ae1c24eSEd L. Cashin struct block_device *bd; 7953ae1c24eSEd L. Cashin unsigned long flags; 7963ae1c24eSEd L. Cashin u64 ssize; 7973ae1c24eSEd L. Cashin 79880795aefSTejun Heo ssize = get_capacity(d->gd); 7993ae1c24eSEd L. Cashin bd = bdget_disk(d->gd, 0); 8003ae1c24eSEd L. Cashin 8013ae1c24eSEd L. Cashin if (bd) { 8023ae1c24eSEd L. Cashin mutex_lock(&bd->bd_inode->i_mutex); 8033ae1c24eSEd L. Cashin i_size_write(bd->bd_inode, (loff_t)ssize<<9); 8043ae1c24eSEd L. Cashin mutex_unlock(&bd->bd_inode->i_mutex); 8053ae1c24eSEd L. Cashin bdput(bd); 8063ae1c24eSEd L. Cashin } 8073ae1c24eSEd L. Cashin spin_lock_irqsave(&d->lock, flags); 8083ae1c24eSEd L. Cashin d->flags |= DEVFL_UP; 8093ae1c24eSEd L. Cashin d->flags &= ~DEVFL_NEWSIZE; 8103ae1c24eSEd L. Cashin spin_unlock_irqrestore(&d->lock, flags); 8113ae1c24eSEd L. Cashin } 8123ae1c24eSEd L. Cashin } 8133ae1c24eSEd L. Cashin 8141da177e4SLinus Torvalds static void 81568e0d42fSEd L. Cashin ataid_complete(struct aoedev *d, struct aoetgt *t, unsigned char *id) 8161da177e4SLinus Torvalds { 8171da177e4SLinus Torvalds u64 ssize; 8181da177e4SLinus Torvalds u16 n; 8191da177e4SLinus Torvalds 8201da177e4SLinus Torvalds /* word 83: command set supported */ 821f885f8d1SHarvey Harrison n = get_unaligned_le16(&id[83 << 1]); 8221da177e4SLinus Torvalds 8231da177e4SLinus Torvalds /* word 86: command set/feature enabled */ 824f885f8d1SHarvey Harrison n |= get_unaligned_le16(&id[86 << 1]); 8251da177e4SLinus Torvalds 8261da177e4SLinus Torvalds if (n & (1<<10)) { /* bit 10: LBA 48 */ 8271da177e4SLinus Torvalds d->flags |= DEVFL_EXT; 8281da177e4SLinus Torvalds 8291da177e4SLinus Torvalds /* word 100: number lba48 sectors */ 830f885f8d1SHarvey Harrison ssize = get_unaligned_le64(&id[100 << 1]); 8311da177e4SLinus Torvalds 8321da177e4SLinus Torvalds /* set as in ide-disk.c:init_idedisk_capacity */ 8331da177e4SLinus Torvalds d->geo.cylinders = ssize; 8341da177e4SLinus Torvalds d->geo.cylinders /= (255 * 63); 8351da177e4SLinus Torvalds d->geo.heads = 255; 8361da177e4SLinus Torvalds d->geo.sectors = 63; 8371da177e4SLinus Torvalds } else { 8381da177e4SLinus Torvalds d->flags &= ~DEVFL_EXT; 8391da177e4SLinus Torvalds 8401da177e4SLinus Torvalds /* number lba28 sectors */ 841f885f8d1SHarvey Harrison ssize = get_unaligned_le32(&id[60 << 1]); 8421da177e4SLinus Torvalds 8431da177e4SLinus Torvalds /* NOTE: obsolete in ATA 6 */ 844f885f8d1SHarvey Harrison d->geo.cylinders = get_unaligned_le16(&id[54 << 1]); 845f885f8d1SHarvey Harrison d->geo.heads = get_unaligned_le16(&id[55 << 1]); 846f885f8d1SHarvey Harrison d->geo.sectors = get_unaligned_le16(&id[56 << 1]); 8471da177e4SLinus Torvalds } 8483ae1c24eSEd L. Cashin 8493ae1c24eSEd L. Cashin if (d->ssize != ssize) 8501d75981aSEd L. Cashin printk(KERN_INFO 851411c41eeSHarvey Harrison "aoe: %pm e%ld.%d v%04x has %llu sectors\n", 852411c41eeSHarvey Harrison t->addr, 8533ae1c24eSEd L. Cashin d->aoemajor, d->aoeminor, 8543ae1c24eSEd L. Cashin d->fw_ver, (long long)ssize); 8551da177e4SLinus Torvalds d->ssize = ssize; 8561da177e4SLinus Torvalds d->geo.start = 0; 8576b9699bbSEd L. Cashin if (d->flags & (DEVFL_GDALLOC|DEVFL_NEWSIZE)) 8586b9699bbSEd L. Cashin return; 8591da177e4SLinus Torvalds if (d->gd != NULL) { 86080795aefSTejun Heo set_capacity(d->gd, ssize); 8613ae1c24eSEd L. Cashin d->flags |= DEVFL_NEWSIZE; 86268e0d42fSEd L. Cashin } else 8633ae1c24eSEd L. Cashin d->flags |= DEVFL_GDALLOC; 8641da177e4SLinus Torvalds schedule_work(&d->work); 8651da177e4SLinus Torvalds } 8661da177e4SLinus Torvalds 8671da177e4SLinus Torvalds static void 8681da177e4SLinus Torvalds calc_rttavg(struct aoedev *d, int rtt) 8691da177e4SLinus Torvalds { 8701da177e4SLinus Torvalds register long n; 8711da177e4SLinus Torvalds 8721da177e4SLinus Torvalds n = rtt; 873dced3a05SEd L. Cashin if (n < 0) { 874dced3a05SEd L. Cashin n = -rtt; 8751da177e4SLinus Torvalds if (n < MINTIMER) 8761da177e4SLinus Torvalds n = MINTIMER; 8771da177e4SLinus Torvalds else if (n > MAXTIMER) 8781da177e4SLinus Torvalds n = MAXTIMER; 879dced3a05SEd L. Cashin d->mintimer += (n - d->mintimer) >> 1; 880dced3a05SEd L. Cashin } else if (n < d->mintimer) 881dced3a05SEd L. Cashin n = d->mintimer; 882dced3a05SEd L. Cashin else if (n > MAXTIMER) 883dced3a05SEd L. Cashin n = MAXTIMER; 8841da177e4SLinus Torvalds 8851da177e4SLinus Torvalds /* g == .25; cf. Congestion Avoidance and Control, Jacobson & Karels; 1988 */ 8861da177e4SLinus Torvalds n -= d->rttavg; 8871da177e4SLinus Torvalds d->rttavg += n >> 2; 8881da177e4SLinus Torvalds } 8891da177e4SLinus Torvalds 89068e0d42fSEd L. Cashin static struct aoetgt * 89168e0d42fSEd L. Cashin gettgt(struct aoedev *d, char *addr) 89268e0d42fSEd L. Cashin { 89368e0d42fSEd L. Cashin struct aoetgt **t, **e; 89468e0d42fSEd L. Cashin 89568e0d42fSEd L. Cashin t = d->targets; 89668e0d42fSEd L. Cashin e = t + NTARGETS; 89768e0d42fSEd L. Cashin for (; t < e && *t; t++) 89868e0d42fSEd L. Cashin if (memcmp((*t)->addr, addr, sizeof((*t)->addr)) == 0) 89968e0d42fSEd L. Cashin return *t; 90068e0d42fSEd L. Cashin return NULL; 90168e0d42fSEd L. Cashin } 90268e0d42fSEd L. Cashin 9033d5b0605SEd Cashin static void 904896831f5SEd Cashin bvcpy(struct bio_vec *bv, ulong off, struct sk_buff *skb, long cnt) 9053d5b0605SEd Cashin { 9063d5b0605SEd Cashin ulong fcnt; 9073d5b0605SEd Cashin char *p; 9083d5b0605SEd Cashin int soff = 0; 9093d5b0605SEd Cashin loop: 9103d5b0605SEd Cashin fcnt = bv->bv_len - (off - bv->bv_offset); 9113d5b0605SEd Cashin if (fcnt > cnt) 9123d5b0605SEd Cashin fcnt = cnt; 9133d5b0605SEd Cashin p = page_address(bv->bv_page) + off; 9143d5b0605SEd Cashin skb_copy_bits(skb, soff, p, fcnt); 9153d5b0605SEd Cashin soff += fcnt; 9163d5b0605SEd Cashin cnt -= fcnt; 9173d5b0605SEd Cashin if (cnt <= 0) 9183d5b0605SEd Cashin return; 9193d5b0605SEd Cashin bv++; 9203d5b0605SEd Cashin off = bv->bv_offset; 9213d5b0605SEd Cashin goto loop; 9223d5b0605SEd Cashin } 9233d5b0605SEd Cashin 92469cf2d85SEd Cashin void 92569cf2d85SEd Cashin aoe_end_request(struct aoedev *d, struct request *rq, int fastfail) 92669cf2d85SEd Cashin { 92769cf2d85SEd Cashin struct bio *bio; 92869cf2d85SEd Cashin int bok; 92969cf2d85SEd Cashin struct request_queue *q; 93069cf2d85SEd Cashin 93169cf2d85SEd Cashin q = d->blkq; 93269cf2d85SEd Cashin if (rq == d->ip.rq) 93369cf2d85SEd Cashin d->ip.rq = NULL; 93469cf2d85SEd Cashin do { 93569cf2d85SEd Cashin bio = rq->bio; 93669cf2d85SEd Cashin bok = !fastfail && test_bit(BIO_UPTODATE, &bio->bi_flags); 93769cf2d85SEd Cashin } while (__blk_end_request(rq, bok ? 0 : -EIO, bio->bi_size)); 93869cf2d85SEd Cashin 93969cf2d85SEd Cashin /* cf. http://lkml.org/lkml/2006/10/31/28 */ 94069cf2d85SEd Cashin if (!fastfail) 94169cf2d85SEd Cashin q->request_fn(q); 94269cf2d85SEd Cashin } 94369cf2d85SEd Cashin 94469cf2d85SEd Cashin static void 94569cf2d85SEd Cashin aoe_end_buf(struct aoedev *d, struct buf *buf) 94669cf2d85SEd Cashin { 94769cf2d85SEd Cashin struct request *rq; 94869cf2d85SEd Cashin unsigned long n; 94969cf2d85SEd Cashin 95069cf2d85SEd Cashin if (buf == d->ip.buf) 95169cf2d85SEd Cashin d->ip.buf = NULL; 95269cf2d85SEd Cashin rq = buf->rq; 95369cf2d85SEd Cashin bio_pagedec(buf->bio); 95469cf2d85SEd Cashin mempool_free(buf, d->bufpool); 95569cf2d85SEd Cashin n = (unsigned long) rq->special; 95669cf2d85SEd Cashin rq->special = (void *) --n; 95769cf2d85SEd Cashin if (n == 0) 95869cf2d85SEd Cashin aoe_end_request(d, rq, 0); 95969cf2d85SEd Cashin } 96069cf2d85SEd Cashin 9613d5b0605SEd Cashin static void 962896831f5SEd Cashin ktiocomplete(struct frame *f) 9633d5b0605SEd Cashin { 964ddec63e8SEd L. Cashin struct aoe_hdr *hin, *hout; 9651da177e4SLinus Torvalds struct aoe_atahdr *ahin, *ahout; 9661da177e4SLinus Torvalds struct buf *buf; 967896831f5SEd Cashin struct sk_buff *skb; 96868e0d42fSEd L. Cashin struct aoetgt *t; 96968e0d42fSEd L. Cashin struct aoeif *ifp; 970896831f5SEd Cashin struct aoedev *d; 971896831f5SEd Cashin long n; 972896831f5SEd Cashin 973896831f5SEd Cashin if (f == NULL) 974896831f5SEd Cashin return; 975896831f5SEd Cashin 976896831f5SEd Cashin t = f->t; 977896831f5SEd Cashin d = t->d; 978896831f5SEd Cashin 979896831f5SEd Cashin hout = (struct aoe_hdr *) skb_mac_header(f->skb); 980896831f5SEd Cashin ahout = (struct aoe_atahdr *) (hout+1); 981896831f5SEd Cashin buf = f->buf; 982896831f5SEd Cashin skb = f->r_skb; 983896831f5SEd Cashin if (skb == NULL) 984896831f5SEd Cashin goto noskb; /* just fail the buf. */ 985896831f5SEd Cashin 986896831f5SEd Cashin hin = (struct aoe_hdr *) skb->data; 987896831f5SEd Cashin skb_pull(skb, sizeof(*hin)); 988896831f5SEd Cashin ahin = (struct aoe_atahdr *) skb->data; 989896831f5SEd Cashin skb_pull(skb, sizeof(*ahin)); 990896831f5SEd Cashin if (ahin->cmdstat & 0xa9) { /* these bits cleared on success */ 991896831f5SEd Cashin pr_err("aoe: ata error cmd=%2.2Xh stat=%2.2Xh from e%ld.%d\n", 992896831f5SEd Cashin ahout->cmdstat, ahin->cmdstat, 993896831f5SEd Cashin d->aoemajor, d->aoeminor); 994896831f5SEd Cashin noskb: if (buf) 99569cf2d85SEd Cashin clear_bit(BIO_UPTODATE, &buf->bio->bi_flags); 996896831f5SEd Cashin goto badrsp; 997896831f5SEd Cashin } 998896831f5SEd Cashin 999896831f5SEd Cashin n = ahout->scnt << 9; 1000896831f5SEd Cashin switch (ahout->cmdstat) { 1001896831f5SEd Cashin case ATA_CMD_PIO_READ: 1002896831f5SEd Cashin case ATA_CMD_PIO_READ_EXT: 1003896831f5SEd Cashin if (skb->len < n) { 1004896831f5SEd Cashin pr_err("aoe: runt data size in read. skb->len=%d need=%ld\n", 1005896831f5SEd Cashin skb->len, n); 100669cf2d85SEd Cashin clear_bit(BIO_UPTODATE, &buf->bio->bi_flags); 1007896831f5SEd Cashin break; 1008896831f5SEd Cashin } 1009896831f5SEd Cashin bvcpy(f->bv, f->bv_off, skb, n); 1010896831f5SEd Cashin case ATA_CMD_PIO_WRITE: 1011896831f5SEd Cashin case ATA_CMD_PIO_WRITE_EXT: 1012896831f5SEd Cashin spin_lock_irq(&d->lock); 1013896831f5SEd Cashin ifp = getif(t, skb->dev); 1014*3f0f0133SEd Cashin if (ifp) 1015896831f5SEd Cashin ifp->lost = 0; 1016896831f5SEd Cashin if (d->htgt == t) /* I'll help myself, thank you. */ 1017896831f5SEd Cashin d->htgt = NULL; 1018896831f5SEd Cashin spin_unlock_irq(&d->lock); 1019896831f5SEd Cashin break; 1020896831f5SEd Cashin case ATA_CMD_ID_ATA: 1021896831f5SEd Cashin if (skb->len < 512) { 1022896831f5SEd Cashin pr_info("aoe: runt data size in ataid. skb->len=%d\n", 1023896831f5SEd Cashin skb->len); 1024896831f5SEd Cashin break; 1025896831f5SEd Cashin } 1026896831f5SEd Cashin if (skb_linearize(skb)) 1027896831f5SEd Cashin break; 1028896831f5SEd Cashin spin_lock_irq(&d->lock); 1029896831f5SEd Cashin ataid_complete(d, t, skb->data); 1030896831f5SEd Cashin spin_unlock_irq(&d->lock); 1031896831f5SEd Cashin break; 1032896831f5SEd Cashin default: 1033896831f5SEd Cashin pr_info("aoe: unrecognized ata command %2.2Xh for %d.%d\n", 1034896831f5SEd Cashin ahout->cmdstat, 1035896831f5SEd Cashin be16_to_cpu(get_unaligned(&hin->major)), 1036896831f5SEd Cashin hin->minor); 1037896831f5SEd Cashin } 1038896831f5SEd Cashin badrsp: 1039896831f5SEd Cashin spin_lock_irq(&d->lock); 1040896831f5SEd Cashin 1041896831f5SEd Cashin aoe_freetframe(f); 1042896831f5SEd Cashin 104369cf2d85SEd Cashin if (buf && --buf->nframesout == 0 && buf->resid == 0) 104469cf2d85SEd Cashin aoe_end_buf(d, buf); 1045896831f5SEd Cashin 104669cf2d85SEd Cashin aoecmd_work(d); 104769cf2d85SEd Cashin 1048896831f5SEd Cashin spin_unlock_irq(&d->lock); 104969cf2d85SEd Cashin aoedev_put(d); 1050896831f5SEd Cashin dev_kfree_skb(skb); 1051896831f5SEd Cashin } 1052896831f5SEd Cashin 1053896831f5SEd Cashin /* Enters with iocq.lock held. 1054896831f5SEd Cashin * Returns true iff responses needing processing remain. 1055896831f5SEd Cashin */ 1056896831f5SEd Cashin static int 1057896831f5SEd Cashin ktio(void) 1058896831f5SEd Cashin { 1059896831f5SEd Cashin struct frame *f; 1060896831f5SEd Cashin struct list_head *pos; 1061896831f5SEd Cashin int i; 1062896831f5SEd Cashin 1063896831f5SEd Cashin for (i = 0; ; ++i) { 1064896831f5SEd Cashin if (i == MAXIOC) 1065896831f5SEd Cashin return 1; 1066896831f5SEd Cashin if (list_empty(&iocq.head)) 1067896831f5SEd Cashin return 0; 1068896831f5SEd Cashin pos = iocq.head.next; 1069896831f5SEd Cashin list_del(pos); 1070896831f5SEd Cashin spin_unlock_irq(&iocq.lock); 1071896831f5SEd Cashin f = list_entry(pos, struct frame, head); 1072896831f5SEd Cashin ktiocomplete(f); 1073896831f5SEd Cashin spin_lock_irq(&iocq.lock); 1074896831f5SEd Cashin } 1075896831f5SEd Cashin } 1076896831f5SEd Cashin 1077896831f5SEd Cashin static int 1078896831f5SEd Cashin kthread(void *vp) 1079896831f5SEd Cashin { 1080896831f5SEd Cashin struct ktstate *k; 1081896831f5SEd Cashin DECLARE_WAITQUEUE(wait, current); 1082896831f5SEd Cashin int more; 1083896831f5SEd Cashin 1084896831f5SEd Cashin k = vp; 1085896831f5SEd Cashin current->flags |= PF_NOFREEZE; 1086896831f5SEd Cashin set_user_nice(current, -10); 1087896831f5SEd Cashin complete(&k->rendez); /* tell spawner we're running */ 1088896831f5SEd Cashin do { 1089896831f5SEd Cashin spin_lock_irq(k->lock); 1090896831f5SEd Cashin more = k->fn(); 1091896831f5SEd Cashin if (!more) { 1092896831f5SEd Cashin add_wait_queue(k->waitq, &wait); 1093896831f5SEd Cashin __set_current_state(TASK_INTERRUPTIBLE); 1094896831f5SEd Cashin } 1095896831f5SEd Cashin spin_unlock_irq(k->lock); 1096896831f5SEd Cashin if (!more) { 1097896831f5SEd Cashin schedule(); 1098896831f5SEd Cashin remove_wait_queue(k->waitq, &wait); 1099896831f5SEd Cashin } else 1100896831f5SEd Cashin cond_resched(); 1101896831f5SEd Cashin } while (!kthread_should_stop()); 1102896831f5SEd Cashin complete(&k->rendez); /* tell spawner we're stopping */ 1103896831f5SEd Cashin return 0; 1104896831f5SEd Cashin } 1105896831f5SEd Cashin 1106eb086ec5SEd Cashin void 1107896831f5SEd Cashin aoe_ktstop(struct ktstate *k) 1108896831f5SEd Cashin { 1109896831f5SEd Cashin kthread_stop(k->task); 1110896831f5SEd Cashin wait_for_completion(&k->rendez); 1111896831f5SEd Cashin } 1112896831f5SEd Cashin 1113eb086ec5SEd Cashin int 1114896831f5SEd Cashin aoe_ktstart(struct ktstate *k) 1115896831f5SEd Cashin { 1116896831f5SEd Cashin struct task_struct *task; 1117896831f5SEd Cashin 1118896831f5SEd Cashin init_completion(&k->rendez); 1119896831f5SEd Cashin task = kthread_run(kthread, k, k->name); 1120896831f5SEd Cashin if (task == NULL || IS_ERR(task)) 1121896831f5SEd Cashin return -ENOMEM; 1122896831f5SEd Cashin k->task = task; 1123896831f5SEd Cashin wait_for_completion(&k->rendez); /* allow kthread to start */ 1124896831f5SEd Cashin init_completion(&k->rendez); /* for waiting for exit later */ 1125896831f5SEd Cashin return 0; 1126896831f5SEd Cashin } 1127896831f5SEd Cashin 1128896831f5SEd Cashin /* pass it off to kthreads for processing */ 1129896831f5SEd Cashin static void 1130896831f5SEd Cashin ktcomplete(struct frame *f, struct sk_buff *skb) 1131896831f5SEd Cashin { 1132896831f5SEd Cashin ulong flags; 1133896831f5SEd Cashin 1134896831f5SEd Cashin f->r_skb = skb; 1135896831f5SEd Cashin spin_lock_irqsave(&iocq.lock, flags); 1136896831f5SEd Cashin list_add_tail(&f->head, &iocq.head); 1137896831f5SEd Cashin spin_unlock_irqrestore(&iocq.lock, flags); 1138896831f5SEd Cashin wake_up(&ktiowq); 1139896831f5SEd Cashin } 1140896831f5SEd Cashin 1141896831f5SEd Cashin struct sk_buff * 1142896831f5SEd Cashin aoecmd_ata_rsp(struct sk_buff *skb) 1143896831f5SEd Cashin { 1144896831f5SEd Cashin struct aoedev *d; 1145896831f5SEd Cashin struct aoe_hdr *h; 1146896831f5SEd Cashin struct frame *f; 1147896831f5SEd Cashin struct aoetgt *t; 1148896831f5SEd Cashin u32 n; 11491da177e4SLinus Torvalds ulong flags; 11501da177e4SLinus Torvalds char ebuf[128]; 115132465c65Secashin@coraid.com u16 aoemajor; 11521da177e4SLinus Torvalds 1153896831f5SEd Cashin h = (struct aoe_hdr *) skb->data; 1154896831f5SEd Cashin aoemajor = be16_to_cpu(get_unaligned(&h->major)); 1155896831f5SEd Cashin d = aoedev_by_aoeaddr(aoemajor, h->minor); 11561da177e4SLinus Torvalds if (d == NULL) { 11571da177e4SLinus Torvalds snprintf(ebuf, sizeof ebuf, "aoecmd_ata_rsp: ata response " 11581da177e4SLinus Torvalds "for unknown device %d.%d\n", 1159896831f5SEd Cashin aoemajor, h->minor); 11601da177e4SLinus Torvalds aoechr_error(ebuf); 1161896831f5SEd Cashin return skb; 11621da177e4SLinus Torvalds } 11631da177e4SLinus Torvalds 11641da177e4SLinus Torvalds spin_lock_irqsave(&d->lock, flags); 11651da177e4SLinus Torvalds 1166896831f5SEd Cashin n = be32_to_cpu(get_unaligned(&h->tag)); 1167896831f5SEd Cashin t = gettgt(d, h->src); 116868e0d42fSEd L. Cashin if (t == NULL) { 1169411c41eeSHarvey Harrison printk(KERN_INFO "aoe: can't find target e%ld.%d:%pm\n", 1170896831f5SEd Cashin d->aoemajor, d->aoeminor, h->src); 117168e0d42fSEd L. Cashin spin_unlock_irqrestore(&d->lock, flags); 117269cf2d85SEd Cashin aoedev_put(d); 1173896831f5SEd Cashin return skb; 117468e0d42fSEd L. Cashin } 117568e0d42fSEd L. Cashin f = getframe(t, n); 11761da177e4SLinus Torvalds if (f == NULL) { 1177dced3a05SEd L. Cashin calc_rttavg(d, -tsince(n)); 11781da177e4SLinus Torvalds spin_unlock_irqrestore(&d->lock, flags); 117969cf2d85SEd Cashin aoedev_put(d); 11801da177e4SLinus Torvalds snprintf(ebuf, sizeof ebuf, 11811da177e4SLinus Torvalds "%15s e%d.%d tag=%08x@%08lx\n", 11821da177e4SLinus Torvalds "unexpected rsp", 1183896831f5SEd Cashin get_unaligned_be16(&h->major), 1184896831f5SEd Cashin h->minor, 1185896831f5SEd Cashin get_unaligned_be32(&h->tag), 11861da177e4SLinus Torvalds jiffies); 11871da177e4SLinus Torvalds aoechr_error(ebuf); 1188896831f5SEd Cashin return skb; 11891da177e4SLinus Torvalds } 11901da177e4SLinus Torvalds calc_rttavg(d, tsince(f->tag)); 119168e0d42fSEd L. Cashin t->nout--; 11921da177e4SLinus Torvalds aoecmd_work(d); 11931da177e4SLinus Torvalds 11941da177e4SLinus Torvalds spin_unlock_irqrestore(&d->lock, flags); 1195896831f5SEd Cashin 1196896831f5SEd Cashin ktcomplete(f, skb); 1197896831f5SEd Cashin 1198896831f5SEd Cashin /* 1199896831f5SEd Cashin * Note here that we do not perform an aoedev_put, as we are 1200896831f5SEd Cashin * leaving this reference for the ktio to release. 1201896831f5SEd Cashin */ 1202896831f5SEd Cashin return NULL; 12031da177e4SLinus Torvalds } 12041da177e4SLinus Torvalds 12051da177e4SLinus Torvalds void 12061da177e4SLinus Torvalds aoecmd_cfg(ushort aoemajor, unsigned char aoeminor) 12071da177e4SLinus Torvalds { 1208e9bb8fb0SDavid S. Miller struct sk_buff_head queue; 12091da177e4SLinus Torvalds 1210e9bb8fb0SDavid S. Miller __skb_queue_head_init(&queue); 1211e9bb8fb0SDavid S. Miller aoecmd_cfg_pkts(aoemajor, aoeminor, &queue); 1212e9bb8fb0SDavid S. Miller aoenet_xmit(&queue); 12131da177e4SLinus Torvalds } 12141da177e4SLinus Torvalds 121568e0d42fSEd L. Cashin struct sk_buff * 12161da177e4SLinus Torvalds aoecmd_ata_id(struct aoedev *d) 12171da177e4SLinus Torvalds { 12181da177e4SLinus Torvalds struct aoe_hdr *h; 12191da177e4SLinus Torvalds struct aoe_atahdr *ah; 12201da177e4SLinus Torvalds struct frame *f; 12211da177e4SLinus Torvalds struct sk_buff *skb; 122268e0d42fSEd L. Cashin struct aoetgt *t; 12231da177e4SLinus Torvalds 1224896831f5SEd Cashin f = newframe(d); 122568e0d42fSEd L. Cashin if (f == NULL) 12261da177e4SLinus Torvalds return NULL; 122768e0d42fSEd L. Cashin 122868e0d42fSEd L. Cashin t = *d->tgt; 12291da177e4SLinus Torvalds 12301da177e4SLinus Torvalds /* initialize the headers & frame */ 1231e407a7f6SEd L. Cashin skb = f->skb; 1232abdbf94dSEd L. Cashin h = (struct aoe_hdr *) skb_mac_header(skb); 12331da177e4SLinus Torvalds ah = (struct aoe_atahdr *) (h+1); 123419900cdeSEd L. Cashin skb_put(skb, sizeof *h + sizeof *ah); 123519900cdeSEd L. Cashin memset(h, 0, skb->len); 123668e0d42fSEd L. Cashin f->tag = aoehdr_atainit(d, t, h); 1237896831f5SEd Cashin fhash(f); 123868e0d42fSEd L. Cashin t->nout++; 12391da177e4SLinus Torvalds f->waited = 0; 12401da177e4SLinus Torvalds 12411da177e4SLinus Torvalds /* set up ata header */ 12421da177e4SLinus Torvalds ah->scnt = 1; 124304b3ab52SBartlomiej Zolnierkiewicz ah->cmdstat = ATA_CMD_ID_ATA; 12441da177e4SLinus Torvalds ah->lba3 = 0xa0; 12451da177e4SLinus Torvalds 124668e0d42fSEd L. Cashin skb->dev = t->ifp->nd; 12471da177e4SLinus Torvalds 12483ae1c24eSEd L. Cashin d->rttavg = MAXTIMER; 12491da177e4SLinus Torvalds d->timer.function = rexmit_timer; 12501da177e4SLinus Torvalds 12514f51dc5eSEd L. Cashin return skb_clone(skb, GFP_ATOMIC); 12521da177e4SLinus Torvalds } 12531da177e4SLinus Torvalds 125468e0d42fSEd L. Cashin static struct aoetgt * 125568e0d42fSEd L. Cashin addtgt(struct aoedev *d, char *addr, ulong nframes) 125668e0d42fSEd L. Cashin { 125768e0d42fSEd L. Cashin struct aoetgt *t, **tt, **te; 1258896831f5SEd Cashin int i; 125968e0d42fSEd L. Cashin 126068e0d42fSEd L. Cashin tt = d->targets; 126168e0d42fSEd L. Cashin te = tt + NTARGETS; 126268e0d42fSEd L. Cashin for (; tt < te && *tt; tt++) 126368e0d42fSEd L. Cashin ; 126468e0d42fSEd L. Cashin 1265578c4aa0SEd L. Cashin if (tt == te) { 1266578c4aa0SEd L. Cashin printk(KERN_INFO 1267578c4aa0SEd L. Cashin "aoe: device addtgt failure; too many targets\n"); 126868e0d42fSEd L. Cashin return NULL; 1269578c4aa0SEd L. Cashin } 1270896831f5SEd Cashin t = kzalloc(sizeof(*t), GFP_ATOMIC); 1271896831f5SEd Cashin if (!t) { 1272578c4aa0SEd L. Cashin printk(KERN_INFO "aoe: cannot allocate memory to add target\n"); 12739bb237b6SEd L. Cashin return NULL; 12749bb237b6SEd L. Cashin } 12759bb237b6SEd L. Cashin 1276896831f5SEd Cashin d->ntargets++; 127768e0d42fSEd L. Cashin t->nframes = nframes; 1278896831f5SEd Cashin t->d = d; 127968e0d42fSEd L. Cashin memcpy(t->addr, addr, sizeof t->addr); 128068e0d42fSEd L. Cashin t->ifp = t->ifs; 128168e0d42fSEd L. Cashin t->maxout = t->nframes; 1282896831f5SEd Cashin INIT_LIST_HEAD(&t->ffree); 1283896831f5SEd Cashin for (i = 0; i < NFACTIVE; ++i) 1284896831f5SEd Cashin INIT_LIST_HEAD(&t->factive[i]); 128568e0d42fSEd L. Cashin return *tt = t; 128668e0d42fSEd L. Cashin } 128768e0d42fSEd L. Cashin 1288*3f0f0133SEd Cashin static void 1289*3f0f0133SEd Cashin setdbcnt(struct aoedev *d) 1290*3f0f0133SEd Cashin { 1291*3f0f0133SEd Cashin struct aoetgt **t, **e; 1292*3f0f0133SEd Cashin int bcnt = 0; 1293*3f0f0133SEd Cashin 1294*3f0f0133SEd Cashin t = d->targets; 1295*3f0f0133SEd Cashin e = t + NTARGETS; 1296*3f0f0133SEd Cashin for (; t < e && *t; t++) 1297*3f0f0133SEd Cashin if (bcnt == 0 || bcnt > (*t)->minbcnt) 1298*3f0f0133SEd Cashin bcnt = (*t)->minbcnt; 1299*3f0f0133SEd Cashin if (bcnt != d->maxbcnt) { 1300*3f0f0133SEd Cashin d->maxbcnt = bcnt; 1301*3f0f0133SEd Cashin pr_info("aoe: e%ld.%d: setting %d byte data frames\n", 1302*3f0f0133SEd Cashin d->aoemajor, d->aoeminor, bcnt); 1303*3f0f0133SEd Cashin } 1304*3f0f0133SEd Cashin } 1305*3f0f0133SEd Cashin 1306*3f0f0133SEd Cashin static void 1307*3f0f0133SEd Cashin setifbcnt(struct aoetgt *t, struct net_device *nd, int bcnt) 1308*3f0f0133SEd Cashin { 1309*3f0f0133SEd Cashin struct aoedev *d; 1310*3f0f0133SEd Cashin struct aoeif *p, *e; 1311*3f0f0133SEd Cashin int minbcnt; 1312*3f0f0133SEd Cashin 1313*3f0f0133SEd Cashin d = t->d; 1314*3f0f0133SEd Cashin minbcnt = bcnt; 1315*3f0f0133SEd Cashin p = t->ifs; 1316*3f0f0133SEd Cashin e = p + NAOEIFS; 1317*3f0f0133SEd Cashin for (; p < e; p++) { 1318*3f0f0133SEd Cashin if (p->nd == NULL) 1319*3f0f0133SEd Cashin break; /* end of the valid interfaces */ 1320*3f0f0133SEd Cashin if (p->nd == nd) { 1321*3f0f0133SEd Cashin p->bcnt = bcnt; /* we're updating */ 1322*3f0f0133SEd Cashin nd = NULL; 1323*3f0f0133SEd Cashin } else if (minbcnt > p->bcnt) 1324*3f0f0133SEd Cashin minbcnt = p->bcnt; /* find the min interface */ 1325*3f0f0133SEd Cashin } 1326*3f0f0133SEd Cashin if (nd) { 1327*3f0f0133SEd Cashin if (p == e) { 1328*3f0f0133SEd Cashin pr_err("aoe: device setifbcnt failure; too many interfaces.\n"); 1329*3f0f0133SEd Cashin return; 1330*3f0f0133SEd Cashin } 1331*3f0f0133SEd Cashin p->nd = nd; 1332*3f0f0133SEd Cashin p->bcnt = bcnt; 1333*3f0f0133SEd Cashin } 1334*3f0f0133SEd Cashin t->minbcnt = minbcnt; 1335*3f0f0133SEd Cashin setdbcnt(d); 1336*3f0f0133SEd Cashin } 1337*3f0f0133SEd Cashin 13381da177e4SLinus Torvalds void 13391da177e4SLinus Torvalds aoecmd_cfg_rsp(struct sk_buff *skb) 13401da177e4SLinus Torvalds { 13411da177e4SLinus Torvalds struct aoedev *d; 13421da177e4SLinus Torvalds struct aoe_hdr *h; 13431da177e4SLinus Torvalds struct aoe_cfghdr *ch; 134468e0d42fSEd L. Cashin struct aoetgt *t; 134563e9cc5dSecashin@coraid.com ulong flags, sysminor, aoemajor; 13461da177e4SLinus Torvalds struct sk_buff *sl; 134769cf2d85SEd Cashin struct sk_buff_head queue; 134819bf2635SEd L. Cashin u16 n; 13491da177e4SLinus Torvalds 135069cf2d85SEd Cashin sl = NULL; 1351abdbf94dSEd L. Cashin h = (struct aoe_hdr *) skb_mac_header(skb); 13521da177e4SLinus Torvalds ch = (struct aoe_cfghdr *) (h+1); 13531da177e4SLinus Torvalds 13541da177e4SLinus Torvalds /* 13551da177e4SLinus Torvalds * Enough people have their dip switches set backwards to 13561da177e4SLinus Torvalds * warrant a loud message for this special case. 13571da177e4SLinus Torvalds */ 1358823ed72eSHarvey Harrison aoemajor = get_unaligned_be16(&h->major); 13591da177e4SLinus Torvalds if (aoemajor == 0xfff) { 1360a12c93f0SEd L. Cashin printk(KERN_ERR "aoe: Warning: shelf address is all ones. " 13616bb6285fSEd L. Cashin "Check shelf dip switches.\n"); 13621da177e4SLinus Torvalds return; 13631da177e4SLinus Torvalds } 13641da177e4SLinus Torvalds 13651da177e4SLinus Torvalds sysminor = SYSMINOR(aoemajor, h->minor); 1366fc458dcdSecashin@coraid.com if (sysminor * AOE_PARTITIONS + AOE_PARTITIONS > MINORMASK) { 1367a12c93f0SEd L. Cashin printk(KERN_INFO "aoe: e%ld.%d: minor number too large\n", 1368fc458dcdSecashin@coraid.com aoemajor, (int) h->minor); 13691da177e4SLinus Torvalds return; 13701da177e4SLinus Torvalds } 13711da177e4SLinus Torvalds 137219bf2635SEd L. Cashin n = be16_to_cpu(ch->bufcnt); 13737df620d8SEd L. Cashin if (n > aoe_maxout) /* keep it reasonable */ 13747df620d8SEd L. Cashin n = aoe_maxout; 13751da177e4SLinus Torvalds 137668e0d42fSEd L. Cashin d = aoedev_by_sysminor_m(sysminor); 13771da177e4SLinus Torvalds if (d == NULL) { 1378a12c93f0SEd L. Cashin printk(KERN_INFO "aoe: device sysminor_m failure\n"); 13791da177e4SLinus Torvalds return; 13801da177e4SLinus Torvalds } 13811da177e4SLinus Torvalds 13821da177e4SLinus Torvalds spin_lock_irqsave(&d->lock, flags); 13831da177e4SLinus Torvalds 138468e0d42fSEd L. Cashin t = gettgt(d, h->src); 138568e0d42fSEd L. Cashin if (!t) { 138668e0d42fSEd L. Cashin t = addtgt(d, h->src, n); 138769cf2d85SEd Cashin if (!t) 138869cf2d85SEd Cashin goto bail; 138968e0d42fSEd L. Cashin } 1390*3f0f0133SEd Cashin n = skb->dev->mtu; 139119bf2635SEd L. Cashin n -= sizeof(struct aoe_hdr) + sizeof(struct aoe_atahdr); 139219bf2635SEd L. Cashin n /= 512; 139319bf2635SEd L. Cashin if (n > ch->scnt) 139419bf2635SEd L. Cashin n = ch->scnt; 13954f51dc5eSEd L. Cashin n = n ? n * 512 : DEFAULTBCNT; 1396*3f0f0133SEd Cashin setifbcnt(t, skb->dev, n); 13973ae1c24eSEd L. Cashin 13983ae1c24eSEd L. Cashin /* don't change users' perspective */ 139969cf2d85SEd Cashin if (d->nopen == 0) { 140063e9cc5dSecashin@coraid.com d->fw_ver = be16_to_cpu(ch->fwver); 140168e0d42fSEd L. Cashin sl = aoecmd_ata_id(d); 140269cf2d85SEd Cashin } 140369cf2d85SEd Cashin bail: 14041da177e4SLinus Torvalds spin_unlock_irqrestore(&d->lock, flags); 140569cf2d85SEd Cashin aoedev_put(d); 1406e9bb8fb0SDavid S. Miller if (sl) { 1407e9bb8fb0SDavid S. Miller __skb_queue_head_init(&queue); 1408e9bb8fb0SDavid S. Miller __skb_queue_tail(&queue, sl); 1409e9bb8fb0SDavid S. Miller aoenet_xmit(&queue); 1410e9bb8fb0SDavid S. Miller } 14111da177e4SLinus Torvalds } 14121da177e4SLinus Torvalds 141368e0d42fSEd L. Cashin void 141468e0d42fSEd L. Cashin aoecmd_cleanslate(struct aoedev *d) 141568e0d42fSEd L. Cashin { 141668e0d42fSEd L. Cashin struct aoetgt **t, **te; 141768e0d42fSEd L. Cashin 141868e0d42fSEd L. Cashin d->mintimer = MINTIMER; 1419*3f0f0133SEd Cashin d->maxbcnt = 0; 142068e0d42fSEd L. Cashin 142168e0d42fSEd L. Cashin t = d->targets; 142268e0d42fSEd L. Cashin te = t + NTARGETS; 1423*3f0f0133SEd Cashin for (; t < te && *t; t++) 142468e0d42fSEd L. Cashin (*t)->maxout = (*t)->nframes; 142568e0d42fSEd L. Cashin } 1426896831f5SEd Cashin 142769cf2d85SEd Cashin void 142869cf2d85SEd Cashin aoe_failbuf(struct aoedev *d, struct buf *buf) 142969cf2d85SEd Cashin { 143069cf2d85SEd Cashin if (buf == NULL) 143169cf2d85SEd Cashin return; 143269cf2d85SEd Cashin buf->resid = 0; 143369cf2d85SEd Cashin clear_bit(BIO_UPTODATE, &buf->bio->bi_flags); 143469cf2d85SEd Cashin if (buf->nframesout == 0) 143569cf2d85SEd Cashin aoe_end_buf(d, buf); 143669cf2d85SEd Cashin } 143769cf2d85SEd Cashin 143869cf2d85SEd Cashin void 143969cf2d85SEd Cashin aoe_flush_iocq(void) 1440896831f5SEd Cashin { 1441896831f5SEd Cashin struct frame *f; 1442896831f5SEd Cashin struct aoedev *d; 1443896831f5SEd Cashin LIST_HEAD(flist); 1444896831f5SEd Cashin struct list_head *pos; 1445896831f5SEd Cashin struct sk_buff *skb; 1446896831f5SEd Cashin ulong flags; 1447896831f5SEd Cashin 1448896831f5SEd Cashin spin_lock_irqsave(&iocq.lock, flags); 1449896831f5SEd Cashin list_splice_init(&iocq.head, &flist); 1450896831f5SEd Cashin spin_unlock_irqrestore(&iocq.lock, flags); 1451896831f5SEd Cashin while (!list_empty(&flist)) { 1452896831f5SEd Cashin pos = flist.next; 1453896831f5SEd Cashin list_del(pos); 1454896831f5SEd Cashin f = list_entry(pos, struct frame, head); 1455896831f5SEd Cashin d = f->t->d; 1456896831f5SEd Cashin skb = f->r_skb; 1457896831f5SEd Cashin spin_lock_irqsave(&d->lock, flags); 1458896831f5SEd Cashin if (f->buf) { 1459896831f5SEd Cashin f->buf->nframesout--; 1460896831f5SEd Cashin aoe_failbuf(d, f->buf); 1461896831f5SEd Cashin } 1462896831f5SEd Cashin aoe_freetframe(f); 1463896831f5SEd Cashin spin_unlock_irqrestore(&d->lock, flags); 1464896831f5SEd Cashin dev_kfree_skb(skb); 146569cf2d85SEd Cashin aoedev_put(d); 1466896831f5SEd Cashin } 1467896831f5SEd Cashin } 1468896831f5SEd Cashin 1469896831f5SEd Cashin int __init 1470896831f5SEd Cashin aoecmd_init(void) 1471896831f5SEd Cashin { 1472896831f5SEd Cashin INIT_LIST_HEAD(&iocq.head); 1473896831f5SEd Cashin spin_lock_init(&iocq.lock); 1474896831f5SEd Cashin init_waitqueue_head(&ktiowq); 1475896831f5SEd Cashin kts.name = "aoe_ktio"; 1476896831f5SEd Cashin kts.fn = ktio; 1477896831f5SEd Cashin kts.waitq = &ktiowq; 1478896831f5SEd Cashin kts.lock = &iocq.lock; 1479896831f5SEd Cashin return aoe_ktstart(&kts); 1480896831f5SEd Cashin } 1481896831f5SEd Cashin 1482896831f5SEd Cashin void 1483896831f5SEd Cashin aoecmd_exit(void) 1484896831f5SEd Cashin { 1485896831f5SEd Cashin aoe_ktstop(&kts); 148669cf2d85SEd Cashin aoe_flush_iocq(); 1487896831f5SEd Cashin } 1488