aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorEd L. Cashin <ecashin@coraid.com>2006-01-19 13:46:19 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2006-03-24 01:01:55 -0500
commit3ae1c24e395b2b65326439622223d88d92bfa03a (patch)
treedf1e7e8e63a37ed91407ea5da6535b64f50e64a2 /drivers
parent50bba752ca0a740a6ba9eb96d61ef7bbdfe405cf (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')
-rw-r--r--drivers/block/aoe/aoe.h12
-rw-r--r--drivers/block/aoe/aoeblk.c22
-rw-r--r--drivers/block/aoe/aoechr.c37
-rw-r--r--drivers/block/aoe/aoecmd.c177
-rw-r--r--drivers/block/aoe/aoedev.c69
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);
152void aoechr_error(char *); 153void aoechr_error(char *);
153 154
154void aoecmd_work(struct aoedev *d); 155void aoecmd_work(struct aoedev *d);
155void aoecmd_cfg(ushort, unsigned char); 156void aoecmd_cfg(ushort aoemajor, unsigned char aoeminor);
156void aoecmd_ata_rsp(struct sk_buff *); 157void aoecmd_ata_rsp(struct sk_buff *);
157void aoecmd_cfg_rsp(struct sk_buff *); 158void aoecmd_cfg_rsp(struct sk_buff *);
159void aoecmd_sleepwork(void *vp);
158 160
159int aoedev_init(void); 161int aoedev_init(void);
160void aoedev_exit(void); 162void aoedev_exit(void);
161struct aoedev *aoedev_by_aoeaddr(int maj, int min); 163struct aoedev *aoedev_by_aoeaddr(int maj, int min);
164struct aoedev *aoedev_by_sysminor_m(ulong sysminor, ulong bufcnt);
162void aoedev_downdev(struct aoedev *d); 165void aoedev_downdev(struct aoedev *d);
163struct aoedev *aoedev_set(ulong, unsigned char *, struct net_device *, ulong); 166int aoedev_isbusy(struct aoedev *d);
164int aoedev_busy(void);
165 167
166int aoenet_init(void); 168int aoenet_init(void);
167void aoenet_exit(void); 169void 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}
27static ssize_t aoedisk_show_mac(struct gendisk * disk, char *page) 29static 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
252void 248void
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
46static int 48static int
@@ -62,6 +64,39 @@ interfaces(const char __user *str, size_t size)
62 return 0; 64 return 0;
63} 65}
64 66
67static int
68revalidate(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
65void 100void
66aoechr_error(char *msg) 101aoechr_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 */
196static struct sk_buff *
197aoecmd_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 */
193void 241void
194aoecmd_work(struct aoedev *d) 242aoecmd_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
198loop: 254loop:
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 */
367void
368aoecmd_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
309static void 396static void
310ataid_complete(struct aoedev *d, unsigned char *id) 397ataid_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
360static void 455static 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
497void 590void
498aoecmd_cfg(ushort aoemajor, unsigned char aoeminor) 591aoecmd_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 @@
12static struct aoedev *devlist; 12static struct aoedev *devlist;
13static spinlock_t devlist_lock; 13static spinlock_t devlist_lock;
14 14
15int
16aoedev_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
15struct aoedev * 33struct aoedev *
16aoedev_by_aoeaddr(int maj, int min) 34aoedev_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
49static void
50dummy_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 */
32static struct aoedev * 62static struct aoedev *
33aoedev_newdev(ulong nframes) 63aoedev_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 */
103struct aoedev * 135struct aoedev *
104aoedev_set(ulong sysminor, unsigned char *addr, struct net_device *ifp, ulong bufcnt) 136aoedev_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);