aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/lpfc/lpfc_els.c
diff options
context:
space:
mode:
authorJames Smart <james.smart@emulex.com>2011-02-16 12:39:44 -0500
committerJames Bottomley <James.Bottomley@suse.de>2011-02-18 13:47:20 -0500
commit924941444b481fc862b2de5e1dd7692ca85274d7 (patch)
tree4a19d10d1e8803f3662b93d615c35a474b3d8328 /drivers/scsi/lpfc/lpfc_els.c
parent1151e3ec15c32021a8a12a123459ab5e41692898 (diff)
[SCSI] lpfc 8.3.21: FC Discovery changes
FC Discovery changes - Treat received PLOGI while logged in as a relogin (unregister and reregister). - Added a timer to delay Nport discovery when clean bit is cleared and Fabric portname/nodename/FCID is changed. - Invalidate Port's DID when receiving PLOGI from p2p port with CONFIG_PORT mailbox command. Signed-off-by: Alex Iannicelli <alex.iannicelli@emulex.com> Signed-off-by: James Smart <james.smart@emulex.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_els.c')
-rw-r--r--drivers/scsi/lpfc/lpfc_els.c118
1 files changed, 115 insertions, 3 deletions
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index c6d01f63f557..8e28edf9801e 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -1,7 +1,7 @@
1/******************************************************************* 1/*******************************************************************
2 * This file is part of the Emulex Linux Device Driver for * 2 * This file is part of the Emulex Linux Device Driver for *
3 * Fibre Channel Host Bus Adapters. * 3 * Fibre Channel Host Bus Adapters. *
4 * Copyright (C) 2004-2009 Emulex. All rights reserved. * 4 * Copyright (C) 2004-2011 Emulex. All rights reserved. *
5 * EMULEX and SLI are trademarks of Emulex. * 5 * EMULEX and SLI are trademarks of Emulex. *
6 * www.emulex.com * 6 * www.emulex.com *
7 * Portions Copyright (C) 2004-2005 Christoph Hellwig * 7 * Portions Copyright (C) 2004-2005 Christoph Hellwig *
@@ -485,6 +485,59 @@ fail:
485} 485}
486 486
487/** 487/**
488 * lpfc_check_clean_addr_bit - Check whether assigned FCID is clean.
489 * @vport: pointer to a host virtual N_Port data structure.
490 * @sp: pointer to service parameter data structure.
491 *
492 * This routine is called from FLOGI/FDISC completion handler functions.
493 * lpfc_check_clean_addr_bit return 1 when FCID/Fabric portname/ Fabric
494 * node nodename is changed in the completion service parameter else return
495 * 0. This function also set flag in the vport data structure to delay
496 * NP_Port discovery after the FLOGI/FDISC completion if Clean address bit
497 * in FLOGI/FDISC response is cleared and FCID/Fabric portname/ Fabric
498 * node nodename is changed in the completion service parameter.
499 *
500 * Return code
501 * 0 - FCID and Fabric Nodename and Fabric portname is not changed.
502 * 1 - FCID or Fabric Nodename or Fabric portname is changed.
503 *
504 **/
505static uint8_t
506lpfc_check_clean_addr_bit(struct lpfc_vport *vport,
507 struct serv_parm *sp)
508{
509 uint8_t fabric_param_changed = 0;
510 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
511
512 if ((vport->fc_prevDID != vport->fc_myDID) ||
513 memcmp(&vport->fabric_portname, &sp->portName,
514 sizeof(struct lpfc_name)) ||
515 memcmp(&vport->fabric_nodename, &sp->nodeName,
516 sizeof(struct lpfc_name)))
517 fabric_param_changed = 1;
518
519 /*
520 * Word 1 Bit 31 in common service parameter is overloaded.
521 * Word 1 Bit 31 in FLOGI request is multiple NPort request
522 * Word 1 Bit 31 in FLOGI response is clean address bit
523 *
524 * If fabric parameter is changed and clean address bit is
525 * cleared delay nport discovery if
526 * - vport->fc_prevDID != 0 (not initial discovery) OR
527 * - lpfc_delay_discovery module parameter is set.
528 */
529 if (fabric_param_changed && !sp->cmn.clean_address_bit &&
530 (vport->fc_prevDID || lpfc_delay_discovery)) {
531 spin_lock_irq(shost->host_lock);
532 vport->fc_flag |= FC_DISC_DELAYED;
533 spin_unlock_irq(shost->host_lock);
534 }
535
536 return fabric_param_changed;
537}
538
539
540/**
488 * lpfc_cmpl_els_flogi_fabric - Completion function for flogi to a fabric port 541 * lpfc_cmpl_els_flogi_fabric - Completion function for flogi to a fabric port
489 * @vport: pointer to a host virtual N_Port data structure. 542 * @vport: pointer to a host virtual N_Port data structure.
490 * @ndlp: pointer to a node-list data structure. 543 * @ndlp: pointer to a node-list data structure.
@@ -512,6 +565,7 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
512 struct lpfc_hba *phba = vport->phba; 565 struct lpfc_hba *phba = vport->phba;
513 struct lpfc_nodelist *np; 566 struct lpfc_nodelist *np;
514 struct lpfc_nodelist *next_np; 567 struct lpfc_nodelist *next_np;
568 uint8_t fabric_param_changed;
515 569
516 spin_lock_irq(shost->host_lock); 570 spin_lock_irq(shost->host_lock);
517 vport->fc_flag |= FC_FABRIC; 571 vport->fc_flag |= FC_FABRIC;
@@ -544,6 +598,12 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
544 ndlp->nlp_class_sup |= FC_COS_CLASS4; 598 ndlp->nlp_class_sup |= FC_COS_CLASS4;
545 ndlp->nlp_maxframe = ((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) | 599 ndlp->nlp_maxframe = ((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) |
546 sp->cmn.bbRcvSizeLsb; 600 sp->cmn.bbRcvSizeLsb;
601
602 fabric_param_changed = lpfc_check_clean_addr_bit(vport, sp);
603 memcpy(&vport->fabric_portname, &sp->portName,
604 sizeof(struct lpfc_name));
605 memcpy(&vport->fabric_nodename, &sp->nodeName,
606 sizeof(struct lpfc_name));
547 memcpy(&phba->fc_fabparam, sp, sizeof(struct serv_parm)); 607 memcpy(&phba->fc_fabparam, sp, sizeof(struct serv_parm));
548 608
549 if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) { 609 if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
@@ -565,7 +625,7 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
565 } 625 }
566 } 626 }
567 627
568 if ((vport->fc_prevDID != vport->fc_myDID) && 628 if (fabric_param_changed &&
569 !(vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)) { 629 !(vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)) {
570 630
571 /* If our NportID changed, we need to ensure all 631 /* If our NportID changed, we need to ensure all
@@ -2203,6 +2263,7 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
2203 struct Scsi_Host *shost = lpfc_shost_from_vport(vport); 2263 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
2204 IOCB_t *irsp; 2264 IOCB_t *irsp;
2205 struct lpfc_sli *psli; 2265 struct lpfc_sli *psli;
2266 struct lpfcMboxq *mbox;
2206 2267
2207 psli = &phba->sli; 2268 psli = &phba->sli;
2208 /* we pass cmdiocb to state machine which needs rspiocb as well */ 2269 /* we pass cmdiocb to state machine which needs rspiocb as well */
@@ -2260,6 +2321,21 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
2260 NLP_EVT_CMPL_LOGO); 2321 NLP_EVT_CMPL_LOGO);
2261out: 2322out:
2262 lpfc_els_free_iocb(phba, cmdiocb); 2323 lpfc_els_free_iocb(phba, cmdiocb);
2324 /* If we are in pt2pt mode, we could rcv new S_ID on PLOGI */
2325 if ((vport->fc_flag & FC_PT2PT) &&
2326 !(vport->fc_flag & FC_PT2PT_PLOGI)) {
2327 phba->pport->fc_myDID = 0;
2328 mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
2329 if (mbox) {
2330 lpfc_config_link(phba, mbox);
2331 mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
2332 mbox->vport = vport;
2333 if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT) ==
2334 MBX_NOT_FINISHED) {
2335 mempool_free(mbox, phba->mbox_mem_pool);
2336 }
2337 }
2338 }
2263 return; 2339 return;
2264} 2340}
2265 2341
@@ -6181,6 +6257,11 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
6181 if (vport->load_flag & FC_UNLOADING) 6257 if (vport->load_flag & FC_UNLOADING)
6182 goto dropit; 6258 goto dropit;
6183 6259
6260 /* If NPort discovery is delayed drop incoming ELS */
6261 if ((vport->fc_flag & FC_DISC_DELAYED) &&
6262 (cmd != ELS_CMD_PLOGI))
6263 goto dropit;
6264
6184 ndlp = lpfc_findnode_did(vport, did); 6265 ndlp = lpfc_findnode_did(vport, did);
6185 if (!ndlp) { 6266 if (!ndlp) {
6186 /* Cannot find existing Fabric ndlp, so allocate a new one */ 6267 /* Cannot find existing Fabric ndlp, so allocate a new one */
@@ -6233,6 +6314,12 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
6233 ndlp = lpfc_plogi_confirm_nport(phba, payload, ndlp); 6314 ndlp = lpfc_plogi_confirm_nport(phba, payload, ndlp);
6234 6315
6235 lpfc_send_els_event(vport, ndlp, payload); 6316 lpfc_send_els_event(vport, ndlp, payload);
6317
6318 /* If Nport discovery is delayed, reject PLOGIs */
6319 if (vport->fc_flag & FC_DISC_DELAYED) {
6320 rjt_err = LSRJT_UNABLE_TPC;
6321 break;
6322 }
6236 if (vport->port_state < LPFC_DISC_AUTH) { 6323 if (vport->port_state < LPFC_DISC_AUTH) {
6237 if (!(phba->pport->fc_flag & FC_PT2PT) || 6324 if (!(phba->pport->fc_flag & FC_PT2PT) ||
6238 (phba->pport->fc_flag & FC_PT2PT_PLOGI)) { 6325 (phba->pport->fc_flag & FC_PT2PT_PLOGI)) {
@@ -6611,6 +6698,21 @@ void
6611lpfc_do_scr_ns_plogi(struct lpfc_hba *phba, struct lpfc_vport *vport) 6698lpfc_do_scr_ns_plogi(struct lpfc_hba *phba, struct lpfc_vport *vport)
6612{ 6699{
6613 struct lpfc_nodelist *ndlp, *ndlp_fdmi; 6700 struct lpfc_nodelist *ndlp, *ndlp_fdmi;
6701 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
6702
6703 /*
6704 * If lpfc_delay_discovery parameter is set and the clean address
6705 * bit is cleared and fc fabric parameters chenged, delay FC NPort
6706 * discovery.
6707 */
6708 spin_lock_irq(shost->host_lock);
6709 if (vport->fc_flag & FC_DISC_DELAYED) {
6710 spin_unlock_irq(shost->host_lock);
6711 mod_timer(&vport->delayed_disc_tmo,
6712 jiffies + HZ * phba->fc_ratov);
6713 return;
6714 }
6715 spin_unlock_irq(shost->host_lock);
6614 6716
6615 ndlp = lpfc_findnode_did(vport, NameServer_DID); 6717 ndlp = lpfc_findnode_did(vport, NameServer_DID);
6616 if (!ndlp) { 6718 if (!ndlp) {
@@ -6953,6 +7055,9 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
6953 struct lpfc_nodelist *next_np; 7055 struct lpfc_nodelist *next_np;
6954 IOCB_t *irsp = &rspiocb->iocb; 7056 IOCB_t *irsp = &rspiocb->iocb;
6955 struct lpfc_iocbq *piocb; 7057 struct lpfc_iocbq *piocb;
7058 struct lpfc_dmabuf *pcmd = cmdiocb->context2, *prsp;
7059 struct serv_parm *sp;
7060 uint8_t fabric_param_changed;
6956 7061
6957 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, 7062 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
6958 "0123 FDISC completes. x%x/x%x prevDID: x%x\n", 7063 "0123 FDISC completes. x%x/x%x prevDID: x%x\n",
@@ -6996,7 +7101,14 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
6996 7101
6997 vport->fc_myDID = irsp->un.ulpWord[4] & Mask_DID; 7102 vport->fc_myDID = irsp->un.ulpWord[4] & Mask_DID;
6998 lpfc_vport_set_state(vport, FC_VPORT_ACTIVE); 7103 lpfc_vport_set_state(vport, FC_VPORT_ACTIVE);
6999 if ((vport->fc_prevDID != vport->fc_myDID) && 7104 prsp = list_get_first(&pcmd->list, struct lpfc_dmabuf, list);
7105 sp = prsp->virt + sizeof(uint32_t);
7106 fabric_param_changed = lpfc_check_clean_addr_bit(vport, sp);
7107 memcpy(&vport->fabric_portname, &sp->portName,
7108 sizeof(struct lpfc_name));
7109 memcpy(&vport->fabric_nodename, &sp->nodeName,
7110 sizeof(struct lpfc_name));
7111 if (fabric_param_changed &&
7000 !(vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)) { 7112 !(vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)) {
7001 /* If our NportID changed, we need to ensure all 7113 /* If our NportID changed, we need to ensure all
7002 * remaining NPORTs get unreg_login'ed so we can 7114 * remaining NPORTs get unreg_login'ed so we can