blob: 1be5150bcd3bb6fddcf0fc8878e4cab32e5e357e [file] [log] [blame]
Ed L. Cashin26114642006-09-20 14:36:48 -04001/* Copyright (c) 2006 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
7#include <linux/hdreg.h>
8#include <linux/blkdev.h>
9#include <linux/skbuff.h>
10#include <linux/netdevice.h>
Ed L. Cashin3ae1c242006-01-19 13:46:19 -050011#include <linux/genhd.h>
Ed L. Cashin68e0d422008-02-08 04:20:00 -080012#include <linux/moduleparam.h>
Eric W. Biederman881d9662007-09-17 11:56:21 -070013#include <net/net_namespace.h>
Ed L. Cashin475172f2005-09-29 12:47:40 -040014#include <asm/unaligned.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#include "aoe.h"
16
Ed L. Cashinb751e8b2006-09-20 14:36:50 -040017static int aoe_deadsecs = 60 * 3;
18module_param(aoe_deadsecs, int, 0644);
19MODULE_PARM_DESC(aoe_deadsecs, "After aoe_deadsecs seconds, give up and fail dev.");
Linus Torvalds1da177e2005-04-16 15:20:36 -070020
Ed L. Cashin68e0d422008-02-08 04:20:00 -080021static struct sk_buff *
Ed L. Cashine407a7f2006-09-20 14:36:49 -040022new_skb(ulong len)
Linus Torvalds1da177e2005-04-16 15:20:36 -070023{
24 struct sk_buff *skb;
25
26 skb = alloc_skb(len, GFP_ATOMIC);
27 if (skb) {
Arnaldo Carvalho de Melo459a98e2007-03-19 15:30:44 -070028 skb_reset_mac_header(skb);
Arnaldo Carvalho de Meloc1d2bbe2007-04-10 20:45:18 -070029 skb_reset_network_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -070030 skb->protocol = __constant_htons(ETH_P_AOE);
31 skb->priority = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070032 skb->next = skb->prev = NULL;
33
34 /* tell the network layer not to perform IP checksums
35 * or to get the NIC to do it
36 */
37 skb->ip_summed = CHECKSUM_NONE;
38 }
39 return skb;
40}
41
Linus Torvalds1da177e2005-04-16 15:20:36 -070042static struct frame *
Ed L. Cashin68e0d422008-02-08 04:20:00 -080043getframe(struct aoetgt *t, int tag)
Linus Torvalds1da177e2005-04-16 15:20:36 -070044{
45 struct frame *f, *e;
46
Ed L. Cashin68e0d422008-02-08 04:20:00 -080047 f = t->frames;
48 e = f + t->nframes;
Linus Torvalds1da177e2005-04-16 15:20:36 -070049 for (; f<e; f++)
50 if (f->tag == tag)
51 return f;
52 return NULL;
53}
54
55/*
56 * Leave the top bit clear so we have tagspace for userland.
57 * The bottom 16 bits are the xmit tick for rexmit/rttavg processing.
58 * This driver reserves tag -1 to mean "unused frame."
59 */
60static int
Ed L. Cashin68e0d422008-02-08 04:20:00 -080061newtag(struct aoetgt *t)
Linus Torvalds1da177e2005-04-16 15:20:36 -070062{
63 register ulong n;
64
65 n = jiffies & 0xffff;
Ed L. Cashin68e0d422008-02-08 04:20:00 -080066 return n |= (++t->lasttag & 0x7fff) << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -070067}
68
69static int
Ed L. Cashin68e0d422008-02-08 04:20:00 -080070aoehdr_atainit(struct aoedev *d, struct aoetgt *t, struct aoe_hdr *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -070071{
Ed L. Cashin68e0d422008-02-08 04:20:00 -080072 u32 host_tag = newtag(t);
Linus Torvalds1da177e2005-04-16 15:20:36 -070073
Ed L. Cashin68e0d422008-02-08 04:20:00 -080074 memcpy(h->src, t->ifp->nd->dev_addr, sizeof h->src);
75 memcpy(h->dst, t->addr, sizeof h->dst);
ecashin@coraid.com63e9cc52005-04-18 22:00:20 -070076 h->type = __constant_cpu_to_be16(ETH_P_AOE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070077 h->verfl = AOE_HVER;
ecashin@coraid.com63e9cc52005-04-18 22:00:20 -070078 h->major = cpu_to_be16(d->aoemajor);
Linus Torvalds1da177e2005-04-16 15:20:36 -070079 h->minor = d->aoeminor;
80 h->cmd = AOECMD_ATA;
ecashin@coraid.com63e9cc52005-04-18 22:00:20 -070081 h->tag = cpu_to_be32(host_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -070082
83 return host_tag;
84}
85
Ed L. Cashin19bf2632006-09-20 14:36:49 -040086static inline void
87put_lba(struct aoe_atahdr *ah, sector_t lba)
88{
89 ah->lba0 = lba;
90 ah->lba1 = lba >>= 8;
91 ah->lba2 = lba >>= 8;
92 ah->lba3 = lba >>= 8;
93 ah->lba4 = lba >>= 8;
94 ah->lba5 = lba >>= 8;
95}
96
Linus Torvalds1da177e2005-04-16 15:20:36 -070097static void
Ed L. Cashin68e0d422008-02-08 04:20:00 -080098ifrotate(struct aoetgt *t)
Linus Torvalds1da177e2005-04-16 15:20:36 -070099{
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800100 t->ifp++;
101 if (t->ifp >= &t->ifs[NAOEIFS] || t->ifp->nd == NULL)
102 t->ifp = t->ifs;
103 if (t->ifp->nd == NULL) {
104 printk(KERN_INFO "aoe: no interface to rotate to\n");
105 BUG();
106 }
107}
108
109static struct frame *
110freeframe(struct aoedev *d)
111{
112 struct frame *f, *e;
113 struct aoetgt **t;
114 ulong n;
115
116 if (d->targets[0] == NULL) { /* shouldn't happen, but I'm paranoid */
117 printk(KERN_ERR "aoe: NULL TARGETS!\n");
118 return NULL;
119 }
120 t = d->targets;
121 do {
122 if (t != d->htgt
123 && (*t)->ifp->nd
124 && (*t)->nout < (*t)->maxout) {
125 n = (*t)->nframes;
126 f = (*t)->frames;
127 e = f + n;
128 for (; f < e; f++) {
129 if (f->tag != FREETAG)
130 continue;
131 if (atomic_read(&skb_shinfo(f->skb)->dataref)
132 != 1) {
133 n--;
134 continue;
135 }
136 skb_shinfo(f->skb)->nr_frags = 0;
137 f->skb->data_len = 0;
138 skb_trim(f->skb, 0);
139 d->tgt = t;
140 ifrotate(*t);
141 return f;
142 }
143 if (n == 0) /* slow polling network card */
144 d->flags |= DEVFL_KICKME;
145 }
146 t++;
147 } while (t < &d->targets[NTARGETS] && *t);
148 return NULL;
149}
150
151static int
152aoecmd_ata_rw(struct aoedev *d)
153{
154 struct frame *f;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 struct aoe_hdr *h;
156 struct aoe_atahdr *ah;
157 struct buf *buf;
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800158 struct bio_vec *bv;
159 struct aoetgt *t;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160 struct sk_buff *skb;
161 ulong bcnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 char writebit, extbit;
163
164 writebit = 0x10;
165 extbit = 0x4;
166
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800167 f = freeframe(d);
168 if (f == NULL)
169 return 0;
170 t = *d->tgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 buf = d->inprocess;
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800172 bv = buf->bv;
173 bcnt = t->ifp->maxbcnt;
174 if (bcnt == 0)
175 bcnt = DEFAULTBCNT;
176 if (bcnt > buf->bv_resid)
177 bcnt = buf->bv_resid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 /* initialize the headers & frame */
Ed L. Cashine407a7f2006-09-20 14:36:49 -0400179 skb = f->skb;
Ed L. Cashinabdbf942007-10-16 23:27:03 -0700180 h = (struct aoe_hdr *) skb_mac_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 ah = (struct aoe_atahdr *) (h+1);
Ed L. Cashin19900cd2006-12-22 01:09:21 -0800182 skb_put(skb, sizeof *h + sizeof *ah);
183 memset(h, 0, skb->len);
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800184 f->tag = aoehdr_atainit(d, t, h);
185 t->nout++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186 f->waited = 0;
187 f->buf = buf;
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800188 f->bufaddr = page_address(bv->bv_page) + buf->bv_off;
Ed L. Cashin19bf2632006-09-20 14:36:49 -0400189 f->bcnt = bcnt;
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800190 f->lba = buf->sector;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191
192 /* set up ata header */
193 ah->scnt = bcnt >> 9;
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800194 put_lba(ah, buf->sector);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 if (d->flags & DEVFL_EXT) {
196 ah->aflags |= AOEAFL_EXT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 } else {
198 extbit = 0;
199 ah->lba3 &= 0x0f;
200 ah->lba3 |= 0xe0; /* LBA bit + obsolete 0xa0 */
201 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 if (bio_data_dir(buf->bio) == WRITE) {
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800203 skb_fill_page_desc(skb, 0, bv->bv_page, buf->bv_off, bcnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204 ah->aflags |= AOEAFL_WRITE;
Ed L. Cashin4f51dc52006-09-20 14:36:49 -0400205 skb->len += bcnt;
206 skb->data_len = bcnt;
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800207 t->wpkts++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 } else {
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800209 t->rpkts++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 writebit = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 }
212
213 ah->cmdstat = WIN_READ | writebit | extbit;
214
215 /* mark all tracking fields and load out */
216 buf->nframesout += 1;
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800217 buf->bv_off += bcnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 buf->bv_resid -= bcnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 buf->resid -= bcnt;
220 buf->sector += bcnt >> 9;
221 if (buf->resid == 0) {
222 d->inprocess = NULL;
223 } else if (buf->bv_resid == 0) {
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800224 buf->bv = ++bv;
225 buf->bv_resid = bv->bv_len;
226 WARN_ON(buf->bv_resid == 0);
227 buf->bv_off = bv->bv_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 }
229
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800230 skb->dev = t->ifp->nd;
Ed L. Cashin4f51dc52006-09-20 14:36:49 -0400231 skb = skb_clone(skb, GFP_ATOMIC);
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800232 if (skb) {
233 if (d->sendq_hd)
234 d->sendq_tl->next = skb;
235 else
236 d->sendq_hd = skb;
237 d->sendq_tl = skb;
238 }
239 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240}
241
Ed L. Cashin3ae1c242006-01-19 13:46:19 -0500242/* some callers cannot sleep, and they can call this function,
243 * transmitting the packets later, when interrupts are on
244 */
245static struct sk_buff *
246aoecmd_cfg_pkts(ushort aoemajor, unsigned char aoeminor, struct sk_buff **tail)
247{
248 struct aoe_hdr *h;
249 struct aoe_cfghdr *ch;
250 struct sk_buff *skb, *sl, *sl_tail;
251 struct net_device *ifp;
252
253 sl = sl_tail = NULL;
254
255 read_lock(&dev_base_lock);
Eric W. Biederman881d9662007-09-17 11:56:21 -0700256 for_each_netdev(&init_net, ifp) {
Ed L. Cashin3ae1c242006-01-19 13:46:19 -0500257 dev_hold(ifp);
258 if (!is_aoe_netif(ifp))
Pavel Emelianov7562f872007-05-03 15:13:45 -0700259 goto cont;
Ed L. Cashin3ae1c242006-01-19 13:46:19 -0500260
Ed L. Cashine407a7f2006-09-20 14:36:49 -0400261 skb = new_skb(sizeof *h + sizeof *ch);
Ed L. Cashin3ae1c242006-01-19 13:46:19 -0500262 if (skb == NULL) {
Ed L. Cashina12c93f2006-09-20 14:36:51 -0400263 printk(KERN_INFO "aoe: skb alloc failure\n");
Pavel Emelianov7562f872007-05-03 15:13:45 -0700264 goto cont;
Ed L. Cashin3ae1c242006-01-19 13:46:19 -0500265 }
Ed L. Cashin19900cd2006-12-22 01:09:21 -0800266 skb_put(skb, sizeof *h + sizeof *ch);
Ed L. Cashine407a7f2006-09-20 14:36:49 -0400267 skb->dev = ifp;
Ed L. Cashin3ae1c242006-01-19 13:46:19 -0500268 if (sl_tail == NULL)
269 sl_tail = skb;
Ed L. Cashinabdbf942007-10-16 23:27:03 -0700270 h = (struct aoe_hdr *) skb_mac_header(skb);
Ed L. Cashin3ae1c242006-01-19 13:46:19 -0500271 memset(h, 0, sizeof *h + sizeof *ch);
272
273 memset(h->dst, 0xff, sizeof h->dst);
274 memcpy(h->src, ifp->dev_addr, sizeof h->src);
275 h->type = __constant_cpu_to_be16(ETH_P_AOE);
276 h->verfl = AOE_HVER;
277 h->major = cpu_to_be16(aoemajor);
278 h->minor = aoeminor;
279 h->cmd = AOECMD_CFG;
280
281 skb->next = sl;
282 sl = skb;
Pavel Emelianov7562f872007-05-03 15:13:45 -0700283cont:
284 dev_put(ifp);
Ed L. Cashin3ae1c242006-01-19 13:46:19 -0500285 }
286 read_unlock(&dev_base_lock);
287
288 if (tail != NULL)
289 *tail = sl_tail;
290 return sl;
291}
292
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293static void
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800294resend(struct aoedev *d, struct aoetgt *t, struct frame *f)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295{
296 struct sk_buff *skb;
297 struct aoe_hdr *h;
Ed L. Cashin19bf2632006-09-20 14:36:49 -0400298 struct aoe_atahdr *ah;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 char buf[128];
300 u32 n;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800302 ifrotate(t);
303 n = newtag(t);
Ed L. Cashine407a7f2006-09-20 14:36:49 -0400304 skb = f->skb;
Ed L. Cashinabdbf942007-10-16 23:27:03 -0700305 h = (struct aoe_hdr *) skb_mac_header(skb);
Ed L. Cashin19bf2632006-09-20 14:36:49 -0400306 ah = (struct aoe_atahdr *) (h+1);
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800307
308 snprintf(buf, sizeof buf,
309 "%15s e%ld.%d oldtag=%08x@%08lx newtag=%08x "
310 "s=%012llx d=%012llx nout=%d\n",
311 "retransmit", d->aoemajor, d->aoeminor, f->tag, jiffies, n,
Ed L. Cashin1eb0da42008-02-08 04:20:01 -0800312 mac_addr(h->src),
313 mac_addr(h->dst), t->nout);
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800314 aoechr_error(buf);
315
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 f->tag = n;
ecashin@coraid.com63e9cc52005-04-18 22:00:20 -0700317 h->tag = cpu_to_be32(n);
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800318 memcpy(h->dst, t->addr, sizeof h->dst);
319 memcpy(h->src, t->ifp->nd->dev_addr, sizeof h->src);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800321 switch (ah->cmdstat) {
322 default:
323 break;
324 case WIN_READ:
325 case WIN_READ_EXT:
326 case WIN_WRITE:
327 case WIN_WRITE_EXT:
328 put_lba(ah, f->lba);
329
330 n = f->bcnt;
331 if (n > DEFAULTBCNT)
332 n = DEFAULTBCNT;
333 ah->scnt = n >> 9;
Ed L. Cashin4f51dc52006-09-20 14:36:49 -0400334 if (ah->aflags & AOEAFL_WRITE) {
Ed L. Cashin19bf2632006-09-20 14:36:49 -0400335 skb_fill_page_desc(skb, 0, virt_to_page(f->bufaddr),
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800336 offset_in_page(f->bufaddr), n);
337 skb->len = sizeof *h + sizeof *ah + n;
338 skb->data_len = n;
Ed L. Cashin19bf2632006-09-20 14:36:49 -0400339 }
340 }
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800341 skb->dev = t->ifp->nd;
Ed L. Cashin4f51dc52006-09-20 14:36:49 -0400342 skb = skb_clone(skb, GFP_ATOMIC);
343 if (skb == NULL)
344 return;
Ed L. Cashine407a7f2006-09-20 14:36:49 -0400345 if (d->sendq_hd)
346 d->sendq_tl->next = skb;
347 else
348 d->sendq_hd = skb;
349 d->sendq_tl = skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350}
351
352static int
353tsince(int tag)
354{
355 int n;
356
357 n = jiffies & 0xffff;
358 n -= tag & 0xffff;
359 if (n < 0)
360 n += 1<<16;
361 return n;
362}
363
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800364static struct aoeif *
365getif(struct aoetgt *t, struct net_device *nd)
366{
367 struct aoeif *p, *e;
368
369 p = t->ifs;
370 e = p + NAOEIFS;
371 for (; p < e; p++)
372 if (p->nd == nd)
373 return p;
374 return NULL;
375}
376
377static struct aoeif *
378addif(struct aoetgt *t, struct net_device *nd)
379{
380 struct aoeif *p;
381
382 p = getif(t, NULL);
383 if (!p)
384 return NULL;
385 p->nd = nd;
386 p->maxbcnt = DEFAULTBCNT;
387 p->lost = 0;
388 p->lostjumbo = 0;
389 return p;
390}
391
392static void
393ejectif(struct aoetgt *t, struct aoeif *ifp)
394{
395 struct aoeif *e;
396 ulong n;
397
398 e = t->ifs + NAOEIFS - 1;
399 n = (e - ifp) * sizeof *ifp;
400 memmove(ifp, ifp+1, n);
401 e->nd = NULL;
402}
403
404static int
405sthtith(struct aoedev *d)
406{
407 struct frame *f, *e, *nf;
408 struct sk_buff *skb;
409 struct aoetgt *ht = *d->htgt;
410
411 f = ht->frames;
412 e = f + ht->nframes;
413 for (; f < e; f++) {
414 if (f->tag == FREETAG)
415 continue;
416 nf = freeframe(d);
417 if (!nf)
418 return 0;
419 skb = nf->skb;
420 *nf = *f;
421 f->skb = skb;
422 f->tag = FREETAG;
423 nf->waited = 0;
424 ht->nout--;
425 (*d->tgt)->nout++;
426 resend(d, *d->tgt, nf);
427 }
428 /* he's clean, he's useless. take away his interfaces */
429 memset(ht->ifs, 0, sizeof ht->ifs);
430 d->htgt = NULL;
431 return 1;
432}
433
434static inline unsigned char
435ata_scnt(unsigned char *packet) {
436 struct aoe_hdr *h;
437 struct aoe_atahdr *ah;
438
439 h = (struct aoe_hdr *) packet;
440 ah = (struct aoe_atahdr *) (h+1);
441 return ah->scnt;
442}
443
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444static void
445rexmit_timer(ulong vp)
446{
447 struct aoedev *d;
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800448 struct aoetgt *t, **tt, **te;
449 struct aoeif *ifp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 struct frame *f, *e;
451 struct sk_buff *sl;
452 register long timeout;
453 ulong flags, n;
454
455 d = (struct aoedev *) vp;
456 sl = NULL;
457
458 /* timeout is always ~150% of the moving average */
459 timeout = d->rttavg;
460 timeout += timeout >> 1;
461
462 spin_lock_irqsave(&d->lock, flags);
463
464 if (d->flags & DEVFL_TKILL) {
Ed L. Cashin1c6f3fc2006-01-25 13:54:44 -0500465 spin_unlock_irqrestore(&d->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466 return;
467 }
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800468 tt = d->targets;
469 te = tt + NTARGETS;
470 for (; tt < te && *tt; tt++) {
471 t = *tt;
472 f = t->frames;
473 e = f + t->nframes;
474 for (; f < e; f++) {
475 if (f->tag == FREETAG
476 || tsince(f->tag) < timeout)
477 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 n = f->waited += timeout;
479 n /= HZ;
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800480 if (n > aoe_deadsecs) {
481 /* waited too long. device failure. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 aoedev_downdev(d);
Ed L. Cashin1c6f3fc2006-01-25 13:54:44 -0500483 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 }
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800485
486 if (n > HELPWAIT /* see if another target can help */
487 && (tt != d->targets || d->targets[1]))
488 d->htgt = tt;
489
490 if (t->nout == t->maxout) {
491 if (t->maxout > 1)
492 t->maxout--;
493 t->lastwadj = jiffies;
494 }
495
496 ifp = getif(t, f->skb->dev);
497 if (ifp && ++ifp->lost > (t->nframes << 1)
498 && (ifp != t->ifs || t->ifs[1].nd)) {
499 ejectif(t, ifp);
500 ifp = NULL;
501 }
502
503 if (ata_scnt(skb_mac_header(f->skb)) > DEFAULTBCNT / 512
504 && ifp && ++ifp->lostjumbo > (t->nframes << 1)
505 && ifp->maxbcnt != DEFAULTBCNT) {
506 printk(KERN_INFO
507 "aoe: e%ld.%d: "
508 "too many lost jumbo on "
509 "%s:%012llx - "
510 "falling back to %d frames.\n",
511 d->aoemajor, d->aoeminor,
512 ifp->nd->name, mac_addr(t->addr),
513 DEFAULTBCNT);
514 ifp->maxbcnt = 0;
515 }
516 resend(d, t, f);
517 }
518
519 /* window check */
520 if (t->nout == t->maxout
521 && t->maxout < t->nframes
522 && (jiffies - t->lastwadj)/HZ > 10) {
523 t->maxout++;
524 t->lastwadj = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 }
526 }
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800527
528 if (d->sendq_hd) {
529 n = d->rttavg <<= 1;
530 if (n > MAXTIMER)
531 d->rttavg = MAXTIMER;
532 }
533
534 if (d->flags & DEVFL_KICKME || d->htgt) {
Ed L. Cashin4f51dc52006-09-20 14:36:49 -0400535 d->flags &= ~DEVFL_KICKME;
536 aoecmd_work(d);
537 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538
ecashin@coraid.coma4b38362005-04-18 22:00:22 -0700539 sl = d->sendq_hd;
540 d->sendq_hd = d->sendq_tl = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541
542 d->timer.expires = jiffies + TIMERTICK;
543 add_timer(&d->timer);
544
545 spin_unlock_irqrestore(&d->lock, flags);
546
547 aoenet_xmit(sl);
548}
549
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800550/* enters with d->lock held */
551void
552aoecmd_work(struct aoedev *d)
553{
554 struct buf *buf;
555loop:
556 if (d->htgt && !sthtith(d))
557 return;
558 if (d->inprocess == NULL) {
559 if (list_empty(&d->bufq))
560 return;
561 buf = container_of(d->bufq.next, struct buf, bufs);
562 list_del(d->bufq.next);
563 d->inprocess = buf;
564 }
565 if (aoecmd_ata_rw(d))
566 goto loop;
567}
568
Ed L. Cashin3ae1c242006-01-19 13:46:19 -0500569/* this function performs work that has been deferred until sleeping is OK
570 */
571void
David Howellsc4028952006-11-22 14:57:56 +0000572aoecmd_sleepwork(struct work_struct *work)
Ed L. Cashin3ae1c242006-01-19 13:46:19 -0500573{
David Howellsc4028952006-11-22 14:57:56 +0000574 struct aoedev *d = container_of(work, struct aoedev, work);
Ed L. Cashin3ae1c242006-01-19 13:46:19 -0500575
576 if (d->flags & DEVFL_GDALLOC)
577 aoeblk_gdalloc(d);
578
579 if (d->flags & DEVFL_NEWSIZE) {
580 struct block_device *bd;
581 unsigned long flags;
582 u64 ssize;
583
584 ssize = d->gd->capacity;
585 bd = bdget_disk(d->gd, 0);
586
587 if (bd) {
588 mutex_lock(&bd->bd_inode->i_mutex);
589 i_size_write(bd->bd_inode, (loff_t)ssize<<9);
590 mutex_unlock(&bd->bd_inode->i_mutex);
591 bdput(bd);
592 }
593 spin_lock_irqsave(&d->lock, flags);
594 d->flags |= DEVFL_UP;
595 d->flags &= ~DEVFL_NEWSIZE;
596 spin_unlock_irqrestore(&d->lock, flags);
597 }
598}
599
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600static void
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800601ataid_complete(struct aoedev *d, struct aoetgt *t, unsigned char *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602{
603 u64 ssize;
604 u16 n;
605
606 /* word 83: command set supported */
Ed L. Cashin475172f2005-09-29 12:47:40 -0400607 n = le16_to_cpu(get_unaligned((__le16 *) &id[83<<1]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608
609 /* word 86: command set/feature enabled */
Ed L. Cashin475172f2005-09-29 12:47:40 -0400610 n |= le16_to_cpu(get_unaligned((__le16 *) &id[86<<1]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611
612 if (n & (1<<10)) { /* bit 10: LBA 48 */
613 d->flags |= DEVFL_EXT;
614
615 /* word 100: number lba48 sectors */
Ed L. Cashin475172f2005-09-29 12:47:40 -0400616 ssize = le64_to_cpu(get_unaligned((__le64 *) &id[100<<1]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617
618 /* set as in ide-disk.c:init_idedisk_capacity */
619 d->geo.cylinders = ssize;
620 d->geo.cylinders /= (255 * 63);
621 d->geo.heads = 255;
622 d->geo.sectors = 63;
623 } else {
624 d->flags &= ~DEVFL_EXT;
625
626 /* number lba28 sectors */
Ed L. Cashin475172f2005-09-29 12:47:40 -0400627 ssize = le32_to_cpu(get_unaligned((__le32 *) &id[60<<1]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628
629 /* NOTE: obsolete in ATA 6 */
Ed L. Cashin475172f2005-09-29 12:47:40 -0400630 d->geo.cylinders = le16_to_cpu(get_unaligned((__le16 *) &id[54<<1]));
631 d->geo.heads = le16_to_cpu(get_unaligned((__le16 *) &id[55<<1]));
632 d->geo.sectors = le16_to_cpu(get_unaligned((__le16 *) &id[56<<1]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 }
Ed L. Cashin3ae1c242006-01-19 13:46:19 -0500634
635 if (d->ssize != ssize)
Ed L. Cashina12c93f2006-09-20 14:36:51 -0400636 printk(KERN_INFO "aoe: %012llx e%lu.%lu v%04x has %llu sectors\n",
Ed L. Cashin1eb0da42008-02-08 04:20:01 -0800637 mac_addr(t->addr),
Ed L. Cashin3ae1c242006-01-19 13:46:19 -0500638 d->aoemajor, d->aoeminor,
639 d->fw_ver, (long long)ssize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 d->ssize = ssize;
641 d->geo.start = 0;
642 if (d->gd != NULL) {
643 d->gd->capacity = ssize;
Ed L. Cashin3ae1c242006-01-19 13:46:19 -0500644 d->flags |= DEVFL_NEWSIZE;
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800645 } else
Ed L. Cashin3ae1c242006-01-19 13:46:19 -0500646 d->flags |= DEVFL_GDALLOC;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 schedule_work(&d->work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648}
649
650static void
651calc_rttavg(struct aoedev *d, int rtt)
652{
653 register long n;
654
655 n = rtt;
Ed L. Cashindced3a02006-09-20 14:36:49 -0400656 if (n < 0) {
657 n = -rtt;
658 if (n < MINTIMER)
659 n = MINTIMER;
660 else if (n > MAXTIMER)
661 n = MAXTIMER;
662 d->mintimer += (n - d->mintimer) >> 1;
663 } else if (n < d->mintimer)
664 n = d->mintimer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 else if (n > MAXTIMER)
666 n = MAXTIMER;
667
668 /* g == .25; cf. Congestion Avoidance and Control, Jacobson & Karels; 1988 */
669 n -= d->rttavg;
670 d->rttavg += n >> 2;
671}
672
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800673static struct aoetgt *
674gettgt(struct aoedev *d, char *addr)
675{
676 struct aoetgt **t, **e;
677
678 t = d->targets;
679 e = t + NTARGETS;
680 for (; t < e && *t; t++)
681 if (memcmp((*t)->addr, addr, sizeof((*t)->addr)) == 0)
682 return *t;
683 return NULL;
684}
685
686static inline void
687diskstats(struct gendisk *disk, struct bio *bio, ulong duration)
688{
689 unsigned long n_sect = bio->bi_size >> 9;
690 const int rw = bio_data_dir(bio);
691
692 disk_stat_inc(disk, ios[rw]);
693 disk_stat_add(disk, ticks[rw], duration);
694 disk_stat_add(disk, sectors[rw], n_sect);
695 disk_stat_add(disk, io_ticks, duration);
696}
697
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698void
699aoecmd_ata_rsp(struct sk_buff *skb)
700{
701 struct aoedev *d;
Ed L. Cashinddec63e2006-09-20 14:36:49 -0400702 struct aoe_hdr *hin, *hout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 struct aoe_atahdr *ahin, *ahout;
704 struct frame *f;
705 struct buf *buf;
706 struct sk_buff *sl;
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800707 struct aoetgt *t;
708 struct aoeif *ifp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 register long n;
710 ulong flags;
711 char ebuf[128];
ecashin@coraid.com32465c62005-04-18 22:00:18 -0700712 u16 aoemajor;
713
Ed L. Cashinabdbf942007-10-16 23:27:03 -0700714 hin = (struct aoe_hdr *) skb_mac_header(skb);
David S. Miller43ecf522007-03-01 18:30:08 -0800715 aoemajor = be16_to_cpu(get_unaligned(&hin->major));
ecashin@coraid.com32465c62005-04-18 22:00:18 -0700716 d = aoedev_by_aoeaddr(aoemajor, hin->minor);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 if (d == NULL) {
718 snprintf(ebuf, sizeof ebuf, "aoecmd_ata_rsp: ata response "
719 "for unknown device %d.%d\n",
ecashin@coraid.com32465c62005-04-18 22:00:18 -0700720 aoemajor, hin->minor);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 aoechr_error(ebuf);
722 return;
723 }
724
725 spin_lock_irqsave(&d->lock, flags);
726
David S. Miller43ecf522007-03-01 18:30:08 -0800727 n = be32_to_cpu(get_unaligned(&hin->tag));
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800728 t = gettgt(d, hin->src);
729 if (t == NULL) {
730 printk(KERN_INFO "aoe: can't find target e%ld.%d:%012llx\n",
Ed L. Cashin1eb0da42008-02-08 04:20:01 -0800731 d->aoemajor, d->aoeminor, mac_addr(hin->src));
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800732 spin_unlock_irqrestore(&d->lock, flags);
733 return;
734 }
735 f = getframe(t, n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 if (f == NULL) {
Ed L. Cashindced3a02006-09-20 14:36:49 -0400737 calc_rttavg(d, -tsince(n));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 spin_unlock_irqrestore(&d->lock, flags);
739 snprintf(ebuf, sizeof ebuf,
740 "%15s e%d.%d tag=%08x@%08lx\n",
741 "unexpected rsp",
David S. Miller43ecf522007-03-01 18:30:08 -0800742 be16_to_cpu(get_unaligned(&hin->major)),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 hin->minor,
David S. Miller43ecf522007-03-01 18:30:08 -0800744 be32_to_cpu(get_unaligned(&hin->tag)),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 jiffies);
746 aoechr_error(ebuf);
747 return;
748 }
749
750 calc_rttavg(d, tsince(f->tag));
751
752 ahin = (struct aoe_atahdr *) (hin+1);
Ed L. Cashinabdbf942007-10-16 23:27:03 -0700753 hout = (struct aoe_hdr *) skb_mac_header(f->skb);
Ed L. Cashinddec63e2006-09-20 14:36:49 -0400754 ahout = (struct aoe_atahdr *) (hout+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 buf = f->buf;
756
757 if (ahin->cmdstat & 0xa9) { /* these bits cleared on success */
Ed L. Cashina12c93f2006-09-20 14:36:51 -0400758 printk(KERN_ERR
759 "aoe: ata error cmd=%2.2Xh stat=%2.2Xh from e%ld.%ld\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 ahout->cmdstat, ahin->cmdstat,
761 d->aoemajor, d->aoeminor);
762 if (buf)
763 buf->flags |= BUFFL_FAIL;
764 } else {
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800765 if (d->htgt && t == *d->htgt) /* I'll help myself, thank you. */
766 d->htgt = NULL;
Ed L. Cashin19bf2632006-09-20 14:36:49 -0400767 n = ahout->scnt << 9;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 switch (ahout->cmdstat) {
769 case WIN_READ:
770 case WIN_READ_EXT:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 if (skb->len - sizeof *hin - sizeof *ahin < n) {
Ed L. Cashina12c93f2006-09-20 14:36:51 -0400772 printk(KERN_ERR
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800773 "aoe: %s. skb->len=%d need=%ld\n",
774 "runt data size in read", skb->len, n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 /* fail frame f? just returning will rexmit. */
776 spin_unlock_irqrestore(&d->lock, flags);
777 return;
778 }
779 memcpy(f->bufaddr, ahin+1, n);
780 case WIN_WRITE:
781 case WIN_WRITE_EXT:
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800782 ifp = getif(t, skb->dev);
783 if (ifp) {
784 ifp->lost = 0;
Ed L. Cashin6bb6285f2006-09-20 14:36:49 -0400785 if (n > DEFAULTBCNT)
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800786 ifp->lostjumbo = 0;
Ed L. Cashin19bf2632006-09-20 14:36:49 -0400787 }
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800788 if (f->bcnt -= n) {
789 f->lba += n >> 9;
790 f->bufaddr += n;
791 resend(d, t, f);
792 goto xmit;
793 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 break;
795 case WIN_IDENTIFY:
796 if (skb->len - sizeof *hin - sizeof *ahin < 512) {
Ed L. Cashina12c93f2006-09-20 14:36:51 -0400797 printk(KERN_INFO
798 "aoe: runt data size in ataid. skb->len=%d\n",
Ed L. Cashin6bb6285f2006-09-20 14:36:49 -0400799 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 spin_unlock_irqrestore(&d->lock, flags);
801 return;
802 }
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800803 ataid_complete(d, t, (char *) (ahin+1));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 break;
805 default:
Ed L. Cashina12c93f2006-09-20 14:36:51 -0400806 printk(KERN_INFO
807 "aoe: unrecognized ata command %2.2Xh for %d.%d\n",
Ed L. Cashin6bb6285f2006-09-20 14:36:49 -0400808 ahout->cmdstat,
David S. Miller43ecf522007-03-01 18:30:08 -0800809 be16_to_cpu(get_unaligned(&hin->major)),
Ed L. Cashin6bb6285f2006-09-20 14:36:49 -0400810 hin->minor);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 }
812 }
813
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800814 if (buf && --buf->nframesout == 0 && buf->resid == 0) {
815 diskstats(d->gd, buf->bio, jiffies - buf->stime);
816 n = (buf->flags & BUFFL_FAIL) ? -EIO : 0;
817 bio_endio(buf->bio, n);
818 mempool_free(buf, d->bufpool);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 }
820
821 f->buf = NULL;
822 f->tag = FREETAG;
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800823 t->nout--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824
825 aoecmd_work(d);
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800826xmit:
ecashin@coraid.coma4b38362005-04-18 22:00:22 -0700827 sl = d->sendq_hd;
828 d->sendq_hd = d->sendq_tl = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829
830 spin_unlock_irqrestore(&d->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 aoenet_xmit(sl);
832}
833
834void
835aoecmd_cfg(ushort aoemajor, unsigned char aoeminor)
836{
Ed L. Cashin3ae1c242006-01-19 13:46:19 -0500837 struct sk_buff *sl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838
Ed L. Cashin3ae1c242006-01-19 13:46:19 -0500839 sl = aoecmd_cfg_pkts(aoemajor, aoeminor, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840
841 aoenet_xmit(sl);
842}
843
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800844struct sk_buff *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845aoecmd_ata_id(struct aoedev *d)
846{
847 struct aoe_hdr *h;
848 struct aoe_atahdr *ah;
849 struct frame *f;
850 struct sk_buff *skb;
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800851 struct aoetgt *t;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852
Ed L. Cashin4f51dc52006-09-20 14:36:49 -0400853 f = freeframe(d);
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800854 if (f == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 return NULL;
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800856
857 t = *d->tgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858
859 /* initialize the headers & frame */
Ed L. Cashine407a7f2006-09-20 14:36:49 -0400860 skb = f->skb;
Ed L. Cashinabdbf942007-10-16 23:27:03 -0700861 h = (struct aoe_hdr *) skb_mac_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 ah = (struct aoe_atahdr *) (h+1);
Ed L. Cashin19900cd2006-12-22 01:09:21 -0800863 skb_put(skb, sizeof *h + sizeof *ah);
864 memset(h, 0, skb->len);
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800865 f->tag = aoehdr_atainit(d, t, h);
866 t->nout++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 f->waited = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 /* set up ata header */
870 ah->scnt = 1;
871 ah->cmdstat = WIN_IDENTIFY;
872 ah->lba3 = 0xa0;
873
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800874 skb->dev = t->ifp->nd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875
Ed L. Cashin3ae1c242006-01-19 13:46:19 -0500876 d->rttavg = MAXTIMER;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 d->timer.function = rexmit_timer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878
Ed L. Cashin4f51dc52006-09-20 14:36:49 -0400879 return skb_clone(skb, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880}
881
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800882static struct aoetgt *
883addtgt(struct aoedev *d, char *addr, ulong nframes)
884{
885 struct aoetgt *t, **tt, **te;
886 struct frame *f, *e;
887
888 tt = d->targets;
889 te = tt + NTARGETS;
890 for (; tt < te && *tt; tt++)
891 ;
892
893 if (tt == te)
894 return NULL;
895
896 t = kcalloc(1, sizeof *t, GFP_ATOMIC);
897 f = kcalloc(nframes, sizeof *f, GFP_ATOMIC);
898 if (!t || !f)
899 goto bail;
900 t->nframes = nframes;
901 t->frames = f;
902 e = f + nframes;
903 for (; f < e; f++) {
904 f->tag = FREETAG;
905 f->skb = new_skb(ETH_ZLEN);
906 if (!f->skb)
907 break;
908 }
909 if (f != e) {
910 while (f > t->frames) {
911 f--;
912 dev_kfree_skb(f->skb);
913 }
914 goto bail;
915 }
916 memcpy(t->addr, addr, sizeof t->addr);
917 t->ifp = t->ifs;
918 t->maxout = t->nframes;
919 return *tt = t;
920bail:
921 kfree(t);
922 kfree(f);
923 return NULL;
924}
925
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926void
927aoecmd_cfg_rsp(struct sk_buff *skb)
928{
929 struct aoedev *d;
930 struct aoe_hdr *h;
931 struct aoe_cfghdr *ch;
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800932 struct aoetgt *t;
933 struct aoeif *ifp;
ecashin@coraid.com63e9cc52005-04-18 22:00:20 -0700934 ulong flags, sysminor, aoemajor;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 struct sk_buff *sl;
Ed L. Cashineaf0a3c2006-01-19 13:46:20 -0500936 enum { MAXFRAMES = 16 };
Ed L. Cashin19bf2632006-09-20 14:36:49 -0400937 u16 n;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938
Ed L. Cashinabdbf942007-10-16 23:27:03 -0700939 h = (struct aoe_hdr *) skb_mac_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 ch = (struct aoe_cfghdr *) (h+1);
941
942 /*
943 * Enough people have their dip switches set backwards to
944 * warrant a loud message for this special case.
945 */
David S. Miller43ecf522007-03-01 18:30:08 -0800946 aoemajor = be16_to_cpu(get_unaligned(&h->major));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 if (aoemajor == 0xfff) {
Ed L. Cashina12c93f2006-09-20 14:36:51 -0400948 printk(KERN_ERR "aoe: Warning: shelf address is all ones. "
Ed L. Cashin6bb6285f2006-09-20 14:36:49 -0400949 "Check shelf dip switches.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 return;
951 }
952
953 sysminor = SYSMINOR(aoemajor, h->minor);
ecashin@coraid.comfc458dc2005-04-18 22:00:17 -0700954 if (sysminor * AOE_PARTITIONS + AOE_PARTITIONS > MINORMASK) {
Ed L. Cashina12c93f2006-09-20 14:36:51 -0400955 printk(KERN_INFO "aoe: e%ld.%d: minor number too large\n",
ecashin@coraid.comfc458dc2005-04-18 22:00:17 -0700956 aoemajor, (int) h->minor);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 return;
958 }
959
Ed L. Cashin19bf2632006-09-20 14:36:49 -0400960 n = be16_to_cpu(ch->bufcnt);
961 if (n > MAXFRAMES) /* keep it reasonable */
962 n = MAXFRAMES;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800964 d = aoedev_by_sysminor_m(sysminor);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965 if (d == NULL) {
Ed L. Cashina12c93f2006-09-20 14:36:51 -0400966 printk(KERN_INFO "aoe: device sysminor_m failure\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 return;
968 }
969
970 spin_lock_irqsave(&d->lock, flags);
971
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800972 t = gettgt(d, h->src);
973 if (!t) {
974 t = addtgt(d, h->src, n);
975 if (!t) {
976 printk(KERN_INFO
977 "aoe: device addtgt failure; "
978 "too many targets?\n");
979 spin_unlock_irqrestore(&d->lock, flags);
980 return;
981 }
982 }
983 ifp = getif(t, skb->dev);
984 if (!ifp) {
985 ifp = addif(t, skb->dev);
986 if (!ifp) {
987 printk(KERN_INFO
988 "aoe: device addif failure; "
989 "too many interfaces?\n");
990 spin_unlock_irqrestore(&d->lock, flags);
991 return;
992 }
993 }
994 if (ifp->maxbcnt) {
995 n = ifp->nd->mtu;
Ed L. Cashin19bf2632006-09-20 14:36:49 -0400996 n -= sizeof (struct aoe_hdr) + sizeof (struct aoe_atahdr);
997 n /= 512;
998 if (n > ch->scnt)
999 n = ch->scnt;
Ed L. Cashin4f51dc52006-09-20 14:36:49 -04001000 n = n ? n * 512 : DEFAULTBCNT;
Ed L. Cashin68e0d422008-02-08 04:20:00 -08001001 if (n != ifp->maxbcnt) {
Ed L. Cashina12c93f2006-09-20 14:36:51 -04001002 printk(KERN_INFO
Ed L. Cashin68e0d422008-02-08 04:20:00 -08001003 "aoe: e%ld.%d: setting %d%s%s:%012llx\n",
1004 d->aoemajor, d->aoeminor, n,
1005 " byte data frames on ", ifp->nd->name,
Ed L. Cashin1eb0da42008-02-08 04:20:01 -08001006 mac_addr(t->addr));
Ed L. Cashin68e0d422008-02-08 04:20:00 -08001007 ifp->maxbcnt = n;
Ed L. Cashin4f51dc52006-09-20 14:36:49 -04001008 }
Ed L. Cashin19bf2632006-09-20 14:36:49 -04001009 }
Ed L. Cashin3ae1c242006-01-19 13:46:19 -05001010
1011 /* don't change users' perspective */
Ed L. Cashin68e0d422008-02-08 04:20:00 -08001012 if (d->nopen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013 spin_unlock_irqrestore(&d->lock, flags);
1014 return;
1015 }
ecashin@coraid.com63e9cc52005-04-18 22:00:20 -07001016 d->fw_ver = be16_to_cpu(ch->fwver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017
Ed L. Cashin68e0d422008-02-08 04:20:00 -08001018 sl = aoecmd_ata_id(d);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019
1020 spin_unlock_irqrestore(&d->lock, flags);
1021
1022 aoenet_xmit(sl);
1023}
1024
Ed L. Cashin68e0d422008-02-08 04:20:00 -08001025void
1026aoecmd_cleanslate(struct aoedev *d)
1027{
1028 struct aoetgt **t, **te;
1029 struct aoeif *p, *e;
1030
1031 d->mintimer = MINTIMER;
1032
1033 t = d->targets;
1034 te = t + NTARGETS;
1035 for (; t < te && *t; t++) {
1036 (*t)->maxout = (*t)->nframes;
1037 p = (*t)->ifs;
1038 e = p + NAOEIFS;
1039 for (; p < e; p++) {
1040 p->lostjumbo = 0;
1041 p->lost = 0;
1042 p->maxbcnt = DEFAULTBCNT;
1043 }
1044 }
1045}