diff options
author | Ed L. Cashin <ecashin@coraid.com> | 2006-01-19 13:46:19 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-03-24 01:01:55 -0500 |
commit | 3ae1c24e395b2b65326439622223d88d92bfa03a (patch) | |
tree | df1e7e8e63a37ed91407ea5da6535b64f50e64a2 /drivers/block/aoe | |
parent | 50bba752ca0a740a6ba9eb96d61ef7bbdfe405cf (diff) |
[PATCH] aoe [2/8]: support dynamic resizing of AoE devices
Allow the driver to recognize AoE devices that have changed size.
Devices not in use are updated automatically, and devices that are in
use are updated at user request.
Signed-off-by: "Ed L. Cashin" <ecashin@coraid.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/block/aoe')
-rw-r--r-- | drivers/block/aoe/aoe.h | 12 | ||||
-rw-r--r-- | drivers/block/aoe/aoeblk.c | 22 | ||||
-rw-r--r-- | drivers/block/aoe/aoechr.c | 37 | ||||
-rw-r--r-- | drivers/block/aoe/aoecmd.c | 177 | ||||
-rw-r--r-- | drivers/block/aoe/aoedev.c | 69 |
5 files changed, 220 insertions, 97 deletions
diff --git a/drivers/block/aoe/aoe.h b/drivers/block/aoe/aoe.h index 881c48d941b7..bb7dd91e5d48 100644 --- a/drivers/block/aoe/aoe.h +++ b/drivers/block/aoe/aoe.h | |||
@@ -75,8 +75,9 @@ enum { | |||
75 | DEVFL_TKILL = (1<<1), /* flag for timer to know when to kill self */ | 75 | DEVFL_TKILL = (1<<1), /* flag for timer to know when to kill self */ |
76 | DEVFL_EXT = (1<<2), /* device accepts lba48 commands */ | 76 | DEVFL_EXT = (1<<2), /* device accepts lba48 commands */ |
77 | DEVFL_CLOSEWAIT = (1<<3), /* device is waiting for all closes to revalidate */ | 77 | DEVFL_CLOSEWAIT = (1<<3), /* device is waiting for all closes to revalidate */ |
78 | DEVFL_WC_UPDATE = (1<<4), /* this device needs to update write cache status */ | 78 | DEVFL_GDALLOC = (1<<4), /* need to alloc gendisk */ |
79 | DEVFL_WORKON = (1<<4), | 79 | DEVFL_PAUSE = (1<<5), |
80 | DEVFL_NEWSIZE = (1<<6), /* need to update dev size in block layer */ | ||
80 | 81 | ||
81 | BUFFL_FAIL = 1, | 82 | BUFFL_FAIL = 1, |
82 | }; | 83 | }; |
@@ -152,16 +153,17 @@ void aoechr_exit(void); | |||
152 | void aoechr_error(char *); | 153 | void aoechr_error(char *); |
153 | 154 | ||
154 | void aoecmd_work(struct aoedev *d); | 155 | void aoecmd_work(struct aoedev *d); |
155 | void aoecmd_cfg(ushort, unsigned char); | 156 | void aoecmd_cfg(ushort aoemajor, unsigned char aoeminor); |
156 | void aoecmd_ata_rsp(struct sk_buff *); | 157 | void aoecmd_ata_rsp(struct sk_buff *); |
157 | void aoecmd_cfg_rsp(struct sk_buff *); | 158 | void aoecmd_cfg_rsp(struct sk_buff *); |
159 | void aoecmd_sleepwork(void *vp); | ||
158 | 160 | ||
159 | int aoedev_init(void); | 161 | int aoedev_init(void); |
160 | void aoedev_exit(void); | 162 | void aoedev_exit(void); |
161 | struct aoedev *aoedev_by_aoeaddr(int maj, int min); | 163 | struct aoedev *aoedev_by_aoeaddr(int maj, int min); |
164 | struct aoedev *aoedev_by_sysminor_m(ulong sysminor, ulong bufcnt); | ||
162 | void aoedev_downdev(struct aoedev *d); | 165 | void aoedev_downdev(struct aoedev *d); |
163 | struct aoedev *aoedev_set(ulong, unsigned char *, struct net_device *, ulong); | 166 | int aoedev_isbusy(struct aoedev *d); |
164 | int aoedev_busy(void); | ||
165 | 167 | ||
166 | int aoenet_init(void); | 168 | int aoenet_init(void); |
167 | void aoenet_exit(void); | 169 | void aoenet_exit(void); |
diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c index c05ee8bffd97..039c0911fa8f 100644 --- a/drivers/block/aoe/aoeblk.c +++ b/drivers/block/aoe/aoeblk.c | |||
@@ -22,7 +22,9 @@ static ssize_t aoedisk_show_state(struct gendisk * disk, char *page) | |||
22 | return snprintf(page, PAGE_SIZE, | 22 | return snprintf(page, PAGE_SIZE, |
23 | "%s%s\n", | 23 | "%s%s\n", |
24 | (d->flags & DEVFL_UP) ? "up" : "down", | 24 | (d->flags & DEVFL_UP) ? "up" : "down", |
25 | (d->flags & DEVFL_CLOSEWAIT) ? ",closewait" : ""); | 25 | (d->flags & DEVFL_PAUSE) ? ",paused" : |
26 | (d->nopen && !(d->flags & DEVFL_UP)) ? ",closewait" : ""); | ||
27 | /* I'd rather see nopen exported so we can ditch closewait */ | ||
26 | } | 28 | } |
27 | static ssize_t aoedisk_show_mac(struct gendisk * disk, char *page) | 29 | static ssize_t aoedisk_show_mac(struct gendisk * disk, char *page) |
28 | { | 30 | { |
@@ -107,8 +109,7 @@ aoeblk_release(struct inode *inode, struct file *filp) | |||
107 | 109 | ||
108 | spin_lock_irqsave(&d->lock, flags); | 110 | spin_lock_irqsave(&d->lock, flags); |
109 | 111 | ||
110 | if (--d->nopen == 0 && (d->flags & DEVFL_CLOSEWAIT)) { | 112 | if (--d->nopen == 0 && !(d->flags & DEVFL_UP)) { |
111 | d->flags &= ~DEVFL_CLOSEWAIT; | ||
112 | spin_unlock_irqrestore(&d->lock, flags); | 113 | spin_unlock_irqrestore(&d->lock, flags); |
113 | aoecmd_cfg(d->aoemajor, d->aoeminor); | 114 | aoecmd_cfg(d->aoemajor, d->aoeminor); |
114 | return 0; | 115 | return 0; |
@@ -158,14 +159,14 @@ aoeblk_make_request(request_queue_t *q, struct bio *bio) | |||
158 | } | 159 | } |
159 | 160 | ||
160 | list_add_tail(&buf->bufs, &d->bufq); | 161 | list_add_tail(&buf->bufs, &d->bufq); |
161 | aoecmd_work(d); | ||
162 | 162 | ||
163 | aoecmd_work(d); | ||
163 | sl = d->sendq_hd; | 164 | sl = d->sendq_hd; |
164 | d->sendq_hd = d->sendq_tl = NULL; | 165 | d->sendq_hd = d->sendq_tl = NULL; |
165 | 166 | ||
166 | spin_unlock_irqrestore(&d->lock, flags); | 167 | spin_unlock_irqrestore(&d->lock, flags); |
167 | |||
168 | aoenet_xmit(sl); | 168 | aoenet_xmit(sl); |
169 | |||
169 | return 0; | 170 | return 0; |
170 | } | 171 | } |
171 | 172 | ||
@@ -205,7 +206,7 @@ aoeblk_gdalloc(void *vp) | |||
205 | printk(KERN_ERR "aoe: aoeblk_gdalloc: cannot allocate disk " | 206 | printk(KERN_ERR "aoe: aoeblk_gdalloc: cannot allocate disk " |
206 | "structure for %ld.%ld\n", d->aoemajor, d->aoeminor); | 207 | "structure for %ld.%ld\n", d->aoemajor, d->aoeminor); |
207 | spin_lock_irqsave(&d->lock, flags); | 208 | spin_lock_irqsave(&d->lock, flags); |
208 | d->flags &= ~DEVFL_WORKON; | 209 | d->flags &= ~DEVFL_GDALLOC; |
209 | spin_unlock_irqrestore(&d->lock, flags); | 210 | spin_unlock_irqrestore(&d->lock, flags); |
210 | return; | 211 | return; |
211 | } | 212 | } |
@@ -218,7 +219,7 @@ aoeblk_gdalloc(void *vp) | |||
218 | "for %ld.%ld\n", d->aoemajor, d->aoeminor); | 219 | "for %ld.%ld\n", d->aoemajor, d->aoeminor); |
219 | put_disk(gd); | 220 | put_disk(gd); |
220 | spin_lock_irqsave(&d->lock, flags); | 221 | spin_lock_irqsave(&d->lock, flags); |
221 | d->flags &= ~DEVFL_WORKON; | 222 | d->flags &= ~DEVFL_GDALLOC; |
222 | spin_unlock_irqrestore(&d->lock, flags); | 223 | spin_unlock_irqrestore(&d->lock, flags); |
223 | return; | 224 | return; |
224 | } | 225 | } |
@@ -235,18 +236,13 @@ aoeblk_gdalloc(void *vp) | |||
235 | 236 | ||
236 | gd->queue = &d->blkq; | 237 | gd->queue = &d->blkq; |
237 | d->gd = gd; | 238 | d->gd = gd; |
238 | d->flags &= ~DEVFL_WORKON; | 239 | d->flags &= ~DEVFL_GDALLOC; |
239 | d->flags |= DEVFL_UP; | 240 | d->flags |= DEVFL_UP; |
240 | 241 | ||
241 | spin_unlock_irqrestore(&d->lock, flags); | 242 | spin_unlock_irqrestore(&d->lock, flags); |
242 | 243 | ||
243 | add_disk(gd); | 244 | add_disk(gd); |
244 | aoedisk_add_sysfs(d); | 245 | aoedisk_add_sysfs(d); |
245 | |||
246 | printk(KERN_INFO "aoe: %012llx e%lu.%lu v%04x has %llu " | ||
247 | "sectors\n", (unsigned long long)mac_addr(d->addr), | ||
248 | d->aoemajor, d->aoeminor, | ||
249 | d->fw_ver, (long long)d->ssize); | ||
250 | } | 246 | } |
251 | 247 | ||
252 | void | 248 | void |
diff --git a/drivers/block/aoe/aoechr.c b/drivers/block/aoe/aoechr.c index 41ae0ede619a..5327f553b4f5 100644 --- a/drivers/block/aoe/aoechr.c +++ b/drivers/block/aoe/aoechr.c | |||
@@ -13,6 +13,7 @@ enum { | |||
13 | MINOR_ERR = 2, | 13 | MINOR_ERR = 2, |
14 | MINOR_DISCOVER, | 14 | MINOR_DISCOVER, |
15 | MINOR_INTERFACES, | 15 | MINOR_INTERFACES, |
16 | MINOR_REVALIDATE, | ||
16 | MSGSZ = 2048, | 17 | MSGSZ = 2048, |
17 | NARGS = 10, | 18 | NARGS = 10, |
18 | NMSG = 100, /* message backlog to retain */ | 19 | NMSG = 100, /* message backlog to retain */ |
@@ -41,6 +42,7 @@ static struct aoe_chardev chardevs[] = { | |||
41 | { MINOR_ERR, "err" }, | 42 | { MINOR_ERR, "err" }, |
42 | { MINOR_DISCOVER, "discover" }, | 43 | { MINOR_DISCOVER, "discover" }, |
43 | { MINOR_INTERFACES, "interfaces" }, | 44 | { MINOR_INTERFACES, "interfaces" }, |
45 | { MINOR_REVALIDATE, "revalidate" }, | ||
44 | }; | 46 | }; |
45 | 47 | ||
46 | static int | 48 | static int |
@@ -62,6 +64,39 @@ interfaces(const char __user *str, size_t size) | |||
62 | return 0; | 64 | return 0; |
63 | } | 65 | } |
64 | 66 | ||
67 | static int | ||
68 | revalidate(const char __user *str, size_t size) | ||
69 | { | ||
70 | int major, minor, n; | ||
71 | ulong flags; | ||
72 | struct aoedev *d; | ||
73 | char buf[16]; | ||
74 | |||
75 | if (size >= sizeof buf) | ||
76 | return -EINVAL; | ||
77 | buf[sizeof buf - 1] = '\0'; | ||
78 | if (copy_from_user(buf, str, size)) | ||
79 | return -EFAULT; | ||
80 | |||
81 | /* should be e%d.%d format */ | ||
82 | n = sscanf(buf, "e%d.%d", &major, &minor); | ||
83 | if (n != 2) { | ||
84 | printk(KERN_ERR "aoe: %s: invalid device specification\n", | ||
85 | __FUNCTION__); | ||
86 | return -EINVAL; | ||
87 | } | ||
88 | d = aoedev_by_aoeaddr(major, minor); | ||
89 | if (!d) | ||
90 | return -EINVAL; | ||
91 | |||
92 | spin_lock_irqsave(&d->lock, flags); | ||
93 | d->flags |= DEVFL_PAUSE; | ||
94 | spin_unlock_irqrestore(&d->lock, flags); | ||
95 | aoecmd_cfg(major, minor); | ||
96 | |||
97 | return 0; | ||
98 | } | ||
99 | |||
65 | void | 100 | void |
66 | aoechr_error(char *msg) | 101 | aoechr_error(char *msg) |
67 | { | 102 | { |
@@ -114,6 +149,8 @@ aoechr_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offp | |||
114 | case MINOR_INTERFACES: | 149 | case MINOR_INTERFACES: |
115 | ret = interfaces(buf, cnt); | 150 | ret = interfaces(buf, cnt); |
116 | break; | 151 | break; |
152 | case MINOR_REVALIDATE: | ||
153 | ret = revalidate(buf, cnt); | ||
117 | } | 154 | } |
118 | if (ret == 0) | 155 | if (ret == 0) |
119 | ret = cnt; | 156 | ret = cnt; |
diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index 4ab01ce5cf36..150eb78cd5a9 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c | |||
@@ -8,6 +8,7 @@ | |||
8 | #include <linux/blkdev.h> | 8 | #include <linux/blkdev.h> |
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 <asm/unaligned.h> | 12 | #include <asm/unaligned.h> |
12 | #include "aoe.h" | 13 | #include "aoe.h" |
13 | 14 | ||
@@ -189,12 +190,67 @@ aoecmd_ata_rw(struct aoedev *d, struct frame *f) | |||
189 | } | 190 | } |
190 | } | 191 | } |
191 | 192 | ||
193 | /* some callers cannot sleep, and they can call this function, | ||
194 | * transmitting the packets later, when interrupts are on | ||
195 | */ | ||
196 | static struct sk_buff * | ||
197 | aoecmd_cfg_pkts(ushort aoemajor, unsigned char aoeminor, struct sk_buff **tail) | ||
198 | { | ||
199 | struct aoe_hdr *h; | ||
200 | struct aoe_cfghdr *ch; | ||
201 | struct sk_buff *skb, *sl, *sl_tail; | ||
202 | struct net_device *ifp; | ||
203 | |||
204 | sl = sl_tail = NULL; | ||
205 | |||
206 | read_lock(&dev_base_lock); | ||
207 | for (ifp = dev_base; ifp; dev_put(ifp), ifp = ifp->next) { | ||
208 | dev_hold(ifp); | ||
209 | if (!is_aoe_netif(ifp)) | ||
210 | continue; | ||
211 | |||
212 | skb = new_skb(ifp, sizeof *h + sizeof *ch); | ||
213 | if (skb == NULL) { | ||
214 | printk(KERN_INFO "aoe: aoecmd_cfg: skb alloc failure\n"); | ||
215 | continue; | ||
216 | } | ||
217 | if (sl_tail == NULL) | ||
218 | sl_tail = skb; | ||
219 | h = (struct aoe_hdr *) skb->mac.raw; | ||
220 | memset(h, 0, sizeof *h + sizeof *ch); | ||
221 | |||
222 | memset(h->dst, 0xff, sizeof h->dst); | ||
223 | memcpy(h->src, ifp->dev_addr, sizeof h->src); | ||
224 | h->type = __constant_cpu_to_be16(ETH_P_AOE); | ||
225 | h->verfl = AOE_HVER; | ||
226 | h->major = cpu_to_be16(aoemajor); | ||
227 | h->minor = aoeminor; | ||
228 | h->cmd = AOECMD_CFG; | ||
229 | |||
230 | skb->next = sl; | ||
231 | sl = skb; | ||
232 | } | ||
233 | read_unlock(&dev_base_lock); | ||
234 | |||
235 | if (tail != NULL) | ||
236 | *tail = sl_tail; | ||
237 | return sl; | ||
238 | } | ||
239 | |||
192 | /* enters with d->lock held */ | 240 | /* enters with d->lock held */ |
193 | void | 241 | void |
194 | aoecmd_work(struct aoedev *d) | 242 | aoecmd_work(struct aoedev *d) |
195 | { | 243 | { |
196 | struct frame *f; | 244 | struct frame *f; |
197 | struct buf *buf; | 245 | struct buf *buf; |
246 | |||
247 | if (d->flags & DEVFL_PAUSE) { | ||
248 | if (!aoedev_isbusy(d)) | ||
249 | d->sendq_hd = aoecmd_cfg_pkts(d->aoemajor, | ||
250 | d->aoeminor, &d->sendq_tl); | ||
251 | return; | ||
252 | } | ||
253 | |||
198 | loop: | 254 | loop: |
199 | f = getframe(d, FREETAG); | 255 | f = getframe(d, FREETAG); |
200 | if (f == NULL) | 256 | if (f == NULL) |
@@ -306,6 +362,37 @@ tdie: spin_unlock_irqrestore(&d->lock, flags); | |||
306 | aoenet_xmit(sl); | 362 | aoenet_xmit(sl); |
307 | } | 363 | } |
308 | 364 | ||
365 | /* this function performs work that has been deferred until sleeping is OK | ||
366 | */ | ||
367 | void | ||
368 | aoecmd_sleepwork(void *vp) | ||
369 | { | ||
370 | struct aoedev *d = (struct aoedev *) vp; | ||
371 | |||
372 | if (d->flags & DEVFL_GDALLOC) | ||
373 | aoeblk_gdalloc(d); | ||
374 | |||
375 | if (d->flags & DEVFL_NEWSIZE) { | ||
376 | struct block_device *bd; | ||
377 | unsigned long flags; | ||
378 | u64 ssize; | ||
379 | |||
380 | ssize = d->gd->capacity; | ||
381 | bd = bdget_disk(d->gd, 0); | ||
382 | |||
383 | if (bd) { | ||
384 | mutex_lock(&bd->bd_inode->i_mutex); | ||
385 | i_size_write(bd->bd_inode, (loff_t)ssize<<9); | ||
386 | mutex_unlock(&bd->bd_inode->i_mutex); | ||
387 | bdput(bd); | ||
388 | } | ||
389 | spin_lock_irqsave(&d->lock, flags); | ||
390 | d->flags |= DEVFL_UP; | ||
391 | d->flags &= ~DEVFL_NEWSIZE; | ||
392 | spin_unlock_irqrestore(&d->lock, flags); | ||
393 | } | ||
394 | } | ||
395 | |||
309 | static void | 396 | static void |
310 | ataid_complete(struct aoedev *d, unsigned char *id) | 397 | ataid_complete(struct aoedev *d, unsigned char *id) |
311 | { | 398 | { |
@@ -340,21 +427,29 @@ ataid_complete(struct aoedev *d, unsigned char *id) | |||
340 | d->geo.heads = le16_to_cpu(get_unaligned((__le16 *) &id[55<<1])); | 427 | d->geo.heads = le16_to_cpu(get_unaligned((__le16 *) &id[55<<1])); |
341 | d->geo.sectors = le16_to_cpu(get_unaligned((__le16 *) &id[56<<1])); | 428 | d->geo.sectors = le16_to_cpu(get_unaligned((__le16 *) &id[56<<1])); |
342 | } | 429 | } |
430 | |||
431 | if (d->ssize != ssize) | ||
432 | printk(KERN_INFO "aoe: %012llx e%lu.%lu v%04x has %llu " | ||
433 | "sectors\n", (unsigned long long)mac_addr(d->addr), | ||
434 | d->aoemajor, d->aoeminor, | ||
435 | d->fw_ver, (long long)ssize); | ||
343 | d->ssize = ssize; | 436 | d->ssize = ssize; |
344 | d->geo.start = 0; | 437 | d->geo.start = 0; |
345 | if (d->gd != NULL) { | 438 | if (d->gd != NULL) { |
346 | d->gd->capacity = ssize; | 439 | d->gd->capacity = ssize; |
347 | d->flags |= DEVFL_UP; | 440 | d->flags |= DEVFL_NEWSIZE; |
348 | return; | 441 | } else { |
349 | } | 442 | if (d->flags & DEVFL_GDALLOC) { |
350 | if (d->flags & DEVFL_WORKON) { | 443 | printk(KERN_INFO "aoe: %s: %s e%lu.%lu, %s\n", |
351 | printk(KERN_INFO "aoe: ataid_complete: can't schedule work, it's already on! " | 444 | __FUNCTION__, |
352 | "(This really shouldn't happen).\n"); | 445 | "can't schedule work for", |
353 | return; | 446 | d->aoemajor, d->aoeminor, |
447 | "it's already on! (This really shouldn't happen).\n"); | ||
448 | return; | ||
449 | } | ||
450 | d->flags |= DEVFL_GDALLOC; | ||
354 | } | 451 | } |
355 | INIT_WORK(&d->work, aoeblk_gdalloc, d); | ||
356 | schedule_work(&d->work); | 452 | schedule_work(&d->work); |
357 | d->flags |= DEVFL_WORKON; | ||
358 | } | 453 | } |
359 | 454 | ||
360 | static void | 455 | static void |
@@ -452,7 +547,7 @@ aoecmd_ata_rsp(struct sk_buff *skb) | |||
452 | return; | 547 | return; |
453 | } | 548 | } |
454 | ataid_complete(d, (char *) (ahin+1)); | 549 | ataid_complete(d, (char *) (ahin+1)); |
455 | /* d->flags |= DEVFL_WC_UPDATE; */ | 550 | d->flags &= ~DEVFL_PAUSE; |
456 | break; | 551 | break; |
457 | default: | 552 | default: |
458 | printk(KERN_INFO "aoe: aoecmd_ata_rsp: unrecognized " | 553 | printk(KERN_INFO "aoe: aoecmd_ata_rsp: unrecognized " |
@@ -485,51 +580,19 @@ aoecmd_ata_rsp(struct sk_buff *skb) | |||
485 | f->tag = FREETAG; | 580 | f->tag = FREETAG; |
486 | 581 | ||
487 | aoecmd_work(d); | 582 | aoecmd_work(d); |
488 | |||
489 | sl = d->sendq_hd; | 583 | sl = d->sendq_hd; |
490 | d->sendq_hd = d->sendq_tl = NULL; | 584 | d->sendq_hd = d->sendq_tl = NULL; |
491 | 585 | ||
492 | spin_unlock_irqrestore(&d->lock, flags); | 586 | spin_unlock_irqrestore(&d->lock, flags); |
493 | |||
494 | aoenet_xmit(sl); | 587 | aoenet_xmit(sl); |
495 | } | 588 | } |
496 | 589 | ||
497 | void | 590 | void |
498 | aoecmd_cfg(ushort aoemajor, unsigned char aoeminor) | 591 | aoecmd_cfg(ushort aoemajor, unsigned char aoeminor) |
499 | { | 592 | { |
500 | struct aoe_hdr *h; | 593 | struct sk_buff *sl; |
501 | struct aoe_cfghdr *ch; | ||
502 | struct sk_buff *skb, *sl; | ||
503 | struct net_device *ifp; | ||
504 | |||
505 | sl = NULL; | ||
506 | |||
507 | read_lock(&dev_base_lock); | ||
508 | for (ifp = dev_base; ifp; dev_put(ifp), ifp = ifp->next) { | ||
509 | dev_hold(ifp); | ||
510 | if (!is_aoe_netif(ifp)) | ||
511 | continue; | ||
512 | |||
513 | skb = new_skb(ifp, sizeof *h + sizeof *ch); | ||
514 | if (skb == NULL) { | ||
515 | printk(KERN_INFO "aoe: aoecmd_cfg: skb alloc failure\n"); | ||
516 | continue; | ||
517 | } | ||
518 | h = (struct aoe_hdr *) skb->mac.raw; | ||
519 | memset(h, 0, sizeof *h + sizeof *ch); | ||
520 | |||
521 | memset(h->dst, 0xff, sizeof h->dst); | ||
522 | memcpy(h->src, ifp->dev_addr, sizeof h->src); | ||
523 | h->type = __constant_cpu_to_be16(ETH_P_AOE); | ||
524 | h->verfl = AOE_HVER; | ||
525 | h->major = cpu_to_be16(aoemajor); | ||
526 | h->minor = aoeminor; | ||
527 | h->cmd = AOECMD_CFG; | ||
528 | 594 | ||
529 | skb->next = sl; | 595 | sl = aoecmd_cfg_pkts(aoemajor, aoeminor, NULL); |
530 | sl = skb; | ||
531 | } | ||
532 | read_unlock(&dev_base_lock); | ||
533 | 596 | ||
534 | aoenet_xmit(sl); | 597 | aoenet_xmit(sl); |
535 | } | 598 | } |
@@ -562,9 +625,6 @@ aoecmd_ata_id(struct aoedev *d) | |||
562 | f->waited = 0; | 625 | f->waited = 0; |
563 | f->writedatalen = 0; | 626 | f->writedatalen = 0; |
564 | 627 | ||
565 | /* this message initializes the device, so we reset the rttavg */ | ||
566 | d->rttavg = MAXTIMER; | ||
567 | |||
568 | /* set up ata header */ | 628 | /* set up ata header */ |
569 | ah->scnt = 1; | 629 | ah->scnt = 1; |
570 | ah->cmdstat = WIN_IDENTIFY; | 630 | ah->cmdstat = WIN_IDENTIFY; |
@@ -572,12 +632,8 @@ aoecmd_ata_id(struct aoedev *d) | |||
572 | 632 | ||
573 | skb = skb_prepare(d, f); | 633 | skb = skb_prepare(d, f); |
574 | 634 | ||
575 | /* we now want to start the rexmit tracking */ | 635 | d->rttavg = MAXTIMER; |
576 | d->flags &= ~DEVFL_TKILL; | ||
577 | d->timer.data = (ulong) d; | ||
578 | d->timer.function = rexmit_timer; | 636 | d->timer.function = rexmit_timer; |
579 | d->timer.expires = jiffies + TIMERTICK; | ||
580 | add_timer(&d->timer); | ||
581 | 637 | ||
582 | return skb; | 638 | return skb; |
583 | } | 639 | } |
@@ -619,23 +675,28 @@ aoecmd_cfg_rsp(struct sk_buff *skb) | |||
619 | if (bufcnt > MAXFRAMES) /* keep it reasonable */ | 675 | if (bufcnt > MAXFRAMES) /* keep it reasonable */ |
620 | bufcnt = MAXFRAMES; | 676 | bufcnt = MAXFRAMES; |
621 | 677 | ||
622 | d = aoedev_set(sysminor, h->src, skb->dev, bufcnt); | 678 | d = aoedev_by_sysminor_m(sysminor, bufcnt); |
623 | if (d == NULL) { | 679 | if (d == NULL) { |
624 | printk(KERN_INFO "aoe: aoecmd_cfg_rsp: device set failure\n"); | 680 | printk(KERN_INFO "aoe: aoecmd_cfg_rsp: device sysminor_m failure\n"); |
625 | return; | 681 | return; |
626 | } | 682 | } |
627 | 683 | ||
628 | spin_lock_irqsave(&d->lock, flags); | 684 | spin_lock_irqsave(&d->lock, flags); |
629 | 685 | ||
630 | if (d->flags & (DEVFL_UP | DEVFL_CLOSEWAIT)) { | 686 | /* permit device to migrate mac and network interface */ |
687 | d->ifp = skb->dev; | ||
688 | memcpy(d->addr, h->src, sizeof d->addr); | ||
689 | |||
690 | /* don't change users' perspective */ | ||
691 | if (d->nopen && !(d->flags & DEVFL_PAUSE)) { | ||
631 | spin_unlock_irqrestore(&d->lock, flags); | 692 | spin_unlock_irqrestore(&d->lock, flags); |
632 | return; | 693 | return; |
633 | } | 694 | } |
634 | 695 | d->flags |= DEVFL_PAUSE; /* force pause */ | |
635 | d->fw_ver = be16_to_cpu(ch->fwver); | 696 | d->fw_ver = be16_to_cpu(ch->fwver); |
636 | 697 | ||
637 | /* we get here only if the device is new */ | 698 | /* check for already outstanding ataid */ |
638 | sl = aoecmd_ata_id(d); | 699 | sl = aoedev_isbusy(d) == 0 ? aoecmd_ata_id(d) : NULL; |
639 | 700 | ||
640 | spin_unlock_irqrestore(&d->lock, flags); | 701 | spin_unlock_irqrestore(&d->lock, flags); |
641 | 702 | ||
diff --git a/drivers/block/aoe/aoedev.c b/drivers/block/aoe/aoedev.c index ded33ba31acc..ed4258a62df5 100644 --- a/drivers/block/aoe/aoedev.c +++ b/drivers/block/aoe/aoedev.c | |||
@@ -12,6 +12,24 @@ | |||
12 | static struct aoedev *devlist; | 12 | static struct aoedev *devlist; |
13 | static spinlock_t devlist_lock; | 13 | static spinlock_t devlist_lock; |
14 | 14 | ||
15 | int | ||
16 | aoedev_isbusy(struct aoedev *d) | ||
17 | { | ||
18 | struct frame *f, *e; | ||
19 | |||
20 | f = d->frames; | ||
21 | e = f + d->nframes; | ||
22 | do { | ||
23 | if (f->tag != FREETAG) { | ||
24 | printk(KERN_DEBUG "aoe: %ld.%ld isbusy\n", | ||
25 | d->aoemajor, d->aoeminor); | ||
26 | return 1; | ||
27 | } | ||
28 | } while (++f < e); | ||
29 | |||
30 | return 0; | ||
31 | } | ||
32 | |||
15 | struct aoedev * | 33 | struct aoedev * |
16 | aoedev_by_aoeaddr(int maj, int min) | 34 | aoedev_by_aoeaddr(int maj, int min) |
17 | { | 35 | { |
@@ -28,6 +46,18 @@ aoedev_by_aoeaddr(int maj, int min) | |||
28 | return d; | 46 | return d; |
29 | } | 47 | } |
30 | 48 | ||
49 | static void | ||
50 | dummy_timer(ulong vp) | ||
51 | { | ||
52 | struct aoedev *d; | ||
53 | |||
54 | d = (struct aoedev *)vp; | ||
55 | if (d->flags & DEVFL_TKILL) | ||
56 | return; | ||
57 | d->timer.expires = jiffies + HZ; | ||
58 | add_timer(&d->timer); | ||
59 | } | ||
60 | |||
31 | /* called with devlist lock held */ | 61 | /* called with devlist lock held */ |
32 | static struct aoedev * | 62 | static struct aoedev * |
33 | aoedev_newdev(ulong nframes) | 63 | aoedev_newdev(ulong nframes) |
@@ -44,6 +74,8 @@ aoedev_newdev(ulong nframes) | |||
44 | return NULL; | 74 | return NULL; |
45 | } | 75 | } |
46 | 76 | ||
77 | INIT_WORK(&d->work, aoecmd_sleepwork, d); | ||
78 | |||
47 | d->nframes = nframes; | 79 | d->nframes = nframes; |
48 | d->frames = f; | 80 | d->frames = f; |
49 | e = f + nframes; | 81 | e = f + nframes; |
@@ -52,6 +84,10 @@ aoedev_newdev(ulong nframes) | |||
52 | 84 | ||
53 | spin_lock_init(&d->lock); | 85 | spin_lock_init(&d->lock); |
54 | init_timer(&d->timer); | 86 | init_timer(&d->timer); |
87 | d->timer.data = (ulong) d; | ||
88 | d->timer.function = dummy_timer; | ||
89 | d->timer.expires = jiffies + HZ; | ||
90 | add_timer(&d->timer); | ||
55 | d->bufpool = NULL; /* defer to aoeblk_gdalloc */ | 91 | d->bufpool = NULL; /* defer to aoeblk_gdalloc */ |
56 | INIT_LIST_HEAD(&d->bufq); | 92 | INIT_LIST_HEAD(&d->bufq); |
57 | d->next = devlist; | 93 | d->next = devlist; |
@@ -67,9 +103,6 @@ aoedev_downdev(struct aoedev *d) | |||
67 | struct buf *buf; | 103 | struct buf *buf; |
68 | struct bio *bio; | 104 | struct bio *bio; |
69 | 105 | ||
70 | d->flags |= DEVFL_TKILL; | ||
71 | del_timer(&d->timer); | ||
72 | |||
73 | f = d->frames; | 106 | f = d->frames; |
74 | e = f + d->nframes; | 107 | e = f + d->nframes; |
75 | for (; f<e; f->tag = FREETAG, f->buf = NULL, f++) { | 108 | for (; f<e; f->tag = FREETAG, f->buf = NULL, f++) { |
@@ -92,16 +125,15 @@ aoedev_downdev(struct aoedev *d) | |||
92 | bio_endio(bio, bio->bi_size, -EIO); | 125 | bio_endio(bio, bio->bi_size, -EIO); |
93 | } | 126 | } |
94 | 127 | ||
95 | if (d->nopen) | ||
96 | d->flags |= DEVFL_CLOSEWAIT; | ||
97 | if (d->gd) | 128 | if (d->gd) |
98 | d->gd->capacity = 0; | 129 | d->gd->capacity = 0; |
99 | 130 | ||
100 | d->flags &= ~DEVFL_UP; | 131 | d->flags &= ~(DEVFL_UP | DEVFL_PAUSE); |
101 | } | 132 | } |
102 | 133 | ||
134 | /* find it or malloc it */ | ||
103 | struct aoedev * | 135 | struct aoedev * |
104 | aoedev_set(ulong sysminor, unsigned char *addr, struct net_device *ifp, ulong bufcnt) | 136 | aoedev_by_sysminor_m(ulong sysminor, ulong bufcnt) |
105 | { | 137 | { |
106 | struct aoedev *d; | 138 | struct aoedev *d; |
107 | ulong flags; | 139 | ulong flags; |
@@ -112,25 +144,19 @@ aoedev_set(ulong sysminor, unsigned char *addr, struct net_device *ifp, ulong bu | |||
112 | if (d->sysminor == sysminor) | 144 | if (d->sysminor == sysminor) |
113 | break; | 145 | break; |
114 | 146 | ||
115 | if (d == NULL && (d = aoedev_newdev(bufcnt)) == NULL) { | 147 | if (d == NULL) { |
116 | spin_unlock_irqrestore(&devlist_lock, flags); | 148 | d = aoedev_newdev(bufcnt); |
117 | printk(KERN_INFO "aoe: aoedev_set: aoedev_newdev failure.\n"); | 149 | if (d == NULL) { |
118 | return NULL; | 150 | spin_unlock_irqrestore(&devlist_lock, flags); |
119 | } /* if newdev, (d->flags & DEVFL_UP) == 0 for below */ | 151 | printk(KERN_INFO "aoe: aoedev_set: aoedev_newdev failure.\n"); |
120 | 152 | return NULL; | |
121 | spin_unlock_irqrestore(&devlist_lock, flags); | 153 | } |
122 | spin_lock_irqsave(&d->lock, flags); | ||
123 | |||
124 | d->ifp = ifp; | ||
125 | memcpy(d->addr, addr, sizeof d->addr); | ||
126 | if ((d->flags & DEVFL_UP) == 0) { | ||
127 | aoedev_downdev(d); /* flushes outstanding frames */ | ||
128 | d->sysminor = sysminor; | 154 | d->sysminor = sysminor; |
129 | d->aoemajor = AOEMAJOR(sysminor); | 155 | d->aoemajor = AOEMAJOR(sysminor); |
130 | d->aoeminor = AOEMINOR(sysminor); | 156 | d->aoeminor = AOEMINOR(sysminor); |
131 | } | 157 | } |
132 | 158 | ||
133 | spin_unlock_irqrestore(&d->lock, flags); | 159 | spin_unlock_irqrestore(&devlist_lock, flags); |
134 | return d; | 160 | return d; |
135 | } | 161 | } |
136 | 162 | ||
@@ -161,6 +187,7 @@ aoedev_exit(void) | |||
161 | 187 | ||
162 | spin_lock_irqsave(&d->lock, flags); | 188 | spin_lock_irqsave(&d->lock, flags); |
163 | aoedev_downdev(d); | 189 | aoedev_downdev(d); |
190 | d->flags |= DEVFL_TKILL; | ||
164 | spin_unlock_irqrestore(&d->lock, flags); | 191 | spin_unlock_irqrestore(&d->lock, flags); |
165 | 192 | ||
166 | del_timer_sync(&d->timer); | 193 | del_timer_sync(&d->timer); |