diff options
author | Mike Christie <michaelc@cs.wisc.edu> | 2008-05-21 16:54:18 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2008-07-12 09:22:22 -0400 |
commit | 913e5bf435617aa529919a4f7567f849f9f35f9f (patch) | |
tree | db7357d78d7d6f20358d61bf88a8137ad044a5a5 | |
parent | 3cf7b233ffc45d4fc381221f74d24f10e692c4ea (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.c | 20 | ||||
-rw-r--r-- | drivers/infiniband/ulp/iser/iscsi_iser.h | 2 | ||||
-rw-r--r-- | drivers/infiniband/ulp/iser/iser_initiator.c | 6 | ||||
-rw-r--r-- | drivers/scsi/iscsi_tcp.c | 73 | ||||
-rw-r--r-- | drivers/scsi/libiscsi.c | 152 | ||||
-rw-r--r-- | include/scsi/libiscsi.h | 8 |
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 { | |||
263 | struct iscsi_iser_conn { | 263 | struct 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 | ||
270 | struct iscsi_iser_task { | 268 | struct 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 | |||
741 | iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr) | 741 | iscsi_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 | |||
1578 | iscsi_tcp_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) | 1577 | iscsi_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 | ||
365 | static void __iscsi_get_task(struct iscsi_task *task) | 365 | void __iscsi_get_task(struct iscsi_task *task) |
366 | { | 366 | { |
367 | atomic_inc(&task->refcount); | 367 | atomic_inc(&task->refcount); |
368 | } | 368 | } |
369 | EXPORT_SYMBOL_GPL(__iscsi_get_task); | ||
369 | 370 | ||
370 | static void __iscsi_put_task(struct iscsi_task *task) | 371 | static 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 | */ | ||
714 | static 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 | */ |
710 | static int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | 740 | int __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 | } |
885 | EXPORT_SYMBOL_GPL(__iscsi_complete_pdu); | ||
844 | 886 | ||
845 | int iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | 887 | int 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); | |||
857 | int iscsi_verify_itt(struct iscsi_conn *conn, itt_t itt) | 899 | int 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 | } |
893 | EXPORT_SYMBOL_GPL(iscsi_verify_itt); | 924 | EXPORT_SYMBOL_GPL(iscsi_verify_itt); |
894 | 925 | ||
895 | struct iscsi_task * | 926 | /** |
896 | iscsi_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 | */ | ||
935 | struct 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); |
375 | extern int iscsi_complete_pdu(struct iscsi_conn *, struct iscsi_hdr *, | 370 | extern int iscsi_complete_pdu(struct iscsi_conn *, struct iscsi_hdr *, |
376 | char *, int); | 371 | char *, int); |
372 | extern int __iscsi_complete_pdu(struct iscsi_conn *, struct iscsi_hdr *, | ||
373 | char *, int); | ||
377 | extern int iscsi_verify_itt(struct iscsi_conn *, itt_t); | 374 | extern int iscsi_verify_itt(struct iscsi_conn *, itt_t); |
378 | extern struct iscsi_task *iscsi_itt_to_ctask(struct iscsi_conn *, itt_t); | 375 | extern struct iscsi_task *iscsi_itt_to_ctask(struct iscsi_conn *, itt_t); |
379 | extern void iscsi_requeue_task(struct iscsi_task *task); | 376 | extern void iscsi_requeue_task(struct iscsi_task *task); |
380 | extern void iscsi_put_task(struct iscsi_task *task); | 377 | extern void iscsi_put_task(struct iscsi_task *task); |
378 | extern void __iscsi_get_task(struct iscsi_task *task); | ||
381 | 379 | ||
382 | /* | 380 | /* |
383 | * generic helpers | 381 | * generic helpers |