aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-08-03 21:12:09 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-08-03 21:12:09 -0400
commita9e4e6e14c322e08d1c615afc8f504fb415f9613 (patch)
tree7c842bbfdc322b5ff99644e8b1bc7b415669233e
parent27665ffa22b9b83bab226bf12c61424f7f1f8995 (diff)
parentdcd998ccdbf74a7d8fe0f0a44e85da1ed5975946 (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--MAINTAINERS1
-rw-r--r--drivers/target/iscsi/Kconfig1
-rw-r--r--drivers/target/iscsi/iscsi_target.c15
-rw-r--r--drivers/target/iscsi/iscsi_target_configfs.c2
-rw-r--r--drivers/target/iscsi/iscsi_target_nego.c2
-rw-r--r--drivers/target/target_core_transport.c33
-rw-r--r--drivers/target/tcm_fc/tcm_fc.h5
-rw-r--r--drivers/target/tcm_fc/tfc_cmd.c1
-rw-r--r--drivers/target/tcm_fc/tfc_io.c121
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
6319TARGET SUBSYSTEM 6319TARGET SUBSYSTEM
6320M: Nicholas A. Bellinger <nab@linux-iscsi.org> 6320M: Nicholas A. Bellinger <nab@linux-iscsi.org>
6321L: linux-scsi@vger.kernel.org 6321L: linux-scsi@vger.kernel.org
6322L: target-devel@vger.kernel.org
6322L: http://groups.google.com/group/linux-iscsi-target-dev 6323L: http://groups.google.com/group/linux-iscsi-target-dev
6323W: http://www.linux-iscsi.org 6324W: http://www.linux-iscsi.org
6324T: git git://git.kernel.org/pub/scm/linux/kernel/git/nab/lio-core-2.6.git master 6325T: 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 @@
1config ISCSI_TARGET 1config 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
3472void 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}
1748EXPORT_SYMBOL(transport_generic_handle_cdb); 1748EXPORT_SYMBOL(transport_generic_handle_cdb);
1749 1749
1750static 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);
1754int transport_handle_cdb_direct( 1756int 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}
1771EXPORT_SYMBOL(transport_handle_cdb_direct); 1798EXPORT_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
188ssize_t ft_format_wwn(char *, size_t, u64); 188ssize_t ft_format_wwn(char *, size_t, u64);
189 189
190/*
191 * Underlying HW specific helper function
192 */
193void 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:
331drop: 318drop:
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 */
326void 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}