xref: /openbmc/linux/drivers/block/aoe/aoecmd.c (revision 896831f5909e2733c13c9cb13a1a215f10c3eaa8)
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