|
@@ -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:
|