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.
25 #include <gpxe/scsi.h>
26 #include <gpxe/process.h>
27 #include <gpxe/iscsi.h>
35 static void iscsi_start_tx ( struct iscsi_session *iscsi );
36 static void iscsi_start_data_out ( struct iscsi_session *iscsi,
37 unsigned int datasn );
39 /****************************************************************************
41 * iSCSI SCSI command issuing
46 * Build iSCSI SCSI command BHS
48 * @v iscsi iSCSI session
50 * We don't currently support bidirectional commands (i.e. with both
51 * Data-In and Data-Out segments); these would require providing code
52 * to generate an AHS, and there doesn't seem to be any need for it at
55 static void iscsi_start_command ( struct iscsi_session *iscsi ) {
56 struct iscsi_bhs_scsi_command *command = &iscsi->tx_bhs.scsi_command;
58 assert ( ! ( iscsi->command->data_in && iscsi->command->data_out ) );
60 /* Construct BHS and initiate transmission */
61 iscsi_start_tx ( iscsi );
62 command->opcode = ISCSI_OPCODE_SCSI_COMMAND;
63 command->flags = ( ISCSI_FLAG_FINAL |
64 ISCSI_COMMAND_ATTR_SIMPLE );
65 if ( iscsi->command->data_in )
66 command->flags |= ISCSI_COMMAND_FLAG_READ;
67 if ( iscsi->command->data_out )
68 command->flags |= ISCSI_COMMAND_FLAG_WRITE;
69 /* lengths left as zero */
70 command->lun = iscsi->lun;
71 command->itt = htonl ( ++iscsi->itt );
72 command->exp_len = htonl ( iscsi->command->data_in_len |
73 iscsi->command->data_out_len );
74 command->cmdsn = htonl ( iscsi->cmdsn );
75 command->expstatsn = htonl ( iscsi->statsn + 1 );
76 memcpy ( &command->cdb, &iscsi->command->cdb, sizeof ( command->cdb ));
80 * Receive data segment of an iSCSI SCSI response PDU
82 * @v iscsi iSCSI session
83 * @v data Received data
84 * @v len Length of received data
85 * @v remaining Data remaining after this data
88 static void iscsi_rx_scsi_response ( struct iscsi_session *iscsi, void *data,
89 size_t len, size_t remaining ) {
90 struct iscsi_bhs_scsi_response *response
91 = &iscsi->rx_bhs.scsi_response;
94 /* Capture the sense response code as it floats past, if present */
95 sense_offset = ISCSI_SENSE_RESPONSE_CODE_OFFSET - iscsi->rx_offset;
96 if ( ( sense_offset >= 0 ) && len ) {
97 iscsi->command->sense_response =
98 * ( ( char * ) data + sense_offset );
101 /* Wait for whole SCSI response to arrive */
105 /* Record SCSI status code */
106 iscsi->command->status = response->status;
108 /* Mark as completed, with error if applicable */
109 iscsi->status |= ISCSI_STATUS_DONE;
110 if ( response->response != ISCSI_RESPONSE_COMMAND_COMPLETE )
111 iscsi->status |= ISCSI_STATUS_ERR;
115 * Receive data segment of an iSCSI data-in PDU
117 * @v iscsi iSCSI session
118 * @v data Received data
119 * @v len Length of received data
120 * @v remaining Data remaining after this data
123 static void iscsi_rx_data_in ( struct iscsi_session *iscsi, void *data,
124 size_t len, size_t remaining __unused ) {
125 struct iscsi_bhs_data_in *data_in = &iscsi->rx_bhs.data_in;
126 unsigned long offset;
128 /* Copy data to data-in buffer */
129 offset = ntohl ( data_in->offset ) + iscsi->rx_offset;
130 assert ( iscsi->command != NULL );
131 assert ( iscsi->command->data_in != NULL );
132 assert ( ( offset + len ) <= iscsi->command->data_in_len );
133 memcpy ( ( iscsi->command->data_in + offset ), data, len );
135 /* Record SCSI status, if present */
136 if ( data_in->flags & ISCSI_DATA_FLAG_STATUS )
137 iscsi->command->status = data_in->status;
139 /* If this is the end, flag as complete */
140 if ( ( offset + len ) == iscsi->command->data_in_len ) {
141 assert ( data_in->flags & ISCSI_FLAG_FINAL );
142 assert ( remaining == 0 );
143 iscsi->status |= ISCSI_STATUS_DONE;
148 * Receive data segment of an iSCSI R2T PDU
150 * @v iscsi iSCSI session
151 * @v data Received data
152 * @v len Length of received data
153 * @v remaining Data remaining after this data
156 static void iscsi_rx_r2t ( struct iscsi_session *iscsi, void *data __unused,
157 size_t len __unused, size_t remaining __unused ) {
158 struct iscsi_bhs_r2t *r2t = &iscsi->rx_bhs.r2t;
160 /* Record transfer parameters and trigger first data-out */
161 iscsi->ttt = ntohl ( r2t->ttt );
162 iscsi->transfer_offset = ntohl ( r2t->offset );
163 iscsi->transfer_len = ntohl ( r2t->len );
164 iscsi_start_data_out ( iscsi, 0 );
168 * Build iSCSI data-out BHS
170 * @v iscsi iSCSI session
171 * @v datasn Data sequence number within the transfer
174 static void iscsi_start_data_out ( struct iscsi_session *iscsi,
175 unsigned int datasn ) {
176 struct iscsi_bhs_data_out *data_out = &iscsi->tx_bhs.data_out;
177 unsigned long offset;
178 unsigned long remaining;
181 /* We always send 512-byte Data-Out PDUs; this removes the
182 * need to worry about the target's MaxRecvDataSegmentLength.
184 offset = datasn * 512;
185 remaining = iscsi->transfer_len - offset;
190 /* Construct BHS and initiate transmission */
191 iscsi_start_tx ( iscsi );
192 data_out->opcode = ISCSI_OPCODE_DATA_OUT;
193 if ( len == remaining )
194 data_out->flags = ( ISCSI_FLAG_FINAL );
195 ISCSI_SET_LENGTHS ( data_out->lengths, 0, len );
196 data_out->lun = iscsi->lun;
197 data_out->itt = htonl ( iscsi->itt );
198 data_out->ttt = htonl ( iscsi->ttt );
199 data_out->expstatsn = htonl ( iscsi->statsn + 1 );
200 data_out->datasn = htonl ( datasn );
201 data_out->offset = htonl ( iscsi->transfer_offset + offset );
205 * Complete iSCSI data-out PDU transmission
207 * @v iscsi iSCSI session
210 static void iscsi_data_out_done ( struct iscsi_session *iscsi ) {
211 struct iscsi_bhs_data_out *data_out = &iscsi->tx_bhs.data_out;
213 /* If we haven't reached the end of the sequence, start
214 * sending the next data-out PDU.
216 if ( ! ( data_out->flags & ISCSI_FLAG_FINAL ) )
217 iscsi_start_data_out ( iscsi, ntohl ( data_out->datasn ) + 1 );
221 * Send iSCSI data-out data segment
223 * @v iscsi iSCSI session
225 static void iscsi_tx_data_out ( struct iscsi_session *iscsi ) {
226 struct iscsi_bhs_data_out *data_out = &iscsi->tx_bhs.data_out;
227 unsigned long offset;
230 offset = ( iscsi->transfer_offset + ntohl ( data_out->offset ) +
232 len = ( ISCSI_DATA_LEN ( data_out->lengths ) - iscsi->tx_offset );
233 assert ( iscsi->command != NULL );
234 assert ( iscsi->command->data_out != NULL );
235 assert ( ( offset + len ) <= iscsi->command->data_out_len );
237 tcp_send ( &iscsi->tcp, iscsi->command->data_out + offset, len );
240 /****************************************************************************
247 * Build iSCSI login request strings
249 * @v iscsi iSCSI session
251 * These are the initial set of strings sent in the first login
252 * request PDU. We want the following settings:
256 * MaxConnections is irrelevant; we make only one connection anyway
257 * InitialR2T=Yes (default) [1]
258 * ImmediateData is irrelevant; we never send immediate data
259 * MaxRecvDataSegmentLength=8192 (default)
260 * MaxBurstLength=262144 (default)
261 * FirstBurstLength=262144 (default)
262 * DefaultTime2Wait=0 [2]
263 * DefaultTime2Retain=0 [2]
264 * MaxOutstandingR2T=1 (default)
265 * DataPDUInOrder=Yes (default)
266 * DataSequenceInOrder=Yes (default)
267 * ErrorRecoveryLevel=0 (default)
269 * [1] InitialR2T has an OR resolution function, so the target may
270 * force us to use it. We therefore simplify our logic by always
273 * [2] These ensure that we can safely start a new task once we have
274 * reconnected after a failure, without having to manually tidy up
277 static int iscsi_build_login_request_strings ( struct iscsi_session *iscsi,
278 void *data, size_t len ) {
279 return snprintf ( data, len,
282 "SessionType=Normal%c"
284 "HeaderDigest=None%c"
285 "DefaultTime2Wait=0%c"
286 "DefaultTime2Retain=0%c",
287 iscsi->initiator, 0, iscsi->target, 0,
292 * Build iSCSI login request BHS
294 * @v iscsi iSCSI session
295 * @v first Login request is the first in a sequence
297 static void iscsi_start_login ( struct iscsi_session *iscsi, int first ) {
298 struct iscsi_bhs_login_request *request = &iscsi->tx_bhs.login_request;
301 /* Construct BHS and initiate transmission */
302 iscsi_start_tx ( iscsi );
303 request->opcode = ( ISCSI_OPCODE_LOGIN_REQUEST |
304 ISCSI_FLAG_IMMEDIATE );
305 request->flags = ( ISCSI_LOGIN_FLAG_TRANSITION |
306 ISCSI_LOGIN_CSG_OPERATIONAL_NEGOTIATION |
307 ISCSI_LOGIN_NSG_FULL_FEATURE_PHASE );
308 /* version_max and version_min left as zero */
310 len = iscsi_build_login_request_strings ( iscsi, NULL, 0 );
311 ISCSI_SET_LENGTHS ( request->lengths, 0, len );
313 request->isid_iana_en = htonl ( ISCSI_ISID_IANA |
314 IANA_EN_FEN_SYSTEMS );
315 /* isid_iana_qual left as zero */
316 request->tsih = htons ( iscsi->tsih );
319 request->itt = htonl ( iscsi->itt );
320 /* cid left as zero */
321 request->cmdsn = htonl ( iscsi->cmdsn );
322 request->expstatsn = htonl ( iscsi->statsn + 1 );
326 * Transmit data segment of an iSCSI login request PDU
328 * @v iscsi iSCSI session
330 * For login requests, the data segment consists of the login strings.
332 static void iscsi_tx_login_request ( struct iscsi_session *iscsi ) {
335 len = iscsi_build_login_request_strings ( iscsi, tcp_buffer,
337 tcp_send ( &iscsi->tcp, tcp_buffer + iscsi->tx_offset,
338 len - iscsi->tx_offset );
342 * Receive data segment of an iSCSI login response PDU
344 * @v iscsi iSCSI session
345 * @v data Received data
346 * @v len Length of received data
347 * @v remaining Data remaining after this data
350 static void iscsi_rx_login_response ( struct iscsi_session *iscsi,
353 size_t remaining __unused ) {
354 struct iscsi_bhs_login_response *response
355 = &iscsi->rx_bhs.login_response;
357 /* Check for fatal errors */
358 if ( response->status_class != 0 ) {
359 printf ( "iSCSI login failure: class %02x detail %02x\n",
360 response->status_class, response->status_detail );
361 iscsi->status |= ( ISCSI_STATUS_DONE | ISCSI_STATUS_ERR );
362 tcp_close ( &iscsi->tcp );
366 /* If server did not transition, send back another login
367 * request without any login strings.
369 if ( ! ( response->flags & ISCSI_LOGIN_FLAG_TRANSITION ) ) {
370 iscsi_start_login ( iscsi, 0 );
374 /* Record TSIH for future reference */
375 iscsi->tsih = ntohl ( response->tsih );
377 /* Send the SCSI command */
378 iscsi_start_command ( iscsi );
381 /****************************************************************************
383 * iSCSI to TCP interface
387 static inline struct iscsi_session *
388 tcp_to_iscsi ( struct tcp_connection *conn ) {
389 return container_of ( conn, struct iscsi_session, tcp );
393 * Start up a new TX PDU
395 * @v iscsi iSCSI session
397 * This initiates the process of sending a new PDU. Only one PDU may
398 * be in transit at any one time.
400 static void iscsi_start_tx ( struct iscsi_session *iscsi ) {
401 assert ( iscsi->tx_state == ISCSI_TX_IDLE );
403 /* Initialise TX BHS */
404 memset ( &iscsi->tx_bhs, 0, sizeof ( iscsi->tx_bhs ) );
406 /* Flag TX engine to start transmitting */
407 iscsi->tx_state = ISCSI_TX_BHS;
408 iscsi->tx_offset = 0;
412 * Transmit data segment of an iSCSI PDU
414 * @v iscsi iSCSI session
416 * Handle transmission of part of a PDU data segment. iscsi::tx_bhs
417 * will be valid when this is called.
419 static void iscsi_tx_data ( struct iscsi_session *iscsi ) {
420 struct iscsi_bhs_common *common = &iscsi->tx_bhs.common;
422 switch ( common->opcode & ISCSI_OPCODE_MASK ) {
423 case ISCSI_OPCODE_DATA_OUT:
424 iscsi_tx_data_out ( iscsi );
426 case ISCSI_OPCODE_LOGIN_REQUEST:
427 iscsi_tx_login_request ( iscsi );
436 * Complete iSCSI PDU transmission
438 * @v iscsi iSCSI session
440 * Called when a PDU has been completely transmitted and the TX state
441 * machine is about to enter the idle state. iscsi::tx_bhs will be
442 * valid for the just-completed PDU when this is called.
444 static void iscsi_tx_done ( struct iscsi_session *iscsi ) {
445 struct iscsi_bhs_common *common = &iscsi->tx_bhs.common;
447 switch ( common->opcode & ISCSI_OPCODE_MASK ) {
448 case ISCSI_OPCODE_DATA_OUT:
449 iscsi_data_out_done ( iscsi );
459 * @v iscsi iSCSI session
461 * Updates iscsi->tx_offset and, if applicable, transitions to the
464 static void iscsi_acked ( struct tcp_connection *conn, size_t len ) {
465 struct iscsi_session *iscsi = tcp_to_iscsi ( conn );
466 struct iscsi_bhs_common *common = &iscsi->tx_bhs.common;
467 size_t max_tx_offset;
468 enum iscsi_tx_state next_state;
470 iscsi->tx_offset += len;
472 switch ( iscsi->tx_state ) {
474 max_tx_offset = sizeof ( iscsi->tx_bhs );
475 next_state = ISCSI_TX_AHS;
478 max_tx_offset = 4 * ISCSI_AHS_LEN ( common->lengths );
479 next_state = ISCSI_TX_DATA;
482 max_tx_offset = ISCSI_DATA_LEN ( common->lengths );
483 next_state = ISCSI_TX_DATA_PADDING;
485 case ISCSI_TX_DATA_PADDING:
486 max_tx_offset = ISCSI_DATA_PAD_LEN ( common->lengths );
487 next_state = ISCSI_TX_IDLE;
495 assert ( iscsi->tx_offset <= max_tx_offset );
497 /* If the whole of the current portion has not yet
498 * been acked, stay in this state for now.
500 if ( iscsi->tx_offset != max_tx_offset )
503 /* Move to next state. Call iscsi_tx_done() when PDU
504 * transmission is complete.
506 iscsi->tx_state = next_state;
507 iscsi->tx_offset = 0;
508 if ( next_state == ISCSI_TX_IDLE )
509 iscsi_tx_done ( iscsi );
516 * @v iscsi iSCSI session
518 * Constructs data to be sent for the current TX state
520 static void iscsi_senddata ( struct tcp_connection *conn ) {
521 struct iscsi_session *iscsi = tcp_to_iscsi ( conn );
522 struct iscsi_bhs_common *common = &iscsi->tx_bhs.common;
523 static const char pad[] = { '\0', '\0', '\0' };
525 switch ( iscsi->tx_state ) {
527 /* Nothing to send */
530 tcp_send ( conn, &iscsi->tx_bhs.bytes[iscsi->tx_offset],
531 ( sizeof ( iscsi->tx_bhs ) - iscsi->tx_offset ) );
534 /* We don't yet have an AHS transmission mechanism */
538 iscsi_tx_data ( iscsi );
540 case ISCSI_TX_DATA_PADDING:
541 tcp_send ( conn, pad, ( ISCSI_DATA_PAD_LEN ( common->lengths )
542 - iscsi->tx_offset ) );
551 * Receive data segment of an iSCSI PDU
553 * @v iscsi iSCSI session
554 * @v data Received data
555 * @v len Length of received data
556 * @v remaining Data remaining after this data
558 * Handle processing of part of a PDU data segment. iscsi::rx_bhs
559 * will be valid when this is called.
561 static void iscsi_rx_data ( struct iscsi_session *iscsi, void *data,
562 size_t len, size_t remaining ) {
563 struct iscsi_bhs_common_response *response
564 = &iscsi->rx_bhs.common_response;
566 /* Update cmdsn and statsn */
567 iscsi->cmdsn = ntohl ( response->expcmdsn );
568 iscsi->statsn = ntohl ( response->statsn );
570 switch ( response->opcode & ISCSI_OPCODE_MASK ) {
571 case ISCSI_OPCODE_LOGIN_RESPONSE:
572 iscsi_rx_login_response ( iscsi, data, len, remaining );
574 case ISCSI_OPCODE_SCSI_RESPONSE:
575 iscsi_rx_scsi_response ( iscsi, data, len, remaining );
577 case ISCSI_OPCODE_DATA_IN:
578 iscsi_rx_data_in ( iscsi, data, len, remaining );
580 case ISCSI_OPCODE_R2T:
581 iscsi_rx_r2t ( iscsi, data, len, remaining );
584 printf ( "Unknown iSCSI opcode %02x\n", response->opcode );
585 iscsi->status |= ( ISCSI_STATUS_DONE | ISCSI_STATUS_ERR );
591 * Discard portion of an iSCSI PDU.
593 * @v iscsi iSCSI session
594 * @v data Received data
595 * @v len Length of received data
596 * @v remaining Data remaining after this data
598 * This discards data from a portion of a received PDU.
600 static void iscsi_rx_discard ( struct iscsi_session *iscsi __unused,
601 void *data __unused, size_t len __unused,
602 size_t remaining __unused ) {
607 * Receive basic header segment of an iSCSI PDU
609 * @v iscsi iSCSI session
610 * @v data Received data
611 * @v len Length of received data
612 * @v remaining Data remaining after this data
614 * This fills in iscsi::rx_bhs with the data from the BHS portion of
617 static void iscsi_rx_bhs ( struct iscsi_session *iscsi, void *data,
618 size_t len, size_t remaining __unused ) {
619 memcpy ( &iscsi->rx_bhs.bytes[iscsi->rx_offset], data, len );
625 * @v tcp TCP connection
626 * @v data Received data
627 * @v len Length of received data
629 * This handles received PDUs. The receive strategy is to fill in
630 * iscsi::rx_bhs with the contents of the BHS portion of the PDU,
631 * throw away any AHS portion, and then process each part of the data
632 * portion as it arrives. The data processing routine therefore
633 * always has a full copy of the BHS available, even for portions of
634 * the data in different packets to the BHS.
636 static void iscsi_newdata ( struct tcp_connection *conn, void *data,
638 struct iscsi_session *iscsi = tcp_to_iscsi ( conn );
639 struct iscsi_bhs_common *common = &iscsi->rx_bhs.common;
640 void ( *process ) ( struct iscsi_session *iscsi, void *data,
641 size_t len, size_t remaining );
642 size_t max_rx_offset;
643 enum iscsi_rx_state next_state;
648 switch ( iscsi->rx_state ) {
650 process = iscsi_rx_bhs;
651 max_rx_offset = sizeof ( iscsi->rx_bhs );
652 next_state = ISCSI_RX_AHS;
655 process = iscsi_rx_discard;
656 max_rx_offset = 4 * ISCSI_AHS_LEN ( common->lengths );
657 next_state = ISCSI_RX_DATA;
660 process = iscsi_rx_data;
661 max_rx_offset = ISCSI_DATA_LEN ( common->lengths );
662 next_state = ISCSI_RX_DATA_PADDING;
664 case ISCSI_RX_DATA_PADDING:
665 process = iscsi_rx_discard;
666 max_rx_offset = ISCSI_DATA_PAD_LEN ( common->lengths );
667 next_state = ISCSI_RX_BHS;
674 frag_len = max_rx_offset - iscsi->rx_offset;
675 if ( frag_len > len )
677 remaining = max_rx_offset - iscsi->rx_offset - frag_len;
678 process ( iscsi, data, frag_len, remaining );
680 iscsi->rx_offset += frag_len;
684 /* If all the data for this state has not yet been
685 * received, stay in this state for now.
687 if ( iscsi->rx_offset != max_rx_offset )
690 iscsi->rx_state = next_state;
691 iscsi->rx_offset = 0;
696 * Handle TCP connection closure
698 * @v conn TCP connection
699 * @v status Error code, if any
702 static void iscsi_closed ( struct tcp_connection *conn, int status __unused ) {
703 struct iscsi_session *iscsi = tcp_to_iscsi ( conn );
705 /* Clear connected flag */
706 iscsi->status &= ~ISCSI_STATUS_CONNECTED;
708 /* Retry connection if within the retry limit, otherwise fail */
709 if ( ++iscsi->retry_count <= ISCSI_MAX_RETRIES ) {
710 tcp_connect ( conn );
712 printf ( "iSCSI retry count exceeded\n" );
713 iscsi->status |= ( ISCSI_STATUS_DONE | ISCSI_STATUS_ERR );
718 * Handle TCP connection opening
720 * @v conn TCP connection
723 static void iscsi_connected ( struct tcp_connection *conn ) {
724 struct iscsi_session *iscsi = tcp_to_iscsi ( conn );
726 /* Set connected flag and reset retry count */
727 iscsi->status |= ISCSI_STATUS_CONNECTED;
728 iscsi->retry_count = 0;
730 /* Prepare to receive PDUs. */
731 iscsi->rx_state = ISCSI_RX_BHS;
732 iscsi->rx_offset = 0;
734 /* Start logging in */
735 iscsi_start_login ( iscsi, 1 );
738 /** iSCSI TCP operations */
739 static struct tcp_operations iscsi_tcp_operations = {
740 .closed = iscsi_closed,
741 .connected = iscsi_connected,
742 .acked = iscsi_acked,
743 .newdata = iscsi_newdata,
744 .senddata = iscsi_senddata,
748 * Issue SCSI command via iSCSI session
750 * @v iscsi iSCSI session
751 * @v command SCSI command
752 * @ret rc Return status code
754 int iscsi_issue ( struct iscsi_session *iscsi,
755 struct scsi_command *command ) {
756 iscsi->command = command;
757 iscsi->status &= ~( ISCSI_STATUS_DONE | ISCSI_STATUS_ERR );
759 if ( iscsi->status & ISCSI_STATUS_CONNECTED ) {
760 iscsi_start_command ( iscsi );
762 iscsi->tcp.tcp_op = &iscsi_tcp_operations;
763 tcp_connect ( &iscsi->tcp );
766 while ( ! ( iscsi->status & ISCSI_STATUS_DONE ) ) {
770 iscsi->command = NULL;
772 return ( ( iscsi->status & ISCSI_STATUS_ERR ) ? -EIO : 0 );