diff options
-rw-r--r-- | Documentation/aoe/mkdevs.sh | 2 | ||||
-rw-r--r-- | Documentation/aoe/udev.txt | 1 | ||||
-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 |
7 files changed, 223 insertions, 97 deletions
diff --git a/Documentation/aoe/mkdevs.sh b/Documentation/aoe/mkdevs.sh index ec5a6de1cd7b..97374aacacb2 100644 --- a/Documentation/aoe/mkdevs.sh +++ b/Documentation/aoe/mkdevs.sh | |||
@@ -27,6 +27,8 @@ rm -f $dir/discover | |||
27 | mknod -m 0200 $dir/discover c $MAJOR 3 | 27 | mknod -m 0200 $dir/discover c $MAJOR 3 |
28 | rm -f $dir/interfaces | 28 | rm -f $dir/interfaces |
29 | mknod -m 0200 $dir/interfaces c $MAJOR 4 | 29 | mknod -m 0200 $dir/interfaces c $MAJOR 4 |
30 | rm -f $dir/revalidate | ||
31 | mknod -m 0200 $dir/revalidate c $MAJOR 5 | ||
30 | 32 | ||
31 | export n_partitions | 33 | export n_partitions |
32 | mkshelf=`echo $0 | sed 's!mkdevs!mkshelf!'` | 34 | mkshelf=`echo $0 | sed 's!mkdevs!mkshelf!'` |
diff --git a/Documentation/aoe/udev.txt b/Documentation/aoe/udev.txt index ab39d8bb634c..a7ed1dc4f331 100644 --- a/Documentation/aoe/udev.txt +++ b/Documentation/aoe/udev.txt | |||
@@ -18,6 +18,7 @@ | |||
18 | SUBSYSTEM="aoe", KERNEL="discover", NAME="etherd/%k", GROUP="disk", MODE="0220" | 18 | SUBSYSTEM="aoe", KERNEL="discover", NAME="etherd/%k", GROUP="disk", MODE="0220" |
19 | SUBSYSTEM="aoe", KERNEL="err", NAME="etherd/%k", GROUP="disk", MODE="0440" | 19 | SUBSYSTEM="aoe", KERNEL="err", NAME="etherd/%k", GROUP="disk", MODE="0440" |
20 | SUBSYSTEM="aoe", KERNEL="interfaces", NAME="etherd/%k", GROUP="disk", MODE="0220" | 20 | SUBSYSTEM="aoe", KERNEL="interfaces", NAME="etherd/%k", GROUP="disk", MODE="0220" |
21 | SUBSYSTEM="aoe", KERNEL="revalidate", NAME="etherd/%k", GROUP="disk", MODE="0220" | ||
21 | 22 | ||
22 | # aoe block devices | 23 | # aoe block devices |
23 | KERNEL="etherd*", NAME="%k", GROUP="disk" | 24 | KERNEL="etherd*", NAME="%k", GROUP="disk" |
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); |