diff options
Diffstat (limited to 'drivers/target/target_core_iblock.c')
-rw-r--r-- | drivers/target/target_core_iblock.c | 86 |
1 files changed, 79 insertions, 7 deletions
diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index 53f4501819f9..664604616576 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c | |||
@@ -151,6 +151,11 @@ static int iblock_configure_device(struct se_device *dev) | |||
151 | pr_debug("IBLOCK: BLOCK Discard support available," | 151 | pr_debug("IBLOCK: BLOCK Discard support available," |
152 | " disabled by default\n"); | 152 | " disabled by default\n"); |
153 | } | 153 | } |
154 | /* | ||
155 | * Enable write same emulation for IBLOCK and use 0xFFFF as | ||
156 | * the smaller WRITE_SAME(10) only has a two-byte block count. | ||
157 | */ | ||
158 | dev->dev_attrib.max_write_same_len = 0xFFFF; | ||
154 | 159 | ||
155 | if (blk_queue_nonrot(q)) | 160 | if (blk_queue_nonrot(q)) |
156 | dev->dev_attrib.is_nonrot = 1; | 161 | dev->dev_attrib.is_nonrot = 1; |
@@ -375,17 +380,20 @@ err: | |||
375 | return ret; | 380 | return ret; |
376 | } | 381 | } |
377 | 382 | ||
383 | static struct bio *iblock_get_bio(struct se_cmd *, sector_t, u32); | ||
384 | static void iblock_submit_bios(struct bio_list *, int); | ||
385 | static void iblock_complete_cmd(struct se_cmd *); | ||
386 | |||
378 | static sense_reason_t | 387 | static sense_reason_t |
379 | iblock_execute_write_same(struct se_cmd *cmd) | 388 | iblock_execute_write_same_unmap(struct se_cmd *cmd) |
380 | { | 389 | { |
381 | struct iblock_dev *ib_dev = IBLOCK_DEV(cmd->se_dev); | 390 | struct iblock_dev *ib_dev = IBLOCK_DEV(cmd->se_dev); |
382 | int ret; | 391 | int rc; |
383 | 392 | ||
384 | ret = blkdev_issue_discard(ib_dev->ibd_bd, cmd->t_task_lba, | 393 | rc = blkdev_issue_discard(ib_dev->ibd_bd, cmd->t_task_lba, |
385 | spc_get_write_same_sectors(cmd), GFP_KERNEL, | 394 | spc_get_write_same_sectors(cmd), GFP_KERNEL, 0); |
386 | 0); | 395 | if (rc < 0) { |
387 | if (ret < 0) { | 396 | pr_warn("blkdev_issue_discard() failed: %d\n", rc); |
388 | pr_debug("blkdev_issue_discard() failed for WRITE_SAME\n"); | ||
389 | return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | 397 | return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; |
390 | } | 398 | } |
391 | 399 | ||
@@ -393,6 +401,69 @@ iblock_execute_write_same(struct se_cmd *cmd) | |||
393 | return 0; | 401 | return 0; |
394 | } | 402 | } |
395 | 403 | ||
404 | static sense_reason_t | ||
405 | iblock_execute_write_same(struct se_cmd *cmd) | ||
406 | { | ||
407 | struct iblock_req *ibr; | ||
408 | struct scatterlist *sg; | ||
409 | struct bio *bio; | ||
410 | struct bio_list list; | ||
411 | sector_t block_lba = cmd->t_task_lba; | ||
412 | unsigned int sectors = spc_get_write_same_sectors(cmd); | ||
413 | |||
414 | sg = &cmd->t_data_sg[0]; | ||
415 | |||
416 | if (cmd->t_data_nents > 1 || | ||
417 | sg->length != cmd->se_dev->dev_attrib.block_size) { | ||
418 | pr_err("WRITE_SAME: Illegal SGL t_data_nents: %u length: %u" | ||
419 | " block_size: %u\n", cmd->t_data_nents, sg->length, | ||
420 | cmd->se_dev->dev_attrib.block_size); | ||
421 | return TCM_INVALID_CDB_FIELD; | ||
422 | } | ||
423 | |||
424 | ibr = kzalloc(sizeof(struct iblock_req), GFP_KERNEL); | ||
425 | if (!ibr) | ||
426 | goto fail; | ||
427 | cmd->priv = ibr; | ||
428 | |||
429 | bio = iblock_get_bio(cmd, block_lba, 1); | ||
430 | if (!bio) | ||
431 | goto fail_free_ibr; | ||
432 | |||
433 | bio_list_init(&list); | ||
434 | bio_list_add(&list, bio); | ||
435 | |||
436 | atomic_set(&ibr->pending, 1); | ||
437 | |||
438 | while (sectors) { | ||
439 | while (bio_add_page(bio, sg_page(sg), sg->length, sg->offset) | ||
440 | != sg->length) { | ||
441 | |||
442 | bio = iblock_get_bio(cmd, block_lba, 1); | ||
443 | if (!bio) | ||
444 | goto fail_put_bios; | ||
445 | |||
446 | atomic_inc(&ibr->pending); | ||
447 | bio_list_add(&list, bio); | ||
448 | } | ||
449 | |||
450 | /* Always in 512 byte units for Linux/Block */ | ||
451 | block_lba += sg->length >> IBLOCK_LBA_SHIFT; | ||
452 | sectors -= 1; | ||
453 | } | ||
454 | |||
455 | iblock_submit_bios(&list, WRITE); | ||
456 | return 0; | ||
457 | |||
458 | fail_put_bios: | ||
459 | while ((bio = bio_list_pop(&list))) | ||
460 | bio_put(bio); | ||
461 | fail_free_ibr: | ||
462 | kfree(ibr); | ||
463 | fail: | ||
464 | return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | ||
465 | } | ||
466 | |||
396 | enum { | 467 | enum { |
397 | Opt_udev_path, Opt_readonly, Opt_force, Opt_err | 468 | Opt_udev_path, Opt_readonly, Opt_force, Opt_err |
398 | }; | 469 | }; |
@@ -701,6 +772,7 @@ static struct sbc_ops iblock_sbc_ops = { | |||
701 | .execute_rw = iblock_execute_rw, | 772 | .execute_rw = iblock_execute_rw, |
702 | .execute_sync_cache = iblock_execute_sync_cache, | 773 | .execute_sync_cache = iblock_execute_sync_cache, |
703 | .execute_write_same = iblock_execute_write_same, | 774 | .execute_write_same = iblock_execute_write_same, |
775 | .execute_write_same_unmap = iblock_execute_write_same_unmap, | ||
704 | .execute_unmap = iblock_execute_unmap, | 776 | .execute_unmap = iblock_execute_unmap, |
705 | }; | 777 | }; |
706 | 778 | ||