Browse Source

Added generic asynchronous operations code.

Removed data_in_len and data_out_len from ata_command structure; the
lengths are implied by the sector count and the presence of the data_in
or data_out pointers.

Changed AoE code to use subcommands by default, and made aoe_issue()
nonblocking (with completion via async_wait()).
tags/v0.9.3
Michael Brown 18 years ago
parent
commit
68125bc441
6 changed files with 161 additions and 117 deletions
  1. 2
    1
      src/drivers/ata/aoedev.c
  2. 4
    5
      src/drivers/block/ata.c
  3. 12
    8
      src/include/gpxe/aoe.h
  4. 62
    0
      src/include/gpxe/async.h
  5. 8
    10
      src/include/gpxe/ata.h
  6. 73
    93
      src/net/aoe.c

+ 2
- 1
src/drivers/ata/aoedev.c View File

37
 	struct aoe_device *aoedev
37
 	struct aoe_device *aoedev
38
 		= container_of ( ata, struct aoe_device, ata );
38
 		= container_of ( ata, struct aoe_device, ata );
39
 
39
 
40
-	return aoe_issue_split ( &aoedev->aoe, command );
40
+	aoe_issue ( &aoedev->aoe, command );
41
+	return async_wait ( &aoedev->aoe.aop );
41
 }
42
 }
42
 
43
 
43
 /**
44
 /**

+ 4
- 5
src/drivers/block/ata.c View File

18
 
18
 
19
 #include <stddef.h>
19
 #include <stddef.h>
20
 #include <string.h>
20
 #include <string.h>
21
+#include <assert.h>
21
 #include <byteswap.h>
22
 #include <byteswap.h>
22
 #include <gpxe/blockdev.h>
23
 #include <gpxe/blockdev.h>
23
 #include <gpxe/ata.h>
24
 #include <gpxe/ata.h>
73
 		command.cb.device |= command.cb.lba.bytes.low_prev;
74
 		command.cb.device |= command.cb.lba.bytes.low_prev;
74
 	command.cb.cmd_stat = ( ata->lba48 ? ATA_CMD_READ_EXT : ATA_CMD_READ );
75
 	command.cb.cmd_stat = ( ata->lba48 ? ATA_CMD_READ_EXT : ATA_CMD_READ );
75
 	command.data_in = buffer;
76
 	command.data_in = buffer;
76
-	command.data_in_len = ( count * blockdev->blksize );
77
 	return ata_command ( ata, &command );
77
 	return ata_command ( ata, &command );
78
 }
78
 }
79
 
79
 
101
 	command.cb.cmd_stat = ( ata->lba48 ?
101
 	command.cb.cmd_stat = ( ata->lba48 ?
102
 				ATA_CMD_WRITE_EXT : ATA_CMD_WRITE );
102
 				ATA_CMD_WRITE_EXT : ATA_CMD_WRITE );
103
 	command.data_out = buffer;
103
 	command.data_out = buffer;
104
-	command.data_out_len = ( count * blockdev->blksize );
105
 	return ata_command ( ata, &command );
104
 	return ata_command ( ata, &command );
106
 }
105
 }
107
 
106
 
119
 
118
 
120
 	/* Issue IDENTIFY */
119
 	/* Issue IDENTIFY */
121
 	memset ( &command, 0, sizeof ( command ) );
120
 	memset ( &command, 0, sizeof ( command ) );
122
-	command.cb.count.native = 1; /* n/a according to spec, but at least
123
-				      * AoE vblade devices require it. */
121
+	command.cb.count.native = 1;
124
 	command.cb.device = ( ata->device | ATA_DEV_OBSOLETE | ATA_DEV_LBA );
122
 	command.cb.device = ( ata->device | ATA_DEV_OBSOLETE | ATA_DEV_LBA );
125
 	command.cb.cmd_stat = ATA_CMD_IDENTIFY;
123
 	command.cb.cmd_stat = ATA_CMD_IDENTIFY;
126
 	command.data_in = virt_to_user ( &identity );
124
 	command.data_in = virt_to_user ( &identity );
127
-	command.data_in_len = sizeof ( identity );
125
+	linker_assert ( sizeof ( identity ) == ATA_SECTOR_SIZE,
126
+			__ata_identity_bad_size__ );
128
 	if ( ( rc = ata_command ( ata, &command ) ) != 0 )
127
 	if ( ( rc = ata_command ( ata, &command ) ) != 0 )
129
 		return rc;
128
 		return rc;
130
 
129
 

+ 12
- 8
src/include/gpxe/aoe.h View File

10
 #include <stdint.h>
10
 #include <stdint.h>
11
 #include <gpxe/list.h>
11
 #include <gpxe/list.h>
12
 #include <gpxe/if_ether.h>
12
 #include <gpxe/if_ether.h>
13
+#include <gpxe/retry.h>
14
+#include <gpxe/async.h>
13
 #include <gpxe/ata.h>
15
 #include <gpxe/ata.h>
14
 
16
 
15
 /** An AoE ATA command */
17
 /** An AoE ATA command */
89
 	/** Target MAC address */
91
 	/** Target MAC address */
90
 	uint8_t target[ETH_ALEN];
92
 	uint8_t target[ETH_ALEN];
91
 
93
 
92
-	/** Tag for current command */
94
+	/** Tag for current AoE command */
93
 	uint32_t tag;
95
 	uint32_t tag;
96
+
94
 	/** Current ATA command */
97
 	/** Current ATA command */
95
 	struct ata_command *command;
98
 	struct ata_command *command;
96
-	/** Status of the command */
97
-	int status;
99
+	/** Overall status of current ATA command */
100
+	unsigned int status;
98
 	/** Byte offset within command's data buffer */
101
 	/** Byte offset within command's data buffer */
99
 	unsigned int command_offset;
102
 	unsigned int command_offset;
103
+	/** Asynchronous operation for this command */
104
+	struct async_operation aop;
105
+
106
+	/** Retransmission timer */
107
+	struct retry_timer timer;
100
 };
108
 };
101
 
109
 
102
 #define AOE_STATUS_ERR_MASK	0x0f /**< Error portion of status code */ 
110
 #define AOE_STATUS_ERR_MASK	0x0f /**< Error portion of status code */ 
103
 #define AOE_STATUS_PENDING	0x80 /**< Command pending */
111
 #define AOE_STATUS_PENDING	0x80 /**< Command pending */
104
-#define AOE_STATUS_UNDERRUN	0x40 /**< Buffer overrun */
105
-#define AOE_STATUS_OVERRUN	0x20 /**< Buffer underrun */
106
 
112
 
107
 /** Maximum number of sectors per packet */
113
 /** Maximum number of sectors per packet */
108
 #define AOE_MAX_COUNT 2
114
 #define AOE_MAX_COUNT 2
109
 
115
 
110
 extern void aoe_open ( struct aoe_session *aoe );
116
 extern void aoe_open ( struct aoe_session *aoe );
111
 extern void aoe_close ( struct aoe_session *aoe );
117
 extern void aoe_close ( struct aoe_session *aoe );
112
-extern int aoe_issue ( struct aoe_session *aoe, struct ata_command *command );
113
-extern int aoe_issue_split ( struct aoe_session *aoe,
114
-			     struct ata_command *command );
118
+extern void aoe_issue ( struct aoe_session *aoe, struct ata_command *command );
115
 
119
 
116
 /** An AoE device */
120
 /** An AoE device */
117
 struct aoe_device {
121
 struct aoe_device {

+ 62
- 0
src/include/gpxe/async.h View File

1
+#ifndef _GPXE_ASYNC_H
2
+#define _GPXE_ASYNC_H
3
+
4
+/** @file
5
+ *
6
+ * Asynchronous operations
7
+ *
8
+ */
9
+
10
+#include <errno.h>
11
+#include <assert.h>
12
+
13
+/** An asynchronous operation */
14
+struct async_operation {
15
+	/** Operation status
16
+	 *
17
+	 * This is an error code as defined in errno.h, plus an offset
18
+	 * of EINPROGRESS.  This means that a status value of 0
19
+	 * corresponds to a return status code of -EINPROGRESS,
20
+	 * i.e. that the default state of an asynchronous operation is
21
+	 * "not yet completed".
22
+	 */
23
+	int status;
24
+};
25
+
26
+/**
27
+ * Set asynchronous operation status
28
+ *
29
+ * @v aop	Asynchronous operation
30
+ * @v rc	Return status code
31
+ */
32
+static inline __attribute__ (( always_inline )) void
33
+async_set_status ( struct async_operation *aop, int rc ) {
34
+	aop->status = ( rc + EINPROGRESS );
35
+}
36
+
37
+/**
38
+ * Get asynchronous operation status
39
+ *
40
+ * @v aop	Asynchronous operation
41
+ * @ret rc	Return status code
42
+ */
43
+static inline __attribute__ (( always_inline )) int
44
+async_status ( struct async_operation *aop ) {
45
+	return ( aop->status - EINPROGRESS );
46
+}
47
+
48
+/**
49
+ * Flag asynchronous operation as complete
50
+ *
51
+ * @v aop	Asynchronous operation
52
+ * @v rc	Return status code
53
+ */
54
+static inline __attribute__ (( always_inline )) void
55
+async_done ( struct async_operation *aop, int rc ) {
56
+	assert ( rc != -EINPROGRESS );
57
+	async_set_status ( aop, rc );
58
+}
59
+
60
+extern int async_wait ( struct async_operation *aop );
61
+
62
+#endif /* _GPXE_ASYNC_H */

+ 8
- 10
src/include/gpxe/ata.h View File

139
 struct ata_command {
139
 struct ata_command {
140
 	/** ATA command block */
140
 	/** ATA command block */
141
 	struct ata_cb cb;
141
 	struct ata_cb cb;
142
-	/** Data-out buffer (may be NULL) */
143
-	userptr_t data_out;
144
-	/** Data-out buffer length
142
+	/** Data-out buffer (may be NULL)
145
 	 *
143
 	 *
146
-	 * Must be zero if @c data_out is NULL
144
+	 * If non-NULL, this buffer must be ata_command::cb::count
145
+	 * sectors in size.
147
 	 */
146
 	 */
148
-	size_t data_out_len;
149
-	/** Data-in buffer (may be NULL) */
150
-	userptr_t data_in;
151
-	/** Data-in buffer length
147
+	userptr_t data_out;
148
+	/** Data-in buffer (may be NULL)
152
 	 *
149
 	 *
153
-	 * Must be zero if @c data_in is NULL
150
+	 * If non-NULL, this buffer must be ata_command::cb::count
151
+	 * sectors in size.
154
 	 */
152
 	 */
155
-	size_t data_in_len;
153
+	userptr_t data_in;
156
 };
154
 };
157
 
155
 
158
 /**
156
 /**

+ 73
- 93
src/net/aoe.c View File

28
 #include <gpxe/uaccess.h>
28
 #include <gpxe/uaccess.h>
29
 #include <gpxe/ata.h>
29
 #include <gpxe/ata.h>
30
 #include <gpxe/netdevice.h>
30
 #include <gpxe/netdevice.h>
31
-#include <gpxe/process.h>
31
+#include <gpxe/async.h>
32
 #include <gpxe/aoe.h>
32
 #include <gpxe/aoe.h>
33
 
33
 
34
 /** @file
34
 /** @file
42
 /** List of all AoE sessions */
42
 /** List of all AoE sessions */
43
 static LIST_HEAD ( aoe_sessions );
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
  * Send AoE command
62
  * Send AoE command
47
  *
63
  *
56
 	struct pk_buff *pkb;
72
 	struct pk_buff *pkb;
57
 	struct aoehdr *aoehdr;
73
 	struct aoehdr *aoehdr;
58
 	struct aoecmd *aoecmd;
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
 	/* Create outgoing packet buffer */
84
 	/* Create outgoing packet buffer */
61
 	pkb = alloc_pkb ( ETH_HLEN + sizeof ( *aoehdr ) + sizeof ( *aoecmd ) +
85
 	pkb = alloc_pkb ( ETH_HLEN + sizeof ( *aoehdr ) + sizeof ( *aoecmd ) +
62
-			  command->data_out_len );
86
+			  data_out_len );
63
 	if ( ! pkb )
87
 	if ( ! pkb )
64
 		return -ENOMEM;
88
 		return -ENOMEM;
65
 	pkb->net_protocol = &aoe_protocol;
89
 	pkb->net_protocol = &aoe_protocol;
78
 	linker_assert ( AOE_FL_DEV_HEAD	== ATA_DEV_SLAVE, __fix_ata_h__ );
102
 	linker_assert ( AOE_FL_DEV_HEAD	== ATA_DEV_SLAVE, __fix_ata_h__ );
79
 	aoecmd->aflags = ( ( command->cb.lba48 ? AOE_FL_EXTENDED : 0 ) |
103
 	aoecmd->aflags = ( ( command->cb.lba48 ? AOE_FL_EXTENDED : 0 ) |
80
 			   ( command->cb.device & ATA_DEV_SLAVE ) |
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
 	aoecmd->err_feat = command->cb.err_feat.bytes.cur;
106
 	aoecmd->err_feat = command->cb.err_feat.bytes.cur;
83
-	aoecmd->count = command->cb.count.bytes.cur;
107
+	aoecmd->count = count;
84
 	aoecmd->cmd_stat = command->cb.cmd_stat;
108
 	aoecmd->cmd_stat = command->cb.cmd_stat;
85
 	aoecmd->lba.u64 = cpu_to_le64 ( command->cb.lba.native );
109
 	aoecmd->lba.u64 = cpu_to_le64 ( command->cb.lba.native );
86
 	if ( ! command->cb.lba48 )
110
 	if ( ! command->cb.lba48 )
87
 		aoecmd->lba.bytes[3] |= ( command->cb.device & ATA_DEV_MASK );
111
 		aoecmd->lba.bytes[3] |= ( command->cb.device & ATA_DEV_MASK );
88
 
112
 
89
 	/* Fill data payload */
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
 	/* Send packet */
117
 	/* Send packet */
95
 	return net_transmit_via ( pkb, aoe->netdev );
118
 	return net_transmit_via ( pkb, aoe->netdev );
106
 			     unsigned int len ) {
129
 			     unsigned int len ) {
107
 	struct aoecmd *aoecmd = aoehdr->arg.command;
130
 	struct aoecmd *aoecmd = aoehdr->arg.command;
108
 	struct ata_command *command = aoe->command;
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
 	/* Sanity check */
136
 	/* Sanity check */
112
 	if ( len < ( sizeof ( *aoehdr ) + sizeof ( *aoecmd ) ) )
137
 	if ( len < ( sizeof ( *aoehdr ) + sizeof ( *aoecmd ) ) )
113
 		return -EINVAL;
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
 	/* Copy data payload */
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
 	return 0;
178
 	return 0;
138
 }
179
 }
228
 	list_del ( &aoe->list );
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
  * Issue ATA command via an open AoE session
273
  * Issue ATA command via an open AoE session
245
  *
274
  *
246
  * @v aoe		AoE session
275
  * @v aoe		AoE session
247
  * @v command		ATA command
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
 	aoe->command = command;
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
 	aoe->command_offset = 0;
285
 	aoe->command_offset = 0;
306
-	return rc;
286
+	aoe_send_command ( aoe );
307
 }
287
 }

Loading…
Cancel
Save