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 DBGC ( iscsi, "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 DBGC ( iscsi, "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 DBGC ( iscsi, "iSCSI %p received invalid TargetAddress "
529 "\"%s\"\n", iscsi, value );
533 DBGC ( iscsi, "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 DBGC ( iscsi, "iSCSI %p initiating CHAP authentication\n",
550 iscsi->status |= ISCSI_STATUS_STRINGS_CHAP_ALGORITHM;
555 * Handle iSCSI CHAP_A text value
557 * @v iscsi iSCSI session
558 * @v value CHAP_A value
560 static void iscsi_handle_chap_a_value ( struct iscsi_session *iscsi,
561 const char *value ) {
564 /* We only ever offer "5" (i.e. MD5) as an algorithm, so if
565 * the server responds with anything else it is a protocol
568 if ( strcmp ( value, "5" ) != 0 ) {
569 DBGC ( iscsi, "iSCSI %p got invalid CHAP algorithm \"%s\"\n",
573 /* Prepare for CHAP with MD5 */
574 if ( ( rc = chap_init ( &iscsi->chap, &md5_algorithm ) ) != 0 ) {
575 DBGC ( iscsi, "iSCSI %p could not initialise CHAP: %s\n",
576 iscsi, strerror ( rc ) );
577 iscsi_close ( iscsi );
578 iscsi_done ( iscsi, rc );
583 * Handle iSCSI CHAP_I text value
585 * @v iscsi iSCSI session
586 * @v value CHAP_I value
588 static void iscsi_handle_chap_i_value ( struct iscsi_session *iscsi,
589 const char *value ) {
590 unsigned int identifier;
593 /* The CHAP identifier is an integer value */
594 identifier = strtoul ( value, &endp, 0 );
595 if ( *endp != '\0' ) {
596 DBGC ( iscsi, "iSCSI %p saw invalid CHAP identifier \"%s\"\n",
600 /* Identifier and secret are the first two components of the
603 chap_set_identifier ( &iscsi->chap, identifier );
604 if ( iscsi->password ) {
605 chap_update ( &iscsi->chap, iscsi->password,
606 strlen ( iscsi->password ) );
611 * Handle iSCSI CHAP_C text value
613 * @v iscsi iSCSI session
614 * @v value CHAP_C value
616 static void iscsi_handle_chap_c_value ( struct iscsi_session *iscsi,
617 const char *value ) {
622 /* Check and strip leading "0x" */
623 if ( ( value[0] != '0' ) || ( value[1] != 'x' ) ) {
624 DBGC ( iscsi, "iSCSI %p saw invalid CHAP challenge \"%s\"\n",
629 /* Process challenge an octet at a time */
630 for ( ; ( value[0] && value[1] ) ; value += 2 ) {
631 memcpy ( buf, value, 2 );
633 byte = strtoul ( buf, &endp, 16 );
634 if ( *endp != '\0' ) {
635 DBGC ( iscsi, "iSCSI %p saw invalid CHAP challenge "
636 "byte \"%s\"\n", iscsi, buf );
638 chap_update ( &iscsi->chap, &byte, sizeof ( byte ) );
641 /* Build CHAP response */
642 DBGC ( iscsi, "iSCSI %p sending CHAP response\n", iscsi );
643 chap_respond ( &iscsi->chap );
644 iscsi->status |= ISCSI_STATUS_STRINGS_CHAP_RESPONSE;
647 /** An iSCSI text string that we want to handle */
648 struct iscsi_string_type {
651 * This is the portion up to and including the "=" sign,
652 * e.g. "InitiatorName=", "CHAP_A=", etc.
655 /** Handle iSCSI string value
657 * @v iscsi iSCSI session
658 * @v value iSCSI string value
660 void ( * handle_value ) ( struct iscsi_session *iscsi,
664 /** iSCSI text strings that we want to handle */
665 struct iscsi_string_type iscsi_string_types[] = {
666 { "TargetAddress=", iscsi_handle_targetaddress_value },
667 { "AuthMethod=", iscsi_handle_authmethod_value },
668 { "CHAP_A=", iscsi_handle_chap_a_value },
669 { "CHAP_I=", iscsi_handle_chap_i_value },
670 { "CHAP_C=", iscsi_handle_chap_c_value },
675 * Handle iSCSI string
677 * @v iscsi iSCSI session
678 * @v string iSCSI string (in "key=value" format)
680 static void iscsi_handle_string ( struct iscsi_session *iscsi,
681 const char *string ) {
682 struct iscsi_string_type *type;
685 for ( type = iscsi_string_types ; type->key ; type++ ) {
686 key_len = strlen ( type->key );
687 if ( strncmp ( string, type->key, key_len ) == 0 ) {
688 DBGC ( iscsi, "iSCSI %p handling %s\n",
690 type->handle_value ( iscsi, ( string + key_len ) );
694 DBGC ( iscsi, "iSCSI %p ignoring %s\n", iscsi, string );
698 * Handle iSCSI strings
700 * @v iscsi iSCSI session
701 * @v string iSCSI string buffer
702 * @v len Length of string buffer
704 static void iscsi_handle_strings ( struct iscsi_session *iscsi,
705 const char *strings, size_t len ) {
708 /* Handle each string in turn, taking care not to overrun the
709 * data buffer in case of badly-terminated data.
712 string_len = ( strnlen ( strings, len ) + 1 );
713 if ( string_len > len )
715 iscsi_handle_string ( iscsi, strings );
716 strings += string_len;
722 * Receive data segment of an iSCSI login response PDU
724 * @v iscsi iSCSI session
725 * @v data Received data
726 * @v len Length of received data
727 * @v remaining Data remaining after this data
730 static void iscsi_rx_login_response ( struct iscsi_session *iscsi, void *data,
731 size_t len, size_t remaining ) {
732 struct iscsi_bhs_login_response *response
733 = &iscsi->rx_bhs.login_response;
736 /* Buffer up the PDU data */
737 if ( ( rc = iscsi_rx_buffered_data ( iscsi, data, len ) ) != 0 ) {
738 DBGC ( iscsi, "iSCSI %p could not buffer login response: %s\n",
739 iscsi, strerror ( rc ) );
740 iscsi_close ( iscsi );
741 iscsi_done ( iscsi, rc );
747 /* Process string data and discard string buffer */
748 iscsi_handle_strings ( iscsi, iscsi->rx_buffer, iscsi->rx_len );
749 iscsi_rx_buffered_data_done ( iscsi );
751 /* Check for login redirection */
752 if ( response->status_class == ISCSI_STATUS_REDIRECT ) {
753 DBGC ( iscsi, "iSCSI %p redirecting to new server\n", iscsi );
754 iscsi_close ( iscsi );
755 if ( ( rc = tcp_connect ( &iscsi->tcp, &iscsi->target,
757 DBGC ( iscsi, "iSCSI %p could not open TCP "
758 "connection: %s\n", iscsi, strerror ( rc ) );
759 iscsi_done ( iscsi, rc );
764 /* Check for fatal errors */
765 if ( response->status_class != 0 ) {
766 DBGC ( iscsi, "iSCSI login failure: class %02x detail %02x\n",
767 response->status_class, response->status_detail );
768 iscsi->instant_rc = -EPERM;
769 iscsi_close ( iscsi );
770 iscsi_done ( iscsi, -EPERM );
774 /* Handle login transitions */
775 if ( response->flags & ISCSI_LOGIN_FLAG_TRANSITION ) {
776 switch ( response->flags & ISCSI_LOGIN_NSG_MASK ) {
777 case ISCSI_LOGIN_NSG_OPERATIONAL_NEGOTIATION:
779 ( ISCSI_STATUS_OPERATIONAL_NEGOTIATION_PHASE |
780 ISCSI_STATUS_STRINGS_OPERATIONAL );
782 case ISCSI_LOGIN_NSG_FULL_FEATURE_PHASE:
783 iscsi->status = ISCSI_STATUS_FULL_FEATURE_PHASE;
786 DBGC ( iscsi, "iSCSI %p got invalid response flags "
787 "%02x\n", iscsi, response->flags );
788 iscsi_close ( iscsi );
789 iscsi_done ( iscsi, -EIO );
794 /* Send next login request PDU if we haven't reached the full
797 if ( ( iscsi->status & ISCSI_STATUS_PHASE_MASK ) !=
798 ISCSI_STATUS_FULL_FEATURE_PHASE ) {
799 iscsi_start_login ( iscsi );
803 /* Reset retry count */
804 iscsi->retry_count = 0;
806 /* Record TSIH for future reference */
807 iscsi->tsih = ntohl ( response->tsih );
809 /* Send the actual SCSI command */
810 iscsi_start_command ( iscsi );
813 /****************************************************************************
815 * iSCSI to TCP interface
819 static inline struct iscsi_session *
820 tcp_to_iscsi ( struct tcp_application *app ) {
821 return container_of ( app, struct iscsi_session, tcp );
825 * Start up a new TX PDU
827 * @v iscsi iSCSI session
829 * This initiates the process of sending a new PDU. Only one PDU may
830 * be in transit at any one time.
832 static void iscsi_start_tx ( struct iscsi_session *iscsi ) {
833 assert ( iscsi->tx_state == ISCSI_TX_IDLE );
835 /* Initialise TX BHS */
836 memset ( &iscsi->tx_bhs, 0, sizeof ( iscsi->tx_bhs ) );
838 /* Flag TX engine to start transmitting */
839 iscsi->tx_state = ISCSI_TX_BHS;
840 iscsi->tx_offset = 0;
844 * Transmit data segment of an iSCSI PDU
846 * @v iscsi iSCSI session
847 * @v buf Temporary data buffer
848 * @v len Length of temporary data buffer
850 * Handle transmission of part of a PDU data segment. iscsi::tx_bhs
851 * will be valid when this is called.
853 static void iscsi_tx_data ( struct iscsi_session *iscsi,
854 void *buf, size_t len ) {
855 struct iscsi_bhs_common *common = &iscsi->tx_bhs.common;
857 switch ( common->opcode & ISCSI_OPCODE_MASK ) {
858 case ISCSI_OPCODE_DATA_OUT:
859 iscsi_tx_data_out ( iscsi, buf, len );
861 case ISCSI_OPCODE_LOGIN_REQUEST:
862 iscsi_tx_login_request ( iscsi, buf, len );
871 * Complete iSCSI PDU transmission
873 * @v iscsi iSCSI session
875 * Called when a PDU has been completely transmitted and the TX state
876 * machine is about to enter the idle state. iscsi::tx_bhs will be
877 * valid for the just-completed PDU when this is called.
879 static void iscsi_tx_done ( struct iscsi_session *iscsi ) {
880 struct iscsi_bhs_common *common = &iscsi->tx_bhs.common;
882 switch ( common->opcode & ISCSI_OPCODE_MASK ) {
883 case ISCSI_OPCODE_DATA_OUT:
884 iscsi_data_out_done ( iscsi );
885 case ISCSI_OPCODE_LOGIN_REQUEST:
886 iscsi_login_request_done ( iscsi );
896 * @v iscsi iSCSI session
898 * Updates iscsi->tx_offset and, if applicable, transitions to the
901 static void iscsi_acked ( struct tcp_application *app, size_t len ) {
902 struct iscsi_session *iscsi = tcp_to_iscsi ( app );
903 struct iscsi_bhs_common *common = &iscsi->tx_bhs.common;
904 enum iscsi_tx_state next_state;
906 iscsi->tx_offset += len;
908 switch ( iscsi->tx_state ) {
910 iscsi->tx_len = sizeof ( iscsi->tx_bhs );
911 next_state = ISCSI_TX_AHS;
914 iscsi->tx_len = 4 * ISCSI_AHS_LEN ( common->lengths );
915 next_state = ISCSI_TX_DATA;
918 iscsi->tx_len = ISCSI_DATA_LEN ( common->lengths );
919 next_state = ISCSI_TX_DATA_PADDING;
921 case ISCSI_TX_DATA_PADDING:
922 iscsi->tx_len = ISCSI_DATA_PAD_LEN ( common->lengths );
923 next_state = ISCSI_TX_IDLE;
931 assert ( iscsi->tx_offset <= iscsi->tx_len );
933 /* If the whole of the current portion has not yet
934 * been acked, stay in this state for now.
936 if ( iscsi->tx_offset != iscsi->tx_len )
939 /* Move to next state. Call iscsi_tx_done() when PDU
940 * transmission is complete.
942 iscsi->tx_state = next_state;
943 iscsi->tx_offset = 0;
944 if ( next_state == ISCSI_TX_IDLE )
945 iscsi_tx_done ( iscsi );
952 * @v iscsi iSCSI session
953 * @v buf Temporary data buffer
954 * @v len Length of temporary data buffer
956 * Constructs data to be sent for the current TX state
958 static void iscsi_senddata ( struct tcp_application *app,
959 void *buf, size_t len ) {
960 struct iscsi_session *iscsi = tcp_to_iscsi ( app );
961 struct iscsi_bhs_common *common = &iscsi->tx_bhs.common;
962 static const char pad[] = { '\0', '\0', '\0' };
964 switch ( iscsi->tx_state ) {
966 /* Nothing to send */
969 tcp_send ( app, &iscsi->tx_bhs.bytes[iscsi->tx_offset],
970 ( sizeof ( iscsi->tx_bhs ) - iscsi->tx_offset ) );
973 /* We don't yet have an AHS transmission mechanism */
977 iscsi_tx_data ( iscsi, buf, len );
979 case ISCSI_TX_DATA_PADDING:
980 tcp_send ( app, pad, ( ISCSI_DATA_PAD_LEN ( common->lengths )
981 - iscsi->tx_offset ) );
990 * Receive data segment of an iSCSI PDU
992 * @v iscsi iSCSI session
993 * @v data Received data
994 * @v len Length of received data
995 * @v remaining Data remaining after this data
997 * Handle processing of part of a PDU data segment. iscsi::rx_bhs
998 * will be valid when this is called.
1000 static void iscsi_rx_data ( struct iscsi_session *iscsi, void *data,
1001 size_t len, size_t remaining ) {
1002 struct iscsi_bhs_common_response *response
1003 = &iscsi->rx_bhs.common_response;
1005 /* Update cmdsn and statsn */
1006 iscsi->cmdsn = ntohl ( response->expcmdsn );
1007 iscsi->statsn = ntohl ( response->statsn );
1009 switch ( response->opcode & ISCSI_OPCODE_MASK ) {
1010 case ISCSI_OPCODE_LOGIN_RESPONSE:
1011 iscsi_rx_login_response ( iscsi, data, len, remaining );
1013 case ISCSI_OPCODE_SCSI_RESPONSE:
1014 iscsi_rx_scsi_response ( iscsi, data, len, remaining );
1016 case ISCSI_OPCODE_DATA_IN:
1017 iscsi_rx_data_in ( iscsi, data, len, remaining );
1019 case ISCSI_OPCODE_R2T:
1020 iscsi_rx_r2t ( iscsi, data, len, remaining );
1025 DBGC ( iscsi, "iSCSI %p unknown opcode %02x\n", iscsi,
1027 iscsi_close ( iscsi );
1028 iscsi_done ( iscsi, -EOPNOTSUPP );
1034 * Discard portion of an iSCSI PDU.
1036 * @v iscsi iSCSI session
1037 * @v data Received data
1038 * @v len Length of received data
1039 * @v remaining Data remaining after this data
1041 * This discards data from a portion of a received PDU.
1043 static void iscsi_rx_discard ( struct iscsi_session *iscsi __unused,
1044 void *data __unused, size_t len __unused,
1045 size_t remaining __unused ) {
1050 * Receive basic header segment of an iSCSI PDU
1052 * @v iscsi iSCSI session
1053 * @v data Received data
1054 * @v len Length of received data
1055 * @v remaining Data remaining after this data
1057 * This fills in iscsi::rx_bhs with the data from the BHS portion of
1060 static void iscsi_rx_bhs ( struct iscsi_session *iscsi, void *data,
1061 size_t len, size_t remaining __unused ) {
1062 memcpy ( &iscsi->rx_bhs.bytes[iscsi->rx_offset], data, len );
1063 if ( ( iscsi->rx_offset + len ) >= sizeof ( iscsi->rx_bhs ) ) {
1064 DBGC ( iscsi, "iSCSI %p received PDU opcode %#x len %#lx\n",
1065 iscsi, iscsi->rx_bhs.common.opcode,
1066 ISCSI_DATA_LEN ( iscsi->rx_bhs.common.lengths ) );
1073 * @v tcp TCP application
1074 * @v data Received data
1075 * @v len Length of received data
1077 * This handles received PDUs. The receive strategy is to fill in
1078 * iscsi::rx_bhs with the contents of the BHS portion of the PDU,
1079 * throw away any AHS portion, and then process each part of the data
1080 * portion as it arrives. The data processing routine therefore
1081 * always has a full copy of the BHS available, even for portions of
1082 * the data in different packets to the BHS.
1084 static void iscsi_newdata ( struct tcp_application *app, void *data,
1086 struct iscsi_session *iscsi = tcp_to_iscsi ( app );
1087 struct iscsi_bhs_common *common = &iscsi->rx_bhs.common;
1088 void ( *process ) ( struct iscsi_session *iscsi, void *data,
1089 size_t len, size_t remaining );
1090 enum iscsi_rx_state next_state;
1095 switch ( iscsi->rx_state ) {
1097 process = iscsi_rx_bhs;
1098 iscsi->rx_len = sizeof ( iscsi->rx_bhs );
1099 next_state = ISCSI_RX_AHS;
1102 process = iscsi_rx_discard;
1103 iscsi->rx_len = 4 * ISCSI_AHS_LEN ( common->lengths );
1104 next_state = ISCSI_RX_DATA;
1107 process = iscsi_rx_data;
1108 iscsi->rx_len = ISCSI_DATA_LEN ( common->lengths );
1109 next_state = ISCSI_RX_DATA_PADDING;
1111 case ISCSI_RX_DATA_PADDING:
1112 process = iscsi_rx_discard;
1113 iscsi->rx_len = ISCSI_DATA_PAD_LEN ( common->lengths );
1114 next_state = ISCSI_RX_BHS;
1121 frag_len = iscsi->rx_len - iscsi->rx_offset;
1122 if ( frag_len > len )
1124 remaining = iscsi->rx_len - iscsi->rx_offset - frag_len;
1125 process ( iscsi, data, frag_len, remaining );
1127 iscsi->rx_offset += frag_len;
1131 /* If all the data for this state has not yet been
1132 * received, stay in this state for now.
1134 if ( iscsi->rx_offset != iscsi->rx_len )
1137 iscsi->rx_state = next_state;
1138 iscsi->rx_offset = 0;
1143 * Handle TCP connection closure
1145 * @v app TCP application
1146 * @v status Error code, if any
1149 static void iscsi_closed ( struct tcp_application *app, int status ) {
1150 struct iscsi_session *iscsi = tcp_to_iscsi ( app );
1153 /* Even a graceful close counts as an error for iSCSI */
1155 status = -ECONNRESET;
1157 /* Close session cleanly */
1158 iscsi_close ( iscsi );
1160 /* Retry connection if within the retry limit, otherwise fail */
1161 if ( ++iscsi->retry_count <= ISCSI_MAX_RETRIES ) {
1162 DBGC ( iscsi, "iSCSI %p retrying connection (retry #%d)\n",
1163 iscsi, iscsi->retry_count );
1164 if ( ( rc = tcp_connect ( app, &iscsi->target, 0 ) ) != 0 ) {
1165 DBGC ( iscsi, "iSCSI %p could not open TCP "
1166 "connection: %s\n", iscsi, strerror ( rc ) );
1167 iscsi_done ( iscsi, rc );
1170 DBGC ( iscsi, "iSCSI %p retry count exceeded\n", iscsi );
1171 iscsi->instant_rc = status;
1172 iscsi_done ( iscsi, status );
1177 * Handle TCP connection opening
1179 * @v app TCP application
1182 static void iscsi_connected ( struct tcp_application *app ) {
1183 struct iscsi_session *iscsi = tcp_to_iscsi ( app );
1185 assert ( iscsi->rx_state == ISCSI_RX_BHS );
1186 assert ( iscsi->rx_offset == 0 );
1188 /* Enter security negotiation phase */
1189 iscsi->status = ( ISCSI_STATUS_SECURITY_NEGOTIATION_PHASE |
1190 ISCSI_STATUS_STRINGS_SECURITY );
1192 /* Assign fresh initiator task tag */
1195 /* Start logging in */
1196 iscsi_start_login ( iscsi );
1199 /** iSCSI TCP operations */
1200 static struct tcp_operations iscsi_tcp_operations = {
1201 .closed = iscsi_closed,
1202 .connected = iscsi_connected,
1203 .acked = iscsi_acked,
1204 .newdata = iscsi_newdata,
1205 .senddata = iscsi_senddata,
1209 * Issue SCSI command via iSCSI session
1211 * @v iscsi iSCSI session
1212 * @v command SCSI command
1213 * @ret aop Asynchronous operation for this SCSI command
1215 struct async_operation * iscsi_issue ( struct iscsi_session *iscsi,
1216 struct scsi_command *command ) {
1219 assert ( iscsi->command == NULL );
1220 iscsi->command = command;
1222 if ( iscsi->instant_rc ) {
1223 /* Abort immediately rather than retrying */
1224 iscsi_done ( iscsi, iscsi->instant_rc );
1225 } else if ( iscsi->status ) {
1226 /* Session already open: issue command */
1227 iscsi_start_command ( iscsi );
1228 tcp_senddata ( &iscsi->tcp );
1230 /* Session not open: initiate login */
1231 iscsi->tcp.tcp_op = &iscsi_tcp_operations;
1232 if ( ( rc = tcp_connect ( &iscsi->tcp, &iscsi->target,
1234 DBGC ( iscsi, "iSCSI %p could not open TCP "
1235 "connection: %s\n", iscsi, strerror ( rc ) );
1236 iscsi_done ( iscsi, rc );
1244 * Close down iSCSI session
1246 * @v iscsi iSCSI session
1247 * @ret aop Asynchronous operation
1249 void iscsi_shutdown ( struct iscsi_session *iscsi ) {
1250 iscsi_close ( iscsi );