|
@@ -28,7 +28,7 @@
|
28
|
28
|
#include <gpxe/uaccess.h>
|
29
|
29
|
#include <gpxe/ata.h>
|
30
|
30
|
#include <gpxe/netdevice.h>
|
31
|
|
-#include <gpxe/process.h>
|
|
31
|
+#include <gpxe/async.h>
|
32
|
32
|
#include <gpxe/aoe.h>
|
33
|
33
|
|
34
|
34
|
/** @file
|
|
@@ -42,6 +42,22 @@ struct net_protocol aoe_protocol;
|
42
|
42
|
/** List of all AoE sessions */
|
43
|
43
|
static LIST_HEAD ( aoe_sessions );
|
44
|
44
|
|
|
45
|
+/**
|
|
46
|
+ * Mark current AoE command complete
|
|
47
|
+ *
|
|
48
|
+ * @v aoe AoE session
|
|
49
|
+ * @v rc Return status code
|
|
50
|
+ */
|
|
51
|
+static void aoe_done ( struct aoe_session *aoe, int rc ) {
|
|
52
|
+
|
|
53
|
+ /* Record overall command status */
|
|
54
|
+ aoe->command->cb.cmd_stat = aoe->status;
|
|
55
|
+ aoe->command = NULL;
|
|
56
|
+
|
|
57
|
+ /* Mark async operation as complete */
|
|
58
|
+ async_done ( &aoe->aop, rc );
|
|
59
|
+}
|
|
60
|
+
|
45
|
61
|
/**
|
46
|
62
|
* Send AoE command
|
47
|
63
|
*
|
|
@@ -56,10 +72,18 @@ static int aoe_send_command ( struct aoe_session *aoe ) {
|
56
|
72
|
struct pk_buff *pkb;
|
57
|
73
|
struct aoehdr *aoehdr;
|
58
|
74
|
struct aoecmd *aoecmd;
|
|
75
|
+ unsigned int count;
|
|
76
|
+ unsigned int data_out_len;
|
|
77
|
+
|
|
78
|
+ /* Calculate count and data_out_len for this subcommand */
|
|
79
|
+ count = command->cb.count.native;
|
|
80
|
+ if ( count > AOE_MAX_COUNT )
|
|
81
|
+ count = AOE_MAX_COUNT;
|
|
82
|
+ data_out_len = ( command->data_out ? ( count * ATA_SECTOR_SIZE ) : 0 );
|
59
|
83
|
|
60
|
84
|
/* Create outgoing packet buffer */
|
61
|
85
|
pkb = alloc_pkb ( ETH_HLEN + sizeof ( *aoehdr ) + sizeof ( *aoecmd ) +
|
62
|
|
- command->data_out_len );
|
|
86
|
+ data_out_len );
|
63
|
87
|
if ( ! pkb )
|
64
|
88
|
return -ENOMEM;
|
65
|
89
|
pkb->net_protocol = &aoe_protocol;
|
|
@@ -78,18 +102,17 @@ static int aoe_send_command ( struct aoe_session *aoe ) {
|
78
|
102
|
linker_assert ( AOE_FL_DEV_HEAD == ATA_DEV_SLAVE, __fix_ata_h__ );
|
79
|
103
|
aoecmd->aflags = ( ( command->cb.lba48 ? AOE_FL_EXTENDED : 0 ) |
|
80
|
104
|
( command->cb.device & ATA_DEV_SLAVE ) |
|
81
|
|
- ( command->data_out_len ? AOE_FL_WRITE : 0 ) );
|
|
105
|
+ ( data_out_len ? AOE_FL_WRITE : 0 ) );
|
82
|
106
|
aoecmd->err_feat = command->cb.err_feat.bytes.cur;
|
83
|
|
- aoecmd->count = command->cb.count.bytes.cur;
|
|
107
|
+ aoecmd->count = count;
|
84
|
108
|
aoecmd->cmd_stat = command->cb.cmd_stat;
|
85
|
109
|
aoecmd->lba.u64 = cpu_to_le64 ( command->cb.lba.native );
|
86
|
110
|
if ( ! command->cb.lba48 )
|
87
|
111
|
aoecmd->lba.bytes[3] |= ( command->cb.device & ATA_DEV_MASK );
|
88
|
112
|
|
89
|
113
|
/* 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 );
|
|
114
|
+ copy_from_user ( pkb_put ( pkb, data_out_len ), command->data_out,
|
|
115
|
+ aoe->command_offset, data_out_len );
|
93
|
116
|
|
94
|
117
|
/* Send packet */
|
95
|
118
|
return net_transmit_via ( pkb, aoe->netdev );
|
|
@@ -106,33 +129,51 @@ static int aoe_rx_response ( struct aoe_session *aoe, struct aoehdr *aoehdr,
|
106
|
129
|
unsigned int len ) {
|
107
|
130
|
struct aoecmd *aoecmd = aoehdr->arg.command;
|
108
|
131
|
struct ata_command *command = aoe->command;
|
109
|
|
- unsigned int data_in_len;
|
|
132
|
+ unsigned int rx_data_len;
|
|
133
|
+ unsigned int count;
|
|
134
|
+ unsigned int data_len;
|
110
|
135
|
|
111
|
136
|
/* Sanity check */
|
112
|
137
|
if ( len < ( sizeof ( *aoehdr ) + sizeof ( *aoecmd ) ) )
|
113
|
138
|
return -EINVAL;
|
|
139
|
+ rx_data_len = ( len - sizeof ( *aoehdr ) - sizeof ( *aoecmd ) );
|
114
|
140
|
|
115
|
|
- /* Set overall status code */
|
116
|
|
- aoe->status = ( ( aoehdr->ver_flags & AOE_FL_ERROR ) ?
|
117
|
|
- aoehdr->error : 0 );
|
|
141
|
+ /* Check for fatal errors */
|
|
142
|
+ if ( aoehdr->ver_flags & AOE_FL_ERROR ) {
|
|
143
|
+ aoe_done ( aoe, -EIO );
|
|
144
|
+ return 0;
|
|
145
|
+ }
|
|
146
|
+
|
|
147
|
+ /* Calculate count and data_len for this subcommand */
|
|
148
|
+ count = command->cb.count.native;
|
|
149
|
+ if ( count > AOE_MAX_COUNT )
|
|
150
|
+ count = AOE_MAX_COUNT;
|
|
151
|
+ data_len = count * ATA_SECTOR_SIZE;
|
|
152
|
+
|
|
153
|
+ /* Merge into overall ATA status */
|
|
154
|
+ aoe->status |= aoecmd->cmd_stat;
|
118
|
155
|
|
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
|
156
|
/* 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;
|
|
157
|
+ if ( command->data_in ) {
|
|
158
|
+ if ( rx_data_len > data_len )
|
|
159
|
+ rx_data_len = data_len;
|
|
160
|
+ copy_to_user ( command->data_in, aoe->command_offset,
|
|
161
|
+ aoecmd->data, rx_data_len );
|
133
|
162
|
}
|
134
|
|
- copy_to_user ( command->data_in, aoe->command_offset,
|
135
|
|
- aoecmd->data, data_in_len );
|
|
163
|
+
|
|
164
|
+ /* Update ATA command and offset */
|
|
165
|
+ aoe->command_offset += data_len;
|
|
166
|
+ command->cb.lba.native += count;
|
|
167
|
+ command->cb.count.native -= count;
|
|
168
|
+
|
|
169
|
+ /* Check for operation complete */
|
|
170
|
+ if ( ! command->cb.count.native ) {
|
|
171
|
+ aoe_done ( aoe, 0 );
|
|
172
|
+ return 0;
|
|
173
|
+ }
|
|
174
|
+
|
|
175
|
+ /* Transmit next portion of request */
|
|
176
|
+ aoe_send_command ( aoe );
|
136
|
177
|
|
137
|
178
|
return 0;
|
138
|
179
|
}
|
|
@@ -228,80 +269,19 @@ void aoe_close ( struct aoe_session *aoe ) {
|
228
|
269
|
list_del ( &aoe->list );
|
229
|
270
|
}
|
230
|
271
|
|
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
|
272
|
/**
|
244
|
273
|
* Issue ATA command via an open AoE session
|
245
|
274
|
*
|
246
|
275
|
* @v aoe AoE session
|
247
|
276
|
* @v command ATA command
|
248
|
|
- * @ret rc Return status code
|
249
|
277
|
*
|
250
|
|
- * The ATA command must fit within a single AoE frame (i.e. the sector
|
251
|
|
- * count must not exceed AOE_MAX_COUNT).
|
|
278
|
+ * Only one command may be issued concurrently per session. This call
|
|
279
|
+ * is non-blocking; use async_wait() to wait for the command to
|
|
280
|
+ * complete.
|
252
|
281
|
*/
|
253
|
|
-int aoe_issue ( struct aoe_session *aoe, struct ata_command *command ) {
|
|
282
|
+void aoe_issue ( struct aoe_session *aoe, struct ata_command *command ) {
|
254
|
283
|
aoe->command = command;
|
255
|
|
- aoe->status = AOE_STATUS_PENDING;
|
256
|
|
-
|
257
|
|
- aoe_kick ( aoe );
|
258
|
|
- while ( aoe->status & AOE_STATUS_PENDING ) {
|
259
|
|
- step();
|
260
|
|
- }
|
261
|
|
- aoe->command = NULL;
|
262
|
|
-
|
263
|
|
- return ( ( aoe->status & AOE_STATUS_ERR_MASK ) ? -EIO : 0 );
|
264
|
|
-}
|
265
|
|
-
|
266
|
|
-/**
|
267
|
|
- * Issue ATA command via an open AoE session
|
268
|
|
- *
|
269
|
|
- * @v aoe AoE session
|
270
|
|
- * @v command ATA command
|
271
|
|
- * @ret rc Return status code
|
272
|
|
- *
|
273
|
|
- * The ATA command will be split into several smaller ATA commands,
|
274
|
|
- * each with a sector count no larger than AOE_MAX_COUNT.
|
275
|
|
- */
|
276
|
|
-int aoe_issue_split ( struct aoe_session *aoe, struct ata_command *command ) {
|
277
|
|
- struct ata_command subcommand;
|
278
|
|
- unsigned int offset;
|
279
|
|
- unsigned int count;
|
280
|
|
- unsigned int data_len;
|
281
|
|
- unsigned int status = 0;
|
282
|
|
- int rc = 0;
|
283
|
|
-
|
284
|
|
- /* Split ATA command into AoE-sized subcommands */
|
285
|
|
- for ( offset = 0; offset < command->cb.count.native; offset += count ){
|
286
|
|
- memcpy ( &subcommand, command, sizeof ( subcommand ) );
|
287
|
|
- count = ( command->cb.count.native - offset );
|
288
|
|
- if ( count > AOE_MAX_COUNT )
|
289
|
|
- count = AOE_MAX_COUNT;
|
290
|
|
- data_len = count * ATA_SECTOR_SIZE;
|
291
|
|
- if ( subcommand.data_in_len )
|
292
|
|
- subcommand.data_in_len = data_len;
|
293
|
|
- if ( subcommand.data_out_len )
|
294
|
|
- subcommand.data_out_len = data_len;
|
295
|
|
- aoe->command_offset = ( offset * ATA_SECTOR_SIZE );
|
296
|
|
- subcommand.cb.lba.native += offset;
|
297
|
|
- subcommand.cb.count.native = count;
|
298
|
|
- if ( ( rc = aoe_issue ( aoe, &subcommand ) ) != 0 )
|
299
|
|
- goto done;
|
300
|
|
- status |= subcommand.cb.cmd_stat;
|
301
|
|
- }
|
302
|
|
- command->cb.cmd_stat = status;
|
303
|
|
-
|
304
|
|
- done:
|
|
284
|
+ aoe->status = 0;
|
305
|
285
|
aoe->command_offset = 0;
|
306
|
|
- return rc;
|
|
286
|
+ aoe_send_command ( aoe );
|
307
|
287
|
}
|