2 * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include <gpxe/scsi.h>
27 #include <gpxe/process.h>
28 #include <gpxe/uaccess.h>
29 #include <gpxe/iscsi.h>
37 static void iscsi_start_tx ( struct iscsi_session *iscsi );
38 static void iscsi_start_data_out ( struct iscsi_session *iscsi,
39 unsigned int datasn );
42 * Receive PDU data into buffer
44 * @v iscsi iSCSI session
45 * @v data Data to receive
46 * @v len Length of data
47 * @ret rc Return status code
49 * This can be used when the RX PDU type handler wishes to buffer up
50 * all received data and process the PDU as a single unit. The caller
51 * is repsonsible for calling iscsi_rx_buffered_data_done() after
52 * processing the data.
54 static int iscsi_rx_buffered_data ( struct iscsi_session *iscsi,
55 const void *data, size_t len ) {
57 /* Allocate buffer on first call */
58 if ( ! iscsi->rx_buffer ) {
59 iscsi->rx_buffer = malloc ( iscsi->rx_len );
60 if ( ! iscsi->rx_buffer )
64 /* Copy data to buffer */
65 assert ( ( iscsi->rx_offset + len ) <= iscsi->rx_len );
66 memcpy ( ( iscsi->rx_buffer + iscsi->rx_offset ), data, len );
72 * Finish receiving PDU data into buffer
74 * @v iscsi iSCSI session
76 static void iscsi_rx_buffered_data_done ( struct iscsi_session *iscsi ) {
77 free ( iscsi->rx_buffer );
78 iscsi->rx_buffer = NULL;
82 * Close iSCSI connection
84 * @v iscsi iSCSI session
86 static void iscsi_close ( struct iscsi_session *iscsi ) {
88 /* Close TCP connection */
89 tcp_close ( &iscsi->tcp );
91 /* Clear connection status */
94 /* Reset TX and RX state machines */
95 iscsi->tx_state = ISCSI_TX_IDLE;
96 iscsi->rx_state = ISCSI_RX_BHS;
98 /* Free any dynamically allocated memory */
99 chap_finish ( &iscsi->chap );
100 iscsi_rx_buffered_data_done ( iscsi );
104 * Mark iSCSI operation as complete
106 * @v iscsi iSCSI session
107 * @v rc Return status code
109 * Note that iscsi_done() will not close the connection, and must
110 * therefore be called only when the internal state machines are in an
111 * appropriate state, otherwise bad things may happen on the next call
112 * to iscsi_issue(). The general rule is to call iscsi_done() only at
113 * the end of receiving a PDU; at this point the TX and RX engines
114 * should both be idle.
116 static void iscsi_done ( struct iscsi_session *iscsi, int rc ) {
118 assert ( iscsi->tx_state == ISCSI_TX_IDLE );
119 assert ( iscsi->rx_state == ISCSI_RX_BHS );
120 assert ( iscsi->rx_offset == 0 );
122 /* Clear current SCSI command */
123 iscsi->command = NULL;
125 /* Mark asynchronous operation as complete */
126 async_done ( &iscsi->aop, rc );
129 /****************************************************************************
131 * iSCSI SCSI command issuing
136 * Build iSCSI SCSI command BHS
138 * @v iscsi iSCSI session
140 * We don't currently support bidirectional commands (i.e. with both
141 * Data-In and Data-Out segments); these would require providing code
142 * to generate an AHS, and there doesn't seem to be any need for it at
145 static void iscsi_start_command ( struct iscsi_session *iscsi ) {
146 struct iscsi_bhs_scsi_command *command = &iscsi->tx_bhs.scsi_command;
148 assert ( ! ( iscsi->command->data_in && iscsi->command->data_out ) );
150 /* Construct BHS and initiate transmission */
151 iscsi_start_tx ( iscsi );
152 command->opcode = ISCSI_OPCODE_SCSI_COMMAND;
153 command->flags = ( ISCSI_FLAG_FINAL |
154 ISCSI_COMMAND_ATTR_SIMPLE );
155 if ( iscsi->command->data_in )
156 command->flags |= ISCSI_COMMAND_FLAG_READ;
157 if ( iscsi->command->data_out )
158 command->flags |= ISCSI_COMMAND_FLAG_WRITE;
159 /* lengths left as zero */
160 command->lun = iscsi->lun;
161 command->itt = htonl ( ++iscsi->itt );
162 command->exp_len = htonl ( iscsi->command->data_in_len |
163 iscsi->command->data_out_len );
164 command->cmdsn = htonl ( iscsi->cmdsn );
165 command->expstatsn = htonl ( iscsi->statsn + 1 );
166 memcpy ( &command->cdb, &iscsi->command->cdb, sizeof ( command->cdb ));
167 DBG ( "iSCSI %p start " SCSI_CDB_FORMAT " %s %#x\n",
168 iscsi, SCSI_CDB_DATA ( command->cdb ),
169 ( iscsi->command->data_in ? "in" : "out" ),
170 ( iscsi->command->data_in ?
171 iscsi->command->data_in_len : iscsi->command->data_out_len ) );
175 * Receive data segment of an iSCSI SCSI response PDU
177 * @v iscsi iSCSI session
178 * @v data Received data
179 * @v len Length of received data
180 * @v remaining Data remaining after this data
183 static void iscsi_rx_scsi_response ( struct iscsi_session *iscsi, void *data,
184 size_t len, size_t remaining ) {
185 struct iscsi_bhs_scsi_response *response
186 = &iscsi->rx_bhs.scsi_response;
189 /* Capture the sense response code as it floats past, if present */
190 sense_offset = ISCSI_SENSE_RESPONSE_CODE_OFFSET - iscsi->rx_offset;
191 if ( ( sense_offset >= 0 ) && len ) {
192 iscsi->command->sense_response =
193 * ( ( char * ) data + sense_offset );
196 /* Wait for whole SCSI response to arrive */
200 /* Record SCSI status code */
201 iscsi->command->status = response->status;
203 /* Mark as completed, with error if applicable */
204 if ( response->response == ISCSI_RESPONSE_COMMAND_COMPLETE ) {
205 iscsi_done ( iscsi, 0 );
207 iscsi_done ( iscsi, -EIO );
212 * Receive data segment of an iSCSI data-in PDU
214 * @v iscsi iSCSI session
215 * @v data Received data
216 * @v len Length of received data
217 * @v remaining Data remaining after this data
220 static void iscsi_rx_data_in ( struct iscsi_session *iscsi, void *data,
221 size_t len, size_t remaining __unused ) {
222 struct iscsi_bhs_data_in *data_in = &iscsi->rx_bhs.data_in;
223 unsigned long offset;
225 /* Copy data to data-in buffer */
226 offset = ntohl ( data_in->offset ) + iscsi->rx_offset;
227 assert ( iscsi->command != NULL );
228 assert ( iscsi->command->data_in );
229 assert ( ( offset + len ) <= iscsi->command->data_in_len );
230 copy_to_user ( iscsi->command->data_in, offset, data, len );
232 /* Record SCSI status, if present */
233 if ( data_in->flags & ISCSI_DATA_FLAG_STATUS )
234 iscsi->command->status = data_in->status;
236 /* If this is the end, flag as complete */
237 if ( ( offset + len ) == iscsi->command->data_in_len ) {
238 assert ( data_in->flags & ISCSI_FLAG_FINAL );
239 assert ( remaining == 0 );
240 iscsi_done ( iscsi, 0 );
245 * Receive data segment of an iSCSI R2T PDU
247 * @v iscsi iSCSI session
248 * @v data Received data
249 * @v len Length of received data
250 * @v remaining Data remaining after this data
253 static void iscsi_rx_r2t ( struct iscsi_session *iscsi, void *data __unused,
254 size_t len __unused, size_t remaining __unused ) {
255 struct iscsi_bhs_r2t *r2t = &iscsi->rx_bhs.r2t;
257 /* Record transfer parameters and trigger first data-out */
258 iscsi->ttt = ntohl ( r2t->ttt );
259 iscsi->transfer_offset = ntohl ( r2t->offset );
260 iscsi->transfer_len = ntohl ( r2t->len );
261 iscsi_start_data_out ( iscsi, 0 );
265 * Build iSCSI data-out BHS
267 * @v iscsi iSCSI session
268 * @v datasn Data sequence number within the transfer
271 static void iscsi_start_data_out ( struct iscsi_session *iscsi,
272 unsigned int datasn ) {
273 struct iscsi_bhs_data_out *data_out = &iscsi->tx_bhs.data_out;
274 unsigned long offset;
275 unsigned long remaining;
278 /* We always send 512-byte Data-Out PDUs; this removes the
279 * need to worry about the target's MaxRecvDataSegmentLength.
281 offset = datasn * 512;
282 remaining = iscsi->transfer_len - offset;
287 /* Construct BHS and initiate transmission */
288 iscsi_start_tx ( iscsi );
289 data_out->opcode = ISCSI_OPCODE_DATA_OUT;
290 if ( len == remaining )
291 data_out->flags = ( ISCSI_FLAG_FINAL );
292 ISCSI_SET_LENGTHS ( data_out->lengths, 0, len );
293 data_out->lun = iscsi->lun;
294 data_out->itt = htonl ( iscsi->itt );
295 data_out->ttt = htonl ( iscsi->ttt );
296 data_out->expstatsn = htonl ( iscsi->statsn + 1 );
297 data_out->datasn = htonl ( datasn );
298 data_out->offset = htonl ( iscsi->transfer_offset + offset );
299 DBG ( "iSCSI %p start data out DataSN %#x len %#lx\n",
300 iscsi, datasn, len );
304 * Complete iSCSI data-out PDU transmission
306 * @v iscsi iSCSI session
309 static void iscsi_data_out_done ( struct iscsi_session *iscsi ) {
310 struct iscsi_bhs_data_out *data_out = &iscsi->tx_bhs.data_out;
312 /* If we haven't reached the end of the sequence, start
313 * sending the next data-out PDU.
315 if ( ! ( data_out->flags & ISCSI_FLAG_FINAL ) )
316 iscsi_start_data_out ( iscsi, ntohl ( data_out->datasn ) + 1 );
320 * Send iSCSI data-out data segment
322 * @v iscsi iSCSI session
323 * @v buf Temporary data buffer
324 * @v len Length of temporary data buffer
326 static void iscsi_tx_data_out ( struct iscsi_session *iscsi,
327 void *buf, size_t len ) {
328 struct iscsi_bhs_data_out *data_out = &iscsi->tx_bhs.data_out;
329 unsigned long offset;
330 unsigned long remaining;
332 offset = ( iscsi->transfer_offset + ntohl ( data_out->offset ) +
334 remaining = ( iscsi->tx_len - iscsi->tx_offset );
335 assert ( iscsi->command != NULL );
336 assert ( iscsi->command->data_out );
337 assert ( ( offset + remaining ) <= iscsi->command->data_out_len );
339 if ( remaining < len )
341 copy_from_user ( buf, iscsi->command->data_out, offset, len );
343 tcp_send ( &iscsi->tcp, buf, len );
346 /****************************************************************************
353 * Version of snprintf() that accepts a signed buffer size
355 * @v buf Buffer into which to write the string
356 * @v size Size of buffer
357 * @v fmt Format string
358 * @v args Arguments corresponding to the format string
359 * @ret len Length of formatted string
361 * This is a utility function for iscsi_build_login_request_strings().
363 static int ssnprintf ( char *buf, ssize_t ssize, const char *fmt, ... ) {
367 /* Treat negative buffer size as zero buffer size */
371 /* Hand off to vsnprintf */
372 va_start ( args, fmt );
373 len = vsnprintf ( buf, ssize, fmt, args );
379 * Build iSCSI login request strings
381 * @v iscsi iSCSI session
383 * These are the initial set of strings sent in the first login
384 * request PDU. We want the following settings:
388 * MaxConnections is irrelevant; we make only one connection anyway
390 * ImmediateData is irrelevant; we never send immediate data
391 * MaxRecvDataSegmentLength=8192 (default; we don't care)
392 * MaxBurstLength=262144 (default; we don't care)
393 * FirstBurstLength=262144 (default; we don't care)
394 * DefaultTime2Wait=0 [2]
395 * DefaultTime2Retain=0 [2]
396 * MaxOutstandingR2T=1
398 * DataSequenceInOrder=Yes
399 * ErrorRecoveryLevel=0
401 * [1] InitialR2T has an OR resolution function, so the target may
402 * force us to use it. We therefore simplify our logic by always
405 * [2] These ensure that we can safely start a new task once we have
406 * reconnected after a failure, without having to manually tidy up
409 static int iscsi_build_login_request_strings ( struct iscsi_session *iscsi,
410 void *data, size_t len ) {
411 unsigned int used = 0;
414 if ( iscsi->status & ISCSI_STATUS_STRINGS_SECURITY ) {
415 used += ssnprintf ( data + used, len - used,
418 "SessionType=Normal%c"
419 "AuthMethod=CHAP,None%c",
420 iscsi->initiator_iqn, 0,
421 iscsi->target_iqn, 0, 0, 0 );
424 if ( iscsi->status & ISCSI_STATUS_STRINGS_CHAP_ALGORITHM ) {
425 used += ssnprintf ( data + used, len - used, "CHAP_A=5%c", 0 );
428 if ( ( iscsi->status & ISCSI_STATUS_STRINGS_CHAP_RESPONSE ) &&
430 used += ssnprintf ( data + used, len - used,
431 "CHAP_N=%s%cCHAP_R=0x",
432 iscsi->username, 0 );
433 for ( i = 0 ; i < iscsi->chap.response_len ; i++ ) {
434 used += ssnprintf ( data + used, len - used, "%02x",
435 iscsi->chap.response[i] );
437 used += ssnprintf ( data + used, len - used, "%c", 0 );
440 if ( iscsi->status & ISCSI_STATUS_STRINGS_OPERATIONAL ) {
441 used += ssnprintf ( data + used, len - used,
442 "HeaderDigest=None%c"
445 "DefaultTime2Wait=0%c"
446 "DefaultTime2Retain=0%c"
447 "MaxOutstandingR2T=1%c"
448 "DataPDUInOrder=Yes%c"
449 "DataSequenceInOrder=Yes%c"
450 "ErrorRecoveryLevel=0%c",
451 0, 0, 0, 0, 0, 0, 0, 0, 0 );
458 * Build iSCSI login request BHS
460 * @v iscsi iSCSI session
462 static void iscsi_start_login ( struct iscsi_session *iscsi ) {
463 struct iscsi_bhs_login_request *request = &iscsi->tx_bhs.login_request;
466 /* Construct BHS and initiate transmission */
467 iscsi_start_tx ( iscsi );
468 request->opcode = ( ISCSI_OPCODE_LOGIN_REQUEST |
469 ISCSI_FLAG_IMMEDIATE );
470 request->flags = ( ( iscsi->status & ISCSI_STATUS_PHASE_MASK ) |
471 ISCSI_LOGIN_FLAG_TRANSITION );
472 /* version_max and version_min left as zero */
473 len = iscsi_build_login_request_strings ( iscsi, NULL, 0 );
474 ISCSI_SET_LENGTHS ( request->lengths, 0, len );
475 request->isid_iana_en = htonl ( ISCSI_ISID_IANA |
476 IANA_EN_FEN_SYSTEMS );
477 /* isid_iana_qual left as zero */
478 request->tsih = htons ( iscsi->tsih );
479 request->itt = htonl ( iscsi->itt );
480 /* cid left as zero */
481 request->cmdsn = htonl ( iscsi->cmdsn );
482 request->expstatsn = htonl ( iscsi->statsn + 1 );
486 * Complete iSCSI login request PDU transmission
488 * @v iscsi iSCSI session
491 static void iscsi_login_request_done ( struct iscsi_session *iscsi ) {
493 /* Clear any "strings to send" flags */
494 iscsi->status &= ~ISCSI_STATUS_STRINGS_MASK;
496 /* Free any dynamically allocated storage used for login */
497 chap_finish ( &iscsi->chap );
501 * Transmit data segment of an iSCSI login request PDU
503 * @v iscsi iSCSI session
504 * @v buf Temporary data buffer
505 * @v len Length of temporary data buffer
507 * For login requests, the data segment consists of the login strings.
509 static void iscsi_tx_login_request ( struct iscsi_session *iscsi,
510 void *buf, size_t len ) {
511 len = iscsi_build_login_request_strings ( iscsi, buf, len );
512 tcp_send ( &iscsi->tcp, buf + iscsi->tx_offset,
513 len - iscsi->tx_offset );
517 * Handle iSCSI TargetAddress text value
519 * @v iscsi iSCSI session
520 * @v value TargetAddress value
522 static void iscsi_handle_targetaddress_value ( struct iscsi_session *iscsi,
523 const char *value ) {
524 struct in_addr address;
525 struct sockaddr_in *sin = ( struct sockaddr_in * ) &iscsi->target;
527 if ( inet_aton ( value, &address ) == 0 ) {
528 DBG ( "iSCSI %p received invalid TargetAddress \"%s\"\n",
533 DBG ( "iSCSI %p will redirect to %s\n", iscsi, value );
534 sin->sin_addr = address;
538 * Handle iSCSI AuthMethod text value
540 * @v iscsi iSCSI session
541 * @v value AuthMethod value
543 static void iscsi_handle_authmethod_value ( struct iscsi_session *iscsi,
544 const char *value ) {
546 /* If server requests CHAP, send the CHAP_A string */
547 if ( strcmp ( value, "CHAP" ) == 0 ) {
548 DBG ( "iSCSI %p initiating CHAP authentication\n", iscsi );
549 iscsi->status |= ISCSI_STATUS_STRINGS_CHAP_ALGORITHM;
554 * Handle iSCSI CHAP_A text value
556 * @v iscsi iSCSI session
557 * @v value CHAP_A value
559 static void iscsi_handle_chap_a_value ( struct iscsi_session *iscsi,
560 const char *value ) {
563 /* We only ever offer "5" (i.e. MD5) as an algorithm, so if
564 * the server responds with anything else it is a protocol
567 if ( strcmp ( value, "5" ) != 0 ) {
568 DBG ( "iSCSI %p got invalid CHAP algorithm \"%s\"\n",
572 /* Prepare for CHAP with MD5 */
573 if ( ( rc = chap_init ( &iscsi->chap, &md5_algorithm ) ) != 0 ) {
574 DBG ( "iSCSI %p could not initialise CHAP\n", iscsi );
575 iscsi_close ( iscsi );
576 iscsi_done ( iscsi, rc );
581 * Handle iSCSI CHAP_I text value
583 * @v iscsi iSCSI session
584 * @v value CHAP_I value
586 static void iscsi_handle_chap_i_value ( struct iscsi_session *iscsi,
587 const char *value ) {
588 unsigned int identifier;
591 /* The CHAP identifier is an integer value */
592 identifier = strtoul ( value, &endp, 0 );
593 if ( *endp != '\0' ) {
594 DBG ( "iSCSI %p saw invalid CHAP identifier \"%s\"\n",
598 /* Identifier and secret are the first two components of the
601 chap_set_identifier ( &iscsi->chap, identifier );
602 if ( iscsi->password ) {
603 chap_update ( &iscsi->chap, iscsi->password,
604 strlen ( iscsi->password ) );
609 * Handle iSCSI CHAP_C text value
611 * @v iscsi iSCSI session
612 * @v value CHAP_C value
614 static void iscsi_handle_chap_c_value ( struct iscsi_session *iscsi,
615 const char *value ) {
620 /* Check and strip leading "0x" */
621 if ( ( value[0] != '0' ) || ( value[1] != 'x' ) ) {
622 DBG ( "iSCSI %p saw invalid CHAP challenge \"%s\"\n",
627 /* Process challenge an octet at a time */
628 for ( ; ( value[0] && value[1] ) ; value += 2 ) {
629 memcpy ( buf, value, 2 );
631 byte = strtoul ( buf, &endp, 16 );
632 if ( *endp != '\0' ) {
633 DBG ( "iSCSI %p saw invalid CHAP challenge byte "
634 "\"%s\"\n", iscsi, buf );
636 chap_update ( &iscsi->chap, &byte, sizeof ( byte ) );
639 /* Build CHAP response */
640 DBG ( "iSCSI %p sending CHAP response\n", iscsi );
641 chap_respond ( &iscsi->chap );
642 iscsi->status |= ISCSI_STATUS_STRINGS_CHAP_RESPONSE;
645 /** An iSCSI text string that we want to handle */
646 struct iscsi_string_type {
649 * This is the portion up to and including the "=" sign,
650 * e.g. "InitiatorName=", "CHAP_A=", etc.
653 /** Handle iSCSI string value
655 * @v iscsi iSCSI session
656 * @v value iSCSI string value
658 void ( * handle_value ) ( struct iscsi_session *iscsi,
662 /** iSCSI text strings that we want to handle */
663 struct iscsi_string_type iscsi_string_types[] = {
664 { "TargetAddress=", iscsi_handle_targetaddress_value },
665 { "AuthMethod=", iscsi_handle_authmethod_value },
666 { "CHAP_A=", iscsi_handle_chap_a_value },
667 { "CHAP_I=", iscsi_handle_chap_i_value },
668 { "CHAP_C=", iscsi_handle_chap_c_value },
673 * Handle iSCSI string
675 * @v iscsi iSCSI session
676 * @v string iSCSI string (in "key=value" format)
678 static void iscsi_handle_string ( struct iscsi_session *iscsi,
679 const char *string ) {
680 struct iscsi_string_type *type;
683 for ( type = iscsi_string_types ; type->key ; type++ ) {
684 key_len = strlen ( type->key );
685 if ( strncmp ( string, type->key, key_len ) == 0 ) {
686 DBG ( "iSCSI %p handling %s\n", iscsi, string );
687 type->handle_value ( iscsi, ( string + key_len ) );
691 DBG ( "iSCSI %p ignoring %s\n", iscsi, string );
695 * Handle iSCSI strings
697 * @v iscsi iSCSI session
698 * @v string iSCSI string buffer
699 * @v len Length of string buffer
701 static void iscsi_handle_strings ( struct iscsi_session *iscsi,
702 const char *strings, size_t len ) {
705 /* Handle each string in turn, taking care not to overrun the
706 * data buffer in case of badly-terminated data.
709 string_len = ( strnlen ( strings, len ) + 1 );
710 if ( string_len > len )
712 iscsi_handle_string ( iscsi, strings );
713 strings += string_len;
719 * Receive data segment of an iSCSI login response PDU
721 * @v iscsi iSCSI session
722 * @v data Received data
723 * @v len Length of received data
724 * @v remaining Data remaining after this data
727 static void iscsi_rx_login_response ( struct iscsi_session *iscsi, void *data,
728 size_t len, size_t remaining ) {
729 struct iscsi_bhs_login_response *response
730 = &iscsi->rx_bhs.login_response;
733 /* Buffer up the PDU data */
734 if ( ( rc = iscsi_rx_buffered_data ( iscsi, data, len ) ) != 0 ) {
735 DBG ( "iSCSI %p could not buffer login response\n", iscsi );
736 iscsi_close ( iscsi );
737 iscsi_done ( iscsi, rc );
743 /* Process string data and discard string buffer */
744 iscsi_handle_strings ( iscsi, iscsi->rx_buffer, iscsi->rx_len );
745 iscsi_rx_buffered_data_done ( iscsi );
747 /* Check for login redirection */
748 if ( response->status_class == ISCSI_STATUS_REDIRECT ) {
749 DBG ( "iSCSI %p redirecting to new server\n", iscsi );
750 iscsi_close ( iscsi );
751 if ( ( rc = tcp_connect ( &iscsi->tcp, &iscsi->target,
753 DBG ( "iSCSI %p could not open TCP connection\n",
755 iscsi_done ( iscsi, rc );
760 /* Check for fatal errors */
761 if ( response->status_class != 0 ) {
762 DBG ( "iSCSI login failure: class %02x detail %02x\n",
763 response->status_class, response->status_detail );
764 iscsi->instant_rc = -EPERM;
765 iscsi_close ( iscsi );
766 iscsi_done ( iscsi, -EPERM );
770 /* Handle login transitions */
771 if ( response->flags & ISCSI_LOGIN_FLAG_TRANSITION ) {
772 switch ( response->flags & ISCSI_LOGIN_NSG_MASK ) {
773 case ISCSI_LOGIN_NSG_OPERATIONAL_NEGOTIATION:
775 ( ISCSI_STATUS_OPERATIONAL_NEGOTIATION_PHASE |
776 ISCSI_STATUS_STRINGS_OPERATIONAL );
778 case ISCSI_LOGIN_NSG_FULL_FEATURE_PHASE:
779 iscsi->status = ISCSI_STATUS_FULL_FEATURE_PHASE;
782 DBG ( "iSCSI %p got invalid response flags %02x\n",
783 iscsi, response->flags );
784 iscsi_close ( iscsi );
785 iscsi_done ( iscsi, -EIO );
790 /* Send next login request PDU if we haven't reached the full
793 if ( ( iscsi->status & ISCSI_STATUS_PHASE_MASK ) !=
794 ISCSI_STATUS_FULL_FEATURE_PHASE ) {
795 iscsi_start_login ( iscsi );
799 /* Reset retry count */
800 iscsi->retry_count = 0;
802 /* Record TSIH for future reference */
803 iscsi->tsih = ntohl ( response->tsih );
805 /* Send the actual SCSI command */
806 iscsi_start_command ( iscsi );
809 /****************************************************************************
811 * iSCSI to TCP interface
815 static inline struct iscsi_session *
816 tcp_to_iscsi ( struct tcp_application *app ) {
817 return container_of ( app, struct iscsi_session, tcp );
821 * Start up a new TX PDU
823 * @v iscsi iSCSI session
825 * This initiates the process of sending a new PDU. Only one PDU may
826 * be in transit at any one time.
828 static void iscsi_start_tx ( struct iscsi_session *iscsi ) {
829 assert ( iscsi->tx_state == ISCSI_TX_IDLE );
831 /* Initialise TX BHS */
832 memset ( &iscsi->tx_bhs, 0, sizeof ( iscsi->tx_bhs ) );
834 /* Flag TX engine to start transmitting */
835 iscsi->tx_state = ISCSI_TX_BHS;
836 iscsi->tx_offset = 0;
840 * Transmit data segment of an iSCSI PDU
842 * @v iscsi iSCSI session
843 * @v buf Temporary data buffer
844 * @v len Length of temporary data buffer
846 * Handle transmission of part of a PDU data segment. iscsi::tx_bhs
847 * will be valid when this is called.
849 static void iscsi_tx_data ( struct iscsi_session *iscsi,
850 void *buf, size_t len ) {
851 struct iscsi_bhs_common *common = &iscsi->tx_bhs.common;
853 switch ( common->opcode & ISCSI_OPCODE_MASK ) {
854 case ISCSI_OPCODE_DATA_OUT:
855 iscsi_tx_data_out ( iscsi, buf, len );
857 case ISCSI_OPCODE_LOGIN_REQUEST:
858 iscsi_tx_login_request ( iscsi, buf, len );
867 * Complete iSCSI PDU transmission
869 * @v iscsi iSCSI session
871 * Called when a PDU has been completely transmitted and the TX state
872 * machine is about to enter the idle state. iscsi::tx_bhs will be
873 * valid for the just-completed PDU when this is called.
875 static void iscsi_tx_done ( struct iscsi_session *iscsi ) {
876 struct iscsi_bhs_common *common = &iscsi->tx_bhs.common;
878 switch ( common->opcode & ISCSI_OPCODE_MASK ) {
879 case ISCSI_OPCODE_DATA_OUT:
880 iscsi_data_out_done ( iscsi );
881 case ISCSI_OPCODE_LOGIN_REQUEST:
882 iscsi_login_request_done ( iscsi );
892 * @v iscsi iSCSI session
894 * Updates iscsi->tx_offset and, if applicable, transitions to the
897 static void iscsi_acked ( struct tcp_application *app, size_t len ) {
898 struct iscsi_session *iscsi = tcp_to_iscsi ( app );
899 struct iscsi_bhs_common *common = &iscsi->tx_bhs.common;
900 enum iscsi_tx_state next_state;
902 iscsi->tx_offset += len;
904 switch ( iscsi->tx_state ) {
906 iscsi->tx_len = sizeof ( iscsi->tx_bhs );
907 next_state = ISCSI_TX_AHS;
910 iscsi->tx_len = 4 * ISCSI_AHS_LEN ( common->lengths );
911 next_state = ISCSI_TX_DATA;
914 iscsi->tx_len = ISCSI_DATA_LEN ( common->lengths );
915 next_state = ISCSI_TX_DATA_PADDING;
917 case ISCSI_TX_DATA_PADDING:
918 iscsi->tx_len = ISCSI_DATA_PAD_LEN ( common->lengths );
919 next_state = ISCSI_TX_IDLE;
927 assert ( iscsi->tx_offset <= iscsi->tx_len );
929 /* If the whole of the current portion has not yet
930 * been acked, stay in this state for now.
932 if ( iscsi->tx_offset != iscsi->tx_len )
935 /* Move to next state. Call iscsi_tx_done() when PDU
936 * transmission is complete.
938 iscsi->tx_state = next_state;
939 iscsi->tx_offset = 0;
940 if ( next_state == ISCSI_TX_IDLE )
941 iscsi_tx_done ( iscsi );
948 * @v iscsi iSCSI session
949 * @v buf Temporary data buffer
950 * @v len Length of temporary data buffer
952 * Constructs data to be sent for the current TX state
954 static void iscsi_senddata ( struct tcp_application *app,
955 void *buf, size_t len ) {
956 struct iscsi_session *iscsi = tcp_to_iscsi ( app );
957 struct iscsi_bhs_common *common = &iscsi->tx_bhs.common;
958 static const char pad[] = { '\0', '\0', '\0' };
960 switch ( iscsi->tx_state ) {
962 /* Nothing to send */
965 tcp_send ( app, &iscsi->tx_bhs.bytes[iscsi->tx_offset],
966 ( sizeof ( iscsi->tx_bhs ) - iscsi->tx_offset ) );
969 /* We don't yet have an AHS transmission mechanism */
973 iscsi_tx_data ( iscsi, buf, len );
975 case ISCSI_TX_DATA_PADDING:
976 tcp_send ( app, pad, ( ISCSI_DATA_PAD_LEN ( common->lengths )
977 - iscsi->tx_offset ) );
986 * Receive data segment of an iSCSI PDU
988 * @v iscsi iSCSI session
989 * @v data Received data
990 * @v len Length of received data
991 * @v remaining Data remaining after this data
993 * Handle processing of part of a PDU data segment. iscsi::rx_bhs
994 * will be valid when this is called.
996 static void iscsi_rx_data ( struct iscsi_session *iscsi, void *data,
997 size_t len, size_t remaining ) {
998 struct iscsi_bhs_common_response *response
999 = &iscsi->rx_bhs.common_response;
1001 /* Update cmdsn and statsn */
1002 iscsi->cmdsn = ntohl ( response->expcmdsn );
1003 iscsi->statsn = ntohl ( response->statsn );
1005 switch ( response->opcode & ISCSI_OPCODE_MASK ) {
1006 case ISCSI_OPCODE_LOGIN_RESPONSE:
1007 iscsi_rx_login_response ( iscsi, data, len, remaining );
1009 case ISCSI_OPCODE_SCSI_RESPONSE:
1010 iscsi_rx_scsi_response ( iscsi, data, len, remaining );
1012 case ISCSI_OPCODE_DATA_IN:
1013 iscsi_rx_data_in ( iscsi, data, len, remaining );
1015 case ISCSI_OPCODE_R2T:
1016 iscsi_rx_r2t ( iscsi, data, len, remaining );
1021 DBG ( "Unknown iSCSI opcode %02x\n", response->opcode );
1022 iscsi_close ( iscsi );
1023 iscsi_done ( iscsi, -EOPNOTSUPP );
1029 * Discard portion of an iSCSI PDU.
1031 * @v iscsi iSCSI session
1032 * @v data Received data
1033 * @v len Length of received data
1034 * @v remaining Data remaining after this data
1036 * This discards data from a portion of a received PDU.
1038 static void iscsi_rx_discard ( struct iscsi_session *iscsi __unused,
1039 void *data __unused, size_t len __unused,
1040 size_t remaining __unused ) {
1045 * Receive basic header segment of an iSCSI PDU
1047 * @v iscsi iSCSI session
1048 * @v data Received data
1049 * @v len Length of received data
1050 * @v remaining Data remaining after this data
1052 * This fills in iscsi::rx_bhs with the data from the BHS portion of
1055 static void iscsi_rx_bhs ( struct iscsi_session *iscsi, void *data,
1056 size_t len, size_t remaining __unused ) {
1057 memcpy ( &iscsi->rx_bhs.bytes[iscsi->rx_offset], data, len );
1058 if ( ( iscsi->rx_offset + len ) >= sizeof ( iscsi->rx_bhs ) ) {
1059 DBG ( "iSCSI %p received PDU opcode %#x len %#lx\n",
1060 iscsi, iscsi->rx_bhs.common.opcode,
1061 ISCSI_DATA_LEN ( iscsi->rx_bhs.common.lengths ) );
1068 * @v tcp TCP application
1069 * @v data Received data
1070 * @v len Length of received data
1072 * This handles received PDUs. The receive strategy is to fill in
1073 * iscsi::rx_bhs with the contents of the BHS portion of the PDU,
1074 * throw away any AHS portion, and then process each part of the data
1075 * portion as it arrives. The data processing routine therefore
1076 * always has a full copy of the BHS available, even for portions of
1077 * the data in different packets to the BHS.
1079 static void iscsi_newdata ( struct tcp_application *app, void *data,
1081 struct iscsi_session *iscsi = tcp_to_iscsi ( app );
1082 struct iscsi_bhs_common *common = &iscsi->rx_bhs.common;
1083 void ( *process ) ( struct iscsi_session *iscsi, void *data,
1084 size_t len, size_t remaining );
1085 enum iscsi_rx_state next_state;
1090 switch ( iscsi->rx_state ) {
1092 process = iscsi_rx_bhs;
1093 iscsi->rx_len = sizeof ( iscsi->rx_bhs );
1094 next_state = ISCSI_RX_AHS;
1097 process = iscsi_rx_discard;
1098 iscsi->rx_len = 4 * ISCSI_AHS_LEN ( common->lengths );
1099 next_state = ISCSI_RX_DATA;
1102 process = iscsi_rx_data;
1103 iscsi->rx_len = ISCSI_DATA_LEN ( common->lengths );
1104 next_state = ISCSI_RX_DATA_PADDING;
1106 case ISCSI_RX_DATA_PADDING:
1107 process = iscsi_rx_discard;
1108 iscsi->rx_len = ISCSI_DATA_PAD_LEN ( common->lengths );
1109 next_state = ISCSI_RX_BHS;
1116 frag_len = iscsi->rx_len - iscsi->rx_offset;
1117 if ( frag_len > len )
1119 remaining = iscsi->rx_len - iscsi->rx_offset - frag_len;
1120 process ( iscsi, data, frag_len, remaining );
1122 iscsi->rx_offset += frag_len;
1126 /* If all the data for this state has not yet been
1127 * received, stay in this state for now.
1129 if ( iscsi->rx_offset != iscsi->rx_len )
1132 iscsi->rx_state = next_state;
1133 iscsi->rx_offset = 0;
1138 * Handle TCP connection closure
1140 * @v app TCP application
1141 * @v status Error code, if any
1144 static void iscsi_closed ( struct tcp_application *app, int status ) {
1145 struct iscsi_session *iscsi = tcp_to_iscsi ( app );
1148 /* Even a graceful close counts as an error for iSCSI */
1150 status = -ECONNRESET;
1152 /* Close session cleanly */
1153 iscsi_close ( iscsi );
1155 /* Retry connection if within the retry limit, otherwise fail */
1156 if ( ++iscsi->retry_count <= ISCSI_MAX_RETRIES ) {
1157 DBG ( "iSCSI %p retrying connection (retry #%d)\n",
1158 iscsi, iscsi->retry_count );
1159 if ( ( rc = tcp_connect ( app, &iscsi->target, 0 ) ) != 0 ) {
1160 DBG ( "iSCSI %p could not open TCP connection\n",
1162 iscsi_done ( iscsi, rc );
1165 DBG ( "iSCSI %p retry count exceeded\n", iscsi );
1166 iscsi->instant_rc = status;
1167 iscsi_done ( iscsi, status );
1172 * Handle TCP connection opening
1174 * @v app TCP application
1177 static void iscsi_connected ( struct tcp_application *app ) {
1178 struct iscsi_session *iscsi = tcp_to_iscsi ( app );
1180 assert ( iscsi->rx_state == ISCSI_RX_BHS );
1181 assert ( iscsi->rx_offset == 0 );
1183 /* Enter security negotiation phase */
1184 iscsi->status = ( ISCSI_STATUS_SECURITY_NEGOTIATION_PHASE |
1185 ISCSI_STATUS_STRINGS_SECURITY );
1187 /* Assign fresh initiator task tag */
1190 /* Start logging in */
1191 iscsi_start_login ( iscsi );
1194 /** iSCSI TCP operations */
1195 static struct tcp_operations iscsi_tcp_operations = {
1196 .closed = iscsi_closed,
1197 .connected = iscsi_connected,
1198 .acked = iscsi_acked,
1199 .newdata = iscsi_newdata,
1200 .senddata = iscsi_senddata,
1204 * Issue SCSI command via iSCSI session
1206 * @v iscsi iSCSI session
1207 * @v command SCSI command
1208 * @ret aop Asynchronous operation for this SCSI command
1210 struct async_operation * iscsi_issue ( struct iscsi_session *iscsi,
1211 struct scsi_command *command ) {
1214 assert ( iscsi->command == NULL );
1215 iscsi->command = command;
1217 if ( iscsi->instant_rc ) {
1218 /* Abort immediately rather than retrying */
1219 iscsi_done ( iscsi, iscsi->instant_rc );
1220 } else if ( iscsi->status ) {
1221 /* Session already open: issue command */
1222 iscsi_start_command ( iscsi );
1223 tcp_senddata ( &iscsi->tcp );
1225 /* Session not open: initiate login */
1226 iscsi->tcp.tcp_op = &iscsi_tcp_operations;
1227 if ( ( rc = tcp_connect ( &iscsi->tcp, &iscsi->target,
1229 DBG ( "iSCSI %p could not open TCP connection\n",
1231 iscsi_done ( iscsi, rc );
1239 * Close down iSCSI session
1241 * @v iscsi iSCSI session
1242 * @ret aop Asynchronous operation
1244 void iscsi_shutdown ( struct iscsi_session *iscsi ) {
1245 iscsi_close ( iscsi );