diff options
Diffstat (limited to 'drivers/target/target_core_sbc.c')
-rw-r--r-- | drivers/target/target_core_sbc.c | 33 |
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); |