]>
Commit | Line | Data |
---|---|---|
52e112b3 | 1 | /* Copyright (c) 2007 Coraid, Inc. See COPYING for GPL terms. */ |
1da177e4 LT |
2 | /* |
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> | |
3ae1c24e | 11 | #include <linux/genhd.h> |
68e0d42f | 12 | #include <linux/moduleparam.h> |
881d966b | 13 | #include <net/net_namespace.h> |
475172fb | 14 | #include <asm/unaligned.h> |
1da177e4 LT |
15 | #include "aoe.h" |
16 | ||
b751e8b6 EC |
17 | static int aoe_deadsecs = 60 * 3; |
18 | module_param(aoe_deadsecs, int, 0644); | |
19 | MODULE_PARM_DESC(aoe_deadsecs, "After aoe_deadsecs seconds, give up and fail dev."); | |
1da177e4 | 20 | |
7df620d8 EC |
21 | static int aoe_maxout = 16; |
22 | module_param(aoe_maxout, int, 0644); | |
23 | MODULE_PARM_DESC(aoe_maxout, | |
24 | "Only aoe_maxout outstanding packets for every MAC on eX.Y."); | |
25 | ||
68e0d42f | 26 | static struct sk_buff * |
e407a7f6 | 27 | new_skb(ulong len) |
1da177e4 LT |
28 | { |
29 | struct sk_buff *skb; | |
30 | ||
31 | skb = alloc_skb(len, GFP_ATOMIC); | |
32 | if (skb) { | |
459a98ed | 33 | skb_reset_mac_header(skb); |
c1d2bbe1 | 34 | skb_reset_network_header(skb); |
1da177e4 LT |
35 | skb->protocol = __constant_htons(ETH_P_AOE); |
36 | skb->priority = 0; | |
1da177e4 LT |
37 | skb->next = skb->prev = NULL; |
38 | ||
39 | /* tell the network layer not to perform IP checksums | |
40 | * or to get the NIC to do it | |
41 | */ | |
42 | skb->ip_summed = CHECKSUM_NONE; | |
43 | } | |
44 | return skb; | |
45 | } | |
46 | ||
1da177e4 | 47 | static struct frame * |
68e0d42f | 48 | getframe(struct aoetgt *t, int tag) |
1da177e4 LT |
49 | { |
50 | struct frame *f, *e; | |
51 | ||
68e0d42f EC |
52 | f = t->frames; |
53 | e = f + t->nframes; | |
1da177e4 LT |
54 | for (; f<e; f++) |
55 | if (f->tag == tag) | |
56 | return f; | |
57 | return NULL; | |
58 | } | |
59 | ||
60 | /* | |
61 | * Leave the top bit clear so we have tagspace for userland. | |
62 | * The bottom 16 bits are the xmit tick for rexmit/rttavg processing. | |
63 | * This driver reserves tag -1 to mean "unused frame." | |
64 | */ | |
65 | static int | |
68e0d42f | 66 | newtag(struct aoetgt *t) |
1da177e4 LT |
67 | { |
68 | register ulong n; | |
69 | ||
70 | n = jiffies & 0xffff; | |
68e0d42f | 71 | return n |= (++t->lasttag & 0x7fff) << 16; |
1da177e4 LT |
72 | } |
73 | ||
74 | static int | |
68e0d42f | 75 | aoehdr_atainit(struct aoedev *d, struct aoetgt *t, struct aoe_hdr *h) |
1da177e4 | 76 | { |
68e0d42f | 77 | u32 host_tag = newtag(t); |
1da177e4 | 78 | |
68e0d42f EC |
79 | memcpy(h->src, t->ifp->nd->dev_addr, sizeof h->src); |
80 | memcpy(h->dst, t->addr, sizeof h->dst); | |
63e9cc5d | 81 | h->type = __constant_cpu_to_be16(ETH_P_AOE); |
1da177e4 | 82 | h->verfl = AOE_HVER; |
63e9cc5d | 83 | h->major = cpu_to_be16(d->aoemajor); |
1da177e4 LT |
84 | h->minor = d->aoeminor; |
85 | h->cmd = AOECMD_ATA; | |
63e9cc5d | 86 | h->tag = cpu_to_be32(host_tag); |
1da177e4 LT |
87 | |
88 | return host_tag; | |
89 | } | |
90 | ||
19bf2635 EC |
91 | static inline void |
92 | put_lba(struct aoe_atahdr *ah, sector_t lba) | |
93 | { | |
94 | ah->lba0 = lba; | |
95 | ah->lba1 = lba >>= 8; | |
96 | ah->lba2 = lba >>= 8; | |
97 | ah->lba3 = lba >>= 8; | |
98 | ah->lba4 = lba >>= 8; | |
99 | ah->lba5 = lba >>= 8; | |
100 | } | |
101 | ||
1da177e4 | 102 | static void |
68e0d42f EC |
103 | ifrotate(struct aoetgt *t) |
104 | { | |
105 | t->ifp++; | |
106 | if (t->ifp >= &t->ifs[NAOEIFS] || t->ifp->nd == NULL) | |
107 | t->ifp = t->ifs; | |
108 | if (t->ifp->nd == NULL) { | |
109 | printk(KERN_INFO "aoe: no interface to rotate to\n"); | |
110 | BUG(); | |
111 | } | |
112 | } | |
113 | ||
9bb237b6 EC |
114 | static void |
115 | skb_pool_put(struct aoedev *d, struct sk_buff *skb) | |
116 | { | |
117 | if (!d->skbpool_hd) | |
118 | d->skbpool_hd = skb; | |
119 | else | |
120 | d->skbpool_tl->next = skb; | |
121 | d->skbpool_tl = skb; | |
122 | } | |
123 | ||
124 | static struct sk_buff * | |
125 | skb_pool_get(struct aoedev *d) | |
126 | { | |
127 | struct sk_buff *skb; | |
128 | ||
129 | skb = d->skbpool_hd; | |
130 | if (skb && atomic_read(&skb_shinfo(skb)->dataref) == 1) { | |
131 | d->skbpool_hd = skb->next; | |
132 | skb->next = NULL; | |
133 | return skb; | |
134 | } | |
135 | if (d->nskbpool < NSKBPOOLMAX | |
136 | && (skb = new_skb(ETH_ZLEN))) { | |
137 | d->nskbpool++; | |
138 | return skb; | |
139 | } | |
140 | return NULL; | |
141 | } | |
142 | ||
143 | /* freeframe is where we do our load balancing so it's a little hairy. */ | |
68e0d42f EC |
144 | static struct frame * |
145 | freeframe(struct aoedev *d) | |
1da177e4 | 146 | { |
9bb237b6 | 147 | struct frame *f, *e, *rf; |
68e0d42f | 148 | struct aoetgt **t; |
9bb237b6 | 149 | struct sk_buff *skb; |
68e0d42f EC |
150 | |
151 | if (d->targets[0] == NULL) { /* shouldn't happen, but I'm paranoid */ | |
152 | printk(KERN_ERR "aoe: NULL TARGETS!\n"); | |
153 | return NULL; | |
154 | } | |
9bb237b6 EC |
155 | t = d->tgt; |
156 | t++; | |
157 | if (t >= &d->targets[NTARGETS] || !*t) | |
158 | t = d->targets; | |
159 | for (;;) { | |
160 | if ((*t)->nout < (*t)->maxout | |
161 | && t != d->htgt | |
162 | && (*t)->ifp->nd) { | |
163 | rf = NULL; | |
68e0d42f | 164 | f = (*t)->frames; |
9bb237b6 | 165 | e = f + (*t)->nframes; |
68e0d42f EC |
166 | for (; f < e; f++) { |
167 | if (f->tag != FREETAG) | |
168 | continue; | |
9bb237b6 EC |
169 | skb = f->skb; |
170 | if (!skb | |
171 | && !(f->skb = skb = new_skb(ETH_ZLEN))) | |
172 | continue; | |
173 | if (atomic_read(&skb_shinfo(skb)->dataref) | |
68e0d42f | 174 | != 1) { |
9bb237b6 EC |
175 | if (!rf) |
176 | rf = f; | |
68e0d42f EC |
177 | continue; |
178 | } | |
9bb237b6 EC |
179 | gotone: skb_shinfo(skb)->nr_frags = skb->data_len = 0; |
180 | skb_trim(skb, 0); | |
68e0d42f EC |
181 | d->tgt = t; |
182 | ifrotate(*t); | |
183 | return f; | |
184 | } | |
9bb237b6 EC |
185 | /* Work can be done, but the network layer is |
186 | holding our precious packets. Try to grab | |
187 | one from the pool. */ | |
188 | f = rf; | |
189 | if (f == NULL) { /* more paranoia */ | |
190 | printk(KERN_ERR | |
191 | "aoe: freeframe: %s.\n", | |
192 | "unexpected null rf"); | |
193 | d->flags |= DEVFL_KICKME; | |
194 | return NULL; | |
195 | } | |
196 | skb = skb_pool_get(d); | |
197 | if (skb) { | |
198 | skb_pool_put(d, f->skb); | |
199 | f->skb = skb; | |
200 | goto gotone; | |
201 | } | |
202 | (*t)->dataref++; | |
203 | if ((*t)->nout == 0) | |
68e0d42f EC |
204 | d->flags |= DEVFL_KICKME; |
205 | } | |
9bb237b6 EC |
206 | if (t == d->tgt) /* we've looped and found nada */ |
207 | break; | |
68e0d42f | 208 | t++; |
9bb237b6 EC |
209 | if (t >= &d->targets[NTARGETS] || !*t) |
210 | t = d->targets; | |
211 | } | |
68e0d42f EC |
212 | return NULL; |
213 | } | |
214 | ||
215 | static int | |
216 | aoecmd_ata_rw(struct aoedev *d) | |
217 | { | |
218 | struct frame *f; | |
1da177e4 LT |
219 | struct aoe_hdr *h; |
220 | struct aoe_atahdr *ah; | |
221 | struct buf *buf; | |
68e0d42f EC |
222 | struct bio_vec *bv; |
223 | struct aoetgt *t; | |
1da177e4 LT |
224 | struct sk_buff *skb; |
225 | ulong bcnt; | |
1da177e4 LT |
226 | char writebit, extbit; |
227 | ||
228 | writebit = 0x10; | |
229 | extbit = 0x4; | |
230 | ||
68e0d42f EC |
231 | f = freeframe(d); |
232 | if (f == NULL) | |
233 | return 0; | |
234 | t = *d->tgt; | |
1da177e4 | 235 | buf = d->inprocess; |
68e0d42f EC |
236 | bv = buf->bv; |
237 | bcnt = t->ifp->maxbcnt; | |
238 | if (bcnt == 0) | |
239 | bcnt = DEFAULTBCNT; | |
240 | if (bcnt > buf->bv_resid) | |
241 | bcnt = buf->bv_resid; | |
1da177e4 | 242 | /* initialize the headers & frame */ |
e407a7f6 | 243 | skb = f->skb; |
abdbf94d | 244 | h = (struct aoe_hdr *) skb_mac_header(skb); |
1da177e4 | 245 | ah = (struct aoe_atahdr *) (h+1); |
19900cde EC |
246 | skb_put(skb, sizeof *h + sizeof *ah); |
247 | memset(h, 0, skb->len); | |
68e0d42f EC |
248 | f->tag = aoehdr_atainit(d, t, h); |
249 | t->nout++; | |
1da177e4 LT |
250 | f->waited = 0; |
251 | f->buf = buf; | |
68e0d42f | 252 | f->bufaddr = page_address(bv->bv_page) + buf->bv_off; |
19bf2635 | 253 | f->bcnt = bcnt; |
68e0d42f | 254 | f->lba = buf->sector; |
1da177e4 LT |
255 | |
256 | /* set up ata header */ | |
257 | ah->scnt = bcnt >> 9; | |
68e0d42f | 258 | put_lba(ah, buf->sector); |
1da177e4 LT |
259 | if (d->flags & DEVFL_EXT) { |
260 | ah->aflags |= AOEAFL_EXT; | |
1da177e4 LT |
261 | } else { |
262 | extbit = 0; | |
263 | ah->lba3 &= 0x0f; | |
264 | ah->lba3 |= 0xe0; /* LBA bit + obsolete 0xa0 */ | |
265 | } | |
1da177e4 | 266 | if (bio_data_dir(buf->bio) == WRITE) { |
68e0d42f | 267 | skb_fill_page_desc(skb, 0, bv->bv_page, buf->bv_off, bcnt); |
1da177e4 | 268 | ah->aflags |= AOEAFL_WRITE; |
4f51dc5e EC |
269 | skb->len += bcnt; |
270 | skb->data_len = bcnt; | |
68e0d42f | 271 | t->wpkts++; |
1da177e4 | 272 | } else { |
68e0d42f | 273 | t->rpkts++; |
1da177e4 | 274 | writebit = 0; |
1da177e4 LT |
275 | } |
276 | ||
277 | ah->cmdstat = WIN_READ | writebit | extbit; | |
278 | ||
279 | /* mark all tracking fields and load out */ | |
280 | buf->nframesout += 1; | |
68e0d42f | 281 | buf->bv_off += bcnt; |
1da177e4 | 282 | buf->bv_resid -= bcnt; |
1da177e4 LT |
283 | buf->resid -= bcnt; |
284 | buf->sector += bcnt >> 9; | |
285 | if (buf->resid == 0) { | |
286 | d->inprocess = NULL; | |
287 | } else if (buf->bv_resid == 0) { | |
68e0d42f EC |
288 | buf->bv = ++bv; |
289 | buf->bv_resid = bv->bv_len; | |
290 | WARN_ON(buf->bv_resid == 0); | |
291 | buf->bv_off = bv->bv_offset; | |
1da177e4 LT |
292 | } |
293 | ||
68e0d42f | 294 | skb->dev = t->ifp->nd; |
4f51dc5e | 295 | skb = skb_clone(skb, GFP_ATOMIC); |
68e0d42f EC |
296 | if (skb) { |
297 | if (d->sendq_hd) | |
298 | d->sendq_tl->next = skb; | |
299 | else | |
300 | d->sendq_hd = skb; | |
301 | d->sendq_tl = skb; | |
302 | } | |
303 | return 1; | |
1da177e4 LT |
304 | } |
305 | ||
3ae1c24e EC |
306 | /* some callers cannot sleep, and they can call this function, |
307 | * transmitting the packets later, when interrupts are on | |
308 | */ | |
309 | static struct sk_buff * | |
310 | aoecmd_cfg_pkts(ushort aoemajor, unsigned char aoeminor, struct sk_buff **tail) | |
311 | { | |
312 | struct aoe_hdr *h; | |
313 | struct aoe_cfghdr *ch; | |
314 | struct sk_buff *skb, *sl, *sl_tail; | |
315 | struct net_device *ifp; | |
316 | ||
317 | sl = sl_tail = NULL; | |
318 | ||
319 | read_lock(&dev_base_lock); | |
881d966b | 320 | for_each_netdev(&init_net, ifp) { |
3ae1c24e EC |
321 | dev_hold(ifp); |
322 | if (!is_aoe_netif(ifp)) | |
7562f876 | 323 | goto cont; |
3ae1c24e | 324 | |
e407a7f6 | 325 | skb = new_skb(sizeof *h + sizeof *ch); |
3ae1c24e | 326 | if (skb == NULL) { |
a12c93f0 | 327 | printk(KERN_INFO "aoe: skb alloc failure\n"); |
7562f876 | 328 | goto cont; |
3ae1c24e | 329 | } |
19900cde | 330 | skb_put(skb, sizeof *h + sizeof *ch); |
e407a7f6 | 331 | skb->dev = ifp; |
3ae1c24e EC |
332 | if (sl_tail == NULL) |
333 | sl_tail = skb; | |
abdbf94d | 334 | h = (struct aoe_hdr *) skb_mac_header(skb); |
3ae1c24e EC |
335 | memset(h, 0, sizeof *h + sizeof *ch); |
336 | ||
337 | memset(h->dst, 0xff, sizeof h->dst); | |
338 | memcpy(h->src, ifp->dev_addr, sizeof h->src); | |
339 | h->type = __constant_cpu_to_be16(ETH_P_AOE); | |
340 | h->verfl = AOE_HVER; | |
341 | h->major = cpu_to_be16(aoemajor); | |
342 | h->minor = aoeminor; | |
343 | h->cmd = AOECMD_CFG; | |
344 | ||
345 | skb->next = sl; | |
346 | sl = skb; | |
7562f876 PE |
347 | cont: |
348 | dev_put(ifp); | |
3ae1c24e EC |
349 | } |
350 | read_unlock(&dev_base_lock); | |
351 | ||
352 | if (tail != NULL) | |
353 | *tail = sl_tail; | |
354 | return sl; | |
355 | } | |
356 | ||
1da177e4 | 357 | static void |
68e0d42f | 358 | resend(struct aoedev *d, struct aoetgt *t, struct frame *f) |
1da177e4 LT |
359 | { |
360 | struct sk_buff *skb; | |
361 | struct aoe_hdr *h; | |
19bf2635 | 362 | struct aoe_atahdr *ah; |
1da177e4 LT |
363 | char buf[128]; |
364 | u32 n; | |
1da177e4 | 365 | |
68e0d42f EC |
366 | ifrotate(t); |
367 | n = newtag(t); | |
368 | skb = f->skb; | |
369 | h = (struct aoe_hdr *) skb_mac_header(skb); | |
370 | ah = (struct aoe_atahdr *) (h+1); | |
1da177e4 LT |
371 | |
372 | snprintf(buf, sizeof buf, | |
68e0d42f EC |
373 | "%15s e%ld.%d oldtag=%08x@%08lx newtag=%08x " |
374 | "s=%012llx d=%012llx nout=%d\n", | |
375 | "retransmit", d->aoemajor, d->aoeminor, f->tag, jiffies, n, | |
1eb0da4c EC |
376 | mac_addr(h->src), |
377 | mac_addr(h->dst), t->nout); | |
1da177e4 LT |
378 | aoechr_error(buf); |
379 | ||
1da177e4 | 380 | f->tag = n; |
63e9cc5d | 381 | h->tag = cpu_to_be32(n); |
68e0d42f EC |
382 | memcpy(h->dst, t->addr, sizeof h->dst); |
383 | memcpy(h->src, t->ifp->nd->dev_addr, sizeof h->src); | |
384 | ||
385 | switch (ah->cmdstat) { | |
386 | default: | |
387 | break; | |
388 | case WIN_READ: | |
389 | case WIN_READ_EXT: | |
390 | case WIN_WRITE: | |
391 | case WIN_WRITE_EXT: | |
392 | put_lba(ah, f->lba); | |
393 | ||
394 | n = f->bcnt; | |
395 | if (n > DEFAULTBCNT) | |
396 | n = DEFAULTBCNT; | |
397 | ah->scnt = n >> 9; | |
4f51dc5e | 398 | if (ah->aflags & AOEAFL_WRITE) { |
19bf2635 | 399 | skb_fill_page_desc(skb, 0, virt_to_page(f->bufaddr), |
68e0d42f EC |
400 | offset_in_page(f->bufaddr), n); |
401 | skb->len = sizeof *h + sizeof *ah + n; | |
402 | skb->data_len = n; | |
19bf2635 EC |
403 | } |
404 | } | |
68e0d42f | 405 | skb->dev = t->ifp->nd; |
4f51dc5e EC |
406 | skb = skb_clone(skb, GFP_ATOMIC); |
407 | if (skb == NULL) | |
408 | return; | |
e407a7f6 EC |
409 | if (d->sendq_hd) |
410 | d->sendq_tl->next = skb; | |
411 | else | |
412 | d->sendq_hd = skb; | |
413 | d->sendq_tl = skb; | |
1da177e4 LT |
414 | } |
415 | ||
416 | static int | |
417 | tsince(int tag) | |
418 | { | |
419 | int n; | |
420 | ||
421 | n = jiffies & 0xffff; | |
422 | n -= tag & 0xffff; | |
423 | if (n < 0) | |
424 | n += 1<<16; | |
425 | return n; | |
426 | } | |
427 | ||
68e0d42f EC |
428 | static struct aoeif * |
429 | getif(struct aoetgt *t, struct net_device *nd) | |
430 | { | |
431 | struct aoeif *p, *e; | |
432 | ||
433 | p = t->ifs; | |
434 | e = p + NAOEIFS; | |
435 | for (; p < e; p++) | |
436 | if (p->nd == nd) | |
437 | return p; | |
438 | return NULL; | |
439 | } | |
440 | ||
441 | static struct aoeif * | |
442 | addif(struct aoetgt *t, struct net_device *nd) | |
443 | { | |
444 | struct aoeif *p; | |
445 | ||
446 | p = getif(t, NULL); | |
447 | if (!p) | |
448 | return NULL; | |
449 | p->nd = nd; | |
450 | p->maxbcnt = DEFAULTBCNT; | |
451 | p->lost = 0; | |
452 | p->lostjumbo = 0; | |
453 | return p; | |
454 | } | |
455 | ||
456 | static void | |
457 | ejectif(struct aoetgt *t, struct aoeif *ifp) | |
458 | { | |
459 | struct aoeif *e; | |
460 | ulong n; | |
461 | ||
462 | e = t->ifs + NAOEIFS - 1; | |
463 | n = (e - ifp) * sizeof *ifp; | |
464 | memmove(ifp, ifp+1, n); | |
465 | e->nd = NULL; | |
466 | } | |
467 | ||
468 | static int | |
469 | sthtith(struct aoedev *d) | |
470 | { | |
471 | struct frame *f, *e, *nf; | |
472 | struct sk_buff *skb; | |
473 | struct aoetgt *ht = *d->htgt; | |
474 | ||
475 | f = ht->frames; | |
476 | e = f + ht->nframes; | |
477 | for (; f < e; f++) { | |
478 | if (f->tag == FREETAG) | |
479 | continue; | |
480 | nf = freeframe(d); | |
481 | if (!nf) | |
482 | return 0; | |
483 | skb = nf->skb; | |
484 | *nf = *f; | |
485 | f->skb = skb; | |
486 | f->tag = FREETAG; | |
487 | nf->waited = 0; | |
488 | ht->nout--; | |
489 | (*d->tgt)->nout++; | |
490 | resend(d, *d->tgt, nf); | |
491 | } | |
492 | /* he's clean, he's useless. take away his interfaces */ | |
493 | memset(ht->ifs, 0, sizeof ht->ifs); | |
494 | d->htgt = NULL; | |
495 | return 1; | |
496 | } | |
497 | ||
498 | static inline unsigned char | |
499 | ata_scnt(unsigned char *packet) { | |
500 | struct aoe_hdr *h; | |
501 | struct aoe_atahdr *ah; | |
502 | ||
503 | h = (struct aoe_hdr *) packet; | |
504 | ah = (struct aoe_atahdr *) (h+1); | |
505 | return ah->scnt; | |
506 | } | |
507 | ||
1da177e4 LT |
508 | static void |
509 | rexmit_timer(ulong vp) | |
510 | { | |
511 | struct aoedev *d; | |
68e0d42f EC |
512 | struct aoetgt *t, **tt, **te; |
513 | struct aoeif *ifp; | |
1da177e4 LT |
514 | struct frame *f, *e; |
515 | struct sk_buff *sl; | |
516 | register long timeout; | |
517 | ulong flags, n; | |
518 | ||
519 | d = (struct aoedev *) vp; | |
520 | sl = NULL; | |
521 | ||
522 | /* timeout is always ~150% of the moving average */ | |
523 | timeout = d->rttavg; | |
524 | timeout += timeout >> 1; | |
525 | ||
526 | spin_lock_irqsave(&d->lock, flags); | |
527 | ||
528 | if (d->flags & DEVFL_TKILL) { | |
1c6f3fca | 529 | spin_unlock_irqrestore(&d->lock, flags); |
1da177e4 LT |
530 | return; |
531 | } | |
68e0d42f EC |
532 | tt = d->targets; |
533 | te = tt + NTARGETS; | |
534 | for (; tt < te && *tt; tt++) { | |
535 | t = *tt; | |
536 | f = t->frames; | |
537 | e = f + t->nframes; | |
538 | for (; f < e; f++) { | |
539 | if (f->tag == FREETAG | |
540 | || tsince(f->tag) < timeout) | |
541 | continue; | |
1da177e4 LT |
542 | n = f->waited += timeout; |
543 | n /= HZ; | |
68e0d42f EC |
544 | if (n > aoe_deadsecs) { |
545 | /* waited too long. device failure. */ | |
1da177e4 | 546 | aoedev_downdev(d); |
1c6f3fca | 547 | break; |
1da177e4 | 548 | } |
68e0d42f EC |
549 | |
550 | if (n > HELPWAIT /* see if another target can help */ | |
551 | && (tt != d->targets || d->targets[1])) | |
552 | d->htgt = tt; | |
553 | ||
554 | if (t->nout == t->maxout) { | |
555 | if (t->maxout > 1) | |
556 | t->maxout--; | |
557 | t->lastwadj = jiffies; | |
558 | } | |
559 | ||
560 | ifp = getif(t, f->skb->dev); | |
561 | if (ifp && ++ifp->lost > (t->nframes << 1) | |
562 | && (ifp != t->ifs || t->ifs[1].nd)) { | |
563 | ejectif(t, ifp); | |
564 | ifp = NULL; | |
565 | } | |
566 | ||
567 | if (ata_scnt(skb_mac_header(f->skb)) > DEFAULTBCNT / 512 | |
568 | && ifp && ++ifp->lostjumbo > (t->nframes << 1) | |
569 | && ifp->maxbcnt != DEFAULTBCNT) { | |
570 | printk(KERN_INFO | |
571 | "aoe: e%ld.%d: " | |
572 | "too many lost jumbo on " | |
573 | "%s:%012llx - " | |
574 | "falling back to %d frames.\n", | |
575 | d->aoemajor, d->aoeminor, | |
576 | ifp->nd->name, mac_addr(t->addr), | |
577 | DEFAULTBCNT); | |
578 | ifp->maxbcnt = 0; | |
579 | } | |
580 | resend(d, t, f); | |
581 | } | |
582 | ||
583 | /* window check */ | |
584 | if (t->nout == t->maxout | |
585 | && t->maxout < t->nframes | |
586 | && (jiffies - t->lastwadj)/HZ > 10) { | |
587 | t->maxout++; | |
588 | t->lastwadj = jiffies; | |
1da177e4 LT |
589 | } |
590 | } | |
68e0d42f EC |
591 | |
592 | if (d->sendq_hd) { | |
593 | n = d->rttavg <<= 1; | |
594 | if (n > MAXTIMER) | |
595 | d->rttavg = MAXTIMER; | |
596 | } | |
597 | ||
598 | if (d->flags & DEVFL_KICKME || d->htgt) { | |
4f51dc5e EC |
599 | d->flags &= ~DEVFL_KICKME; |
600 | aoecmd_work(d); | |
601 | } | |
1da177e4 | 602 | |
a4b38364 EC |
603 | sl = d->sendq_hd; |
604 | d->sendq_hd = d->sendq_tl = NULL; | |
1da177e4 LT |
605 | |
606 | d->timer.expires = jiffies + TIMERTICK; | |
607 | add_timer(&d->timer); | |
608 | ||
609 | spin_unlock_irqrestore(&d->lock, flags); | |
610 | ||
611 | aoenet_xmit(sl); | |
612 | } | |
613 | ||
68e0d42f EC |
614 | /* enters with d->lock held */ |
615 | void | |
616 | aoecmd_work(struct aoedev *d) | |
617 | { | |
618 | struct buf *buf; | |
619 | loop: | |
620 | if (d->htgt && !sthtith(d)) | |
621 | return; | |
622 | if (d->inprocess == NULL) { | |
623 | if (list_empty(&d->bufq)) | |
624 | return; | |
625 | buf = container_of(d->bufq.next, struct buf, bufs); | |
626 | list_del(d->bufq.next); | |
627 | d->inprocess = buf; | |
628 | } | |
629 | if (aoecmd_ata_rw(d)) | |
630 | goto loop; | |
631 | } | |
632 | ||
3ae1c24e EC |
633 | /* this function performs work that has been deferred until sleeping is OK |
634 | */ | |
635 | void | |
c4028958 | 636 | aoecmd_sleepwork(struct work_struct *work) |
3ae1c24e | 637 | { |
c4028958 | 638 | struct aoedev *d = container_of(work, struct aoedev, work); |
3ae1c24e EC |
639 | |
640 | if (d->flags & DEVFL_GDALLOC) | |
641 | aoeblk_gdalloc(d); | |
642 | ||
643 | if (d->flags & DEVFL_NEWSIZE) { | |
644 | struct block_device *bd; | |
645 | unsigned long flags; | |
646 | u64 ssize; | |
647 | ||
648 | ssize = d->gd->capacity; | |
649 | bd = bdget_disk(d->gd, 0); | |
650 | ||
651 | if (bd) { | |
652 | mutex_lock(&bd->bd_inode->i_mutex); | |
653 | i_size_write(bd->bd_inode, (loff_t)ssize<<9); | |
654 | mutex_unlock(&bd->bd_inode->i_mutex); | |
655 | bdput(bd); | |
656 | } | |
657 | spin_lock_irqsave(&d->lock, flags); | |
658 | d->flags |= DEVFL_UP; | |
659 | d->flags &= ~DEVFL_NEWSIZE; | |
660 | spin_unlock_irqrestore(&d->lock, flags); | |
661 | } | |
662 | } | |
663 | ||
1da177e4 | 664 | static void |
68e0d42f | 665 | ataid_complete(struct aoedev *d, struct aoetgt *t, unsigned char *id) |
1da177e4 LT |
666 | { |
667 | u64 ssize; | |
668 | u16 n; | |
669 | ||
670 | /* word 83: command set supported */ | |
f885f8d1 | 671 | n = get_unaligned_le16(&id[83 << 1]); |
1da177e4 LT |
672 | |
673 | /* word 86: command set/feature enabled */ | |
f885f8d1 | 674 | n |= get_unaligned_le16(&id[86 << 1]); |
1da177e4 LT |
675 | |
676 | if (n & (1<<10)) { /* bit 10: LBA 48 */ | |
677 | d->flags |= DEVFL_EXT; | |
678 | ||
679 | /* word 100: number lba48 sectors */ | |
f885f8d1 | 680 | ssize = get_unaligned_le64(&id[100 << 1]); |
1da177e4 LT |
681 | |
682 | /* set as in ide-disk.c:init_idedisk_capacity */ | |
683 | d->geo.cylinders = ssize; | |
684 | d->geo.cylinders /= (255 * 63); | |
685 | d->geo.heads = 255; | |
686 | d->geo.sectors = 63; | |
687 | } else { | |
688 | d->flags &= ~DEVFL_EXT; | |
689 | ||
690 | /* number lba28 sectors */ | |
f885f8d1 | 691 | ssize = get_unaligned_le32(&id[60 << 1]); |
1da177e4 LT |
692 | |
693 | /* NOTE: obsolete in ATA 6 */ | |
f885f8d1 HH |
694 | d->geo.cylinders = get_unaligned_le16(&id[54 << 1]); |
695 | d->geo.heads = get_unaligned_le16(&id[55 << 1]); | |
696 | d->geo.sectors = get_unaligned_le16(&id[56 << 1]); | |
1da177e4 | 697 | } |
3ae1c24e EC |
698 | |
699 | if (d->ssize != ssize) | |
1d75981a EC |
700 | printk(KERN_INFO |
701 | "aoe: %012llx e%ld.%d v%04x has %llu sectors\n", | |
1eb0da4c | 702 | mac_addr(t->addr), |
3ae1c24e EC |
703 | d->aoemajor, d->aoeminor, |
704 | d->fw_ver, (long long)ssize); | |
1da177e4 LT |
705 | d->ssize = ssize; |
706 | d->geo.start = 0; | |
6b9699bb EC |
707 | if (d->flags & (DEVFL_GDALLOC|DEVFL_NEWSIZE)) |
708 | return; | |
1da177e4 LT |
709 | if (d->gd != NULL) { |
710 | d->gd->capacity = ssize; | |
3ae1c24e | 711 | d->flags |= DEVFL_NEWSIZE; |
68e0d42f | 712 | } else |
3ae1c24e | 713 | d->flags |= DEVFL_GDALLOC; |
1da177e4 | 714 | schedule_work(&d->work); |
1da177e4 LT |
715 | } |
716 | ||
717 | static void | |
718 | calc_rttavg(struct aoedev *d, int rtt) | |
719 | { | |
720 | register long n; | |
721 | ||
722 | n = rtt; | |
dced3a05 EC |
723 | if (n < 0) { |
724 | n = -rtt; | |
725 | if (n < MINTIMER) | |
726 | n = MINTIMER; | |
727 | else if (n > MAXTIMER) | |
728 | n = MAXTIMER; | |
729 | d->mintimer += (n - d->mintimer) >> 1; | |
730 | } else if (n < d->mintimer) | |
731 | n = d->mintimer; | |
1da177e4 LT |
732 | else if (n > MAXTIMER) |
733 | n = MAXTIMER; | |
734 | ||
735 | /* g == .25; cf. Congestion Avoidance and Control, Jacobson & Karels; 1988 */ | |
736 | n -= d->rttavg; | |
737 | d->rttavg += n >> 2; | |
738 | } | |
739 | ||
68e0d42f EC |
740 | static struct aoetgt * |
741 | gettgt(struct aoedev *d, char *addr) | |
742 | { | |
743 | struct aoetgt **t, **e; | |
744 | ||
745 | t = d->targets; | |
746 | e = t + NTARGETS; | |
747 | for (; t < e && *t; t++) | |
748 | if (memcmp((*t)->addr, addr, sizeof((*t)->addr)) == 0) | |
749 | return *t; | |
750 | return NULL; | |
751 | } | |
752 | ||
753 | static inline void | |
03054de1 | 754 | diskstats(struct gendisk *disk, struct bio *bio, ulong duration, sector_t sector) |
68e0d42f EC |
755 | { |
756 | unsigned long n_sect = bio->bi_size >> 9; | |
757 | const int rw = bio_data_dir(bio); | |
28f13702 | 758 | struct hd_struct *part; |
68e0d42f | 759 | |
28f13702 JA |
760 | part = get_part(disk, sector); |
761 | all_stat_inc(disk, part, ios[rw], sector); | |
762 | all_stat_add(disk, part, ticks[rw], duration, sector); | |
763 | all_stat_add(disk, part, sectors[rw], n_sect, sector); | |
764 | all_stat_add(disk, part, io_ticks, duration, sector); | |
68e0d42f EC |
765 | } |
766 | ||
1da177e4 LT |
767 | void |
768 | aoecmd_ata_rsp(struct sk_buff *skb) | |
769 | { | |
770 | struct aoedev *d; | |
ddec63e8 | 771 | struct aoe_hdr *hin, *hout; |
1da177e4 LT |
772 | struct aoe_atahdr *ahin, *ahout; |
773 | struct frame *f; | |
774 | struct buf *buf; | |
775 | struct sk_buff *sl; | |
68e0d42f EC |
776 | struct aoetgt *t; |
777 | struct aoeif *ifp; | |
1da177e4 LT |
778 | register long n; |
779 | ulong flags; | |
780 | char ebuf[128]; | |
32465c65 EC |
781 | u16 aoemajor; |
782 | ||
abdbf94d | 783 | hin = (struct aoe_hdr *) skb_mac_header(skb); |
f885f8d1 | 784 | aoemajor = get_unaligned_be16(&hin->major); |
32465c65 | 785 | d = aoedev_by_aoeaddr(aoemajor, hin->minor); |
1da177e4 LT |
786 | if (d == NULL) { |
787 | snprintf(ebuf, sizeof ebuf, "aoecmd_ata_rsp: ata response " | |
788 | "for unknown device %d.%d\n", | |
32465c65 | 789 | aoemajor, hin->minor); |
1da177e4 LT |
790 | aoechr_error(ebuf); |
791 | return; | |
792 | } | |
793 | ||
794 | spin_lock_irqsave(&d->lock, flags); | |
795 | ||
f885f8d1 | 796 | n = get_unaligned_be32(&hin->tag); |
68e0d42f EC |
797 | t = gettgt(d, hin->src); |
798 | if (t == NULL) { | |
799 | printk(KERN_INFO "aoe: can't find target e%ld.%d:%012llx\n", | |
1eb0da4c | 800 | d->aoemajor, d->aoeminor, mac_addr(hin->src)); |
68e0d42f EC |
801 | spin_unlock_irqrestore(&d->lock, flags); |
802 | return; | |
803 | } | |
804 | f = getframe(t, n); | |
1da177e4 | 805 | if (f == NULL) { |
dced3a05 | 806 | calc_rttavg(d, -tsince(n)); |
1da177e4 LT |
807 | spin_unlock_irqrestore(&d->lock, flags); |
808 | snprintf(ebuf, sizeof ebuf, | |
809 | "%15s e%d.%d tag=%08x@%08lx\n", | |
810 | "unexpected rsp", | |
f885f8d1 | 811 | get_unaligned_be16(&hin->major), |
1da177e4 | 812 | hin->minor, |
f885f8d1 | 813 | get_unaligned_be32(&hin->tag), |
1da177e4 LT |
814 | jiffies); |
815 | aoechr_error(ebuf); | |
816 | return; | |
817 | } | |
818 | ||
819 | calc_rttavg(d, tsince(f->tag)); | |
820 | ||
821 | ahin = (struct aoe_atahdr *) (hin+1); | |
abdbf94d | 822 | hout = (struct aoe_hdr *) skb_mac_header(f->skb); |
ddec63e8 | 823 | ahout = (struct aoe_atahdr *) (hout+1); |
1da177e4 LT |
824 | buf = f->buf; |
825 | ||
826 | if (ahin->cmdstat & 0xa9) { /* these bits cleared on success */ | |
a12c93f0 | 827 | printk(KERN_ERR |
1d75981a | 828 | "aoe: ata error cmd=%2.2Xh stat=%2.2Xh from e%ld.%d\n", |
1da177e4 LT |
829 | ahout->cmdstat, ahin->cmdstat, |
830 | d->aoemajor, d->aoeminor); | |
831 | if (buf) | |
832 | buf->flags |= BUFFL_FAIL; | |
833 | } else { | |
68e0d42f EC |
834 | if (d->htgt && t == *d->htgt) /* I'll help myself, thank you. */ |
835 | d->htgt = NULL; | |
19bf2635 | 836 | n = ahout->scnt << 9; |
1da177e4 LT |
837 | switch (ahout->cmdstat) { |
838 | case WIN_READ: | |
839 | case WIN_READ_EXT: | |
1da177e4 | 840 | if (skb->len - sizeof *hin - sizeof *ahin < n) { |
a12c93f0 | 841 | printk(KERN_ERR |
68e0d42f EC |
842 | "aoe: %s. skb->len=%d need=%ld\n", |
843 | "runt data size in read", skb->len, n); | |
1da177e4 LT |
844 | /* fail frame f? just returning will rexmit. */ |
845 | spin_unlock_irqrestore(&d->lock, flags); | |
846 | return; | |
847 | } | |
848 | memcpy(f->bufaddr, ahin+1, n); | |
849 | case WIN_WRITE: | |
850 | case WIN_WRITE_EXT: | |
68e0d42f EC |
851 | ifp = getif(t, skb->dev); |
852 | if (ifp) { | |
853 | ifp->lost = 0; | |
854 | if (n > DEFAULTBCNT) | |
855 | ifp->lostjumbo = 0; | |
856 | } | |
19bf2635 | 857 | if (f->bcnt -= n) { |
68e0d42f | 858 | f->lba += n >> 9; |
19bf2635 | 859 | f->bufaddr += n; |
68e0d42f EC |
860 | resend(d, t, f); |
861 | goto xmit; | |
19bf2635 | 862 | } |
1da177e4 LT |
863 | break; |
864 | case WIN_IDENTIFY: | |
865 | if (skb->len - sizeof *hin - sizeof *ahin < 512) { | |
a12c93f0 EC |
866 | printk(KERN_INFO |
867 | "aoe: runt data size in ataid. skb->len=%d\n", | |
6bb6285f | 868 | skb->len); |
1da177e4 LT |
869 | spin_unlock_irqrestore(&d->lock, flags); |
870 | return; | |
871 | } | |
68e0d42f | 872 | ataid_complete(d, t, (char *) (ahin+1)); |
1da177e4 LT |
873 | break; |
874 | default: | |
a12c93f0 EC |
875 | printk(KERN_INFO |
876 | "aoe: unrecognized ata command %2.2Xh for %d.%d\n", | |
6bb6285f | 877 | ahout->cmdstat, |
f885f8d1 | 878 | get_unaligned_be16(&hin->major), |
6bb6285f | 879 | hin->minor); |
1da177e4 LT |
880 | } |
881 | } | |
882 | ||
68e0d42f | 883 | if (buf && --buf->nframesout == 0 && buf->resid == 0) { |
03054de1 | 884 | diskstats(d->gd, buf->bio, jiffies - buf->stime, buf->sector); |
68e0d42f EC |
885 | n = (buf->flags & BUFFL_FAIL) ? -EIO : 0; |
886 | bio_endio(buf->bio, n); | |
887 | mempool_free(buf, d->bufpool); | |
1da177e4 LT |
888 | } |
889 | ||
890 | f->buf = NULL; | |
891 | f->tag = FREETAG; | |
68e0d42f | 892 | t->nout--; |
1da177e4 LT |
893 | |
894 | aoecmd_work(d); | |
68e0d42f | 895 | xmit: |
a4b38364 EC |
896 | sl = d->sendq_hd; |
897 | d->sendq_hd = d->sendq_tl = NULL; | |
1da177e4 LT |
898 | |
899 | spin_unlock_irqrestore(&d->lock, flags); | |
1da177e4 LT |
900 | aoenet_xmit(sl); |
901 | } | |
902 | ||
903 | void | |
904 | aoecmd_cfg(ushort aoemajor, unsigned char aoeminor) | |
905 | { | |
3ae1c24e | 906 | struct sk_buff *sl; |
1da177e4 | 907 | |
3ae1c24e | 908 | sl = aoecmd_cfg_pkts(aoemajor, aoeminor, NULL); |
1da177e4 LT |
909 | |
910 | aoenet_xmit(sl); | |
911 | } | |
912 | ||
68e0d42f | 913 | struct sk_buff * |
1da177e4 LT |
914 | aoecmd_ata_id(struct aoedev *d) |
915 | { | |
916 | struct aoe_hdr *h; | |
917 | struct aoe_atahdr *ah; | |
918 | struct frame *f; | |
919 | struct sk_buff *skb; | |
68e0d42f | 920 | struct aoetgt *t; |
1da177e4 | 921 | |
4f51dc5e | 922 | f = freeframe(d); |
68e0d42f | 923 | if (f == NULL) |
1da177e4 | 924 | return NULL; |
68e0d42f EC |
925 | |
926 | t = *d->tgt; | |
1da177e4 LT |
927 | |
928 | /* initialize the headers & frame */ | |
e407a7f6 | 929 | skb = f->skb; |
abdbf94d | 930 | h = (struct aoe_hdr *) skb_mac_header(skb); |
1da177e4 | 931 | ah = (struct aoe_atahdr *) (h+1); |
19900cde EC |
932 | skb_put(skb, sizeof *h + sizeof *ah); |
933 | memset(h, 0, skb->len); | |
68e0d42f EC |
934 | f->tag = aoehdr_atainit(d, t, h); |
935 | t->nout++; | |
1da177e4 | 936 | f->waited = 0; |
1da177e4 | 937 | |
1da177e4 LT |
938 | /* set up ata header */ |
939 | ah->scnt = 1; | |
940 | ah->cmdstat = WIN_IDENTIFY; | |
941 | ah->lba3 = 0xa0; | |
942 | ||
68e0d42f | 943 | skb->dev = t->ifp->nd; |
1da177e4 | 944 | |
3ae1c24e | 945 | d->rttavg = MAXTIMER; |
1da177e4 | 946 | d->timer.function = rexmit_timer; |
1da177e4 | 947 | |
4f51dc5e | 948 | return skb_clone(skb, GFP_ATOMIC); |
1da177e4 LT |
949 | } |
950 | ||
68e0d42f EC |
951 | static struct aoetgt * |
952 | addtgt(struct aoedev *d, char *addr, ulong nframes) | |
953 | { | |
954 | struct aoetgt *t, **tt, **te; | |
955 | struct frame *f, *e; | |
956 | ||
957 | tt = d->targets; | |
958 | te = tt + NTARGETS; | |
959 | for (; tt < te && *tt; tt++) | |
960 | ; | |
961 | ||
578c4aa0 EC |
962 | if (tt == te) { |
963 | printk(KERN_INFO | |
964 | "aoe: device addtgt failure; too many targets\n"); | |
68e0d42f | 965 | return NULL; |
578c4aa0 | 966 | } |
68e0d42f EC |
967 | t = kcalloc(1, sizeof *t, GFP_ATOMIC); |
968 | f = kcalloc(nframes, sizeof *f, GFP_ATOMIC); | |
578c4aa0 EC |
969 | if (!t || !f) { |
970 | kfree(f); | |
9bb237b6 | 971 | kfree(t); |
578c4aa0 | 972 | printk(KERN_INFO "aoe: cannot allocate memory to add target\n"); |
9bb237b6 EC |
973 | return NULL; |
974 | } | |
975 | ||
68e0d42f EC |
976 | t->nframes = nframes; |
977 | t->frames = f; | |
978 | e = f + nframes; | |
9bb237b6 | 979 | for (; f < e; f++) |
68e0d42f | 980 | f->tag = FREETAG; |
68e0d42f EC |
981 | memcpy(t->addr, addr, sizeof t->addr); |
982 | t->ifp = t->ifs; | |
983 | t->maxout = t->nframes; | |
984 | return *tt = t; | |
68e0d42f EC |
985 | } |
986 | ||
1da177e4 LT |
987 | void |
988 | aoecmd_cfg_rsp(struct sk_buff *skb) | |
989 | { | |
990 | struct aoedev *d; | |
991 | struct aoe_hdr *h; | |
992 | struct aoe_cfghdr *ch; | |
68e0d42f EC |
993 | struct aoetgt *t; |
994 | struct aoeif *ifp; | |
63e9cc5d | 995 | ulong flags, sysminor, aoemajor; |
1da177e4 | 996 | struct sk_buff *sl; |
19bf2635 | 997 | u16 n; |
1da177e4 | 998 | |
abdbf94d | 999 | h = (struct aoe_hdr *) skb_mac_header(skb); |
1da177e4 LT |
1000 | ch = (struct aoe_cfghdr *) (h+1); |
1001 | ||
1002 | /* | |
1003 | * Enough people have their dip switches set backwards to | |
1004 | * warrant a loud message for this special case. | |
1005 | */ | |
823ed72e | 1006 | aoemajor = get_unaligned_be16(&h->major); |
1da177e4 | 1007 | if (aoemajor == 0xfff) { |
a12c93f0 | 1008 | printk(KERN_ERR "aoe: Warning: shelf address is all ones. " |
6bb6285f | 1009 | "Check shelf dip switches.\n"); |
1da177e4 LT |
1010 | return; |
1011 | } | |
1012 | ||
1013 | sysminor = SYSMINOR(aoemajor, h->minor); | |
fc458dcd | 1014 | if (sysminor * AOE_PARTITIONS + AOE_PARTITIONS > MINORMASK) { |
a12c93f0 | 1015 | printk(KERN_INFO "aoe: e%ld.%d: minor number too large\n", |
fc458dcd | 1016 | aoemajor, (int) h->minor); |
1da177e4 LT |
1017 | return; |
1018 | } | |
1019 | ||
19bf2635 | 1020 | n = be16_to_cpu(ch->bufcnt); |
7df620d8 EC |
1021 | if (n > aoe_maxout) /* keep it reasonable */ |
1022 | n = aoe_maxout; | |
1da177e4 | 1023 | |
68e0d42f | 1024 | d = aoedev_by_sysminor_m(sysminor); |
1da177e4 | 1025 | if (d == NULL) { |
a12c93f0 | 1026 | printk(KERN_INFO "aoe: device sysminor_m failure\n"); |
1da177e4 LT |
1027 | return; |
1028 | } | |
1029 | ||
1030 | spin_lock_irqsave(&d->lock, flags); | |
1031 | ||
68e0d42f EC |
1032 | t = gettgt(d, h->src); |
1033 | if (!t) { | |
1034 | t = addtgt(d, h->src, n); | |
1035 | if (!t) { | |
68e0d42f EC |
1036 | spin_unlock_irqrestore(&d->lock, flags); |
1037 | return; | |
1038 | } | |
1039 | } | |
1040 | ifp = getif(t, skb->dev); | |
1041 | if (!ifp) { | |
1042 | ifp = addif(t, skb->dev); | |
1043 | if (!ifp) { | |
1044 | printk(KERN_INFO | |
1045 | "aoe: device addif failure; " | |
1046 | "too many interfaces?\n"); | |
1047 | spin_unlock_irqrestore(&d->lock, flags); | |
1048 | return; | |
1049 | } | |
1050 | } | |
1051 | if (ifp->maxbcnt) { | |
1052 | n = ifp->nd->mtu; | |
19bf2635 EC |
1053 | n -= sizeof (struct aoe_hdr) + sizeof (struct aoe_atahdr); |
1054 | n /= 512; | |
1055 | if (n > ch->scnt) | |
1056 | n = ch->scnt; | |
4f51dc5e | 1057 | n = n ? n * 512 : DEFAULTBCNT; |
68e0d42f | 1058 | if (n != ifp->maxbcnt) { |
a12c93f0 | 1059 | printk(KERN_INFO |
68e0d42f EC |
1060 | "aoe: e%ld.%d: setting %d%s%s:%012llx\n", |
1061 | d->aoemajor, d->aoeminor, n, | |
1062 | " byte data frames on ", ifp->nd->name, | |
1eb0da4c | 1063 | mac_addr(t->addr)); |
68e0d42f | 1064 | ifp->maxbcnt = n; |
4f51dc5e | 1065 | } |
19bf2635 | 1066 | } |
3ae1c24e EC |
1067 | |
1068 | /* don't change users' perspective */ | |
68e0d42f | 1069 | if (d->nopen) { |
1da177e4 LT |
1070 | spin_unlock_irqrestore(&d->lock, flags); |
1071 | return; | |
1072 | } | |
63e9cc5d | 1073 | d->fw_ver = be16_to_cpu(ch->fwver); |
1da177e4 | 1074 | |
68e0d42f | 1075 | sl = aoecmd_ata_id(d); |
1da177e4 LT |
1076 | |
1077 | spin_unlock_irqrestore(&d->lock, flags); | |
1078 | ||
1079 | aoenet_xmit(sl); | |
1080 | } | |
1081 | ||
68e0d42f EC |
1082 | void |
1083 | aoecmd_cleanslate(struct aoedev *d) | |
1084 | { | |
1085 | struct aoetgt **t, **te; | |
1086 | struct aoeif *p, *e; | |
1087 | ||
1088 | d->mintimer = MINTIMER; | |
1089 | ||
1090 | t = d->targets; | |
1091 | te = t + NTARGETS; | |
1092 | for (; t < te && *t; t++) { | |
1093 | (*t)->maxout = (*t)->nframes; | |
1094 | p = (*t)->ifs; | |
1095 | e = p + NAOEIFS; | |
1096 | for (; p < e; p++) { | |
1097 | p->lostjumbo = 0; | |
1098 | p->lost = 0; | |
1099 | p->maxbcnt = DEFAULTBCNT; | |
1100 | } | |
1101 | } | |
1102 | } |