blob: 9a58242290c049dbfda60b64581ea1378dd8f45e [file] [log] [blame]
Ed L. Cashin52e112b2008-02-08 04:20:09 -08001/* Copyright (c) 2007 Coraid, Inc. See COPYING for GPL terms. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002/*
3 * aoecmd.c
4 * Filesystem request handling methods
5 */
6
Bartlomiej Zolnierkiewicz04b3ab52009-04-01 21:42:24 +02007#include <linux/ata.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +09008#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -07009#include <linux/hdreg.h>
10#include <linux/blkdev.h>
11#include <linux/skbuff.h>
12#include <linux/netdevice.h>
Ed L. Cashin3ae1c242006-01-19 13:46:19 -050013#include <linux/genhd.h>
Ed L. Cashin68e0d422008-02-08 04:20:00 -080014#include <linux/moduleparam.h>
Eric W. Biederman881d9662007-09-17 11:56:21 -070015#include <net/net_namespace.h>
Ed L. Cashin475172f2005-09-29 12:47:40 -040016#include <asm/unaligned.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070017#include "aoe.h"
18
Ed L. Cashinb751e8b2006-09-20 14:36:50 -040019static int aoe_deadsecs = 60 * 3;
20module_param(aoe_deadsecs, int, 0644);
21MODULE_PARM_DESC(aoe_deadsecs, "After aoe_deadsecs seconds, give up and fail dev.");
Linus Torvalds1da177e2005-04-16 15:20:36 -070022
Ed L. Cashin7df620d2008-02-08 04:20:07 -080023static int aoe_maxout = 16;
24module_param(aoe_maxout, int, 0644);
25MODULE_PARM_DESC(aoe_maxout,
26 "Only aoe_maxout outstanding packets for every MAC on eX.Y.");
27
Ed L. Cashin68e0d422008-02-08 04:20:00 -080028static struct sk_buff *
Ed L. Cashine407a7f2006-09-20 14:36:49 -040029new_skb(ulong len)
Linus Torvalds1da177e2005-04-16 15:20:36 -070030{
31 struct sk_buff *skb;
32
33 skb = alloc_skb(len, GFP_ATOMIC);
34 if (skb) {
Arnaldo Carvalho de Melo459a98e2007-03-19 15:30:44 -070035 skb_reset_mac_header(skb);
Arnaldo Carvalho de Meloc1d2bbe2007-04-10 20:45:18 -070036 skb_reset_network_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -070037 skb->protocol = __constant_htons(ETH_P_AOE);
Ed Cashin8babe8c2012-09-19 15:46:39 +000038 skb_checksum_none_assert(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -070039 }
40 return skb;
41}
42
Linus Torvalds1da177e2005-04-16 15:20:36 -070043static struct frame *
Ed L. Cashin68e0d422008-02-08 04:20:00 -080044getframe(struct aoetgt *t, int tag)
Linus Torvalds1da177e2005-04-16 15:20:36 -070045{
46 struct frame *f, *e;
47
Ed L. Cashin68e0d422008-02-08 04:20:00 -080048 f = t->frames;
49 e = f + t->nframes;
Linus Torvalds1da177e2005-04-16 15:20:36 -070050 for (; f<e; f++)
51 if (f->tag == tag)
52 return f;
53 return NULL;
54}
55
56/*
57 * Leave the top bit clear so we have tagspace for userland.
58 * The bottom 16 bits are the xmit tick for rexmit/rttavg processing.
59 * This driver reserves tag -1 to mean "unused frame."
60 */
61static int
Ed L. Cashin68e0d422008-02-08 04:20:00 -080062newtag(struct aoetgt *t)
Linus Torvalds1da177e2005-04-16 15:20:36 -070063{
64 register ulong n;
65
66 n = jiffies & 0xffff;
Ed L. Cashin68e0d422008-02-08 04:20:00 -080067 return n |= (++t->lasttag & 0x7fff) << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -070068}
69
70static int
Ed L. Cashin68e0d422008-02-08 04:20:00 -080071aoehdr_atainit(struct aoedev *d, struct aoetgt *t, struct aoe_hdr *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -070072{
Ed L. Cashin68e0d422008-02-08 04:20:00 -080073 u32 host_tag = newtag(t);
Linus Torvalds1da177e2005-04-16 15:20:36 -070074
Ed L. Cashin68e0d422008-02-08 04:20:00 -080075 memcpy(h->src, t->ifp->nd->dev_addr, sizeof h->src);
76 memcpy(h->dst, t->addr, sizeof h->dst);
ecashin@coraid.com63e9cc52005-04-18 22:00:20 -070077 h->type = __constant_cpu_to_be16(ETH_P_AOE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070078 h->verfl = AOE_HVER;
ecashin@coraid.com63e9cc52005-04-18 22:00:20 -070079 h->major = cpu_to_be16(d->aoemajor);
Linus Torvalds1da177e2005-04-16 15:20:36 -070080 h->minor = d->aoeminor;
81 h->cmd = AOECMD_ATA;
ecashin@coraid.com63e9cc52005-04-18 22:00:20 -070082 h->tag = cpu_to_be32(host_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -070083
84 return host_tag;
85}
86
Ed L. Cashin19bf2632006-09-20 14:36:49 -040087static inline void
88put_lba(struct aoe_atahdr *ah, sector_t lba)
89{
90 ah->lba0 = lba;
91 ah->lba1 = lba >>= 8;
92 ah->lba2 = lba >>= 8;
93 ah->lba3 = lba >>= 8;
94 ah->lba4 = lba >>= 8;
95 ah->lba5 = lba >>= 8;
96}
97
Linus Torvalds1da177e2005-04-16 15:20:36 -070098static void
Ed L. Cashin68e0d422008-02-08 04:20:00 -080099ifrotate(struct aoetgt *t)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100{
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800101 t->ifp++;
102 if (t->ifp >= &t->ifs[NAOEIFS] || t->ifp->nd == NULL)
103 t->ifp = t->ifs;
104 if (t->ifp->nd == NULL) {
105 printk(KERN_INFO "aoe: no interface to rotate to\n");
106 BUG();
107 }
108}
109
Ed L. Cashin9bb237b2008-02-08 04:20:05 -0800110static void
111skb_pool_put(struct aoedev *d, struct sk_buff *skb)
112{
David S. Millere9bb8fb02008-09-21 22:36:49 -0700113 __skb_queue_tail(&d->skbpool, skb);
Ed L. Cashin9bb237b2008-02-08 04:20:05 -0800114}
115
116static struct sk_buff *
117skb_pool_get(struct aoedev *d)
118{
David S. Millere9bb8fb02008-09-21 22:36:49 -0700119 struct sk_buff *skb = skb_peek(&d->skbpool);
Ed L. Cashin9bb237b2008-02-08 04:20:05 -0800120
Ed L. Cashin9bb237b2008-02-08 04:20:05 -0800121 if (skb && atomic_read(&skb_shinfo(skb)->dataref) == 1) {
David S. Millere9bb8fb02008-09-21 22:36:49 -0700122 __skb_unlink(skb, &d->skbpool);
Ed L. Cashin9bb237b2008-02-08 04:20:05 -0800123 return skb;
124 }
David S. Millere9bb8fb02008-09-21 22:36:49 -0700125 if (skb_queue_len(&d->skbpool) < NSKBPOOLMAX &&
126 (skb = new_skb(ETH_ZLEN)))
Ed L. Cashin9bb237b2008-02-08 04:20:05 -0800127 return skb;
David S. Millere9bb8fb02008-09-21 22:36:49 -0700128
Ed L. Cashin9bb237b2008-02-08 04:20:05 -0800129 return NULL;
130}
131
132/* freeframe is where we do our load balancing so it's a little hairy. */
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800133static struct frame *
134freeframe(struct aoedev *d)
135{
Ed L. Cashin9bb237b2008-02-08 04:20:05 -0800136 struct frame *f, *e, *rf;
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800137 struct aoetgt **t;
Ed L. Cashin9bb237b2008-02-08 04:20:05 -0800138 struct sk_buff *skb;
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800139
140 if (d->targets[0] == NULL) { /* shouldn't happen, but I'm paranoid */
141 printk(KERN_ERR "aoe: NULL TARGETS!\n");
142 return NULL;
143 }
Ed L. Cashin9bb237b2008-02-08 04:20:05 -0800144 t = d->tgt;
145 t++;
146 if (t >= &d->targets[NTARGETS] || !*t)
147 t = d->targets;
148 for (;;) {
149 if ((*t)->nout < (*t)->maxout
150 && t != d->htgt
151 && (*t)->ifp->nd) {
152 rf = NULL;
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800153 f = (*t)->frames;
Ed L. Cashin9bb237b2008-02-08 04:20:05 -0800154 e = f + (*t)->nframes;
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800155 for (; f < e; f++) {
156 if (f->tag != FREETAG)
157 continue;
Ed L. Cashin9bb237b2008-02-08 04:20:05 -0800158 skb = f->skb;
159 if (!skb
160 && !(f->skb = skb = new_skb(ETH_ZLEN)))
161 continue;
162 if (atomic_read(&skb_shinfo(skb)->dataref)
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800163 != 1) {
Ed L. Cashin9bb237b2008-02-08 04:20:05 -0800164 if (!rf)
165 rf = f;
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800166 continue;
167 }
Ed Cashin3d5b0602012-10-04 17:16:20 -0700168gotone: skb->truesize -= skb->data_len;
169 skb_shinfo(skb)->nr_frags = skb->data_len = 0;
Ed L. Cashin9bb237b2008-02-08 04:20:05 -0800170 skb_trim(skb, 0);
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800171 d->tgt = t;
172 ifrotate(*t);
173 return f;
174 }
Ed L. Cashin9bb237b2008-02-08 04:20:05 -0800175 /* Work can be done, but the network layer is
176 holding our precious packets. Try to grab
177 one from the pool. */
178 f = rf;
179 if (f == NULL) { /* more paranoia */
180 printk(KERN_ERR
181 "aoe: freeframe: %s.\n",
182 "unexpected null rf");
183 d->flags |= DEVFL_KICKME;
184 return NULL;
185 }
186 skb = skb_pool_get(d);
187 if (skb) {
188 skb_pool_put(d, f->skb);
189 f->skb = skb;
190 goto gotone;
191 }
192 (*t)->dataref++;
193 if ((*t)->nout == 0)
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800194 d->flags |= DEVFL_KICKME;
195 }
Ed L. Cashin9bb237b2008-02-08 04:20:05 -0800196 if (t == d->tgt) /* we've looped and found nada */
197 break;
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800198 t++;
Ed L. Cashin9bb237b2008-02-08 04:20:05 -0800199 if (t >= &d->targets[NTARGETS] || !*t)
200 t = d->targets;
201 }
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800202 return NULL;
203}
204
Ed Cashin3d5b0602012-10-04 17:16:20 -0700205static void
206skb_fillup(struct sk_buff *skb, struct bio_vec *bv, ulong off, ulong cnt)
207{
208 int frag = 0;
209 ulong fcnt;
210loop:
211 fcnt = bv->bv_len - (off - bv->bv_offset);
212 if (fcnt > cnt)
213 fcnt = cnt;
214 skb_fill_page_desc(skb, frag++, bv->bv_page, off, fcnt);
215 cnt -= fcnt;
216 if (cnt <= 0)
217 return;
218 bv++;
219 off = bv->bv_offset;
220 goto loop;
221}
222
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800223static int
224aoecmd_ata_rw(struct aoedev *d)
225{
226 struct frame *f;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 struct aoe_hdr *h;
228 struct aoe_atahdr *ah;
229 struct buf *buf;
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800230 struct bio_vec *bv;
231 struct aoetgt *t;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232 struct sk_buff *skb;
Ed Cashin3d5b0602012-10-04 17:16:20 -0700233 ulong bcnt, fbcnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 char writebit, extbit;
235
236 writebit = 0x10;
237 extbit = 0x4;
238
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800239 f = freeframe(d);
240 if (f == NULL)
241 return 0;
242 t = *d->tgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243 buf = d->inprocess;
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800244 bv = buf->bv;
245 bcnt = t->ifp->maxbcnt;
246 if (bcnt == 0)
247 bcnt = DEFAULTBCNT;
Ed Cashin3d5b0602012-10-04 17:16:20 -0700248 if (bcnt > buf->resid)
249 bcnt = buf->resid;
250 fbcnt = bcnt;
251 f->bv = buf->bv;
252 f->bv_off = f->bv->bv_offset + (f->bv->bv_len - buf->bv_resid);
253 do {
254 if (fbcnt < buf->bv_resid) {
255 buf->bv_resid -= fbcnt;
256 buf->resid -= fbcnt;
257 break;
258 }
259 fbcnt -= buf->bv_resid;
260 buf->resid -= buf->bv_resid;
261 if (buf->resid == 0) {
262 d->inprocess = NULL;
263 break;
264 }
265 buf->bv++;
266 buf->bv_resid = buf->bv->bv_len;
267 WARN_ON(buf->bv_resid == 0);
268 } while (fbcnt);
269
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 /* initialize the headers & frame */
Ed L. Cashine407a7f2006-09-20 14:36:49 -0400271 skb = f->skb;
Ed L. Cashinabdbf942007-10-16 23:27:03 -0700272 h = (struct aoe_hdr *) skb_mac_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 ah = (struct aoe_atahdr *) (h+1);
Ed L. Cashin19900cd2006-12-22 01:09:21 -0800274 skb_put(skb, sizeof *h + sizeof *ah);
275 memset(h, 0, skb->len);
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800276 f->tag = aoehdr_atainit(d, t, h);
277 t->nout++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 f->waited = 0;
279 f->buf = buf;
Ed L. Cashin19bf2632006-09-20 14:36:49 -0400280 f->bcnt = bcnt;
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800281 f->lba = buf->sector;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282
283 /* set up ata header */
284 ah->scnt = bcnt >> 9;
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800285 put_lba(ah, buf->sector);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 if (d->flags & DEVFL_EXT) {
287 ah->aflags |= AOEAFL_EXT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 } else {
289 extbit = 0;
290 ah->lba3 &= 0x0f;
291 ah->lba3 |= 0xe0; /* LBA bit + obsolete 0xa0 */
292 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 if (bio_data_dir(buf->bio) == WRITE) {
Ed Cashin3d5b0602012-10-04 17:16:20 -0700294 skb_fillup(skb, f->bv, f->bv_off, bcnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 ah->aflags |= AOEAFL_WRITE;
Ed L. Cashin4f51dc52006-09-20 14:36:49 -0400296 skb->len += bcnt;
297 skb->data_len = bcnt;
Ed Cashin3d5b0602012-10-04 17:16:20 -0700298 skb->truesize += bcnt;
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800299 t->wpkts++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 } else {
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800301 t->rpkts++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 writebit = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303 }
304
Bartlomiej Zolnierkiewicz04b3ab52009-04-01 21:42:24 +0200305 ah->cmdstat = ATA_CMD_PIO_READ | writebit | extbit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306
307 /* mark all tracking fields and load out */
308 buf->nframesout += 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 buf->sector += bcnt >> 9;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800311 skb->dev = t->ifp->nd;
Ed L. Cashin4f51dc52006-09-20 14:36:49 -0400312 skb = skb_clone(skb, GFP_ATOMIC);
David S. Millere9bb8fb02008-09-21 22:36:49 -0700313 if (skb)
314 __skb_queue_tail(&d->sendq, skb);
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800315 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316}
317
Ed L. Cashin3ae1c242006-01-19 13:46:19 -0500318/* some callers cannot sleep, and they can call this function,
319 * transmitting the packets later, when interrupts are on
320 */
David S. Millere9bb8fb02008-09-21 22:36:49 -0700321static void
322aoecmd_cfg_pkts(ushort aoemajor, unsigned char aoeminor, struct sk_buff_head *queue)
Ed L. Cashin3ae1c242006-01-19 13:46:19 -0500323{
324 struct aoe_hdr *h;
325 struct aoe_cfghdr *ch;
David S. Millere9bb8fb02008-09-21 22:36:49 -0700326 struct sk_buff *skb;
Ed L. Cashin3ae1c242006-01-19 13:46:19 -0500327 struct net_device *ifp;
328
Eric Dumazet840a1852010-10-29 01:15:29 +0000329 rcu_read_lock();
330 for_each_netdev_rcu(&init_net, ifp) {
Ed L. Cashin3ae1c242006-01-19 13:46:19 -0500331 dev_hold(ifp);
332 if (!is_aoe_netif(ifp))
Pavel Emelianov7562f872007-05-03 15:13:45 -0700333 goto cont;
Ed L. Cashin3ae1c242006-01-19 13:46:19 -0500334
Ed L. Cashine407a7f2006-09-20 14:36:49 -0400335 skb = new_skb(sizeof *h + sizeof *ch);
Ed L. Cashin3ae1c242006-01-19 13:46:19 -0500336 if (skb == NULL) {
Ed L. Cashina12c93f2006-09-20 14:36:51 -0400337 printk(KERN_INFO "aoe: skb alloc failure\n");
Pavel Emelianov7562f872007-05-03 15:13:45 -0700338 goto cont;
Ed L. Cashin3ae1c242006-01-19 13:46:19 -0500339 }
Ed L. Cashin19900cd2006-12-22 01:09:21 -0800340 skb_put(skb, sizeof *h + sizeof *ch);
Ed L. Cashine407a7f2006-09-20 14:36:49 -0400341 skb->dev = ifp;
David S. Millere9bb8fb02008-09-21 22:36:49 -0700342 __skb_queue_tail(queue, skb);
Ed L. Cashinabdbf942007-10-16 23:27:03 -0700343 h = (struct aoe_hdr *) skb_mac_header(skb);
Ed L. Cashin3ae1c242006-01-19 13:46:19 -0500344 memset(h, 0, sizeof *h + sizeof *ch);
345
346 memset(h->dst, 0xff, sizeof h->dst);
347 memcpy(h->src, ifp->dev_addr, sizeof h->src);
348 h->type = __constant_cpu_to_be16(ETH_P_AOE);
349 h->verfl = AOE_HVER;
350 h->major = cpu_to_be16(aoemajor);
351 h->minor = aoeminor;
352 h->cmd = AOECMD_CFG;
353
Pavel Emelianov7562f872007-05-03 15:13:45 -0700354cont:
355 dev_put(ifp);
Ed L. Cashin3ae1c242006-01-19 13:46:19 -0500356 }
Eric Dumazet840a1852010-10-29 01:15:29 +0000357 rcu_read_unlock();
Ed L. Cashin3ae1c242006-01-19 13:46:19 -0500358}
359
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360static void
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800361resend(struct aoedev *d, struct aoetgt *t, struct frame *f)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362{
363 struct sk_buff *skb;
364 struct aoe_hdr *h;
Ed L. Cashin19bf2632006-09-20 14:36:49 -0400365 struct aoe_atahdr *ah;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 char buf[128];
367 u32 n;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800369 ifrotate(t);
370 n = newtag(t);
Ed L. Cashine407a7f2006-09-20 14:36:49 -0400371 skb = f->skb;
Ed L. Cashinabdbf942007-10-16 23:27:03 -0700372 h = (struct aoe_hdr *) skb_mac_header(skb);
Ed L. Cashin19bf2632006-09-20 14:36:49 -0400373 ah = (struct aoe_atahdr *) (h+1);
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800374
375 snprintf(buf, sizeof buf,
Harvey Harrison411c41e2008-11-25 00:40:37 -0800376 "%15s e%ld.%d oldtag=%08x@%08lx newtag=%08x s=%pm d=%pm nout=%d\n",
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800377 "retransmit", d->aoemajor, d->aoeminor, f->tag, jiffies, n,
Harvey Harrison411c41e2008-11-25 00:40:37 -0800378 h->src, h->dst, t->nout);
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800379 aoechr_error(buf);
380
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 f->tag = n;
ecashin@coraid.com63e9cc52005-04-18 22:00:20 -0700382 h->tag = cpu_to_be32(n);
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800383 memcpy(h->dst, t->addr, sizeof h->dst);
384 memcpy(h->src, t->ifp->nd->dev_addr, sizeof h->src);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800386 switch (ah->cmdstat) {
387 default:
388 break;
Bartlomiej Zolnierkiewicz04b3ab52009-04-01 21:42:24 +0200389 case ATA_CMD_PIO_READ:
390 case ATA_CMD_PIO_READ_EXT:
391 case ATA_CMD_PIO_WRITE:
392 case ATA_CMD_PIO_WRITE_EXT:
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800393 put_lba(ah, f->lba);
394
395 n = f->bcnt;
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800396 ah->scnt = n >> 9;
Ed L. Cashin4f51dc52006-09-20 14:36:49 -0400397 if (ah->aflags & AOEAFL_WRITE) {
Ed Cashin3d5b0602012-10-04 17:16:20 -0700398 skb_fillup(skb, f->bv, f->bv_off, n);
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800399 skb->len = sizeof *h + sizeof *ah + n;
400 skb->data_len = n;
Ed Cashin3d5b0602012-10-04 17:16:20 -0700401 skb->truesize += n;
Ed L. Cashin19bf2632006-09-20 14:36:49 -0400402 }
403 }
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800404 skb->dev = t->ifp->nd;
Ed L. Cashin4f51dc52006-09-20 14:36:49 -0400405 skb = skb_clone(skb, GFP_ATOMIC);
406 if (skb == NULL)
407 return;
David S. Millere9bb8fb02008-09-21 22:36:49 -0700408 __skb_queue_tail(&d->sendq, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409}
410
411static int
412tsince(int tag)
413{
414 int n;
415
416 n = jiffies & 0xffff;
417 n -= tag & 0xffff;
418 if (n < 0)
419 n += 1<<16;
420 return n;
421}
422
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800423static struct aoeif *
424getif(struct aoetgt *t, struct net_device *nd)
425{
426 struct aoeif *p, *e;
427
428 p = t->ifs;
429 e = p + NAOEIFS;
430 for (; p < e; p++)
431 if (p->nd == nd)
432 return p;
433 return NULL;
434}
435
436static struct aoeif *
437addif(struct aoetgt *t, struct net_device *nd)
438{
439 struct aoeif *p;
440
441 p = getif(t, NULL);
442 if (!p)
443 return NULL;
444 p->nd = nd;
445 p->maxbcnt = DEFAULTBCNT;
446 p->lost = 0;
447 p->lostjumbo = 0;
448 return p;
449}
450
451static void
452ejectif(struct aoetgt *t, struct aoeif *ifp)
453{
454 struct aoeif *e;
455 ulong n;
456
457 e = t->ifs + NAOEIFS - 1;
458 n = (e - ifp) * sizeof *ifp;
459 memmove(ifp, ifp+1, n);
460 e->nd = NULL;
461}
462
463static int
464sthtith(struct aoedev *d)
465{
466 struct frame *f, *e, *nf;
467 struct sk_buff *skb;
468 struct aoetgt *ht = *d->htgt;
469
470 f = ht->frames;
471 e = f + ht->nframes;
472 for (; f < e; f++) {
473 if (f->tag == FREETAG)
474 continue;
475 nf = freeframe(d);
476 if (!nf)
477 return 0;
478 skb = nf->skb;
479 *nf = *f;
480 f->skb = skb;
481 f->tag = FREETAG;
482 nf->waited = 0;
483 ht->nout--;
484 (*d->tgt)->nout++;
485 resend(d, *d->tgt, nf);
486 }
487 /* he's clean, he's useless. take away his interfaces */
488 memset(ht->ifs, 0, sizeof ht->ifs);
489 d->htgt = NULL;
490 return 1;
491}
492
493static inline unsigned char
494ata_scnt(unsigned char *packet) {
495 struct aoe_hdr *h;
496 struct aoe_atahdr *ah;
497
498 h = (struct aoe_hdr *) packet;
499 ah = (struct aoe_atahdr *) (h+1);
500 return ah->scnt;
501}
502
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503static void
504rexmit_timer(ulong vp)
505{
David S. Millere9bb8fb02008-09-21 22:36:49 -0700506 struct sk_buff_head queue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 struct aoedev *d;
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800508 struct aoetgt *t, **tt, **te;
509 struct aoeif *ifp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 struct frame *f, *e;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511 register long timeout;
512 ulong flags, n;
513
514 d = (struct aoedev *) vp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515
516 /* timeout is always ~150% of the moving average */
517 timeout = d->rttavg;
518 timeout += timeout >> 1;
519
520 spin_lock_irqsave(&d->lock, flags);
521
522 if (d->flags & DEVFL_TKILL) {
Ed L. Cashin1c6f3fc2006-01-25 13:54:44 -0500523 spin_unlock_irqrestore(&d->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 return;
525 }
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800526 tt = d->targets;
527 te = tt + NTARGETS;
528 for (; tt < te && *tt; tt++) {
529 t = *tt;
530 f = t->frames;
531 e = f + t->nframes;
532 for (; f < e; f++) {
533 if (f->tag == FREETAG
534 || tsince(f->tag) < timeout)
535 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 n = f->waited += timeout;
537 n /= HZ;
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800538 if (n > aoe_deadsecs) {
539 /* waited too long. device failure. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 aoedev_downdev(d);
Ed L. Cashin1c6f3fc2006-01-25 13:54:44 -0500541 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 }
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800543
544 if (n > HELPWAIT /* see if another target can help */
545 && (tt != d->targets || d->targets[1]))
546 d->htgt = tt;
547
548 if (t->nout == t->maxout) {
549 if (t->maxout > 1)
550 t->maxout--;
551 t->lastwadj = jiffies;
552 }
553
554 ifp = getif(t, f->skb->dev);
555 if (ifp && ++ifp->lost > (t->nframes << 1)
556 && (ifp != t->ifs || t->ifs[1].nd)) {
557 ejectif(t, ifp);
558 ifp = NULL;
559 }
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800560 resend(d, t, f);
561 }
562
563 /* window check */
564 if (t->nout == t->maxout
565 && t->maxout < t->nframes
566 && (jiffies - t->lastwadj)/HZ > 10) {
567 t->maxout++;
568 t->lastwadj = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 }
570 }
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800571
David S. Millere9bb8fb02008-09-21 22:36:49 -0700572 if (!skb_queue_empty(&d->sendq)) {
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800573 n = d->rttavg <<= 1;
574 if (n > MAXTIMER)
575 d->rttavg = MAXTIMER;
576 }
577
578 if (d->flags & DEVFL_KICKME || d->htgt) {
Ed L. Cashin4f51dc52006-09-20 14:36:49 -0400579 d->flags &= ~DEVFL_KICKME;
580 aoecmd_work(d);
581 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582
David S. Millere9bb8fb02008-09-21 22:36:49 -0700583 __skb_queue_head_init(&queue);
584 skb_queue_splice_init(&d->sendq, &queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585
586 d->timer.expires = jiffies + TIMERTICK;
587 add_timer(&d->timer);
588
589 spin_unlock_irqrestore(&d->lock, flags);
590
David S. Millere9bb8fb02008-09-21 22:36:49 -0700591 aoenet_xmit(&queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592}
593
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800594/* enters with d->lock held */
595void
596aoecmd_work(struct aoedev *d)
597{
598 struct buf *buf;
599loop:
600 if (d->htgt && !sthtith(d))
601 return;
602 if (d->inprocess == NULL) {
603 if (list_empty(&d->bufq))
604 return;
605 buf = container_of(d->bufq.next, struct buf, bufs);
606 list_del(d->bufq.next);
607 d->inprocess = buf;
608 }
609 if (aoecmd_ata_rw(d))
610 goto loop;
611}
612
Ed L. Cashin3ae1c242006-01-19 13:46:19 -0500613/* this function performs work that has been deferred until sleeping is OK
614 */
615void
David Howellsc4028952006-11-22 14:57:56 +0000616aoecmd_sleepwork(struct work_struct *work)
Ed L. Cashin3ae1c242006-01-19 13:46:19 -0500617{
David Howellsc4028952006-11-22 14:57:56 +0000618 struct aoedev *d = container_of(work, struct aoedev, work);
Ed L. Cashin3ae1c242006-01-19 13:46:19 -0500619
620 if (d->flags & DEVFL_GDALLOC)
621 aoeblk_gdalloc(d);
622
623 if (d->flags & DEVFL_NEWSIZE) {
624 struct block_device *bd;
625 unsigned long flags;
626 u64 ssize;
627
Tejun Heo80795ae2008-08-25 19:56:07 +0900628 ssize = get_capacity(d->gd);
Ed L. Cashin3ae1c242006-01-19 13:46:19 -0500629 bd = bdget_disk(d->gd, 0);
630
631 if (bd) {
632 mutex_lock(&bd->bd_inode->i_mutex);
633 i_size_write(bd->bd_inode, (loff_t)ssize<<9);
634 mutex_unlock(&bd->bd_inode->i_mutex);
635 bdput(bd);
636 }
637 spin_lock_irqsave(&d->lock, flags);
638 d->flags |= DEVFL_UP;
639 d->flags &= ~DEVFL_NEWSIZE;
640 spin_unlock_irqrestore(&d->lock, flags);
641 }
642}
643
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644static void
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800645ataid_complete(struct aoedev *d, struct aoetgt *t, unsigned char *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646{
647 u64 ssize;
648 u16 n;
649
650 /* word 83: command set supported */
Harvey Harrisonf885f8d2008-04-29 01:03:30 -0700651 n = get_unaligned_le16(&id[83 << 1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652
653 /* word 86: command set/feature enabled */
Harvey Harrisonf885f8d2008-04-29 01:03:30 -0700654 n |= get_unaligned_le16(&id[86 << 1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655
656 if (n & (1<<10)) { /* bit 10: LBA 48 */
657 d->flags |= DEVFL_EXT;
658
659 /* word 100: number lba48 sectors */
Harvey Harrisonf885f8d2008-04-29 01:03:30 -0700660 ssize = get_unaligned_le64(&id[100 << 1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661
662 /* set as in ide-disk.c:init_idedisk_capacity */
663 d->geo.cylinders = ssize;
664 d->geo.cylinders /= (255 * 63);
665 d->geo.heads = 255;
666 d->geo.sectors = 63;
667 } else {
668 d->flags &= ~DEVFL_EXT;
669
670 /* number lba28 sectors */
Harvey Harrisonf885f8d2008-04-29 01:03:30 -0700671 ssize = get_unaligned_le32(&id[60 << 1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672
673 /* NOTE: obsolete in ATA 6 */
Harvey Harrisonf885f8d2008-04-29 01:03:30 -0700674 d->geo.cylinders = get_unaligned_le16(&id[54 << 1]);
675 d->geo.heads = get_unaligned_le16(&id[55 << 1]);
676 d->geo.sectors = get_unaligned_le16(&id[56 << 1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 }
Ed L. Cashin3ae1c242006-01-19 13:46:19 -0500678
679 if (d->ssize != ssize)
Ed L. Cashin1d759812008-02-08 04:20:08 -0800680 printk(KERN_INFO
Harvey Harrison411c41e2008-11-25 00:40:37 -0800681 "aoe: %pm e%ld.%d v%04x has %llu sectors\n",
682 t->addr,
Ed L. Cashin3ae1c242006-01-19 13:46:19 -0500683 d->aoemajor, d->aoeminor,
684 d->fw_ver, (long long)ssize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 d->ssize = ssize;
686 d->geo.start = 0;
Ed L. Cashin6b9699b2008-02-08 04:20:06 -0800687 if (d->flags & (DEVFL_GDALLOC|DEVFL_NEWSIZE))
688 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 if (d->gd != NULL) {
Tejun Heo80795ae2008-08-25 19:56:07 +0900690 set_capacity(d->gd, ssize);
Ed L. Cashin3ae1c242006-01-19 13:46:19 -0500691 d->flags |= DEVFL_NEWSIZE;
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800692 } else
Ed L. Cashin3ae1c242006-01-19 13:46:19 -0500693 d->flags |= DEVFL_GDALLOC;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 schedule_work(&d->work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695}
696
697static void
698calc_rttavg(struct aoedev *d, int rtt)
699{
700 register long n;
701
702 n = rtt;
Ed L. Cashindced3a02006-09-20 14:36:49 -0400703 if (n < 0) {
704 n = -rtt;
705 if (n < MINTIMER)
706 n = MINTIMER;
707 else if (n > MAXTIMER)
708 n = MAXTIMER;
709 d->mintimer += (n - d->mintimer) >> 1;
710 } else if (n < d->mintimer)
711 n = d->mintimer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 else if (n > MAXTIMER)
713 n = MAXTIMER;
714
715 /* g == .25; cf. Congestion Avoidance and Control, Jacobson & Karels; 1988 */
716 n -= d->rttavg;
717 d->rttavg += n >> 2;
718}
719
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800720static struct aoetgt *
721gettgt(struct aoedev *d, char *addr)
722{
723 struct aoetgt **t, **e;
724
725 t = d->targets;
726 e = t + NTARGETS;
727 for (; t < e && *t; t++)
728 if (memcmp((*t)->addr, addr, sizeof((*t)->addr)) == 0)
729 return *t;
730 return NULL;
731}
732
733static inline void
Linus Torvalds03054de2008-02-08 09:42:46 -0800734diskstats(struct gendisk *disk, struct bio *bio, ulong duration, sector_t sector)
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800735{
736 unsigned long n_sect = bio->bi_size >> 9;
737 const int rw = bio_data_dir(bio);
Jens Axboe28f13702008-05-07 10:15:46 +0200738 struct hd_struct *part;
Tejun Heoc9959052008-08-25 19:47:21 +0900739 int cpu;
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800740
Tejun Heo074a7ac2008-08-25 19:56:14 +0900741 cpu = part_stat_lock();
Tejun Heoe71bf0d2008-09-03 09:03:02 +0200742 part = disk_map_sector_rcu(disk, sector);
Tejun Heoe71bf0d2008-09-03 09:03:02 +0200743
Tejun Heo074a7ac2008-08-25 19:56:14 +0900744 part_stat_inc(cpu, part, ios[rw]);
745 part_stat_add(cpu, part, ticks[rw], duration);
746 part_stat_add(cpu, part, sectors[rw], n_sect);
747 part_stat_add(cpu, part, io_ticks, duration);
Tejun Heoc9959052008-08-25 19:47:21 +0900748
Tejun Heo074a7ac2008-08-25 19:56:14 +0900749 part_stat_unlock();
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800750}
751
Ed Cashin3d5b0602012-10-04 17:16:20 -0700752static void
753bvcpy(struct bio_vec *bv, ulong off, struct sk_buff *skb, ulong cnt)
754{
755 ulong fcnt;
756 char *p;
757 int soff = 0;
758loop:
759 fcnt = bv->bv_len - (off - bv->bv_offset);
760 if (fcnt > cnt)
761 fcnt = cnt;
762 p = page_address(bv->bv_page) + off;
763 skb_copy_bits(skb, soff, p, fcnt);
764 soff += fcnt;
765 cnt -= fcnt;
766 if (cnt <= 0)
767 return;
768 bv++;
769 off = bv->bv_offset;
770 goto loop;
771}
772
773static void
774fadvance(struct frame *f, ulong cnt)
775{
776 ulong fcnt;
777
778 f->lba += cnt >> 9;
779loop:
780 fcnt = f->bv->bv_len - (f->bv_off - f->bv->bv_offset);
781 if (fcnt > cnt) {
782 f->bv_off += cnt;
783 return;
784 }
785 cnt -= fcnt;
786 f->bv++;
787 f->bv_off = f->bv->bv_offset;
788 goto loop;
789}
790
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791void
792aoecmd_ata_rsp(struct sk_buff *skb)
793{
David S. Millere9bb8fb02008-09-21 22:36:49 -0700794 struct sk_buff_head queue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 struct aoedev *d;
Ed L. Cashinddec63e2006-09-20 14:36:49 -0400796 struct aoe_hdr *hin, *hout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 struct aoe_atahdr *ahin, *ahout;
798 struct frame *f;
799 struct buf *buf;
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800800 struct aoetgt *t;
801 struct aoeif *ifp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 register long n;
803 ulong flags;
804 char ebuf[128];
ecashin@coraid.com32465c62005-04-18 22:00:18 -0700805 u16 aoemajor;
806
Ed L. Cashinabdbf942007-10-16 23:27:03 -0700807 hin = (struct aoe_hdr *) skb_mac_header(skb);
Ed Cashin3d5b0602012-10-04 17:16:20 -0700808 skb_pull(skb, sizeof(*hin));
Harvey Harrisonf885f8d2008-04-29 01:03:30 -0700809 aoemajor = get_unaligned_be16(&hin->major);
ecashin@coraid.com32465c62005-04-18 22:00:18 -0700810 d = aoedev_by_aoeaddr(aoemajor, hin->minor);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 if (d == NULL) {
812 snprintf(ebuf, sizeof ebuf, "aoecmd_ata_rsp: ata response "
813 "for unknown device %d.%d\n",
ecashin@coraid.com32465c62005-04-18 22:00:18 -0700814 aoemajor, hin->minor);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 aoechr_error(ebuf);
816 return;
817 }
818
819 spin_lock_irqsave(&d->lock, flags);
820
Harvey Harrisonf885f8d2008-04-29 01:03:30 -0700821 n = get_unaligned_be32(&hin->tag);
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800822 t = gettgt(d, hin->src);
823 if (t == NULL) {
Harvey Harrison411c41e2008-11-25 00:40:37 -0800824 printk(KERN_INFO "aoe: can't find target e%ld.%d:%pm\n",
825 d->aoemajor, d->aoeminor, hin->src);
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800826 spin_unlock_irqrestore(&d->lock, flags);
827 return;
828 }
829 f = getframe(t, n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 if (f == NULL) {
Ed L. Cashindced3a02006-09-20 14:36:49 -0400831 calc_rttavg(d, -tsince(n));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 spin_unlock_irqrestore(&d->lock, flags);
833 snprintf(ebuf, sizeof ebuf,
834 "%15s e%d.%d tag=%08x@%08lx\n",
835 "unexpected rsp",
Harvey Harrisonf885f8d2008-04-29 01:03:30 -0700836 get_unaligned_be16(&hin->major),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 hin->minor,
Harvey Harrisonf885f8d2008-04-29 01:03:30 -0700838 get_unaligned_be32(&hin->tag),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 jiffies);
840 aoechr_error(ebuf);
841 return;
842 }
843
844 calc_rttavg(d, tsince(f->tag));
845
Ed Cashin3d5b0602012-10-04 17:16:20 -0700846 ahin = (struct aoe_atahdr *) skb->data;
847 skb_pull(skb, sizeof(*ahin));
Ed L. Cashinabdbf942007-10-16 23:27:03 -0700848 hout = (struct aoe_hdr *) skb_mac_header(f->skb);
Ed L. Cashinddec63e2006-09-20 14:36:49 -0400849 ahout = (struct aoe_atahdr *) (hout+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 buf = f->buf;
851
852 if (ahin->cmdstat & 0xa9) { /* these bits cleared on success */
Ed L. Cashina12c93f2006-09-20 14:36:51 -0400853 printk(KERN_ERR
Ed L. Cashin1d759812008-02-08 04:20:08 -0800854 "aoe: ata error cmd=%2.2Xh stat=%2.2Xh from e%ld.%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 ahout->cmdstat, ahin->cmdstat,
856 d->aoemajor, d->aoeminor);
857 if (buf)
858 buf->flags |= BUFFL_FAIL;
859 } else {
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800860 if (d->htgt && t == *d->htgt) /* I'll help myself, thank you. */
861 d->htgt = NULL;
Ed L. Cashin19bf2632006-09-20 14:36:49 -0400862 n = ahout->scnt << 9;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 switch (ahout->cmdstat) {
Bartlomiej Zolnierkiewicz04b3ab52009-04-01 21:42:24 +0200864 case ATA_CMD_PIO_READ:
865 case ATA_CMD_PIO_READ_EXT:
Ed Cashin3d5b0602012-10-04 17:16:20 -0700866 if (skb->len < n) {
Ed L. Cashina12c93f2006-09-20 14:36:51 -0400867 printk(KERN_ERR
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800868 "aoe: %s. skb->len=%d need=%ld\n",
869 "runt data size in read", skb->len, n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 /* fail frame f? just returning will rexmit. */
871 spin_unlock_irqrestore(&d->lock, flags);
872 return;
873 }
Ed Cashin3d5b0602012-10-04 17:16:20 -0700874 bvcpy(f->bv, f->bv_off, skb, n);
Bartlomiej Zolnierkiewicz04b3ab52009-04-01 21:42:24 +0200875 case ATA_CMD_PIO_WRITE:
876 case ATA_CMD_PIO_WRITE_EXT:
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800877 ifp = getif(t, skb->dev);
878 if (ifp) {
879 ifp->lost = 0;
Ed L. Cashin6bb6285f2006-09-20 14:36:49 -0400880 if (n > DEFAULTBCNT)
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800881 ifp->lostjumbo = 0;
Ed L. Cashin19bf2632006-09-20 14:36:49 -0400882 }
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800883 if (f->bcnt -= n) {
Ed Cashin3d5b0602012-10-04 17:16:20 -0700884 fadvance(f, n);
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800885 resend(d, t, f);
886 goto xmit;
887 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 break;
Bartlomiej Zolnierkiewicz04b3ab52009-04-01 21:42:24 +0200889 case ATA_CMD_ID_ATA:
Ed Cashin3d5b0602012-10-04 17:16:20 -0700890 if (skb->len < 512) {
Ed L. Cashina12c93f2006-09-20 14:36:51 -0400891 printk(KERN_INFO
892 "aoe: runt data size in ataid. skb->len=%d\n",
Ed L. Cashin6bb6285f2006-09-20 14:36:49 -0400893 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 spin_unlock_irqrestore(&d->lock, flags);
895 return;
896 }
Ed Cashin3d5b0602012-10-04 17:16:20 -0700897 if (skb_linearize(skb))
898 break;
899 ataid_complete(d, t, skb->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 break;
901 default:
Ed L. Cashina12c93f2006-09-20 14:36:51 -0400902 printk(KERN_INFO
903 "aoe: unrecognized ata command %2.2Xh for %d.%d\n",
Ed L. Cashin6bb6285f2006-09-20 14:36:49 -0400904 ahout->cmdstat,
Harvey Harrisonf885f8d2008-04-29 01:03:30 -0700905 get_unaligned_be16(&hin->major),
Ed L. Cashin6bb6285f2006-09-20 14:36:49 -0400906 hin->minor);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 }
908 }
909
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800910 if (buf && --buf->nframesout == 0 && buf->resid == 0) {
Linus Torvalds03054de2008-02-08 09:42:46 -0800911 diskstats(d->gd, buf->bio, jiffies - buf->stime, buf->sector);
Peter Horton0a1f1272009-12-01 13:17:46 -0800912 if (buf->flags & BUFFL_FAIL)
913 bio_endio(buf->bio, -EIO);
914 else {
Andrew Morton6ec14802009-12-21 16:27:50 -0800915 bio_flush_dcache_pages(buf->bio);
Peter Horton0a1f1272009-12-01 13:17:46 -0800916 bio_endio(buf->bio, 0);
917 }
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800918 mempool_free(buf, d->bufpool);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 }
920
921 f->buf = NULL;
922 f->tag = FREETAG;
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800923 t->nout--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924
925 aoecmd_work(d);
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800926xmit:
David S. Millere9bb8fb02008-09-21 22:36:49 -0700927 __skb_queue_head_init(&queue);
928 skb_queue_splice_init(&d->sendq, &queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929
930 spin_unlock_irqrestore(&d->lock, flags);
David S. Millere9bb8fb02008-09-21 22:36:49 -0700931 aoenet_xmit(&queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932}
933
934void
935aoecmd_cfg(ushort aoemajor, unsigned char aoeminor)
936{
David S. Millere9bb8fb02008-09-21 22:36:49 -0700937 struct sk_buff_head queue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938
David S. Millere9bb8fb02008-09-21 22:36:49 -0700939 __skb_queue_head_init(&queue);
940 aoecmd_cfg_pkts(aoemajor, aoeminor, &queue);
941 aoenet_xmit(&queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942}
943
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800944struct sk_buff *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945aoecmd_ata_id(struct aoedev *d)
946{
947 struct aoe_hdr *h;
948 struct aoe_atahdr *ah;
949 struct frame *f;
950 struct sk_buff *skb;
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800951 struct aoetgt *t;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952
Ed L. Cashin4f51dc52006-09-20 14:36:49 -0400953 f = freeframe(d);
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800954 if (f == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955 return NULL;
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800956
957 t = *d->tgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958
959 /* initialize the headers & frame */
Ed L. Cashine407a7f2006-09-20 14:36:49 -0400960 skb = f->skb;
Ed L. Cashinabdbf942007-10-16 23:27:03 -0700961 h = (struct aoe_hdr *) skb_mac_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 ah = (struct aoe_atahdr *) (h+1);
Ed L. Cashin19900cd2006-12-22 01:09:21 -0800963 skb_put(skb, sizeof *h + sizeof *ah);
964 memset(h, 0, skb->len);
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800965 f->tag = aoehdr_atainit(d, t, h);
966 t->nout++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 f->waited = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 /* set up ata header */
970 ah->scnt = 1;
Bartlomiej Zolnierkiewicz04b3ab52009-04-01 21:42:24 +0200971 ah->cmdstat = ATA_CMD_ID_ATA;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 ah->lba3 = 0xa0;
973
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800974 skb->dev = t->ifp->nd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975
Ed L. Cashin3ae1c242006-01-19 13:46:19 -0500976 d->rttavg = MAXTIMER;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 d->timer.function = rexmit_timer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978
Ed L. Cashin4f51dc52006-09-20 14:36:49 -0400979 return skb_clone(skb, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980}
981
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800982static struct aoetgt *
983addtgt(struct aoedev *d, char *addr, ulong nframes)
984{
985 struct aoetgt *t, **tt, **te;
986 struct frame *f, *e;
987
988 tt = d->targets;
989 te = tt + NTARGETS;
990 for (; tt < te && *tt; tt++)
991 ;
992
Ed L. Cashin578c4aa2008-02-08 04:20:09 -0800993 if (tt == te) {
994 printk(KERN_INFO
995 "aoe: device addtgt failure; too many targets\n");
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800996 return NULL;
Ed L. Cashin578c4aa2008-02-08 04:20:09 -0800997 }
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800998 t = kcalloc(1, sizeof *t, GFP_ATOMIC);
999 f = kcalloc(nframes, sizeof *f, GFP_ATOMIC);
Ed L. Cashin578c4aa2008-02-08 04:20:09 -08001000 if (!t || !f) {
1001 kfree(f);
Ed L. Cashin9bb237b2008-02-08 04:20:05 -08001002 kfree(t);
Ed L. Cashin578c4aa2008-02-08 04:20:09 -08001003 printk(KERN_INFO "aoe: cannot allocate memory to add target\n");
Ed L. Cashin9bb237b2008-02-08 04:20:05 -08001004 return NULL;
1005 }
1006
Ed L. Cashin68e0d422008-02-08 04:20:00 -08001007 t->nframes = nframes;
1008 t->frames = f;
1009 e = f + nframes;
Ed L. Cashin9bb237b2008-02-08 04:20:05 -08001010 for (; f < e; f++)
Ed L. Cashin68e0d422008-02-08 04:20:00 -08001011 f->tag = FREETAG;
Ed L. Cashin68e0d422008-02-08 04:20:00 -08001012 memcpy(t->addr, addr, sizeof t->addr);
1013 t->ifp = t->ifs;
1014 t->maxout = t->nframes;
1015 return *tt = t;
Ed L. Cashin68e0d422008-02-08 04:20:00 -08001016}
1017
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018void
1019aoecmd_cfg_rsp(struct sk_buff *skb)
1020{
1021 struct aoedev *d;
1022 struct aoe_hdr *h;
1023 struct aoe_cfghdr *ch;
Ed L. Cashin68e0d422008-02-08 04:20:00 -08001024 struct aoetgt *t;
1025 struct aoeif *ifp;
ecashin@coraid.com63e9cc52005-04-18 22:00:20 -07001026 ulong flags, sysminor, aoemajor;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 struct sk_buff *sl;
Ed L. Cashin19bf2632006-09-20 14:36:49 -04001028 u16 n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029
Ed L. Cashinabdbf942007-10-16 23:27:03 -07001030 h = (struct aoe_hdr *) skb_mac_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 ch = (struct aoe_cfghdr *) (h+1);
1032
1033 /*
1034 * Enough people have their dip switches set backwards to
1035 * warrant a loud message for this special case.
1036 */
Harvey Harrison823ed722008-07-04 09:28:32 +02001037 aoemajor = get_unaligned_be16(&h->major);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 if (aoemajor == 0xfff) {
Ed L. Cashina12c93f2006-09-20 14:36:51 -04001039 printk(KERN_ERR "aoe: Warning: shelf address is all ones. "
Ed L. Cashin6bb6285f2006-09-20 14:36:49 -04001040 "Check shelf dip switches.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041 return;
1042 }
1043
1044 sysminor = SYSMINOR(aoemajor, h->minor);
ecashin@coraid.comfc458dc2005-04-18 22:00:17 -07001045 if (sysminor * AOE_PARTITIONS + AOE_PARTITIONS > MINORMASK) {
Ed L. Cashina12c93f2006-09-20 14:36:51 -04001046 printk(KERN_INFO "aoe: e%ld.%d: minor number too large\n",
ecashin@coraid.comfc458dc2005-04-18 22:00:17 -07001047 aoemajor, (int) h->minor);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048 return;
1049 }
1050
Ed L. Cashin19bf2632006-09-20 14:36:49 -04001051 n = be16_to_cpu(ch->bufcnt);
Ed L. Cashin7df620d2008-02-08 04:20:07 -08001052 if (n > aoe_maxout) /* keep it reasonable */
1053 n = aoe_maxout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054
Ed L. Cashin68e0d422008-02-08 04:20:00 -08001055 d = aoedev_by_sysminor_m(sysminor);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 if (d == NULL) {
Ed L. Cashina12c93f2006-09-20 14:36:51 -04001057 printk(KERN_INFO "aoe: device sysminor_m failure\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 return;
1059 }
1060
1061 spin_lock_irqsave(&d->lock, flags);
1062
Ed L. Cashin68e0d422008-02-08 04:20:00 -08001063 t = gettgt(d, h->src);
1064 if (!t) {
1065 t = addtgt(d, h->src, n);
1066 if (!t) {
Ed L. Cashin68e0d422008-02-08 04:20:00 -08001067 spin_unlock_irqrestore(&d->lock, flags);
1068 return;
1069 }
1070 }
1071 ifp = getif(t, skb->dev);
1072 if (!ifp) {
1073 ifp = addif(t, skb->dev);
1074 if (!ifp) {
1075 printk(KERN_INFO
1076 "aoe: device addif failure; "
1077 "too many interfaces?\n");
1078 spin_unlock_irqrestore(&d->lock, flags);
1079 return;
1080 }
1081 }
1082 if (ifp->maxbcnt) {
1083 n = ifp->nd->mtu;
Ed L. Cashin19bf2632006-09-20 14:36:49 -04001084 n -= sizeof (struct aoe_hdr) + sizeof (struct aoe_atahdr);
1085 n /= 512;
1086 if (n > ch->scnt)
1087 n = ch->scnt;
Ed L. Cashin4f51dc52006-09-20 14:36:49 -04001088 n = n ? n * 512 : DEFAULTBCNT;
Ed L. Cashin68e0d422008-02-08 04:20:00 -08001089 if (n != ifp->maxbcnt) {
Ed L. Cashina12c93f2006-09-20 14:36:51 -04001090 printk(KERN_INFO
Harvey Harrison411c41e2008-11-25 00:40:37 -08001091 "aoe: e%ld.%d: setting %d%s%s:%pm\n",
Ed L. Cashin68e0d422008-02-08 04:20:00 -08001092 d->aoemajor, d->aoeminor, n,
1093 " byte data frames on ", ifp->nd->name,
Harvey Harrison411c41e2008-11-25 00:40:37 -08001094 t->addr);
Ed L. Cashin68e0d422008-02-08 04:20:00 -08001095 ifp->maxbcnt = n;
Ed L. Cashin4f51dc52006-09-20 14:36:49 -04001096 }
Ed L. Cashin19bf2632006-09-20 14:36:49 -04001097 }
Ed L. Cashin3ae1c242006-01-19 13:46:19 -05001098
1099 /* don't change users' perspective */
Ed L. Cashin68e0d422008-02-08 04:20:00 -08001100 if (d->nopen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 spin_unlock_irqrestore(&d->lock, flags);
1102 return;
1103 }
ecashin@coraid.com63e9cc52005-04-18 22:00:20 -07001104 d->fw_ver = be16_to_cpu(ch->fwver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105
Ed L. Cashin68e0d422008-02-08 04:20:00 -08001106 sl = aoecmd_ata_id(d);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107
1108 spin_unlock_irqrestore(&d->lock, flags);
1109
David S. Millere9bb8fb02008-09-21 22:36:49 -07001110 if (sl) {
1111 struct sk_buff_head queue;
1112 __skb_queue_head_init(&queue);
1113 __skb_queue_tail(&queue, sl);
1114 aoenet_xmit(&queue);
1115 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116}
1117
Ed L. Cashin68e0d422008-02-08 04:20:00 -08001118void
1119aoecmd_cleanslate(struct aoedev *d)
1120{
1121 struct aoetgt **t, **te;
1122 struct aoeif *p, *e;
1123
1124 d->mintimer = MINTIMER;
1125
1126 t = d->targets;
1127 te = t + NTARGETS;
1128 for (; t < te && *t; t++) {
1129 (*t)->maxout = (*t)->nframes;
1130 p = (*t)->ifs;
1131 e = p + NAOEIFS;
1132 for (; p < e; p++) {
1133 p->lostjumbo = 0;
1134 p->lost = 0;
1135 p->maxbcnt = DEFAULTBCNT;
1136 }
1137 }
1138}