From: Chenguangli chenguangli2@huawei.com
driver inclusion category: feature bugzilla: NA
-----------------------------------------------------------------------
This module is used to register the hifc driver FC capability to the SCSI layer.
Signed-off-by: Chenguangli chenguangli2@huawei.com Reviewed-by: Zengweiliang zengweiliang.zengweiliang@huawei.com Acked-by: Hanjun Guo guohanjun@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- drivers/scsi/huawei/hifc/hifc_knl_adp.h | 48 + drivers/scsi/huawei/hifc/hifc_module.c | 104 ++ drivers/scsi/huawei/hifc/hifc_module.h | 289 +++ drivers/scsi/huawei/hifc/hifc_utils.c | 72 + drivers/scsi/huawei/hifc/hifc_utils.h | 361 ++++ drivers/scsi/huawei/hifc/unf_common.h | 1893 ++++++++++++++++++++ drivers/scsi/huawei/hifc/unf_init.c | 564 ++++++ drivers/scsi/huawei/hifc/unf_log.h | 183 ++ drivers/scsi/huawei/hifc/unf_scsi.c | 1556 ++++++++++++++++ drivers/scsi/huawei/hifc/unf_scsi_common.h | 1136 ++++++++++++ 10 files changed, 6206 insertions(+) create mode 100644 drivers/scsi/huawei/hifc/hifc_knl_adp.h create mode 100644 drivers/scsi/huawei/hifc/hifc_module.c create mode 100644 drivers/scsi/huawei/hifc/hifc_module.h create mode 100644 drivers/scsi/huawei/hifc/hifc_utils.c create mode 100644 drivers/scsi/huawei/hifc/hifc_utils.h create mode 100644 drivers/scsi/huawei/hifc/unf_common.h create mode 100644 drivers/scsi/huawei/hifc/unf_init.c create mode 100644 drivers/scsi/huawei/hifc/unf_log.h create mode 100644 drivers/scsi/huawei/hifc/unf_scsi.c create mode 100644 drivers/scsi/huawei/hifc/unf_scsi_common.h
diff --git a/drivers/scsi/huawei/hifc/hifc_knl_adp.h b/drivers/scsi/huawei/hifc/hifc_knl_adp.h new file mode 100644 index 000000000000..5b05ff6eb9bd --- /dev/null +++ b/drivers/scsi/huawei/hifc/hifc_knl_adp.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Huawei Hifc PCI Express Linux driver + * Copyright(c) 2017 Huawei Technologies Co., Ltd + * + */ + +#ifndef HIFC_KNL_ADP_H_ +#define HIFC_KNL_ADP_H_ + +#include <linux/types.h> +#include <linux/compiler.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/interrupt.h> +#include <linux/jiffies.h> +#include <linux/cpufreq.h> +#include <linux/semaphore.h> +#include <linux/sched.h> +#include <linux/kthread.h> +#include <linux/vmalloc.h> +#include <linux/version.h> +#include <linux/list.h> +#include <linux/spinlock.h> +#include <linux/delay.h> +#include <linux/workqueue.h> +#include <linux/scatterlist.h> +#include <scsi/scsi.h> +#include <scsi/scsi_host.h> +#include <scsi/scsi_device.h> +#include <scsi/scsi_cmnd.h> +#include <scsi/scsi_tcq.h> +#include <scsi/scsi_transport_fc.h> +#include <linux/sched/signal.h> + +#define __TIME_STR__ "[compiled with the kernel]" + +#define sdk_err(dev, format, ...) \ + dev_err(dev, "[COMM]"format, ##__VA_ARGS__) +#define sdk_warn(dev, format, ...) \ + dev_warn(dev, "[COMM]"format, ##__VA_ARGS__) +#define sdk_notice(dev, format, ...) \ + dev_notice(dev, "[COMM]"format, ##__VA_ARGS__) +#define sdk_info(dev, format, ...) \ + dev_info(dev, "[COMM]"format, ##__VA_ARGS__) + +#endif diff --git a/drivers/scsi/huawei/hifc/hifc_module.c b/drivers/scsi/huawei/hifc/hifc_module.c new file mode 100644 index 000000000000..127e8f9de9ea --- /dev/null +++ b/drivers/scsi/huawei/hifc/hifc_module.c @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Huawei Hifc PCI Express Linux driver + * Copyright(c) 2017 Huawei Technologies Co., Ltd + * + */ + +#include "hifc_module.h" + +struct unf_cm_handle_op_s hifc_cm_handle = { 0 }; +unsigned int dif_sgl_mode; +unsigned int max_speed = HIFC_SPEED_32G; +unsigned int accum_db_num = 1; +unsigned int dif_type = 0x1; +unsigned int wqe_page_size = 4096; +unsigned int wqe_pre_load = 6; +unsigned int combo_length_kb = 8; +unsigned int cos_bit_map = 0x1f; +unsigned int hifc_dif_type; +unsigned int hifc_dif_enable; +unsigned char hifc_guard; + +/* dfx counter */ +atomic64_t rx_tx_stat[HIFC_MAX_PORT_NUM][HIFC_TASK_TYPE_STAT_NUM]; +atomic64_t rx_tx_err[HIFC_MAX_PORT_NUM][HIFC_TASK_TYPE_STAT_NUM]; +atomic64_t scq_err_stat[HIFC_MAX_PORT_NUM][HIFC_TASK_TYPE_STAT_NUM]; +atomic64_t aeq_err_stat[HIFC_MAX_PORT_NUM][HIFC_TASK_TYPE_STAT_NUM]; +atomic64_t dif_err_stat[HIFC_MAX_PORT_NUM][HIFC_TASK_TYPE_STAT_NUM]; +atomic64_t mail_box_stat[HIFC_MAX_PORT_NUM][HIFC_TASK_TYPE_STAT_NUM]; +atomic64_t up_err_event_stat[HIFC_MAX_PORT_NUM][HIFC_TASK_TYPE_STAT_NUM]; +unsigned long long link_event_stat[HIFC_MAX_PORT_NUM][HIFC_MAX_LINK_EVENT_CNT]; +unsigned long long link_reason_stat[HIFC_MAX_PORT_NUM][HIFC_MAX_LINK_REASON_CNT]; +unsigned long long hba_stat[HIFC_MAX_PORT_NUM][HIFC_HBA_STAT_BUTT]; +atomic64_t com_up_event_err_stat[HIFC_MAX_PORT_NUM][HIFC_TASK_TYPE_STAT_NUM]; + +static void hifc_realease_cmo_op_handle(void) +{ + memset(&hifc_cm_handle, 0, sizeof(struct unf_cm_handle_op_s)); +} + +static void hifc_check_module_para(void) +{ + if (dif_sgl_mode != 0) + dif_sgl_mode = 1; +} + +int hifc_init_module(void) +{ + int ret = RETURN_OK; + + ret = unf_common_init(); + if (ret != RETURN_OK) { + UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_REG_ATT, UNF_ERR, + "[err]unf_common_init failed"); + + return RETURN_ERROR_S32; + } + + memset(rx_tx_stat, 0, sizeof(rx_tx_stat)); + memset(rx_tx_err, 0, sizeof(rx_tx_err)); + memset(scq_err_stat, 0, sizeof(scq_err_stat)); + memset(aeq_err_stat, 0, sizeof(aeq_err_stat)); + memset(dif_err_stat, 0, sizeof(dif_err_stat)); + memset(link_event_stat, 0, sizeof(link_event_stat)); + memset(link_reason_stat, 0, sizeof(link_reason_stat)); + memset(hba_stat, 0, sizeof(hba_stat)); + memset(&hifc_cm_handle, 0, sizeof(struct unf_cm_handle_op_s)); + memset(up_err_event_stat, 0, sizeof(up_err_event_stat)); + memset(mail_box_stat, 0, sizeof(mail_box_stat)); + memset(hifc_hba, 0, sizeof(hifc_hba)); + + spin_lock_init(&probe_spin_lock); + + /* 2. Module parameters check */ + hifc_check_module_para(); + + /* 4. Get COM Handlers used for low_level */ + if (unf_get_cm_handle_op(&hifc_cm_handle) != RETURN_OK) { + hifc_realease_cmo_op_handle(); + return RETURN_ERROR_S32; + } + + HIFC_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_KEVENT, + "[event]Init HIFC module succeed"); + + return ret; +} + +void hifc_exit_module(void) +{ + HIFC_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_MAJOR, + "[event]HIFC module removing..."); + + hifc_realease_cmo_op_handle(); + + /* 2. Unregister FC COM module(level) */ + unf_common_exit(); +} + +module_param(dif_sgl_mode, uint, 0444); +module_param(max_speed, uint, 0444); +module_param(wqe_page_size, uint, 0444); +module_param(combo_length_kb, uint, 0444); +module_param(cos_bit_map, uint, 0444); + diff --git a/drivers/scsi/huawei/hifc/hifc_module.h b/drivers/scsi/huawei/hifc/hifc_module.h new file mode 100644 index 000000000000..5ae9a4962495 --- /dev/null +++ b/drivers/scsi/huawei/hifc/hifc_module.h @@ -0,0 +1,289 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Huawei Hifc PCI Express Linux driver + * Copyright(c) 2017 Huawei Technologies Co., Ltd + * + */ + +#ifndef __HIFC_MODULE_H__ +#define __HIFC_MODULE_H__ +#include "unf_log.h" +#include "unf_common.h" +#include "hifc_utils.h" +#include "hifc_hba.h" + +#define HIFC_SPEED_16G 0x10 +#define HIFC_SPEED_32G 0x20 +#define HIFC_MAX_PORT_NUM HIFC_MAX_PROBE_PORT_NUM +#define HIFC_TASK_TYPE_STAT_NUM 128 +#define HIFC_MAX_LINK_EVENT_CNT 4 +#define HIFC_MAX_LINK_REASON_CNT 256 + +/* Declare the global function. */ +extern struct unf_cm_handle_op_s hifc_cm_handle; +extern unsigned int max_speed; +extern unsigned int accum_db_num; +extern unsigned int wqe_page_size; +extern unsigned int dif_type; +extern unsigned int wqe_pre_load; +extern unsigned int combo_length_kb; +extern unsigned int cos_bit_map; + +extern atomic64_t rx_tx_stat[HIFC_MAX_PORT_NUM][HIFC_TASK_TYPE_STAT_NUM]; +extern atomic64_t rx_tx_err[HIFC_MAX_PORT_NUM][HIFC_TASK_TYPE_STAT_NUM]; +extern atomic64_t scq_err_stat[HIFC_MAX_PORT_NUM][HIFC_TASK_TYPE_STAT_NUM]; +extern atomic64_t aeq_err_stat[HIFC_MAX_PORT_NUM][HIFC_TASK_TYPE_STAT_NUM]; +extern atomic64_t dif_err_stat[HIFC_MAX_PORT_NUM][HIFC_TASK_TYPE_STAT_NUM]; +extern atomic64_t mail_box_stat[HIFC_MAX_PORT_NUM][HIFC_TASK_TYPE_STAT_NUM]; +extern atomic64_t com_up_event_err_stat[HIFC_MAX_PORT_NUM][HIFC_TASK_TYPE_STAT_NUM]; +extern unsigned long long link_event_stat[HIFC_MAX_PORT_NUM][HIFC_MAX_LINK_EVENT_CNT]; +extern unsigned long long link_reason_stat[HIFC_MAX_PORT_NUM][HIFC_MAX_LINK_REASON_CNT]; +extern atomic64_t up_err_event_stat[HIFC_MAX_PORT_NUM][HIFC_TASK_TYPE_STAT_NUM]; +extern unsigned long long hba_stat[HIFC_MAX_PORT_NUM][HIFC_HBA_STAT_BUTT]; + +#define HIFC_LINK_EVENT_STAT(v_hba, link_ent) \ + (link_event_stat[(v_hba)->probe_index][link_ent]++) +#define HIFC_LINK_REASON_STAT(v_hba, link_rsn) \ + (link_reason_stat[(v_hba)->probe_index][link_rsn]++) +#define HIFC_HBA_STAT(v_hba, hba_stat_type) \ + (hba_stat[(v_hba)->probe_index][hba_stat_type]++) + +#define HIFC_UP_ERR_EVENT_STAT(v_hba, err_type) \ + (atomic64_inc(&up_err_event_stat[(v_hba)->probe_index][err_type])) +#define HIFC_UP_ERR_EVENT_STAT_READ(probe_index, io_type) \ + (atomic64_read(&up_err_event_stat[probe_index][io_type])) +#define HIFC_DIF_ERR_STAT(v_hba, dif_err) \ + (atomic64_inc(&dif_err_stat[(v_hba)->probe_index][dif_err])) +#define HIFC_DIF_ERR_STAT_READ(probe_index, dif_err) \ + (atomic64_read(&dif_err_stat[probe_index][dif_err])) + +#define HIFC_IO_STAT(v_hba, io_type) \ + (atomic64_inc(&rx_tx_stat[(v_hba)->probe_index][io_type])) +#define HIFC_IO_STAT_READ(probe_index, io_type) \ + (atomic64_read(&rx_tx_stat[probe_index][io_type])) + +#define HIFC_ERR_IO_STAT(v_hba, io_type) \ + (atomic64_inc(&rx_tx_err[(v_hba)->probe_index][io_type])) +#define HIFC_ERR_IO_STAT_READ(probe_index, io_type) \ + (atomic64_read(&rx_tx_err[probe_index][io_type])) + +#define HIFC_SCQ_ERR_TYPE_STAT(v_hba, err_type) \ + (atomic64_inc(&scq_err_stat[(v_hba)->probe_index][err_type])) +#define HIFC_SCQ_ERR_TYPE_STAT_READ(probe_index, io_type) \ + (atomic64_read(&scq_err_stat[probe_index][io_type])) +#define HIFC_AEQ_ERR_TYPE_STAT(v_hba, err_type) \ + (atomic64_inc(&aeq_err_stat[(v_hba)->probe_index][err_type])) +#define HIFC_AEQ_ERR_TYPE_STAT_READ(probe_index, io_type) \ + (atomic64_read(&aeq_err_stat[probe_index][io_type])) + +#define HIFC_MAILBOX_STAT(v_hba, io_type) \ + (atomic64_inc(&mail_box_stat[(v_hba)->probe_index][io_type])) + +#define HIFC_COM_UP_ERR_EVENT_STAT(v_hba, err_type) \ + (atomic64_inc(&com_up_event_err_stat[(v_hba)->probe_index][err_type])) +#define HIFC_COM_UP_ERR_EVENT_STAT_READ(probe_index, err_type) \ + (atomic64_read(&com_up_event_err_stat[probe_index][err_type])) + +/* + *----------------------------------------------* + * Define function * + *---------------------------------------------- + */ + +#define UNF_LOWLEVEL_ALLOC_LPORT(v_lport, fc_port, stLowLevel)\ + do {\ + if (hifc_cm_handle.pfn_unf_alloc_local_port) { \ + v_lport = \ + hifc_cm_handle.pfn_unf_alloc_local_port((fc_port), \ + (stLowLevel));\ + } else { \ + v_lport = NULL; \ + } \ + } while (0) + +#define UNF_LOWLEVEL_RECEIVE_ELS_PKG(v_ret, fc_port, pkg) \ + do { \ + if (hifc_cm_handle.pfn_unf_receive_els_pkg) {\ + v_ret =\ + hifc_cm_handle.pfn_unf_receive_els_pkg(\ + (fc_port), (pkg));\ + } else { \ + v_ret = UNF_RETURN_ERROR; \ + } \ + } while (0) + +#define UNF_LOWLEVEL_SEND_ELS_DONE(v_ret, fc_port, pkg) \ + do { \ + if (hifc_cm_handle.pfn_unf_send_els_done) {\ + v_ret = hifc_cm_handle.pfn_unf_send_els_done((fc_port),\ + (pkg)); \ + } else { \ + v_ret = UNF_RETURN_ERROR; \ + } \ + } while (0) + +#define UNF_LOWLEVEL_RECEIVE_GS_PKG(v_ret, fc_port, pkg)\ + do { \ + if (hifc_cm_handle.pfn_unf_receive_gs_pkg) {\ + v_ret = hifc_cm_handle.pfn_unf_receive_gs_pkg(\ + (fc_port),\ + (pkg)); \ + } else { \ + v_ret = UNF_RETURN_ERROR; \ + } \ + } while (0) + +#define UNF_LOWLEVEL_GET_CFG_PARMS(v_ret, \ + v_section_name, \ + v_cfg_parm, \ + v_cfg_value, \ + v_item_num) \ + do { \ + if (hifc_cm_handle.pfn_unf_get_cfg_parms) { \ + v_ret = (unsigned int)\ + hifc_cm_handle.pfn_unf_get_cfg_parms(\ + (v_section_name), \ + (v_cfg_parm), \ + (v_cfg_value), \ + (v_item_num)); \ + } else { \ + HIFC_TRACE(UNF_EVTLOG_DRIVER_WARN, UNF_LOG_REG_ATT,\ + UNF_WARN,\ + "Get config parameter function is NULL.");\ + v_ret = UNF_RETURN_ERROR; \ + } \ + } while (0) + +#define UNF_LOWLEVEL_RELEASE_LOCAL_PORT(v_ret, lport) \ + do { \ + if (unlikely(!hifc_cm_handle.pfn_unf_release_local_port)) {\ + v_ret = UNF_RETURN_ERROR; \ + } else { \ + v_ret =\ + hifc_cm_handle.pfn_unf_release_local_port(\ + (lport));\ + } \ + } while (0) + +#define UNF_LOWLEVEL_TO_CM_HINICADM(v_ret, lport, pkg) \ + do { \ + if (unlikely(!hifc_cm_handle.pfn_unf_ioctl_to_com_handler)) {\ + v_ret = UNF_RETURN_ERROR; \ + } else { \ + v_ret = hifc_cm_handle.pfn_unf_ioctl_to_com_handler(\ + lport, pkg); \ + } \ + } while (0) + +#define UNF_CM_GET_SGL_ENTRY(v_ret, pkg, v_buf, v_buf_len) \ + do { \ + if (unlikely(!hifc_cm_handle.pfn_unf_cm_get_sgl_entry)) {\ + v_ret = UNF_RETURN_ERROR; \ + } else { \ + v_ret = hifc_cm_handle.pfn_unf_cm_get_sgl_entry(\ + pkg, v_buf, v_buf_len);\ + } \ + } while (0) + +#define UNF_CM_GET_DIF_SGL_ENTRY(v_ret, pkg, v_buf, v_buf_len)\ + do { \ + if (unlikely(!hifc_cm_handle.pfn_unf_cm_get_dif_sgl_entry)) {\ + v_ret = UNF_RETURN_ERROR; \ + } else { \ + v_ret = hifc_cm_handle.pfn_unf_cm_get_dif_sgl_entry(\ + pkg,\ + v_buf,\ + v_buf_len);\ + } \ + } while (0) + +#define UNF_GET_SGL_ENTRY(v_ret, pkg, v_buf, v_buf_len, v_dif_flag) \ + do { \ + if (v_dif_flag) { \ + UNF_CM_GET_DIF_SGL_ENTRY(v_ret, pkg, v_buf, v_buf_len);\ + } else { \ + UNF_CM_GET_SGL_ENTRY(v_ret, pkg, v_buf, v_buf_len);\ + } \ + } while (0) + +#define UNF_GET_FREE_ESGL_PAGE(v_ret, lport, pkg) \ + do { \ + if (unlikely(!hifc_cm_handle.pfn_unf_get_one_free_esgl_page)) {\ + v_ret = NULL; \ + } else { \ + v_ret = hifc_cm_handle.pfn_unf_get_one_free_esgl_page(\ + lport, pkg); \ + } \ + } while (0) + +#define UNF_LOWLEVEL_SCSI_COMPLETED(v_ret, lport, pkg) \ + do { \ + if (unlikely(!hifc_cm_handle.pfn_unf_receive_ini_rsponse)) {\ + v_ret = UNF_RETURN_ERROR; \ + } else { \ + v_ret = hifc_cm_handle.pfn_unf_receive_ini_rsponse(\ + lport, pkg);\ + } \ + } while (0) + +#define UNF_LOWLEVEL_PORT_EVENT(v_ret, lport, v_events, v_input)\ + do { \ + if (unlikely(!hifc_cm_handle.pfn_unf_fc_port_link_event)) {\ + v_ret = UNF_RETURN_ERROR; \ + } else { \ + v_ret = hifc_cm_handle.pfn_unf_fc_port_link_event(\ + lport, v_events, v_input);\ + } \ + } while (0) + +#define UNF_LOWLEVEL_RECEIVE_FC4LS_PKG(v_ret, fc_port, pkg)\ + do { \ + if (hifc_cm_handle.pfn_unf_receive_fc4_pkg) {\ + v_ret = hifc_cm_handle.pfn_unf_receive_fc4_pkg(\ + (fc_port), (pkg));\ + } else { \ + v_ret = UNF_RETURN_ERROR; \ + } \ + } while (0) + +#define UNF_LOWLEVEL_SEND_FC4LS_DONE(v_ret, lport, pkg) \ + do { \ + if (hifc_cm_handle.pfn_unf_send_fc4_done) {\ + v_ret = hifc_cm_handle.pfn_unf_send_fc4_done(\ + (lport), (pkg));\ + } else { \ + v_ret = UNF_RETURN_ERROR; \ + } \ + } while (0) + +#define UNF_LOWLEVEL_RECEIVE_BLS_PKG(v_ret, lport, pkg) \ + do { \ + if (hifc_cm_handle.pfn_unf_receive_bls_pkg) {\ + v_ret = hifc_cm_handle.pfn_unf_receive_bls_pkg(\ + (lport), (pkg)); \ + } else { \ + v_ret = UNF_RETURN_ERROR; \ + } \ + } while (0) + +#define UNF_LOWLEVEL_RECEIVE_MARKER_STS(v_ret, lport, pkg)\ + do { \ + if (hifc_cm_handle.pfn_unf_receive_marker_status) {\ + v_ret = hifc_cm_handle.pfn_unf_receive_marker_status(\ + (lport), (pkg));\ + } else { \ + v_ret = UNF_RETURN_ERROR; \ + } \ + } while (0) + +#define UNF_LOWLEVEL_RECEIVE_ABTS_MARKER_STS(v_ret, lport, pkg) \ + do { \ + if (hifc_cm_handle.pfn_unf_receive_abts_marker_status) {\ + v_ret =\ + hifc_cm_handle.pfn_unf_receive_abts_marker_status(\ + (lport), (pkg));\ + } else { \ + v_ret = UNF_RETURN_ERROR; \ + } \ + } while (0) + +#endif diff --git a/drivers/scsi/huawei/hifc/hifc_utils.c b/drivers/scsi/huawei/hifc/hifc_utils.c new file mode 100644 index 000000000000..c2c6ef1fe120 --- /dev/null +++ b/drivers/scsi/huawei/hifc/hifc_utils.c @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Huawei Hifc PCI Express Linux driver + * Copyright(c) 2017 Huawei Technologies Co., Ltd + * + */ +#include "hifc_utils.h" +#include "unf_log.h" +#include "unf_common.h" + +void hifc_cpu_to_big64(void *v_addr, unsigned int size) +{ + unsigned int index = 0; + unsigned int cnt = 0; + unsigned long long *temp = NULL; + + UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, + v_addr, dump_stack(); return); + UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, + (size % HIFC_QWORD_BYTE) == 0, dump_stack(); return); + + temp = (unsigned long long *)v_addr; + cnt = HIFC_SHIFT_TO_U64(size); + + for (index = 0; index < cnt; index++) { + *temp = cpu_to_be64(*temp); + temp++; + } +} + +void hifc_big_to_cpu64(void *v_addr, unsigned int size) +{ + unsigned int index = 0; + unsigned int cnt = 0; + unsigned long long *tmp = NULL; + + UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, + v_addr, dump_stack(); return); + UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, + (size % HIFC_QWORD_BYTE) == 0, dump_stack(); return); + + tmp = (unsigned long long *)v_addr; + cnt = HIFC_SHIFT_TO_U64(size); + + for (index = 0; index < cnt; index++) { + *tmp = be64_to_cpu(*tmp); + tmp++; + } +} + +void hifc_cpu_to_big32(void *v_addr, unsigned int size) +{ + unf_cpu_to_big_end(v_addr, size); +} + +void hifc_big_to_cpu32(void *v_addr, unsigned int size) +{ + if (size % UNF_BYTES_OF_DWORD) + dump_stack(); + unf_big_end_to_cpu(v_addr, size); +} + +unsigned int hifc_log2n(unsigned int val) +{ + unsigned int result = 0; + unsigned int logn = (val >> 1); + + while (logn) { + logn >>= 1; + result++; + } + return result; +} diff --git a/drivers/scsi/huawei/hifc/hifc_utils.h b/drivers/scsi/huawei/hifc/hifc_utils.h new file mode 100644 index 000000000000..548e5c9bb95d --- /dev/null +++ b/drivers/scsi/huawei/hifc/hifc_utils.h @@ -0,0 +1,361 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Huawei Hifc PCI Express Linux driver + * Copyright(c) 2017 Huawei Technologies Co., Ltd + * + */ + +#ifndef __HIFC_UTILS_H__ +#define __HIFC_UTILS_H__ + +#define UNF_ZERO 0 +#define HIFC_BIT(n) (0x1UL << (n)) +#define HIFC_BIT_0 HIFC_BIT(0) +#define HIFC_BIT_1 HIFC_BIT(1) +#define HIFC_BIT_2 HIFC_BIT(2) +#define HIFC_BIT_3 HIFC_BIT(3) +#define HIFC_BIT_4 HIFC_BIT(4) +#define HIFC_BIT_5 HIFC_BIT(5) +#define HIFC_BIT_6 HIFC_BIT(6) +#define HIFC_BIT_7 HIFC_BIT(7) +#define HIFC_BIT_8 HIFC_BIT(8) +#define HIFC_BIT_9 HIFC_BIT(9) +#define HIFC_BIT_10 HIFC_BIT(10) +#define HIFC_BIT_11 HIFC_BIT(11) +#define HIFC_BIT_12 HIFC_BIT(12) +#define HIFC_BIT_13 HIFC_BIT(13) +#define HIFC_BIT_14 HIFC_BIT(14) +#define HIFC_BIT_15 HIFC_BIT(15) +#define HIFC_BIT_16 HIFC_BIT(16) +#define HIFC_BIT_17 HIFC_BIT(17) +#define HIFC_BIT_18 HIFC_BIT(18) +#define HIFC_BIT_19 HIFC_BIT(19) +#define HIFC_BIT_20 HIFC_BIT(20) +#define HIFC_BIT_21 HIFC_BIT(21) +#define HIFC_BIT_22 HIFC_BIT(22) +#define HIFC_BIT_23 HIFC_BIT(23) +#define HIFC_BIT_24 HIFC_BIT(24) +#define HIFC_BIT_25 HIFC_BIT(25) +#define HIFC_BIT_26 HIFC_BIT(26) +#define HIFC_BIT_27 HIFC_BIT(27) +#define HIFC_BIT_28 HIFC_BIT(28) +#define HIFC_BIT_29 HIFC_BIT(29) +#define HIFC_BIT_30 HIFC_BIT(30) +#define HIFC_BIT_31 HIFC_BIT(31) + +#define HIFC_GET_BITS(data, mask) ((data) & (mask)) /* Obtains the bit */ +#define HIFC_SET_BITS(data, mask) ((data) |= (mask)) /* set the bit */ +#define HIFC_CLR_BITS(data, mask) ((data) &= ~(mask)) /* clear the bit */ + +/* Byte alignment */ +#define HIFC_ALIGN_N(n) __attribute__((__packed, __aligned(n))) +#define HIFC_ALIGN_1 HIFC_ALIGN_N(1) +#define HIFC_ALIGN_2 HIFC_ALIGN_N(2) +#define HIFC_ALIGN_4 HIFC_ALIGN_N(4) +#define HIFC_ALIGN_8 HIFC_ALIGN_N(8) + +#define HIFC_ADJUST_ALIGN_4(n) ((n) - (n) % 4) + +#define HIFC_LSB(x) ((unsigned char)(x)) +#define HIFC_MSB(x) ((unsigned char)((unsigned short)(x) >> 8)) + +#define HIFC_LSW(x) ((unsigned short)(x)) +#define HIFC_MSW(x) ((unsigned short)((unsigned int)(x) >> 16)) + +#define HIFC_LSD(x) ((unsigned int)((unsigned long long)(x))) +#define HIFC_MSD(x) ((unsigned int)((((unsigned long long)(x)) >> 16) >> 16)) + +#define HIFC_BYTES_TO_QW_NUM(x) ((x) >> 3) +#define HIFC_BYTES_TO_DW_NUM(x) ((x) >> 2) + +#define UNF_GET_SHIFTMASK(__src, __shift, __mask) \ + (((__src) & (__mask)) >> (__shift)) +#define UNF_FC_SET_SHIFTMASK(__des, __val, __shift, __mask)\ + ((__des) = \ + (((__des) & ~(__mask)) | (((__val) << (__shift)) & (__mask)))) + +/* D_ID */ +#define UNF_FC_HEADER_DID_MASK 0x00FFFFFF +#define UNF_FC_HEADER_DID_SHIFT 0 +#define UNF_FC_HEADER_DID_DWORD 0 +#define UNF_GET_FC_HEADER_DID(__pfcheader)\ + UNF_GET_SHIFTMASK(\ + ((unsigned int *)(void *)__pfcheader)[UNF_FC_HEADER_DID_DWORD],\ + UNF_FC_HEADER_DID_SHIFT, UNF_FC_HEADER_DID_MASK) + +#define UNF_SET_FC_HEADER_DID(__pfcheader, __val)\ + UNF_FC_SET_SHIFTMASK(\ + ((unsigned int *)(void *)__pfcheader)[UNF_FC_HEADER_DID_DWORD],\ + __val, UNF_FC_HEADER_DID_SHIFT, UNF_FC_HEADER_DID_MASK) + +/* R_CTL */ +#define UNF_FC_HEADER_RCTL_MASK 0xFF000000 +#define UNF_FC_HEADER_RCTL_SHIFT 24 +#define UNF_FC_HEADER_RCTL_DWORD 0 +#define UNF_GET_FC_HEADER_RCTL(__pfcheader)\ + UNF_GET_SHIFTMASK(\ + ((unsigned int *)(void *)__pfcheader)[UNF_FC_HEADER_RCTL_DWORD],\ + UNF_FC_HEADER_RCTL_SHIFT, UNF_FC_HEADER_RCTL_MASK) + +#define UNF_SET_FC_HEADER_RCTL(__pfcheader, __val)\ + UNF_FC_SET_SHIFTMASK(\ + ((unsigned int *)(void *)__pfcheader)[UNF_FC_HEADER_RCTL_DWORD],\ + __val, UNF_FC_HEADER_RCTL_SHIFT, UNF_FC_HEADER_RCTL_MASK) + +/* S_ID */ +#define UNF_FC_HEADER_SID_MASK 0x00FFFFFF +#define UNF_FC_HEADER_SID_SHIFT 0 +#define UNF_FC_HEADER_SID_DWORD 1 +#define UNF_GET_FC_HEADER_SID(__pfcheader)\ + UNF_GET_SHIFTMASK(\ + ((unsigned int *)(void *)__pfcheader)[UNF_FC_HEADER_SID_DWORD],\ + UNF_FC_HEADER_SID_SHIFT, UNF_FC_HEADER_SID_MASK) +#define UNF_SET_FC_HEADER_SID(__pfcheader, __val)\ + UNF_FC_SET_SHIFTMASK(\ + ((unsigned int *)(void *)__pfcheader)[UNF_FC_HEADER_SID_DWORD],\ + __val, UNF_FC_HEADER_SID_SHIFT, UNF_FC_HEADER_SID_MASK) + +/* CS_CTL */ +#define UNF_FC_HEADER_CS_CTL_MASK 0xFF000000 +#define UNF_FC_HEADER_CS_CTL_SHIFT 24 +#define UNF_FC_HEADER_CS_CTL_DWORD 1 +#define UNF_GET_FC_HEADER_CS_CTL(__pfcheader)\ + UNF_GET_SHIFTMASK(\ + ((unsigned int *)(void *)__pfcheader)[UNF_FC_HEADER_CS_CTL_DWORD],\ + UNF_FC_HEADER_CS_CTL_SHIFT, UNF_FC_HEADER_CS_CTL_MASK) + +#define UNF_SET_FC_HEADER_CS_CTL(__pfcheader, __val)\ + UNF_FC_SET_SHIFTMASK(\ + ((unsigned int *)(void *)__pfcheader)[UNF_FC_HEADER_CS_CTL_DWORD],\ + __val, UNF_FC_HEADER_CS_CTL_SHIFT, UNF_FC_HEADER_CS_CTL_MASK) + +/* F_CTL */ +#define UNF_FC_HEADER_FCTL_MASK 0x00FFFFFF +#define UNF_FC_HEADER_FCTL_SHIFT 0 +#define UNF_FC_HEADER_FCTL_DWORD 2 +#define UNF_GET_FC_HEADER_FCTL(__pfcheader)\ + UNF_GET_SHIFTMASK(\ + ((unsigned int *)(void *)__pfcheader)[UNF_FC_HEADER_FCTL_DWORD],\ + UNF_FC_HEADER_FCTL_SHIFT, UNF_FC_HEADER_FCTL_MASK) +#define UNF_SET_FC_HEADER_FCTL(__pfcheader, __val)\ + UNF_FC_SET_SHIFTMASK(\ + ((unsigned int *)(void *)__pfcheader)[UNF_FC_HEADER_FCTL_DWORD],\ + __val, UNF_FC_HEADER_FCTL_SHIFT, UNF_FC_HEADER_FCTL_MASK) + +/* TYPE */ +#define UNF_FC_HEADER_TYPE_MASK 0xFF000000 +#define UNF_FC_HEADER_TYPE_SHIFT 24 +#define UNF_FC_HEADER_TYPE_DWORD 2 +#define UNF_GET_FC_HEADER_TYPE(__pfcheader)\ + UNF_GET_SHIFTMASK(\ + ((unsigned int *)(void *)__pfcheader)[UNF_FC_HEADER_TYPE_DWORD],\ + UNF_FC_HEADER_TYPE_SHIFT, UNF_FC_HEADER_TYPE_MASK) + +#define UNF_SET_FC_HEADER_TYPE(__pfcheader, __val)\ + UNF_FC_SET_SHIFTMASK(\ + ((unsigned int *)(void *)__pfcheader)[UNF_FC_HEADER_TYPE_DWORD],\ + __val, UNF_FC_HEADER_TYPE_SHIFT, UNF_FC_HEADER_TYPE_MASK) + +/* SEQ_CNT */ +#define UNF_FC_HEADER_SEQ_CNT_MASK 0x0000FFFF +#define UNF_FC_HEADER_SEQ_CNT_SHIFT 0 +#define UNF_FC_HEADER_SEQ_CNT_DWORD 3 +#define UNF_GET_FC_HEADER_SEQ_CNT(__pfcheader)\ + UNF_GET_SHIFTMASK(\ + ((unsigned int *)(void *)__pfcheader)[UNF_FC_HEADER_SEQ_CNT_DWORD],\ + UNF_FC_HEADER_SEQ_CNT_SHIFT, UNF_FC_HEADER_SEQ_CNT_MASK) + +#define UNF_SET_FC_HEADER_SEQ_CNT(__pfcheader, __val)\ + UNF_FC_SET_SHIFTMASK(\ + ((unsigned int *)(void *)__pfcheader)[UNF_FC_HEADER_SEQ_CNT_DWORD],\ + __val, UNF_FC_HEADER_SEQ_CNT_SHIFT, UNF_FC_HEADER_SEQ_CNT_MASK) + +/* DF_CTL */ +#define UNF_FC_HEADER_DF_CTL_MASK 0x00FF0000 +#define UNF_FC_HEADER_DF_CTL_SHIFT 16 +#define UNF_FC_HEADER_DF_CTL_DWORD 3 +#define UNF_GET_FC_HEADER_DF_CTL(__pfcheader)\ + UNF_GET_SHIFTMASK(\ + ((unsigned int *)(void *)__pfcheader)[UNF_FC_HEADER_DF_CTL_DWORD],\ + UNF_FC_HEADER_DF_CTL_SHIFT, UNF_FC_HEADER_DF_CTL_MASK) +#define UNF_SET_FC_HEADER_DF_CTL(__pfcheader, __val)\ + UNF_FC_SET_SHIFTMASK(\ + ((unsigned int *)(void *)__pfcheader)[UNF_FC_HEADER_DF_CTL_DWORD],\ + __val, UNF_FC_HEADER_DF_CTL_SHIFT, UNF_FC_HEADER_DF_CTL_MASK) + +/* SEQ_ID */ +#define UNF_FC_HEADER_SEQ_ID_MASK 0xFF000000 +#define UNF_FC_HEADER_SEQ_ID_SHIFT 24 +#define UNF_FC_HEADER_SEQ_ID_DWORD 3 +#define UNF_GET_FC_HEADER_SEQ_ID(__pfcheader)\ + UNF_GET_SHIFTMASK(\ + ((unsigned int *)(void *)__pfcheader)[UNF_FC_HEADER_SEQ_ID_DWORD],\ + UNF_FC_HEADER_SEQ_ID_SHIFT, UNF_FC_HEADER_SEQ_ID_MASK) +#define UNF_SET_FC_HEADER_SEQ_ID(__pfcheader, __val)\ + UNF_FC_SET_SHIFTMASK(\ + ((unsigned int *)(void *)__pfcheader)[UNF_FC_HEADER_SEQ_ID_DWORD],\ + __val, UNF_FC_HEADER_SEQ_ID_SHIFT, UNF_FC_HEADER_SEQ_ID_MASK) + +/* RX_ID */ +#define UNF_FC_HEADER_RXID_MASK 0x0000FFFF +#define UNF_FC_HEADER_RXID_SHIFT 0 +#define UNF_FC_HEADER_RXID_DWORD 4 +#define UNF_GET_FC_HEADER_RXID(__pfcheader)\ + UNF_GET_SHIFTMASK(\ + ((unsigned int *)(void *)__pfcheader)[UNF_FC_HEADER_RXID_DWORD],\ + UNF_FC_HEADER_RXID_SHIFT, UNF_FC_HEADER_RXID_MASK) +#define UNF_SET_FC_HEADER_RXID(__pfcheader, __val)\ + UNF_FC_SET_SHIFTMASK(\ + ((unsigned int *)(void *)__pfcheader)[UNF_FC_HEADER_RXID_DWORD],\ + __val, UNF_FC_HEADER_RXID_SHIFT, UNF_FC_HEADER_RXID_MASK) + +/* OX_ID */ +#define UNF_FC_HEADER_OXID_MASK 0xFFFF0000 +#define UNF_FC_HEADER_OXID_SHIFT 16 +#define UNF_FC_HEADER_OXID_DWORD 4 +#define UNF_GET_FC_HEADER_OXID(__pfcheader)\ + ((unsigned short)UNF_GET_SHIFTMASK(\ + ((unsigned int *)(void *)__pfcheader)[UNF_FC_HEADER_OXID_DWORD],\ + UNF_FC_HEADER_OXID_SHIFT\ + , UNF_FC_HEADER_OXID_MASK)) + +#define UNF_SET_FC_HEADER_OXID(__pfcheader, __val)\ + (UNF_FC_SET_SHIFTMASK(\ + ((unsigned int *)(void *)__pfcheader)[UNF_FC_HEADER_OXID_DWORD],\ + __val, UNF_FC_HEADER_OXID_SHIFT, UNF_FC_HEADER_OXID_MASK)) + +/* PRLI PARAM 3 */ +#define HIFC_PRLI_PARAM_WXFER_ENABLE_MASK 0x00000001 +#define HIFC_PRLI_PARAM_WXFER_ENABLE_SHIFT 0 +#define HIFC_PRLI_PARAM_WXFER_DWORD 3 +#define HIFC_GET_PRLI_PARAM_WXFER(__pfcheader)\ + UNF_GET_SHIFTMASK(\ + ((unsigned int *)(void *)(__pfcheader))[HIFC_PRLI_PARAM_WXFER_DWORD],\ + HIFC_PRLI_PARAM_WXFER_ENABLE_SHIFT, HIFC_PRLI_PARAM_WXFER_ENABLE_MASK) + +#define HIFC_PRLI_PARAM_CONF_ENABLE_MASK 0x00000080 +#define HIFC_PRLI_PARAM_CONF_ENABLE_SHIFT 7 +#define HIFC_PRLI_PARAM_CONF_DWORD 3 +#define HIFC_GET_PRLI_PARAM_CONF(__pfcheader)\ + UNF_GET_SHIFTMASK(\ + ((unsigned int *)(void *)(__pfcheader))[HIFC_PRLI_PARAM_CONF_DWORD],\ + HIFC_PRLI_PARAM_CONF_ENABLE_SHIFT, HIFC_PRLI_PARAM_CONF_ENABLE_MASK) + +#define HIFC_PRLI_PARAM_REC_ENABLE_MASK 0x00000400 +#define HIFC_PRLI_PARAM_REC_ENABLE_SHIFT 10 +#define HIFC_PRLI_PARAM_CONF_REC 3 +#define HIFC_GET_PRLI_PARAM_REC(__pfcheader)\ + UNF_GET_SHIFTMASK(\ + ((unsigned int *)(void *)(__pfcheader))[HIFC_PRLI_PARAM_CONF_REC],\ + HIFC_PRLI_PARAM_REC_ENABLE_SHIFT, HIFC_PRLI_PARAM_REC_ENABLE_MASK) + +#define HIFC_WQE_TYPE_MASK 0x000000FF +#define HIFC_WQE_TYPE_SHIFT 0 +#define HIFC_WQE_TYPE_DWORD 0 +#define HIFC_GET_WQE_TYPE_BE(__pfcheader)\ + UNF_GET_SHIFTMASK(\ + ((unsigned int *)(void *)__pfcheader)[HIFC_WQE_TYPE_DWORD],\ + HIFC_WQE_TYPE_SHIFT, HIFC_WQE_TYPE_MASK) + +#define HIFC_MAKE_64BIT_ADDR(__high32, __low32) \ + (unsigned long long)(((unsigned long long)(__high32) << 32) |\ + (unsigned long long)(__low32)) + +#define HIFC_TRACE(log_id, log_att, log_level, fmt, ...) \ + UNF_TRACE(log_id, log_att, log_level, fmt, ##__VA_ARGS__) + +/* Valid check */ +#define HIFC_CHECK(log_id, condition, fail_do) \ + do { \ + if (unlikely(!(condition))) { \ + HIFC_TRACE((log_id), UNF_LOG_IO_ATT, UNF_ERR, \ + "[err]Function:%s parameter check[%s] invalid",\ + __func__, #condition); \ + fail_do; \ + } \ + } while (0) + +#define PRINT_IN_MBOX(dbg_level, data, count) \ + do { \ + unsigned int index = 0; \ + if ((dbg_level) <= unf_dbg_level) { \ + printk("HIFC send inbound mailbox: "); \ + for (index = 0; index < (count) / 4; index++) { \ + printk("%08x ", \ + (((unsigned int *)(data))[index]));\ + } \ + printk("\n"); \ + } \ + } while (0) +#define PRINT_OUT_MBOX(dbg_level, data, count) \ + do { \ + unsigned int index = 0; \ + if ((dbg_level) <= unf_dbg_level) { \ + printk("HIFC receive outbound mailbox: "); \ + for (index = 0; index < (count) / 4; index++) { \ + printk("%08x ",\ + (((unsigned int *)(data))[index]));\ + } \ + printk("\n"); \ + } \ + } while (0) + +#define PRINT_INBOUND_IOB(dbg_level, data, count) \ + do { \ + unsigned int index = 0; \ + if ((dbg_level) <= unf_dbg_level) { \ + printk("HIFC send inbound iob: "); \ + for (index = 0; index < (count) / 4; index++) { \ + printk("%08x ",\ + (((unsigned int *)(data))[index]));\ + } \ + printk("\n"); \ + } \ + } while (0) + +#define PRINT_OUTBOUND_IOB(dbg_level, data, count) \ + do { \ + unsigned int index = 0; \ + if ((dbg_level) <= unf_dbg_level) { \ + printk("HIFC receive outbound iob: "); \ + for (index = 0; index < (count) / 4; index++) { \ + printk("%08x ",\ + (((unsigned int *)(data))[index]));\ + } \ + printk("\n"); \ + } \ + } while (0) +#define HIFC_REFERNCE_VAR(ref, cmp, ret) + +#define RETURN_ERROR_S32 (-1) +#define UNF_RETURN_ERROR_S32 (-1) + +enum HIFC_HBA_ERR_STAT_E { + HIFC_STAT_CTXT_FLUSH_DONE = 0, + HIFC_STAT_SQ_WAIT_EMPTY, + HIFC_STAT_LAST_GS_SCQE, + HIFC_STAT_SQ_POOL_EMPTY, + HIFC_STAT_PARENT_IO_FLUSHED, + HIFC_STAT_ROOT_IO_FLUSHED, /* 5 */ + HIFC_STAT_ROOT_SQ_FULL, + HIFC_STAT_ELS_RSP_EXCH_REUSE, + HIFC_STAT_GS_RSP_EXCH_REUSE, + HIFC_STAT_SQ_IO_BUFFER_CLEARED, + HIFC_STAT_PARENT_SQ_NOT_OFFLOADED, /* 10 */ + HIFC_STAT_PARENT_SQ_QUEUE_DELAYED_WORK, + HIFC_STAT_PARENT_SQ_INVALID_CACHED_ID, + HIFC_HBA_STAT_BUTT +}; + +#define HIFC_DWORD_BYTE 4 +#define HIFC_QWORD_BYTE 8 +#define HIFC_SHIFT_TO_U64(x) ((x) >> 3) +#define HIFC_SHIFT_TO_U32(x) ((x) >> 2) + +void hifc_cpu_to_big64(void *v_addr, unsigned int size); +void hifc_big_to_cpu64(void *v_addr, unsigned int size); +void hifc_cpu_to_big32(void *v_addr, unsigned int size); +void hifc_big_to_cpu32(void *v_addr, unsigned int size); +unsigned int hifc_log2n(unsigned int val); + +#endif /* __HIFC_UTILS_H__ */ + diff --git a/drivers/scsi/huawei/hifc/unf_common.h b/drivers/scsi/huawei/hifc/unf_common.h new file mode 100644 index 000000000000..7f5161676ebb --- /dev/null +++ b/drivers/scsi/huawei/hifc/unf_common.h @@ -0,0 +1,1893 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Huawei Hifc PCI Express Linux driver + * Copyright(c) 2017 Huawei Technologies Co., Ltd + * + */ +#ifndef __UNF_COMMON_H +#define __UNF_COMMON_H + +#include "unf_scsi_common.h" + +/* V/C version number */ +#define UNF_MAJOR_VERSION "3" +/* B version, B0XX Corresponding x.x */ +#define UNF_B_VERSION "5.0" +/* Indicates the minor version number of the driver */ +#define UNF_DRIVER_VERSION "8" +/* version num */ +#define UNF_FC_VERSION UNF_MAJOR_VERSION "." UNF_B_VERSION "." UNF_DRIVER_VERSION +extern unsigned int unf_dbg_level; +extern unsigned int hifc_dif_type; +extern unsigned int hifc_dif_enable; +extern unsigned char hifc_guard; + +#define RETURN_ERROR_S32 (-1) +#define UNF_RETURN_ERROR_S32 (-1) + +#define UNF_IO_SUCCESS 0x00000000 +/* the host system aborted the command */ +#define UNF_IO_ABORTED 0x00000001 +#define UNF_IO_FAILED 0x00000002 +#define UNF_IO_ABORT_ABTS 0x00000003 +#define UNF_IO_ABORT_LOGIN 0x00000004 /* abort login */ +/* reset event aborted the transport */ +#define UNF_IO_ABORT_REET 0x00000005 +#define UNF_IO_ABORT_FAILED 0x00000006 /* abort failed */ +/* data out of order ,data reassembly error */ +#define UNF_IO_OUTOF_ORDER 0x00000007 +#define UNF_IO_FTO 0x00000008 /* frame time out */ +#define UNF_IO_LINK_FAILURE 0x00000009 +#define UNF_IO_OVER_FLOW 0x0000000a /* data over run */ +#define UNF_IO_RSP_OVER 0x0000000b +#define UNF_IO_LOST_FRAME 0x0000000c +#define UNF_IO_UNDER_FLOW 0x0000000d /* data under run */ +#define UNF_IO_HOST_PROG_ERROR 0x0000000e +#define UNF_IO_SEST_PROG_ERROR 0x0000000f +#define UNF_IO_INVALID_ENTRY 0x00000010 +#define UNF_IO_ABORT_SEQ_NOT 0x00000011 +#define UNF_IO_REJECT 0x00000012 +#define UNF_IO_RS_INFO 0x00000013 +#define UNF_IO_EDC_IN_ERROR 0x00000014 +#define UNF_IO_EDC_OUT_ERROR 0x00000015 +#define UNF_IO_UNINIT_KEK_ERR 0x00000016 +#define UNF_IO_DEK_OUTOF_RANGE 0x00000017 +#define UNF_IO_KEY_UNWRAP_ERR 0x00000018 +#define UNF_IO_KEY_TAG_ERR 0x00000019 +#define UNF_IO_KEY_ECC_ERR 0x0000001a +#define UNF_IO_BLOCK_SIZE_ERROR 0x0000001b +#define UNF_IO_ILLEGAL_CIPHER_MODE 0x0000001c +#define UNF_IO_CLEAN_UP 0x0000001d +#define UNF_SRR_RECEIVE 0x0000001e /* receive srr */ +/* The target device sent an ABTS to abort the I/O. */ +#define UNF_IO_ABORTED_BY_TARGET 0x0000001f +#define UNF_IO_TRANSPORT_ERROR 0x00000020 +#define UNF_IO_LINK_FLASH 0x00000021 +#define UNF_IO_TIMEOUT 0x00000022 +#define UNF_IO_PORT_UNAVAILABLE 0x00000023 +#define UNF_IO_PORT_LOGOUT 0x00000024 +#define UNF_IO_PORT_CFG_CHG 0x00000025 +#define UNF_IO_FIRMWARE_RES_UNAVAILABLE 0x00000026 +#define UNF_IO_TASK_MGT_OVERRUN 0x00000027 +#define UNF_IO_DMA_ERROR 0x00000028 +#define UNF_IO_DIF_ERROR 0x00000029 +#define UNF_IO_NO_LPORT 0x0000002a +#define UNF_IO_NO_XCHG 0x0000002b +#define UNF_IO_SOFT_ERR 0x0000002c +#define UNF_IO_XCHG_ADD_ERROR 0x0000002d +#define UNF_IO_NO_LOGIN 0x0000002e +#define UNF_IO_NO_BUFFER 0x0000002f +#define UNF_IO_DID_ERROR 0x00000030 +#define UNF_IO_UNSUPPORT 0x00000031 +#define UNF_IO_NOREADY 0x00000032 +#define UNF_IO_NPORTID_REUSED 0x00000033 +#define UNF_IO_NPORT_HANDLE_REUSED 0x00000034 +#define UNF_IO_NO_NPORT_HANDLE 0x00000035 +#define UNF_IO_ABORT_BY_FW 0x00000036 +#define UNF_IO_ABORT_PORT_REMOVING 0x00000037 +#define UNF_IO_INCOMPLETE 0x00000038 +#define UNF_IO_DIF_REF_ERROR 0x00000039 +#define UNF_IO_DIF_GEN_ERROR 0x0000003a + +#define UNF_IO_ERREND 0xFFFFFFFF + +/* define bits */ +#define UNF_BIT(n) (0x1UL << (n)) +#define UNF_BIT_0 UNF_BIT(0) +#define UNF_BIT_1 UNF_BIT(1) +#define UNF_BIT_2 UNF_BIT(2) +#define UNF_BIT_3 UNF_BIT(3) +#define UNF_BIT_4 UNF_BIT(4) +#define UNF_BIT_5 UNF_BIT(5) + +struct buff_list_s { + u8 *vaddr; + dma_addr_t paddr; +}; + +struct buf_describe_s { + struct buff_list_s *buflist; + u32 buf_size; + u32 buf_num; +}; + +#define BUF_LIST_PAGE_SIZE (PAGE_SIZE << 8) + +/* Echo macro define */ +#define ECHO_MG_VERSION_LOCAL 1 +#define ECHO_MG_VERSION_REMOTE 2 + +/* save hba info macro define */ +#define SAVE_PORT_INFO_LEN 1016 + +#define UNF_GET_NAME_HIGH_WORD(v_name) \ + (((v_name) >> 32) & 0xffffffff) +#define UNF_GET_NAME_LOW_WORD(v_name) \ + ((v_name) & 0xffffffff) + +#define UNF_FIRST_LPORT_ID_MASK 0xffffff00 +#define HIFC_MAX_COUNTER_TYPE 128 + +#define UNF_EVENT_ASYN 0 +#define UNF_EVENT_SYN 1 +#define UNF_GLOBAL_EVENT_ASYN 2 +#define UNF_GLOBAL_EVENT_SYN 3 + +/* define sfp err */ +#define UNF_SFP_PRESENT_FAIL 0x1 +#define UNF_SFP_POWER_FAIL 0x2 +#define UNF_9545_FAIL 0x3 + +/* obtain the values of board type and ID */ +#define UNF_GET_BOARD_TYPE_AND_SLOT_ID_BY_PORTID(port_id) \ + (((port_id) & 0x00FF00) >> 8) + +#define UNF_FC_SERVER_BOARD_8_G 13 /* 8G mode */ +#define UNF_FC_SERVER_BOARD_16_G 7 /* 16G mode */ +#define UNF_FC_SERVER_BOARD_32_G 6 /* 32G mode */ + +#define UNF_PORT_TYPE_FC_QSFP 1 +#define UNF_PORT_TYPE_FC_SFP 0 +#define UNF_PORT_UNGRADE_FW_RESET_ACTIVE 0 +#define UNF_PORT_UNGRADE_FW_RESET_INACTIVE 1 + +#ifndef __BIG_ENDIAN__ +#define __BIG_ENDIAN__ 0x4321 +#endif + +#ifndef __LITTLE_ENDIAN__ +#define __LITTLE_ENDIAN__ 0x1234 +#endif + +#ifdef __BYTE_ORDER__ +#undef __BYTE_ORDER__ +#endif +#define __BYTE_ORDER__ __LITTLE_ENDIAN__ + +#ifndef INVALID_VALUE64 +#define INVALID_VALUE64 0xFFFFFFFFFFFFFFFFULL +#endif /* INVALID_VALUE64 */ + +#ifndef INVALID_VALUE32 +#define INVALID_VALUE32 0xFFFFFFFF +#endif /* INVALID_VALUE32 */ + +#ifndef INVALID_VALUE16 +#define INVALID_VALUE16 0xFFFF +#endif /* INVALID_VALUE16 */ + +#ifndef INVALID_VALUE8 +#define INVALID_VALUE8 0xFF +#endif /* INVALID_VALUE8 */ + +#ifndef RETURN_OK +#define RETURN_OK 0 +#endif + +#ifndef RETURN_ERROR +#define RETURN_ERROR (~0) +#endif +#define UNF_RETURN_ERROR (~0) + +#ifndef UNF_RETURN_NOT_SUPPORT +#define UNF_RETURN_NOT_SUPPORT (2) +#endif + +enum int_e { + UNF_FALSE = 0, + UNF_TRUE = 1 +}; + +#define DRV_DIF_CRC_ERR 0x1001 +#define DRV_DIF_LBA_ERR 0x1002 +#define DRV_DIF_APP_ERR 0x1003 + +#define UNF_SCSI_SENSE_DATA_LEN SCSI_SENSE_DATA_LEN + +/* RPort Management information related to Rport, + * only used at the boundary between common and lowlevel + */ +struct unf_rport_info_s { + unsigned int local_nport_id; + unsigned int nport_id; + unsigned int rport_index; + unsigned long long port_name; + unsigned char rsvd0[3]; +}; + +struct unf_cfg_item_s { + char *name; + unsigned int min_value; + unsigned int default_value; + unsigned int max_value; +}; + +struct unf_port_params_s { + unsigned int ra_tov; + unsigned int ed_tov; +}; + +/* get wwpn adn wwnn */ +struct unf_get_chip_info_argout { + unsigned char board_type; + unsigned long long wwpn; + unsigned long long wwnn; + unsigned long long sys_mac; +}; + +/* get sfp info: present and speed */ +struct unf_get_port_info_argout { + unsigned char sfp_speed; + unsigned char present; + unsigned char rsvd[2]; +}; + +/* SFF-8436(QSFP+) Rev 4.7 */ +struct sfp_plus_field_a0_s { + unsigned char identifier; + /* offset 1~2 */ + struct { + unsigned char reserved; + unsigned char status; + } status_indicator; + /* offset 3~21 */ + struct { + unsigned char rx_tx_los; + unsigned char tx_fault; + unsigned char all_resv; + + unsigned char ini_complete : 1; + unsigned char bit_resv : 3; + unsigned char temp_low_warn : 1; + unsigned char temp_high_warn : 1; + unsigned char temp_low_alarm : 1; + unsigned char temp_high_alarm : 1; + + unsigned char resv : 4; + unsigned char vcc_low_warn : 1; + unsigned char vcc_high_warn : 1; + unsigned char vcc_low_alarm : 1; + unsigned char vcc_high_alarm : 1; + + unsigned char resv8; + unsigned char rx_pow[2]; + unsigned char tx_bias[2]; + unsigned char reserved[6]; + unsigned char vendor_specifics[3]; + } interrupt_flag; + /* offset 22~33 */ + struct { + unsigned char temp[2]; + unsigned char reserved[2]; + unsigned char supply_vol[2]; + unsigned char reserveds[2]; + unsigned char vendor_specific[4]; + } module_monitors; + /* offset 34~81 */ + struct { + unsigned char rx_pow[8]; + unsigned char tx_bias[8]; + unsigned char reserved[16]; + unsigned char vendor_specific[16]; + } channel_monitor_val; + + /* offset 82~85 */ + unsigned char reserved[4]; + + /* offset 86~97 */ + struct { + /* 86~88 */ + unsigned char tx_disable; + unsigned char rx_rate_select; + unsigned char tx_rate_select; + + /* 89~92 */ + unsigned char rx_4_app_select; + unsigned char rx_3_app_select; + unsigned char rx_2_app_select; + unsigned char rx_1_app_select; + /* 93 */ + unsigned char power_override : 1; + unsigned char power_set : 1; + unsigned char reserved : 6; + + /* 94~97 */ + unsigned char tx_4_app_select; + unsigned char tx_3_app_select; + unsigned char tx_2_app_select; + unsigned char tx_1_app_select; + /* 98~99 */ + unsigned char auc_reserved[2]; + } control; + /* 100~106 */ + struct { + /* 100 */ + unsigned char mrx_1_os : 1; + unsigned char mrx_2_los : 1; + unsigned char mrx_3_los : 1; + unsigned char mrx_4_los : 1; + unsigned char mtx_1_los : 1; + unsigned char mtx_2_los : 1; + unsigned char mtx_3_los : 1; + unsigned char mtx_4_los : 1; + /* 101 */ + unsigned char mtx_1_fault : 1; + unsigned char mtx_2_fault : 1; + unsigned char mtx_3_fault : 1; + unsigned char mtx_4_fault : 1; + unsigned char reserved : 4; + /* 102 */ + unsigned char uc_reserved; + /* 103 */ + unsigned char mini_cmp_flag : 1; + unsigned char rsv : 3; + unsigned char mtemp_low_warn : 1; + unsigned char mtemp_high_warn : 1; + unsigned char mtemp_low_alarm : 1; + unsigned char mtemp_high_alarm : 1; + /* 104 */ + unsigned char rsv1 : 4; + unsigned char mvcc_low_warn : 1; + unsigned char mvcc_high_warn : 1; + unsigned char mvcc_low_alarm : 1; + unsigned char mvcc_high_alarm : 1; + /* 105~106 */ + unsigned char vendor_specific[2]; + } module_channel_mask_bit; + /* 107~118 */ + unsigned char auc_resv[12]; + /* 119~126 */ + unsigned char auc_reserved[8]; + /* 127 */ + unsigned char page_select; +}; + +/* page 00 */ +struct sfp_plus_field_00_s { + /* 128~191 */ + struct { + unsigned char id; + unsigned char id_ext; + unsigned char connector; + unsigned char speci_com[6]; + unsigned char mode; + unsigned char speed; + unsigned char encoding; + unsigned char br_nominal; + unsigned char ext_rate_select_com; + unsigned char length_smf; + unsigned char length_om3; + unsigned char length_om2; + unsigned char length_om1; + unsigned char length_copper; + unsigned char device_tech; + unsigned char vendor_name[16]; + unsigned char ex_module; + unsigned char vendor_oui[3]; + unsigned char vendor_pn[16]; + unsigned char vendor_rev[2]; + /* Wave length or Copper cable Attenuation */ + unsigned char wave_or_copper_attenuation[2]; + unsigned char wave_length_toler[2]; /* Wavelength tolerance */ + unsigned char max_temp; + unsigned char cc_base; + } base_id_fields; + /* 192~223 */ + struct { + unsigned char options[4]; + unsigned char vendor_sn[16]; + unsigned char date_code[8]; + unsigned char diagn_monit_type; + unsigned char enhance_opt; + unsigned char uc_reserved; + unsigned char ccext; + } ext_id_fields; + /* 224~255 */ + unsigned char vendor_spec_eeprom[32]; +}; + +/* page 01 */ +struct sfp_field_01_s { + unsigned char optiona_l01[128]; +}; + +/* page 02 */ +struct sfp_field_02_s { + unsigned char optiona_l02[128]; +}; + +/* page 03 */ +struct sfp_field_03_s { + unsigned char temp_high_alarm[2]; + unsigned char temp_low_alarm[2]; + unsigned char temp_high_warn[2]; + unsigned char temp_low_warn[2]; + + unsigned char reserved1[8]; + + unsigned char vcc_high_alarm[2]; + unsigned char vcc_low_alarm[2]; + unsigned char vcc_high_warn[2]; + unsigned char vcc_low_warn[2]; + + unsigned char reserved2[8]; + unsigned char vendor_specific1[16]; + + unsigned char pow_high_alarm[2]; + unsigned char pow_low_alarm[2]; + unsigned char pow_high_warn[2]; + unsigned char pow_low_warn[2]; + + unsigned char bias_high_alarm[2]; + unsigned char bias_low_alarm[2]; + unsigned char bias_high_warn[2]; + unsigned char bias_low_warn[2]; + + unsigned char tx_power_high_alarm[2]; + unsigned char tx_power_low_alarm[2]; + unsigned char reserved3[4]; + + unsigned char reserved4[8]; + + unsigned char vendor_specific2[16]; + unsigned char reserved5[2]; + unsigned char vendor_specific3[12]; + unsigned char rx_ampl[2]; + unsigned char rx_tx_sq_disable; + unsigned char rx_output_disable; + unsigned char chan_monit_mask[12]; + unsigned char reserved6[2]; + +}; + +struct sfp_plus_info_s { + struct sfp_plus_field_a0_s sfp_plus_info_a0; + struct sfp_plus_field_00_s sfp_plus_info_00; + struct sfp_field_01_s sfp_plus_info_01; + struct sfp_field_02_s sfp_plus_info_02; + struct sfp_field_03_s sfp_plus_info_03; +}; + +/* SFF-8472 Rev 10.4 */ +struct unf_sfp_data_field_a0_s { + /* Offset 0~63 */ + struct { + unsigned char id; + unsigned char id_ext; + unsigned char connector; + unsigned char atransceiver[8]; + unsigned char encoding; + /* Nominal signalling rate, units of 100MBd. */ + unsigned char br_nominal; + /* Type of rate select functionality */ + unsigned char rate_identifier; + /* Link length supported for single mode fiber, units of km */ + unsigned char length_smf_km; + /* Link length supported for single mode fiber, + * units of 100 m + */ + unsigned char length_smf; + /* Link length supported for 50 um OM2 fiber, units of 10 m */ + unsigned char length_smf_om2; + /* Link length supported for 62.5 um OM1 fiber, units of 10 m */ + unsigned char length_smf_om1; + /* Link length supported for copper or direct attach cable, + * units of m + */ + unsigned char length_cable; + /* Link length supported for 50 um OM3 fiber, units of 10 m */ + unsigned char length_om3; + unsigned char vendor_name[16]; /* ASCII */ + /* Code for electronic or optical compatibility */ + unsigned char transceiver; + unsigned char vendor_oui[3]; /* SFP vendor IEEE company ID */ + /* Part number provided by SFP vendor (ASCII) */ + unsigned char vendor_pn[16]; + /* Revision level for part number provided by vendor (ASCII) */ + unsigned char vendor_rev[4]; + /* Laser wavelength (Passive/Active Cable + * Specification Compliance) + */ + unsigned char wave_length[2]; + unsigned char unallocated; + /* Check code for Base ID Fields (addresses 0 to 62) */ + unsigned char cc_base; + } base_id_fields; + + /* Offset 64~95 */ + struct { + unsigned char options[2]; + unsigned char br_max; + unsigned char br_min; + unsigned char vendor_sn[16]; + unsigned char date_code[8]; + unsigned char diag_monitoring_type; + unsigned char enhanced_options; + unsigned char sff8472_compliance; + unsigned char cc_ext; + } ext_id_fields; + + /* Offset 96~255 */ + struct { + unsigned char vendor_spec_eeprom[32]; + unsigned char rsvd[128]; + } vendor_spec_id_fields; +}; + +struct unf_sfp_data_field_a2_s { + /* Offset 0~119 */ + struct { + /* 0~39 */ + struct { + unsigned char temp_alarm_high[2]; + unsigned char temp_alarm_low[2]; + unsigned char temp_warning_high[2]; + unsigned char temp_warning_low[2]; + + unsigned char vcc_alarm_high[2]; + unsigned char vcc_alarm_low[2]; + unsigned char vcc_warning_high[2]; + unsigned char vcc_warning_low[2]; + + unsigned char bias_alarm_high[2]; + unsigned char bias_alarm_low[2]; + unsigned char bias_warning_high[2]; + unsigned char bias_warning_low[2]; + + unsigned char tx_alarm_high[2]; + unsigned char tx_alarm_low[2]; + unsigned char tx_warning_high[2]; + unsigned char tx_warning_low[2]; + + unsigned char rx_alarm_high[2]; + unsigned char rx_alarm_low[2]; + unsigned char rx_warning_high[2]; + unsigned char rx_warning_low[2]; + } alarm_warn_th; + + unsigned char unallocated0[16]; + unsigned char ext_cal_constants[36]; + unsigned char unallocated1[3]; + unsigned char cc_dmi; + + /* 96~105 */ + struct { + unsigned char temp[2]; + unsigned char vcc[2]; + unsigned char tx_bias[2]; + unsigned char tx_power[2]; + unsigned char rx_power[2]; + } diag; + + unsigned char unallocated2[4]; + + struct { + unsigned char data_rdy_bar_state : 1; + unsigned char rx_los : 1; + unsigned char tx_fault_state : 1; + unsigned char soft_rate_select_state : 1; + unsigned char rate_select_state : 1; + unsigned char rs_state : 1; + unsigned char soft_tx_disable_select : 1; + unsigned char tx_disable_state : 1; + } status_ctrl; + unsigned char rsvd; + + /* 112~113 */ + struct { + /* 112 */ + unsigned char tx_alarm_low : 1; + unsigned char tx_alarm_high : 1; + unsigned char tx_bias_alarm_low : 1; + unsigned char tx_bias_alarm_high : 1; + unsigned char vcc_alarm_low : 1; + unsigned char vcc_alarm_high : 1; + unsigned char temp_alarm_low : 1; + unsigned char temp_alarm_high : 1; + + /* 113 */ + unsigned char rsvd : 6; + unsigned char rx_alarm_low : 1; + unsigned char rx_alarm_high : 1; + } alarm; + + unsigned char unallocated3[2]; + + /* 116~117 */ + struct { + /* 116 */ + unsigned char tx_warn_lo : 1; + unsigned char tx_warn_hi : 1; + unsigned char bias_warn_lo : 1; + unsigned char bias_warn_hi : 1; + unsigned char vcc_warn_lo : 1; + unsigned char vcc_warn_hi : 1; + unsigned char temp_warn_lo : 1; + unsigned char temp_warn_hi : 1; + + /* 117 */ + unsigned char rsvd : 6; + unsigned char rx_warn_lo : 1; + unsigned char rx_warn_hi : 1; + } warning; + + unsigned char ext_status_and_ctrl[2]; + } diag; + + /* Offset 120~255 */ + struct { + unsigned char vendor_spec[8]; + unsigned char user_eeprom[120]; + unsigned char vendor_ctrl[8]; + } general_use_fields; +}; + +struct unf_sfp_info_s { + struct unf_sfp_data_field_a0_s sfp_info_a0; + struct unf_sfp_data_field_a2_s sfp_info_a2; +}; + +union unf_sfp_eeprome_info { + struct unf_sfp_info_s sfp_info; + struct sfp_plus_info_s sfp_plus_info; +}; + +/* sfp info end */ +struct unf_lport_sfp_info { + unsigned int status; + union unf_sfp_eeprome_info sfp_eeprom_info; +}; + +struct unf_err_code_s { + unsigned int loss_of_signal_count; + unsigned int bad_rx_char_count; + unsigned int loss_of_sync_count; + unsigned int link_fail_count; + unsigned int rx_eo_fa_count; + unsigned int dis_frame_count; + unsigned int bad_crc_count; + unsigned int proto_error_count; +}; + +/* config file */ +enum unf_scsi_mode_e { + UNF_PORT_MODE_UNKNOWN = 0x00, + UNF_PORT_MODE_TGT = 0x10, + UNF_PORT_MODE_INI = 0x20, + UNF_PORT_MODE_BOTH = 0x30 +}; + +enum unf_port_upgrade_e { + UNF_PORT_UNSUPPORT_UPGRADE_REPORT = 0x00, + UNF_PORT_SUPPORT_UPGRADE_REPORT = 0x01, + UNF_PORT_UPGRADE_BUTT +}; + +#define UNF_BYTES_OF_DWORD 0x4 +static inline void __attribute__((unused)) unf_big_end_to_cpu( + unsigned char *v_buffer, unsigned int v_size) +{ + unsigned int *buffer = NULL; + unsigned int word_sum = 0; + unsigned int i = 0; + + if (!v_buffer) + return; + + buffer = (unsigned int *)v_buffer; + + /* byte to word */ + if (v_size % UNF_BYTES_OF_DWORD == 0) + word_sum = v_size / UNF_BYTES_OF_DWORD; + else + return; + + /* word to byte */ + while (i < word_sum) { + *buffer = be32_to_cpu(*buffer); + buffer++; + i++; + } +} + +static inline void __attribute__((unused)) unf_cpu_to_big_end( + void *v_buffer, unsigned int v_size) +{ +#define DWORD_BIT 32 +#define BYTE_BIT 8 + unsigned int *buffer = NULL; + unsigned int word_sum = 0; + unsigned int i = 0; + unsigned int tmp = 0; + + if (!v_buffer) + return; + + buffer = (unsigned int *)v_buffer; + + /* byte to dword */ + word_sum = v_size / 4; + + /* dword to byte */ + while (i < word_sum) { + *buffer = cpu_to_be32(*buffer); + buffer++; + i++; + } + + if (v_size % 4) { + tmp = cpu_to_be32(*buffer); + tmp = tmp >> (DWORD_BIT - (v_size % 4) * BYTE_BIT); + memcpy(buffer, &tmp, (v_size % 4)); + } +} + +#define UNF_FUNCTION_RETURN_CHECK(ret, dstlen) \ + do { \ + if (((ret) <= 0) || ((ret) >= (dstlen))) { \ + UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, \ + UNF_LOG_REG_ATT, UNF_ERR, \ + "function return (%d) check invalid, dst len(%d).", \ + (ret), (dstlen)); \ + } \ + } while (0) + +#define UNF_TOP_AUTO_MASK 0x0f + +#define UNF_NORMAL_MODE 0 +#define UNF_SET_NOMAL_MODE(mode) (mode = UNF_NORMAL_MODE) + +/* + * SCSI status + */ +#define SCSI_CHECK_CONDITION 0x02 + +enum unf_act_topo_e { + UNF_ACT_TOP_PUBLIC_LOOP = 0x1, + UNF_ACT_TOP_PRIVATE_LOOP = 0x2, + UNF_ACT_TOP_P2P_DIRECT = 0x4, + UNF_ACT_TOP_P2P_FABRIC = 0x8, + UNF_TOP_LOOP_MASK = 0x03, + UNF_TOP_P2P_MASK = 0x0c, + UNF_TOP_FCOE_MASK = 0x30, + UNF_ACT_TOP_UNKNOWN +}; + +#define UNF_FL_PORT_LOOP_ADDR 0x00 + +#define UNF_FC_PROTOCOL_TYPE 0x100 + +#define UNF_LOOP_ROLE_MASTER_OR_SLAVE 0x0 + +#define UNF_TOU16_CHECK(dest, src, over_action) \ + do { \ + if (unlikely((src) > 0xFFFF)) { \ + UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_REG_ATT, \ + UNF_ERR, "ToU16 error, src 0x%x ", (src)); \ + over_action; \ + } \ + ((dest) = (unsigned short)(src)); \ + } while (0) + +#define UNF_PORT_SPEED_AUTO 0 +#define UNF_PORT_SPEED_2_G 2 +#define UNF_PORT_SPEED_4_G 4 +#define UNF_PORT_SPEED_8_G 8 +#define UNF_PORT_SPEED_10_G 10 +#define UNF_PORT_SPEED_16_G 16 +#define UNF_PORT_SPEED_32_G 32 + +#define UNF_PORT_SPEED_UNKNOWN (~0) +#define UNF_PORT_SFP_SPEED_ERR 0xFF + +#define UNF_FW_VERSION_LEN 32 +#define UNF_HW_VERSION_LEN 32 + +/* max frame size */ +#define UNF_MAX_FRAME_SIZE 2112 + +/* default */ +#define UNF_DEFAULT_FRAME_SIZE 2048 +#define UNF_DEFAULT_EDTOV 2000 +#define UNF_DEFAULT_RATOV 10000 +#define UNF_DEFAULT_FABRIC_RATOV 10000 +#define UNF_MAX_RETRY_COUNT 3 +#define UNF_DEFAULT_RRTOV (10000 + 500) /* FCP-4 10.4.10 */ +#define UNF_RRQ_MIN_TIMEOUT_INTERVAL 30000 +#define UNF_LOGO_TIMEOUT_INTERVAL 3000 +#define UNF_WRITE_RRQ_SENDERR_INTERVAL 3000 +#define UNF_REC_TOV 3000 + +#define UNF_WAIT_SEM_TIMEOUT (5000UL) +#define UNF_WAIT_ABTS_RSP_TIMEOUT (20000UL) + +#define UNF_INI_RRQ_REDUNDANT_TIME 500 +#define UNF_INI_ELS_REDUNDANT_TIME 2000 + +/* ELS command values */ +#define UNF_ELS_CMND_HIGH_MASK 0xff000000 +#define UNF_ELS_CMND_RJT 0x01000000 +#define UNF_ELS_CMND_ACC 0x02000000 +#define UNF_ELS_CMND_PLOGI 0x03000000 +#define UNF_ELS_CMND_FLOGI 0x04000000 +#define UNF_ELS_CMND_LOGO 0x05000000 +#define UNF_ELS_CMND_RLS 0x0F000000 +#define UNF_ELS_CMND_ECHO 0x10000000 +#define UNF_ELS_CMND_REC 0x13000000 +#define UNF_ELS_CMND_RRQ 0x12000000 +#define UNF_ELS_CMND_PRLI 0x20000000 +#define UNF_ELS_CMND_PRLO 0x21000000 +#define UNF_ELS_CMND_PDISC 0x50000000 +#define UNF_ELS_CMND_FDISC 0x51000000 +#define UNF_ELS_CMND_ADISC 0x52000000 +#define UNF_ELS_CMND_FAN 0x60000000 +#define UNF_ELS_CMND_RSCN 0x61000000 +#define UNF_FCP_CMND_SRR 0x14000000 +#define UNF_GS_CMND_SCR 0x62000000 + +#define UNF_PLOGI_VERSION_UPPER 0x20 +#define UNF_PLOGI_VERSION_LOWER 0x20 +#define UNF_PLOGI_CONCURRENT_SEQ 0x00FF +#define UNF_PLOGI_RO_CATEGORY 0x00FE +#define UNF_PLOGI_SEQ_PER_XCHG 0x0001 + +/* CT_IU pream defines */ +#define UNF_REV_NPORTID_INIT 0x01000000 +#define UNF_FSTYPE_OPT_INIT 0xfc020000 +#define UNF_FSTYPE_RFT_ID 0x02170000 +#define UNF_FSTYPE_GID_PT 0x01A10000 +#define UNF_FSTYPE_GID_FT 0x01710000 +#define UNF_FSTYPE_RFF_ID 0x021F0000 +#define UNF_FSTYPE_GFF_ID 0x011F0000 +#define UNF_FSTYPE_GNN_ID 0x01130000 +#define UNF_FSTYPE_GPN_ID 0x01120000 + +#define UNF_CT_IU_RSP_MASK 0xffff0000 +#define UNF_CT_IU_REASON_MASK 0x00ff0000 +#define UNF_CT_IU_EXPLAN_MASK 0x0000ff00 +#define UNF_CT_IU_REJECT 0x80010000 +#define UNF_CT_IU_ACCEPT 0x80020000 + +#define UNF_FABRIC_FULL_REG 0x00000003 + +#define UNF_FC4_SCSI_BIT8 0x00000100 +#define UNF_FC4_FCP_TYPE 0x00000008 +#define UNF_FRAG_REASON_VENDOR 0 + +/* GID_PT, GID_FT */ +#define UNF_GID_PT_TYPE 0x7F000000 +#define UNF_GID_FT_TYPE 0x00000008 + +/* + * FC4 defines + */ +#define UNF_FC4_FRAME_PAGE_SIZE 0x10 +#define UNF_FC4_FRAME_PAGE_SIZE_SHIFT 16 + +#define UNF_FC4_FRAME_PARM_0_FCP 0x08000000 +#define UNF_FC4_FRAME_PARM_0_I_PAIR 0x00002000 +#define UNF_FC4_FRAME_PARM_0_GOOD_RSP_CODE 0x00000100 + +#define UNF_FC4_FRAME_PARM_3_INI 0x00000020 +#define UNF_FC4_FRAME_PARM_3_TGT 0x00000010 +#define UNF_FC4_FRAME_PARM_3_R_XFER_DIS 0x00000002 +#define UNF_FC4_FRAME_PARM_3_CONF_ALLOW 0x00000080 /* bit 7 */ +#define UNF_FC4_FRAME_PARM_3_REC_SUPPORT 0x00000400 /* bit 10 */ +#define UNF_FC4_FRAME_PARM_3_TASK_RETRY_ID_SUPPORT 0x00000200 /* bit 9 */ +#define UNF_FC4_FRAME_PARM_3_RETRY_SUPPORT 0x00000100 /* bit 8 */ +#define UNF_FC4_FRAME_PARM_3_CONF_ALLOW 0x00000080 /* bit 7 */ + + +#define UNF_GFF_ACC_MASK 0xFF000000 + +/* Reject CT_IU Reason Codes */ +#define UNF_CTIU_RJT_MASK 0xffff0000 +#define UNF_CTIU_RJT_INVALID_COMMAND 0x00010000 +#define UNF_CTIU_RJT_INVALID_VERSION 0x00020000 +#define UNF_CTIU_RJT_LOGIC_ERR 0x00030000 +#define UNF_CTIU_RJT_INVALID_SIZE 0x00040000 +#define UNF_CTIU_RJT_LOGIC_BUSY 0x00050000 +#define UNF_CTIU_RJT_PROTOCOL_ERR 0x00070000 +#define UNF_CTIU_RJT_UNABLE_PERFORM 0x00090000 +#define UNF_CTIU_RJT_NOT_SUPPORTED 0x000B0000 + +/* FS_RJT Reason code explanations, FC-GS-2 6.5 */ +#define UNF_CTIU_RJT_EXP_MASK 0x0000FF00 +#define UNF_CTIU_RJT_EXP_NO_ADDTION 0x00000000 +#define UNF_CTIU_RJT_EXP_PORTID_NO_REG 0x00000100 +#define UNF_CTIU_RJT_EXP_PORTNAME_NO_REG 0x00000200 +#define UNF_CTIU_RJT_EXP_NODENAME_NO_REG 0x00000300 +#define UNF_CTIU_RJT_EXP_FC4TYPE_NO_REG 0x00000700 +#define UNF_CTIU_RJT_EXP_PORTTYPE_NO_REG 0x00000A00 + +/* + * LS_RJT defines + */ +#define UNF_FC_LS_RJT_REASON_MASK 0x00ff0000 + +/* + * LS_RJT reason code defines + */ +#define UNF_LS_OK 0x00000000 +#define UNF_LS_RJT_INVALID_COMMAND 0x00010000 +#define UNF_LS_RJT_LOGICAL_ERROR 0x00030000 +#define UNF_LS_RJT_BUSY 0x00050000 +#define UNF_LS_RJT_PROTOCOL_ERROR 0x00070000 +#define UNF_LS_RJT_REQUEST_DENIED 0x00090000 +#define UNF_LS_RJT_NOT_SUPPORTED 0x000b0000 +#define UNF_LS_RJT_CLASS_ERROR 0x000c0000 + +/* + * LS_RJT code explanation + */ +#define UNF_LS_RJT_NO_ADDITIONAL_INFO 0x00000000 +#define UNF_LS_RJT_INV_DATA_FIELD_SIZE 0x00000700 +#define UNF_LS_RJT_INV_COMMON_SERV_PARAM 0x00000F00 +#define UNF_LS_RJT_INVALID_OXID_RXID 0x00001700 +#define UNF_LS_RJT_COMMAND_IN_PROGRESS 0x00001900 +#define UNF_LS_RJT_INSUFFICIENT_RESOURCES 0x00002900 +#define UNF_LS_RJT_COMMAND_NOT_SUPPORTED 0x00002C00 +#define UNF_LS_RJT_UNABLE_TO_SUPLY_REQ_DATA 0x00002A00 +#define UNF_LS_RJT_INVALID_PAYLOAD_LENGTH 0x00002D00 + +#define UNF_P2P_LOCAL_NPORT_ID 0x000000EF +#define UNF_P2P_REMOTE_NPORT_ID 0x000000D6 + +#define UNF_BBCREDIT_MANAGE_NFPORT 0 +#define UNF_BBCREDIT_MANAGE_LPORT 1 +#define UNF_BBCREDIT_LPORT 0 +#define UNF_CONTIN_INCREASE_SUPPORT 1 +#define UNF_CLASS_VALID 1 +#define UNF_CLASS_INVALID 0 +#define UNF_NOT_MEANINGFUL 0 +#define UNF_NO_SERVICE_PARAMS 0 +#define UNF_CLEAN_ADDRESS_DEFAULT 0 +#define UNF_PRIORITY_ENABLE 1 +#define UNF_PRIORITY_DISABLE 0 +#define UNF_SEQUEN_DELIVERY_REQ 1 /* Sequential delivery requested */ + +/* RSCN */ +#define UNF_RSCN_PORT_ADDR 0x0 +#define UNF_RSCN_AREA_ADDR_GROUP 0x1 +#define UNF_RSCN_DOMAIN_ADDR_GROUP 0x2 +#define UNF_RSCN_FABRIC_ADDR_GROUP 0x3 + +#define UNF_GET_RSCN_PLD_LEN(v_cmnd) ((v_cmnd)&0x0000ffff) +#define UNF_RSCN_PAGE_LEN 0x4 + +#define UNF_PORT_LINK_UP 0x0000 +#define UNF_PORT_LINK_DOWN 0x0001 +#define UNF_PORT_RESET_START 0x0002 +#define UNF_PORT_RESET_END 0x0003 +#define UNF_PORT_LINK_UNKNOWN 0x0004 +#define UNF_PORT_NOP 0x0005 +#define UNF_PORT_CORE_FATAL_ERROR 0x0006 +#define UNF_PORT_CORE_UNRECOVERABLE_ERROR 0x0007 +#define UNF_PORT_CORE_RECOVERABLE_ERROR 0x0008 +#define UNF_PORT_UPDATE_PROCESS 0x000b +#define UNF_PORT_DEBUG_DUMP 0x000c +#define UNF_PORT_GET_FWLOG 0x000d +#define UNF_PORT_CLEAN_DONE 0x000e +#define UNF_PORT_BEGIN_REMOVE 0x000f +#define UNF_PORT_RELEASE_RPORT_INDEX 0x0010 +#define UNF_PORT_ABNORMAL_RESET 0x0012 + +#define UNF_READ 0 +#define UNF_WRITE 1 +#define UNF_READ_64 2 +#define UNF_WRITE_64 3 +/* + *SCSI begin + */ +#define SCSIOPC_TEST_UNIT_READY 0x00 +#define SCSIOPC_INQUIRY 0x12 +#define SCSIOPC_MODE_SENSE_6 0x1A +#define SCSIOPC_MODE_SENSE_10 0x5A +#define SCSIOPC_MODE_SELECT_6 0x15 +#define SCSIOPC_RESERVE 0x16 +#define SCSIOPC_RELEASE 0x17 +#define SCSIOPC_START_STOP_UNIT 0x1B +#define SCSIOPC_READ_CAPACITY_10 0x25 +#define SCSIOPC_READ_CAPACITY_16 0x9E +#define SCSIOPC_READ_6 0x08 +#define SCSIOPC_READ_10 0x28 +#define SCSIOPC_READ_12 0xA8 +#define SCSIOPC_READ_16 0x88 +#define SCSIOPC_WRITE_6 0x0A +#define SCSIOPC_WRITE_10 0x2A +#define SCSIOPC_WRITE_12 0xAA +#define SCSIOPC_WRITE_16 0x8A +#define SCSIOPC_WRITE_VERIFY 0x2E +#define SCSIOPC_VERIFY_10 0x2F +#define SCSIOPC_VERIFY_12 0xAF +#define SCSIOPC_VERIFY_16 0x8F +#define SCSIOPC_REQUEST_SENSE 0x03 +#define SCSIOPC_REPORT_LUN 0xA0 +#define SCSIOPC_FORMAT_UNIT 0x04 +#define SCSIOPC_SEND_DIAGNOSTIC 0x1D +#define SCSIOPC_WRITE_SAME_10 0x41 +#define SCSIOPC_WRITE_SAME_16 0x93 +#define SCSIOPC_READ_BUFFER 0x3C +#define SCSIOPC_WRITE_BUFFER 0x3B + +#define SCSIOPC_LOG_SENSE 0x4D +#define SCSIOPC_MODE_SELECT_10 0x55 +#define SCSIOPC_SYNCHRONIZE_CACHE_10 0x35 +#define SCSIOPC_SYNCHRONIZE_CACHE_16 0x91 +#define SCSIOPC_WRITE_AND_VERIFY_10 0x2E +#define SCSIOPC_WRITE_AND_VERIFY_12 0xAE +#define SCSIOPC_WRITE_AND_VERIFY_16 0x8E +#define SCSIOPC_READ_MEDIA_SERIAL_NUMBER 0xAB +#define SCSIOPC_REASSIGN_BLOCKS 0x07 +#define SCSIOPC_ATA_PASSTHROUGH_16 0x85 +#define SCSIOPC_ATA_PASSTHROUGH_12 0xa1 + +/* + * SCSI end + */ +#define IS_READ_COMMAND(opcode) ((opcode) == SCSIOPC_READ_6 || \ + (opcode) == SCSIOPC_READ_10 || \ + (opcode) == SCSIOPC_READ_12 || \ + (opcode) == SCSIOPC_READ_16) +#define IS_WRITE_COMMAND(opcode) ((opcode) == SCSIOPC_WRITE_6 || \ + (opcode) == SCSIOPC_WRITE_10 || \ + (opcode) == SCSIOPC_WRITE_12 || \ + (opcode) == SCSIOPC_WRITE_16) + +#define FCP_RSP_LEN_VALID_MASK 0x1 +#define FCP_SNS_LEN_VALID_MASK 0x2 +#define FCP_RESID_OVER_MASK 0x4 +#define FCP_RESID_UNDER_MASK 0x8 +#define FCP_CONF_REQ_MASK 0x10 +#define FCP_SCSI_STATUS_GOOD 0x0 + +#define UNF_DELAYED_WORK_SYNC(v_ret, v_pord_id, v_work, v_work_symb) \ + do { \ + if (!cancel_delayed_work_sync(v_work)) { \ + UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, \ + UNF_INFO, \ + "[info]LPort or RPort(0x%x) %s worker can't destroy, or no worker", \ + v_pord_id, v_work_symb); \ + v_ret = UNF_RETURN_ERROR; \ + } else { \ + v_ret = RETURN_OK; \ + } \ + } while (0) + +#define UNF_DELAYED_WORK(v_ret, v_pord_id, v_work, v_work_symb) \ + do { \ + if (!cancel_delayed_work(v_work)) { \ + UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, \ + UNF_MAJOR, \ + "LPort or RPort(0x%x) %s worker can't destroy, or no worker.", \ + v_pord_id, v_work_symb); \ + v_ret = UNF_RETURN_ERROR; \ + } else { \ + v_ret = RETURN_OK; \ + } \ + } while (0) + +#define UNF_DELAYED_WORK_CONFUSED(v_ret, v_pord_id, v_work, v_work_symb) \ + do { \ + if (in_interrupt()) { \ + UNF_DELAYED_WORK(v_ret, v_pord_id, v_work, \ + v_work_symb) \ + } else { \ + UNF_DELAYED_WORK_SYNC(v_ret, v_pord_id, v_work, \ + v_work_symb) \ + } \ + } while (0) + +#define UNF_GET_IO_XCHG_TAG(v_pkg) \ + ((unsigned short)((v_pkg)->private[PKG_PRIVATE_XCHG_HOT_POOL_INDEX])) + +#define UNF_GET_SFS_ENTRY(v_pkg) ((union unf_sfs_u *)(void *) \ + (((struct unf_frame_pkg_s *)v_pkg)->unf_cmnd_pload_bl.buffer_ptr)) + +/* FLOGI */ +#define UNF_GET_FLOGI_PAYLOAD(v_pkg) (&(((union unf_sfs_u *) \ + (UNF_GET_SFS_ENTRY(v_pkg)))->flogi.flogi_payload)) +#define UNF_FLOGI_PAYLOAD_LEN sizeof(struct unf_flogi_payload_s) + +/* FLOGI ACC */ +#define UNF_GET_FLOGI_ACC_PAYLOAD(v_pkg) (&(((union unf_sfs_u *) \ + (UNF_GET_SFS_ENTRY(v_pkg)))->flogi_acc.flogi_payload)) +#define UNF_FLOGI_ACC_PAYLOAD_LEN sizeof(struct unf_flogi_payload_s) + +/* FDISC */ +#define UNF_FDISC_PAYLOAD_LEN UNF_FLOGI_PAYLOAD_LEN +#define UNF_FDISC_ACC_PAYLOAD_LEN UNF_FLOGI_ACC_PAYLOAD_LEN + +/* PLOGI */ +#define UNF_GET_PLOGI_PAYLOAD(v_pkg) \ + (&(((union unf_sfs_u *)(UNF_GET_SFS_ENTRY(v_pkg)))->plogi.payload)) +#define UNF_PLOGI_PAYLOAD_LEN sizeof(struct unf_plogi_payload_s) + +/* PLOGI ACC */ +#define UNF_GET_PLOGI_ACC_PAYLOAD(v_pkg) \ + (&(((union unf_sfs_u *)(UNF_GET_SFS_ENTRY(v_pkg)))->plogi_acc.payload)) +#define UNF_PLOGI_ACC_PAYLOAD_LEN sizeof(struct unf_plogi_payload_s) + +/* LOGO */ +#define UNF_LOGO_PAYLOAD_LEN sizeof(struct unf_logo_payload_s) + +/* ECHO */ +#define UNF_GET_ECHO_PAYLOAD(v_pkg) \ + (((union unf_sfs_u *)(UNF_GET_SFS_ENTRY(v_pkg)))->echo.echo_pld) + +/* ECHO PHYADDR */ +#define UNF_GET_ECHO_PAYLOAD_PHYADDR(v_pkg) \ + (((union unf_sfs_u *)(UNF_GET_SFS_ENTRY(v_pkg)))->echo.phy_echo_addr) + +#define UNF_ECHO_PAYLOAD_LEN sizeof(struct unf_echo_payload_s) + +/* RLS */ +#define UNF_RLS_PAYLOAD_LEN sizeof(struct unf_rls_payload_s) + +/* ECHO ACC */ +#define UNF_ECHO_ACC_PAYLOAD_LEN sizeof(struct unf_echo_payload_s) +/* REC */ +#define UNF_REC_PAYLOAD_LEN sizeof(struct unf_rec_pld_s) + +/* REC ACC */ +#define UNF_GET_REC_ACC_PAYLOAD(v_pkg) \ + (&(((union unf_sfs_u *)(UNF_GET_SFS_ENTRY(v_pkg)))->els_acc.cmnd)) + +#define UNF_REC_ACC_PAYLOAD_LEN (sizeof(struct unf_els_acc_s) - \ + sizeof(struct unf_fchead_s)) + +/* RRQ */ +#define UNF_RRQ_PAYLOAD_LEN (sizeof(struct unf_rrq_s) - \ + sizeof(struct unf_fchead_s)) + +/* PRLI */ +#define UNF_PRLI_PAYLOAD_LEN sizeof(struct unf_pril_payload_s) + +/* PRLI ACC */ +#define UNF_PRLI_ACC_PAYLOAD_LEN sizeof(struct unf_pril_payload_s) + +/* PRLO */ +#define UNF_PRLO_PAYLOAD_LEN sizeof(struct unf_pril_payload_s) + +#define UNF_PRLO_ACC_PAYLOAD_LEN sizeof(struct unf_pril_payload_s) + +/* PDISC */ +#define UNF_PDISC_PAYLOAD_LEN sizeof(struct unf_plogi_payload_s) + +/* PDISC ACC */ +#define UNF_PDISC_ACC_PAYLOAD_LEN sizeof(struct unf_plogi_payload_s) + +/* ADISC */ +#define UNF_ADISC_PAYLOAD_LEN sizeof(struct unf_adisc_payload_s) + +/* ADISC ACC */ +#define UNF_ADISC_ACC_PAYLOAD_LEN sizeof(struct unf_adisc_payload_s) + +/* RSCN ACC */ +#define UNF_GET_RSCN_ACC_PAYLOAD(v_pkg) \ + (&(((union unf_sfs_u *)(UNF_GET_SFS_ENTRY(v_pkg)))->els_acc.cmnd)) +#define UNF_RSCN_ACC_PAYLOAD_LEN (sizeof(struct unf_els_acc_s) - \ + sizeof(struct unf_fchead_s)) + +/* LOGO ACC */ +#define UNF_LOGO_ACC_PAYLOAD_LEN (sizeof(struct unf_els_acc_s) - \ + sizeof(struct unf_fchead_s)) + +/* RRQ ACC */ +#define UNF_RRQ_ACC_PAYLOAD_LEN (sizeof(struct unf_els_acc_s) - \ + sizeof(struct unf_fchead_s)) + +/* RLS ACC */ +#define UNF_RLS_ACC_PAYLOAD_LEN (sizeof(struct unf_rls_acc_s) - \ + sizeof(struct unf_fchead_s)) + +/* GPN_ID */ +#define UNF_GPNID_PAYLOAD_LEN (sizeof(struct unf_gpnid_s) - \ + sizeof(struct unf_fchead_s)) + +#define UNF_GPNID_RSP_PAYLOAD_LEN (sizeof(struct unf_gpnid_rsp_s) - \ + sizeof(struct unf_fchead_s)) + +/* GNN_ID */ +#define UNF_GNNID_PAYLOAD_LEN (sizeof(struct unf_gnnid_s) - \ + sizeof(struct unf_fchead_s)) + +#define UNF_GNNID_RSP_PAYLOAD_LEN (sizeof(struct unf_gnnid_rsp_s) - \ + sizeof(struct unf_fchead_s)) + +/* GFF_ID */ +#define UNF_GFFID_PAYLOAD_LEN (sizeof(struct unf_gffid_s) - \ + sizeof(struct unf_fchead_s)) + +#define UNF_GFFID_RSP_PAYLOAD_LEN (sizeof(struct unf_gffid_rsp_s) - \ + sizeof(struct unf_fchead_s)) + +/* GID_FT/GID_PT */ +#define UNF_GET_GID_PAYLOAD(v_pkg) (&(((union unf_sfs_u *) \ + UNF_GET_SFS_ENTRY(v_pkg))->get_id.gid_req.ctiu_pream)) + +#define UNF_GID_PAYLOAD_LEN (sizeof(struct unf_ctiu_prem_s) + \ + sizeof(unsigned int)) + +#define UNF_GID_ACC_PAYLOAD_LEN sizeof(struct unf_gif_acc_pld_s) + +/* RFT_ID */ +#define UNF_RFTID_PAYLOAD_LEN (sizeof(struct unf_rftid_s) - \ + sizeof(struct unf_fchead_s)) + +#define UNF_RFTID_RSP_PAYLOAD_LEN sizeof(struct unf_ctiu_prem_s) + +/* RFF_ID */ +#define UNF_RFFID_PAYLOAD_LEN (sizeof(struct unf_rffid_s) - \ + sizeof(struct unf_fchead_s)) + +#define UNF_RFFID_RSP_PAYLOAD_LEN sizeof(struct unf_ctiu_prem_s) + +/* SRR */ +#define UNF_SRR_PAYLOAD_LEN \ + sizeof(struct unf_srr_payload_s) + +/* ACC&RJT */ +#define UNF_ELS_ACC_RJT_LEN (sizeof(struct unf_els_rjt_s) - \ + sizeof(struct unf_fchead_s)) + +/* SCR */ +#define UNF_SCR_PAYLOAD_LEN (sizeof(struct unf_scr_s) - \ + sizeof(struct unf_fchead_s)) + +#define UNF_SCR_RSP_PAYLOAD_LEN (sizeof(struct unf_els_acc_s) - \ + sizeof(struct unf_fchead_s)) + +/**********************************************************/ +#define UNF_GET_XCHG_TAG(v_pkg) (((struct unf_frame_pkg_s *) \ + v_pkg)->private[PKG_PRIVATE_XCHG_HOT_POOL_INDEX]) + +#define UNF_GET_SID(v_pkg) (((struct unf_frame_pkg_s *) \ + v_pkg)->frame_head.csctl_sid & UNF_NPORTID_MASK) +#define UNF_GET_DID(v_pkg) (((struct unf_frame_pkg_s *) \ + v_pkg)->frame_head.rctl_did & UNF_NPORTID_MASK) +#define UNF_GET_OXID(v_pkg) (((struct unf_frame_pkg_s *) \ + v_pkg)->frame_head.oxid_rxid >> 16) +#define UNF_GET_RXID(v_pkg) ((unsigned short)((struct unf_frame_pkg_s *) \ + v_pkg)->frame_head.oxid_rxid) +#define UNF_GET_XFER_LEN(v_pkg) (((struct unf_frame_pkg_s *)v_pkg)->transfer_len) + +/* ioc abort */ +#define UNF_GETXCHGALLOCTIME(v_pkg) \ + (((struct unf_frame_pkg_s *)v_pkg)->private[PKG_PRIVATE_XCHG_ALLOC_TIME]) +#define UNF_SET_XCHG_ALLOC_TIME(pkg, xchg) \ + (((struct unf_frame_pkg_s *)(pkg))->private[PKG_PRIVATE_XCHG_ALLOC_TIME] = \ + (((struct unf_xchg_s *)(xchg))->private[PKG_PRIVATE_XCHG_ALLOC_TIME])) +#define UNF_SET_ABORT_INFO_IOTYPE(pkg, xchg) \ + (((struct unf_frame_pkg_s *)(pkg))->private[PKG_PRIVATE_XCHG_ABORT_INFO] |= \ + (((unsigned char)(((struct unf_xchg_s *)(xchg))->data_direction & 0x7))\ + << 2)) + +#define UNF_CHECK_NPORT_FPORT_BIT(els_payload) \ + (((struct unf_flogi_payload_s *)els_payload)->fabric_parms.co_parms.n_port) + +#define UNF_N_PORT 0 +#define UNF_F_PORT 1 + +#define UNF_GET_RA_TOV_FROM_PARAMS(params) \ + (((struct unf_fabric_parms_s *)params)->co_parms.r_a_tov) +#define UNF_GET_RT_TOV_FROM_PARAMS(params) \ + (((struct unf_fabric_parms_s *)params)->co_parms.r_t_tov) +#define UNF_GET_E_D_TOV_FROM_PARAMS(params) \ + (((struct unf_fabric_parms_s *)params)->co_parms.e_d_tov) +#define UNF_GET_E_D_TOV_RESOLUTION_FROM_PARAMS(params) \ + (((struct unf_fabric_parms_s *)params)->co_parms.e_d_tov_resolution) +#define UNF_GET_BB_SC_N_FROM_PARAMS(params) \ + (((struct unf_fabric_parms_s *)params)->co_parms.bb_scn) +#define UNF_GET_BB_CREDIT_FROM_PARAMS(params) \ + (((struct unf_fabric_parms_s *)params)->co_parms.bb_credit) +enum unf_pcie_error_code_e { + UNF_PCIE_ERROR_NONE = 0, + UNF_PCIE_DATAPARITYDETECTED = 1, + UNF_PCIE_SIGNALTARGETABORT, + UNF_PCIE_RECEIVEDTARGETABORT, + UNF_PCIE_RECEIVEDMASTERABORT, + UNF_PCIE_SIGNALEDSYSTEMERROR, + UNF_PCIE_DETECTEDPARITYERROR, + UNF_PCIE_CORRECTABLEERRORDETECTED, + UNF_PCIE_NONFATALERRORDETECTED, + UNF_PCIE_FATALERRORDETECTED, + UNF_PCIE_UNSUPPORTEDREQUESTDETECTED, + UNF_PCIE_AUXILIARYPOWERDETECTED, + UNF_PCIE_TRANSACTIONSPENDING, + + UNF_PCIE_UNCORRECTINTERERRSTATUS, + UNF_PCIE_UNSUPPORTREQERRSTATUS, + UNF_PCIE_ECRCERRORSTATUS, + UNF_PCIE_MALFORMEDTLPSTATUS, + UNF_PCIE_RECEIVEROVERFLOWSTATUS, + UNF_PCIE_UNEXPECTCOMPLETESTATUS, + UNF_PCIE_COMPLETERABORTSTATUS, + UNF_PCIE_COMPLETIONTIMEOUTSTATUS, + UNF_PCIE_FLOWCTRLPROTOCOLERRSTATUS, + UNF_PCIE_POISONEDTLPSTATUS, + UNF_PCIE_SURPRISEDOWNERRORSTATUS, + UNF_PCIE_DATALINKPROTOCOLERRSTATUS, + UNF_PCIE_ADVISORYNONFATALERRSTATUS, + UNF_PCIE_REPLAYTIMERTIMEOUTSTATUS, + UNF_PCIE_REPLAYNUMROLLOVERSTATUS, + UNF_PCIE_BADDLLPSTATUS, + UNF_PCIE_BADTLPSTATUS, + UNF_PCIE_RECEIVERERRORSTATUS, + + UNF_PCIE_BUTT +}; + +#define UNF_DMA_HI32(a) (((a) >> 32) & 0xffffffff) +#define UNF_DMA_LO32(a) ((a) & 0xffffffff) + +#define UNF_WWN_LEN 8 +#define UNF_MAC_LEN 6 + +/* send BLS/ELS/BLS REPLY/ELS REPLY/GS/ */ +/* rcvd BLS/ELS/REQ DONE/REPLY DONE */ +#define UNF_PKG_BLS_REQ 0x0100 +#define UNF_PKG_BLS_REQ_DONE 0x0101 + +#define UNF_PKG_ELS_REQ 0x0200 + +#define UNF_PKG_ELS_REQ_DONE 0x0201 + +#define UNF_PKG_ELS_REPLY 0x0202 + +#define UNF_PKG_ELS_REPLY_DONE 0x0203 + +#define UNF_PKG_GS_REQ 0x0300 + +#define UNF_PKG_GS_REQ_DONE 0x0301 + +#define UNF_PKG_INI_IO 0x0500 +#define UNF_PKG_INI_RCV_TGT_RSP 0x0507 + +/* external sgl struct start */ +struct unf_esgl_page_s { + unsigned long long page_address; + dma_addr_t esgl_phyaddr; + unsigned int page_size; +}; + +struct unf_esgl_s { + struct list_head entry_esgl; + struct unf_esgl_page_s page; +}; + +/* external sgl struct end */ +struct unf_frame_payld_s { + unsigned char *buffer_ptr; + dma_addr_t buf_dma_addr; + unsigned int length; +}; + +enum pkg_private_index_e { + PKG_PRIVATE_LOWLEVEL_XCHG_ADD = 0, + PKG_PRIVATE_XCHG_HOT_POOL_INDEX = 1, /* Hot Pool Index */ + PKG_PRIVATE_XCHG_RPORT_INDEX = 2, /* RPort index */ + PKG_PRIVATE_XCHG_VP_INDEX = 3, /* VPort index */ + PKG_PRIVATE_RPORT_RX_SIZE, + PKG_PRIVATE_XCHG_TIMEER, + PKG_PRIVATE_XCHG_ALLOC_TIME, + PKG_PRIVATE_XCHG_ABORT_INFO, + PKG_PRIVATE_ECHO_CMD_SND_TIME, /* local send echo cmd time stamp */ + PKG_PRIVATE_ECHO_ACC_RCV_TIME, /* local receive echo acc time stamp */ + PKG_PRIVATE_ECHO_CMD_RCV_TIME, /* remote receive echo cmd time stamp */ + PKG_PRIVATE_ECHO_RSP_SND_TIME, /* remote send echo rsp time stamp */ + PKG_MAX_PRIVATE_DATA_SIZE +}; + +extern unsigned int dix_flag; +extern unsigned int dif_sgl_mode; +extern unsigned int dif_app_esc_check; +extern unsigned int dif_ref_esc_check; + +#define UNF_DIF_ACTION_NONE 0 + +enum unf_adm_dif_mode_e { + UNF_SWITCH_DIF_DIX = 0, + UNF_APP_REF_ESCAPE, + ALL_DIF_MODE = 20, +}; + +#define UNF_VERIFY_CRC_MASK (1 << 1) +#define UNF_VERIFY_APP_MASK (1 << 2) +#define UNF_VERIFY_LBA_MASK (1 << 3) + +#define UNF_REPLACE_CRC_MASK (1 << 8) +#define UNF_REPLACE_APP_MASK (1 << 9) +#define UNF_REPLACE_LBA_MASK (1 << 10) + +#define UNF_DIF_ACTION_MASK (0xff << 16) +#define UNF_DIF_ACTION_INSERT (0x1 << 16) +#define UNF_DIF_ACTION_VERIFY_AND_DELETE (0x2 << 16) +#define UNF_DIF_ACTION_VERIFY_AND_FORWARD (0x3 << 16) +#define UNF_DIF_ACTION_VERIFY_AND_REPLACE (0x4 << 16) + +#define UNF_DIF_ACTION_NO_INCREASE_REFTAG (0x1 << 24) + +#define UNF_DEFAULT_CRC_GUARD_SEED (0) +#define UNF_CAL_BLOCK_CNT(data_len, sector_size) ((data_len) / (sector_size)) + +#define UNF_DIF_DOUBLE_SGL (1 << 1) +#define UNF_DIF_SECTSIZE_4KB (1 << 2) +#define UNF_DIF_LBA_NONE_INCREASE (1 << 3) +#define UNF_DIF_TYPE3 (1 << 4) + +#define HIFC_DIF_APP_REF_ESC_NOT_CHECK 1 +#define HIFC_DIF_APP_REF_ESC_CHECK 0 + +enum unf_io_state_e { + UNF_INI_IO = 0, + UNF_TGT_XFER = 1, + UNF_TGT_RSP = 2 +}; + +#define UNF_PKG_LAST_RESPONSE 0 +#define UNF_PKG_NOT_LAST_RESPONSE 1 + +#define UNF_PKG_LAST_REQUEST 1 +#define UNF_PKG_NOT_LAST_REQUEST 0 + +struct unf_frame_pkg_s { + /* pkt type:BLS/ELS/FC4LS/CMND/XFER/RSP */ + unsigned int type; + unsigned int last_pkg_flag; + +#define UNF_FCP_RESPONSE_VALID 0x01 +#define UNF_FCP_SENSE_VALID 0x02 + /* resp and sense vailed flag */ + unsigned int response_and_sense_valid_flag; + unsigned int cmnd; + struct unf_fchead_s frame_head; + unsigned int entry_count; + void *xchg_contex; + unsigned int transfer_len; + unsigned int residus_len; + unsigned int status; + unsigned int status_sub_code; + enum unf_io_state_e io_state; + unsigned int qos_level; + + unsigned int private[PKG_MAX_PRIVATE_DATA_SIZE]; + + unsigned char byte_orders; + + struct unf_fcp_cmnd_s *fcp_cmnd; + struct unf_dif_control_info_s dif_control; + struct unf_frame_payld_s unf_cmnd_pload_bl; + struct unf_frame_payld_s unf_rsp_pload_bl; + struct unf_frame_payld_s unf_sense_pload_bl; + void *upper_cmd; + unsigned int abts_maker_status; + +}; + +#define UNF_MAX_SFS_XCHG 2048 +#define UNF_RESERVE_SFS_XCHG 128 /* times on exchange mgr num */ + +struct unf_lport_cfg_item_s { + unsigned int port_id; + unsigned int port_mode; /* INI(0x20) TGT(0x10) BOTH(0x30) */ + unsigned int port_topology; /* 0x3:loop , 0xc:p2p ,0xf:auto */ + unsigned int max_queue_depth; + unsigned int max_io; /* Recommended Value 512-4096 */ + unsigned int max_login; + unsigned int max_sfs_xchg; + /* 0:auto 1:1Gbps 2:2Gbps 4:4Gbps 8:8Gbps 16:16Gbps */ + unsigned int port_speed; + unsigned int tape_support; /* tape support */ + unsigned int fcp_conf; /* fcp confirm support */ + unsigned int bb_scn; + unsigned int sum_resource; + enum int_e res_mgmt_enabled; +}; + +struct unf_port_dynamic_info_s { + unsigned int sfp_posion; + unsigned int sfp_valid; + unsigned int phy_link; + unsigned int firmware_state; + unsigned int cur_speed; + unsigned int mailbox_timeout_cnt; +}; + +struct unf_hinicam_pkg { + unsigned int msg_format; + void *buff_in; + void *buff_out; + unsigned int in_size; + unsigned int *out_size; +}; + +struct unf_version_str_s { + char *buf; + unsigned int buf_len; +}; + +struct unf_buf_s { + unsigned char *cbuf; + unsigned int buf_len; +}; + +struct unf_rw_reg_param_s { + unsigned int rw_type; + unsigned int offset; + unsigned long long value; +}; + +/* get ucode & up ver */ +#define HIFC_VER_LEN (16) +#define HIFC_COMPILE_TIME_LEN (20) +struct unf_fw_version_s { + unsigned int message_type; + unsigned char fw_version[HIFC_VER_LEN]; +}; + +enum unf_port_config_set_op_e { + UNF_PORT_CFG_SET_SPEED, + UNF_PORT_CFG_SET_TOPO, + UNF_PORT_CFG_SET_BBSCN, + UNF_PORT_CFG_SET_MODE, + UNF_PORT_CFG_SET_SFP_SWITCH, + UNF_PORT_CFG_SET_PORT_SWITCH, + UNF_PORT_CFG_SET_POWER_STATE, + UNF_PORT_CFG_SET_PORT_STATE, + UNF_PORT_CFG_SET_INTR_COALSEC, + UNF_PORT_CFG_UPDATE_PORT, + UNF_PORT_CFG_UPDATE_WWN, + UNF_PORT_CFG_TEST_FLASH, + UNF_PORT_CFG_SET_FCP_CONF, + UNF_PORT_CFG_SET_LOOP_ROLE, + UNF_PORT_CFG_SET_INIT_REQ, + UNF_PORT_CFG_SET_MAX_SUPPORT_SPEED, + UNF_PORT_CFG_SET_MAC_ADDR, + UNF_PORT_CFG_SET_SFP_USEDTIME, + UNF_PORT_CFG_SET_PORT_TRANSFER_PARAMETER, + UNF_PORT_CFG_SET_SFP_REG_WRITE, + UNF_PORT_CFG_UPDATE_SFP, + UNF_PORT_CFG_UPDATE_FABRIC_PARAM, + UNF_PORT_CFG_UPDATE_PLOGI_PARAM, + UNF_PORT_CFG_UPDATE_FDISC_PARAM, + UNF_PORT_CFG_SAVE_HBA_INFO, + UNF_PORT_CFG_SET_HBA_BASE_INFO, + UNF_PORT_CFG_SET_FLASH_DATA_INFO, + UNF_PORT_CFG_SET_BUTT +}; + +enum unf_port_config_get_op_e { + UNF_PORT_CFG_GET_SPEED_CFG, + UNF_PORT_CFG_GET_SPEED_ACT, + UNF_PORT_CFG_GET_TOPO_CFG, + UNF_PORT_CFG_GET_TOPO_ACT, + UNF_PORT_CFG_GET_MODE, + UNF_PORT_CFG_GET_LOOP_MAP, + UNF_PORT_CFG_GET_TOV, + UNF_PORT_CFG_GET_SFP_PRESENT, + UNF_PORT_CFG_GET_SFP_INFO, + UNF_PORT_CFG_GET_FW_VER, + UNF_PORT_CFG_GET_HW_VER, + UNF_PORT_CFG_GET_LESB_THEN_CLR, /* Link Error Status Block, LESB */ + UNF_PORT_CFG_GET_DYNAMIC_INFO, + UNF_PORT_CFG_GET_VITAL_REGS, + UNF_PORT_CFG_CLR_LESB, + UNF_PORT_CFG_GET_WORKBALE_BBCREDIT, + UNF_PORT_CFG_GET_WORKBALE_BBSCN, + UNF_PORT_CFG_GET_FC_SERDES, + UNF_PORT_CFG_GET_LOOP_ALPA, + UNF_PORT_CFG_GET_SFP_DYNAMIC_INFO, + UNF_PORT_CFG_GET_MAC_ADDR, + UNF_PORT_CFG_GET_SFP_USEDTIME, + UNF_PORT_CFG_GET_PORT_INFO, + UNF_PORT_CFG_DDT_TEST, + UNF_PORT_CFG_GET_LED_STATE, + UNF_PORT_CFG_GET_VLAN, + UNF_PORT_CFG_GET_SFP_REG_READ, + UNF_PORT_CFG_GET_SFP_VER, + UNF_PORT_CFG_GET_SFP_SUPPORT_UPDATE, + UNF_PORT_CFG_GET_SFP_LOG, + UNF_PORT_CFG_GET_FEC, + UNF_PORT_CFG_GET_PCIE_LINK_STATE, + UNF_PORT_CFG_GET_FLASH_DATA_INFO, + UNF_PORT_CFG_GET_BUTT +}; + +enum unf_port_diag_op_e { + UNF_PORT_DIAG_PORT_DETAIL, + UNF_PORT_DIAG_RD_WR_REG, + UNF_PORT_DIAG_BUTT +}; + +enum unf_port_config_state_e { + UNF_PORT_CONFIG_STATE_START, + UNF_PORT_CONFIG_STATE_STOP, + UNF_PORT_CONFIG_STATE_RESET, + UNF_PORT_CONFIG_STATE_STOP_INTR, + UNF_PORT_CONFIG_STATE_BUTT +}; + +struct unf_port_login_parms_s { + enum unf_act_topo_e en_act_topo; + + unsigned int rport_index; + unsigned int seq_cnt : 1; + unsigned int ed_tov : 1; + unsigned int reserved : 14; + unsigned int tx_mfs : 16; + unsigned int ed_tov_timer_val; + + unsigned char remote_rttov_tag; + unsigned char remote_edtov_tag; + unsigned short remote_bbcredit; + unsigned short compared_bbscn; + unsigned int compared_edtov_val; + unsigned int compared_ratov_val; + unsigned int els_cmnd_code; +}; + +#define HIFC_FLASH_MAX_LEN 1024 // bytes + +struct unf_mbox_head_info_s { + /* mbox header */ + unsigned char cmnd_type; + unsigned char length; + unsigned char port_id; + unsigned char pad0; + + /* operation */ + unsigned int op_code : 4; + unsigned int pad1 : 28; +}; + +#define HIFC_FLASH_MBOX_HEAD_MAX_LEN 8 // bytes +struct unf_mbox_head_sts_s { + /* mbox header */ + unsigned char cmnd_type; + unsigned char length; + unsigned char port_id; + unsigned char pad0; + + /* operation */ + unsigned short pad1; + unsigned char pad2; + unsigned char status; +}; + +#define HIFC_FLASH_UEFI_MAX_LEN 16 // bytes +struct unf_flash_uefi_switch_s { + unsigned char writeflag; + unsigned char sanbooten; + unsigned char reserved[14]; +}; + +#define HIFC_MGMT_UEFI_MAGIC_NUM 0xAF +#define HIFC_MGMT_TMO_MAGIC_NUM 0xAE + +#define HIFC_FLASH_LINK_TMO_MAX_LEN 16 // bytes +struct unf_flash_link_tmo_s { + unsigned char writeflag; + unsigned char link_tmo0; + unsigned char link_tmo1; + unsigned char link_tmo2; + unsigned char link_tmo3; + unsigned char reserved[11]; +}; + +#define HIFC_FLASH_DATA_MAX_LEN (HIFC_FLASH_MAX_LEN - \ + HIFC_FLASH_MBOX_HEAD_MAX_LEN) // bytes +struct unf_flash_data_s { + struct unf_flash_uefi_switch_s uefi_switch; // 16 bytes + struct unf_flash_link_tmo_s link_tmo; // 16 bytes + /* once the related struct change, the reserved size needs modify */ + unsigned char reserved[HIFC_FLASH_DATA_MAX_LEN - 32]; +}; + +/* size of hifc_flash_data_mgmt not more than 1024 bytes */ +struct unf_mbox_flash_data_mgmt_s { + struct unf_mbox_head_info_s mbox_head; // 8 bytes + struct unf_flash_data_s flash_data; +}; + +struct unf_flash_data_mgmt_sts_s { + struct unf_mbox_head_sts_s mbox_head; // 8 bytes + struct unf_flash_data_s flash_data; +}; + +struct unf_low_level_service_op_s { + unsigned int (*pfn_unf_els_send)(void *, struct unf_frame_pkg_s *); + unsigned int (*pfn_unf_bls_send)(void *, struct unf_frame_pkg_s *); + unsigned int (*pfn_unf_gs_send)(void *, struct unf_frame_pkg_s *); + unsigned int (*pfn_unf_fc_4_ls_send)(void *, struct unf_frame_pkg_s *); + unsigned int (*pfn_unf_cmnd_send)(void *, struct unf_frame_pkg_s *); + unsigned int (*pfn_ll_relese_xchg_res)(void *, + struct unf_frame_pkg_s *); + unsigned int (*pfn_unf_release_rport_res)(void *, struct + unf_rport_info_s *); + unsigned int (*pfn_unf_get_consumed_res)(void *, + struct unf_frame_pkg_s *); + unsigned int (*pfn_unf_flush_ini_resp_que)(void *); + unsigned int (*pfn_unf_alloc_rport_res)(void *, + struct unf_rport_info_s *); + unsigned int (*pfn_unf_rport_session_rst)(void *, + struct unf_rport_info_s *); +}; + +struct unf_low_level_port_mgr_op_s { + /* fcport/opcode/input parameter */ + unsigned int (*pfn_ll_port_config_set) + (void *v_fc_port, + enum unf_port_config_set_op_e v_op_code, + void *v_para_in); + /* fcport/opcode/output parameter */ + unsigned int (*pfn_ll_port_config_get) + (void *v_fc_port, + enum unf_port_config_get_op_e v_op_code, + void *v_para_out); + /* fcport/opcode/input parameter/output parameter */ + unsigned int (*pfn_ll_port_diagnose) + (void *v_fc_port, + enum unf_port_diag_op_e v_op_code, + void *v_para); + +}; + +struct unf_chip_info_s { + unsigned char chip_type; + unsigned char chip_work_mode; + unsigned char disable_err_flag; +}; + +struct unf_low_level_function_op_s { + struct unf_chip_info_s chip_info; + /* low level type */ + unsigned int low_level_type; + /* low level name, fc etc. */ + const char *name; + struct pci_dev *dev; + unsigned long long sys_node_name; + unsigned long long sys_port_name; + + struct unf_lport_cfg_item_s lport_cfg_items; + + /* low level Xchg mgr type, + * active --alloc oxid and rxid + * passtive -- not alloc oxid and rxid + */ +#define UNF_LOW_LEVEL_MGR_TYPE_ACTIVE 0 +#define UNF_LOW_LEVEL_MGR_TYPE_PASSTIVE 1 + const unsigned int xchg_mgr_type; + +#define UNF_NO_EXTRA_ABTS_XCHG 0x0 +#define UNF_LL_IOC_ABTS_XCHG 0x1 + const unsigned int abts_xchg; +#define UNF_CM_RPORT_SET_QUALIFIER 0x0 +#define UNF_CM_RPORT_SET_QUALIFIER_REUSE 0x1 +#define UNF_CM_RPORT_SET_QUALIFIER_HIFC 0x2 + /* low level pass-through flag. */ +#define UNF_LOW_LEVEL_PASS_THROUGH_FIP 0x0 +#define UNF_LOW_LEVEL_PASS_THROUGH_FABRIC_LOGIN 0x1 +#define UNF_LOW_LEVEL_PASS_THROUGH_PORT_LOGIN 0x2 + unsigned int pass_through_flag; + /* low level parameter */ + unsigned int support_max_npiv_num; + unsigned int support_max_speed; + unsigned int fc_ser_max_speed; + unsigned int support_max_rport; + unsigned int support_max_xid_range; + unsigned int sfp_type; + unsigned int update_fw_reset_active; + unsigned int support_upgrade_report; + unsigned int multi_conf_support; + unsigned int port_type; +#define UNF_LOW_LEVEL_RELEASE_RPORT_SYNC 0x0 +#define UNF_LOW_LEVEL_RELEASE_RPORT_ASYNC 0x1 + unsigned char rport_release_type; +#define UNF_LOW_LEVEL_SIRT_PAGE_MODE_FIXED 0x0 +#define UNF_LOW_LEVEL_SIRT_PAGE_MODE_XCHG 0x1 + unsigned char sirt_page_mode; + unsigned char sfp_speed; + /* IO reference */ + struct unf_low_level_service_op_s service_op; + /* Port Mgr reference */ + struct unf_low_level_port_mgr_op_s port_mgr_op; + unsigned char chip_id; +}; + +struct unf_cm_handle_op_s { + /* return:L_Port */ + void *(*pfn_unf_alloc_local_port)(void *, + struct unf_low_level_function_op_s *); + /* input para:L_Port */ + unsigned int (*pfn_unf_release_local_port)(void *); + /* input para:lport vn2vnid,output para:ok/err */ + unsigned int (*pfn_unf_set_vn2vn_id)(void *, unsigned int); + unsigned char (*pfn_unf_get_loop_id)(unsigned int v_port_id); + /* input para:L_Port, FRAME_PKG_S */ + unsigned int (*pfn_unf_receive_els_pkg)(void *v_lport, + struct unf_frame_pkg_s *v_pkg); + /* input para:L_Port, FRAME_PKG_S */ + unsigned int (*pfn_unf_receive_gs_pkg)(void *v_lport, + struct unf_frame_pkg_s *v_pkg); + /* input para:L_Port, FRAME_PKG_S */ + unsigned int (*pfn_unf_receive_bls_pkg)(void *v_lport, + struct unf_frame_pkg_s *v_pkg); + /* input para:L_Port, FRAME_PKG_S */ + unsigned int (*pfn_unf_receive_fc4_ls_pkg)( + void *v_lport, + struct unf_frame_pkg_s *v_pkg); + /* input para:L_Port, FRAME_PKG_S */ + unsigned int (*pfn_unf_send_els_done)(void *v_lport, + struct unf_frame_pkg_s *v_pkg); + unsigned int (*pfn_unf_send_fc4_ls_done)(void *v_lport, + struct unf_frame_pkg_s *v_pkg); + /* input para:L_Port, FRAME_PKG_S */ + unsigned int (*pfn_unf_receive_marker_status)( + void *v_lport, struct unf_frame_pkg_s *v_pkg); + unsigned int (*pfn_unf_receive_abts_marker_status)( + void *v_lport, struct unf_frame_pkg_s *v_pkg); + /* input para:L_Port, FRAME_PKG_S */ + unsigned int (*pfn_unf_receive_ini_rsponse)( + void *v_lport, struct unf_frame_pkg_s *v_pkg); + int (*pfn_unf_get_cfg_parms)(char *v_section_name, + struct unf_cfg_item_s *v_cfg_parm, + unsigned int *v_cfg_value, + unsigned int v_item_num); + unsigned int (*pfn_unf_cm_get_sgl_entry)(void *v_pkg, + char **v_buf, + unsigned int *v_buf_len); + unsigned int (*pfn_unf_cm_get_dif_sgl_entry)(void *v_pkg, + char **v_buf, + unsigned int *v_buf_len); + struct unf_esgl_page_s *(*pfn_unf_get_one_free_esgl_page)( + void *v_lport, struct unf_frame_pkg_s *v_pkg); + /* input para:L_Port, EVENT */ + unsigned int (*pfn_unf_fc_port_link_event)(void *v_lport, + unsigned int v_events, + void *v_input); + unsigned int (*pfn_unf_fcoe_update_fcf_name)(void *v_lport, + void *v_input); + int (*pfn_unf_ioctl_to_com_handler)(void *v_lport, + struct unf_hinicam_pkg *v_pkg); +}; + +unsigned int unf_get_cm_handle_op(struct unf_cm_handle_op_s *v_cm_handle); +int unf_common_init(void); +void unf_common_exit(void); + +struct unf_port_info_entry_s { + unsigned int bb_scn; + unsigned int speed; + unsigned int topo; + unsigned int fec; +}; + +enum drv_cable_connector_type_e { + DRV_CABLE_CONNECTOR_NONE, + DRV_CABLE_CONNECTOR_OPTICAL, + DRV_CABLE_CONNECTOR_COPPER, + DRV_CABLE_CONNECTOR_INVALID, + DRV_CABLE_CONNECTOR_BUTT +}; + +#endif diff --git a/drivers/scsi/huawei/hifc/unf_init.c b/drivers/scsi/huawei/hifc/unf_init.c new file mode 100644 index 000000000000..c902a7f71bf5 --- /dev/null +++ b/drivers/scsi/huawei/hifc/unf_init.c @@ -0,0 +1,564 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Huawei Fabric Channel Linux driver + * Copyright(c) 2018 Huawei Technologies Co., Ltd + * + */ + +#include "unf_log.h" +#include "unf_event.h" +#include "unf_exchg.h" +#include "unf_portman.h" +#include "unf_rport.h" +#include "unf_service.h" +#include "unf_io.h" + +#define RPORT_FEATURE_POOL_SIZE 4096 + +static struct unf_esgl_page_s *unf_cm_get_one_free_esgl_page( + void *v_lport, + struct unf_frame_pkg_s *v_fra_pkg); +static unsigned int unf_recv_tmf_marker_status( + void *v_lport, + struct unf_frame_pkg_s *v_fra_pkg); +static unsigned int unf_recv_abts_mrker_status( + void *v_lport, + struct unf_frame_pkg_s *v_fra_pkg); +static int unf_get_cfg_parms(char *v_section_name, + struct unf_cfg_item_s *v_cfg_parm, + unsigned int *v_cfg_value, + unsigned int v_item_num); + + +/* global variables */ +unsigned int event_thread_exit; +struct task_struct *event_thread; + +struct completion *fc_event_handle_thd_comp; +struct workqueue_struct *unf_work_queue; + +struct unf_global_card_thread_s card_thread_mgr; +unsigned int unf_dbg_level = UNF_MAJOR; +unsigned int log_print_level = UNF_INFO; +unsigned int log_limted_times = UNF_LOGIN_ATT_PRINT_TIMES; + +struct unf_cm_handle_op_s cm_low_levle_handle = { + .pfn_unf_alloc_local_port = unf_lport_create_and_init, + .pfn_unf_release_local_port = unf_release_local_port, + .pfn_unf_receive_els_pkg = unf_receive_els_pkg, + .pfn_unf_receive_gs_pkg = unf_receive_gs_pkg, + .pfn_unf_receive_bls_pkg = unf_receive_bls_pkg, + .pfn_unf_send_els_done = unf_send_els_done, + .pfn_unf_receive_ini_rsponse = unf_ini_scsi_completed, + .pfn_unf_get_cfg_parms = unf_get_cfg_parms, + .pfn_unf_receive_marker_status = unf_recv_tmf_marker_status, + .pfn_unf_receive_abts_marker_status = unf_recv_abts_mrker_status, + + .pfn_unf_cm_get_sgl_entry = unf_ini_get_sgl_entry, + .pfn_unf_cm_get_dif_sgl_entry = unf_ini_get_dif_sgl_entry, + .pfn_unf_get_one_free_esgl_page = unf_cm_get_one_free_esgl_page, + .pfn_unf_fc_port_link_event = unf_fc_port_link_event, + .pfn_unf_ioctl_to_com_handler = unf_cmd_adm_handler, +}; + +static struct unf_esgl_page_s *unf_cm_get_one_free_esgl_page( + void *v_lport, + struct unf_frame_pkg_s *v_fra_pkg) +{ + struct unf_lport_s *lport = NULL; + struct unf_xchg_s *xchg = NULL; + + UNF_CHECK_VALID(0x1700, 1, v_lport, return NULL); + UNF_CHECK_VALID(0x1701, 1, v_fra_pkg, return NULL); + + lport = (struct unf_lport_s *)v_lport; + xchg = (struct unf_xchg_s *)v_fra_pkg->xchg_contex; + + return unf_get_one_free_esgl_page(lport, xchg); /* from esgl pool */ +} + +static int unf_get_cfg_parms(char *v_section_name, + struct unf_cfg_item_s *v_cfg_parm, + unsigned int *v_cfg_value, + unsigned int v_item_num) +{ + /* Maximum length of a configuration item value, + * including the end character + */ +#define UNF_MAX_ITEM_VALUE_LEN (256) + + unsigned int *value = NULL; + struct unf_cfg_item_s *cfg_parm = NULL; + unsigned int i = 0; + + cfg_parm = v_cfg_parm; + value = v_cfg_value; + + for (i = 0; i < v_item_num; i++) { + if (!cfg_parm || !value) { + UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, + UNF_LOG_REG_ATT, UNF_ERR, + "[err]Config name or value is NULL"); + + return UNF_RETURN_ERROR; + } + + if (strcmp("End", cfg_parm->name) == 0) + break; + + if (strcmp("fw_path", cfg_parm->name) == 0) { + cfg_parm++; + value += UNF_MAX_ITEM_VALUE_LEN / sizeof(unsigned int); + + continue; + } + + *value = cfg_parm->default_value; + cfg_parm++; + value++; + } + + return RETURN_OK; +} + +static unsigned int unf_recv_tmf_marker_status( + void *v_lport, + struct unf_frame_pkg_s *v_fra_pkg) +{ + struct unf_lport_s *lport = NULL; + struct unf_xchg_s *xchg = NULL; + unsigned short hot_pool_tag = 0; + + UNF_CHECK_VALID(0x3543, UNF_TRUE, v_lport, return UNF_RETURN_ERROR); + UNF_CHECK_VALID(0x3544, UNF_TRUE, v_fra_pkg, return UNF_RETURN_ERROR); + lport = (struct unf_lport_s *)v_lport; + + /* Find exchange which point to marker sts */ + if (!lport->xchg_mgr_temp.pfn_unf_look_up_xchg_by_tag) { + UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_LOGIN_ATT, UNF_ERR, + "[err]Port(0x%x) tag function is NULL", + lport->port_id); + + return UNF_RETURN_ERROR; + } + + hot_pool_tag = (unsigned short) + (v_fra_pkg->private[PKG_PRIVATE_XCHG_HOT_POOL_INDEX]); + + xchg = (struct unf_xchg_s *) + (lport->xchg_mgr_temp.pfn_unf_look_up_xchg_by_tag((void *)lport, + hot_pool_tag)); + if (!xchg) { + UNF_TRACE(UNF_EVTLOG_DRIVER_WARN, UNF_LOG_LOGIN_ATT, UNF_WARN, + "[warn]Port(0x%x_0x%x) find exchange by tag(0x%x) failed", + lport->port_id, lport->nport_id, hot_pool_tag); + + return UNF_RETURN_ERROR; + } + + /* + * NOTE: set exchange TMF state with MARKER_STS_RECEIVED + * + * About TMF state + * 1. STS received + * 2. Response received + * 3. Do check if necessary + */ + xchg->tmf_state |= MARKER_STS_RECEIVED; + + UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_IO_ATT, UNF_MAJOR, + "[info]Marker STS: D_ID(0x%x) S_ID(0x%x) OX_ID(0x%x) RX_ID(0x%x), EXCH: D_ID(0x%x) S_ID(0x%x) OX_ID(0x%x) RX_ID(0x%x)", + v_fra_pkg->frame_head.rctl_did & UNF_NPORTID_MASK, + v_fra_pkg->frame_head.csctl_sid & UNF_NPORTID_MASK, + (unsigned short)(v_fra_pkg->frame_head.oxid_rxid >> 16), + (unsigned short)(v_fra_pkg->frame_head.oxid_rxid), + xchg->did, + xchg->sid, + xchg->ox_id, + xchg->rx_id); + + return RETURN_OK; +} + +static unsigned int unf_recv_abts_mrker_status( + void *v_lport, + struct unf_frame_pkg_s *v_fra_pkg) +{ + struct unf_lport_s *lport = NULL; + struct unf_xchg_s *xchg = NULL; + unsigned short hot_pool_tag = 0; + unsigned long flags = 0; + + UNF_CHECK_VALID(0x3543, UNF_TRUE, v_lport, return UNF_RETURN_ERROR); + UNF_CHECK_VALID(0x3544, UNF_TRUE, v_fra_pkg, return UNF_RETURN_ERROR); + lport = (struct unf_lport_s *)v_lport; + + /* Find exchange by tag */ + if (!lport->xchg_mgr_temp.pfn_unf_look_up_xchg_by_tag) { + UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_LOGIN_ATT, UNF_ERR, + "[err]Port(0x%x) tag function is NULL", + lport->port_id); + + return UNF_RETURN_ERROR; + } + + hot_pool_tag = (unsigned short) + (v_fra_pkg->private[PKG_PRIVATE_XCHG_HOT_POOL_INDEX]); + + xchg = (struct unf_xchg_s *) + (lport->xchg_mgr_temp.pfn_unf_look_up_xchg_by_tag((void *)lport, + hot_pool_tag)); + if (!xchg) { + UNF_TRACE(UNF_EVTLOG_DRIVER_WARN, UNF_LOG_LOGIN_ATT, UNF_WARN, + "[warn]Port(0x%x_0x%x) find exchange by tag(0x%x) failed", + lport->port_id, lport->nport_id, hot_pool_tag); + + return UNF_RETURN_ERROR; + } + + /* + * NOTE: set exchange ABTS state with MARKER_STS_RECEIVED + * + * About exchange ABTS state + * 1. STS received + * 2. Response received + * 3. Do check if necessary + * + * About Exchange status get from low level + * 1. Set: when RCVD ABTS Marker + * 2. Set: when RCVD ABTS Req Done + * 3. value: set value with pkg->status + */ + spin_lock_irqsave(&xchg->xchg_state_lock, flags); + xchg->ucode_abts_state = v_fra_pkg->status; + xchg->abts_state |= MARKER_STS_RECEIVED; + + UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_LOGIN_ATT, UNF_KEVENT, + "[info]Port(0x%x) wake up SEMA for Abts marker exchange(0x%p) oxid(0x%x 0x%x) status(0x%x)", + lport->port_id, xchg, xchg->ox_id, xchg->hot_pool_tag, + v_fra_pkg->abts_maker_status); + + /* + * NOTE: Second time for ABTS marker received, or + * ABTS response have been received, no need to wake up sema + */ + if ((xchg->io_state & INI_IO_STATE_ABORT_TIMEOUT) || + (xchg->abts_state & ABTS_RESPONSE_RECEIVED)) { + spin_unlock_irqrestore(&xchg->xchg_state_lock, flags); + + UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_LOGIN_ATT, + UNF_KEVENT, + "[info]Port(0x%x) no need to wake up SEMA for Abts marker ABTS_STATE(0x%x) IO_STATE(0x%x)", + lport->port_id, xchg->abts_state, + xchg->io_state); + + return RETURN_OK; + } + if (xchg->io_state & INI_IO_STATE_TMF_ABORT) { + spin_unlock_irqrestore(&xchg->xchg_state_lock, flags); + UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_LOGIN_ATT, + UNF_KEVENT, + "[info]Port(0x%x) receive Abts marker, exchange(%p) state(0x%x) free it", + lport->port_id, xchg, xchg->io_state); + + unf_cm_free_xchg(lport, xchg); + } else { + spin_unlock_irqrestore(&xchg->xchg_state_lock, flags); + up(&xchg->task_sema); + } + + return RETURN_OK; +} + +unsigned int unf_get_cm_handle_op(struct unf_cm_handle_op_s *v_cm_handle) +{ + UNF_CHECK_VALID(0x1708, UNF_TRUE, v_cm_handle, + return UNF_RETURN_ERROR); + + memcpy(v_cm_handle, &cm_low_levle_handle, + sizeof(struct unf_cm_handle_op_s)); + + return RETURN_OK; +} + +static void unf_uninit_cm_low_level_handle(void) +{ + memset(&cm_low_levle_handle, 0, sizeof(struct unf_cm_handle_op_s)); +} + +int unf_event_process(void *v_arg) +{ + struct list_head *node = NULL; + struct unf_cm_event_report *event_node = NULL; + unsigned long flags = 0; + + UNF_REFERNCE_VAR(v_arg); + + set_user_nice(current, 4); + recalc_sigpending(); + + UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_INFO, + "[event]Enter event thread"); + + complete(fc_event_handle_thd_comp); + + do { + spin_lock_irqsave(&fc_event_list.fc_eventlist_lock, flags); + if (list_empty(&fc_event_list.list_head) == UNF_TRUE) { + spin_unlock_irqrestore(&fc_event_list.fc_eventlist_lock, + flags); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout((long)msecs_to_jiffies(1000)); + } else { + node = (&fc_event_list.list_head)->next; + list_del_init(node); + fc_event_list.list_num--; + event_node = list_entry(node, + struct unf_cm_event_report, + list_entry); + spin_unlock_irqrestore(&fc_event_list.fc_eventlist_lock, + flags); + + /* Process event node */ + unf_handle_event(event_node); + } + } while (!event_thread_exit); + + complete_and_exit(fc_event_handle_thd_comp, 0); + + UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_EVENT, UNF_MAJOR, + "[event]Event thread exit"); + + return RETURN_OK; +} + +static unsigned int unf_creat_event_center(void) +{ + struct completion fc_event_completion = + COMPLETION_INITIALIZER(fc_event_completion); + + struct completion *p_fc_event_completion = &fc_event_completion; + + INIT_LIST_HEAD(&fc_event_list.list_head); + fc_event_list.list_num = 0; + spin_lock_init(&fc_event_list.fc_eventlist_lock); + fc_event_handle_thd_comp = p_fc_event_completion; + + event_thread = kthread_run(unf_event_process, NULL, "hifc_event"); + if (IS_ERR(event_thread)) { + complete_and_exit(fc_event_handle_thd_comp, 0); + fc_event_handle_thd_comp = NULL; + + UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_REG_ATT, UNF_ERR, + "[err]Create event thread failed(0x%p)", + event_thread); + + return UNF_RETURN_ERROR; + } + wait_for_completion(fc_event_handle_thd_comp); + return RETURN_OK; +} + +static void unf_cm_event_thread_exit(void) +{ + struct completion fc_event_completion = + COMPLETION_INITIALIZER(fc_event_completion); + + struct completion *p_fc_event_completion = &fc_event_completion; + + fc_event_handle_thd_comp = p_fc_event_completion; + event_thread_exit = 1; + wake_up_process(event_thread); + wait_for_completion(fc_event_handle_thd_comp); + + fc_event_handle_thd_comp = NULL; +} + +static void unf_cm_cread_card_mgr_list(void) +{ + /* So far, do not care */ + INIT_LIST_HEAD(&card_thread_mgr.list_card_list_head); + + spin_lock_init(&card_thread_mgr.global_card_list_lock); + + card_thread_mgr.card_sum = 0; +} + +static int unf_port_feature_pool_init(void) +{ + unsigned int i = 0; + unsigned int rport_fea_pool_size = 0; + struct unf_rport_feature_recard_s *rport_fea_recard = NULL; + unsigned long flags = 0; + + rport_fea_pool_size = sizeof(struct unf_rport_feature_pool_s); + port_fea_pool = vmalloc(rport_fea_pool_size); + if (!port_fea_pool) { + UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_REG_ATT, UNF_ERR, + "[err]cannot allocate rport feature pool"); + + return UNF_RETURN_ERROR; + } + memset(port_fea_pool, 0, rport_fea_pool_size); + spin_lock_init(&port_fea_pool->port_fea_pool_lock); + INIT_LIST_HEAD(&port_fea_pool->list_busy_head); + INIT_LIST_HEAD(&port_fea_pool->list_free_head); + + port_fea_pool->p_port_feature_pool_addr = + vmalloc((size_t)(RPORT_FEATURE_POOL_SIZE * + sizeof(struct unf_rport_feature_recard_s))); + if (!port_fea_pool->p_port_feature_pool_addr) { + UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_REG_ATT, UNF_ERR, + "[err]cannot allocate rport feature pool address"); + + vfree(port_fea_pool); + port_fea_pool = NULL; + + return UNF_RETURN_ERROR; + } + + memset(port_fea_pool->p_port_feature_pool_addr, 0, + sizeof(struct unf_rport_feature_recard_s) * + RPORT_FEATURE_POOL_SIZE); + rport_fea_recard = + (struct unf_rport_feature_recard_s *) + port_fea_pool->p_port_feature_pool_addr; + + spin_lock_irqsave(&port_fea_pool->port_fea_pool_lock, flags); + for (i = 0; i < RPORT_FEATURE_POOL_SIZE; i++) { + list_add_tail(&rport_fea_recard->entry_feature, + &port_fea_pool->list_free_head); + rport_fea_recard++; + } + spin_unlock_irqrestore(&port_fea_pool->port_fea_pool_lock, flags); + + return RETURN_OK; +} + +void unf_free_port_feature_pool(void) +{ + if (port_fea_pool->p_port_feature_pool_addr) { + vfree(port_fea_pool->p_port_feature_pool_addr); + port_fea_pool->p_port_feature_pool_addr = NULL; + } + vfree(port_fea_pool); + port_fea_pool = NULL; +} + +int unf_common_init(void) +{ + int ret = RETURN_OK; + + unf_dbg_level = UNF_MAJOR; + log_print_level = UNF_KEVENT; + + UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_KEVENT, + "UNF Driver Version:%s.", UNF_FC_VERSION); + UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_KEVENT, + "UNF Compile Time: %s", __TIME_STR__); + + ret = unf_port_feature_pool_init(); + if (ret != RETURN_OK) { + UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_REG_ATT, UNF_ERR, + "[err]Port Feature Pool init failed"); + + return ret; + } + + /* 1. Init Transport */ + ret = (int)unf_register_ini_transport(); + if (ret != RETURN_OK) { + UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_REG_ATT, UNF_ERR, + "[err]INI interface init failed"); + unf_free_port_feature_pool(); + + return ret; + } + + /* 2. Init L_Port MG: Y */ + unf_port_mgmt_init(); + + /* 3. Init card MG list: N */ + unf_cm_cread_card_mgr_list(); + + /* 4. Init global event resource: N */ + ret = (int)unf_init_global_event_msg(); + if (ret != RETURN_OK) { + unf_unregister_ini_transport(); + unf_free_port_feature_pool(); + + UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_REG_ATT, UNF_ERR, + "[err]Create global event center failed"); + + return ret; + } + + /* 5. Create event center(one thread per pf): Y */ + ret = (int)unf_creat_event_center(); + if (ret != RETURN_OK) { + unf_destroy_global_event_msg(); + unf_unregister_ini_transport(); + unf_free_port_feature_pool(); + + fc_event_handle_thd_comp = NULL; + UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_REG_ATT, UNF_ERR, + "[err]Create event center (thread) failed"); + + return ret; + } + + /* 6. Create work queue: Y */ + unf_work_queue = create_workqueue("unf_wq"); + if (!unf_work_queue) { + /* event thread exist */ + unf_cm_event_thread_exit(); + unf_destroy_global_event_msg(); + + fc_event_handle_thd_comp = NULL; + unf_unregister_ini_transport(); + unf_free_port_feature_pool(); + + UNF_TRACE(UNF_EVTLOG_DRIVER_ERR, UNF_LOG_REG_ATT, UNF_ERR, + "[err]Create work queue failed"); + + return UNF_RETURN_ERROR; + } + + UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_MAJOR, + "[info]Init common layer succeed"); + + return ret; +} + +static void unf_destroy_dirty_port(void) +{ + unsigned int v_ditry_port_num = 0; + + unf_show_dirty_port(UNF_FALSE, &v_ditry_port_num); + + UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_MAJOR, + "[info]Sys has %d dirty L_Port(s)", v_ditry_port_num); +} + +void unf_common_exit(void) +{ + unf_free_port_feature_pool(); + + unf_destroy_dirty_port(); + + flush_workqueue(unf_work_queue); + destroy_workqueue(unf_work_queue); + unf_work_queue = NULL; + + unf_cm_event_thread_exit(); + + unf_destroy_global_event_msg(); + + unf_uninit_cm_low_level_handle(); + + unf_port_mgmt_deinit(); + + unf_unregister_ini_transport(); + + UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_KEVENT, + "[info]HIFC module remove succeed"); +} diff --git a/drivers/scsi/huawei/hifc/unf_log.h b/drivers/scsi/huawei/hifc/unf_log.h new file mode 100644 index 000000000000..a46a77a42ded --- /dev/null +++ b/drivers/scsi/huawei/hifc/unf_log.h @@ -0,0 +1,183 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Huawei Hifc PCI Express Linux driver + * Copyright(c) 2017 Huawei Technologies Co., Ltd + * + */ +#ifndef __UNF_LOG_H__ +#define __UNF_LOG_H__ + +#define UNF_CRITICAL 1 +#define UNF_ERR 2 +#define UNF_WARN 3 +#define UNF_KEVENT 4 +#define UNF_MAJOR 5 +#define UNF_MINOR 6 +#define UNF_INFO 7 +#define UNF_DATA 7 +#define UNF_ALL 7 + +enum unf_debug_type_e { + UNF_DEBUG_TYPE_MML = 0, + UNF_DEBUG_TYPE_DIAGNOSE = 1, + UNF_DEBUG_TYPE_MESSAGE = 2, + UNF_DEBUG_TYPE_BUTT +}; + +enum unf_log_attr_e { + UNF_LOG_LOGIN_ATT = 0x1, + UNF_LOG_IO_ATT = 0x2, + UNF_LOG_EQUIP_ATT = 0x4, + UNF_LOG_REG_ATT = 0x8, + UNF_LOG_REG_MML_TEST = 0x10, + UNF_LOG_EVENT = 0x20, + UNF_LOG_NORMAL = 0x40, + UNF_LOG_ABNORMAL = 0X80, + UNF_LOG_BUTT +}; + +enum event_log_e { + UNF_EVTLOG_DRIVER_SUC = 0, + UNF_EVTLOG_DRIVER_INFO, + UNF_EVTLOG_DRIVER_WARN, + UNF_EVTLOG_DRIVER_ERR, + UNF_EVTLOG_LINK_SUC, + UNF_EVTLOG_LINK_INFO, + UNF_EVTLOG_LINK_WARN, + UNF_EVTLOG_LINK_ERR, + UNF_EVTLOG_IO_SUC, + UNF_EVTLOG_IO_INFO, + UNF_EVTLOG_IO_WARN, + UNF_EVTLOG_IO_ERR, + UNF_EVTLOG_TOOL_SUC, + UNF_EVTLOG_TOOL_INFO, + UNF_EVTLOG_TOOL_WARN, + UNF_EVTLOG_TOOL_ERR, + UNF_EVTLOG_BUT +}; + +#define UNF_IO_ATT_PRINT_TIMES 2 +#define UNF_LOGIN_ATT_PRINT_TIMES 100 + +#define UNF_IO_ATT_PRINT_LIMIT msecs_to_jiffies(2 * 1000) + +extern unsigned int unf_dbg_level; +extern unsigned int log_print_level; +extern unsigned int log_limted_times; + +#define DRV_LOG_LIMIT(module_id, log_level, log_id, log_att, format, ...) \ + do { \ + static unsigned long pre; \ + static int should_print = UNF_LOGIN_ATT_PRINT_TIMES; \ + if (time_after_eq(jiffies, pre + (UNF_IO_ATT_PRINT_LIMIT))) { \ + if (log_att == UNF_LOG_ABNORMAL) { \ + should_print = UNF_IO_ATT_PRINT_TIMES; \ + } else { \ + should_print = log_limted_times; \ + } \ + } \ + if (should_print < 0) { \ + if (log_att != UNF_LOG_ABNORMAL) { \ + pre = jiffies; \ + } \ + break; \ + } \ + if (should_print-- > 0) { \ + printk(log_level \ + "[%d][FC_UNF]" format "[%s][%-5d]\n", \ + smp_processor_id(), ##__VA_ARGS__, \ + __func__, __LINE__); \ + } \ + if (should_print == 0) { \ + printk(log_level \ + "[FC_UNF]log is limited[%s][%-5d]\n", \ + __func__, __LINE__); \ + } \ + pre = jiffies; \ + } while (0) + +#define UNF_CHECK_VALID(logid, need_check, condition, fail_do) \ + do { \ + if (unlikely(!(condition))) { \ + UNF_TRACE((logid), UNF_LOG_REG_ATT, UNF_ERR, \ + "Para check(%s) invalid", #condition); \ + fail_do; \ + } \ + } while (0) + +#define HIUNF_TRACE(log_id, log_att, log_level, format, ...) \ + do { \ + if (unlikely((log_level) <= log_print_level)) { \ + if (log_level == UNF_CRITICAL) { \ + DRV_LOG_LIMIT(UNF_PID, KERN_CRIT, log_id, \ + log_att, format, ##__VA_ARGS__); \ + } else if (log_level == UNF_WARN) { \ + DRV_LOG_LIMIT(UNF_PID, KERN_WARNING, log_id, \ + log_att, format, ##__VA_ARGS__); \ + } else if (log_level == UNF_ERR) { \ + DRV_LOG_LIMIT(UNF_PID, KERN_ERR, log_id, \ + log_att, format, ##__VA_ARGS__); \ + } else if (log_level == UNF_MAJOR || \ + log_level == UNF_MINOR || \ + log_level == UNF_KEVENT) { \ + DRV_LOG_LIMIT(UNF_PID, KERN_NOTICE, log_id, \ + log_att, format, ##__VA_ARGS__); \ + } else if (log_level == UNF_INFO || \ + log_level == UNF_DATA) { \ + DRV_LOG_LIMIT(UNF_PID, KERN_INFO, log_id, \ + log_att, format, ##__VA_ARGS__); \ + } \ + } \ + } while (0) + +#define UNF_TRACE(log_id, log_att, log_level, fmt, ...) \ + do { \ + HIUNF_TRACE(log_id, log_att, log_level, fmt, ##__VA_ARGS__); \ + } while (0) + +#define UNF_INIT_PRIVATE_ST(private_st) \ + do { \ + memset(&(private_st), 0, sizeof(private_st)); \ + } while (0) + +#define UNF_PRINT_SFS(dbg_level, portid, v_data, v_size) \ + do { \ + if ((dbg_level) <= log_print_level) { \ + unsigned int cnt = 0; \ + printk(KERN_INFO "[INFO]Port(0x%x) sfs:0x", \ + (portid)); \ + for (cnt = 0; cnt < (v_size) / 4; cnt++) { \ + printk(KERN_INFO "%08x ", \ + ((unsigned int *)v_data)[cnt]); \ + } \ + printk(KERN_INFO "[FC_UNF][%s]\n", __FUNCTION__); \ + } \ + } while (0) + +#define UNF_PRINT_SFS_LIMIT(dbg_level, portid, v_data, v_size) \ + do { \ + if ((dbg_level) <= log_print_level) { \ + static unsigned long pre; \ + static int should_print = UNF_LOGIN_ATT_PRINT_TIMES; \ + if (time_after_eq(jiffies, pre + \ + UNF_IO_ATT_PRINT_LIMIT)) { \ + should_print = log_limted_times; \ + } \ + if (should_print < 0) { \ + pre = jiffies; \ + break; \ + } \ + if (should_print-- > 0) { \ + UNF_PRINT_SFS(dbg_level, portid, \ + v_data, v_size); \ + } \ + if (should_print == 0) { \ + printk(KERN_INFO "[FC_UNF]sfs log is limited[%s][%-5d]\n", \ + __func__, __LINE__); \ + } \ + pre = jiffies; \ + } \ + } while (0) + +#define UNF_REFERNCE_VAR(var) + +#endif diff --git a/drivers/scsi/huawei/hifc/unf_scsi.c b/drivers/scsi/huawei/hifc/unf_scsi.c new file mode 100644 index 000000000000..11331bacb914 --- /dev/null +++ b/drivers/scsi/huawei/hifc/unf_scsi.c @@ -0,0 +1,1556 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Huawei Hifc PCI Express Linux driver + * Copyright(c) 2017 Huawei Technologies Co., Ltd + * + */ +#include "unf_log.h" +#include "unf_scsi_common.h" +#include "unf_lport.h" +#include "unf_rport.h" +#include "unf_portman.h" +#include "unf_npiv.h" +#include "unf_exchg.h" +#include "unf_io.h" + +static int unf_scsi_queue_cmd(struct Scsi_Host *shost, + struct scsi_cmnd *v_cmnd); +static int unf_scsi_abort_scsi_cmnd(struct scsi_cmnd *v_cmnd); +static int unf_scsi_device_reset_handler(struct scsi_cmnd *v_cmnd); +static int unf_scsi_bus_reset_handler(struct scsi_cmnd *v_cmnd); +static int unf_scsi_target_reset_handler(struct scsi_cmnd *v_cmnd); +static int unf_scsi_slave_alloc(struct scsi_device *sdev); +static void unf_scsi_destroy_slave(struct scsi_device *sdev); +static int unf_scsi_slave_configure(struct scsi_device *sdev); +static int unf_scsi_scan_finished(struct Scsi_Host *shost, unsigned long time); +static void unf_scsi_scan_start(struct Scsi_Host *shost); + +static struct scsi_transport_template *scsi_transport_template; +static struct scsi_transport_template *scsi_transport_template_v; + +struct unf_ini_error_code_s ini_error_code_table1[] = { + { UNF_IO_SUCCESS, UNF_SCSI_HOST(DID_OK) }, + { UNF_IO_ABORTED, UNF_SCSI_HOST(DID_ABORT) }, + { UNF_IO_FAILED, UNF_SCSI_HOST(DID_ERROR) }, + { UNF_IO_ABORT_ABTS, UNF_SCSI_HOST(DID_ERROR) }, + { UNF_IO_ABORT_LOGIN, UNF_SCSI_HOST(DID_NO_CONNECT) }, + { UNF_IO_ABORT_REET, UNF_SCSI_HOST(DID_RESET) }, + { UNF_IO_ABORT_FAILED, UNF_SCSI_HOST(DID_ERROR) }, + { UNF_IO_OUTOF_ORDER, UNF_SCSI_HOST(DID_ERROR) }, + { UNF_IO_FTO, UNF_SCSI_HOST(DID_TIME_OUT) }, + { UNF_IO_LINK_FAILURE, UNF_SCSI_HOST(DID_ERROR) }, + { UNF_IO_OVER_FLOW, UNF_SCSI_HOST(DID_ERROR) }, + { UNF_IO_RSP_OVER, UNF_SCSI_HOST(DID_ERROR) }, + { UNF_IO_LOST_FRAME, UNF_SCSI_HOST(DID_ERROR) }, + { UNF_IO_UNDER_FLOW, UNF_SCSI_HOST(DID_OK) }, + { UNF_IO_HOST_PROG_ERROR, UNF_SCSI_HOST(DID_ERROR) }, + { UNF_IO_SEST_PROG_ERROR, UNF_SCSI_HOST(DID_ERROR) }, + { UNF_IO_INVALID_ENTRY, UNF_SCSI_HOST(DID_ERROR) }, + { UNF_IO_ABORT_SEQ_NOT, UNF_SCSI_HOST(DID_ERROR) }, + { UNF_IO_REJECT, UNF_SCSI_HOST(DID_ERROR) }, + { UNF_IO_EDC_IN_ERROR, UNF_SCSI_HOST(DID_ERROR) }, + { UNF_IO_EDC_OUT_ERROR, UNF_SCSI_HOST(DID_ERROR) }, + { UNF_IO_UNINIT_KEK_ERR, UNF_SCSI_HOST(DID_ERROR) }, + { UNF_IO_DEK_OUTOF_RANGE, UNF_SCSI_HOST(DID_ERROR) }, + { UNF_IO_KEY_UNWRAP_ERR, UNF_SCSI_HOST(DID_ERROR) }, + { UNF_IO_KEY_TAG_ERR, UNF_SCSI_HOST(DID_ERROR) }, + { UNF_IO_KEY_ECC_ERR, UNF_SCSI_HOST(DID_ERROR) }, + { UNF_IO_BLOCK_SIZE_ERROR, UNF_SCSI_HOST(DID_ERROR) }, + { UNF_IO_ILLEGAL_CIPHER_MODE, UNF_SCSI_HOST(DID_ERROR) }, + { UNF_IO_CLEAN_UP, UNF_SCSI_HOST(DID_ERROR) }, + { UNF_IO_ABORTED_BY_TARGET, UNF_SCSI_HOST(DID_ERROR) }, + { UNF_IO_TRANSPORT_ERROR, UNF_SCSI_HOST(DID_ERROR) }, + { UNF_IO_LINK_FLASH, UNF_SCSI_HOST(DID_NO_CONNECT) }, + { UNF_IO_TIMEOUT, UNF_SCSI_HOST(DID_TIME_OUT) }, + { UNF_IO_DMA_ERROR, UNF_SCSI_HOST(DID_ERROR) }, + { UNF_IO_NO_LPORT, UNF_SCSI_HOST(DID_NO_CONNECT) }, + { UNF_IO_NO_XCHG, UNF_SCSI_HOST(DID_SOFT_ERROR) }, + { UNF_IO_SOFT_ERR, UNF_SCSI_HOST(DID_SOFT_ERROR) }, + { UNF_IO_PORT_LOGOUT, UNF_SCSI_HOST(DID_NO_CONNECT) }, + { UNF_IO_ERREND, UNF_SCSI_HOST(DID_ERROR) }, + { UNF_IO_DIF_ERROR, (UNF_SCSI_HOST(DID_OK) | UNF_SCSI_STATUS(SCSI_CHECK_CONDITION)) }, + { UNF_IO_INCOMPLETE, UNF_SCSI_HOST(DID_IMM_RETRY) }, + { UNF_IO_DIF_REF_ERROR, (UNF_SCSI_HOST(DID_OK) | UNF_SCSI_STATUS(SCSI_CHECK_CONDITION)) }, + { UNF_IO_DIF_GEN_ERROR, (UNF_SCSI_HOST(DID_OK) | UNF_SCSI_STATUS(SCSI_CHECK_CONDITION)) } +}; + +unsigned int ini_err_code_table_cnt1 = + sizeof(ini_error_code_table1) / sizeof(struct unf_ini_error_code_s); + +static void unf_set_rport_loss_tmo(struct fc_rport *rport, + unsigned int timeout) +{ + if (timeout) + rport->dev_loss_tmo = timeout; + else + rport->dev_loss_tmo = 1; +} + +static void unf_get_host_port_id(struct Scsi_Host *shost) +{ + struct unf_lport_s *lport = NULL; + + lport = (struct unf_lport_s *)shost->hostdata[0]; + if (unlikely(!lport)) { + UNF_TRACE(0x3808, UNF_LOG_LOGIN_ATT, UNF_ERR, + "[err]Port is null"); + + return; + } + + fc_host_port_id(shost) = lport->port_id; +} + +static void unf_get_host_speed(struct Scsi_Host *shost) +{ + struct unf_lport_s *lport = NULL; + unsigned int speed = FC_PORTSPEED_UNKNOWN; + + lport = (struct unf_lport_s *)shost->hostdata[0]; + if (unlikely(!lport)) { + UNF_TRACE(0x3808, UNF_LOG_LOGIN_ATT, UNF_ERR, + "[err]Port is null"); + + return; + } + + switch (lport->speed) { + case UNF_PORT_SPEED_2_G: + speed = FC_PORTSPEED_2GBIT; + break; + + case UNF_PORT_SPEED_4_G: + speed = FC_PORTSPEED_4GBIT; + break; + + case UNF_PORT_SPEED_8_G: + speed = FC_PORTSPEED_8GBIT; + break; + + case UNF_PORT_SPEED_16_G: + speed = FC_PORTSPEED_16GBIT; + break; + + case UNF_PORT_SPEED_32_G: + speed = FC_PORTSPEED_32GBIT; + break; + + default: + UNF_TRACE(0x3808, UNF_LOG_LOGIN_ATT, UNF_MAJOR, + "[info]Port(0x%x) with unknown speed(0x%x) for FC mode", + lport->port_id, lport->speed); + break; + } + + fc_host_speed(shost) = speed; +} + +static void unf_get_host_port_type(struct Scsi_Host *shost) +{ + struct unf_lport_s *lport = NULL; + unsigned int port_type = FC_PORTTYPE_UNKNOWN; + + lport = (struct unf_lport_s *)shost->hostdata[0]; + if (unlikely(!lport)) { + UNF_TRACE(0x3808, UNF_LOG_LOGIN_ATT, UNF_ERR, + "[err]Port is null"); + + return; + } + + switch (lport->en_act_topo) { + case UNF_ACT_TOP_PRIVATE_LOOP: + port_type = FC_PORTTYPE_LPORT; + break; + + case UNF_ACT_TOP_PUBLIC_LOOP: + port_type = FC_PORTTYPE_NLPORT; + break; + + case UNF_ACT_TOP_P2P_DIRECT: + port_type = FC_PORTTYPE_PTP; + break; + + case UNF_ACT_TOP_P2P_FABRIC: + port_type = FC_PORTTYPE_NPORT; + break; + + default: + UNF_TRACE(0x3808, UNF_LOG_LOGIN_ATT, UNF_MAJOR, + "[info]Port(0x%x) with unknown topo type(0x%x) for FC mode", + lport->port_id, lport->en_act_topo); + break; + } + + fc_host_port_type(shost) = port_type; +} + +static void unf_get_symbolic_name(struct Scsi_Host *shost) +{ + unsigned char *name = NULL; + struct unf_lport_s *lport = NULL; + + lport = (struct unf_lport_s *)shost->hostdata[0]; + if (unlikely(!lport)) { + UNF_TRACE(0x3808, UNF_LOG_LOGIN_ATT, UNF_ERR, + "[err]Check l_port failed"); + + return; + } + + name = fc_host_symbolic_name(shost); + if (name) { + snprintf(name, FC_SYMBOLIC_NAME_SIZE, + "HIFC_FW_RELEASE:%s HIFC_DRV_RELEASE:%s", + lport->fw_version, UNF_FC_VERSION); + } +} + +static void unf_get_host_fabric_name(struct Scsi_Host *shost) +{ + struct unf_lport_s *lport = NULL; + + lport = (struct unf_lport_s *)shost->hostdata[0]; + if (unlikely(!lport)) { + UNF_TRACE(0x3808, UNF_LOG_LOGIN_ATT, UNF_ERR, + "[err]Port is null"); + + return; + } + + fc_host_fabric_name(shost) = lport->fabric_node_name; +} + +static void unf_get_host_port_state(struct Scsi_Host *shost) +{ + struct unf_lport_s *lport = NULL; + enum fc_port_state port_state; + + lport = (struct unf_lport_s *)shost->hostdata[0]; + if (unlikely(!lport)) { + UNF_TRACE(0x3808, UNF_LOG_LOGIN_ATT, UNF_ERR, + "[err]Port is null"); + + return; + } + + switch (lport->link_up) { + case UNF_PORT_LINK_DOWN: + port_state = FC_PORTSTATE_OFFLINE; + break; + + case UNF_PORT_LINK_UP: + port_state = FC_PORTSTATE_ONLINE; + break; + + default: + port_state = FC_PORTSTATE_UNKNOWN; + break; + } + + fc_host_port_state(shost) = port_state; +} + +static void unf_dev_loss_timeout_callbk(struct fc_rport *rport) +{ + /* + * NOTE: about rport->dd_data + * --->>> local SCSI_ID + * 1. Assignment during scsi rport link up + * 2. Released when scsi rport link down & timeout(30s) + * 3. Used during scsi do callback with slave_alloc function + */ + struct Scsi_Host *host = NULL; + struct unf_lport_s *lport = NULL; + unsigned int scsi_id = 0; + + if (unlikely(!rport)) { + UNF_TRACE(0x3808, UNF_LOG_LOGIN_ATT, UNF_ERR, + "[err]SCSI rport is null"); + + return; + } + + host = rport_to_shost(rport); + if (unlikely(!host)) { + UNF_TRACE(0x3808, UNF_LOG_LOGIN_ATT, UNF_ERR, + "[err]Host is null"); + + return; + } + + /* according to Local SCSI_ID */ + scsi_id = *(unsigned int *)(rport->dd_data); + if (unlikely(scsi_id >= UNF_MAX_SCSI_ID)) { + UNF_TRACE(0x3808, UNF_LOG_LOGIN_ATT, UNF_ERR, + "[err]scsi_id(0x%x) is max than(0x%x)", + scsi_id, UNF_MAX_SCSI_ID); + + return; + } + + lport = (struct unf_lport_s *)host->hostdata[0]; + if (unf_is_lport_valid(lport) == RETURN_OK) { + UNF_TRACE(0x3097, UNF_LOG_LOGIN_ATT, UNF_INFO, + "[event]Port(0x%x_0x%x) RPort scsi_id(0x%x) target_id(0x%x) loss timeout", + lport->port_id, lport->nport_id, + scsi_id, rport->scsi_target_id); + + atomic_inc(&lport->session_loss_tmo); + + /* Free SCSI ID & set table state with DEAD */ + (void)unf_free_scsi_id(lport, scsi_id); + } else { + UNF_TRACE(0x3097, UNF_LOG_LOGIN_ATT, UNF_ERR, + "[err]Port(%p) is invalid", lport); + } + + /* reset scsi rport dd_data(local SCSI_ID) */ + *((unsigned int *)rport->dd_data) = INVALID_VALUE32; +} + +int unf_scsi_create_vport(struct fc_vport *fc_port, bool disabled) +{ + struct unf_lport_s *vport = NULL; + struct unf_lport_s *lport = NULL; + struct Scsi_Host *shost = NULL; + struct vport_config_s vport_config = { 0 }; + + shost = vport_to_shost(fc_port); + + lport = (struct unf_lport_s *)shost->hostdata[0]; + if (unf_is_lport_valid(lport) != RETURN_OK) { + UNF_TRACE(0x3097, UNF_LOG_LOGIN_ATT, UNF_ERR, + "[err]Port(%p) is invalid", lport); + + return RETURN_ERROR; + } + + vport_config.port_name = fc_port->port_name; + + vport_config.port_mode = fc_port->roles; + + vport = unf_create_vport(lport, &vport_config); + if (!vport) { + UNF_TRACE(0x3097, UNF_LOG_LOGIN_ATT, UNF_ERR, + "[err]Port(0x%x) Create Vport failed on lldrive", + lport->port_id); + + return RETURN_ERROR; + } + + fc_port->dd_data = vport; + + vport->vport = fc_port; + + return RETURN_OK; +} + +int unf_scsi_delete_vport(struct fc_vport *fc_port) +{ + int ret = RETURN_ERROR; + struct unf_lport_s *vport = NULL; + + vport = (struct unf_lport_s *)fc_port->dd_data; + + if (unf_is_lport_valid(vport) != RETURN_OK) { + UNF_TRACE(0x3097, UNF_LOG_LOGIN_ATT, UNF_WARN, + "[warn]VPort(%p) is invalid or is removing", + vport); + + fc_port->dd_data = NULL; + + return ret; + } + + ret = (int)unf_destroy_one_vport(vport); + if (ret != RETURN_OK) { + UNF_TRACE(0x3097, UNF_LOG_LOGIN_ATT, UNF_ERR, + "[err]VPort(0x%x) destroy failed on drive", + vport->port_id); + + return ret; + } + + fc_port->dd_data = NULL; + + return ret; +} + +struct fc_function_template function_template = { + .show_host_node_name = 1, + .show_host_port_name = 1, + .show_host_supported_classes = 1, + .show_host_supported_speeds = 1, + + .get_host_port_id = unf_get_host_port_id, + .show_host_port_id = 1, + .get_host_speed = unf_get_host_speed, + .show_host_speed = 1, + .get_host_port_type = unf_get_host_port_type, + .show_host_port_type = 1, + .get_host_symbolic_name = unf_get_symbolic_name, + .show_host_symbolic_name = 1, + .set_host_system_hostname = NULL, + .show_host_system_hostname = 1, + .get_host_fabric_name = unf_get_host_fabric_name, + .show_host_fabric_name = 1, + .get_host_port_state = unf_get_host_port_state, + .show_host_port_state = 1, + + .dd_fcrport_size = sizeof(void *), + .show_rport_supported_classes = 1, + + .get_starget_node_name = NULL, + .show_starget_node_name = 1, + .get_starget_port_name = NULL, + .show_starget_port_name = 1, + .get_starget_port_id = NULL, + .show_starget_port_id = 1, + + .set_rport_dev_loss_tmo = unf_set_rport_loss_tmo, + .show_rport_dev_loss_tmo = 0, + + .issue_fc_host_lip = NULL, + .dev_loss_tmo_callbk = unf_dev_loss_timeout_callbk, + .terminate_rport_io = NULL, + .get_fc_host_stats = NULL, + + .vport_create = unf_scsi_create_vport, + .vport_disable = NULL, + .vport_delete = unf_scsi_delete_vport, + .bsg_request = NULL, + .bsg_timeout = NULL, +}; + +struct fc_function_template function_template_v = { + .show_host_node_name = 1, + .show_host_port_name = 1, + .show_host_supported_classes = 1, + .show_host_supported_speeds = 1, + + .get_host_port_id = unf_get_host_port_id, + .show_host_port_id = 1, + .get_host_speed = unf_get_host_speed, + .show_host_speed = 1, + .get_host_port_type = unf_get_host_port_type, + .show_host_port_type = 1, + .get_host_symbolic_name = unf_get_symbolic_name, + .show_host_symbolic_name = 1, + .set_host_system_hostname = NULL, + .show_host_system_hostname = 1, + .get_host_fabric_name = unf_get_host_fabric_name, + .show_host_fabric_name = 1, + .get_host_port_state = unf_get_host_port_state, + .show_host_port_state = 1, + + .dd_fcrport_size = sizeof(void *), + .show_rport_supported_classes = 1, + + .get_starget_node_name = NULL, + .show_starget_node_name = 1, + .get_starget_port_name = NULL, + .show_starget_port_name = 1, + .get_starget_port_id = NULL, + .show_starget_port_id = 1, + + .set_rport_dev_loss_tmo = unf_set_rport_loss_tmo, + .show_rport_dev_loss_tmo = 1, + + .issue_fc_host_lip = NULL, + .dev_loss_tmo_callbk = unf_dev_loss_timeout_callbk, + .terminate_rport_io = NULL, + .get_fc_host_stats = NULL, + + .vport_create = NULL, + .vport_disable = NULL, + .vport_delete = NULL, + .bsg_request = NULL, + .bsg_timeout = NULL, +}; + +struct scsi_host_template scsi_host_template = { + .module = THIS_MODULE, + .name = "HIFC", + + .queuecommand = unf_scsi_queue_cmd, + .eh_abort_handler = unf_scsi_abort_scsi_cmnd, + .eh_device_reset_handler = unf_scsi_device_reset_handler, + + .eh_target_reset_handler = unf_scsi_target_reset_handler, + .eh_bus_reset_handler = unf_scsi_bus_reset_handler, + .eh_host_reset_handler = NULL, + + .slave_configure = unf_scsi_slave_configure, + .slave_alloc = unf_scsi_slave_alloc, + .slave_destroy = unf_scsi_destroy_slave, + + .scan_finished = unf_scsi_scan_finished, + .scan_start = unf_scsi_scan_start, + + .this_id = -1, + .cmd_per_lun = 3, + .use_clustering = ENABLE_CLUSTERING, + .shost_attrs = NULL, + .sg_tablesize = SG_ALL, + .max_sectors = 0xFFFF, + .supported_mode = MODE_INITIATOR, +}; + +static void unf_unmap_prot_sgl(struct scsi_cmnd *v_cmnd) +{ + struct device *dev; + + if ((scsi_get_prot_op(v_cmnd) != SCSI_PROT_NORMAL) && + hifc_dif_enable && (scsi_prot_sg_count(v_cmnd))) { + dev = v_cmnd->device->host->dma_dev; + dma_unmap_sg(dev, scsi_prot_sglist(v_cmnd), + (int)scsi_prot_sg_count(v_cmnd), + v_cmnd->sc_data_direction); + + UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_INFO, + "scsi done cmd:%p op:%d,difsglcount:%d", + v_cmnd, scsi_get_prot_op(v_cmnd), + scsi_prot_sg_count(v_cmnd)); + } +} + +void unf_scsi_done(struct unf_scsi_cmd_s *v_scsi_cmnd) +{ + struct scsi_cmnd *cmnd = NULL; + + UNF_CHECK_VALID(0x509, UNF_TRUE, v_scsi_cmnd, return); + cmnd = (struct scsi_cmnd *)v_scsi_cmnd->upper_cmnd; + UNF_CHECK_VALID(0x510, UNF_TRUE, cmnd, return); + UNF_CHECK_VALID(0x511, UNF_TRUE, cmnd->scsi_done, return); + + scsi_set_resid(cmnd, (int)v_scsi_cmnd->resid); + + cmnd->result = v_scsi_cmnd->result; + scsi_dma_unmap(cmnd); + unf_unmap_prot_sgl(cmnd); + return cmnd->scsi_done(cmnd); +} + +void unf_host_init_attr_setting(unf_scsi_host_s *scsi_host) +{ + struct unf_lport_s *lport = NULL; + unsigned int speed = FC_PORTSPEED_UNKNOWN; + + lport = (struct unf_lport_s *)scsi_host->hostdata[0]; + fc_host_supported_classes(scsi_host) = FC_COS_CLASS3; /* class_3 */ + fc_host_dev_loss_tmo(scsi_host) = + (unsigned int)unf_get_link_lose_tmo(lport); /* 30s */ + fc_host_node_name(scsi_host) = lport->node_name; + fc_host_port_name(scsi_host) = lport->port_name; + + fc_host_max_npiv_vports(scsi_host) = + (unsigned short)((lport == lport->root_lport) ? + lport->low_level_func.support_max_npiv_num : 0); + fc_host_npiv_vports_inuse(scsi_host) = 0; + fc_host_next_vport_number(scsi_host) = 0; + + /* About speed mode */ + if ((lport->low_level_func.fc_ser_max_speed == UNF_PORT_SPEED_32_G) && + (lport->card_type == UNF_FC_SERVER_BOARD_32_G)) { + speed = FC_PORTSPEED_32GBIT | FC_PORTSPEED_16GBIT | + FC_PORTSPEED_8GBIT; + } else if ((lport->low_level_func.fc_ser_max_speed == + UNF_PORT_SPEED_16_G) && + (lport->card_type == UNF_FC_SERVER_BOARD_16_G)) { + speed = FC_PORTSPEED_16GBIT | FC_PORTSPEED_8GBIT | + FC_PORTSPEED_4GBIT; + } else if ((lport->low_level_func.fc_ser_max_speed == + UNF_PORT_SPEED_8_G) && + (lport->card_type == UNF_FC_SERVER_BOARD_8_G)) { + speed = FC_PORTSPEED_8GBIT | FC_PORTSPEED_4GBIT | + FC_PORTSPEED_2GBIT; + } + + fc_host_supported_speeds(scsi_host) = speed; +} + +int unf_alloc_scsi_host(unf_scsi_host_s **v_scsi_host, + struct unf_host_param_s *v_host_param) +{ + int ret = RETURN_ERROR; + struct Scsi_Host *scsi_host = NULL; + struct unf_lport_s *lport = NULL; + + UNF_CHECK_VALID(0x512, UNF_TRUE, v_scsi_host, return RETURN_ERROR); + UNF_CHECK_VALID(0x513, UNF_TRUE, v_host_param, return RETURN_ERROR); + + UNF_TRACE(0x3808, UNF_LOG_LOGIN_ATT, UNF_MAJOR, + "[event]Alloc scsi host..."); + + /* Check L_Port validity */ + lport = (struct unf_lport_s *)(v_host_param->lport); + if (unlikely(!lport)) { + UNF_TRACE(0x3808, UNF_LOG_LOGIN_ATT, UNF_ERR, + "[err]Port is NULL and return directly"); + + return RETURN_ERROR; + } + + scsi_host_template.can_queue = v_host_param->can_queue; + scsi_host_template.cmd_per_lun = v_host_param->cmnd_per_lun; + scsi_host_template.sg_tablesize = v_host_param->sg_table_size; + scsi_host_template.max_sectors = v_host_param->max_sectors; + + /* Alloc scsi host */ + scsi_host = scsi_host_alloc(&scsi_host_template, + sizeof(unsigned long long)); + if (unlikely(!scsi_host)) { + UNF_TRACE(0x3808, UNF_LOG_LOGIN_ATT, UNF_ERR, + "[err]Register scsi host failed"); + + return RETURN_ERROR; + } + + scsi_host->max_channel = v_host_param->max_channel; + scsi_host->max_lun = v_host_param->max_lun; + scsi_host->max_cmd_len = v_host_param->max_cmnd_len; + scsi_host->unchecked_isa_dma = 0; + scsi_host->hostdata[0] = (unsigned long)lport; /* save L_Port to scsi */ + scsi_host->unique_id = scsi_host->host_no; + scsi_host->max_id = v_host_param->max_id; + scsi_host->transportt = (lport == lport->root_lport) ? + scsi_transport_template : scsi_transport_template_v; + + /* register DIF/DIX protection */ + if (hifc_dif_enable) { + /* Enable DIF and DIX function */ + scsi_host_set_prot(scsi_host, hifc_dif_type); + + hifc_guard = SHOST_DIX_GUARD_CRC; + /* Enable IP checksum algorithm in DIX */ + if (dix_flag) + hifc_guard |= SHOST_DIX_GUARD_IP; + scsi_host_set_guard(scsi_host, hifc_guard); + } + + /* Add scsi host */ + ret = scsi_add_host(scsi_host, v_host_param->pdev); + if (unlikely(ret)) { + UNF_TRACE(0x3808, UNF_LOG_LOGIN_ATT, UNF_ERR, + "[err]Add scsi host failed with return value %d", + ret); + + scsi_host_put(scsi_host); + return RETURN_ERROR; + } + + /* Set scsi host attribute */ + unf_host_init_attr_setting(scsi_host); + *v_scsi_host = scsi_host; + + UNF_TRACE(0x3808, UNF_LOG_LOGIN_ATT, UNF_MAJOR, + "[event]Alloc and add scsi host(0x%llx) succeed", + (unsigned long long)scsi_host); + + return RETURN_OK; +} + +void unf_free_scsi_host(unf_scsi_host_s *v_scsi_host) +{ + struct Scsi_Host *scsi_host = NULL; + + scsi_host = v_scsi_host; + fc_remove_host(scsi_host); + scsi_remove_host(scsi_host); + + UNF_TRACE(0x3808, UNF_LOG_LOGIN_ATT, UNF_MAJOR, + "[event]Remove scsi host(%d) succeed", scsi_host->host_no); + + scsi_host_put(scsi_host); +} + +static int unf_get_protect_mode(struct unf_lport_s *lport, + struct scsi_cmnd *v_cmnd, + struct unf_scsi_cmd_s *v_scsi_cmnd) +{ + struct scsi_cmnd *cmd = NULL; + int difsegcnt = 0; + struct unf_dif_control_info_s *dif_control_info = NULL; + + cmd = v_cmnd; + dif_control_info = &v_scsi_cmnd->dif_control; + + switch (scsi_get_prot_op(cmd)) { + /* OS-HBA: Unprotected, HBA-Target: Protected */ + case SCSI_PROT_READ_STRIP: + dif_control_info->protect_opcode |= + UNF_DIF_ACTION_VERIFY_AND_DELETE; + break; + case SCSI_PROT_WRITE_INSERT: + dif_control_info->protect_opcode |= + UNF_DIF_ACTION_INSERT; + break; + + /* OS-HBA: Protected, HBA-Target: Unprotected */ + case SCSI_PROT_READ_INSERT: + dif_control_info->protect_opcode |= + UNF_DIF_ACTION_INSERT; + break; + case SCSI_PROT_WRITE_STRIP: + dif_control_info->protect_opcode |= + UNF_DIF_ACTION_VERIFY_AND_DELETE; + break; + + /* OS-HBA: Protected, HBA-Target: Protected */ + case SCSI_PROT_READ_PASS: + case SCSI_PROT_WRITE_PASS: + dif_control_info->protect_opcode |= + UNF_DIF_ACTION_VERIFY_AND_FORWARD; + break; + + default: + dif_control_info->protect_opcode |= + UNF_DIF_ACTION_VERIFY_AND_FORWARD; + break; + } + + if (dif_sgl_mode) + dif_control_info->flags |= UNF_DIF_DOUBLE_SGL; + + dif_control_info->protect_opcode |= + UNF_VERIFY_CRC_MASK | UNF_VERIFY_LBA_MASK; + dif_control_info->dif_sge_count = scsi_prot_sg_count(cmd); + dif_control_info->dif_sgl = scsi_prot_sglist(cmd); + dif_control_info->start_lba = + cpu_to_le32(((uint32_t)(0xffffffff & scsi_get_lba(cmd)))); + + if (scsi_prot_sg_count(cmd)) { + difsegcnt = dma_map_sg(&lport->low_level_func.dev->dev, + scsi_prot_sglist(cmd), + (int)scsi_prot_sg_count(cmd), + cmd->sc_data_direction); + if (unlikely(!difsegcnt)) { + UNF_TRACE(0x3808, UNF_LOG_LOGIN_ATT, UNF_WARN, + "[warn]Port(0x%x) cmd:%p map dif sgl err", + lport->port_id, cmd); + return UNF_RETURN_ERROR; + } + } + + UNF_TRACE(UNF_EVTLOG_DRIVER_INFO, UNF_LOG_REG_ATT, UNF_INFO, + "build scsi cmd:%p op:%d,difsglcount:%d,difsegcnt:%d", + cmd, scsi_get_prot_op(cmd), scsi_prot_sg_count(cmd), + difsegcnt); + return RETURN_OK; +} + +unsigned int unf_get_frame_entry_buf(void *v_up_cmnd, + void *v_driver_sgl, + void **v_upper_sgl, + unsigned int *v_port_id, + unsigned int *v_index, + char **v_buf, + unsigned int *v_buf_len) +{ +#define HIFC_1822_MAX_DMA_LENGTH (0x20000 - 1) + struct scatterlist *scsi_sgl = *v_upper_sgl; + + UNF_REFERNCE_VAR(v_up_cmnd); + UNF_REFERNCE_VAR(v_driver_sgl); + UNF_REFERNCE_VAR(v_port_id); + + if (unlikely(!scsi_sgl)) { + UNF_TRACE(UNF_EVTLOG_IO_ERR, UNF_LOG_IO_ATT, UNF_ERR, + "[err]Command(0x%p) can not get SGL.", v_up_cmnd); + return RETURN_ERROR; + } + *v_buf = (char *)sg_dma_address(scsi_sgl); + *v_buf_len = sg_dma_len(scsi_sgl); + *v_upper_sgl = (void *)sg_next(scsi_sgl); + if (unlikely((*v_buf_len > HIFC_1822_MAX_DMA_LENGTH) || + (*v_buf_len == 0))) { + UNF_TRACE(UNF_EVTLOG_IO_ERR, UNF_LOG_IO_ATT, UNF_ERR, + "[err]Command(0x%p) dmalen:0x%x is not support.", + v_up_cmnd, *v_buf_len); + return RETURN_ERROR; + } + + return RETURN_OK; +} + +static int unf_scsi_queue_cmd(struct Scsi_Host *shost, + struct scsi_cmnd *v_cmnd) +{ + struct Scsi_Host *host = NULL; + struct scsi_cmnd *cmd = NULL; + struct unf_scsi_cmd_s scsi_cmnd = { 0 }; + unsigned int scsi_id = 0; + unsigned int en_scsi_state = 0; + int ret = SCSI_MLQUEUE_HOST_BUSY; + // unsigned int uiError = 0; + struct unf_lport_s *lport = NULL; + struct fc_rport *p_rport = NULL; + struct unf_rport_scsi_id_image_s *scsi_image_table = NULL; + unsigned int ret_value = 0; + struct unf_rport_s *rport = NULL; + unsigned int cmnd_result = 0; + unsigned int rport_state_err = 0; + unsigned int scan_device_cmd = 0; + unsigned long long raw_lun_id = 0; + int data_seg_cnt = 0; + + static atomic64_t ull_count; + host = shost; + cmd = v_cmnd; + UNF_CHECK_VALID(0x515, UNF_TRUE, host, return RETURN_ERROR); + UNF_CHECK_VALID(0x514, UNF_TRUE, cmd, return RETURN_ERROR); + + /* Get L_Port from scsi_cmnd */ + lport = (struct unf_lport_s *)host->hostdata[0]; + if (unlikely(!lport)) { + UNF_TRACE(0x3808, UNF_LOG_LOGIN_ATT, UNF_ERR, + "[err]Check l_port failed, cmd(%p)", cmd); + + /* scsi_done & return 0 & I/O error */ + cmd->result = DID_NO_CONNECT << 16; + cmd->scsi_done(cmd); + return 0; + } + + /* Check device/session local state by device_id */ + /* local SCSI_ID from device */ + scsi_id = (unsigned int)((unsigned long long)cmd->device->hostdata); + if (unlikely(scsi_id >= UNF_MAX_SCSI_ID)) { + UNF_TRACE(0x3808, UNF_LOG_LOGIN_ATT, UNF_ERR, + "[err]Port(0x%x) scsi_id(0x%x) is max than %d", + lport->port_id, scsi_id, UNF_MAX_SCSI_ID); + + /* scsi_done & return 0 & I/O error */ + cmd->result = DID_NO_CONNECT << 16; + cmd->scsi_done(cmd); + return 0; + } + + scsi_image_table = &lport->rport_scsi_table; + UNF_SCSI_CMD_CNT(scsi_image_table, scsi_id, cmd->cmnd[0]); + + /* Get scsi r_port */ + /*lint -e666 -esym(666,*)*/ + p_rport = starget_to_rport(scsi_target(cmd->device)); + if (unlikely(!p_rport)) { + UNF_TRACE(0x3808, UNF_LOG_LOGIN_ATT, UNF_ERR, + "[err]Port(0x%x) cmd(%p) to get scsi rport failed", + lport->port_id, cmd); + + /* scsi_done & return 0 & I/O error */ + cmd->result = DID_NO_CONNECT << 16; + cmd->scsi_done(cmd); + ret_value = DID_NO_CONNECT; + UNF_IO_RESULT_CNT(scsi_image_table, scsi_id, ret_value); + return 0; + } + + en_scsi_state = atomic_read(&scsi_image_table->wwn_rport_info_table[scsi_id].en_scsi_state); + if (unlikely(en_scsi_state != UNF_SCSI_ST_ONLINE)) { + if (en_scsi_state == UNF_SCSI_ST_OFFLINE) { + UNF_TRACE(0x3808, UNF_LOG_LOGIN_ATT, UNF_WARN, + "[warn]Port(0x%x) scsi_state(0x%x) scsi_id(0x%x) rport(0x%p) target_id(0x%x) cmd(0x%p), target is busy", + lport->port_id, en_scsi_state, scsi_id, + p_rport, p_rport->scsi_target_id, cmd); + + scan_device_cmd = (cmd->cmnd[0] == INQUIRY) || + (cmd->cmnd[0] == REPORT_LUNS); + + /* report lun or inquiry cmd, if send failed, + * do not retry, prevent the scan_mutex in + * scsi host locked up by eachother + */ + if (scan_device_cmd) { + UNF_TRACE(0x3808, UNF_LOG_LOGIN_ATT, UNF_WARN, + "[warn]Port(0x%x) host(0x%x) scsi_id(0x%x) lun(0x%llx) cmd(0x%x) DID_NO_CONNECT", + lport->port_id, host->host_no, + scsi_id, + (unsigned long long)cmd->device->lun, + cmd->cmnd[0]); + + cmd->result = DID_NO_CONNECT << 16; + cmd->scsi_done(cmd); + ret_value = DID_NO_CONNECT; + UNF_IO_RESULT_CNT(scsi_image_table, scsi_id, + ret_value); + + return 0; + } + + if (likely(scsi_image_table->wwn_rport_info_table)) { + if (likely(scsi_image_table->wwn_rport_info_table[scsi_id].dfx_counter)) + atomic64_inc(&scsi_image_table->wwn_rport_info_table[scsi_id].dfx_counter->target_busy); + } + + /* Target busy: need scsi retry */ + return SCSI_MLQUEUE_TARGET_BUSY; + } + /* timeout(DEAD): scsi_done & return 0 & I/O error */ + UNF_TRACE(0x3808, UNF_LOG_LOGIN_ATT, UNF_WARN, + "[warn]Port(0x%x) scsi_id(0x%x) rport(0x%p) target_id(0x%x) cmd(0x%p), target is loss timeout", + lport->port_id, scsi_id, p_rport, + p_rport->scsi_target_id, cmd); + cmd->result = DID_NO_CONNECT << 16; + cmd->scsi_done(cmd); + ret_value = DID_NO_CONNECT; + UNF_IO_RESULT_CNT(scsi_image_table, scsi_id, ret_value); + + return 0; + } + + raw_lun_id = ((unsigned long long)cmd->device->lun << 16) & + 0x00000000ffff0000; + if (scsi_sg_count(cmd)) { + data_seg_cnt = dma_map_sg(&lport->low_level_func.dev->dev, + scsi_sglist(cmd), + (int)scsi_sg_count(cmd), + cmd->sc_data_direction); + if (unlikely(!data_seg_cnt)) { + UNF_TRACE(0x3808, UNF_LOG_LOGIN_ATT, UNF_WARN, + "[warn]Port(0x%x) scsi_id(0x%x) rport(0x%p) target_id(0x%x) cmd(0x%p), dma map sg err", + lport->port_id, scsi_id, + p_rport, p_rport->scsi_target_id, cmd); + cmd->result = DID_BUS_BUSY << 16; + cmd->scsi_done(cmd); + ret_value = DID_BUS_BUSY; + UNF_IO_RESULT_CNT(scsi_image_table, scsi_id, ret_value); + return SCSI_MLQUEUE_HOST_BUSY; + } + } + + /* Construct local SCSI CMND info */ + /* save host_no to scsi_cmnd->scsi_host_id */ + scsi_cmnd.scsi_host_id = host->host_no; + scsi_cmnd.scsi_id = scsi_id; + scsi_cmnd.lun_id = raw_lun_id; + scsi_cmnd.data_direction = cmd->sc_data_direction; + scsi_cmnd.underflow = cmd->underflow; + scsi_cmnd.cmnd_len = cmd->cmd_len; + scsi_cmnd.pcmnd = cmd->cmnd; + scsi_cmnd.transfer_len = cpu_to_le32((uint32_t)scsi_bufflen(cmd)); + scsi_cmnd.sense_buf_len = SCSI_SENSE_DATA_LEN; + scsi_cmnd.sense_buf = cmd->sense_buffer; + scsi_cmnd.time_out = 0; + scsi_cmnd.upper_cmnd = cmd; + scsi_cmnd.drv_private = + (void *)(*(unsigned long long *)shost_priv(host)); + scsi_cmnd.entry_count = data_seg_cnt; + scsi_cmnd.sgl = scsi_sglist(cmd); + scsi_cmnd.pfn_unf_ini_get_sgl_entry = unf_get_frame_entry_buf; + scsi_cmnd.pfn_done = unf_scsi_done; + scsi_cmnd.pc_lun_id = (unsigned char *)&scsi_cmnd.lun_id; + scsi_cmnd.err_code_table_cout = ini_err_code_table_cnt1; + scsi_cmnd.err_code_table = ini_error_code_table1; + scsi_cmnd.world_id = 0xfffffffc; + scsi_cmnd.cmnd_sn = atomic64_inc_return(&ull_count); + if (unlikely(scsi_cmnd.cmnd_sn == 0)) + scsi_cmnd.cmnd_sn = atomic64_inc_return(&ull_count); + + if ((scsi_get_prot_op(cmd) != SCSI_PROT_NORMAL) && + hifc_dif_enable) { + ret = unf_get_protect_mode(lport, cmd, &scsi_cmnd); + if (ret != RETURN_OK) { + cmd->result = DID_BUS_BUSY << 16; + cmd->scsi_done(cmd); + ret_value = DID_BUS_BUSY; + UNF_IO_RESULT_CNT(scsi_image_table, scsi_id, + ret_value); + scsi_dma_unmap(cmd); + return SCSI_MLQUEUE_HOST_BUSY; + } + } + + UNF_TRACE(0x3808, UNF_LOG_LOGIN_ATT, UNF_INFO, + "[info]Port(0x%x) host(0x%x) scsi_id(0x%x) lun(0x%llx) transfer length(0x%x) cmd_len(0x%x) direction(0x%x) cmd(0x%x) under_flow(0x%x)", + lport->port_id, host->host_no, scsi_id, + (unsigned long long)cmd->device->lun, + scsi_cmnd.transfer_len, + scsi_cmnd.cmnd_len, cmd->sc_data_direction, + scsi_cmnd.pcmnd[0], scsi_cmnd.underflow); + /* Bind the Exchange address corresponding to scsi_cmnd to + * scsi_cmnd->host_scribble + */ + cmd->host_scribble = (unsigned char *)scsi_cmnd.cmnd_sn; + ret = unf_cm_queue_command(&scsi_cmnd); + if (ret != RETURN_OK) { + rport = unf_find_rport_by_scsi_id(lport, + ini_error_code_table1, + ini_err_code_table_cnt1, + scsi_id, + &cmnd_result); + rport_state_err = (!rport) || + (rport->lport_ini_state != + UNF_PORT_STATE_LINKUP) || + (rport->rp_state == UNF_RPORT_ST_CLOSING); + scan_device_cmd = (cmd->cmnd[0] == INQUIRY) || + (cmd->cmnd[0] == REPORT_LUNS); + + /* report lun or inquiry cmd if send failed, do not retry, + * prevent the scan_mutex in scsi host locked up by eachother + */ + if (rport_state_err && scan_device_cmd) { + UNF_TRACE(0x3808, UNF_LOG_LOGIN_ATT, UNF_WARN, + "[warn]Port(0x%x) host(0x%x) scsi_id(0x%x) lun(0x%llx) cmd(0x%x) cmResult(0x%x) DID_NO_CONNECT", + lport->port_id, host->host_no, scsi_id, + (unsigned long long)cmd->device->lun, + cmd->cmnd[0], cmnd_result); + + cmd->result = DID_NO_CONNECT << 16; + cmd->scsi_done(cmd); + ret_value = DID_NO_CONNECT; + UNF_IO_RESULT_CNT(scsi_image_table, scsi_id, ret_value); + scsi_dma_unmap(cmd); + unf_unmap_prot_sgl(cmd); + return 0; + } + + /* Host busy: scsi need to retry */ + ret = SCSI_MLQUEUE_HOST_BUSY; + if (likely(scsi_image_table->wwn_rport_info_table)) { + if (likely(scsi_image_table->wwn_rport_info_table[scsi_id].dfx_counter)) + atomic64_inc(&scsi_image_table->wwn_rport_info_table[scsi_id].dfx_counter->host_busy); + } + scsi_dma_unmap(cmd); + unf_unmap_prot_sgl(cmd); + UNF_TRACE(0x3808, UNF_LOG_LOGIN_ATT, UNF_WARN, + "[warn]Port(0x%x) return(0x%x) to process INI IO falid", + lport->port_id, ret); + } + return ret; +} + +static int unf_scsi_abort_scsi_cmnd(struct scsi_cmnd *v_cmnd) +{ + /* SCSI ABORT Command --->>> FC ABTS */ + struct unf_scsi_cmd_s scsi_cmnd = { 0 }; + struct Scsi_Host *scsi_host = NULL; + int ret = FAILED; + struct unf_rport_scsi_id_image_s *scsi_image_table = NULL; + struct unf_lport_s *lport = NULL; + unsigned int scsi_id = 0; + unsigned int err_handle = 0; + + UNF_CHECK_VALID(0x516, UNF_TRUE, v_cmnd, return FAILED); + + lport = (struct unf_lport_s *)v_cmnd->device->host->hostdata[0]; + scsi_id = (unsigned int)((unsigned long long)v_cmnd->device->hostdata); + + if (unf_is_lport_valid(lport) == RETURN_OK) { + scsi_image_table = &lport->rport_scsi_table; + err_handle = UNF_SCSI_ABORT_IO_TYPE; + UNF_SCSI_ERROR_HANDLE_CNT(scsi_image_table, + scsi_id, err_handle); + + UNF_TRACE(0x3808, UNF_LOG_LOGIN_ATT, UNF_MAJOR, + "[abort]Port(0x%x) scsi_id(0x%x) lun_id(0x%x) cmnd_type(0x%x)", + lport->port_id, scsi_id, + (unsigned int)v_cmnd->device->lun, + v_cmnd->cmnd[0]); + } else { + UNF_TRACE(0x3808, UNF_LOG_LOGIN_ATT, UNF_ERR, + "[err]Lport(%p) is moving or null", lport); + + return UNF_SCSI_ABORT_FAIL; + } + + /* Check local SCSI_ID validity */ + if (unlikely(scsi_id >= UNF_MAX_SCSI_ID)) { + UNF_TRACE(0x3808, UNF_LOG_LOGIN_ATT, UNF_ERR, + "[err]scsi_id(0x%x) is max than(0x%x)", + scsi_id, UNF_MAX_SCSI_ID); + + return UNF_SCSI_ABORT_FAIL; + } + + /* Block scsi (check rport state -> whether offline or not) */ + ret = fc_block_scsi_eh(v_cmnd); + if (unlikely(ret != 0)) { + UNF_TRACE(0x3808, UNF_LOG_LOGIN_ATT, UNF_WARN, + "[warn]Block scsi eh failed(0x%x)", ret); + + return ret; + } + + scsi_host = v_cmnd->device->host; + scsi_cmnd.scsi_host_id = scsi_host->host_no; // L_Port ID + scsi_cmnd.scsi_id = scsi_id; // R_Port ID (Target ID) + scsi_cmnd.lun_id = (unsigned long long)v_cmnd->device->lun; // LUN ID + scsi_cmnd.upper_cmnd = v_cmnd; // scsi_cmnd + // L_Port + scsi_cmnd.drv_private = + (void *)(*(unsigned long long *)shost_priv(scsi_host)); + scsi_cmnd.cmnd_sn = (unsigned long long)(v_cmnd->host_scribble); + scsi_cmnd.pc_lun_id = (unsigned char *)&scsi_cmnd.lun_id; + scsi_cmnd.pfn_done = unf_scsi_done; + scsi_cmnd.world_id = 0xfffffffc; + /* Process scsi Abort cmnd */ + ret = unf_cm_eh_abort_handler(&scsi_cmnd); + if (ret == UNF_SCSI_ABORT_SUCCESS) { + if (unf_is_lport_valid(lport) == RETURN_OK) { + scsi_image_table = &lport->rport_scsi_table; + err_handle = UNF_SCSI_ABORT_IO_TYPE; + UNF_SCSI_ERROR_HANDLE_RESULT_CNT(scsi_image_table, + scsi_id, err_handle); + } + } + + return ret; +} + +static int unf_scsi_device_reset_handler(struct scsi_cmnd *v_cmnd) +{ + /* LUN reset */ + struct unf_scsi_cmd_s scsi_cmnd = { 0 }; + struct Scsi_Host *scsi_host = NULL; + struct unf_rport_scsi_id_image_s *scsi_image_table = NULL; + int ret = FAILED; + struct unf_lport_s *lport = NULL; + unsigned int scsi_id = 0; + unsigned int err_handle = 0; + + UNF_CHECK_VALID(0x517, UNF_TRUE, v_cmnd, return FAILED); + + lport = (struct unf_lport_s *)v_cmnd->device->host->hostdata[0]; + if (unf_is_lport_valid(lport) == RETURN_OK) { + scsi_image_table = &lport->rport_scsi_table; + err_handle = UNF_SCSI_DEVICE_RESET_TYPE; + UNF_SCSI_ERROR_HANDLE_CNT(scsi_image_table, + scsi_id, err_handle); + + UNF_TRACE(0x3808, UNF_LOG_LOGIN_ATT, UNF_KEVENT, + "[device_reset]Port(0x%x) scsi_id(0x%x) lun_id(0x%x) cmnd_type(0x%x)", + lport->port_id, scsi_id, + (unsigned int)v_cmnd->device->lun, + v_cmnd->cmnd[0]); + } else { + UNF_TRACE(0x3808, UNF_LOG_LOGIN_ATT, UNF_ERR, + "[err]Port is invalid"); + + return FAILED; + } + + /* Check local SCSI_ID validity */ + scsi_id = (unsigned int)((unsigned long long)v_cmnd->device->hostdata); + if (unlikely(scsi_id >= UNF_MAX_SCSI_ID)) { + UNF_TRACE(0x3808, UNF_LOG_LOGIN_ATT, UNF_ERR, + "[err]scsi_id(0x%x) is max than(0x%x)", + scsi_id, UNF_MAX_SCSI_ID); + + return FAILED; + } + + /* Block scsi (check rport state -> whether offline or not) */ + ret = fc_block_scsi_eh(v_cmnd); + if (unlikely(ret != 0)) { + UNF_TRACE(0x3808, UNF_LOG_LOGIN_ATT, UNF_WARN, + "[warn]Block scsi eh failed(0x%x)", ret); + + return ret; + } + + scsi_host = v_cmnd->device->host; + scsi_cmnd.scsi_host_id = scsi_host->host_no; /* l_port id */ + scsi_cmnd.scsi_id = scsi_id; /* r_port id */ + scsi_cmnd.lun_id = (unsigned long long)v_cmnd->device->lun; /* lun id */ + scsi_cmnd.upper_cmnd = v_cmnd; /* scsi_cmnd */ + /* l_port */ + scsi_cmnd.drv_private = + (void *)(*(unsigned long long *)shost_priv(scsi_host)); + scsi_cmnd.pc_lun_id = (unsigned char *)&scsi_cmnd.lun_id; /* lun id */ + + /* Process scsi device/LUN reset cmnd */ + ret = unf_cm_eh_device_reset_handler(&scsi_cmnd); + if (ret == UNF_SCSI_ABORT_SUCCESS) { + if (unf_is_lport_valid(lport) == RETURN_OK) { + scsi_image_table = &lport->rport_scsi_table; + err_handle = UNF_SCSI_DEVICE_RESET_TYPE; + UNF_SCSI_ERROR_HANDLE_RESULT_CNT(scsi_image_table, + scsi_id, + err_handle); + } + } + + return ret; +} + +static int unf_scsi_bus_reset_handler(struct scsi_cmnd *v_cmnd) +{ + /* BUS Reset */ + struct unf_scsi_cmd_s scsi_cmnd = { 0 }; + struct unf_lport_s *lport = NULL; + struct Scsi_Host *scsi_host = NULL; + struct unf_rport_scsi_id_image_s *scsi_image_table = NULL; + int ret = FAILED; + unsigned int scsi_id = 0; + unsigned int err_handle = 0; + + UNF_CHECK_VALID(0x517, UNF_TRUE, v_cmnd, return FAILED); + + lport = (struct unf_lport_s *)v_cmnd->device->host->hostdata[0]; + if (unlikely(!lport)) { + UNF_TRACE(0x3808, UNF_LOG_LOGIN_ATT, UNF_ERR, + "[err]Port is null"); + + return FAILED; + } + + /* Check local SCSI_ID validity */ + scsi_id = (unsigned int)((unsigned long long)v_cmnd->device->hostdata); + if (unlikely(scsi_id >= UNF_MAX_SCSI_ID)) { + UNF_TRACE(0x3808, UNF_LOG_LOGIN_ATT, UNF_ERR, + "[err]scsi_id(0x%x) is max than(0x%x)", + scsi_id, UNF_MAX_SCSI_ID); + + return FAILED; + } + + if (unf_is_lport_valid(lport) == RETURN_OK) { + scsi_image_table = &lport->rport_scsi_table; + err_handle = UNF_SCSI_BUS_RESET_TYPE; + UNF_SCSI_ERROR_HANDLE_CNT(scsi_image_table, + scsi_id, err_handle); + + UNF_TRACE(0x3808, UNF_LOG_LOGIN_ATT, UNF_MAJOR, + "[info][bus_reset]Port(0x%x) scsi_id(0x%x) lun_id(0x%x) cmnd_type(0x%x)", + lport->port_id, scsi_id, + (unsigned int)v_cmnd->device->lun, + v_cmnd->cmnd[0]); + } + + /* Block scsi (check rport state -> whether offline or not) */ + ret = fc_block_scsi_eh(v_cmnd); + if (unlikely(ret != 0)) { + UNF_TRACE(0x3808, UNF_LOG_LOGIN_ATT, UNF_WARN, + "[warn]Block scsi eh failed(0x%x)", ret); + + return ret; + } + + scsi_host = v_cmnd->device->host; + scsi_cmnd.scsi_host_id = scsi_host->host_no; /* l_port id */ + scsi_cmnd.scsi_id = scsi_id; /* r_port id */ + scsi_cmnd.lun_id = (unsigned long long)v_cmnd->device->lun; /* lun id */ + scsi_cmnd.upper_cmnd = v_cmnd; /* scsi_cmnd */ + /* l_port */ + scsi_cmnd.drv_private = + (void *)(*(unsigned long long *)shost_priv(scsi_host)); + scsi_cmnd.pc_lun_id = (unsigned char *)&scsi_cmnd.lun_id; /* lun id */ + + /* Process scsi BUS Reset cmnd */ + ret = unf_cm_bus_reset_handler(&scsi_cmnd); + if (ret == UNF_SCSI_ABORT_SUCCESS) { + if (unf_is_lport_valid(lport) == RETURN_OK) { + scsi_image_table = &lport->rport_scsi_table; + err_handle = UNF_SCSI_BUS_RESET_TYPE; + UNF_SCSI_ERROR_HANDLE_RESULT_CNT(scsi_image_table, + scsi_id, + err_handle); + } + } + + return ret; +} + +static int unf_scsi_target_reset_handler(struct scsi_cmnd *v_cmnd) +{ + /* Session reset/delete */ + struct unf_scsi_cmd_s scsi_cmnd = { 0 }; + struct Scsi_Host *scsi_host = NULL; + struct unf_rport_scsi_id_image_s *scsi_image_table = NULL; + int ret = FAILED; + struct unf_lport_s *lport = NULL; + unsigned int scsi_id = 0; + unsigned int err_handle = 0; + + UNF_CHECK_VALID(0x517, UNF_TRUE, v_cmnd, return RETURN_ERROR); + + lport = (struct unf_lport_s *)v_cmnd->device->host->hostdata[0]; + if (unlikely(!lport)) { + UNF_TRACE(0x3808, UNF_LOG_LOGIN_ATT, UNF_ERR, + "[err]Port is null"); + + return FAILED; + } + + /* Check local SCSI_ID validity */ + scsi_id = (unsigned int)((unsigned long long)v_cmnd->device->hostdata); + if (unlikely(scsi_id >= UNF_MAX_SCSI_ID)) { + UNF_TRACE(0x3808, UNF_LOG_LOGIN_ATT, UNF_ERR, + "[err]scsi_id(0x%x) is max than(0x%x)", + scsi_id, UNF_MAX_SCSI_ID); + + return FAILED; + } + + if (unf_is_lport_valid(lport) == RETURN_OK) { + scsi_image_table = &lport->rport_scsi_table; + err_handle = UNF_SCSI_TARGET_RESET_TYPE; + UNF_SCSI_ERROR_HANDLE_CNT(scsi_image_table, scsi_id, + err_handle); + + UNF_TRACE(0x3808, UNF_LOG_LOGIN_ATT, UNF_KEVENT, + "[target_reset]Port(0x%x) scsi_id(0x%x) lun_id(0x%x) cmnd_type(0x%x)", + lport->port_id, scsi_id, + (unsigned int)v_cmnd->device->lun, + v_cmnd->cmnd[0]); + } + + /* Block scsi (check rport state -> whether offline or not) */ + ret = fc_block_scsi_eh(v_cmnd); + if (unlikely(ret != 0)) { + UNF_TRACE(0x3808, UNF_LOG_LOGIN_ATT, UNF_WARN, + "[warn]Block scsi eh failed(0x%x)", ret); + + return ret; + } + + scsi_host = v_cmnd->device->host; + scsi_cmnd.scsi_host_id = scsi_host->host_no; /* l_port id */ + scsi_cmnd.scsi_id = scsi_id; /* r_port id */ + scsi_cmnd.lun_id = (unsigned long long)v_cmnd->device->lun; /* lun id */ + scsi_cmnd.upper_cmnd = v_cmnd; /* scsi_cmnd */ + /* l_port */ + scsi_cmnd.drv_private = + (void *)(*(unsigned long long *)shost_priv(scsi_host)); + scsi_cmnd.pc_lun_id = (unsigned char *)&scsi_cmnd.lun_id; /* lun id */ + + /* Process scsi Target/Session reset/delete cmnd */ + ret = unf_cm_target_reset_handler(&scsi_cmnd); + if (ret == UNF_SCSI_ABORT_SUCCESS) { + if (unf_is_lport_valid(lport) == RETURN_OK) { + scsi_image_table = &lport->rport_scsi_table; + err_handle = UNF_SCSI_TARGET_RESET_TYPE; + UNF_SCSI_ERROR_HANDLE_RESULT_CNT(scsi_image_table, + scsi_id, err_handle); + } + } + + return ret; +} + +static int unf_scsi_slave_alloc(struct scsi_device *sdev) +{ + /*lint -e666 -esym(666,*)*/ + struct fc_rport *rport = NULL; + unsigned int scsi_id = 0; + struct unf_lport_s *lport = NULL; + struct Scsi_Host *host = NULL; + struct unf_rport_scsi_id_image_s *scsi_image_table = NULL; + + /* About device */ + if (unlikely(!sdev)) { + UNF_TRACE(0x4101, UNF_LOG_LOGIN_ATT, UNF_ERR, + "[err]SDev is null"); + + return -ENXIO; + } + + /* About scsi rport */ + rport = starget_to_rport(scsi_target(sdev)); + if (unlikely(!rport || fc_remote_port_chkready(rport))) { + UNF_TRACE(0x4101, UNF_LOG_LOGIN_ATT, UNF_ERR, + "[err]SCSI rport is null"); + + if (rport) { + UNF_TRACE(0x4101, UNF_LOG_LOGIN_ATT, UNF_ERR, + "[err]SCSI rport is not ready(0x%x)", + fc_remote_port_chkready(rport)); + } + + return -ENXIO; + } + + /* About host */ + host = rport_to_shost(rport); + if (unlikely(!host)) { + UNF_TRACE(0x3808, UNF_LOG_LOGIN_ATT, UNF_ERR, + "[err]Host is null"); + + return -ENXIO; + } + + /* About Local Port */ + lport = (struct unf_lport_s *)host->hostdata[0]; + if (unf_is_lport_valid(lport) != RETURN_OK) { + UNF_TRACE(0x3808, UNF_LOG_LOGIN_ATT, UNF_ERR, + "[err]Port is invalid"); + + return -ENXIO; + } + + /* About Local SCSI_ID */ + /* use local SCSI_ID to alloc slave device */ + scsi_id = *(unsigned int *)rport->dd_data; + if (unlikely(scsi_id >= UNF_MAX_SCSI_ID)) { + UNF_TRACE(0x3808, UNF_LOG_LOGIN_ATT, UNF_ERR, + "[err]scsi_id(0x%x) is max than(0x%x)", + scsi_id, UNF_MAX_SCSI_ID); + + return -ENXIO; + } + + scsi_image_table = &lport->rport_scsi_table; + if (scsi_image_table->wwn_rport_info_table[scsi_id].dfx_counter) + atomic_inc(&scsi_image_table->wwn_rport_info_table[scsi_id].dfx_counter->device_alloc); + + atomic_inc(&lport->device_alloc); + /* save local SCSI_ID */ + sdev->hostdata = (void *)(unsigned long long)scsi_id; + + UNF_TRACE(0x4101, UNF_LOG_LOGIN_ATT, UNF_KEVENT, + "[event]Port(0x%x) use scsi_id(%d) to alloc device[%u:%u:%u:%u]", + lport->port_id, scsi_id, host->host_no, + sdev->channel, sdev->id, (unsigned int)sdev->lun); + + return 0; +} + +static void unf_scsi_destroy_slave(struct scsi_device *sdev) +{ + /* + * NOTE: about sdev->hostdata + * --->>> pointing to local SCSI_ID + * 1. Assignment during slave allocation + * 2. Released when callback for slave destroy + * 3. Used during: Queue_CMND, Abort CMND, Device Reset, + * Target Reset & Bus Reset + */ + /*lint -e666 -esym(666,*)*/ + struct fc_rport *rport = NULL; + unsigned int scsi_id = 0; + struct unf_lport_s *lport = NULL; + struct Scsi_Host *host = NULL; + struct unf_rport_scsi_id_image_s *scsi_image_table = NULL; + + /* About scsi device */ + if (unlikely(!sdev)) { + UNF_TRACE(0x4101, UNF_LOG_LOGIN_ATT, UNF_ERR, + "[err]SDev is null"); + return; + } + + /* About scsi rport */ + rport = starget_to_rport(scsi_target(sdev)); + if (unlikely(!rport)) { + UNF_TRACE(0x4101, UNF_LOG_LOGIN_ATT, UNF_ERR, + "[err]SCSI rport is null or remote port is not ready"); + return; + } + + /* About host */ + host = rport_to_shost(rport); + if (unlikely(!host)) { + UNF_TRACE(0x3808, UNF_LOG_LOGIN_ATT, UNF_ERR, + "[err]Host is null"); + return; + } + + /* About L_Port */ + lport = (struct unf_lport_s *)host->hostdata[0]; + if (unf_is_lport_valid(lport) == RETURN_OK) { + scsi_image_table = &lport->rport_scsi_table; + atomic_inc(&lport->device_destroy); + + scsi_id = (unsigned int)((unsigned long long)sdev->hostdata); + if ((scsi_id < UNF_MAX_SCSI_ID) && + (scsi_image_table->wwn_rport_info_table)) { + if (scsi_image_table->wwn_rport_info_table[scsi_id].dfx_counter) + atomic_inc(&scsi_image_table->wwn_rport_info_table[scsi_id].dfx_counter->device_destroy); + + UNF_TRACE(0x4101, UNF_LOG_LOGIN_ATT, UNF_KEVENT, + "[event]Port(0x%x) with scsi_id(%d) to destroy slave device[%u:%u:%u:%u]", + lport->port_id, scsi_id, host->host_no, + sdev->channel, sdev->id, + (unsigned int)sdev->lun); + } else { + UNF_TRACE(0x4101, UNF_LOG_LOGIN_ATT, UNF_WARN, + "[err]Port(0x%x) scsi_id(%d) is invalid and destroy device[%u:%u:%u:%u]", + lport->port_id, scsi_id, host->host_no, + sdev->channel, sdev->id, + (unsigned int)sdev->lun); + } + } else { + UNF_TRACE(0x3097, UNF_LOG_LOGIN_ATT, UNF_ERR, + "[err]Port(%p) is invalid", lport); + } + + sdev->hostdata = NULL; /* reset local SCSI_ID */ +} + +static int unf_scsi_slave_configure(struct scsi_device *sdev) +{ +#define UNF_SCSI_DEV_DEPTH 32 + blk_queue_update_dma_alignment(sdev->request_queue, 0x7); + scsi_change_queue_depth(sdev, UNF_SCSI_DEV_DEPTH); + UNF_TRACE(0x4101, UNF_LOG_LOGIN_ATT, UNF_INFO, + "[event]Enter slave configure, set depth is %d, sdev->tagged_supported is (%d)", + UNF_SCSI_DEV_DEPTH, sdev->tagged_supported); + + return 0; +} + +static int unf_scsi_scan_finished(struct Scsi_Host *shost, unsigned long time) +{ + UNF_TRACE(0x4101, UNF_LOG_LOGIN_ATT, UNF_MAJOR, + "[event]Scan finished"); + + return 1; +} + +static void unf_scsi_scan_start(struct Scsi_Host *shost) +{ + UNF_TRACE(0x4101, UNF_LOG_LOGIN_ATT, UNF_MAJOR, + "[event]Start scsi scan..."); +} + +unsigned int unf_register_ini_transport(void) +{ + /* Register INI Transport */ + scsi_transport_template = fc_attach_transport(&function_template); + + if (!scsi_transport_template) { + UNF_TRACE(0x4101, UNF_LOG_LOGIN_ATT, UNF_ERR, + "[err]Register FC transport to scsi failed"); + + return RETURN_ERROR; + } + + scsi_transport_template_v = fc_attach_transport(&function_template_v); + if (!scsi_transport_template_v) { + UNF_TRACE(0x4101, UNF_LOG_LOGIN_ATT, UNF_ERR, + "[err]Register FC vport transport to scsi failed"); + + fc_release_transport(scsi_transport_template); + + return RETURN_ERROR; + } + + UNF_TRACE(0x4101, UNF_LOG_LOGIN_ATT, UNF_MAJOR, + "[event]Register FC transport to scsi succeed"); + + return RETURN_OK; +} + +void unf_unregister_ini_transport(void) +{ + fc_release_transport(scsi_transport_template); + fc_release_transport(scsi_transport_template_v); + UNF_TRACE(0x4101, UNF_LOG_LOGIN_ATT, UNF_MAJOR, + "[event]Unregister FC transport succeed"); +} + +void unf_report_io_dm_event(void *v_lport, unsigned int type, + unsigned int value) +{ +} + +void unf_save_sense_data(void *scsicmd, const char *sense, int senslen) +{ + struct scsi_cmnd *cmd; + + UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, scsicmd, return); + UNF_CHECK_VALID(INVALID_VALUE32, UNF_TRUE, sense, return); + + cmd = (struct scsi_cmnd *)scsicmd; + memcpy(cmd->sense_buffer, sense, senslen); +} diff --git a/drivers/scsi/huawei/hifc/unf_scsi_common.h b/drivers/scsi/huawei/hifc/unf_scsi_common.h new file mode 100644 index 000000000000..59580ad2e63e --- /dev/null +++ b/drivers/scsi/huawei/hifc/unf_scsi_common.h @@ -0,0 +1,1136 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Huawei Hifc PCI Express Linux driver + * Copyright(c) 2017 Huawei Technologies Co., Ltd + * + */ +#ifndef __UNF_SCSI_COMMON__ +#define __UNF_SCSI_COMMON__ + +#include "unf_log.h" +#include "hifc_knl_adp.h" + +#define DRV_ISCSI_NAME 223 + +#define SCSI_SENSE_DATA_LEN 96 + +#define DRV_SCSI_CDB_LEN 16 +#define DRV_SCSI_LUN_LEN 8 +#define DRV_PORTID_NUM 32 + +#ifndef SUCCESS +#define SUCCESS 0x2002 +#endif + +#ifndef FAILED +#define FAILED 0x2003 +#endif + +#ifndef FC_PORTSPEED_32GBIT +#define FC_PORTSPEED_32GBIT 0x40 +#endif + +/* + * FCTL defines (FrameHdr.Type_Fctl) + */ +#define FC_EXCHANGE_RESPONDER 0x00800000 +#define FC_LAST_SEQUENCE 0x00100000 +#define FC_END_SEQUENCE 0x00080000 +#define FC_SEQUENCE_INITIATIVE 0x00010000 + +/* + * FCTL common use defines + */ +#define FC_FCTL_RSP (FC_EXCHANGE_RESPONDER | FC_LAST_SEQUENCE | \ + FC_END_SEQUENCE) + +#define UNF_GID_PORT_CNT 2048 +#define UNF_RSCN_PAGE_SUM 255 + +#define UNF_CPU_ENDIAN + +#define UNF_NPORTID_MASK 0x00FFFFFF +#define UNF_DOMAIN_MASK 0x00FF0000 +#define UNF_AREA_MASK 0x0000FF00 +#define UNF_ALPA_MASK 0x000000FF + +#define UNF_NPORTID_WELLKNOWN_MASK 0x00fffff0 + +#define UNF_SCSI_ABORT_SUCCESS SUCCESS +#define UNF_SCSI_ABORT_FAIL FAILED + +#define UNF_SCSI_STATUS(byte) (byte) +#define UNF_SCSI_MSG(byte) ((byte) << 8) +#define UNF_SCSI_HOST(byte) ((byte) << 16) +#define UNF_SCSI_DRIVER(byte) ((byte) << 24) + +#define UNF_GET_SCSI_HOST_ID(scsi_host) ((scsi_host)->host_no) + +struct unf_fchead_s { + /* Routing control and Destination address of the seq */ + unsigned int rctl_did; + /* Class control and Source address of the sequence */ + unsigned int csctl_sid; + /* Data type and Initial frame control value of the seq */ + unsigned int type_fctl; + /* Seq ID, Data Field and Initial seq count */ + unsigned int seq_id_dfctl_seq_cnt; + /* Originator & Responder exchange IDs for the sequence */ + unsigned int oxid_rxid; + /* Relative offset of the first frame of the sequence */ + unsigned int parameter; +}; + +#define UNF_FCPRSP_CTL_LEN (24) +#define UNF_MAX_RSP_INFO_LEN (8) +#define UNF_RSP_LEN_VLD (1 << 0) +#define UNF_SENSE_LEN_VLD (1 << 1) +#define UNF_RESID_OVERRUN (1 << 2) +#define UNF_RESID_UNDERRUN (1 << 3) + +/* T10: FCP2r.07 9.4.1 Overview and format of FCP_RSP IU */ +struct unf_fcprsp_iu_s { + unsigned int ui_reserved[2]; + unsigned char uc_reserved[2]; + unsigned char control; + unsigned char fcp_status; + unsigned int fcp_residual; + unsigned int fcp_sense_len; /* Length of sense info field */ + /* Length of response info field in bytes 0,4 or 8 */ + unsigned int fcp_response_len; + /* Buffer for response info */ + unsigned char fcp_rsp_info[UNF_MAX_RSP_INFO_LEN]; + /* Buffer for sense info */ + unsigned char fcp_sense_info[SCSI_SENSE_DATA_LEN]; +} __attribute__((packed)); + +#define UNF_CMD_REF_MASK 0xFF000000 +#define UNF_TASK_ATTR_MASK 0x00070000 +#define UNF_TASK_MGMT_MASK 0x0000FF00 +#define UNF_FCP_WR_DATA 0x00000001 +#define UNF_FCP_RD_DATA 0x00000002 +#define UNF_CDB_LEN_MASK 0x0000007C +#define UNF_FCP_CDB_LEN_16 (16) +#define UNF_FCP_CDB_LEN_32 (32) +#define UNF_FCP_LUNID_LEN_8 (8) + +/* FCP-4 :Table 27 - RSP_CODE field */ +#define UNF_FCP_TM_RSP_COMPLETE (0) +#define UNF_FCP_TM_INVALID_CMND (0x2) +#define UNF_FCP_TM_RSP_REJECT (0x4) +#define UNF_FCP_TM_RSP_FAIL (0x5) +#define UNF_FCP_TM_RSP_SUCCEED (0x8) +#define UNF_FCP_TM_RSP_INCRECT_LUN (0x9) + +#define UNF_SET_TASK_MGMT_FLAGS(v_fcp_tm_code) ((v_fcp_tm_code) << 8) +#define UNF_GET_TASK_MGMT_FLAGS(v_control) \ + (((v_control) & UNF_TASK_MGMT_MASK) >> 8) + +enum unf_task_mgmt_cmnd_e { + UNF_FCP_TM_QUERY_TASK_SET = (1 << 0), + UNF_FCP_TM_ABORT_TASK_SET = (1 << 1), + UNF_FCP_TM_CLEAR_TASK_SET = (1 << 2), + UNF_FCP_TM_QUERY_UNIT_ATTENTION = (1 << 3), + UNF_FCP_TM_LOGICAL_UNIT_RESET = (1 << 4), + UNF_FCP_TM_TARGET_RESET = (1 << 5), + UNF_FCP_TM_CLEAR_ACA = (1 << 6), + UNF_FCP_TM_TERMINATE_TASK = (1 << 7) /* obsolete */ +}; + +struct unf_fcp_cmnd_s { + unsigned char lun[UNF_FCP_LUNID_LEN_8]; /* Logical unit number */ + + unsigned int control; /* Control field : + * uint8_t cmnd_ref; + * uint8_t task_attr:3; + * uint8_t reserved:5; + * uint8_t task_mgmt_flags; + * uint8_t wrdata:1; + * uint8_t rddata:1; + * uint8_t add_cdb_len:6; + */ + /* Payload data containing cdb info */ + unsigned char cdb[UNF_FCP_CDB_LEN_16]; + /* Number of bytes expected to be transferred */ + unsigned int data_length; +} __attribute__((packed)); + +struct unf_fcp_cmd_hdr_s { + struct unf_fchead_s frame_hdr; /* FCHS structure */ + struct unf_fcp_cmnd_s fcp_cmnd; /* Fcp Cmnd struct */ +}; + +/* + * parameter struct + */ + +/* Common Services Parameter used for returning Fabric + * parameters. See FC-FS Rev. 1.90, FC-PH-3 Rev. 9.4 and see FC-DA 3.1. + * This is the structure that is used to enquire Fabric parameters + * after a Fabric login is successful. The fileds in this structure + * are relevant for FLOGI ACC. + */ + +/* FC-LS-2 Table 140 Common Service Parameter applicability */ +struct unf_fabric_coparms_s { +#if defined(UNF_CPU_ENDIAN) + unsigned int bb_credit : 16; /* 0 [0-15] */ + unsigned int lowest_version : 8; /* 0 [16-23] */ + unsigned int highest_version : 8; /* 0 [24-31] */ +#else + unsigned int highest_version : 8; /* 0 [24-31] */ + unsigned int lowest_version : 8; /* 0 [16-23] */ + unsigned int bb_credit : 16; /* 0 [0-15] */ +#endif + + /* Word1 Common Features */ +#if defined(UNF_CPU_ENDIAN) + unsigned int bb_receive_data_field_size : 12; /* 1 [0-11] */ + unsigned int bb_scn : 4; /* 1 [12-15] */ + unsigned int payload_length : 1; /* 1 [16] */ + unsigned int seq_cnt : 1; /* 1 [17] */ + unsigned int dynamic_half_duplex : 1; /* 1 [18] */ + unsigned int r_t_tov : 1; /* 1 [19] */ + unsigned int reserved_co2 : 6; /* 1 [20-25] */ + unsigned int e_d_tov_resolution : 1; /* 1 [26] */ + unsigned int alternate_bb_credit_mgmt : 1; /* 1 [27] */ + unsigned int n_port : 1; /* 1 [28] */ + unsigned int mnid_assignment : 1; /* 1 [29] */ + unsigned int random_relative_offset : 1; /* 1 [30] */ + unsigned int clean_address : 1; /* 1 [31] */ +#else + unsigned int reserved_co22 : 2; /* 1 [24-25] */ + unsigned int e_d_tov_resolution : 1; /* 1 [26] */ + unsigned int alternate_bb_credit_mgmt : 1; /* 1 [27] */ + unsigned int n_port : 1; /* 1 [28] */ + unsigned int mnid_assignment : 1; /* 1 [29] */ + unsigned int random_relative_offset : 1; /* 1 [30] */ + unsigned int clean_address : 1; /* 1 [31] */ + + unsigned int payload_length : 1; /* 1 [16] */ + unsigned int seq_cnt : 1; /* 1 [17] */ + unsigned int dynamic_half_duplex : 1; /* 1 [18] */ + unsigned int r_t_tov : 1; /* 1 [19] */ + unsigned int reserved_co25 : 4; /* 1 [20-23] */ + + unsigned int bb_receive_data_field_size : 12; /* 1 [0-11] */ + unsigned int bb_scn : 4; /* 1 [12-15] */ +#endif + unsigned int r_a_tov; /* 2 [0-31] */ + unsigned int e_d_tov; /* 3 [0-31] */ +}; + +/* + * Common Services Parameter 16 byte structure. + * See FC-PH 4.3 Section 23.6.3, FC-PLDA Section 5.2 and + * TachLite Users Manual 3.24.1 + * the structure does not need to be packed. + */ + +/* FC-LS-2 Table 140 Common Service Parameter applicability */ +/* Table 142 Common Service Parameters - PLOGI and PLOGI LS_ACC */ +struct unf_lgn_port_coparms_s { +#if defined(UNF_CPU_ENDIAN) + unsigned int bb_credit : 16; /* 0 [0-15] */ + unsigned int lowest_version : 8; /* 0 [16-23] */ + unsigned int highest_version : 8; /* 0 [24-31] */ +#else + unsigned int highest_version : 8; /* 0 [24-31] */ + unsigned int lowest_version : 8; /* 0 [16-23] */ + unsigned int bb_credit : 16; /* 0 [0-15] */ +#endif + +#if defined(UNF_CPU_ENDIAN) + unsigned int bb_receive_data_field_size : 12; /* 1 [0-11] */ + unsigned int bb_scn : 4; /* 1 [12-15] */ + unsigned int payload_length : 1; /* 1 [16] */ + unsigned int seq_cnt : 1; /* 1 [17] */ + unsigned int dynamic_half_duplex : 1; /* 1 [18] */ + unsigned int reserved_co2 : 7; /* 1 [19-25] */ + unsigned int e_d_tov_resolution : 1; /* 1 [26] */ + unsigned int alternate_bb_credit_mgmt : 1; /* 1 [27] */ + unsigned int n_port : 1; /* 1 [28] */ + unsigned int vendor_version_level : 1; /* 1 [29] */ + unsigned int random_relative_offset : 1; /* 1 [30] */ + unsigned int continuously_increasing : 1; /* 1 [31] */ +#else + unsigned int reserved_co22 : 2; /* 1 [24-25] */ + unsigned int e_d_tov_resolution : 1; /* 1 [26] */ + unsigned int alternate_bb_credit_mgmt : 1; /* 1 [27] */ + unsigned int n_port : 1; /* 1 [28] */ + unsigned int vendor_version_level : 1; /* 1 [29] */ + unsigned int random_relative_offset : 1; /* 1 [30] */ + unsigned int continuously_increasing : 1; /* 1 [31] */ + + unsigned int payload_length : 1; /* 1 [16] */ + unsigned int seq_cnt : 1; /* 1 [17] */ + unsigned int dynamic_half_duplex : 1; /* 1 [18] */ + unsigned int reserved_co25 : 5; /* 1 [19-23] */ + + unsigned int bb_receive_data_field_size : 12; /* 1 [0-11] */ + unsigned int reserved_co1 : 4; /* 1 [12-15] */ +#endif + +#if defined(UNF_CPU_ENDIAN) + unsigned int relative_offset : 16; /* 2 [0-15] */ + unsigned int nport_total_concurrent_sequences : 16; /* 2 [16-31] */ +#else + unsigned int nport_total_concurrent_sequences : 16; /* 2 [16-31] */ + unsigned int relative_offset : 16; /* 2 [0-15] */ +#endif + + unsigned int e_d_tov; +}; + +/* + * Class services 16 byte structure. See FC-PH 4.3 Section 23.6.8 and + * FC-PLDA Section 5.3 + * the structure does not need to be packed + */ + +/* FC-LS-2 Table 145 Class Service Parameters Applicability */ +struct unf_lgn_port_clparms_s { +#if defined(UNF_CPU_ENDIAN) + unsigned int reserved_cl1 : 6; /* 0 [0-5] */ + unsigned int ic_data_compression_history_buffer_size : 2; /* 0 [6-7] */ + unsigned int ic_data_compression_capable : 1; /* 0 [8] */ + + unsigned int ic_ack_generation_assistance : 1; /* 0 [9] */ + unsigned int ic_ack_n_capable : 1; /* 0 [10] */ + unsigned int ic_ack_o_capable : 1; /* 0 [11] */ + /* 0 [12-13] */ + unsigned int ic_initial_responder_processes_accociator : 2; + unsigned int ic_x_id_reassignment : 2; /* 0 [14-15] */ + + unsigned int reserved_cl2 : 7; /* 0 [16-22] */ + unsigned int priority : 1; /* 0 [23] */ + unsigned int buffered_class : 1; /* 0 [24] */ + unsigned int camp_on : 1; /* 0 [25] */ + unsigned int dedicated_simplex : 1; /* 0 [26] */ + unsigned int sequential_delivery : 1; /* 0 [27] */ + unsigned int stacked_connect_request : 2; /* 0 [28-29] */ + unsigned int intermix_mode : 1; /* 0 [30] */ + unsigned int valid : 1; /* 0 [31] */ +#else + unsigned int buffered_class : 1; /* 0 [24] */ + unsigned int camp_on : 1; /* 0 [25] */ + unsigned int dedicated_simplex : 1; /* 0 [26] */ + unsigned int sequential_delivery : 1; /* 0 [27] */ + unsigned int stacked_connect_request : 2; /* 0 [28-29] */ + unsigned int intermix_mode : 1; /* 0 [30] */ + unsigned int valid : 1; /* 0 [31] */ + unsigned int reserved_cl2 : 7; /* 0 [16-22] */ + unsigned int priority : 1; /* 0 [23] */ + unsigned int ic_data_compression_capable : 1; /* 0 [8] */ + unsigned int ic_ack_generation_assistance : 1; /* 0 [9] */ + unsigned int ic_ack_n_capable : 1; /* 0 [10] */ + unsigned int ic_ack_o_capable : 1; /* 0 [11] */ + /* 0 [12-13] */ + unsigned int ic_initial_responder_processes_accociator : 2; + unsigned int ic_x_id_reassignment : 2; /* 0 [14-15] */ + + unsigned int reserved_cl1 : 6; /* 0 [0-5] */ + /* 0 [6-7] */ + unsigned int ic_data_compression_history_buffer_size : 2; +#endif + +#if defined(UNF_CPU_ENDIAN) + unsigned int received_data_field_size : 16; /* 1 [0-15] */ + + unsigned int reserved_cl3 : 5; /* 1 [16-20] */ + /* 1 [21-22] */ + unsigned int rc_data_compression_history_buffer_size : 2; + unsigned int rc_data_compression_capable : 1; /* 1 [23] */ + + unsigned int rc_categories_per_sequence : 2; /* 1 [24-25] */ + unsigned int reserved_cl4 : 1; /* 1 [26] */ + unsigned int rc_error_policy_supported : 2; /* 1 [27-28] */ + unsigned int rc_x_id_interlock : 1; /* 1 [29] */ + unsigned int rc_ack_n_capable : 1; /* 1 [30] */ + unsigned int rc_ack_o_capable : 1; /* 1 [31] */ +#else + unsigned int rc_categories_per_sequence : 2; /* 1 [24-25] */ + unsigned int reserved_cl4 : 1; /* 1 [26] */ + unsigned int rc_error_policy_supported : 2; /* 1 [27-28] */ + unsigned int rc_x_id_interlock : 1; /* 1 [29] */ + unsigned int rc_ack_n_capable : 1; /* 1 [30] */ + unsigned int rc_ack_o_capable : 1; /* 1 [31] */ + + unsigned int reserved_cl3 : 5; /* 1 [16-20] */ + /* 1 [21-22] */ + unsigned int rc_data_compression_history_buffer_size : 2; + unsigned int rc_data_compression_capable : 1; /* 1 [23] */ + + unsigned int received_data_field_size : 16; /* 1 [0-15] */ +#endif + +#if defined(UNF_CPU_ENDIAN) + unsigned int n_port_end_to_end_credit : 15; /* 2 [0-14] */ + unsigned int reserved_cl5 : 1; /* 2 [15] */ + + unsigned int concurrent_sequences : 16; /* 2 [16-31] */ +#else + unsigned int concurrent_sequences : 16; /* 2 [16-31] */ + + unsigned int n_port_end_to_end_credit : 15; /* 2 [0-14] */ + unsigned int reserved_cl5 : 1; /* 2 [15] */ +#endif + +#if defined(UNF_CPU_ENDIAN) + unsigned int reserved_cl6 : 16; /* 3 [0-15] */ + unsigned int open_sequences_per_exchange : 16; /* 3 [16-31] */ +#else + unsigned int open_sequences_per_exchange : 16; /* 3 [16-31] */ + unsigned int reserved_cl6 : 16; /* 3 [0-15] */ +#endif +}; + +struct unf_fabric_parms_s { + struct unf_fabric_coparms_s co_parms; + unsigned int high_port_name; + unsigned int low_port_name; + unsigned int high_node_name; + unsigned int low_node_name; + struct unf_lgn_port_clparms_s cl_parms[3]; + unsigned int reserved_1[4]; + unsigned int vendor_version_level[4]; +}; + +struct unf_lgn_parms_s { + struct unf_lgn_port_coparms_s co_parms; + unsigned int high_port_name; + unsigned int low_port_name; + unsigned int high_node_name; + unsigned int low_node_name; + struct unf_lgn_port_clparms_s cl_parms[3]; + unsigned int reserved_1[4]; + unsigned int vendor_version_level[4]; +}; + +#define ELS_RJT 0x1 +#define ELS_ACC 0x2 +#define ELS_PLOGI 0x3 +#define ELS_FLOGI 0x4 +#define ELS_LOGO 0x5 +#define ELS_RLS 0xf +#define ELS_ECHO 0x10 +#define ELS_RRQ 0x12 +#define ELS_REC 0x13 +#define ELS_PRLI 0x20 +#define ELS_PRLO 0x21 +#define ELS_TPRLO 0x24 +#define ELS_PDISC 0x50 +#define ELS_FDISC 0x51 +#define ELS_ADISC 0x52 +#define ELS_RSCN 0x61 /* registered state change notification */ +#define ELS_SCR 0x62 /* state change registration */ + +#define NS_GIEL 0X0101 +#define NS_GA_NXT 0X0100 +#define NS_GPN_ID 0x0112 /* get port name by ID */ +#define NS_GNN_ID 0x0113 /* get node name by ID */ +#define NS_GFF_ID 0x011f /* get FC-4 features by ID */ +#define NS_GID_PN 0x0121 /* get ID for port name */ +#define NS_GID_NN 0x0131 /* get IDs for node name */ +#define NS_GID_FT 0x0171 /* get IDs by FC4 type */ +#define NS_GPN_FT 0x0172 /* get port names by FC4 type */ +#define NS_GID_PT 0x01a1 /* get IDs by port type */ +#define NS_RFT_ID 0x0217 /* reg FC4 type for ID */ +#define NS_RPN_ID 0x0212 /* reg port name for ID */ +#define NS_RNN_ID 0x0213 /* reg node name for ID */ +#define NS_RSNPN 0x0218 /* reg symbolic port name */ +#define NS_RFF_ID 0x021f /* reg FC4 Features for ID */ +#define NS_RSNN 0x0239 /* reg symbolic node name */ +#define ST_NULL 0xffff /* reg symbolic node name */ + +#define BLS_ABTS 0xA001 /* ABTS */ + +#define FCP_SRR 0x14 /* Sequence Retransmission Request */ + +#define UNF_FC_FID_DOM_MGR 0xfffc00 /* domain manager base */ +enum unf_fc_well_known_fabric_id { + UNF_FC_FID_NONE = 0x000000, /* No destination */ + UNF_FC_FID_DOM_CTRL = 0xfffc01, /* domain controller */ + UNF_FC_FID_BCAST = 0xffffff, /* broadcast */ + UNF_FC_FID_FLOGI = 0xfffffe, /* fabric login */ + UNF_FC_FID_FCTRL = 0xfffffd, /* fabric controller */ + UNF_FC_FID_DIR_SERV = 0xfffffc, /* directory server */ + UNF_FC_FID_TIME_SERV = 0xfffffb, /* time server */ + UNF_FC_FID_MGMT_SERV = 0xfffffa, /* management server */ + UNF_FC_FID_QOS = 0xfffff9, /* QoS Facilitator */ + UNF_FC_FID_ALIASES = 0xfffff8, /* alias server (FC-PH2) */ + UNF_FC_FID_SEC_KEY = 0xfffff7, /* Security key dist. server */ + UNF_FC_FID_CLOCK = 0xfffff6, /* clock synch server */ + UNF_FC_FID_MCAST_SERV = 0xfffff5 /* multicast server */ +}; + +#define DRV_ENTRY_PER_SGL 64 /* Size of an entry array in a hash table */ +#define DRV_DATA_PROTECTION_LEN 8 + +struct dif_result_info_s { + unsigned char actual_dif[DRV_DATA_PROTECTION_LEN]; + unsigned char expected_dif[DRV_DATA_PROTECTION_LEN]; +}; + +struct drv_sge { + char *buf; + void *page_ctrl; + unsigned int length; + unsigned int offset; +}; + +/* + * @enum drv_io_direction + * SCSI data direction + */ +enum drv_io_direction { + DRV_IO_BIDIRECTIONAL = 0, + DRV_IO_DIRECTION_WRITE = 1, + DRV_IO_DIRECTION_READ = 2, + DRV_IO_DIRECTION_NONE = 3, +}; + +/* + * Hash table data structure + */ +struct drv_sgl { + struct drv_sgl *next_sgl; /* poin to SGL,SGL list */ + unsigned short num_sges_in_chain; + unsigned short num_sges_in_sgl; + unsigned int flag; + unsigned long long serial_num; + struct drv_sge sge[DRV_ENTRY_PER_SGL]; + struct list_head node; + unsigned int cpu_id; +}; + +struct dif_info_s { + /* Indicates the result returned when the data + * protection information is inconsistent,add by pangea + */ + struct dif_result_info_s dif_result; + /* Data protection information operation code + * bit[31-24] other operation code + * bit[23-16] Data Protection Information Operation + * bit[15-8] Data protection information verification + * bit[7-0] Data protection information replace + */ + unsigned int protect_opcode; + unsigned short app_tag; + unsigned long long start_lba; /* IO start LBA */ + struct drv_sgl *protection_sgl; +}; + +typedef struct Scsi_Host unf_scsi_host_s; + +struct unf_ini_error_code_s { + unsigned int drv_err_code; /* driver error code */ + unsigned int ap_err_code; /* up level error code */ +}; + +typedef unsigned int (*ini_get_sgl_entry_buf)(void *v_upper_cmnd, + void *v_driver_sgl, + void **v_upper_sgl, + unsigned int *v_req_index, + unsigned int *v_index, + char **v_buf, + unsigned int *v_buf_len); + +struct unf_host_param_s { + int can_queue; + unsigned short sg_table_size; + short cmnd_per_lun; + unsigned int max_id; + unsigned int max_lun; + unsigned int max_channel; + unsigned short max_cmnd_len; + unsigned short max_sectors; + unsigned long long dma_boundary; + unsigned int port_id; + void *lport; + struct device *pdev; +}; + +#define UNF_DIF_AREA_SIZE 8 + +struct unf_dif_control_info_s { + unsigned short app_tag; + unsigned short flags; + unsigned int protect_opcode; + unsigned int fcp_dl; + unsigned int start_lba; + unsigned char actual_dif[UNF_DIF_AREA_SIZE]; + unsigned char expected_dif[UNF_DIF_AREA_SIZE]; + unsigned int dif_sge_count; + void *dif_sgl; +}; + +struct unf_scsi_cmd_s { + unsigned int scsi_host_id; + unsigned int scsi_id; /* cmd->dev->id */ + unsigned long long lun_id; + unsigned long long port_id; + unsigned int underflow; /* Underflow */ + unsigned int transfer_len; /* Transfer Length */ + unsigned int resid; /* Resid */ + unsigned int sense_buf_len; + int result; + unsigned int entry_count; /* IO Buffer counter */ + unsigned int abort; + unsigned int err_code_table_cout; /* error code size */ + unsigned long long cmnd_sn; + unsigned long time_out; /* EPL driver add timer */ + unsigned short cmnd_len; /* Cdb length */ + unsigned char data_direction; /* data direction */ + unsigned char *pcmnd; /* SCSI CDB */ + unsigned char *sense_buf; + void *drv_private; /* driver host pionter */ + void *driver_scribble; /* Xchg pionter */ + void *upper_cmnd; /* UpperCmnd pointer by driver */ + unsigned char *pc_lun_id; /* new lunid */ + unsigned int world_id; + struct unf_dif_control_info_s dif_control; /* DIF control */ + struct unf_ini_error_code_s *err_code_table; /* error code table */ + void *sgl; /* Sgl pointer */ + ini_get_sgl_entry_buf pfn_unf_ini_get_sgl_entry; + void (*pfn_done)(struct unf_scsi_cmd_s *); + struct dif_info_s dif_info; +}; + +/* + * R_CTL Basic Link Data defines + */ +#define FC_RCTL_BLS 0x80000000 +#define FC_RCTL_BLS_ACC (FC_RCTL_BLS | 0x04000000) +#define FC_RCTL_BLS_RJT (FC_RCTL_BLS | 0x05000000) + +/* + * BA_RJT reason code defines + */ +#define FCXLS_BA_OK 0x00000000 +#define FCXLS_BA_RJT_INVALID_COMMAND 0x00010000 +#define FCXLS_BA_RJT_LOGICAL_ERROR 0x00030000 + +/* + * BA_RJT code explanation + */ + +#define FCXLS_BA_RJT_INV_OXID_RXID 0x00000300 +#define FCXLS_LS_RJT_INVALID_OXID_RXID 0x00001700 + +/* + * Types (word) + */ +#define FC_TYPE_WORD_BLS 0x00000000 + +/* + * SFS structures + */ +struct unf_ba_rjt_s { + unsigned int reason_code; /* BLS reason code and Reason Explanation */ +}; + +#define FC_ABTS_ACC_SEQ_CNT 0x0000ffff +struct unf_ba_acc_s { + unsigned int seq_id; + unsigned int oxid_rxid; + unsigned int seq_cnt; +}; + +union unf_ba_pld_u { + struct unf_ba_rjt_s ba_rjt; + struct unf_ba_acc_s ba_acc; +}; + +struct unf_abts_rsps_s { + struct unf_fchead_s frame_hdr; + union unf_ba_pld_u ba_pld; +}; + +/* + * BLS RJT structure header and payload + */ +struct unf_bls_rjt_s { + struct unf_fchead_s frame_hdr; + /* BLS reason code and Reason Explanation */ + unsigned int reason_code; +}; + +/* + * ELS ACC + */ +struct unf_els_acc_s { + struct unf_fchead_s frame_hdr; + unsigned int cmnd; +}; + +/* + * ELS RJT + */ +struct unf_els_rjt_s { + struct unf_fchead_s frame_hdr; + unsigned int cmnd; + unsigned int reason_code; +}; + +/* + * FLOGI payload, + * FC-LS-2 Table 139 FLOGI, PLOGI, FDISC or LS_ACC Payload + */ +struct unf_flogi_payload_s { + unsigned int cmnd; + struct unf_fabric_parms_s fabric_parms; +}; + +/* + * Flogi and Flogi accept frames. They are the same structure + */ +struct unf_flogi_fdisc_acc_s { + struct unf_fchead_s frame_hdr; + struct unf_flogi_payload_s flogi_payload; +}; + +/* + * Fdisc and Fdisc accept frames. They are the same structure + */ +struct unf_fdisc_acc_s { + struct unf_fchead_s frame_hdr; + struct unf_flogi_payload_s fdisc_payload; +}; + +/* + * PLOGI payload + */ +struct unf_plogi_payload_s { + unsigned int cmnd; + struct unf_lgn_parms_s parms; +}; + +/* + * Plogi, Plogi accept, Pdisc and Pdisc accept frames. + * They are all the same structure. + */ +struct unf_plogi_pdisc_s { + struct unf_fchead_s frame_hdr; + struct unf_plogi_payload_s payload; +}; + +/* + * LOGO logout link service requests invalidation of service parameters and + * port name. + * see FC-PH 4.3 Section 21.4.8 + */ + +/* FC-LS-2 Table 12 LOGO Payload */ +struct unf_logo_payload_s { + unsigned int cmnd; + unsigned int nport_id; + unsigned int high_port_name; + unsigned int low_port_name; +}; + +/* + * payload to hold LOGO command + */ +struct unf_logo_s { + struct unf_fchead_s frame_hdr; + struct unf_logo_payload_s payload; +}; + +/* + * payload for ECHO command, refer to FC-LS-2 4.2.4 + */ +struct unf_echo_payload_s { + unsigned int cmnd; +#define UNF_FC_ECHO_PAYLOAD_LENGTH 255 /* Length in words */ + unsigned int data[UNF_FC_ECHO_PAYLOAD_LENGTH]; +}; + +struct unf_echo_s { + struct unf_fchead_s frame_hdr; + struct unf_echo_payload_s *echo_pld; + dma_addr_t phy_echo_addr; +}; + +#define UNF_PRLI_SIRT_EXTRA_SIZE 12 +/* + * payload for PRLI and PRLO + */ +struct unf_pril_payload_s { + unsigned int cmnd; +#define UNF_FC_PRLI_PAYLOAD_LENGTH 7 /* Length in words */ + unsigned int parms[UNF_FC_PRLI_PAYLOAD_LENGTH]; +}; + +/* + * FCHS structure with payload + */ +struct unf_prli_prlo_s { + struct unf_fchead_s frame_hdr; + struct unf_pril_payload_s payload; +}; + +/* + * ADISC payload + */ + +/* FC-LS-2 Table 75 ADISC Request payload */ +struct unf_adisc_payload_s { + unsigned int cmnd; + unsigned int hard_address; + unsigned int high_port_name; + unsigned int low_port_name; + unsigned int high_node_name; + unsigned int low_node_name; + unsigned int nport_id; +}; + +/* + * FCHS structure with payload + */ +struct unf_adisc_s { + /* FCHS structure */ + struct unf_fchead_s frame_hdr; + /* Payload data containing ADISC info */ + struct unf_adisc_payload_s adisc_payl; +}; + +/* + * RLS payload + */ +struct unf_rls_payload_s { + unsigned int cmnd; + unsigned int nport_id; /* in litle endian format */ +}; + +/* + * RLS + */ +struct unf_rls_s { + struct unf_fchead_s frame_hdr; /* FCHS structure */ + /* payload data containing the RLS info */ + struct unf_rls_payload_s rls; +}; + +/* + * RLS accept payload + */ +struct unf_rls_acc_payload_s { + unsigned int cmnd; + unsigned int link_failure_count; + unsigned int loss_of_sync_count; + unsigned int loss_of_signal_count; + unsigned int primitive_seq_count; + unsigned int invalid_trans_word_count; + unsigned int invalid_crc_count; +}; + +/* + * RLS accept + */ +struct unf_rls_acc_s { + struct unf_fchead_s frame_hdr; /* FCHS structure */ + /* payload data containing the RLS ACC info */ + struct unf_rls_acc_payload_s rls; +}; + +/* + * FCHS structure with payload + */ +struct unf_rrq_s { + struct unf_fchead_s frame_hdr; + unsigned int cmnd; + unsigned int sid; + unsigned int oxid_rxid; +}; + +/* + * ABTA accept + */ +struct unf_abts_acc_s { + struct unf_fchead_s frame_hdr; + unsigned int seq_id; + unsigned int oxid_rxid; + unsigned int seq_cnt; +}; + +struct unf_scr_s { + struct unf_fchead_s frame_hdr; + unsigned int payload[2]; +}; + +struct unf_ctiu_prem_s { + unsigned int rev_inid; + unsigned int gstype_gssub_options; + unsigned int cmnd_rsp_size; + unsigned int frag_reason_exp_vend; +}; + +struct unf_rftid_s { + struct unf_fchead_s frame_hdr; + struct unf_ctiu_prem_s ctiu_pream; + unsigned int nport_id; + unsigned int fc_4_types[8]; +}; + +struct unf_rffid_s { + struct unf_fchead_s frame_hdr; + struct unf_ctiu_prem_s ctiu_pream; + unsigned int nport_id; + unsigned int fc_4_feature; +}; + +struct unf_rffid_rsp_s { + struct unf_fchead_s frame_hdr; + struct unf_ctiu_prem_s ctiu_pream; +}; + +struct unf_gffid_s { + struct unf_fchead_s frame_hdr; + struct unf_ctiu_prem_s ctiu_pream; + unsigned int nport_id; +}; + +struct unf_gffid_rsp_s { + struct unf_fchead_s frame_hdr; + struct unf_ctiu_prem_s ctiu_pream; + unsigned int fc_4_feature[32]; +}; + +struct unf_gnnid_s { + struct unf_fchead_s frame_hdr; + struct unf_ctiu_prem_s ctiu_pream; + unsigned int nport_id; +}; + +struct unf_gnnid_rsp_s { + struct unf_fchead_s frame_hdr; + struct unf_ctiu_prem_s ctiu_pream; + unsigned int node_name[2]; +}; + +struct unf_gpnid_s { + struct unf_fchead_s frame_hdr; + struct unf_ctiu_prem_s ctiu_pream; + unsigned int nport_id; +}; + +struct unf_gpnid_rsp_s { + struct unf_fchead_s frame_hdr; + struct unf_ctiu_prem_s ctiu_pream; + unsigned int port_name[2]; +}; + +struct unf_rft_rsp_s { + struct unf_fchead_s frame_hdr; + struct unf_ctiu_prem_s ctiu_pream; +}; + +struct unf_srr_payload_s { + unsigned int srr_op; + unsigned short rx_id; + unsigned short ox_id; + unsigned int rel_offset; + unsigned char reserved[3]; + unsigned char rctl_for_iu; +}; + +struct unf_srr_s { + struct unf_fchead_s frame_hdr; + struct unf_srr_payload_s pld; +}; + +struct unf_srr_acc_pld_s { + unsigned int srr_op; /* 02000000h */ +}; + +struct unf_srr_acc_s { + struct unf_fchead_s frame_hdr; + struct unf_srr_acc_pld_s pld; +}; + +struct unf_ls_rjt_pld_s { + unsigned int srr_op; /* 01000000h */ + unsigned char vandor; + unsigned char reason_exp; + unsigned char reason; + unsigned char reserved; +}; + +struct unf_ls_rjt_s { + struct unf_fchead_s frame_hdr; + struct unf_ls_rjt_pld_s pld; +}; + +struct unf_rec_pld_s { + unsigned int rec_cmnd; + unsigned int xchg_org_sid; /* bit0-bit23 */ + unsigned short rx_id; + unsigned short ox_id; +}; + +struct unf_rec_s { + struct unf_fchead_s frame_hdr; + struct unf_rec_pld_s rec_pld; +}; + +struct unf_rec_acc_pld_s { + unsigned int cmnd; + unsigned short rx_id; + unsigned short ox_id; + unsigned int org_addr_id; /* bit0-bit23 */ + unsigned int rsp_addr_id; /* bit0-bit23 */ +}; + +struct unf_rec_acc_s { + struct unf_fchead_s frame_hdr; + struct unf_rec_acc_pld_s payload; +}; + +struct unf_gid_s { + struct unf_ctiu_prem_s ctiu_pream; + unsigned int scope_type; +}; + +struct unf_gid_acc_s { + struct unf_fchead_s frame_hdr; + struct unf_ctiu_prem_s ctiu_pream; +}; + +#define UNF_LOOPMAP_COUNT 128 +struct unf_loop_init_s { + struct unf_fchead_s frame_hdr; + unsigned int cmnd; +#define UNF_FC_ALPA_BIT_MAP_SIZE 4 + unsigned int alpa_bit_map[UNF_FC_ALPA_BIT_MAP_SIZE]; +}; + +struct unf_loop_map_s { + struct unf_fchead_s frame_hdr; + unsigned int cmnd; + unsigned int loop_map[32]; +}; + +struct unf_ctiu_rjt_s { + struct unf_fchead_s frame_hdr; + struct unf_ctiu_prem_s ctiu_pream; +}; + +struct unf_gif_acc_pld_s { + struct unf_ctiu_prem_s ctiu_pream; + + unsigned int gid_port_id[UNF_GID_PORT_CNT]; +}; + +struct unf_gid_rsp_s { + struct unf_gif_acc_pld_s *gid_acc_pld; +}; + +struct unf_gid_req_rsp_s { + struct unf_fchead_s frame_hdr; + struct unf_gid_s gid_req; + struct unf_gid_rsp_s gid_rsp; +}; + +/* Added by fangtao FC-LS-2 Table 31 RSCN Payload */ +struct unf_rscn_port_id_page_s { + unsigned char port_id_port; + unsigned char port_id_area; + unsigned char port_id_domain; + + unsigned char addr_format : 2; + unsigned char event_qualifier : 4; + unsigned char reserved : 2; +}; + +struct unf_rscn_pld_s { + unsigned int cmnd; + struct unf_rscn_port_id_page_s port_id_page[UNF_RSCN_PAGE_SUM]; +}; + +struct unf_rscn_s { + struct unf_fchead_s frame_hdr; + struct unf_rscn_pld_s *rscn_pld; +}; + +union unf_sfs_u { + struct { + struct unf_fchead_s frame_head; + unsigned char data[0]; + } sfs_common; + struct unf_abts_rsps_s abts_rsps; + struct unf_els_acc_s els_acc; + struct unf_els_rjt_s els_rjt; + struct unf_plogi_pdisc_s plogi; + struct unf_logo_s logo; + struct unf_echo_s echo; + struct unf_echo_s echo_acc; + struct unf_prli_prlo_s prli; + struct unf_prli_prlo_s prlo; + struct unf_rls_s rls; + struct unf_rls_acc_s rls_acc; + struct unf_plogi_pdisc_s pdisc; + struct unf_adisc_s adisc; + struct unf_rrq_s rrq; + struct unf_flogi_fdisc_acc_s flogi; + struct unf_fdisc_acc_s fdisc; + struct unf_scr_s scr; + struct unf_rec_s rec; + struct unf_rec_acc_s rec_acc; + struct unf_srr_s srr; + struct unf_srr_acc_s srr_acc; + struct unf_ls_rjt_s ls_rjt; + struct unf_rscn_s rscn; + struct unf_gid_req_rsp_s get_id; + struct unf_rftid_s rft_id; + struct unf_rft_rsp_s rft_id_rsp; + struct unf_rffid_s rff_id; + struct unf_rffid_rsp_s rff_id_rsp; + struct unf_gffid_s gff_id; + struct unf_gffid_rsp_s gff_id_rsp; + struct unf_gnnid_s gnn_id; + struct unf_gnnid_rsp_s gnn_id_rsp; + struct unf_gpnid_s gpn_id; + struct unf_gpnid_rsp_s gpn_id_rsp; + struct unf_plogi_pdisc_s plogi_acc; + struct unf_plogi_pdisc_s pdisc_acc; + struct unf_adisc_s adisc_acc; + struct unf_prli_prlo_s prli_acc; + struct unf_prli_prlo_s prlo_acc; + struct unf_flogi_fdisc_acc_s flogi_acc; + struct unf_fdisc_acc_s fdisc_acc; + struct unf_loop_init_s lpi; + struct unf_loop_map_s loopmap; + struct unf_ctiu_rjt_s ctiu_rjt; +}; + +struct unf_sfs_entry_s { + /* Virtual addr of SFS buffer */ + union unf_sfs_u *fc_sfs_entry_ptr; + /* Physical addr of SFS buffer */ + unsigned long long sfs_buff_phy_addr; + /* Length of bytes in SFS buffer */ + unsigned int sfs_buff_len; + unsigned int cur_offset; +}; + +struct unf_fcp_rsp_iu_entry_s { + struct unf_fcprsp_iu_s *fcp_rsp_iu; + dma_addr_t fcp_rsp_iu_phy_addr; +}; + +struct unf_rjt_info_s { + unsigned int els_cmnd_code; + unsigned int reason_code; + unsigned int reason_explanation; +}; + +int unf_alloc_scsi_host(unf_scsi_host_s **v_scsi_host, + struct unf_host_param_s *v_host_param); +void unf_free_scsi_host(unf_scsi_host_s *v_scsi_host); +unsigned int unf_register_ini_transport(void); +void unf_unregister_ini_transport(void); +void unf_report_io_dm_event(void *v_lport, unsigned int type, + unsigned int value); +void unf_save_sense_data(void *scsicmd, const char *sense, int senslen); + +#endif