blob: 5e7daa1ff6f668eb9b066e27798fff9b72d27acb [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,
312 mac_addr(h->src), mac_addr(h->dst), t->nout);
313 aoechr_error(buf);
314
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 f->tag = n;
ecashin@coraid.com63e9cc52005-04-18 22:00:20 -0700316 h->tag = cpu_to_be32(n);
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800317 memcpy(h->dst, t->addr, sizeof h->dst);
318 memcpy(h->src, t->ifp->nd->dev_addr, sizeof h->src);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800320 switch (ah->cmdstat) {
321 default:
322 break;
323 case WIN_READ:
324 case WIN_READ_EXT:
325 case WIN_WRITE:
326 case WIN_WRITE_EXT:
327 put_lba(ah, f->lba);
328
329 n = f->bcnt;
330 if (n > DEFAULTBCNT)
331 n = DEFAULTBCNT;
332 ah->scnt = n >> 9;
Ed L. Cashin4f51dc52006-09-20 14:36:49 -0400333 if (ah->aflags & AOEAFL_WRITE) {
Ed L. Cashin19bf2632006-09-20 14:36:49 -0400334 skb_fill_page_desc(skb, 0, virt_to_page(f->bufaddr),
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800335 offset_in_page(f->bufaddr), n);
336 skb->len = sizeof *h + sizeof *ah + n;
337 skb->data_len = n;
Ed L. Cashin19bf2632006-09-20 14:36:49 -0400338 }
339 }
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800340 skb->dev = t->ifp->nd;
Ed L. Cashin4f51dc52006-09-20 14:36:49 -0400341 skb = skb_clone(skb, GFP_ATOMIC);
342 if (skb == NULL)
343 return;
Ed L. Cashine407a7f2006-09-20 14:36:49 -0400344 if (d->sendq_hd)
345 d->sendq_tl->next = skb;
346 else
347 d->sendq_hd = skb;
348 d->sendq_tl = skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349}
350
351static int
352tsince(int tag)
353{
354 int n;
355
356 n = jiffies & 0xffff;
357 n -= tag & 0xffff;
358 if (n < 0)
359 n += 1<<16;
360 return n;
361}
362
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800363static struct aoeif *
364getif(struct aoetgt *t, struct net_device *nd)
365{
366 struct aoeif *p, *e;
367
368 p = t->ifs;
369 e = p + NAOEIFS;
370 for (; p < e; p++)
371 if (p->nd == nd)
372 return p;
373 return NULL;
374}
375
376static struct aoeif *
377addif(struct aoetgt *t, struct net_device *nd)
378{
379 struct aoeif *p;
380
381 p = getif(t, NULL);
382 if (!p)
383 return NULL;
384 p->nd = nd;
385 p->maxbcnt = DEFAULTBCNT;
386 p->lost = 0;
387 p->lostjumbo = 0;
388 return p;
389}
390
391static void
392ejectif(struct aoetgt *t, struct aoeif *ifp)
393{
394 struct aoeif *e;
395 ulong n;
396
397 e = t->ifs + NAOEIFS - 1;
398 n = (e - ifp) * sizeof *ifp;
399 memmove(ifp, ifp+1, n);
400 e->nd = NULL;
401}
402
403static int
404sthtith(struct aoedev *d)
405{
406 struct frame *f, *e, *nf;
407 struct sk_buff *skb;
408 struct aoetgt *ht = *d->htgt;
409
410 f = ht->frames;
411 e = f + ht->nframes;
412 for (; f < e; f++) {
413 if (f->tag == FREETAG)
414 continue;
415 nf = freeframe(d);
416 if (!nf)
417 return 0;
418 skb = nf->skb;
419 *nf = *f;
420 f->skb = skb;
421 f->tag = FREETAG;
422 nf->waited = 0;
423 ht->nout--;
424 (*d->tgt)->nout++;
425 resend(d, *d->tgt, nf);
426 }
427 /* he's clean, he's useless. take away his interfaces */
428 memset(ht->ifs, 0, sizeof ht->ifs);
429 d->htgt = NULL;
430 return 1;
431}
432
433static inline unsigned char
434ata_scnt(unsigned char *packet) {
435 struct aoe_hdr *h;
436 struct aoe_atahdr *ah;
437
438 h = (struct aoe_hdr *) packet;
439 ah = (struct aoe_atahdr *) (h+1);
440 return ah->scnt;
441}
442
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443static void
444rexmit_timer(ulong vp)
445{
446 struct aoedev *d;
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800447 struct aoetgt *t, **tt, **te;
448 struct aoeif *ifp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449 struct frame *f, *e;
450 struct sk_buff *sl;
451 register long timeout;
452 ulong flags, n;
453
454 d = (struct aoedev *) vp;
455 sl = NULL;
456
457 /* timeout is always ~150% of the moving average */
458 timeout = d->rttavg;
459 timeout += timeout >> 1;
460
461 spin_lock_irqsave(&d->lock, flags);
462
463 if (d->flags & DEVFL_TKILL) {
Ed L. Cashin1c6f3fc2006-01-25 13:54:44 -0500464 spin_unlock_irqrestore(&d->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 return;
466 }
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800467 tt = d->targets;
468 te = tt + NTARGETS;
469 for (; tt < te && *tt; tt++) {
470 t = *tt;
471 f = t->frames;
472 e = f + t->nframes;
473 for (; f < e; f++) {
474 if (f->tag == FREETAG
475 || tsince(f->tag) < timeout)
476 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 n = f->waited += timeout;
478 n /= HZ;
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800479 if (n > aoe_deadsecs) {
480 /* waited too long. device failure. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 aoedev_downdev(d);
Ed L. Cashin1c6f3fc2006-01-25 13:54:44 -0500482 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 }
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800484
485 if (n > HELPWAIT /* see if another target can help */
486 && (tt != d->targets || d->targets[1]))
487 d->htgt = tt;
488
489 if (t->nout == t->maxout) {
490 if (t->maxout > 1)
491 t->maxout--;
492 t->lastwadj = jiffies;
493 }
494
495 ifp = getif(t, f->skb->dev);
496 if (ifp && ++ifp->lost > (t->nframes << 1)
497 && (ifp != t->ifs || t->ifs[1].nd)) {
498 ejectif(t, ifp);
499 ifp = NULL;
500 }
501
502 if (ata_scnt(skb_mac_header(f->skb)) > DEFAULTBCNT / 512
503 && ifp && ++ifp->lostjumbo > (t->nframes << 1)
504 && ifp->maxbcnt != DEFAULTBCNT) {
505 printk(KERN_INFO
506 "aoe: e%ld.%d: "
507 "too many lost jumbo on "
508 "%s:%012llx - "
509 "falling back to %d frames.\n",
510 d->aoemajor, d->aoeminor,
511 ifp->nd->name, mac_addr(t->addr),
512 DEFAULTBCNT);
513 ifp->maxbcnt = 0;
514 }
515 resend(d, t, f);
516 }
517
518 /* window check */
519 if (t->nout == t->maxout
520 && t->maxout < t->nframes
521 && (jiffies - t->lastwadj)/HZ > 10) {
522 t->maxout++;
523 t->lastwadj = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 }
525 }
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800526
527 if (d->sendq_hd) {
528 n = d->rttavg <<= 1;
529 if (n > MAXTIMER)
530 d->rttavg = MAXTIMER;
531 }
532
533 if (d->flags & DEVFL_KICKME || d->htgt) {
Ed L. Cashin4f51dc52006-09-20 14:36:49 -0400534 d->flags &= ~DEVFL_KICKME;
535 aoecmd_work(d);
536 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537
ecashin@coraid.coma4b38362005-04-18 22:00:22 -0700538 sl = d->sendq_hd;
539 d->sendq_hd = d->sendq_tl = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540
541 d->timer.expires = jiffies + TIMERTICK;
542 add_timer(&d->timer);
543
544 spin_unlock_irqrestore(&d->lock, flags);
545
546 aoenet_xmit(sl);
547}
548
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800549/* enters with d->lock held */
550void
551aoecmd_work(struct aoedev *d)
552{
553 struct buf *buf;
554loop:
555 if (d->htgt && !sthtith(d))
556 return;
557 if (d->inprocess == NULL) {
558 if (list_empty(&d->bufq))
559 return;
560 buf = container_of(d->bufq.next, struct buf, bufs);
561 list_del(d->bufq.next);
562 d->inprocess = buf;
563 }
564 if (aoecmd_ata_rw(d))
565 goto loop;
566}
567
Ed L. Cashin3ae1c242006-01-19 13:46:19 -0500568/* this function performs work that has been deferred until sleeping is OK
569 */
570void
David Howellsc4028952006-11-22 14:57:56 +0000571aoecmd_sleepwork(struct work_struct *work)
Ed L. Cashin3ae1c242006-01-19 13:46:19 -0500572{
David Howellsc4028952006-11-22 14:57:56 +0000573 struct aoedev *d = container_of(work, struct aoedev, work);
Ed L. Cashin3ae1c242006-01-19 13:46:19 -0500574
575 if (d->flags & DEVFL_GDALLOC)
576 aoeblk_gdalloc(d);
577
578 if (d->flags & DEVFL_NEWSIZE) {
579 struct block_device *bd;
580 unsigned long flags;
581 u64 ssize;
582
583 ssize = d->gd->capacity;
584 bd = bdget_disk(d->gd, 0);
585
586 if (bd) {
587 mutex_lock(&bd->bd_inode->i_mutex);
588 i_size_write(bd->bd_inode, (loff_t)ssize<<9);
589 mutex_unlock(&bd->bd_inode->i_mutex);
590 bdput(bd);
591 }
592 spin_lock_irqsave(&d->lock, flags);
593 d->flags |= DEVFL_UP;
594 d->flags &= ~DEVFL_NEWSIZE;
595 spin_unlock_irqrestore(&d->lock, flags);
596 }
597}
598
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599static void
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800600ataid_complete(struct aoedev *d, struct aoetgt *t, unsigned char *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601{
602 u64 ssize;
603 u16 n;
604
605 /* word 83: command set supported */
Ed L. Cashin475172f2005-09-29 12:47:40 -0400606 n = le16_to_cpu(get_unaligned((__le16 *) &id[83<<1]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607
608 /* word 86: command set/feature enabled */
Ed L. Cashin475172f2005-09-29 12:47:40 -0400609 n |= le16_to_cpu(get_unaligned((__le16 *) &id[86<<1]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610
611 if (n & (1<<10)) { /* bit 10: LBA 48 */
612 d->flags |= DEVFL_EXT;
613
614 /* word 100: number lba48 sectors */
Ed L. Cashin475172f2005-09-29 12:47:40 -0400615 ssize = le64_to_cpu(get_unaligned((__le64 *) &id[100<<1]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616
617 /* set as in ide-disk.c:init_idedisk_capacity */
618 d->geo.cylinders = ssize;
619 d->geo.cylinders /= (255 * 63);
620 d->geo.heads = 255;
621 d->geo.sectors = 63;
622 } else {
623 d->flags &= ~DEVFL_EXT;
624
625 /* number lba28 sectors */
Ed L. Cashin475172f2005-09-29 12:47:40 -0400626 ssize = le32_to_cpu(get_unaligned((__le32 *) &id[60<<1]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627
628 /* NOTE: obsolete in ATA 6 */
Ed L. Cashin475172f2005-09-29 12:47:40 -0400629 d->geo.cylinders = le16_to_cpu(get_unaligned((__le16 *) &id[54<<1]));
630 d->geo.heads = le16_to_cpu(get_unaligned((__le16 *) &id[55<<1]));
631 d->geo.sectors = le16_to_cpu(get_unaligned((__le16 *) &id[56<<1]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 }
Ed L. Cashin3ae1c242006-01-19 13:46:19 -0500633
634 if (d->ssize != ssize)
Ed L. Cashina12c93f2006-09-20 14:36:51 -0400635 printk(KERN_INFO "aoe: %012llx e%lu.%lu v%04x has %llu sectors\n",
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800636 (unsigned long long)mac_addr(t->addr),
Ed L. Cashin3ae1c242006-01-19 13:46:19 -0500637 d->aoemajor, d->aoeminor,
638 d->fw_ver, (long long)ssize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 d->ssize = ssize;
640 d->geo.start = 0;
641 if (d->gd != NULL) {
642 d->gd->capacity = ssize;
Ed L. Cashin3ae1c242006-01-19 13:46:19 -0500643 d->flags |= DEVFL_NEWSIZE;
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800644 } else
Ed L. Cashin3ae1c242006-01-19 13:46:19 -0500645 d->flags |= DEVFL_GDALLOC;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 schedule_work(&d->work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647}
648
649static void
650calc_rttavg(struct aoedev *d, int rtt)
651{
652 register long n;
653
654 n = rtt;
Ed L. Cashindced3a02006-09-20 14:36:49 -0400655 if (n < 0) {
656 n = -rtt;
657 if (n < MINTIMER)
658 n = MINTIMER;
659 else if (n > MAXTIMER)
660 n = MAXTIMER;
661 d->mintimer += (n - d->mintimer) >> 1;
662 } else if (n < d->mintimer)
663 n = d->mintimer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 else if (n > MAXTIMER)
665 n = MAXTIMER;
666
667 /* g == .25; cf. Congestion Avoidance and Control, Jacobson & Karels; 1988 */
668 n -= d->rttavg;
669 d->rttavg += n >> 2;
670}
671
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800672static struct aoetgt *
673gettgt(struct aoedev *d, char *addr)
674{
675 struct aoetgt **t, **e;
676
677 t = d->targets;
678 e = t + NTARGETS;
679 for (; t < e && *t; t++)
680 if (memcmp((*t)->addr, addr, sizeof((*t)->addr)) == 0)
681 return *t;
682 return NULL;
683}
684
685static inline void
686diskstats(struct gendisk *disk, struct bio *bio, ulong duration)
687{
688 unsigned long n_sect = bio->bi_size >> 9;
689 const int rw = bio_data_dir(bio);
690
691 disk_stat_inc(disk, ios[rw]);
692 disk_stat_add(disk, ticks[rw], duration);
693 disk_stat_add(disk, sectors[rw], n_sect);
694 disk_stat_add(disk, io_ticks, duration);
695}
696
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697void
698aoecmd_ata_rsp(struct sk_buff *skb)
699{
700 struct aoedev *d;
Ed L. Cashinddec63e2006-09-20 14:36:49 -0400701 struct aoe_hdr *hin, *hout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 struct aoe_atahdr *ahin, *ahout;
703 struct frame *f;
704 struct buf *buf;
705 struct sk_buff *sl;
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800706 struct aoetgt *t;
707 struct aoeif *ifp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 register long n;
709 ulong flags;
710 char ebuf[128];
ecashin@coraid.com32465c62005-04-18 22:00:18 -0700711 u16 aoemajor;
712
Ed L. Cashinabdbf942007-10-16 23:27:03 -0700713 hin = (struct aoe_hdr *) skb_mac_header(skb);
David S. Miller43ecf522007-03-01 18:30:08 -0800714 aoemajor = be16_to_cpu(get_unaligned(&hin->major));
ecashin@coraid.com32465c62005-04-18 22:00:18 -0700715 d = aoedev_by_aoeaddr(aoemajor, hin->minor);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 if (d == NULL) {
717 snprintf(ebuf, sizeof ebuf, "aoecmd_ata_rsp: ata response "
718 "for unknown device %d.%d\n",
ecashin@coraid.com32465c62005-04-18 22:00:18 -0700719 aoemajor, hin->minor);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 aoechr_error(ebuf);
721 return;
722 }
723
724 spin_lock_irqsave(&d->lock, flags);
725
David S. Miller43ecf522007-03-01 18:30:08 -0800726 n = be32_to_cpu(get_unaligned(&hin->tag));
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800727 t = gettgt(d, hin->src);
728 if (t == NULL) {
729 printk(KERN_INFO "aoe: can't find target e%ld.%d:%012llx\n",
730 d->aoemajor, d->aoeminor,
731 (unsigned long long) mac_addr(hin->src));
732 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,
1006 (unsigned long long) mac_addr(t->addr));
1007 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}