aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/libiscsi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/libiscsi.c')
-rw-r--r--drivers/scsi/libiscsi.c106
1 files changed, 87 insertions, 19 deletions
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index c68cb53a984b..1d7a8b7e8a75 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -857,27 +857,102 @@ static void iscsi_send_nopout(struct iscsi_conn *conn, struct iscsi_nopin *rhdr)
857 } 857 }
858} 858}
859 859
860static int iscsi_nop_out_rsp(struct iscsi_task *task,
861 struct iscsi_nopin *nop, char *data, int datalen)
862{
863 struct iscsi_conn *conn = task->conn;
864 int rc = 0;
865
866 if (conn->ping_task != task) {
867 /*
868 * If this is not in response to one of our
869 * nops then it must be from userspace.
870 */
871 if (iscsi_recv_pdu(conn->cls_conn, (struct iscsi_hdr *)nop,
872 data, datalen))
873 rc = ISCSI_ERR_CONN_FAILED;
874 } else
875 mod_timer(&conn->transport_timer, jiffies + conn->recv_timeout);
876 iscsi_complete_task(task, ISCSI_TASK_COMPLETED);
877 return rc;
878}
879
860static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr, 880static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
861 char *data, int datalen) 881 char *data, int datalen)
862{ 882{
863 struct iscsi_reject *reject = (struct iscsi_reject *)hdr; 883 struct iscsi_reject *reject = (struct iscsi_reject *)hdr;
864 struct iscsi_hdr rejected_pdu; 884 struct iscsi_hdr rejected_pdu;
885 int opcode, rc = 0;
865 886
866 conn->exp_statsn = be32_to_cpu(reject->statsn) + 1; 887 conn->exp_statsn = be32_to_cpu(reject->statsn) + 1;
867 888
868 if (reject->reason == ISCSI_REASON_DATA_DIGEST_ERROR) { 889 if (ntoh24(reject->dlength) > datalen ||
869 if (ntoh24(reject->dlength) > datalen) 890 ntoh24(reject->dlength) < sizeof(struct iscsi_hdr)) {
870 return ISCSI_ERR_PROTO; 891 iscsi_conn_printk(KERN_ERR, conn, "Cannot handle rejected "
892 "pdu. Invalid data length (pdu dlength "
893 "%u, datalen %d\n", ntoh24(reject->dlength),
894 datalen);
895 return ISCSI_ERR_PROTO;
896 }
897 memcpy(&rejected_pdu, data, sizeof(struct iscsi_hdr));
898 opcode = rejected_pdu.opcode & ISCSI_OPCODE_MASK;
871 899
872 if (ntoh24(reject->dlength) >= sizeof(struct iscsi_hdr)) { 900 switch (reject->reason) {
873 memcpy(&rejected_pdu, data, sizeof(struct iscsi_hdr)); 901 case ISCSI_REASON_DATA_DIGEST_ERROR:
874 iscsi_conn_printk(KERN_ERR, conn, 902 iscsi_conn_printk(KERN_ERR, conn,
875 "pdu (op 0x%x) rejected " 903 "pdu (op 0x%x itt 0x%x) rejected "
876 "due to DataDigest error.\n", 904 "due to DataDigest error.\n",
877 rejected_pdu.opcode); 905 rejected_pdu.itt, opcode);
906 break;
907 case ISCSI_REASON_IMM_CMD_REJECT:
908 iscsi_conn_printk(KERN_ERR, conn,
909 "pdu (op 0x%x itt 0x%x) rejected. Too many "
910 "immediate commands.\n",
911 rejected_pdu.itt, opcode);
912 /*
913 * We only send one TMF at a time so if the target could not
914 * handle it, then it should get fixed (RFC mandates that
915 * a target can handle one immediate TMF per conn).
916 *
917 * For nops-outs, we could have sent more than one if
918 * the target is sending us lots of nop-ins
919 */
920 if (opcode != ISCSI_OP_NOOP_OUT)
921 return 0;
922
923 if (rejected_pdu.itt == cpu_to_be32(ISCSI_RESERVED_TAG))
924 /*
925 * nop-out in response to target's nop-out rejected.
926 * Just resend.
927 */
928 iscsi_send_nopout(conn,
929 (struct iscsi_nopin*)&rejected_pdu);
930 else {
931 struct iscsi_task *task;
932 /*
933 * Our nop as ping got dropped. We know the target
934 * and transport are ok so just clean up
935 */
936 task = iscsi_itt_to_task(conn, rejected_pdu.itt);
937 if (!task) {
938 iscsi_conn_printk(KERN_ERR, conn,
939 "Invalid pdu reject. Could "
940 "not lookup rejected task.\n");
941 rc = ISCSI_ERR_BAD_ITT;
942 } else
943 rc = iscsi_nop_out_rsp(task,
944 (struct iscsi_nopin*)&rejected_pdu,
945 NULL, 0);
878 } 946 }
947 break;
948 default:
949 iscsi_conn_printk(KERN_ERR, conn,
950 "pdu (op 0x%x itt 0x%x) rejected. Reason "
951 "code 0x%x\n", rejected_pdu.itt,
952 rejected_pdu.opcode, reject->reason);
953 break;
879 } 954 }
880 return 0; 955 return rc;
881} 956}
882 957
883/** 958/**
@@ -1038,15 +1113,8 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
1038 } 1113 }
1039 conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; 1114 conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1;
1040 1115
1041 if (conn->ping_task != task) 1116 rc = iscsi_nop_out_rsp(task, (struct iscsi_nopin*)hdr,
1042 /* 1117 data, datalen);
1043 * If this is not in response to one of our
1044 * nops then it must be from userspace.
1045 */
1046 goto recv_pdu;
1047
1048 mod_timer(&conn->transport_timer, jiffies + conn->recv_timeout);
1049 iscsi_complete_task(task, ISCSI_TASK_COMPLETED);
1050 break; 1118 break;
1051 default: 1119 default:
1052 rc = ISCSI_ERR_BAD_OPCODE; 1120 rc = ISCSI_ERR_BAD_OPCODE;