Browse Source

Initial AoE implementation. Limitations are:

  Cannot yet handle reads of more than two sectors

  No retransmission

  No way to find out a target's MAC address (this proof of concept uses
  broadcasts)

These limitations shall not last long!  :)
tags/v0.9.3
Michael Brown 18 years ago
parent
commit
9a2a52693d
3 changed files with 437 additions and 0 deletions
  1. 52
    0
      src/drivers/ata/aoedev.c
  2. 124
    0
      src/include/gpxe/aoe.h
  3. 261
    0
      src/net/aoe.c

+ 52
- 0
src/drivers/ata/aoedev.c View File

@@ -0,0 +1,52 @@
1
+/*
2
+ * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
+ */
18
+
19
+#include <stddef.h>
20
+#include <gpxe/aoe.h>
21
+
22
+/** @file
23
+ *
24
+ * AoE ATA device
25
+ *
26
+ */
27
+
28
+/**
29
+ * Issue ATA command via AoE device
30
+ *
31
+ * @v ata		ATA device
32
+ * @v command		ATA command
33
+ * @ret rc		Return status code
34
+ */
35
+static int aoe_command ( struct ata_device *ata,
36
+			 struct ata_command *command ) {
37
+	struct aoe_device *aoedev
38
+		= container_of ( ata, struct aoe_device, ata );
39
+
40
+	return aoe_issue ( &aoedev->aoe, command );
41
+}
42
+
43
+/**
44
+ * Initialise AoE device
45
+ *
46
+ * @v aoedev		AoE device
47
+ */
48
+int init_aoedev ( struct aoe_device *aoedev ) {
49
+	aoedev->ata.command = aoe_command;
50
+	aoe_open ( &aoedev->aoe );
51
+	return init_atadev ( &aoedev->ata );
52
+}

+ 124
- 0
src/include/gpxe/aoe.h View File

@@ -0,0 +1,124 @@
1
+#ifndef _GPXE_AOE_H
2
+#define _GPXE_AOE_H
3
+
4
+/** @file
5
+ *
6
+ * AoE protocol
7
+ *
8
+ */
9
+
10
+#include <stdint.h>
11
+#include <gpxe/list.h>
12
+#include <gpxe/if_ether.h>
13
+#include <gpxe/ata.h>
14
+
15
+/** An AoE ATA command */
16
+struct aoecmd {
17
+	/** AoE command flags */
18
+	uint8_t aflags;
19
+	/** ATA error/feature register */
20
+	uint8_t err_feat;
21
+	/** ATA sector count register */
22
+	uint8_t count;
23
+	/** ATA command/status register */
24
+	uint8_t cmd_stat;
25
+	/** Logical block address, in little-endian order */
26
+	union {
27
+		uint64_t u64;
28
+		uint8_t bytes[6];
29
+	} lba;
30
+	/** Data payload */
31
+	uint8_t data[0];
32
+} __attribute__ (( packed ));
33
+
34
+#define AOE_FL_EXTENDED	0x40	/**< LBA48 extended addressing */
35
+#define AOE_FL_DEV_HEAD	0x10	/**< Device/head flag */
36
+#define AOE_FL_ASYNC	0x02	/**< Asynchronous write */
37
+#define AOE_FL_WRITE	0x01	/**< Write command */
38
+
39
+/** An AoE header */
40
+struct aoehdr {
41
+	/** Protocol version number and flags */
42
+	uint8_t ver_flags;
43
+	/** Error code */
44
+	uint8_t error;
45
+	/** Major device number, in network byte order */
46
+	uint16_t major;
47
+	/** Minor device number */
48
+	uint8_t minor;
49
+	/** Command number */
50
+	uint8_t command;
51
+	/** Tag, in network byte order */
52
+	uint32_t tag;
53
+	/** Payload */
54
+	union {
55
+		/** ATA command */
56
+		struct aoecmd command[0];
57
+	} arg;
58
+} __attribute__ (( packed ));
59
+
60
+#define AOE_VERSION	0x10	/**< Version 1 */
61
+#define AOE_VERSION_MASK 0xf0	/**< Version part of ver_flags field */
62
+
63
+#define AOE_FL_RESPONSE	0x08	/**< Message is a response */
64
+#define AOE_FL_ERROR	0x04	/**< Command generated an error */
65
+
66
+#define AOE_MAJOR_BROADCAST 0xffff
67
+#define AOE_MINOR_BROADCAST 0xff
68
+
69
+#define AOE_CMD_ATA	0x00	/**< Issue ATA command */
70
+#define AOE_CMD_CONFIG	0x01	/**< Query Config Information */
71
+
72
+#define AOE_ERR_BAD_COMMAND	1 /**< Unrecognised command code */
73
+#define AOE_ERR_BAD_PARAMETER	2 /**< Bad argument parameter */
74
+#define AOE_ERR_UNAVAILABLE	3 /**< Device unavailable */
75
+#define AOE_ERR_CONFIG_EXISTS	4 /**< Config string present */
76
+#define AOE_ERR_BAD_VERSION	5 /**< Unsupported version */
77
+
78
+/** An AoE session */
79
+struct aoe_session {
80
+	/** List of all AoE sessions */
81
+	struct list_head list;
82
+
83
+	/** Network device */
84
+	struct net_device *netdev;
85
+	/** Major number */
86
+	uint16_t major;
87
+	/** Minor number */
88
+	uint8_t minor;
89
+	/** Target MAC address */
90
+	uint8_t target[ETH_ALEN];
91
+
92
+	/** Tag for current command */
93
+	uint32_t tag;
94
+	/** Current ATA command */
95
+	struct ata_command *command;
96
+	/** Status of the command */
97
+	int status;
98
+	/** Byte offset within command's data buffer */
99
+	unsigned int command_offset;
100
+};
101
+
102
+#define AOE_STATUS_ERR_MASK	0x0f /**< Error portion of status code */ 
103
+#define AOE_STATUS_PENDING	0x80 /**< Command pending */
104
+#define AOE_STATUS_UNDERRUN	0x40 /**< Buffer overrun */
105
+#define AOE_STATUS_OVERRUN	0x20 /**< Buffer underrun */
106
+
107
+/** Maximum number of sectors per packet */
108
+#define AOE_MAX_COUNT 2
109
+
110
+extern void aoe_open ( struct aoe_session *aoe );
111
+extern void aoe_close ( struct aoe_session *aoe );
112
+extern int aoe_issue ( struct aoe_session *aoe, struct ata_command *command );
113
+
114
+/** An AoE device */
115
+struct aoe_device {
116
+	/** ATA device interface */
117
+	struct ata_device ata;
118
+	/** AoE protocol instance */
119
+	struct aoe_session aoe;
120
+};
121
+
122
+extern int init_aoedev ( struct aoe_device *aoedev );
123
+
124
+#endif /* _GPXE_AOE_H */

+ 261
- 0
src/net/aoe.c View File

@@ -0,0 +1,261 @@
1
+/*
2
+ * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
+ */
18
+
19
+#include <stddef.h>
20
+#include <string.h>
21
+#include <vsprintf.h>
22
+#include <errno.h>
23
+#include <assert.h>
24
+#include <byteswap.h>
25
+#include <gpxe/list.h>
26
+#include <gpxe/if_ether.h>
27
+#include <gpxe/pkbuff.h>
28
+#include <gpxe/uaccess.h>
29
+#include <gpxe/ata.h>
30
+#include <gpxe/netdevice.h>
31
+#include <gpxe/process.h>
32
+#include <gpxe/aoe.h>
33
+
34
+/** @file
35
+ *
36
+ * AoE protocol
37
+ *
38
+ */
39
+
40
+struct net_protocol aoe_protocol;
41
+
42
+/** List of all AoE sessions */
43
+static LIST_HEAD ( aoe_sessions );
44
+
45
+/**
46
+ * Send AoE command
47
+ *
48
+ * @v aoe		AoE session
49
+ * @ret rc		Return status code
50
+ *
51
+ * This transmits an AoE command packet.  It does not wait for a
52
+ * response.
53
+ */
54
+static int aoe_send_command ( struct aoe_session *aoe ) {
55
+	struct ata_command *command = aoe->command;
56
+	struct pk_buff *pkb;
57
+	struct aoehdr *aoehdr;
58
+	struct aoecmd *aoecmd;
59
+
60
+	/* Create outgoing packet buffer */
61
+	pkb = alloc_pkb ( ETH_HLEN + sizeof ( *aoehdr ) + sizeof ( *aoecmd ) +
62
+			  command->data_out_len );
63
+	if ( ! pkb )
64
+		return -ENOMEM;
65
+	pkb->net_protocol = &aoe_protocol;
66
+	pkb_reserve ( pkb, ETH_HLEN );
67
+	aoehdr = pkb_put ( pkb, sizeof ( *aoehdr ) );
68
+	aoecmd = pkb_put ( pkb, sizeof ( *aoecmd ) );
69
+	memset ( aoehdr, 0, ( sizeof ( *aoehdr ) + sizeof ( *aoecmd ) ) );
70
+
71
+	/* Fill AoE header */
72
+	aoehdr->ver_flags = AOE_VERSION;
73
+	aoehdr->major = htons ( aoe->major );
74
+	aoehdr->minor = aoe->minor;
75
+	aoehdr->tag = htonl ( ++aoe->tag );
76
+
77
+	/* Fill AoE command */
78
+	linker_assert ( AOE_FL_DEV_HEAD	== ATA_DEV_SLAVE, __fix_ata_h__ );
79
+	aoecmd->aflags = ( ( command->cb.lba48 ? AOE_FL_EXTENDED : 0 ) |
80
+			   ( command->cb.device & ATA_DEV_SLAVE ) |
81
+			   ( command->data_out_len ? AOE_FL_WRITE : 0 ) );
82
+	aoecmd->err_feat = command->cb.err_feat.bytes.cur;
83
+	aoecmd->count = command->cb.count.bytes.cur;
84
+	aoecmd->cmd_stat = command->cb.cmd_stat;
85
+	aoecmd->lba.u64 = cpu_to_le64 ( command->cb.lba.native );
86
+	if ( ! command->cb.lba48 )
87
+		aoecmd->lba.bytes[3] |= command->cb.device;
88
+
89
+	/* Fill data payload */
90
+	copy_from_user ( pkb_put ( pkb, command->data_out_len ),
91
+			 command->data_out, aoe->command_offset,
92
+			 command->data_out_len );
93
+
94
+	/* Send packet */
95
+	return net_transmit_via ( pkb, aoe->netdev );
96
+}
97
+
98
+/**
99
+ * Handle AoE response
100
+ *
101
+ * @v aoe		AoE session
102
+ * @v aoehdr		AoE header
103
+ * @ret rc		Return status code
104
+ */
105
+static int aoe_rx_response ( struct aoe_session *aoe, struct aoehdr *aoehdr,
106
+			     unsigned int len ) {
107
+	struct aoecmd *aoecmd = aoehdr->arg.command;
108
+	struct ata_command *command = aoe->command;
109
+	unsigned int data_in_len;
110
+	
111
+	/* Sanity check */
112
+	if ( len < ( sizeof ( *aoehdr ) + sizeof ( *aoecmd ) ) )
113
+		return -EINVAL;
114
+
115
+	/* Set overall status code */
116
+	aoe->status = ( ( aoehdr->ver_flags & AOE_FL_ERROR ) ?
117
+			aoehdr->error : 0 );
118
+
119
+	/* Copy ATA results */
120
+	command->cb.err_feat.bytes.cur = aoecmd->err_feat;
121
+	command->cb.count.bytes.cur = aoecmd->count;
122
+	command->cb.cmd_stat = aoecmd->cmd_stat;
123
+	command->cb.lba.native = le64_to_cpu ( aoecmd->lba.u64 );
124
+	command->cb.lba.bytes.pad = 0;
125
+	
126
+	/* Copy data payload */
127
+	data_in_len = ( len - sizeof ( *aoehdr ) - sizeof ( *aoecmd ) );
128
+	if ( data_in_len > command->data_in_len ) {
129
+		data_in_len = command->data_in_len;
130
+		aoe->status |= AOE_STATUS_OVERRUN;
131
+	} else if ( data_in_len < command->data_in_len ) {
132
+		aoe->status |= AOE_STATUS_UNDERRUN;
133
+	}
134
+	copy_to_user ( command->data_in, aoe->command_offset,
135
+		       aoecmd->data, data_in_len );
136
+
137
+	return 0;
138
+}
139
+
140
+/**
141
+ * Process incoming AoE packets
142
+ *
143
+ * @v pkb		Packet buffer
144
+ * @ret rc		Return status code
145
+ *
146
+ */
147
+static int aoe_rx ( struct pk_buff *pkb ) {
148
+	struct aoehdr *aoehdr = pkb->data;
149
+	unsigned int len = pkb_len ( pkb );
150
+	struct aoe_session *aoe;
151
+	int rc = 0;
152
+
153
+	/* Sanity checks */
154
+	if ( len < sizeof ( *aoehdr ) ) {
155
+		rc = -EINVAL;
156
+		goto done;
157
+	}
158
+	if ( ( aoehdr->ver_flags & AOE_VERSION_MASK ) != AOE_VERSION ) {
159
+		rc = -EPROTONOSUPPORT;
160
+		goto done;
161
+	}
162
+	if ( ! ( aoehdr->ver_flags & AOE_FL_RESPONSE ) ) {
163
+		/* Ignore AoE requests that we happen to see */
164
+		goto done;
165
+	}
166
+
167
+	/* Demultiplex amongst active AoE sessions */
168
+	list_for_each_entry ( aoe, &aoe_sessions, list ) {
169
+		if ( ntohs ( aoehdr->major ) != aoe->major )
170
+			continue;
171
+		if ( aoehdr->minor != aoe->minor )
172
+			continue;
173
+		if ( ntohl ( aoehdr->tag ) != aoe->tag )
174
+			continue;
175
+
176
+#warning "Need a way to get the MAC address for future reference"
177
+
178
+		rc = aoe_rx_response ( aoe, aoehdr, len );
179
+		break;
180
+	}
181
+
182
+ done:
183
+	free_pkb ( pkb );
184
+	return rc;
185
+}
186
+
187
+/**
188
+ * Perform AoE network-layer routing
189
+ *
190
+ * @v pkb	Packet buffer
191
+ * @ret source	Network-layer source address
192
+ * @ret dest	Network-layer destination address
193
+ * @ret rc	Return status code
194
+ */
195
+static int aoe_route ( const struct pk_buff *pkb __unused,
196
+		       struct net_header *nethdr ) {
197
+
198
+#warning "Need a way to find out the MAC address"
199
+	nethdr->flags = PKT_FL_BROADCAST;
200
+	return 0;
201
+}
202
+
203
+/** AoE protocol */
204
+struct net_protocol aoe_protocol = {
205
+	.name = "AoE",
206
+	.net_proto = htons ( ETH_P_AOE ),
207
+	.rx_process = aoe_rx,
208
+	.route = aoe_route,
209
+};
210
+
211
+NET_PROTOCOL ( aoe_protocol );
212
+
213
+/**
214
+ * Open AoE session
215
+ *
216
+ * @v aoe		AoE session
217
+ */
218
+void aoe_open ( struct aoe_session *aoe ) {
219
+	list_add ( &aoe->list, &aoe_sessions );
220
+}
221
+
222
+/**
223
+ * Close AoE session
224
+ *
225
+ * @v aoe		AoE session
226
+ */
227
+void aoe_close ( struct aoe_session *aoe ) {
228
+	list_del ( &aoe->list );
229
+}
230
+
231
+/**
232
+ * Kick an AoE session into life
233
+ *
234
+ * @v aoe		AoE session
235
+ *
236
+ * Transmits an AoE request.  Call this function to issue a new
237
+ * command, or when a retransmission timer expires.
238
+ */
239
+void aoe_kick ( struct aoe_session *aoe ) {
240
+	aoe_send_command ( aoe );
241
+}
242
+
243
+/**
244
+ * Issue ATA command via an open AoE session
245
+ *
246
+ * @v aoe		AoE session
247
+ * @v command		AoE command
248
+ * @ret rc		Return status code
249
+ */
250
+int aoe_issue ( struct aoe_session *aoe, struct ata_command *command ) {
251
+	aoe->command = command;
252
+	aoe->status = AOE_STATUS_PENDING;
253
+
254
+	aoe_kick ( aoe );
255
+	while ( aoe->status & AOE_STATUS_PENDING ) {
256
+		step();
257
+	}
258
+	aoe->command = NULL;
259
+
260
+	return ( ( aoe->status & AOE_STATUS_ERR_MASK ) ? -EIO : 0 );
261
+}

Loading…
Cancel
Save