diff options
author | Mike Christie <michaelc@cs.wisc.edu> | 2006-05-18 21:31:42 -0400 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.il.steeleye.com> | 2006-05-20 10:36:17 -0400 |
commit | 656cffc95f0cb8211aa75eaca249e6ff4f59ec83 (patch) | |
tree | 7b10e224ef3ac140570101ed98c918949863995b | |
parent | 790f39a2d5f03623b027f340b945f135d006ceba (diff) |
[SCSI] iscsi: fix command requeues during iscsi recovery
Do not flush queues then block session. This will cause commands
to needlessly swing around on us and remove goofy
recovery_failed field and replace with state value.
And do not start recovery from within the host reset function.
This causeis too many problems becuase open-iscsi was desinged to
call out to userspace then have userpscae decide if we should
go into recovery or kill the session.
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
-rw-r--r-- | drivers/scsi/libiscsi.c | 87 | ||||
-rw-r--r-- | include/scsi/libiscsi.h | 3 | ||||
-rw-r--r-- | include/scsi/scsi_transport_iscsi.h | 2 |
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 | ||
1569 | void iscsi_start_session_recovery(struct iscsi_session *session, | 1579 | static 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 | } |
1633 | EXPORT_SYMBOL_GPL(iscsi_start_session_recovery); | ||
1634 | 1643 | ||
1635 | void iscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) | 1644 | void 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 *); |
242 | extern void iscsi_session_teardown(struct iscsi_cls_session *); | 241 | extern void iscsi_session_teardown(struct iscsi_cls_session *); |
243 | extern struct iscsi_session *class_to_transport_session(struct iscsi_cls_session *); | 242 | extern struct iscsi_session *class_to_transport_session(struct iscsi_cls_session *); |
244 | extern void iscsi_start_session_recovery(struct iscsi_session *, | ||
245 | struct iscsi_conn *, int); | ||
246 | extern void iscsi_session_recovery_timedout(struct iscsi_cls_session *); | 243 | extern 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 | ||
177 | struct iscsi_cls_session { | 179 | struct iscsi_cls_session { |
178 | struct list_head sess_list; /* item in session_list */ | 180 | struct list_head sess_list; /* item in session_list */ |