diff options
author | James Smart <james.smart@emulex.com> | 2011-02-16 12:39:44 -0500 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2011-02-18 13:47:20 -0500 |
commit | 924941444b481fc862b2de5e1dd7692ca85274d7 (patch) | |
tree | 4a19d10d1e8803f3662b93d615c35a474b3d8328 /drivers/scsi/lpfc/lpfc_els.c | |
parent | 1151e3ec15c32021a8a12a123459ab5e41692898 (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.c | 118 |
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 | **/ | ||
505 | static uint8_t | ||
506 | lpfc_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); |
2261 | out: | 2322 | out: |
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 | |||
6611 | lpfc_do_scr_ns_plogi(struct lpfc_hba *phba, struct lpfc_vport *vport) | 6698 | lpfc_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 |