diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-08-03 21:12:09 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-08-03 21:12:09 -0400 |
| commit | a9e4e6e14c322e08d1c615afc8f504fb415f9613 (patch) | |
| tree | 7c842bbfdc322b5ff99644e8b1bc7b415669233e | |
| parent | 27665ffa22b9b83bab226bf12c61424f7f1f8995 (diff) | |
| parent | dcd998ccdbf74a7d8fe0f0a44e85da1ed5975946 (diff) | |
Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending
* 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending:
tcm_fc: Handle DDP/SW fc_frame_payload_get failures in ft_recv_write_data
target: Fix bug for transport_generic_wait_for_tasks with direct operation
target: iscsi_target depends on NET
target: Fix WRITE_SAME_16 lba assignment breakage
MAINTAINERS: Add target-devel list for drivers/target/
iscsi-target: Fix CONFIG_SMP=n and CONFIG_MODULES=n build failure
iscsi-target: Fix snprintf usage with MAX_PORTAL_LEN
iscsi-target: Fix uninitialized usage of cmd->pad_bytes
iscsi-target: strlen() doesn't count the terminator
iscsi-target: Fix NULL dereference on allocation failure
| -rw-r--r-- | MAINTAINERS | 1 | ||||
| -rw-r--r-- | drivers/target/iscsi/Kconfig | 1 | ||||
| -rw-r--r-- | drivers/target/iscsi/iscsi_target.c | 15 | ||||
| -rw-r--r-- | drivers/target/iscsi/iscsi_target_configfs.c | 2 | ||||
| -rw-r--r-- | drivers/target/iscsi/iscsi_target_nego.c | 2 | ||||
| -rw-r--r-- | drivers/target/target_core_transport.c | 33 | ||||
| -rw-r--r-- | drivers/target/tcm_fc/tcm_fc.h | 5 | ||||
| -rw-r--r-- | drivers/target/tcm_fc/tfc_cmd.c | 1 | ||||
| -rw-r--r-- | drivers/target/tcm_fc/tfc_io.c | 121 |
9 files changed, 122 insertions, 59 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 0d2fcda465eb..6c84a219c833 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
| @@ -6319,6 +6319,7 @@ F: include/linux/sysv_fs.h | |||
| 6319 | TARGET SUBSYSTEM | 6319 | TARGET SUBSYSTEM |
| 6320 | M: Nicholas A. Bellinger <nab@linux-iscsi.org> | 6320 | M: Nicholas A. Bellinger <nab@linux-iscsi.org> |
| 6321 | L: linux-scsi@vger.kernel.org | 6321 | L: linux-scsi@vger.kernel.org |
| 6322 | L: target-devel@vger.kernel.org | ||
| 6322 | L: http://groups.google.com/group/linux-iscsi-target-dev | 6323 | L: http://groups.google.com/group/linux-iscsi-target-dev |
| 6323 | W: http://www.linux-iscsi.org | 6324 | W: http://www.linux-iscsi.org |
| 6324 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/nab/lio-core-2.6.git master | 6325 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/nab/lio-core-2.6.git master |
diff --git a/drivers/target/iscsi/Kconfig b/drivers/target/iscsi/Kconfig index 564ff4e0dbc4..8345fb457a40 100644 --- a/drivers/target/iscsi/Kconfig +++ b/drivers/target/iscsi/Kconfig | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | config ISCSI_TARGET | 1 | config ISCSI_TARGET |
| 2 | tristate "Linux-iSCSI.org iSCSI Target Mode Stack" | 2 | tristate "Linux-iSCSI.org iSCSI Target Mode Stack" |
| 3 | depends on NET | ||
| 3 | select CRYPTO | 4 | select CRYPTO |
| 4 | select CRYPTO_CRC32C | 5 | select CRYPTO_CRC32C |
| 5 | select CRYPTO_CRC32C_INTEL if X86 | 6 | select CRYPTO_CRC32C_INTEL if X86 |
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 14c81c4265bd..c24fb10de60b 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c | |||
| @@ -120,7 +120,7 @@ struct iscsi_tiqn *iscsit_add_tiqn(unsigned char *buf) | |||
| 120 | struct iscsi_tiqn *tiqn = NULL; | 120 | struct iscsi_tiqn *tiqn = NULL; |
| 121 | int ret; | 121 | int ret; |
| 122 | 122 | ||
| 123 | if (strlen(buf) > ISCSI_IQN_LEN) { | 123 | if (strlen(buf) >= ISCSI_IQN_LEN) { |
| 124 | pr_err("Target IQN exceeds %d bytes\n", | 124 | pr_err("Target IQN exceeds %d bytes\n", |
| 125 | ISCSI_IQN_LEN); | 125 | ISCSI_IQN_LEN); |
| 126 | return ERR_PTR(-EINVAL); | 126 | return ERR_PTR(-EINVAL); |
| @@ -1857,7 +1857,7 @@ static int iscsit_handle_text_cmd( | |||
| 1857 | char *text_ptr, *text_in; | 1857 | char *text_ptr, *text_in; |
| 1858 | int cmdsn_ret, niov = 0, rx_got, rx_size; | 1858 | int cmdsn_ret, niov = 0, rx_got, rx_size; |
| 1859 | u32 checksum = 0, data_crc = 0, payload_length; | 1859 | u32 checksum = 0, data_crc = 0, payload_length; |
| 1860 | u32 padding = 0, text_length = 0; | 1860 | u32 padding = 0, pad_bytes = 0, text_length = 0; |
| 1861 | struct iscsi_cmd *cmd; | 1861 | struct iscsi_cmd *cmd; |
| 1862 | struct kvec iov[3]; | 1862 | struct kvec iov[3]; |
| 1863 | struct iscsi_text *hdr; | 1863 | struct iscsi_text *hdr; |
| @@ -1896,7 +1896,7 @@ static int iscsit_handle_text_cmd( | |||
| 1896 | 1896 | ||
| 1897 | padding = ((-payload_length) & 3); | 1897 | padding = ((-payload_length) & 3); |
| 1898 | if (padding != 0) { | 1898 | if (padding != 0) { |
| 1899 | iov[niov].iov_base = cmd->pad_bytes; | 1899 | iov[niov].iov_base = &pad_bytes; |
| 1900 | iov[niov++].iov_len = padding; | 1900 | iov[niov++].iov_len = padding; |
| 1901 | rx_size += padding; | 1901 | rx_size += padding; |
| 1902 | pr_debug("Receiving %u additional bytes" | 1902 | pr_debug("Receiving %u additional bytes" |
| @@ -1917,7 +1917,7 @@ static int iscsit_handle_text_cmd( | |||
| 1917 | if (conn->conn_ops->DataDigest) { | 1917 | if (conn->conn_ops->DataDigest) { |
| 1918 | iscsit_do_crypto_hash_buf(&conn->conn_rx_hash, | 1918 | iscsit_do_crypto_hash_buf(&conn->conn_rx_hash, |
| 1919 | text_in, text_length, | 1919 | text_in, text_length, |
| 1920 | padding, cmd->pad_bytes, | 1920 | padding, (u8 *)&pad_bytes, |
| 1921 | (u8 *)&data_crc); | 1921 | (u8 *)&data_crc); |
| 1922 | 1922 | ||
| 1923 | if (checksum != data_crc) { | 1923 | if (checksum != data_crc) { |
| @@ -3468,7 +3468,12 @@ static inline void iscsit_thread_check_cpumask( | |||
| 3468 | } | 3468 | } |
| 3469 | 3469 | ||
| 3470 | #else | 3470 | #else |
| 3471 | #define iscsit_thread_get_cpumask(X) ({}) | 3471 | |
| 3472 | void iscsit_thread_get_cpumask(struct iscsi_conn *conn) | ||
| 3473 | { | ||
| 3474 | return; | ||
| 3475 | } | ||
| 3476 | |||
| 3472 | #define iscsit_thread_check_cpumask(X, Y, Z) ({}) | 3477 | #define iscsit_thread_check_cpumask(X, Y, Z) ({}) |
| 3473 | #endif /* CONFIG_SMP */ | 3478 | #endif /* CONFIG_SMP */ |
| 3474 | 3479 | ||
diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index 32bb92c44450..f095e65b1ccf 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c | |||
| @@ -181,7 +181,7 @@ struct se_tpg_np *lio_target_call_addnptotpg( | |||
| 181 | return ERR_PTR(-EOVERFLOW); | 181 | return ERR_PTR(-EOVERFLOW); |
| 182 | } | 182 | } |
| 183 | memset(buf, 0, MAX_PORTAL_LEN + 1); | 183 | memset(buf, 0, MAX_PORTAL_LEN + 1); |
| 184 | snprintf(buf, MAX_PORTAL_LEN, "%s", name); | 184 | snprintf(buf, MAX_PORTAL_LEN + 1, "%s", name); |
| 185 | 185 | ||
| 186 | memset(&sockaddr, 0, sizeof(struct __kernel_sockaddr_storage)); | 186 | memset(&sockaddr, 0, sizeof(struct __kernel_sockaddr_storage)); |
| 187 | 187 | ||
diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c index 713a4d23557a..4d087ac11067 100644 --- a/drivers/target/iscsi/iscsi_target_nego.c +++ b/drivers/target/iscsi/iscsi_target_nego.c | |||
| @@ -978,7 +978,7 @@ struct iscsi_login *iscsi_target_init_negotiation( | |||
| 978 | pr_err("Unable to allocate memory for struct iscsi_login.\n"); | 978 | pr_err("Unable to allocate memory for struct iscsi_login.\n"); |
| 979 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, | 979 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, |
| 980 | ISCSI_LOGIN_STATUS_NO_RESOURCES); | 980 | ISCSI_LOGIN_STATUS_NO_RESOURCES); |
| 981 | goto out; | 981 | return NULL; |
| 982 | } | 982 | } |
| 983 | 983 | ||
| 984 | login->req = kzalloc(ISCSI_HDR_LEN, GFP_KERNEL); | 984 | login->req = kzalloc(ISCSI_HDR_LEN, GFP_KERNEL); |
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index c75a01a1c475..89760329d5d0 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c | |||
| @@ -1747,6 +1747,8 @@ int transport_generic_handle_cdb( | |||
| 1747 | } | 1747 | } |
| 1748 | EXPORT_SYMBOL(transport_generic_handle_cdb); | 1748 | EXPORT_SYMBOL(transport_generic_handle_cdb); |
| 1749 | 1749 | ||
| 1750 | static void transport_generic_request_failure(struct se_cmd *, | ||
| 1751 | struct se_device *, int, int); | ||
| 1750 | /* | 1752 | /* |
| 1751 | * Used by fabric module frontends to queue tasks directly. | 1753 | * Used by fabric module frontends to queue tasks directly. |
| 1752 | * Many only be used from process context only | 1754 | * Many only be used from process context only |
| @@ -1754,6 +1756,8 @@ EXPORT_SYMBOL(transport_generic_handle_cdb); | |||
| 1754 | int transport_handle_cdb_direct( | 1756 | int transport_handle_cdb_direct( |
| 1755 | struct se_cmd *cmd) | 1757 | struct se_cmd *cmd) |
| 1756 | { | 1758 | { |
| 1759 | int ret; | ||
| 1760 | |||
| 1757 | if (!cmd->se_lun) { | 1761 | if (!cmd->se_lun) { |
| 1758 | dump_stack(); | 1762 | dump_stack(); |
| 1759 | pr_err("cmd->se_lun is NULL\n"); | 1763 | pr_err("cmd->se_lun is NULL\n"); |
| @@ -1765,8 +1769,31 @@ int transport_handle_cdb_direct( | |||
| 1765 | " from interrupt context\n"); | 1769 | " from interrupt context\n"); |
| 1766 | return -EINVAL; | 1770 | return -EINVAL; |
| 1767 | } | 1771 | } |
| 1768 | 1772 | /* | |
| 1769 | return transport_generic_new_cmd(cmd); | 1773 | * Set TRANSPORT_NEW_CMD state and cmd->t_transport_active=1 following |
| 1774 | * transport_generic_handle_cdb*() -> transport_add_cmd_to_queue() | ||
| 1775 | * in existing usage to ensure that outstanding descriptors are handled | ||
| 1776 | * correctly during shutdown via transport_generic_wait_for_tasks() | ||
| 1777 | * | ||
| 1778 | * Also, we don't take cmd->t_state_lock here as we only expect | ||
| 1779 | * this to be called for initial descriptor submission. | ||
| 1780 | */ | ||
| 1781 | cmd->t_state = TRANSPORT_NEW_CMD; | ||
| 1782 | atomic_set(&cmd->t_transport_active, 1); | ||
| 1783 | /* | ||
| 1784 | * transport_generic_new_cmd() is already handling QUEUE_FULL, | ||
| 1785 | * so follow TRANSPORT_NEW_CMD processing thread context usage | ||
| 1786 | * and call transport_generic_request_failure() if necessary.. | ||
| 1787 | */ | ||
| 1788 | ret = transport_generic_new_cmd(cmd); | ||
| 1789 | if (ret == -EAGAIN) | ||
| 1790 | return 0; | ||
| 1791 | else if (ret < 0) { | ||
| 1792 | cmd->transport_error_status = ret; | ||
| 1793 | transport_generic_request_failure(cmd, NULL, 0, | ||
| 1794 | (cmd->data_direction != DMA_TO_DEVICE)); | ||
| 1795 | } | ||
| 1796 | return 0; | ||
| 1770 | } | 1797 | } |
| 1771 | EXPORT_SYMBOL(transport_handle_cdb_direct); | 1798 | EXPORT_SYMBOL(transport_handle_cdb_direct); |
| 1772 | 1799 | ||
| @@ -3324,7 +3351,7 @@ static int transport_generic_cmd_sequencer( | |||
| 3324 | goto out_invalid_cdb_field; | 3351 | goto out_invalid_cdb_field; |
| 3325 | } | 3352 | } |
| 3326 | 3353 | ||
| 3327 | cmd->t_task_lba = get_unaligned_be16(&cdb[2]); | 3354 | cmd->t_task_lba = get_unaligned_be64(&cdb[2]); |
| 3328 | passthrough = (dev->transport->transport_type == | 3355 | passthrough = (dev->transport->transport_type == |
| 3329 | TRANSPORT_PLUGIN_PHBA_PDEV); | 3356 | TRANSPORT_PLUGIN_PHBA_PDEV); |
| 3330 | /* | 3357 | /* |
diff --git a/drivers/target/tcm_fc/tcm_fc.h b/drivers/target/tcm_fc/tcm_fc.h index f7fff7ed63c3..bd4fe21a23b8 100644 --- a/drivers/target/tcm_fc/tcm_fc.h +++ b/drivers/target/tcm_fc/tcm_fc.h | |||
| @@ -187,4 +187,9 @@ void ft_dump_cmd(struct ft_cmd *, const char *caller); | |||
| 187 | 187 | ||
| 188 | ssize_t ft_format_wwn(char *, size_t, u64); | 188 | ssize_t ft_format_wwn(char *, size_t, u64); |
| 189 | 189 | ||
| 190 | /* | ||
| 191 | * Underlying HW specific helper function | ||
| 192 | */ | ||
| 193 | void ft_invl_hw_context(struct ft_cmd *); | ||
| 194 | |||
| 190 | #endif /* __TCM_FC_H__ */ | 195 | #endif /* __TCM_FC_H__ */ |
diff --git a/drivers/target/tcm_fc/tfc_cmd.c b/drivers/target/tcm_fc/tfc_cmd.c index 09df38b4610c..5654dc22f7ae 100644 --- a/drivers/target/tcm_fc/tfc_cmd.c +++ b/drivers/target/tcm_fc/tfc_cmd.c | |||
| @@ -320,6 +320,7 @@ static void ft_recv_seq(struct fc_seq *sp, struct fc_frame *fp, void *arg) | |||
| 320 | default: | 320 | default: |
| 321 | pr_debug("%s: unhandled frame r_ctl %x\n", | 321 | pr_debug("%s: unhandled frame r_ctl %x\n", |
| 322 | __func__, fh->fh_r_ctl); | 322 | __func__, fh->fh_r_ctl); |
| 323 | ft_invl_hw_context(cmd); | ||
| 323 | fc_frame_free(fp); | 324 | fc_frame_free(fp); |
| 324 | transport_generic_free_cmd(&cmd->se_cmd, 0, 0); | 325 | transport_generic_free_cmd(&cmd->se_cmd, 0, 0); |
| 325 | break; | 326 | break; |
diff --git a/drivers/target/tcm_fc/tfc_io.c b/drivers/target/tcm_fc/tfc_io.c index 8e2a46ddcccb..c37f4cd96452 100644 --- a/drivers/target/tcm_fc/tfc_io.c +++ b/drivers/target/tcm_fc/tfc_io.c | |||
| @@ -213,62 +213,49 @@ void ft_recv_write_data(struct ft_cmd *cmd, struct fc_frame *fp) | |||
| 213 | if (!(ntoh24(fh->fh_f_ctl) & FC_FC_REL_OFF)) | 213 | if (!(ntoh24(fh->fh_f_ctl) & FC_FC_REL_OFF)) |
| 214 | goto drop; | 214 | goto drop; |
| 215 | 215 | ||
| 216 | f_ctl = ntoh24(fh->fh_f_ctl); | ||
| 217 | ep = fc_seq_exch(seq); | ||
| 218 | lport = ep->lp; | ||
| 219 | if (cmd->was_ddp_setup) { | ||
| 220 | BUG_ON(!ep); | ||
| 221 | BUG_ON(!lport); | ||
| 222 | } | ||
| 223 | |||
| 216 | /* | 224 | /* |
| 217 | * Doesn't expect even single byte of payload. Payload | 225 | * Doesn't expect payload if DDP is setup. Payload |
| 218 | * is expected to be copied directly to user buffers | 226 | * is expected to be copied directly to user buffers |
| 219 | * due to DDP (Large Rx offload) feature, hence | 227 | * due to DDP (Large Rx offload), |
| 220 | * BUG_ON if BUF is non-NULL | ||
| 221 | */ | 228 | */ |
| 222 | buf = fc_frame_payload_get(fp, 1); | 229 | buf = fc_frame_payload_get(fp, 1); |
| 223 | if (cmd->was_ddp_setup && buf) { | 230 | if (buf) |
| 224 | pr_debug("%s: When DDP was setup, not expected to" | 231 | pr_err("%s: xid 0x%x, f_ctl 0x%x, cmd->sg %p, " |
| 225 | "receive frame with payload, Payload shall be" | 232 | "cmd->sg_cnt 0x%x. DDP was setup" |
| 226 | "copied directly to buffer instead of coming " | 233 | " hence not expected to receive frame with " |
| 227 | "via. legacy receive queues\n", __func__); | 234 | "payload, Frame will be dropped if " |
| 228 | BUG_ON(buf); | 235 | "'Sequence Initiative' bit in f_ctl is " |
| 229 | } | 236 | "not set\n", __func__, ep->xid, f_ctl, |
| 237 | cmd->sg, cmd->sg_cnt); | ||
| 238 | /* | ||
| 239 | * Invalidate HW DDP context if it was setup for respective | ||
| 240 | * command. Invalidation of HW DDP context is requited in both | ||
| 241 | * situation (success and error). | ||
| 242 | */ | ||
| 243 | ft_invl_hw_context(cmd); | ||
| 230 | 244 | ||
| 231 | /* | 245 | /* |
| 232 | * If ft_cmd indicated 'ddp_setup', in that case only the last frame | 246 | * If "Sequence Initiative (TSI)" bit set in f_ctl, means last |
| 233 | * should come with 'TSI bit being set'. If 'TSI bit is not set and if | 247 | * write data frame is received successfully where payload is |
| 234 | * data frame appears here, means error condition. In both the cases | 248 | * posted directly to user buffer and only the last frame's |
| 235 | * release the DDP context (ddp_put) and in error case, as well | 249 | * header is posted in receive queue. |
| 236 | * initiate error recovery mechanism. | 250 | * |
| 251 | * If "Sequence Initiative (TSI)" bit is not set, means error | ||
| 252 | * condition w.r.t. DDP, hence drop the packet and let explict | ||
| 253 | * ABORTS from other end of exchange timer trigger the recovery. | ||
| 237 | */ | 254 | */ |
| 238 | ep = fc_seq_exch(seq); | 255 | if (f_ctl & FC_FC_SEQ_INIT) |
| 239 | if (cmd->was_ddp_setup) { | 256 | goto last_frame; |
| 240 | BUG_ON(!ep); | 257 | else |
| 241 | lport = ep->lp; | 258 | goto drop; |
| 242 | BUG_ON(!lport); | ||
| 243 | } | ||
| 244 | if (cmd->was_ddp_setup && ep->xid != FC_XID_UNKNOWN) { | ||
| 245 | f_ctl = ntoh24(fh->fh_f_ctl); | ||
| 246 | /* | ||
| 247 | * If TSI bit set in f_ctl, means last write data frame is | ||
| 248 | * received successfully where payload is posted directly | ||
| 249 | * to user buffer and only the last frame's header is posted | ||
| 250 | * in legacy receive queue | ||
| 251 | */ | ||
| 252 | if (f_ctl & FC_FC_SEQ_INIT) { /* TSI bit set in FC frame */ | ||
| 253 | cmd->write_data_len = lport->tt.ddp_done(lport, | ||
| 254 | ep->xid); | ||
| 255 | goto last_frame; | ||
| 256 | } else { | ||
| 257 | /* | ||
| 258 | * Updating the write_data_len may be meaningless at | ||
| 259 | * this point, but just in case if required in future | ||
| 260 | * for debugging or any other purpose | ||
| 261 | */ | ||
| 262 | pr_err("%s: Received frame with TSI bit not" | ||
| 263 | " being SET, dropping the frame, " | ||
| 264 | "cmd->sg <%p>, cmd->sg_cnt <0x%x>\n", | ||
| 265 | __func__, cmd->sg, cmd->sg_cnt); | ||
| 266 | cmd->write_data_len = lport->tt.ddp_done(lport, | ||
| 267 | ep->xid); | ||
| 268 | lport->tt.seq_exch_abort(cmd->seq, 0); | ||
| 269 | goto drop; | ||
| 270 | } | ||
| 271 | } | ||
| 272 | 259 | ||
| 273 | rel_off = ntohl(fh->fh_parm_offset); | 260 | rel_off = ntohl(fh->fh_parm_offset); |
| 274 | frame_len = fr_len(fp); | 261 | frame_len = fr_len(fp); |
| @@ -331,3 +318,39 @@ last_frame: | |||
| 331 | drop: | 318 | drop: |
| 332 | fc_frame_free(fp); | 319 | fc_frame_free(fp); |
| 333 | } | 320 | } |
| 321 | |||
| 322 | /* | ||
| 323 | * Handle and cleanup any HW specific resources if | ||
| 324 | * received ABORTS, errors, timeouts. | ||
| 325 | */ | ||
| 326 | void ft_invl_hw_context(struct ft_cmd *cmd) | ||
| 327 | { | ||
| 328 | struct fc_seq *seq = cmd->seq; | ||
| 329 | struct fc_exch *ep = NULL; | ||
| 330 | struct fc_lport *lport = NULL; | ||
| 331 | |||
| 332 | BUG_ON(!cmd); | ||
| 333 | |||
| 334 | /* Cleanup the DDP context in HW if DDP was setup */ | ||
| 335 | if (cmd->was_ddp_setup && seq) { | ||
| 336 | ep = fc_seq_exch(seq); | ||
| 337 | if (ep) { | ||
| 338 | lport = ep->lp; | ||
| 339 | if (lport && (ep->xid <= lport->lro_xid)) | ||
| 340 | /* | ||
| 341 | * "ddp_done" trigger invalidation of HW | ||
| 342 | * specific DDP context | ||
| 343 | */ | ||
| 344 | cmd->write_data_len = lport->tt.ddp_done(lport, | ||
| 345 | ep->xid); | ||
| 346 | |||
| 347 | /* | ||
| 348 | * Resetting same variable to indicate HW's | ||
| 349 | * DDP context has been invalidated to avoid | ||
| 350 | * re_invalidation of same context (context is | ||
| 351 | * identified using ep->xid) | ||
| 352 | */ | ||
| 353 | cmd->was_ddp_setup = 0; | ||
| 354 | } | ||
| 355 | } | ||
| 356 | } | ||
