|
@@ -1,545 +0,0 @@
|
1
|
|
-#include <stddef.h>
|
2
|
|
-#include <string.h>
|
3
|
|
-#include <vsprintf.h>
|
4
|
|
-#include <assert.h>
|
5
|
|
-#include <byteswap.h>
|
6
|
|
-#include <gpxe/iscsi.h>
|
7
|
|
-
|
8
|
|
-/** @file
|
9
|
|
- *
|
10
|
|
- * iSCSI protocol
|
11
|
|
- *
|
12
|
|
- */
|
13
|
|
-
|
14
|
|
-/****************************************************************************
|
15
|
|
- *
|
16
|
|
- * Utility functions
|
17
|
|
- *
|
18
|
|
- */
|
19
|
|
-
|
20
|
|
-/**
|
21
|
|
- * Start up a new TX PDU
|
22
|
|
- *
|
23
|
|
- * @v iscsi iSCSI session
|
24
|
|
- *
|
25
|
|
- * This initiates the process of sending a new PDU. Only one PDU may
|
26
|
|
- * be in transit at any one time.
|
27
|
|
- */
|
28
|
|
-static void iscsi_start_tx ( struct iscsi_session *iscsi ) {
|
29
|
|
- assert ( iscsi->tx_state == ISCSI_TX_IDLE );
|
30
|
|
- iscsi->tx_state = ISCSI_TX_BHS;
|
31
|
|
- iscsi->tx_offset = 0;
|
32
|
|
-}
|
33
|
|
-
|
34
|
|
-/**
|
35
|
|
- * Mark session as failed
|
36
|
|
- *
|
37
|
|
- * @v iscsi iSCSI session
|
38
|
|
- *
|
39
|
|
- * This marks the session as permanently failed. The session will not
|
40
|
|
- * be automatically logged back in.
|
41
|
|
- */
|
42
|
|
-static void iscsi_fail ( struct iscsi_session *iscsi ) {
|
43
|
|
- iscsi->state = ISCSI_STATE_FAILED;
|
44
|
|
- tcp_close ( &iscsi->tcp );
|
45
|
|
-}
|
46
|
|
-
|
47
|
|
-/****************************************************************************
|
48
|
|
- *
|
49
|
|
- * iSCSI SCSI command issuing
|
50
|
|
- *
|
51
|
|
- */
|
52
|
|
-
|
53
|
|
-/**
|
54
|
|
- * Start up a block read
|
55
|
|
- *
|
56
|
|
- * @v iscsi iSCSI session
|
57
|
|
- *
|
58
|
|
- */
|
59
|
|
-static void iscsi_start_read_block ( struct iscsi_session *iscsi ) {
|
60
|
|
- struct iscsi_bhs_scsi_command *command = &iscsi->tx_bhs.scsi_command;
|
61
|
|
- struct scsi_cdb_read_10 *read = &command->cdb.read_10;
|
62
|
|
-
|
63
|
|
- assert ( iscsi->block_size != 0 );
|
64
|
|
- assert ( iscsi->block_count != 0 );
|
65
|
|
- assert ( iscsi->block_read_callback != NULL );
|
66
|
|
-
|
67
|
|
- /* Construct BHS */
|
68
|
|
- memset ( command, 0, sizeof ( *command ) );
|
69
|
|
- command->opcode = ISCSI_OPCODE_SCSI_COMMAND;
|
70
|
|
- command->flags = ( ISCSI_FLAG_FINAL |
|
71
|
|
- ISCSI_COMMAND_FLAG_READ |
|
72
|
|
- ISCSI_COMMAND_ATTR_SIMPLE );
|
73
|
|
- /* lengths left as zero */
|
74
|
|
- /* lun left as zero, on the assumption that no-one uses LUNs > 0 */
|
75
|
|
- command->itt = htonl ( iscsi->itt );
|
76
|
|
- command->exp_len = htonl ( iscsi->block_count * iscsi->block_size );
|
77
|
|
- command->cmdsn = htonl ( iscsi->cmdsn );
|
78
|
|
- command->expstatsn = htonl ( iscsi->statsn + 1 );
|
79
|
|
- read->opcode = SCSI_OPCODE_READ_10;
|
80
|
|
- read->lba = htonl ( iscsi->block_start );
|
81
|
|
- read->len = htons ( iscsi->block_count );
|
82
|
|
-
|
83
|
|
- iscsi->state = ISCSI_STATE_READING_DATA;
|
84
|
|
- iscsi_start_tx ( iscsi );
|
85
|
|
-}
|
86
|
|
-
|
87
|
|
-/**
|
88
|
|
- * Receive data segment of an iSCSI data-in PDU
|
89
|
|
- *
|
90
|
|
- * @v iscsi iSCSI session
|
91
|
|
- * @v data Received data
|
92
|
|
- * @v len Length of received data
|
93
|
|
- * @v remaining Data remaining after this data
|
94
|
|
- *
|
95
|
|
- */
|
96
|
|
-static void iscsi_rx_data_in ( struct iscsi_session *iscsi, void *data,
|
97
|
|
- size_t len, size_t remaining ) {
|
98
|
|
- struct iscsi_bhs_data_in *data_in = &iscsi->rx_bhs.data_in;
|
99
|
|
- unsigned long offset;
|
100
|
|
-
|
101
|
|
- /* Update cmdsn and statsn */
|
102
|
|
- iscsi->cmdsn = ntohl ( data_in->expcmdsn );
|
103
|
|
- iscsi->statsn = ntohl ( data_in->statsn );
|
104
|
|
-
|
105
|
|
- /* Process data via callback */
|
106
|
|
- offset = ntohl ( data_in->offset ) + iscsi->rx_offset;
|
107
|
|
- iscsi->block_read_callback ( iscsi->block_read_private,
|
108
|
|
- data, offset, len );
|
109
|
|
-
|
110
|
|
- /* If this is the end, mark state as idle */
|
111
|
|
- if ( ( data_in->flags & ISCSI_FLAG_FINAL ) && ( remaining == 0 ) )
|
112
|
|
- iscsi->state = ISCSI_STATE_IDLE;
|
113
|
|
-}
|
114
|
|
-
|
115
|
|
-/****************************************************************************
|
116
|
|
- *
|
117
|
|
- * iSCSI login
|
118
|
|
- *
|
119
|
|
- */
|
120
|
|
-
|
121
|
|
-/**
|
122
|
|
- * Build iSCSI login request strings
|
123
|
|
- *
|
124
|
|
- * @v iscsi iSCSI session
|
125
|
|
- *
|
126
|
|
- * These are the initial set of strings sent in the first login
|
127
|
|
- * request PDU.
|
128
|
|
- */
|
129
|
|
-static int iscsi_build_login_request_strings ( struct iscsi_session *iscsi,
|
130
|
|
- void *data, size_t len ) {
|
131
|
|
- return snprintf ( data, len,
|
132
|
|
- "InitiatorName=%s:initiator%c"
|
133
|
|
- "TargetName=%s%c"
|
134
|
|
- "MaxRecvDataSegmentLength=512%c"
|
135
|
|
- "SessionType=Normal%c"
|
136
|
|
- "DataDigest=None%c"
|
137
|
|
- "HeaderDigest=None%c",
|
138
|
|
- iscsi->initiator, 0, iscsi->target, 0,
|
139
|
|
- 0, 0, 0, 0 );
|
140
|
|
-}
|
141
|
|
-
|
142
|
|
-/**
|
143
|
|
- * Transmit data segment of an iSCSI login request PDU
|
144
|
|
- *
|
145
|
|
- * @v iscsi iSCSI session
|
146
|
|
- *
|
147
|
|
- * For login requests, the data segment consists of the login strings.
|
148
|
|
- */
|
149
|
|
-static void iscsi_tx_login_request ( struct iscsi_session *iscsi ) {
|
150
|
|
- int len;
|
151
|
|
-
|
152
|
|
- len = iscsi_build_login_request_strings ( iscsi, tcp_buffer,
|
153
|
|
- tcp_buflen );
|
154
|
|
- tcp_send ( &iscsi->tcp, tcp_buffer + iscsi->tx_offset,
|
155
|
|
- len - iscsi->tx_offset );
|
156
|
|
-}
|
157
|
|
-
|
158
|
|
-/**
|
159
|
|
- * Start up a login request
|
160
|
|
- *
|
161
|
|
- * @v iscsi iSCSI session
|
162
|
|
- *
|
163
|
|
- */
|
164
|
|
-static void iscsi_start_login ( struct iscsi_session *iscsi ) {
|
165
|
|
- struct iscsi_bhs_login_request *request = &iscsi->tx_bhs.login_request;
|
166
|
|
- int len;
|
167
|
|
-
|
168
|
|
- /* Construct login request BHS */
|
169
|
|
- memset ( request, 0, sizeof ( *request ) );
|
170
|
|
- request->opcode = ( ISCSI_OPCODE_LOGIN_REQUEST |
|
171
|
|
- ISCSI_FLAG_IMMEDIATE );
|
172
|
|
- request->flags = ( ISCSI_LOGIN_FLAG_TRANSITION |
|
173
|
|
- ISCSI_LOGIN_CSG_OPERATIONAL_NEGOTIATION |
|
174
|
|
- ISCSI_LOGIN_NSG_FULL_FEATURE_PHASE );
|
175
|
|
- /* version_max and version_min left as zero */
|
176
|
|
- len = iscsi_build_login_request_strings ( iscsi, NULL, 0 );
|
177
|
|
- ISCSI_SET_LENGTHS ( request->lengths, 0, len );
|
178
|
|
- request->isid_iana_en = htonl ( ISCSI_ISID_IANA |
|
179
|
|
- IANA_EN_FEN_SYSTEMS );
|
180
|
|
- /* isid_iana_qual left as zero */
|
181
|
|
- request->tsih = htons ( iscsi->tsih );
|
182
|
|
- /* itt left as zero */
|
183
|
|
- /* cid left as zero */
|
184
|
|
- request->cmdsn = htonl ( iscsi->cmdsn );
|
185
|
|
- request->expstatsn = htonl ( iscsi->statsn + 1 );
|
186
|
|
-
|
187
|
|
- iscsi->state = ISCSI_STATE_LOGGING_IN;
|
188
|
|
- iscsi_start_tx ( iscsi );
|
189
|
|
-}
|
190
|
|
-
|
191
|
|
-/**
|
192
|
|
- * Receive data segment of an iSCSI login response PDU
|
193
|
|
- *
|
194
|
|
- * @v iscsi iSCSI session
|
195
|
|
- * @v data Received data
|
196
|
|
- * @v len Length of received data
|
197
|
|
- * @v remaining Data remaining after this data
|
198
|
|
- *
|
199
|
|
- */
|
200
|
|
-static void iscsi_rx_login_response ( struct iscsi_session *iscsi,
|
201
|
|
- void *data __unused,
|
202
|
|
- size_t len __unused,
|
203
|
|
- size_t remaining __unused ) {
|
204
|
|
- struct iscsi_bhs_login_request *request = &iscsi->tx_bhs.login_request;
|
205
|
|
- struct iscsi_bhs_login_response *response
|
206
|
|
- = &iscsi->rx_bhs.login_response;
|
207
|
|
-
|
208
|
|
- /* Sanity check */
|
209
|
|
- if ( iscsi->state != ISCSI_STATE_LOGGING_IN ) {
|
210
|
|
- printf ( "Spurious iSCSI login response\n" );
|
211
|
|
- iscsi_fail ( iscsi );
|
212
|
|
- return;
|
213
|
|
- }
|
214
|
|
-
|
215
|
|
- /* Check for fatal errors */
|
216
|
|
- if ( response->status_class != 0 ) {
|
217
|
|
- printf ( "iSCSI login failure: class %02x detail %02x\n",
|
218
|
|
- response->status_class, response->status_detail );
|
219
|
|
- iscsi_fail ( iscsi );
|
220
|
|
- return;
|
221
|
|
- }
|
222
|
|
-
|
223
|
|
- /* Update cmdsn and statsn */
|
224
|
|
- iscsi->cmdsn = ntohl ( response->expcmdsn );
|
225
|
|
- iscsi->statsn = ntohl ( response->statsn );
|
226
|
|
-
|
227
|
|
- /* If server did not transition, we send it another login
|
228
|
|
- * request with empty strings.
|
229
|
|
- */
|
230
|
|
- if ( ! ( response->flags & ISCSI_LOGIN_FLAG_TRANSITION ) ) {
|
231
|
|
- ISCSI_SET_LENGTHS ( request->lengths, 0, 0 );
|
232
|
|
- iscsi_start_tx ( iscsi );
|
233
|
|
- return;
|
234
|
|
- }
|
235
|
|
-
|
236
|
|
- /* Record TSIH for future reference */
|
237
|
|
- iscsi->tsih = ntohl ( response->tsih );
|
238
|
|
-
|
239
|
|
- /* Start reading data */
|
240
|
|
- iscsi_start_read_block ( iscsi );
|
241
|
|
-}
|
242
|
|
-
|
243
|
|
-/****************************************************************************
|
244
|
|
- *
|
245
|
|
- * iSCSI to TCP interface
|
246
|
|
- *
|
247
|
|
- */
|
248
|
|
-
|
249
|
|
-static inline struct iscsi_session *
|
250
|
|
-tcp_to_iscsi ( struct tcp_connection *conn ) {
|
251
|
|
- return container_of ( conn, struct iscsi_session, tcp );
|
252
|
|
-}
|
253
|
|
-
|
254
|
|
-static void iscsi_closed ( struct tcp_connection *conn, int status ) {
|
255
|
|
- struct iscsi_session *iscsi = tcp_to_iscsi ( conn );
|
256
|
|
-
|
257
|
|
-}
|
258
|
|
-
|
259
|
|
-static void iscsi_connected ( struct tcp_connection *conn ) {
|
260
|
|
- struct iscsi_session *iscsi = tcp_to_iscsi ( conn );
|
261
|
|
-
|
262
|
|
- /* Prepare to receive PDUs. */
|
263
|
|
- iscsi->rx_state = ISCSI_RX_BHS;
|
264
|
|
- iscsi->rx_offset = 0;
|
265
|
|
-
|
266
|
|
- /* TX state should already have been set up */
|
267
|
|
- assert ( iscsi->tx_state != ISCSI_TX_IDLE );
|
268
|
|
- assert ( iscsi->tx_offset == 0 );
|
269
|
|
-}
|
270
|
|
-
|
271
|
|
-/**
|
272
|
|
- * Transmit data segment of an iSCSI PDU
|
273
|
|
- *
|
274
|
|
- * @v iscsi iSCSI session
|
275
|
|
- *
|
276
|
|
- * Handle transmission of part of a PDU data segment. iscsi::tx_bhs
|
277
|
|
- * will be valid when this is called.
|
278
|
|
- */
|
279
|
|
-static void iscsi_tx_data ( struct iscsi_session *iscsi ) {
|
280
|
|
- struct iscsi_bhs_common *common = &iscsi->tx_bhs.common;
|
281
|
|
-
|
282
|
|
- switch ( common->opcode & ISCSI_OPCODE_MASK ) {
|
283
|
|
- case ISCSI_OPCODE_LOGIN_REQUEST:
|
284
|
|
- iscsi_tx_login_request ( iscsi );
|
285
|
|
- break;
|
286
|
|
- default:
|
287
|
|
- assert ( 0 );
|
288
|
|
- break;
|
289
|
|
- }
|
290
|
|
-}
|
291
|
|
-
|
292
|
|
-/**
|
293
|
|
- * Handle TCP ACKs
|
294
|
|
- *
|
295
|
|
- * @v iscsi iSCSI session
|
296
|
|
- *
|
297
|
|
- * Updates iscsi->tx_offset and, if applicable, transitions to the
|
298
|
|
- * next TX state.
|
299
|
|
- */
|
300
|
|
-static void iscsi_acked ( struct tcp_connection *conn, size_t len ) {
|
301
|
|
- struct iscsi_session *iscsi = tcp_to_iscsi ( conn );
|
302
|
|
- struct iscsi_bhs_common *common = &iscsi->tx_bhs.common;
|
303
|
|
- size_t max_tx_offset;
|
304
|
|
- enum iscsi_tx_state next_state;
|
305
|
|
-
|
306
|
|
- iscsi->tx_offset += len;
|
307
|
|
- while ( 1 ) {
|
308
|
|
- switch ( iscsi->tx_state ) {
|
309
|
|
- case ISCSI_TX_BHS:
|
310
|
|
- max_tx_offset = sizeof ( iscsi->tx_bhs );
|
311
|
|
- next_state = ISCSI_TX_AHS;
|
312
|
|
- break;
|
313
|
|
- case ISCSI_TX_AHS:
|
314
|
|
- max_tx_offset = 4 * ISCSI_AHS_LEN ( common->lengths );
|
315
|
|
- next_state = ISCSI_TX_DATA;
|
316
|
|
- break;
|
317
|
|
- case ISCSI_TX_DATA:
|
318
|
|
- max_tx_offset = ISCSI_DATA_LEN ( common->lengths );
|
319
|
|
- next_state = ISCSI_TX_DATA_PADDING;
|
320
|
|
- break;
|
321
|
|
- case ISCSI_TX_DATA_PADDING:
|
322
|
|
- max_tx_offset = ISCSI_DATA_PAD_LEN ( common->lengths );
|
323
|
|
- next_state = ISCSI_TX_IDLE;
|
324
|
|
- break;
|
325
|
|
- case ISCSI_TX_IDLE:
|
326
|
|
- return;
|
327
|
|
- default:
|
328
|
|
- assert ( 0 );
|
329
|
|
- return;
|
330
|
|
- }
|
331
|
|
- assert ( iscsi->tx_offset <= max_tx_offset );
|
332
|
|
-
|
333
|
|
- /* If the whole of the current portion has not yet
|
334
|
|
- * been acked, stay in this state for now.
|
335
|
|
- */
|
336
|
|
- if ( iscsi->tx_offset != max_tx_offset )
|
337
|
|
- return;
|
338
|
|
-
|
339
|
|
- iscsi->tx_state = next_state;
|
340
|
|
- iscsi->tx_offset = 0;
|
341
|
|
- }
|
342
|
|
-}
|
343
|
|
-
|
344
|
|
-/**
|
345
|
|
- * Transmit iSCSI PDU
|
346
|
|
- *
|
347
|
|
- * @v iscsi iSCSI session
|
348
|
|
- *
|
349
|
|
- * Constructs data to be sent for the current TX state
|
350
|
|
- */
|
351
|
|
-static void iscsi_senddata ( struct tcp_connection *conn ) {
|
352
|
|
- struct iscsi_session *iscsi = tcp_to_iscsi ( conn );
|
353
|
|
- struct iscsi_bhs_common *common = &iscsi->tx_bhs.common;
|
354
|
|
- static const char pad[] = { '\0', '\0', '\0' };
|
355
|
|
-
|
356
|
|
- switch ( iscsi->tx_state ) {
|
357
|
|
- case ISCSI_TX_IDLE:
|
358
|
|
- /* Do nothing */
|
359
|
|
- break;
|
360
|
|
- case ISCSI_TX_BHS:
|
361
|
|
- tcp_send ( conn, &iscsi->tx_bhs.bytes[iscsi->tx_offset],
|
362
|
|
- ( sizeof ( iscsi->tx_bhs ) - iscsi->tx_offset ) );
|
363
|
|
- break;
|
364
|
|
- case ISCSI_TX_AHS:
|
365
|
|
- /* We don't yet have an AHS transmission mechanism */
|
366
|
|
- assert ( 0 );
|
367
|
|
- break;
|
368
|
|
- case ISCSI_TX_DATA:
|
369
|
|
- iscsi_tx_data ( iscsi );
|
370
|
|
- break;
|
371
|
|
- case ISCSI_TX_DATA_PADDING:
|
372
|
|
- tcp_send ( conn, pad, ( ISCSI_DATA_PAD_LEN ( common->lengths )
|
373
|
|
- - iscsi->tx_offset ) );
|
374
|
|
- break;
|
375
|
|
- default:
|
376
|
|
- assert ( 0 );
|
377
|
|
- break;
|
378
|
|
- }
|
379
|
|
-}
|
380
|
|
-
|
381
|
|
-/**
|
382
|
|
- * Receive data segment of an iSCSI PDU
|
383
|
|
- *
|
384
|
|
- * @v iscsi iSCSI session
|
385
|
|
- * @v data Received data
|
386
|
|
- * @v len Length of received data
|
387
|
|
- * @v remaining Data remaining after this data
|
388
|
|
- *
|
389
|
|
- * Handle processing of part of a PDU data segment. iscsi::rx_bhs
|
390
|
|
- * will be valid when this is called.
|
391
|
|
- */
|
392
|
|
-static void iscsi_rx_data ( struct iscsi_session *iscsi, void *data,
|
393
|
|
- size_t len, size_t remaining ) {
|
394
|
|
- struct iscsi_bhs_common *common = &iscsi->rx_bhs.common;
|
395
|
|
-
|
396
|
|
- switch ( common->opcode & ISCSI_OPCODE_MASK ) {
|
397
|
|
- case ISCSI_OPCODE_LOGIN_RESPONSE:
|
398
|
|
- iscsi_rx_login_response ( iscsi, data, len, remaining );
|
399
|
|
- break;
|
400
|
|
- case ISCSI_OPCODE_DATA_IN:
|
401
|
|
- iscsi_rx_data_in ( iscsi, data, len, remaining );
|
402
|
|
- break;
|
403
|
|
- default:
|
404
|
|
- printf ( "Unknown iSCSI opcode %02x\n", common->opcode );
|
405
|
|
- break;
|
406
|
|
- }
|
407
|
|
-}
|
408
|
|
-
|
409
|
|
-/**
|
410
|
|
- * Discard portion of an iSCSI PDU.
|
411
|
|
- *
|
412
|
|
- * @v iscsi iSCSI session
|
413
|
|
- * @v data Received data
|
414
|
|
- * @v len Length of received data
|
415
|
|
- * @v remaining Data remaining after this data
|
416
|
|
- *
|
417
|
|
- * This discards data from a portion of a received PDU.
|
418
|
|
- */
|
419
|
|
-static void iscsi_rx_discard ( struct iscsi_session *iscsi __unused,
|
420
|
|
- void *data __unused, size_t len __unused,
|
421
|
|
- size_t remaining __unused ) {
|
422
|
|
- /* Do nothing */
|
423
|
|
-}
|
424
|
|
-
|
425
|
|
-/**
|
426
|
|
- * Receive basic header segment of an iSCSI PDU
|
427
|
|
- *
|
428
|
|
- * @v iscsi iSCSI session
|
429
|
|
- * @v data Received data
|
430
|
|
- * @v len Length of received data
|
431
|
|
- * @v remaining Data remaining after this data
|
432
|
|
- *
|
433
|
|
- * This fills in iscsi::rx_bhs with the data from the BHS portion of
|
434
|
|
- * the received PDU.
|
435
|
|
- */
|
436
|
|
-static void iscsi_rx_bhs ( struct iscsi_session *iscsi, void *data,
|
437
|
|
- size_t len, size_t remaining __unused ) {
|
438
|
|
- memcpy ( &iscsi->rx_bhs.bytes[iscsi->rx_offset], data, len );
|
439
|
|
-}
|
440
|
|
-
|
441
|
|
-/**
|
442
|
|
- * Receive new data
|
443
|
|
- *
|
444
|
|
- * @v tcp TCP connection
|
445
|
|
- * @v data Received data
|
446
|
|
- * @v len Length of received data
|
447
|
|
- *
|
448
|
|
- * This handles received PDUs. The receive strategy is to fill in
|
449
|
|
- * iscsi::rx_bhs with the contents of the BHS portion of the PDU,
|
450
|
|
- * throw away any AHS portion, and then process each part of the data
|
451
|
|
- * portion as it arrives. The data processing routine therefore
|
452
|
|
- * always has a full copy of the BHS available, even for portions of
|
453
|
|
- * the data in different packets to the BHS.
|
454
|
|
- */
|
455
|
|
-static void iscsi_newdata ( struct tcp_connection *conn, void *data,
|
456
|
|
- size_t len ) {
|
457
|
|
- struct iscsi_session *iscsi = tcp_to_iscsi ( conn );
|
458
|
|
- struct iscsi_bhs_common *common = &iscsi->rx_bhs.common;
|
459
|
|
- void ( *process ) ( struct iscsi_session *iscsi, void *data,
|
460
|
|
- size_t len, size_t remaining );
|
461
|
|
- size_t max_rx_offset;
|
462
|
|
- enum iscsi_rx_state next_state;
|
463
|
|
- size_t frag_len;
|
464
|
|
- size_t remaining;
|
465
|
|
-
|
466
|
|
- while ( 1 ) {
|
467
|
|
- switch ( iscsi->rx_state ) {
|
468
|
|
- case ISCSI_RX_BHS:
|
469
|
|
- process = iscsi_rx_bhs;
|
470
|
|
- max_rx_offset = sizeof ( iscsi->rx_bhs );
|
471
|
|
- next_state = ISCSI_RX_AHS;
|
472
|
|
- break;
|
473
|
|
- case ISCSI_RX_AHS:
|
474
|
|
- process = iscsi_rx_discard;
|
475
|
|
- max_rx_offset = 4 * ISCSI_AHS_LEN ( common->lengths );
|
476
|
|
- next_state = ISCSI_RX_DATA;
|
477
|
|
- break;
|
478
|
|
- case ISCSI_RX_DATA:
|
479
|
|
- process = iscsi_rx_data;
|
480
|
|
- max_rx_offset = ISCSI_DATA_LEN ( common->lengths );
|
481
|
|
- next_state = ISCSI_RX_DATA_PADDING;
|
482
|
|
- break;
|
483
|
|
- case ISCSI_RX_DATA_PADDING:
|
484
|
|
- process = iscsi_rx_discard;
|
485
|
|
- max_rx_offset = ISCSI_DATA_PAD_LEN ( common->lengths );
|
486
|
|
- next_state = ISCSI_RX_BHS;
|
487
|
|
- break;
|
488
|
|
- default:
|
489
|
|
- assert ( 0 );
|
490
|
|
- return;
|
491
|
|
- }
|
492
|
|
-
|
493
|
|
- frag_len = max_rx_offset - iscsi->rx_offset;
|
494
|
|
- if ( frag_len > len )
|
495
|
|
- frag_len = len;
|
496
|
|
- remaining = max_rx_offset - iscsi->rx_offset - frag_len;
|
497
|
|
- process ( iscsi, data, frag_len, remaining );
|
498
|
|
-
|
499
|
|
- iscsi->rx_offset += frag_len;
|
500
|
|
- data += frag_len;
|
501
|
|
- len -= frag_len;
|
502
|
|
-
|
503
|
|
- /* If all the data for this state has not yet been
|
504
|
|
- * received, stay in this state for now.
|
505
|
|
- */
|
506
|
|
- if ( iscsi->rx_offset != max_rx_offset )
|
507
|
|
- return;
|
508
|
|
-
|
509
|
|
- iscsi->rx_state = next_state;
|
510
|
|
- iscsi->rx_offset = 0;
|
511
|
|
- }
|
512
|
|
-}
|
513
|
|
-
|
514
|
|
-/** iSCSI TCP operations */
|
515
|
|
-static struct tcp_operations iscsi_tcp_operations = {
|
516
|
|
- .closed = iscsi_closed,
|
517
|
|
- .connected = iscsi_connected,
|
518
|
|
- .acked = iscsi_acked,
|
519
|
|
- .newdata = iscsi_newdata,
|
520
|
|
- .senddata = iscsi_senddata,
|
521
|
|
-};
|
522
|
|
-
|
523
|
|
-/**
|
524
|
|
- * Wake up session
|
525
|
|
- *
|
526
|
|
- * @v iscsi iSCSI session
|
527
|
|
- *
|
528
|
|
- */
|
529
|
|
-void iscsi_wakeup ( struct iscsi_session *iscsi ) {
|
530
|
|
- iscsi->tcp.tcp_op = &iscsi_tcp_operations;
|
531
|
|
-
|
532
|
|
- switch ( iscsi->state ) {
|
533
|
|
- case ISCSI_STATE_NOT_CONNECTED:
|
534
|
|
- case ISCSI_STATE_FAILED:
|
535
|
|
- tcp_connect ( &iscsi->tcp );
|
536
|
|
- iscsi_start_login ( iscsi );
|
537
|
|
- break;
|
538
|
|
- case ISCSI_STATE_IDLE:
|
539
|
|
- iscsi_start_read_block ( iscsi );
|
540
|
|
- break;
|
541
|
|
- default:
|
542
|
|
- /* Stay in same state */
|
543
|
|
- break;
|
544
|
|
- }
|
545
|
|
-}
|