aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Christie <michaelc@cs.wisc.edu>2008-05-21 16:54:18 -0400
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2008-07-12 09:22:22 -0400
commit913e5bf435617aa529919a4f7567f849f9f35f9f (patch)
treedb7357d78d7d6f20358d61bf88a8137ad044a5a5
parent3cf7b233ffc45d4fc381221f74d24f10e692c4ea (diff)
[SCSI] libiscsi, iser, tcp: remove recv_lock
The recv lock was defined so the iscsi layer could block the recv path from processing IO during recovery. It turns out iser just set a lock to that pointer which was pointless. We now disconnect the transport connection before doing recovery so we do not need the recv lock. For iscsi_tcp we still stop the recv path incase older tools are being used. This patch also has iscsi_itt_to_ctask user grab the session lock and has the caller access the task with the lock or get a ref to it in case the target is broken and sends a tmf success response then sends data or a response for the command that was supposed to be affected bty the tmf. Signed-off-by: Mike Christie <michaelc@cs.wisc.edu> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
-rw-r--r--drivers/infiniband/ulp/iser/iscsi_iser.c20
-rw-r--r--drivers/infiniband/ulp/iser/iscsi_iser.h2
-rw-r--r--drivers/infiniband/ulp/iser/iser_initiator.c6
-rw-r--r--drivers/scsi/iscsi_tcp.c73
-rw-r--r--drivers/scsi/libiscsi.c152
-rw-r--r--include/scsi/libiscsi.h8
6 files changed, 144 insertions, 117 deletions
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c
index 08edbaf89223..c02eabd383a1 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.c
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.c
@@ -281,9 +281,6 @@ iscsi_iser_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx)
281 conn->max_recv_dlength = 128; 281 conn->max_recv_dlength = 128;
282 282
283 iser_conn = conn->dd_data; 283 iser_conn = conn->dd_data;
284 /* currently this is the only field which need to be initiated */
285 rwlock_init(&iser_conn->lock);
286
287 conn->dd_data = iser_conn; 284 conn->dd_data = iser_conn;
288 iser_conn->iscsi_conn = conn; 285 iser_conn->iscsi_conn = conn;
289 286
@@ -342,9 +339,6 @@ iscsi_iser_conn_bind(struct iscsi_cls_session *cls_session,
342 ib_conn->iser_conn = iser_conn; 339 ib_conn->iser_conn = iser_conn;
343 iser_conn->ib_conn = ib_conn; 340 iser_conn->ib_conn = ib_conn;
344 iser_conn_get(ib_conn); 341 iser_conn_get(ib_conn);
345
346 conn->recv_lock = &iser_conn->lock;
347
348 return 0; 342 return 0;
349} 343}
350 344
@@ -355,12 +349,18 @@ iscsi_iser_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
355 struct iscsi_iser_conn *iser_conn = conn->dd_data; 349 struct iscsi_iser_conn *iser_conn = conn->dd_data;
356 struct iser_conn *ib_conn = iser_conn->ib_conn; 350 struct iser_conn *ib_conn = iser_conn->ib_conn;
357 351
358 iscsi_conn_stop(cls_conn, flag);
359 /* 352 /*
360 * There is no unbind event so the stop callback 353 * Userspace may have goofed up and not bound the connection or
361 * must release the ref from the bind. 354 * might have only partially setup the connection.
362 */ 355 */
363 iser_conn_put(ib_conn); 356 if (ib_conn) {
357 iscsi_conn_stop(cls_conn, flag);
358 /*
359 * There is no unbind event so the stop callback
360 * must release the ref from the bind.
361 */
362 iser_conn_put(ib_conn);
363 }
364 iser_conn->ib_conn = NULL; 364 iser_conn->ib_conn = NULL;
365} 365}
366 366
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h
index cdf48763b082..a547edeea969 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.h
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.h
@@ -263,8 +263,6 @@ struct iser_conn {
263struct iscsi_iser_conn { 263struct iscsi_iser_conn {
264 struct iscsi_conn *iscsi_conn;/* ptr to iscsi conn */ 264 struct iscsi_conn *iscsi_conn;/* ptr to iscsi conn */
265 struct iser_conn *ib_conn; /* iSER IB conn */ 265 struct iser_conn *ib_conn; /* iSER IB conn */
266
267 rwlock_t lock;
268}; 266};
269 267
270struct iscsi_iser_task { 268struct iscsi_iser_task {
diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c
index 35af60a23c61..c36083922134 100644
--- a/drivers/infiniband/ulp/iser/iser_initiator.c
+++ b/drivers/infiniband/ulp/iser/iser_initiator.c
@@ -558,7 +558,12 @@ void iser_rcv_completion(struct iser_desc *rx_desc,
558 opcode = hdr->opcode & ISCSI_OPCODE_MASK; 558 opcode = hdr->opcode & ISCSI_OPCODE_MASK;
559 559
560 if (opcode == ISCSI_OP_SCSI_CMD_RSP) { 560 if (opcode == ISCSI_OP_SCSI_CMD_RSP) {
561 spin_lock(&conn->iscsi_conn->session->lock);
561 task = iscsi_itt_to_ctask(conn->iscsi_conn, hdr->itt); 562 task = iscsi_itt_to_ctask(conn->iscsi_conn, hdr->itt);
563 if (task)
564 __iscsi_get_task(task);
565 spin_unlock(&conn->iscsi_conn->session->lock);
566
562 if (!task) 567 if (!task)
563 iser_err("itt can't be matched to task!!! " 568 iser_err("itt can't be matched to task!!! "
564 "conn %p opcode %d itt %d\n", 569 "conn %p opcode %d itt %d\n",
@@ -568,6 +573,7 @@ void iser_rcv_completion(struct iser_desc *rx_desc,
568 iser_dbg("itt %d task %p\n",hdr->itt, task); 573 iser_dbg("itt %d task %p\n",hdr->itt, task);
569 iser_task->status = ISER_TASK_STATUS_COMPLETED; 574 iser_task->status = ISER_TASK_STATUS_COMPLETED;
570 iser_task_rdma_finalize(iser_task); 575 iser_task_rdma_finalize(iser_task);
576 iscsi_put_task(task);
571 } 577 }
572 } 578 }
573 iser_dto_buffs_release(dto); 579 iser_dto_buffs_release(dto);
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index 7552dd8a88f3..91cb1fd523f0 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -741,7 +741,6 @@ static int
741iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr) 741iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
742{ 742{
743 int rc = 0, opcode, ahslen; 743 int rc = 0, opcode, ahslen;
744 struct iscsi_session *session = conn->session;
745 struct iscsi_tcp_conn *tcp_conn = conn->dd_data; 744 struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
746 struct iscsi_task *task; 745 struct iscsi_task *task;
747 746
@@ -770,17 +769,17 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
770 769
771 switch(opcode) { 770 switch(opcode) {
772 case ISCSI_OP_SCSI_DATA_IN: 771 case ISCSI_OP_SCSI_DATA_IN:
772 spin_lock(&conn->session->lock);
773 task = iscsi_itt_to_ctask(conn, hdr->itt); 773 task = iscsi_itt_to_ctask(conn, hdr->itt);
774 if (!task) 774 if (!task)
775 return ISCSI_ERR_BAD_ITT; 775 rc = ISCSI_ERR_BAD_ITT;
776 if (!task->sc) 776 else
777 return ISCSI_ERR_NO_SCSI_CMD; 777 rc = iscsi_data_rsp(conn, task);
778 if (rc) {
779 spin_unlock(&conn->session->lock);
780 break;
781 }
778 782
779 spin_lock(&conn->session->lock);
780 rc = iscsi_data_rsp(conn, task);
781 spin_unlock(&conn->session->lock);
782 if (rc)
783 return rc;
784 if (tcp_conn->in.datalen) { 783 if (tcp_conn->in.datalen) {
785 struct iscsi_tcp_task *tcp_task = task->dd_data; 784 struct iscsi_tcp_task *tcp_task = task->dd_data;
786 struct hash_desc *rx_hash = NULL; 785 struct hash_desc *rx_hash = NULL;
@@ -801,15 +800,19 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
801 "datalen=%d)\n", tcp_conn, 800 "datalen=%d)\n", tcp_conn,
802 tcp_task->data_offset, 801 tcp_task->data_offset,
803 tcp_conn->in.datalen); 802 tcp_conn->in.datalen);
804 return iscsi_segment_seek_sg(&tcp_conn->in.segment, 803 rc = iscsi_segment_seek_sg(&tcp_conn->in.segment,
805 sdb->table.sgl, 804 sdb->table.sgl,
806 sdb->table.nents, 805 sdb->table.nents,
807 tcp_task->data_offset, 806 tcp_task->data_offset,
808 tcp_conn->in.datalen, 807 tcp_conn->in.datalen,
809 iscsi_tcp_process_data_in, 808 iscsi_tcp_process_data_in,
810 rx_hash); 809 rx_hash);
810 spin_unlock(&conn->session->lock);
811 return rc;
811 } 812 }
812 /* fall through */ 813 rc = __iscsi_complete_pdu(conn, hdr, NULL, 0);
814 spin_unlock(&conn->session->lock);
815 break;
813 case ISCSI_OP_SCSI_CMD_RSP: 816 case ISCSI_OP_SCSI_CMD_RSP:
814 if (tcp_conn->in.datalen) { 817 if (tcp_conn->in.datalen) {
815 iscsi_tcp_data_recv_prep(tcp_conn); 818 iscsi_tcp_data_recv_prep(tcp_conn);
@@ -818,20 +821,17 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
818 rc = iscsi_complete_pdu(conn, hdr, NULL, 0); 821 rc = iscsi_complete_pdu(conn, hdr, NULL, 0);
819 break; 822 break;
820 case ISCSI_OP_R2T: 823 case ISCSI_OP_R2T:
824 spin_lock(&conn->session->lock);
821 task = iscsi_itt_to_ctask(conn, hdr->itt); 825 task = iscsi_itt_to_ctask(conn, hdr->itt);
822 if (!task) 826 if (!task)
823 return ISCSI_ERR_BAD_ITT; 827 rc = ISCSI_ERR_BAD_ITT;
824 if (!task->sc) 828 else if (ahslen)
825 return ISCSI_ERR_NO_SCSI_CMD;
826
827 if (ahslen)
828 rc = ISCSI_ERR_AHSLEN; 829 rc = ISCSI_ERR_AHSLEN;
829 else if (task->sc->sc_data_direction == DMA_TO_DEVICE) { 830 else if (task->sc->sc_data_direction == DMA_TO_DEVICE)
830 spin_lock(&session->lock);
831 rc = iscsi_r2t_rsp(conn, task); 831 rc = iscsi_r2t_rsp(conn, task);
832 spin_unlock(&session->lock); 832 else
833 } else
834 rc = ISCSI_ERR_PROTO; 833 rc = ISCSI_ERR_PROTO;
834 spin_unlock(&conn->session->lock);
835 break; 835 break;
836 case ISCSI_OP_LOGIN_RSP: 836 case ISCSI_OP_LOGIN_RSP:
837 case ISCSI_OP_TEXT_RSP: 837 case ISCSI_OP_TEXT_RSP:
@@ -1553,7 +1553,6 @@ iscsi_tcp_release_conn(struct iscsi_conn *conn)
1553 1553
1554 spin_lock_bh(&session->lock); 1554 spin_lock_bh(&session->lock);
1555 tcp_conn->sock = NULL; 1555 tcp_conn->sock = NULL;
1556 conn->recv_lock = NULL;
1557 spin_unlock_bh(&session->lock); 1556 spin_unlock_bh(&session->lock);
1558 sockfd_put(sock); 1557 sockfd_put(sock);
1559} 1558}
@@ -1578,6 +1577,19 @@ static void
1578iscsi_tcp_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) 1577iscsi_tcp_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
1579{ 1578{
1580 struct iscsi_conn *conn = cls_conn->dd_data; 1579 struct iscsi_conn *conn = cls_conn->dd_data;
1580 struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
1581
1582 /* userspace may have goofed up and not bound us */
1583 if (!tcp_conn->sock)
1584 return;
1585 /*
1586 * Make sure our recv side is stopped.
1587 * Older tools called conn stop before ep_disconnect
1588 * so IO could still be coming in.
1589 */
1590 write_lock_bh(&tcp_conn->sock->sk->sk_callback_lock);
1591 set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx);
1592 write_unlock_bh(&tcp_conn->sock->sk->sk_callback_lock);
1581 1593
1582 iscsi_conn_stop(cls_conn, flag); 1594 iscsi_conn_stop(cls_conn, flag);
1583 iscsi_tcp_release_conn(conn); 1595 iscsi_tcp_release_conn(conn);
@@ -1671,13 +1683,6 @@ iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session,
1671 sk->sk_sndtimeo = 15 * HZ; /* FIXME: make it configurable */ 1683 sk->sk_sndtimeo = 15 * HZ; /* FIXME: make it configurable */
1672 sk->sk_allocation = GFP_ATOMIC; 1684 sk->sk_allocation = GFP_ATOMIC;
1673 1685
1674 /* FIXME: disable Nagle's algorithm */
1675
1676 /*
1677 * Intercept TCP callbacks for sendfile like receive
1678 * processing.
1679 */
1680 conn->recv_lock = &sk->sk_callback_lock;
1681 iscsi_conn_set_callbacks(conn); 1686 iscsi_conn_set_callbacks(conn);
1682 tcp_conn->sendpage = tcp_conn->sock->ops->sendpage; 1687 tcp_conn->sendpage = tcp_conn->sock->ops->sendpage;
1683 /* 1688 /*
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index c723e60f02b0..9c267b440444 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -362,10 +362,11 @@ static void iscsi_complete_command(struct iscsi_task *task)
362 } 362 }
363} 363}
364 364
365static void __iscsi_get_task(struct iscsi_task *task) 365void __iscsi_get_task(struct iscsi_task *task)
366{ 366{
367 atomic_inc(&task->refcount); 367 atomic_inc(&task->refcount);
368} 368}
369EXPORT_SYMBOL_GPL(__iscsi_get_task);
369 370
370static void __iscsi_put_task(struct iscsi_task *task) 371static void __iscsi_put_task(struct iscsi_task *task)
371{ 372{
@@ -403,9 +404,13 @@ static void fail_command(struct iscsi_conn *conn, struct iscsi_task *task,
403 conn->session->queued_cmdsn--; 404 conn->session->queued_cmdsn--;
404 else 405 else
405 conn->session->tt->cleanup_task(conn, task); 406 conn->session->tt->cleanup_task(conn, task);
407 /*
408 * Check if cleanup_task dropped the lock and the command completed,
409 */
410 if (!task->sc)
411 return;
406 412
407 sc->result = err; 413 sc->result = err;
408
409 if (!scsi_bidi_cmnd(sc)) 414 if (!scsi_bidi_cmnd(sc))
410 scsi_set_resid(sc, scsi_bufflen(sc)); 415 scsi_set_resid(sc, scsi_bufflen(sc));
411 else { 416 else {
@@ -697,6 +702,31 @@ static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
697} 702}
698 703
699/** 704/**
705 * iscsi_itt_to_task - look up task by itt
706 * @conn: iscsi connection
707 * @itt: itt
708 *
709 * This should be used for mgmt tasks like login and nops, or if
710 * the LDD's itt space does not include the session age.
711 *
712 * The session lock must be held.
713 */
714static struct iscsi_task *iscsi_itt_to_task(struct iscsi_conn *conn, itt_t itt)
715{
716 struct iscsi_session *session = conn->session;
717 uint32_t i;
718
719 if (itt == RESERVED_ITT)
720 return NULL;
721
722 i = get_itt(itt);
723 if (i >= session->cmds_max)
724 return NULL;
725
726 return session->cmds[i];
727}
728
729/**
700 * __iscsi_complete_pdu - complete pdu 730 * __iscsi_complete_pdu - complete pdu
701 * @conn: iscsi conn 731 * @conn: iscsi conn
702 * @hdr: iscsi header 732 * @hdr: iscsi header
@@ -707,8 +737,8 @@ static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
707 * queuecommand or send generic. session lock must be held and verify 737 * queuecommand or send generic. session lock must be held and verify
708 * itt must have been called. 738 * itt must have been called.
709 */ 739 */
710static int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, 740int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
711 char *data, int datalen) 741 char *data, int datalen)
712{ 742{
713 struct iscsi_session *session = conn->session; 743 struct iscsi_session *session = conn->session;
714 int opcode = hdr->opcode & ISCSI_OPCODE_MASK, rc = 0; 744 int opcode = hdr->opcode & ISCSI_OPCODE_MASK, rc = 0;
@@ -758,22 +788,36 @@ static int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
758 goto out; 788 goto out;
759 } 789 }
760 790
761 task = session->cmds[itt];
762 switch(opcode) { 791 switch(opcode) {
763 case ISCSI_OP_SCSI_CMD_RSP: 792 case ISCSI_OP_SCSI_CMD_RSP:
764 if (!task->sc) { 793 case ISCSI_OP_SCSI_DATA_IN:
765 rc = ISCSI_ERR_NO_SCSI_CMD; 794 task = iscsi_itt_to_ctask(conn, hdr->itt);
766 break; 795 if (!task)
767 } 796 return ISCSI_ERR_BAD_ITT;
768 BUG_ON((void*)task != task->sc->SCp.ptr); 797 break;
798 case ISCSI_OP_R2T:
799 /*
800 * LLD handles R2Ts if they need to.
801 */
802 return 0;
803 case ISCSI_OP_LOGOUT_RSP:
804 case ISCSI_OP_LOGIN_RSP:
805 case ISCSI_OP_TEXT_RSP:
806 case ISCSI_OP_SCSI_TMFUNC_RSP:
807 case ISCSI_OP_NOOP_IN:
808 task = iscsi_itt_to_task(conn, hdr->itt);
809 if (!task)
810 return ISCSI_ERR_BAD_ITT;
811 break;
812 default:
813 return ISCSI_ERR_BAD_OPCODE;
814 }
815
816 switch(opcode) {
817 case ISCSI_OP_SCSI_CMD_RSP:
769 iscsi_scsi_cmd_rsp(conn, hdr, task, data, datalen); 818 iscsi_scsi_cmd_rsp(conn, hdr, task, data, datalen);
770 break; 819 break;
771 case ISCSI_OP_SCSI_DATA_IN: 820 case ISCSI_OP_SCSI_DATA_IN:
772 if (!task->sc) {
773 rc = ISCSI_ERR_NO_SCSI_CMD;
774 break;
775 }
776 BUG_ON((void*)task != task->sc->SCp.ptr);
777 if (hdr->flags & ISCSI_FLAG_DATA_STATUS) { 821 if (hdr->flags & ISCSI_FLAG_DATA_STATUS) {
778 conn->scsirsp_pdus_cnt++; 822 conn->scsirsp_pdus_cnt++;
779 iscsi_update_cmdsn(session, 823 iscsi_update_cmdsn(session,
@@ -781,9 +825,6 @@ static int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
781 __iscsi_put_task(task); 825 __iscsi_put_task(task);
782 } 826 }
783 break; 827 break;
784 case ISCSI_OP_R2T:
785 /* LLD handles this for now */
786 break;
787 case ISCSI_OP_LOGOUT_RSP: 828 case ISCSI_OP_LOGOUT_RSP:
788 iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr); 829 iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr);
789 if (datalen) { 830 if (datalen) {
@@ -841,6 +882,7 @@ recv_pdu:
841 __iscsi_put_task(task); 882 __iscsi_put_task(task);
842 return rc; 883 return rc;
843} 884}
885EXPORT_SYMBOL_GPL(__iscsi_complete_pdu);
844 886
845int iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, 887int iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
846 char *data, int datalen) 888 char *data, int datalen)
@@ -857,7 +899,6 @@ EXPORT_SYMBOL_GPL(iscsi_complete_pdu);
857int iscsi_verify_itt(struct iscsi_conn *conn, itt_t itt) 899int iscsi_verify_itt(struct iscsi_conn *conn, itt_t itt)
858{ 900{
859 struct iscsi_session *session = conn->session; 901 struct iscsi_session *session = conn->session;
860 struct iscsi_task *task;
861 uint32_t i; 902 uint32_t i;
862 903
863 if (itt == RESERVED_ITT) 904 if (itt == RESERVED_ITT)
@@ -867,8 +908,7 @@ int iscsi_verify_itt(struct iscsi_conn *conn, itt_t itt)
867 (session->age << ISCSI_AGE_SHIFT)) { 908 (session->age << ISCSI_AGE_SHIFT)) {
868 iscsi_conn_printk(KERN_ERR, conn, 909 iscsi_conn_printk(KERN_ERR, conn,
869 "received itt %x expected session age (%x)\n", 910 "received itt %x expected session age (%x)\n",
870 (__force u32)itt, 911 (__force u32)itt, session->age);
871 session->age & ISCSI_AGE_MASK);
872 return ISCSI_ERR_BAD_ITT; 912 return ISCSI_ERR_BAD_ITT;
873 } 913 }
874 914
@@ -879,42 +919,36 @@ int iscsi_verify_itt(struct iscsi_conn *conn, itt_t itt)
879 "%u.\n", i, session->cmds_max); 919 "%u.\n", i, session->cmds_max);
880 return ISCSI_ERR_BAD_ITT; 920 return ISCSI_ERR_BAD_ITT;
881 } 921 }
882
883 task = session->cmds[i];
884 if (task->sc && task->sc->SCp.phase != session->age) {
885 iscsi_conn_printk(KERN_ERR, conn,
886 "iscsi: task's session age %d, "
887 "expected %d\n", task->sc->SCp.phase,
888 session->age);
889 return ISCSI_ERR_SESSION_FAILED;
890 }
891 return 0; 922 return 0;
892} 923}
893EXPORT_SYMBOL_GPL(iscsi_verify_itt); 924EXPORT_SYMBOL_GPL(iscsi_verify_itt);
894 925
895struct iscsi_task * 926/**
896iscsi_itt_to_ctask(struct iscsi_conn *conn, itt_t itt) 927 * iscsi_itt_to_ctask - look up ctask by itt
928 * @conn: iscsi connection
929 * @itt: itt
930 *
931 * This should be used for cmd tasks.
932 *
933 * The session lock must be held.
934 */
935struct iscsi_task *iscsi_itt_to_ctask(struct iscsi_conn *conn, itt_t itt)
897{ 936{
898 struct iscsi_session *session = conn->session;
899 struct iscsi_task *task; 937 struct iscsi_task *task;
900 uint32_t i;
901 938
902 if (iscsi_verify_itt(conn, itt)) 939 if (iscsi_verify_itt(conn, itt))
903 return NULL; 940 return NULL;
904 941
905 if (itt == RESERVED_ITT) 942 task = iscsi_itt_to_task(conn, itt);
943 if (!task || !task->sc)
906 return NULL; 944 return NULL;
907 945
908 i = get_itt(itt); 946 if (task->sc->SCp.phase != conn->session->age) {
909 if (i >= session->cmds_max) 947 iscsi_session_printk(KERN_ERR, conn->session,
910 return NULL; 948 "task's session age %d, expected %d\n",
911 949 task->sc->SCp.phase, conn->session->age);
912 task = session->cmds[i];
913 if (!task->sc)
914 return NULL;
915
916 if (task->sc->SCp.phase != session->age)
917 return NULL; 950 return NULL;
951 }
918 952
919 return task; 953 return task;
920} 954}
@@ -1620,16 +1654,20 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
1620 switch (conn->tmf_state) { 1654 switch (conn->tmf_state) {
1621 case TMF_SUCCESS: 1655 case TMF_SUCCESS:
1622 spin_unlock_bh(&session->lock); 1656 spin_unlock_bh(&session->lock);
1657 /*
1658 * stop tx side incase the target had sent a abort rsp but
1659 * the initiator was still writing out data.
1660 */
1623 iscsi_suspend_tx(conn); 1661 iscsi_suspend_tx(conn);
1624 /* 1662 /*
1625 * clean up task if aborted. grab the recv lock as a writer 1663 * we do not stop the recv side because targets have been
1664 * good and have never sent us a successful tmf response
1665 * then sent more data for the cmd.
1626 */ 1666 */
1627 write_lock_bh(conn->recv_lock);
1628 spin_lock(&session->lock); 1667 spin_lock(&session->lock);
1629 fail_command(conn, task, DID_ABORT << 16); 1668 fail_command(conn, task, DID_ABORT << 16);
1630 conn->tmf_state = TMF_INITIAL; 1669 conn->tmf_state = TMF_INITIAL;
1631 spin_unlock(&session->lock); 1670 spin_unlock(&session->lock);
1632 write_unlock_bh(conn->recv_lock);
1633 iscsi_start_tx(conn); 1671 iscsi_start_tx(conn);
1634 goto success_unlocked; 1672 goto success_unlocked;
1635 case TMF_TIMEDOUT: 1673 case TMF_TIMEDOUT:
@@ -1729,13 +1767,11 @@ int iscsi_eh_device_reset(struct scsi_cmnd *sc)
1729 spin_unlock_bh(&session->lock); 1767 spin_unlock_bh(&session->lock);
1730 1768
1731 iscsi_suspend_tx(conn); 1769 iscsi_suspend_tx(conn);
1732 /* need to grab the recv lock then session lock */ 1770
1733 write_lock_bh(conn->recv_lock);
1734 spin_lock(&session->lock); 1771 spin_lock(&session->lock);
1735 fail_all_commands(conn, sc->device->lun, DID_ERROR); 1772 fail_all_commands(conn, sc->device->lun, DID_ERROR);
1736 conn->tmf_state = TMF_INITIAL; 1773 conn->tmf_state = TMF_INITIAL;
1737 spin_unlock(&session->lock); 1774 spin_unlock(&session->lock);
1738 write_unlock_bh(conn->recv_lock);
1739 1775
1740 iscsi_start_tx(conn); 1776 iscsi_start_tx(conn);
1741 goto done; 1777 goto done;
@@ -2257,17 +2293,6 @@ static void iscsi_start_session_recovery(struct iscsi_session *session,
2257 } 2293 }
2258 2294
2259 /* 2295 /*
2260 * The LLD either freed/unset the lock on us, or userspace called
2261 * stop but did not create a proper connection (connection was never
2262 * bound or it was unbound then stop was called).
2263 */
2264 if (!conn->recv_lock) {
2265 spin_unlock_bh(&session->lock);
2266 mutex_unlock(&session->eh_mutex);
2267 return;
2268 }
2269
2270 /*
2271 * When this is called for the in_login state, we only want to clean 2296 * When this is called for the in_login state, we only want to clean
2272 * up the login task and connection. We do not need to block and set 2297 * up the login task and connection. We do not need to block and set
2273 * the recovery state again 2298 * the recovery state again
@@ -2283,11 +2308,6 @@ static void iscsi_start_session_recovery(struct iscsi_session *session,
2283 spin_unlock_bh(&session->lock); 2308 spin_unlock_bh(&session->lock);
2284 2309
2285 iscsi_suspend_tx(conn); 2310 iscsi_suspend_tx(conn);
2286
2287 write_lock_bh(conn->recv_lock);
2288 set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx);
2289 write_unlock_bh(conn->recv_lock);
2290
2291 /* 2311 /*
2292 * for connection level recovery we should not calculate 2312 * for connection level recovery we should not calculate
2293 * header digest. conn->hdr_size used for optimization 2313 * header digest. conn->hdr_size used for optimization
diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
index 5bf0187e7520..5e75bb7f311c 100644
--- a/include/scsi/libiscsi.h
+++ b/include/scsi/libiscsi.h
@@ -139,11 +139,6 @@ struct iscsi_conn {
139 void *dd_data; /* iscsi_transport data */ 139 void *dd_data; /* iscsi_transport data */
140 struct iscsi_session *session; /* parent session */ 140 struct iscsi_session *session; /* parent session */
141 /* 141 /*
142 * LLDs should set this lock. It protects the transport recv
143 * code
144 */
145 rwlock_t *recv_lock;
146 /*
147 * conn_stop() flag: stop to recover, stop to terminate 142 * conn_stop() flag: stop to recover, stop to terminate
148 */ 143 */
149 int stop_stage; 144 int stop_stage;
@@ -374,10 +369,13 @@ extern int iscsi_conn_send_pdu(struct iscsi_cls_conn *, struct iscsi_hdr *,
374 char *, uint32_t); 369 char *, uint32_t);
375extern int iscsi_complete_pdu(struct iscsi_conn *, struct iscsi_hdr *, 370extern int iscsi_complete_pdu(struct iscsi_conn *, struct iscsi_hdr *,
376 char *, int); 371 char *, int);
372extern int __iscsi_complete_pdu(struct iscsi_conn *, struct iscsi_hdr *,
373 char *, int);
377extern int iscsi_verify_itt(struct iscsi_conn *, itt_t); 374extern int iscsi_verify_itt(struct iscsi_conn *, itt_t);
378extern struct iscsi_task *iscsi_itt_to_ctask(struct iscsi_conn *, itt_t); 375extern struct iscsi_task *iscsi_itt_to_ctask(struct iscsi_conn *, itt_t);
379extern void iscsi_requeue_task(struct iscsi_task *task); 376extern void iscsi_requeue_task(struct iscsi_task *task);
380extern void iscsi_put_task(struct iscsi_task *task); 377extern void iscsi_put_task(struct iscsi_task *task);
378extern void __iscsi_get_task(struct iscsi_task *task);
381 379
382/* 380/*
383 * generic helpers 381 * generic helpers