Add target hooks. Signed-off-by: Sebastian Herbszt <herbszt@xxxxxx> --- diff -upNr 4.1-rc7.orig/drivers/scsi/Kconfig 4.1-rc7/drivers/scsi/Kconfig --- 4.1-rc7.orig/drivers/scsi/Kconfig 2015-05-31 10:05:16.189204634 +0200 +++ 4.1-rc7/drivers/scsi/Kconfig 2015-06-14 16:33:02.479543894 +0200 @@ -1299,6 +1299,12 @@ config SCSI_LPFC_DEBUG_FS This makes debugging information from the lpfc driver available via the debugfs filesystem. +config SCSI_LPFC_TARGET + bool "Emulex LightPulse Fibre Channel Target Support" + depends on SCSI_LPFC + help + Support target mode. + config SCSI_SIM710 tristate "Simple 53c710 SCSI support (Compaq, NCR machines)" depends on (EISA || MCA) && SCSI diff -upNr 4.1-rc7.orig/drivers/scsi/lpfc/Makefile 4.1-rc7/drivers/scsi/lpfc/Makefile --- 4.1-rc7.orig/drivers/scsi/lpfc/Makefile 2015-05-25 03:22:35.000000000 +0200 +++ 4.1-rc7/drivers/scsi/lpfc/Makefile 2015-06-14 16:33:02.479543894 +0200 @@ -31,3 +31,8 @@ obj-$(CONFIG_SCSI_LPFC) := lpfc.o lpfc-objs := lpfc_mem.o lpfc_sli.o lpfc_ct.o lpfc_els.o lpfc_hbadisc.o \ lpfc_init.o lpfc_mbox.o lpfc_nportdisc.o lpfc_scsi.o lpfc_attr.o \ lpfc_vport.o lpfc_debugfs.o lpfc_bsg.o + +ifdef CONFIG_SCSI_LPFC_TARGET + ccflags-y += -DLPFC_TARGET_MODE + lpfc-objs += lpfc_target_api.o +endif diff -upNr 4.1-rc7.orig/drivers/scsi/lpfc/lpfc.h 4.1-rc7/drivers/scsi/lpfc/lpfc.h --- 4.1-rc7.orig/drivers/scsi/lpfc/lpfc.h 2015-05-25 03:22:35.000000000 +0200 +++ 4.1-rc7/drivers/scsi/lpfc/lpfc.h 2015-06-14 16:33:02.479543894 +0200 @@ -441,6 +441,9 @@ struct lpfc_vport { unsigned long rcv_buffer_time_stamp; uint32_t vport_flag; #define STATIC_VPORT 1 +#if defined LPFC_TARGET_MODE && defined _H_LPFC_TGT_API_BASE + tm_tgtport_t target_tgtport; +#endif }; struct hbq_s { @@ -991,6 +994,15 @@ struct lpfc_hba { spinlock_t devicelock; /* lock for luns list */ mempool_t *device_data_mem_pool; struct list_head luns; +#if defined LPFC_TARGET_MODE && defined _H_LPFC_TGT_API_BASE + uint32_t cfg_initialize_link; + uint32_t cfg_fcp_mode; +#define LPFC_FCP_MODE_INITIATOR 1 +#define LPFC_FCP_MODE_TARGET 2 + uint32_t poll_rsp_cnt; + uint32_t num_targets_bound; + tm_sliport_t target_sliport; +#endif }; static inline struct Scsi_Host * diff -upNr 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_attr.c 4.1-rc7/drivers/scsi/lpfc/lpfc_attr.c --- 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_attr.c 2015-05-25 03:22:35.000000000 +0200 +++ 4.1-rc7/drivers/scsi/lpfc/lpfc_attr.c 2015-06-14 16:33:02.483543894 +0200 @@ -39,6 +39,10 @@ #include "lpfc_hw.h" #include "lpfc_sli.h" #include "lpfc_sli4.h" +#ifdef LPFC_TARGET_MODE +#include "lpfc_target_api.h" +#include "lpfc_target_api_base.h" +#endif #include "lpfc_nl.h" #include "lpfc_disc.h" #include "lpfc_scsi.h" @@ -1144,7 +1148,7 @@ board_mode_out: * zero on error * one for success **/ -static int +int lpfc_get_hba_info(struct lpfc_hba *phba, uint32_t *mxri, uint32_t *axri, uint32_t *mrpi, uint32_t *arpi, @@ -4571,6 +4575,30 @@ LPFC_ATTR_R(multi_ring_rctl, FC_RCTL_DD_ LPFC_ATTR_R(multi_ring_type, FC_TYPE_IP, 1, 255, "Identifies TYPE for additional ring configuration"); +#ifdef LPFC_TARGET_MODE +/* +# lpfc_initialize_link: Bring link up at initialization +# 0x0 = do NOT bring link up (MBX_INIT_LINK) +# 0x1 = bring link up (issue MBX_INIT_LINK) +# Default value is 1. +*/ +LPFC_ATTR_R(initialize_link, 1, 0, 1, "Bring Link Up at initialization"); + +/* +# lpfc_fcp_mode: determines target/initiator behavior. This is expressed +# as an array. Every successive pair indicates {n, c}, where "n" is +# hba number and "c" is characteristics. Value range of "c" is [1, 2]. +# where LPFC_FCP_MODE_INITIATOR is 1 and LPFC_FCP_MODE_TARGET is 2. +# Its possible to be both a target and an initiator. +# The default value can be modified with the pair {-1, c}. +*/ +static int lpfc_fcp_mode[64] = {-1, LPFC_FCP_MODE_TARGET}; +static int num_lpfc_fcp_mode; +module_param_array(lpfc_fcp_mode, int, &num_lpfc_fcp_mode, 0); +MODULE_PARM_DESC(lpfc_fcp_mode, + "List of values determining target/initiator behavior"); +#endif + /* # lpfc_fdmi_on: controls FDMI support. # Set NOT Set @@ -4806,6 +4834,9 @@ struct device_attribute *lpfc_hba_attrs[ &dev_attr_lpfc_ack0, &dev_attr_lpfc_topology, &dev_attr_lpfc_scan_down, +#ifdef LPFC_TARGET_MODE + &dev_attr_lpfc_initialize_link, +#endif &dev_attr_lpfc_link_speed, &dev_attr_lpfc_fcp_io_sched, &dev_attr_lpfc_fcp2_no_tgt_reset, @@ -5808,6 +5839,27 @@ struct fc_function_template lpfc_vport_t void lpfc_get_cfgparam(struct lpfc_hba *phba) { +#ifdef LPFC_TARGET_MODE + int i = 0, mode = LPFC_FCP_MODE_TARGET; + + if (num_lpfc_fcp_mode & 1) { + printk("lpfc_fcp_mode expects pairs. Defaulting to " + "LPFC_FCP_MODE_TARGET.\n"); + } else { + for (i = 0; i < num_lpfc_fcp_mode; i += 2) { + if (lpfc_fcp_mode[i] == -1) { + mode = lpfc_fcp_mode[i + 1]; + break; + } + if (lpfc_fcp_mode[i] == phba->brd_no) { + mode = lpfc_fcp_mode[i + 1]; + break; + } + } + } + phba->cfg_fcp_mode = mode; + lpfc_initialize_link_init(phba, lpfc_initialize_link); +#endif lpfc_fcp_io_sched_init(phba, lpfc_fcp_io_sched); lpfc_fcp2_no_tgt_reset_init(phba, lpfc_fcp2_no_tgt_reset); lpfc_cr_delay_init(phba, lpfc_cr_delay); @@ -5855,6 +5907,16 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) lpfc_suppress_link_up_init(phba, lpfc_suppress_link_up); lpfc_iocb_cnt_init(phba, lpfc_iocb_cnt); phba->cfg_enable_dss = 1; +#ifdef LPFC_TARGET_MODE + /* Its possible to be BOTH Target and Initiator */ + if (!(phba->cfg_fcp_mode & LPFC_FCP_MODE_INITIATOR)) + phba->cfg_initialize_link = 0; + if (phba->cfg_fcp_mode & LPFC_FCP_MODE_TARGET) { + phba->cfg_multi_ring_support = 2; + phba->cfg_multi_ring_rctl = FC_RCTL_DD_UNSOL_CMD; + phba->cfg_multi_ring_type = FC_TYPE_FCP; + } +#endif return; } @@ -5881,5 +5943,9 @@ lpfc_get_vport_cfgparam(struct lpfc_vpor lpfc_max_luns_init(vport, lpfc_max_luns); lpfc_scan_down_init(vport, lpfc_scan_down); lpfc_enable_da_id_init(vport, lpfc_enable_da_id); +#ifdef LPFC_TARGET_MODE + if (!(vport->phba->cfg_fcp_mode & LPFC_FCP_MODE_INITIATOR)) + vport->cfg_use_adisc = 1; +#endif return; } diff -upNr 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_ct.c 4.1-rc7/drivers/scsi/lpfc/lpfc_ct.c --- 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_ct.c 2015-05-25 03:22:35.000000000 +0200 +++ 4.1-rc7/drivers/scsi/lpfc/lpfc_ct.c 2015-06-14 16:33:02.483543894 +0200 @@ -38,6 +38,10 @@ #include "lpfc_hw.h" #include "lpfc_sli.h" #include "lpfc_sli4.h" +#ifdef LPFC_TARGET_MODE +#include "lpfc_target_api.h" +#include "lpfc_target_api_base.h" +#endif #include "lpfc_nl.h" #include "lpfc_disc.h" #include "lpfc_scsi.h" @@ -1284,7 +1288,13 @@ lpfc_ns_cmd(struct lpfc_vport *vport, in CtReq->CommandResponse.bits.CmdRsp = cpu_to_be16(SLI_CTNS_RFF_ID); CtReq->un.rff.PortId = cpu_to_be32(vport->fc_myDID); +#ifdef LPFC_TARGET_MODE + CtReq->un.rff.fbits = 0; + if (phba->cfg_fcp_mode & LPFC_FCP_MODE_INITIATOR) + CtReq->un.rff.fbits = FC4_FEATURE_INIT; +#else CtReq->un.rff.fbits = FC4_FEATURE_INIT; +#endif CtReq->un.rff.type_code = FC_TYPE_FCP; cmpl = lpfc_cmpl_ct_cmd_rff_id; break; diff -upNr 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_debugfs.c 4.1-rc7/drivers/scsi/lpfc/lpfc_debugfs.c --- 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_debugfs.c 2015-05-25 03:22:35.000000000 +0200 +++ 4.1-rc7/drivers/scsi/lpfc/lpfc_debugfs.c 2015-06-14 16:33:02.487543894 +0200 @@ -40,6 +40,10 @@ #include "lpfc_sli.h" #include "lpfc_sli4.h" #include "lpfc_nl.h" +#ifdef LPFC_TARGET_MODE +#include "lpfc_target_api.h" +#include "lpfc_target_api_base.h" +#endif #include "lpfc_disc.h" #include "lpfc_scsi.h" #include "lpfc.h" diff -upNr 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_disc.h 4.1-rc7/drivers/scsi/lpfc/lpfc_disc.h --- 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_disc.h 2015-05-25 03:22:35.000000000 +0200 +++ 4.1-rc7/drivers/scsi/lpfc/lpfc_disc.h 2015-06-14 16:33:02.487543894 +0200 @@ -119,6 +119,15 @@ struct lpfc_nodelist { unsigned long last_change_time; unsigned long *active_rrqs_xri_bitmap; struct lpfc_scsicmd_bkt *lat_data; /* Latency data */ +#if defined LPFC_TARGET_MODE && defined _H_LPFC_TGT_API + tm_login_info_t tm_login_info; + tm_login_handle_t login_handle; + uint32_t tm_check_login_result; + uint8_t tm_check_login_called; + uint8_t login_handle_valid; + uint16_t tm_login_flags; +#define NLP_TM_DELAYED_LOGIN 0x1 +#endif }; struct lpfc_node_rrq { struct list_head list; @@ -147,6 +156,9 @@ struct lpfc_node_rrq { #define NLP_LOGO_ACC 0x00100000 /* Process LOGO after ACC completes */ #define NLP_TGT_NO_SCSIID 0x00200000 /* good PRLI but no binding for scsid */ #define NLP_ISSUE_LOGO 0x00400000 /* waiting to issue a LOGO */ +#ifdef LPFC_TARGET_MODE +#define NLP_NEED_PRLI 0x00800000 /* Need PRLI to determine capability */ +#endif #define NLP_ACC_REGLOGIN 0x01000000 /* Issue Reg Login after successful ACC */ #define NLP_NPR_ADISC 0x02000000 /* Issue ADISC when dq'ed from diff -upNr 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_els.c 4.1-rc7/drivers/scsi/lpfc/lpfc_els.c --- 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_els.c 2015-05-25 03:22:35.000000000 +0200 +++ 4.1-rc7/drivers/scsi/lpfc/lpfc_els.c 2015-06-14 16:33:02.491543894 +0200 @@ -34,6 +34,10 @@ #include "lpfc_hw.h" #include "lpfc_sli.h" #include "lpfc_sli4.h" +#ifdef LPFC_TARGET_MODE +#include "lpfc_target_api.h" +#include "lpfc_target_api_base.h" +#endif #include "lpfc_nl.h" #include "lpfc_disc.h" #include "lpfc_scsi.h" @@ -42,6 +46,9 @@ #include "lpfc_crtn.h" #include "lpfc_vport.h" #include "lpfc_debugfs.h" +#ifdef LPFC_TARGET_MODE +#include "lpfc_target_protos.h" +#endif static int lpfc_els_retry(struct lpfc_hba *, struct lpfc_iocbq *, struct lpfc_iocbq *); @@ -1963,6 +1970,18 @@ lpfc_issue_els_plogi(struct lpfc_vport * uint16_t cmdsize; int ret; +#ifdef LPFC_TARGET_MODE + if (!(phba->cfg_fcp_mode & LPFC_FCP_MODE_INITIATOR) && + ((did & Fabric_DID_MASK) != Fabric_DID_MASK) && + !(vport->fc_flag & FC_PT2PT_PLOGI)) { + ndlp = lpfc_findnode_did(vport, did); + if (ndlp) { + ndlp->nlp_prev_state = ndlp->nlp_state; + lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); + } + return 1; + } +#endif psli = &phba->sli; ndlp = lpfc_findnode_did(vport, did); @@ -2137,6 +2156,29 @@ lpfc_issue_els_prli(struct lpfc_vport *v /* For PRLI, remainder of payload is PRLI parameter page */ npr = (PRLI *) pcmd; +#ifdef LPFC_TARGET_MODE + /* check if we want to act as target */ + if (lpfc_target_check_login(vport, ndlp) == TM_RCD_SUCCESS) { + /* success */ + npr->targetFunc = 1; + } + npr->initiatorFunc = 0; + if (phba->cfg_fcp_mode & LPFC_FCP_MODE_INITIATOR) { + npr->initiatorFunc = 1; + /* If we don't want to act as target, then tape OK */ + if (!npr->targetFunc) { + /* + * If our firmware version is 3.20 or later, + * set the following bits for FC-TAPE support. + */ + if (phba->vpd.rev.feaLevelHigh >= 0x02) { + npr->ConfmComplAllowed = 1; + npr->Retry = 1; + npr->TaskRetryIdReq = 1; + } + } + } +#else /* * If our firmware version is 3.20 or later, * set the following bits for FC-TAPE support. @@ -2146,6 +2188,8 @@ lpfc_issue_els_prli(struct lpfc_vport *v npr->Retry = 1; npr->TaskRetryIdReq = 1; } + npr->initiatorFunc = 1; +#endif npr->estabImagePair = 1; npr->readXferRdyDis = 1; if (vport->cfg_first_burst_size) @@ -2153,7 +2197,6 @@ lpfc_issue_els_prli(struct lpfc_vport *v /* For FCP support */ npr->prliType = PRLI_FCP_TYPE; - npr->initiatorFunc = 1; lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, "Issue PRLI: did:x%x", @@ -4222,6 +4265,9 @@ lpfc_els_rsp_prli_acc(struct lpfc_vport uint8_t *pcmd; uint16_t cmdsize; int rc; +#ifdef LPFC_TARGET_MODE + uint8_t rem_initiatorFunc; +#endif psli = &phba->sli; @@ -4236,6 +4282,13 @@ lpfc_els_rsp_prli_acc(struct lpfc_vport icmd->ulpContext = oldcmd->ulpContext; /* Xri / rx_id */ icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id; +#ifdef LPFC_TARGET_MODE + /* Check if the remote port support initiatorFunc */ + pcmd = (uint8_t *) (((struct lpfc_dmabuf *) oldiocb->context2)->virt); + pcmd += sizeof(uint32_t); + npr = (PRLI *) pcmd; + rem_initiatorFunc = npr->initiatorFunc; +#endif /* Xmit PRLI ACC response tag <ulpIoTag> */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0131 Xmit PRLI ACC response tag x%x xri x%x, " @@ -4253,6 +4306,29 @@ lpfc_els_rsp_prli_acc(struct lpfc_vport npr = (PRLI *) pcmd; vpd = &phba->vpd; +#ifdef LPFC_TARGET_MODE + /* check if we want to act as target */ + if (lpfc_target_check_login(vport, ndlp) == TM_RCD_SUCCESS) { + /* success */ + npr->targetFunc = 1; + } + npr->initiatorFunc = 0; + if (phba->cfg_fcp_mode & LPFC_FCP_MODE_INITIATOR) { + npr->initiatorFunc = 1; + /* If we don't want to act as target, then tape OK */ + if (!npr->targetFunc) { + /* + * If our firmware version is 3.20 or later, + * set the following bits for FC-TAPE support. + */ + if (vpd->rev.feaLevelHigh >= 0x02) { + npr->ConfmComplAllowed = 1; + npr->Retry = 1; + npr->TaskRetryIdReq = 1; + } + } + } +#else /* * If the remote port is a target and our firmware version is 3.20 or * later, set the following bits for FC-TAPE support. @@ -4263,6 +4339,8 @@ lpfc_els_rsp_prli_acc(struct lpfc_vport npr->Retry = 1; npr->TaskRetryIdReq = 1; } + npr->initiatorFunc = 1; +#endif npr->acceptRspCode = PRLI_REQ_EXECUTED; npr->estabImagePair = 1; @@ -4270,7 +4348,6 @@ lpfc_els_rsp_prli_acc(struct lpfc_vport npr->ConfmComplAllowed = 1; npr->prliType = PRLI_FCP_TYPE; - npr->initiatorFunc = 1; lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP, "Issue ACC PRLI: did:x%x flg:x%x", @@ -4284,6 +4361,23 @@ lpfc_els_rsp_prli_acc(struct lpfc_vport lpfc_els_free_iocb(phba, elsiocb); return 1; } +#ifdef LPFC_TARGET_MODE + /* at this point initialize the target */ + if (npr->acceptRspCode == PRLI_REQ_EXECUTED + && npr->prliType == PRLI_FCP_TYPE + && ndlp->tm_check_login_called + && ndlp->tm_check_login_result == TM_RCD_SUCCESS + && !ndlp->login_handle_valid + && rem_initiatorFunc) { + + if (ndlp->nlp_rpi) { + ndlp->login_handle = tm_tgtport_login(vport, ndlp); + if (ndlp->login_handle) + ndlp->login_handle_valid = 1; + } else + ndlp->tm_login_flags |= NLP_TM_DELAYED_LOGIN; + } +#endif return 0; } @@ -8107,7 +8201,7 @@ static void lpfc_fabric_abort_vport(stru void lpfc_fabric_abort_nport(struct lpfc_nodelist *ndlp) { LIST_HEAD(completions); - struct lpfc_hba *phba = ndlp->phba; + struct lpfc_hba *phba = ndlp->vport->phba; struct lpfc_iocbq *tmp_iocb, *piocb; struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING]; diff -upNr 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_hbadisc.c 4.1-rc7/drivers/scsi/lpfc/lpfc_hbadisc.c --- 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_hbadisc.c 2015-05-25 03:22:35.000000000 +0200 +++ 4.1-rc7/drivers/scsi/lpfc/lpfc_hbadisc.c 2015-06-14 16:33:02.495543894 +0200 @@ -33,6 +33,10 @@ #include "lpfc_hw4.h" #include "lpfc_hw.h" +#ifdef LPFC_TARGET_MODE +#include "lpfc_target_api.h" +#include "lpfc_target_api_base.h" +#endif #include "lpfc_nl.h" #include "lpfc_disc.h" #include "lpfc_sli.h" @@ -43,6 +47,9 @@ #include "lpfc_crtn.h" #include "lpfc_vport.h" #include "lpfc_debugfs.h" +#ifdef LPFC_TARGET_MODE +#include "lpfc_target_protos.h" +#endif /* AlpaArray for assignment of scsid for scan-down and bind_method */ static uint8_t lpfcAlpaArray[] = { @@ -3473,6 +3480,17 @@ lpfc_mbx_cmpl_reg_login(struct lpfc_hba */ lpfc_nlp_put(ndlp); +#ifdef LPFC_TARGET_MODE + /* check if we need to notify the target api + * set when prli has completed before reg_login mailbox cmd */ + if (ndlp->tm_login_flags & NLP_TM_DELAYED_LOGIN) { + ndlp->tm_login_flags &= ~NLP_TM_DELAYED_LOGIN; + ndlp->login_handle = tm_tgtport_login(vport, ndlp); + if (ndlp->login_handle != NULL) + ndlp->login_handle_valid = 1; + } +#endif + return; } @@ -3567,8 +3585,16 @@ lpfc_mbx_cmpl_reg_vpi(struct lpfc_hba *p spin_unlock_irq(shost->host_lock); vport->num_disc_nodes = 0; /* go thru NPR list and issue ELS PLOGIs */ +#ifdef LPFC_TARGET_MODE + if ((phba->cfg_fcp_mode & LPFC_FCP_MODE_INITIATOR) || + (vport->fc_flag & FC_PT2PT_PLOGI)) { + if (vport->fc_npr_cnt) + lpfc_els_disc_plogi(vport); + } +#else if (vport->fc_npr_cnt) lpfc_els_disc_plogi(vport); +#endif if (!vport->num_disc_nodes) { spin_lock_irq(shost->host_lock); @@ -4513,6 +4539,13 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, int rc; uint16_t rpi; +#ifdef LPFC_TARGET_MODE + /* if there is a valid target login, need to logout now. */ + tm_tgtport_logout(vport, ndlp->login_handle); + ndlp->login_handle = 0; + ndlp->login_handle_valid = 0; + ndlp->tm_check_login_called = 0; +#endif if (ndlp->nlp_flag & NLP_RPI_REGISTERED || ndlp->nlp_flag & NLP_REG_LOGIN_SEND) { if (ndlp->nlp_flag & NLP_REG_LOGIN_SEND) @@ -4904,6 +4937,10 @@ lpfc_setup_disc_node(struct lpfc_vport * ndlp = lpfc_findnode_did(vport, did); if (!ndlp) { +#ifdef LPFC_TARGET_MODE + if (!(vport->phba->cfg_fcp_mode & LPFC_FCP_MODE_INITIATOR)) + return NULL; +#endif if ((vport->fc_flag & FC_RSCN_MODE) != 0 && lpfc_rscn_payload_check(vport, did) == 0) return NULL; @@ -5121,8 +5158,16 @@ lpfc_disc_start(struct lpfc_vport *vport if (!(vport->fc_flag & FC_ABORT_DISCOVERY)) { vport->num_disc_nodes = 0; /* go thru NPR nodes and issue ELS PLOGIs */ +#ifdef LPFC_TARGET_MODE + if ((phba->cfg_fcp_mode & LPFC_FCP_MODE_INITIATOR) || + (vport->fc_flag & FC_PT2PT_PLOGI)) { + if (vport->fc_npr_cnt) + lpfc_els_disc_plogi(vport); + } +#else if (vport->fc_npr_cnt) lpfc_els_disc_plogi(vport); +#endif if (!vport->num_disc_nodes) { spin_lock_irq(shost->host_lock); @@ -5134,7 +5179,14 @@ lpfc_disc_start(struct lpfc_vport *vport vport->port_state = LPFC_VPORT_READY; } else { /* Next do PLOGIs - if any */ +#ifdef LPFC_TARGET_MODE + if ((phba->cfg_fcp_mode & LPFC_FCP_MODE_INITIATOR) || + (vport->fc_flag & FC_PT2PT_PLOGI)) { + num_sent = lpfc_els_disc_plogi(vport); + } +#else num_sent = lpfc_els_disc_plogi(vport); +#endif if (num_sent) return; diff -upNr 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_hw.h 4.1-rc7/drivers/scsi/lpfc/lpfc_hw.h --- 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_hw.h 2015-05-25 03:22:35.000000000 +0200 +++ 4.1-rc7/drivers/scsi/lpfc/lpfc_hw.h 2015-06-14 16:33:02.495543894 +0200 @@ -1427,6 +1427,8 @@ typedef struct { /* FireFly BIU registe #define MBX_PORT_IOV_CONTROL 0x3C #define MBX_CONFIG_HBQ 0x7C +#define MBX_PAUSE_HBQ 0x7D +#define MBX_RESUME_HBQ 0x7E #define MBX_LOAD_AREA 0x81 #define MBX_RUN_BIU_DIAG64 0x84 #define MBX_CONFIG_PORT 0x88 @@ -1862,6 +1864,10 @@ typedef struct { #define FLAGS_UNREG_LOGIN_ALL 0x08 /* UNREG_LOGIN all on link down */ #define FLAGS_LIRP_LILP 0x80 /* LIRP / LILP is disabled */ +#ifdef LPFC_TARGET_MODE +#define FLAGS_DISABLE_TGT_ABTS 0x20 /* Bit 5 */ +#define FLAGS_DISABLE_GLBL_ABTS 0x02000 /* Bit 13 */ +#endif #define FLAGS_TOPOLOGY_FAILOVER 0x0400 /* Bit 10 */ #define FLAGS_LINK_SPEED 0x0800 /* Bit 11 */ #define FLAGS_IMED_ABORT 0x04000 /* Bit 14 */ @@ -2787,7 +2793,37 @@ struct config_hbq_var { }; +/* Structure for MB Command PAUSE_HBQ (7d) */ +struct pause_hbq_var { +#ifdef __BIG_ENDIAN_BITFIELD + uint32_t hbqId:16; + uint32_t rsvd1:16; +#else /* __LITTLE_ENDIAN */ + uint32_t rsvd1:16; + uint32_t hbqId:16; +#endif + +#ifdef __BIG_ENDIAN_BITFIELD + uint32_t rsvd2:16; + uint32_t mbTag16:16; +#else /* __LITTLE_ENDIAN */ + uint32_t mbTag16:16; + uint32_t rsvd2:16; +#endif + +}; + +/* Structure for MB Command RESUME_HBQ (7e) */ +struct resume_hbq_var { +#ifdef __BIG_ENDIAN_BITFIELD + uint32_t hbqId:16; + uint32_t hbqGetPtr:16; +#else /* __LITTLE_ENDIAN */ + uint32_t hbqGetPtr:16; + uint32_t hbqId:16; +#endif +}; /* Structure for MB Command CONFIG_PORT (0x88) */ typedef struct { @@ -3068,6 +3104,8 @@ typedef union { * NEW_FEATURE */ struct config_hbq_var varCfgHbq;/* cmd = 0x7c (CONFIG_HBQ) */ + struct pause_hbq_var varPauseHbq; /* cmd = 0x7d (PAUSE_HBQ) */ + struct resume_hbq_var varResumeHbq; /* cmd = 0x7e (RESUME_HBQ) */ struct update_cfg_var varUpdateCfg; /* cmd = 0x1B (UPDATE_CFG)*/ CONFIG_PORT_VAR varCfgPort; /* cmd = 0x88 (CONFIG_PORT) */ struct lpfc_mbx_read_top varReadTop; /* cmd = 0x95 (READ_TOPOLOGY) */ @@ -3711,6 +3749,9 @@ typedef struct _IOCB { /* IOCB structure uint32_t ulpTimeout:8; #endif +#define ulpAc ulpOwner +#define ulpAutoResponse ulpFCP2Rcvy + union { struct rcv_sli3 rcvsli3; /* words 8 - 15 */ @@ -3748,7 +3789,7 @@ typedef struct _IOCB { /* IOCB structure #define IOSTAT_INTERMED_RSP 0x8 #define IOSTAT_LS_RJT 0x9 #define IOSTAT_BA_RJT 0xA -#define IOSTAT_RSVD1 0xB +#define IOSTAT_CMD_RJT 0xB #define IOSTAT_RSVD2 0xC #define IOSTAT_RSVD3 0xD #define IOSTAT_RSVD4 0xE diff -upNr 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_init.c 4.1-rc7/drivers/scsi/lpfc/lpfc_init.c --- 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_init.c 2015-05-25 03:22:35.000000000 +0200 +++ 4.1-rc7/drivers/scsi/lpfc/lpfc_init.c 2015-06-14 16:33:02.503543894 +0200 @@ -44,6 +44,10 @@ #include "lpfc_hw.h" #include "lpfc_sli.h" #include "lpfc_sli4.h" +#ifdef LPFC_TARGET_MODE +#include "lpfc_target_api.h" +#include "lpfc_target_api_base.h" +#endif #include "lpfc_nl.h" #include "lpfc_disc.h" #include "lpfc_scsi.h" @@ -570,6 +574,11 @@ lpfc_config_port_post(struct lpfc_hba *p mod_timer(&phba->eratt_poll, jiffies + msecs_to_jiffies(1000 * LPFC_ERATT_POLL_INTERVAL)); +#ifdef LPFC_TARGET_MODE + if (phba->cfg_initialize_link) + lpfc_init_link(phba, pmb, phba->cfg_topology, + phba->cfg_link_speed); +#endif if (phba->hba_flag & LINK_DISABLED) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, @@ -6296,6 +6305,14 @@ lpfc_post_init_setup(struct lpfc_hba *ph spin_unlock_irq(shost->host_lock); } +#ifdef LPFC_TARGET_MODE + if (!phba->cfg_initialize_link) { + /* After initialization, this should always be set */ + phba->cfg_initialize_link = 1; + return; + } +#endif + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "0428 Perform SCSI scan\n"); /* Send board arrival event to upper layer */ diff -upNr 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_mbox.c 4.1-rc7/drivers/scsi/lpfc/lpfc_mbox.c --- 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_mbox.c 2015-05-25 03:22:35.000000000 +0200 +++ 4.1-rc7/drivers/scsi/lpfc/lpfc_mbox.c 2015-06-14 16:33:02.503543894 +0200 @@ -33,6 +33,10 @@ #include "lpfc_hw.h" #include "lpfc_sli.h" #include "lpfc_sli4.h" +#ifdef LPFC_TARGET_MODE +#include "lpfc_target_api.h" +#include "lpfc_target_api_base.h" +#endif #include "lpfc_nl.h" #include "lpfc_disc.h" #include "lpfc_scsi.h" @@ -553,6 +557,12 @@ lpfc_init_link(struct lpfc_hba * phba, else mb->un.varInitLnk.link_speed = LINK_SPEED_AUTO; +#ifdef LPFC_TARGET_MODE + if (phba->cfg_fcp_mode & LPFC_FCP_MODE_TARGET) { + mb->un.varInitLnk.link_flags |= + (FLAGS_DISABLE_TGT_ABTS | FLAGS_DISABLE_TGT_ABTS); + } +#endif mb->mbxCommand = (volatile uint8_t)MBX_INIT_LINK; mb->mbxOwner = OWN_HOST; mb->un.varInitLnk.fabric_AL_PA = phba->fc_pref_ALPA; diff -upNr 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_mem.c 4.1-rc7/drivers/scsi/lpfc/lpfc_mem.c --- 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_mem.c 2015-05-25 03:22:35.000000000 +0200 +++ 4.1-rc7/drivers/scsi/lpfc/lpfc_mem.c 2015-06-14 16:33:02.503543894 +0200 @@ -34,6 +34,10 @@ #include "lpfc_sli.h" #include "lpfc_sli4.h" #include "lpfc_nl.h" +#ifdef LPFC_TARGET_MODE +#include "lpfc_target_api.h" +#include "lpfc_target_api_base.h" +#endif #include "lpfc_disc.h" #include "lpfc_scsi.h" #include "lpfc.h" @@ -560,6 +564,7 @@ lpfc_in_buf_free(struct lpfc_hba *phba, { struct hbq_dmabuf *hbq_entry; unsigned long flags; + uint32_t hbqno; if (!mp) return; @@ -573,7 +578,8 @@ lpfc_in_buf_free(struct lpfc_hba *phba, } hbq_entry = container_of(mp, struct hbq_dmabuf, dbuf); list_del(&hbq_entry->dbuf.list); - if (hbq_entry->tag == -1) { + hbqno = lpfc_hbqno_get(hbq_entry->tag); + if (hbqno >= LPFC_MAX_HBQS) { (phba->hbqs[LPFC_ELS_HBQ].hbq_free_buffer) (phba, hbq_entry); } else { diff -upNr 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_nportdisc.c 4.1-rc7/drivers/scsi/lpfc/lpfc_nportdisc.c --- 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_nportdisc.c 2015-05-25 03:22:35.000000000 +0200 +++ 4.1-rc7/drivers/scsi/lpfc/lpfc_nportdisc.c 2015-06-14 16:33:02.507543894 +0200 @@ -33,6 +33,10 @@ #include "lpfc_hw.h" #include "lpfc_sli.h" #include "lpfc_sli4.h" +#ifdef LPFC_TARGET_MODE +#include "lpfc_target_api.h" +#include "lpfc_target_api_base.h" +#endif #include "lpfc_nl.h" #include "lpfc_disc.h" #include "lpfc_scsi.h" @@ -375,9 +379,11 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, case NLP_STE_NPR_NODE: if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) break; + case NLP_STE_UNMAPPED_NODE: + if (!ndlp->nlp_rpi) + break; case NLP_STE_REG_LOGIN_ISSUE: case NLP_STE_PRLI_ISSUE: - case NLP_STE_UNMAPPED_NODE: case NLP_STE_MAPPED_NODE: /* lpfc_plogi_confirm_nport skips fabric did, handle it here */ if (!(ndlp->nlp_type & NLP_FABRIC)) { @@ -1333,6 +1339,9 @@ lpfc_cmpl_adisc_adisc_issue(struct lpfc_ struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; struct lpfc_iocbq *cmdiocb, *rspiocb; +#ifdef LPFC_TARGET_MODE + struct ls_rjt stat; +#endif IOCB_t *irsp; ADISC *ap; int rc; @@ -1343,6 +1352,72 @@ lpfc_cmpl_adisc_adisc_issue(struct lpfc_ ap = (ADISC *)lpfc_check_elscmpl_iocb(phba, cmdiocb, rspiocb); irsp = &rspiocb->iocb; +#ifdef LPFC_TARGET_MODE + if (irsp->ulpStatus) { + stat.un.lsRjtError = be32_to_cpu(irsp->un.ulpWord[4]); + + /* did is alive but can't be authenticated */ + if (stat.un.b.lsRjtRsnCode == LSRJT_UNABLE_TPC || + stat.un.b.lsRjtRsnCode == LSRJT_CMD_UNSUPPORTED) { + + lpfc_issue_els_logo(vport, ndlp, 0); + /* Put ndlp in npr state set plogi timer for 1 sec */ + mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1); + spin_lock_irq(shost->host_lock); + ndlp->nlp_flag |= NLP_DELAY_TMO; + spin_unlock_irq(shost->host_lock); + ndlp->nlp_last_elscmd = ELS_CMD_ADISC; + ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE; + lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); + return ndlp->nlp_state; + } + + /* 1 sec timeout */ + mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ); + spin_lock_irq(shost->host_lock); + ndlp->nlp_flag |= NLP_DELAY_TMO; + spin_unlock_irq(shost->host_lock); + ndlp->nlp_last_elscmd = ELS_CMD_PLOGI; + + memset(&ndlp->nlp_nodename, 0, sizeof(struct lpfc_name)); + memset(&ndlp->nlp_portname, 0, sizeof(struct lpfc_name)); + + ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE; + lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); + lpfc_unreg_rpi(vport, ndlp); + return ndlp->nlp_state; + + } else if (!lpfc_check_adisc(vport, + ndlp, &ap->nodeName, &ap->portName)) { + /* 1 sec timeout */ + mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ); + spin_lock_irq(shost->host_lock); + ndlp->nlp_flag |= NLP_DELAY_TMO; + spin_unlock_irq(shost->host_lock); + ndlp->nlp_last_elscmd = ELS_CMD_PLOGI; + + memset(&ndlp->nlp_nodename, 0, sizeof(struct lpfc_name)); + memset(&ndlp->nlp_portname, 0, sizeof(struct lpfc_name)); + + ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE; + lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); + lpfc_unreg_rpi(vport, ndlp); + return ndlp->nlp_state; + } + if (ndlp->nlp_flag & NLP_NEED_PRLI) { + /* Only if we are not a fabric nport do we issue PRLI */ + if (!(ndlp->nlp_type & NLP_FABRIC)) { + ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE; + lpfc_nlp_set_state(vport, ndlp, NLP_STE_PRLI_ISSUE); + lpfc_issue_els_prli(vport, ndlp, 0); + } else { + ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE; + lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); + } + return ndlp->nlp_state; + } + +#else if ((irsp->ulpStatus) || (!lpfc_check_adisc(vport, ndlp, &ap->nodeName, &ap->portName))) { /* 1 sec timeout */ @@ -1361,6 +1436,7 @@ lpfc_cmpl_adisc_adisc_issue(struct lpfc_ lpfc_unreg_rpi(vport, ndlp); return ndlp->nlp_state; } +#endif if (phba->sli_rev == LPFC_SLI_REV4) { rc = lpfc_sli4_resume_rpi(ndlp, NULL, NULL); @@ -1574,9 +1650,22 @@ lpfc_cmpl_reglogin_reglogin_issue(struct /* Only if we are not a fabric nport do we issue PRLI */ if (!(ndlp->nlp_type & NLP_FABRIC)) { +#ifdef LPFC_TARGET_MODE + struct lpfc_hba *phba = vport->phba; + + if (phba->cfg_fcp_mode & LPFC_FCP_MODE_INITIATOR) { + ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE; + lpfc_nlp_set_state(vport, ndlp, NLP_STE_PRLI_ISSUE); + lpfc_issue_els_prli(vport, ndlp, 0); + } else { + ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE; + lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); + } +#else ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE; lpfc_nlp_set_state(vport, ndlp, NLP_STE_PRLI_ISSUE); lpfc_issue_els_prli(vport, ndlp, 0); +#endif } else { ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE; lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); @@ -1699,6 +1788,9 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vp cmdiocb = (struct lpfc_iocbq *) arg; rspiocb = cmdiocb->context_un.rsp_iocb; +#ifdef LPFC_TARGET_MODE + ndlp->nlp_flag &= ~NLP_NEED_PRLI; +#endif npr = (PRLI *)lpfc_check_elscmpl_iocb(phba, cmdiocb, rspiocb); irsp = &rspiocb->iocb; @@ -1828,6 +1920,9 @@ lpfc_device_recov_prli_issue(struct lpfc spin_lock_irq(shost->host_lock); ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); spin_unlock_irq(shost->host_lock); +#ifdef LPFC_TARGET_MODE + ndlp->nlp_flag |= NLP_NEED_PRLI; +#endif lpfc_disc_set_adisc(vport, ndlp); return ndlp->nlp_state; } @@ -2119,7 +2214,16 @@ lpfc_rcv_prli_npr_node(struct lpfc_vport struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; struct ls_rjt stat; +#ifdef LPFC_TARGET_MODE + struct lpfc_hba *phba = vport->phba; + if (!(phba->cfg_fcp_mode & LPFC_FCP_MODE_INITIATOR)) { + lpfc_rcv_prli(vport, ndlp, cmdiocb); + ndlp->nlp_prev_state = NLP_STE_NPR_NODE; + lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); + return ndlp->nlp_state; + } +#endif memset(&stat, 0, sizeof (struct ls_rjt)); stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE; diff -upNr 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_scsi.c 4.1-rc7/drivers/scsi/lpfc/lpfc_scsi.c --- 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_scsi.c 2015-05-25 03:22:35.000000000 +0200 +++ 4.1-rc7/drivers/scsi/lpfc/lpfc_scsi.c 2015-06-14 16:33:02.507543894 +0200 @@ -40,6 +40,10 @@ #include "lpfc_sli.h" #include "lpfc_sli4.h" #include "lpfc_nl.h" +#ifdef LPFC_TARGET_MODE +#include "lpfc_target_api.h" +#include "lpfc_target_api_base.h" +#endif #include "lpfc_disc.h" #include "lpfc.h" #include "lpfc_scsi.h" diff -upNr 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_sli.c 4.1-rc7/drivers/scsi/lpfc/lpfc_sli.c --- 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_sli.c 2015-05-25 03:22:35.000000000 +0200 +++ 4.1-rc7/drivers/scsi/lpfc/lpfc_sli.c 2015-06-14 16:33:02.515543895 +0200 @@ -37,6 +37,10 @@ #include "lpfc_hw.h" #include "lpfc_sli.h" #include "lpfc_sli4.h" +#ifdef LPFC_TARGET_MODE +#include "lpfc_target_api.h" +#include "lpfc_target_api_base.h" +#endif #include "lpfc_nl.h" #include "lpfc_disc.h" #include "lpfc_scsi.h" @@ -55,6 +59,9 @@ typedef enum _lpfc_iocb_type { LPFC_ABORT_IOCB } lpfc_iocb_type; +#ifdef LPFC_TARGET_MODE +void lpfc_tm_hbq_free(struct lpfc_hba *phba, struct hbq_dmabuf *hbqbp); +#endif /* Provide function prototypes local to this module. */ static int lpfc_sli_issue_mbox_s4(struct lpfc_hba *, LPFC_MBOXQ_t *, @@ -1225,6 +1232,9 @@ lpfc_sli_iocb_cmd_type(uint8_t iocb_cmnd case CMD_IOCB_RCV_ELS64_CX: case CMD_IOCB_RCV_CONT64_CX: case CMD_IOCB_RET_XRI64_CX: +#ifdef LPFC_TARGET_MODE + case CMD_IOCB_RET_HBQE64_CN: +#endif type = LPFC_UNSOL_IOCB; break; case CMD_IOCB_XMIT_MSEQ64_CR: @@ -1233,7 +1243,9 @@ lpfc_sli_iocb_cmd_type(uint8_t iocb_cmnd case CMD_IOCB_RCV_ELS_LIST64_CX: case CMD_IOCB_CLOSE_EXTENDED_CN: case CMD_IOCB_ABORT_EXTENDED_CN: +#ifndef LPFC_TARGET_MODE case CMD_IOCB_RET_HBQE64_CN: +#endif case CMD_IOCB_FCP_IBIDIR64_CR: case CMD_IOCB_FCP_IBIDIR64_CX: case CMD_IOCB_FCP_ITASKMGT64_CX: @@ -1716,8 +1728,13 @@ lpfc_sli_hbqbuf_free_all(struct lpfc_hba (phba->hbqs[LPFC_ELS_HBQ].hbq_free_buffer) (phba, hbq_buf); } else { +#ifdef LPFC_TARGET_MODE + hbqno = lpfc_hbqno_get(hbq_buf->tag); + if (hbq_buf->tag & QUE_BUFTAG_BIT) +#else hbqno = hbq_buf->tag >> 16; if (hbqno >= LPFC_MAX_HBQS) +#endif (phba->hbqs[LPFC_ELS_HBQ].hbq_free_buffer) (phba, hbq_buf); else @@ -1824,7 +1841,7 @@ lpfc_sli_hbq_to_firmware_s4(struct lpfc_ /* HBQ for ELS and CT traffic. */ static struct lpfc_hbq_init lpfc_els_hbq = { .rn = 1, - .entry_count = 256, + .entry_count = 200, /* 12 bits max size */ .mask_count = 0, .profile = 0, .ring_mask = (1 << LPFC_ELS_RING), @@ -1861,7 +1878,7 @@ struct lpfc_hbq_init *lpfc_hbq_defs[] = * given HBQ. The function returns the number of HBQ buffers successfully * posted. **/ -static int +int lpfc_sli_hbqbuf_fill_hbqs(struct lpfc_hba *phba, uint32_t hbqno, uint32_t count) { uint32_t i, posted = 0; @@ -1891,8 +1908,14 @@ lpfc_sli_hbqbuf_fill_hbqs(struct lpfc_hb while (!list_empty(&hbq_buf_list)) { list_remove_head(&hbq_buf_list, hbq_buffer, struct hbq_dmabuf, dbuf.list); +#ifdef LPFC_TARGET_MODE + /* convert app tag to base driver hbq tag */ + i = phba->hbqs[hbqno].buffer_count; + hbq_buffer->tag = lpfc_build_hbq_tag(hbqno, i, hbq_buffer->tag); +#else hbq_buffer->tag = (phba->hbqs[hbqno].buffer_count | (hbqno << 16)); +#endif if (!lpfc_sli_hbq_to_firmware(phba, hbqno, hbq_buffer)) { phba->hbqs[hbqno].buffer_count++; posted++; @@ -1980,31 +2003,45 @@ lpfc_sli_hbqbuf_get(struct list_head *rb * it returns NULL. **/ static struct hbq_dmabuf * -lpfc_sli_hbqbuf_find(struct lpfc_hba *phba, uint32_t tag) +__lpfc_sli_hbqbuf_find(struct lpfc_hba *phba, uint32_t tag) { struct lpfc_dmabuf *d_buf; struct hbq_dmabuf *hbq_buf; uint32_t hbqno; +#ifdef LPFC_TARGET_MODE + hbqno = lpfc_hbqno_get(tag); + if (tag & QUE_BUFTAG_BIT) + return NULL; +#else hbqno = tag >> 16; if (hbqno >= LPFC_MAX_HBQS) return NULL; - - spin_lock_irq(&phba->hbalock); +#endif list_for_each_entry(d_buf, &phba->hbqs[hbqno].hbq_buffer_list, list) { hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf); if (hbq_buf->tag == tag) { - spin_unlock_irq(&phba->hbalock); return hbq_buf; } } - spin_unlock_irq(&phba->hbalock); lpfc_printf_log(phba, KERN_ERR, LOG_SLI | LOG_VPORT, "1803 Bad hbq tag. Data: x%x x%x\n", - tag, phba->hbqs[tag >> 16].buffer_count); + tag, phba->hbqs[hbqno].buffer_count); return NULL; } +static struct hbq_dmabuf * +lpfc_sli_hbqbuf_find(struct lpfc_hba *phba, uint32_t tag) +{ + struct hbq_dmabuf *hbq_buf; + + spin_lock_irq(&phba->hbalock); + hbq_buf = __lpfc_sli_hbqbuf_find(phba, tag); + spin_unlock_irq(&phba->hbalock); + + return hbq_buf; +} + /** * lpfc_sli_free_hbq - Give back the hbq buffer to firmware * @phba: Pointer to HBA context object. @@ -2020,7 +2057,11 @@ lpfc_sli_free_hbq(struct lpfc_hba *phba, uint32_t hbqno; if (hbq_buffer) { +#ifdef LPFC_TARGET_MODE + hbqno = lpfc_hbqno_get(hbq_buffer->tag); +#else hbqno = hbq_buffer->tag >> 16; +#endif if (lpfc_sli_hbq_to_firmware(phba, hbqno, hbq_buffer)) (phba->hbqs[hbqno].hbq_free_buffer)(phba, hbq_buffer); } @@ -2389,6 +2430,55 @@ lpfc_sli_handle_mb_event(struct lpfc_hba return 0; } +#ifdef LPFC_TARGET_MODE +static struct lpfc_dmabuf * +lpfc_sli_replace_hbqbuff(struct lpfc_hba *phba, uint32_t tag) +{ + struct hbq_dmabuf *hbq_entry, *new_hbq_entry; + uint32_t hbqno, hbqidx, new_tag; + void *virt; /* virtual address ptr */ + dma_addr_t phys; /* mapped address */ + unsigned long flags; + + /* Check whether HBQ is still in use */ + spin_lock_irqsave(&phba->hbalock, flags); + if (!phba->hbq_in_use) { + spin_unlock_irqrestore(&phba->hbalock, flags); + return NULL; + } + + hbq_entry = __lpfc_sli_hbqbuf_find(phba, tag); + if (hbq_entry == NULL) { + spin_unlock_irqrestore(&phba->hbalock, flags); + return NULL; + } + list_del(&hbq_entry->dbuf.list); + + hbqno = lpfc_hbqno_get(tag); + hbqidx = lpfc_hbq_idx_get(tag); + new_hbq_entry = (phba->hbqs[hbqno].hbq_alloc_buffer)(phba); + if (new_hbq_entry == NULL) { + list_add_tail(&hbq_entry->dbuf.list, &phba->rb_pend_list); + spin_unlock_irqrestore(&phba->hbalock, flags); + return &hbq_entry->dbuf; + } + new_tag = lpfc_build_hbq_tag(hbqno, hbqidx, new_hbq_entry->tag); + phys = new_hbq_entry->dbuf.phys; + virt = new_hbq_entry->dbuf.virt; + new_hbq_entry->dbuf.phys = hbq_entry->dbuf.phys; + new_hbq_entry->dbuf.virt = hbq_entry->dbuf.virt; + new_hbq_entry->tag = tag; + hbq_entry->dbuf.phys = phys; + hbq_entry->dbuf.virt = virt; + hbq_entry->tag = new_tag; + lpfc_sli_free_hbq(phba, hbq_entry); + list_add_tail(&new_hbq_entry->dbuf.list, &phba->rb_pend_list); + spin_unlock_irqrestore(&phba->hbalock, flags); + + return &new_hbq_entry->dbuf; +} +#endif + /** * lpfc_sli_get_buff - Get the buffer associated with the buffer tag * @phba: Pointer to HBA context object. @@ -2406,14 +2496,20 @@ lpfc_sli_get_buff(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, uint32_t tag) { +#ifndef LPFC_TARGET_MODE struct hbq_dmabuf *hbq_entry; +#endif if (tag & QUE_BUFTAG_BIT) return lpfc_sli_ring_taggedbuf_get(phba, pring, tag); +#ifdef LPFC_TARGET_MODE + return lpfc_sli_replace_hbqbuff(phba, tag); +#else hbq_entry = lpfc_sli_hbqbuf_find(phba, tag); if (!hbq_entry) return NULL; return &hbq_entry->dbuf; +#endif } /** @@ -2479,9 +2575,20 @@ lpfc_sli_process_unsol_iocb(struct lpfc_ uint32_t Rctl, Type; struct lpfc_iocbq *iocbq; struct lpfc_dmabuf *dmzbuf; +#ifdef LPFC_TARGET_MODE + uint32_t i, tag; + struct hbq_dmabuf *hbq_entry; +#endif irsp = &(saveq->iocb); + if (unlikely(irsp->ulpStatus == IOSTAT_NEED_BUFFER)) { +#ifdef LPFC_TARGET_MODE + if (pring->ringno == LPFC_EXTRA_RING) + lpfc_sli_hbqbuf_add_hbqs(phba, LPFC_EXTRA_HBQ); +#endif + return 1; + } if (irsp->ulpCommand == CMD_ASYNC_STATUS) { if (pring->lpfc_sli_rcv_async_status) pring->lpfc_sli_rcv_async_status(phba, pring, saveq); @@ -2497,6 +2604,18 @@ lpfc_sli_process_unsol_iocb(struct lpfc_ return 1; } +#ifdef LPFC_TARGET_MODE + /* Forward XRI ABORTED async response to target driver */ + if ((saveq->iocb.ulpCommand == CMD_XRI_ABORTED_CX) && + (pring->ringno == LPFC_EXTRA_RING)) { + if (pring->prt[0].lpfc_sli_rcv_unsol_event) { + (pring->prt[0].lpfc_sli_rcv_unsol_event) + (phba, pring, saveq); + } + return 1; + } +#endif + if ((irsp->ulpCommand == CMD_IOCB_RET_XRI64_CX) && (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)) { if (irsp->ulpBdeCount > 0) { @@ -2520,6 +2639,37 @@ lpfc_sli_process_unsol_iocb(struct lpfc_ return 1; } + if ((irsp->ulpCommand == CMD_IOCB_RET_HBQE64_CN) && + (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)) { +#ifdef LPFC_TARGET_MODE + if (pring->ringno != LPFC_EXTRA_RING) + return 1; + + for (i = 0; i < irsp->ulpBdeCount; i++) { + switch (i) { + case 0: + tag = irsp->un.ulpWord[3]; + break; + case 1: + tag = irsp->unsli3.sli3Words[3]; + break; + case 2: + tag = irsp->unsli3.sli3Words[7]; + break; + default: + return 1; + } + hbq_entry = lpfc_sli_hbqbuf_find(phba, tag); + + if (hbq_entry) { + list_del(&hbq_entry->dbuf.list); + lpfc_tm_hbq_free(phba, hbq_entry); + } + } +#endif + return 1; + } + if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { if (irsp->ulpBdeCount != 0) { saveq->context2 = lpfc_sli_get_buff(phba, pring, @@ -2972,6 +3122,9 @@ lpfc_sli_handle_fast_ring_event(struct l lpfc_iocb_type type; unsigned long iflag; uint32_t rsp_cmpl = 0; +#ifdef LPFC_TARGET_MODE + int rsp_cnt = 0; +#endif spin_lock_irqsave(&phba->hbalock, iflag); pring->stats.iocb_event++; @@ -3030,7 +3183,8 @@ lpfc_sli_handle_fast_ring_event(struct l } /* Rsp ring <ringno> error: IOCB */ - lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, + if (irsp->ulpStatus != IOSTAT_NEED_BUFFER) { + lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, "0336 Rsp Ring %d error: IOCB Data: " "x%x x%x x%x x%x x%x x%x x%x x%x\n", pring->ringno, @@ -3042,6 +3196,7 @@ lpfc_sli_handle_fast_ring_event(struct l irsp->un.ulpWord[5], *(uint32_t *)&irsp->un1, *((uint32_t *)&irsp->un1 + 1)); + } } switch (type) { @@ -3052,6 +3207,18 @@ lpfc_sli_handle_fast_ring_event(struct l * resources need to be recovered. */ if (unlikely(irsp->ulpCommand == CMD_XRI_ABORTED_CX)) { +#ifdef LPFC_TARGET_MODE + /* If target mode port */ + /* send XRI_ABORTED to target driver */ + if ((pring->ringno == LPFC_EXTRA_RING) && + (phba->cfg_fcp_mode & LPFC_FCP_MODE_TARGET)) { + spin_unlock_irqrestore(&phba->hbalock, iflag); + lpfc_sli_process_unsol_iocb + (phba, pring, &rspiocbq); + spin_lock_irqsave(&phba->hbalock, iflag); + break; + } +#endif lpfc_printf_log(phba, KERN_INFO, LOG_SLI, "0333 IOCB cmd 0x%x" " processed. Skipping" @@ -3111,6 +3278,13 @@ lpfc_sli_handle_fast_ring_event(struct l if (pring->sli.sli3.rspidx == portRspPut) portRspPut = le32_to_cpu(pgp->rspPutInx); +#ifdef LPFC_TARGET_MODE + if ((pring->ringno == LPFC_EXTRA_RING) && phba->poll_rsp_cnt) { + rsp_cnt++; + if (rsp_cnt >= phba->poll_rsp_cnt) + break; + } +#endif } if ((rsp_cmpl > 0) && (mask & HA_R0RE_REQ)) { @@ -7955,9 +8129,10 @@ __lpfc_sli_issue_iocb_s3(struct lpfc_hba /* * Check to see if we are blocking IOCB processing because of a - * outstanding event. + * outstanding event. IOCBs like CMD_QUE_RING_BUF* (without a cmpl) + * should be allowed through. */ - if (unlikely(pring->flag & LPFC_STOP_IOCB_EVENT)) + if (unlikely(pring->flag & LPFC_STOP_IOCB_EVENT) && piocb->iocb_cmpl) goto iocb_busy; if (unlikely(phba->link_state == LPFC_LINK_DOWN)) { diff -upNr 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_sli.h 4.1-rc7/drivers/scsi/lpfc/lpfc_sli.h --- 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_sli.h 2015-05-25 03:22:35.000000000 +0200 +++ 4.1-rc7/drivers/scsi/lpfc/lpfc_sli.h 2015-06-14 16:33:02.519543895 +0200 @@ -321,6 +321,37 @@ struct lpfc_sli { struct lpfc_lnk_stat lnk_stat_offsets; }; +/* + * Functions to build or extract fields for HBQ buffer tags. + * The applications tag is in bits 30:16, the hbqno in 15:12, + * the hbq entry index is in bits 11:0 The high order bit (31) + * is reserved for non-hbq buffer use. + */ +static inline uint32_t +lpfc_build_hbq_tag(uint16_t hbqno, uint16_t hbqidx, uint16_t app_tag) +{ + return ((app_tag & 0x7fff) << 16) | + ((hbqno & 0xf) << 12) | (hbqidx & 0xfff); +} + +static inline uint16_t +lpfc_hbq_app_tag_get(uint32_t tag) +{ + return (tag >> 16) & 0x7fff; +} + +static inline uint16_t +lpfc_hbq_idx_get(uint32_t tag) +{ + return tag & 0xfff; +} + +static inline uint16_t +lpfc_hbqno_get(uint32_t tag) +{ + return (tag >> 12) & 0xf; +} + /* Timeout for normal outstanding mbox command (Seconds) */ #define LPFC_MBOX_TMO 30 /* Timeout for non-flash-based outstanding sli_config mbox command (Seconds) */ diff -upNr 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_version.h 4.1-rc7/drivers/scsi/lpfc/lpfc_version.h --- 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_version.h 2015-05-25 03:22:35.000000000 +0200 +++ 4.1-rc7/drivers/scsi/lpfc/lpfc_version.h 2015-06-14 16:33:02.519543895 +0200 @@ -18,7 +18,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "10.5.0.0." +#define LPFC_DRIVER_VERSION "10.5.0.0_tm_10.0.0." #define LPFC_DRIVER_NAME "lpfc" /* Used for SLI 2/3 */ diff -upNr 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_vport.c 4.1-rc7/drivers/scsi/lpfc/lpfc_vport.c --- 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_vport.c 2015-05-25 03:22:35.000000000 +0200 +++ 4.1-rc7/drivers/scsi/lpfc/lpfc_vport.c 2015-06-14 16:33:02.519543895 +0200 @@ -37,6 +37,10 @@ #include "lpfc_hw.h" #include "lpfc_sli.h" #include "lpfc_sli4.h" +#ifdef LPFC_TARGET_MODE +#include "lpfc_target_api.h" +#include "lpfc_target_api_base.h" +#endif #include "lpfc_nl.h" #include "lpfc_disc.h" #include "lpfc_scsi.h" @@ -45,6 +49,9 @@ #include "lpfc_crtn.h" #include "lpfc_version.h" #include "lpfc_vport.h" +#ifdef LPFC_TARGET_MODE +#include "lpfc_target_protos.h" +#endif inline void lpfc_vport_set_state(struct lpfc_vport *vport, enum fc_vport_state new_state) @@ -419,6 +426,11 @@ lpfc_vport_create(struct fc_vport *fc_vp goto out; } +#ifdef LPFC_TARGET_MODE + if (phba->cfg_fcp_mode & LPFC_FCP_MODE_TARGET) + lpfc_target_new_tgtport(vport); +#endif + if ((phba->link_state < LPFC_LINK_UP) || (pport->port_state < LPFC_FABRIC_CFG_LINK) || (phba->fc_topology == LPFC_TOPOLOGY_LOOP)) { @@ -777,6 +789,11 @@ skip_logo: } else scsi_host_put(shost); +#ifdef LPFC_TARGET_MODE + if (phba->cfg_fcp_mode & LPFC_FCP_MODE_TARGET) + lpfc_target_rm_tgtport(vport); +#endif + lpfc_free_vpi(phba, vport->vpi); vport->work_port_events = 0; spin_lock_irq(&phba->hbalock); -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html