diff options
author | Mike Christie <michaelc@cs.wisc.edu> | 2007-12-13 13:43:20 -0500 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2008-01-11 19:28:19 -0500 |
commit | 843c0a8a76078cf961b244b839683d0667313740 (patch) | |
tree | 3feaf71c8e67f38e10e78e315bbc8623dcf38a3d /drivers/scsi/libiscsi.c | |
parent | 8ae732a91df051aba6820068a47b631a06599d84 (diff) |
[SCSI] libiscsi, iscsi_tcp: add device support
This patch adds logical unit reset support. This should work for ib_iser,
but I have not finished testing that driver so it is not hooked in yet.
This patch also temporarily reverts the iscsi_tcp r2t write out patch.
That code is completely rewritten in this patchset.
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/scsi/libiscsi.c')
-rw-r--r-- | drivers/scsi/libiscsi.c | 494 |
1 files changed, 281 insertions, 213 deletions
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 8b57af5baaec..176458f35316 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c | |||
@@ -86,7 +86,7 @@ iscsi_update_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr) | |||
86 | * xmit thread | 86 | * xmit thread |
87 | */ | 87 | */ |
88 | if (!list_empty(&session->leadconn->xmitqueue) || | 88 | if (!list_empty(&session->leadconn->xmitqueue) || |
89 | __kfifo_len(session->leadconn->mgmtqueue)) | 89 | !list_empty(&session->leadconn->mgmtqueue)) |
90 | scsi_queue_work(session->host, | 90 | scsi_queue_work(session->host, |
91 | &session->leadconn->xmitwork); | 91 | &session->leadconn->xmitwork); |
92 | } | 92 | } |
@@ -318,15 +318,15 @@ static void iscsi_tmf_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr) | |||
318 | conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; | 318 | conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; |
319 | conn->tmfrsp_pdus_cnt++; | 319 | conn->tmfrsp_pdus_cnt++; |
320 | 320 | ||
321 | if (conn->tmabort_state != TMABORT_INITIAL) | 321 | if (conn->tmf_state != TMF_QUEUED) |
322 | return; | 322 | return; |
323 | 323 | ||
324 | if (tmf->response == ISCSI_TMF_RSP_COMPLETE) | 324 | if (tmf->response == ISCSI_TMF_RSP_COMPLETE) |
325 | conn->tmabort_state = TMABORT_SUCCESS; | 325 | conn->tmf_state = TMF_SUCCESS; |
326 | else if (tmf->response == ISCSI_TMF_RSP_NO_TASK) | 326 | else if (tmf->response == ISCSI_TMF_RSP_NO_TASK) |
327 | conn->tmabort_state = TMABORT_NOT_FOUND; | 327 | conn->tmf_state = TMF_NOT_FOUND; |
328 | else | 328 | else |
329 | conn->tmabort_state = TMABORT_FAILED; | 329 | conn->tmf_state = TMF_FAILED; |
330 | wake_up(&conn->ehwait); | 330 | wake_up(&conn->ehwait); |
331 | } | 331 | } |
332 | 332 | ||
@@ -429,7 +429,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | |||
429 | */ | 429 | */ |
430 | if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen)) | 430 | if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen)) |
431 | rc = ISCSI_ERR_CONN_FAILED; | 431 | rc = ISCSI_ERR_CONN_FAILED; |
432 | list_del(&mtask->running); | 432 | list_del_init(&mtask->running); |
433 | if (conn->login_mtask != mtask) | 433 | if (conn->login_mtask != mtask) |
434 | __kfifo_put(session->mgmtpool.queue, | 434 | __kfifo_put(session->mgmtpool.queue, |
435 | (void*)&mtask, sizeof(void*)); | 435 | (void*)&mtask, sizeof(void*)); |
@@ -451,10 +451,9 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | |||
451 | 451 | ||
452 | if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen)) | 452 | if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen)) |
453 | rc = ISCSI_ERR_CONN_FAILED; | 453 | rc = ISCSI_ERR_CONN_FAILED; |
454 | list_del(&mtask->running); | 454 | list_del_init(&mtask->running); |
455 | if (conn->login_mtask != mtask) | 455 | __kfifo_put(session->mgmtpool.queue, |
456 | __kfifo_put(session->mgmtpool.queue, | 456 | (void*)&mtask, sizeof(void*)); |
457 | (void*)&mtask, sizeof(void*)); | ||
458 | break; | 457 | break; |
459 | default: | 458 | default: |
460 | rc = ISCSI_ERR_BAD_OPCODE; | 459 | rc = ISCSI_ERR_BAD_OPCODE; |
@@ -609,7 +608,8 @@ static void iscsi_prep_mtask(struct iscsi_conn *conn, | |||
609 | session->tt->init_mgmt_task(conn, mtask); | 608 | session->tt->init_mgmt_task(conn, mtask); |
610 | 609 | ||
611 | debug_scsi("mgmtpdu [op 0x%x hdr->itt 0x%x datalen %d]\n", | 610 | debug_scsi("mgmtpdu [op 0x%x hdr->itt 0x%x datalen %d]\n", |
612 | hdr->opcode, hdr->itt, mtask->data_count); | 611 | hdr->opcode & ISCSI_OPCODE_MASK, hdr->itt, |
612 | mtask->data_count); | ||
613 | } | 613 | } |
614 | 614 | ||
615 | static int iscsi_xmit_mtask(struct iscsi_conn *conn) | 615 | static int iscsi_xmit_mtask(struct iscsi_conn *conn) |
@@ -658,21 +658,13 @@ static int iscsi_check_cmdsn_window_closed(struct iscsi_conn *conn) | |||
658 | static int iscsi_xmit_ctask(struct iscsi_conn *conn) | 658 | static int iscsi_xmit_ctask(struct iscsi_conn *conn) |
659 | { | 659 | { |
660 | struct iscsi_cmd_task *ctask = conn->ctask; | 660 | struct iscsi_cmd_task *ctask = conn->ctask; |
661 | int rc = 0; | 661 | int rc; |
662 | |||
663 | /* | ||
664 | * serialize with TMF AbortTask | ||
665 | */ | ||
666 | if (ctask->state == ISCSI_TASK_ABORTING) | ||
667 | goto done; | ||
668 | 662 | ||
669 | __iscsi_get_ctask(ctask); | 663 | __iscsi_get_ctask(ctask); |
670 | spin_unlock_bh(&conn->session->lock); | 664 | spin_unlock_bh(&conn->session->lock); |
671 | rc = conn->session->tt->xmit_cmd_task(conn, ctask); | 665 | rc = conn->session->tt->xmit_cmd_task(conn, ctask); |
672 | spin_lock_bh(&conn->session->lock); | 666 | spin_lock_bh(&conn->session->lock); |
673 | __iscsi_put_ctask(ctask); | 667 | __iscsi_put_ctask(ctask); |
674 | |||
675 | done: | ||
676 | if (!rc) | 668 | if (!rc) |
677 | /* done with this ctask */ | 669 | /* done with this ctask */ |
678 | conn->ctask = NULL; | 670 | conn->ctask = NULL; |
@@ -680,6 +672,22 @@ done: | |||
680 | } | 672 | } |
681 | 673 | ||
682 | /** | 674 | /** |
675 | * iscsi_requeue_ctask - requeue ctask to run from session workqueue | ||
676 | * @ctask: ctask to requeue | ||
677 | * | ||
678 | * LLDs that need to run a ctask from the session workqueue should call | ||
679 | * this. The session lock must be held. | ||
680 | */ | ||
681 | void iscsi_requeue_ctask(struct iscsi_cmd_task *ctask) | ||
682 | { | ||
683 | struct iscsi_conn *conn = ctask->conn; | ||
684 | |||
685 | list_move_tail(&ctask->running, &conn->requeue); | ||
686 | scsi_queue_work(conn->session->host, &conn->xmitwork); | ||
687 | } | ||
688 | EXPORT_SYMBOL_GPL(iscsi_requeue_ctask); | ||
689 | |||
690 | /** | ||
683 | * iscsi_data_xmit - xmit any command into the scheduled connection | 691 | * iscsi_data_xmit - xmit any command into the scheduled connection |
684 | * @conn: iscsi connection | 692 | * @conn: iscsi connection |
685 | * | 693 | * |
@@ -717,36 +725,27 @@ static int iscsi_data_xmit(struct iscsi_conn *conn) | |||
717 | * overflow us with nop-ins | 725 | * overflow us with nop-ins |
718 | */ | 726 | */ |
719 | check_mgmt: | 727 | check_mgmt: |
720 | while (__kfifo_get(conn->mgmtqueue, (void*)&conn->mtask, | 728 | while (!list_empty(&conn->mgmtqueue)) { |
721 | sizeof(void*))) { | 729 | conn->mtask = list_entry(conn->mgmtqueue.next, |
730 | struct iscsi_mgmt_task, running); | ||
722 | iscsi_prep_mtask(conn, conn->mtask); | 731 | iscsi_prep_mtask(conn, conn->mtask); |
723 | list_add_tail(&conn->mtask->running, &conn->mgmt_run_list); | 732 | list_move_tail(conn->mgmtqueue.next, &conn->mgmt_run_list); |
724 | rc = iscsi_xmit_mtask(conn); | 733 | rc = iscsi_xmit_mtask(conn); |
725 | if (rc) | 734 | if (rc) |
726 | goto again; | 735 | goto again; |
727 | } | 736 | } |
728 | 737 | ||
729 | /* process command queue */ | 738 | /* process pending command queue */ |
730 | while (!list_empty(&conn->xmitqueue)) { | 739 | while (!list_empty(&conn->xmitqueue)) { |
731 | /* | 740 | if (conn->tmf_state == TMF_QUEUED) |
732 | * iscsi tcp may readd the task to the xmitqueue to send | 741 | break; |
733 | * write data | 742 | |
734 | */ | ||
735 | conn->ctask = list_entry(conn->xmitqueue.next, | 743 | conn->ctask = list_entry(conn->xmitqueue.next, |
736 | struct iscsi_cmd_task, running); | 744 | struct iscsi_cmd_task, running); |
737 | switch (conn->ctask->state) { | 745 | iscsi_prep_scsi_cmd_pdu(conn->ctask); |
738 | case ISCSI_TASK_ABORTING: | 746 | conn->session->tt->init_cmd_task(conn->ctask); |
739 | break; | 747 | conn->ctask->state = ISCSI_TASK_RUNNING; |
740 | case ISCSI_TASK_PENDING: | ||
741 | iscsi_prep_scsi_cmd_pdu(conn->ctask); | ||
742 | conn->session->tt->init_cmd_task(conn->ctask); | ||
743 | /* fall through */ | ||
744 | default: | ||
745 | conn->ctask->state = ISCSI_TASK_RUNNING; | ||
746 | break; | ||
747 | } | ||
748 | list_move_tail(conn->xmitqueue.next, &conn->run_list); | 748 | list_move_tail(conn->xmitqueue.next, &conn->run_list); |
749 | |||
750 | rc = iscsi_xmit_ctask(conn); | 749 | rc = iscsi_xmit_ctask(conn); |
751 | if (rc) | 750 | if (rc) |
752 | goto again; | 751 | goto again; |
@@ -755,7 +754,22 @@ check_mgmt: | |||
755 | * we need to check the mgmt queue for nops that need to | 754 | * we need to check the mgmt queue for nops that need to |
756 | * be sent to aviod starvation | 755 | * be sent to aviod starvation |
757 | */ | 756 | */ |
758 | if (__kfifo_len(conn->mgmtqueue)) | 757 | if (!list_empty(&conn->mgmtqueue)) |
758 | goto check_mgmt; | ||
759 | } | ||
760 | |||
761 | while (!list_empty(&conn->requeue)) { | ||
762 | if (conn->session->fast_abort && conn->tmf_state != TMF_INITIAL) | ||
763 | break; | ||
764 | |||
765 | conn->ctask = list_entry(conn->requeue.next, | ||
766 | struct iscsi_cmd_task, running); | ||
767 | conn->ctask->state = ISCSI_TASK_RUNNING; | ||
768 | list_move_tail(conn->requeue.next, &conn->run_list); | ||
769 | rc = iscsi_xmit_ctask(conn); | ||
770 | if (rc) | ||
771 | goto again; | ||
772 | if (!list_empty(&conn->mgmtqueue)) | ||
759 | goto check_mgmt; | 773 | goto check_mgmt; |
760 | } | 774 | } |
761 | spin_unlock_bh(&conn->session->lock); | 775 | spin_unlock_bh(&conn->session->lock); |
@@ -859,7 +873,6 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) | |||
859 | 873 | ||
860 | atomic_set(&ctask->refcount, 1); | 874 | atomic_set(&ctask->refcount, 1); |
861 | ctask->state = ISCSI_TASK_PENDING; | 875 | ctask->state = ISCSI_TASK_PENDING; |
862 | ctask->mtask = NULL; | ||
863 | ctask->conn = conn; | 876 | ctask->conn = conn; |
864 | ctask->sc = sc; | 877 | ctask->sc = sc; |
865 | INIT_LIST_HEAD(&ctask->running); | 878 | INIT_LIST_HEAD(&ctask->running); |
@@ -929,9 +942,9 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | |||
929 | } else | 942 | } else |
930 | mtask->data_count = 0; | 943 | mtask->data_count = 0; |
931 | 944 | ||
932 | INIT_LIST_HEAD(&mtask->running); | ||
933 | memcpy(mtask->hdr, hdr, sizeof(struct iscsi_hdr)); | 945 | memcpy(mtask->hdr, hdr, sizeof(struct iscsi_hdr)); |
934 | __kfifo_put(conn->mgmtqueue, (void*)&mtask, sizeof(void*)); | 946 | INIT_LIST_HEAD(&mtask->running); |
947 | list_add_tail(&mtask->running, &conn->mgmtqueue); | ||
935 | return mtask; | 948 | return mtask; |
936 | } | 949 | } |
937 | 950 | ||
@@ -954,13 +967,12 @@ EXPORT_SYMBOL_GPL(iscsi_conn_send_pdu); | |||
954 | void iscsi_session_recovery_timedout(struct iscsi_cls_session *cls_session) | 967 | void iscsi_session_recovery_timedout(struct iscsi_cls_session *cls_session) |
955 | { | 968 | { |
956 | struct iscsi_session *session = class_to_transport_session(cls_session); | 969 | struct iscsi_session *session = class_to_transport_session(cls_session); |
957 | struct iscsi_conn *conn = session->leadconn; | ||
958 | 970 | ||
959 | spin_lock_bh(&session->lock); | 971 | spin_lock_bh(&session->lock); |
960 | if (session->state != ISCSI_STATE_LOGGED_IN) { | 972 | if (session->state != ISCSI_STATE_LOGGED_IN) { |
961 | session->state = ISCSI_STATE_RECOVERY_FAILED; | 973 | session->state = ISCSI_STATE_RECOVERY_FAILED; |
962 | if (conn) | 974 | if (session->leadconn) |
963 | wake_up(&conn->ehwait); | 975 | wake_up(&session->leadconn->ehwait); |
964 | } | 976 | } |
965 | spin_unlock_bh(&session->lock); | 977 | spin_unlock_bh(&session->lock); |
966 | } | 978 | } |
@@ -971,7 +983,6 @@ int iscsi_eh_host_reset(struct scsi_cmnd *sc) | |||
971 | struct Scsi_Host *host = sc->device->host; | 983 | struct Scsi_Host *host = sc->device->host; |
972 | struct iscsi_session *session = iscsi_hostdata(host->hostdata); | 984 | struct iscsi_session *session = iscsi_hostdata(host->hostdata); |
973 | struct iscsi_conn *conn = session->leadconn; | 985 | struct iscsi_conn *conn = session->leadconn; |
974 | int fail_session = 0; | ||
975 | 986 | ||
976 | spin_lock_bh(&session->lock); | 987 | spin_lock_bh(&session->lock); |
977 | if (session->state == ISCSI_STATE_TERMINATE) { | 988 | if (session->state == ISCSI_STATE_TERMINATE) { |
@@ -982,19 +993,13 @@ failed: | |||
982 | return FAILED; | 993 | return FAILED; |
983 | } | 994 | } |
984 | 995 | ||
985 | if (sc->SCp.phase == session->age) { | ||
986 | debug_scsi("failing connection CID %d due to SCSI host reset\n", | ||
987 | conn->id); | ||
988 | fail_session = 1; | ||
989 | } | ||
990 | spin_unlock_bh(&session->lock); | 996 | spin_unlock_bh(&session->lock); |
991 | 997 | ||
992 | /* | 998 | /* |
993 | * we drop the lock here but the leadconn cannot be destoyed while | 999 | * we drop the lock here but the leadconn cannot be destoyed while |
994 | * we are in the scsi eh | 1000 | * we are in the scsi eh |
995 | */ | 1001 | */ |
996 | if (fail_session) | 1002 | iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); |
997 | iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); | ||
998 | 1003 | ||
999 | debug_scsi("iscsi_eh_host_reset wait for relogin\n"); | 1004 | debug_scsi("iscsi_eh_host_reset wait for relogin\n"); |
1000 | wait_event_interruptible(conn->ehwait, | 1005 | wait_event_interruptible(conn->ehwait, |
@@ -1015,62 +1020,43 @@ failed: | |||
1015 | } | 1020 | } |
1016 | EXPORT_SYMBOL_GPL(iscsi_eh_host_reset); | 1021 | EXPORT_SYMBOL_GPL(iscsi_eh_host_reset); |
1017 | 1022 | ||
1018 | static void iscsi_tmabort_timedout(unsigned long data) | 1023 | static void iscsi_tmf_timedout(unsigned long data) |
1019 | { | 1024 | { |
1020 | struct iscsi_cmd_task *ctask = (struct iscsi_cmd_task *)data; | 1025 | struct iscsi_conn *conn = (struct iscsi_conn *)data; |
1021 | struct iscsi_conn *conn = ctask->conn; | ||
1022 | struct iscsi_session *session = conn->session; | 1026 | struct iscsi_session *session = conn->session; |
1023 | 1027 | ||
1024 | spin_lock(&session->lock); | 1028 | spin_lock(&session->lock); |
1025 | if (conn->tmabort_state == TMABORT_INITIAL) { | 1029 | if (conn->tmf_state == TMF_QUEUED) { |
1026 | conn->tmabort_state = TMABORT_TIMEDOUT; | 1030 | conn->tmf_state = TMF_TIMEDOUT; |
1027 | debug_scsi("tmabort timedout [sc %p itt 0x%x]\n", | 1031 | debug_scsi("tmf timedout\n"); |
1028 | ctask->sc, ctask->itt); | ||
1029 | /* unblock eh_abort() */ | 1032 | /* unblock eh_abort() */ |
1030 | wake_up(&conn->ehwait); | 1033 | wake_up(&conn->ehwait); |
1031 | } | 1034 | } |
1032 | spin_unlock(&session->lock); | 1035 | spin_unlock(&session->lock); |
1033 | } | 1036 | } |
1034 | 1037 | ||
1035 | static int iscsi_exec_abort_task(struct scsi_cmnd *sc, | 1038 | static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn, |
1036 | struct iscsi_cmd_task *ctask) | 1039 | struct iscsi_tm *hdr, int age) |
1037 | { | 1040 | { |
1038 | struct iscsi_conn *conn = ctask->conn; | ||
1039 | struct iscsi_session *session = conn->session; | 1041 | struct iscsi_session *session = conn->session; |
1040 | struct iscsi_tm *hdr = &conn->tmhdr; | 1042 | struct iscsi_mgmt_task *mtask; |
1041 | |||
1042 | /* | ||
1043 | * ctask timed out but session is OK requests must be serialized. | ||
1044 | */ | ||
1045 | memset(hdr, 0, sizeof(struct iscsi_tm)); | ||
1046 | hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE; | ||
1047 | hdr->flags = ISCSI_TM_FUNC_ABORT_TASK; | ||
1048 | hdr->flags |= ISCSI_FLAG_CMD_FINAL; | ||
1049 | memcpy(hdr->lun, ctask->hdr->lun, sizeof(hdr->lun)); | ||
1050 | hdr->rtt = ctask->hdr->itt; | ||
1051 | hdr->refcmdsn = ctask->hdr->cmdsn; | ||
1052 | 1043 | ||
1053 | ctask->mtask = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)hdr, | 1044 | mtask = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)hdr, |
1054 | NULL, 0); | 1045 | NULL, 0); |
1055 | if (!ctask->mtask) { | 1046 | if (!mtask) { |
1056 | spin_unlock_bh(&session->lock); | 1047 | spin_unlock_bh(&session->lock); |
1057 | iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); | 1048 | iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); |
1058 | spin_lock_bh(&session->lock) | 1049 | spin_lock_bh(&session->lock); |
1059 | debug_scsi("abort sent failure [itt 0x%x]\n", ctask->itt); | 1050 | debug_scsi("tmf exec failure\n"); |
1060 | return -EPERM; | 1051 | return -EPERM; |
1061 | } | 1052 | } |
1062 | ctask->state = ISCSI_TASK_ABORTING; | 1053 | conn->tmfcmd_pdus_cnt++; |
1063 | 1054 | conn->tmf_timer.expires = 30 * HZ + jiffies; | |
1064 | debug_scsi("abort sent [itt 0x%x]\n", ctask->itt); | 1055 | conn->tmf_timer.function = iscsi_tmf_timedout; |
1056 | conn->tmf_timer.data = (unsigned long)conn; | ||
1057 | add_timer(&conn->tmf_timer); | ||
1058 | debug_scsi("tmf set timeout\n"); | ||
1065 | 1059 | ||
1066 | if (conn->tmabort_state == TMABORT_INITIAL) { | ||
1067 | conn->tmfcmd_pdus_cnt++; | ||
1068 | conn->tmabort_timer.expires = 20*HZ + jiffies; | ||
1069 | conn->tmabort_timer.function = iscsi_tmabort_timedout; | ||
1070 | conn->tmabort_timer.data = (unsigned long)ctask; | ||
1071 | add_timer(&conn->tmabort_timer); | ||
1072 | debug_scsi("abort set timeout [itt 0x%x]\n", ctask->itt); | ||
1073 | } | ||
1074 | spin_unlock_bh(&session->lock); | 1060 | spin_unlock_bh(&session->lock); |
1075 | mutex_unlock(&session->eh_mutex); | 1061 | mutex_unlock(&session->eh_mutex); |
1076 | scsi_queue_work(session->host, &conn->xmitwork); | 1062 | scsi_queue_work(session->host, &conn->xmitwork); |
@@ -1078,61 +1064,30 @@ static int iscsi_exec_abort_task(struct scsi_cmnd *sc, | |||
1078 | /* | 1064 | /* |
1079 | * block eh thread until: | 1065 | * block eh thread until: |
1080 | * | 1066 | * |
1081 | * 1) abort response | 1067 | * 1) tmf response |
1082 | * 2) abort timeout | 1068 | * 2) tmf timeout |
1083 | * 3) session is terminated or restarted or userspace has | 1069 | * 3) session is terminated or restarted or userspace has |
1084 | * given up on recovery | 1070 | * given up on recovery |
1085 | */ | 1071 | */ |
1086 | wait_event_interruptible(conn->ehwait, | 1072 | wait_event_interruptible(conn->ehwait, age != session->age || |
1087 | sc->SCp.phase != session->age || | ||
1088 | session->state != ISCSI_STATE_LOGGED_IN || | 1073 | session->state != ISCSI_STATE_LOGGED_IN || |
1089 | conn->tmabort_state != TMABORT_INITIAL); | 1074 | conn->tmf_state != TMF_QUEUED); |
1090 | if (signal_pending(current)) | 1075 | if (signal_pending(current)) |
1091 | flush_signals(current); | 1076 | flush_signals(current); |
1092 | del_timer_sync(&conn->tmabort_timer); | 1077 | del_timer_sync(&conn->tmf_timer); |
1078 | |||
1093 | mutex_lock(&session->eh_mutex); | 1079 | mutex_lock(&session->eh_mutex); |
1094 | spin_lock_bh(&session->lock); | 1080 | spin_lock_bh(&session->lock); |
1095 | return 0; | 1081 | /* if the session drops it will clean up the mtask */ |
1096 | } | 1082 | if (age != session->age || |
1097 | 1083 | session->state != ISCSI_STATE_LOGGED_IN) | |
1098 | /* | 1084 | return -ENOTCONN; |
1099 | * session lock must be held | ||
1100 | */ | ||
1101 | static struct iscsi_mgmt_task * | ||
1102 | iscsi_remove_mgmt_task(struct kfifo *fifo, uint32_t itt) | ||
1103 | { | ||
1104 | int i, nr_tasks = __kfifo_len(fifo) / sizeof(void*); | ||
1105 | struct iscsi_mgmt_task *task; | ||
1106 | |||
1107 | debug_scsi("searching %d tasks\n", nr_tasks); | ||
1108 | |||
1109 | for (i = 0; i < nr_tasks; i++) { | ||
1110 | __kfifo_get(fifo, (void*)&task, sizeof(void*)); | ||
1111 | debug_scsi("check task %u\n", task->itt); | ||
1112 | |||
1113 | if (task->itt == itt) { | ||
1114 | debug_scsi("matched task\n"); | ||
1115 | return task; | ||
1116 | } | ||
1117 | 1085 | ||
1118 | __kfifo_put(fifo, (void*)&task, sizeof(void*)); | 1086 | if (!list_empty(&mtask->running)) { |
1087 | list_del_init(&mtask->running); | ||
1088 | __kfifo_put(session->mgmtpool.queue, (void*)&mtask, | ||
1089 | sizeof(void*)); | ||
1119 | } | 1090 | } |
1120 | return NULL; | ||
1121 | } | ||
1122 | |||
1123 | static int iscsi_ctask_mtask_cleanup(struct iscsi_cmd_task *ctask) | ||
1124 | { | ||
1125 | struct iscsi_conn *conn = ctask->conn; | ||
1126 | struct iscsi_session *session = conn->session; | ||
1127 | |||
1128 | if (!ctask->mtask) | ||
1129 | return -EINVAL; | ||
1130 | |||
1131 | if (!iscsi_remove_mgmt_task(conn->mgmtqueue, ctask->mtask->itt)) | ||
1132 | list_del(&ctask->mtask->running); | ||
1133 | __kfifo_put(session->mgmtpool.queue, (void*)&ctask->mtask, | ||
1134 | sizeof(void*)); | ||
1135 | ctask->mtask = NULL; | ||
1136 | return 0; | 1091 | return 0; |
1137 | } | 1092 | } |
1138 | 1093 | ||
@@ -1156,7 +1111,6 @@ static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, | |||
1156 | conn->session->queued_cmdsn--; | 1111 | conn->session->queued_cmdsn--; |
1157 | else | 1112 | else |
1158 | conn->session->tt->cleanup_cmd_task(conn, ctask); | 1113 | conn->session->tt->cleanup_cmd_task(conn, ctask); |
1159 | iscsi_ctask_mtask_cleanup(ctask); | ||
1160 | 1114 | ||
1161 | sc->result = err; | 1115 | sc->result = err; |
1162 | scsi_set_resid(sc, scsi_bufflen(sc)); | 1116 | scsi_set_resid(sc, scsi_bufflen(sc)); |
@@ -1166,6 +1120,44 @@ static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, | |||
1166 | __iscsi_put_ctask(ctask); | 1120 | __iscsi_put_ctask(ctask); |
1167 | } | 1121 | } |
1168 | 1122 | ||
1123 | /* | ||
1124 | * Fail commands. session lock held and recv side suspended and xmit | ||
1125 | * thread flushed | ||
1126 | */ | ||
1127 | static void fail_all_commands(struct iscsi_conn *conn, unsigned lun) | ||
1128 | { | ||
1129 | struct iscsi_cmd_task *ctask, *tmp; | ||
1130 | |||
1131 | if (conn->ctask && (conn->ctask->sc->device->lun == lun || lun == -1)) | ||
1132 | conn->ctask = NULL; | ||
1133 | |||
1134 | /* flush pending */ | ||
1135 | list_for_each_entry_safe(ctask, tmp, &conn->xmitqueue, running) { | ||
1136 | if (lun == ctask->sc->device->lun || lun == -1) { | ||
1137 | debug_scsi("failing pending sc %p itt 0x%x\n", | ||
1138 | ctask->sc, ctask->itt); | ||
1139 | fail_command(conn, ctask, DID_BUS_BUSY << 16); | ||
1140 | } | ||
1141 | } | ||
1142 | |||
1143 | list_for_each_entry_safe(ctask, tmp, &conn->requeue, running) { | ||
1144 | if (lun == ctask->sc->device->lun || lun == -1) { | ||
1145 | debug_scsi("failing requeued sc %p itt 0x%x\n", | ||
1146 | ctask->sc, ctask->itt); | ||
1147 | fail_command(conn, ctask, DID_BUS_BUSY << 16); | ||
1148 | } | ||
1149 | } | ||
1150 | |||
1151 | /* fail all other running */ | ||
1152 | list_for_each_entry_safe(ctask, tmp, &conn->run_list, running) { | ||
1153 | if (lun == ctask->sc->device->lun || lun == -1) { | ||
1154 | debug_scsi("failing in progress sc %p itt 0x%x\n", | ||
1155 | ctask->sc, ctask->itt); | ||
1156 | fail_command(conn, ctask, DID_BUS_BUSY << 16); | ||
1157 | } | ||
1158 | } | ||
1159 | } | ||
1160 | |||
1169 | static void iscsi_suspend_tx(struct iscsi_conn *conn) | 1161 | static void iscsi_suspend_tx(struct iscsi_conn *conn) |
1170 | { | 1162 | { |
1171 | set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); | 1163 | set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); |
@@ -1178,13 +1170,26 @@ static void iscsi_start_tx(struct iscsi_conn *conn) | |||
1178 | scsi_queue_work(conn->session->host, &conn->xmitwork); | 1170 | scsi_queue_work(conn->session->host, &conn->xmitwork); |
1179 | } | 1171 | } |
1180 | 1172 | ||
1173 | static void iscsi_prep_abort_task_pdu(struct iscsi_cmd_task *ctask, | ||
1174 | struct iscsi_tm *hdr) | ||
1175 | { | ||
1176 | memset(hdr, 0, sizeof(*hdr)); | ||
1177 | hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE; | ||
1178 | hdr->flags = ISCSI_TM_FUNC_ABORT_TASK & ISCSI_FLAG_TM_FUNC_MASK; | ||
1179 | hdr->flags |= ISCSI_FLAG_CMD_FINAL; | ||
1180 | memcpy(hdr->lun, ctask->hdr->lun, sizeof(hdr->lun)); | ||
1181 | hdr->rtt = ctask->hdr->itt; | ||
1182 | hdr->refcmdsn = ctask->hdr->cmdsn; | ||
1183 | } | ||
1184 | |||
1181 | int iscsi_eh_abort(struct scsi_cmnd *sc) | 1185 | int iscsi_eh_abort(struct scsi_cmnd *sc) |
1182 | { | 1186 | { |
1183 | struct Scsi_Host *host = sc->device->host; | 1187 | struct Scsi_Host *host = sc->device->host; |
1184 | struct iscsi_session *session = iscsi_hostdata(host->hostdata); | 1188 | struct iscsi_session *session = iscsi_hostdata(host->hostdata); |
1185 | struct iscsi_cmd_task *ctask; | ||
1186 | struct iscsi_conn *conn; | 1189 | struct iscsi_conn *conn; |
1187 | int rc; | 1190 | struct iscsi_cmd_task *ctask; |
1191 | struct iscsi_tm *hdr; | ||
1192 | int rc, age; | ||
1188 | 1193 | ||
1189 | mutex_lock(&session->eh_mutex); | 1194 | mutex_lock(&session->eh_mutex); |
1190 | spin_lock_bh(&session->lock); | 1195 | spin_lock_bh(&session->lock); |
@@ -1199,19 +1204,23 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) | |||
1199 | return SUCCESS; | 1204 | return SUCCESS; |
1200 | } | 1205 | } |
1201 | 1206 | ||
1202 | ctask = (struct iscsi_cmd_task *)sc->SCp.ptr; | ||
1203 | conn = ctask->conn; | ||
1204 | |||
1205 | conn->eh_abort_cnt++; | ||
1206 | debug_scsi("aborting [sc %p itt 0x%x]\n", sc, ctask->itt); | ||
1207 | |||
1208 | /* | 1207 | /* |
1209 | * If we are not logged in or we have started a new session | 1208 | * If we are not logged in or we have started a new session |
1210 | * then let the host reset code handle this | 1209 | * then let the host reset code handle this |
1211 | */ | 1210 | */ |
1212 | if (session->state != ISCSI_STATE_LOGGED_IN || | 1211 | if (!session->leadconn || session->state != ISCSI_STATE_LOGGED_IN || |
1213 | sc->SCp.phase != session->age) | 1212 | sc->SCp.phase != session->age) { |
1214 | goto failed; | 1213 | spin_unlock_bh(&session->lock); |
1214 | mutex_unlock(&session->eh_mutex); | ||
1215 | return FAILED; | ||
1216 | } | ||
1217 | |||
1218 | conn = session->leadconn; | ||
1219 | conn->eh_abort_cnt++; | ||
1220 | age = session->age; | ||
1221 | |||
1222 | ctask = (struct iscsi_cmd_task *)sc->SCp.ptr; | ||
1223 | debug_scsi("aborting [sc %p itt 0x%x]\n", sc, ctask->itt); | ||
1215 | 1224 | ||
1216 | /* ctask completed before time out */ | 1225 | /* ctask completed before time out */ |
1217 | if (!ctask->sc) { | 1226 | if (!ctask->sc) { |
@@ -1219,27 +1228,26 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) | |||
1219 | goto success; | 1228 | goto success; |
1220 | } | 1229 | } |
1221 | 1230 | ||
1222 | /* what should we do here ? */ | ||
1223 | if (conn->ctask == ctask) { | ||
1224 | printk(KERN_INFO "iscsi: sc %p itt 0x%x partially sent. " | ||
1225 | "Failing abort\n", sc, ctask->itt); | ||
1226 | goto failed; | ||
1227 | } | ||
1228 | |||
1229 | if (ctask->state == ISCSI_TASK_PENDING) { | 1231 | if (ctask->state == ISCSI_TASK_PENDING) { |
1230 | fail_command(conn, ctask, DID_ABORT << 16); | 1232 | fail_command(conn, ctask, DID_ABORT << 16); |
1231 | goto success; | 1233 | goto success; |
1232 | } | 1234 | } |
1233 | 1235 | ||
1234 | conn->tmabort_state = TMABORT_INITIAL; | 1236 | /* only have one tmf outstanding at a time */ |
1235 | rc = iscsi_exec_abort_task(sc, ctask); | 1237 | if (conn->tmf_state != TMF_INITIAL) |
1236 | if (rc || sc->SCp.phase != session->age || | ||
1237 | session->state != ISCSI_STATE_LOGGED_IN) | ||
1238 | goto failed; | 1238 | goto failed; |
1239 | iscsi_ctask_mtask_cleanup(ctask); | 1239 | conn->tmf_state = TMF_QUEUED; |
1240 | 1240 | ||
1241 | switch (conn->tmabort_state) { | 1241 | hdr = &conn->tmhdr; |
1242 | case TMABORT_SUCCESS: | 1242 | iscsi_prep_abort_task_pdu(ctask, hdr); |
1243 | |||
1244 | if (iscsi_exec_task_mgmt_fn(conn, hdr, age)) { | ||
1245 | rc = FAILED; | ||
1246 | goto failed; | ||
1247 | } | ||
1248 | |||
1249 | switch (conn->tmf_state) { | ||
1250 | case TMF_SUCCESS: | ||
1243 | spin_unlock_bh(&session->lock); | 1251 | spin_unlock_bh(&session->lock); |
1244 | iscsi_suspend_tx(conn); | 1252 | iscsi_suspend_tx(conn); |
1245 | /* | 1253 | /* |
@@ -1248,22 +1256,26 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) | |||
1248 | write_lock_bh(conn->recv_lock); | 1256 | write_lock_bh(conn->recv_lock); |
1249 | spin_lock(&session->lock); | 1257 | spin_lock(&session->lock); |
1250 | fail_command(conn, ctask, DID_ABORT << 16); | 1258 | fail_command(conn, ctask, DID_ABORT << 16); |
1259 | conn->tmf_state = TMF_INITIAL; | ||
1251 | spin_unlock(&session->lock); | 1260 | spin_unlock(&session->lock); |
1252 | write_unlock_bh(conn->recv_lock); | 1261 | write_unlock_bh(conn->recv_lock); |
1253 | iscsi_start_tx(conn); | 1262 | iscsi_start_tx(conn); |
1254 | goto success_unlocked; | 1263 | goto success_unlocked; |
1255 | case TMABORT_NOT_FOUND: | 1264 | case TMF_TIMEDOUT: |
1256 | if (!ctask->sc) { | 1265 | spin_unlock_bh(&session->lock); |
1266 | iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); | ||
1267 | goto failed_unlocked; | ||
1268 | case TMF_NOT_FOUND: | ||
1269 | if (!sc->SCp.ptr) { | ||
1270 | conn->tmf_state = TMF_INITIAL; | ||
1257 | /* ctask completed before tmf abort response */ | 1271 | /* ctask completed before tmf abort response */ |
1258 | debug_scsi("sc completed while abort in progress\n"); | 1272 | debug_scsi("sc completed while abort in progress\n"); |
1259 | goto success; | 1273 | goto success; |
1260 | } | 1274 | } |
1261 | /* fall through */ | 1275 | /* fall through */ |
1262 | default: | 1276 | default: |
1263 | /* timedout or failed */ | 1277 | conn->tmf_state = TMF_INITIAL; |
1264 | spin_unlock_bh(&session->lock); | 1278 | goto failed; |
1265 | iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); | ||
1266 | goto failed_unlocked; | ||
1267 | } | 1279 | } |
1268 | 1280 | ||
1269 | success: | 1281 | success: |
@@ -1276,12 +1288,93 @@ success_unlocked: | |||
1276 | failed: | 1288 | failed: |
1277 | spin_unlock_bh(&session->lock); | 1289 | spin_unlock_bh(&session->lock); |
1278 | failed_unlocked: | 1290 | failed_unlocked: |
1279 | debug_scsi("abort failed [sc %lx itt 0x%x]\n", (long)sc, ctask->itt); | 1291 | debug_scsi("abort failed [sc %p itt 0x%x]\n", sc, |
1292 | ctask ? ctask->itt : 0); | ||
1280 | mutex_unlock(&session->eh_mutex); | 1293 | mutex_unlock(&session->eh_mutex); |
1281 | return FAILED; | 1294 | return FAILED; |
1282 | } | 1295 | } |
1283 | EXPORT_SYMBOL_GPL(iscsi_eh_abort); | 1296 | EXPORT_SYMBOL_GPL(iscsi_eh_abort); |
1284 | 1297 | ||
1298 | static void iscsi_prep_lun_reset_pdu(struct scsi_cmnd *sc, struct iscsi_tm *hdr) | ||
1299 | { | ||
1300 | memset(hdr, 0, sizeof(*hdr)); | ||
1301 | hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE; | ||
1302 | hdr->flags = ISCSI_TM_FUNC_LOGICAL_UNIT_RESET & ISCSI_FLAG_TM_FUNC_MASK; | ||
1303 | hdr->flags |= ISCSI_FLAG_CMD_FINAL; | ||
1304 | int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun); | ||
1305 | hdr->rtt = ISCSI_RESERVED_TAG; | ||
1306 | } | ||
1307 | |||
1308 | int iscsi_eh_device_reset(struct scsi_cmnd *sc) | ||
1309 | { | ||
1310 | struct Scsi_Host *host = sc->device->host; | ||
1311 | struct iscsi_session *session = iscsi_hostdata(host->hostdata); | ||
1312 | struct iscsi_conn *conn; | ||
1313 | struct iscsi_tm *hdr; | ||
1314 | int rc = FAILED; | ||
1315 | |||
1316 | debug_scsi("LU Reset [sc %p lun %u]\n", sc, sc->device->lun); | ||
1317 | |||
1318 | mutex_lock(&session->eh_mutex); | ||
1319 | spin_lock_bh(&session->lock); | ||
1320 | /* | ||
1321 | * Just check if we are not logged in. We cannot check for | ||
1322 | * the phase because the reset could come from a ioctl. | ||
1323 | */ | ||
1324 | if (!session->leadconn || session->state != ISCSI_STATE_LOGGED_IN) | ||
1325 | goto unlock; | ||
1326 | conn = session->leadconn; | ||
1327 | |||
1328 | /* only have one tmf outstanding at a time */ | ||
1329 | if (conn->tmf_state != TMF_INITIAL) | ||
1330 | goto unlock; | ||
1331 | conn->tmf_state = TMF_QUEUED; | ||
1332 | |||
1333 | hdr = &conn->tmhdr; | ||
1334 | iscsi_prep_lun_reset_pdu(sc, hdr); | ||
1335 | |||
1336 | if (iscsi_exec_task_mgmt_fn(conn, hdr, session->age)) { | ||
1337 | rc = FAILED; | ||
1338 | goto unlock; | ||
1339 | } | ||
1340 | |||
1341 | switch (conn->tmf_state) { | ||
1342 | case TMF_SUCCESS: | ||
1343 | break; | ||
1344 | case TMF_TIMEDOUT: | ||
1345 | spin_unlock_bh(&session->lock); | ||
1346 | iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); | ||
1347 | goto done; | ||
1348 | default: | ||
1349 | conn->tmf_state = TMF_INITIAL; | ||
1350 | goto unlock; | ||
1351 | } | ||
1352 | |||
1353 | rc = SUCCESS; | ||
1354 | spin_unlock_bh(&session->lock); | ||
1355 | |||
1356 | iscsi_suspend_tx(conn); | ||
1357 | /* need to grab the recv lock then session lock */ | ||
1358 | write_lock_bh(conn->recv_lock); | ||
1359 | spin_lock(&session->lock); | ||
1360 | fail_all_commands(conn, sc->device->lun); | ||
1361 | conn->tmf_state = TMF_INITIAL; | ||
1362 | spin_unlock(&session->lock); | ||
1363 | write_unlock_bh(conn->recv_lock); | ||
1364 | |||
1365 | iscsi_start_tx(conn); | ||
1366 | goto done; | ||
1367 | |||
1368 | unlock: | ||
1369 | spin_unlock_bh(&session->lock); | ||
1370 | done: | ||
1371 | debug_scsi("iscsi_eh_device_reset %s\n", | ||
1372 | rc == SUCCESS ? "SUCCESS" : "FAILED"); | ||
1373 | mutex_unlock(&session->eh_mutex); | ||
1374 | return rc; | ||
1375 | } | ||
1376 | EXPORT_SYMBOL_GPL(iscsi_eh_device_reset); | ||
1377 | |||
1285 | int | 1378 | int |
1286 | iscsi_pool_init(struct iscsi_queue *q, int max, void ***items, int item_size) | 1379 | iscsi_pool_init(struct iscsi_queue *q, int max, void ***items, int item_size) |
1287 | { | 1380 | { |
@@ -1546,17 +1639,12 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx) | |||
1546 | conn->c_stage = ISCSI_CONN_INITIAL_STAGE; | 1639 | conn->c_stage = ISCSI_CONN_INITIAL_STAGE; |
1547 | conn->id = conn_idx; | 1640 | conn->id = conn_idx; |
1548 | conn->exp_statsn = 0; | 1641 | conn->exp_statsn = 0; |
1549 | conn->tmabort_state = TMABORT_INITIAL; | 1642 | conn->tmf_state = TMF_INITIAL; |
1550 | INIT_LIST_HEAD(&conn->run_list); | 1643 | INIT_LIST_HEAD(&conn->run_list); |
1551 | INIT_LIST_HEAD(&conn->mgmt_run_list); | 1644 | INIT_LIST_HEAD(&conn->mgmt_run_list); |
1645 | INIT_LIST_HEAD(&conn->mgmtqueue); | ||
1552 | INIT_LIST_HEAD(&conn->xmitqueue); | 1646 | INIT_LIST_HEAD(&conn->xmitqueue); |
1553 | 1647 | INIT_LIST_HEAD(&conn->requeue); | |
1554 | /* initialize general immediate & non-immediate PDU commands queue */ | ||
1555 | conn->mgmtqueue = kfifo_alloc(session->mgmtpool_max * sizeof(void*), | ||
1556 | GFP_KERNEL, NULL); | ||
1557 | if (conn->mgmtqueue == ERR_PTR(-ENOMEM)) | ||
1558 | goto mgmtqueue_alloc_fail; | ||
1559 | |||
1560 | INIT_WORK(&conn->xmitwork, iscsi_xmitworker); | 1648 | INIT_WORK(&conn->xmitwork, iscsi_xmitworker); |
1561 | 1649 | ||
1562 | /* allocate login_mtask used for the login/text sequences */ | 1650 | /* allocate login_mtask used for the login/text sequences */ |
@@ -1574,7 +1662,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx) | |||
1574 | goto login_mtask_data_alloc_fail; | 1662 | goto login_mtask_data_alloc_fail; |
1575 | conn->login_mtask->data = conn->data = data; | 1663 | conn->login_mtask->data = conn->data = data; |
1576 | 1664 | ||
1577 | init_timer(&conn->tmabort_timer); | 1665 | init_timer(&conn->tmf_timer); |
1578 | init_waitqueue_head(&conn->ehwait); | 1666 | init_waitqueue_head(&conn->ehwait); |
1579 | 1667 | ||
1580 | return cls_conn; | 1668 | return cls_conn; |
@@ -1583,8 +1671,6 @@ login_mtask_data_alloc_fail: | |||
1583 | __kfifo_put(session->mgmtpool.queue, (void*)&conn->login_mtask, | 1671 | __kfifo_put(session->mgmtpool.queue, (void*)&conn->login_mtask, |
1584 | sizeof(void*)); | 1672 | sizeof(void*)); |
1585 | login_mtask_alloc_fail: | 1673 | login_mtask_alloc_fail: |
1586 | kfifo_free(conn->mgmtqueue); | ||
1587 | mgmtqueue_alloc_fail: | ||
1588 | iscsi_destroy_conn(cls_conn); | 1674 | iscsi_destroy_conn(cls_conn); |
1589 | return NULL; | 1675 | return NULL; |
1590 | } | 1676 | } |
@@ -1604,7 +1690,6 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn) | |||
1604 | unsigned long flags; | 1690 | unsigned long flags; |
1605 | 1691 | ||
1606 | spin_lock_bh(&session->lock); | 1692 | spin_lock_bh(&session->lock); |
1607 | set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); | ||
1608 | conn->c_stage = ISCSI_CONN_CLEANUP_WAIT; | 1693 | conn->c_stage = ISCSI_CONN_CLEANUP_WAIT; |
1609 | if (session->leadconn == conn) { | 1694 | if (session->leadconn == conn) { |
1610 | /* | 1695 | /* |
@@ -1637,7 +1722,7 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn) | |||
1637 | } | 1722 | } |
1638 | 1723 | ||
1639 | /* flush queued up work because we free the connection below */ | 1724 | /* flush queued up work because we free the connection below */ |
1640 | scsi_flush_work(session->host); | 1725 | iscsi_suspend_tx(conn); |
1641 | 1726 | ||
1642 | spin_lock_bh(&session->lock); | 1727 | spin_lock_bh(&session->lock); |
1643 | kfree(conn->data); | 1728 | kfree(conn->data); |
@@ -1648,8 +1733,6 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn) | |||
1648 | session->leadconn = NULL; | 1733 | session->leadconn = NULL; |
1649 | spin_unlock_bh(&session->lock); | 1734 | spin_unlock_bh(&session->lock); |
1650 | 1735 | ||
1651 | kfifo_free(conn->mgmtqueue); | ||
1652 | |||
1653 | iscsi_destroy_conn(cls_conn); | 1736 | iscsi_destroy_conn(cls_conn); |
1654 | } | 1737 | } |
1655 | EXPORT_SYMBOL_GPL(iscsi_conn_teardown); | 1738 | EXPORT_SYMBOL_GPL(iscsi_conn_teardown); |
@@ -1684,7 +1767,7 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn) | |||
1684 | * commands after successful recovery | 1767 | * commands after successful recovery |
1685 | */ | 1768 | */ |
1686 | conn->stop_stage = 0; | 1769 | conn->stop_stage = 0; |
1687 | conn->tmabort_state = TMABORT_INITIAL; | 1770 | conn->tmf_state = TMF_INITIAL; |
1688 | session->age++; | 1771 | session->age++; |
1689 | spin_unlock_bh(&session->lock); | 1772 | spin_unlock_bh(&session->lock); |
1690 | 1773 | ||
@@ -1709,10 +1792,11 @@ flush_control_queues(struct iscsi_session *session, struct iscsi_conn *conn) | |||
1709 | struct iscsi_mgmt_task *mtask, *tmp; | 1792 | struct iscsi_mgmt_task *mtask, *tmp; |
1710 | 1793 | ||
1711 | /* handle pending */ | 1794 | /* handle pending */ |
1712 | while (__kfifo_get(conn->mgmtqueue, (void*)&mtask, sizeof(void*))) { | 1795 | list_for_each_entry_safe(mtask, tmp, &conn->mgmtqueue, running) { |
1796 | debug_scsi("flushing pending mgmt task itt 0x%x\n", mtask->itt); | ||
1797 | list_del_init(&mtask->running); | ||
1713 | if (mtask == conn->login_mtask) | 1798 | if (mtask == conn->login_mtask) |
1714 | continue; | 1799 | continue; |
1715 | debug_scsi("flushing pending mgmt task itt 0x%x\n", mtask->itt); | ||
1716 | __kfifo_put(session->mgmtpool.queue, (void*)&mtask, | 1800 | __kfifo_put(session->mgmtpool.queue, (void*)&mtask, |
1717 | sizeof(void*)); | 1801 | sizeof(void*)); |
1718 | } | 1802 | } |
@@ -1720,7 +1804,7 @@ flush_control_queues(struct iscsi_session *session, struct iscsi_conn *conn) | |||
1720 | /* handle running */ | 1804 | /* handle running */ |
1721 | list_for_each_entry_safe(mtask, tmp, &conn->mgmt_run_list, running) { | 1805 | list_for_each_entry_safe(mtask, tmp, &conn->mgmt_run_list, running) { |
1722 | debug_scsi("flushing running mgmt task itt 0x%x\n", mtask->itt); | 1806 | debug_scsi("flushing running mgmt task itt 0x%x\n", mtask->itt); |
1723 | list_del(&mtask->running); | 1807 | list_del_init(&mtask->running); |
1724 | 1808 | ||
1725 | if (mtask == conn->login_mtask) | 1809 | if (mtask == conn->login_mtask) |
1726 | continue; | 1810 | continue; |
@@ -1731,28 +1815,6 @@ flush_control_queues(struct iscsi_session *session, struct iscsi_conn *conn) | |||
1731 | conn->mtask = NULL; | 1815 | conn->mtask = NULL; |
1732 | } | 1816 | } |
1733 | 1817 | ||
1734 | /* Fail commands. Mutex and session lock held and recv side suspended */ | ||
1735 | static void fail_all_commands(struct iscsi_conn *conn) | ||
1736 | { | ||
1737 | struct iscsi_cmd_task *ctask, *tmp; | ||
1738 | |||
1739 | /* flush pending */ | ||
1740 | list_for_each_entry_safe(ctask, tmp, &conn->xmitqueue, running) { | ||
1741 | debug_scsi("failing pending sc %p itt 0x%x\n", ctask->sc, | ||
1742 | ctask->itt); | ||
1743 | fail_command(conn, ctask, DID_BUS_BUSY << 16); | ||
1744 | } | ||
1745 | |||
1746 | /* fail all other running */ | ||
1747 | list_for_each_entry_safe(ctask, tmp, &conn->run_list, running) { | ||
1748 | debug_scsi("failing in progress sc %p itt 0x%x\n", | ||
1749 | ctask->sc, ctask->itt); | ||
1750 | fail_command(conn, ctask, DID_BUS_BUSY << 16); | ||
1751 | } | ||
1752 | |||
1753 | conn->ctask = NULL; | ||
1754 | } | ||
1755 | |||
1756 | static void iscsi_start_session_recovery(struct iscsi_session *session, | 1818 | static void iscsi_start_session_recovery(struct iscsi_session *session, |
1757 | struct iscsi_conn *conn, int flag) | 1819 | struct iscsi_conn *conn, int flag) |
1758 | { | 1820 | { |
@@ -1818,7 +1880,7 @@ static void iscsi_start_session_recovery(struct iscsi_session *session, | |||
1818 | * flush queues. | 1880 | * flush queues. |
1819 | */ | 1881 | */ |
1820 | spin_lock_bh(&session->lock); | 1882 | spin_lock_bh(&session->lock); |
1821 | fail_all_commands(conn); | 1883 | fail_all_commands(conn, -1); |
1822 | flush_control_queues(session, conn); | 1884 | flush_control_queues(session, conn); |
1823 | spin_unlock_bh(&session->lock); | 1885 | spin_unlock_bh(&session->lock); |
1824 | mutex_unlock(&session->eh_mutex); | 1886 | mutex_unlock(&session->eh_mutex); |
@@ -1869,6 +1931,9 @@ int iscsi_set_param(struct iscsi_cls_conn *cls_conn, | |||
1869 | uint32_t value; | 1931 | uint32_t value; |
1870 | 1932 | ||
1871 | switch(param) { | 1933 | switch(param) { |
1934 | case ISCSI_PARAM_FAST_ABORT: | ||
1935 | sscanf(buf, "%d", &session->fast_abort); | ||
1936 | break; | ||
1872 | case ISCSI_PARAM_MAX_RECV_DLENGTH: | 1937 | case ISCSI_PARAM_MAX_RECV_DLENGTH: |
1873 | sscanf(buf, "%d", &conn->max_recv_dlength); | 1938 | sscanf(buf, "%d", &conn->max_recv_dlength); |
1874 | break; | 1939 | break; |
@@ -1983,6 +2048,9 @@ int iscsi_session_get_param(struct iscsi_cls_session *cls_session, | |||
1983 | int len; | 2048 | int len; |
1984 | 2049 | ||
1985 | switch(param) { | 2050 | switch(param) { |
2051 | case ISCSI_PARAM_FAST_ABORT: | ||
2052 | len = sprintf(buf, "%d\n", session->fast_abort); | ||
2053 | break; | ||
1986 | case ISCSI_PARAM_INITIAL_R2T_EN: | 2054 | case ISCSI_PARAM_INITIAL_R2T_EN: |
1987 | len = sprintf(buf, "%d\n", session->initial_r2t_en); | 2055 | len = sprintf(buf, "%d\n", session->initial_r2t_en); |
1988 | break; | 2056 | break; |