aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/libiscsi.c
diff options
context:
space:
mode:
authorMike Christie <michaelc@cs.wisc.edu>2008-09-24 12:46:09 -0400
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2008-10-13 09:28:58 -0400
commit1d9edf0270cb5a434d32e95279ce9493581906b3 (patch)
tree1b54cdd2c8b18e78a788d7f1f3c17c7b73043c24 /drivers/scsi/libiscsi.c
parentcbdc14459bd7d99d20341ec057b8f4ffab2a7fb6 (diff)
[SCSI] libiscsi: fix data corruption when target has to resend data-in packets
iscsi_tcp was updating the exp_statsn (exp_statsn acknowledges status and tells the target it is ok to let the resources for a iscsi pdu to be reused) before it got all the data for pdu read into OS buffers. Data corruption was occuring if something happens to a packet and the network layer requests a retransmit, and the initiator has told the target about the udpated exp_statsn ack, then the target may be sending data from a buffer it has reused for a new iscsi pdu. This fixes the problem by having the LLD (iscsi_tcp in this case) just handle the transferring of data, and has libiscsi handle the processing of status (libiscsi completion processing is done after LLD data transfers are complete). 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.c41
1 files changed, 35 insertions, 6 deletions
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 0e8f26baca6e..f9539af28f02 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -633,6 +633,40 @@ out:
633 __iscsi_put_task(task); 633 __iscsi_put_task(task);
634} 634}
635 635
636/**
637 * iscsi_data_in_rsp - SCSI Data-In Response processing
638 * @conn: iscsi connection
639 * @hdr: iscsi pdu
640 * @task: scsi command task
641 **/
642static void
643iscsi_data_in_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
644 struct iscsi_task *task)
645{
646 struct iscsi_data_rsp *rhdr = (struct iscsi_data_rsp *)hdr;
647 struct scsi_cmnd *sc = task->sc;
648
649 if (!(rhdr->flags & ISCSI_FLAG_DATA_STATUS))
650 return;
651
652 sc->result = (DID_OK << 16) | rhdr->cmd_status;
653 conn->exp_statsn = be32_to_cpu(rhdr->statsn) + 1;
654 if (rhdr->flags & (ISCSI_FLAG_DATA_UNDERFLOW |
655 ISCSI_FLAG_DATA_OVERFLOW)) {
656 int res_count = be32_to_cpu(rhdr->residual_count);
657
658 if (res_count > 0 &&
659 (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW ||
660 res_count <= scsi_in(sc)->length))
661 scsi_in(sc)->resid = res_count;
662 else
663 sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
664 }
665
666 conn->scsirsp_pdus_cnt++;
667 __iscsi_put_task(task);
668}
669
636static void iscsi_tmf_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr) 670static void iscsi_tmf_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
637{ 671{
638 struct iscsi_tm_rsp *tmf = (struct iscsi_tm_rsp *)hdr; 672 struct iscsi_tm_rsp *tmf = (struct iscsi_tm_rsp *)hdr;
@@ -818,12 +852,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
818 iscsi_scsi_cmd_rsp(conn, hdr, task, data, datalen); 852 iscsi_scsi_cmd_rsp(conn, hdr, task, data, datalen);
819 break; 853 break;
820 case ISCSI_OP_SCSI_DATA_IN: 854 case ISCSI_OP_SCSI_DATA_IN:
821 if (hdr->flags & ISCSI_FLAG_DATA_STATUS) { 855 iscsi_data_in_rsp(conn, hdr, task);
822 conn->scsirsp_pdus_cnt++;
823 iscsi_update_cmdsn(session,
824 (struct iscsi_nopin*) hdr);
825 __iscsi_put_task(task);
826 }
827 break; 856 break;
828 case ISCSI_OP_LOGOUT_RSP: 857 case ISCSI_OP_LOGOUT_RSP:
829 iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr); 858 iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr);