Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

lpfc: add support to generate RSCN events for nport

This patch adds general RSCN support:

- The ability to transmit an RSCN to the port on the other end of
the link (regular port if pt2pt, or fabric controller if fabric).
- And general recognition of an RSCN ELS when an ELS is received.

Signed-off-by: Dick Kennedy <dick.kennedy@broadcom.com>
Signed-off-by: James Smart <jsmart2021@gmail.com>
Reviewed-by: Hannes Reinecke <hare@suse.com>
Reviewed-by: Arun Easi <aeasi@marvell.com>
Signed-off-by: Sagi Grimberg <sagi@grimberg.me>
Signed-off-by: Christoph Hellwig <hch@lst.de>

authored by

James Smart and committed by
Christoph Hellwig
f60cb93b 4cf7c363

+163
+1
drivers/scsi/lpfc/lpfc.h
··· 274 274 uint32_t elsXmitADISC; 275 275 uint32_t elsXmitLOGO; 276 276 uint32_t elsXmitSCR; 277 + uint32_t elsXmitRSCN; 277 278 uint32_t elsXmitRNID; 278 279 uint32_t elsXmitFARP; 279 280 uint32_t elsXmitFARPR;
+2
drivers/scsi/lpfc/lpfc_crtn.h
··· 141 141 int lpfc_issue_els_logo(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t); 142 142 int lpfc_issue_els_npiv_logo(struct lpfc_vport *, struct lpfc_nodelist *); 143 143 int lpfc_issue_els_scr(struct lpfc_vport *, uint32_t, uint8_t); 144 + int lpfc_issue_els_rscn(struct lpfc_vport *vport, uint8_t retry); 144 145 int lpfc_issue_fabric_reglogin(struct lpfc_vport *); 145 146 int lpfc_els_free_iocb(struct lpfc_hba *, struct lpfc_iocbq *); 146 147 int lpfc_ct_free_iocb(struct lpfc_hba *, struct lpfc_iocbq *); ··· 356 355 struct lpfc_nodelist *lpfc_findnode_did(struct lpfc_vport *, uint32_t); 357 356 struct lpfc_nodelist *lpfc_findnode_wwpn(struct lpfc_vport *, 358 357 struct lpfc_name *); 358 + struct lpfc_nodelist *lpfc_findnode_mapped(struct lpfc_vport *vport); 359 359 360 360 int lpfc_sli_issue_mbox_wait(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t); 361 361
+122
drivers/scsi/lpfc/lpfc_els.c
··· 30 30 #include <scsi/scsi_device.h> 31 31 #include <scsi/scsi_host.h> 32 32 #include <scsi/scsi_transport_fc.h> 33 + #include <uapi/scsi/fc/fc_fs.h> 34 + #include <uapi/scsi/fc/fc_els.h> 33 35 34 36 #include "lpfc_hw4.h" 35 37 #include "lpfc_hw.h" ··· 3077 3075 */ 3078 3076 if (!(vport->fc_flag & FC_PT2PT)) 3079 3077 lpfc_nlp_put(ndlp); 3078 + return 0; 3079 + } 3080 + 3081 + /** 3082 + * lpfc_issue_els_rscn - Issue an RSCN to the Fabric Controller (Fabric) 3083 + * or the other nport (pt2pt). 3084 + * @vport: pointer to a host virtual N_Port data structure. 3085 + * @retry: number of retries to the command IOCB. 3086 + * 3087 + * This routine issues a RSCN to the Fabric Controller (DID 0xFFFFFD) 3088 + * when connected to a fabric, or to the remote port when connected 3089 + * in point-to-point mode. When sent to the Fabric Controller, it will 3090 + * replay the RSCN to registered recipients. 3091 + * 3092 + * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp 3093 + * will be incremented by 1 for holding the ndlp and the reference to ndlp 3094 + * will be stored into the context1 field of the IOCB for the completion 3095 + * callback function to the RSCN ELS command. 3096 + * 3097 + * Return code 3098 + * 0 - Successfully issued RSCN command 3099 + * 1 - Failed to issue RSCN command 3100 + **/ 3101 + int 3102 + lpfc_issue_els_rscn(struct lpfc_vport *vport, uint8_t retry) 3103 + { 3104 + struct lpfc_hba *phba = vport->phba; 3105 + struct lpfc_iocbq *elsiocb; 3106 + struct lpfc_nodelist *ndlp; 3107 + struct { 3108 + struct fc_els_rscn rscn; 3109 + struct fc_els_rscn_page portid; 3110 + } *event; 3111 + uint32_t nportid; 3112 + uint16_t cmdsize = sizeof(*event); 3113 + 3114 + /* Not supported for private loop */ 3115 + if (phba->fc_topology == LPFC_TOPOLOGY_LOOP && 3116 + !(vport->fc_flag & FC_PUBLIC_LOOP)) 3117 + return 1; 3118 + 3119 + if (vport->fc_flag & FC_PT2PT) { 3120 + /* find any mapped nport - that would be the other nport */ 3121 + ndlp = lpfc_findnode_mapped(vport); 3122 + if (!ndlp) 3123 + return 1; 3124 + } else { 3125 + nportid = FC_FID_FCTRL; 3126 + /* find the fabric controller node */ 3127 + ndlp = lpfc_findnode_did(vport, nportid); 3128 + if (!ndlp) { 3129 + /* if one didn't exist, make one */ 3130 + ndlp = lpfc_nlp_init(vport, nportid); 3131 + if (!ndlp) 3132 + return 1; 3133 + lpfc_enqueue_node(vport, ndlp); 3134 + } else if (!NLP_CHK_NODE_ACT(ndlp)) { 3135 + ndlp = lpfc_enable_node(vport, ndlp, 3136 + NLP_STE_UNUSED_NODE); 3137 + if (!ndlp) 3138 + return 1; 3139 + } 3140 + } 3141 + 3142 + elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, 3143 + ndlp->nlp_DID, ELS_CMD_RSCN_XMT); 3144 + 3145 + if (!elsiocb) { 3146 + /* This will trigger the release of the node just 3147 + * allocated 3148 + */ 3149 + lpfc_nlp_put(ndlp); 3150 + return 1; 3151 + } 3152 + 3153 + event = ((struct lpfc_dmabuf *)elsiocb->context2)->virt; 3154 + 3155 + event->rscn.rscn_cmd = ELS_RSCN; 3156 + event->rscn.rscn_page_len = sizeof(struct fc_els_rscn_page); 3157 + event->rscn.rscn_plen = cpu_to_be16(cmdsize); 3158 + 3159 + nportid = vport->fc_myDID; 3160 + /* appears that page flags must be 0 for fabric to broadcast RSCN */ 3161 + event->portid.rscn_page_flags = 0; 3162 + event->portid.rscn_fid[0] = (nportid & 0x00FF0000) >> 16; 3163 + event->portid.rscn_fid[1] = (nportid & 0x0000FF00) >> 8; 3164 + event->portid.rscn_fid[2] = nportid & 0x000000FF; 3165 + 3166 + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, 3167 + "Issue RSCN: did:x%x", 3168 + ndlp->nlp_DID, 0, 0); 3169 + 3170 + phba->fc_stat.elsXmitRSCN++; 3171 + elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd; 3172 + if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == 3173 + IOCB_ERROR) { 3174 + /* The additional lpfc_nlp_put will cause the following 3175 + * lpfc_els_free_iocb routine to trigger the rlease of 3176 + * the node. 3177 + */ 3178 + lpfc_nlp_put(ndlp); 3179 + lpfc_els_free_iocb(phba, elsiocb); 3180 + return 1; 3181 + } 3182 + /* This will cause the callback-function lpfc_cmpl_els_cmd to 3183 + * trigger the release of node. 3184 + */ 3185 + if (!(vport->fc_flag & FC_PT2PT)) 3186 + lpfc_nlp_put(ndlp); 3187 + 3080 3188 return 0; 3081 3189 } 3082 3190 ··· 6429 6317 for (i = 0; i < payload_len/sizeof(uint32_t); i++) 6430 6318 fc_host_post_event(shost, fc_get_event_number(), 6431 6319 FCH_EVT_RSCN, lp[i]); 6320 + 6321 + /* Check if RSCN is coming from a direct-connected remote NPort */ 6322 + if (vport->fc_flag & FC_PT2PT) { 6323 + /* If so, just ACC it, no other action needed for now */ 6324 + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, 6325 + "2024 pt2pt RSCN %08x Data: x%x x%x\n", 6326 + *lp, vport->fc_flag, payload_len); 6327 + lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); 6328 + return 0; 6329 + } 6432 6330 6433 6331 /* If we are about to begin discovery, just ACC the RSCN. 6434 6332 * Discovery processing will satisfy it.
+35
drivers/scsi/lpfc/lpfc_hbadisc.c
··· 5277 5277 } 5278 5278 5279 5279 struct lpfc_nodelist * 5280 + lpfc_findnode_mapped(struct lpfc_vport *vport) 5281 + { 5282 + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); 5283 + struct lpfc_nodelist *ndlp; 5284 + uint32_t data1; 5285 + unsigned long iflags; 5286 + 5287 + spin_lock_irqsave(shost->host_lock, iflags); 5288 + 5289 + list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { 5290 + if (ndlp->nlp_state == NLP_STE_UNMAPPED_NODE || 5291 + ndlp->nlp_state == NLP_STE_MAPPED_NODE) { 5292 + data1 = (((uint32_t)ndlp->nlp_state << 24) | 5293 + ((uint32_t)ndlp->nlp_xri << 16) | 5294 + ((uint32_t)ndlp->nlp_type << 8) | 5295 + ((uint32_t)ndlp->nlp_rpi & 0xff)); 5296 + spin_unlock_irqrestore(shost->host_lock, iflags); 5297 + lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, 5298 + "2025 FIND node DID " 5299 + "Data: x%p x%x x%x x%x %p\n", 5300 + ndlp, ndlp->nlp_DID, 5301 + ndlp->nlp_flag, data1, 5302 + ndlp->active_rrqs_xri_bitmap); 5303 + return ndlp; 5304 + } 5305 + } 5306 + spin_unlock_irqrestore(shost->host_lock, iflags); 5307 + 5308 + /* FIND node did <did> NOT FOUND */ 5309 + lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, 5310 + "2026 FIND mapped did NOT FOUND.\n"); 5311 + return NULL; 5312 + } 5313 + 5314 + struct lpfc_nodelist * 5280 5315 lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) 5281 5316 { 5282 5317 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+2
drivers/scsi/lpfc/lpfc_hw.h
··· 601 601 #define ELS_CMD_RPL 0x57000000 602 602 #define ELS_CMD_FAN 0x60000000 603 603 #define ELS_CMD_RSCN 0x61040000 604 + #define ELS_CMD_RSCN_XMT 0x61040008 604 605 #define ELS_CMD_SCR 0x62000000 605 606 #define ELS_CMD_RNID 0x78000000 606 607 #define ELS_CMD_LIRR 0x7A000000 ··· 643 642 #define ELS_CMD_RPL 0x57 644 643 #define ELS_CMD_FAN 0x60 645 644 #define ELS_CMD_RSCN 0x0461 645 + #define ELS_CMD_RSCN_XMT 0x08000461 646 646 #define ELS_CMD_SCR 0x62 647 647 #define ELS_CMD_RNID 0x78 648 648 #define ELS_CMD_LIRR 0x7A
+1
drivers/scsi/lpfc/lpfc_sli.c
··· 9398 9398 if (if_type >= LPFC_SLI_INTF_IF_TYPE_2) { 9399 9399 if (pcmd && (*pcmd == ELS_CMD_FLOGI || 9400 9400 *pcmd == ELS_CMD_SCR || 9401 + *pcmd == ELS_CMD_RSCN_XMT || 9401 9402 *pcmd == ELS_CMD_FDISC || 9402 9403 *pcmd == ELS_CMD_LOGO || 9403 9404 *pcmd == ELS_CMD_PLOGI)) {