Commit 4e13c5d0 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending

Pull SCSI target updates from Nicholas Bellinger:
 "The highlights this round include:

  - add support for SCSI Referrals (Hannes)
  - add support for T10 DIF into target core (nab + mkp)
  - add support for T10 DIF emulation in FILEIO + RAMDISK backends (Sagi + nab)
  - add support for T10 DIF -> bio_integrity passthrough in IBLOCK backend (nab)
  - prep changes to iser-target for >= v3.15 T10 DIF support (Sagi)
  - add support for qla2xxx N_Port ID Virtualization - NPIV (Saurav + Quinn)
  - allow percpu_ida_alloc() to receive task state bitmask (Kent)
  - fix >= v3.12 iscsi-target session reset hung task regression (nab)
  - fix >= v3.13 percpu_ref se_lun->lun_ref_active race (nab)
  - fix a long-standing network portal creation race (Andy)"

* 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending: (51 commits)
  target: Fix percpu_ref_put race in transport_lun_remove_cmd
  target/iscsi: Fix network portal creation race
  target: Report bad sector in sense data for DIF errors
  iscsi-target: Convert gfp_t parameter to task state bitmask
  iscsi-target: Fix connection reset hang with percpu_ida_alloc
  percpu_ida: Make percpu_ida_alloc + callers accept task state bitmask
  iscsi-target: Pre-allocate more tags to avoid ack starvation
  qla2xxx: Configure NPIV fc_vport via tcm_qla2xxx_npiv_make_lport
  qla2xxx: Enhancements to enable NPIV support for QLOGIC ISPs with TCM/LIO.
  qla2xxx: Fix scsi_host leak on qlt_lport_register callback failure
  IB/isert: pass scatterlist instead of cmd to fast_reg_mr routine
  IB/isert: Move fastreg descriptor creation to a function
  IB/isert: Avoid frwr notation, user fastreg
  IB/isert: seperate connection protection domains and dma MRs
  tcm_loop: Enable DIF/DIX modes in SCSI host LLD
  target/rd: Add DIF protection into rd_execute_rw
  target/rd: Add support for protection SGL setup + release
  target/rd: Refactor rd_build_device_space + rd_release_device_space
  target/file: Add DIF protection support to fd_execute_rw
  target/file: Add DIF protection init/format support
  ...
parents deb2a1d2 5259a06e
......@@ -36,7 +36,8 @@ static unsigned int __blk_mq_get_tag(struct blk_mq_tags *tags, gfp_t gfp)
{
int tag;
tag = percpu_ida_alloc(&tags->free_tags, gfp);
tag = percpu_ida_alloc(&tags->free_tags, (gfp & __GFP_WAIT) ?
TASK_UNINTERRUPTIBLE : TASK_RUNNING);
if (tag < 0)
return BLK_MQ_TAG_FAIL;
return tag + tags->nr_reserved_tags;
......@@ -52,7 +53,8 @@ static unsigned int __blk_mq_get_reserved_tag(struct blk_mq_tags *tags,
return BLK_MQ_TAG_FAIL;
}
tag = percpu_ida_alloc(&tags->reserved_tags, gfp);
tag = percpu_ida_alloc(&tags->reserved_tags, (gfp & __GFP_WAIT) ?
TASK_UNINTERRUPTIBLE : TASK_RUNNING);
if (tag < 0)
return BLK_MQ_TAG_FAIL;
return tag;
......
This diff is collapsed.
......@@ -119,9 +119,9 @@ struct isert_conn {
wait_queue_head_t conn_wait;
wait_queue_head_t conn_wait_comp_err;
struct kref conn_kref;
struct list_head conn_frwr_pool;
int conn_frwr_pool_size;
/* lock to protect frwr_pool */
struct list_head conn_fr_pool;
int conn_fr_pool_size;
/* lock to protect fastreg pool */
spinlock_t conn_lock;
#define ISERT_COMP_BATCH_COUNT 8
int conn_comp_batch;
......@@ -139,13 +139,11 @@ struct isert_cq_desc {
};
struct isert_device {
int use_frwr;
int use_fastreg;
int cqs_used;
int refcount;
int cq_active_qps[ISERT_MAX_CQ];
struct ib_device *ib_device;
struct ib_pd *dev_pd;
struct ib_mr *dev_mr;
struct ib_cq *dev_rx_cq[ISERT_MAX_CQ];
struct ib_cq *dev_tx_cq[ISERT_MAX_CQ];
struct isert_cq_desc *cq_desc;
......
......@@ -1990,6 +1990,8 @@ qla24xx_vport_delete(struct fc_vport *fc_vport)
vha->flags.delete_progress = 1;
qlt_remove_target(ha, vha);
fc_remove_host(vha->host);
scsi_remove_host(vha->host);
......
......@@ -2750,6 +2750,13 @@ struct qlfc_fw {
uint32_t len;
};
struct scsi_qlt_host {
void *target_lport_ptr;
struct mutex tgt_mutex;
struct mutex tgt_host_action_mutex;
struct qla_tgt *qla_tgt;
};
struct qlt_hw_data {
/* Protected by hw lock */
uint32_t enable_class_2:1;
......@@ -2765,15 +2772,11 @@ struct qlt_hw_data {
uint32_t __iomem *atio_q_in;
uint32_t __iomem *atio_q_out;
void *target_lport_ptr;
struct qla_tgt_func_tmpl *tgt_ops;
struct qla_tgt *qla_tgt;
struct qla_tgt_cmd *cmds[DEFAULT_OUTSTANDING_COMMANDS];
uint16_t current_handle;
struct qla_tgt_vp_map *tgt_vp_map;
struct mutex tgt_mutex;
struct mutex tgt_host_action_mutex;
int saved_set;
uint16_t saved_exchange_count;
......@@ -3435,6 +3438,7 @@ typedef struct scsi_qla_host {
#define VP_ERR_FAB_LOGOUT 4
#define VP_ERR_ADAP_NORESOURCES 5
struct qla_hw_data *hw;
struct scsi_qlt_host vha_tgt;
struct req_que *req;
int fw_heartbeat_counter;
int seconds_since_last_heartbeat;
......
This diff is collapsed.
......@@ -932,8 +932,8 @@ void qlt_disable_vha(struct scsi_qla_host *);
*/
extern int qlt_add_target(struct qla_hw_data *, struct scsi_qla_host *);
extern int qlt_remove_target(struct qla_hw_data *, struct scsi_qla_host *);
extern int qlt_lport_register(struct qla_tgt_func_tmpl *, u64,
int (*callback)(struct scsi_qla_host *), void *);
extern int qlt_lport_register(void *, u64, u64, u64,
int (*callback)(struct scsi_qla_host *, void *, u64, u64));
extern void qlt_lport_deregister(struct scsi_qla_host *);
extern void qlt_unreg_sess(struct qla_tgt_sess *);
extern void qlt_fc_port_added(struct scsi_qla_host *, fc_port_t *);
......
This diff is collapsed.
......@@ -70,12 +70,8 @@ struct tcm_qla2xxx_lport {
struct tcm_qla2xxx_fc_loopid *lport_loopid_map;
/* Pointer to struct scsi_qla_host from qla2xxx LLD */
struct scsi_qla_host *qla_vha;
/* Pointer to struct scsi_qla_host for NPIV VP from qla2xxx LLD */
struct scsi_qla_host *qla_npiv_vp;
/* Pointer to struct qla_tgt pointer */
struct qla_tgt lport_qla_tgt;
/* Pointer to struct fc_vport for NPIV vport from libfc */
struct fc_vport *npiv_vport;
/* Pointer to TPG=1 for non NPIV mode */
struct tcm_qla2xxx_tpg *tpg_1;
/* Returned by tcm_qla2xxx_make_lport() */
......
......@@ -3,6 +3,7 @@ menuconfig TARGET_CORE
tristate "Generic Target Core Mod (TCM) and ConfigFS Infrastructure"
depends on SCSI && BLOCK
select CONFIGFS_FS
select CRC_T10DIF
default n
help
Say Y or M here to enable the TCM Storage Engine and ConfigFS enabled
......@@ -13,6 +14,7 @@ if TARGET_CORE
config TCM_IBLOCK
tristate "TCM/IBLOCK Subsystem Plugin for Linux/BLOCK"
select BLK_DEV_INTEGRITY
help
Say Y here to enable the TCM/IBLOCK subsystem plugin for non-buffered
access to Linux/Block devices using BIO
......
......@@ -52,7 +52,7 @@
static LIST_HEAD(g_tiqn_list);
static LIST_HEAD(g_np_list);
static DEFINE_SPINLOCK(tiqn_lock);
static DEFINE_SPINLOCK(np_lock);
static DEFINE_MUTEX(np_lock);
static struct idr tiqn_idr;
struct idr sess_idr;
......@@ -307,6 +307,9 @@ bool iscsit_check_np_match(
return false;
}
/*
* Called with mutex np_lock held
*/
static struct iscsi_np *iscsit_get_np(
struct __kernel_sockaddr_storage *sockaddr,
int network_transport)
......@@ -314,11 +317,10 @@ static struct iscsi_np *iscsit_get_np(
struct iscsi_np *np;
bool match;
spin_lock_bh(&np_lock);
list_for_each_entry(np, &g_np_list, np_list) {
spin_lock(&np->np_thread_lock);
spin_lock_bh(&np->np_thread_lock);
if (np->np_thread_state != ISCSI_NP_THREAD_ACTIVE) {
spin_unlock(&np->np_thread_lock);
spin_unlock_bh(&np->np_thread_lock);
continue;
}
......@@ -330,13 +332,11 @@ static struct iscsi_np *iscsit_get_np(
* while iscsi_tpg_add_network_portal() is called.
*/
np->np_exports++;
spin_unlock(&np->np_thread_lock);
spin_unlock_bh(&np_lock);
spin_unlock_bh(&np->np_thread_lock);
return np;
}
spin_unlock(&np->np_thread_lock);
spin_unlock_bh(&np->np_thread_lock);
}
spin_unlock_bh(&np_lock);
return NULL;
}
......@@ -350,16 +350,22 @@ struct iscsi_np *iscsit_add_np(
struct sockaddr_in6 *sock_in6;
struct iscsi_np *np;
int ret;
mutex_lock(&np_lock);
/*
* Locate the existing struct iscsi_np if already active..
*/
np = iscsit_get_np(sockaddr, network_transport);
if (np)
if (np) {
mutex_unlock(&np_lock);
return np;
}
np = kzalloc(sizeof(struct iscsi_np), GFP_KERNEL);
if (!np) {
pr_err("Unable to allocate memory for struct iscsi_np\n");
mutex_unlock(&np_lock);
return ERR_PTR(-ENOMEM);
}
......@@ -382,6 +388,7 @@ struct iscsi_np *iscsit_add_np(
ret = iscsi_target_setup_login_socket(np, sockaddr);
if (ret != 0) {
kfree(np);
mutex_unlock(&np_lock);
return ERR_PTR(ret);
}
......@@ -390,6 +397,7 @@ struct iscsi_np *iscsit_add_np(
pr_err("Unable to create kthread: iscsi_np\n");
ret = PTR_ERR(np->np_thread);
kfree(np);
mutex_unlock(&np_lock);
return ERR_PTR(ret);
}
/*
......@@ -400,10 +408,10 @@ struct iscsi_np *iscsit_add_np(
* point because iscsi_np has not been added to g_np_list yet.
*/
np->np_exports = 1;
np->np_thread_state = ISCSI_NP_THREAD_ACTIVE;
spin_lock_bh(&np_lock);
list_add_tail(&np->np_list, &g_np_list);
spin_unlock_bh(&np_lock);
mutex_unlock(&np_lock);
pr_debug("CORE[0] - Added Network Portal: %s:%hu on %s\n",
np->np_ip, np->np_port, np->np_transport->name);
......@@ -470,9 +478,9 @@ int iscsit_del_np(struct iscsi_np *np)
np->np_transport->iscsit_free_np(np);
spin_lock_bh(&np_lock);
mutex_lock(&np_lock);
list_del(&np->np_list);
spin_unlock_bh(&np_lock);
mutex_unlock(&np_lock);
pr_debug("CORE[0] - Removed Network Portal: %s:%hu on %s\n",
np->np_ip, np->np_port, np->np_transport->name);
......@@ -622,7 +630,7 @@ static int iscsit_add_reject(
{
struct iscsi_cmd *cmd;
cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
cmd = iscsit_allocate_cmd(conn, TASK_INTERRUPTIBLE);
if (!cmd)
return -1;
......@@ -2475,7 +2483,7 @@ static void iscsit_build_conn_drop_async_message(struct iscsi_conn *conn)
if (!conn_p)
return;
cmd = iscsit_allocate_cmd(conn_p, GFP_ATOMIC);
cmd = iscsit_allocate_cmd(conn_p, TASK_RUNNING);
if (!cmd) {
iscsit_dec_conn_usage_count(conn_p);
return;
......@@ -3951,7 +3959,7 @@ static int iscsi_target_rx_opcode(struct iscsi_conn *conn, unsigned char *buf)
switch (hdr->opcode & ISCSI_OPCODE_MASK) {
case ISCSI_OP_SCSI_CMD:
cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
cmd = iscsit_allocate_cmd(conn, TASK_INTERRUPTIBLE);
if (!cmd)
goto reject;
......@@ -3963,28 +3971,28 @@ static int iscsi_target_rx_opcode(struct iscsi_conn *conn, unsigned char *buf)
case ISCSI_OP_NOOP_OUT:
cmd = NULL;
if (hdr->ttt == cpu_to_be32(0xFFFFFFFF)) {
cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
cmd = iscsit_allocate_cmd(conn, TASK_INTERRUPTIBLE);
if (!cmd)
goto reject;
}
ret = iscsit_handle_nop_out(conn, cmd, buf);
break;
case ISCSI_OP_SCSI_TMFUNC:
cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
cmd = iscsit_allocate_cmd(conn, TASK_INTERRUPTIBLE);
if (!cmd)
goto reject;
ret = iscsit_handle_task_mgt_cmd(conn, cmd, buf);
break;
case ISCSI_OP_TEXT:
cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
cmd = iscsit_allocate_cmd(conn, TASK_INTERRUPTIBLE);
if (!cmd)
goto reject;
ret = iscsit_handle_text_cmd(conn, cmd, buf);
break;
case ISCSI_OP_LOGOUT:
cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
cmd = iscsit_allocate_cmd(conn, TASK_INTERRUPTIBLE);
if (!cmd)
goto reject;
......
......@@ -1192,7 +1192,7 @@ int iscsi_target_locate_portal(
*/
alloc_tags:
tag_num = max_t(u32, ISCSIT_MIN_TAGS, queue_depth);
tag_num += (tag_num / 2) + ISCSIT_EXTRA_TAGS;
tag_num = (tag_num * 2) + ISCSIT_EXTRA_TAGS;
tag_size = sizeof(struct iscsi_cmd) + conn->conn_transport->priv_size;
ret = transport_alloc_session_tags(sess->se_sess, tag_num, tag_size);
......
......@@ -152,13 +152,16 @@ void iscsit_free_r2ts_from_list(struct iscsi_cmd *cmd)
* May be called from software interrupt (timer) context for allocating
* iSCSI NopINs.
*/
struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *conn, gfp_t gfp_mask)
struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *conn, int state)
{
struct iscsi_cmd *cmd;
struct se_session *se_sess = conn->sess->se_sess;
int size, tag;
tag = percpu_ida_alloc(&se_sess->sess_tag_pool, gfp_mask);
tag = percpu_ida_alloc(&se_sess->sess_tag_pool, state);
if (tag < 0)
return NULL;
size = sizeof(struct iscsi_cmd) + conn->conn_transport->priv_size;
cmd = (struct iscsi_cmd *)(se_sess->sess_cmd_map + (tag * size));
memset(cmd, 0, size);
......@@ -926,7 +929,7 @@ static int iscsit_add_nopin(struct iscsi_conn *conn, int want_response)
u8 state;
struct iscsi_cmd *cmd;
cmd = iscsit_allocate_cmd(conn, GFP_ATOMIC);
cmd = iscsit_allocate_cmd(conn, TASK_RUNNING);
if (!cmd)
return -1;
......
......@@ -9,7 +9,7 @@ extern struct iscsi_r2t *iscsit_get_r2t_from_list(struct iscsi_cmd *);
extern void iscsit_free_r2t(struct iscsi_r2t *, struct iscsi_cmd *);
extern void iscsit_free_r2ts_from_list(struct iscsi_cmd *);
extern struct iscsi_cmd *iscsit_alloc_cmd(struct iscsi_conn *, gfp_t);
extern struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *, gfp_t);
extern struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *, int);
extern struct iscsi_seq *iscsit_get_seq_holder_for_datain(struct iscsi_cmd *, u32);
extern struct iscsi_seq *iscsit_get_seq_holder_for_r2t(struct iscsi_cmd *);
extern struct iscsi_r2t *iscsit_get_holder_for_r2tsn(struct iscsi_cmd *, u32);
......
......@@ -217,7 +217,8 @@ static void tcm_loop_submission_work(struct work_struct *work)
scsi_bufflen(sc), tcm_loop_sam_attr(sc),
sc->sc_data_direction, 0,
scsi_sglist(sc), scsi_sg_count(sc),
sgl_bidi, sgl_bidi_count);
sgl_bidi, sgl_bidi_count,
scsi_prot_sglist(sc), scsi_prot_sg_count(sc));
if (rc < 0) {
set_host_byte(sc, DID_NO_CONNECT);
goto out_done;
......@@ -462,7 +463,7 @@ static int tcm_loop_driver_probe(struct device *dev)
{
struct tcm_loop_hba *tl_hba;
struct Scsi_Host *sh;
int error;
int error, host_prot;
tl_hba = to_tcm_loop_hba(dev);
......@@ -486,6 +487,13 @@ static int tcm_loop_driver_probe(struct device *dev)
sh->max_channel = 0;
sh->max_cmd_len = TL_SCSI_MAX_CMD_LEN;
host_prot = SHOST_DIF_TYPE1_PROTECTION | SHOST_DIF_TYPE2_PROTECTION |
SHOST_DIF_TYPE3_PROTECTION | SHOST_DIX_TYPE1_PROTECTION |
SHOST_DIX_TYPE2_PROTECTION | SHOST_DIX_TYPE3_PROTECTION;
scsi_host_set_prot(sh, host_prot);
scsi_host_set_guard(sh, SHOST_DIX_GUARD_CRC);
error = scsi_add_host(sh, &tl_hba->dev);
if (error) {
pr_err("%s: scsi_add_host failed\n", __func__);
......@@ -1228,7 +1236,7 @@ static struct configfs_attribute *tcm_loop_tpg_attrs[] = {
/* Start items for tcm_loop_naa_cit */
struct se_portal_group *tcm_loop_make_naa_tpg(
static struct se_portal_group *tcm_loop_make_naa_tpg(
struct se_wwn *wwn,
struct config_group *group,
const char *name)
......@@ -1273,7 +1281,7 @@ struct se_portal_group *tcm_loop_make_naa_tpg(
return &tl_tpg->tl_se_tpg;
}
void tcm_loop_drop_naa_tpg(
static void tcm_loop_drop_naa_tpg(
struct se_portal_group *se_tpg)
{
struct se_wwn *wwn = se_tpg->se_tpg_wwn;
......@@ -1305,7 +1313,7 @@ void tcm_loop_drop_naa_tpg(
/* Start items for tcm_loop_cit */
struct se_wwn *tcm_loop_make_scsi_hba(
static struct se_wwn *tcm_loop_make_scsi_hba(
struct target_fabric_configfs *tf,
struct config_group *group,
const char *name)
......@@ -1375,7 +1383,7 @@ struct se_wwn *tcm_loop_make_scsi_hba(
return ERR_PTR(ret);
}
void tcm_loop_drop_scsi_hba(
static void tcm_loop_drop_scsi_hba(
struct se_wwn *wwn)
{
struct tcm_loop_hba *tl_hba = container_of(wwn,
......
This diff is collapsed.
......@@ -13,12 +13,13 @@
/*
* ASYMMETRIC ACCESS STATE field
*
* from spc4r17 section 6.27 Table 245
* from spc4r36j section 6.37 Table 307
*/
#define ALUA_ACCESS_STATE_ACTIVE_OPTIMIZED 0x0
#define ALUA_ACCESS_STATE_ACTIVE_NON_OPTIMIZED 0x1
#define ALUA_ACCESS_STATE_STANDBY 0x2
#define ALUA_ACCESS_STATE_UNAVAILABLE 0x3
#define ALUA_ACCESS_STATE_LBA_DEPENDENT 0x4
#define ALUA_ACCESS_STATE_OFFLINE 0xe
#define ALUA_ACCESS_STATE_TRANSITION 0xf
......@@ -78,18 +79,30 @@
*/
#define ALUA_SECONDARY_METADATA_WWN_LEN 256
/* Used by core_alua_update_tpg_(primary,secondary)_metadata */
#define ALUA_MD_BUF_LEN 1024
extern struct kmem_cache *t10_alua_lu_gp_cache;
extern struct kmem_cache *t10_alua_lu_gp_mem_cache;
extern struct kmem_cache *t10_alua_tg_pt_gp_cache;
extern struct kmem_cache *t10_alua_tg_pt_gp_mem_cache;
extern struct kmem_cache *t10_alua_lba_map_cache;
extern struct kmem_cache *t10_alua_lba_map_mem_cache;
extern sense_reason_t target_emulate_report_target_port_groups(struct se_cmd *);
extern sense_reason_t target_emulate_set_target_port_groups(struct se_cmd *);
extern sense_reason_t target_emulate_report_referrals(struct se_cmd *);
extern int core_alua_check_nonop_delay(struct se_cmd *);
extern int core_alua_do_port_transition(struct t10_alua_tg_pt_gp *,
struct se_device *, struct se_port *,
struct se_node_acl *, int, int);
extern char *core_alua_dump_status(int);
extern struct t10_alua_lba_map *core_alua_allocate_lba_map(
struct list_head *, u64, u64);
extern int core_alua_allocate_lba_map_mem(struct t10_alua_lba_map *, int, int);
extern void core_alua_free_lba_map(struct list_head *);
extern void core_alua_set_lba_map(struct se_device *, struct list_head *,
int, int);
extern struct t10_alua_lu_gp *core_alua_allocate_lu_gp(const char *, int);
extern int core_alua_set_lu_gp_id(struct t10_alua_lu_gp *, u16);
extern void core_alua_free_lu_gp(struct t10_alua_lu_gp *);
......
......@@ -643,6 +643,15 @@ SE_DEV_ATTR(emulate_caw, S_IRUGO | S_IWUSR);
DEF_DEV_ATTRIB(emulate_3pc);
SE_DEV_ATTR(emulate_3pc, S_IRUGO | S_IWUSR);
DEF_DEV_ATTRIB(pi_prot_type);
SE_DEV_ATTR(pi_prot_type, S_IRUGO | S_IWUSR);
DEF_DEV_ATTRIB_RO(hw_pi_prot_type);
SE_DEV_ATTR_RO(hw_pi_prot_type);
DEF_DEV_ATTRIB(pi_prot_format);
SE_DEV_ATTR(pi_prot_format, S_IRUGO | S_IWUSR);
DEF_DEV_ATTRIB(enforce_pr_isids);
SE_DEV_ATTR(enforce_pr_isids, S_IRUGO | S_IWUSR);
......@@ -702,6 +711,9 @@ static struct configfs_attribute *target_core_dev_attrib_attrs[] = {
&target_core_dev_attrib_emulate_tpws.attr,
&target_core_dev_attrib_emulate_caw.attr,
&target_core_dev_attrib_emulate_3pc.attr,
&target_core_dev_attrib_pi_prot_type.attr,
&target_core_dev_attrib_hw_pi_prot_type.attr,
&target_core_dev_attrib_pi_prot_format.attr,
&target_core_dev_attrib_enforce_pr_isids.attr,
&target_core_dev_attrib_is_nonrot.attr,
&target_core_dev_attrib_emulate_rest_reord.attr,
......@@ -1741,6 +1753,176 @@ static struct target_core_configfs_attribute target_core_attr_dev_alua_lu_gp = {
.store = target_core_store_alua_lu_gp,
};
static ssize_t target_core_show_dev_lba_map(void *p, char *page)
{
struct se_device *dev = p;
struct t10_alua_lba_map *map;
struct t10_alua_lba_map_member *mem;
char *b = page;
int bl = 0;
char state;
spin_lock(&dev->t10_alua.lba_map_lock);
if (!list_empty(&dev->t10_alua.lba_map_list))
bl += sprintf(b + bl, "%u %u\n",
dev->t10_alua.lba_map_segment_size,
dev->t10_alua.lba_map_segment_multiplier);
list_for_each_entry(map, &dev->t10_alua.lba_map_list, lba_map_list) {
bl += sprintf(b + bl, "%llu %llu",
map->lba_map_first_lba, map->lba_map_last_lba);
list_for_each_entry(mem, &map->lba_map_mem_list,
lba_map_mem_list) {
switch (mem->lba_map_mem_alua_state) {
case ALUA_ACCESS_STATE_ACTIVE_OPTIMIZED:
state = 'O';
break;
case ALUA_ACCESS_STATE_ACTIVE_NON_OPTIMIZED:
state = 'A';
break;
case ALUA_ACCESS_STATE_STANDBY:
state = 'S';
break;
case ALUA_ACCESS_STATE_UNAVAILABLE:
state = 'U';
break;
default:
state = '.';
break;
}
bl += sprintf(b + bl, " %d:%c",
mem->lba_map_mem_alua_pg_id, state);
}
bl += sprintf(b + bl, "\n");
}
spin_unlock(&dev->t10_alua.lba_map_lock);
return bl;
}
static ssize_t target_core_store_dev_lba_map(
void *p,
const char *page,
size_t count)
{
struct se_device *dev = p;
struct t10_alua_lba_map *lba_map = NULL;
struct list_head lba_list;
char *map_entries, *ptr;
char state;
int pg_num = -1, pg;
int ret = 0, num = 0, pg_id, alua_state;
unsigned long start_lba = -1, end_lba = -1;
unsigned long segment_size = -1, segment_mult = -1;
map_entries = kstrdup(page, GFP_KERNEL);
if (!map_entries)
return -ENOMEM;
INIT_LIST_HEAD(&lba_list);
while ((ptr = strsep(&map_entries, "\n")) != NULL) {
if (!*ptr)
continue;
if (num == 0) {
if (sscanf(ptr, "%lu %lu\n",
&segment_size, &segment_mult) != 2) {
pr_err("Invalid line %d\n", num);
ret = -EINVAL;
break;
}
num++;
continue;
}
if (sscanf(ptr, "%lu %lu", &start_lba, &end_lba) != 2) {
pr_err("Invalid line %d\n", num);
ret = -EINVAL;
break;
}
ptr = strchr(ptr, ' ');
if (!ptr) {
pr_err("Invalid line %d, missing end lba\n", num);
ret = -EINVAL;
break;
}
ptr++;
ptr = strchr(ptr, ' ');
if (!ptr) {
pr_err("Invalid line %d, missing state definitions\n",
num);
ret = -EINVAL;
break;
}
ptr++;
lba_map = core_alua_allocate_lba_map(&lba_list,
start_lba, end_lba);
if (IS_ERR(lba_map)) {
ret = PTR_ERR(lba_map);
break;
}
pg = 0;
while (sscanf(ptr, "%d:%c", &pg_id, &state) == 2) {
switch (state) {
case 'O':
alua_state = ALUA_ACCESS_STATE_ACTIVE_OPTIMIZED;
break;
case 'A':
alua_state = ALUA_ACCESS_STATE_ACTIVE_NON_OPTIMIZED;
break;
case 'S':
alua_state = ALUA_ACCESS_STATE_STANDBY;
break;
case 'U':
alua_state = ALUA_ACCESS_STATE_UNAVAILABLE;
break;
default:
pr_err("Invalid ALUA state '%c'\n", state);
ret = -EINVAL;
goto out;
}
ret = core_alua_allocate_lba_map_mem(lba_map,
pg_id, alua_state);
if (ret) {
pr_err("Invalid target descriptor %d:%c "
"at line %d\n",
pg_id, state, num);
break;
}
pg++;
ptr = strchr(ptr, ' ');
if (ptr)
ptr++;
else
break;
}
if (pg_num == -1)
pg_num = pg;
else if (pg != pg_num) {
pr_err("Only %d from %d port groups definitions "
"at line %d\n", pg, pg_num, num);
ret = -EINVAL;
break;
}
num++;
}
out:
if (ret) {
core_alua_free_lba_map(&lba_list);
count = ret;
} else
core_alua_set_lba_map(dev, &lba_list,
segment_size, segment_mult);
kfree(map_entries);
return count;
}
static struct target_core_configfs_attribute target_core_attr_dev_lba_map = {
.attr = { .ca_owner = THIS_MODULE,
.ca_name = "lba_map",
.ca_mode = S_IRUGO | S_IWUSR },
.show = target_core_show_dev_lba_map,
.store = target_core_store_dev_lba_map,
};
static struct configfs_attribute *lio_core_dev_attrs[] = {
&target_core_attr_dev_info.attr,
&target_core_attr_dev_control.attr,
......@@ -1748,6 +1930,7 @@ static struct configfs_attribute *lio_core_dev_attrs[] = {
&target_core_attr_dev_udev_path.attr,
&target_core_attr_dev_enable.attr,
&target_core_attr_dev_alua_lu_gp.attr,
&target_core_attr_dev_lba_map.attr,
NULL,
};
......@@ -2054,6 +2237,13 @@ static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_access_state(
" transition while TPGS_IMPLICIT_ALUA is disabled\n");
return -EINVAL;
}
if (tg_pt_gp->tg_pt_gp_alua_access_type & TPGS_EXPLICIT_ALUA &&
new_state == ALUA_ACCESS_STATE_LBA_DEPENDENT) {
/* LBA DEPENDENT is only allowed with implicit ALUA */
pr_err("Unable to process implicit configfs ALUA transition"
" while explicit ALUA management is enabled\n");
return -EINVAL;
}
ret = core_alua_do_port_transition(tg_pt_gp, dev,
NULL, NULL, new_state, 0);
......@@ -2188,7 +2378,7 @@ SE_DEV_ALUA_SUPPORT_STATE_SHOW(lba_dependent,
tg_pt_gp_alua_supported_states, ALUA_LBD_SUP);
SE_DEV_ALUA_SUPPORT_STATE_STORE(lba_dependent,
tg_pt_gp_alua_supported_states, ALUA_LBD_SUP);
SE_DEV_ALUA_TG_PT_ATTR(alua_support_lba_dependent, S_IRUGO | S_IWUSR);
SE_DEV_ALUA_TG_PT_ATTR(alua_support_lba_dependent, S_IRUGO);
SE_DEV_ALUA_SUPPORT_STATE_SHOW(unavailable,
tg_pt_gp_alua_supported_states, ALUA_U_SUP);
......@@ -2937,7 +3127,7 @@ static int __init target_core_init_configfs(void)
* and ALUA Logical Unit Group and Target Port Group infrastructure.
*/
target_cg = &subsys->su_group;
target_cg->default_groups = kmalloc(sizeof(struct config_group) * 2,
target_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2,
GFP_KERNEL);
if (!target_cg->default_groups) {
pr_err("Unable to allocate target_cg->default_groups\n");
......
......@@ -918,6 +918,90 @@ int se_dev_set_emulate_3pc(struct se_device *dev, int flag)
return 0;
}
int se_dev_set_pi_prot_type(struct se_device *dev, int flag)
{
int rc, old_prot = dev->dev_attrib.pi_prot_type;
if (flag != 0 && flag != 1 && flag != 2 && flag != 3) {
pr_err("Illegal value %d for pi_prot_type\n", flag);
return -EINVAL;
}
if (flag == 2) {
pr_err("DIF TYPE2 protection currently not supported\n");
return -ENOSYS;
}
if (dev->dev_attrib.hw_pi_prot_type) {
pr_warn("DIF protection enabled on underlying hardware,"
" ignoring\n");
return 0;
}
if (!dev->transport->init_prot || !dev->transport->free_prot) {
pr_err("DIF protection not supported by backend: %s\n",
dev->transport->name);
return -ENOSYS;
}
if (!(dev->dev_flags & DF_CONFIGURED)) {
pr_err("DIF protection requires device to be configured\n");
return -ENODEV;
}
if (dev->export_count) {
pr_err("dev[%p]: Unable to change SE Device PROT type while"
" export_count is %d\n", dev, dev->export_count);
return -EINVAL;
}
dev->dev_attrib.pi_prot_type = flag;
if (flag && !old_prot) {
rc = dev->transport->init_prot(dev);
if (rc) {
dev->dev_attrib.pi_prot_type = old_prot;
return rc;
}
} else if (!flag && old_prot) {
dev->transport->free_prot(dev);
}
pr_debug("dev[%p]: SE Device Protection Type: %d\n", dev, flag);
return 0;
}
int se_dev_set_pi_prot_format(struct se_device *dev, int flag)
{
int rc;
if (!flag)
return 0;
if (flag != 1) {
pr_err("Illegal value %d for pi_prot_format\n", flag);
return -EINVAL;
}
if (!dev->transport->format_prot) {
pr_err("DIF protection format not supported by backend %s\n",
dev->transport->name);
return -ENOSYS;
}
if (!(dev->dev_flags & DF_CONFIGURED)) {
pr_err("DIF protection format requires device to be configured\n");
return -ENODEV;
}
if (dev->export_count) {
pr_err("dev[%p]: Unable to format SE Device PROT type while"
" export_count is %d\n", dev, dev->export_count);
return -EINVAL;
}
rc = dev->transport->format_prot(dev);
if (rc)
return rc;
pr_debug("dev[%p]: SE Device Protection Format complete\n", dev);
return 0;
}
int se_dev_set_enforce_pr_isids(struct se_device *dev, int flag)
{
if ((flag != 0) && (flag != 1)) {
......@@ -1117,23 +1201,23 @@ int se_dev_set_block_size(struct se_device *dev, u32 block_size)
struct se_lun *core_dev_add_lun(
struct se_portal_group *tpg,
struct se_device *dev,
u32 lun)
u32 unpacked_lun)
{
struct se_lun *lun_p;
struct se_lun *lun;
int rc;
lun_p = core_tpg_pre_addlun(tpg, lun);
if (IS_ERR(lun_p))
return lun_p;
lun = core_tpg_alloc_lun(tpg, unpacked_lun);
if (IS_ERR(lun))
return lun;
rc = core_tpg_post_addlun(tpg, lun_p,
rc = core_tpg_add_lun(tpg, lun,
TRANSPORT_LUNFLAGS_READ_WRITE, dev);
if (rc < 0)
return ERR_PTR(rc);
pr_debug("%s_TPG[%u]_LUN[%u] - Activated %s Logical Unit from"
" CORE HBA: %u\n", tpg->se_tpg_tfo->get_fabric_name(),
tpg->se_tpg_tfo->tpg_get_tag(tpg), lun_p->unpacked_lun,
tpg->se_tpg_tfo->tpg_get_tag(tpg), lun->unpacked_lun,
tpg->se_tpg_tfo->get_fabric_name(), dev->se_hba->hba_id);
/*
* Update LUN maps for dynamically added initiators when
......@@ -1154,7 +1238,7 @@ struct se_lun *core_dev_add_lun(
spin_unlock_irq(&tpg->acl_node_lock);
}
return lun_p;
return lun;
}
/* core_dev_del_lun():
......@@ -1420,6 +1504,7 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name)
dev->dev_link_magic = SE_DEV_LINK_MAGIC;
dev->se_hba = hba;
dev->transport = hba->transport;
dev->prot_length = sizeof(struct se_dif_v1_tuple);
INIT_LIST_HEAD(&dev->dev_list);
INIT_LIST_HEAD(&dev->dev_sep_list);
......@@ -1444,6 +1529,8 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name)
spin_lock_init(&dev->t10_pr.aptpl_reg_lock);
INIT_LIST_HEAD(&dev->t10_alua.tg_pt_gps_list);
spin_lock_init(&dev->t10_alua.tg_pt_gps_lock);
INIT_LIST_HEAD(&dev->t10_alua.lba_map_list);
spin_lock_init(&dev->t10_alua.lba_map_lock);
dev->t10_wwn.t10_dev = dev;
dev->t10_alua.t10_dev = dev;
......@@ -1460,6 +1547,7 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name)
dev->dev_attrib.emulate_tpws = DA_EMULATE_TPWS;
dev->dev_attrib.emulate_caw = DA_EMULATE_CAW;
dev->dev_attrib.emulate_3pc = DA_EMULATE_3PC;
dev->dev_attrib.pi_prot_type = TARGET_DIF_TYPE0_PROT;
dev->dev_attrib.enforce_pr_isids = DA_ENFORCE_PR_ISIDS;
dev->dev_attrib.is_nonrot = DA_IS_NONROT;
dev->dev_attrib.emulate_rest_reord = DA_EMULATE_REST_REORD;
......@@ -1588,9 +1676,13 @@ void target_free_device(struct se_device *dev)
}
core_alua_free_lu_gp_mem(dev);
core_alua_set_lba_map(dev, NULL, 0, 0);
core_scsi3_free_all_registrations(dev);
se_release_vpd_for_dev(dev);
if (dev->transport->free_prot)
dev->transport->free_prot(dev);
dev->transport->free_device(dev);
}
......
......@@ -906,7 +906,7 @@ static struct config_group *target_fabric_make_lun(
lun_cg->default_groups[1] = NULL;
port_stat_grp = &lun->port_stat_grps.stat_group;
port_stat_grp->default_groups = kzalloc(sizeof(struct config_group) * 3,
port_stat_grp->default_groups = kzalloc(sizeof(struct config_group *) * 4,
GFP_KERNEL);
if (!port_stat_grp->default_groups) {
pr_err("Unable to allocate port_stat_grp->default_groups\n");
......
......@@ -257,6 +257,72 @@ static void fd_free_device(struct se_device *dev)
kfree(fd_dev);
}
static int fd_do_prot_rw(struct se_cmd *cmd, struct fd_prot *fd_prot,
int is_write)
{
struct se_device *se_dev = cmd->se_dev;
struct fd_dev *dev = FD_DEV(se_dev);
struct file *prot_fd = dev->fd_prot_file;
struct scatterlist *sg;
loff_t pos = (cmd->t_task_lba * se_dev->prot_length);
unsigned char *buf;
u32 prot_size, len, size;
int rc, ret = 1, i;
prot_size = (cmd->data_length / se_dev->dev_attrib.block_size) *
se_dev->prot_length;
if (!is_write) {
fd_prot->prot_buf = vzalloc(prot_size);
if (!fd_prot->prot_buf) {
pr_err("Unable to allocate fd_prot->prot_buf\n");
return -ENOMEM;
}
buf = fd_prot->prot_buf;
fd_prot->prot_sg_nents = cmd->t_prot_nents;
fd_prot->prot_sg = kzalloc(sizeof(struct scatterlist) *
fd_prot->prot_sg_nents, GFP_KERNEL);
if (!fd_prot->prot_sg) {
pr_err("Unable to allocate fd_prot->prot_sg\n");
vfree(fd_prot->prot_buf);
return -ENOMEM;
}
size = prot_size;
for_each_sg(fd_prot->prot_sg, sg, fd_prot->prot_sg_nents, i) {
len = min_t(u32, PAGE_SIZE, size);
sg_set_buf(sg, buf, len);
size -= len;
buf += len;
}
}
if (is_write) {
rc = kernel_write(prot_fd, fd_prot->prot_buf, prot_size, pos);
if (rc < 0 || prot_size != rc) {
pr_err("kernel_write() for fd_do_prot_rw failed:"
" %d\n", rc);
ret = -EINVAL;
}
} else {
rc = kernel_read(prot_fd, pos, fd_prot->prot_buf, prot_size);
if (rc < 0) {
pr_err("kernel_read() for fd_do_prot_rw failed:"
" %d\n", rc);
ret = -EINVAL;
}
}
if (is_write || ret < 0) {
kfree(fd_prot->prot_sg);
vfree(fd_prot->prot_buf);
}
return ret;
}
static int fd_do_rw(struct se_cmd *cmd, struct scatterlist *sgl,
u32 sgl_nents, int is_write)
{
......@@ -551,6 +617,8 @@ fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
enum dma_data_direction data_direction)
{
struct se_device *dev = cmd->se_dev;
struct fd_prot fd_prot;
sense_reason_t rc;
int ret = 0;
/*
......@@ -558,8 +626,48 @@ fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
* physical memory addresses to struct iovec virtual memory.
*/
if (data_direction == DMA_FROM_DEVICE) {
memset(&fd_prot, 0, sizeof(struct fd_prot));
if (cmd->prot_type) {
ret = fd_do_prot_rw(cmd, &fd_prot, false);
if (ret < 0)
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
}
ret = fd_do_rw(cmd, sgl, sgl_nents, 0);
if (ret > 0 && cmd->prot_type) {
u32 sectors = cmd->data_length / dev->dev_attrib.block_size;
rc = sbc_dif_verify_read(cmd, cmd->t_task_lba, sectors,
0, fd_prot.prot_sg, 0);
if (rc) {
kfree(fd_prot.prot_sg);
vfree(fd_prot.prot_buf);
return rc;
}
kfree(fd_prot.prot_sg);
vfree(fd_prot.prot_buf);
}
} else {
memset(&fd_prot, 0, sizeof(struct fd_prot));
if (cmd->prot_type) {
u32 sectors = cmd->data_length / dev->dev_attrib.block_size;
ret = fd_do_prot_rw(cmd, &fd_prot, false);
if (ret < 0)
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
rc = sbc_dif_verify_write(cmd, cmd->t_task_lba, sectors,
0, fd_prot.prot_sg, 0);
if (rc) {
kfree(fd_prot.prot_sg);
vfree(fd_prot.prot_buf);
return rc;
}
}
ret = fd_do_rw(cmd, sgl, sgl_nents, 1);
/*
* Perform implicit vfs_fsync_range() for fd_do_writev() ops
......@@ -576,10 +684,19 @@ fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
vfs_fsync_range(fd_dev->fd_file, start, end, 1);
}
}
if (ret > 0 && cmd->prot_type) {
ret = fd_do_prot_rw(cmd, &fd_prot, true);
if (ret < 0)
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
}
}
if (ret < 0) {
kfree(fd_prot.prot_sg);
vfree(fd_prot.prot_buf);
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
}
if (ret)
target_complete_cmd(cmd, SAM_STAT_GOOD);
......@@ -700,6 +817,140 @@ static sector_t fd_get_blocks(struct se_device *dev)
dev->dev_attrib.block_size);
}
static int fd_init_prot(struct se_device *dev)
{
struct fd_dev *fd_dev = FD_DEV(dev);
struct file *prot_file, *file = fd_dev->fd_file;
struct inode *inode;
int ret, flags = O_RDWR | O_CREAT | O_LARGEFILE | O_DSYNC;
char buf[FD_MAX_DEV_PROT_NAME];
if (!file) {
pr_err("Unable to locate fd_dev->fd_file\n");
return -ENODEV;
}
inode = file->f_mapping->host;
if (S_ISBLK(inode->i_mode)) {
pr_err("FILEIO Protection emulation only supported on"
" !S_ISBLK\n");
return -ENOSYS;
}
if (fd_dev->fbd_flags & FDBD_HAS_BUFFERED_IO_WCE)
flags &= ~O_DSYNC;
snprintf(buf, FD_MAX_DEV_PROT_NAME, "%s.protection",
fd_dev->fd_dev_name);
prot_file = filp_open(buf, flags, 0600);
if (IS_ERR(prot_file)) {
pr_err("filp_open(%s) failed\n", buf);
ret = PTR_ERR(prot_file);
return ret;
}
fd_dev->fd_prot_file = prot_file;
return 0;
}
static void fd_init_format_buf(struct se_device *dev, unsigned char *buf,
u32 unit_size, u32 *ref_tag, u16 app_tag,
bool inc_reftag)
{
unsigned char *p = buf;
int i;
for (i = 0; i < unit_size; i += dev->prot_length) {
*((u16 *)&p[0]) = 0xffff;
*((__be16 *)&p[2]) = cpu_to_be16(app_tag);
*((__be32 *)&p[4]) = cpu_to_be32(*ref_tag);
if (inc_reftag)
(*ref_tag)++;
p += dev->prot_length;
}
}
static int fd_format_prot(struct se_device *dev)
{
struct fd_dev *fd_dev = FD_DEV(dev);
struct file *prot_fd = fd_dev->fd_prot_file;
sector_t prot_length, prot;
unsigned char *buf;
loff_t pos = 0;
u32 ref_tag = 0;
int unit_size = FDBD_FORMAT_UNIT_SIZE * dev->dev_attrib.block_size;
int rc, ret = 0, size, len;
bool inc_reftag = false;
if (!dev->dev_attrib.pi_prot_type) {
pr_err("Unable to format_prot while pi_prot_type == 0\n");
return -ENODEV;
}
if (!prot_fd) {
pr_err("Unable to locate fd_dev->fd_prot_file\n");
return -ENODEV;
}
switch (dev->dev_attrib.pi_prot_type) {
case TARGET_DIF_TYPE3_PROT:
ref_tag = 0xffffffff;
break;
case TARGET_DIF_TYPE2_PROT:
case TARGET_DIF_TYPE1_PROT:
inc_reftag = true;
break;
default:
break;
}
buf = vzalloc(unit_size);
if (!buf) {
pr_err("Unable to allocate FILEIO prot buf\n");
return -ENOMEM;
}
prot_length = (dev->transport->get_blocks(dev) + 1) * dev->prot_length;
size = prot_length;
pr_debug("Using FILEIO prot_length: %llu\n",
(unsigned long long)prot_length);
for (prot = 0; prot < prot_length; prot += unit_size) {
fd_init_format_buf(dev, buf, unit_size, &ref_tag, 0xffff,
inc_reftag);
len = min(unit_size, size);
rc = kernel_write(prot_fd, buf, len, pos);
if (rc != len) {
pr_err("vfs_write to prot file failed: %d\n", rc);
ret = -ENODEV;
goto out;
}
pos += len;
size -= len;
}
out:
vfree(buf);
return ret;
}
static void fd_free_prot(struct se_device *dev)
{
struct fd_dev *fd_dev = FD_DEV(dev);
if (!fd_dev->fd_prot_file)
return;
filp_close(fd_dev->fd_prot_file, NULL);
fd_dev->fd_prot_file = NULL;
}
static struct sbc_ops fd_sbc_ops = {
.execute_rw = fd_execute_rw,
.execute_sync_cache = fd_execute_sync_cache,
......@@ -730,6 +981,9 @@ static struct se_subsystem_api fileio_template = {
.show_configfs_dev_params = fd_show_configfs_dev_params,
.get_device_type = sbc_get_device_type,
.get_blocks = fd_get_blocks,
.init_prot = fd_init_prot,
.format_prot = fd_format_prot,
.free_prot = fd_free_prot,
};
static int __init fileio_module_init(void)
......
......@@ -4,6 +4,7 @@
#define FD_VERSION "4.0"
#define FD_MAX_DEV_NAME 256
#define FD_MAX_DEV_PROT_NAME FD_MAX_DEV_NAME + 16
#define FD_DEVICE_QUEUE_DEPTH 32
#define FD_MAX_DEVICE_QUEUE_DEPTH 128
#define FD_BLOCKSIZE 512
......@@ -18,6 +19,13 @@
#define FBDF_HAS_PATH 0x01
#define FBDF_HAS_SIZE 0x02
#define FDBD_HAS_BUFFERED_IO_WCE 0x04
#define FDBD_FORMAT_UNIT_SIZE 2048
struct fd_prot {
unsigned char *prot_buf;
struct scatterlist *prot_sg;
u32 prot_sg_nents;
};
struct fd_dev {
struct se_device dev;
......@@ -32,6 +40,7 @@ struct fd_dev {
u32 fd_block_size;
unsigned long long fd_dev_size;
struct file *fd_file;
struct file *fd_prot_file;
/* FILEIO HBA device is connected to */
struct fd_host *fd_host;
} ____cacheline_aligned;
......
......@@ -91,6 +91,7 @@ static int iblock_configure_device(struct se_device *dev)
struct iblock_dev *ib_dev = IBLOCK_DEV(dev);
struct request_queue *q;
struct block_device *bd = NULL;
struct blk_integrity *bi;
fmode_t mode;
int ret = -ENOMEM;
......@@ -155,8 +156,40 @@ static int iblock_configure_device(struct se_device *dev)
if (blk_queue_nonrot(q))
dev->dev_attrib.is_nonrot = 1;
bi = bdev_get_integrity(bd);
if (bi) {
struct bio_set *bs = ib_dev->ibd_bio_set;
if (!strcmp(bi->name, "T10-DIF-TYPE3-IP") ||
!strcmp(bi->name, "T10-DIF-TYPE1-IP")) {
pr_err("IBLOCK export of blk_integrity: %s not"
" supported\n", bi->name);
ret = -ENOSYS;
goto out_blkdev_put;
}
if (!strcmp(bi->name, "T10-DIF-TYPE3-CRC")) {
dev->dev_attrib.pi_prot_type = TARGET_DIF_TYPE3_PROT;
} else if (!strcmp(bi->name, "T10-DIF-TYPE1-CRC")) {
dev->dev_attrib.pi_prot_type = TARGET_DIF_TYPE1_PROT;
}
if (dev->dev_attrib.pi_prot_type) {
if (bioset_integrity_create(bs, IBLOCK_BIO_POOL_SIZE) < 0) {
pr_err("Unable to allocate bioset for PI\n");
ret = -ENOMEM;
goto out_blkdev_put;
}
pr_debug("IBLOCK setup BIP bs->bio_integrity_pool: %p\n",
bs->bio_integrity_pool);
}
dev->dev_attrib.hw_pi_prot_type = dev->dev_attrib.pi_prot_type;
}
return 0;
out_blkdev_put:
blkdev_put(ib_dev->ibd_bd, FMODE_WRITE|FMODE_READ|FMODE_EXCL);
out_free_bioset:
bioset_free(ib_dev->ibd_bio_set);
ib_dev->ibd_bio_set = NULL;
......@@ -170,8 +203,10 @@ static void iblock_free_device(struct se_device *dev)
if (ib_dev->ibd_bd != NULL)
blkdev_put(ib_dev->ibd_bd, FMODE_WRITE|FMODE_READ|FMODE_EXCL);
if (ib_dev->ibd_bio_set != NULL)
if (ib_dev->ibd_bio_set != NULL) {
bioset_integrity_free(ib_dev->ibd_bio_set);
bioset_free(ib_dev->ibd_bio_set);
}
kfree(ib_dev);
}
......@@ -586,13 +621,58 @@ static ssize_t iblock_show_configfs_dev_params(struct se_device *dev, char *b)
return bl;
}
static int
iblock_alloc_bip(struct se_cmd *cmd, struct bio *bio)
{
struct se_device *dev = cmd->se_dev;
struct blk_integrity *bi;
struct bio_integrity_payload *bip;
struct iblock_dev *ib_dev = IBLOCK_DEV(dev);
struct scatterlist *sg;
int i, rc;
bi = bdev_get_integrity(ib_dev->ibd_bd);
if (!bi) {
pr_err("Unable to locate bio_integrity\n");
return -ENODEV;
}
bip = bio_integrity_alloc(bio, GFP_NOIO, cmd->t_prot_nents);
if (!bip) {
pr_err("Unable to allocate bio_integrity_payload\n");
return -ENOMEM;
}
bip->bip_iter.bi_size = (cmd->data_length / dev->dev_attrib.block_size) *
dev->prot_length;
bip->bip_iter.bi_sector = bio->bi_iter.bi_sector;
pr_debug("IBLOCK BIP Size: %u Sector: %llu\n", bip->bip_iter.bi_size,
(unsigned long long)bip->bip_iter.bi_sector);
for_each_sg(cmd->t_prot_sg, sg, cmd->t_prot_nents, i) {
rc = bio_integrity_add_page(bio, sg_page(sg), sg->length,
sg->offset);
if (rc != sg->length) {
pr_err("bio_integrity_add_page() failed; %d\n", rc);
return -ENOMEM;
}
pr_debug("Added bio integrity page: %p length: %d offset; %d\n",
sg_page(sg), sg->length, sg->offset);
}
return 0;
}
static sense_reason_t
iblock_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
enum dma_data_direction data_direction)
{
struct se_device *dev = cmd->se_dev;
struct iblock_req *ibr;
struct bio *bio;
struct bio *bio, *bio_start;
struct bio_list list;
struct scatterlist *sg;
u32 sg_num = sgl_nents;
......@@ -655,6 +735,7 @@ iblock_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
if (!bio)
goto fail_free_ibr;
bio_start = bio;
bio_list_init(&list);
bio_list_add(&list, bio);
......@@ -688,6 +769,12 @@ iblock_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
sg_num--;
}
if (cmd->prot_type) {
int rc = iblock_alloc_bip(cmd, bio_start);
if (rc)
goto fail_put_bios;
}
iblock_submit_bios(&list, rw);
iblock_complete_cmd(cmd);
return 0;
......@@ -763,7 +850,7 @@ iblock_parse_cdb(struct se_cmd *cmd)
return sbc_parse_cdb(cmd, &iblock_sbc_ops);
}
bool iblock_get_write_cache(struct se_device *dev)
static bool iblock_get_write_cache(struct se_device *dev)
{
struct iblock_dev *ib_dev = IBLOCK_DEV(dev);
struct block_device *bd = ib_dev->ibd_bd;
......
......@@ -35,6 +35,8 @@ int se_dev_set_emulate_tpu(struct se_device *, int);
int se_dev_set_emulate_tpws(struct se_device *, int);
int se_dev_set_emulate_caw(struct se_device *, int);
int se_dev_set_emulate_3pc(struct se_device *, int);
int se_dev_set_pi_prot_type(struct se_device *, int);
int se_dev_set_pi_prot_format(struct se_device *, int);
int se_dev_set_enforce_pr_isids(struct se_device *, int);
int se_dev_set_is_nonrot(struct se_device *, int);
int se_dev_set_emulate_rest_reord(struct se_device *dev, int);
......@@ -77,9 +79,9 @@ struct se_node_acl *__core_tpg_get_initiator_node_acl(struct se_portal_group *tp
const char *);
void core_tpg_add_node_to_devs(struct se_node_acl *, struct se_portal_group *);
void core_tpg_wait_for_nacl_pr_ref(struct se_node_acl *);
struct se_lun *core_tpg_pre_addlun(struct se_portal_group *, u32);
int core_tpg_post_addlun(struct se_portal_group *, struct se_lun *,
u32, void *);
struct se_lun *core_tpg_alloc_lun(struct se_portal_group *, u32);
int core_tpg_add_lun(struct se_portal_group *, struct se_lun *,
u32, struct se_device *);
struct se_lun *core_tpg_pre_dellun(struct se_portal_group *, u32 unpacked_lun);
int core_tpg_post_dellun(struct se_portal_group *, struct se_lun *);
......
......@@ -43,6 +43,11 @@
#define PR_APTPL_MAX_IPORT_LEN 256
#define PR_APTPL_MAX_TPORT_LEN 256
/*
* Function defined in target_core_spc.c
*/
void spc_parse_naa_6h_vendor_specific(struct se_device *, unsigned char *);
extern struct kmem_cache *t10_pr_reg_cache;
extern void core_pr_dump_initiator_port(struct t10_pr_registration *,
......
......@@ -78,23 +78,14 @@ static void rd_detach_hba(struct se_hba *hba)
hba->hba_ptr = NULL;
}
/* rd_release_device_space():
*
*
*/
static void rd_release_device_space(struct rd_dev *rd_dev)
static u32 rd_release_sgl_table(struct rd_dev *rd_dev, struct rd_dev_sg_table *sg_table,
u32 sg_table_count)
{
u32 i, j, page_count = 0, sg_per_table;
struct rd_dev_sg_table *sg_table;
struct page *pg;
struct scatterlist *sg;
u32 i, j, page_count = 0, sg_per_table;
if (!rd_dev->sg_table_array || !rd_dev->sg_table_count)
return;
sg_table = rd_dev->sg_table_array;
for (i = 0; i < rd_dev->sg_table_count; i++) {
for (i = 0; i < sg_table_count; i++) {
sg = sg_table[i].sg_table;
sg_per_table = sg_table[i].rd_sg_count;
......@@ -105,16 +96,28 @@ static void rd_release_device_space(struct rd_dev *rd_dev)
page_count++;
}
}
kfree(sg);
}
kfree(sg_table);
return page_count;
}
static void rd_release_device_space(struct rd_dev *rd_dev)
{
u32 page_count;
if (!rd_dev->sg_table_array || !rd_dev->sg_table_count)
return;
page_count = rd_release_sgl_table(rd_dev, rd_dev->sg_table_array,
rd_dev->sg_table_count);
pr_debug("CORE_RD[%u] - Released device space for Ramdisk"
" Device ID: %u, pages %u in %u tables total bytes %lu\n",
rd_dev->rd_host->rd_host_id, rd_dev->rd_dev_id, page_count,
rd_dev->sg_table_count, (unsigned long)page_count * PAGE_SIZE);
kfree(sg_table);
rd_dev->sg_table_array = NULL;
rd_dev->sg_table_count = 0;
}
......@@ -124,38 +127,15 @@ static void rd_release_device_space(struct rd_dev *rd_dev)
*
*
*/
static int rd_build_device_space(struct rd_dev *rd_dev)
static int rd_allocate_sgl_table(struct rd_dev *rd_dev, struct rd_dev_sg_table *sg_table,
u32 total_sg_needed, unsigned char init_payload)
{
u32 i = 0, j, page_offset = 0, sg_per_table, sg_tables, total_sg_needed;
u32 i = 0, j, page_offset = 0, sg_per_table;
u32 max_sg_per_table = (RD_MAX_ALLOCATION_SIZE /
sizeof(struct scatterlist));
struct rd_dev_sg_table *sg_table;
struct page *pg;
struct scatterlist *sg;
if (rd_dev->rd_page_count <= 0) {
pr_err("Illegal page count: %u for Ramdisk device\n",
rd_dev->rd_page_count);
return -EINVAL;
}
/* Don't need backing pages for NULLIO */
if (rd_dev->rd_flags & RDF_NULLIO)
return 0;
total_sg_needed = rd_dev->rd_page_count;
sg_tables = (total_sg_needed / max_sg_per_table) + 1;
sg_table = kzalloc(sg_tables * sizeof(struct rd_dev_sg_table), GFP_KERNEL);
if (!sg_table) {
pr_err("Unable to allocate memory for Ramdisk"
" scatterlist tables\n");
return -ENOMEM;
}
rd_dev->sg_table_array = sg_table;
rd_dev->sg_table_count = sg_tables;
unsigned char *p;
while (total_sg_needed) {
sg_per_table = (total_sg_needed > max_sg_per_table) ?
......@@ -186,12 +166,55 @@ static int rd_build_device_space(struct rd_dev *rd_dev)
}
sg_assign_page(&sg[j], pg);
sg[j].length = PAGE_SIZE;
p = kmap(pg);
memset(p, init_payload, PAGE_SIZE);
kunmap(pg);
}
page_offset += sg_per_table;
total_sg_needed -= sg_per_table;
}
return 0;
}
static int rd_build_device_space(struct rd_dev *rd_dev)
{
struct rd_dev_sg_table *sg_table;
u32 sg_tables, total_sg_needed;
u32 max_sg_per_table = (RD_MAX_ALLOCATION_SIZE /
sizeof(struct scatterlist));
int rc;
if (rd_dev->rd_page_count <= 0) {
pr_err("Illegal page count: %u for Ramdisk device\n",
rd_dev->rd_page_count);
return -EINVAL;
}
/* Don't need backing pages for NULLIO */
if (rd_dev->rd_flags & RDF_NULLIO)
return 0;
total_sg_needed = rd_dev->rd_page_count;
sg_tables = (total_sg_needed / max_sg_per_table) + 1;
sg_table = kzalloc(sg_tables * sizeof(struct rd_dev_sg_table), GFP_KERNEL);
if (!sg_table) {
pr_err("Unable to allocate memory for Ramdisk"
" scatterlist tables\n");
return -ENOMEM;
}
rd_dev->sg_table_array = sg_table;
rd_dev->sg_table_count = sg_tables;
rc = rd_allocate_sgl_table(rd_dev, sg_table, total_sg_needed, 0x00);
if (rc)
return rc;
pr_debug("CORE_RD[%u] - Built Ramdisk Device ID: %u space of"
" %u pages in %u tables\n", rd_dev->rd_host->rd_host_id,
rd_dev->rd_dev_id, rd_dev->rd_page_count,
......@@ -200,6 +223,61 @@ static int rd_build_device_space(struct rd_dev *rd_dev)
return 0;
}
static void rd_release_prot_space(struct rd_dev *rd_dev)
{
u32 page_count;
if (!rd_dev->sg_prot_array || !rd_dev->sg_prot_count)
return;
page_count = rd_release_sgl_table(rd_dev, rd_dev->sg_prot_array,
rd_dev->sg_prot_count);
pr_debug("CORE_RD[%u] - Released protection space for Ramdisk"
" Device ID: %u, pages %u in %u tables total bytes %lu\n",
rd_dev->rd_host->rd_host_id, rd_dev->rd_dev_id, page_count,
rd_dev->sg_table_count, (unsigned long)page_count * PAGE_SIZE);
rd_dev->sg_prot_array = NULL;
rd_dev->sg_prot_count = 0;
}
static int rd_build_prot_space(struct rd_dev *rd_dev, int prot_length)
{
struct rd_dev_sg_table *sg_table;
u32 total_sg_needed, sg_tables;
u32 max_sg_per_table = (RD_MAX_ALLOCATION_SIZE /
sizeof(struct scatterlist));
int rc;
if (rd_dev->rd_flags & RDF_NULLIO)
return 0;
total_sg_needed = rd_dev->rd_page_count / prot_length;
sg_tables = (total_sg_needed / max_sg_per_table) + 1;
sg_table = kzalloc(sg_tables * sizeof(struct rd_dev_sg_table), GFP_KERNEL);
if (!sg_table) {
pr_err("Unable to allocate memory for Ramdisk protection"
" scatterlist tables\n");
return -ENOMEM;
}
rd_dev->sg_prot_array = sg_table;
rd_dev->sg_prot_count = sg_tables;
rc = rd_allocate_sgl_table(rd_dev, sg_table, total_sg_needed, 0xff);
if (rc)
return rc;
pr_debug("CORE_RD[%u] - Built Ramdisk Device ID: %u prot space of"
" %u pages in %u tables\n", rd_dev->rd_host->rd_host_id,
rd_dev->rd_dev_id, total_sg_needed, rd_dev->sg_prot_count);
return 0;
}
static struct se_device *rd_alloc_device(struct se_hba *hba, const char *name)
{
struct rd_dev *rd_dev;
......@@ -278,6 +356,26 @@ static struct rd_dev_sg_table *rd_get_sg_table(struct rd_dev *rd_dev, u32 page)
return NULL;
}
static struct rd_dev_sg_table *rd_get_prot_table(struct rd_dev *rd_dev, u32 page)
{
struct rd_dev_sg_table *sg_table;
u32 i, sg_per_table = (RD_MAX_ALLOCATION_SIZE /
sizeof(struct scatterlist));
i = page / sg_per_table;
if (i < rd_dev->sg_prot_count) {
sg_table = &rd_dev->sg_prot_array[i];
if ((sg_table->page_start_offset <= page) &&
(sg_table->page_end_offset >= page))
return sg_table;
}
pr_err("Unable to locate struct prot rd_dev_sg_table for page: %u\n",
page);
return NULL;
}
static sense_reason_t
rd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
enum dma_data_direction data_direction)
......@@ -292,6 +390,7 @@ rd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
u32 rd_page;
u32 src_len;
u64 tmp;
sense_reason_t rc;
if (dev->rd_flags & RDF_NULLIO) {
target_complete_cmd(cmd, SAM_STAT_GOOD);
......@@ -314,6 +413,28 @@ rd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
data_direction == DMA_FROM_DEVICE ? "Read" : "Write",
cmd->t_task_lba, rd_size, rd_page, rd_offset);
if (cmd->prot_type && data_direction == DMA_TO_DEVICE) {
struct rd_dev_sg_table *prot_table;
struct scatterlist *prot_sg;
u32 sectors = cmd->data_length / se_dev->dev_attrib.block_size;
u32 prot_offset, prot_page;
tmp = cmd->t_task_lba * se_dev->prot_length;
prot_offset = do_div(tmp, PAGE_SIZE);
prot_page = tmp;
prot_table = rd_get_prot_table(dev, prot_page);
if (!prot_table)
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
prot_sg = &prot_table->sg_table[prot_page - prot_table->page_start_offset];
rc = sbc_dif_verify_write(cmd, cmd->t_task_lba, sectors, 0,
prot_sg, prot_offset);
if (rc)
return rc;
}
src_len = PAGE_SIZE - rd_offset;
sg_miter_start(&m, sgl, sgl_nents,
data_direction == DMA_FROM_DEVICE ?
......@@ -375,6 +496,28 @@ rd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
}
sg_miter_stop(&m);
if (cmd->prot_type && data_direction == DMA_FROM_DEVICE) {
struct rd_dev_sg_table *prot_table;
struct scatterlist *prot_sg;
u32 sectors = cmd->data_length / se_dev->dev_attrib.block_size;
u32 prot_offset, prot_page;
tmp = cmd->t_task_lba * se_dev->prot_length;
prot_offset = do_div(tmp, PAGE_SIZE);
prot_page = tmp;
prot_table = rd_get_prot_table(dev, prot_page);
if (!prot_table)
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
prot_sg = &prot_table->sg_table[prot_page - prot_table->page_start_offset];
rc = sbc_dif_verify_read(cmd, cmd->t_task_lba, sectors, 0,
prot_sg, prot_offset);
if (rc)
return rc;
}
target_complete_cmd(cmd, SAM_STAT_GOOD);
return 0;
}
......@@ -456,6 +599,23 @@ static sector_t rd_get_blocks(struct se_device *dev)
return blocks_long;
}
static int rd_init_prot(struct se_device *dev)
{
struct rd_dev *rd_dev = RD_DEV(dev);
if (!dev->dev_attrib.pi_prot_type)
return 0;
return rd_build_prot_space(rd_dev, dev->prot_length);
}
static void rd_free_prot(struct se_device *dev)
{
struct rd_dev *rd_dev = RD_DEV(dev);
rd_release_prot_space(rd_dev);
}
static struct sbc_ops rd_sbc_ops = {
.execute_rw = rd_execute_rw,
};
......@@ -481,6 +641,8 @@ static struct se_subsystem_api rd_mcp_template = {
.show_configfs_dev_params = rd_show_configfs_dev_params,
.get_device_type = sbc_get_device_type,
.get_blocks = rd_get_blocks,
.init_prot = rd_init_prot,
.free_prot = rd_free_prot,
};
int __init rd_module_init(void)
......
......@@ -33,8 +33,12 @@ struct rd_dev {
u32 rd_page_count;
/* Number of SG tables in sg_table_array */
u32 sg_table_count;
/* Number of SG tables in sg_prot_array */
u32 sg_prot_count;
/* Array of rd_dev_sg_table_t containing scatterlists */
struct rd_dev_sg_table *sg_table_array;
/* Array of rd_dev_sg_table containing protection scatterlists */
struct rd_dev_sg_table *sg_prot_array;
/* Ramdisk HBA device is connected to */
struct rd_host *rd_host;
} ____cacheline_aligned;
......
......@@ -23,6 +23,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/ratelimit.h>
#include <linux/crc-t10dif.h>
#include <asm/unaligned.h>
#include <scsi/scsi.h>
#include <scsi/scsi_tcq.h>
......@@ -33,7 +34,7 @@
#include "target_core_internal.h"
#include "target_core_ua.h"
#include "target_core_alua.h"
static sense_reason_t
sbc_emulate_readcapacity(struct se_cmd *cmd)
......@@ -105,6 +106,11 @@ sbc_emulate_readcapacity_16(struct se_cmd *cmd)
buf[9] = (dev->dev_attrib.block_size >> 16) & 0xff;
buf[10] = (dev->dev_attrib.block_size >> 8) & 0xff;
buf[11] = dev->dev_attrib.block_size & 0xff;
/*
* Set P_TYPE and PROT_EN bits for DIF support
*/
if (dev->dev_attrib.pi_prot_type)
buf[12] = (dev->dev_attrib.pi_prot_type - 1) << 1 | 0x1;
if (dev->transport->get_lbppbe)
buf[13] = dev->transport->get_lbppbe(dev) & 0x0f;
......@@ -563,6 +569,44 @@ sbc_compare_and_write(struct se_cmd *cmd)
return TCM_NO_SENSE;
}
static bool
sbc_check_prot(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb,
u32 sectors)
{
if (!cmd->t_prot_sg || !cmd->t_prot_nents)
return true;
switch (dev->dev_attrib.pi_prot_type) {
case TARGET_DIF_TYPE3_PROT:
if (!(cdb[1] & 0xe0))
return true;
cmd->reftag_seed = 0xffffffff;
break;
case TARGET_DIF_TYPE2_PROT:
if (cdb[1] & 0xe0)
return false;
cmd->reftag_seed = cmd->t_task_lba;
break;
case TARGET_DIF_TYPE1_PROT:
if (!(cdb[1] & 0xe0))
return true;
cmd->reftag_seed = cmd->t_task_lba;
break;
case TARGET_DIF_TYPE0_PROT:
default:
return true;
}
cmd->prot_type = dev->dev_attrib.pi_prot_type;
cmd->prot_length = dev->prot_length * sectors;
cmd->prot_handover = PROT_SEPERATED;
return true;
}
sense_reason_t
sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
{
......@@ -583,6 +627,10 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
case READ_10:
sectors = transport_get_sectors_10(cdb);
cmd->t_task_lba = transport_lba_32(cdb);
if (!sbc_check_prot(dev, cmd, cdb, sectors))
return TCM_UNSUPPORTED_SCSI_OPCODE;
cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
cmd->execute_rw = ops->execute_rw;
cmd->execute_cmd = sbc_execute_rw;
......@@ -590,6 +638,10 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
case READ_12:
sectors = transport_get_sectors_12(cdb);
cmd->t_task_lba = transport_lba_32(cdb);
if (!sbc_check_prot(dev, cmd, cdb, sectors))
return TCM_UNSUPPORTED_SCSI_OPCODE;
cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
cmd->execute_rw = ops->execute_rw;
cmd->execute_cmd = sbc_execute_rw;
......@@ -597,6 +649,10 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
case READ_16:
sectors = transport_get_sectors_16(cdb);
cmd->t_task_lba = transport_lba_64(cdb);
if (!sbc_check_prot(dev, cmd, cdb, sectors))
return TCM_UNSUPPORTED_SCSI_OPCODE;
cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
cmd->execute_rw = ops->execute_rw;
cmd->execute_cmd = sbc_execute_rw;
......@@ -612,6 +668,10 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
case WRITE_VERIFY:
sectors = transport_get_sectors_10(cdb);
cmd->t_task_lba = transport_lba_32(cdb);
if (!sbc_check_prot(dev, cmd, cdb, sectors))
return TCM_UNSUPPORTED_SCSI_OPCODE;
if (cdb[1] & 0x8)
cmd->se_cmd_flags |= SCF_FUA;
cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
......@@ -621,6 +681,10 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
case WRITE_12:
sectors = transport_get_sectors_12(cdb);
cmd->t_task_lba = transport_lba_32(cdb);
if (!sbc_check_prot(dev, cmd, cdb, sectors))
return TCM_UNSUPPORTED_SCSI_OPCODE;
if (cdb[1] & 0x8)
cmd->se_cmd_flags |= SCF_FUA;
cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
......@@ -630,6 +694,10 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
case WRITE_16:
sectors = transport_get_sectors_16(cdb);
cmd->t_task_lba = transport_lba_64(cdb);
if (!sbc_check_prot(dev, cmd, cdb, sectors))
return TCM_UNSUPPORTED_SCSI_OPCODE;
if (cdb[1] & 0x8)
cmd->se_cmd_flags |= SCF_FUA;
cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
......@@ -731,6 +799,9 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
case SAI_READ_CAPACITY_16:
cmd->execute_cmd = sbc_emulate_readcapacity_16;
break;
case SAI_REPORT_REFERRALS:
cmd->execute_cmd = target_emulate_report_referrals;
break;
default:
pr_err("Unsupported SA: 0x%02x\n",
cmd->t_task_cdb[1] & 0x1f);
......@@ -959,3 +1030,182 @@ sbc_execute_unmap(struct se_cmd *cmd,
return ret;
}
EXPORT_SYMBOL(sbc_execute_unmap);
static sense_reason_t
sbc_dif_v1_verify(struct se_device *dev, struct se_dif_v1_tuple *sdt,
const void *p, sector_t sector, unsigned int ei_lba)
{
int block_size = dev->dev_attrib.block_size;
__be16 csum;
csum = cpu_to_be16(crc_t10dif(p, block_size));
if (sdt->guard_tag != csum) {
pr_err("DIFv1 checksum failed on sector %llu guard tag 0x%04x"
" csum 0x%04x\n", (unsigned long long)sector,
be16_to_cpu(sdt->guard_tag), be16_to_cpu(csum));
return TCM_LOGICAL_BLOCK_GUARD_CHECK_FAILED;
}
if (dev->dev_attrib.pi_prot_type == TARGET_DIF_TYPE1_PROT &&
be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
pr_err("DIFv1 Type 1 reference failed on sector: %llu tag: 0x%08x"
" sector MSB: 0x%08x\n", (unsigned long long)sector,
be32_to_cpu(sdt->ref_tag), (u32)(sector & 0xffffffff));
return TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED;
}
if (dev->dev_attrib.pi_prot_type == TARGET_DIF_TYPE2_PROT &&
be32_to_cpu(sdt->ref_tag) != ei_lba) {
pr_err("DIFv1 Type 2 reference failed on sector: %llu tag: 0x%08x"
" ei_lba: 0x%08x\n", (unsigned long long)sector,
be32_to_cpu(sdt->ref_tag), ei_lba);
return TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED;
}
return 0;
}
static void
sbc_dif_copy_prot(struct se_cmd *cmd, unsigned int sectors, bool read,
struct scatterlist *sg, int sg_off)
{
struct se_device *dev = cmd->se_dev;
struct scatterlist *psg;
void *paddr, *addr;
unsigned int i, len, left;
left = sectors * dev->prot_length;
for_each_sg(cmd->t_prot_sg, psg, cmd->t_prot_nents, i) {
len = min(psg->length, left);
paddr = kmap_atomic(sg_page(psg)) + psg->offset;
addr = kmap_atomic(sg_page(sg)) + sg_off;
if (read)
memcpy(paddr, addr, len);
else
memcpy(addr, paddr, len);
left -= len;
kunmap_atomic(paddr);
kunmap_atomic(addr);
}
}
sense_reason_t
sbc_dif_verify_write(struct se_cmd *cmd, sector_t start, unsigned int sectors,
unsigned int ei_lba, struct scatterlist *sg, int sg_off)
{
struct se_device *dev = cmd->se_dev;
struct se_dif_v1_tuple *sdt;
struct scatterlist *dsg, *psg = cmd->t_prot_sg;
sector_t sector = start;
void *daddr, *paddr;
int i, j, offset = 0;
sense_reason_t rc;
for_each_sg(cmd->t_data_sg, dsg, cmd->t_data_nents, i) {
daddr = kmap_atomic(sg_page(dsg)) + dsg->offset;
paddr = kmap_atomic(sg_page(psg)) + psg->offset;
for (j = 0; j < dsg->length; j += dev->dev_attrib.block_size) {
if (offset >= psg->length) {
kunmap_atomic(paddr);
psg = sg_next(psg);
paddr = kmap_atomic(sg_page(psg)) + psg->offset;
offset = 0;
}
sdt = paddr + offset;
pr_debug("DIF WRITE sector: %llu guard_tag: 0x%04x"
" app_tag: 0x%04x ref_tag: %u\n",
(unsigned long long)sector, sdt->guard_tag,
sdt->app_tag, be32_to_cpu(sdt->ref_tag));
rc = sbc_dif_v1_verify(dev, sdt, daddr + j, sector,
ei_lba);
if (rc) {
kunmap_atomic(paddr);
kunmap_atomic(daddr);
cmd->bad_sector = sector;
return rc;
}
sector++;
ei_lba++;
offset += sizeof(struct se_dif_v1_tuple);
}
kunmap_atomic(paddr);
kunmap_atomic(daddr);
}
sbc_dif_copy_prot(cmd, sectors, false, sg, sg_off);
return 0;
}
EXPORT_SYMBOL(sbc_dif_verify_write);
sense_reason_t
sbc_dif_verify_read(struct se_cmd *cmd, sector_t start, unsigned int sectors,
unsigned int ei_lba, struct scatterlist *sg, int sg_off)
{
struct se_device *dev = cmd->se_dev;
struct se_dif_v1_tuple *sdt;
struct scatterlist *dsg;
sector_t sector = start;
void *daddr, *paddr;
int i, j, offset = sg_off;
sense_reason_t rc;
for_each_sg(cmd->t_data_sg, dsg, cmd->t_data_nents, i) {
daddr = kmap_atomic(sg_page(dsg)) + dsg->offset;
paddr = kmap_atomic(sg_page(sg)) + sg->offset;
for (j = 0; j < dsg->length; j += dev->dev_attrib.block_size) {
if (offset >= sg->length) {
kunmap_atomic(paddr);
sg = sg_next(sg);
paddr = kmap_atomic(sg_page(sg)) + sg->offset;
offset = 0;
}
sdt = paddr + offset;
pr_debug("DIF READ sector: %llu guard_tag: 0x%04x"
" app_tag: 0x%04x ref_tag: %u\n",
(unsigned long long)sector, sdt->guard_tag,
sdt->app_tag, be32_to_cpu(sdt->ref_tag));
if (sdt->app_tag == cpu_to_be16(0xffff)) {
sector++;
offset += sizeof(struct se_dif_v1_tuple);
continue;
}
rc = sbc_dif_v1_verify(dev, sdt, daddr + j, sector,
ei_lba);
if (rc) {
kunmap_atomic(paddr);
kunmap_atomic(daddr);
cmd->bad_sector = sector;
return rc;
}
sector++;
ei_lba++;
offset += sizeof(struct se_dif_v1_tuple);
}
kunmap_atomic(paddr);
kunmap_atomic(daddr);
}
sbc_dif_copy_prot(cmd, sectors, true, sg, sg_off);
return 0;
}
EXPORT_SYMBOL(sbc_dif_verify_read);
......@@ -100,6 +100,11 @@ spc_emulate_inquiry_std(struct se_cmd *cmd, unsigned char *buf)
*/
if (dev->dev_attrib.emulate_3pc)
buf[5] |= 0x8;
/*
* Set Protection (PROTECT) bit when DIF has been enabled.
*/
if (dev->dev_attrib.pi_prot_type)
buf[5] |= 0x1;
buf[7] = 0x2; /* CmdQue=1 */
......@@ -267,7 +272,7 @@ spc_emulate_evpd_83(struct se_cmd *cmd, unsigned char *buf)
port = lun->lun_sep;
if (port) {
struct t10_alua_lu_gp *lu_gp;
u32 padding, scsi_name_len;
u32 padding, scsi_name_len, scsi_target_len;
u16 lu_gp_id = 0;
u16 tg_pt_gp_id = 0;
u16 tpgt;
......@@ -365,16 +370,6 @@ spc_emulate_evpd_83(struct se_cmd *cmd, unsigned char *buf)
* section 7.5.1 Table 362
*/
check_scsi_name:
scsi_name_len = strlen(tpg->se_tpg_tfo->tpg_get_wwn(tpg));
/* UTF-8 ",t,0x<16-bit TPGT>" + NULL Terminator */
scsi_name_len += 10;
/* Check for 4-byte padding */
padding = ((-scsi_name_len) & 3);
if (padding != 0)
scsi_name_len += padding;
/* Header size + Designation descriptor */
scsi_name_len += 4;
buf[off] =
(tpg->se_tpg_tfo->get_fabric_proto_ident(tpg) << 4);
buf[off++] |= 0x3; /* CODE SET == UTF-8 */
......@@ -402,13 +397,57 @@ spc_emulate_evpd_83(struct se_cmd *cmd, unsigned char *buf)
* shall be no larger than 256 and shall be a multiple
* of four.
*/
padding = ((-scsi_name_len) & 3);
if (padding)
scsi_name_len += padding;
if (scsi_name_len > 256)
scsi_name_len = 256;
buf[off-1] = scsi_name_len;
off += scsi_name_len;
/* Header size + Designation descriptor */
len += (scsi_name_len + 4);
/*
* Target device designator
*/
buf[off] =
(tpg->se_tpg_tfo->get_fabric_proto_ident(tpg) << 4);
buf[off++] |= 0x3; /* CODE SET == UTF-8 */
buf[off] = 0x80; /* Set PIV=1 */
/* Set ASSOCIATION == target device: 10b */
buf[off] |= 0x20;
/* DESIGNATOR TYPE == SCSI name string */
buf[off++] |= 0x8;
off += 2; /* Skip over Reserved and length */
/*
* SCSI name string identifer containing, $FABRIC_MOD
* dependent information. For LIO-Target and iSCSI
* Target Port, this means "<iSCSI name>" in
* UTF-8 encoding.
*/
scsi_target_len = sprintf(&buf[off], "%s",
tpg->se_tpg_tfo->tpg_get_wwn(tpg));
scsi_target_len += 1 /* Include NULL terminator */;
/*
* The null-terminated, null-padded (see 4.4.2) SCSI
* NAME STRING field contains a UTF-8 format string.
* The number of bytes in the SCSI NAME STRING field
* (i.e., the value in the DESIGNATOR LENGTH field)
* shall be no larger than 256 and shall be a multiple
* of four.
*/
padding = ((-scsi_target_len) & 3);
if (padding)
scsi_target_len += padding;
if (scsi_name_len > 256)
scsi_name_len = 256;
buf[off-1] = scsi_target_len;
off += scsi_target_len;
/* Header size + Designation descriptor */
len += (scsi_target_len + 4);
}
buf[2] = ((len >> 8) & 0xff);
buf[3] = (len & 0xff); /* Page Length for VPD 0x83 */
......@@ -436,12 +475,26 @@ spc_emulate_evpd_86(struct se_cmd *cmd, unsigned char *buf)
struct se_device *dev = cmd->se_dev;
buf[3] = 0x3c;
/*
* Set GRD_CHK + REF_CHK for TYPE1 protection, or GRD_CHK
* only for TYPE3 protection.
*/
if (dev->dev_attrib.pi_prot_type == TARGET_DIF_TYPE1_PROT)
buf[4] = 0x5;
else if (dev->dev_attrib.pi_prot_type == TARGET_DIF_TYPE3_PROT)
buf[4] = 0x4;
/* Set HEADSUP, ORDSUP, SIMPSUP */
buf[5] = 0x07;
/* If WriteCache emulation is enabled, set V_SUP */
if (spc_check_dev_wce(dev))
buf[6] = 0x01;
/* If an LBA map is present set R_SUP */
spin_lock(&cmd->se_dev->t10_alua.lba_map_lock);
if (!list_empty(&dev->t10_alua.lba_map_list))
buf[8] = 0x10;
spin_unlock(&cmd->se_dev->t10_alua.lba_map_lock);
return 0;
}
......@@ -600,6 +653,20 @@ spc_emulate_evpd_b2(struct se_cmd *cmd, unsigned char *buf)
return 0;
}
/* Referrals VPD page */
static sense_reason_t
spc_emulate_evpd_b3(struct se_cmd *cmd, unsigned char *buf)
{
struct se_device *dev = cmd->se_dev;
buf[0] = dev->transport->get_device_type(dev);
buf[3] = 0x0c;
put_unaligned_be32(dev->t10_alua.lba_map_segment_size, &buf[8]);
put_unaligned_be32(dev->t10_alua.lba_map_segment_size, &buf[12]);
return 0;
}
static sense_reason_t
spc_emulate_evpd_00(struct se_cmd *cmd, unsigned char *buf);
......@@ -614,6 +681,7 @@ static struct {
{ .page = 0xb0, .emulate = spc_emulate_evpd_b0 },
{ .page = 0xb1, .emulate = spc_emulate_evpd_b1 },
{ .page = 0xb2, .emulate = spc_emulate_evpd_b2 },
{ .page = 0xb3, .emulate = spc_emulate_evpd_b3 },
};
/* supported vital product data pages */
......@@ -643,11 +711,15 @@ spc_emulate_inquiry(struct se_cmd *cmd)
struct se_portal_group *tpg = cmd->se_lun->lun_sep->sep_tpg;
unsigned char *rbuf;
unsigned char *cdb = cmd->t_task_cdb;
unsigned char buf[SE_INQUIRY_BUF];
unsigned char *buf;
sense_reason_t ret;
int p;
memset(buf, 0, SE_INQUIRY_BUF);
buf = kzalloc(SE_INQUIRY_BUF, GFP_KERNEL);
if (!buf) {
pr_err("Unable to allocate response buffer for INQUIRY\n");
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
}
if (dev == tpg->tpg_virt_lun0.lun_se_dev)
buf[0] = 0x3f; /* Not connected */
......@@ -680,9 +752,10 @@ spc_emulate_inquiry(struct se_cmd *cmd)
out:
rbuf = transport_kmap_data_sg(cmd);
if (rbuf) {
memcpy(rbuf, buf, min_t(u32, sizeof(buf), cmd->data_length));
memcpy(rbuf, buf, min_t(u32, SE_INQUIRY_BUF, cmd->data_length));
transport_kunmap_data_sg(cmd);
}
kfree(buf);
if (!ret)
target_complete_cmd(cmd, GOOD);
......@@ -785,6 +858,19 @@ static int spc_modesense_control(struct se_device *dev, u8 pc, u8 *p)
* status (see SAM-4).
*/
p[5] = (dev->dev_attrib.emulate_tas) ? 0x40 : 0x00;
/*
* From spc4r30, section 7.5.7 Control mode page
*
* Application Tag Owner (ATO) bit set to one.
*
* If the ATO bit is set to one the device server shall not modify the
* LOGICAL BLOCK APPLICATION TAG field and, depending on the protection
* type, shall not modify the contents of the LOGICAL BLOCK REFERENCE
* TAG field.
*/
if (dev->dev_attrib.pi_prot_type)
p[5] |= 0x80;
p[8] = 0xff;
p[9] = 0xff;
p[11] = 30;
......
......@@ -656,7 +656,7 @@ static int core_tpg_setup_virtual_lun0(struct se_portal_group *se_tpg)
spin_lock_init(&lun->lun_sep_lock);
init_completion(&lun->lun_ref_comp);
ret = core_tpg_post_addlun(se_tpg, lun, lun_access, dev);
ret = core_tpg_add_lun(se_tpg, lun, lun_access, dev);
if (ret < 0)
return ret;
......@@ -781,7 +781,7 @@ int core_tpg_deregister(struct se_portal_group *se_tpg)
}
EXPORT_SYMBOL(core_tpg_deregister);
struct se_lun *core_tpg_pre_addlun(
struct se_lun *core_tpg_alloc_lun(
struct se_portal_group *tpg,
u32 unpacked_lun)
{
......@@ -811,11 +811,11 @@ struct se_lun *core_tpg_pre_addlun(
return lun;
}
int core_tpg_post_addlun(
int core_tpg_add_lun(
struct se_portal_group *tpg,
struct se_lun *lun,
u32 lun_access,
void *lun_ptr)
struct se_device *dev)
{
int ret;
......@@ -823,7 +823,7 @@ int core_tpg_post_addlun(
if (ret < 0)
return ret;
ret = core_dev_export(lun_ptr, tpg, lun);
ret = core_dev_export(dev, tpg, lun);
if (ret < 0) {
percpu_ref_cancel_init(&lun->lun_ref);
return ret;
......
......@@ -62,6 +62,8 @@ struct kmem_cache *t10_alua_lu_gp_cache;
struct kmem_cache *t10_alua_lu_gp_mem_cache;
struct kmem_cache *t10_alua_tg_pt_gp_cache;
struct kmem_cache *t10_alua_tg_pt_gp_mem_cache;
struct kmem_cache *t10_alua_lba_map_cache;
struct kmem_cache *t10_alua_lba_map_mem_cache;
static void transport_complete_task_attr(struct se_cmd *cmd);
static void transport_handle_queue_full(struct se_cmd *cmd,
......@@ -128,14 +130,36 @@ int init_se_kmem_caches(void)
"mem_t failed\n");
goto out_free_tg_pt_gp_cache;
}
t10_alua_lba_map_cache = kmem_cache_create(
"t10_alua_lba_map_cache",
sizeof(struct t10_alua_lba_map),
__alignof__(struct t10_alua_lba_map), 0, NULL);
if (!t10_alua_lba_map_cache) {
pr_err("kmem_cache_create() for t10_alua_lba_map_"
"cache failed\n");
goto out_free_tg_pt_gp_mem_cache;
}
t10_alua_lba_map_mem_cache = kmem_cache_create(
"t10_alua_lba_map_mem_cache",
sizeof(struct t10_alua_lba_map_member),
__alignof__(struct t10_alua_lba_map_member), 0, NULL);
if (!t10_alua_lba_map_mem_cache) {
pr_err("kmem_cache_create() for t10_alua_lba_map_mem_"
"cache failed\n");
goto out_free_lba_map_cache;
}
target_completion_wq = alloc_workqueue("target_completion",
WQ_MEM_RECLAIM, 0);
if (!target_completion_wq)
goto out_free_tg_pt_gp_mem_cache;
goto out_free_lba_map_mem_cache;
return 0;
out_free_lba_map_mem_cache:
kmem_cache_destroy(t10_alua_lba_map_mem_cache);
out_free_lba_map_cache:
kmem_cache_destroy(t10_alua_lba_map_cache);
out_free_tg_pt_gp_mem_cache:
kmem_cache_destroy(t10_alua_tg_pt_gp_mem_cache);
out_free_tg_pt_gp_cache:
......@@ -164,6 +188,8 @@ void release_se_kmem_caches(void)
kmem_cache_destroy(t10_alua_lu_gp_mem_cache);
kmem_cache_destroy(t10_alua_tg_pt_gp_cache);
kmem_cache_destroy(t10_alua_tg_pt_gp_mem_cache);
kmem_cache_destroy(t10_alua_lba_map_cache);
kmem_cache_destroy(t10_alua_lba_map_mem_cache);
}
/* This code ensures unique mib indexes are handed out. */
......@@ -568,9 +594,10 @@ static void transport_lun_remove_cmd(struct se_cmd *cmd)
{
struct se_lun *lun = cmd->se_lun;
if (!lun || !cmd->lun_ref_active)
if (!lun)
return;
if (cmpxchg(&cmd->lun_ref_active, true, false))
percpu_ref_put(&lun->lun_ref);
}
......@@ -1284,6 +1311,8 @@ transport_generic_map_mem_to_cmd(struct se_cmd *cmd, struct scatterlist *sgl,
* @sgl_count: scatterlist count for unidirectional mapping
* @sgl_bidi: struct scatterlist memory for bidirectional READ mapping
* @sgl_bidi_count: scatterlist count for bidirectional READ mapping
* @sgl_prot: struct scatterlist memory protection information
* @sgl_prot_count: scatterlist count for protection information
*
* Returns non zero to signal active I/O shutdown failure. All other
* setup exceptions will be returned as a SCSI CHECK_CONDITION response,
......@@ -1296,7 +1325,8 @@ int target_submit_cmd_map_sgls(struct se_cmd *se_cmd, struct se_session *se_sess
unsigned char *cdb, unsigned char *sense, u32 unpacked_lun,
u32 data_length, int task_attr, int data_dir, int flags,
struct scatterlist *sgl, u32 sgl_count,
struct scatterlist *sgl_bidi, u32 sgl_bidi_count)
struct scatterlist *sgl_bidi, u32 sgl_bidi_count,
struct scatterlist *sgl_prot, u32 sgl_prot_count)
{
struct se_portal_group *se_tpg;
sense_reason_t rc;
......@@ -1338,6 +1368,14 @@ int target_submit_cmd_map_sgls(struct se_cmd *se_cmd, struct se_session *se_sess
target_put_sess_cmd(se_sess, se_cmd);
return 0;
}
/*
* Save pointers for SGLs containing protection information,
* if present.
*/
if (sgl_prot_count) {
se_cmd->t_prot_sg = sgl_prot;
se_cmd->t_prot_nents = sgl_prot_count;
}
rc = target_setup_cmd_from_cdb(se_cmd, cdb);
if (rc != 0) {
......@@ -1380,6 +1418,7 @@ int target_submit_cmd_map_sgls(struct se_cmd *se_cmd, struct se_session *se_sess
return 0;
}
}
/*
* Check if we need to delay processing because of ALUA
* Active/NonOptimized primary access state..
......@@ -1419,7 +1458,7 @@ int target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess,
{
return target_submit_cmd_map_sgls(se_cmd, se_sess, cdb, sense,
unpacked_lun, data_length, task_attr, data_dir,
flags, NULL, 0, NULL, 0);
flags, NULL, 0, NULL, 0, NULL, 0);
}
EXPORT_SYMBOL(target_submit_cmd);
......@@ -2455,6 +2494,19 @@ static int transport_get_sense_codes(
return 0;
}
static
void transport_err_sector_info(unsigned char *buffer, sector_t bad_sector)
{
/* Place failed LBA in sense data information descriptor 0. */
buffer[SPC_ADD_SENSE_LEN_OFFSET] = 0xc;
buffer[SPC_DESC_TYPE_OFFSET] = 0; /* Information */
buffer[SPC_ADDITIONAL_DESC_LEN_OFFSET] = 0xa;
buffer[SPC_VALIDITY_OFFSET] = 0x80;
/* Descriptor Information: failing sector */
put_unaligned_be64(bad_sector, &buffer[12]);
}
int
transport_send_check_condition_and_sense(struct se_cmd *cmd,
sense_reason_t reason, int from_transport)
......@@ -2648,6 +2700,39 @@ transport_send_check_condition_and_sense(struct se_cmd *cmd,
buffer[SPC_ASC_KEY_OFFSET] = 0x1d;
buffer[SPC_ASCQ_KEY_OFFSET] = 0x00;
break;
case TCM_LOGICAL_BLOCK_GUARD_CHECK_FAILED:
/* CURRENT ERROR */
buffer[0] = 0x70;
buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
/* ILLEGAL REQUEST */
buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
/* LOGICAL BLOCK GUARD CHECK FAILED */
buffer[SPC_ASC_KEY_OFFSET] = 0x10;
buffer[SPC_ASCQ_KEY_OFFSET] = 0x01;
transport_err_sector_info(buffer, cmd->bad_sector);
break;
case TCM_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED:
/* CURRENT ERROR */
buffer[0] = 0x70;
buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
/* ILLEGAL REQUEST */
buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
/* LOGICAL BLOCK APPLICATION TAG CHECK FAILED */
buffer[SPC_ASC_KEY_OFFSET] = 0x10;
buffer[SPC_ASCQ_KEY_OFFSET] = 0x02;
transport_err_sector_info(buffer, cmd->bad_sector);
break;
case TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED:
/* CURRENT ERROR */
buffer[0] = 0x70;
buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
/* ILLEGAL REQUEST */
buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
/* LOGICAL BLOCK REFERENCE TAG CHECK FAILED */
buffer[SPC_ASC_KEY_OFFSET] = 0x10;
buffer[SPC_ASCQ_KEY_OFFSET] = 0x03;
transport_err_sector_info(buffer, cmd->bad_sector);
break;
case TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE:
default:
/* CURRENT ERROR */
......
......@@ -98,7 +98,6 @@ int core_scsi3_ua_allocate(
pr_err("Unable to allocate struct se_ua\n");
return -ENOMEM;
}
INIT_LIST_HEAD(&ua->ua_dev_list);
INIT_LIST_HEAD(&ua->ua_nacl_list);
ua->ua_nacl = nacl;
......
......@@ -39,10 +39,6 @@
#include "target_core_xcopy.h"
static struct workqueue_struct *xcopy_wq = NULL;
/*
* From target_core_spc.c
*/
extern void spc_parse_naa_6h_vendor_specific(struct se_device *, unsigned char *);
/*
* From target_core_device.c
*/
......
......@@ -438,7 +438,7 @@ static void ft_recv_cmd(struct ft_sess *sess, struct fc_frame *fp)
struct se_session *se_sess = sess->se_sess;
int tag;
tag = percpu_ida_alloc(&se_sess->sess_tag_pool, GFP_ATOMIC);
tag = percpu_ida_alloc(&se_sess->sess_tag_pool, TASK_RUNNING);
if (tag < 0)
goto busy;
......
......@@ -267,7 +267,7 @@ struct ft_node_acl *ft_acl_get(struct ft_tpg *tpg, struct fc_rport_priv *rdata)
return found;
}
struct se_node_acl *ft_tpg_alloc_fabric_acl(struct se_portal_group *se_tpg)
static struct se_node_acl *ft_tpg_alloc_fabric_acl(struct se_portal_group *se_tpg)
{
struct ft_node_acl *acl;
......@@ -552,7 +552,7 @@ static struct target_core_fabric_ops ft_fabric_ops = {
.fabric_drop_nodeacl = &ft_del_acl,
};
int ft_register_configfs(void)
static int ft_register_configfs(void)
{
struct target_fabric_configfs *fabric;
int ret;
......@@ -599,7 +599,7 @@ int ft_register_configfs(void)
return 0;
}
void ft_deregister_configfs(void)
static void ft_deregister_configfs(void)
{
if (!ft_configfs)
return;
......
......@@ -728,7 +728,7 @@ vhost_scsi_get_tag(struct vhost_virtqueue *vq,
}
se_sess = tv_nexus->tvn_se_sess;
tag = percpu_ida_alloc(&se_sess->sess_tag_pool, GFP_ATOMIC);
tag = percpu_ida_alloc(&se_sess->sess_tag_pool, TASK_RUNNING);
if (tag < 0) {
pr_err("Unable to obtain tag for tcm_vhost_cmd\n");
return ERR_PTR(-ENOMEM);
......@@ -889,7 +889,7 @@ static void tcm_vhost_submission_work(struct work_struct *work)
cmd->tvc_lun, cmd->tvc_exp_data_len,
cmd->tvc_task_attr, cmd->tvc_data_direction,
TARGET_SCF_ACK_KREF, sg_ptr, cmd->tvc_sgl_count,
sg_bidi_ptr, sg_no_bidi);
sg_bidi_ptr, sg_no_bidi, NULL, 0);
if (rc < 0) {
transport_send_check_condition_and_sense(se_cmd,
TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0);
......
......@@ -4,6 +4,7 @@
#include <linux/types.h>
#include <linux/bitops.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/spinlock_types.h>
#include <linux/wait.h>
#include <linux/cpumask.h>
......@@ -61,7 +62,7 @@ struct percpu_ida {
/* Max size of percpu freelist, */
#define IDA_DEFAULT_PCPU_SIZE ((IDA_DEFAULT_PCPU_BATCH_MOVE * 3) / 2)
int percpu_ida_alloc(struct percpu_ida *pool, gfp_t gfp);
int percpu_ida_alloc(struct percpu_ida *pool, int state);
void percpu_ida_free(struct percpu_ida *pool, unsigned tag);
void percpu_ida_destroy(struct percpu_ida *pool);
......
......@@ -155,6 +155,7 @@ enum scsi_timeouts {
/* values for service action in */
#define SAI_READ_CAPACITY_16 0x10
#define SAI_GET_LBA_STATUS 0x12
#define SAI_REPORT_REFERRALS 0x13
/* values for VARIABLE_LENGTH_CMD service action codes
* see spc4r17 Section D.3.5, table D.7 and D.8 */
#define VLC_SA_RECEIVE_CREDENTIAL 0x1800
......
......@@ -94,7 +94,7 @@ extern int iscsit_tmr_post_handler(struct iscsi_cmd *, struct iscsi_conn *);
/*
* From iscsi_target_util.c
*/
extern struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *, gfp_t);
extern struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *, int);
extern int iscsit_sequence_cmd(struct iscsi_conn *, struct iscsi_cmd *,
unsigned char *, __be32);
extern void iscsit_release_cmd(struct iscsi_cmd *);
......@@ -41,6 +41,9 @@ struct se_subsystem_api {
unsigned int (*get_io_opt)(struct se_device *);
unsigned char *(*get_sense_buffer)(struct se_cmd *);
bool (*get_write_cache)(struct se_device *);
int (*init_prot)(struct se_device *);
int (*format_prot)(struct se_device *);
void (*free_prot)(struct se_device *);
};
struct sbc_ops {
......@@ -70,6 +73,10 @@ sense_reason_t sbc_execute_unmap(struct se_cmd *cmd,
sense_reason_t (*do_unmap_fn)(struct se_cmd *cmd, void *priv,
sector_t lba, sector_t nolb),
void *priv);
sense_reason_t sbc_dif_verify_write(struct se_cmd *, sector_t, unsigned int,
unsigned int, struct scatterlist *, int);
sense_reason_t sbc_dif_verify_read(struct se_cmd *, sector_t, unsigned int,
unsigned int, struct scatterlist *, int);
void transport_set_vpd_proto_id(struct t10_vpd *, unsigned char *);
int transport_set_vpd_assoc(struct t10_vpd *, unsigned char *);
......
......@@ -37,6 +37,9 @@
/* Used by transport_send_check_condition_and_sense() */
#define SPC_SENSE_KEY_OFFSET 2
#define SPC_ADD_SENSE_LEN_OFFSET 7
#define SPC_DESC_TYPE_OFFSET 8
#define SPC_ADDITIONAL_DESC_LEN_OFFSET 9
#define SPC_VALIDITY_OFFSET 10
#define SPC_ASC_KEY_OFFSET 12
#define SPC_ASCQ_KEY_OFFSET 13
#define TRANSPORT_IQN_LEN 224
......@@ -112,7 +115,7 @@
/* Queue Algorithm Modifier default for restricted reordering in control mode page */
#define DA_EMULATE_REST_REORD 0
#define SE_INQUIRY_BUF 512
#define SE_INQUIRY_BUF 1024
#define SE_MODE_PAGE_BUF 512
#define SE_SENSE_BUF 96
......@@ -205,6 +208,9 @@ enum tcm_sense_reason_table {
TCM_OUT_OF_RESOURCES = R(0x12),
TCM_PARAMETER_LIST_LENGTH_ERROR = R(0x13),
TCM_MISCOMPARE_VERIFY = R(0x14),
TCM_LOGICAL_BLOCK_GUARD_CHECK_FAILED = R(0x15),
TCM_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED = R(0x16),
TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED = R(0x17),
#undef R
};
......@@ -247,10 +253,28 @@ typedef enum {
struct se_cmd;
struct t10_alua_lba_map_member {
struct list_head lba_map_mem_list;
int lba_map_mem_alua_state;
int lba_map_mem_alua_pg_id;
};
struct t10_alua_lba_map {
u64 lba_map_first_lba;
u64 lba_map_last_lba;
struct list_head lba_map_list;
struct list_head lba_map_mem_list;
};
struct t10_alua {
/* ALUA Target Port Group ID */
u16 alua_tg_pt_gps_counter;
u32 alua_tg_pt_gps_count;
/* Referrals support */
spinlock_t lba_map_lock;
u32 lba_map_segment_size;
u32 lba_map_segment_multiplier;
struct list_head lba_map_list;
spinlock_t tg_pt_gps_lock;
struct se_device *t10_dev;
/* Used for default ALUA Target Port Group */
......@@ -284,6 +308,8 @@ struct t10_alua_tg_pt_gp {
u16 tg_pt_gp_id;
int tg_pt_gp_valid_id;
int tg_pt_gp_alua_supported_states;
int tg_pt_gp_alua_pending_state;
int tg_pt_gp_alua_previous_state;
int tg_pt_gp_alua_access_status;
int tg_pt_gp_alua_access_type;
int tg_pt_gp_nonop_delay_msecs;
......@@ -291,9 +317,6 @@ struct t10_alua_tg_pt_gp {
int tg_pt_gp_implicit_trans_secs;
int tg_pt_gp_pref;
int tg_pt_gp_write_metadata;
/* Used by struct t10_alua_tg_pt_gp->tg_pt_gp_md_buf_len */
#define ALUA_MD_BUF_LEN 1024
u32 tg_pt_gp_md_buf_len;
u32 tg_pt_gp_members;
atomic_t tg_pt_gp_alua_access_state;
atomic_t tg_pt_gp_ref_cnt;
......@@ -303,6 +326,10 @@ struct t10_alua_tg_pt_gp {
struct config_group tg_pt_gp_group;
struct list_head tg_pt_gp_list;
struct list_head tg_pt_gp_mem_list;
struct se_port *tg_pt_gp_alua_port;
struct se_node_acl *tg_pt_gp_alua_nacl;
struct delayed_work tg_pt_gp_transition_work;
struct completion *tg_pt_gp_transition_complete;
};
struct t10_alua_tg_pt_gp_member {
......@@ -414,6 +441,34 @@ struct se_tmr_req {
struct list_head tmr_list;
};
enum target_prot_op {
TARGET_PROT_NORMAL = 0,
TARGET_PROT_DIN_INSERT,
TARGET_PROT_DOUT_INSERT,
TARGET_PROT_DIN_STRIP,
TARGET_PROT_DOUT_STRIP,
TARGET_PROT_DIN_PASS,
TARGET_PROT_DOUT_PASS,
};
enum target_prot_ho {
PROT_SEPERATED,
PROT_INTERLEAVED,
};
enum target_prot_type {
TARGET_DIF_TYPE0_PROT,
TARGET_DIF_TYPE1_PROT,
TARGET_DIF_TYPE2_PROT,
TARGET_DIF_TYPE3_PROT,
};
struct se_dif_v1_tuple {
__be16 guard_tag;
__be16 app_tag;
__be32 ref_tag;
};
struct se_cmd {
/* SAM response code being sent to initiator */
u8 scsi_status;
......@@ -497,14 +552,24 @@ struct se_cmd {
void *priv;
/* Used for lun->lun_ref counting */
bool lun_ref_active;
int lun_ref_active;
/* DIF related members */
enum target_prot_op prot_op;
enum target_prot_type prot_type;
u32 prot_length;
u32 reftag_seed;
struct scatterlist *t_prot_sg;
unsigned int t_prot_nents;
enum target_prot_ho prot_handover;
sense_reason_t pi_err;
sector_t bad_sector;
};
struct se_ua {
u8 ua_asc;
u8 ua_ascq;
struct se_node_acl *ua_nacl;
struct list_head ua_dev_list;
struct list_head ua_nacl_list;
};
......@@ -605,6 +670,9 @@ struct se_dev_attrib {
int emulate_tpws;
int emulate_caw;
int emulate_3pc;
int pi_prot_format;
enum target_prot_type pi_prot_type;
enum target_prot_type hw_pi_prot_type;
int enforce_pr_isids;
int is_nonrot;
int emulate_rest_reord;
......@@ -736,6 +804,8 @@ struct se_device {
/* Linked list for struct se_hba struct se_device list */
struct list_head dev_list;
struct se_lun xcopy_lun;
/* Protection Information */
int prot_length;
};
struct se_hba {
......
......@@ -105,7 +105,8 @@ sense_reason_t transport_lookup_cmd_lun(struct se_cmd *, u32);
sense_reason_t target_setup_cmd_from_cdb(struct se_cmd *, unsigned char *);
int target_submit_cmd_map_sgls(struct se_cmd *, struct se_session *,
unsigned char *, unsigned char *, u32, u32, int, int, int,
struct scatterlist *, u32, struct scatterlist *, u32);
struct scatterlist *, u32, struct scatterlist *, u32,
struct scatterlist *, u32);
int target_submit_cmd(struct se_cmd *, struct se_session *, unsigned char *,
unsigned char *, u32, u32, int, int, int);
int target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess,
......
......@@ -132,22 +132,22 @@ static inline unsigned alloc_local_tag(struct percpu_ida_cpu *tags)
/**
* percpu_ida_alloc - allocate a tag
* @pool: pool to allocate from
* @gfp: gfp flags
* @state: task state for prepare_to_wait
*
* Returns a tag - an integer in the range [0..nr_tags) (passed to
* tag_pool_init()), or otherwise -ENOSPC on allocation failure.
*
* Safe to be called from interrupt context (assuming it isn't passed
* __GFP_WAIT, of course).
* TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, of course).
*
* @gfp indicates whether or not to wait until a free id is available (it's not
* used for internal memory allocations); thus if passed __GFP_WAIT we may sleep
* however long it takes until another thread frees an id (same semantics as a
* mempool).
*
* Will not fail if passed __GFP_WAIT.
* Will not fail if passed TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE.
*/
int percpu_ida_alloc(struct percpu_ida *pool, gfp_t gfp)
int percpu_ida_alloc(struct percpu_ida *pool, int state)
{
DEFINE_WAIT(wait);
struct percpu_ida_cpu *tags;
......@@ -174,7 +174,8 @@ int percpu_ida_alloc(struct percpu_ida *pool, gfp_t gfp)
*
* global lock held and irqs disabled, don't need percpu lock
*/
prepare_to_wait(&pool->wait, &wait, TASK_UNINTERRUPTIBLE);
if (state != TASK_RUNNING)
prepare_to_wait(&pool->wait, &wait, state);
if (!tags->nr_free)
alloc_global_tags(pool, tags);
......@@ -191,16 +192,22 @@ int percpu_ida_alloc(struct percpu_ida *pool, gfp_t gfp)
spin_unlock(&pool->lock);
local_irq_restore(flags);
if (tag >= 0 || !(gfp & __GFP_WAIT))
if (tag >= 0 || state == TASK_RUNNING)
break;
if (signal_pending_state(state, current)) {
tag = -ERESTARTSYS;
break;
}
schedule();
local_irq_save(flags);
tags = this_cpu_ptr(pool->tag_cpu);
}
if (state != TASK_RUNNING)
finish_wait(&pool->wait, &wait);
return tag;
}
EXPORT_SYMBOL_GPL(percpu_ida_alloc);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment