aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/target/target_core_sbc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/target/target_core_sbc.c')
-rw-r--r--drivers/target/target_core_sbc.c33
1 files changed, 31 insertions, 2 deletions
diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c
index 6c17295e8d7c..d9b92b2c524d 100644
--- a/drivers/target/target_core_sbc.c
+++ b/drivers/target/target_core_sbc.c
@@ -263,6 +263,11 @@ sbc_setup_write_same(struct se_cmd *cmd, unsigned char *flags, struct sbc_ops *o
263 sectors, cmd->se_dev->dev_attrib.max_write_same_len); 263 sectors, cmd->se_dev->dev_attrib.max_write_same_len);
264 return TCM_INVALID_CDB_FIELD; 264 return TCM_INVALID_CDB_FIELD;
265 } 265 }
266 /* We always have ANC_SUP == 0 so setting ANCHOR is always an error */
267 if (flags[0] & 0x10) {
268 pr_warn("WRITE SAME with ANCHOR not supported\n");
269 return TCM_INVALID_CDB_FIELD;
270 }
266 /* 271 /*
267 * Special case for WRITE_SAME w/ UNMAP=1 that ends up getting 272 * Special case for WRITE_SAME w/ UNMAP=1 that ends up getting
268 * translated into block discard requests within backend code. 273 * translated into block discard requests within backend code.
@@ -349,7 +354,16 @@ static sense_reason_t compare_and_write_post(struct se_cmd *cmd)
349{ 354{
350 struct se_device *dev = cmd->se_dev; 355 struct se_device *dev = cmd->se_dev;
351 356
352 cmd->se_cmd_flags |= SCF_COMPARE_AND_WRITE_POST; 357 /*
358 * Only set SCF_COMPARE_AND_WRITE_POST to force a response fall-through
359 * within target_complete_ok_work() if the command was successfully
360 * sent to the backend driver.
361 */
362 spin_lock_irq(&cmd->t_state_lock);
363 if ((cmd->transport_state & CMD_T_SENT) && !cmd->scsi_status)
364 cmd->se_cmd_flags |= SCF_COMPARE_AND_WRITE_POST;
365 spin_unlock_irq(&cmd->t_state_lock);
366
353 /* 367 /*
354 * Unlock ->caw_sem originally obtained during sbc_compare_and_write() 368 * Unlock ->caw_sem originally obtained during sbc_compare_and_write()
355 * before the original READ I/O submission. 369 * before the original READ I/O submission.
@@ -363,7 +377,7 @@ static sense_reason_t compare_and_write_callback(struct se_cmd *cmd)
363{ 377{
364 struct se_device *dev = cmd->se_dev; 378 struct se_device *dev = cmd->se_dev;
365 struct scatterlist *write_sg = NULL, *sg; 379 struct scatterlist *write_sg = NULL, *sg;
366 unsigned char *buf, *addr; 380 unsigned char *buf = NULL, *addr;
367 struct sg_mapping_iter m; 381 struct sg_mapping_iter m;
368 unsigned int offset = 0, len; 382 unsigned int offset = 0, len;
369 unsigned int nlbas = cmd->t_task_nolb; 383 unsigned int nlbas = cmd->t_task_nolb;
@@ -378,6 +392,15 @@ static sense_reason_t compare_and_write_callback(struct se_cmd *cmd)
378 */ 392 */
379 if (!cmd->t_data_sg || !cmd->t_bidi_data_sg) 393 if (!cmd->t_data_sg || !cmd->t_bidi_data_sg)
380 return TCM_NO_SENSE; 394 return TCM_NO_SENSE;
395 /*
396 * Immediately exit + release dev->caw_sem if command has already
397 * been failed with a non-zero SCSI status.
398 */
399 if (cmd->scsi_status) {
400 pr_err("compare_and_write_callback: non zero scsi_status:"
401 " 0x%02x\n", cmd->scsi_status);
402 goto out;
403 }
381 404
382 buf = kzalloc(cmd->data_length, GFP_KERNEL); 405 buf = kzalloc(cmd->data_length, GFP_KERNEL);
383 if (!buf) { 406 if (!buf) {
@@ -508,6 +531,12 @@ sbc_compare_and_write(struct se_cmd *cmd)
508 cmd->transport_complete_callback = NULL; 531 cmd->transport_complete_callback = NULL;
509 return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; 532 return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
510 } 533 }
534 /*
535 * Reset cmd->data_length to individual block_size in order to not
536 * confuse backend drivers that depend on this value matching the
537 * size of the I/O being submitted.
538 */
539 cmd->data_length = cmd->t_task_nolb * dev->dev_attrib.block_size;
511 540
512 ret = cmd->execute_rw(cmd, cmd->t_bidi_data_sg, cmd->t_bidi_data_nents, 541 ret = cmd->execute_rw(cmd, cmd->t_bidi_data_sg, cmd->t_bidi_data_nents,
513 DMA_FROM_DEVICE); 542 DMA_FROM_DEVICE);