xref: /openbmc/linux/drivers/block/aoe/aoedev.c (revision 643d1f7f)
1 /* Copyright (c) 2006 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 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 			return 1;
25 	} while (++f < e);
26 
27 	return 0;
28 }
29 
30 struct aoedev *
31 aoedev_by_aoeaddr(int maj, int min)
32 {
33 	struct aoedev *d;
34 	ulong flags;
35 
36 	spin_lock_irqsave(&devlist_lock, flags);
37 
38 	for (d=devlist; d; d=d->next)
39 		if (d->aoemajor == maj && d->aoeminor == min)
40 			break;
41 
42 	spin_unlock_irqrestore(&devlist_lock, flags);
43 	return d;
44 }
45 
46 static void
47 dummy_timer(ulong vp)
48 {
49 	struct aoedev *d;
50 
51 	d = (struct aoedev *)vp;
52 	if (d->flags & DEVFL_TKILL)
53 		return;
54 	d->timer.expires = jiffies + HZ;
55 	add_timer(&d->timer);
56 }
57 
58 /* called with devlist lock held */
59 static struct aoedev *
60 aoedev_newdev(ulong nframes)
61 {
62 	struct aoedev *d;
63 	struct frame *f, *e;
64 
65 	d = kzalloc(sizeof *d, GFP_ATOMIC);
66 	f = kcalloc(nframes, sizeof *f, GFP_ATOMIC);
67  	switch (!d || !f) {
68  	case 0:
69  		d->nframes = nframes;
70  		d->frames = f;
71  		e = f + nframes;
72  		for (; f<e; f++) {
73  			f->tag = FREETAG;
74  			f->skb = new_skb(ETH_ZLEN);
75  			if (!f->skb)
76  				break;
77  		}
78  		if (f == e)
79  			break;
80  		while (f > d->frames) {
81  			f--;
82  			dev_kfree_skb(f->skb);
83  		}
84  	default:
85  		if (f)
86  			kfree(f);
87  		if (d)
88  			kfree(d);
89 		return NULL;
90 	}
91 	INIT_WORK(&d->work, aoecmd_sleepwork);
92 	spin_lock_init(&d->lock);
93 	init_timer(&d->timer);
94 	d->timer.data = (ulong) d;
95 	d->timer.function = dummy_timer;
96 	d->timer.expires = jiffies + HZ;
97 	add_timer(&d->timer);
98 	d->bufpool = NULL;	/* defer to aoeblk_gdalloc */
99 	INIT_LIST_HEAD(&d->bufq);
100 	d->next = devlist;
101 	devlist = d;
102 
103 	return d;
104 }
105 
106 void
107 aoedev_downdev(struct aoedev *d)
108 {
109 	struct frame *f, *e;
110 	struct buf *buf;
111 	struct bio *bio;
112 
113 	f = d->frames;
114 	e = f + d->nframes;
115 	for (; f<e; f->tag = FREETAG, f->buf = NULL, f++) {
116 		if (f->tag == FREETAG || f->buf == NULL)
117 			continue;
118 		buf = f->buf;
119 		bio = buf->bio;
120 		if (--buf->nframesout == 0) {
121 			mempool_free(buf, d->bufpool);
122 			bio_endio(bio, -EIO);
123 		}
124 		skb_shinfo(f->skb)->nr_frags = f->skb->data_len = 0;
125 	}
126 	d->inprocess = NULL;
127 
128 	while (!list_empty(&d->bufq)) {
129 		buf = container_of(d->bufq.next, struct buf, bufs);
130 		list_del(d->bufq.next);
131 		bio = buf->bio;
132 		mempool_free(buf, d->bufpool);
133 		bio_endio(bio, -EIO);
134 	}
135 
136 	if (d->gd)
137 		d->gd->capacity = 0;
138 
139 	d->flags &= ~(DEVFL_UP | DEVFL_PAUSE);
140 }
141 
142 /* find it or malloc it */
143 struct aoedev *
144 aoedev_by_sysminor_m(ulong sysminor, ulong bufcnt)
145 {
146 	struct aoedev *d;
147 	ulong flags;
148 
149 	spin_lock_irqsave(&devlist_lock, flags);
150 
151 	for (d=devlist; d; d=d->next)
152 		if (d->sysminor == sysminor)
153 			break;
154 
155 	if (d == NULL) {
156 		d = aoedev_newdev(bufcnt);
157 	 	if (d == NULL) {
158 			spin_unlock_irqrestore(&devlist_lock, flags);
159 			printk(KERN_INFO "aoe: aoedev_newdev failure.\n");
160 			return NULL;
161 		}
162 		d->sysminor = sysminor;
163 		d->aoemajor = AOEMAJOR(sysminor);
164 		d->aoeminor = AOEMINOR(sysminor);
165 	}
166 
167 	spin_unlock_irqrestore(&devlist_lock, flags);
168 	return d;
169 }
170 
171 static void
172 aoedev_freedev(struct aoedev *d)
173 {
174 	struct frame *f, *e;
175 
176 	if (d->gd) {
177 		aoedisk_rm_sysfs(d);
178 		del_gendisk(d->gd);
179 		put_disk(d->gd);
180 	}
181 	f = d->frames;
182 	e = f + d->nframes;
183 	for (; f<e; f++) {
184 		skb_shinfo(f->skb)->nr_frags = 0;
185 		dev_kfree_skb(f->skb);
186 	}
187 	kfree(d->frames);
188 	if (d->bufpool)
189 		mempool_destroy(d->bufpool);
190 	kfree(d);
191 }
192 
193 void
194 aoedev_exit(void)
195 {
196 	struct aoedev *d;
197 	ulong flags;
198 
199 	flush_scheduled_work();
200 
201 	while ((d = devlist)) {
202 		devlist = d->next;
203 
204 		spin_lock_irqsave(&d->lock, flags);
205 		aoedev_downdev(d);
206 		d->flags |= DEVFL_TKILL;
207 		spin_unlock_irqrestore(&d->lock, flags);
208 
209 		del_timer_sync(&d->timer);
210 		aoedev_freedev(d);
211 	}
212 }
213 
214 int __init
215 aoedev_init(void)
216 {
217 	spin_lock_init(&devlist_lock);
218 	return 0;
219 }
220 
221