aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/libiscsi.c
diff options
context:
space:
mode:
authorMike Christie <michaelc@cs.wisc.edu>2009-08-20 16:10:59 -0400
committerJames Bottomley <James.Bottomley@suse.de>2009-09-05 10:42:42 -0400
commit8afa1439fcff58da8f28c1d083046f229f6ab3de (patch)
treeef09869134e5aadbc883762b4b1668619229463a /drivers/scsi/libiscsi.c
parentd3305f3407fa3e9452079ec6cc8379067456e4aa (diff)
[SCSI] libiscsi: handle immediate command rejections
If we sent multiple pdus as immediate the target could be rejecting some and we have just been dropping the rejection notification. This adds code to handle nop-out rejections, so if a nop-out was sent as a ping and rejected we do not mark the connection bad. Instead we just clean up the timers since we have pdu making a rount trip we know the connection is good. Signed-off-by: Mike Christie <michaelc@cs.wisc.edu> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
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;