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 | } | ||