diff options
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/libiscsi.c | 62 | ||||
-rw-r--r-- | drivers/scsi/libiscsi_tcp.c | 6 |
2 files changed, 53 insertions, 15 deletions
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 59908aead531..b55b7991d5fa 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c | |||
@@ -954,6 +954,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | |||
954 | task = iscsi_itt_to_ctask(conn, hdr->itt); | 954 | task = iscsi_itt_to_ctask(conn, hdr->itt); |
955 | if (!task) | 955 | if (!task) |
956 | return ISCSI_ERR_BAD_ITT; | 956 | return ISCSI_ERR_BAD_ITT; |
957 | task->last_xfer = jiffies; | ||
957 | break; | 958 | break; |
958 | case ISCSI_OP_R2T: | 959 | case ISCSI_OP_R2T: |
959 | /* | 960 | /* |
@@ -1192,10 +1193,12 @@ static int iscsi_xmit_task(struct iscsi_conn *conn) | |||
1192 | spin_unlock_bh(&conn->session->lock); | 1193 | spin_unlock_bh(&conn->session->lock); |
1193 | rc = conn->session->tt->xmit_task(task); | 1194 | rc = conn->session->tt->xmit_task(task); |
1194 | spin_lock_bh(&conn->session->lock); | 1195 | spin_lock_bh(&conn->session->lock); |
1195 | __iscsi_put_task(task); | 1196 | if (!rc) { |
1196 | if (!rc) | ||
1197 | /* done with this task */ | 1197 | /* done with this task */ |
1198 | task->last_xfer = jiffies; | ||
1198 | conn->task = NULL; | 1199 | conn->task = NULL; |
1200 | } | ||
1201 | __iscsi_put_task(task); | ||
1199 | return rc; | 1202 | return rc; |
1200 | } | 1203 | } |
1201 | 1204 | ||
@@ -1361,6 +1364,9 @@ static inline struct iscsi_task *iscsi_alloc_task(struct iscsi_conn *conn, | |||
1361 | task->state = ISCSI_TASK_PENDING; | 1364 | task->state = ISCSI_TASK_PENDING; |
1362 | task->conn = conn; | 1365 | task->conn = conn; |
1363 | task->sc = sc; | 1366 | task->sc = sc; |
1367 | task->have_checked_conn = false; | ||
1368 | task->last_timeout = jiffies; | ||
1369 | task->last_xfer = jiffies; | ||
1364 | INIT_LIST_HEAD(&task->running); | 1370 | INIT_LIST_HEAD(&task->running); |
1365 | return task; | 1371 | return task; |
1366 | } | 1372 | } |
@@ -1716,17 +1722,18 @@ static int iscsi_has_ping_timed_out(struct iscsi_conn *conn) | |||
1716 | return 0; | 1722 | return 0; |
1717 | } | 1723 | } |
1718 | 1724 | ||
1719 | static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *scmd) | 1725 | static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc) |
1720 | { | 1726 | { |
1727 | enum blk_eh_timer_return rc = BLK_EH_NOT_HANDLED; | ||
1728 | struct iscsi_task *task = NULL; | ||
1721 | struct iscsi_cls_session *cls_session; | 1729 | struct iscsi_cls_session *cls_session; |
1722 | struct iscsi_session *session; | 1730 | struct iscsi_session *session; |
1723 | struct iscsi_conn *conn; | 1731 | struct iscsi_conn *conn; |
1724 | enum blk_eh_timer_return rc = BLK_EH_NOT_HANDLED; | ||
1725 | 1732 | ||
1726 | cls_session = starget_to_session(scsi_target(scmd->device)); | 1733 | cls_session = starget_to_session(scsi_target(sc->device)); |
1727 | session = cls_session->dd_data; | 1734 | session = cls_session->dd_data; |
1728 | 1735 | ||
1729 | ISCSI_DBG_SESSION(session, "scsi cmd %p timedout\n", scmd); | 1736 | ISCSI_DBG_SESSION(session, "scsi cmd %p timedout\n", sc); |
1730 | 1737 | ||
1731 | spin_lock(&session->lock); | 1738 | spin_lock(&session->lock); |
1732 | if (session->state != ISCSI_STATE_LOGGED_IN) { | 1739 | if (session->state != ISCSI_STATE_LOGGED_IN) { |
@@ -1745,6 +1752,26 @@ static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *scmd) | |||
1745 | goto done; | 1752 | goto done; |
1746 | } | 1753 | } |
1747 | 1754 | ||
1755 | task = (struct iscsi_task *)sc->SCp.ptr; | ||
1756 | if (!task) | ||
1757 | goto done; | ||
1758 | /* | ||
1759 | * If we have sent (at least queued to the network layer) a pdu or | ||
1760 | * recvd one for the task since the last timeout ask for | ||
1761 | * more time. If on the next timeout we have not made progress | ||
1762 | * we can check if it is the task or connection when we send the | ||
1763 | * nop as a ping. | ||
1764 | */ | ||
1765 | if (time_after_eq(task->last_xfer, task->last_timeout)) { | ||
1766 | ISCSI_DBG_CONN(conn, "Command making progress. Asking " | ||
1767 | "scsi-ml for more time to complete. " | ||
1768 | "Last data recv at %lu. Last timeout was at " | ||
1769 | "%lu\n.", task->last_xfer, task->last_timeout); | ||
1770 | task->have_checked_conn = false; | ||
1771 | rc = BLK_EH_RESET_TIMER; | ||
1772 | goto done; | ||
1773 | } | ||
1774 | |||
1748 | if (!conn->recv_timeout && !conn->ping_timeout) | 1775 | if (!conn->recv_timeout && !conn->ping_timeout) |
1749 | goto done; | 1776 | goto done; |
1750 | /* | 1777 | /* |
@@ -1755,20 +1782,29 @@ static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *scmd) | |||
1755 | rc = BLK_EH_RESET_TIMER; | 1782 | rc = BLK_EH_RESET_TIMER; |
1756 | goto done; | 1783 | goto done; |
1757 | } | 1784 | } |
1785 | |||
1786 | /* Assumes nop timeout is shorter than scsi cmd timeout */ | ||
1787 | if (task->have_checked_conn) | ||
1788 | goto done; | ||
1789 | |||
1758 | /* | 1790 | /* |
1759 | * if we are about to check the transport then give the command | 1791 | * Checking the transport already or nop from a cmd timeout still |
1760 | * more time | 1792 | * running |
1761 | */ | 1793 | */ |
1762 | if (time_before_eq(conn->last_recv + (conn->recv_timeout * HZ), | 1794 | if (conn->ping_task) { |
1763 | jiffies)) { | 1795 | task->have_checked_conn = true; |
1764 | rc = BLK_EH_RESET_TIMER; | 1796 | rc = BLK_EH_RESET_TIMER; |
1765 | goto done; | 1797 | goto done; |
1766 | } | 1798 | } |
1767 | 1799 | ||
1768 | /* if in the middle of checking the transport then give us more time */ | 1800 | /* Make sure there is a transport check done */ |
1769 | if (conn->ping_task) | 1801 | iscsi_send_nopout(conn, NULL); |
1770 | rc = BLK_EH_RESET_TIMER; | 1802 | task->have_checked_conn = true; |
1803 | rc = BLK_EH_RESET_TIMER; | ||
1804 | |||
1771 | done: | 1805 | done: |
1806 | if (task) | ||
1807 | task->last_timeout = jiffies; | ||
1772 | spin_unlock(&session->lock); | 1808 | spin_unlock(&session->lock); |
1773 | ISCSI_DBG_SESSION(session, "return %s\n", rc == BLK_EH_RESET_TIMER ? | 1809 | ISCSI_DBG_SESSION(session, "return %s\n", rc == BLK_EH_RESET_TIMER ? |
1774 | "timer reset" : "nh"); | 1810 | "timer reset" : "nh"); |
diff --git a/drivers/scsi/libiscsi_tcp.c b/drivers/scsi/libiscsi_tcp.c index 2bc07090321d..2e0746d70303 100644 --- a/drivers/scsi/libiscsi_tcp.c +++ b/drivers/scsi/libiscsi_tcp.c | |||
@@ -686,6 +686,7 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr) | |||
686 | "offset=%d, datalen=%d)\n", | 686 | "offset=%d, datalen=%d)\n", |
687 | tcp_task->data_offset, | 687 | tcp_task->data_offset, |
688 | tcp_conn->in.datalen); | 688 | tcp_conn->in.datalen); |
689 | task->last_xfer = jiffies; | ||
689 | rc = iscsi_segment_seek_sg(&tcp_conn->in.segment, | 690 | rc = iscsi_segment_seek_sg(&tcp_conn->in.segment, |
690 | sdb->table.sgl, | 691 | sdb->table.sgl, |
691 | sdb->table.nents, | 692 | sdb->table.nents, |
@@ -713,9 +714,10 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr) | |||
713 | rc = ISCSI_ERR_BAD_ITT; | 714 | rc = ISCSI_ERR_BAD_ITT; |
714 | else if (ahslen) | 715 | else if (ahslen) |
715 | rc = ISCSI_ERR_AHSLEN; | 716 | rc = ISCSI_ERR_AHSLEN; |
716 | else if (task->sc->sc_data_direction == DMA_TO_DEVICE) | 717 | else if (task->sc->sc_data_direction == DMA_TO_DEVICE) { |
718 | task->last_xfer = jiffies; | ||
717 | rc = iscsi_tcp_r2t_rsp(conn, task); | 719 | rc = iscsi_tcp_r2t_rsp(conn, task); |
718 | else | 720 | } else |
719 | rc = ISCSI_ERR_PROTO; | 721 | rc = ISCSI_ERR_PROTO; |
720 | spin_unlock(&conn->session->lock); | 722 | spin_unlock(&conn->session->lock); |
721 | break; | 723 | break; |