]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/target/target_core_iblock.c
Merge branch 'kbuild' of git://git.kernel.org/pub/scm/linux/kernel/git/mmarek/kbuild
[karo-tx-linux.git] / drivers / target / target_core_iblock.c
index 701877f9cd33ebd62f5375b120364abd6b41466a..b526d23dcd4f178be3fd06b4fdcc273a0ba78a4f 100644 (file)
@@ -4,10 +4,7 @@
  * This file contains the Storage Engine  <-> Linux BlockIO transport
  * specific functions.
  *
- * Copyright (c) 2003, 2004, 2005 PyX Technologies, Inc.
- * Copyright (c) 2005, 2006, 2007 SBE, Inc.
- * Copyright (c) 2007-2010 Rising Tide Systems
- * Copyright (c) 2008-2010 Linux-iSCSI.org
+ * (c) Copyright 2003-2012 RisingTide Systems LLC.
  *
  * Nicholas A. Bellinger <nab@kernel.org>
  *
@@ -58,8 +55,6 @@ static inline struct iblock_dev *IBLOCK_DEV(struct se_device *dev)
 
 static struct se_subsystem_api iblock_template;
 
-static void iblock_bio_done(struct bio *, int);
-
 /*     iblock_attach_hba(): (Part of se_subsystem_api_t template)
  *
  *
@@ -151,6 +146,11 @@ static int iblock_configure_device(struct se_device *dev)
                pr_debug("IBLOCK: BLOCK Discard support available,"
                                " disabled by default\n");
        }
+       /*
+        * Enable write same emulation for IBLOCK and use 0xFFFF as
+        * the smaller WRITE_SAME(10) only has a two-byte block count.
+        */
+       dev->dev_attrib.max_write_same_len = 0xFFFF;
 
        if (blk_queue_nonrot(q))
                dev->dev_attrib.is_nonrot = 1;
@@ -253,6 +253,87 @@ static unsigned long long iblock_emulate_read_cap_with_block_size(
        return blocks_long;
 }
 
+static void iblock_complete_cmd(struct se_cmd *cmd)
+{
+       struct iblock_req *ibr = cmd->priv;
+       u8 status;
+
+       if (!atomic_dec_and_test(&ibr->pending))
+               return;
+
+       if (atomic_read(&ibr->ib_bio_err_cnt))
+               status = SAM_STAT_CHECK_CONDITION;
+       else
+               status = SAM_STAT_GOOD;
+
+       target_complete_cmd(cmd, status);
+       kfree(ibr);
+}
+
+static void iblock_bio_done(struct bio *bio, int err)
+{
+       struct se_cmd *cmd = bio->bi_private;
+       struct iblock_req *ibr = cmd->priv;
+
+       /*
+        * Set -EIO if !BIO_UPTODATE and the passed is still err=0
+        */
+       if (!test_bit(BIO_UPTODATE, &bio->bi_flags) && !err)
+               err = -EIO;
+
+       if (err != 0) {
+               pr_err("test_bit(BIO_UPTODATE) failed for bio: %p,"
+                       " err: %d\n", bio, err);
+               /*
+                * Bump the ib_bio_err_cnt and release bio.
+                */
+               atomic_inc(&ibr->ib_bio_err_cnt);
+               smp_mb__after_atomic_inc();
+       }
+
+       bio_put(bio);
+
+       iblock_complete_cmd(cmd);
+}
+
+static struct bio *
+iblock_get_bio(struct se_cmd *cmd, sector_t lba, u32 sg_num)
+{
+       struct iblock_dev *ib_dev = IBLOCK_DEV(cmd->se_dev);
+       struct bio *bio;
+
+       /*
+        * Only allocate as many vector entries as the bio code allows us to,
+        * we'll loop later on until we have handled the whole request.
+        */
+       if (sg_num > BIO_MAX_PAGES)
+               sg_num = BIO_MAX_PAGES;
+
+       bio = bio_alloc_bioset(GFP_NOIO, sg_num, ib_dev->ibd_bio_set);
+       if (!bio) {
+               pr_err("Unable to allocate memory for bio\n");
+               return NULL;
+       }
+
+       bio->bi_bdev = ib_dev->ibd_bd;
+       bio->bi_private = cmd;
+       bio->bi_end_io = &iblock_bio_done;
+       bio->bi_sector = lba;
+
+       return bio;
+}
+
+static void iblock_submit_bios(struct bio_list *list, int rw)
+{
+       struct blk_plug plug;
+       struct bio *bio;
+
+       blk_start_plug(&plug);
+       while ((bio = bio_list_pop(list)))
+               submit_bio(rw, bio);
+       blk_finish_plug(&plug);
+}
+
 static void iblock_end_io_flush(struct bio *bio, int err)
 {
        struct se_cmd *cmd = bio->bi_private;
@@ -261,13 +342,10 @@ static void iblock_end_io_flush(struct bio *bio, int err)
                pr_err("IBLOCK: cache flush failed: %d\n", err);
 
        if (cmd) {
-               if (err) {
-                       cmd->scsi_sense_reason =
-                               TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+               if (err)
                        target_complete_cmd(cmd, SAM_STAT_CHECK_CONDITION);
-               } else {
+               else
                        target_complete_cmd(cmd, SAM_STAT_GOOD);
-               }
        }
 
        bio_put(bio);
@@ -277,7 +355,8 @@ static void iblock_end_io_flush(struct bio *bio, int err)
  * Implement SYCHRONIZE CACHE.  Note that we can't handle lba ranges and must
  * always flush the whole cache.
  */
-static int iblock_execute_sync_cache(struct se_cmd *cmd)
+static sense_reason_t
+iblock_execute_sync_cache(struct se_cmd *cmd)
 {
        struct iblock_dev *ib_dev = IBLOCK_DEV(cmd->se_dev);
        int immed = (cmd->t_task_cdb[1] & 0x2);
@@ -299,7 +378,8 @@ static int iblock_execute_sync_cache(struct se_cmd *cmd)
        return 0;
 }
 
-static int iblock_execute_unmap(struct se_cmd *cmd)
+static sense_reason_t
+iblock_execute_unmap(struct se_cmd *cmd)
 {
        struct se_device *dev = cmd->se_dev;
        struct iblock_dev *ib_dev = IBLOCK_DEV(dev);
@@ -307,17 +387,18 @@ static int iblock_execute_unmap(struct se_cmd *cmd)
        sector_t lba;
        int size;
        u32 range;
-       int ret = 0;
-       int dl, bd_dl;
+       sense_reason_t ret = 0;
+       int dl, bd_dl, err;
 
        if (cmd->data_length < 8) {
                pr_warn("UNMAP parameter list length %u too small\n",
                        cmd->data_length);
-               cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST;
-               return -EINVAL;
+               return TCM_INVALID_PARAMETER_LIST;
        }
 
        buf = transport_kmap_data_sg(cmd);
+       if (!buf)
+               return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
 
        dl = get_unaligned_be16(&buf[0]);
        bd_dl = get_unaligned_be16(&buf[2]);
@@ -330,8 +411,7 @@ static int iblock_execute_unmap(struct se_cmd *cmd)
                size = bd_dl;
 
        if (size / 16 > dev->dev_attrib.max_unmap_block_desc_count) {
-               cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST;
-               ret = -EINVAL;
+               ret = TCM_INVALID_PARAMETER_LIST;
                goto err;
        }
 
@@ -347,22 +427,21 @@ static int iblock_execute_unmap(struct se_cmd *cmd)
                                 (unsigned long long)lba, range);
 
                if (range > dev->dev_attrib.max_unmap_lba_count) {
-                       cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST;
-                       ret = -EINVAL;
+                       ret = TCM_INVALID_PARAMETER_LIST;
                        goto err;
                }
 
                if (lba + range > dev->transport->get_blocks(dev) + 1) {
-                       cmd->scsi_sense_reason = TCM_ADDRESS_OUT_OF_RANGE;
-                       ret = -EINVAL;
+                       ret = TCM_ADDRESS_OUT_OF_RANGE;
                        goto err;
                }
 
-               ret = blkdev_issue_discard(ib_dev->ibd_bd, lba, range,
+               err = blkdev_issue_discard(ib_dev->ibd_bd, lba, range,
                                           GFP_KERNEL, 0);
-               if (ret < 0) {
+               if (err < 0) {
                        pr_err("blkdev_issue_discard() failed: %d\n",
-                                       ret);
+                                       err);
+                       ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
                        goto err;
                }
 
@@ -377,23 +456,86 @@ err:
        return ret;
 }
 
-static int iblock_execute_write_same(struct se_cmd *cmd)
+static sense_reason_t
+iblock_execute_write_same_unmap(struct se_cmd *cmd)
 {
        struct iblock_dev *ib_dev = IBLOCK_DEV(cmd->se_dev);
-       int ret;
-
-       ret = blkdev_issue_discard(ib_dev->ibd_bd, cmd->t_task_lba,
-                                  spc_get_write_same_sectors(cmd), GFP_KERNEL,
-                                  0);
-       if (ret < 0) {
-               pr_debug("blkdev_issue_discard() failed for WRITE_SAME\n");
-               return ret;
+       int rc;
+
+       rc = blkdev_issue_discard(ib_dev->ibd_bd, cmd->t_task_lba,
+                       spc_get_write_same_sectors(cmd), GFP_KERNEL, 0);
+       if (rc < 0) {
+               pr_warn("blkdev_issue_discard() failed: %d\n", rc);
+               return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
        }
 
        target_complete_cmd(cmd, GOOD);
        return 0;
 }
 
+static sense_reason_t
+iblock_execute_write_same(struct se_cmd *cmd)
+{
+       struct iblock_req *ibr;
+       struct scatterlist *sg;
+       struct bio *bio;
+       struct bio_list list;
+       sector_t block_lba = cmd->t_task_lba;
+       sector_t sectors = spc_get_write_same_sectors(cmd);
+
+       sg = &cmd->t_data_sg[0];
+
+       if (cmd->t_data_nents > 1 ||
+           sg->length != cmd->se_dev->dev_attrib.block_size) {
+               pr_err("WRITE_SAME: Illegal SGL t_data_nents: %u length: %u"
+                       " block_size: %u\n", cmd->t_data_nents, sg->length,
+                       cmd->se_dev->dev_attrib.block_size);
+               return TCM_INVALID_CDB_FIELD;
+       }
+
+       ibr = kzalloc(sizeof(struct iblock_req), GFP_KERNEL);
+       if (!ibr)
+               goto fail;
+       cmd->priv = ibr;
+
+       bio = iblock_get_bio(cmd, block_lba, 1);
+       if (!bio)
+               goto fail_free_ibr;
+
+       bio_list_init(&list);
+       bio_list_add(&list, bio);
+
+       atomic_set(&ibr->pending, 1);
+
+       while (sectors) {
+               while (bio_add_page(bio, sg_page(sg), sg->length, sg->offset)
+                               != sg->length) {
+
+                       bio = iblock_get_bio(cmd, block_lba, 1);
+                       if (!bio)
+                               goto fail_put_bios;
+
+                       atomic_inc(&ibr->pending);
+                       bio_list_add(&list, bio);
+               }
+
+               /* Always in 512 byte units for Linux/Block */
+               block_lba += sg->length >> IBLOCK_LBA_SHIFT;
+               sectors -= 1;
+       }
+
+       iblock_submit_bios(&list, WRITE);
+       return 0;
+
+fail_put_bios:
+       while ((bio = bio_list_pop(&list)))
+               bio_put(bio);
+fail_free_ibr:
+       kfree(ibr);
+fail:
+       return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+}
+
 enum {
        Opt_udev_path, Opt_readonly, Opt_force, Opt_err
 };
@@ -498,61 +640,8 @@ static ssize_t iblock_show_configfs_dev_params(struct se_device *dev, char *b)
        return bl;
 }
 
-static void iblock_complete_cmd(struct se_cmd *cmd)
-{
-       struct iblock_req *ibr = cmd->priv;
-       u8 status;
-
-       if (!atomic_dec_and_test(&ibr->pending))
-               return;
-
-       if (atomic_read(&ibr->ib_bio_err_cnt))
-               status = SAM_STAT_CHECK_CONDITION;
-       else
-               status = SAM_STAT_GOOD;
-
-       target_complete_cmd(cmd, status);
-       kfree(ibr);
-}
-
-static struct bio *
-iblock_get_bio(struct se_cmd *cmd, sector_t lba, u32 sg_num)
-{
-       struct iblock_dev *ib_dev = IBLOCK_DEV(cmd->se_dev);
-       struct bio *bio;
-
-       /*
-        * Only allocate as many vector entries as the bio code allows us to,
-        * we'll loop later on until we have handled the whole request.
-        */
-       if (sg_num > BIO_MAX_PAGES)
-               sg_num = BIO_MAX_PAGES;
-
-       bio = bio_alloc_bioset(GFP_NOIO, sg_num, ib_dev->ibd_bio_set);
-       if (!bio) {
-               pr_err("Unable to allocate memory for bio\n");
-               return NULL;
-       }
-
-       bio->bi_bdev = ib_dev->ibd_bd;
-       bio->bi_private = cmd;
-       bio->bi_end_io = &iblock_bio_done;
-       bio->bi_sector = lba;
-       return bio;
-}
-
-static void iblock_submit_bios(struct bio_list *list, int rw)
-{
-       struct blk_plug plug;
-       struct bio *bio;
-
-       blk_start_plug(&plug);
-       while ((bio = bio_list_pop(list)))
-               submit_bio(rw, bio);
-       blk_finish_plug(&plug);
-}
-
-static int iblock_execute_rw(struct se_cmd *cmd)
+static sense_reason_t
+iblock_execute_rw(struct se_cmd *cmd)
 {
        struct scatterlist *sgl = cmd->t_data_sg;
        u32 sgl_nents = cmd->t_data_nents;
@@ -598,8 +687,7 @@ static int iblock_execute_rw(struct se_cmd *cmd)
        else {
                pr_err("Unsupported SCSI -> BLOCK LBA conversion:"
                                " %u\n", dev->dev_attrib.block_size);
-               cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
-               return -ENOSYS;
+               return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
        }
 
        ibr = kzalloc(sizeof(struct iblock_req), GFP_KERNEL);
@@ -659,9 +747,8 @@ fail_put_bios:
                bio_put(bio);
 fail_free_ibr:
        kfree(ibr);
-       cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
 fail:
-       return -ENOMEM;
+       return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
 }
 
 static sector_t iblock_get_blocks(struct se_device *dev)
@@ -673,40 +760,16 @@ static sector_t iblock_get_blocks(struct se_device *dev)
        return iblock_emulate_read_cap_with_block_size(dev, bd, q);
 }
 
-static void iblock_bio_done(struct bio *bio, int err)
-{
-       struct se_cmd *cmd = bio->bi_private;
-       struct iblock_req *ibr = cmd->priv;
-
-       /*
-        * Set -EIO if !BIO_UPTODATE and the passed is still err=0
-        */
-       if (!test_bit(BIO_UPTODATE, &bio->bi_flags) && !err)
-               err = -EIO;
-
-       if (err != 0) {
-               pr_err("test_bit(BIO_UPTODATE) failed for bio: %p,"
-                       " err: %d\n", bio, err);
-               /*
-                * Bump the ib_bio_err_cnt and release bio.
-                */
-               atomic_inc(&ibr->ib_bio_err_cnt);
-               smp_mb__after_atomic_inc();
-       }
-
-       bio_put(bio);
-
-       iblock_complete_cmd(cmd);
-}
-
 static struct sbc_ops iblock_sbc_ops = {
        .execute_rw             = iblock_execute_rw,
        .execute_sync_cache     = iblock_execute_sync_cache,
        .execute_write_same     = iblock_execute_write_same,
+       .execute_write_same_unmap = iblock_execute_write_same_unmap,
        .execute_unmap          = iblock_execute_unmap,
 };
 
-static int iblock_parse_cdb(struct se_cmd *cmd)
+static sense_reason_t
+iblock_parse_cdb(struct se_cmd *cmd)
 {
        return sbc_parse_cdb(cmd, &iblock_sbc_ops);
 }
@@ -725,7 +788,6 @@ static struct se_subsystem_api iblock_template = {
        .parse_cdb              = iblock_parse_cdb,
        .set_configfs_dev_params = iblock_set_configfs_dev_params,
        .show_configfs_dev_params = iblock_show_configfs_dev_params,
-       .get_device_rev         = sbc_get_device_rev,
        .get_device_type        = sbc_get_device_type,
        .get_blocks             = iblock_get_blocks,
 };