@@ -487,6 +487,11 @@ void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err)
487
487
unsigned long flags ;
488
488
489
489
spin_lock_irqsave (& session -> lock , flags );
490
+ if (session -> state == ISCSI_STATE_FAILED ) {
491
+ spin_unlock_irqrestore (& session -> lock , flags );
492
+ return ;
493
+ }
494
+
490
495
if (session -> conn_cnt == 1 || session -> leadconn == conn )
491
496
session -> state = ISCSI_STATE_FAILED ;
492
497
spin_unlock_irqrestore (& session -> lock , flags );
@@ -612,6 +617,7 @@ enum {
612
617
FAILURE_SESSION_FREED ,
613
618
FAILURE_WINDOW_CLOSED ,
614
619
FAILURE_SESSION_TERMINATE ,
620
+ FAILURE_SESSION_IN_RECOVERY ,
615
621
FAILURE_SESSION_RECOVERY_TIMEOUT ,
616
622
};
617
623
@@ -631,18 +637,30 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
631
637
632
638
spin_lock (& session -> lock );
633
639
634
- if (session -> state != ISCSI_STATE_LOGGED_IN ) {
635
- if (session -> recovery_failed ) {
636
- reason = FAILURE_SESSION_RECOVERY_TIMEOUT ;
637
- goto fault ;
638
- } else if (session -> state == ISCSI_STATE_FAILED ) {
639
- reason = FAILURE_SESSION_FAILED ;
640
- goto reject ;
641
- } else if (session -> state == ISCSI_STATE_TERMINATE ) {
642
- reason = FAILURE_SESSION_TERMINATE ;
640
+ /*
641
+ * ISCSI_STATE_FAILED is a temp. state. The recovery
642
+ * code will decide what is best to do with command queued
643
+ * during this time
644
+ */
645
+ if (session -> state != ISCSI_STATE_LOGGED_IN &&
646
+ session -> state != ISCSI_STATE_FAILED ) {
647
+ /*
648
+ * to handle the race between when we set the recovery state
649
+ * and block the session we requeue here (commands could
650
+ * be entering our queuecommand while a block is starting
651
+ * up because the block code is not locked)
652
+ */
653
+ if (session -> state == ISCSI_STATE_IN_RECOVERY ) {
654
+ reason = FAILURE_SESSION_IN_RECOVERY ;
643
655
goto fault ;
644
656
}
645
- reason = FAILURE_SESSION_FREED ;
657
+
658
+ if (session -> state == ISCSI_STATE_RECOVERY_FAILED )
659
+ reason = FAILURE_SESSION_RECOVERY_TIMEOUT ;
660
+ else if (session -> state == ISCSI_STATE_TERMINATE )
661
+ reason = FAILURE_SESSION_TERMINATE ;
662
+ else
663
+ reason = FAILURE_SESSION_FREED ;
646
664
goto fault ;
647
665
}
648
666
@@ -728,8 +746,8 @@ iscsi_conn_send_generic(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
728
746
*/
729
747
mtask = conn -> login_mtask ;
730
748
else {
731
- BUG_ON (conn -> c_stage == ISCSI_CONN_INITIAL_STAGE );
732
- BUG_ON (conn -> c_stage == ISCSI_CONN_STOPPED );
749
+ BUG_ON (conn -> c_stage == ISCSI_CONN_INITIAL_STAGE );
750
+ BUG_ON (conn -> c_stage == ISCSI_CONN_STOPPED );
733
751
734
752
nop -> exp_statsn = cpu_to_be32 (conn -> exp_statsn );
735
753
if (!__kfifo_get (session -> mgmtpool .queue ,
@@ -803,7 +821,7 @@ void iscsi_session_recovery_timedout(struct iscsi_cls_session *cls_session)
803
821
804
822
spin_lock_bh (& session -> lock );
805
823
if (session -> state != ISCSI_STATE_LOGGED_IN ) {
806
- session -> recovery_failed = 1 ;
824
+ session -> state = ISCSI_STATE_RECOVERY_FAILED ;
807
825
if (conn )
808
826
wake_up (& conn -> ehwait );
809
827
}
@@ -838,20 +856,14 @@ int iscsi_eh_host_reset(struct scsi_cmnd *sc)
838
856
* we drop the lock here but the leadconn cannot be destoyed while
839
857
* we are in the scsi eh
840
858
*/
841
- if (fail_session ) {
859
+ if (fail_session )
842
860
iscsi_conn_failure (conn , ISCSI_ERR_CONN_FAILED );
843
- /*
844
- * if userspace cannot respond then we must kick this off
845
- * here for it
846
- */
847
- iscsi_start_session_recovery (session , conn , STOP_CONN_RECOVER );
848
- }
849
861
850
862
debug_scsi ("iscsi_eh_host_reset wait for relogin\n" );
851
863
wait_event_interruptible (conn -> ehwait ,
852
864
session -> state == ISCSI_STATE_TERMINATE ||
853
865
session -> state == ISCSI_STATE_LOGGED_IN ||
854
- session -> recovery_failed );
866
+ session -> state == ISCSI_STATE_RECOVERY_FAILED );
855
867
if (signal_pending (current ))
856
868
flush_signals (current );
857
869
@@ -940,8 +952,7 @@ static int iscsi_exec_abort_task(struct scsi_cmnd *sc,
940
952
wait_event_interruptible (conn -> ehwait ,
941
953
sc -> SCp .phase != session -> age ||
942
954
session -> state != ISCSI_STATE_LOGGED_IN ||
943
- conn -> tmabort_state != TMABORT_INITIAL ||
944
- session -> recovery_failed );
955
+ conn -> tmabort_state != TMABORT_INITIAL );
945
956
if (signal_pending (current ))
946
957
flush_signals (current );
947
958
del_timer_sync (& conn -> tmabort_timer );
@@ -1491,7 +1502,6 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn)
1491
1502
conn -> stop_stage = 0 ;
1492
1503
conn -> tmabort_state = TMABORT_INITIAL ;
1493
1504
session -> age ++ ;
1494
- session -> recovery_failed = 0 ;
1495
1505
spin_unlock_bh (& session -> lock );
1496
1506
1497
1507
iscsi_unblock_session (session_to_cls (session ));
@@ -1566,8 +1576,8 @@ static void fail_all_commands(struct iscsi_conn *conn)
1566
1576
conn -> ctask = NULL ;
1567
1577
}
1568
1578
1569
- void iscsi_start_session_recovery (struct iscsi_session * session ,
1570
- struct iscsi_conn * conn , int flag )
1579
+ static void iscsi_start_session_recovery (struct iscsi_session * session ,
1580
+ struct iscsi_conn * conn , int flag )
1571
1581
{
1572
1582
int old_stop_stage ;
1573
1583
@@ -1597,19 +1607,10 @@ void iscsi_start_session_recovery(struct iscsi_session *session,
1597
1607
set_bit (ISCSI_SUSPEND_BIT , & conn -> suspend_tx );
1598
1608
1599
1609
if (session -> conn_cnt == 0 || session -> leadconn == conn )
1600
- session -> state = ISCSI_STATE_FAILED ;
1610
+ session -> state = ISCSI_STATE_IN_RECOVERY ;
1601
1611
1602
1612
spin_unlock_bh (& session -> lock );
1603
1613
1604
- session -> tt -> terminate_conn (conn );
1605
- /*
1606
- * flush queues.
1607
- */
1608
- spin_lock_bh (& session -> lock );
1609
- fail_all_commands (conn );
1610
- flush_control_queues (session , conn );
1611
- spin_unlock_bh (& session -> lock );
1612
-
1613
1614
/*
1614
1615
* for connection level recovery we should not calculate
1615
1616
* header digest. conn->hdr_size used for optimization
@@ -1619,18 +1620,26 @@ void iscsi_start_session_recovery(struct iscsi_session *session,
1619
1620
if (flag == STOP_CONN_RECOVER ) {
1620
1621
conn -> hdrdgst_en = 0 ;
1621
1622
conn -> datadgst_en = 0 ;
1622
-
1623
1623
/*
1624
1624
* if this is called from the eh and and from userspace
1625
1625
* then we only need to block once.
1626
1626
*/
1627
- if (session -> state == ISCSI_STATE_FAILED &&
1627
+ if (session -> state == ISCSI_STATE_IN_RECOVERY &&
1628
1628
old_stop_stage != STOP_CONN_RECOVER )
1629
1629
iscsi_block_session (session_to_cls (session ));
1630
1630
}
1631
+
1632
+ session -> tt -> terminate_conn (conn );
1633
+ /*
1634
+ * flush queues.
1635
+ */
1636
+ spin_lock_bh (& session -> lock );
1637
+ fail_all_commands (conn );
1638
+ flush_control_queues (session , conn );
1639
+ spin_unlock_bh (& session -> lock );
1640
+
1631
1641
mutex_unlock (& conn -> xmitmutex );
1632
1642
}
1633
- EXPORT_SYMBOL_GPL (iscsi_start_session_recovery );
1634
1643
1635
1644
void iscsi_conn_stop (struct iscsi_cls_conn * cls_conn , int flag )
1636
1645
{
0 commit comments