|
@@ -78,6 +78,28 @@ static void iscsi_rx_buffered_data_done ( struct iscsi_session *iscsi ) {
|
78
|
78
|
iscsi->rx_buffer = NULL;
|
79
|
79
|
}
|
80
|
80
|
|
|
81
|
+/**
|
|
82
|
+ * Close iSCSI connection
|
|
83
|
+ *
|
|
84
|
+ * @v iscsi iSCSI session
|
|
85
|
+ */
|
|
86
|
+static void iscsi_close ( struct iscsi_session *iscsi ) {
|
|
87
|
+
|
|
88
|
+ /* Close TCP connection */
|
|
89
|
+ tcp_close ( &iscsi->tcp );
|
|
90
|
+
|
|
91
|
+ /* Clear connection status */
|
|
92
|
+ iscsi->status = 0;
|
|
93
|
+
|
|
94
|
+ /* Reset TX and RX state machines */
|
|
95
|
+ iscsi->tx_state = ISCSI_TX_IDLE;
|
|
96
|
+ iscsi->rx_state = ISCSI_RX_BHS;
|
|
97
|
+
|
|
98
|
+ /* Free any dynamically allocated memory */
|
|
99
|
+ chap_finish ( &iscsi->chap );
|
|
100
|
+ iscsi_rx_buffered_data_done ( iscsi );
|
|
101
|
+}
|
|
102
|
+
|
81
|
103
|
/**
|
82
|
104
|
* Mark iSCSI operation as complete
|
83
|
105
|
*
|
|
@@ -93,13 +115,13 @@ static void iscsi_rx_buffered_data_done ( struct iscsi_session *iscsi ) {
|
93
|
115
|
*/
|
94
|
116
|
static void iscsi_done ( struct iscsi_session *iscsi, int rc ) {
|
95
|
117
|
|
|
118
|
+ assert ( iscsi->tx_state == ISCSI_TX_IDLE );
|
|
119
|
+ assert ( iscsi->rx_state == ISCSI_RX_BHS );
|
|
120
|
+ assert ( iscsi->rx_offset == 0 );
|
|
121
|
+
|
96
|
122
|
/* Clear current SCSI command */
|
97
|
123
|
iscsi->command = NULL;
|
98
|
124
|
|
99
|
|
- /* Free any dynamically allocated memory */
|
100
|
|
- chap_finish ( &iscsi->chap );
|
101
|
|
- iscsi_rx_buffered_data_done ( iscsi );
|
102
|
|
-
|
103
|
125
|
/* Mark asynchronous operation as complete */
|
104
|
126
|
async_done ( &iscsi->aop, rc );
|
105
|
127
|
}
|
|
@@ -470,6 +492,9 @@ static void iscsi_login_request_done ( struct iscsi_session *iscsi ) {
|
470
|
492
|
|
471
|
493
|
/* Clear any "strings to send" flags */
|
472
|
494
|
iscsi->status &= ~ISCSI_STATUS_STRINGS_MASK;
|
|
495
|
+
|
|
496
|
+ /* Free any dynamically allocated storage used for login */
|
|
497
|
+ chap_finish ( &iscsi->chap );
|
473
|
498
|
}
|
474
|
499
|
|
475
|
500
|
/**
|
|
@@ -547,6 +572,7 @@ static void iscsi_handle_chap_a_value ( struct iscsi_session *iscsi,
|
547
|
572
|
/* Prepare for CHAP with MD5 */
|
548
|
573
|
if ( ( rc = chap_init ( &iscsi->chap, &md5_algorithm ) ) != 0 ) {
|
549
|
574
|
DBG ( "iSCSI %p could not initialise CHAP\n", iscsi );
|
|
575
|
+ iscsi_close ( iscsi );
|
550
|
576
|
iscsi_done ( iscsi, rc );
|
551
|
577
|
}
|
552
|
578
|
}
|
|
@@ -707,6 +733,7 @@ static void iscsi_rx_login_response ( struct iscsi_session *iscsi, void *data,
|
707
|
733
|
/* Buffer up the PDU data */
|
708
|
734
|
if ( ( rc = iscsi_rx_buffered_data ( iscsi, data, len ) ) != 0 ) {
|
709
|
735
|
DBG ( "iSCSI %p could not buffer login response\n", iscsi );
|
|
736
|
+ iscsi_close ( iscsi );
|
710
|
737
|
iscsi_done ( iscsi, rc );
|
711
|
738
|
return;
|
712
|
739
|
}
|
|
@@ -720,8 +747,7 @@ static void iscsi_rx_login_response ( struct iscsi_session *iscsi, void *data,
|
720
|
747
|
/* Check for login redirection */
|
721
|
748
|
if ( response->status_class == ISCSI_STATUS_REDIRECT ) {
|
722
|
749
|
DBG ( "iSCSI %p redirecting to new server\n", iscsi );
|
723
|
|
- tcp_close ( &iscsi->tcp );
|
724
|
|
- iscsi->status = 0;
|
|
750
|
+ iscsi_close ( iscsi );
|
725
|
751
|
if ( ( rc = tcp_connect ( &iscsi->tcp, &iscsi->target,
|
726
|
752
|
0 ) ) != 0 ) {
|
727
|
753
|
DBG ( "iSCSI %p could not open TCP connection\n",
|
|
@@ -735,6 +761,8 @@ static void iscsi_rx_login_response ( struct iscsi_session *iscsi, void *data,
|
735
|
761
|
if ( response->status_class != 0 ) {
|
736
|
762
|
DBG ( "iSCSI login failure: class %02x detail %02x\n",
|
737
|
763
|
response->status_class, response->status_detail );
|
|
764
|
+ iscsi->instant_rc = -EPERM;
|
|
765
|
+ iscsi_close ( iscsi );
|
738
|
766
|
iscsi_done ( iscsi, -EPERM );
|
739
|
767
|
return;
|
740
|
768
|
}
|
|
@@ -753,6 +781,7 @@ static void iscsi_rx_login_response ( struct iscsi_session *iscsi, void *data,
|
753
|
781
|
default:
|
754
|
782
|
DBG ( "iSCSI %p got invalid response flags %02x\n",
|
755
|
783
|
iscsi, response->flags );
|
|
784
|
+ iscsi_close ( iscsi );
|
756
|
785
|
iscsi_done ( iscsi, -EIO );
|
757
|
786
|
return;
|
758
|
787
|
}
|
|
@@ -767,6 +796,9 @@ static void iscsi_rx_login_response ( struct iscsi_session *iscsi, void *data,
|
767
|
796
|
return;
|
768
|
797
|
}
|
769
|
798
|
|
|
799
|
+ /* Reset retry count */
|
|
800
|
+ iscsi->retry_count = 0;
|
|
801
|
+
|
770
|
802
|
/* Record TSIH for future reference */
|
771
|
803
|
iscsi->tsih = ntohl ( response->tsih );
|
772
|
804
|
|
|
@@ -986,7 +1018,8 @@ static void iscsi_rx_data ( struct iscsi_session *iscsi, void *data,
|
986
|
1018
|
default:
|
987
|
1019
|
if ( remaining )
|
988
|
1020
|
return;
|
989
|
|
- printf ( "Unknown iSCSI opcode %02x\n", response->opcode );
|
|
1021
|
+ DBG ( "Unknown iSCSI opcode %02x\n", response->opcode );
|
|
1022
|
+ iscsi_close ( iscsi );
|
990
|
1023
|
iscsi_done ( iscsi, -EOPNOTSUPP );
|
991
|
1024
|
break;
|
992
|
1025
|
}
|
|
@@ -1112,19 +1145,25 @@ static void iscsi_closed ( struct tcp_application *app, int status ) {
|
1112
|
1145
|
struct iscsi_session *iscsi = tcp_to_iscsi ( app );
|
1113
|
1146
|
int rc;
|
1114
|
1147
|
|
1115
|
|
- /* Clear session status */
|
1116
|
|
- iscsi->status = 0;
|
|
1148
|
+ /* Even a graceful close counts as an error for iSCSI */
|
|
1149
|
+ if ( ! status )
|
|
1150
|
+ status = -ECONNRESET;
|
|
1151
|
+
|
|
1152
|
+ /* Close session cleanly */
|
|
1153
|
+ iscsi_close ( iscsi );
|
1117
|
1154
|
|
1118
|
1155
|
/* Retry connection if within the retry limit, otherwise fail */
|
1119
|
1156
|
if ( ++iscsi->retry_count <= ISCSI_MAX_RETRIES ) {
|
1120
|
|
- DBG ( "iSCSI %p retrying connection\n", iscsi );
|
|
1157
|
+ DBG ( "iSCSI %p retrying connection (retry #%d)\n",
|
|
1158
|
+ iscsi, iscsi->retry_count );
|
1121
|
1159
|
if ( ( rc = tcp_connect ( app, &iscsi->target, 0 ) ) != 0 ) {
|
1122
|
1160
|
DBG ( "iSCSI %p could not open TCP connection\n",
|
1123
|
1161
|
iscsi );
|
1124
|
1162
|
iscsi_done ( iscsi, rc );
|
1125
|
1163
|
}
|
1126
|
1164
|
} else {
|
1127
|
|
- printf ( "iSCSI %p retry count exceeded\n", iscsi );
|
|
1165
|
+ DBG ( "iSCSI %p retry count exceeded\n", iscsi );
|
|
1166
|
+ iscsi->instant_rc = status;
|
1128
|
1167
|
iscsi_done ( iscsi, status );
|
1129
|
1168
|
}
|
1130
|
1169
|
}
|
|
@@ -1138,14 +1177,12 @@ static void iscsi_closed ( struct tcp_application *app, int status ) {
|
1138
|
1177
|
static void iscsi_connected ( struct tcp_application *app ) {
|
1139
|
1178
|
struct iscsi_session *iscsi = tcp_to_iscsi ( app );
|
1140
|
1179
|
|
1141
|
|
- /* Set connected flag and reset retry count */
|
|
1180
|
+ assert ( iscsi->rx_state == ISCSI_RX_BHS );
|
|
1181
|
+ assert ( iscsi->rx_offset == 0 );
|
|
1182
|
+
|
|
1183
|
+ /* Enter security negotiation phase */
|
1142
|
1184
|
iscsi->status = ( ISCSI_STATUS_SECURITY_NEGOTIATION_PHASE |
|
1143
|
1185
|
ISCSI_STATUS_STRINGS_SECURITY );
|
1144
|
|
- iscsi->retry_count = 0;
|
1145
|
|
-
|
1146
|
|
- /* Prepare to receive PDUs. */
|
1147
|
|
- iscsi->rx_state = ISCSI_RX_BHS;
|
1148
|
|
- iscsi->rx_offset = 0;
|
1149
|
1186
|
|
1150
|
1187
|
/* Assign fresh initiator task tag */
|
1151
|
1188
|
iscsi->itt++;
|
|
@@ -1177,19 +1214,13 @@ struct async_operation * iscsi_issue ( struct iscsi_session *iscsi,
|
1177
|
1214
|
assert ( iscsi->command == NULL );
|
1178
|
1215
|
iscsi->command = command;
|
1179
|
1216
|
|
1180
|
|
- if ( iscsi->status ) {
|
1181
|
|
- if ( ( iscsi->status & ISCSI_STATUS_PHASE_MASK ) ==
|
1182
|
|
- ISCSI_STATUS_FULL_FEATURE_PHASE ) {
|
1183
|
|
- /* Session already open: issue command */
|
1184
|
|
- iscsi_start_command ( iscsi );
|
1185
|
|
- tcp_senddata ( &iscsi->tcp );
|
1186
|
|
- } else {
|
1187
|
|
- /* Session failed to reach full feature phase:
|
1188
|
|
- * abort immediately rather than retrying the
|
1189
|
|
- * login.
|
1190
|
|
- */
|
1191
|
|
- iscsi_done ( iscsi, -EPERM );
|
1192
|
|
- }
|
|
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 );
|
1193
|
1224
|
} else {
|
1194
|
1225
|
/* Session not open: initiate login */
|
1195
|
1226
|
iscsi->tcp.tcp_op = &iscsi_tcp_operations;
|
|
@@ -1211,6 +1242,5 @@ struct async_operation * iscsi_issue ( struct iscsi_session *iscsi,
|
1211
|
1242
|
* @ret aop Asynchronous operation
|
1212
|
1243
|
*/
|
1213
|
1244
|
void iscsi_shutdown ( struct iscsi_session *iscsi ) {
|
1214
|
|
- iscsi->status = 0;
|
1215
|
|
- tcp_close ( &iscsi->tcp );
|
|
1245
|
+ iscsi_close ( iscsi );
|
1216
|
1246
|
}
|