1ca47bbd9SEd Cashin /* Copyright (c) 2013 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 *); 25bbb44e30SEd Cashin static int count_targets(struct aoedev *d, int *untainted); 26896831f5SEd Cashin 2769cf2d85SEd Cashin static struct buf *nextbuf(struct aoedev *); 2869cf2d85SEd Cashin 29b751e8b6SEd L. Cashin static int aoe_deadsecs = 60 * 3; 30b751e8b6SEd L. Cashin module_param(aoe_deadsecs, int, 0644); 31b751e8b6SEd L. Cashin MODULE_PARM_DESC(aoe_deadsecs, "After aoe_deadsecs seconds, give up and fail dev."); 321da177e4SLinus Torvalds 337b6ccc5fSEd Cashin static int aoe_maxout = 64; 347df620d8SEd L. Cashin module_param(aoe_maxout, int, 0644); 357df620d8SEd L. Cashin MODULE_PARM_DESC(aoe_maxout, 367df620d8SEd L. Cashin "Only aoe_maxout outstanding packets for every MAC on eX.Y."); 377df620d8SEd L. Cashin 388030d343SEd Cashin /* The number of online cpus during module initialization gives us a 398030d343SEd Cashin * convenient heuristic cap on the parallelism used for ktio threads 408030d343SEd Cashin * doing I/O completion. It is not important that the cap equal the 418030d343SEd Cashin * actual number of running CPUs at any given time, but because of CPU 428030d343SEd Cashin * hotplug, we take care to use ncpus instead of using 438030d343SEd Cashin * num_online_cpus() after module initialization. 448030d343SEd Cashin */ 458030d343SEd Cashin static int ncpus; 468030d343SEd Cashin 478030d343SEd Cashin /* mutex lock used for synchronization while thread spawning */ 488030d343SEd Cashin static DEFINE_MUTEX(ktio_spawn_lock); 498030d343SEd Cashin 508030d343SEd Cashin static wait_queue_head_t *ktiowq; 518030d343SEd Cashin static struct ktstate *kts; 52896831f5SEd Cashin 53896831f5SEd Cashin /* io completion queue */ 548030d343SEd Cashin struct iocq_ktio { 55896831f5SEd Cashin struct list_head head; 56896831f5SEd Cashin spinlock_t lock; 578030d343SEd Cashin }; 588030d343SEd Cashin static struct iocq_ktio *iocq; 59896831f5SEd Cashin 60bbb44e30SEd Cashin static struct page *empty_page; 61bbb44e30SEd Cashin 6268e0d42fSEd L. Cashin static struct sk_buff * 63e407a7f6SEd L. Cashin new_skb(ulong len) 641da177e4SLinus Torvalds { 651da177e4SLinus Torvalds struct sk_buff *skb; 661da177e4SLinus Torvalds 6791c57464SEric Dumazet skb = alloc_skb(len + MAX_HEADER, GFP_ATOMIC); 681da177e4SLinus Torvalds if (skb) { 6991c57464SEric Dumazet skb_reserve(skb, MAX_HEADER); 70459a98edSArnaldo Carvalho de Melo skb_reset_mac_header(skb); 71c1d2bbe1SArnaldo Carvalho de Melo skb_reset_network_header(skb); 721da177e4SLinus Torvalds skb->protocol = __constant_htons(ETH_P_AOE); 738babe8ccSEd Cashin skb_checksum_none_assert(skb); 741da177e4SLinus Torvalds } 751da177e4SLinus Torvalds return skb; 761da177e4SLinus Torvalds } 771da177e4SLinus Torvalds 781da177e4SLinus Torvalds static struct frame * 793a0c40d2SEd Cashin getframe_deferred(struct aoedev *d, u32 tag) 803a0c40d2SEd Cashin { 813a0c40d2SEd Cashin struct list_head *head, *pos, *nx; 823a0c40d2SEd Cashin struct frame *f; 833a0c40d2SEd Cashin 843a0c40d2SEd Cashin head = &d->rexmitq; 853a0c40d2SEd Cashin list_for_each_safe(pos, nx, head) { 863a0c40d2SEd Cashin f = list_entry(pos, struct frame, head); 873a0c40d2SEd Cashin if (f->tag == tag) { 883a0c40d2SEd Cashin list_del(pos); 893a0c40d2SEd Cashin return f; 903a0c40d2SEd Cashin } 913a0c40d2SEd Cashin } 923a0c40d2SEd Cashin return NULL; 933a0c40d2SEd Cashin } 943a0c40d2SEd Cashin 953a0c40d2SEd Cashin static struct frame * 9664a80f5aSEd Cashin getframe(struct aoedev *d, u32 tag) 971da177e4SLinus Torvalds { 98896831f5SEd Cashin struct frame *f; 99896831f5SEd Cashin struct list_head *head, *pos, *nx; 100896831f5SEd Cashin u32 n; 1011da177e4SLinus Torvalds 102896831f5SEd Cashin n = tag % NFACTIVE; 10364a80f5aSEd Cashin head = &d->factive[n]; 104896831f5SEd Cashin list_for_each_safe(pos, nx, head) { 105896831f5SEd Cashin f = list_entry(pos, struct frame, head); 106896831f5SEd Cashin if (f->tag == tag) { 107896831f5SEd Cashin list_del(pos); 1081da177e4SLinus Torvalds return f; 109896831f5SEd Cashin } 110896831f5SEd Cashin } 1111da177e4SLinus Torvalds return NULL; 1121da177e4SLinus Torvalds } 1131da177e4SLinus Torvalds 1141da177e4SLinus Torvalds /* 1151da177e4SLinus Torvalds * Leave the top bit clear so we have tagspace for userland. 1161da177e4SLinus Torvalds * The bottom 16 bits are the xmit tick for rexmit/rttavg processing. 1171da177e4SLinus Torvalds * This driver reserves tag -1 to mean "unused frame." 1181da177e4SLinus Torvalds */ 1191da177e4SLinus Torvalds static int 12064a80f5aSEd Cashin newtag(struct aoedev *d) 1211da177e4SLinus Torvalds { 1221da177e4SLinus Torvalds register ulong n; 1231da177e4SLinus Torvalds 1241da177e4SLinus Torvalds n = jiffies & 0xffff; 12564a80f5aSEd Cashin return n |= (++d->lasttag & 0x7fff) << 16; 1261da177e4SLinus Torvalds } 1271da177e4SLinus Torvalds 128896831f5SEd Cashin static u32 12968e0d42fSEd L. Cashin aoehdr_atainit(struct aoedev *d, struct aoetgt *t, struct aoe_hdr *h) 1301da177e4SLinus Torvalds { 13164a80f5aSEd Cashin u32 host_tag = newtag(d); 1321da177e4SLinus Torvalds 13368e0d42fSEd L. Cashin memcpy(h->src, t->ifp->nd->dev_addr, sizeof h->src); 13468e0d42fSEd L. Cashin memcpy(h->dst, t->addr, sizeof h->dst); 13563e9cc5dSecashin@coraid.com h->type = __constant_cpu_to_be16(ETH_P_AOE); 1361da177e4SLinus Torvalds h->verfl = AOE_HVER; 13763e9cc5dSecashin@coraid.com h->major = cpu_to_be16(d->aoemajor); 1381da177e4SLinus Torvalds h->minor = d->aoeminor; 1391da177e4SLinus Torvalds h->cmd = AOECMD_ATA; 14063e9cc5dSecashin@coraid.com h->tag = cpu_to_be32(host_tag); 1411da177e4SLinus Torvalds 1421da177e4SLinus Torvalds return host_tag; 1431da177e4SLinus Torvalds } 1441da177e4SLinus Torvalds 14519bf2635SEd L. Cashin static inline void 14619bf2635SEd L. Cashin put_lba(struct aoe_atahdr *ah, sector_t lba) 14719bf2635SEd L. Cashin { 14819bf2635SEd L. Cashin ah->lba0 = lba; 14919bf2635SEd L. Cashin ah->lba1 = lba >>= 8; 15019bf2635SEd L. Cashin ah->lba2 = lba >>= 8; 15119bf2635SEd L. Cashin ah->lba3 = lba >>= 8; 15219bf2635SEd L. Cashin ah->lba4 = lba >>= 8; 15319bf2635SEd L. Cashin ah->lba5 = lba >>= 8; 15419bf2635SEd L. Cashin } 15519bf2635SEd L. Cashin 1563f0f0133SEd Cashin static struct aoeif * 15768e0d42fSEd L. Cashin ifrotate(struct aoetgt *t) 1581da177e4SLinus Torvalds { 1593f0f0133SEd Cashin struct aoeif *ifp; 1603f0f0133SEd Cashin 1613f0f0133SEd Cashin ifp = t->ifp; 1623f0f0133SEd Cashin ifp++; 1633f0f0133SEd Cashin if (ifp >= &t->ifs[NAOEIFS] || ifp->nd == NULL) 1643f0f0133SEd Cashin ifp = t->ifs; 1653f0f0133SEd Cashin if (ifp->nd == NULL) 1663f0f0133SEd Cashin return NULL; 1673f0f0133SEd Cashin return t->ifp = ifp; 16868e0d42fSEd L. Cashin } 16968e0d42fSEd L. Cashin 1709bb237b6SEd L. Cashin static void 1719bb237b6SEd L. Cashin skb_pool_put(struct aoedev *d, struct sk_buff *skb) 1729bb237b6SEd L. Cashin { 173e9bb8fb0SDavid S. Miller __skb_queue_tail(&d->skbpool, skb); 1749bb237b6SEd L. Cashin } 1759bb237b6SEd L. Cashin 1769bb237b6SEd L. Cashin static struct sk_buff * 1779bb237b6SEd L. Cashin skb_pool_get(struct aoedev *d) 1789bb237b6SEd L. Cashin { 179e9bb8fb0SDavid S. Miller struct sk_buff *skb = skb_peek(&d->skbpool); 1809bb237b6SEd L. Cashin 1819bb237b6SEd L. Cashin if (skb && atomic_read(&skb_shinfo(skb)->dataref) == 1) { 182e9bb8fb0SDavid S. Miller __skb_unlink(skb, &d->skbpool); 1839bb237b6SEd L. Cashin return skb; 1849bb237b6SEd L. Cashin } 185e9bb8fb0SDavid S. Miller if (skb_queue_len(&d->skbpool) < NSKBPOOLMAX && 186e9bb8fb0SDavid S. Miller (skb = new_skb(ETH_ZLEN))) 1879bb237b6SEd L. Cashin return skb; 188e9bb8fb0SDavid S. Miller 1899bb237b6SEd L. Cashin return NULL; 1909bb237b6SEd L. Cashin } 1919bb237b6SEd L. Cashin 192896831f5SEd Cashin void 193896831f5SEd Cashin aoe_freetframe(struct frame *f) 19468e0d42fSEd L. Cashin { 195896831f5SEd Cashin struct aoetgt *t; 196896831f5SEd Cashin 197896831f5SEd Cashin t = f->t; 198896831f5SEd Cashin f->buf = NULL; 199feb261e2SKent Overstreet memset(&f->iter, 0, sizeof(f->iter)); 200896831f5SEd Cashin f->r_skb = NULL; 201bbb44e30SEd Cashin f->flags = 0; 202896831f5SEd Cashin list_add(&f->head, &t->ffree); 203896831f5SEd Cashin } 204896831f5SEd Cashin 205896831f5SEd Cashin static struct frame * 206896831f5SEd Cashin newtframe(struct aoedev *d, struct aoetgt *t) 207896831f5SEd Cashin { 208896831f5SEd Cashin struct frame *f; 2099bb237b6SEd L. Cashin struct sk_buff *skb; 210896831f5SEd Cashin struct list_head *pos; 211896831f5SEd Cashin 212896831f5SEd Cashin if (list_empty(&t->ffree)) { 213896831f5SEd Cashin if (t->falloc >= NSKBPOOLMAX*2) 214896831f5SEd Cashin return NULL; 215896831f5SEd Cashin f = kcalloc(1, sizeof(*f), GFP_ATOMIC); 216896831f5SEd Cashin if (f == NULL) 217896831f5SEd Cashin return NULL; 218896831f5SEd Cashin t->falloc++; 219896831f5SEd Cashin f->t = t; 220896831f5SEd Cashin } else { 221896831f5SEd Cashin pos = t->ffree.next; 222896831f5SEd Cashin list_del(pos); 223896831f5SEd Cashin f = list_entry(pos, struct frame, head); 224896831f5SEd Cashin } 225896831f5SEd Cashin 226896831f5SEd Cashin skb = f->skb; 227896831f5SEd Cashin if (skb == NULL) { 228896831f5SEd Cashin f->skb = skb = new_skb(ETH_ZLEN); 229896831f5SEd Cashin if (!skb) { 230896831f5SEd Cashin bail: aoe_freetframe(f); 231896831f5SEd Cashin return NULL; 232896831f5SEd Cashin } 233896831f5SEd Cashin } 234896831f5SEd Cashin 235896831f5SEd Cashin if (atomic_read(&skb_shinfo(skb)->dataref) != 1) { 236896831f5SEd Cashin skb = skb_pool_get(d); 237896831f5SEd Cashin if (skb == NULL) 238896831f5SEd Cashin goto bail; 239896831f5SEd Cashin skb_pool_put(d, f->skb); 240896831f5SEd Cashin f->skb = skb; 241896831f5SEd Cashin } 242896831f5SEd Cashin 243896831f5SEd Cashin skb->truesize -= skb->data_len; 244896831f5SEd Cashin skb_shinfo(skb)->nr_frags = skb->data_len = 0; 245896831f5SEd Cashin skb_trim(skb, 0); 246896831f5SEd Cashin return f; 247896831f5SEd Cashin } 248896831f5SEd Cashin 249896831f5SEd Cashin static struct frame * 250896831f5SEd Cashin newframe(struct aoedev *d) 251896831f5SEd Cashin { 252896831f5SEd Cashin struct frame *f; 253896831f5SEd Cashin struct aoetgt *t, **tt; 254896831f5SEd Cashin int totout = 0; 255bbb44e30SEd Cashin int use_tainted; 256bbb44e30SEd Cashin int has_untainted; 25768e0d42fSEd L. Cashin 25871114ec4SEd Cashin if (!d->targets || !d->targets[0]) { 25968e0d42fSEd L. Cashin printk(KERN_ERR "aoe: NULL TARGETS!\n"); 26068e0d42fSEd L. Cashin return NULL; 26168e0d42fSEd L. Cashin } 262896831f5SEd Cashin tt = d->tgt; /* last used target */ 263bbb44e30SEd Cashin for (use_tainted = 0, has_untainted = 0;;) { 264896831f5SEd Cashin tt++; 26571114ec4SEd Cashin if (tt >= &d->targets[d->ntargets] || !*tt) 266896831f5SEd Cashin tt = d->targets; 267896831f5SEd Cashin t = *tt; 268bbb44e30SEd Cashin if (!t->taint) { 269bbb44e30SEd Cashin has_untainted = 1; 270896831f5SEd Cashin totout += t->nout; 271bbb44e30SEd Cashin } 272896831f5SEd Cashin if (t->nout < t->maxout 273bbb44e30SEd Cashin && (use_tainted || !t->taint) 274896831f5SEd Cashin && t->ifp->nd) { 275896831f5SEd Cashin f = newtframe(d, t); 276896831f5SEd Cashin if (f) { 277896831f5SEd Cashin ifrotate(t); 2783f0f0133SEd Cashin d->tgt = tt; 27968e0d42fSEd L. Cashin return f; 28068e0d42fSEd L. Cashin } 2819bb237b6SEd L. Cashin } 282bbb44e30SEd Cashin if (tt == d->tgt) { /* we've looped and found nada */ 283bbb44e30SEd Cashin if (!use_tainted && !has_untainted) 284bbb44e30SEd Cashin use_tainted = 1; 285bbb44e30SEd Cashin else 2869bb237b6SEd L. Cashin break; 287896831f5SEd Cashin } 288bbb44e30SEd Cashin } 289896831f5SEd Cashin if (totout == 0) { 290896831f5SEd Cashin d->kicked++; 291896831f5SEd Cashin d->flags |= DEVFL_KICKME; 2929bb237b6SEd L. Cashin } 29368e0d42fSEd L. Cashin return NULL; 29468e0d42fSEd L. Cashin } 29568e0d42fSEd L. Cashin 2963d5b0605SEd Cashin static void 297feb261e2SKent Overstreet skb_fillup(struct sk_buff *skb, struct bio *bio, struct bvec_iter iter) 2983d5b0605SEd Cashin { 2993d5b0605SEd Cashin int frag = 0; 300feb261e2SKent Overstreet struct bio_vec bv; 301feb261e2SKent Overstreet 302feb261e2SKent Overstreet __bio_for_each_segment(bv, bio, iter, iter) 303feb261e2SKent Overstreet skb_fill_page_desc(skb, frag++, bv.bv_page, 304feb261e2SKent Overstreet bv.bv_offset, bv.bv_len); 3053d5b0605SEd Cashin } 3063d5b0605SEd Cashin 307896831f5SEd Cashin static void 308896831f5SEd Cashin fhash(struct frame *f) 309896831f5SEd Cashin { 31064a80f5aSEd Cashin struct aoedev *d = f->t->d; 311896831f5SEd Cashin u32 n; 312896831f5SEd Cashin 313896831f5SEd Cashin n = f->tag % NFACTIVE; 31464a80f5aSEd Cashin list_add_tail(&f->head, &d->factive[n]); 315896831f5SEd Cashin } 316896831f5SEd Cashin 317bbb44e30SEd Cashin static void 318bbb44e30SEd Cashin ata_rw_frameinit(struct frame *f) 319bbb44e30SEd Cashin { 320bbb44e30SEd Cashin struct aoetgt *t; 321bbb44e30SEd Cashin struct aoe_hdr *h; 322bbb44e30SEd Cashin struct aoe_atahdr *ah; 323bbb44e30SEd Cashin struct sk_buff *skb; 324bbb44e30SEd Cashin char writebit, extbit; 325bbb44e30SEd Cashin 326bbb44e30SEd Cashin skb = f->skb; 327bbb44e30SEd Cashin h = (struct aoe_hdr *) skb_mac_header(skb); 328bbb44e30SEd Cashin ah = (struct aoe_atahdr *) (h + 1); 329bbb44e30SEd Cashin skb_put(skb, sizeof(*h) + sizeof(*ah)); 330bbb44e30SEd Cashin memset(h, 0, skb->len); 331bbb44e30SEd Cashin 332bbb44e30SEd Cashin writebit = 0x10; 333bbb44e30SEd Cashin extbit = 0x4; 334bbb44e30SEd Cashin 335bbb44e30SEd Cashin t = f->t; 336bbb44e30SEd Cashin f->tag = aoehdr_atainit(t->d, t, h); 337bbb44e30SEd Cashin fhash(f); 338bbb44e30SEd Cashin t->nout++; 339bbb44e30SEd Cashin f->waited = 0; 340bbb44e30SEd Cashin f->waited_total = 0; 341bbb44e30SEd Cashin 342bbb44e30SEd Cashin /* set up ata header */ 343feb261e2SKent Overstreet ah->scnt = f->iter.bi_size >> 9; 344feb261e2SKent Overstreet put_lba(ah, f->iter.bi_sector); 345bbb44e30SEd Cashin if (t->d->flags & DEVFL_EXT) { 346bbb44e30SEd Cashin ah->aflags |= AOEAFL_EXT; 347bbb44e30SEd Cashin } else { 348bbb44e30SEd Cashin extbit = 0; 349bbb44e30SEd Cashin ah->lba3 &= 0x0f; 350bbb44e30SEd Cashin ah->lba3 |= 0xe0; /* LBA bit + obsolete 0xa0 */ 351bbb44e30SEd Cashin } 352bbb44e30SEd Cashin if (f->buf && bio_data_dir(f->buf->bio) == WRITE) { 353feb261e2SKent Overstreet skb_fillup(skb, f->buf->bio, f->iter); 354bbb44e30SEd Cashin ah->aflags |= AOEAFL_WRITE; 355feb261e2SKent Overstreet skb->len += f->iter.bi_size; 356feb261e2SKent Overstreet skb->data_len = f->iter.bi_size; 357feb261e2SKent Overstreet skb->truesize += f->iter.bi_size; 358bbb44e30SEd Cashin t->wpkts++; 359bbb44e30SEd Cashin } else { 360bbb44e30SEd Cashin t->rpkts++; 361bbb44e30SEd Cashin writebit = 0; 362bbb44e30SEd Cashin } 363bbb44e30SEd Cashin 364bbb44e30SEd Cashin ah->cmdstat = ATA_CMD_PIO_READ | writebit | extbit; 365bbb44e30SEd Cashin skb->dev = t->ifp->nd; 366bbb44e30SEd Cashin } 367bbb44e30SEd Cashin 36868e0d42fSEd L. Cashin static int 36968e0d42fSEd L. Cashin aoecmd_ata_rw(struct aoedev *d) 37068e0d42fSEd L. Cashin { 37168e0d42fSEd L. Cashin struct frame *f; 3721da177e4SLinus Torvalds struct buf *buf; 3731da177e4SLinus Torvalds struct sk_buff *skb; 37469cf2d85SEd Cashin struct sk_buff_head queue; 3751da177e4SLinus Torvalds 37669cf2d85SEd Cashin buf = nextbuf(d); 37769cf2d85SEd Cashin if (buf == NULL) 37869cf2d85SEd Cashin return 0; 379896831f5SEd Cashin f = newframe(d); 38068e0d42fSEd L. Cashin if (f == NULL) 38168e0d42fSEd L. Cashin return 0; 3823d5b0605SEd Cashin 3831da177e4SLinus Torvalds /* initialize the headers & frame */ 3841da177e4SLinus Torvalds f->buf = buf; 385feb261e2SKent Overstreet f->iter = buf->iter; 386feb261e2SKent Overstreet f->iter.bi_size = min_t(unsigned long, 387feb261e2SKent Overstreet d->maxbcnt ?: DEFAULTBCNT, 388feb261e2SKent Overstreet f->iter.bi_size); 389feb261e2SKent Overstreet bio_advance_iter(buf->bio, &buf->iter, f->iter.bi_size); 390feb261e2SKent Overstreet 391feb261e2SKent Overstreet if (!buf->iter.bi_size) 392feb261e2SKent Overstreet d->ip.buf = NULL; 3931da177e4SLinus Torvalds 3941da177e4SLinus Torvalds /* mark all tracking fields and load out */ 3951da177e4SLinus Torvalds buf->nframesout += 1; 396feb261e2SKent Overstreet 397feb261e2SKent Overstreet ata_rw_frameinit(f); 3981da177e4SLinus Torvalds 399bbb44e30SEd Cashin skb = skb_clone(f->skb, GFP_ATOMIC); 40069cf2d85SEd Cashin if (skb) { 4015f0c9c48SEd Cashin do_gettimeofday(&f->sent); 4025f0c9c48SEd Cashin f->sent_jiffs = (u32) jiffies; 40369cf2d85SEd Cashin __skb_queue_head_init(&queue); 40469cf2d85SEd Cashin __skb_queue_tail(&queue, skb); 40569cf2d85SEd Cashin aoenet_xmit(&queue); 40669cf2d85SEd Cashin } 40768e0d42fSEd L. Cashin return 1; 40868e0d42fSEd L. Cashin } 4091da177e4SLinus Torvalds 4103ae1c24eSEd L. Cashin /* some callers cannot sleep, and they can call this function, 4113ae1c24eSEd L. Cashin * transmitting the packets later, when interrupts are on 4123ae1c24eSEd L. Cashin */ 413e9bb8fb0SDavid S. Miller static void 414e9bb8fb0SDavid S. Miller aoecmd_cfg_pkts(ushort aoemajor, unsigned char aoeminor, struct sk_buff_head *queue) 4153ae1c24eSEd L. Cashin { 4163ae1c24eSEd L. Cashin struct aoe_hdr *h; 4173ae1c24eSEd L. Cashin struct aoe_cfghdr *ch; 418e9bb8fb0SDavid S. Miller struct sk_buff *skb; 4193ae1c24eSEd L. Cashin struct net_device *ifp; 4203ae1c24eSEd L. Cashin 421840a185dSEric Dumazet rcu_read_lock(); 422840a185dSEric Dumazet for_each_netdev_rcu(&init_net, ifp) { 4233ae1c24eSEd L. Cashin dev_hold(ifp); 4243ae1c24eSEd L. Cashin if (!is_aoe_netif(ifp)) 4257562f876SPavel Emelianov goto cont; 4263ae1c24eSEd L. Cashin 427e407a7f6SEd L. Cashin skb = new_skb(sizeof *h + sizeof *ch); 4283ae1c24eSEd L. Cashin if (skb == NULL) { 429a12c93f0SEd L. Cashin printk(KERN_INFO "aoe: skb alloc failure\n"); 4307562f876SPavel Emelianov goto cont; 4313ae1c24eSEd L. Cashin } 43219900cdeSEd L. Cashin skb_put(skb, sizeof *h + sizeof *ch); 433e407a7f6SEd L. Cashin skb->dev = ifp; 434e9bb8fb0SDavid S. Miller __skb_queue_tail(queue, skb); 435abdbf94dSEd L. Cashin h = (struct aoe_hdr *) skb_mac_header(skb); 4363ae1c24eSEd L. Cashin memset(h, 0, sizeof *h + sizeof *ch); 4373ae1c24eSEd L. Cashin 4383ae1c24eSEd L. Cashin memset(h->dst, 0xff, sizeof h->dst); 4393ae1c24eSEd L. Cashin memcpy(h->src, ifp->dev_addr, sizeof h->src); 4403ae1c24eSEd L. Cashin h->type = __constant_cpu_to_be16(ETH_P_AOE); 4413ae1c24eSEd L. Cashin h->verfl = AOE_HVER; 4423ae1c24eSEd L. Cashin h->major = cpu_to_be16(aoemajor); 4433ae1c24eSEd L. Cashin h->minor = aoeminor; 4443ae1c24eSEd L. Cashin h->cmd = AOECMD_CFG; 4453ae1c24eSEd L. Cashin 4467562f876SPavel Emelianov cont: 4477562f876SPavel Emelianov dev_put(ifp); 4483ae1c24eSEd L. Cashin } 449840a185dSEric Dumazet rcu_read_unlock(); 4503ae1c24eSEd L. Cashin } 4513ae1c24eSEd L. Cashin 4521da177e4SLinus Torvalds static void 453896831f5SEd Cashin resend(struct aoedev *d, struct frame *f) 4541da177e4SLinus Torvalds { 4551da177e4SLinus Torvalds struct sk_buff *skb; 45669cf2d85SEd Cashin struct sk_buff_head queue; 4571da177e4SLinus Torvalds struct aoe_hdr *h; 458896831f5SEd Cashin struct aoetgt *t; 4591da177e4SLinus Torvalds char buf[128]; 4601da177e4SLinus Torvalds u32 n; 4611da177e4SLinus Torvalds 462896831f5SEd Cashin t = f->t; 46364a80f5aSEd Cashin n = newtag(d); 464e407a7f6SEd L. Cashin skb = f->skb; 4653f0f0133SEd Cashin if (ifrotate(t) == NULL) { 4663f0f0133SEd Cashin /* probably can't happen, but set it up to fail anyway */ 4673f0f0133SEd Cashin pr_info("aoe: resend: no interfaces to rotate to.\n"); 4683f0f0133SEd Cashin ktcomplete(f, NULL); 4693f0f0133SEd Cashin return; 4703f0f0133SEd Cashin } 471abdbf94dSEd L. Cashin h = (struct aoe_hdr *) skb_mac_header(skb); 47268e0d42fSEd L. Cashin 473bbb44e30SEd Cashin if (!(f->flags & FFL_PROBE)) { 474bbb44e30SEd Cashin snprintf(buf, sizeof(buf), 475411c41eeSHarvey Harrison "%15s e%ld.%d oldtag=%08x@%08lx newtag=%08x s=%pm d=%pm nout=%d\n", 476bbb44e30SEd Cashin "retransmit", d->aoemajor, d->aoeminor, 477bbb44e30SEd Cashin f->tag, jiffies, n, 478411c41eeSHarvey Harrison h->src, h->dst, t->nout); 47968e0d42fSEd L. Cashin aoechr_error(buf); 480bbb44e30SEd Cashin } 48168e0d42fSEd L. Cashin 4821da177e4SLinus Torvalds f->tag = n; 483896831f5SEd Cashin fhash(f); 48463e9cc5dSecashin@coraid.com h->tag = cpu_to_be32(n); 48568e0d42fSEd L. Cashin memcpy(h->dst, t->addr, sizeof h->dst); 48668e0d42fSEd L. Cashin memcpy(h->src, t->ifp->nd->dev_addr, sizeof h->src); 4871da177e4SLinus Torvalds 48868e0d42fSEd L. Cashin skb->dev = t->ifp->nd; 4894f51dc5eSEd L. Cashin skb = skb_clone(skb, GFP_ATOMIC); 4904f51dc5eSEd L. Cashin if (skb == NULL) 4914f51dc5eSEd L. Cashin return; 4925f0c9c48SEd Cashin do_gettimeofday(&f->sent); 4935f0c9c48SEd Cashin f->sent_jiffs = (u32) jiffies; 49469cf2d85SEd Cashin __skb_queue_head_init(&queue); 49569cf2d85SEd Cashin __skb_queue_tail(&queue, skb); 49669cf2d85SEd Cashin aoenet_xmit(&queue); 4971da177e4SLinus Torvalds } 4981da177e4SLinus Torvalds 4991da177e4SLinus Torvalds static int 5005f0c9c48SEd Cashin tsince_hr(struct frame *f) 5015f0c9c48SEd Cashin { 5025f0c9c48SEd Cashin struct timeval now; 5035f0c9c48SEd Cashin int n; 5045f0c9c48SEd Cashin 5055f0c9c48SEd Cashin do_gettimeofday(&now); 5065f0c9c48SEd Cashin n = now.tv_usec - f->sent.tv_usec; 5075f0c9c48SEd Cashin n += (now.tv_sec - f->sent.tv_sec) * USEC_PER_SEC; 5085f0c9c48SEd Cashin 5095f0c9c48SEd Cashin if (n < 0) 5105f0c9c48SEd Cashin n = -n; 5115f0c9c48SEd Cashin 5125f0c9c48SEd Cashin /* For relatively long periods, use jiffies to avoid 5135f0c9c48SEd Cashin * discrepancies caused by updates to the system time. 5145f0c9c48SEd Cashin * 5155f0c9c48SEd Cashin * On system with HZ of 1000, 32-bits is over 49 days 5165f0c9c48SEd Cashin * worth of jiffies, or over 71 minutes worth of usecs. 5175f0c9c48SEd Cashin * 5185f0c9c48SEd Cashin * Jiffies overflow is handled by subtraction of unsigned ints: 5195f0c9c48SEd Cashin * (gdb) print (unsigned) 2 - (unsigned) 0xfffffffe 5205f0c9c48SEd Cashin * $3 = 4 5215f0c9c48SEd Cashin * (gdb) 5225f0c9c48SEd Cashin */ 5235f0c9c48SEd Cashin if (n > USEC_PER_SEC / 4) { 5245f0c9c48SEd Cashin n = ((u32) jiffies) - f->sent_jiffs; 5255f0c9c48SEd Cashin n *= USEC_PER_SEC / HZ; 5265f0c9c48SEd Cashin } 5275f0c9c48SEd Cashin 5285f0c9c48SEd Cashin return n; 5295f0c9c48SEd Cashin } 5305f0c9c48SEd Cashin 5315f0c9c48SEd Cashin static int 532896831f5SEd Cashin tsince(u32 tag) 5331da177e4SLinus Torvalds { 5341da177e4SLinus Torvalds int n; 5351da177e4SLinus Torvalds 5361da177e4SLinus Torvalds n = jiffies & 0xffff; 5371da177e4SLinus Torvalds n -= tag & 0xffff; 5381da177e4SLinus Torvalds if (n < 0) 5391da177e4SLinus Torvalds n += 1<<16; 5405f0c9c48SEd Cashin return jiffies_to_usecs(n + 1); 5411da177e4SLinus Torvalds } 5421da177e4SLinus Torvalds 54368e0d42fSEd L. Cashin static struct aoeif * 54468e0d42fSEd L. Cashin getif(struct aoetgt *t, struct net_device *nd) 54568e0d42fSEd L. Cashin { 54668e0d42fSEd L. Cashin struct aoeif *p, *e; 54768e0d42fSEd L. Cashin 54868e0d42fSEd L. Cashin p = t->ifs; 54968e0d42fSEd L. Cashin e = p + NAOEIFS; 55068e0d42fSEd L. Cashin for (; p < e; p++) 55168e0d42fSEd L. Cashin if (p->nd == nd) 55268e0d42fSEd L. Cashin return p; 55368e0d42fSEd L. Cashin return NULL; 55468e0d42fSEd L. Cashin } 55568e0d42fSEd L. Cashin 55668e0d42fSEd L. Cashin static void 55768e0d42fSEd L. Cashin ejectif(struct aoetgt *t, struct aoeif *ifp) 55868e0d42fSEd L. Cashin { 55968e0d42fSEd L. Cashin struct aoeif *e; 5601b86fda9SEd Cashin struct net_device *nd; 56168e0d42fSEd L. Cashin ulong n; 56268e0d42fSEd L. Cashin 5631b86fda9SEd Cashin nd = ifp->nd; 56468e0d42fSEd L. Cashin e = t->ifs + NAOEIFS - 1; 56568e0d42fSEd L. Cashin n = (e - ifp) * sizeof *ifp; 56668e0d42fSEd L. Cashin memmove(ifp, ifp+1, n); 56768e0d42fSEd L. Cashin e->nd = NULL; 5681b86fda9SEd Cashin dev_put(nd); 56968e0d42fSEd L. Cashin } 57068e0d42fSEd L. Cashin 5713fc9b032SEd Cashin static struct frame * 572bbb44e30SEd Cashin reassign_frame(struct frame *f) 57368e0d42fSEd L. Cashin { 5743fc9b032SEd Cashin struct frame *nf; 57568e0d42fSEd L. Cashin struct sk_buff *skb; 57668e0d42fSEd L. Cashin 5773fc9b032SEd Cashin nf = newframe(f->t->d); 57868e0d42fSEd L. Cashin if (!nf) 5793fc9b032SEd Cashin return NULL; 580bbb44e30SEd Cashin if (nf->t == f->t) { 581bbb44e30SEd Cashin aoe_freetframe(nf); 582bbb44e30SEd Cashin return NULL; 583bbb44e30SEd Cashin } 584896831f5SEd Cashin 58568e0d42fSEd L. Cashin skb = nf->skb; 586896831f5SEd Cashin nf->skb = f->skb; 587896831f5SEd Cashin nf->buf = f->buf; 588feb261e2SKent Overstreet nf->iter = f->iter; 58968e0d42fSEd L. Cashin nf->waited = 0; 5903fc9b032SEd Cashin nf->waited_total = f->waited_total; 5913fc9b032SEd Cashin nf->sent = f->sent; 592fe7252bfSEd Cashin nf->sent_jiffs = f->sent_jiffs; 593896831f5SEd Cashin f->skb = skb; 5943fc9b032SEd Cashin 5953fc9b032SEd Cashin return nf; 5963fc9b032SEd Cashin } 5973fc9b032SEd Cashin 598bbb44e30SEd Cashin static void 599bbb44e30SEd Cashin probe(struct aoetgt *t) 6003fc9b032SEd Cashin { 601bbb44e30SEd Cashin struct aoedev *d; 602bbb44e30SEd Cashin struct frame *f; 603bbb44e30SEd Cashin struct sk_buff *skb; 604bbb44e30SEd Cashin struct sk_buff_head queue; 605bbb44e30SEd Cashin size_t n, m; 606bbb44e30SEd Cashin int frag; 6073fc9b032SEd Cashin 608bbb44e30SEd Cashin d = t->d; 609bbb44e30SEd Cashin f = newtframe(d, t); 610bbb44e30SEd Cashin if (!f) { 611bbb44e30SEd Cashin pr_err("%s %pm for e%ld.%d: %s\n", 612bbb44e30SEd Cashin "aoe: cannot probe remote address", 613bbb44e30SEd Cashin t->addr, 614bbb44e30SEd Cashin (long) d->aoemajor, d->aoeminor, 615bbb44e30SEd Cashin "no frame available"); 616bbb44e30SEd Cashin return; 617bbb44e30SEd Cashin } 618bbb44e30SEd Cashin f->flags |= FFL_PROBE; 619bbb44e30SEd Cashin ifrotate(t); 620feb261e2SKent Overstreet f->iter.bi_size = t->d->maxbcnt ? t->d->maxbcnt : DEFAULTBCNT; 621bbb44e30SEd Cashin ata_rw_frameinit(f); 622bbb44e30SEd Cashin skb = f->skb; 623feb261e2SKent Overstreet for (frag = 0, n = f->iter.bi_size; n > 0; ++frag, n -= m) { 624bbb44e30SEd Cashin if (n < PAGE_SIZE) 625bbb44e30SEd Cashin m = n; 626bbb44e30SEd Cashin else 627bbb44e30SEd Cashin m = PAGE_SIZE; 628bbb44e30SEd Cashin skb_fill_page_desc(skb, frag, empty_page, 0, m); 629bbb44e30SEd Cashin } 630feb261e2SKent Overstreet skb->len += f->iter.bi_size; 631feb261e2SKent Overstreet skb->data_len = f->iter.bi_size; 632feb261e2SKent Overstreet skb->truesize += f->iter.bi_size; 633bbb44e30SEd Cashin 634bbb44e30SEd Cashin skb = skb_clone(f->skb, GFP_ATOMIC); 635bbb44e30SEd Cashin if (skb) { 636bbb44e30SEd Cashin do_gettimeofday(&f->sent); 637bbb44e30SEd Cashin f->sent_jiffs = (u32) jiffies; 638bbb44e30SEd Cashin __skb_queue_head_init(&queue); 639bbb44e30SEd Cashin __skb_queue_tail(&queue, skb); 640bbb44e30SEd Cashin aoenet_xmit(&queue); 641896831f5SEd Cashin } 64268e0d42fSEd L. Cashin } 643bbb44e30SEd Cashin 644bbb44e30SEd Cashin static long 645bbb44e30SEd Cashin rto(struct aoedev *d) 646bbb44e30SEd Cashin { 647bbb44e30SEd Cashin long t; 648bbb44e30SEd Cashin 649bbb44e30SEd Cashin t = 2 * d->rttavg >> RTTSCALE; 650bbb44e30SEd Cashin t += 8 * d->rttdev >> RTTDSCALE; 651bbb44e30SEd Cashin if (t == 0) 652bbb44e30SEd Cashin t = 1; 653bbb44e30SEd Cashin 654bbb44e30SEd Cashin return t; 65568e0d42fSEd L. Cashin } 65668e0d42fSEd L. Cashin 6571da177e4SLinus Torvalds static void 6583a0c40d2SEd Cashin rexmit_deferred(struct aoedev *d) 6593a0c40d2SEd Cashin { 6603a0c40d2SEd Cashin struct aoetgt *t; 6613a0c40d2SEd Cashin struct frame *f; 662bbb44e30SEd Cashin struct frame *nf; 6633a0c40d2SEd Cashin struct list_head *pos, *nx, *head; 6643fc9b032SEd Cashin int since; 665bbb44e30SEd Cashin int untainted; 666bbb44e30SEd Cashin 667bbb44e30SEd Cashin count_targets(d, &untainted); 6683a0c40d2SEd Cashin 6693a0c40d2SEd Cashin head = &d->rexmitq; 6703a0c40d2SEd Cashin list_for_each_safe(pos, nx, head) { 6713a0c40d2SEd Cashin f = list_entry(pos, struct frame, head); 6723a0c40d2SEd Cashin t = f->t; 673bbb44e30SEd Cashin if (t->taint) { 674bbb44e30SEd Cashin if (!(f->flags & FFL_PROBE)) { 675bbb44e30SEd Cashin nf = reassign_frame(f); 676bbb44e30SEd Cashin if (nf) { 677bbb44e30SEd Cashin if (t->nout_probes == 0 678bbb44e30SEd Cashin && untainted > 0) { 679bbb44e30SEd Cashin probe(t); 680bbb44e30SEd Cashin t->nout_probes++; 681bbb44e30SEd Cashin } 682bbb44e30SEd Cashin list_replace(&f->head, &nf->head); 683bbb44e30SEd Cashin pos = &nf->head; 684bbb44e30SEd Cashin aoe_freetframe(f); 685bbb44e30SEd Cashin f = nf; 686bbb44e30SEd Cashin t = f->t; 687bbb44e30SEd Cashin } 688bbb44e30SEd Cashin } else if (untainted < 1) { 689bbb44e30SEd Cashin /* don't probe w/o other untainted aoetgts */ 690bbb44e30SEd Cashin goto stop_probe; 691bbb44e30SEd Cashin } else if (tsince_hr(f) < t->taint * rto(d)) { 692bbb44e30SEd Cashin /* reprobe slowly when taint is high */ 693bbb44e30SEd Cashin continue; 694bbb44e30SEd Cashin } 695bbb44e30SEd Cashin } else if (f->flags & FFL_PROBE) { 696bbb44e30SEd Cashin stop_probe: /* don't probe untainted aoetgts */ 697bbb44e30SEd Cashin list_del(pos); 698bbb44e30SEd Cashin aoe_freetframe(f); 699bbb44e30SEd Cashin /* leaving d->kicked, because this is routine */ 700bbb44e30SEd Cashin f->t->d->flags |= DEVFL_KICKME; 701bbb44e30SEd Cashin continue; 702bbb44e30SEd Cashin } 7033a0c40d2SEd Cashin if (t->nout >= t->maxout) 7043a0c40d2SEd Cashin continue; 7053a0c40d2SEd Cashin list_del(pos); 7063a0c40d2SEd Cashin t->nout++; 707bbb44e30SEd Cashin if (f->flags & FFL_PROBE) 708bbb44e30SEd Cashin t->nout_probes++; 7093fc9b032SEd Cashin since = tsince_hr(f); 7103fc9b032SEd Cashin f->waited += since; 7113fc9b032SEd Cashin f->waited_total += since; 7123a0c40d2SEd Cashin resend(d, f); 7133a0c40d2SEd Cashin } 7143a0c40d2SEd Cashin } 7153a0c40d2SEd Cashin 716bbb44e30SEd Cashin /* An aoetgt accumulates demerits quickly, and successful 717bbb44e30SEd Cashin * probing redeems the aoetgt slowly. 718bbb44e30SEd Cashin */ 719bbb44e30SEd Cashin static void 720bbb44e30SEd Cashin scorn(struct aoetgt *t) 721bbb44e30SEd Cashin { 722bbb44e30SEd Cashin int n; 723bbb44e30SEd Cashin 724bbb44e30SEd Cashin n = t->taint++; 725bbb44e30SEd Cashin t->taint += t->taint * 2; 726bbb44e30SEd Cashin if (n > t->taint) 727bbb44e30SEd Cashin t->taint = n; 728bbb44e30SEd Cashin if (t->taint > MAX_TAINT) 729bbb44e30SEd Cashin t->taint = MAX_TAINT; 730bbb44e30SEd Cashin } 731bbb44e30SEd Cashin 732bbb44e30SEd Cashin static int 733bbb44e30SEd Cashin count_targets(struct aoedev *d, int *untainted) 734bbb44e30SEd Cashin { 735bbb44e30SEd Cashin int i, good; 736bbb44e30SEd Cashin 737bbb44e30SEd Cashin for (i = good = 0; i < d->ntargets && d->targets[i]; ++i) 738bbb44e30SEd Cashin if (d->targets[i]->taint == 0) 739bbb44e30SEd Cashin good++; 740bbb44e30SEd Cashin 741bbb44e30SEd Cashin if (untainted) 742bbb44e30SEd Cashin *untainted = good; 743bbb44e30SEd Cashin return i; 744bbb44e30SEd Cashin } 745bbb44e30SEd Cashin 7463a0c40d2SEd Cashin static void 747*0e0cc9dfSKees Cook rexmit_timer(struct timer_list *timer) 7481da177e4SLinus Torvalds { 7491da177e4SLinus Torvalds struct aoedev *d; 7503a0c40d2SEd Cashin struct aoetgt *t; 75168e0d42fSEd L. Cashin struct aoeif *ifp; 752896831f5SEd Cashin struct frame *f; 753896831f5SEd Cashin struct list_head *head, *pos, *nx; 754896831f5SEd Cashin LIST_HEAD(flist); 7551da177e4SLinus Torvalds register long timeout; 7561da177e4SLinus Torvalds ulong flags, n; 757896831f5SEd Cashin int i; 758bbb44e30SEd Cashin int utgts; /* number of aoetgt descriptors (not slots) */ 7593fc9b032SEd Cashin int since; 7601da177e4SLinus Torvalds 761*0e0cc9dfSKees Cook d = from_timer(d, timer, timer); 7621da177e4SLinus Torvalds 7630d555ecfSEd Cashin spin_lock_irqsave(&d->lock, flags); 7640d555ecfSEd Cashin 7653a0c40d2SEd Cashin /* timeout based on observed timings and variations */ 766bbb44e30SEd Cashin timeout = rto(d); 767bbb44e30SEd Cashin 768bbb44e30SEd Cashin utgts = count_targets(d, NULL); 7691da177e4SLinus Torvalds 7701da177e4SLinus Torvalds if (d->flags & DEVFL_TKILL) { 7711c6f3fcaSEd L. Cashin spin_unlock_irqrestore(&d->lock, flags); 7721da177e4SLinus Torvalds return; 7731da177e4SLinus Torvalds } 774896831f5SEd Cashin 775896831f5SEd Cashin /* collect all frames to rexmit into flist */ 776896831f5SEd Cashin for (i = 0; i < NFACTIVE; i++) { 77764a80f5aSEd Cashin head = &d->factive[i]; 778896831f5SEd Cashin list_for_each_safe(pos, nx, head) { 779896831f5SEd Cashin f = list_entry(pos, struct frame, head); 7805f0c9c48SEd Cashin if (tsince_hr(f) < timeout) 78164a80f5aSEd Cashin break; /* end of expired frames */ 782896831f5SEd Cashin /* move to flist for later processing */ 783896831f5SEd Cashin list_move_tail(pos, &flist); 784896831f5SEd Cashin } 785896831f5SEd Cashin } 78669cf2d85SEd Cashin 787896831f5SEd Cashin /* process expired frames */ 788896831f5SEd Cashin while (!list_empty(&flist)) { 789896831f5SEd Cashin pos = flist.next; 790896831f5SEd Cashin f = list_entry(pos, struct frame, head); 7913fc9b032SEd Cashin since = tsince_hr(f); 7923fc9b032SEd Cashin n = f->waited_total + since; 7935f0c9c48SEd Cashin n /= USEC_PER_SEC; 794c450ba0fSEd Cashin if (aoe_deadsecs 795c450ba0fSEd Cashin && n > aoe_deadsecs 796c450ba0fSEd Cashin && !(f->flags & FFL_PROBE)) { 797896831f5SEd Cashin /* Waited too long. Device failure. 798896831f5SEd Cashin * Hang all frames on first hash bucket for downdev 799896831f5SEd Cashin * to clean up. 800896831f5SEd Cashin */ 80164a80f5aSEd Cashin list_splice(&flist, &d->factive[0]); 8021da177e4SLinus Torvalds aoedev_downdev(d); 8033a0c40d2SEd Cashin goto out; 8041da177e4SLinus Torvalds } 80568e0d42fSEd L. Cashin 806896831f5SEd Cashin t = f->t; 807bbb44e30SEd Cashin n = f->waited + since; 808bbb44e30SEd Cashin n /= USEC_PER_SEC; 809bbb44e30SEd Cashin if (aoe_deadsecs && utgts > 0 810bbb44e30SEd Cashin && (n > aoe_deadsecs / utgts || n > HARD_SCORN_SECS)) 811bbb44e30SEd Cashin scorn(t); /* avoid this target */ 812d54d35acSEd Cashin 8133a0c40d2SEd Cashin if (t->maxout != 1) { 8143a0c40d2SEd Cashin t->ssthresh = t->maxout / 2; 8153a0c40d2SEd Cashin t->maxout = 1; 81668e0d42fSEd L. Cashin } 81768e0d42fSEd L. Cashin 818bbb44e30SEd Cashin if (f->flags & FFL_PROBE) { 819bbb44e30SEd Cashin t->nout_probes--; 820bbb44e30SEd Cashin } else { 82168e0d42fSEd L. Cashin ifp = getif(t, f->skb->dev); 82268e0d42fSEd L. Cashin if (ifp && ++ifp->lost > (t->nframes << 1) 82368e0d42fSEd L. Cashin && (ifp != t->ifs || t->ifs[1].nd)) { 82468e0d42fSEd L. Cashin ejectif(t, ifp); 82568e0d42fSEd L. Cashin ifp = NULL; 82668e0d42fSEd L. Cashin } 827bbb44e30SEd Cashin } 8283a0c40d2SEd Cashin list_move_tail(pos, &d->rexmitq); 8293a0c40d2SEd Cashin t->nout--; 8301da177e4SLinus Torvalds } 8313a0c40d2SEd Cashin rexmit_deferred(d); 83268e0d42fSEd L. Cashin 8333a0c40d2SEd Cashin out: 834bbb44e30SEd Cashin if ((d->flags & DEVFL_KICKME) && d->blkq) { 8354f51dc5eSEd L. Cashin d->flags &= ~DEVFL_KICKME; 83669cf2d85SEd Cashin d->blkq->request_fn(d->blkq); 8374f51dc5eSEd L. Cashin } 8381da177e4SLinus Torvalds 8391da177e4SLinus Torvalds d->timer.expires = jiffies + TIMERTICK; 8401da177e4SLinus Torvalds add_timer(&d->timer); 8411da177e4SLinus Torvalds 8421da177e4SLinus Torvalds spin_unlock_irqrestore(&d->lock, flags); 84369cf2d85SEd Cashin } 8441da177e4SLinus Torvalds 84569cf2d85SEd Cashin static unsigned long 84669cf2d85SEd Cashin rqbiocnt(struct request *r) 84769cf2d85SEd Cashin { 84869cf2d85SEd Cashin struct bio *bio; 84969cf2d85SEd Cashin unsigned long n = 0; 85069cf2d85SEd Cashin 85169cf2d85SEd Cashin __rq_for_each_bio(bio, r) 85269cf2d85SEd Cashin n++; 85369cf2d85SEd Cashin return n; 85469cf2d85SEd Cashin } 85569cf2d85SEd Cashin 85669cf2d85SEd Cashin static void 85769cf2d85SEd Cashin bufinit(struct buf *buf, struct request *rq, struct bio *bio) 85869cf2d85SEd Cashin { 85969cf2d85SEd Cashin memset(buf, 0, sizeof(*buf)); 86069cf2d85SEd Cashin buf->rq = rq; 86169cf2d85SEd Cashin buf->bio = bio; 862feb261e2SKent Overstreet buf->iter = bio->bi_iter; 86369cf2d85SEd Cashin } 86469cf2d85SEd Cashin 86569cf2d85SEd Cashin static struct buf * 86669cf2d85SEd Cashin nextbuf(struct aoedev *d) 86769cf2d85SEd Cashin { 86869cf2d85SEd Cashin struct request *rq; 86969cf2d85SEd Cashin struct request_queue *q; 87069cf2d85SEd Cashin struct buf *buf; 87169cf2d85SEd Cashin struct bio *bio; 87269cf2d85SEd Cashin 87369cf2d85SEd Cashin q = d->blkq; 87469cf2d85SEd Cashin if (q == NULL) 87569cf2d85SEd Cashin return NULL; /* initializing */ 87669cf2d85SEd Cashin if (d->ip.buf) 87769cf2d85SEd Cashin return d->ip.buf; 87869cf2d85SEd Cashin rq = d->ip.rq; 87969cf2d85SEd Cashin if (rq == NULL) { 88069cf2d85SEd Cashin rq = blk_peek_request(q); 88169cf2d85SEd Cashin if (rq == NULL) 88269cf2d85SEd Cashin return NULL; 88369cf2d85SEd Cashin blk_start_request(rq); 88469cf2d85SEd Cashin d->ip.rq = rq; 88569cf2d85SEd Cashin d->ip.nxbio = rq->bio; 88669cf2d85SEd Cashin rq->special = (void *) rqbiocnt(rq); 88769cf2d85SEd Cashin } 88869cf2d85SEd Cashin buf = mempool_alloc(d->bufpool, GFP_ATOMIC); 88969cf2d85SEd Cashin if (buf == NULL) { 89069cf2d85SEd Cashin pr_err("aoe: nextbuf: unable to mempool_alloc!\n"); 89169cf2d85SEd Cashin return NULL; 89269cf2d85SEd Cashin } 89369cf2d85SEd Cashin bio = d->ip.nxbio; 89469cf2d85SEd Cashin bufinit(buf, rq, bio); 89569cf2d85SEd Cashin bio = bio->bi_next; 89669cf2d85SEd Cashin d->ip.nxbio = bio; 89769cf2d85SEd Cashin if (bio == NULL) 89869cf2d85SEd Cashin d->ip.rq = NULL; 89969cf2d85SEd Cashin return d->ip.buf = buf; 9001da177e4SLinus Torvalds } 9011da177e4SLinus Torvalds 90268e0d42fSEd L. Cashin /* enters with d->lock held */ 90368e0d42fSEd L. Cashin void 90468e0d42fSEd L. Cashin aoecmd_work(struct aoedev *d) 90568e0d42fSEd L. Cashin { 9063a0c40d2SEd Cashin rexmit_deferred(d); 90769cf2d85SEd Cashin while (aoecmd_ata_rw(d)) 90869cf2d85SEd Cashin ; 90968e0d42fSEd L. Cashin } 91068e0d42fSEd L. Cashin 9113ae1c24eSEd L. Cashin /* this function performs work that has been deferred until sleeping is OK 9123ae1c24eSEd L. Cashin */ 9133ae1c24eSEd L. Cashin void 914c4028958SDavid Howells aoecmd_sleepwork(struct work_struct *work) 9153ae1c24eSEd L. Cashin { 916c4028958SDavid Howells struct aoedev *d = container_of(work, struct aoedev, work); 917b21faa25SEd Cashin struct block_device *bd; 918b21faa25SEd Cashin u64 ssize; 9193ae1c24eSEd L. Cashin 9203ae1c24eSEd L. Cashin if (d->flags & DEVFL_GDALLOC) 9213ae1c24eSEd L. Cashin aoeblk_gdalloc(d); 9223ae1c24eSEd L. Cashin 9233ae1c24eSEd L. Cashin if (d->flags & DEVFL_NEWSIZE) { 92480795aefSTejun Heo ssize = get_capacity(d->gd); 9253ae1c24eSEd L. Cashin bd = bdget_disk(d->gd, 0); 9263ae1c24eSEd L. Cashin if (bd) { 9275955102cSAl Viro inode_lock(bd->bd_inode); 9283ae1c24eSEd L. Cashin i_size_write(bd->bd_inode, (loff_t)ssize<<9); 9295955102cSAl Viro inode_unlock(bd->bd_inode); 9303ae1c24eSEd L. Cashin bdput(bd); 9313ae1c24eSEd L. Cashin } 932b21faa25SEd Cashin spin_lock_irq(&d->lock); 9333ae1c24eSEd L. Cashin d->flags |= DEVFL_UP; 9343ae1c24eSEd L. Cashin d->flags &= ~DEVFL_NEWSIZE; 935b21faa25SEd Cashin spin_unlock_irq(&d->lock); 9363ae1c24eSEd L. Cashin } 9373ae1c24eSEd L. Cashin } 9383ae1c24eSEd L. Cashin 9391da177e4SLinus Torvalds static void 940667be1e7SEd Cashin ata_ident_fixstring(u16 *id, int ns) 941667be1e7SEd Cashin { 942667be1e7SEd Cashin u16 s; 943667be1e7SEd Cashin 944667be1e7SEd Cashin while (ns-- > 0) { 945667be1e7SEd Cashin s = *id; 946667be1e7SEd Cashin *id++ = s >> 8 | s << 8; 947667be1e7SEd Cashin } 948667be1e7SEd Cashin } 949667be1e7SEd Cashin 950667be1e7SEd Cashin static void 95168e0d42fSEd L. Cashin ataid_complete(struct aoedev *d, struct aoetgt *t, unsigned char *id) 9521da177e4SLinus Torvalds { 9531da177e4SLinus Torvalds u64 ssize; 9541da177e4SLinus Torvalds u16 n; 9551da177e4SLinus Torvalds 9561da177e4SLinus Torvalds /* word 83: command set supported */ 957f885f8d1SHarvey Harrison n = get_unaligned_le16(&id[83 << 1]); 9581da177e4SLinus Torvalds 9591da177e4SLinus Torvalds /* word 86: command set/feature enabled */ 960f885f8d1SHarvey Harrison n |= get_unaligned_le16(&id[86 << 1]); 9611da177e4SLinus Torvalds 9621da177e4SLinus Torvalds if (n & (1<<10)) { /* bit 10: LBA 48 */ 9631da177e4SLinus Torvalds d->flags |= DEVFL_EXT; 9641da177e4SLinus Torvalds 9651da177e4SLinus Torvalds /* word 100: number lba48 sectors */ 966f885f8d1SHarvey Harrison ssize = get_unaligned_le64(&id[100 << 1]); 9671da177e4SLinus Torvalds 9681da177e4SLinus Torvalds /* set as in ide-disk.c:init_idedisk_capacity */ 9691da177e4SLinus Torvalds d->geo.cylinders = ssize; 9701da177e4SLinus Torvalds d->geo.cylinders /= (255 * 63); 9711da177e4SLinus Torvalds d->geo.heads = 255; 9721da177e4SLinus Torvalds d->geo.sectors = 63; 9731da177e4SLinus Torvalds } else { 9741da177e4SLinus Torvalds d->flags &= ~DEVFL_EXT; 9751da177e4SLinus Torvalds 9761da177e4SLinus Torvalds /* number lba28 sectors */ 977f885f8d1SHarvey Harrison ssize = get_unaligned_le32(&id[60 << 1]); 9781da177e4SLinus Torvalds 9791da177e4SLinus Torvalds /* NOTE: obsolete in ATA 6 */ 980f885f8d1SHarvey Harrison d->geo.cylinders = get_unaligned_le16(&id[54 << 1]); 981f885f8d1SHarvey Harrison d->geo.heads = get_unaligned_le16(&id[55 << 1]); 982f885f8d1SHarvey Harrison d->geo.sectors = get_unaligned_le16(&id[56 << 1]); 9831da177e4SLinus Torvalds } 9843ae1c24eSEd L. Cashin 985667be1e7SEd Cashin ata_ident_fixstring((u16 *) &id[10<<1], 10); /* serial */ 986667be1e7SEd Cashin ata_ident_fixstring((u16 *) &id[23<<1], 4); /* firmware */ 987667be1e7SEd Cashin ata_ident_fixstring((u16 *) &id[27<<1], 20); /* model */ 988667be1e7SEd Cashin memcpy(d->ident, id, sizeof(d->ident)); 989667be1e7SEd Cashin 9903ae1c24eSEd L. Cashin if (d->ssize != ssize) 9911d75981aSEd L. Cashin printk(KERN_INFO 992411c41eeSHarvey Harrison "aoe: %pm e%ld.%d v%04x has %llu sectors\n", 993411c41eeSHarvey Harrison t->addr, 9943ae1c24eSEd L. Cashin d->aoemajor, d->aoeminor, 9953ae1c24eSEd L. Cashin d->fw_ver, (long long)ssize); 9961da177e4SLinus Torvalds d->ssize = ssize; 9971da177e4SLinus Torvalds d->geo.start = 0; 9986b9699bbSEd L. Cashin if (d->flags & (DEVFL_GDALLOC|DEVFL_NEWSIZE)) 9996b9699bbSEd L. Cashin return; 10001da177e4SLinus Torvalds if (d->gd != NULL) { 100180795aefSTejun Heo set_capacity(d->gd, ssize); 10023ae1c24eSEd L. Cashin d->flags |= DEVFL_NEWSIZE; 100368e0d42fSEd L. Cashin } else 10043ae1c24eSEd L. Cashin d->flags |= DEVFL_GDALLOC; 10051da177e4SLinus Torvalds schedule_work(&d->work); 10061da177e4SLinus Torvalds } 10071da177e4SLinus Torvalds 10081da177e4SLinus Torvalds static void 10093a0c40d2SEd Cashin calc_rttavg(struct aoedev *d, struct aoetgt *t, int rtt) 10101da177e4SLinus Torvalds { 10111da177e4SLinus Torvalds register long n; 10121da177e4SLinus Torvalds 10131da177e4SLinus Torvalds n = rtt; 10141da177e4SLinus Torvalds 10153a0c40d2SEd Cashin /* cf. Congestion Avoidance and Control, Jacobson & Karels, 1988 */ 10163a0c40d2SEd Cashin n -= d->rttavg >> RTTSCALE; 10173a0c40d2SEd Cashin d->rttavg += n; 10183a0c40d2SEd Cashin if (n < 0) 10193a0c40d2SEd Cashin n = -n; 10203a0c40d2SEd Cashin n -= d->rttdev >> RTTDSCALE; 10213a0c40d2SEd Cashin d->rttdev += n; 10223a0c40d2SEd Cashin 10233a0c40d2SEd Cashin if (!t || t->maxout >= t->nframes) 10243a0c40d2SEd Cashin return; 10253a0c40d2SEd Cashin if (t->maxout < t->ssthresh) 10263a0c40d2SEd Cashin t->maxout += 1; 10273a0c40d2SEd Cashin else if (t->nout == t->maxout && t->next_cwnd-- == 0) { 10283a0c40d2SEd Cashin t->maxout += 1; 10293a0c40d2SEd Cashin t->next_cwnd = t->maxout; 10303a0c40d2SEd Cashin } 10311da177e4SLinus Torvalds } 10321da177e4SLinus Torvalds 103368e0d42fSEd L. Cashin static struct aoetgt * 103468e0d42fSEd L. Cashin gettgt(struct aoedev *d, char *addr) 103568e0d42fSEd L. Cashin { 103668e0d42fSEd L. Cashin struct aoetgt **t, **e; 103768e0d42fSEd L. Cashin 103868e0d42fSEd L. Cashin t = d->targets; 103971114ec4SEd Cashin e = t + d->ntargets; 104068e0d42fSEd L. Cashin for (; t < e && *t; t++) 104168e0d42fSEd L. Cashin if (memcmp((*t)->addr, addr, sizeof((*t)->addr)) == 0) 104268e0d42fSEd L. Cashin return *t; 104368e0d42fSEd L. Cashin return NULL; 104468e0d42fSEd L. Cashin } 104568e0d42fSEd L. Cashin 10463d5b0605SEd Cashin static void 1047feb261e2SKent Overstreet bvcpy(struct sk_buff *skb, struct bio *bio, struct bvec_iter iter, long cnt) 10483d5b0605SEd Cashin { 10493d5b0605SEd Cashin int soff = 0; 1050feb261e2SKent Overstreet struct bio_vec bv; 1051feb261e2SKent Overstreet 1052feb261e2SKent Overstreet iter.bi_size = cnt; 1053feb261e2SKent Overstreet 1054feb261e2SKent Overstreet __bio_for_each_segment(bv, bio, iter, iter) { 1055feb261e2SKent Overstreet char *p = page_address(bv.bv_page) + bv.bv_offset; 1056feb261e2SKent Overstreet skb_copy_bits(skb, soff, p, bv.bv_len); 1057feb261e2SKent Overstreet soff += bv.bv_len; 1058feb261e2SKent Overstreet } 10593d5b0605SEd Cashin } 10603d5b0605SEd Cashin 106169cf2d85SEd Cashin void 106269cf2d85SEd Cashin aoe_end_request(struct aoedev *d, struct request *rq, int fastfail) 106369cf2d85SEd Cashin { 106469cf2d85SEd Cashin struct bio *bio; 106569cf2d85SEd Cashin int bok; 106669cf2d85SEd Cashin struct request_queue *q; 106769cf2d85SEd Cashin 106869cf2d85SEd Cashin q = d->blkq; 106969cf2d85SEd Cashin if (rq == d->ip.rq) 107069cf2d85SEd Cashin d->ip.rq = NULL; 107169cf2d85SEd Cashin do { 107269cf2d85SEd Cashin bio = rq->bio; 10734e4cbee9SChristoph Hellwig bok = !fastfail && !bio->bi_status; 10742a842acaSChristoph Hellwig } while (__blk_end_request(rq, bok ? BLK_STS_OK : BLK_STS_IOERR, bio->bi_iter.bi_size)); 107569cf2d85SEd Cashin 107669cf2d85SEd Cashin /* cf. http://lkml.org/lkml/2006/10/31/28 */ 107769cf2d85SEd Cashin if (!fastfail) 107811cfb6ffSEd Cashin __blk_run_queue(q); 107969cf2d85SEd Cashin } 108069cf2d85SEd Cashin 108169cf2d85SEd Cashin static void 108269cf2d85SEd Cashin aoe_end_buf(struct aoedev *d, struct buf *buf) 108369cf2d85SEd Cashin { 108469cf2d85SEd Cashin struct request *rq; 108569cf2d85SEd Cashin unsigned long n; 108669cf2d85SEd Cashin 108769cf2d85SEd Cashin if (buf == d->ip.buf) 108869cf2d85SEd Cashin d->ip.buf = NULL; 108969cf2d85SEd Cashin rq = buf->rq; 109069cf2d85SEd Cashin mempool_free(buf, d->bufpool); 109169cf2d85SEd Cashin n = (unsigned long) rq->special; 109269cf2d85SEd Cashin rq->special = (void *) --n; 109369cf2d85SEd Cashin if (n == 0) 109469cf2d85SEd Cashin aoe_end_request(d, rq, 0); 109569cf2d85SEd Cashin } 109669cf2d85SEd Cashin 10973d5b0605SEd Cashin static void 1098896831f5SEd Cashin ktiocomplete(struct frame *f) 10993d5b0605SEd Cashin { 1100ddec63e8SEd L. Cashin struct aoe_hdr *hin, *hout; 11011da177e4SLinus Torvalds struct aoe_atahdr *ahin, *ahout; 11021da177e4SLinus Torvalds struct buf *buf; 1103896831f5SEd Cashin struct sk_buff *skb; 110468e0d42fSEd L. Cashin struct aoetgt *t; 110568e0d42fSEd L. Cashin struct aoeif *ifp; 1106896831f5SEd Cashin struct aoedev *d; 1107896831f5SEd Cashin long n; 1108bbb44e30SEd Cashin int untainted; 1109896831f5SEd Cashin 1110896831f5SEd Cashin if (f == NULL) 1111896831f5SEd Cashin return; 1112896831f5SEd Cashin 1113896831f5SEd Cashin t = f->t; 1114896831f5SEd Cashin d = t->d; 1115bbb44e30SEd Cashin skb = f->r_skb; 1116bbb44e30SEd Cashin buf = f->buf; 1117bbb44e30SEd Cashin if (f->flags & FFL_PROBE) 1118bbb44e30SEd Cashin goto out; 1119bbb44e30SEd Cashin if (!skb) /* just fail the buf. */ 1120bbb44e30SEd Cashin goto noskb; 1121896831f5SEd Cashin 1122896831f5SEd Cashin hout = (struct aoe_hdr *) skb_mac_header(f->skb); 1123896831f5SEd Cashin ahout = (struct aoe_atahdr *) (hout+1); 1124896831f5SEd Cashin 1125896831f5SEd Cashin hin = (struct aoe_hdr *) skb->data; 1126896831f5SEd Cashin skb_pull(skb, sizeof(*hin)); 1127896831f5SEd Cashin ahin = (struct aoe_atahdr *) skb->data; 1128896831f5SEd Cashin skb_pull(skb, sizeof(*ahin)); 1129896831f5SEd Cashin if (ahin->cmdstat & 0xa9) { /* these bits cleared on success */ 1130896831f5SEd Cashin pr_err("aoe: ata error cmd=%2.2Xh stat=%2.2Xh from e%ld.%d\n", 1131896831f5SEd Cashin ahout->cmdstat, ahin->cmdstat, 1132896831f5SEd Cashin d->aoemajor, d->aoeminor); 1133896831f5SEd Cashin noskb: if (buf) 11344e4cbee9SChristoph Hellwig buf->bio->bi_status = BLK_STS_IOERR; 1135bbb44e30SEd Cashin goto out; 1136896831f5SEd Cashin } 1137896831f5SEd Cashin 1138896831f5SEd Cashin n = ahout->scnt << 9; 1139896831f5SEd Cashin switch (ahout->cmdstat) { 1140896831f5SEd Cashin case ATA_CMD_PIO_READ: 1141896831f5SEd Cashin case ATA_CMD_PIO_READ_EXT: 1142896831f5SEd Cashin if (skb->len < n) { 1143bf29754aSEd Cashin pr_err("%s e%ld.%d. skb->len=%d need=%ld\n", 1144bf29754aSEd Cashin "aoe: runt data size in read from", 1145bf29754aSEd Cashin (long) d->aoemajor, d->aoeminor, 1146896831f5SEd Cashin skb->len, n); 11474e4cbee9SChristoph Hellwig buf->bio->bi_status = BLK_STS_IOERR; 1148896831f5SEd Cashin break; 1149896831f5SEd Cashin } 1150feb261e2SKent Overstreet if (n > f->iter.bi_size) { 1151feb261e2SKent Overstreet pr_err_ratelimited("%s e%ld.%d. bytes=%ld need=%u\n", 1152feb261e2SKent Overstreet "aoe: too-large data size in read from", 1153feb261e2SKent Overstreet (long) d->aoemajor, d->aoeminor, 1154feb261e2SKent Overstreet n, f->iter.bi_size); 11554e4cbee9SChristoph Hellwig buf->bio->bi_status = BLK_STS_IOERR; 1156feb261e2SKent Overstreet break; 1157feb261e2SKent Overstreet } 1158feb261e2SKent Overstreet bvcpy(skb, f->buf->bio, f->iter, n); 1159896831f5SEd Cashin case ATA_CMD_PIO_WRITE: 1160896831f5SEd Cashin case ATA_CMD_PIO_WRITE_EXT: 1161896831f5SEd Cashin spin_lock_irq(&d->lock); 1162896831f5SEd Cashin ifp = getif(t, skb->dev); 11633f0f0133SEd Cashin if (ifp) 1164896831f5SEd Cashin ifp->lost = 0; 1165896831f5SEd Cashin spin_unlock_irq(&d->lock); 1166896831f5SEd Cashin break; 1167896831f5SEd Cashin case ATA_CMD_ID_ATA: 1168896831f5SEd Cashin if (skb->len < 512) { 1169bf29754aSEd Cashin pr_info("%s e%ld.%d. skb->len=%d need=512\n", 1170bf29754aSEd Cashin "aoe: runt data size in ataid from", 1171bf29754aSEd Cashin (long) d->aoemajor, d->aoeminor, 1172896831f5SEd Cashin skb->len); 1173896831f5SEd Cashin break; 1174896831f5SEd Cashin } 1175896831f5SEd Cashin if (skb_linearize(skb)) 1176896831f5SEd Cashin break; 1177896831f5SEd Cashin spin_lock_irq(&d->lock); 1178896831f5SEd Cashin ataid_complete(d, t, skb->data); 1179896831f5SEd Cashin spin_unlock_irq(&d->lock); 1180896831f5SEd Cashin break; 1181896831f5SEd Cashin default: 1182896831f5SEd Cashin pr_info("aoe: unrecognized ata command %2.2Xh for %d.%d\n", 1183896831f5SEd Cashin ahout->cmdstat, 1184896831f5SEd Cashin be16_to_cpu(get_unaligned(&hin->major)), 1185896831f5SEd Cashin hin->minor); 1186896831f5SEd Cashin } 1187bbb44e30SEd Cashin out: 1188896831f5SEd Cashin spin_lock_irq(&d->lock); 1189bbb44e30SEd Cashin if (t->taint > 0 1190bbb44e30SEd Cashin && --t->taint > 0 1191bbb44e30SEd Cashin && t->nout_probes == 0) { 1192bbb44e30SEd Cashin count_targets(d, &untainted); 1193bbb44e30SEd Cashin if (untainted > 0) { 1194bbb44e30SEd Cashin probe(t); 1195bbb44e30SEd Cashin t->nout_probes++; 1196bbb44e30SEd Cashin } 1197bbb44e30SEd Cashin } 1198896831f5SEd Cashin 1199896831f5SEd Cashin aoe_freetframe(f); 1200896831f5SEd Cashin 1201feb261e2SKent Overstreet if (buf && --buf->nframesout == 0 && buf->iter.bi_size == 0) 120269cf2d85SEd Cashin aoe_end_buf(d, buf); 1203896831f5SEd Cashin 1204896831f5SEd Cashin spin_unlock_irq(&d->lock); 120569cf2d85SEd Cashin aoedev_put(d); 1206896831f5SEd Cashin dev_kfree_skb(skb); 1207896831f5SEd Cashin } 1208896831f5SEd Cashin 1209896831f5SEd Cashin /* Enters with iocq.lock held. 1210896831f5SEd Cashin * Returns true iff responses needing processing remain. 1211896831f5SEd Cashin */ 1212896831f5SEd Cashin static int 12138030d343SEd Cashin ktio(int id) 1214896831f5SEd Cashin { 1215896831f5SEd Cashin struct frame *f; 1216896831f5SEd Cashin struct list_head *pos; 1217896831f5SEd Cashin int i; 12188030d343SEd Cashin int actual_id; 1219896831f5SEd Cashin 1220896831f5SEd Cashin for (i = 0; ; ++i) { 1221896831f5SEd Cashin if (i == MAXIOC) 1222896831f5SEd Cashin return 1; 12238030d343SEd Cashin if (list_empty(&iocq[id].head)) 1224896831f5SEd Cashin return 0; 12258030d343SEd Cashin pos = iocq[id].head.next; 1226896831f5SEd Cashin list_del(pos); 1227896831f5SEd Cashin f = list_entry(pos, struct frame, head); 12288030d343SEd Cashin spin_unlock_irq(&iocq[id].lock); 1229896831f5SEd Cashin ktiocomplete(f); 12308030d343SEd Cashin 12318030d343SEd Cashin /* Figure out if extra threads are required. */ 12328030d343SEd Cashin actual_id = f->t->d->aoeminor % ncpus; 12338030d343SEd Cashin 12348030d343SEd Cashin if (!kts[actual_id].active) { 12358030d343SEd Cashin BUG_ON(id != 0); 12368030d343SEd Cashin mutex_lock(&ktio_spawn_lock); 12378030d343SEd Cashin if (!kts[actual_id].active 12388030d343SEd Cashin && aoe_ktstart(&kts[actual_id]) == 0) 12398030d343SEd Cashin kts[actual_id].active = 1; 12408030d343SEd Cashin mutex_unlock(&ktio_spawn_lock); 12418030d343SEd Cashin } 12428030d343SEd Cashin spin_lock_irq(&iocq[id].lock); 1243896831f5SEd Cashin } 1244896831f5SEd Cashin } 1245896831f5SEd Cashin 1246896831f5SEd Cashin static int 1247896831f5SEd Cashin kthread(void *vp) 1248896831f5SEd Cashin { 1249896831f5SEd Cashin struct ktstate *k; 1250896831f5SEd Cashin DECLARE_WAITQUEUE(wait, current); 1251896831f5SEd Cashin int more; 1252896831f5SEd Cashin 1253896831f5SEd Cashin k = vp; 1254896831f5SEd Cashin current->flags |= PF_NOFREEZE; 1255896831f5SEd Cashin set_user_nice(current, -10); 1256896831f5SEd Cashin complete(&k->rendez); /* tell spawner we're running */ 1257896831f5SEd Cashin do { 1258896831f5SEd Cashin spin_lock_irq(k->lock); 12598030d343SEd Cashin more = k->fn(k->id); 1260896831f5SEd Cashin if (!more) { 1261896831f5SEd Cashin add_wait_queue(k->waitq, &wait); 1262896831f5SEd Cashin __set_current_state(TASK_INTERRUPTIBLE); 1263896831f5SEd Cashin } 1264896831f5SEd Cashin spin_unlock_irq(k->lock); 1265896831f5SEd Cashin if (!more) { 1266896831f5SEd Cashin schedule(); 1267896831f5SEd Cashin remove_wait_queue(k->waitq, &wait); 1268896831f5SEd Cashin } else 1269896831f5SEd Cashin cond_resched(); 1270896831f5SEd Cashin } while (!kthread_should_stop()); 1271896831f5SEd Cashin complete(&k->rendez); /* tell spawner we're stopping */ 1272896831f5SEd Cashin return 0; 1273896831f5SEd Cashin } 1274896831f5SEd Cashin 1275eb086ec5SEd Cashin void 1276896831f5SEd Cashin aoe_ktstop(struct ktstate *k) 1277896831f5SEd Cashin { 1278896831f5SEd Cashin kthread_stop(k->task); 1279896831f5SEd Cashin wait_for_completion(&k->rendez); 1280896831f5SEd Cashin } 1281896831f5SEd Cashin 1282eb086ec5SEd Cashin int 1283896831f5SEd Cashin aoe_ktstart(struct ktstate *k) 1284896831f5SEd Cashin { 1285896831f5SEd Cashin struct task_struct *task; 1286896831f5SEd Cashin 1287896831f5SEd Cashin init_completion(&k->rendez); 1288f170168bSKees Cook task = kthread_run(kthread, k, "%s", k->name); 1289896831f5SEd Cashin if (task == NULL || IS_ERR(task)) 1290896831f5SEd Cashin return -ENOMEM; 1291896831f5SEd Cashin k->task = task; 1292896831f5SEd Cashin wait_for_completion(&k->rendez); /* allow kthread to start */ 1293896831f5SEd Cashin init_completion(&k->rendez); /* for waiting for exit later */ 1294896831f5SEd Cashin return 0; 1295896831f5SEd Cashin } 1296896831f5SEd Cashin 1297896831f5SEd Cashin /* pass it off to kthreads for processing */ 1298896831f5SEd Cashin static void 1299896831f5SEd Cashin ktcomplete(struct frame *f, struct sk_buff *skb) 1300896831f5SEd Cashin { 13018030d343SEd Cashin int id; 1302896831f5SEd Cashin ulong flags; 1303896831f5SEd Cashin 1304896831f5SEd Cashin f->r_skb = skb; 13058030d343SEd Cashin id = f->t->d->aoeminor % ncpus; 13068030d343SEd Cashin spin_lock_irqsave(&iocq[id].lock, flags); 13078030d343SEd Cashin if (!kts[id].active) { 13088030d343SEd Cashin spin_unlock_irqrestore(&iocq[id].lock, flags); 13098030d343SEd Cashin /* The thread with id has not been spawned yet, 13108030d343SEd Cashin * so delegate the work to the main thread and 13118030d343SEd Cashin * try spawning a new thread. 13128030d343SEd Cashin */ 13138030d343SEd Cashin id = 0; 13148030d343SEd Cashin spin_lock_irqsave(&iocq[id].lock, flags); 13158030d343SEd Cashin } 13168030d343SEd Cashin list_add_tail(&f->head, &iocq[id].head); 13178030d343SEd Cashin spin_unlock_irqrestore(&iocq[id].lock, flags); 13188030d343SEd Cashin wake_up(&ktiowq[id]); 1319896831f5SEd Cashin } 1320896831f5SEd Cashin 1321896831f5SEd Cashin struct sk_buff * 1322896831f5SEd Cashin aoecmd_ata_rsp(struct sk_buff *skb) 1323896831f5SEd Cashin { 1324896831f5SEd Cashin struct aoedev *d; 1325896831f5SEd Cashin struct aoe_hdr *h; 1326896831f5SEd Cashin struct frame *f; 1327896831f5SEd Cashin u32 n; 13281da177e4SLinus Torvalds ulong flags; 13291da177e4SLinus Torvalds char ebuf[128]; 133032465c65Secashin@coraid.com u16 aoemajor; 13311da177e4SLinus Torvalds 1332896831f5SEd Cashin h = (struct aoe_hdr *) skb->data; 1333896831f5SEd Cashin aoemajor = be16_to_cpu(get_unaligned(&h->major)); 13340c966214SEd Cashin d = aoedev_by_aoeaddr(aoemajor, h->minor, 0); 13351da177e4SLinus Torvalds if (d == NULL) { 13361da177e4SLinus Torvalds snprintf(ebuf, sizeof ebuf, "aoecmd_ata_rsp: ata response " 13371da177e4SLinus Torvalds "for unknown device %d.%d\n", 1338896831f5SEd Cashin aoemajor, h->minor); 13391da177e4SLinus Torvalds aoechr_error(ebuf); 1340896831f5SEd Cashin return skb; 13411da177e4SLinus Torvalds } 13421da177e4SLinus Torvalds 13431da177e4SLinus Torvalds spin_lock_irqsave(&d->lock, flags); 13441da177e4SLinus Torvalds 1345896831f5SEd Cashin n = be32_to_cpu(get_unaligned(&h->tag)); 134664a80f5aSEd Cashin f = getframe(d, n); 13473a0c40d2SEd Cashin if (f) { 13485f0c9c48SEd Cashin calc_rttavg(d, f->t, tsince_hr(f)); 13493a0c40d2SEd Cashin f->t->nout--; 1350bbb44e30SEd Cashin if (f->flags & FFL_PROBE) 1351bbb44e30SEd Cashin f->t->nout_probes--; 13523a0c40d2SEd Cashin } else { 13533a0c40d2SEd Cashin f = getframe_deferred(d, n); 13543a0c40d2SEd Cashin if (f) { 13555f0c9c48SEd Cashin calc_rttavg(d, NULL, tsince_hr(f)); 13563a0c40d2SEd Cashin } else { 13573a0c40d2SEd Cashin calc_rttavg(d, NULL, tsince(n)); 13581da177e4SLinus Torvalds spin_unlock_irqrestore(&d->lock, flags); 135969cf2d85SEd Cashin aoedev_put(d); 13603a0c40d2SEd Cashin snprintf(ebuf, sizeof(ebuf), 13612292a7e1SEd Cashin "%15s e%d.%d tag=%08x@%08lx s=%pm d=%pm\n", 13621da177e4SLinus Torvalds "unexpected rsp", 1363896831f5SEd Cashin get_unaligned_be16(&h->major), 1364896831f5SEd Cashin h->minor, 1365896831f5SEd Cashin get_unaligned_be32(&h->tag), 13662292a7e1SEd Cashin jiffies, 13672292a7e1SEd Cashin h->src, 13682292a7e1SEd Cashin h->dst); 13691da177e4SLinus Torvalds aoechr_error(ebuf); 1370896831f5SEd Cashin return skb; 13711da177e4SLinus Torvalds } 13723a0c40d2SEd Cashin } 13731da177e4SLinus Torvalds aoecmd_work(d); 13741da177e4SLinus Torvalds 13751da177e4SLinus Torvalds spin_unlock_irqrestore(&d->lock, flags); 1376896831f5SEd Cashin 1377896831f5SEd Cashin ktcomplete(f, skb); 1378896831f5SEd Cashin 1379896831f5SEd Cashin /* 1380896831f5SEd Cashin * Note here that we do not perform an aoedev_put, as we are 1381896831f5SEd Cashin * leaving this reference for the ktio to release. 1382896831f5SEd Cashin */ 1383896831f5SEd Cashin return NULL; 13841da177e4SLinus Torvalds } 13851da177e4SLinus Torvalds 13861da177e4SLinus Torvalds void 13871da177e4SLinus Torvalds aoecmd_cfg(ushort aoemajor, unsigned char aoeminor) 13881da177e4SLinus Torvalds { 1389e9bb8fb0SDavid S. Miller struct sk_buff_head queue; 13901da177e4SLinus Torvalds 1391e9bb8fb0SDavid S. Miller __skb_queue_head_init(&queue); 1392e9bb8fb0SDavid S. Miller aoecmd_cfg_pkts(aoemajor, aoeminor, &queue); 1393e9bb8fb0SDavid S. Miller aoenet_xmit(&queue); 13941da177e4SLinus Torvalds } 13951da177e4SLinus Torvalds 139668e0d42fSEd L. Cashin struct sk_buff * 13971da177e4SLinus Torvalds aoecmd_ata_id(struct aoedev *d) 13981da177e4SLinus Torvalds { 13991da177e4SLinus Torvalds struct aoe_hdr *h; 14001da177e4SLinus Torvalds struct aoe_atahdr *ah; 14011da177e4SLinus Torvalds struct frame *f; 14021da177e4SLinus Torvalds struct sk_buff *skb; 140368e0d42fSEd L. Cashin struct aoetgt *t; 14041da177e4SLinus Torvalds 1405896831f5SEd Cashin f = newframe(d); 140668e0d42fSEd L. Cashin if (f == NULL) 14071da177e4SLinus Torvalds return NULL; 140868e0d42fSEd L. Cashin 140968e0d42fSEd L. Cashin t = *d->tgt; 14101da177e4SLinus Torvalds 14111da177e4SLinus Torvalds /* initialize the headers & frame */ 1412e407a7f6SEd L. Cashin skb = f->skb; 1413abdbf94dSEd L. Cashin h = (struct aoe_hdr *) skb_mac_header(skb); 14141da177e4SLinus Torvalds ah = (struct aoe_atahdr *) (h+1); 141519900cdeSEd L. Cashin skb_put(skb, sizeof *h + sizeof *ah); 141619900cdeSEd L. Cashin memset(h, 0, skb->len); 141768e0d42fSEd L. Cashin f->tag = aoehdr_atainit(d, t, h); 1418896831f5SEd Cashin fhash(f); 141968e0d42fSEd L. Cashin t->nout++; 14201da177e4SLinus Torvalds f->waited = 0; 14213fc9b032SEd Cashin f->waited_total = 0; 14221da177e4SLinus Torvalds 14231da177e4SLinus Torvalds /* set up ata header */ 14241da177e4SLinus Torvalds ah->scnt = 1; 142504b3ab52SBartlomiej Zolnierkiewicz ah->cmdstat = ATA_CMD_ID_ATA; 14261da177e4SLinus Torvalds ah->lba3 = 0xa0; 14271da177e4SLinus Torvalds 142868e0d42fSEd L. Cashin skb->dev = t->ifp->nd; 14291da177e4SLinus Torvalds 14303a0c40d2SEd Cashin d->rttavg = RTTAVG_INIT; 14313a0c40d2SEd Cashin d->rttdev = RTTDEV_INIT; 1432*0e0cc9dfSKees Cook d->timer.function = (TIMER_FUNC_TYPE)rexmit_timer; 14331da177e4SLinus Torvalds 14345f0c9c48SEd Cashin skb = skb_clone(skb, GFP_ATOMIC); 14355f0c9c48SEd Cashin if (skb) { 14365f0c9c48SEd Cashin do_gettimeofday(&f->sent); 14375f0c9c48SEd Cashin f->sent_jiffs = (u32) jiffies; 14385f0c9c48SEd Cashin } 14395f0c9c48SEd Cashin 14405f0c9c48SEd Cashin return skb; 14411da177e4SLinus Torvalds } 14421da177e4SLinus Torvalds 144371114ec4SEd Cashin static struct aoetgt ** 144471114ec4SEd Cashin grow_targets(struct aoedev *d) 144571114ec4SEd Cashin { 144671114ec4SEd Cashin ulong oldn, newn; 144771114ec4SEd Cashin struct aoetgt **tt; 144871114ec4SEd Cashin 144971114ec4SEd Cashin oldn = d->ntargets; 145071114ec4SEd Cashin newn = oldn * 2; 145171114ec4SEd Cashin tt = kcalloc(newn, sizeof(*d->targets), GFP_ATOMIC); 145271114ec4SEd Cashin if (!tt) 145371114ec4SEd Cashin return NULL; 145471114ec4SEd Cashin memmove(tt, d->targets, sizeof(*d->targets) * oldn); 145571114ec4SEd Cashin d->tgt = tt + (d->tgt - d->targets); 145671114ec4SEd Cashin kfree(d->targets); 145771114ec4SEd Cashin d->targets = tt; 145871114ec4SEd Cashin d->ntargets = newn; 145971114ec4SEd Cashin 146071114ec4SEd Cashin return &d->targets[oldn]; 146171114ec4SEd Cashin } 146271114ec4SEd Cashin 146368e0d42fSEd L. Cashin static struct aoetgt * 146468e0d42fSEd L. Cashin addtgt(struct aoedev *d, char *addr, ulong nframes) 146568e0d42fSEd L. Cashin { 146668e0d42fSEd L. Cashin struct aoetgt *t, **tt, **te; 146768e0d42fSEd L. Cashin 146868e0d42fSEd L. Cashin tt = d->targets; 146971114ec4SEd Cashin te = tt + d->ntargets; 147068e0d42fSEd L. Cashin for (; tt < te && *tt; tt++) 147168e0d42fSEd L. Cashin ; 147268e0d42fSEd L. Cashin 1473578c4aa0SEd L. Cashin if (tt == te) { 147471114ec4SEd Cashin tt = grow_targets(d); 147571114ec4SEd Cashin if (!tt) 147671114ec4SEd Cashin goto nomem; 1477578c4aa0SEd L. Cashin } 1478896831f5SEd Cashin t = kzalloc(sizeof(*t), GFP_ATOMIC); 147971114ec4SEd Cashin if (!t) 148071114ec4SEd Cashin goto nomem; 148168e0d42fSEd L. Cashin t->nframes = nframes; 1482896831f5SEd Cashin t->d = d; 148368e0d42fSEd L. Cashin memcpy(t->addr, addr, sizeof t->addr); 148468e0d42fSEd L. Cashin t->ifp = t->ifs; 14853a0c40d2SEd Cashin aoecmd_wreset(t); 1486bbb44e30SEd Cashin t->maxout = t->nframes / 2; 1487896831f5SEd Cashin INIT_LIST_HEAD(&t->ffree); 148868e0d42fSEd L. Cashin return *tt = t; 148971114ec4SEd Cashin 149071114ec4SEd Cashin nomem: 149171114ec4SEd Cashin pr_info("aoe: cannot allocate memory to add target\n"); 149271114ec4SEd Cashin return NULL; 149368e0d42fSEd L. Cashin } 149468e0d42fSEd L. Cashin 14953f0f0133SEd Cashin static void 14963f0f0133SEd Cashin setdbcnt(struct aoedev *d) 14973f0f0133SEd Cashin { 14983f0f0133SEd Cashin struct aoetgt **t, **e; 14993f0f0133SEd Cashin int bcnt = 0; 15003f0f0133SEd Cashin 15013f0f0133SEd Cashin t = d->targets; 150271114ec4SEd Cashin e = t + d->ntargets; 15033f0f0133SEd Cashin for (; t < e && *t; t++) 15043f0f0133SEd Cashin if (bcnt == 0 || bcnt > (*t)->minbcnt) 15053f0f0133SEd Cashin bcnt = (*t)->minbcnt; 15063f0f0133SEd Cashin if (bcnt != d->maxbcnt) { 15073f0f0133SEd Cashin d->maxbcnt = bcnt; 15083f0f0133SEd Cashin pr_info("aoe: e%ld.%d: setting %d byte data frames\n", 15093f0f0133SEd Cashin d->aoemajor, d->aoeminor, bcnt); 15103f0f0133SEd Cashin } 15113f0f0133SEd Cashin } 15123f0f0133SEd Cashin 15133f0f0133SEd Cashin static void 15143f0f0133SEd Cashin setifbcnt(struct aoetgt *t, struct net_device *nd, int bcnt) 15153f0f0133SEd Cashin { 15163f0f0133SEd Cashin struct aoedev *d; 15173f0f0133SEd Cashin struct aoeif *p, *e; 15183f0f0133SEd Cashin int minbcnt; 15193f0f0133SEd Cashin 15203f0f0133SEd Cashin d = t->d; 15213f0f0133SEd Cashin minbcnt = bcnt; 15223f0f0133SEd Cashin p = t->ifs; 15233f0f0133SEd Cashin e = p + NAOEIFS; 15243f0f0133SEd Cashin for (; p < e; p++) { 15253f0f0133SEd Cashin if (p->nd == NULL) 15263f0f0133SEd Cashin break; /* end of the valid interfaces */ 15273f0f0133SEd Cashin if (p->nd == nd) { 15283f0f0133SEd Cashin p->bcnt = bcnt; /* we're updating */ 15293f0f0133SEd Cashin nd = NULL; 15303f0f0133SEd Cashin } else if (minbcnt > p->bcnt) 15313f0f0133SEd Cashin minbcnt = p->bcnt; /* find the min interface */ 15323f0f0133SEd Cashin } 15333f0f0133SEd Cashin if (nd) { 15343f0f0133SEd Cashin if (p == e) { 15353f0f0133SEd Cashin pr_err("aoe: device setifbcnt failure; too many interfaces.\n"); 15363f0f0133SEd Cashin return; 15373f0f0133SEd Cashin } 15381b86fda9SEd Cashin dev_hold(nd); 15393f0f0133SEd Cashin p->nd = nd; 15403f0f0133SEd Cashin p->bcnt = bcnt; 15413f0f0133SEd Cashin } 15423f0f0133SEd Cashin t->minbcnt = minbcnt; 15433f0f0133SEd Cashin setdbcnt(d); 15443f0f0133SEd Cashin } 15453f0f0133SEd Cashin 15461da177e4SLinus Torvalds void 15471da177e4SLinus Torvalds aoecmd_cfg_rsp(struct sk_buff *skb) 15481da177e4SLinus Torvalds { 15491da177e4SLinus Torvalds struct aoedev *d; 15501da177e4SLinus Torvalds struct aoe_hdr *h; 15511da177e4SLinus Torvalds struct aoe_cfghdr *ch; 155268e0d42fSEd L. Cashin struct aoetgt *t; 15530c966214SEd Cashin ulong flags, aoemajor; 15541da177e4SLinus Torvalds struct sk_buff *sl; 155569cf2d85SEd Cashin struct sk_buff_head queue; 155619bf2635SEd L. Cashin u16 n; 15571da177e4SLinus Torvalds 155869cf2d85SEd Cashin sl = NULL; 1559abdbf94dSEd L. Cashin h = (struct aoe_hdr *) skb_mac_header(skb); 15601da177e4SLinus Torvalds ch = (struct aoe_cfghdr *) (h+1); 15611da177e4SLinus Torvalds 15621da177e4SLinus Torvalds /* 15631da177e4SLinus Torvalds * Enough people have their dip switches set backwards to 15641da177e4SLinus Torvalds * warrant a loud message for this special case. 15651da177e4SLinus Torvalds */ 1566823ed72eSHarvey Harrison aoemajor = get_unaligned_be16(&h->major); 15671da177e4SLinus Torvalds if (aoemajor == 0xfff) { 1568a12c93f0SEd L. Cashin printk(KERN_ERR "aoe: Warning: shelf address is all ones. " 15696bb6285fSEd L. Cashin "Check shelf dip switches.\n"); 15701da177e4SLinus Torvalds return; 15711da177e4SLinus Torvalds } 15727159e969SEd Cashin if (aoemajor == 0xffff) { 15737159e969SEd Cashin pr_info("aoe: e%ld.%d: broadcast shelf number invalid\n", 15740c966214SEd Cashin aoemajor, (int) h->minor); 15756583303cSEd Cashin return; 15766583303cSEd Cashin } 15777159e969SEd Cashin if (h->minor == 0xff) { 15787159e969SEd Cashin pr_info("aoe: e%ld.%d: broadcast slot number invalid\n", 15797159e969SEd Cashin aoemajor, (int) h->minor); 15801da177e4SLinus Torvalds return; 15811da177e4SLinus Torvalds } 15821da177e4SLinus Torvalds 158319bf2635SEd L. Cashin n = be16_to_cpu(ch->bufcnt); 15847df620d8SEd L. Cashin if (n > aoe_maxout) /* keep it reasonable */ 15857df620d8SEd L. Cashin n = aoe_maxout; 15861da177e4SLinus Torvalds 15877159e969SEd Cashin d = aoedev_by_aoeaddr(aoemajor, h->minor, 1); 15887159e969SEd Cashin if (d == NULL) { 15897159e969SEd Cashin pr_info("aoe: device allocation failure\n"); 15907159e969SEd Cashin return; 15917159e969SEd Cashin } 15927159e969SEd Cashin 15931da177e4SLinus Torvalds spin_lock_irqsave(&d->lock, flags); 15941da177e4SLinus Torvalds 159568e0d42fSEd L. Cashin t = gettgt(d, h->src); 15961b8a1636SEd Cashin if (t) { 15971b8a1636SEd Cashin t->nframes = n; 15981b8a1636SEd Cashin if (n < t->maxout) 15993a0c40d2SEd Cashin aoecmd_wreset(t); 16001b8a1636SEd Cashin } else { 160168e0d42fSEd L. Cashin t = addtgt(d, h->src, n); 160269cf2d85SEd Cashin if (!t) 160369cf2d85SEd Cashin goto bail; 160468e0d42fSEd L. Cashin } 16053f0f0133SEd Cashin n = skb->dev->mtu; 160619bf2635SEd L. Cashin n -= sizeof(struct aoe_hdr) + sizeof(struct aoe_atahdr); 160719bf2635SEd L. Cashin n /= 512; 160819bf2635SEd L. Cashin if (n > ch->scnt) 160919bf2635SEd L. Cashin n = ch->scnt; 16104f51dc5eSEd L. Cashin n = n ? n * 512 : DEFAULTBCNT; 16113f0f0133SEd Cashin setifbcnt(t, skb->dev, n); 16123ae1c24eSEd L. Cashin 16133ae1c24eSEd L. Cashin /* don't change users' perspective */ 161469cf2d85SEd Cashin if (d->nopen == 0) { 161563e9cc5dSecashin@coraid.com d->fw_ver = be16_to_cpu(ch->fwver); 161668e0d42fSEd L. Cashin sl = aoecmd_ata_id(d); 161769cf2d85SEd Cashin } 161869cf2d85SEd Cashin bail: 16191da177e4SLinus Torvalds spin_unlock_irqrestore(&d->lock, flags); 162069cf2d85SEd Cashin aoedev_put(d); 1621e9bb8fb0SDavid S. Miller if (sl) { 1622e9bb8fb0SDavid S. Miller __skb_queue_head_init(&queue); 1623e9bb8fb0SDavid S. Miller __skb_queue_tail(&queue, sl); 1624e9bb8fb0SDavid S. Miller aoenet_xmit(&queue); 1625e9bb8fb0SDavid S. Miller } 16261da177e4SLinus Torvalds } 16271da177e4SLinus Torvalds 162868e0d42fSEd L. Cashin void 16293a0c40d2SEd Cashin aoecmd_wreset(struct aoetgt *t) 16303a0c40d2SEd Cashin { 16313a0c40d2SEd Cashin t->maxout = 1; 16323a0c40d2SEd Cashin t->ssthresh = t->nframes / 2; 16333a0c40d2SEd Cashin t->next_cwnd = t->nframes; 16343a0c40d2SEd Cashin } 16353a0c40d2SEd Cashin 16363a0c40d2SEd Cashin void 163768e0d42fSEd L. Cashin aoecmd_cleanslate(struct aoedev *d) 163868e0d42fSEd L. Cashin { 163968e0d42fSEd L. Cashin struct aoetgt **t, **te; 164068e0d42fSEd L. Cashin 16413a0c40d2SEd Cashin d->rttavg = RTTAVG_INIT; 16423a0c40d2SEd Cashin d->rttdev = RTTDEV_INIT; 16433f0f0133SEd Cashin d->maxbcnt = 0; 164468e0d42fSEd L. Cashin 164568e0d42fSEd L. Cashin t = d->targets; 164671114ec4SEd Cashin te = t + d->ntargets; 16473f0f0133SEd Cashin for (; t < te && *t; t++) 16483a0c40d2SEd Cashin aoecmd_wreset(*t); 164968e0d42fSEd L. Cashin } 1650896831f5SEd Cashin 165169cf2d85SEd Cashin void 165269cf2d85SEd Cashin aoe_failbuf(struct aoedev *d, struct buf *buf) 165369cf2d85SEd Cashin { 165469cf2d85SEd Cashin if (buf == NULL) 165569cf2d85SEd Cashin return; 1656feb261e2SKent Overstreet buf->iter.bi_size = 0; 16574e4cbee9SChristoph Hellwig buf->bio->bi_status = BLK_STS_IOERR; 165869cf2d85SEd Cashin if (buf->nframesout == 0) 165969cf2d85SEd Cashin aoe_end_buf(d, buf); 166069cf2d85SEd Cashin } 166169cf2d85SEd Cashin 166269cf2d85SEd Cashin void 166369cf2d85SEd Cashin aoe_flush_iocq(void) 1664896831f5SEd Cashin { 16658030d343SEd Cashin int i; 16668030d343SEd Cashin 16678030d343SEd Cashin for (i = 0; i < ncpus; i++) { 16688030d343SEd Cashin if (kts[i].active) 16698030d343SEd Cashin aoe_flush_iocq_by_index(i); 16708030d343SEd Cashin } 16718030d343SEd Cashin } 16728030d343SEd Cashin 16738030d343SEd Cashin void 16748030d343SEd Cashin aoe_flush_iocq_by_index(int id) 16758030d343SEd Cashin { 1676896831f5SEd Cashin struct frame *f; 1677896831f5SEd Cashin struct aoedev *d; 1678896831f5SEd Cashin LIST_HEAD(flist); 1679896831f5SEd Cashin struct list_head *pos; 1680896831f5SEd Cashin struct sk_buff *skb; 1681896831f5SEd Cashin ulong flags; 1682896831f5SEd Cashin 16838030d343SEd Cashin spin_lock_irqsave(&iocq[id].lock, flags); 16848030d343SEd Cashin list_splice_init(&iocq[id].head, &flist); 16858030d343SEd Cashin spin_unlock_irqrestore(&iocq[id].lock, flags); 1686896831f5SEd Cashin while (!list_empty(&flist)) { 1687896831f5SEd Cashin pos = flist.next; 1688896831f5SEd Cashin list_del(pos); 1689896831f5SEd Cashin f = list_entry(pos, struct frame, head); 1690896831f5SEd Cashin d = f->t->d; 1691896831f5SEd Cashin skb = f->r_skb; 1692896831f5SEd Cashin spin_lock_irqsave(&d->lock, flags); 1693896831f5SEd Cashin if (f->buf) { 1694896831f5SEd Cashin f->buf->nframesout--; 1695896831f5SEd Cashin aoe_failbuf(d, f->buf); 1696896831f5SEd Cashin } 1697896831f5SEd Cashin aoe_freetframe(f); 1698896831f5SEd Cashin spin_unlock_irqrestore(&d->lock, flags); 1699896831f5SEd Cashin dev_kfree_skb(skb); 170069cf2d85SEd Cashin aoedev_put(d); 1701896831f5SEd Cashin } 1702896831f5SEd Cashin } 1703896831f5SEd Cashin 1704896831f5SEd Cashin int __init 1705896831f5SEd Cashin aoecmd_init(void) 1706896831f5SEd Cashin { 1707bbb44e30SEd Cashin void *p; 17088030d343SEd Cashin int i; 17098030d343SEd Cashin int ret; 1710bbb44e30SEd Cashin 1711bbb44e30SEd Cashin /* get_zeroed_page returns page with ref count 1 */ 171232d6bd90SMichal Hocko p = (void *) get_zeroed_page(GFP_KERNEL); 1713bbb44e30SEd Cashin if (!p) 1714bbb44e30SEd Cashin return -ENOMEM; 1715bbb44e30SEd Cashin empty_page = virt_to_page(p); 1716bbb44e30SEd Cashin 17178030d343SEd Cashin ncpus = num_online_cpus(); 17188030d343SEd Cashin 17198030d343SEd Cashin iocq = kcalloc(ncpus, sizeof(struct iocq_ktio), GFP_KERNEL); 17208030d343SEd Cashin if (!iocq) 17218030d343SEd Cashin return -ENOMEM; 17228030d343SEd Cashin 17238030d343SEd Cashin kts = kcalloc(ncpus, sizeof(struct ktstate), GFP_KERNEL); 17248030d343SEd Cashin if (!kts) { 17258030d343SEd Cashin ret = -ENOMEM; 17268030d343SEd Cashin goto kts_fail; 17278030d343SEd Cashin } 17288030d343SEd Cashin 17298030d343SEd Cashin ktiowq = kcalloc(ncpus, sizeof(wait_queue_head_t), GFP_KERNEL); 17308030d343SEd Cashin if (!ktiowq) { 17318030d343SEd Cashin ret = -ENOMEM; 17328030d343SEd Cashin goto ktiowq_fail; 17338030d343SEd Cashin } 17348030d343SEd Cashin 17358030d343SEd Cashin mutex_init(&ktio_spawn_lock); 17368030d343SEd Cashin 17378030d343SEd Cashin for (i = 0; i < ncpus; i++) { 17388030d343SEd Cashin INIT_LIST_HEAD(&iocq[i].head); 17398030d343SEd Cashin spin_lock_init(&iocq[i].lock); 17408030d343SEd Cashin init_waitqueue_head(&ktiowq[i]); 17418030d343SEd Cashin snprintf(kts[i].name, sizeof(kts[i].name), "aoe_ktio%d", i); 17428030d343SEd Cashin kts[i].fn = ktio; 17438030d343SEd Cashin kts[i].waitq = &ktiowq[i]; 17448030d343SEd Cashin kts[i].lock = &iocq[i].lock; 17458030d343SEd Cashin kts[i].id = i; 17468030d343SEd Cashin kts[i].active = 0; 17478030d343SEd Cashin } 17488030d343SEd Cashin kts[0].active = 1; 17498030d343SEd Cashin if (aoe_ktstart(&kts[0])) { 17508030d343SEd Cashin ret = -ENOMEM; 17518030d343SEd Cashin goto ktstart_fail; 17528030d343SEd Cashin } 17538030d343SEd Cashin return 0; 17548030d343SEd Cashin 17558030d343SEd Cashin ktstart_fail: 17568030d343SEd Cashin kfree(ktiowq); 17578030d343SEd Cashin ktiowq_fail: 17588030d343SEd Cashin kfree(kts); 17598030d343SEd Cashin kts_fail: 17608030d343SEd Cashin kfree(iocq); 17618030d343SEd Cashin 17628030d343SEd Cashin return ret; 1763896831f5SEd Cashin } 1764896831f5SEd Cashin 1765896831f5SEd Cashin void 1766896831f5SEd Cashin aoecmd_exit(void) 1767896831f5SEd Cashin { 17688030d343SEd Cashin int i; 17698030d343SEd Cashin 17708030d343SEd Cashin for (i = 0; i < ncpus; i++) 17718030d343SEd Cashin if (kts[i].active) 17728030d343SEd Cashin aoe_ktstop(&kts[i]); 17738030d343SEd Cashin 177469cf2d85SEd Cashin aoe_flush_iocq(); 1775bbb44e30SEd Cashin 17768030d343SEd Cashin /* Free up the iocq and thread speicific configuration 17778030d343SEd Cashin * allocated during startup. 17788030d343SEd Cashin */ 17798030d343SEd Cashin kfree(iocq); 17808030d343SEd Cashin kfree(kts); 17818030d343SEd Cashin kfree(ktiowq); 17828030d343SEd Cashin 1783bbb44e30SEd Cashin free_page((unsigned long) page_address(empty_page)); 1784bbb44e30SEd Cashin empty_page = NULL; 1785896831f5SEd Cashin } 1786