From: Nicholas Bellinger <nab@xxxxxxxxxxxxxxx> This patch adds an initial conversion to cmwq using qla_tgt->qla_tgt_wq for I/O dispatch into qla_hw_data->qla_tgt specific context. This includes removal of transport_generic_handle_cdb_map() usage, and moves transport_lookup_cmd_lun() into tcm_qla2xxx_do_work() process context for incoming descriptor dispatch. It passes WQ_UNBOUND during alloc_workqueue() setup, and also keeps all target_core_mod referenced symbols within tcm_qla2xxx code in order to avoid an qla2xxx LLD target_core_mod dependency. Cc: Christoph Hellwig <hch@xxxxxx> Signed-off-by: Nicholas Bellinger <nab@xxxxxxxxxxxxxxx> --- drivers/scsi/qla2xxx/qla_os.c | 8 +- drivers/scsi/qla2xxx/qla_target.c | 76 ++++++++++---------- drivers/scsi/qla2xxx/qla_target.h | 5 +- drivers/target/tcm_qla2xxx/tcm_qla2xxx_configfs.c | 19 ++++-- drivers/target/tcm_qla2xxx/tcm_qla2xxx_fabric.c | 51 +++++++------- drivers/target/tcm_qla2xxx/tcm_qla2xxx_fabric.h | 2 +- 6 files changed, 87 insertions(+), 74 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 0a7c9dd..1f760e0 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -4,9 +4,6 @@ * * See LICENSE.qla2xxx for copyright and licensing details. */ -#include "qla_def.h" -#include "qla_target.h" - #include <linux/moduleparam.h> #include <linux/vmalloc.h> #include <linux/delay.h> @@ -14,12 +11,15 @@ #include <linux/mutex.h> #include <linux/kobject.h> #include <linux/slab.h> - +#include <linux/workqueue.h> #include <scsi/scsi_tcq.h> #include <scsi/scsicam.h> #include <scsi/scsi_transport.h> #include <scsi/scsi_transport_fc.h> +#include "qla_def.h" +#include "qla_target.h" + /* * Driver version */ diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index 636ebfa..c9b2337 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -32,6 +32,7 @@ #include <linux/pci.h> #include <linux/delay.h> #include <linux/list.h> +#include <linux/workqueue.h> #include <asm/unaligned.h> #include <scsi/scsi.h> #include <scsi/scsi_host.h> @@ -116,9 +117,6 @@ static int qla_tgt_unreg_sess(struct qla_tgt_sess *sess); 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 DECLARE_RWSEM(qla_tgt_unreg_rwsem); - /* * From qla2xxx/qla_iobc.c and used by various qla_target.c logic */ @@ -3020,16 +3018,16 @@ static inline int qla_tgt_get_fcp_task_attr(uint8_t task_codes) /* ha->hardware_lock supposed to be held on entry */ /* This functions sends the ISP 2xxx command to the tcm_qla2xxx target */ -static int qla_tgt_2xxx_send_cmd_to_tcm(struct scsi_qla_host *vha, struct qla_tgt_cmd *cmd) +static int qla_tgt_2xxx_send_cmd(struct scsi_qla_host *vha, struct qla_tgt_cmd *cmd) { atio_from_isp_t *atio = &cmd->atio; uint32_t data_length; int fcp_task_attr, data_dir, bidi = 0, ret; - uint16_t lun, unpacked_lun; + uint16_t lun; /* make it be in network byte order */ lun = swab16(le16_to_cpu(atio->u.isp2x.lun)); - unpacked_lun = scsilun_to_int((struct scsi_lun *)&lun); + cmd->unpacked_lun = scsilun_to_int((struct scsi_lun *)&lun); cmd->tag = atio->u.isp2x.rx_id; if ((atio->u.isp2x.execution_codes & (ATIO_EXEC_READ | ATIO_EXEC_WRITE)) == @@ -3048,24 +3046,21 @@ static int qla_tgt_2xxx_send_cmd_to_tcm(struct scsi_qla_host *vha, struct qla_tg ql_dbg(ql_dbg_tgt_pkt, vha, 0xe207, "qla_target: START q2x command: %p" " lun: 0x%04x (tag %d)\n", cmd, lun, cmd->tag); - /* - * Dispatch command to tcm_qla2xxx fabric module code - */ - ret = vha->hw->tgt_ops->handle_cmd(vha, cmd, unpacked_lun, data_length, + return vha->hw->tgt_ops->handle_cmd(vha, cmd, data_length, fcp_task_attr, data_dir, bidi); - return ret; } /* ha->hardware_lock supposed to be held on entry */ /* This function sends the ISP 24xx command to the tcm_qla2xxx target */ -static int qla_tgt_24xx_send_cmd_to_tcm(struct scsi_qla_host *vha, struct qla_tgt_cmd *cmd) +static int qla_tgt_24xx_send_cmd(struct scsi_qla_host *vha, struct qla_tgt_cmd *cmd) { atio_from_isp_t *atio = &cmd->atio; - uint32_t unpacked_lun, data_length; + uint32_t data_length; int fcp_task_attr, data_dir, bidi = 0, ret; cmd->tag = atio->u.isp24.exchange_addr; - unpacked_lun = scsilun_to_int((struct scsi_lun *)&atio->u.isp24.fcp_cmnd.lun); + cmd->unpacked_lun = scsilun_to_int( + (struct scsi_lun *)&atio->u.isp24.fcp_cmnd.lun); if (atio->u.isp24.fcp_cmnd.rddata && atio->u.isp24.fcp_cmnd.wrdata) { bidi = 1; @@ -3082,13 +3077,10 @@ static int qla_tgt_24xx_send_cmd_to_tcm(struct scsi_qla_host *vha, struct qla_tg &atio->u.isp24.fcp_cmnd.add_cdb[atio->u.isp24.fcp_cmnd.add_cdb_len])); ql_dbg(ql_dbg_tgt_pkt, vha, 0xe208, "qla_target: START q24 Command %p" - " unpacked_lun: 0x%08x (tag %d)\n", cmd, unpacked_lun, cmd->tag); - /* - * Dispatch command to tcm_qla2xxx fabric module code - */ - ret = vha->hw->tgt_ops->handle_cmd(vha, cmd, unpacked_lun, data_length, + " unpacked_lun: 0x%08x (tag %d)\n", cmd, cmd->unpacked_lun, cmd->tag); + + return vha->hw->tgt_ops->handle_cmd(vha, cmd, data_length, fcp_task_attr, data_dir, bidi); - return ret; } /* ha->hardware_lock supposed to be held on entry */ @@ -3101,8 +3093,10 @@ static int qla_tgt_send_cmd_to_target(struct scsi_qla_host *vha, cmd->loop_id = sess->loop_id; cmd->conf_compl_supported = sess->conf_compl_supported; - return (IS_FWI2_CAPABLE(ha)) ? qla_tgt_24xx_send_cmd_to_tcm(vha, cmd) : - qla_tgt_2xxx_send_cmd_to_tcm(vha, cmd); + if (IS_FWI2_CAPABLE(ha)) + return qla_tgt_24xx_send_cmd(vha, cmd); + else + return qla_tgt_2xxx_send_cmd(vha, cmd); } /* ha->hardware_lock supposed to be held on entry */ @@ -4859,7 +4853,12 @@ int qla_tgt_add_target(struct qla_hw_data *ha, struct scsi_qla_host *base_vha) INIT_LIST_HEAD(&tgt->srr_imm_list); INIT_WORK(&tgt->srr_work, qla_tgt_handle_srr_work); atomic_set(&tgt->tgt_global_resets_count, 0); + + tgt->qla_tgt_wq = alloc_workqueue("qla_tgt_wq", WQ_UNBOUND, 0); + if (!tgt->qla_tgt_wq) + return -ENOMEM; + printk("Setup tgt->qla_tgt_wq: %p for qla_hw_data: %p\n", tgt->qla_tgt_wq, ha); ha->qla_tgt = tgt; if (IS_FWI2_CAPABLE(ha)) { @@ -4902,6 +4901,7 @@ int qla_tgt_remove_target(struct qla_hw_data *ha, struct scsi_qla_host *vha) "existing target", vha->vp_idx); return 0; } + destroy_workqueue(ha->qla_tgt->qla_tgt_wq); ql_dbg(ql_dbg_tgt, vha, 0xe037, "Unregistering target for host %ld(%p)", vha->host_no, ha); @@ -5393,9 +5393,7 @@ static int __init qla_tgt_parse_ini_mode(void) int __init qla_tgt_init(void) { - qla_tgt_cmd_cachep = NULL; - qla_tgt_mgmt_cmd_cachep = NULL; - qla_tgt_mgmt_cmd_mempool = NULL; + int ret; if (!qla_tgt_parse_ini_mode()) { printk(KERN_ERR "qla_tgt_parse_ini_mode() failed\n"); @@ -5414,29 +5412,31 @@ int __init qla_tgt_init(void) sizeof(struct qla_tgt_mgmt_cmd), __alignof__(struct qla_tgt_mgmt_cmd), 0, NULL); if (!qla_tgt_mgmt_cmd_cachep) { - printk(KERN_ERR "kmem_cache_create for qla_tgt_mgmt_cmd_cachep failed\n"); - kmem_cache_destroy(qla_tgt_cmd_cachep); - return -ENOMEM; + pr_warn(KERN_ERR "kmem_cache_create for qla_tgt_mgmt_cmd_cachep failed\n"); + ret = -ENOMEM; + goto out; } qla_tgt_mgmt_cmd_mempool = mempool_create(25, mempool_alloc_slab, mempool_free_slab, qla_tgt_mgmt_cmd_cachep); if (!qla_tgt_mgmt_cmd_mempool) { - printk(KERN_ERR "mempool_create for qla_tgt_mgmt_cmd_mempool failed\n"); - kmem_cache_destroy(qla_tgt_mgmt_cmd_cachep); - kmem_cache_destroy(qla_tgt_cmd_cachep); - return -ENOMEM; + pr_warn(KERN_ERR "mempool_create for qla_tgt_mgmt_cmd_mempool failed\n"); + ret = -ENOMEM; + goto out_mgmt_cmd_cachep; } return 0; + +out_mgmt_cmd_cachep: + kmem_cache_destroy(qla_tgt_mgmt_cmd_cachep); +out: + kmem_cache_destroy(qla_tgt_cmd_cachep); + return ret; } void __exit qla_tgt_exit(void) { - if (qla_tgt_mgmt_cmd_mempool != NULL) - mempool_destroy(qla_tgt_mgmt_cmd_mempool); - if (qla_tgt_mgmt_cmd_cachep != NULL) - kmem_cache_destroy(qla_tgt_mgmt_cmd_cachep); - if (qla_tgt_cmd_cachep != NULL) - kmem_cache_destroy(qla_tgt_cmd_cachep); + mempool_destroy(qla_tgt_mgmt_cmd_mempool); + kmem_cache_destroy(qla_tgt_mgmt_cmd_cachep); + kmem_cache_destroy(qla_tgt_cmd_cachep); } diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h index 9188e3e..3fcb912 100644 --- a/drivers/scsi/qla2xxx/qla_target.h +++ b/drivers/scsi/qla2xxx/qla_target.h @@ -720,7 +720,7 @@ struct qla_tgt_sess; */ struct qla_tgt_func_tmpl { - int (*handle_cmd)(struct scsi_qla_host *, struct qla_tgt_cmd *, uint32_t, + int (*handle_cmd)(struct scsi_qla_host *, struct qla_tgt_cmd *, uint32_t, int, int, int); int (*handle_data)(struct qla_tgt_cmd *); int (*handle_tmr)(struct qla_tgt_mgmt_cmd *, uint32_t, uint8_t); @@ -869,6 +869,7 @@ struct qla_tgt { spinlock_t sess_work_lock; struct list_head sess_works_list; struct work_struct sess_work; + struct workqueue_struct *qla_tgt_wq; imm_ntfy_from_isp_t link_reinit_iocb; wait_queue_head_t waitQ; @@ -921,6 +922,7 @@ struct qla_tgt_cmd { atomic_t cmd_free; struct completion cmd_stop_free_comp; struct se_cmd se_cmd; + struct work_struct free_work; struct work_struct work; /* Sense buffer that will be mapped into outgoing status */ unsigned char sense_buffer[TRANSPORT_SENSE_BUFFER]; @@ -937,6 +939,7 @@ struct qla_tgt_cmd { int bufflen; /* cmd buffer length */ int offset; uint32_t tag; + uint32_t unpacked_lun; dma_addr_t *srr_dma_buffer; /* Used for SRR offsets with pci_map_page() */ enum dma_data_direction dma_data_direction; diff --git a/drivers/target/tcm_qla2xxx/tcm_qla2xxx_configfs.c b/drivers/target/tcm_qla2xxx/tcm_qla2xxx_configfs.c index 97b6731..f4ee520 100644 --- a/drivers/target/tcm_qla2xxx/tcm_qla2xxx_configfs.c +++ b/drivers/target/tcm_qla2xxx/tcm_qla2xxx_configfs.c @@ -53,6 +53,7 @@ struct target_fabric_configfs *tcm_qla2xxx_fabric_configfs; struct target_fabric_configfs *tcm_qla2xxx_npiv_fabric_configfs; struct workqueue_struct *tcm_qla2xxx_free_wq; +struct workqueue_struct *tcm_qla2xxx_cmd_wq; static int tcm_qla2xxx_setup_nacl_from_rport( struct se_portal_group *se_tpg, @@ -1221,7 +1222,7 @@ static struct target_core_fabric_ops tcm_qla2xxx_ops = { .tpg_alloc_fabric_acl = tcm_qla2xxx_alloc_fabric_acl, .tpg_release_fabric_acl = tcm_qla2xxx_release_fabric_acl, .tpg_get_inst_index = tcm_qla2xxx_tpg_get_inst_index, - .new_cmd_map = tcm_qla2xxx_new_cmd_map, + .new_cmd_map = NULL, .check_stop_free = tcm_qla2xxx_check_stop_free, .check_release_cmd = tcm_qla2xxx_check_release_cmd, .release_cmd = tcm_qla2xxx_release_cmd, @@ -1402,11 +1403,21 @@ static int tcm_qla2xxx_register_configfs(void) tcm_qla2xxx_free_wq = alloc_workqueue("tcm_qla2xxx_free", WQ_MEM_RECLAIM, 0); - if (!tcm_qla2xxx_free_wq) + if (!tcm_qla2xxx_free_wq) { + ret = -ENOMEM; goto out_fabric_npiv; + } + + tcm_qla2xxx_cmd_wq = alloc_workqueue("tcm_qla2xxx_cmd", 0, 0); + if (!tcm_qla2xxx_cmd_wq) { + ret = -ENOMEM; + goto out_free_wq; + } return 0; +out_free_wq: + destroy_workqueue(tcm_qla2xxx_free_wq); out_fabric_npiv: target_fabric_configfs_deregister(tcm_qla2xxx_npiv_fabric_configfs); out_fabric: @@ -1416,9 +1427,7 @@ out_fabric: static void tcm_qla2xxx_deregister_configfs(void) { - if (!tcm_qla2xxx_fabric_configfs) - return; - + destroy_workqueue(tcm_qla2xxx_cmd_wq); destroy_workqueue(tcm_qla2xxx_free_wq); target_fabric_configfs_deregister(tcm_qla2xxx_fabric_configfs); diff --git a/drivers/target/tcm_qla2xxx/tcm_qla2xxx_fabric.c b/drivers/target/tcm_qla2xxx/tcm_qla2xxx_fabric.c index 159423c..a3e4ca3 100644 --- a/drivers/target/tcm_qla2xxx/tcm_qla2xxx_fabric.c +++ b/drivers/target/tcm_qla2xxx/tcm_qla2xxx_fabric.c @@ -53,6 +53,7 @@ #include "tcm_qla2xxx_fabric.h" extern struct workqueue_struct *tcm_qla2xxx_free_wq; +extern struct workqueue_struct *tcm_qla2xxx_cmd_wq; int tcm_qla2xxx_check_true(struct se_portal_group *se_tpg) { @@ -665,13 +666,15 @@ int tcm_qla2xxx_get_cmd_state(struct se_cmd *se_cmd) return 0; } +static void tcm_qla2xxx_do_work(struct work_struct *); + /* * Main entry point for incoming ATIO packets from qla_target.c * and qla2xxx LLD code. Called with qla_hw_data->hardware_lock held */ int tcm_qla2xxx_handle_cmd(scsi_qla_host_t *vha, struct qla_tgt_cmd *cmd, - uint32_t lun, uint32_t data_length, - int fcp_task_attr, int data_dir, int bidi) + uint32_t data_length, int fcp_task_attr, + int data_dir, int bidi) { struct se_cmd *se_cmd = &cmd->se_cmd; struct se_session *se_sess; @@ -706,49 +709,47 @@ int tcm_qla2xxx_handle_cmd(scsi_qla_host_t *vha, struct qla_tgt_cmd *cmd, */ if (bidi) se_cmd->t_tasks_bidi = 1; - /* - * Locate the struct se_lun pointer and attach it to struct se_cmd - */ - if (transport_lookup_cmd_lun(se_cmd, lun) < 0) { - /* - * Clear qla_tgt_cmd->locked_rsp as ha->hardware_lock - * is already held here, and we'll end up calling back - * into ->queue_status (tcm_qla2xxx_queue_status()) - * and hence qla_tgt_xmit_response(). - */ - cmd->locked_rsp = 0; - /* NON_EXISTENT_LUN */ - transport_send_check_condition_and_sense(se_cmd, - se_cmd->scsi_sense_reason, 0); - return 0; - } - /* - * Queue up the newly allocated to be processed in TCM thread context. - */ - transport_generic_handle_cdb_map(se_cmd); + INIT_WORK(&cmd->work, tcm_qla2xxx_do_work); + queue_work(cmd->tgt->qla_tgt_wq, &cmd->work); return 0; } -int tcm_qla2xxx_new_cmd_map(struct se_cmd *se_cmd) +void tcm_qla2xxx_do_work(struct work_struct *work) { - struct qla_tgt_cmd *cmd = container_of(se_cmd, struct qla_tgt_cmd, se_cmd); + struct qla_tgt_cmd *cmd = container_of(work, struct qla_tgt_cmd, work); + struct se_cmd *se_cmd = &cmd->se_cmd; scsi_qla_host_t *vha = cmd->vha; struct qla_hw_data *ha = vha->hw; unsigned char *cdb; atio_from_isp_t *atio = &cmd->atio; + int rc; if (IS_FWI2_CAPABLE(ha)) cdb = &atio->u.isp24.fcp_cmnd.cdb[0]; else cdb = &atio->u.isp2x.cdb[0]; + /* + * Locate se_lun pointer and attach it to struct se_cmd + */ + if (transport_lookup_cmd_lun(se_cmd, cmd->unpacked_lun) < 0) { + transport_send_check_condition_and_sense(se_cmd, + se_cmd->scsi_sense_reason, 0); + return; + } /* * Allocate the necessary tasks to complete the received CDB+data * drivers/target/target_core_transport.c:transport_processing_thread() * falls through to TRANSPORT_NEW_CMD. */ - return transport_generic_allocate_tasks(se_cmd, cdb); + rc = transport_generic_allocate_tasks(se_cmd, cdb); + if (rc != 0) { + transport_send_check_condition_and_sense(se_cmd, + se_cmd->scsi_sense_reason, 0); + return; + } + transport_handle_cdb_direct(se_cmd); } /* diff --git a/drivers/target/tcm_qla2xxx/tcm_qla2xxx_fabric.h b/drivers/target/tcm_qla2xxx/tcm_qla2xxx_fabric.h index e807a1e..ea1f5fb 100644 --- a/drivers/target/tcm_qla2xxx/tcm_qla2xxx_fabric.h +++ b/drivers/target/tcm_qla2xxx/tcm_qla2xxx_fabric.h @@ -40,7 +40,7 @@ extern void tcm_qla2xxx_set_default_node_attrs(struct se_node_acl *); extern u32 tcm_qla2xxx_get_task_tag(struct se_cmd *); extern int tcm_qla2xxx_get_cmd_state(struct se_cmd *); extern int tcm_qla2xxx_handle_cmd(struct scsi_qla_host *, struct qla_tgt_cmd *, - uint32_t, uint32_t, int, int, int); + uint32_t, int, int, int); extern int tcm_qla2xxx_new_cmd_map(struct se_cmd *); extern int tcm_qla2xxx_handle_data(struct qla_tgt_cmd *); extern int tcm_qla2xxx_handle_tmr(struct qla_tgt_mgmt_cmd *, uint32_t, uint8_t); -- 1.7.2.5 -- To unsubscribe from this list: send the line "unsubscribe target-devel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html