// SPDX-License-Identifier: GPL-2.0-or-later
/*******************************************************************************
* Filename: target_core_iblock.c
*
* This file contains the Storage Engine <-> Linux BlockIO transport
* specific functions.
*
* (c) Copyright 2003-2013 Datera, Inc.
*
* Nicholas A. Bellinger <nab@kernel.org>
*
******************************************************************************/
#include <linux/string.h>
#include <linux/parser.h>
#include <linux/timer.h>
#include <linux/fs.h>
#include <linux/blkdev.h>
#include <linux/blk-integrity.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/bio.h>
#include <linux/file.h>
#include <linux/module.h>
#include <linux/scatterlist.h>
#include <linux/pr.h>
#include <scsi/scsi_proto.h>
#include <scsi/scsi_common.h>
#include <asm/unaligned.h>
#include <target/target_core_base.h>
#include <target/target_core_backend.h>
#include "target_core_iblock.h"
#include "target_core_pr.h"
#define IBLOCK_MAX_BIO_PER_TASK 32 /* max # of bios to submit at a time */
#define IBLOCK_BIO_POOL_SIZE 128
static inline struct iblock_dev *IBLOCK_DEV(struct se_device *dev)
{
return container_of(dev, struct iblock_dev, dev);
}
static int iblock_attach_hba(struct se_hba *hba, u32 host_id)
{
pr_debug("CORE_HBA[%d] - TCM iBlock HBA Driver %s on"
" Generic Target Core Stack %s\n", hba->hba_id,
IBLOCK_VERSION, TARGET_CORE_VERSION);
return 0;
}
static void iblock_detach_hba(struct se_hba *hba)
{
}
static struct se_device *iblock_alloc_device(struct se_hba *hba, const char *name)
{
struct iblock_dev *ib_dev = NULL;
ib_dev = kzalloc(sizeof(struct iblock_dev), GFP_KERNEL);
if (!ib_dev) {
pr_err("Unable to allocate struct iblock_dev\n");
return NULL;
}
ib_dev->ibd_plug = kcalloc(nr_cpu_ids, sizeof(*ib_dev->ibd_plug),
GFP_KERNEL);
if (!ib_dev->ibd_plug)
goto free_dev;
pr_debug( "IBLOCK: Allocated ib_dev for %s\n", name);
return &ib_dev->dev;
free_dev:
kfree(ib_dev);
return NULL;
}
static bool iblock_configure_unmap(struct se_device *dev)
{
struct iblock_dev *ib_dev = IBLOCK_DEV(dev);
return target_configure_unmap_from_queue(&dev->dev_attrib,
ib_dev->ibd_bd);
}
static int iblock_configure_device(struct se_device *dev)
{
struct iblock_dev *ib_dev = IBLOCK_DEV(dev);
struct request_queue *q;
struct bdev_handle *bdev_handle;
struct block_device *bd;
struct blk_integrity *bi;
blk_mode_t mode = BLK_OPEN_READ;
unsigned int max_write_zeroes_sectors;
int ret;
if (!(ib_dev->ibd_flags & IBDF_HAS_UDEV_PATH)) {
pr_err("Missing udev_path= parameters for IBLOCK\n");
return -EINVAL;
}
ret = bioset_init(&ib_dev->ibd_bio_set, IBLOCK_BIO_POOL_SIZE, 0, BIOSET_NEED_BVECS);
if (ret) {
pr_err("IBLOCK: Unable to create bioset\n");
goto out;
}
pr_debug( "IBLOCK: Claiming struct block_device: %s\n",
ib_dev->ibd_udev_path);
if (!ib_dev->ibd_readonly)
mode |= BLK_OPEN_WRITE;
else
dev->dev_flags |= DF_READ_ONLY;
bdev_handle = bdev_open_by_path(ib_dev->ibd_udev_path, mode, ib_dev,
NULL);
if (IS_ERR(bdev_handle)) {
ret = PTR_ERR(bdev_handle);
goto out_free_bioset;
}
ib_dev->ibd_bdev_handle = bdev_handle;
ib_dev->ibd_bd = bd = bdev_handle->bdev;
q = bdev_get_queue(bd);
dev->dev_attrib.hw_block_size = bdev_logical_block_size(bd);
dev->dev_attrib.hw_max_sectors = mult_frac(queue_max_hw_sectors(q),
SECTOR_SIZE,
dev->dev_attrib.hw_block_size);