diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /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/Makefile | 6 | ||||
-rw-r--r-- | drivers/block/aoe/aoe.h | 165 | ||||
-rw-r--r-- | drivers/block/aoe/aoeblk.c | 267 | ||||
-rw-r--r-- | drivers/block/aoe/aoechr.c | 244 | ||||
-rw-r--r-- | drivers/block/aoe/aoecmd.c | 629 | ||||
-rw-r--r-- | drivers/block/aoe/aoedev.c | 180 | ||||
-rw-r--r-- | drivers/block/aoe/aoemain.c | 112 | ||||
-rw-r--r-- | drivers/block/aoe/aoenet.c | 172 |
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 | |||
5 | obj-$(CONFIG_ATA_OVER_ETH) += aoe.o | ||
6 | aoe-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 | |||
13 | enum { | ||
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 | |||
34 | struct 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 | |||
46 | struct 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 | |||
60 | struct 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 | |||
68 | enum { | ||
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 | |||
79 | enum { | ||
80 | MAXATADATA = 1024, | ||
81 | NPERSHELF = 10, | ||
82 | FREETAG = -1, | ||
83 | MIN_BUFS = 8, | ||
84 | }; | ||
85 | |||
86 | struct 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 | |||
98 | struct 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 | |||
110 | struct 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 | |||
138 | int aoeblk_init(void); | ||
139 | void aoeblk_exit(void); | ||
140 | void aoeblk_gdalloc(void *); | ||
141 | void aoedisk_rm_sysfs(struct aoedev *d); | ||
142 | |||
143 | int aoechr_init(void); | ||
144 | void aoechr_exit(void); | ||
145 | void aoechr_error(char *); | ||
146 | |||
147 | void aoecmd_work(struct aoedev *d); | ||
148 | void aoecmd_cfg(ushort, unsigned char); | ||
149 | void aoecmd_ata_rsp(struct sk_buff *); | ||
150 | void aoecmd_cfg_rsp(struct sk_buff *); | ||
151 | |||
152 | int aoedev_init(void); | ||
153 | void aoedev_exit(void); | ||
154 | struct aoedev *aoedev_bymac(unsigned char *); | ||
155 | void aoedev_downdev(struct aoedev *d); | ||
156 | struct aoedev *aoedev_set(ulong, unsigned char *, struct net_device *, ulong); | ||
157 | int aoedev_busy(void); | ||
158 | |||
159 | int aoenet_init(void); | ||
160 | void aoenet_exit(void); | ||
161 | void aoenet_xmit(struct sk_buff *); | ||
162 | int is_aoe_netif(struct net_device *ifp); | ||
163 | int set_aoe_iflist(const char __user *str, size_t size); | ||
164 | |||
165 | u64 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 | |||
15 | static kmem_cache_t *buf_pool_cache; | ||
16 | |||
17 | /* add attributes for our block devices in sysfs */ | ||
18 | static 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 | } | ||
27 | static 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 | } | ||
34 | static 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 | |||
41 | static struct disk_attribute disk_attr_state = { | ||
42 | .attr = {.name = "state", .mode = S_IRUGO }, | ||
43 | .show = aoedisk_show_state | ||
44 | }; | ||
45 | static struct disk_attribute disk_attr_mac = { | ||
46 | .attr = {.name = "mac", .mode = S_IRUGO }, | ||
47 | .show = aoedisk_show_mac | ||
48 | }; | ||
49 | static struct disk_attribute disk_attr_netif = { | ||
50 | .attr = {.name = "netif", .mode = S_IRUGO }, | ||
51 | .show = aoedisk_show_netif | ||
52 | }; | ||
53 | |||
54 | static void | ||
55 | aoedisk_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 | } | ||
61 | void | ||
62 | aoedisk_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 | |||
69 | static int | ||
70 | aoeblk_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 | |||
87 | static int | ||
88 | aoeblk_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 | |||
108 | static int | ||
109 | aoeblk_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 | */ | ||
162 | static int | ||
163 | aoeblk_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 | |||
186 | static 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 */ | ||
194 | void | ||
195 | aoeblk_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 | |||
250 | void | ||
251 | aoeblk_exit(void) | ||
252 | { | ||
253 | kmem_cache_destroy(buf_pool_cache); | ||
254 | } | ||
255 | |||
256 | int __init | ||
257 | aoeblk_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 | |||
11 | enum { | ||
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 | |||
21 | struct aoe_chardev { | ||
22 | ulong minor; | ||
23 | char name[32]; | ||
24 | }; | ||
25 | |||
26 | enum { EMFL_VALID = 1 }; | ||
27 | |||
28 | struct ErrMsg { | ||
29 | short flags; | ||
30 | short len; | ||
31 | char *msg; | ||
32 | }; | ||
33 | |||
34 | static struct ErrMsg emsgs[NMSG]; | ||
35 | static int emsgs_head_idx, emsgs_tail_idx; | ||
36 | static struct semaphore emsgs_sema; | ||
37 | static spinlock_t emsgs_lock; | ||
38 | static int nblocked_emsgs_readers; | ||
39 | static struct class_simple *aoe_class; | ||
40 | static struct aoe_chardev chardevs[] = { | ||
41 | { MINOR_ERR, "err" }, | ||
42 | { MINOR_DISCOVER, "discover" }, | ||
43 | { MINOR_INTERFACES, "interfaces" }, | ||
44 | }; | ||
45 | |||
46 | static int | ||
47 | discover(void) | ||
48 | { | ||
49 | aoecmd_cfg(0xffff, 0xff); | ||
50 | return 0; | ||
51 | } | ||
52 | |||
53 | static int | ||
54 | interfaces(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 | |||
65 | void | ||
66 | aoechr_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)) { | ||
78 | bail: 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 | |||
102 | static ssize_t | ||
103 | aoechr_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 | |||
123 | static int | ||
124 | aoechr_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 | |||
137 | static int | ||
138 | aoechr_rel(struct inode *inode, struct file *filp) | ||
139 | { | ||
140 | return 0; | ||
141 | } | ||
142 | |||
143 | static ssize_t | ||
144 | aoechr_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); | ||
156 | loop: | ||
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 | |||
201 | static 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 | |||
209 | int __init | ||
210 | aoechr_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 | |||
234 | void | ||
235 | aoechr_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 | |||
18 | static struct sk_buff * | ||
19 | new_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 | |||
40 | static struct sk_buff * | ||
41 | skb_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 | |||
63 | static struct frame * | ||
64 | getframe(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 | */ | ||
81 | static int | ||
82 | newtag(struct aoedev *d) | ||
83 | { | ||
84 | register ulong n; | ||
85 | |||
86 | n = jiffies & 0xffff; | ||
87 | return n |= (++d->lasttag & 0x7fff) << 16; | ||
88 | } | ||
89 | |||
90 | static int | ||
91 | aoehdr_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 | |||
110 | static void | ||
111 | aoecmd_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 */ | ||
190 | void | ||
191 | aoecmd_work(struct aoedev *d) | ||
192 | { | ||
193 | struct frame *f; | ||
194 | struct buf *buf; | ||
195 | loop: | ||
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 | |||
211 | static void | ||
212 | rexmit(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 | |||
240 | static int | ||
241 | tsince(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 | |||
252 | static void | ||
253 | rexmit_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) { | ||
271 | tdie: 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 | |||
304 | static void | ||
305 | ataid_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 | |||
355 | static void | ||
356 | calc_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 | |||
371 | void | ||
372 | aoecmd_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 | |||
482 | void | ||
483 | aoecmd_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 | */ | ||
528 | static struct sk_buff * | ||
529 | aoecmd_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 | |||
572 | void | ||
573 | aoecmd_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 | |||
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 | |||
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 | |||
12 | MODULE_LICENSE("GPL"); | ||
13 | MODULE_AUTHOR("Sam Hopkins <sah@coraid.com>"); | ||
14 | MODULE_DESCRIPTION("AoE block/char driver for 2.6.[0-9]+"); | ||
15 | MODULE_VERSION(VERSION); | ||
16 | |||
17 | enum { TINIT, TRUN, TKILL }; | ||
18 | |||
19 | static void | ||
20 | discover_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 | |||
56 | static void | ||
57 | aoe_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 | |||
68 | static int __init | ||
69 | aoe_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 | |||
110 | module_init(aoe_init); | ||
111 | module_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 | |||
14 | static 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 | |||
24 | enum { | ||
25 | IFLISTSZ = 1024, | ||
26 | }; | ||
27 | |||
28 | static char aoe_iflist[IFLISTSZ]; | ||
29 | |||
30 | int | ||
31 | is_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 | |||
55 | int | ||
56 | set_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 | |||
69 | u64 | ||
70 | mac_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 | |||
80 | static struct sk_buff * | ||
81 | skb_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 | |||
92 | void | ||
93 | aoenet_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 | */ | ||
107 | static int | ||
108 | aoenet_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 | } | ||
150 | exit: | ||
151 | dev_kfree_skb(skb); | ||
152 | return 0; | ||
153 | } | ||
154 | |||
155 | static struct packet_type aoe_pt = { | ||
156 | .type = __constant_htons(ETH_P_AOE), | ||
157 | .func = aoenet_rcv, | ||
158 | }; | ||
159 | |||
160 | int __init | ||
161 | aoenet_init(void) | ||
162 | { | ||
163 | dev_add_pack(&aoe_pt); | ||
164 | return 0; | ||
165 | } | ||
166 | |||
167 | void | ||
168 | aoenet_exit(void) | ||
169 | { | ||
170 | dev_remove_pack(&aoe_pt); | ||
171 | } | ||
172 | |||