diff options
Diffstat (limited to 'drivers/scsi/libiscsi.c')
-rw-r--r-- | drivers/scsi/libiscsi.c | 78 |
1 files changed, 38 insertions, 40 deletions
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index c542d0e95e68..5d8862189485 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c | |||
@@ -481,8 +481,8 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | |||
481 | break; | 481 | break; |
482 | case ISCSI_OP_ASYNC_EVENT: | 482 | case ISCSI_OP_ASYNC_EVENT: |
483 | conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; | 483 | conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; |
484 | /* we need sth like iscsi_async_event_rsp() */ | 484 | if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen)) |
485 | rc = ISCSI_ERR_BAD_OPCODE; | 485 | rc = ISCSI_ERR_CONN_FAILED; |
486 | break; | 486 | break; |
487 | default: | 487 | default: |
488 | rc = ISCSI_ERR_BAD_OPCODE; | 488 | rc = ISCSI_ERR_BAD_OPCODE; |
@@ -578,6 +578,27 @@ void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err) | |||
578 | } | 578 | } |
579 | EXPORT_SYMBOL_GPL(iscsi_conn_failure); | 579 | EXPORT_SYMBOL_GPL(iscsi_conn_failure); |
580 | 580 | ||
581 | static int iscsi_xmit_imm_task(struct iscsi_conn *conn) | ||
582 | { | ||
583 | struct iscsi_hdr *hdr = conn->mtask->hdr; | ||
584 | int rc, was_logout = 0; | ||
585 | |||
586 | if ((hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGOUT) { | ||
587 | conn->session->state = ISCSI_STATE_IN_RECOVERY; | ||
588 | iscsi_block_session(session_to_cls(conn->session)); | ||
589 | was_logout = 1; | ||
590 | } | ||
591 | rc = conn->session->tt->xmit_mgmt_task(conn, conn->mtask); | ||
592 | if (rc) | ||
593 | return rc; | ||
594 | |||
595 | if (was_logout) { | ||
596 | set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); | ||
597 | return -ENODATA; | ||
598 | } | ||
599 | return 0; | ||
600 | } | ||
601 | |||
581 | /** | 602 | /** |
582 | * iscsi_data_xmit - xmit any command into the scheduled connection | 603 | * iscsi_data_xmit - xmit any command into the scheduled connection |
583 | * @conn: iscsi connection | 604 | * @conn: iscsi connection |
@@ -623,7 +644,7 @@ static int iscsi_data_xmit(struct iscsi_conn *conn) | |||
623 | conn->ctask = NULL; | 644 | conn->ctask = NULL; |
624 | } | 645 | } |
625 | if (conn->mtask) { | 646 | if (conn->mtask) { |
626 | rc = tt->xmit_mgmt_task(conn, conn->mtask); | 647 | rc = iscsi_xmit_imm_task(conn); |
627 | if (rc) | 648 | if (rc) |
628 | goto again; | 649 | goto again; |
629 | /* done with this in-progress mtask */ | 650 | /* done with this in-progress mtask */ |
@@ -638,7 +659,7 @@ static int iscsi_data_xmit(struct iscsi_conn *conn) | |||
638 | list_add_tail(&conn->mtask->running, | 659 | list_add_tail(&conn->mtask->running, |
639 | &conn->mgmt_run_list); | 660 | &conn->mgmt_run_list); |
640 | spin_unlock_bh(&conn->session->lock); | 661 | spin_unlock_bh(&conn->session->lock); |
641 | rc = tt->xmit_mgmt_task(conn, conn->mtask); | 662 | rc = iscsi_xmit_imm_task(conn); |
642 | if (rc) | 663 | if (rc) |
643 | goto again; | 664 | goto again; |
644 | } | 665 | } |
@@ -661,8 +682,6 @@ static int iscsi_data_xmit(struct iscsi_conn *conn) | |||
661 | spin_unlock_bh(&conn->session->lock); | 682 | spin_unlock_bh(&conn->session->lock); |
662 | 683 | ||
663 | rc = tt->xmit_cmd_task(conn, conn->ctask); | 684 | rc = tt->xmit_cmd_task(conn, conn->ctask); |
664 | if (rc) | ||
665 | goto again; | ||
666 | 685 | ||
667 | spin_lock_bh(&conn->session->lock); | 686 | spin_lock_bh(&conn->session->lock); |
668 | __iscsi_put_ctask(conn->ctask); | 687 | __iscsi_put_ctask(conn->ctask); |
@@ -778,6 +797,10 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) | |||
778 | } | 797 | } |
779 | 798 | ||
780 | conn = session->leadconn; | 799 | conn = session->leadconn; |
800 | if (!conn) { | ||
801 | reason = FAILURE_SESSION_FREED; | ||
802 | goto fault; | ||
803 | } | ||
781 | 804 | ||
782 | if (!__kfifo_get(session->cmdpool.queue, (void*)&ctask, | 805 | if (!__kfifo_get(session->cmdpool.queue, (void*)&ctask, |
783 | sizeof(void*))) { | 806 | sizeof(void*))) { |
@@ -952,13 +975,13 @@ int iscsi_eh_host_reset(struct scsi_cmnd *sc) | |||
952 | if (session->state == ISCSI_STATE_TERMINATE) { | 975 | if (session->state == ISCSI_STATE_TERMINATE) { |
953 | failed: | 976 | failed: |
954 | debug_scsi("failing host reset: session terminated " | 977 | debug_scsi("failing host reset: session terminated " |
955 | "[CID %d age %d]", conn->id, session->age); | 978 | "[CID %d age %d]\n", conn->id, session->age); |
956 | spin_unlock_bh(&session->lock); | 979 | spin_unlock_bh(&session->lock); |
957 | return FAILED; | 980 | return FAILED; |
958 | } | 981 | } |
959 | 982 | ||
960 | if (sc->SCp.phase == session->age) { | 983 | if (sc->SCp.phase == session->age) { |
961 | debug_scsi("failing connection CID %d due to SCSI host reset", | 984 | debug_scsi("failing connection CID %d due to SCSI host reset\n", |
962 | conn->id); | 985 | conn->id); |
963 | fail_session = 1; | 986 | fail_session = 1; |
964 | } | 987 | } |
@@ -1031,7 +1054,8 @@ static int iscsi_exec_abort_task(struct scsi_cmnd *sc, | |||
1031 | NULL, 0); | 1054 | NULL, 0); |
1032 | if (rc) { | 1055 | if (rc) { |
1033 | iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); | 1056 | iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); |
1034 | debug_scsi("abort sent failure [itt 0x%x] %d", ctask->itt, rc); | 1057 | debug_scsi("abort sent failure [itt 0x%x] %d\n", ctask->itt, |
1058 | rc); | ||
1035 | return rc; | 1059 | return rc; |
1036 | } | 1060 | } |
1037 | 1061 | ||
@@ -1048,7 +1072,7 @@ static int iscsi_exec_abort_task(struct scsi_cmnd *sc, | |||
1048 | conn->tmabort_timer.function = iscsi_tmabort_timedout; | 1072 | conn->tmabort_timer.function = iscsi_tmabort_timedout; |
1049 | conn->tmabort_timer.data = (unsigned long)ctask; | 1073 | conn->tmabort_timer.data = (unsigned long)ctask; |
1050 | add_timer(&conn->tmabort_timer); | 1074 | add_timer(&conn->tmabort_timer); |
1051 | debug_scsi("abort set timeout [itt 0x%x]", ctask->itt); | 1075 | debug_scsi("abort set timeout [itt 0x%x]\n", ctask->itt); |
1052 | } | 1076 | } |
1053 | spin_unlock_bh(&session->lock); | 1077 | spin_unlock_bh(&session->lock); |
1054 | mutex_unlock(&conn->xmitmutex); | 1078 | mutex_unlock(&conn->xmitmutex); |
@@ -1377,7 +1401,6 @@ iscsi_session_setup(struct iscsi_transport *iscsit, | |||
1377 | } | 1401 | } |
1378 | 1402 | ||
1379 | spin_lock_init(&session->lock); | 1403 | spin_lock_init(&session->lock); |
1380 | INIT_LIST_HEAD(&session->connections); | ||
1381 | 1404 | ||
1382 | /* initialize immediate command pool */ | 1405 | /* initialize immediate command pool */ |
1383 | if (iscsi_pool_init(&session->mgmtpool, session->mgmtpool_max, | 1406 | if (iscsi_pool_init(&session->mgmtpool, session->mgmtpool_max, |
@@ -1580,16 +1603,11 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn) | |||
1580 | kfree(conn->persistent_address); | 1603 | kfree(conn->persistent_address); |
1581 | __kfifo_put(session->mgmtpool.queue, (void*)&conn->login_mtask, | 1604 | __kfifo_put(session->mgmtpool.queue, (void*)&conn->login_mtask, |
1582 | sizeof(void*)); | 1605 | sizeof(void*)); |
1583 | list_del(&conn->item); | 1606 | if (session->leadconn == conn) { |
1584 | if (list_empty(&session->connections)) | ||
1585 | session->leadconn = NULL; | 1607 | session->leadconn = NULL; |
1586 | if (session->leadconn && session->leadconn == conn) | ||
1587 | session->leadconn = container_of(session->connections.next, | ||
1588 | struct iscsi_conn, item); | ||
1589 | |||
1590 | if (session->leadconn == NULL) | ||
1591 | /* no connections exits.. reset sequencing */ | 1608 | /* no connections exits.. reset sequencing */ |
1592 | session->cmdsn = session->max_cmdsn = session->exp_cmdsn = 1; | 1609 | session->cmdsn = session->max_cmdsn = session->exp_cmdsn = 1; |
1610 | } | ||
1593 | spin_unlock_bh(&session->lock); | 1611 | spin_unlock_bh(&session->lock); |
1594 | 1612 | ||
1595 | kfifo_free(conn->immqueue); | 1613 | kfifo_free(conn->immqueue); |
@@ -1777,32 +1795,12 @@ int iscsi_conn_bind(struct iscsi_cls_session *cls_session, | |||
1777 | struct iscsi_cls_conn *cls_conn, int is_leading) | 1795 | struct iscsi_cls_conn *cls_conn, int is_leading) |
1778 | { | 1796 | { |
1779 | struct iscsi_session *session = class_to_transport_session(cls_session); | 1797 | struct iscsi_session *session = class_to_transport_session(cls_session); |
1780 | struct iscsi_conn *tmp = ERR_PTR(-EEXIST), *conn = cls_conn->dd_data; | 1798 | struct iscsi_conn *conn = cls_conn->dd_data; |
1781 | 1799 | ||
1782 | /* lookup for existing connection */ | ||
1783 | spin_lock_bh(&session->lock); | 1800 | spin_lock_bh(&session->lock); |
1784 | list_for_each_entry(tmp, &session->connections, item) { | ||
1785 | if (tmp == conn) { | ||
1786 | if (conn->c_stage != ISCSI_CONN_STOPPED || | ||
1787 | conn->stop_stage == STOP_CONN_TERM) { | ||
1788 | printk(KERN_ERR "iscsi: can't bind " | ||
1789 | "non-stopped connection (%d:%d)\n", | ||
1790 | conn->c_stage, conn->stop_stage); | ||
1791 | spin_unlock_bh(&session->lock); | ||
1792 | return -EIO; | ||
1793 | } | ||
1794 | break; | ||
1795 | } | ||
1796 | } | ||
1797 | if (tmp != conn) { | ||
1798 | /* bind new iSCSI connection to session */ | ||
1799 | conn->session = session; | ||
1800 | list_add(&conn->item, &session->connections); | ||
1801 | } | ||
1802 | spin_unlock_bh(&session->lock); | ||
1803 | |||
1804 | if (is_leading) | 1801 | if (is_leading) |
1805 | session->leadconn = conn; | 1802 | session->leadconn = conn; |
1803 | spin_unlock_bh(&session->lock); | ||
1806 | 1804 | ||
1807 | /* | 1805 | /* |
1808 | * Unblock xmitworker(), Login Phase will pass through. | 1806 | * Unblock xmitworker(), Login Phase will pass through. |