diff options
author | Yi Zou <yi.zou@intel.com> | 2012-09-24 14:52:50 -0400 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2012-10-07 06:52:55 -0400 |
commit | 3b64b1881143ce9e461c211cc81acc72d0cdc476 (patch) | |
tree | 4a4869002d37f8b3257ae442caa67b5071e69fed | |
parent | 31c37a6f21d86e6bca095b71d603ed543ae070ad (diff) |
[SCSI] libfc: fix lun reset failure bugs in fc_fcp_resp handling of FCP_RSP_INFO
In LUN RESET testing involving NetApp targets, it is observed that LUN
RESET is failing. The fc_fcp_resp() is not completing the completion
for the LUN RESET task since fc_fcp_resp assumes that the FCP_RSP_INFO
is 8 bytes with the 4 byte reserved field, where in case of NetApp targets
the FCP_RSP to LUN RESET only has 4 bytes of FCP_RSP_INFO. This leads
fc_fcp_resp to error out w/o completing the task completion, eventually
causing LUN RESET to be escalated to host reset, which is not very nice.
Per FCP-3 r04, clause 9.5.15 and Table 23, the FCP_RSP_INFO field can be either
4 bytes or 8 bytes, with the last 4 bytes as "Reserved (if any)". Therefore it
is valid to have 4 bytes FCP_RSP_INFO like some of the NetApp targets behave.
Fixing this by validating the FCP_RSP_INFO against both the two spec allowed
length.
Reported-by: Frank Zhang <frank_1.zhang@intel.com>
Signed-off-by: Yi Zou <yi.zou@intel.com>
Tested-by: Ross Brattain <ross.b.brattain@intel.com>
Signed-off-by: Robert Love <robert.w.love@intel.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
-rw-r--r-- | drivers/scsi/libfc/fc_fcp.c | 3 | ||||
-rw-r--r-- | include/scsi/fc/fc_fcp.h | 6 |
2 files changed, 8 insertions, 1 deletions
diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c index 14243fa5f8e8..fcb9d0b20ee4 100644 --- a/drivers/scsi/libfc/fc_fcp.c +++ b/drivers/scsi/libfc/fc_fcp.c | |||
@@ -851,7 +851,8 @@ static void fc_fcp_resp(struct fc_fcp_pkt *fsp, struct fc_frame *fp) | |||
851 | fc_rp_info = (struct fcp_resp_rsp_info *)(rp_ex + 1); | 851 | fc_rp_info = (struct fcp_resp_rsp_info *)(rp_ex + 1); |
852 | if (flags & FCP_RSP_LEN_VAL) { | 852 | if (flags & FCP_RSP_LEN_VAL) { |
853 | respl = ntohl(rp_ex->fr_rsp_len); | 853 | respl = ntohl(rp_ex->fr_rsp_len); |
854 | if (respl != sizeof(*fc_rp_info)) | 854 | if ((respl != FCP_RESP_RSP_INFO_LEN4) && |
855 | (respl != FCP_RESP_RSP_INFO_LEN8)) | ||
855 | goto len_err; | 856 | goto len_err; |
856 | if (fsp->wait_for_comp) { | 857 | if (fsp->wait_for_comp) { |
857 | /* Abuse cdb_status for rsp code */ | 858 | /* Abuse cdb_status for rsp code */ |
diff --git a/include/scsi/fc/fc_fcp.h b/include/scsi/fc/fc_fcp.h index 0d7d67e96d43..9c8702942b61 100644 --- a/include/scsi/fc/fc_fcp.h +++ b/include/scsi/fc/fc_fcp.h | |||
@@ -127,6 +127,9 @@ struct fcp_txrdy { | |||
127 | * | 127 | * |
128 | * All response frames will always contain the fcp_resp template. Some | 128 | * All response frames will always contain the fcp_resp template. Some |
129 | * will also include the fcp_resp_len template. | 129 | * will also include the fcp_resp_len template. |
130 | * | ||
131 | * From Table 23, the FCP_RSP_INFO can either be 4 bytes or 8 bytes, both | ||
132 | * are valid length. | ||
130 | */ | 133 | */ |
131 | struct fcp_resp { | 134 | struct fcp_resp { |
132 | __u8 _fr_resvd[8]; /* reserved */ | 135 | __u8 _fr_resvd[8]; /* reserved */ |
@@ -156,6 +159,9 @@ struct fcp_resp_rsp_info { | |||
156 | __u8 _fr_resvd2[4]; /* reserved */ | 159 | __u8 _fr_resvd2[4]; /* reserved */ |
157 | }; | 160 | }; |
158 | 161 | ||
162 | #define FCP_RESP_RSP_INFO_LEN4 4 /* without reserved field */ | ||
163 | #define FCP_RESP_RSP_INFO_LEN8 8 /* with reserved field */ | ||
164 | |||
159 | struct fcp_resp_with_ext { | 165 | struct fcp_resp_with_ext { |
160 | struct fcp_resp resp; | 166 | struct fcp_resp resp; |
161 | struct fcp_resp_ext ext; | 167 | struct fcp_resp_ext ext; |