diff options
Diffstat (limited to 'drivers/block/aoe/aoedev.c')
-rw-r--r-- | drivers/block/aoe/aoedev.c | 180 |
1 files changed, 180 insertions, 0 deletions
diff --git a/drivers/block/aoe/aoedev.c b/drivers/block/aoe/aoedev.c new file mode 100644 index 000000000000..240abaec159b --- /dev/null +++ b/drivers/block/aoe/aoedev.c | |||
@@ -0,0 +1,180 @@ | |||
1 | /* Copyright (c) 2004 Coraid, Inc. See COPYING for GPL terms. */ | ||
2 | /* | ||
3 | * aoedev.c | ||
4 | * AoE device utility functions; maintains device list. | ||
5 | */ | ||
6 | |||
7 | #include <linux/hdreg.h> | ||
8 | #include <linux/blkdev.h> | ||
9 | #include <linux/netdevice.h> | ||
10 | #include "aoe.h" | ||
11 | |||
12 | static struct aoedev *devlist; | ||
13 | static spinlock_t devlist_lock; | ||
14 | |||
15 | struct aoedev * | ||
16 | aoedev_bymac(unsigned char *macaddr) | ||
17 | { | ||
18 | struct aoedev *d; | ||
19 | ulong flags; | ||
20 | |||
21 | spin_lock_irqsave(&devlist_lock, flags); | ||
22 | |||
23 | for (d=devlist; d; d=d->next) | ||
24 | if (!memcmp(d->addr, macaddr, 6)) | ||
25 | break; | ||
26 | |||
27 | spin_unlock_irqrestore(&devlist_lock, flags); | ||
28 | return d; | ||
29 | } | ||
30 | |||
31 | /* called with devlist lock held */ | ||
32 | static struct aoedev * | ||
33 | aoedev_newdev(ulong nframes) | ||
34 | { | ||
35 | struct aoedev *d; | ||
36 | struct frame *f, *e; | ||
37 | |||
38 | d = kcalloc(1, sizeof *d, GFP_ATOMIC); | ||
39 | if (d == NULL) | ||
40 | return NULL; | ||
41 | f = kcalloc(nframes, sizeof *f, GFP_ATOMIC); | ||
42 | if (f == NULL) { | ||
43 | kfree(d); | ||
44 | return NULL; | ||
45 | } | ||
46 | |||
47 | d->nframes = nframes; | ||
48 | d->frames = f; | ||
49 | e = f + nframes; | ||
50 | for (; f<e; f++) | ||
51 | f->tag = FREETAG; | ||
52 | |||
53 | spin_lock_init(&d->lock); | ||
54 | init_timer(&d->timer); | ||
55 | d->bufpool = NULL; /* defer to aoeblk_gdalloc */ | ||
56 | INIT_LIST_HEAD(&d->bufq); | ||
57 | d->next = devlist; | ||
58 | devlist = d; | ||
59 | |||
60 | return d; | ||
61 | } | ||
62 | |||
63 | void | ||
64 | aoedev_downdev(struct aoedev *d) | ||
65 | { | ||
66 | struct frame *f, *e; | ||
67 | struct buf *buf; | ||
68 | struct bio *bio; | ||
69 | |||
70 | d->flags |= DEVFL_TKILL; | ||
71 | del_timer(&d->timer); | ||
72 | |||
73 | f = d->frames; | ||
74 | e = f + d->nframes; | ||
75 | for (; f<e; f->tag = FREETAG, f->buf = NULL, f++) { | ||
76 | if (f->tag == FREETAG || f->buf == NULL) | ||
77 | continue; | ||
78 | buf = f->buf; | ||
79 | bio = buf->bio; | ||
80 | if (--buf->nframesout == 0) { | ||
81 | mempool_free(buf, d->bufpool); | ||
82 | bio_endio(bio, bio->bi_size, -EIO); | ||
83 | } | ||
84 | } | ||
85 | d->inprocess = NULL; | ||
86 | |||
87 | while (!list_empty(&d->bufq)) { | ||
88 | buf = container_of(d->bufq.next, struct buf, bufs); | ||
89 | list_del(d->bufq.next); | ||
90 | bio = buf->bio; | ||
91 | mempool_free(buf, d->bufpool); | ||
92 | bio_endio(bio, bio->bi_size, -EIO); | ||
93 | } | ||
94 | |||
95 | if (d->nopen) | ||
96 | d->flags |= DEVFL_CLOSEWAIT; | ||
97 | if (d->gd) | ||
98 | d->gd->capacity = 0; | ||
99 | |||
100 | d->flags &= ~DEVFL_UP; | ||
101 | } | ||
102 | |||
103 | struct aoedev * | ||
104 | aoedev_set(ulong sysminor, unsigned char *addr, struct net_device *ifp, ulong bufcnt) | ||
105 | { | ||
106 | struct aoedev *d; | ||
107 | ulong flags; | ||
108 | |||
109 | spin_lock_irqsave(&devlist_lock, flags); | ||
110 | |||
111 | for (d=devlist; d; d=d->next) | ||
112 | if (d->sysminor == sysminor | ||
113 | || memcmp(d->addr, addr, sizeof d->addr) == 0) | ||
114 | break; | ||
115 | |||
116 | if (d == NULL && (d = aoedev_newdev(bufcnt)) == NULL) { | ||
117 | spin_unlock_irqrestore(&devlist_lock, flags); | ||
118 | printk(KERN_INFO "aoe: aoedev_set: aoedev_newdev failure.\n"); | ||
119 | return NULL; | ||
120 | } | ||
121 | |||
122 | spin_unlock_irqrestore(&devlist_lock, flags); | ||
123 | spin_lock_irqsave(&d->lock, flags); | ||
124 | |||
125 | d->ifp = ifp; | ||
126 | |||
127 | if (d->sysminor != sysminor | ||
128 | || memcmp(d->addr, addr, sizeof d->addr) | ||
129 | || (d->flags & DEVFL_UP) == 0) { | ||
130 | aoedev_downdev(d); /* flushes outstanding frames */ | ||
131 | memcpy(d->addr, addr, sizeof d->addr); | ||
132 | d->sysminor = sysminor; | ||
133 | d->aoemajor = AOEMAJOR(sysminor); | ||
134 | d->aoeminor = AOEMINOR(sysminor); | ||
135 | } | ||
136 | |||
137 | spin_unlock_irqrestore(&d->lock, flags); | ||
138 | return d; | ||
139 | } | ||
140 | |||
141 | static void | ||
142 | aoedev_freedev(struct aoedev *d) | ||
143 | { | ||
144 | if (d->gd) { | ||
145 | aoedisk_rm_sysfs(d); | ||
146 | del_gendisk(d->gd); | ||
147 | put_disk(d->gd); | ||
148 | } | ||
149 | kfree(d->frames); | ||
150 | mempool_destroy(d->bufpool); | ||
151 | kfree(d); | ||
152 | } | ||
153 | |||
154 | void | ||
155 | aoedev_exit(void) | ||
156 | { | ||
157 | struct aoedev *d; | ||
158 | ulong flags; | ||
159 | |||
160 | flush_scheduled_work(); | ||
161 | |||
162 | while ((d = devlist)) { | ||
163 | devlist = d->next; | ||
164 | |||
165 | spin_lock_irqsave(&d->lock, flags); | ||
166 | aoedev_downdev(d); | ||
167 | spin_unlock_irqrestore(&d->lock, flags); | ||
168 | |||
169 | del_timer_sync(&d->timer); | ||
170 | aoedev_freedev(d); | ||
171 | } | ||
172 | } | ||
173 | |||
174 | int __init | ||
175 | aoedev_init(void) | ||
176 | { | ||
177 | spin_lock_init(&devlist_lock); | ||
178 | return 0; | ||
179 | } | ||
180 | |||