Browse Source

Moved to net/tcp/iscsi.c.

tags/v0.9.3
Michael Brown 18 years ago
parent
commit
21493646c2
1 changed files with 0 additions and 545 deletions
  1. 0
    545
      src/proto/iscsi.c

+ 0
- 545
src/proto/iscsi.c View File

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

Loading…
Cancel
Save