aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/target/target_core_iblock.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/target/target_core_iblock.c')
-rw-r--r--drivers/target/target_core_iblock.c81
1 files changed, 4 insertions, 77 deletions
diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c
index 96a9b620e89a..07f5f94634bb 100644
--- a/drivers/target/target_core_iblock.c
+++ b/drivers/target/target_core_iblock.c
@@ -380,9 +380,10 @@ iblock_execute_sync_cache(struct se_cmd *cmd)
380} 380}
381 381
382static sense_reason_t 382static sense_reason_t
383iblock_do_unmap(struct se_cmd *cmd, struct block_device *bdev, 383iblock_do_unmap(struct se_cmd *cmd, void *priv,
384 sector_t lba, sector_t nolb) 384 sector_t lba, sector_t nolb)
385{ 385{
386 struct block_device *bdev = priv;
386 int ret; 387 int ret;
387 388
388 ret = blkdev_issue_discard(bdev, lba, nolb, GFP_KERNEL, 0); 389 ret = blkdev_issue_discard(bdev, lba, nolb, GFP_KERNEL, 0);
@@ -397,83 +398,9 @@ iblock_do_unmap(struct se_cmd *cmd, struct block_device *bdev,
397static sense_reason_t 398static sense_reason_t
398iblock_execute_unmap(struct se_cmd *cmd) 399iblock_execute_unmap(struct se_cmd *cmd)
399{ 400{
400 struct se_device *dev = cmd->se_dev; 401 struct block_device *bdev = IBLOCK_DEV(cmd->se_dev)->ibd_bd;
401 struct iblock_dev *ib_dev = IBLOCK_DEV(dev);
402 unsigned char *buf, *ptr = NULL;
403 sector_t lba;
404 int size;
405 u32 range;
406 sense_reason_t ret = 0;
407 int dl, bd_dl;
408
409 /* We never set ANC_SUP */
410 if (cmd->t_task_cdb[1])
411 return TCM_INVALID_CDB_FIELD;
412
413 if (cmd->data_length == 0) {
414 target_complete_cmd(cmd, SAM_STAT_GOOD);
415 return 0;
416 }
417
418 if (cmd->data_length < 8) {
419 pr_warn("UNMAP parameter list length %u too small\n",
420 cmd->data_length);
421 return TCM_PARAMETER_LIST_LENGTH_ERROR;
422 }
423
424 buf = transport_kmap_data_sg(cmd);
425 if (!buf)
426 return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
427
428 dl = get_unaligned_be16(&buf[0]);
429 bd_dl = get_unaligned_be16(&buf[2]);
430
431 size = cmd->data_length - 8;
432 if (bd_dl > size)
433 pr_warn("UNMAP parameter list length %u too small, ignoring bd_dl %u\n",
434 cmd->data_length, bd_dl);
435 else
436 size = bd_dl;
437
438 if (size / 16 > dev->dev_attrib.max_unmap_block_desc_count) {
439 ret = TCM_INVALID_PARAMETER_LIST;
440 goto err;
441 }
442
443 /* First UNMAP block descriptor starts at 8 byte offset */
444 ptr = &buf[8];
445 pr_debug("UNMAP: Sub: %s Using dl: %u bd_dl: %u size: %u"
446 " ptr: %p\n", dev->transport->name, dl, bd_dl, size, ptr);
447
448 while (size >= 16) {
449 lba = get_unaligned_be64(&ptr[0]);
450 range = get_unaligned_be32(&ptr[8]);
451 pr_debug("UNMAP: Using lba: %llu and range: %u\n",
452 (unsigned long long)lba, range);
453
454 if (range > dev->dev_attrib.max_unmap_lba_count) {
455 ret = TCM_INVALID_PARAMETER_LIST;
456 goto err;
457 }
458
459 if (lba + range > dev->transport->get_blocks(dev) + 1) {
460 ret = TCM_ADDRESS_OUT_OF_RANGE;
461 goto err;
462 }
463
464 ret = iblock_do_unmap(cmd, ib_dev->ibd_bd, lba, range);
465 if (ret)
466 goto err;
467
468 ptr += 16;
469 size -= 16;
470 }
471 402
472err: 403 return sbc_execute_unmap(cmd, iblock_do_unmap, bdev);
473 transport_kunmap_data_sg(cmd);
474 if (!ret)
475 target_complete_cmd(cmd, GOOD);
476 return ret;
477} 404}
478 405
479static sense_reason_t 406static sense_reason_t