aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/scsi/libiscsi.c87
-rw-r--r--include/scsi/libiscsi.h3
-rw-r--r--include/scsi/scsi_transport_iscsi.h2
3 files changed, 50 insertions, 42 deletions
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 580c0505603c..d810acae45f7 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -487,6 +487,11 @@ void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err)
487 unsigned long flags; 487 unsigned long flags;
488 488
489 spin_lock_irqsave(&session->lock, flags); 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 if (session->conn_cnt == 1 || session->leadconn == conn) 495 if (session->conn_cnt == 1 || session->leadconn == conn)
491 session->state = ISCSI_STATE_FAILED; 496 session->state = ISCSI_STATE_FAILED;
492 spin_unlock_irqrestore(&session->lock, flags); 497 spin_unlock_irqrestore(&session->lock, flags);
@@ -612,6 +617,7 @@ enum {
612 FAILURE_SESSION_FREED, 617 FAILURE_SESSION_FREED,
613 FAILURE_WINDOW_CLOSED, 618 FAILURE_WINDOW_CLOSED,
614 FAILURE_SESSION_TERMINATE, 619 FAILURE_SESSION_TERMINATE,
620 FAILURE_SESSION_IN_RECOVERY,
615 FAILURE_SESSION_RECOVERY_TIMEOUT, 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 spin_lock(&session->lock); 638 spin_lock(&session->lock);
633 639
634 if (session->state != ISCSI_STATE_LOGGED_IN) { 640 /*
635 if (session->recovery_failed) { 641 * ISCSI_STATE_FAILED is a temp. state. The recovery
636 reason = FAILURE_SESSION_RECOVERY_TIMEOUT; 642 * code will decide what is best to do with command queued
637 goto fault; 643 * during this time
638 } else if (session->state == ISCSI_STATE_FAILED) { 644 */
639 reason = FAILURE_SESSION_FAILED; 645 if (session->state != ISCSI_STATE_LOGGED_IN &&
640 goto reject; 646 session->state != ISCSI_STATE_FAILED) {
641 } else if (session->state == ISCSI_STATE_TERMINATE) { 647 /*
642 reason = FAILURE_SESSION_TERMINATE; 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 goto fault; 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 goto fault; 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 mtask = conn->login_mtask; 747 mtask = conn->login_mtask;
730 else { 748 else {
731 BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE); 749 BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE);
732 BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED); 750 BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED);
733 751
734 nop->exp_statsn = cpu_to_be32(conn->exp_statsn); 752 nop->exp_statsn = cpu_to_be32(conn->exp_statsn);
735 if (!__kfifo_get(session->mgmtpool.queue, 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 spin_lock_bh(&session->lock); 822 spin_lock_bh(&session->lock);
805 if (session->state != ISCSI_STATE_LOGGED_IN) { 823 if (session->state != ISCSI_STATE_LOGGED_IN) {
806 session->recovery_failed = 1; 824 session->state = ISCSI_STATE_RECOVERY_FAILED;
807 if (conn) 825 if (conn)
808 wake_up(&conn->ehwait); 826 wake_up(&conn->ehwait);
809 } 827 }
@@ -838,20 +856,14 @@ failed:
838 * we drop the lock here but the leadconn cannot be destoyed while 856 * we drop the lock here but the leadconn cannot be destoyed while
839 * we are in the scsi eh 857 * we are in the scsi eh
840 */ 858 */
841 if (fail_session) { 859 if (fail_session)
842 iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); 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 debug_scsi("iscsi_eh_host_reset wait for relogin\n"); 862 debug_scsi("iscsi_eh_host_reset wait for relogin\n");
851 wait_event_interruptible(conn->ehwait, 863 wait_event_interruptible(conn->ehwait,
852 session->state == ISCSI_STATE_TERMINATE || 864 session->state == ISCSI_STATE_TERMINATE ||
853 session->state == ISCSI_STATE_LOGGED_IN || 865 session->state == ISCSI_STATE_LOGGED_IN ||
854 session->recovery_failed); 866 session->state == ISCSI_STATE_RECOVERY_FAILED);
855 if (signal_pending(current)) 867 if (signal_pending(current))
856 flush_signals(current); 868 flush_signals(current);
857 869
@@ -940,8 +952,7 @@ static int iscsi_exec_abort_task(struct scsi_cmnd *sc,
940 wait_event_interruptible(conn->ehwait, 952 wait_event_interruptible(conn->ehwait,
941 sc->SCp.phase != session->age || 953 sc->SCp.phase != session->age ||
942 session->state != ISCSI_STATE_LOGGED_IN || 954 session->state != ISCSI_STATE_LOGGED_IN ||
943 conn->tmabort_state != TMABORT_INITIAL || 955 conn->tmabort_state != TMABORT_INITIAL);
944 session->recovery_failed);
945 if (signal_pending(current)) 956 if (signal_pending(current))
946 flush_signals(current); 957 flush_signals(current);
947 del_timer_sync(&conn->tmabort_timer); 958 del_timer_sync(&conn->tmabort_timer);
@@ -1491,7 +1502,6 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn)
1491 conn->stop_stage = 0; 1502 conn->stop_stage = 0;
1492 conn->tmabort_state = TMABORT_INITIAL; 1503 conn->tmabort_state = TMABORT_INITIAL;
1493 session->age++; 1504 session->age++;
1494 session->recovery_failed = 0;
1495 spin_unlock_bh(&session->lock); 1505 spin_unlock_bh(&session->lock);
1496 1506
1497 iscsi_unblock_session(session_to_cls(session)); 1507 iscsi_unblock_session(session_to_cls(session));
@@ -1566,8 +1576,8 @@ static void fail_all_commands(struct iscsi_conn *conn)
1566 conn->ctask = NULL; 1576 conn->ctask = NULL;
1567} 1577}
1568 1578
1569void iscsi_start_session_recovery(struct iscsi_session *session, 1579static void iscsi_start_session_recovery(struct iscsi_session *session,
1570 struct iscsi_conn *conn, int flag) 1580 struct iscsi_conn *conn, int flag)
1571{ 1581{
1572 int old_stop_stage; 1582 int old_stop_stage;
1573 1583
@@ -1597,19 +1607,10 @@ void iscsi_start_session_recovery(struct iscsi_session *session,
1597 set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); 1607 set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
1598 1608
1599 if (session->conn_cnt == 0 || session->leadconn == conn) 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 spin_unlock_bh(&session->lock); 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 * for connection level recovery we should not calculate 1615 * for connection level recovery we should not calculate
1615 * header digest. conn->hdr_size used for optimization 1616 * header digest. conn->hdr_size used for optimization
@@ -1619,18 +1620,26 @@ void iscsi_start_session_recovery(struct iscsi_session *session,
1619 if (flag == STOP_CONN_RECOVER) { 1620 if (flag == STOP_CONN_RECOVER) {
1620 conn->hdrdgst_en = 0; 1621 conn->hdrdgst_en = 0;
1621 conn->datadgst_en = 0; 1622 conn->datadgst_en = 0;
1622
1623 /* 1623 /*
1624 * if this is called from the eh and and from userspace 1624 * if this is called from the eh and and from userspace
1625 * then we only need to block once. 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 old_stop_stage != STOP_CONN_RECOVER) 1628 old_stop_stage != STOP_CONN_RECOVER)
1629 iscsi_block_session(session_to_cls(session)); 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 mutex_unlock(&conn->xmitmutex); 1641 mutex_unlock(&conn->xmitmutex);
1632} 1642}
1633EXPORT_SYMBOL_GPL(iscsi_start_session_recovery);
1634 1643
1635void iscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) 1644void iscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
1636{ 1645{
diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
index 2dba929a2a05..17b28f08b692 100644
--- a/include/scsi/libiscsi.h
+++ b/include/scsi/libiscsi.h
@@ -210,7 +210,6 @@ struct iscsi_session {
210 * - mgmtpool, * 210 * - mgmtpool, *
211 * - r2tpool */ 211 * - r2tpool */
212 int state; /* session state */ 212 int state; /* session state */
213 int recovery_failed;
214 struct list_head item; 213 struct list_head item;
215 int conn_cnt; 214 int conn_cnt;
216 int age; /* counts session re-opens */ 215 int age; /* counts session re-opens */
@@ -241,8 +240,6 @@ iscsi_session_setup(struct iscsi_transport *, struct scsi_transport_template *,
241 int, int, uint32_t, uint32_t *); 240 int, int, uint32_t, uint32_t *);
242extern void iscsi_session_teardown(struct iscsi_cls_session *); 241extern void iscsi_session_teardown(struct iscsi_cls_session *);
243extern struct iscsi_session *class_to_transport_session(struct iscsi_cls_session *); 242extern struct iscsi_session *class_to_transport_session(struct iscsi_cls_session *);
244extern void iscsi_start_session_recovery(struct iscsi_session *,
245 struct iscsi_conn *, int);
246extern void iscsi_session_recovery_timedout(struct iscsi_cls_session *); 243extern void iscsi_session_recovery_timedout(struct iscsi_cls_session *);
247 244
248#define session_to_cls(_sess) \ 245#define session_to_cls(_sess) \
diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h
index c9e9475c6dff..92129b97d31e 100644
--- a/include/scsi/scsi_transport_iscsi.h
+++ b/include/scsi/scsi_transport_iscsi.h
@@ -173,6 +173,8 @@ struct iscsi_cls_conn {
173#define ISCSI_STATE_LOGGED_IN 2 173#define ISCSI_STATE_LOGGED_IN 2
174#define ISCSI_STATE_FAILED 3 174#define ISCSI_STATE_FAILED 3
175#define ISCSI_STATE_TERMINATE 4 175#define ISCSI_STATE_TERMINATE 4
176#define ISCSI_STATE_IN_RECOVERY 5
177#define ISCSI_STATE_RECOVERY_FAILED 6
176 178
177struct iscsi_cls_session { 179struct iscsi_cls_session {
178 struct list_head sess_list; /* item in session_list */ 180 struct list_head sess_list; /* item in session_list */