diff options
Diffstat (limited to 'drivers/block/aoe/aoecmd.c')
-rw-r--r-- | drivers/block/aoe/aoecmd.c | 742 |
1 files changed, 521 insertions, 221 deletions
diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index 4d59d5057734..44beb17e8090 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* Copyright (c) 2006 Coraid, Inc. See COPYING for GPL terms. */ | 1 | /* Copyright (c) 2007 Coraid, Inc. See COPYING for GPL terms. */ |
2 | /* | 2 | /* |
3 | * aoecmd.c | 3 | * aoecmd.c |
4 | * Filesystem request handling methods | 4 | * Filesystem request handling methods |
@@ -9,19 +9,21 @@ | |||
9 | #include <linux/skbuff.h> | 9 | #include <linux/skbuff.h> |
10 | #include <linux/netdevice.h> | 10 | #include <linux/netdevice.h> |
11 | #include <linux/genhd.h> | 11 | #include <linux/genhd.h> |
12 | #include <linux/moduleparam.h> | ||
12 | #include <net/net_namespace.h> | 13 | #include <net/net_namespace.h> |
13 | #include <asm/unaligned.h> | 14 | #include <asm/unaligned.h> |
14 | #include "aoe.h" | 15 | #include "aoe.h" |
15 | 16 | ||
16 | #define TIMERTICK (HZ / 10) | ||
17 | #define MINTIMER (2 * TIMERTICK) | ||
18 | #define MAXTIMER (HZ << 1) | ||
19 | |||
20 | static int aoe_deadsecs = 60 * 3; | 17 | static int aoe_deadsecs = 60 * 3; |
21 | module_param(aoe_deadsecs, int, 0644); | 18 | module_param(aoe_deadsecs, int, 0644); |
22 | MODULE_PARM_DESC(aoe_deadsecs, "After aoe_deadsecs seconds, give up and fail dev."); | 19 | MODULE_PARM_DESC(aoe_deadsecs, "After aoe_deadsecs seconds, give up and fail dev."); |
23 | 20 | ||
24 | struct sk_buff * | 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 | |||
26 | static struct sk_buff * | ||
25 | new_skb(ulong len) | 27 | new_skb(ulong len) |
26 | { | 28 | { |
27 | struct sk_buff *skb; | 29 | struct sk_buff *skb; |
@@ -43,12 +45,12 @@ new_skb(ulong len) | |||
43 | } | 45 | } |
44 | 46 | ||
45 | static struct frame * | 47 | static struct frame * |
46 | getframe(struct aoedev *d, int tag) | 48 | getframe(struct aoetgt *t, int tag) |
47 | { | 49 | { |
48 | struct frame *f, *e; | 50 | struct frame *f, *e; |
49 | 51 | ||
50 | f = d->frames; | 52 | f = t->frames; |
51 | e = f + d->nframes; | 53 | e = f + t->nframes; |
52 | for (; f<e; f++) | 54 | for (; f<e; f++) |
53 | if (f->tag == tag) | 55 | if (f->tag == tag) |
54 | return f; | 56 | return f; |
@@ -61,21 +63,21 @@ getframe(struct aoedev *d, int tag) | |||
61 | * This driver reserves tag -1 to mean "unused frame." | 63 | * This driver reserves tag -1 to mean "unused frame." |
62 | */ | 64 | */ |
63 | static int | 65 | static int |
64 | newtag(struct aoedev *d) | 66 | newtag(struct aoetgt *t) |
65 | { | 67 | { |
66 | register ulong n; | 68 | register ulong n; |
67 | 69 | ||
68 | n = jiffies & 0xffff; | 70 | n = jiffies & 0xffff; |
69 | return n |= (++d->lasttag & 0x7fff) << 16; | 71 | return n |= (++t->lasttag & 0x7fff) << 16; |
70 | } | 72 | } |
71 | 73 | ||
72 | static int | 74 | static int |
73 | aoehdr_atainit(struct aoedev *d, struct aoe_hdr *h) | 75 | aoehdr_atainit(struct aoedev *d, struct aoetgt *t, struct aoe_hdr *h) |
74 | { | 76 | { |
75 | u32 host_tag = newtag(d); | 77 | u32 host_tag = newtag(t); |
76 | 78 | ||
77 | memcpy(h->src, d->ifp->dev_addr, sizeof h->src); | 79 | memcpy(h->src, t->ifp->nd->dev_addr, sizeof h->src); |
78 | memcpy(h->dst, d->addr, sizeof h->dst); | 80 | memcpy(h->dst, t->addr, sizeof h->dst); |
79 | h->type = __constant_cpu_to_be16(ETH_P_AOE); | 81 | h->type = __constant_cpu_to_be16(ETH_P_AOE); |
80 | h->verfl = AOE_HVER; | 82 | h->verfl = AOE_HVER; |
81 | h->major = cpu_to_be16(d->aoemajor); | 83 | h->major = cpu_to_be16(d->aoemajor); |
@@ -98,42 +100,162 @@ put_lba(struct aoe_atahdr *ah, sector_t lba) | |||
98 | } | 100 | } |
99 | 101 | ||
100 | static void | 102 | static void |
101 | aoecmd_ata_rw(struct aoedev *d, struct frame *f) | 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 | |||
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. */ | ||
144 | static struct frame * | ||
145 | freeframe(struct aoedev *d) | ||
146 | { | ||
147 | struct frame *f, *e, *rf; | ||
148 | struct aoetgt **t; | ||
149 | struct sk_buff *skb; | ||
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 | } | ||
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; | ||
164 | f = (*t)->frames; | ||
165 | e = f + (*t)->nframes; | ||
166 | for (; f < e; f++) { | ||
167 | if (f->tag != FREETAG) | ||
168 | continue; | ||
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) | ||
174 | != 1) { | ||
175 | if (!rf) | ||
176 | rf = f; | ||
177 | continue; | ||
178 | } | ||
179 | gotone: skb_shinfo(skb)->nr_frags = skb->data_len = 0; | ||
180 | skb_trim(skb, 0); | ||
181 | d->tgt = t; | ||
182 | ifrotate(*t); | ||
183 | return f; | ||
184 | } | ||
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) | ||
204 | d->flags |= DEVFL_KICKME; | ||
205 | } | ||
206 | if (t == d->tgt) /* we've looped and found nada */ | ||
207 | break; | ||
208 | t++; | ||
209 | if (t >= &d->targets[NTARGETS] || !*t) | ||
210 | t = d->targets; | ||
211 | } | ||
212 | return NULL; | ||
213 | } | ||
214 | |||
215 | static int | ||
216 | aoecmd_ata_rw(struct aoedev *d) | ||
102 | { | 217 | { |
218 | struct frame *f; | ||
103 | struct aoe_hdr *h; | 219 | struct aoe_hdr *h; |
104 | struct aoe_atahdr *ah; | 220 | struct aoe_atahdr *ah; |
105 | struct buf *buf; | 221 | struct buf *buf; |
222 | struct bio_vec *bv; | ||
223 | struct aoetgt *t; | ||
106 | struct sk_buff *skb; | 224 | struct sk_buff *skb; |
107 | ulong bcnt; | 225 | ulong bcnt; |
108 | register sector_t sector; | ||
109 | char writebit, extbit; | 226 | char writebit, extbit; |
110 | 227 | ||
111 | writebit = 0x10; | 228 | writebit = 0x10; |
112 | extbit = 0x4; | 229 | extbit = 0x4; |
113 | 230 | ||
231 | f = freeframe(d); | ||
232 | if (f == NULL) | ||
233 | return 0; | ||
234 | t = *d->tgt; | ||
114 | buf = d->inprocess; | 235 | buf = d->inprocess; |
115 | 236 | bv = buf->bv; | |
116 | sector = buf->sector; | 237 | bcnt = t->ifp->maxbcnt; |
117 | bcnt = buf->bv_resid; | 238 | if (bcnt == 0) |
118 | if (bcnt > d->maxbcnt) | 239 | bcnt = DEFAULTBCNT; |
119 | bcnt = d->maxbcnt; | 240 | if (bcnt > buf->bv_resid) |
120 | 241 | bcnt = buf->bv_resid; | |
121 | /* initialize the headers & frame */ | 242 | /* initialize the headers & frame */ |
122 | skb = f->skb; | 243 | skb = f->skb; |
123 | h = (struct aoe_hdr *) skb_mac_header(skb); | 244 | h = (struct aoe_hdr *) skb_mac_header(skb); |
124 | ah = (struct aoe_atahdr *) (h+1); | 245 | ah = (struct aoe_atahdr *) (h+1); |
125 | skb_put(skb, sizeof *h + sizeof *ah); | 246 | skb_put(skb, sizeof *h + sizeof *ah); |
126 | memset(h, 0, skb->len); | 247 | memset(h, 0, skb->len); |
127 | f->tag = aoehdr_atainit(d, h); | 248 | f->tag = aoehdr_atainit(d, t, h); |
249 | t->nout++; | ||
128 | f->waited = 0; | 250 | f->waited = 0; |
129 | f->buf = buf; | 251 | f->buf = buf; |
130 | f->bufaddr = buf->bufaddr; | 252 | f->bufaddr = page_address(bv->bv_page) + buf->bv_off; |
131 | f->bcnt = bcnt; | 253 | f->bcnt = bcnt; |
132 | f->lba = sector; | 254 | f->lba = buf->sector; |
133 | 255 | ||
134 | /* set up ata header */ | 256 | /* set up ata header */ |
135 | ah->scnt = bcnt >> 9; | 257 | ah->scnt = bcnt >> 9; |
136 | put_lba(ah, sector); | 258 | put_lba(ah, buf->sector); |
137 | if (d->flags & DEVFL_EXT) { | 259 | if (d->flags & DEVFL_EXT) { |
138 | ah->aflags |= AOEAFL_EXT; | 260 | ah->aflags |= AOEAFL_EXT; |
139 | } else { | 261 | } else { |
@@ -141,14 +263,14 @@ aoecmd_ata_rw(struct aoedev *d, struct frame *f) | |||
141 | ah->lba3 &= 0x0f; | 263 | ah->lba3 &= 0x0f; |
142 | ah->lba3 |= 0xe0; /* LBA bit + obsolete 0xa0 */ | 264 | ah->lba3 |= 0xe0; /* LBA bit + obsolete 0xa0 */ |
143 | } | 265 | } |
144 | |||
145 | if (bio_data_dir(buf->bio) == WRITE) { | 266 | if (bio_data_dir(buf->bio) == WRITE) { |
146 | skb_fill_page_desc(skb, 0, virt_to_page(f->bufaddr), | 267 | skb_fill_page_desc(skb, 0, bv->bv_page, buf->bv_off, bcnt); |
147 | offset_in_page(f->bufaddr), bcnt); | ||
148 | ah->aflags |= AOEAFL_WRITE; | 268 | ah->aflags |= AOEAFL_WRITE; |
149 | skb->len += bcnt; | 269 | skb->len += bcnt; |
150 | skb->data_len = bcnt; | 270 | skb->data_len = bcnt; |
271 | t->wpkts++; | ||
151 | } else { | 272 | } else { |
273 | t->rpkts++; | ||
152 | writebit = 0; | 274 | writebit = 0; |
153 | } | 275 | } |
154 | 276 | ||
@@ -156,29 +278,29 @@ aoecmd_ata_rw(struct aoedev *d, struct frame *f) | |||
156 | 278 | ||
157 | /* mark all tracking fields and load out */ | 279 | /* mark all tracking fields and load out */ |
158 | buf->nframesout += 1; | 280 | buf->nframesout += 1; |
159 | buf->bufaddr += bcnt; | 281 | buf->bv_off += bcnt; |
160 | buf->bv_resid -= bcnt; | 282 | buf->bv_resid -= bcnt; |
161 | /* printk(KERN_DEBUG "aoe: bv_resid=%ld\n", buf->bv_resid); */ | ||
162 | buf->resid -= bcnt; | 283 | buf->resid -= bcnt; |
163 | buf->sector += bcnt >> 9; | 284 | buf->sector += bcnt >> 9; |
164 | if (buf->resid == 0) { | 285 | if (buf->resid == 0) { |
165 | d->inprocess = NULL; | 286 | d->inprocess = NULL; |
166 | } else if (buf->bv_resid == 0) { | 287 | } else if (buf->bv_resid == 0) { |
167 | buf->bv++; | 288 | buf->bv = ++bv; |
168 | WARN_ON(buf->bv->bv_len == 0); | 289 | buf->bv_resid = bv->bv_len; |
169 | buf->bv_resid = buf->bv->bv_len; | 290 | WARN_ON(buf->bv_resid == 0); |
170 | buf->bufaddr = page_address(buf->bv->bv_page) + buf->bv->bv_offset; | 291 | buf->bv_off = bv->bv_offset; |
171 | } | 292 | } |
172 | 293 | ||
173 | skb->dev = d->ifp; | 294 | skb->dev = t->ifp->nd; |
174 | skb = skb_clone(skb, GFP_ATOMIC); | 295 | skb = skb_clone(skb, GFP_ATOMIC); |
175 | if (skb == NULL) | 296 | if (skb) { |
176 | return; | 297 | if (d->sendq_hd) |
177 | if (d->sendq_hd) | 298 | d->sendq_tl->next = skb; |
178 | d->sendq_tl->next = skb; | 299 | else |
179 | else | 300 | d->sendq_hd = skb; |
180 | d->sendq_hd = skb; | 301 | d->sendq_tl = skb; |
181 | d->sendq_tl = skb; | 302 | } |
303 | return 1; | ||
182 | } | 304 | } |
183 | 305 | ||
184 | /* some callers cannot sleep, and they can call this function, | 306 | /* some callers cannot sleep, and they can call this function, |
@@ -232,62 +354,8 @@ cont: | |||
232 | return sl; | 354 | return sl; |
233 | } | 355 | } |
234 | 356 | ||
235 | static struct frame * | ||
236 | freeframe(struct aoedev *d) | ||
237 | { | ||
238 | struct frame *f, *e; | ||
239 | int n = 0; | ||
240 | |||
241 | f = d->frames; | ||
242 | e = f + d->nframes; | ||
243 | for (; f<e; f++) { | ||
244 | if (f->tag != FREETAG) | ||
245 | continue; | ||
246 | if (atomic_read(&skb_shinfo(f->skb)->dataref) == 1) { | ||
247 | skb_shinfo(f->skb)->nr_frags = f->skb->data_len = 0; | ||
248 | skb_trim(f->skb, 0); | ||
249 | return f; | ||
250 | } | ||
251 | n++; | ||
252 | } | ||
253 | if (n == d->nframes) /* wait for network layer */ | ||
254 | d->flags |= DEVFL_KICKME; | ||
255 | |||
256 | return NULL; | ||
257 | } | ||
258 | |||
259 | /* enters with d->lock held */ | ||
260 | void | ||
261 | aoecmd_work(struct aoedev *d) | ||
262 | { | ||
263 | struct frame *f; | ||
264 | struct buf *buf; | ||
265 | |||
266 | if (d->flags & DEVFL_PAUSE) { | ||
267 | if (!aoedev_isbusy(d)) | ||
268 | d->sendq_hd = aoecmd_cfg_pkts(d->aoemajor, | ||
269 | d->aoeminor, &d->sendq_tl); | ||
270 | return; | ||
271 | } | ||
272 | |||
273 | loop: | ||
274 | f = freeframe(d); | ||
275 | if (f == NULL) | ||
276 | return; | ||
277 | if (d->inprocess == NULL) { | ||
278 | if (list_empty(&d->bufq)) | ||
279 | return; | ||
280 | buf = container_of(d->bufq.next, struct buf, bufs); | ||
281 | list_del(d->bufq.next); | ||
282 | /*printk(KERN_DEBUG "aoe: bi_size=%ld\n", buf->bio->bi_size); */ | ||
283 | d->inprocess = buf; | ||
284 | } | ||
285 | aoecmd_ata_rw(d, f); | ||
286 | goto loop; | ||
287 | } | ||
288 | |||
289 | static void | 357 | static void |
290 | rexmit(struct aoedev *d, struct frame *f) | 358 | resend(struct aoedev *d, struct aoetgt *t, struct frame *f) |
291 | { | 359 | { |
292 | struct sk_buff *skb; | 360 | struct sk_buff *skb; |
293 | struct aoe_hdr *h; | 361 | struct aoe_hdr *h; |
@@ -295,41 +363,46 @@ rexmit(struct aoedev *d, struct frame *f) | |||
295 | char buf[128]; | 363 | char buf[128]; |
296 | u32 n; | 364 | u32 n; |
297 | 365 | ||
298 | n = newtag(d); | 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); | ||
299 | 371 | ||
300 | snprintf(buf, sizeof buf, | 372 | snprintf(buf, sizeof buf, |
301 | "%15s e%ld.%ld oldtag=%08x@%08lx newtag=%08x\n", | 373 | "%15s e%ld.%d oldtag=%08x@%08lx newtag=%08x " |
302 | "retransmit", | 374 | "s=%012llx d=%012llx nout=%d\n", |
303 | d->aoemajor, d->aoeminor, f->tag, jiffies, n); | 375 | "retransmit", d->aoemajor, d->aoeminor, f->tag, jiffies, n, |
376 | mac_addr(h->src), | ||
377 | mac_addr(h->dst), t->nout); | ||
304 | aoechr_error(buf); | 378 | aoechr_error(buf); |
305 | 379 | ||
306 | skb = f->skb; | ||
307 | h = (struct aoe_hdr *) skb_mac_header(skb); | ||
308 | ah = (struct aoe_atahdr *) (h+1); | ||
309 | f->tag = n; | 380 | f->tag = n; |
310 | h->tag = cpu_to_be32(n); | 381 | h->tag = cpu_to_be32(n); |
311 | memcpy(h->dst, d->addr, sizeof h->dst); | 382 | memcpy(h->dst, t->addr, sizeof h->dst); |
312 | memcpy(h->src, d->ifp->dev_addr, sizeof h->src); | 383 | memcpy(h->src, t->ifp->nd->dev_addr, sizeof h->src); |
313 | 384 | ||
314 | n = DEFAULTBCNT / 512; | 385 | switch (ah->cmdstat) { |
315 | if (ah->scnt > n) { | 386 | default: |
316 | ah->scnt = n; | 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; | ||
317 | if (ah->aflags & AOEAFL_WRITE) { | 398 | if (ah->aflags & AOEAFL_WRITE) { |
318 | skb_fill_page_desc(skb, 0, virt_to_page(f->bufaddr), | 399 | skb_fill_page_desc(skb, 0, virt_to_page(f->bufaddr), |
319 | offset_in_page(f->bufaddr), DEFAULTBCNT); | 400 | offset_in_page(f->bufaddr), n); |
320 | skb->len = sizeof *h + sizeof *ah + DEFAULTBCNT; | 401 | skb->len = sizeof *h + sizeof *ah + n; |
321 | skb->data_len = DEFAULTBCNT; | 402 | skb->data_len = n; |
322 | } | ||
323 | if (++d->lostjumbo > (d->nframes << 1)) | ||
324 | if (d->maxbcnt != DEFAULTBCNT) { | ||
325 | printk(KERN_INFO "aoe: e%ld.%ld: too many lost jumbo on %s - using 1KB frames.\n", | ||
326 | d->aoemajor, d->aoeminor, d->ifp->name); | ||
327 | d->maxbcnt = DEFAULTBCNT; | ||
328 | d->flags |= DEVFL_MAXBCNT; | ||
329 | } | 403 | } |
330 | } | 404 | } |
331 | 405 | skb->dev = t->ifp->nd; | |
332 | skb->dev = d->ifp; | ||
333 | skb = skb_clone(skb, GFP_ATOMIC); | 406 | skb = skb_clone(skb, GFP_ATOMIC); |
334 | if (skb == NULL) | 407 | if (skb == NULL) |
335 | return; | 408 | return; |
@@ -352,10 +425,92 @@ tsince(int tag) | |||
352 | return n; | 425 | return n; |
353 | } | 426 | } |
354 | 427 | ||
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 | |||
355 | static void | 508 | static void |
356 | rexmit_timer(ulong vp) | 509 | rexmit_timer(ulong vp) |
357 | { | 510 | { |
358 | struct aoedev *d; | 511 | struct aoedev *d; |
512 | struct aoetgt *t, **tt, **te; | ||
513 | struct aoeif *ifp; | ||
359 | struct frame *f, *e; | 514 | struct frame *f, *e; |
360 | struct sk_buff *sl; | 515 | struct sk_buff *sl; |
361 | register long timeout; | 516 | register long timeout; |
@@ -374,31 +529,79 @@ rexmit_timer(ulong vp) | |||
374 | spin_unlock_irqrestore(&d->lock, flags); | 529 | spin_unlock_irqrestore(&d->lock, flags); |
375 | return; | 530 | return; |
376 | } | 531 | } |
377 | f = d->frames; | 532 | tt = d->targets; |
378 | e = f + d->nframes; | 533 | te = tt + NTARGETS; |
379 | for (; f<e; f++) { | 534 | for (; tt < te && *tt; tt++) { |
380 | if (f->tag != FREETAG && tsince(f->tag) >= timeout) { | 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; | ||
381 | n = f->waited += timeout; | 542 | n = f->waited += timeout; |
382 | n /= HZ; | 543 | n /= HZ; |
383 | if (n > aoe_deadsecs) { /* waited too long for response */ | 544 | if (n > aoe_deadsecs) { |
545 | /* waited too long. device failure. */ | ||
384 | aoedev_downdev(d); | 546 | aoedev_downdev(d); |
385 | break; | 547 | break; |
386 | } | 548 | } |
387 | rexmit(d, f); | 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; | ||
388 | } | 589 | } |
389 | } | 590 | } |
390 | if (d->flags & DEVFL_KICKME) { | 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) { | ||
391 | d->flags &= ~DEVFL_KICKME; | 599 | d->flags &= ~DEVFL_KICKME; |
392 | aoecmd_work(d); | 600 | aoecmd_work(d); |
393 | } | 601 | } |
394 | 602 | ||
395 | sl = d->sendq_hd; | 603 | sl = d->sendq_hd; |
396 | d->sendq_hd = d->sendq_tl = NULL; | 604 | d->sendq_hd = d->sendq_tl = NULL; |
397 | if (sl) { | ||
398 | n = d->rttavg <<= 1; | ||
399 | if (n > MAXTIMER) | ||
400 | d->rttavg = MAXTIMER; | ||
401 | } | ||
402 | 605 | ||
403 | d->timer.expires = jiffies + TIMERTICK; | 606 | d->timer.expires = jiffies + TIMERTICK; |
404 | add_timer(&d->timer); | 607 | add_timer(&d->timer); |
@@ -408,6 +611,25 @@ rexmit_timer(ulong vp) | |||
408 | aoenet_xmit(sl); | 611 | aoenet_xmit(sl); |
409 | } | 612 | } |
410 | 613 | ||
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 | |||
411 | /* this function performs work that has been deferred until sleeping is OK | 633 | /* this function performs work that has been deferred until sleeping is OK |
412 | */ | 634 | */ |
413 | void | 635 | void |
@@ -440,7 +662,7 @@ aoecmd_sleepwork(struct work_struct *work) | |||
440 | } | 662 | } |
441 | 663 | ||
442 | static void | 664 | static void |
443 | ataid_complete(struct aoedev *d, unsigned char *id) | 665 | ataid_complete(struct aoedev *d, struct aoetgt *t, unsigned char *id) |
444 | { | 666 | { |
445 | u64 ssize; | 667 | u64 ssize; |
446 | u16 n; | 668 | u16 n; |
@@ -475,24 +697,20 @@ ataid_complete(struct aoedev *d, unsigned char *id) | |||
475 | } | 697 | } |
476 | 698 | ||
477 | if (d->ssize != ssize) | 699 | if (d->ssize != ssize) |
478 | printk(KERN_INFO "aoe: %012llx e%lu.%lu v%04x has %llu sectors\n", | 700 | printk(KERN_INFO |
479 | (unsigned long long)mac_addr(d->addr), | 701 | "aoe: %012llx e%ld.%d v%04x has %llu sectors\n", |
702 | mac_addr(t->addr), | ||
480 | d->aoemajor, d->aoeminor, | 703 | d->aoemajor, d->aoeminor, |
481 | d->fw_ver, (long long)ssize); | 704 | d->fw_ver, (long long)ssize); |
482 | d->ssize = ssize; | 705 | d->ssize = ssize; |
483 | d->geo.start = 0; | 706 | d->geo.start = 0; |
707 | if (d->flags & (DEVFL_GDALLOC|DEVFL_NEWSIZE)) | ||
708 | return; | ||
484 | if (d->gd != NULL) { | 709 | if (d->gd != NULL) { |
485 | d->gd->capacity = ssize; | 710 | d->gd->capacity = ssize; |
486 | d->flags |= DEVFL_NEWSIZE; | 711 | d->flags |= DEVFL_NEWSIZE; |
487 | } else { | 712 | } else |
488 | if (d->flags & DEVFL_GDALLOC) { | ||
489 | printk(KERN_ERR "aoe: can't schedule work for e%lu.%lu, %s\n", | ||
490 | d->aoemajor, d->aoeminor, | ||
491 | "it's already on! This shouldn't happen.\n"); | ||
492 | return; | ||
493 | } | ||
494 | d->flags |= DEVFL_GDALLOC; | 713 | d->flags |= DEVFL_GDALLOC; |
495 | } | ||
496 | schedule_work(&d->work); | 714 | schedule_work(&d->work); |
497 | } | 715 | } |
498 | 716 | ||
@@ -519,6 +737,31 @@ calc_rttavg(struct aoedev *d, int rtt) | |||
519 | d->rttavg += n >> 2; | 737 | d->rttavg += n >> 2; |
520 | } | 738 | } |
521 | 739 | ||
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 | ||
754 | diskstats(struct gendisk *disk, struct bio *bio, ulong duration) | ||
755 | { | ||
756 | unsigned long n_sect = bio->bi_size >> 9; | ||
757 | const int rw = bio_data_dir(bio); | ||
758 | |||
759 | disk_stat_inc(disk, ios[rw]); | ||
760 | disk_stat_add(disk, ticks[rw], duration); | ||
761 | disk_stat_add(disk, sectors[rw], n_sect); | ||
762 | disk_stat_add(disk, io_ticks, duration); | ||
763 | } | ||
764 | |||
522 | void | 765 | void |
523 | aoecmd_ata_rsp(struct sk_buff *skb) | 766 | aoecmd_ata_rsp(struct sk_buff *skb) |
524 | { | 767 | { |
@@ -528,6 +771,8 @@ aoecmd_ata_rsp(struct sk_buff *skb) | |||
528 | struct frame *f; | 771 | struct frame *f; |
529 | struct buf *buf; | 772 | struct buf *buf; |
530 | struct sk_buff *sl; | 773 | struct sk_buff *sl; |
774 | struct aoetgt *t; | ||
775 | struct aoeif *ifp; | ||
531 | register long n; | 776 | register long n; |
532 | ulong flags; | 777 | ulong flags; |
533 | char ebuf[128]; | 778 | char ebuf[128]; |
@@ -547,7 +792,14 @@ aoecmd_ata_rsp(struct sk_buff *skb) | |||
547 | spin_lock_irqsave(&d->lock, flags); | 792 | spin_lock_irqsave(&d->lock, flags); |
548 | 793 | ||
549 | n = be32_to_cpu(get_unaligned(&hin->tag)); | 794 | n = be32_to_cpu(get_unaligned(&hin->tag)); |
550 | f = getframe(d, n); | 795 | t = gettgt(d, hin->src); |
796 | if (t == NULL) { | ||
797 | printk(KERN_INFO "aoe: can't find target e%ld.%d:%012llx\n", | ||
798 | d->aoemajor, d->aoeminor, mac_addr(hin->src)); | ||
799 | spin_unlock_irqrestore(&d->lock, flags); | ||
800 | return; | ||
801 | } | ||
802 | f = getframe(t, n); | ||
551 | if (f == NULL) { | 803 | if (f == NULL) { |
552 | calc_rttavg(d, -tsince(n)); | 804 | calc_rttavg(d, -tsince(n)); |
553 | spin_unlock_irqrestore(&d->lock, flags); | 805 | spin_unlock_irqrestore(&d->lock, flags); |
@@ -569,24 +821,24 @@ aoecmd_ata_rsp(struct sk_buff *skb) | |||
569 | ahout = (struct aoe_atahdr *) (hout+1); | 821 | ahout = (struct aoe_atahdr *) (hout+1); |
570 | buf = f->buf; | 822 | buf = f->buf; |
571 | 823 | ||
572 | if (ahout->cmdstat == WIN_IDENTIFY) | ||
573 | d->flags &= ~DEVFL_PAUSE; | ||
574 | if (ahin->cmdstat & 0xa9) { /* these bits cleared on success */ | 824 | if (ahin->cmdstat & 0xa9) { /* these bits cleared on success */ |
575 | printk(KERN_ERR | 825 | printk(KERN_ERR |
576 | "aoe: ata error cmd=%2.2Xh stat=%2.2Xh from e%ld.%ld\n", | 826 | "aoe: ata error cmd=%2.2Xh stat=%2.2Xh from e%ld.%d\n", |
577 | ahout->cmdstat, ahin->cmdstat, | 827 | ahout->cmdstat, ahin->cmdstat, |
578 | d->aoemajor, d->aoeminor); | 828 | d->aoemajor, d->aoeminor); |
579 | if (buf) | 829 | if (buf) |
580 | buf->flags |= BUFFL_FAIL; | 830 | buf->flags |= BUFFL_FAIL; |
581 | } else { | 831 | } else { |
832 | if (d->htgt && t == *d->htgt) /* I'll help myself, thank you. */ | ||
833 | d->htgt = NULL; | ||
582 | n = ahout->scnt << 9; | 834 | n = ahout->scnt << 9; |
583 | switch (ahout->cmdstat) { | 835 | switch (ahout->cmdstat) { |
584 | case WIN_READ: | 836 | case WIN_READ: |
585 | case WIN_READ_EXT: | 837 | case WIN_READ_EXT: |
586 | if (skb->len - sizeof *hin - sizeof *ahin < n) { | 838 | if (skb->len - sizeof *hin - sizeof *ahin < n) { |
587 | printk(KERN_ERR | 839 | printk(KERN_ERR |
588 | "aoe: runt data size in read. skb->len=%d\n", | 840 | "aoe: %s. skb->len=%d need=%ld\n", |
589 | skb->len); | 841 | "runt data size in read", skb->len, n); |
590 | /* fail frame f? just returning will rexmit. */ | 842 | /* fail frame f? just returning will rexmit. */ |
591 | spin_unlock_irqrestore(&d->lock, flags); | 843 | spin_unlock_irqrestore(&d->lock, flags); |
592 | return; | 844 | return; |
@@ -594,32 +846,18 @@ aoecmd_ata_rsp(struct sk_buff *skb) | |||
594 | memcpy(f->bufaddr, ahin+1, n); | 846 | memcpy(f->bufaddr, ahin+1, n); |
595 | case WIN_WRITE: | 847 | case WIN_WRITE: |
596 | case WIN_WRITE_EXT: | 848 | case WIN_WRITE_EXT: |
849 | ifp = getif(t, skb->dev); | ||
850 | if (ifp) { | ||
851 | ifp->lost = 0; | ||
852 | if (n > DEFAULTBCNT) | ||
853 | ifp->lostjumbo = 0; | ||
854 | } | ||
597 | if (f->bcnt -= n) { | 855 | if (f->bcnt -= n) { |
598 | skb = f->skb; | 856 | f->lba += n >> 9; |
599 | f->bufaddr += n; | 857 | f->bufaddr += n; |
600 | put_lba(ahout, f->lba += ahout->scnt); | 858 | resend(d, t, f); |
601 | n = f->bcnt; | 859 | goto xmit; |
602 | if (n > DEFAULTBCNT) | ||
603 | n = DEFAULTBCNT; | ||
604 | ahout->scnt = n >> 9; | ||
605 | if (ahout->aflags & AOEAFL_WRITE) { | ||
606 | skb_fill_page_desc(skb, 0, | ||
607 | virt_to_page(f->bufaddr), | ||
608 | offset_in_page(f->bufaddr), n); | ||
609 | skb->len = sizeof *hout + sizeof *ahout + n; | ||
610 | skb->data_len = n; | ||
611 | } | ||
612 | f->tag = newtag(d); | ||
613 | hout->tag = cpu_to_be32(f->tag); | ||
614 | skb->dev = d->ifp; | ||
615 | skb = skb_clone(skb, GFP_ATOMIC); | ||
616 | spin_unlock_irqrestore(&d->lock, flags); | ||
617 | if (skb) | ||
618 | aoenet_xmit(skb); | ||
619 | return; | ||
620 | } | 860 | } |
621 | if (n > DEFAULTBCNT) | ||
622 | d->lostjumbo = 0; | ||
623 | break; | 861 | break; |
624 | case WIN_IDENTIFY: | 862 | case WIN_IDENTIFY: |
625 | if (skb->len - sizeof *hin - sizeof *ahin < 512) { | 863 | if (skb->len - sizeof *hin - sizeof *ahin < 512) { |
@@ -629,7 +867,7 @@ aoecmd_ata_rsp(struct sk_buff *skb) | |||
629 | spin_unlock_irqrestore(&d->lock, flags); | 867 | spin_unlock_irqrestore(&d->lock, flags); |
630 | return; | 868 | return; |
631 | } | 869 | } |
632 | ataid_complete(d, (char *) (ahin+1)); | 870 | ataid_complete(d, t, (char *) (ahin+1)); |
633 | break; | 871 | break; |
634 | default: | 872 | default: |
635 | printk(KERN_INFO | 873 | printk(KERN_INFO |
@@ -640,28 +878,19 @@ aoecmd_ata_rsp(struct sk_buff *skb) | |||
640 | } | 878 | } |
641 | } | 879 | } |
642 | 880 | ||
643 | if (buf) { | 881 | if (buf && --buf->nframesout == 0 && buf->resid == 0) { |
644 | buf->nframesout -= 1; | 882 | diskstats(d->gd, buf->bio, jiffies - buf->stime); |
645 | if (buf->nframesout == 0 && buf->resid == 0) { | 883 | n = (buf->flags & BUFFL_FAIL) ? -EIO : 0; |
646 | unsigned long duration = jiffies - buf->start_time; | 884 | bio_endio(buf->bio, n); |
647 | unsigned long n_sect = buf->bio->bi_size >> 9; | 885 | mempool_free(buf, d->bufpool); |
648 | struct gendisk *disk = d->gd; | ||
649 | const int rw = bio_data_dir(buf->bio); | ||
650 | |||
651 | disk_stat_inc(disk, ios[rw]); | ||
652 | disk_stat_add(disk, ticks[rw], duration); | ||
653 | disk_stat_add(disk, sectors[rw], n_sect); | ||
654 | disk_stat_add(disk, io_ticks, duration); | ||
655 | n = (buf->flags & BUFFL_FAIL) ? -EIO : 0; | ||
656 | bio_endio(buf->bio, n); | ||
657 | mempool_free(buf, d->bufpool); | ||
658 | } | ||
659 | } | 886 | } |
660 | 887 | ||
661 | f->buf = NULL; | 888 | f->buf = NULL; |
662 | f->tag = FREETAG; | 889 | f->tag = FREETAG; |
890 | t->nout--; | ||
663 | 891 | ||
664 | aoecmd_work(d); | 892 | aoecmd_work(d); |
893 | xmit: | ||
665 | sl = d->sendq_hd; | 894 | sl = d->sendq_hd; |
666 | d->sendq_hd = d->sendq_tl = NULL; | 895 | d->sendq_hd = d->sendq_tl = NULL; |
667 | 896 | ||
@@ -679,23 +908,20 @@ aoecmd_cfg(ushort aoemajor, unsigned char aoeminor) | |||
679 | aoenet_xmit(sl); | 908 | aoenet_xmit(sl); |
680 | } | 909 | } |
681 | 910 | ||
682 | /* | 911 | struct sk_buff * |
683 | * Since we only call this in one place (and it only prepares one frame) | ||
684 | * we just return the skb. Usually we'd chain it up to the aoedev sendq. | ||
685 | */ | ||
686 | static struct sk_buff * | ||
687 | aoecmd_ata_id(struct aoedev *d) | 912 | aoecmd_ata_id(struct aoedev *d) |
688 | { | 913 | { |
689 | struct aoe_hdr *h; | 914 | struct aoe_hdr *h; |
690 | struct aoe_atahdr *ah; | 915 | struct aoe_atahdr *ah; |
691 | struct frame *f; | 916 | struct frame *f; |
692 | struct sk_buff *skb; | 917 | struct sk_buff *skb; |
918 | struct aoetgt *t; | ||
693 | 919 | ||
694 | f = freeframe(d); | 920 | f = freeframe(d); |
695 | if (f == NULL) { | 921 | if (f == NULL) |
696 | printk(KERN_ERR "aoe: can't get a frame. This shouldn't happen.\n"); | ||
697 | return NULL; | 922 | return NULL; |
698 | } | 923 | |
924 | t = *d->tgt; | ||
699 | 925 | ||
700 | /* initialize the headers & frame */ | 926 | /* initialize the headers & frame */ |
701 | skb = f->skb; | 927 | skb = f->skb; |
@@ -703,7 +929,8 @@ aoecmd_ata_id(struct aoedev *d) | |||
703 | ah = (struct aoe_atahdr *) (h+1); | 929 | ah = (struct aoe_atahdr *) (h+1); |
704 | skb_put(skb, sizeof *h + sizeof *ah); | 930 | skb_put(skb, sizeof *h + sizeof *ah); |
705 | memset(h, 0, skb->len); | 931 | memset(h, 0, skb->len); |
706 | f->tag = aoehdr_atainit(d, h); | 932 | f->tag = aoehdr_atainit(d, t, h); |
933 | t->nout++; | ||
707 | f->waited = 0; | 934 | f->waited = 0; |
708 | 935 | ||
709 | /* set up ata header */ | 936 | /* set up ata header */ |
@@ -711,7 +938,7 @@ aoecmd_ata_id(struct aoedev *d) | |||
711 | ah->cmdstat = WIN_IDENTIFY; | 938 | ah->cmdstat = WIN_IDENTIFY; |
712 | ah->lba3 = 0xa0; | 939 | ah->lba3 = 0xa0; |
713 | 940 | ||
714 | skb->dev = d->ifp; | 941 | skb->dev = t->ifp->nd; |
715 | 942 | ||
716 | d->rttavg = MAXTIMER; | 943 | d->rttavg = MAXTIMER; |
717 | d->timer.function = rexmit_timer; | 944 | d->timer.function = rexmit_timer; |
@@ -719,15 +946,52 @@ aoecmd_ata_id(struct aoedev *d) | |||
719 | return skb_clone(skb, GFP_ATOMIC); | 946 | return skb_clone(skb, GFP_ATOMIC); |
720 | } | 947 | } |
721 | 948 | ||
949 | static struct aoetgt * | ||
950 | addtgt(struct aoedev *d, char *addr, ulong nframes) | ||
951 | { | ||
952 | struct aoetgt *t, **tt, **te; | ||
953 | struct frame *f, *e; | ||
954 | |||
955 | tt = d->targets; | ||
956 | te = tt + NTARGETS; | ||
957 | for (; tt < te && *tt; tt++) | ||
958 | ; | ||
959 | |||
960 | if (tt == te) { | ||
961 | printk(KERN_INFO | ||
962 | "aoe: device addtgt failure; too many targets\n"); | ||
963 | return NULL; | ||
964 | } | ||
965 | t = kcalloc(1, sizeof *t, GFP_ATOMIC); | ||
966 | f = kcalloc(nframes, sizeof *f, GFP_ATOMIC); | ||
967 | if (!t || !f) { | ||
968 | kfree(f); | ||
969 | kfree(t); | ||
970 | printk(KERN_INFO "aoe: cannot allocate memory to add target\n"); | ||
971 | return NULL; | ||
972 | } | ||
973 | |||
974 | t->nframes = nframes; | ||
975 | t->frames = f; | ||
976 | e = f + nframes; | ||
977 | for (; f < e; f++) | ||
978 | f->tag = FREETAG; | ||
979 | memcpy(t->addr, addr, sizeof t->addr); | ||
980 | t->ifp = t->ifs; | ||
981 | t->maxout = t->nframes; | ||
982 | return *tt = t; | ||
983 | } | ||
984 | |||
722 | void | 985 | void |
723 | aoecmd_cfg_rsp(struct sk_buff *skb) | 986 | aoecmd_cfg_rsp(struct sk_buff *skb) |
724 | { | 987 | { |
725 | struct aoedev *d; | 988 | struct aoedev *d; |
726 | struct aoe_hdr *h; | 989 | struct aoe_hdr *h; |
727 | struct aoe_cfghdr *ch; | 990 | struct aoe_cfghdr *ch; |
991 | struct aoetgt *t; | ||
992 | struct aoeif *ifp; | ||
728 | ulong flags, sysminor, aoemajor; | 993 | ulong flags, sysminor, aoemajor; |
729 | struct sk_buff *sl; | 994 | struct sk_buff *sl; |
730 | enum { MAXFRAMES = 16 }; | ||
731 | u16 n; | 995 | u16 n; |
732 | 996 | ||
733 | h = (struct aoe_hdr *) skb_mac_header(skb); | 997 | h = (struct aoe_hdr *) skb_mac_header(skb); |
@@ -752,10 +1016,10 @@ aoecmd_cfg_rsp(struct sk_buff *skb) | |||
752 | } | 1016 | } |
753 | 1017 | ||
754 | n = be16_to_cpu(ch->bufcnt); | 1018 | n = be16_to_cpu(ch->bufcnt); |
755 | if (n > MAXFRAMES) /* keep it reasonable */ | 1019 | if (n > aoe_maxout) /* keep it reasonable */ |
756 | n = MAXFRAMES; | 1020 | n = aoe_maxout; |
757 | 1021 | ||
758 | d = aoedev_by_sysminor_m(sysminor, n); | 1022 | d = aoedev_by_sysminor_m(sysminor); |
759 | if (d == NULL) { | 1023 | if (d == NULL) { |
760 | printk(KERN_INFO "aoe: device sysminor_m failure\n"); | 1024 | printk(KERN_INFO "aoe: device sysminor_m failure\n"); |
761 | return; | 1025 | return; |
@@ -763,38 +1027,74 @@ aoecmd_cfg_rsp(struct sk_buff *skb) | |||
763 | 1027 | ||
764 | spin_lock_irqsave(&d->lock, flags); | 1028 | spin_lock_irqsave(&d->lock, flags); |
765 | 1029 | ||
766 | /* permit device to migrate mac and network interface */ | 1030 | t = gettgt(d, h->src); |
767 | d->ifp = skb->dev; | 1031 | if (!t) { |
768 | memcpy(d->addr, h->src, sizeof d->addr); | 1032 | t = addtgt(d, h->src, n); |
769 | if (!(d->flags & DEVFL_MAXBCNT)) { | 1033 | if (!t) { |
770 | n = d->ifp->mtu; | 1034 | spin_unlock_irqrestore(&d->lock, flags); |
1035 | return; | ||
1036 | } | ||
1037 | } | ||
1038 | ifp = getif(t, skb->dev); | ||
1039 | if (!ifp) { | ||
1040 | ifp = addif(t, skb->dev); | ||
1041 | if (!ifp) { | ||
1042 | printk(KERN_INFO | ||
1043 | "aoe: device addif failure; " | ||
1044 | "too many interfaces?\n"); | ||
1045 | spin_unlock_irqrestore(&d->lock, flags); | ||
1046 | return; | ||
1047 | } | ||
1048 | } | ||
1049 | if (ifp->maxbcnt) { | ||
1050 | n = ifp->nd->mtu; | ||
771 | n -= sizeof (struct aoe_hdr) + sizeof (struct aoe_atahdr); | 1051 | n -= sizeof (struct aoe_hdr) + sizeof (struct aoe_atahdr); |
772 | n /= 512; | 1052 | n /= 512; |
773 | if (n > ch->scnt) | 1053 | if (n > ch->scnt) |
774 | n = ch->scnt; | 1054 | n = ch->scnt; |
775 | n = n ? n * 512 : DEFAULTBCNT; | 1055 | n = n ? n * 512 : DEFAULTBCNT; |
776 | if (n != d->maxbcnt) { | 1056 | if (n != ifp->maxbcnt) { |
777 | printk(KERN_INFO | 1057 | printk(KERN_INFO |
778 | "aoe: e%ld.%ld: setting %d byte data frames on %s\n", | 1058 | "aoe: e%ld.%d: setting %d%s%s:%012llx\n", |
779 | d->aoemajor, d->aoeminor, n, d->ifp->name); | 1059 | d->aoemajor, d->aoeminor, n, |
780 | d->maxbcnt = n; | 1060 | " byte data frames on ", ifp->nd->name, |
1061 | mac_addr(t->addr)); | ||
1062 | ifp->maxbcnt = n; | ||
781 | } | 1063 | } |
782 | } | 1064 | } |
783 | 1065 | ||
784 | /* don't change users' perspective */ | 1066 | /* don't change users' perspective */ |
785 | if (d->nopen && !(d->flags & DEVFL_PAUSE)) { | 1067 | if (d->nopen) { |
786 | spin_unlock_irqrestore(&d->lock, flags); | 1068 | spin_unlock_irqrestore(&d->lock, flags); |
787 | return; | 1069 | return; |
788 | } | 1070 | } |
789 | d->flags |= DEVFL_PAUSE; /* force pause */ | ||
790 | d->mintimer = MINTIMER; | ||
791 | d->fw_ver = be16_to_cpu(ch->fwver); | 1071 | d->fw_ver = be16_to_cpu(ch->fwver); |
792 | 1072 | ||
793 | /* check for already outstanding ataid */ | 1073 | sl = aoecmd_ata_id(d); |
794 | sl = aoedev_isbusy(d) == 0 ? aoecmd_ata_id(d) : NULL; | ||
795 | 1074 | ||
796 | spin_unlock_irqrestore(&d->lock, flags); | 1075 | spin_unlock_irqrestore(&d->lock, flags); |
797 | 1076 | ||
798 | aoenet_xmit(sl); | 1077 | aoenet_xmit(sl); |
799 | } | 1078 | } |
800 | 1079 | ||
1080 | void | ||
1081 | aoecmd_cleanslate(struct aoedev *d) | ||
1082 | { | ||
1083 | struct aoetgt **t, **te; | ||
1084 | struct aoeif *p, *e; | ||
1085 | |||
1086 | d->mintimer = MINTIMER; | ||
1087 | |||
1088 | t = d->targets; | ||
1089 | te = t + NTARGETS; | ||
1090 | for (; t < te && *t; t++) { | ||
1091 | (*t)->maxout = (*t)->nframes; | ||
1092 | p = (*t)->ifs; | ||
1093 | e = p + NAOEIFS; | ||
1094 | for (; p < e; p++) { | ||
1095 | p->lostjumbo = 0; | ||
1096 | p->lost = 0; | ||
1097 | p->maxbcnt = DEFAULTBCNT; | ||
1098 | } | ||
1099 | } | ||
1100 | } | ||