aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block/aoe
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/block/aoe
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'drivers/block/aoe')
-rw-r--r--drivers/block/aoe/Makefile6
-rw-r--r--drivers/block/aoe/aoe.h165
-rw-r--r--drivers/block/aoe/aoeblk.c267
-rw-r--r--drivers/block/aoe/aoechr.c244
-rw-r--r--drivers/block/aoe/aoecmd.c629
-rw-r--r--drivers/block/aoe/aoedev.c180
-rw-r--r--drivers/block/aoe/aoemain.c112
-rw-r--r--drivers/block/aoe/aoenet.c172
8 files changed, 1775 insertions, 0 deletions
diff --git a/drivers/block/aoe/Makefile b/drivers/block/aoe/Makefile
new file mode 100644
index 000000000000..e76d997183c6
--- /dev/null
+++ b/drivers/block/aoe/Makefile
@@ -0,0 +1,6 @@
1#
2# Makefile for ATA over Ethernet
3#
4
5obj-$(CONFIG_ATA_OVER_ETH) += aoe.o
6aoe-objs := aoeblk.o aoechr.o aoecmd.o aoedev.o aoemain.o aoenet.o
diff --git a/drivers/block/aoe/aoe.h b/drivers/block/aoe/aoe.h
new file mode 100644
index 000000000000..db78f826d40c
--- /dev/null
+++ b/drivers/block/aoe/aoe.h
@@ -0,0 +1,165 @@
1/* Copyright (c) 2004 Coraid, Inc. See COPYING for GPL terms. */
2#define VERSION "5"
3#define AOE_MAJOR 152
4#define DEVICE_NAME "aoe"
5#ifndef AOE_PARTITIONS
6#define AOE_PARTITIONS 16
7#endif
8#define SYSMINOR(aoemajor, aoeminor) ((aoemajor) * 10 + (aoeminor))
9#define AOEMAJOR(sysminor) ((sysminor) / 10)
10#define AOEMINOR(sysminor) ((sysminor) % 10)
11#define WHITESPACE " \t\v\f\n"
12
13enum {
14 AOECMD_ATA,
15 AOECMD_CFG,
16
17 AOEFL_RSP = (1<<3),
18 AOEFL_ERR = (1<<2),
19
20 AOEAFL_EXT = (1<<6),
21 AOEAFL_DEV = (1<<4),
22 AOEAFL_ASYNC = (1<<1),
23 AOEAFL_WRITE = (1<<0),
24
25 AOECCMD_READ = 0,
26 AOECCMD_TEST,
27 AOECCMD_PTEST,
28 AOECCMD_SET,
29 AOECCMD_FSET,
30
31 AOE_HVER = 0x10,
32};
33
34struct aoe_hdr {
35 unsigned char dst[6];
36 unsigned char src[6];
37 unsigned char type[2];
38 unsigned char verfl;
39 unsigned char err;
40 unsigned char major[2];
41 unsigned char minor;
42 unsigned char cmd;
43 unsigned char tag[4];
44};
45
46struct aoe_atahdr {
47 unsigned char aflags;
48 unsigned char errfeat;
49 unsigned char scnt;
50 unsigned char cmdstat;
51 unsigned char lba0;
52 unsigned char lba1;
53 unsigned char lba2;
54 unsigned char lba3;
55 unsigned char lba4;
56 unsigned char lba5;
57 unsigned char res[2];
58};
59
60struct aoe_cfghdr {
61 unsigned char bufcnt[2];
62 unsigned char fwver[2];
63 unsigned char res;
64 unsigned char aoeccmd;
65 unsigned char cslen[2];
66};
67
68enum {
69 DEVFL_UP = 1, /* device is installed in system and ready for AoE->ATA commands */
70 DEVFL_TKILL = (1<<1), /* flag for timer to know when to kill self */
71 DEVFL_EXT = (1<<2), /* device accepts lba48 commands */
72 DEVFL_CLOSEWAIT = (1<<3), /* device is waiting for all closes to revalidate */
73 DEVFL_WC_UPDATE = (1<<4), /* this device needs to update write cache status */
74 DEVFL_WORKON = (1<<4),
75
76 BUFFL_FAIL = 1,
77};
78
79enum {
80 MAXATADATA = 1024,
81 NPERSHELF = 10,
82 FREETAG = -1,
83 MIN_BUFS = 8,
84};
85
86struct buf {
87 struct list_head bufs;
88 ulong flags;
89 ulong nframesout;
90 char *bufaddr;
91 ulong resid;
92 ulong bv_resid;
93 sector_t sector;
94 struct bio *bio;
95 struct bio_vec *bv;
96};
97
98struct frame {
99 int tag;
100 ulong waited;
101 struct buf *buf;
102 char *bufaddr;
103 int writedatalen;
104 int ndata;
105
106 /* largest possible */
107 unsigned char data[sizeof(struct aoe_hdr) + sizeof(struct aoe_atahdr)];
108};
109
110struct aoedev {
111 struct aoedev *next;
112 unsigned char addr[6]; /* remote mac addr */
113 ushort flags;
114 ulong sysminor;
115 ulong aoemajor;
116 ulong aoeminor;
117 ulong nopen; /* (bd_openers isn't available without sleeping) */
118 ulong rttavg; /* round trip average of requests/responses */
119 u16 fw_ver; /* version of blade's firmware */
120 struct work_struct work;/* disk create work struct */
121 struct gendisk *gd;
122 request_queue_t blkq;
123 struct hd_geometry geo;
124 sector_t ssize;
125 struct timer_list timer;
126 spinlock_t lock;
127 struct net_device *ifp; /* interface ed is attached to */
128 struct sk_buff *skblist;/* packets needing to be sent */
129 mempool_t *bufpool; /* for deadlock-free Buf allocation */
130 struct list_head bufq; /* queue of bios to work on */
131 struct buf *inprocess; /* the one we're currently working on */
132 ulong lasttag; /* last tag sent */
133 ulong nframes; /* number of frames below */
134 struct frame *frames;
135};
136
137
138int aoeblk_init(void);
139void aoeblk_exit(void);
140void aoeblk_gdalloc(void *);
141void aoedisk_rm_sysfs(struct aoedev *d);
142
143int aoechr_init(void);
144void aoechr_exit(void);
145void aoechr_error(char *);
146
147void aoecmd_work(struct aoedev *d);
148void aoecmd_cfg(ushort, unsigned char);
149void aoecmd_ata_rsp(struct sk_buff *);
150void aoecmd_cfg_rsp(struct sk_buff *);
151
152int aoedev_init(void);
153void aoedev_exit(void);
154struct aoedev *aoedev_bymac(unsigned char *);
155void aoedev_downdev(struct aoedev *d);
156struct aoedev *aoedev_set(ulong, unsigned char *, struct net_device *, ulong);
157int aoedev_busy(void);
158
159int aoenet_init(void);
160void aoenet_exit(void);
161void aoenet_xmit(struct sk_buff *);
162int is_aoe_netif(struct net_device *ifp);
163int set_aoe_iflist(const char __user *str, size_t size);
164
165u64 mac_addr(char addr[6]);
diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c
new file mode 100644
index 000000000000..63561b280bc5
--- /dev/null
+++ b/drivers/block/aoe/aoeblk.c
@@ -0,0 +1,267 @@
1/* Copyright (c) 2004 Coraid, Inc. See COPYING for GPL terms. */
2/*
3 * aoeblk.c
4 * block device routines
5 */
6
7#include <linux/hdreg.h>
8#include <linux/blkdev.h>
9#include <linux/fs.h>
10#include <linux/ioctl.h>
11#include <linux/genhd.h>
12#include <linux/netdevice.h>
13#include "aoe.h"
14
15static kmem_cache_t *buf_pool_cache;
16
17/* add attributes for our block devices in sysfs */
18static ssize_t aoedisk_show_state(struct gendisk * disk, char *page)
19{
20 struct aoedev *d = disk->private_data;
21
22 return snprintf(page, PAGE_SIZE,
23 "%s%s\n",
24 (d->flags & DEVFL_UP) ? "up" : "down",
25 (d->flags & DEVFL_CLOSEWAIT) ? ",closewait" : "");
26}
27static ssize_t aoedisk_show_mac(struct gendisk * disk, char *page)
28{
29 struct aoedev *d = disk->private_data;
30
31 return snprintf(page, PAGE_SIZE, "%012llx\n",
32 (unsigned long long)mac_addr(d->addr));
33}
34static ssize_t aoedisk_show_netif(struct gendisk * disk, char *page)
35{
36 struct aoedev *d = disk->private_data;
37
38 return snprintf(page, PAGE_SIZE, "%s\n", d->ifp->name);
39}
40
41static struct disk_attribute disk_attr_state = {
42 .attr = {.name = "state", .mode = S_IRUGO },
43 .show = aoedisk_show_state
44};
45static struct disk_attribute disk_attr_mac = {
46 .attr = {.name = "mac", .mode = S_IRUGO },
47 .show = aoedisk_show_mac
48};
49static struct disk_attribute disk_attr_netif = {
50 .attr = {.name = "netif", .mode = S_IRUGO },
51 .show = aoedisk_show_netif
52};
53
54static void
55aoedisk_add_sysfs(struct aoedev *d)
56{
57 sysfs_create_file(&d->gd->kobj, &disk_attr_state.attr);
58 sysfs_create_file(&d->gd->kobj, &disk_attr_mac.attr);
59 sysfs_create_file(&d->gd->kobj, &disk_attr_netif.attr);
60}
61void
62aoedisk_rm_sysfs(struct aoedev *d)
63{
64 sysfs_remove_link(&d->gd->kobj, "state");
65 sysfs_remove_link(&d->gd->kobj, "mac");
66 sysfs_remove_link(&d->gd->kobj, "netif");
67}
68
69static int
70aoeblk_open(struct inode *inode, struct file *filp)
71{
72 struct aoedev *d;
73 ulong flags;
74
75 d = inode->i_bdev->bd_disk->private_data;
76
77 spin_lock_irqsave(&d->lock, flags);
78 if (d->flags & DEVFL_UP) {
79 d->nopen++;
80 spin_unlock_irqrestore(&d->lock, flags);
81 return 0;
82 }
83 spin_unlock_irqrestore(&d->lock, flags);
84 return -ENODEV;
85}
86
87static int
88aoeblk_release(struct inode *inode, struct file *filp)
89{
90 struct aoedev *d;
91 ulong flags;
92
93 d = inode->i_bdev->bd_disk->private_data;
94
95 spin_lock_irqsave(&d->lock, flags);
96
97 if (--d->nopen == 0 && (d->flags & DEVFL_CLOSEWAIT)) {
98 d->flags &= ~DEVFL_CLOSEWAIT;
99 spin_unlock_irqrestore(&d->lock, flags);
100 aoecmd_cfg(d->aoemajor, d->aoeminor);
101 return 0;
102 }
103 spin_unlock_irqrestore(&d->lock, flags);
104
105 return 0;
106}
107
108static int
109aoeblk_make_request(request_queue_t *q, struct bio *bio)
110{
111 struct aoedev *d;
112 struct buf *buf;
113 struct sk_buff *sl;
114 ulong flags;
115
116 blk_queue_bounce(q, &bio);
117
118 d = bio->bi_bdev->bd_disk->private_data;
119 buf = mempool_alloc(d->bufpool, GFP_NOIO);
120 if (buf == NULL) {
121 printk(KERN_INFO "aoe: aoeblk_make_request: buf allocation "
122 "failure\n");
123 bio_endio(bio, bio->bi_size, -ENOMEM);
124 return 0;
125 }
126 memset(buf, 0, sizeof(*buf));
127 INIT_LIST_HEAD(&buf->bufs);
128 buf->bio = bio;
129 buf->resid = bio->bi_size;
130 buf->sector = bio->bi_sector;
131 buf->bv = buf->bio->bi_io_vec;
132 buf->bv_resid = buf->bv->bv_len;
133 buf->bufaddr = page_address(buf->bv->bv_page) + buf->bv->bv_offset;
134
135 spin_lock_irqsave(&d->lock, flags);
136
137 if ((d->flags & DEVFL_UP) == 0) {
138 printk(KERN_INFO "aoe: aoeblk_make_request: device %ld.%ld is not up\n",
139 d->aoemajor, d->aoeminor);
140 spin_unlock_irqrestore(&d->lock, flags);
141 mempool_free(buf, d->bufpool);
142 bio_endio(bio, bio->bi_size, -ENXIO);
143 return 0;
144 }
145
146 list_add_tail(&buf->bufs, &d->bufq);
147 aoecmd_work(d);
148
149 sl = d->skblist;
150 d->skblist = NULL;
151
152 spin_unlock_irqrestore(&d->lock, flags);
153
154 aoenet_xmit(sl);
155 return 0;
156}
157
158/* This ioctl implementation expects userland to have the device node
159 * permissions set so that only priviledged users can open an aoe
160 * block device directly.
161 */
162static int
163aoeblk_ioctl(struct inode *inode, struct file *filp, uint cmd, ulong arg)
164{
165 struct aoedev *d;
166
167 if (!arg)
168 return -EINVAL;
169
170 d = inode->i_bdev->bd_disk->private_data;
171 if ((d->flags & DEVFL_UP) == 0) {
172 printk(KERN_ERR "aoe: aoeblk_ioctl: disk not up\n");
173 return -ENODEV;
174 }
175
176 if (cmd == HDIO_GETGEO) {
177 d->geo.start = get_start_sect(inode->i_bdev);
178 if (!copy_to_user((void __user *) arg, &d->geo, sizeof d->geo))
179 return 0;
180 return -EFAULT;
181 }
182 printk(KERN_INFO "aoe: aoeblk_ioctl: unknown ioctl %d\n", cmd);
183 return -EINVAL;
184}
185
186static struct block_device_operations aoe_bdops = {
187 .open = aoeblk_open,
188 .release = aoeblk_release,
189 .ioctl = aoeblk_ioctl,
190 .owner = THIS_MODULE,
191};
192
193/* alloc_disk and add_disk can sleep */
194void
195aoeblk_gdalloc(void *vp)
196{
197 struct aoedev *d = vp;
198 struct gendisk *gd;
199 ulong flags;
200
201 gd = alloc_disk(AOE_PARTITIONS);
202 if (gd == NULL) {
203 printk(KERN_ERR "aoe: aoeblk_gdalloc: cannot allocate disk "
204 "structure for %ld.%ld\n", d->aoemajor, d->aoeminor);
205 spin_lock_irqsave(&d->lock, flags);
206 d->flags &= ~DEVFL_WORKON;
207 spin_unlock_irqrestore(&d->lock, flags);
208 return;
209 }
210
211 d->bufpool = mempool_create(MIN_BUFS,
212 mempool_alloc_slab, mempool_free_slab,
213 buf_pool_cache);
214 if (d->bufpool == NULL) {
215 printk(KERN_ERR "aoe: aoeblk_gdalloc: cannot allocate bufpool "
216 "for %ld.%ld\n", d->aoemajor, d->aoeminor);
217 put_disk(gd);
218 spin_lock_irqsave(&d->lock, flags);
219 d->flags &= ~DEVFL_WORKON;
220 spin_unlock_irqrestore(&d->lock, flags);
221 return;
222 }
223
224 spin_lock_irqsave(&d->lock, flags);
225 blk_queue_make_request(&d->blkq, aoeblk_make_request);
226 gd->major = AOE_MAJOR;
227 gd->first_minor = d->sysminor * AOE_PARTITIONS;
228 gd->fops = &aoe_bdops;
229 gd->private_data = d;
230 gd->capacity = d->ssize;
231 snprintf(gd->disk_name, sizeof gd->disk_name, "etherd/e%ld.%ld",
232 d->aoemajor, d->aoeminor);
233
234 gd->queue = &d->blkq;
235 d->gd = gd;
236 d->flags &= ~DEVFL_WORKON;
237 d->flags |= DEVFL_UP;
238
239 spin_unlock_irqrestore(&d->lock, flags);
240
241 add_disk(gd);
242 aoedisk_add_sysfs(d);
243
244 printk(KERN_INFO "aoe: %012llx e%lu.%lu v%04x has %llu "
245 "sectors\n", (unsigned long long)mac_addr(d->addr),
246 d->aoemajor, d->aoeminor,
247 d->fw_ver, (long long)d->ssize);
248}
249
250void
251aoeblk_exit(void)
252{
253 kmem_cache_destroy(buf_pool_cache);
254}
255
256int __init
257aoeblk_init(void)
258{
259 buf_pool_cache = kmem_cache_create("aoe_bufs",
260 sizeof(struct buf),
261 0, 0, NULL, NULL);
262 if (buf_pool_cache == NULL)
263 return -ENOMEM;
264
265 return 0;
266}
267
diff --git a/drivers/block/aoe/aoechr.c b/drivers/block/aoe/aoechr.c
new file mode 100644
index 000000000000..14aeca3e2e8c
--- /dev/null
+++ b/drivers/block/aoe/aoechr.c
@@ -0,0 +1,244 @@
1/* Copyright (c) 2004 Coraid, Inc. See COPYING for GPL terms. */
2/*
3 * aoechr.c
4 * AoE character device driver
5 */
6
7#include <linux/hdreg.h>
8#include <linux/blkdev.h>
9#include "aoe.h"
10
11enum {
12 //MINOR_STAT = 1, (moved to sysfs)
13 MINOR_ERR = 2,
14 MINOR_DISCOVER,
15 MINOR_INTERFACES,
16 MSGSZ = 2048,
17 NARGS = 10,
18 NMSG = 100, /* message backlog to retain */
19};
20
21struct aoe_chardev {
22 ulong minor;
23 char name[32];
24};
25
26enum { EMFL_VALID = 1 };
27
28struct ErrMsg {
29 short flags;
30 short len;
31 char *msg;
32};
33
34static struct ErrMsg emsgs[NMSG];
35static int emsgs_head_idx, emsgs_tail_idx;
36static struct semaphore emsgs_sema;
37static spinlock_t emsgs_lock;
38static int nblocked_emsgs_readers;
39static struct class_simple *aoe_class;
40static struct aoe_chardev chardevs[] = {
41 { MINOR_ERR, "err" },
42 { MINOR_DISCOVER, "discover" },
43 { MINOR_INTERFACES, "interfaces" },
44};
45
46static int
47discover(void)
48{
49 aoecmd_cfg(0xffff, 0xff);
50 return 0;
51}
52
53static int
54interfaces(const char __user *str, size_t size)
55{
56 if (set_aoe_iflist(str, size)) {
57 printk(KERN_CRIT
58 "%s: could not set interface list: %s\n",
59 __FUNCTION__, "too many interfaces");
60 return -EINVAL;
61 }
62 return 0;
63}
64
65void
66aoechr_error(char *msg)
67{
68 struct ErrMsg *em;
69 char *mp;
70 ulong flags, n;
71
72 n = strlen(msg);
73
74 spin_lock_irqsave(&emsgs_lock, flags);
75
76 em = emsgs + emsgs_tail_idx;
77 if ((em->flags & EMFL_VALID)) {
78bail: spin_unlock_irqrestore(&emsgs_lock, flags);
79 return;
80 }
81
82 mp = kmalloc(n, GFP_ATOMIC);
83 if (mp == NULL) {
84 printk(KERN_CRIT "aoe: aoechr_error: allocation failure, len=%ld\n", n);
85 goto bail;
86 }
87
88 memcpy(mp, msg, n);
89 em->msg = mp;
90 em->flags |= EMFL_VALID;
91 em->len = n;
92
93 emsgs_tail_idx++;
94 emsgs_tail_idx %= ARRAY_SIZE(emsgs);
95
96 spin_unlock_irqrestore(&emsgs_lock, flags);
97
98 if (nblocked_emsgs_readers)
99 up(&emsgs_sema);
100}
101
102static ssize_t
103aoechr_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offp)
104{
105 int ret = -EINVAL;
106
107 switch ((unsigned long) filp->private_data) {
108 default:
109 printk(KERN_INFO "aoe: aoechr_write: can't write to that file.\n");
110 break;
111 case MINOR_DISCOVER:
112 ret = discover();
113 break;
114 case MINOR_INTERFACES:
115 ret = interfaces(buf, cnt);
116 break;
117 }
118 if (ret == 0)
119 ret = cnt;
120 return ret;
121}
122
123static int
124aoechr_open(struct inode *inode, struct file *filp)
125{
126 int n, i;
127
128 n = MINOR(inode->i_rdev);
129 filp->private_data = (void *) (unsigned long) n;
130
131 for (i = 0; i < ARRAY_SIZE(chardevs); ++i)
132 if (chardevs[i].minor == n)
133 return 0;
134 return -EINVAL;
135}
136
137static int
138aoechr_rel(struct inode *inode, struct file *filp)
139{
140 return 0;
141}
142
143static ssize_t
144aoechr_read(struct file *filp, char __user *buf, size_t cnt, loff_t *off)
145{
146 unsigned long n;
147 char *mp;
148 struct ErrMsg *em;
149 ssize_t len;
150 ulong flags;
151
152 n = (unsigned long) filp->private_data;
153 switch (n) {
154 case MINOR_ERR:
155 spin_lock_irqsave(&emsgs_lock, flags);
156loop:
157 em = emsgs + emsgs_head_idx;
158 if ((em->flags & EMFL_VALID) == 0) {
159 if (filp->f_flags & O_NDELAY) {
160 spin_unlock_irqrestore(&emsgs_lock, flags);
161 return -EAGAIN;
162 }
163 nblocked_emsgs_readers++;
164
165 spin_unlock_irqrestore(&emsgs_lock, flags);
166
167 n = down_interruptible(&emsgs_sema);
168
169 spin_lock_irqsave(&emsgs_lock, flags);
170
171 nblocked_emsgs_readers--;
172
173 if (n) {
174 spin_unlock_irqrestore(&emsgs_lock, flags);
175 return -ERESTARTSYS;
176 }
177 goto loop;
178 }
179 if (em->len > cnt) {
180 spin_unlock_irqrestore(&emsgs_lock, flags);
181 return -EAGAIN;
182 }
183 mp = em->msg;
184 len = em->len;
185 em->msg = NULL;
186 em->flags &= ~EMFL_VALID;
187
188 emsgs_head_idx++;
189 emsgs_head_idx %= ARRAY_SIZE(emsgs);
190
191 spin_unlock_irqrestore(&emsgs_lock, flags);
192
193 n = copy_to_user(buf, mp, len);
194 kfree(mp);
195 return n == 0 ? len : -EFAULT;
196 default:
197 return -EFAULT;
198 }
199}
200
201static struct file_operations aoe_fops = {
202 .write = aoechr_write,
203 .read = aoechr_read,
204 .open = aoechr_open,
205 .release = aoechr_rel,
206 .owner = THIS_MODULE,
207};
208
209int __init
210aoechr_init(void)
211{
212 int n, i;
213
214 n = register_chrdev(AOE_MAJOR, "aoechr", &aoe_fops);
215 if (n < 0) {
216 printk(KERN_ERR "aoe: aoechr_init: can't register char device\n");
217 return n;
218 }
219 sema_init(&emsgs_sema, 0);
220 spin_lock_init(&emsgs_lock);
221 aoe_class = class_simple_create(THIS_MODULE, "aoe");
222 if (IS_ERR(aoe_class)) {
223 unregister_chrdev(AOE_MAJOR, "aoechr");
224 return PTR_ERR(aoe_class);
225 }
226 for (i = 0; i < ARRAY_SIZE(chardevs); ++i)
227 class_simple_device_add(aoe_class,
228 MKDEV(AOE_MAJOR, chardevs[i].minor),
229 NULL, chardevs[i].name);
230
231 return 0;
232}
233
234void
235aoechr_exit(void)
236{
237 int i;
238
239 for (i = 0; i < ARRAY_SIZE(chardevs); ++i)
240 class_simple_device_remove(MKDEV(AOE_MAJOR, chardevs[i].minor));
241 class_simple_destroy(aoe_class);
242 unregister_chrdev(AOE_MAJOR, "aoechr");
243}
244
diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c
new file mode 100644
index 000000000000..fb6d942a4565
--- /dev/null
+++ b/drivers/block/aoe/aoecmd.c
@@ -0,0 +1,629 @@
1/* Copyright (c) 2004 Coraid, Inc. See COPYING for GPL terms. */
2/*
3 * aoecmd.c
4 * Filesystem request handling methods
5 */
6
7#include <linux/hdreg.h>
8#include <linux/blkdev.h>
9#include <linux/skbuff.h>
10#include <linux/netdevice.h>
11#include "aoe.h"
12
13#define TIMERTICK (HZ / 10)
14#define MINTIMER (2 * TIMERTICK)
15#define MAXTIMER (HZ << 1)
16#define MAXWAIT (60 * 3) /* After MAXWAIT seconds, give up and fail dev */
17
18static struct sk_buff *
19new_skb(struct net_device *if_dev, ulong len)
20{
21 struct sk_buff *skb;
22
23 skb = alloc_skb(len, GFP_ATOMIC);
24 if (skb) {
25 skb->nh.raw = skb->mac.raw = skb->data;
26 skb->dev = if_dev;
27 skb->protocol = __constant_htons(ETH_P_AOE);
28 skb->priority = 0;
29 skb_put(skb, len);
30 skb->next = skb->prev = NULL;
31
32 /* tell the network layer not to perform IP checksums
33 * or to get the NIC to do it
34 */
35 skb->ip_summed = CHECKSUM_NONE;
36 }
37 return skb;
38}
39
40static struct sk_buff *
41skb_prepare(struct aoedev *d, struct frame *f)
42{
43 struct sk_buff *skb;
44 char *p;
45
46 skb = new_skb(d->ifp, f->ndata + f->writedatalen);
47 if (!skb) {
48 printk(KERN_INFO "aoe: skb_prepare: failure to allocate skb\n");
49 return NULL;
50 }
51
52 p = skb->mac.raw;
53 memcpy(p, f->data, f->ndata);
54
55 if (f->writedatalen) {
56 p += sizeof(struct aoe_hdr) + sizeof(struct aoe_atahdr);
57 memcpy(p, f->bufaddr, f->writedatalen);
58 }
59
60 return skb;
61}
62
63static struct frame *
64getframe(struct aoedev *d, int tag)
65{
66 struct frame *f, *e;
67
68 f = d->frames;
69 e = f + d->nframes;
70 for (; f<e; f++)
71 if (f->tag == tag)
72 return f;
73 return NULL;
74}
75
76/*
77 * Leave the top bit clear so we have tagspace for userland.
78 * The bottom 16 bits are the xmit tick for rexmit/rttavg processing.
79 * This driver reserves tag -1 to mean "unused frame."
80 */
81static int
82newtag(struct aoedev *d)
83{
84 register ulong n;
85
86 n = jiffies & 0xffff;
87 return n |= (++d->lasttag & 0x7fff) << 16;
88}
89
90static int
91aoehdr_atainit(struct aoedev *d, struct aoe_hdr *h)
92{
93 u16 type = __constant_cpu_to_be16(ETH_P_AOE);
94 u16 aoemajor = __cpu_to_be16(d->aoemajor);
95 u32 host_tag = newtag(d);
96 u32 tag = __cpu_to_be32(host_tag);
97
98 memcpy(h->src, d->ifp->dev_addr, sizeof h->src);
99 memcpy(h->dst, d->addr, sizeof h->dst);
100 memcpy(h->type, &type, sizeof type);
101 h->verfl = AOE_HVER;
102 memcpy(h->major, &aoemajor, sizeof aoemajor);
103 h->minor = d->aoeminor;
104 h->cmd = AOECMD_ATA;
105 memcpy(h->tag, &tag, sizeof tag);
106
107 return host_tag;
108}
109
110static void
111aoecmd_ata_rw(struct aoedev *d, struct frame *f)
112{
113 struct aoe_hdr *h;
114 struct aoe_atahdr *ah;
115 struct buf *buf;
116 struct sk_buff *skb;
117 ulong bcnt;
118 register sector_t sector;
119 char writebit, extbit;
120
121 writebit = 0x10;
122 extbit = 0x4;
123
124 buf = d->inprocess;
125
126 sector = buf->sector;
127 bcnt = buf->bv_resid;
128 if (bcnt > MAXATADATA)
129 bcnt = MAXATADATA;
130
131 /* initialize the headers & frame */
132 h = (struct aoe_hdr *) f->data;
133 ah = (struct aoe_atahdr *) (h+1);
134 f->ndata = sizeof *h + sizeof *ah;
135 memset(h, 0, f->ndata);
136 f->tag = aoehdr_atainit(d, h);
137 f->waited = 0;
138 f->buf = buf;
139 f->bufaddr = buf->bufaddr;
140
141 /* set up ata header */
142 ah->scnt = bcnt >> 9;
143 ah->lba0 = sector;
144 ah->lba1 = sector >>= 8;
145 ah->lba2 = sector >>= 8;
146 ah->lba3 = sector >>= 8;
147 if (d->flags & DEVFL_EXT) {
148 ah->aflags |= AOEAFL_EXT;
149 ah->lba4 = sector >>= 8;
150 ah->lba5 = sector >>= 8;
151 } else {
152 extbit = 0;
153 ah->lba3 &= 0x0f;
154 ah->lba3 |= 0xe0; /* LBA bit + obsolete 0xa0 */
155 }
156
157 if (bio_data_dir(buf->bio) == WRITE) {
158 ah->aflags |= AOEAFL_WRITE;
159 f->writedatalen = bcnt;
160 } else {
161 writebit = 0;
162 f->writedatalen = 0;
163 }
164
165 ah->cmdstat = WIN_READ | writebit | extbit;
166
167 /* mark all tracking fields and load out */
168 buf->nframesout += 1;
169 buf->bufaddr += bcnt;
170 buf->bv_resid -= bcnt;
171/* printk(KERN_INFO "aoe: bv_resid=%ld\n", buf->bv_resid); */
172 buf->resid -= bcnt;
173 buf->sector += bcnt >> 9;
174 if (buf->resid == 0) {
175 d->inprocess = NULL;
176 } else if (buf->bv_resid == 0) {
177 buf->bv++;
178 buf->bv_resid = buf->bv->bv_len;
179 buf->bufaddr = page_address(buf->bv->bv_page) + buf->bv->bv_offset;
180 }
181
182 skb = skb_prepare(d, f);
183 if (skb) {
184 skb->next = d->skblist;
185 d->skblist = skb;
186 }
187}
188
189/* enters with d->lock held */
190void
191aoecmd_work(struct aoedev *d)
192{
193 struct frame *f;
194 struct buf *buf;
195loop:
196 f = getframe(d, FREETAG);
197 if (f == NULL)
198 return;
199 if (d->inprocess == NULL) {
200 if (list_empty(&d->bufq))
201 return;
202 buf = container_of(d->bufq.next, struct buf, bufs);
203 list_del(d->bufq.next);
204/*printk(KERN_INFO "aoecmd_work: bi_size=%ld\n", buf->bio->bi_size); */
205 d->inprocess = buf;
206 }
207 aoecmd_ata_rw(d, f);
208 goto loop;
209}
210
211static void
212rexmit(struct aoedev *d, struct frame *f)
213{
214 struct sk_buff *skb;
215 struct aoe_hdr *h;
216 char buf[128];
217 u32 n;
218 u32 net_tag;
219
220 n = newtag(d);
221
222 snprintf(buf, sizeof buf,
223 "%15s e%ld.%ld oldtag=%08x@%08lx newtag=%08x\n",
224 "retransmit",
225 d->aoemajor, d->aoeminor, f->tag, jiffies, n);
226 aoechr_error(buf);
227
228 h = (struct aoe_hdr *) f->data;
229 f->tag = n;
230 net_tag = __cpu_to_be32(n);
231 memcpy(h->tag, &net_tag, sizeof net_tag);
232
233 skb = skb_prepare(d, f);
234 if (skb) {
235 skb->next = d->skblist;
236 d->skblist = skb;
237 }
238}
239
240static int
241tsince(int tag)
242{
243 int n;
244
245 n = jiffies & 0xffff;
246 n -= tag & 0xffff;
247 if (n < 0)
248 n += 1<<16;
249 return n;
250}
251
252static void
253rexmit_timer(ulong vp)
254{
255 struct aoedev *d;
256 struct frame *f, *e;
257 struct sk_buff *sl;
258 register long timeout;
259 ulong flags, n;
260
261 d = (struct aoedev *) vp;
262 sl = NULL;
263
264 /* timeout is always ~150% of the moving average */
265 timeout = d->rttavg;
266 timeout += timeout >> 1;
267
268 spin_lock_irqsave(&d->lock, flags);
269
270 if (d->flags & DEVFL_TKILL) {
271tdie: spin_unlock_irqrestore(&d->lock, flags);
272 return;
273 }
274 f = d->frames;
275 e = f + d->nframes;
276 for (; f<e; f++) {
277 if (f->tag != FREETAG && tsince(f->tag) >= timeout) {
278 n = f->waited += timeout;
279 n /= HZ;
280 if (n > MAXWAIT) { /* waited too long. device failure. */
281 aoedev_downdev(d);
282 goto tdie;
283 }
284 rexmit(d, f);
285 }
286 }
287
288 sl = d->skblist;
289 d->skblist = NULL;
290 if (sl) {
291 n = d->rttavg <<= 1;
292 if (n > MAXTIMER)
293 d->rttavg = MAXTIMER;
294 }
295
296 d->timer.expires = jiffies + TIMERTICK;
297 add_timer(&d->timer);
298
299 spin_unlock_irqrestore(&d->lock, flags);
300
301 aoenet_xmit(sl);
302}
303
304static void
305ataid_complete(struct aoedev *d, unsigned char *id)
306{
307 u64 ssize;
308 u16 n;
309
310 /* word 83: command set supported */
311 n = __le16_to_cpu(*((u16 *) &id[83<<1]));
312
313 /* word 86: command set/feature enabled */
314 n |= __le16_to_cpu(*((u16 *) &id[86<<1]));
315
316 if (n & (1<<10)) { /* bit 10: LBA 48 */
317 d->flags |= DEVFL_EXT;
318
319 /* word 100: number lba48 sectors */
320 ssize = __le64_to_cpu(*((u64 *) &id[100<<1]));
321
322 /* set as in ide-disk.c:init_idedisk_capacity */
323 d->geo.cylinders = ssize;
324 d->geo.cylinders /= (255 * 63);
325 d->geo.heads = 255;
326 d->geo.sectors = 63;
327 } else {
328 d->flags &= ~DEVFL_EXT;
329
330 /* number lba28 sectors */
331 ssize = __le32_to_cpu(*((u32 *) &id[60<<1]));
332
333 /* NOTE: obsolete in ATA 6 */
334 d->geo.cylinders = __le16_to_cpu(*((u16 *) &id[54<<1]));
335 d->geo.heads = __le16_to_cpu(*((u16 *) &id[55<<1]));
336 d->geo.sectors = __le16_to_cpu(*((u16 *) &id[56<<1]));
337 }
338 d->ssize = ssize;
339 d->geo.start = 0;
340 if (d->gd != NULL) {
341 d->gd->capacity = ssize;
342 d->flags |= DEVFL_UP;
343 return;
344 }
345 if (d->flags & DEVFL_WORKON) {
346 printk(KERN_INFO "aoe: ataid_complete: can't schedule work, it's already on! "
347 "(This really shouldn't happen).\n");
348 return;
349 }
350 INIT_WORK(&d->work, aoeblk_gdalloc, d);
351 schedule_work(&d->work);
352 d->flags |= DEVFL_WORKON;
353}
354
355static void
356calc_rttavg(struct aoedev *d, int rtt)
357{
358 register long n;
359
360 n = rtt;
361 if (n < MINTIMER)
362 n = MINTIMER;
363 else if (n > MAXTIMER)
364 n = MAXTIMER;
365
366 /* g == .25; cf. Congestion Avoidance and Control, Jacobson & Karels; 1988 */
367 n -= d->rttavg;
368 d->rttavg += n >> 2;
369}
370
371void
372aoecmd_ata_rsp(struct sk_buff *skb)
373{
374 struct aoedev *d;
375 struct aoe_hdr *hin;
376 struct aoe_atahdr *ahin, *ahout;
377 struct frame *f;
378 struct buf *buf;
379 struct sk_buff *sl;
380 register long n;
381 ulong flags;
382 char ebuf[128];
383
384 hin = (struct aoe_hdr *) skb->mac.raw;
385 d = aoedev_bymac(hin->src);
386 if (d == NULL) {
387 snprintf(ebuf, sizeof ebuf, "aoecmd_ata_rsp: ata response "
388 "for unknown device %d.%d\n",
389 __be16_to_cpu(*((u16 *) hin->major)),
390 hin->minor);
391 aoechr_error(ebuf);
392 return;
393 }
394
395 spin_lock_irqsave(&d->lock, flags);
396
397 f = getframe(d, __be32_to_cpu(*((u32 *) hin->tag)));
398 if (f == NULL) {
399 spin_unlock_irqrestore(&d->lock, flags);
400 snprintf(ebuf, sizeof ebuf,
401 "%15s e%d.%d tag=%08x@%08lx\n",
402 "unexpected rsp",
403 __be16_to_cpu(*((u16 *) hin->major)),
404 hin->minor,
405 __be32_to_cpu(*((u32 *) hin->tag)),
406 jiffies);
407 aoechr_error(ebuf);
408 return;
409 }
410
411 calc_rttavg(d, tsince(f->tag));
412
413 ahin = (struct aoe_atahdr *) (hin+1);
414 ahout = (struct aoe_atahdr *) (f->data + sizeof(struct aoe_hdr));
415 buf = f->buf;
416
417 if (ahin->cmdstat & 0xa9) { /* these bits cleared on success */
418 printk(KERN_CRIT "aoe: aoecmd_ata_rsp: ata error cmd=%2.2Xh "
419 "stat=%2.2Xh from e%ld.%ld\n",
420 ahout->cmdstat, ahin->cmdstat,
421 d->aoemajor, d->aoeminor);
422 if (buf)
423 buf->flags |= BUFFL_FAIL;
424 } else {
425 switch (ahout->cmdstat) {
426 case WIN_READ:
427 case WIN_READ_EXT:
428 n = ahout->scnt << 9;
429 if (skb->len - sizeof *hin - sizeof *ahin < n) {
430 printk(KERN_CRIT "aoe: aoecmd_ata_rsp: runt "
431 "ata data size in read. skb->len=%d\n",
432 skb->len);
433 /* fail frame f? just returning will rexmit. */
434 spin_unlock_irqrestore(&d->lock, flags);
435 return;
436 }
437 memcpy(f->bufaddr, ahin+1, n);
438 case WIN_WRITE:
439 case WIN_WRITE_EXT:
440 break;
441 case WIN_IDENTIFY:
442 if (skb->len - sizeof *hin - sizeof *ahin < 512) {
443 printk(KERN_INFO "aoe: aoecmd_ata_rsp: runt data size "
444 "in ataid. skb->len=%d\n", skb->len);
445 spin_unlock_irqrestore(&d->lock, flags);
446 return;
447 }
448 ataid_complete(d, (char *) (ahin+1));
449 /* d->flags |= DEVFL_WC_UPDATE; */
450 break;
451 default:
452 printk(KERN_INFO "aoe: aoecmd_ata_rsp: unrecognized "
453 "outbound ata command %2.2Xh for %d.%d\n",
454 ahout->cmdstat,
455 __be16_to_cpu(*((u16 *) hin->major)),
456 hin->minor);
457 }
458 }
459
460 if (buf) {
461 buf->nframesout -= 1;
462 if (buf->nframesout == 0 && buf->resid == 0) {
463 n = (buf->flags & BUFFL_FAIL) ? -EIO : 0;
464 bio_endio(buf->bio, buf->bio->bi_size, n);
465 mempool_free(buf, d->bufpool);
466 }
467 }
468
469 f->buf = NULL;
470 f->tag = FREETAG;
471
472 aoecmd_work(d);
473
474 sl = d->skblist;
475 d->skblist = NULL;
476
477 spin_unlock_irqrestore(&d->lock, flags);
478
479 aoenet_xmit(sl);
480}
481
482void
483aoecmd_cfg(ushort aoemajor, unsigned char aoeminor)
484{
485 struct aoe_hdr *h;
486 struct aoe_cfghdr *ch;
487 struct sk_buff *skb, *sl;
488 struct net_device *ifp;
489 u16 aoe_type = __constant_cpu_to_be16(ETH_P_AOE);
490 u16 net_aoemajor = __cpu_to_be16(aoemajor);
491
492 sl = NULL;
493
494 read_lock(&dev_base_lock);
495 for (ifp = dev_base; ifp; dev_put(ifp), ifp = ifp->next) {
496 dev_hold(ifp);
497 if (!is_aoe_netif(ifp))
498 continue;
499
500 skb = new_skb(ifp, sizeof *h + sizeof *ch);
501 if (skb == NULL) {
502 printk(KERN_INFO "aoe: aoecmd_cfg: skb alloc failure\n");
503 continue;
504 }
505 h = (struct aoe_hdr *) skb->mac.raw;
506 memset(h, 0, sizeof *h + sizeof *ch);
507
508 memset(h->dst, 0xff, sizeof h->dst);
509 memcpy(h->src, ifp->dev_addr, sizeof h->src);
510 memcpy(h->type, &aoe_type, sizeof aoe_type);
511 h->verfl = AOE_HVER;
512 memcpy(h->major, &net_aoemajor, sizeof net_aoemajor);
513 h->minor = aoeminor;
514 h->cmd = AOECMD_CFG;
515
516 skb->next = sl;
517 sl = skb;
518 }
519 read_unlock(&dev_base_lock);
520
521 aoenet_xmit(sl);
522}
523
524/*
525 * Since we only call this in one place (and it only prepares one frame)
526 * we just return the skb. Usually we'd chain it up to the d->skblist.
527 */
528static struct sk_buff *
529aoecmd_ata_id(struct aoedev *d)
530{
531 struct aoe_hdr *h;
532 struct aoe_atahdr *ah;
533 struct frame *f;
534 struct sk_buff *skb;
535
536 f = getframe(d, FREETAG);
537 if (f == NULL) {
538 printk(KERN_CRIT "aoe: aoecmd_ata_id: can't get a frame. "
539 "This shouldn't happen.\n");
540 return NULL;
541 }
542
543 /* initialize the headers & frame */
544 h = (struct aoe_hdr *) f->data;
545 ah = (struct aoe_atahdr *) (h+1);
546 f->ndata = sizeof *h + sizeof *ah;
547 memset(h, 0, f->ndata);
548 f->tag = aoehdr_atainit(d, h);
549 f->waited = 0;
550 f->writedatalen = 0;
551
552 /* this message initializes the device, so we reset the rttavg */
553 d->rttavg = MAXTIMER;
554
555 /* set up ata header */
556 ah->scnt = 1;
557 ah->cmdstat = WIN_IDENTIFY;
558 ah->lba3 = 0xa0;
559
560 skb = skb_prepare(d, f);
561
562 /* we now want to start the rexmit tracking */
563 d->flags &= ~DEVFL_TKILL;
564 d->timer.data = (ulong) d;
565 d->timer.function = rexmit_timer;
566 d->timer.expires = jiffies + TIMERTICK;
567 add_timer(&d->timer);
568
569 return skb;
570}
571
572void
573aoecmd_cfg_rsp(struct sk_buff *skb)
574{
575 struct aoedev *d;
576 struct aoe_hdr *h;
577 struct aoe_cfghdr *ch;
578 ulong flags, bufcnt, sysminor, aoemajor;
579 struct sk_buff *sl;
580 enum { MAXFRAMES = 8, MAXSYSMINOR = 255 };
581
582 h = (struct aoe_hdr *) skb->mac.raw;
583 ch = (struct aoe_cfghdr *) (h+1);
584
585 /*
586 * Enough people have their dip switches set backwards to
587 * warrant a loud message for this special case.
588 */
589 aoemajor = __be16_to_cpu(*((u16 *) h->major));
590 if (aoemajor == 0xfff) {
591 printk(KERN_CRIT "aoe: aoecmd_cfg_rsp: Warning: shelf "
592 "address is all ones. Check shelf dip switches\n");
593 return;
594 }
595
596 sysminor = SYSMINOR(aoemajor, h->minor);
597 if (sysminor > MAXSYSMINOR) {
598 printk(KERN_INFO "aoe: aoecmd_cfg_rsp: sysminor %ld too "
599 "large\n", sysminor);
600 return;
601 }
602
603 bufcnt = __be16_to_cpu(*((u16 *) ch->bufcnt));
604 if (bufcnt > MAXFRAMES) /* keep it reasonable */
605 bufcnt = MAXFRAMES;
606
607 d = aoedev_set(sysminor, h->src, skb->dev, bufcnt);
608 if (d == NULL) {
609 printk(KERN_INFO "aoe: aoecmd_cfg_rsp: device set failure\n");
610 return;
611 }
612
613 spin_lock_irqsave(&d->lock, flags);
614
615 if (d->flags & (DEVFL_UP | DEVFL_CLOSEWAIT)) {
616 spin_unlock_irqrestore(&d->lock, flags);
617 return;
618 }
619
620 d->fw_ver = __be16_to_cpu(*((u16 *) ch->fwver));
621
622 /* we get here only if the device is new */
623 sl = aoecmd_ata_id(d);
624
625 spin_unlock_irqrestore(&d->lock, flags);
626
627 aoenet_xmit(sl);
628}
629
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
12static struct aoedev *devlist;
13static spinlock_t devlist_lock;
14
15struct aoedev *
16aoedev_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 */
32static struct aoedev *
33aoedev_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
63void
64aoedev_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
103struct aoedev *
104aoedev_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
141static void
142aoedev_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
154void
155aoedev_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
174int __init
175aoedev_init(void)
176{
177 spin_lock_init(&devlist_lock);
178 return 0;
179}
180
diff --git a/drivers/block/aoe/aoemain.c b/drivers/block/aoe/aoemain.c
new file mode 100644
index 000000000000..387588a3f4ba
--- /dev/null
+++ b/drivers/block/aoe/aoemain.c
@@ -0,0 +1,112 @@
1/* Copyright (c) 2004 Coraid, Inc. See COPYING for GPL terms. */
2/*
3 * aoemain.c
4 * Module initialization routines, discover timer
5 */
6
7#include <linux/hdreg.h>
8#include <linux/blkdev.h>
9#include <linux/module.h>
10#include "aoe.h"
11
12MODULE_LICENSE("GPL");
13MODULE_AUTHOR("Sam Hopkins <sah@coraid.com>");
14MODULE_DESCRIPTION("AoE block/char driver for 2.6.[0-9]+");
15MODULE_VERSION(VERSION);
16
17enum { TINIT, TRUN, TKILL };
18
19static void
20discover_timer(ulong vp)
21{
22 static struct timer_list t;
23 static volatile ulong die;
24 static spinlock_t lock;
25 ulong flags;
26 enum { DTIMERTICK = HZ * 60 }; /* one minute */
27
28 switch (vp) {
29 case TINIT:
30 init_timer(&t);
31 spin_lock_init(&lock);
32 t.data = TRUN;
33 t.function = discover_timer;
34 die = 0;
35 case TRUN:
36 spin_lock_irqsave(&lock, flags);
37 if (!die) {
38 t.expires = jiffies + DTIMERTICK;
39 add_timer(&t);
40 }
41 spin_unlock_irqrestore(&lock, flags);
42
43 aoecmd_cfg(0xffff, 0xff);
44 return;
45 case TKILL:
46 spin_lock_irqsave(&lock, flags);
47 die = 1;
48 spin_unlock_irqrestore(&lock, flags);
49
50 del_timer_sync(&t);
51 default:
52 return;
53 }
54}
55
56static void
57aoe_exit(void)
58{
59 discover_timer(TKILL);
60
61 aoenet_exit();
62 unregister_blkdev(AOE_MAJOR, DEVICE_NAME);
63 aoechr_exit();
64 aoedev_exit();
65 aoeblk_exit(); /* free cache after de-allocating bufs */
66}
67
68static int __init
69aoe_init(void)
70{
71 int ret;
72
73 ret = aoedev_init();
74 if (ret)
75 return ret;
76 ret = aoechr_init();
77 if (ret)
78 goto chr_fail;
79 ret = aoeblk_init();
80 if (ret)
81 goto blk_fail;
82 ret = aoenet_init();
83 if (ret)
84 goto net_fail;
85 ret = register_blkdev(AOE_MAJOR, DEVICE_NAME);
86 if (ret < 0) {
87 printk(KERN_ERR "aoe: aoeblk_init: can't register major\n");
88 goto blkreg_fail;
89 }
90
91 printk(KERN_INFO
92 "aoe: aoe_init: AoE v2.6-%s initialised.\n",
93 VERSION);
94 discover_timer(TINIT);
95 return 0;
96
97 blkreg_fail:
98 aoenet_exit();
99 net_fail:
100 aoeblk_exit();
101 blk_fail:
102 aoechr_exit();
103 chr_fail:
104 aoedev_exit();
105
106 printk(KERN_INFO "aoe: aoe_init: initialisation failure.\n");
107 return ret;
108}
109
110module_init(aoe_init);
111module_exit(aoe_exit);
112
diff --git a/drivers/block/aoe/aoenet.c b/drivers/block/aoe/aoenet.c
new file mode 100644
index 000000000000..cc1945b8d52b
--- /dev/null
+++ b/drivers/block/aoe/aoenet.c
@@ -0,0 +1,172 @@
1/* Copyright (c) 2004 Coraid, Inc. See COPYING for GPL terms. */
2/*
3 * aoenet.c
4 * Ethernet portion of AoE driver
5 */
6
7#include <linux/hdreg.h>
8#include <linux/blkdev.h>
9#include <linux/netdevice.h>
10#include "aoe.h"
11
12#define NECODES 5
13
14static char *aoe_errlist[] =
15{
16 "no such error",
17 "unrecognized command code",
18 "bad argument parameter",
19 "device unavailable",
20 "config string present",
21 "unsupported version"
22};
23
24enum {
25 IFLISTSZ = 1024,
26};
27
28static char aoe_iflist[IFLISTSZ];
29
30int
31is_aoe_netif(struct net_device *ifp)
32{
33 register char *p, *q;
34 register int len;
35
36 if (aoe_iflist[0] == '\0')
37 return 1;
38
39 for (p = aoe_iflist; *p; p = q + strspn(q, WHITESPACE)) {
40 q = p + strcspn(p, WHITESPACE);
41 if (q != p)
42 len = q - p;
43 else
44 len = strlen(p); /* last token in aoe_iflist */
45
46 if (strlen(ifp->name) == len && !strncmp(ifp->name, p, len))
47 return 1;
48 if (q == p)
49 break;
50 }
51
52 return 0;
53}
54
55int
56set_aoe_iflist(const char __user *user_str, size_t size)
57{
58 if (size >= IFLISTSZ)
59 return -EINVAL;
60
61 if (copy_from_user(aoe_iflist, user_str, size)) {
62 printk(KERN_INFO "aoe: %s: copy from user failed\n", __FUNCTION__);
63 return -EFAULT;
64 }
65 aoe_iflist[size] = 0x00;
66 return 0;
67}
68
69u64
70mac_addr(char addr[6])
71{
72 u64 n = 0;
73 char *p = (char *) &n;
74
75 memcpy(p + 2, addr, 6); /* (sizeof addr != 6) */
76
77 return __be64_to_cpu(n);
78}
79
80static struct sk_buff *
81skb_check(struct sk_buff *skb)
82{
83 if (skb_is_nonlinear(skb))
84 if ((skb = skb_share_check(skb, GFP_ATOMIC)))
85 if (skb_linearize(skb, GFP_ATOMIC) < 0) {
86 dev_kfree_skb(skb);
87 return NULL;
88 }
89 return skb;
90}
91
92void
93aoenet_xmit(struct sk_buff *sl)
94{
95 struct sk_buff *skb;
96
97 while ((skb = sl)) {
98 sl = sl->next;
99 skb->next = skb->prev = NULL;
100 dev_queue_xmit(skb);
101 }
102}
103
104/*
105 * (1) len doesn't include the header by default. I want this.
106 */
107static int
108aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt)
109{
110 struct aoe_hdr *h;
111 ulong n;
112
113 skb = skb_check(skb);
114 if (!skb)
115 return 0;
116
117 if (!is_aoe_netif(ifp))
118 goto exit;
119
120 //skb->len += ETH_HLEN; /* (1) */
121 skb_push(skb, ETH_HLEN); /* (1) */
122
123 h = (struct aoe_hdr *) skb->mac.raw;
124 n = __be32_to_cpu(*((u32 *) h->tag));
125 if ((h->verfl & AOEFL_RSP) == 0 || (n & 1<<31))
126 goto exit;
127
128 if (h->verfl & AOEFL_ERR) {
129 n = h->err;
130 if (n > NECODES)
131 n = 0;
132 if (net_ratelimit())
133 printk(KERN_ERR "aoe: aoenet_rcv: error packet from %d.%d; "
134 "ecode=%d '%s'\n",
135 __be16_to_cpu(*((u16 *) h->major)), h->minor,
136 h->err, aoe_errlist[n]);
137 goto exit;
138 }
139
140 switch (h->cmd) {
141 case AOECMD_ATA:
142 aoecmd_ata_rsp(skb);
143 break;
144 case AOECMD_CFG:
145 aoecmd_cfg_rsp(skb);
146 break;
147 default:
148 printk(KERN_INFO "aoe: aoenet_rcv: unknown cmd %d\n", h->cmd);
149 }
150exit:
151 dev_kfree_skb(skb);
152 return 0;
153}
154
155static struct packet_type aoe_pt = {
156 .type = __constant_htons(ETH_P_AOE),
157 .func = aoenet_rcv,
158};
159
160int __init
161aoenet_init(void)
162{
163 dev_add_pack(&aoe_pt);
164 return 0;
165}
166
167void
168aoenet_exit(void)
169{
170 dev_remove_pack(&aoe_pt);
171}
172