Parcourir la 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 il y a 18 ans
Parent
révision
68125bc441
6 fichiers modifiés avec 161 ajouts et 117 suppressions
  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 Voir le fichier

@@ -37,7 +37,8 @@ static int aoe_command ( struct ata_device *ata,
37 37
 	struct aoe_device *aoedev
38 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 Voir le fichier

@@ -18,6 +18,7 @@
18 18
 
19 19
 #include <stddef.h>
20 20
 #include <string.h>
21
+#include <assert.h>
21 22
 #include <byteswap.h>
22 23
 #include <gpxe/blockdev.h>
23 24
 #include <gpxe/ata.h>
@@ -73,7 +74,6 @@ static int ata_read ( struct block_device *blockdev, uint64_t block,
73 74
 		command.cb.device |= command.cb.lba.bytes.low_prev;
74 75
 	command.cb.cmd_stat = ( ata->lba48 ? ATA_CMD_READ_EXT : ATA_CMD_READ );
75 76
 	command.data_in = buffer;
76
-	command.data_in_len = ( count * blockdev->blksize );
77 77
 	return ata_command ( ata, &command );
78 78
 }
79 79
 
@@ -101,7 +101,6 @@ static int ata_write ( struct block_device *blockdev, uint64_t block,
101 101
 	command.cb.cmd_stat = ( ata->lba48 ?
102 102
 				ATA_CMD_WRITE_EXT : ATA_CMD_WRITE );
103 103
 	command.data_out = buffer;
104
-	command.data_out_len = ( count * blockdev->blksize );
105 104
 	return ata_command ( ata, &command );
106 105
 }
107 106
 
@@ -119,12 +118,12 @@ static int ata_identify ( struct block_device *blockdev ) {
119 118
 
120 119
 	/* Issue IDENTIFY */
121 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 122
 	command.cb.device = ( ata->device | ATA_DEV_OBSOLETE | ATA_DEV_LBA );
125 123
 	command.cb.cmd_stat = ATA_CMD_IDENTIFY;
126 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 127
 	if ( ( rc = ata_command ( ata, &command ) ) != 0 )
129 128
 		return rc;
130 129
 

+ 12
- 8
src/include/gpxe/aoe.h Voir le fichier

@@ -10,6 +10,8 @@
10 10
 #include <stdint.h>
11 11
 #include <gpxe/list.h>
12 12
 #include <gpxe/if_ether.h>
13
+#include <gpxe/retry.h>
14
+#include <gpxe/async.h>
13 15
 #include <gpxe/ata.h>
14 16
 
15 17
 /** An AoE ATA command */
@@ -89,29 +91,31 @@ struct aoe_session {
89 91
 	/** Target MAC address */
90 92
 	uint8_t target[ETH_ALEN];
91 93
 
92
-	/** Tag for current command */
94
+	/** Tag for current AoE command */
93 95
 	uint32_t tag;
96
+
94 97
 	/** Current ATA command */
95 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 101
 	/** Byte offset within command's data buffer */
99 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 110
 #define AOE_STATUS_ERR_MASK	0x0f /**< Error portion of status code */ 
103 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 113
 /** Maximum number of sectors per packet */
108 114
 #define AOE_MAX_COUNT 2
109 115
 
110 116
 extern void aoe_open ( struct aoe_session *aoe );
111 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 120
 /** An AoE device */
117 121
 struct aoe_device {

+ 62
- 0
src/include/gpxe/async.h Voir le fichier

@@ -0,0 +1,62 @@
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 Voir le fichier

@@ -139,20 +139,18 @@ struct ata_cb {
139 139
 struct ata_command {
140 140
 	/** ATA command block */
141 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 Voir le fichier

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

Chargement…
Annuler
Enregistrer