Procházet zdrojové kódy

[aoe] Use an AoE config query to identify the target MAC address

The AoE spec does not specify that the source MAC address of a
received packet actually matches the MAC address of the AoE target.
In principle an AoE server can respond to an AoE request on any
interface available to it, which may not be an address configured to
accept AoE requests.

This issue is resolved by implementing AoE device discovery.  The
purpose of AoE discovery is to find out which addresses an AoE target
can use for requests.  An AoE configuration command is sent when the
AoE attach is attempted.  The AoE target must respond to that
configuration query from an interface that can accept requests.

Based on a patch from Ryan Thomas <ryan@coraid.com>
tags/v0.9.6
Michael Brown před 15 roky
rodič
revize
246ddf5ee4
2 změnil soubory, kde provedl 173 přidání a 56 odebrání
  1. 28
    5
      src/include/gpxe/aoe.h
  2. 145
    51
      src/net/aoe.c

+ 28
- 5
src/include/gpxe/aoe.h Zobrazit soubor

@@ -13,8 +13,24 @@
13 13
 #include <gpxe/retry.h>
14 14
 #include <gpxe/ata.h>
15 15
 
16
+/** An AoE config command */
17
+struct aoecfg {
18
+	/** AoE Queue depth */
19
+	uint16_t bufcnt;
20
+	/** ATA target firmware version */
21
+	uint16_t fwver;
22
+	/** ATA target sector count */
23
+	uint8_t scnt;
24
+	/** AoE config string subcommand */
25
+	uint8_t aoeccmd;
26
+	/** AoE config string length */
27
+	uint16_t cfglen;
28
+	/** AoE config string */
29
+	uint8_t data[0];
30
+} __attribute__ (( packed ));
31
+
16 32
 /** An AoE ATA command */
17
-struct aoecmd {
33
+struct aoeata {
18 34
 	/** AoE command flags */
19 35
 	uint8_t aflags;
20 36
 	/** ATA error/feature register */
@@ -37,6 +53,14 @@ struct aoecmd {
37 53
 #define AOE_FL_ASYNC	0x02	/**< Asynchronous write */
38 54
 #define AOE_FL_WRITE	0x01	/**< Write command */
39 55
 
56
+/** An AoE command */
57
+union aoecmd {
58
+	/** Config command */
59
+	struct aoecfg cfg;
60
+	/** ATA command */
61
+	struct aoeata ata;
62
+};
63
+
40 64
 /** An AoE header */
41 65
 struct aoehdr {
42 66
 	/** Protocol version number and flags */
@@ -52,10 +76,7 @@ struct aoehdr {
52 76
 	/** Tag, in network byte order */
53 77
 	uint32_t tag;
54 78
 	/** Payload */
55
-	union {
56
-		/** ATA command */
57
-		struct aoecmd command[0];
58
-	} arg;
79
+	union aoecmd cmd[0];
59 80
 } __attribute__ (( packed ));
60 81
 
61 82
 #define AOE_VERSION	0x10	/**< Version 1 */
@@ -99,6 +120,8 @@ struct aoe_session {
99 120
 	/** Tag for current AoE command */
100 121
 	uint32_t tag;
101 122
 
123
+	/** Current AOE command */
124
+	uint8_t aoe_cmd_type;
102 125
 	/** Current ATA command */
103 126
 	struct ata_command *command;
104 127
 	/** Overall status of current ATA command */

+ 145
- 51
src/net/aoe.c Zobrazit soubor

@@ -64,8 +64,13 @@ static void aoe_free ( struct refcnt *refcnt ) {
64 64
 static void aoe_done ( struct aoe_session *aoe, int rc ) {
65 65
 
66 66
 	/* Record overall command status */
67
-	aoe->command->cb.cmd_stat = aoe->status;
68
-	aoe->command = NULL;
67
+	if ( aoe->command ) {
68
+		aoe->command->cb.cmd_stat = aoe->status;
69
+		aoe->command = NULL;
70
+	}
71
+
72
+	/* Stop retransmission timer */
73
+	stop_timer ( &aoe->timer );
69 74
 
70 75
 	/* Mark operation as complete */
71 76
 	aoe->rc = rc;
@@ -84,9 +89,11 @@ static int aoe_send_command ( struct aoe_session *aoe ) {
84 89
 	struct ata_command *command = aoe->command;
85 90
 	struct io_buffer *iobuf;
86 91
 	struct aoehdr *aoehdr;
87
-	struct aoecmd *aoecmd;
92
+	union aoecmd *aoecmd;
93
+	struct aoeata *aoeata;
88 94
 	unsigned int count;
89 95
 	unsigned int data_out_len;
96
+	unsigned int aoecmdlen;
90 97
 
91 98
 	/* Fail immediately if we have no netdev to send on */
92 99
 	if ( ! aoe->netdev ) {
@@ -102,42 +109,71 @@ static int aoe_send_command ( struct aoe_session *aoe ) {
102 109
 	start_timer ( &aoe->timer );
103 110
 
104 111
 	/* Calculate count and data_out_len for this subcommand */
105
-	count = command->cb.count.native;
106
-	if ( count > AOE_MAX_COUNT )
107
-		count = AOE_MAX_COUNT;
108
-	data_out_len = ( command->data_out ? ( count * ATA_SECTOR_SIZE ) : 0 );
112
+	switch ( aoe->aoe_cmd_type ) {
113
+	case AOE_CMD_ATA:
114
+		count = command->cb.count.native;
115
+		if ( count > AOE_MAX_COUNT )
116
+			count = AOE_MAX_COUNT;
117
+		data_out_len = ( command->data_out ?
118
+				 ( count * ATA_SECTOR_SIZE ) : 0 );
119
+		aoecmdlen = sizeof ( aoecmd->ata );
120
+		break;
121
+	case AOE_CMD_CONFIG:
122
+		count = 0;
123
+		data_out_len = 0;
124
+		aoecmdlen = sizeof ( aoecmd->cfg );
125
+		break;
126
+	default:
127
+		return -ENOTSUP;
128
+	}
109 129
 
110 130
 	/* Create outgoing I/O buffer */
111 131
 	iobuf = alloc_iob ( ETH_HLEN + sizeof ( *aoehdr ) +
112
-			    sizeof ( *aoecmd ) + data_out_len );
132
+			    aoecmdlen + data_out_len );
133
+
113 134
 	if ( ! iobuf )
114 135
 		return -ENOMEM;
115 136
 	iob_reserve ( iobuf, ETH_HLEN );
116 137
 	aoehdr = iob_put ( iobuf, sizeof ( *aoehdr ) );
117
-	aoecmd = iob_put ( iobuf, sizeof ( *aoecmd ) );
118
-	memset ( aoehdr, 0, ( sizeof ( *aoehdr ) + sizeof ( *aoecmd ) ) );
138
+	aoecmd = iob_put ( iobuf, aoecmdlen );
139
+	memset ( aoehdr, 0, ( sizeof ( *aoehdr ) + aoecmdlen ) );
119 140
 
120 141
 	/* Fill AoE header */
121 142
 	aoehdr->ver_flags = AOE_VERSION;
122 143
 	aoehdr->major = htons ( aoe->major );
123 144
 	aoehdr->minor = aoe->minor;
145
+	aoehdr->command = aoe->aoe_cmd_type;
124 146
 	aoehdr->tag = htonl ( ++aoe->tag );
125 147
 
126
-	/* Fill AoE command */
127
-	linker_assert ( AOE_FL_DEV_HEAD	== ATA_DEV_SLAVE, __fix_ata_h__ );
128
-	aoecmd->aflags = ( ( command->cb.lba48 ? AOE_FL_EXTENDED : 0 ) |
129
-			   ( command->cb.device & ATA_DEV_SLAVE ) |
130
-			   ( data_out_len ? AOE_FL_WRITE : 0 ) );
131
-	aoecmd->err_feat = command->cb.err_feat.bytes.cur;
132
-	aoecmd->count = count;
133
-	aoecmd->cmd_stat = command->cb.cmd_stat;
134
-	aoecmd->lba.u64 = cpu_to_le64 ( command->cb.lba.native );
135
-	if ( ! command->cb.lba48 )
136
-		aoecmd->lba.bytes[3] |= ( command->cb.device & ATA_DEV_MASK );
137
-
138
-	/* Fill data payload */
139
-	copy_from_user ( iob_put ( iobuf, data_out_len ), command->data_out,
140
-			 aoe->command_offset, data_out_len );
148
+	/* Fill AoE payload */
149
+	switch ( aoe->aoe_cmd_type ) {
150
+	case AOE_CMD_ATA:
151
+		/* Fill AoE command */
152
+		aoeata = &aoecmd->ata;
153
+		linker_assert ( AOE_FL_DEV_HEAD	== ATA_DEV_SLAVE,
154
+				__fix_ata_h__ );
155
+		aoeata->aflags = ( ( command->cb.lba48 ? AOE_FL_EXTENDED : 0 )|
156
+				   ( command->cb.device & ATA_DEV_SLAVE ) |
157
+				   ( data_out_len ? AOE_FL_WRITE : 0 ) );
158
+		aoeata->err_feat = command->cb.err_feat.bytes.cur;
159
+		aoeata->count = count;
160
+		aoeata->cmd_stat = command->cb.cmd_stat;
161
+		aoeata->lba.u64 = cpu_to_le64 ( command->cb.lba.native );
162
+		if ( ! command->cb.lba48 )
163
+			aoeata->lba.bytes[3] |=
164
+				( command->cb.device & ATA_DEV_MASK );
165
+
166
+		/* Fill data payload */
167
+		copy_from_user ( iob_put ( iobuf, data_out_len ),
168
+				 command->data_out, aoe->command_offset,
169
+				 data_out_len );
170
+		break;
171
+	case AOE_CMD_CONFIG:
172
+		/* Nothing to do */
173
+		break;
174
+	default:
175
+		assert ( 0 );
176
+	}
141 177
 
142 178
 	/* Send packet */
143 179
 	return net_tx ( iobuf, aoe->netdev, &aoe_protocol, aoe->target );
@@ -161,38 +197,46 @@ static void aoe_timer_expired ( struct retry_timer *timer, int fail ) {
161 197
 }
162 198
 
163 199
 /**
164
- * Handle AoE response
200
+ * Handle AoE configuration command response
201
+ *
202
+ * @v aoe		AoE session
203
+ * @v ll_source		Link-layer source address
204
+ * @ret rc		Return status code
205
+ */
206
+static int aoe_rx_cfg ( struct aoe_session *aoe, const void *ll_source ) {
207
+
208
+	/* Record target MAC address */
209
+	memcpy ( aoe->target, ll_source, sizeof ( aoe->target ) );
210
+	DBGC ( aoe, "AoE %p target MAC address %s\n",
211
+	       aoe, eth_ntoa ( aoe->target ) );
212
+
213
+	/* Mark config request as complete */
214
+	aoe_done ( aoe, 0 );
215
+
216
+	return 0;
217
+}
218
+
219
+/**
220
+ * Handle AoE ATA command response
165 221
  *
166 222
  * @v aoe		AoE session
167
- * @v aoehdr		AoE header
223
+ * @v aoeata		AoE ATA command
224
+ * @v len		Length of AoE ATA command
168 225
  * @ret rc		Return status code
169 226
  */
170
-static int aoe_rx_response ( struct aoe_session *aoe, struct aoehdr *aoehdr,
171
-			     unsigned int len ) {
172
-	struct aoecmd *aoecmd = aoehdr->arg.command;
227
+static int aoe_rx_ata ( struct aoe_session *aoe, struct aoeata *aoeata,
228
+			size_t len ) {
173 229
 	struct ata_command *command = aoe->command;
174 230
 	unsigned int rx_data_len;
175 231
 	unsigned int count;
176 232
 	unsigned int data_len;
177
-	
233
+
178 234
 	/* Sanity check */
179
-	if ( len < ( sizeof ( *aoehdr ) + sizeof ( *aoecmd ) ) ) {
235
+	if ( len < sizeof ( *aoeata ) ) {
180 236
 		/* Ignore packet; allow timer to trigger retransmit */
181 237
 		return -EINVAL;
182 238
 	}
183
-	rx_data_len = ( len - sizeof ( *aoehdr ) - sizeof ( *aoecmd ) );
184
-
185
-	/* Stop retry timer.  After this point, every code path must
186
-	 * either terminate the AoE operation via aoe_done(), or
187
-	 * transmit a new packet.
188
-	 */
189
-	stop_timer ( &aoe->timer );
190
-
191
-	/* Check for fatal errors */
192
-	if ( aoehdr->ver_flags & AOE_FL_ERROR ) {
193
-		aoe_done ( aoe, -EIO );
194
-		return 0;
195
-	}
239
+	rx_data_len = ( len - sizeof ( *aoeata ) );
196 240
 
197 241
 	/* Calculate count and data_len for this subcommand */
198 242
 	count = command->cb.count.native;
@@ -201,14 +245,14 @@ static int aoe_rx_response ( struct aoe_session *aoe, struct aoehdr *aoehdr,
201 245
 	data_len = count * ATA_SECTOR_SIZE;
202 246
 
203 247
 	/* Merge into overall ATA status */
204
-	aoe->status |= aoecmd->cmd_stat;
248
+	aoe->status |= aoeata->cmd_stat;
205 249
 
206 250
 	/* Copy data payload */
207 251
 	if ( command->data_in ) {
208 252
 		if ( rx_data_len > data_len )
209 253
 			rx_data_len = data_len;
210 254
 		copy_to_user ( command->data_in, aoe->command_offset,
211
-			       aoecmd->data, rx_data_len );
255
+			       aoeata->data, rx_data_len );
212 256
 	}
213 257
 
214 258
 	/* Update ATA command and offset */
@@ -223,6 +267,7 @@ static int aoe_rx_response ( struct aoe_session *aoe, struct aoehdr *aoehdr,
223 267
 	}
224 268
 
225 269
 	/* Transmit next portion of request */
270
+	stop_timer ( &aoe->timer );
226 271
 	aoe_send_command ( aoe );
227 272
 
228 273
 	return 0;
@@ -241,12 +286,11 @@ static int aoe_rx ( struct io_buffer *iobuf,
241 286
 		    struct net_device *netdev __unused,
242 287
 		    const void *ll_source ) {
243 288
 	struct aoehdr *aoehdr = iobuf->data;
244
-	unsigned int len = iob_len ( iobuf );
245 289
 	struct aoe_session *aoe;
246 290
 	int rc = 0;
247 291
 
248 292
 	/* Sanity checks */
249
-	if ( len < sizeof ( *aoehdr ) ) {
293
+	if ( iob_len ( iobuf ) < sizeof ( *aoehdr ) ) {
250 294
 		rc = -EINVAL;
251 295
 		goto done;
252 296
 	}
@@ -258,6 +302,7 @@ static int aoe_rx ( struct io_buffer *iobuf,
258 302
 		/* Ignore AoE requests that we happen to see */
259 303
 		goto done;
260 304
 	}
305
+	iob_pull ( iobuf, sizeof ( *aoehdr ) );
261 306
 
262 307
 	/* Demultiplex amongst active AoE sessions */
263 308
 	list_for_each_entry ( aoe, &aoe_sessions, list ) {
@@ -267,8 +312,22 @@ static int aoe_rx ( struct io_buffer *iobuf,
267 312
 			continue;
268 313
 		if ( ntohl ( aoehdr->tag ) != aoe->tag )
269 314
 			continue;
270
-		memcpy ( aoe->target, ll_source, sizeof ( aoe->target ) );
271
-		rc = aoe_rx_response ( aoe, aoehdr, len );
315
+		if ( aoehdr->ver_flags & AOE_FL_ERROR ) {
316
+			aoe_done ( aoe, -EIO );
317
+			break;
318
+		}
319
+		switch ( aoehdr->command ) {
320
+		case AOE_CMD_ATA:
321
+			rc = aoe_rx_ata ( aoe, iobuf->data, iob_len ( iobuf ));
322
+			break;
323
+		case AOE_CMD_CONFIG:
324
+			rc = aoe_rx_cfg ( aoe, ll_source );
325
+			break;
326
+		default:
327
+			DBGC ( aoe, "AoE %p ignoring command %02x\n",
328
+			       aoe, aoehdr->command );
329
+			break;
330
+		}
272 331
 		break;
273 332
 	}
274 333
 
@@ -300,6 +359,32 @@ static int aoe_command ( struct ata_device *ata,
300 359
 	aoe->command = command;
301 360
 	aoe->status = 0;
302 361
 	aoe->command_offset = 0;
362
+	aoe->aoe_cmd_type = AOE_CMD_ATA;
363
+
364
+	aoe_send_command ( aoe );
365
+
366
+	aoe->rc = -EINPROGRESS;
367
+	while ( aoe->rc == -EINPROGRESS )
368
+		step();
369
+	rc = aoe->rc;
370
+
371
+	return rc;
372
+}
373
+
374
+
375
+/**
376
+ * Issue AoE config query for AoE target discovery
377
+ *
378
+ * @v aoe		AoE session
379
+ * @ret rc		Return status code
380
+ */
381
+static int aoe_discover ( struct aoe_session *aoe ) {
382
+	int rc;
383
+
384
+	aoe->status = 0;
385
+	aoe->aoe_cmd_type = AOE_CMD_CONFIG;
386
+	aoe->command = NULL;
387
+
303 388
 	aoe_send_command ( aoe );
304 389
 
305 390
 	aoe->rc = -EINPROGRESS;
@@ -374,6 +459,15 @@ int aoe_attach ( struct ata_device *ata, struct net_device *netdev,
374 459
 	ata->backend = ref_get ( &aoe->refcnt );
375 460
 	ata->command = aoe_command;
376 461
 	list_add ( &aoe->list, &aoe_sessions );
462
+
463
+	/* Send discovery packet to find the target MAC address.
464
+	 * Ideally, this ought to be done asynchronously, but the
465
+	 * block device interface does not yet support asynchronous
466
+	 * operation.
467
+	 */
468
+	if ( ( rc = aoe_discover( aoe ) ) != 0 )
469
+	       goto err;
470
+
377 471
 	return 0;
378 472
 
379 473
  err:

Načítá se…
Zrušit
Uložit