aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/iscsi_tcp.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/iscsi_tcp.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/iscsi_tcp.c')
-rw-r--r--drivers/scsi/iscsi_tcp.c29
1 files changed, 5 insertions, 24 deletions
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index 2a2f0094570f..e960f00da93a 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -523,22 +523,20 @@ iscsi_tcp_cleanup_task(struct iscsi_conn *conn, struct iscsi_task *task)
523} 523}
524 524
525/** 525/**
526 * iscsi_data_rsp - SCSI Data-In Response processing 526 * iscsi_data_in - SCSI Data-In Response processing
527 * @conn: iscsi connection 527 * @conn: iscsi connection
528 * @task: scsi command task 528 * @task: scsi command task
529 **/ 529 **/
530static int 530static int
531iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_task *task) 531iscsi_data_in(struct iscsi_conn *conn, struct iscsi_task *task)
532{ 532{
533 struct iscsi_tcp_conn *tcp_conn = conn->dd_data; 533 struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
534 struct iscsi_tcp_task *tcp_task = task->dd_data; 534 struct iscsi_tcp_task *tcp_task = task->dd_data;
535 struct iscsi_data_rsp *rhdr = (struct iscsi_data_rsp *)tcp_conn->in.hdr; 535 struct iscsi_data_rsp *rhdr = (struct iscsi_data_rsp *)tcp_conn->in.hdr;
536 struct iscsi_session *session = conn->session;
537 struct scsi_cmnd *sc = task->sc;
538 int datasn = be32_to_cpu(rhdr->datasn); 536 int datasn = be32_to_cpu(rhdr->datasn);
539 unsigned total_in_length = scsi_in(sc)->length; 537 unsigned total_in_length = scsi_in(task->sc)->length;
540 538
541 iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr); 539 iscsi_update_cmdsn(conn->session, (struct iscsi_nopin*)rhdr);
542 if (tcp_conn->in.datalen == 0) 540 if (tcp_conn->in.datalen == 0)
543 return 0; 541 return 0;
544 542
@@ -558,23 +556,6 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_task *task)
558 return ISCSI_ERR_DATA_OFFSET; 556 return ISCSI_ERR_DATA_OFFSET;
559 } 557 }
560 558
561 if (rhdr->flags & ISCSI_FLAG_DATA_STATUS) {
562 sc->result = (DID_OK << 16) | rhdr->cmd_status;
563 conn->exp_statsn = be32_to_cpu(rhdr->statsn) + 1;
564 if (rhdr->flags & (ISCSI_FLAG_DATA_UNDERFLOW |
565 ISCSI_FLAG_DATA_OVERFLOW)) {
566 int res_count = be32_to_cpu(rhdr->residual_count);
567
568 if (res_count > 0 &&
569 (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW ||
570 res_count <= total_in_length))
571 scsi_in(sc)->resid = res_count;
572 else
573 sc->result = (DID_BAD_TARGET << 16) |
574 rhdr->cmd_status;
575 }
576 }
577
578 conn->datain_pdus_cnt++; 559 conn->datain_pdus_cnt++;
579 return 0; 560 return 0;
580} 561}
@@ -774,7 +755,7 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
774 if (!task) 755 if (!task)
775 rc = ISCSI_ERR_BAD_ITT; 756 rc = ISCSI_ERR_BAD_ITT;
776 else 757 else
777 rc = iscsi_data_rsp(conn, task); 758 rc = iscsi_data_in(conn, task);
778 if (rc) { 759 if (rc) {
779 spin_unlock(&conn->session->lock); 760 spin_unlock(&conn->session->lock);
780 break; 761 break;