|
|
|
@@ -104,7 +104,6 @@ static void qlt_reject_free_srr_imm(struct scsi_qla_host *ha,
|
|
|
|
|
/*
|
|
|
|
|
* Global Variables
|
|
|
|
|
*/
|
|
|
|
|
static struct kmem_cache *qla_tgt_cmd_cachep;
|
|
|
|
|
static struct kmem_cache *qla_tgt_mgmt_cmd_cachep;
|
|
|
|
|
static mempool_t *qla_tgt_mgmt_cmd_mempool;
|
|
|
|
|
static struct workqueue_struct *qla_tgt_wq;
|
|
|
|
@@ -2165,11 +2164,18 @@ done:
|
|
|
|
|
|
|
|
|
|
void qlt_free_cmd(struct qla_tgt_cmd *cmd)
|
|
|
|
|
{
|
|
|
|
|
struct qla_tgt_sess *sess = cmd->sess;
|
|
|
|
|
|
|
|
|
|
BUG_ON(cmd->sg_mapped);
|
|
|
|
|
|
|
|
|
|
if (unlikely(cmd->free_sg))
|
|
|
|
|
kfree(cmd->sg);
|
|
|
|
|
kmem_cache_free(qla_tgt_cmd_cachep, cmd);
|
|
|
|
|
|
|
|
|
|
if (!sess || !sess->se_sess) {
|
|
|
|
|
WARN_ON(1);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
percpu_ida_free(&sess->se_sess->sess_tag_pool, cmd->se_cmd.map_tag);
|
|
|
|
|
}
|
|
|
|
|
EXPORT_SYMBOL(qlt_free_cmd);
|
|
|
|
|
|
|
|
|
@@ -2489,13 +2495,12 @@ static struct qla_tgt_sess *qlt_make_local_sess(struct scsi_qla_host *,
|
|
|
|
|
/*
|
|
|
|
|
* Process context for I/O path into tcm_qla2xxx code
|
|
|
|
|
*/
|
|
|
|
|
static void qlt_do_work(struct work_struct *work)
|
|
|
|
|
static void __qlt_do_work(struct qla_tgt_cmd *cmd)
|
|
|
|
|
{
|
|
|
|
|
struct qla_tgt_cmd *cmd = container_of(work, struct qla_tgt_cmd, work);
|
|
|
|
|
scsi_qla_host_t *vha = cmd->vha;
|
|
|
|
|
struct qla_hw_data *ha = vha->hw;
|
|
|
|
|
struct qla_tgt *tgt = vha->vha_tgt.qla_tgt;
|
|
|
|
|
struct qla_tgt_sess *sess = NULL;
|
|
|
|
|
struct qla_tgt_sess *sess = cmd->sess;
|
|
|
|
|
struct atio_from_isp *atio = &cmd->atio;
|
|
|
|
|
unsigned char *cdb;
|
|
|
|
|
unsigned long flags;
|
|
|
|
@@ -2505,41 +2510,6 @@ static void qlt_do_work(struct work_struct *work)
|
|
|
|
|
if (tgt->tgt_stop)
|
|
|
|
|
goto out_term;
|
|
|
|
|
|
|
|
|
|
spin_lock_irqsave(&ha->hardware_lock, flags);
|
|
|
|
|
sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha,
|
|
|
|
|
atio->u.isp24.fcp_hdr.s_id);
|
|
|
|
|
/* Do kref_get() before dropping qla_hw_data->hardware_lock. */
|
|
|
|
|
if (sess)
|
|
|
|
|
kref_get(&sess->se_sess->sess_kref);
|
|
|
|
|
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
|
|
|
|
|
|
|
|
|
if (unlikely(!sess)) {
|
|
|
|
|
uint8_t *s_id = atio->u.isp24.fcp_hdr.s_id;
|
|
|
|
|
|
|
|
|
|
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf022,
|
|
|
|
|
"qla_target(%d): Unable to find wwn login"
|
|
|
|
|
" (s_id %x:%x:%x), trying to create it manually\n",
|
|
|
|
|
vha->vp_idx, s_id[0], s_id[1], s_id[2]);
|
|
|
|
|
|
|
|
|
|
if (atio->u.raw.entry_count > 1) {
|
|
|
|
|
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf023,
|
|
|
|
|
"Dropping multy entry cmd %p\n", cmd);
|
|
|
|
|
goto out_term;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mutex_lock(&vha->vha_tgt.tgt_mutex);
|
|
|
|
|
sess = qlt_make_local_sess(vha, s_id);
|
|
|
|
|
/* sess has an extra creation ref. */
|
|
|
|
|
mutex_unlock(&vha->vha_tgt.tgt_mutex);
|
|
|
|
|
|
|
|
|
|
if (!sess)
|
|
|
|
|
goto out_term;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cmd->sess = sess;
|
|
|
|
|
cmd->loop_id = sess->loop_id;
|
|
|
|
|
cmd->conf_compl_supported = sess->conf_compl_supported;
|
|
|
|
|
|
|
|
|
|
cdb = &atio->u.isp24.fcp_cmnd.cdb[0];
|
|
|
|
|
cmd->tag = atio->u.isp24.exchange_addr;
|
|
|
|
|
cmd->unpacked_lun = scsilun_to_int(
|
|
|
|
@@ -2566,8 +2536,8 @@ static void qlt_do_work(struct work_struct *work)
|
|
|
|
|
"qla_target: START qla command: %p lun: 0x%04x (tag %d)\n",
|
|
|
|
|
cmd, cmd->unpacked_lun, cmd->tag);
|
|
|
|
|
|
|
|
|
|
ret = vha->hw->tgt.tgt_ops->handle_cmd(vha, cmd, cdb, data_length,
|
|
|
|
|
fcp_task_attr, data_dir, bidi);
|
|
|
|
|
ret = ha->tgt.tgt_ops->handle_cmd(vha, cmd, cdb, data_length,
|
|
|
|
|
fcp_task_attr, data_dir, bidi);
|
|
|
|
|
if (ret != 0)
|
|
|
|
|
goto out_term;
|
|
|
|
|
/*
|
|
|
|
@@ -2586,17 +2556,114 @@ out_term:
|
|
|
|
|
*/
|
|
|
|
|
spin_lock_irqsave(&ha->hardware_lock, flags);
|
|
|
|
|
qlt_send_term_exchange(vha, NULL, &cmd->atio, 1);
|
|
|
|
|
kmem_cache_free(qla_tgt_cmd_cachep, cmd);
|
|
|
|
|
if (sess)
|
|
|
|
|
ha->tgt.tgt_ops->put_sess(sess);
|
|
|
|
|
percpu_ida_free(&sess->se_sess->sess_tag_pool, cmd->se_cmd.map_tag);
|
|
|
|
|
ha->tgt.tgt_ops->put_sess(sess);
|
|
|
|
|
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void qlt_do_work(struct work_struct *work)
|
|
|
|
|
{
|
|
|
|
|
struct qla_tgt_cmd *cmd = container_of(work, struct qla_tgt_cmd, work);
|
|
|
|
|
|
|
|
|
|
__qlt_do_work(cmd);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct qla_tgt_cmd *qlt_get_tag(scsi_qla_host_t *vha,
|
|
|
|
|
struct qla_tgt_sess *sess,
|
|
|
|
|
struct atio_from_isp *atio)
|
|
|
|
|
{
|
|
|
|
|
struct se_session *se_sess = sess->se_sess;
|
|
|
|
|
struct qla_tgt_cmd *cmd;
|
|
|
|
|
int tag;
|
|
|
|
|
|
|
|
|
|
tag = percpu_ida_alloc(&se_sess->sess_tag_pool, TASK_RUNNING);
|
|
|
|
|
if (tag < 0)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
cmd = &((struct qla_tgt_cmd *)se_sess->sess_cmd_map)[tag];
|
|
|
|
|
memset(cmd, 0, sizeof(struct qla_tgt_cmd));
|
|
|
|
|
|
|
|
|
|
memcpy(&cmd->atio, atio, sizeof(*atio));
|
|
|
|
|
cmd->state = QLA_TGT_STATE_NEW;
|
|
|
|
|
cmd->tgt = vha->vha_tgt.qla_tgt;
|
|
|
|
|
cmd->vha = vha;
|
|
|
|
|
cmd->se_cmd.map_tag = tag;
|
|
|
|
|
cmd->sess = sess;
|
|
|
|
|
cmd->loop_id = sess->loop_id;
|
|
|
|
|
cmd->conf_compl_supported = sess->conf_compl_supported;
|
|
|
|
|
|
|
|
|
|
return cmd;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void qlt_send_busy(struct scsi_qla_host *, struct atio_from_isp *,
|
|
|
|
|
uint16_t);
|
|
|
|
|
|
|
|
|
|
static void qlt_create_sess_from_atio(struct work_struct *work)
|
|
|
|
|
{
|
|
|
|
|
struct qla_tgt_sess_op *op = container_of(work,
|
|
|
|
|
struct qla_tgt_sess_op, work);
|
|
|
|
|
scsi_qla_host_t *vha = op->vha;
|
|
|
|
|
struct qla_hw_data *ha = vha->hw;
|
|
|
|
|
struct qla_tgt_sess *sess;
|
|
|
|
|
struct qla_tgt_cmd *cmd;
|
|
|
|
|
unsigned long flags;
|
|
|
|
|
uint8_t *s_id = op->atio.u.isp24.fcp_hdr.s_id;
|
|
|
|
|
|
|
|
|
|
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf022,
|
|
|
|
|
"qla_target(%d): Unable to find wwn login"
|
|
|
|
|
" (s_id %x:%x:%x), trying to create it manually\n",
|
|
|
|
|
vha->vp_idx, s_id[0], s_id[1], s_id[2]);
|
|
|
|
|
|
|
|
|
|
if (op->atio.u.raw.entry_count > 1) {
|
|
|
|
|
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf023,
|
|
|
|
|
"Dropping multy entry atio %p\n", &op->atio);
|
|
|
|
|
goto out_term;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mutex_lock(&vha->vha_tgt.tgt_mutex);
|
|
|
|
|
sess = qlt_make_local_sess(vha, s_id);
|
|
|
|
|
/* sess has an extra creation ref. */
|
|
|
|
|
mutex_unlock(&vha->vha_tgt.tgt_mutex);
|
|
|
|
|
|
|
|
|
|
if (!sess)
|
|
|
|
|
goto out_term;
|
|
|
|
|
/*
|
|
|
|
|
* Now obtain a pre-allocated session tag using the original op->atio
|
|
|
|
|
* packet header, and dispatch into __qlt_do_work() using the existing
|
|
|
|
|
* process context.
|
|
|
|
|
*/
|
|
|
|
|
cmd = qlt_get_tag(vha, sess, &op->atio);
|
|
|
|
|
if (!cmd) {
|
|
|
|
|
spin_lock_irqsave(&ha->hardware_lock, flags);
|
|
|
|
|
qlt_send_busy(vha, &op->atio, SAM_STAT_BUSY);
|
|
|
|
|
ha->tgt.tgt_ops->put_sess(sess);
|
|
|
|
|
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
|
|
|
|
kfree(op);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* __qlt_do_work() will call ha->tgt.tgt_ops->put_sess() to release
|
|
|
|
|
* the extra reference taken above by qlt_make_local_sess()
|
|
|
|
|
*/
|
|
|
|
|
__qlt_do_work(cmd);
|
|
|
|
|
kfree(op);
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
out_term:
|
|
|
|
|
spin_lock_irqsave(&ha->hardware_lock, flags);
|
|
|
|
|
qlt_send_term_exchange(vha, NULL, &op->atio, 1);
|
|
|
|
|
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
|
|
|
|
kfree(op);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ha->hardware_lock supposed to be held on entry */
|
|
|
|
|
static int qlt_handle_cmd_for_atio(struct scsi_qla_host *vha,
|
|
|
|
|
struct atio_from_isp *atio)
|
|
|
|
|
{
|
|
|
|
|
struct qla_hw_data *ha = vha->hw;
|
|
|
|
|
struct qla_tgt *tgt = vha->vha_tgt.qla_tgt;
|
|
|
|
|
struct qla_tgt_sess *sess;
|
|
|
|
|
struct qla_tgt_cmd *cmd;
|
|
|
|
|
|
|
|
|
|
if (unlikely(tgt->tgt_stop)) {
|
|
|
|
@@ -2605,18 +2672,31 @@ static int qlt_handle_cmd_for_atio(struct scsi_qla_host *vha,
|
|
|
|
|
return -EFAULT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cmd = kmem_cache_zalloc(qla_tgt_cmd_cachep, GFP_ATOMIC);
|
|
|
|
|
sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha, atio->u.isp24.fcp_hdr.s_id);
|
|
|
|
|
if (unlikely(!sess)) {
|
|
|
|
|
struct qla_tgt_sess_op *op = kzalloc(sizeof(struct qla_tgt_sess_op),
|
|
|
|
|
GFP_ATOMIC);
|
|
|
|
|
if (!op)
|
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
|
|
memcpy(&op->atio, atio, sizeof(*atio));
|
|
|
|
|
INIT_WORK(&op->work, qlt_create_sess_from_atio);
|
|
|
|
|
queue_work(qla_tgt_wq, &op->work);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* Do kref_get() before returning + dropping qla_hw_data->hardware_lock.
|
|
|
|
|
*/
|
|
|
|
|
kref_get(&sess->se_sess->sess_kref);
|
|
|
|
|
|
|
|
|
|
cmd = qlt_get_tag(vha, sess, atio);
|
|
|
|
|
if (!cmd) {
|
|
|
|
|
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf05e,
|
|
|
|
|
"qla_target(%d): Allocation of cmd failed\n", vha->vp_idx);
|
|
|
|
|
ha->tgt.tgt_ops->put_sess(sess);
|
|
|
|
|
return -ENOMEM;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
memcpy(&cmd->atio, atio, sizeof(*atio));
|
|
|
|
|
cmd->state = QLA_TGT_STATE_NEW;
|
|
|
|
|
cmd->tgt = vha->vha_tgt.qla_tgt;
|
|
|
|
|
cmd->vha = vha;
|
|
|
|
|
|
|
|
|
|
INIT_WORK(&cmd->work, qlt_do_work);
|
|
|
|
|
queue_work(qla_tgt_wq, &cmd->work);
|
|
|
|
|
return 0;
|
|
|
|
@@ -4911,23 +4991,13 @@ int __init qlt_init(void)
|
|
|
|
|
if (!QLA_TGT_MODE_ENABLED())
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
qla_tgt_cmd_cachep = kmem_cache_create("qla_tgt_cmd_cachep",
|
|
|
|
|
sizeof(struct qla_tgt_cmd), __alignof__(struct qla_tgt_cmd), 0,
|
|
|
|
|
NULL);
|
|
|
|
|
if (!qla_tgt_cmd_cachep) {
|
|
|
|
|
ql_log(ql_log_fatal, NULL, 0xe06c,
|
|
|
|
|
"kmem_cache_create for qla_tgt_cmd_cachep failed\n");
|
|
|
|
|
return -ENOMEM;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
qla_tgt_mgmt_cmd_cachep = kmem_cache_create("qla_tgt_mgmt_cmd_cachep",
|
|
|
|
|
sizeof(struct qla_tgt_mgmt_cmd), __alignof__(struct
|
|
|
|
|
qla_tgt_mgmt_cmd), 0, NULL);
|
|
|
|
|
if (!qla_tgt_mgmt_cmd_cachep) {
|
|
|
|
|
ql_log(ql_log_fatal, NULL, 0xe06d,
|
|
|
|
|
"kmem_cache_create for qla_tgt_mgmt_cmd_cachep failed\n");
|
|
|
|
|
ret = -ENOMEM;
|
|
|
|
|
goto out;
|
|
|
|
|
return -ENOMEM;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
qla_tgt_mgmt_cmd_mempool = mempool_create(25, mempool_alloc_slab,
|
|
|
|
@@ -4955,8 +5025,6 @@ out_cmd_mempool:
|
|
|
|
|
mempool_destroy(qla_tgt_mgmt_cmd_mempool);
|
|
|
|
|
out_mgmt_cmd_cachep:
|
|
|
|
|
kmem_cache_destroy(qla_tgt_mgmt_cmd_cachep);
|
|
|
|
|
out:
|
|
|
|
|
kmem_cache_destroy(qla_tgt_cmd_cachep);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -4968,5 +5036,4 @@ void qlt_exit(void)
|
|
|
|
|
destroy_workqueue(qla_tgt_wq);
|
|
|
|
|
mempool_destroy(qla_tgt_mgmt_cmd_mempool);
|
|
|
|
|
kmem_cache_destroy(qla_tgt_mgmt_cmd_cachep);
|
|
|
|
|
kmem_cache_destroy(qla_tgt_cmd_cachep);
|
|
|
|
|
}
|
|
|
|
|