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> 15*896831f5SEd Cashin #include <linux/workqueue.h> 16*896831f5SEd Cashin #include <linux/kthread.h> 17881d966bSEric W. Biederman #include <net/net_namespace.h> 18475172fbSEd L. Cashin #include <asm/unaligned.h> 19*896831f5SEd Cashin #include <linux/uio.h> 201da177e4SLinus Torvalds #include "aoe.h" 211da177e4SLinus Torvalds 22*896831f5SEd Cashin #define MAXIOC (8192) /* default meant to avoid most soft lockups */ 23*896831f5SEd Cashin 24*896831f5SEd Cashin static void ktcomplete(struct frame *, struct sk_buff *); 25*896831f5SEd Cashin 26b751e8b6SEd L. Cashin static int aoe_deadsecs = 60 * 3; 27b751e8b6SEd L. Cashin module_param(aoe_deadsecs, int, 0644); 28b751e8b6SEd L. Cashin MODULE_PARM_DESC(aoe_deadsecs, "After aoe_deadsecs seconds, give up and fail dev."); 291da177e4SLinus Torvalds 307df620d8SEd L. Cashin static int aoe_maxout = 16; 317df620d8SEd L. Cashin module_param(aoe_maxout, int, 0644); 327df620d8SEd L. Cashin MODULE_PARM_DESC(aoe_maxout, 337df620d8SEd L. Cashin "Only aoe_maxout outstanding packets for every MAC on eX.Y."); 347df620d8SEd L. Cashin 35*896831f5SEd Cashin static wait_queue_head_t ktiowq; 36*896831f5SEd Cashin static struct ktstate kts; 37*896831f5SEd Cashin 38*896831f5SEd Cashin /* io completion queue */ 39*896831f5SEd Cashin static struct { 40*896831f5SEd Cashin struct list_head head; 41*896831f5SEd Cashin spinlock_t lock; 42*896831f5SEd Cashin } iocq; 43*896831f5SEd Cashin 4468e0d42fSEd L. Cashin static struct sk_buff * 45e407a7f6SEd L. Cashin new_skb(ulong len) 461da177e4SLinus Torvalds { 471da177e4SLinus Torvalds struct sk_buff *skb; 481da177e4SLinus Torvalds 491da177e4SLinus Torvalds skb = alloc_skb(len, GFP_ATOMIC); 501da177e4SLinus Torvalds if (skb) { 51459a98edSArnaldo Carvalho de Melo skb_reset_mac_header(skb); 52c1d2bbe1SArnaldo Carvalho de Melo skb_reset_network_header(skb); 531da177e4SLinus Torvalds skb->protocol = __constant_htons(ETH_P_AOE); 548babe8ccSEd Cashin skb_checksum_none_assert(skb); 551da177e4SLinus Torvalds } 561da177e4SLinus Torvalds return skb; 571da177e4SLinus Torvalds } 581da177e4SLinus Torvalds 591da177e4SLinus Torvalds static struct frame * 60*896831f5SEd Cashin getframe(struct aoetgt *t, u32 tag) 611da177e4SLinus Torvalds { 62*896831f5SEd Cashin struct frame *f; 63*896831f5SEd Cashin struct list_head *head, *pos, *nx; 64*896831f5SEd Cashin u32 n; 651da177e4SLinus Torvalds 66*896831f5SEd Cashin n = tag % NFACTIVE; 67*896831f5SEd Cashin head = &t->factive[n]; 68*896831f5SEd Cashin list_for_each_safe(pos, nx, head) { 69*896831f5SEd Cashin f = list_entry(pos, struct frame, head); 70*896831f5SEd Cashin if (f->tag == tag) { 71*896831f5SEd Cashin list_del(pos); 721da177e4SLinus Torvalds return f; 73*896831f5SEd Cashin } 74*896831f5SEd Cashin } 751da177e4SLinus Torvalds return NULL; 761da177e4SLinus Torvalds } 771da177e4SLinus Torvalds 781da177e4SLinus Torvalds /* 791da177e4SLinus Torvalds * Leave the top bit clear so we have tagspace for userland. 801da177e4SLinus Torvalds * The bottom 16 bits are the xmit tick for rexmit/rttavg processing. 811da177e4SLinus Torvalds * This driver reserves tag -1 to mean "unused frame." 821da177e4SLinus Torvalds */ 831da177e4SLinus Torvalds static int 8468e0d42fSEd L. Cashin newtag(struct aoetgt *t) 851da177e4SLinus Torvalds { 861da177e4SLinus Torvalds register ulong n; 871da177e4SLinus Torvalds 881da177e4SLinus Torvalds n = jiffies & 0xffff; 8968e0d42fSEd L. Cashin return n |= (++t->lasttag & 0x7fff) << 16; 901da177e4SLinus Torvalds } 911da177e4SLinus Torvalds 92*896831f5SEd Cashin static u32 9368e0d42fSEd L. Cashin aoehdr_atainit(struct aoedev *d, struct aoetgt *t, struct aoe_hdr *h) 941da177e4SLinus Torvalds { 9568e0d42fSEd L. Cashin u32 host_tag = newtag(t); 961da177e4SLinus Torvalds 9768e0d42fSEd L. Cashin memcpy(h->src, t->ifp->nd->dev_addr, sizeof h->src); 9868e0d42fSEd L. Cashin memcpy(h->dst, t->addr, sizeof h->dst); 9963e9cc5dSecashin@coraid.com h->type = __constant_cpu_to_be16(ETH_P_AOE); 1001da177e4SLinus Torvalds h->verfl = AOE_HVER; 10163e9cc5dSecashin@coraid.com h->major = cpu_to_be16(d->aoemajor); 1021da177e4SLinus Torvalds h->minor = d->aoeminor; 1031da177e4SLinus Torvalds h->cmd = AOECMD_ATA; 10463e9cc5dSecashin@coraid.com h->tag = cpu_to_be32(host_tag); 1051da177e4SLinus Torvalds 1061da177e4SLinus Torvalds return host_tag; 1071da177e4SLinus Torvalds } 1081da177e4SLinus Torvalds 10919bf2635SEd L. Cashin static inline void 11019bf2635SEd L. Cashin put_lba(struct aoe_atahdr *ah, sector_t lba) 11119bf2635SEd L. Cashin { 11219bf2635SEd L. Cashin ah->lba0 = lba; 11319bf2635SEd L. Cashin ah->lba1 = lba >>= 8; 11419bf2635SEd L. Cashin ah->lba2 = lba >>= 8; 11519bf2635SEd L. Cashin ah->lba3 = lba >>= 8; 11619bf2635SEd L. Cashin ah->lba4 = lba >>= 8; 11719bf2635SEd L. Cashin ah->lba5 = lba >>= 8; 11819bf2635SEd L. Cashin } 11919bf2635SEd L. Cashin 1201da177e4SLinus Torvalds static void 12168e0d42fSEd L. Cashin ifrotate(struct aoetgt *t) 1221da177e4SLinus Torvalds { 12368e0d42fSEd L. Cashin t->ifp++; 12468e0d42fSEd L. Cashin if (t->ifp >= &t->ifs[NAOEIFS] || t->ifp->nd == NULL) 12568e0d42fSEd L. Cashin t->ifp = t->ifs; 12668e0d42fSEd L. Cashin if (t->ifp->nd == NULL) { 12768e0d42fSEd L. Cashin printk(KERN_INFO "aoe: no interface to rotate to\n"); 12868e0d42fSEd L. Cashin BUG(); 12968e0d42fSEd L. Cashin } 13068e0d42fSEd L. Cashin } 13168e0d42fSEd L. Cashin 1329bb237b6SEd L. Cashin static void 1339bb237b6SEd L. Cashin skb_pool_put(struct aoedev *d, struct sk_buff *skb) 1349bb237b6SEd L. Cashin { 135e9bb8fb0SDavid S. Miller __skb_queue_tail(&d->skbpool, skb); 1369bb237b6SEd L. Cashin } 1379bb237b6SEd L. Cashin 1389bb237b6SEd L. Cashin static struct sk_buff * 1399bb237b6SEd L. Cashin skb_pool_get(struct aoedev *d) 1409bb237b6SEd L. Cashin { 141e9bb8fb0SDavid S. Miller struct sk_buff *skb = skb_peek(&d->skbpool); 1429bb237b6SEd L. Cashin 1439bb237b6SEd L. Cashin if (skb && atomic_read(&skb_shinfo(skb)->dataref) == 1) { 144e9bb8fb0SDavid S. Miller __skb_unlink(skb, &d->skbpool); 1459bb237b6SEd L. Cashin return skb; 1469bb237b6SEd L. Cashin } 147e9bb8fb0SDavid S. Miller if (skb_queue_len(&d->skbpool) < NSKBPOOLMAX && 148e9bb8fb0SDavid S. Miller (skb = new_skb(ETH_ZLEN))) 1499bb237b6SEd L. Cashin return skb; 150e9bb8fb0SDavid S. Miller 1519bb237b6SEd L. Cashin return NULL; 1529bb237b6SEd L. Cashin } 1539bb237b6SEd L. Cashin 154*896831f5SEd Cashin void 155*896831f5SEd Cashin aoe_freetframe(struct frame *f) 15668e0d42fSEd L. Cashin { 157*896831f5SEd Cashin struct aoetgt *t; 158*896831f5SEd Cashin 159*896831f5SEd Cashin t = f->t; 160*896831f5SEd Cashin f->buf = NULL; 161*896831f5SEd Cashin f->bv = NULL; 162*896831f5SEd Cashin f->r_skb = NULL; 163*896831f5SEd Cashin list_add(&f->head, &t->ffree); 164*896831f5SEd Cashin } 165*896831f5SEd Cashin 166*896831f5SEd Cashin static struct frame * 167*896831f5SEd Cashin newtframe(struct aoedev *d, struct aoetgt *t) 168*896831f5SEd Cashin { 169*896831f5SEd Cashin struct frame *f; 1709bb237b6SEd L. Cashin struct sk_buff *skb; 171*896831f5SEd Cashin struct list_head *pos; 172*896831f5SEd Cashin 173*896831f5SEd Cashin if (list_empty(&t->ffree)) { 174*896831f5SEd Cashin if (t->falloc >= NSKBPOOLMAX*2) 175*896831f5SEd Cashin return NULL; 176*896831f5SEd Cashin f = kcalloc(1, sizeof(*f), GFP_ATOMIC); 177*896831f5SEd Cashin if (f == NULL) 178*896831f5SEd Cashin return NULL; 179*896831f5SEd Cashin t->falloc++; 180*896831f5SEd Cashin f->t = t; 181*896831f5SEd Cashin } else { 182*896831f5SEd Cashin pos = t->ffree.next; 183*896831f5SEd Cashin list_del(pos); 184*896831f5SEd Cashin f = list_entry(pos, struct frame, head); 185*896831f5SEd Cashin } 186*896831f5SEd Cashin 187*896831f5SEd Cashin skb = f->skb; 188*896831f5SEd Cashin if (skb == NULL) { 189*896831f5SEd Cashin f->skb = skb = new_skb(ETH_ZLEN); 190*896831f5SEd Cashin if (!skb) { 191*896831f5SEd Cashin bail: aoe_freetframe(f); 192*896831f5SEd Cashin return NULL; 193*896831f5SEd Cashin } 194*896831f5SEd Cashin } 195*896831f5SEd Cashin 196*896831f5SEd Cashin if (atomic_read(&skb_shinfo(skb)->dataref) != 1) { 197*896831f5SEd Cashin skb = skb_pool_get(d); 198*896831f5SEd Cashin if (skb == NULL) 199*896831f5SEd Cashin goto bail; 200*896831f5SEd Cashin skb_pool_put(d, f->skb); 201*896831f5SEd Cashin f->skb = skb; 202*896831f5SEd Cashin } 203*896831f5SEd Cashin 204*896831f5SEd Cashin skb->truesize -= skb->data_len; 205*896831f5SEd Cashin skb_shinfo(skb)->nr_frags = skb->data_len = 0; 206*896831f5SEd Cashin skb_trim(skb, 0); 207*896831f5SEd Cashin return f; 208*896831f5SEd Cashin } 209*896831f5SEd Cashin 210*896831f5SEd Cashin static struct frame * 211*896831f5SEd Cashin newframe(struct aoedev *d) 212*896831f5SEd Cashin { 213*896831f5SEd Cashin struct frame *f; 214*896831f5SEd Cashin struct aoetgt *t, **tt; 215*896831f5SEd Cashin int totout = 0; 21668e0d42fSEd L. Cashin 21768e0d42fSEd L. Cashin if (d->targets[0] == NULL) { /* shouldn't happen, but I'm paranoid */ 21868e0d42fSEd L. Cashin printk(KERN_ERR "aoe: NULL TARGETS!\n"); 21968e0d42fSEd L. Cashin return NULL; 22068e0d42fSEd L. Cashin } 221*896831f5SEd Cashin tt = d->tgt; /* last used target */ 2229bb237b6SEd L. Cashin for (;;) { 223*896831f5SEd Cashin tt++; 224*896831f5SEd Cashin if (tt >= &d->targets[NTARGETS] || !*tt) 225*896831f5SEd Cashin tt = d->targets; 226*896831f5SEd Cashin t = *tt; 227*896831f5SEd Cashin totout += t->nout; 228*896831f5SEd Cashin if (t->nout < t->maxout 2299bb237b6SEd L. Cashin && t != d->htgt 230*896831f5SEd Cashin && t->ifp->nd) { 231*896831f5SEd Cashin f = newtframe(d, t); 232*896831f5SEd Cashin if (f) { 233*896831f5SEd Cashin d->tgt = tt; 234*896831f5SEd Cashin ifrotate(t); 23568e0d42fSEd L. Cashin return f; 23668e0d42fSEd L. Cashin } 2379bb237b6SEd L. Cashin } 238*896831f5SEd Cashin if (tt == d->tgt) /* we've looped and found nada */ 2399bb237b6SEd L. Cashin break; 240*896831f5SEd Cashin } 241*896831f5SEd Cashin if (totout == 0) { 242*896831f5SEd Cashin d->kicked++; 243*896831f5SEd Cashin d->flags |= DEVFL_KICKME; 2449bb237b6SEd L. Cashin } 24568e0d42fSEd L. Cashin return NULL; 24668e0d42fSEd L. Cashin } 24768e0d42fSEd L. Cashin 2483d5b0605SEd Cashin static void 2493d5b0605SEd Cashin skb_fillup(struct sk_buff *skb, struct bio_vec *bv, ulong off, ulong cnt) 2503d5b0605SEd Cashin { 2513d5b0605SEd Cashin int frag = 0; 2523d5b0605SEd Cashin ulong fcnt; 2533d5b0605SEd Cashin loop: 2543d5b0605SEd Cashin fcnt = bv->bv_len - (off - bv->bv_offset); 2553d5b0605SEd Cashin if (fcnt > cnt) 2563d5b0605SEd Cashin fcnt = cnt; 2573d5b0605SEd Cashin skb_fill_page_desc(skb, frag++, bv->bv_page, off, fcnt); 2583d5b0605SEd Cashin cnt -= fcnt; 2593d5b0605SEd Cashin if (cnt <= 0) 2603d5b0605SEd Cashin return; 2613d5b0605SEd Cashin bv++; 2623d5b0605SEd Cashin off = bv->bv_offset; 2633d5b0605SEd Cashin goto loop; 2643d5b0605SEd Cashin } 2653d5b0605SEd Cashin 266*896831f5SEd Cashin static void 267*896831f5SEd Cashin fhash(struct frame *f) 268*896831f5SEd Cashin { 269*896831f5SEd Cashin struct aoetgt *t = f->t; 270*896831f5SEd Cashin u32 n; 271*896831f5SEd Cashin 272*896831f5SEd Cashin n = f->tag % NFACTIVE; 273*896831f5SEd Cashin list_add_tail(&f->head, &t->factive[n]); 274*896831f5SEd Cashin } 275*896831f5SEd Cashin 27668e0d42fSEd L. Cashin static int 27768e0d42fSEd L. Cashin aoecmd_ata_rw(struct aoedev *d) 27868e0d42fSEd L. Cashin { 27968e0d42fSEd L. Cashin struct frame *f; 2801da177e4SLinus Torvalds struct aoe_hdr *h; 2811da177e4SLinus Torvalds struct aoe_atahdr *ah; 2821da177e4SLinus Torvalds struct buf *buf; 28368e0d42fSEd L. Cashin struct bio_vec *bv; 28468e0d42fSEd L. Cashin struct aoetgt *t; 2851da177e4SLinus Torvalds struct sk_buff *skb; 2863d5b0605SEd Cashin ulong bcnt, fbcnt; 2871da177e4SLinus Torvalds char writebit, extbit; 2881da177e4SLinus Torvalds 2891da177e4SLinus Torvalds writebit = 0x10; 2901da177e4SLinus Torvalds extbit = 0x4; 2911da177e4SLinus Torvalds 292*896831f5SEd Cashin f = newframe(d); 29368e0d42fSEd L. Cashin if (f == NULL) 29468e0d42fSEd L. Cashin return 0; 29568e0d42fSEd L. Cashin t = *d->tgt; 2961da177e4SLinus Torvalds buf = d->inprocess; 29768e0d42fSEd L. Cashin bv = buf->bv; 29868e0d42fSEd L. Cashin bcnt = t->ifp->maxbcnt; 29968e0d42fSEd L. Cashin if (bcnt == 0) 30068e0d42fSEd L. Cashin bcnt = DEFAULTBCNT; 3013d5b0605SEd Cashin if (bcnt > buf->resid) 3023d5b0605SEd Cashin bcnt = buf->resid; 3033d5b0605SEd Cashin fbcnt = bcnt; 3043d5b0605SEd Cashin f->bv = buf->bv; 3053d5b0605SEd Cashin f->bv_off = f->bv->bv_offset + (f->bv->bv_len - buf->bv_resid); 3063d5b0605SEd Cashin do { 3073d5b0605SEd Cashin if (fbcnt < buf->bv_resid) { 3083d5b0605SEd Cashin buf->bv_resid -= fbcnt; 3093d5b0605SEd Cashin buf->resid -= fbcnt; 3103d5b0605SEd Cashin break; 3113d5b0605SEd Cashin } 3123d5b0605SEd Cashin fbcnt -= buf->bv_resid; 3133d5b0605SEd Cashin buf->resid -= buf->bv_resid; 3143d5b0605SEd Cashin if (buf->resid == 0) { 3153d5b0605SEd Cashin d->inprocess = NULL; 3163d5b0605SEd Cashin break; 3173d5b0605SEd Cashin } 3183d5b0605SEd Cashin buf->bv++; 3193d5b0605SEd Cashin buf->bv_resid = buf->bv->bv_len; 3203d5b0605SEd Cashin WARN_ON(buf->bv_resid == 0); 3213d5b0605SEd Cashin } while (fbcnt); 3223d5b0605SEd Cashin 3231da177e4SLinus Torvalds /* initialize the headers & frame */ 324e407a7f6SEd L. Cashin skb = f->skb; 325abdbf94dSEd L. Cashin h = (struct aoe_hdr *) skb_mac_header(skb); 3261da177e4SLinus Torvalds ah = (struct aoe_atahdr *) (h+1); 32719900cdeSEd L. Cashin skb_put(skb, sizeof *h + sizeof *ah); 32819900cdeSEd L. Cashin memset(h, 0, skb->len); 32968e0d42fSEd L. Cashin f->tag = aoehdr_atainit(d, t, h); 330*896831f5SEd Cashin fhash(f); 33168e0d42fSEd L. Cashin t->nout++; 3321da177e4SLinus Torvalds f->waited = 0; 3331da177e4SLinus Torvalds f->buf = buf; 33419bf2635SEd L. Cashin f->bcnt = bcnt; 33568e0d42fSEd L. Cashin f->lba = buf->sector; 3361da177e4SLinus Torvalds 3371da177e4SLinus Torvalds /* set up ata header */ 3381da177e4SLinus Torvalds ah->scnt = bcnt >> 9; 33968e0d42fSEd L. Cashin put_lba(ah, buf->sector); 3401da177e4SLinus Torvalds if (d->flags & DEVFL_EXT) { 3411da177e4SLinus Torvalds ah->aflags |= AOEAFL_EXT; 3421da177e4SLinus Torvalds } else { 3431da177e4SLinus Torvalds extbit = 0; 3441da177e4SLinus Torvalds ah->lba3 &= 0x0f; 3451da177e4SLinus Torvalds ah->lba3 |= 0xe0; /* LBA bit + obsolete 0xa0 */ 3461da177e4SLinus Torvalds } 3471da177e4SLinus Torvalds if (bio_data_dir(buf->bio) == WRITE) { 3483d5b0605SEd Cashin skb_fillup(skb, f->bv, f->bv_off, bcnt); 3491da177e4SLinus Torvalds ah->aflags |= AOEAFL_WRITE; 3504f51dc5eSEd L. Cashin skb->len += bcnt; 3514f51dc5eSEd L. Cashin skb->data_len = bcnt; 3523d5b0605SEd Cashin skb->truesize += bcnt; 35368e0d42fSEd L. Cashin t->wpkts++; 3541da177e4SLinus Torvalds } else { 35568e0d42fSEd L. Cashin t->rpkts++; 3561da177e4SLinus Torvalds writebit = 0; 3571da177e4SLinus Torvalds } 3581da177e4SLinus Torvalds 35904b3ab52SBartlomiej Zolnierkiewicz ah->cmdstat = ATA_CMD_PIO_READ | writebit | extbit; 3601da177e4SLinus Torvalds 3611da177e4SLinus Torvalds /* mark all tracking fields and load out */ 3621da177e4SLinus Torvalds buf->nframesout += 1; 3631da177e4SLinus Torvalds buf->sector += bcnt >> 9; 3641da177e4SLinus Torvalds 36568e0d42fSEd L. Cashin skb->dev = t->ifp->nd; 3664f51dc5eSEd L. Cashin skb = skb_clone(skb, GFP_ATOMIC); 367e9bb8fb0SDavid S. Miller if (skb) 368e9bb8fb0SDavid S. Miller __skb_queue_tail(&d->sendq, skb); 36968e0d42fSEd L. Cashin return 1; 37068e0d42fSEd L. Cashin } 3711da177e4SLinus Torvalds 3723ae1c24eSEd L. Cashin /* some callers cannot sleep, and they can call this function, 3733ae1c24eSEd L. Cashin * transmitting the packets later, when interrupts are on 3743ae1c24eSEd L. Cashin */ 375e9bb8fb0SDavid S. Miller static void 376e9bb8fb0SDavid S. Miller aoecmd_cfg_pkts(ushort aoemajor, unsigned char aoeminor, struct sk_buff_head *queue) 3773ae1c24eSEd L. Cashin { 3783ae1c24eSEd L. Cashin struct aoe_hdr *h; 3793ae1c24eSEd L. Cashin struct aoe_cfghdr *ch; 380e9bb8fb0SDavid S. Miller struct sk_buff *skb; 3813ae1c24eSEd L. Cashin struct net_device *ifp; 3823ae1c24eSEd L. Cashin 383840a185dSEric Dumazet rcu_read_lock(); 384840a185dSEric Dumazet for_each_netdev_rcu(&init_net, ifp) { 3853ae1c24eSEd L. Cashin dev_hold(ifp); 3863ae1c24eSEd L. Cashin if (!is_aoe_netif(ifp)) 3877562f876SPavel Emelianov goto cont; 3883ae1c24eSEd L. Cashin 389e407a7f6SEd L. Cashin skb = new_skb(sizeof *h + sizeof *ch); 3903ae1c24eSEd L. Cashin if (skb == NULL) { 391a12c93f0SEd L. Cashin printk(KERN_INFO "aoe: skb alloc failure\n"); 3927562f876SPavel Emelianov goto cont; 3933ae1c24eSEd L. Cashin } 39419900cdeSEd L. Cashin skb_put(skb, sizeof *h + sizeof *ch); 395e407a7f6SEd L. Cashin skb->dev = ifp; 396e9bb8fb0SDavid S. Miller __skb_queue_tail(queue, skb); 397abdbf94dSEd L. Cashin h = (struct aoe_hdr *) skb_mac_header(skb); 3983ae1c24eSEd L. Cashin memset(h, 0, sizeof *h + sizeof *ch); 3993ae1c24eSEd L. Cashin 4003ae1c24eSEd L. Cashin memset(h->dst, 0xff, sizeof h->dst); 4013ae1c24eSEd L. Cashin memcpy(h->src, ifp->dev_addr, sizeof h->src); 4023ae1c24eSEd L. Cashin h->type = __constant_cpu_to_be16(ETH_P_AOE); 4033ae1c24eSEd L. Cashin h->verfl = AOE_HVER; 4043ae1c24eSEd L. Cashin h->major = cpu_to_be16(aoemajor); 4053ae1c24eSEd L. Cashin h->minor = aoeminor; 4063ae1c24eSEd L. Cashin h->cmd = AOECMD_CFG; 4073ae1c24eSEd L. Cashin 4087562f876SPavel Emelianov cont: 4097562f876SPavel Emelianov dev_put(ifp); 4103ae1c24eSEd L. Cashin } 411840a185dSEric Dumazet rcu_read_unlock(); 4123ae1c24eSEd L. Cashin } 4133ae1c24eSEd L. Cashin 4141da177e4SLinus Torvalds static void 415*896831f5SEd Cashin resend(struct aoedev *d, struct frame *f) 4161da177e4SLinus Torvalds { 4171da177e4SLinus Torvalds struct sk_buff *skb; 4181da177e4SLinus Torvalds struct aoe_hdr *h; 41919bf2635SEd L. Cashin struct aoe_atahdr *ah; 420*896831f5SEd Cashin struct aoetgt *t; 4211da177e4SLinus Torvalds char buf[128]; 4221da177e4SLinus Torvalds u32 n; 4231da177e4SLinus Torvalds 424*896831f5SEd Cashin t = f->t; 42568e0d42fSEd L. Cashin ifrotate(t); 42668e0d42fSEd L. Cashin n = newtag(t); 427e407a7f6SEd L. Cashin skb = f->skb; 428abdbf94dSEd L. Cashin h = (struct aoe_hdr *) skb_mac_header(skb); 42919bf2635SEd L. Cashin ah = (struct aoe_atahdr *) (h+1); 43068e0d42fSEd L. Cashin 43168e0d42fSEd L. Cashin snprintf(buf, sizeof buf, 432411c41eeSHarvey Harrison "%15s e%ld.%d oldtag=%08x@%08lx newtag=%08x s=%pm d=%pm nout=%d\n", 43368e0d42fSEd L. Cashin "retransmit", d->aoemajor, d->aoeminor, f->tag, jiffies, n, 434411c41eeSHarvey Harrison h->src, h->dst, t->nout); 43568e0d42fSEd L. Cashin aoechr_error(buf); 43668e0d42fSEd L. Cashin 4371da177e4SLinus Torvalds f->tag = n; 438*896831f5SEd Cashin fhash(f); 43963e9cc5dSecashin@coraid.com h->tag = cpu_to_be32(n); 44068e0d42fSEd L. Cashin memcpy(h->dst, t->addr, sizeof h->dst); 44168e0d42fSEd L. Cashin memcpy(h->src, t->ifp->nd->dev_addr, sizeof h->src); 4421da177e4SLinus Torvalds 44368e0d42fSEd L. Cashin skb->dev = t->ifp->nd; 4444f51dc5eSEd L. Cashin skb = skb_clone(skb, GFP_ATOMIC); 4454f51dc5eSEd L. Cashin if (skb == NULL) 4464f51dc5eSEd L. Cashin return; 447e9bb8fb0SDavid S. Miller __skb_queue_tail(&d->sendq, skb); 4481da177e4SLinus Torvalds } 4491da177e4SLinus Torvalds 4501da177e4SLinus Torvalds static int 451*896831f5SEd Cashin tsince(u32 tag) 4521da177e4SLinus Torvalds { 4531da177e4SLinus Torvalds int n; 4541da177e4SLinus Torvalds 4551da177e4SLinus Torvalds n = jiffies & 0xffff; 4561da177e4SLinus Torvalds n -= tag & 0xffff; 4571da177e4SLinus Torvalds if (n < 0) 4581da177e4SLinus Torvalds n += 1<<16; 4591da177e4SLinus Torvalds return n; 4601da177e4SLinus Torvalds } 4611da177e4SLinus Torvalds 46268e0d42fSEd L. Cashin static struct aoeif * 46368e0d42fSEd L. Cashin getif(struct aoetgt *t, struct net_device *nd) 46468e0d42fSEd L. Cashin { 46568e0d42fSEd L. Cashin struct aoeif *p, *e; 46668e0d42fSEd L. Cashin 46768e0d42fSEd L. Cashin p = t->ifs; 46868e0d42fSEd L. Cashin e = p + NAOEIFS; 46968e0d42fSEd L. Cashin for (; p < e; p++) 47068e0d42fSEd L. Cashin if (p->nd == nd) 47168e0d42fSEd L. Cashin return p; 47268e0d42fSEd L. Cashin return NULL; 47368e0d42fSEd L. Cashin } 47468e0d42fSEd L. Cashin 47568e0d42fSEd L. Cashin static struct aoeif * 47668e0d42fSEd L. Cashin addif(struct aoetgt *t, struct net_device *nd) 47768e0d42fSEd L. Cashin { 47868e0d42fSEd L. Cashin struct aoeif *p; 47968e0d42fSEd L. Cashin 48068e0d42fSEd L. Cashin p = getif(t, NULL); 48168e0d42fSEd L. Cashin if (!p) 48268e0d42fSEd L. Cashin return NULL; 48368e0d42fSEd L. Cashin p->nd = nd; 48468e0d42fSEd L. Cashin p->maxbcnt = DEFAULTBCNT; 48568e0d42fSEd L. Cashin p->lost = 0; 48668e0d42fSEd L. Cashin p->lostjumbo = 0; 48768e0d42fSEd L. Cashin return p; 48868e0d42fSEd L. Cashin } 48968e0d42fSEd L. Cashin 49068e0d42fSEd L. Cashin static void 49168e0d42fSEd L. Cashin ejectif(struct aoetgt *t, struct aoeif *ifp) 49268e0d42fSEd L. Cashin { 49368e0d42fSEd L. Cashin struct aoeif *e; 49468e0d42fSEd L. Cashin ulong n; 49568e0d42fSEd L. Cashin 49668e0d42fSEd L. Cashin e = t->ifs + NAOEIFS - 1; 49768e0d42fSEd L. Cashin n = (e - ifp) * sizeof *ifp; 49868e0d42fSEd L. Cashin memmove(ifp, ifp+1, n); 49968e0d42fSEd L. Cashin e->nd = NULL; 50068e0d42fSEd L. Cashin } 50168e0d42fSEd L. Cashin 50268e0d42fSEd L. Cashin static int 50368e0d42fSEd L. Cashin sthtith(struct aoedev *d) 50468e0d42fSEd L. Cashin { 505*896831f5SEd Cashin struct frame *f, *nf; 506*896831f5SEd Cashin struct list_head *nx, *pos, *head; 50768e0d42fSEd L. Cashin struct sk_buff *skb; 508*896831f5SEd Cashin struct aoetgt *ht = d->htgt; 509*896831f5SEd Cashin int i; 51068e0d42fSEd L. Cashin 511*896831f5SEd Cashin for (i = 0; i < NFACTIVE; i++) { 512*896831f5SEd Cashin head = &ht->factive[i]; 513*896831f5SEd Cashin list_for_each_safe(pos, nx, head) { 514*896831f5SEd Cashin f = list_entry(pos, struct frame, head); 515*896831f5SEd Cashin nf = newframe(d); 51668e0d42fSEd L. Cashin if (!nf) 51768e0d42fSEd L. Cashin return 0; 518*896831f5SEd Cashin 519*896831f5SEd Cashin /* remove frame from active list */ 520*896831f5SEd Cashin list_del(pos); 521*896831f5SEd Cashin 522*896831f5SEd Cashin /* reassign all pertinent bits to new outbound frame */ 52368e0d42fSEd L. Cashin skb = nf->skb; 524*896831f5SEd Cashin nf->skb = f->skb; 525*896831f5SEd Cashin nf->buf = f->buf; 526*896831f5SEd Cashin nf->bcnt = f->bcnt; 527*896831f5SEd Cashin nf->lba = f->lba; 528*896831f5SEd Cashin nf->bv = f->bv; 529*896831f5SEd Cashin nf->bv_off = f->bv_off; 53068e0d42fSEd L. Cashin nf->waited = 0; 531*896831f5SEd Cashin f->skb = skb; 532*896831f5SEd Cashin aoe_freetframe(f); 53368e0d42fSEd L. Cashin ht->nout--; 534*896831f5SEd Cashin nf->t->nout++; 535*896831f5SEd Cashin resend(d, nf); 536*896831f5SEd Cashin } 53768e0d42fSEd L. Cashin } 53868e0d42fSEd L. Cashin /* he's clean, he's useless. take away his interfaces */ 53968e0d42fSEd L. Cashin memset(ht->ifs, 0, sizeof ht->ifs); 54068e0d42fSEd L. Cashin d->htgt = NULL; 54168e0d42fSEd L. Cashin return 1; 54268e0d42fSEd L. Cashin } 54368e0d42fSEd L. Cashin 54468e0d42fSEd L. Cashin static inline unsigned char 54568e0d42fSEd L. Cashin ata_scnt(unsigned char *packet) { 54668e0d42fSEd L. Cashin struct aoe_hdr *h; 54768e0d42fSEd L. Cashin struct aoe_atahdr *ah; 54868e0d42fSEd L. Cashin 54968e0d42fSEd L. Cashin h = (struct aoe_hdr *) packet; 55068e0d42fSEd L. Cashin ah = (struct aoe_atahdr *) (h+1); 55168e0d42fSEd L. Cashin return ah->scnt; 55268e0d42fSEd L. Cashin } 55368e0d42fSEd L. Cashin 5541da177e4SLinus Torvalds static void 5551da177e4SLinus Torvalds rexmit_timer(ulong vp) 5561da177e4SLinus Torvalds { 557e9bb8fb0SDavid S. Miller struct sk_buff_head queue; 5581da177e4SLinus Torvalds struct aoedev *d; 55968e0d42fSEd L. Cashin struct aoetgt *t, **tt, **te; 56068e0d42fSEd L. Cashin struct aoeif *ifp; 561*896831f5SEd Cashin struct frame *f; 562*896831f5SEd Cashin struct list_head *head, *pos, *nx; 563*896831f5SEd Cashin LIST_HEAD(flist); 5641da177e4SLinus Torvalds register long timeout; 5651da177e4SLinus Torvalds ulong flags, n; 566*896831f5SEd Cashin int i; 5671da177e4SLinus Torvalds 5681da177e4SLinus Torvalds d = (struct aoedev *) vp; 5691da177e4SLinus Torvalds 5701da177e4SLinus Torvalds /* timeout is always ~150% of the moving average */ 5711da177e4SLinus Torvalds timeout = d->rttavg; 5721da177e4SLinus Torvalds timeout += timeout >> 1; 5731da177e4SLinus Torvalds 5741da177e4SLinus Torvalds spin_lock_irqsave(&d->lock, flags); 5751da177e4SLinus Torvalds 5761da177e4SLinus Torvalds if (d->flags & DEVFL_TKILL) { 5771c6f3fcaSEd L. Cashin spin_unlock_irqrestore(&d->lock, flags); 5781da177e4SLinus Torvalds return; 5791da177e4SLinus Torvalds } 580*896831f5SEd Cashin 581*896831f5SEd Cashin /* collect all frames to rexmit into flist */ 58268e0d42fSEd L. Cashin tt = d->targets; 58368e0d42fSEd L. Cashin te = tt + NTARGETS; 58468e0d42fSEd L. Cashin for (; tt < te && *tt; tt++) { 58568e0d42fSEd L. Cashin t = *tt; 586*896831f5SEd Cashin for (i = 0; i < NFACTIVE; i++) { 587*896831f5SEd Cashin head = &t->factive[i]; 588*896831f5SEd Cashin list_for_each_safe(pos, nx, head) { 589*896831f5SEd Cashin f = list_entry(pos, struct frame, head); 590*896831f5SEd Cashin if (tsince(f->tag) < timeout) 59168e0d42fSEd L. Cashin continue; 592*896831f5SEd Cashin /* move to flist for later processing */ 593*896831f5SEd Cashin list_move_tail(pos, &flist); 594*896831f5SEd Cashin } 595*896831f5SEd Cashin } 596*896831f5SEd Cashin 597*896831f5SEd Cashin /* window check */ 598*896831f5SEd Cashin if (t->nout == t->maxout 599*896831f5SEd Cashin && t->maxout < t->nframes 600*896831f5SEd Cashin && (jiffies - t->lastwadj)/HZ > 10) { 601*896831f5SEd Cashin t->maxout++; 602*896831f5SEd Cashin t->lastwadj = jiffies; 603*896831f5SEd Cashin } 604*896831f5SEd Cashin } 605*896831f5SEd Cashin 606*896831f5SEd Cashin /* process expired frames */ 607*896831f5SEd Cashin while (!list_empty(&flist)) { 608*896831f5SEd Cashin pos = flist.next; 609*896831f5SEd Cashin f = list_entry(pos, struct frame, head); 6101da177e4SLinus Torvalds n = f->waited += timeout; 6111da177e4SLinus Torvalds n /= HZ; 61268e0d42fSEd L. Cashin if (n > aoe_deadsecs) { 613*896831f5SEd Cashin /* Waited too long. Device failure. 614*896831f5SEd Cashin * Hang all frames on first hash bucket for downdev 615*896831f5SEd Cashin * to clean up. 616*896831f5SEd Cashin */ 617*896831f5SEd Cashin list_splice(&flist, &f->t->factive[0]); 6181da177e4SLinus Torvalds aoedev_downdev(d); 6191c6f3fcaSEd L. Cashin break; 6201da177e4SLinus Torvalds } 621*896831f5SEd Cashin list_del(pos); 62268e0d42fSEd L. Cashin 623*896831f5SEd Cashin t = f->t; 624*896831f5SEd Cashin if (n > HELPWAIT) { 625*896831f5SEd Cashin /* see if another target can help */ 626*896831f5SEd Cashin if (d->ntargets > 1) 627*896831f5SEd Cashin d->htgt = t; 628*896831f5SEd Cashin } 62968e0d42fSEd L. Cashin if (t->nout == t->maxout) { 63068e0d42fSEd L. Cashin if (t->maxout > 1) 63168e0d42fSEd L. Cashin t->maxout--; 63268e0d42fSEd L. Cashin t->lastwadj = jiffies; 63368e0d42fSEd L. Cashin } 63468e0d42fSEd L. Cashin 63568e0d42fSEd L. Cashin ifp = getif(t, f->skb->dev); 63668e0d42fSEd L. Cashin if (ifp && ++ifp->lost > (t->nframes << 1) 63768e0d42fSEd L. Cashin && (ifp != t->ifs || t->ifs[1].nd)) { 63868e0d42fSEd L. Cashin ejectif(t, ifp); 63968e0d42fSEd L. Cashin ifp = NULL; 64068e0d42fSEd L. Cashin } 641*896831f5SEd Cashin resend(d, f); 6421da177e4SLinus Torvalds } 64368e0d42fSEd L. Cashin 644e9bb8fb0SDavid S. Miller if (!skb_queue_empty(&d->sendq)) { 64568e0d42fSEd L. Cashin n = d->rttavg <<= 1; 64668e0d42fSEd L. Cashin if (n > MAXTIMER) 64768e0d42fSEd L. Cashin d->rttavg = MAXTIMER; 64868e0d42fSEd L. Cashin } 64968e0d42fSEd L. Cashin 65068e0d42fSEd L. Cashin if (d->flags & DEVFL_KICKME || d->htgt) { 6514f51dc5eSEd L. Cashin d->flags &= ~DEVFL_KICKME; 6524f51dc5eSEd L. Cashin aoecmd_work(d); 6534f51dc5eSEd L. Cashin } 6541da177e4SLinus Torvalds 655e9bb8fb0SDavid S. Miller __skb_queue_head_init(&queue); 656e9bb8fb0SDavid S. Miller skb_queue_splice_init(&d->sendq, &queue); 6571da177e4SLinus Torvalds 6581da177e4SLinus Torvalds d->timer.expires = jiffies + TIMERTICK; 6591da177e4SLinus Torvalds add_timer(&d->timer); 6601da177e4SLinus Torvalds 6611da177e4SLinus Torvalds spin_unlock_irqrestore(&d->lock, flags); 6621da177e4SLinus Torvalds 663e9bb8fb0SDavid S. Miller aoenet_xmit(&queue); 6641da177e4SLinus Torvalds } 6651da177e4SLinus Torvalds 66668e0d42fSEd L. Cashin /* enters with d->lock held */ 66768e0d42fSEd L. Cashin void 66868e0d42fSEd L. Cashin aoecmd_work(struct aoedev *d) 66968e0d42fSEd L. Cashin { 67068e0d42fSEd L. Cashin struct buf *buf; 67168e0d42fSEd L. Cashin loop: 67268e0d42fSEd L. Cashin if (d->htgt && !sthtith(d)) 67368e0d42fSEd L. Cashin return; 67468e0d42fSEd L. Cashin if (d->inprocess == NULL) { 67568e0d42fSEd L. Cashin if (list_empty(&d->bufq)) 67668e0d42fSEd L. Cashin return; 67768e0d42fSEd L. Cashin buf = container_of(d->bufq.next, struct buf, bufs); 67868e0d42fSEd L. Cashin list_del(d->bufq.next); 67968e0d42fSEd L. Cashin d->inprocess = buf; 68068e0d42fSEd L. Cashin } 68168e0d42fSEd L. Cashin if (aoecmd_ata_rw(d)) 68268e0d42fSEd L. Cashin goto loop; 68368e0d42fSEd L. Cashin } 68468e0d42fSEd L. Cashin 6853ae1c24eSEd L. Cashin /* this function performs work that has been deferred until sleeping is OK 6863ae1c24eSEd L. Cashin */ 6873ae1c24eSEd L. Cashin void 688c4028958SDavid Howells aoecmd_sleepwork(struct work_struct *work) 6893ae1c24eSEd L. Cashin { 690c4028958SDavid Howells struct aoedev *d = container_of(work, struct aoedev, work); 6913ae1c24eSEd L. Cashin 6923ae1c24eSEd L. Cashin if (d->flags & DEVFL_GDALLOC) 6933ae1c24eSEd L. Cashin aoeblk_gdalloc(d); 6943ae1c24eSEd L. Cashin 6953ae1c24eSEd L. Cashin if (d->flags & DEVFL_NEWSIZE) { 6963ae1c24eSEd L. Cashin struct block_device *bd; 6973ae1c24eSEd L. Cashin unsigned long flags; 6983ae1c24eSEd L. Cashin u64 ssize; 6993ae1c24eSEd L. Cashin 70080795aefSTejun Heo ssize = get_capacity(d->gd); 7013ae1c24eSEd L. Cashin bd = bdget_disk(d->gd, 0); 7023ae1c24eSEd L. Cashin 7033ae1c24eSEd L. Cashin if (bd) { 7043ae1c24eSEd L. Cashin mutex_lock(&bd->bd_inode->i_mutex); 7053ae1c24eSEd L. Cashin i_size_write(bd->bd_inode, (loff_t)ssize<<9); 7063ae1c24eSEd L. Cashin mutex_unlock(&bd->bd_inode->i_mutex); 7073ae1c24eSEd L. Cashin bdput(bd); 7083ae1c24eSEd L. Cashin } 7093ae1c24eSEd L. Cashin spin_lock_irqsave(&d->lock, flags); 7103ae1c24eSEd L. Cashin d->flags |= DEVFL_UP; 7113ae1c24eSEd L. Cashin d->flags &= ~DEVFL_NEWSIZE; 7123ae1c24eSEd L. Cashin spin_unlock_irqrestore(&d->lock, flags); 7133ae1c24eSEd L. Cashin } 7143ae1c24eSEd L. Cashin } 7153ae1c24eSEd L. Cashin 7161da177e4SLinus Torvalds static void 71768e0d42fSEd L. Cashin ataid_complete(struct aoedev *d, struct aoetgt *t, unsigned char *id) 7181da177e4SLinus Torvalds { 7191da177e4SLinus Torvalds u64 ssize; 7201da177e4SLinus Torvalds u16 n; 7211da177e4SLinus Torvalds 7221da177e4SLinus Torvalds /* word 83: command set supported */ 723f885f8d1SHarvey Harrison n = get_unaligned_le16(&id[83 << 1]); 7241da177e4SLinus Torvalds 7251da177e4SLinus Torvalds /* word 86: command set/feature enabled */ 726f885f8d1SHarvey Harrison n |= get_unaligned_le16(&id[86 << 1]); 7271da177e4SLinus Torvalds 7281da177e4SLinus Torvalds if (n & (1<<10)) { /* bit 10: LBA 48 */ 7291da177e4SLinus Torvalds d->flags |= DEVFL_EXT; 7301da177e4SLinus Torvalds 7311da177e4SLinus Torvalds /* word 100: number lba48 sectors */ 732f885f8d1SHarvey Harrison ssize = get_unaligned_le64(&id[100 << 1]); 7331da177e4SLinus Torvalds 7341da177e4SLinus Torvalds /* set as in ide-disk.c:init_idedisk_capacity */ 7351da177e4SLinus Torvalds d->geo.cylinders = ssize; 7361da177e4SLinus Torvalds d->geo.cylinders /= (255 * 63); 7371da177e4SLinus Torvalds d->geo.heads = 255; 7381da177e4SLinus Torvalds d->geo.sectors = 63; 7391da177e4SLinus Torvalds } else { 7401da177e4SLinus Torvalds d->flags &= ~DEVFL_EXT; 7411da177e4SLinus Torvalds 7421da177e4SLinus Torvalds /* number lba28 sectors */ 743f885f8d1SHarvey Harrison ssize = get_unaligned_le32(&id[60 << 1]); 7441da177e4SLinus Torvalds 7451da177e4SLinus Torvalds /* NOTE: obsolete in ATA 6 */ 746f885f8d1SHarvey Harrison d->geo.cylinders = get_unaligned_le16(&id[54 << 1]); 747f885f8d1SHarvey Harrison d->geo.heads = get_unaligned_le16(&id[55 << 1]); 748f885f8d1SHarvey Harrison d->geo.sectors = get_unaligned_le16(&id[56 << 1]); 7491da177e4SLinus Torvalds } 7503ae1c24eSEd L. Cashin 7513ae1c24eSEd L. Cashin if (d->ssize != ssize) 7521d75981aSEd L. Cashin printk(KERN_INFO 753411c41eeSHarvey Harrison "aoe: %pm e%ld.%d v%04x has %llu sectors\n", 754411c41eeSHarvey Harrison t->addr, 7553ae1c24eSEd L. Cashin d->aoemajor, d->aoeminor, 7563ae1c24eSEd L. Cashin d->fw_ver, (long long)ssize); 7571da177e4SLinus Torvalds d->ssize = ssize; 7581da177e4SLinus Torvalds d->geo.start = 0; 7596b9699bbSEd L. Cashin if (d->flags & (DEVFL_GDALLOC|DEVFL_NEWSIZE)) 7606b9699bbSEd L. Cashin return; 7611da177e4SLinus Torvalds if (d->gd != NULL) { 76280795aefSTejun Heo set_capacity(d->gd, ssize); 7633ae1c24eSEd L. Cashin d->flags |= DEVFL_NEWSIZE; 76468e0d42fSEd L. Cashin } else 7653ae1c24eSEd L. Cashin d->flags |= DEVFL_GDALLOC; 7661da177e4SLinus Torvalds schedule_work(&d->work); 7671da177e4SLinus Torvalds } 7681da177e4SLinus Torvalds 7691da177e4SLinus Torvalds static void 7701da177e4SLinus Torvalds calc_rttavg(struct aoedev *d, int rtt) 7711da177e4SLinus Torvalds { 7721da177e4SLinus Torvalds register long n; 7731da177e4SLinus Torvalds 7741da177e4SLinus Torvalds n = rtt; 775dced3a05SEd L. Cashin if (n < 0) { 776dced3a05SEd L. Cashin n = -rtt; 7771da177e4SLinus Torvalds if (n < MINTIMER) 7781da177e4SLinus Torvalds n = MINTIMER; 7791da177e4SLinus Torvalds else if (n > MAXTIMER) 7801da177e4SLinus Torvalds n = MAXTIMER; 781dced3a05SEd L. Cashin d->mintimer += (n - d->mintimer) >> 1; 782dced3a05SEd L. Cashin } else if (n < d->mintimer) 783dced3a05SEd L. Cashin n = d->mintimer; 784dced3a05SEd L. Cashin else if (n > MAXTIMER) 785dced3a05SEd L. Cashin n = MAXTIMER; 7861da177e4SLinus Torvalds 7871da177e4SLinus Torvalds /* g == .25; cf. Congestion Avoidance and Control, Jacobson & Karels; 1988 */ 7881da177e4SLinus Torvalds n -= d->rttavg; 7891da177e4SLinus Torvalds d->rttavg += n >> 2; 7901da177e4SLinus Torvalds } 7911da177e4SLinus Torvalds 79268e0d42fSEd L. Cashin static struct aoetgt * 79368e0d42fSEd L. Cashin gettgt(struct aoedev *d, char *addr) 79468e0d42fSEd L. Cashin { 79568e0d42fSEd L. Cashin struct aoetgt **t, **e; 79668e0d42fSEd L. Cashin 79768e0d42fSEd L. Cashin t = d->targets; 79868e0d42fSEd L. Cashin e = t + NTARGETS; 79968e0d42fSEd L. Cashin for (; t < e && *t; t++) 80068e0d42fSEd L. Cashin if (memcmp((*t)->addr, addr, sizeof((*t)->addr)) == 0) 80168e0d42fSEd L. Cashin return *t; 80268e0d42fSEd L. Cashin return NULL; 80368e0d42fSEd L. Cashin } 80468e0d42fSEd L. Cashin 80568e0d42fSEd L. Cashin static inline void 80603054de1SLinus Torvalds diskstats(struct gendisk *disk, struct bio *bio, ulong duration, sector_t sector) 80768e0d42fSEd L. Cashin { 80868e0d42fSEd L. Cashin unsigned long n_sect = bio->bi_size >> 9; 80968e0d42fSEd L. Cashin const int rw = bio_data_dir(bio); 81028f13702SJens Axboe struct hd_struct *part; 811c9959059STejun Heo int cpu; 81268e0d42fSEd L. Cashin 813074a7acaSTejun Heo cpu = part_stat_lock(); 814e71bf0d0STejun Heo part = disk_map_sector_rcu(disk, sector); 815e71bf0d0STejun Heo 816074a7acaSTejun Heo part_stat_inc(cpu, part, ios[rw]); 817074a7acaSTejun Heo part_stat_add(cpu, part, ticks[rw], duration); 818074a7acaSTejun Heo part_stat_add(cpu, part, sectors[rw], n_sect); 819074a7acaSTejun Heo part_stat_add(cpu, part, io_ticks, duration); 820c9959059STejun Heo 821074a7acaSTejun Heo part_stat_unlock(); 82268e0d42fSEd L. Cashin } 82368e0d42fSEd L. Cashin 8243d5b0605SEd Cashin static void 825*896831f5SEd Cashin bvcpy(struct bio_vec *bv, ulong off, struct sk_buff *skb, long cnt) 8263d5b0605SEd Cashin { 8273d5b0605SEd Cashin ulong fcnt; 8283d5b0605SEd Cashin char *p; 8293d5b0605SEd Cashin int soff = 0; 8303d5b0605SEd Cashin loop: 8313d5b0605SEd Cashin fcnt = bv->bv_len - (off - bv->bv_offset); 8323d5b0605SEd Cashin if (fcnt > cnt) 8333d5b0605SEd Cashin fcnt = cnt; 8343d5b0605SEd Cashin p = page_address(bv->bv_page) + off; 8353d5b0605SEd Cashin skb_copy_bits(skb, soff, p, fcnt); 8363d5b0605SEd Cashin soff += fcnt; 8373d5b0605SEd Cashin cnt -= fcnt; 8383d5b0605SEd Cashin if (cnt <= 0) 8393d5b0605SEd Cashin return; 8403d5b0605SEd Cashin bv++; 8413d5b0605SEd Cashin off = bv->bv_offset; 8423d5b0605SEd Cashin goto loop; 8433d5b0605SEd Cashin } 8443d5b0605SEd Cashin 8453d5b0605SEd Cashin static void 846*896831f5SEd Cashin ktiocomplete(struct frame *f) 8473d5b0605SEd Cashin { 848ddec63e8SEd L. Cashin struct aoe_hdr *hin, *hout; 8491da177e4SLinus Torvalds struct aoe_atahdr *ahin, *ahout; 8501da177e4SLinus Torvalds struct buf *buf; 851*896831f5SEd Cashin struct sk_buff *skb; 85268e0d42fSEd L. Cashin struct aoetgt *t; 85368e0d42fSEd L. Cashin struct aoeif *ifp; 854*896831f5SEd Cashin struct aoedev *d; 855*896831f5SEd Cashin long n; 856*896831f5SEd Cashin 857*896831f5SEd Cashin if (f == NULL) 858*896831f5SEd Cashin return; 859*896831f5SEd Cashin 860*896831f5SEd Cashin t = f->t; 861*896831f5SEd Cashin d = t->d; 862*896831f5SEd Cashin 863*896831f5SEd Cashin hout = (struct aoe_hdr *) skb_mac_header(f->skb); 864*896831f5SEd Cashin ahout = (struct aoe_atahdr *) (hout+1); 865*896831f5SEd Cashin buf = f->buf; 866*896831f5SEd Cashin skb = f->r_skb; 867*896831f5SEd Cashin if (skb == NULL) 868*896831f5SEd Cashin goto noskb; /* just fail the buf. */ 869*896831f5SEd Cashin 870*896831f5SEd Cashin hin = (struct aoe_hdr *) skb->data; 871*896831f5SEd Cashin skb_pull(skb, sizeof(*hin)); 872*896831f5SEd Cashin ahin = (struct aoe_atahdr *) skb->data; 873*896831f5SEd Cashin skb_pull(skb, sizeof(*ahin)); 874*896831f5SEd Cashin if (ahin->cmdstat & 0xa9) { /* these bits cleared on success */ 875*896831f5SEd Cashin pr_err("aoe: ata error cmd=%2.2Xh stat=%2.2Xh from e%ld.%d\n", 876*896831f5SEd Cashin ahout->cmdstat, ahin->cmdstat, 877*896831f5SEd Cashin d->aoemajor, d->aoeminor); 878*896831f5SEd Cashin noskb: if (buf) 879*896831f5SEd Cashin buf->flags |= BUFFL_FAIL; 880*896831f5SEd Cashin goto badrsp; 881*896831f5SEd Cashin } 882*896831f5SEd Cashin 883*896831f5SEd Cashin n = ahout->scnt << 9; 884*896831f5SEd Cashin switch (ahout->cmdstat) { 885*896831f5SEd Cashin case ATA_CMD_PIO_READ: 886*896831f5SEd Cashin case ATA_CMD_PIO_READ_EXT: 887*896831f5SEd Cashin if (skb->len < n) { 888*896831f5SEd Cashin pr_err("aoe: runt data size in read. skb->len=%d need=%ld\n", 889*896831f5SEd Cashin skb->len, n); 890*896831f5SEd Cashin buf->flags |= BUFFL_FAIL; 891*896831f5SEd Cashin break; 892*896831f5SEd Cashin } 893*896831f5SEd Cashin bvcpy(f->bv, f->bv_off, skb, n); 894*896831f5SEd Cashin case ATA_CMD_PIO_WRITE: 895*896831f5SEd Cashin case ATA_CMD_PIO_WRITE_EXT: 896*896831f5SEd Cashin spin_lock_irq(&d->lock); 897*896831f5SEd Cashin ifp = getif(t, skb->dev); 898*896831f5SEd Cashin if (ifp) { 899*896831f5SEd Cashin ifp->lost = 0; 900*896831f5SEd Cashin if (n > DEFAULTBCNT) 901*896831f5SEd Cashin ifp->lostjumbo = 0; 902*896831f5SEd Cashin } 903*896831f5SEd Cashin if (d->htgt == t) /* I'll help myself, thank you. */ 904*896831f5SEd Cashin d->htgt = NULL; 905*896831f5SEd Cashin spin_unlock_irq(&d->lock); 906*896831f5SEd Cashin break; 907*896831f5SEd Cashin case ATA_CMD_ID_ATA: 908*896831f5SEd Cashin if (skb->len < 512) { 909*896831f5SEd Cashin pr_info("aoe: runt data size in ataid. skb->len=%d\n", 910*896831f5SEd Cashin skb->len); 911*896831f5SEd Cashin break; 912*896831f5SEd Cashin } 913*896831f5SEd Cashin if (skb_linearize(skb)) 914*896831f5SEd Cashin break; 915*896831f5SEd Cashin spin_lock_irq(&d->lock); 916*896831f5SEd Cashin ataid_complete(d, t, skb->data); 917*896831f5SEd Cashin spin_unlock_irq(&d->lock); 918*896831f5SEd Cashin break; 919*896831f5SEd Cashin default: 920*896831f5SEd Cashin pr_info("aoe: unrecognized ata command %2.2Xh for %d.%d\n", 921*896831f5SEd Cashin ahout->cmdstat, 922*896831f5SEd Cashin be16_to_cpu(get_unaligned(&hin->major)), 923*896831f5SEd Cashin hin->minor); 924*896831f5SEd Cashin } 925*896831f5SEd Cashin badrsp: 926*896831f5SEd Cashin spin_lock_irq(&d->lock); 927*896831f5SEd Cashin 928*896831f5SEd Cashin aoe_freetframe(f); 929*896831f5SEd Cashin 930*896831f5SEd Cashin if (buf && --buf->nframesout == 0 && buf->resid == 0) { 931*896831f5SEd Cashin struct bio *bio = buf->bio; 932*896831f5SEd Cashin 933*896831f5SEd Cashin diskstats(d->gd, bio, jiffies - buf->stime, buf->sector); 934*896831f5SEd Cashin n = (buf->flags & BUFFL_FAIL) ? -EIO : 0; 935*896831f5SEd Cashin mempool_free(buf, d->bufpool); 936*896831f5SEd Cashin spin_unlock_irq(&d->lock); 937*896831f5SEd Cashin if (n != -EIO) 938*896831f5SEd Cashin bio_flush_dcache_pages(buf->bio); 939*896831f5SEd Cashin bio_endio(bio, n); 940*896831f5SEd Cashin } else 941*896831f5SEd Cashin spin_unlock_irq(&d->lock); 942*896831f5SEd Cashin dev_kfree_skb(skb); 943*896831f5SEd Cashin } 944*896831f5SEd Cashin 945*896831f5SEd Cashin /* Enters with iocq.lock held. 946*896831f5SEd Cashin * Returns true iff responses needing processing remain. 947*896831f5SEd Cashin */ 948*896831f5SEd Cashin static int 949*896831f5SEd Cashin ktio(void) 950*896831f5SEd Cashin { 951*896831f5SEd Cashin struct frame *f; 952*896831f5SEd Cashin struct list_head *pos; 953*896831f5SEd Cashin int i; 954*896831f5SEd Cashin 955*896831f5SEd Cashin for (i = 0; ; ++i) { 956*896831f5SEd Cashin if (i == MAXIOC) 957*896831f5SEd Cashin return 1; 958*896831f5SEd Cashin if (list_empty(&iocq.head)) 959*896831f5SEd Cashin return 0; 960*896831f5SEd Cashin pos = iocq.head.next; 961*896831f5SEd Cashin list_del(pos); 962*896831f5SEd Cashin spin_unlock_irq(&iocq.lock); 963*896831f5SEd Cashin f = list_entry(pos, struct frame, head); 964*896831f5SEd Cashin ktiocomplete(f); 965*896831f5SEd Cashin spin_lock_irq(&iocq.lock); 966*896831f5SEd Cashin } 967*896831f5SEd Cashin } 968*896831f5SEd Cashin 969*896831f5SEd Cashin static int 970*896831f5SEd Cashin kthread(void *vp) 971*896831f5SEd Cashin { 972*896831f5SEd Cashin struct ktstate *k; 973*896831f5SEd Cashin DECLARE_WAITQUEUE(wait, current); 974*896831f5SEd Cashin int more; 975*896831f5SEd Cashin 976*896831f5SEd Cashin k = vp; 977*896831f5SEd Cashin current->flags |= PF_NOFREEZE; 978*896831f5SEd Cashin set_user_nice(current, -10); 979*896831f5SEd Cashin complete(&k->rendez); /* tell spawner we're running */ 980*896831f5SEd Cashin do { 981*896831f5SEd Cashin spin_lock_irq(k->lock); 982*896831f5SEd Cashin more = k->fn(); 983*896831f5SEd Cashin if (!more) { 984*896831f5SEd Cashin add_wait_queue(k->waitq, &wait); 985*896831f5SEd Cashin __set_current_state(TASK_INTERRUPTIBLE); 986*896831f5SEd Cashin } 987*896831f5SEd Cashin spin_unlock_irq(k->lock); 988*896831f5SEd Cashin if (!more) { 989*896831f5SEd Cashin schedule(); 990*896831f5SEd Cashin remove_wait_queue(k->waitq, &wait); 991*896831f5SEd Cashin } else 992*896831f5SEd Cashin cond_resched(); 993*896831f5SEd Cashin } while (!kthread_should_stop()); 994*896831f5SEd Cashin complete(&k->rendez); /* tell spawner we're stopping */ 995*896831f5SEd Cashin return 0; 996*896831f5SEd Cashin } 997*896831f5SEd Cashin 998*896831f5SEd Cashin static void 999*896831f5SEd Cashin aoe_ktstop(struct ktstate *k) 1000*896831f5SEd Cashin { 1001*896831f5SEd Cashin kthread_stop(k->task); 1002*896831f5SEd Cashin wait_for_completion(&k->rendez); 1003*896831f5SEd Cashin } 1004*896831f5SEd Cashin 1005*896831f5SEd Cashin static int 1006*896831f5SEd Cashin aoe_ktstart(struct ktstate *k) 1007*896831f5SEd Cashin { 1008*896831f5SEd Cashin struct task_struct *task; 1009*896831f5SEd Cashin 1010*896831f5SEd Cashin init_completion(&k->rendez); 1011*896831f5SEd Cashin task = kthread_run(kthread, k, k->name); 1012*896831f5SEd Cashin if (task == NULL || IS_ERR(task)) 1013*896831f5SEd Cashin return -ENOMEM; 1014*896831f5SEd Cashin k->task = task; 1015*896831f5SEd Cashin wait_for_completion(&k->rendez); /* allow kthread to start */ 1016*896831f5SEd Cashin init_completion(&k->rendez); /* for waiting for exit later */ 1017*896831f5SEd Cashin return 0; 1018*896831f5SEd Cashin } 1019*896831f5SEd Cashin 1020*896831f5SEd Cashin /* pass it off to kthreads for processing */ 1021*896831f5SEd Cashin static void 1022*896831f5SEd Cashin ktcomplete(struct frame *f, struct sk_buff *skb) 1023*896831f5SEd Cashin { 1024*896831f5SEd Cashin ulong flags; 1025*896831f5SEd Cashin 1026*896831f5SEd Cashin f->r_skb = skb; 1027*896831f5SEd Cashin spin_lock_irqsave(&iocq.lock, flags); 1028*896831f5SEd Cashin list_add_tail(&f->head, &iocq.head); 1029*896831f5SEd Cashin spin_unlock_irqrestore(&iocq.lock, flags); 1030*896831f5SEd Cashin wake_up(&ktiowq); 1031*896831f5SEd Cashin } 1032*896831f5SEd Cashin 1033*896831f5SEd Cashin struct sk_buff * 1034*896831f5SEd Cashin aoecmd_ata_rsp(struct sk_buff *skb) 1035*896831f5SEd Cashin { 1036*896831f5SEd Cashin struct aoedev *d; 1037*896831f5SEd Cashin struct aoe_hdr *h; 1038*896831f5SEd Cashin struct frame *f; 1039*896831f5SEd Cashin struct aoetgt *t; 1040*896831f5SEd Cashin u32 n; 10411da177e4SLinus Torvalds ulong flags; 10421da177e4SLinus Torvalds char ebuf[128]; 104332465c65Secashin@coraid.com u16 aoemajor; 10441da177e4SLinus Torvalds 1045*896831f5SEd Cashin h = (struct aoe_hdr *) skb->data; 1046*896831f5SEd Cashin aoemajor = be16_to_cpu(get_unaligned(&h->major)); 1047*896831f5SEd Cashin d = aoedev_by_aoeaddr(aoemajor, h->minor); 10481da177e4SLinus Torvalds if (d == NULL) { 10491da177e4SLinus Torvalds snprintf(ebuf, sizeof ebuf, "aoecmd_ata_rsp: ata response " 10501da177e4SLinus Torvalds "for unknown device %d.%d\n", 1051*896831f5SEd Cashin aoemajor, h->minor); 10521da177e4SLinus Torvalds aoechr_error(ebuf); 1053*896831f5SEd Cashin return skb; 10541da177e4SLinus Torvalds } 10551da177e4SLinus Torvalds 10561da177e4SLinus Torvalds spin_lock_irqsave(&d->lock, flags); 10571da177e4SLinus Torvalds 1058*896831f5SEd Cashin n = be32_to_cpu(get_unaligned(&h->tag)); 1059*896831f5SEd Cashin t = gettgt(d, h->src); 106068e0d42fSEd L. Cashin if (t == NULL) { 1061411c41eeSHarvey Harrison printk(KERN_INFO "aoe: can't find target e%ld.%d:%pm\n", 1062*896831f5SEd Cashin d->aoemajor, d->aoeminor, h->src); 106368e0d42fSEd L. Cashin spin_unlock_irqrestore(&d->lock, flags); 1064*896831f5SEd Cashin return skb; 106568e0d42fSEd L. Cashin } 106668e0d42fSEd L. Cashin f = getframe(t, n); 10671da177e4SLinus Torvalds if (f == NULL) { 1068dced3a05SEd L. Cashin calc_rttavg(d, -tsince(n)); 10691da177e4SLinus Torvalds spin_unlock_irqrestore(&d->lock, flags); 10701da177e4SLinus Torvalds snprintf(ebuf, sizeof ebuf, 10711da177e4SLinus Torvalds "%15s e%d.%d tag=%08x@%08lx\n", 10721da177e4SLinus Torvalds "unexpected rsp", 1073*896831f5SEd Cashin get_unaligned_be16(&h->major), 1074*896831f5SEd Cashin h->minor, 1075*896831f5SEd Cashin get_unaligned_be32(&h->tag), 10761da177e4SLinus Torvalds jiffies); 10771da177e4SLinus Torvalds aoechr_error(ebuf); 1078*896831f5SEd Cashin return skb; 10791da177e4SLinus Torvalds } 10801da177e4SLinus Torvalds calc_rttavg(d, tsince(f->tag)); 108168e0d42fSEd L. Cashin t->nout--; 10821da177e4SLinus Torvalds aoecmd_work(d); 10831da177e4SLinus Torvalds 10841da177e4SLinus Torvalds spin_unlock_irqrestore(&d->lock, flags); 1085*896831f5SEd Cashin 1086*896831f5SEd Cashin ktcomplete(f, skb); 1087*896831f5SEd Cashin 1088*896831f5SEd Cashin /* 1089*896831f5SEd Cashin * Note here that we do not perform an aoedev_put, as we are 1090*896831f5SEd Cashin * leaving this reference for the ktio to release. 1091*896831f5SEd Cashin */ 1092*896831f5SEd Cashin return NULL; 10931da177e4SLinus Torvalds } 10941da177e4SLinus Torvalds 10951da177e4SLinus Torvalds void 10961da177e4SLinus Torvalds aoecmd_cfg(ushort aoemajor, unsigned char aoeminor) 10971da177e4SLinus Torvalds { 1098e9bb8fb0SDavid S. Miller struct sk_buff_head queue; 10991da177e4SLinus Torvalds 1100e9bb8fb0SDavid S. Miller __skb_queue_head_init(&queue); 1101e9bb8fb0SDavid S. Miller aoecmd_cfg_pkts(aoemajor, aoeminor, &queue); 1102e9bb8fb0SDavid S. Miller aoenet_xmit(&queue); 11031da177e4SLinus Torvalds } 11041da177e4SLinus Torvalds 110568e0d42fSEd L. Cashin struct sk_buff * 11061da177e4SLinus Torvalds aoecmd_ata_id(struct aoedev *d) 11071da177e4SLinus Torvalds { 11081da177e4SLinus Torvalds struct aoe_hdr *h; 11091da177e4SLinus Torvalds struct aoe_atahdr *ah; 11101da177e4SLinus Torvalds struct frame *f; 11111da177e4SLinus Torvalds struct sk_buff *skb; 111268e0d42fSEd L. Cashin struct aoetgt *t; 11131da177e4SLinus Torvalds 1114*896831f5SEd Cashin f = newframe(d); 111568e0d42fSEd L. Cashin if (f == NULL) 11161da177e4SLinus Torvalds return NULL; 111768e0d42fSEd L. Cashin 111868e0d42fSEd L. Cashin t = *d->tgt; 11191da177e4SLinus Torvalds 11201da177e4SLinus Torvalds /* initialize the headers & frame */ 1121e407a7f6SEd L. Cashin skb = f->skb; 1122abdbf94dSEd L. Cashin h = (struct aoe_hdr *) skb_mac_header(skb); 11231da177e4SLinus Torvalds ah = (struct aoe_atahdr *) (h+1); 112419900cdeSEd L. Cashin skb_put(skb, sizeof *h + sizeof *ah); 112519900cdeSEd L. Cashin memset(h, 0, skb->len); 112668e0d42fSEd L. Cashin f->tag = aoehdr_atainit(d, t, h); 1127*896831f5SEd Cashin fhash(f); 112868e0d42fSEd L. Cashin t->nout++; 11291da177e4SLinus Torvalds f->waited = 0; 11301da177e4SLinus Torvalds 11311da177e4SLinus Torvalds /* set up ata header */ 11321da177e4SLinus Torvalds ah->scnt = 1; 113304b3ab52SBartlomiej Zolnierkiewicz ah->cmdstat = ATA_CMD_ID_ATA; 11341da177e4SLinus Torvalds ah->lba3 = 0xa0; 11351da177e4SLinus Torvalds 113668e0d42fSEd L. Cashin skb->dev = t->ifp->nd; 11371da177e4SLinus Torvalds 11383ae1c24eSEd L. Cashin d->rttavg = MAXTIMER; 11391da177e4SLinus Torvalds d->timer.function = rexmit_timer; 11401da177e4SLinus Torvalds 11414f51dc5eSEd L. Cashin return skb_clone(skb, GFP_ATOMIC); 11421da177e4SLinus Torvalds } 11431da177e4SLinus Torvalds 114468e0d42fSEd L. Cashin static struct aoetgt * 114568e0d42fSEd L. Cashin addtgt(struct aoedev *d, char *addr, ulong nframes) 114668e0d42fSEd L. Cashin { 114768e0d42fSEd L. Cashin struct aoetgt *t, **tt, **te; 1148*896831f5SEd Cashin int i; 114968e0d42fSEd L. Cashin 115068e0d42fSEd L. Cashin tt = d->targets; 115168e0d42fSEd L. Cashin te = tt + NTARGETS; 115268e0d42fSEd L. Cashin for (; tt < te && *tt; tt++) 115368e0d42fSEd L. Cashin ; 115468e0d42fSEd L. Cashin 1155578c4aa0SEd L. Cashin if (tt == te) { 1156578c4aa0SEd L. Cashin printk(KERN_INFO 1157578c4aa0SEd L. Cashin "aoe: device addtgt failure; too many targets\n"); 115868e0d42fSEd L. Cashin return NULL; 1159578c4aa0SEd L. Cashin } 1160*896831f5SEd Cashin t = kzalloc(sizeof(*t), GFP_ATOMIC); 1161*896831f5SEd Cashin if (!t) { 1162578c4aa0SEd L. Cashin printk(KERN_INFO "aoe: cannot allocate memory to add target\n"); 11639bb237b6SEd L. Cashin return NULL; 11649bb237b6SEd L. Cashin } 11659bb237b6SEd L. Cashin 1166*896831f5SEd Cashin d->ntargets++; 116768e0d42fSEd L. Cashin t->nframes = nframes; 1168*896831f5SEd Cashin t->d = d; 116968e0d42fSEd L. Cashin memcpy(t->addr, addr, sizeof t->addr); 117068e0d42fSEd L. Cashin t->ifp = t->ifs; 117168e0d42fSEd L. Cashin t->maxout = t->nframes; 1172*896831f5SEd Cashin INIT_LIST_HEAD(&t->ffree); 1173*896831f5SEd Cashin for (i = 0; i < NFACTIVE; ++i) 1174*896831f5SEd Cashin INIT_LIST_HEAD(&t->factive[i]); 117568e0d42fSEd L. Cashin return *tt = t; 117668e0d42fSEd L. Cashin } 117768e0d42fSEd L. Cashin 11781da177e4SLinus Torvalds void 11791da177e4SLinus Torvalds aoecmd_cfg_rsp(struct sk_buff *skb) 11801da177e4SLinus Torvalds { 11811da177e4SLinus Torvalds struct aoedev *d; 11821da177e4SLinus Torvalds struct aoe_hdr *h; 11831da177e4SLinus Torvalds struct aoe_cfghdr *ch; 118468e0d42fSEd L. Cashin struct aoetgt *t; 118568e0d42fSEd L. Cashin struct aoeif *ifp; 118663e9cc5dSecashin@coraid.com ulong flags, sysminor, aoemajor; 11871da177e4SLinus Torvalds struct sk_buff *sl; 118819bf2635SEd L. Cashin u16 n; 11891da177e4SLinus Torvalds 1190abdbf94dSEd L. Cashin h = (struct aoe_hdr *) skb_mac_header(skb); 11911da177e4SLinus Torvalds ch = (struct aoe_cfghdr *) (h+1); 11921da177e4SLinus Torvalds 11931da177e4SLinus Torvalds /* 11941da177e4SLinus Torvalds * Enough people have their dip switches set backwards to 11951da177e4SLinus Torvalds * warrant a loud message for this special case. 11961da177e4SLinus Torvalds */ 1197823ed72eSHarvey Harrison aoemajor = get_unaligned_be16(&h->major); 11981da177e4SLinus Torvalds if (aoemajor == 0xfff) { 1199a12c93f0SEd L. Cashin printk(KERN_ERR "aoe: Warning: shelf address is all ones. " 12006bb6285fSEd L. Cashin "Check shelf dip switches.\n"); 12011da177e4SLinus Torvalds return; 12021da177e4SLinus Torvalds } 12031da177e4SLinus Torvalds 12041da177e4SLinus Torvalds sysminor = SYSMINOR(aoemajor, h->minor); 1205fc458dcdSecashin@coraid.com if (sysminor * AOE_PARTITIONS + AOE_PARTITIONS > MINORMASK) { 1206a12c93f0SEd L. Cashin printk(KERN_INFO "aoe: e%ld.%d: minor number too large\n", 1207fc458dcdSecashin@coraid.com aoemajor, (int) h->minor); 12081da177e4SLinus Torvalds return; 12091da177e4SLinus Torvalds } 12101da177e4SLinus Torvalds 121119bf2635SEd L. Cashin n = be16_to_cpu(ch->bufcnt); 12127df620d8SEd L. Cashin if (n > aoe_maxout) /* keep it reasonable */ 12137df620d8SEd L. Cashin n = aoe_maxout; 12141da177e4SLinus Torvalds 121568e0d42fSEd L. Cashin d = aoedev_by_sysminor_m(sysminor); 12161da177e4SLinus Torvalds if (d == NULL) { 1217a12c93f0SEd L. Cashin printk(KERN_INFO "aoe: device sysminor_m failure\n"); 12181da177e4SLinus Torvalds return; 12191da177e4SLinus Torvalds } 12201da177e4SLinus Torvalds 12211da177e4SLinus Torvalds spin_lock_irqsave(&d->lock, flags); 12221da177e4SLinus Torvalds 122368e0d42fSEd L. Cashin t = gettgt(d, h->src); 122468e0d42fSEd L. Cashin if (!t) { 122568e0d42fSEd L. Cashin t = addtgt(d, h->src, n); 122668e0d42fSEd L. Cashin if (!t) { 122768e0d42fSEd L. Cashin spin_unlock_irqrestore(&d->lock, flags); 122868e0d42fSEd L. Cashin return; 122968e0d42fSEd L. Cashin } 123068e0d42fSEd L. Cashin } 123168e0d42fSEd L. Cashin ifp = getif(t, skb->dev); 123268e0d42fSEd L. Cashin if (!ifp) { 123368e0d42fSEd L. Cashin ifp = addif(t, skb->dev); 123468e0d42fSEd L. Cashin if (!ifp) { 123568e0d42fSEd L. Cashin printk(KERN_INFO 123668e0d42fSEd L. Cashin "aoe: device addif failure; " 123768e0d42fSEd L. Cashin "too many interfaces?\n"); 123868e0d42fSEd L. Cashin spin_unlock_irqrestore(&d->lock, flags); 123968e0d42fSEd L. Cashin return; 124068e0d42fSEd L. Cashin } 124168e0d42fSEd L. Cashin } 124268e0d42fSEd L. Cashin if (ifp->maxbcnt) { 124368e0d42fSEd L. Cashin n = ifp->nd->mtu; 124419bf2635SEd L. Cashin n -= sizeof (struct aoe_hdr) + sizeof (struct aoe_atahdr); 124519bf2635SEd L. Cashin n /= 512; 124619bf2635SEd L. Cashin if (n > ch->scnt) 124719bf2635SEd L. Cashin n = ch->scnt; 12484f51dc5eSEd L. Cashin n = n ? n * 512 : DEFAULTBCNT; 124968e0d42fSEd L. Cashin if (n != ifp->maxbcnt) { 1250a12c93f0SEd L. Cashin printk(KERN_INFO 1251411c41eeSHarvey Harrison "aoe: e%ld.%d: setting %d%s%s:%pm\n", 125268e0d42fSEd L. Cashin d->aoemajor, d->aoeminor, n, 125368e0d42fSEd L. Cashin " byte data frames on ", ifp->nd->name, 1254411c41eeSHarvey Harrison t->addr); 125568e0d42fSEd L. Cashin ifp->maxbcnt = n; 12564f51dc5eSEd L. Cashin } 125719bf2635SEd L. Cashin } 12583ae1c24eSEd L. Cashin 12593ae1c24eSEd L. Cashin /* don't change users' perspective */ 126068e0d42fSEd L. Cashin if (d->nopen) { 12611da177e4SLinus Torvalds spin_unlock_irqrestore(&d->lock, flags); 12621da177e4SLinus Torvalds return; 12631da177e4SLinus Torvalds } 126463e9cc5dSecashin@coraid.com d->fw_ver = be16_to_cpu(ch->fwver); 12651da177e4SLinus Torvalds 126668e0d42fSEd L. Cashin sl = aoecmd_ata_id(d); 12671da177e4SLinus Torvalds 12681da177e4SLinus Torvalds spin_unlock_irqrestore(&d->lock, flags); 12691da177e4SLinus Torvalds 1270e9bb8fb0SDavid S. Miller if (sl) { 1271e9bb8fb0SDavid S. Miller struct sk_buff_head queue; 1272e9bb8fb0SDavid S. Miller __skb_queue_head_init(&queue); 1273e9bb8fb0SDavid S. Miller __skb_queue_tail(&queue, sl); 1274e9bb8fb0SDavid S. Miller aoenet_xmit(&queue); 1275e9bb8fb0SDavid S. Miller } 12761da177e4SLinus Torvalds } 12771da177e4SLinus Torvalds 127868e0d42fSEd L. Cashin void 127968e0d42fSEd L. Cashin aoecmd_cleanslate(struct aoedev *d) 128068e0d42fSEd L. Cashin { 128168e0d42fSEd L. Cashin struct aoetgt **t, **te; 128268e0d42fSEd L. Cashin struct aoeif *p, *e; 128368e0d42fSEd L. Cashin 128468e0d42fSEd L. Cashin d->mintimer = MINTIMER; 128568e0d42fSEd L. Cashin 128668e0d42fSEd L. Cashin t = d->targets; 128768e0d42fSEd L. Cashin te = t + NTARGETS; 128868e0d42fSEd L. Cashin for (; t < te && *t; t++) { 128968e0d42fSEd L. Cashin (*t)->maxout = (*t)->nframes; 129068e0d42fSEd L. Cashin p = (*t)->ifs; 129168e0d42fSEd L. Cashin e = p + NAOEIFS; 129268e0d42fSEd L. Cashin for (; p < e; p++) { 129368e0d42fSEd L. Cashin p->lostjumbo = 0; 129468e0d42fSEd L. Cashin p->lost = 0; 129568e0d42fSEd L. Cashin p->maxbcnt = DEFAULTBCNT; 129668e0d42fSEd L. Cashin } 129768e0d42fSEd L. Cashin } 129868e0d42fSEd L. Cashin } 1299*896831f5SEd Cashin 1300*896831f5SEd Cashin static void 1301*896831f5SEd Cashin flush_iocq(void) 1302*896831f5SEd Cashin { 1303*896831f5SEd Cashin struct frame *f; 1304*896831f5SEd Cashin struct aoedev *d; 1305*896831f5SEd Cashin LIST_HEAD(flist); 1306*896831f5SEd Cashin struct list_head *pos; 1307*896831f5SEd Cashin struct sk_buff *skb; 1308*896831f5SEd Cashin ulong flags; 1309*896831f5SEd Cashin 1310*896831f5SEd Cashin spin_lock_irqsave(&iocq.lock, flags); 1311*896831f5SEd Cashin list_splice_init(&iocq.head, &flist); 1312*896831f5SEd Cashin spin_unlock_irqrestore(&iocq.lock, flags); 1313*896831f5SEd Cashin while (!list_empty(&flist)) { 1314*896831f5SEd Cashin pos = flist.next; 1315*896831f5SEd Cashin list_del(pos); 1316*896831f5SEd Cashin f = list_entry(pos, struct frame, head); 1317*896831f5SEd Cashin d = f->t->d; 1318*896831f5SEd Cashin skb = f->r_skb; 1319*896831f5SEd Cashin spin_lock_irqsave(&d->lock, flags); 1320*896831f5SEd Cashin if (f->buf) { 1321*896831f5SEd Cashin f->buf->nframesout--; 1322*896831f5SEd Cashin aoe_failbuf(d, f->buf); 1323*896831f5SEd Cashin } 1324*896831f5SEd Cashin aoe_freetframe(f); 1325*896831f5SEd Cashin spin_unlock_irqrestore(&d->lock, flags); 1326*896831f5SEd Cashin dev_kfree_skb(skb); 1327*896831f5SEd Cashin } 1328*896831f5SEd Cashin } 1329*896831f5SEd Cashin 1330*896831f5SEd Cashin int __init 1331*896831f5SEd Cashin aoecmd_init(void) 1332*896831f5SEd Cashin { 1333*896831f5SEd Cashin INIT_LIST_HEAD(&iocq.head); 1334*896831f5SEd Cashin spin_lock_init(&iocq.lock); 1335*896831f5SEd Cashin init_waitqueue_head(&ktiowq); 1336*896831f5SEd Cashin kts.name = "aoe_ktio"; 1337*896831f5SEd Cashin kts.fn = ktio; 1338*896831f5SEd Cashin kts.waitq = &ktiowq; 1339*896831f5SEd Cashin kts.lock = &iocq.lock; 1340*896831f5SEd Cashin return aoe_ktstart(&kts); 1341*896831f5SEd Cashin } 1342*896831f5SEd Cashin 1343*896831f5SEd Cashin void 1344*896831f5SEd Cashin aoecmd_exit(void) 1345*896831f5SEd Cashin { 1346*896831f5SEd Cashin aoe_ktstop(&kts); 1347*896831f5SEd Cashin flush_iocq(); 1348*896831f5SEd Cashin } 1349