diff options
-rw-r--r-- | drivers/scsi/lpfc/lpfc.h | 5 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_attr.c | 21 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_crtn.h | 3 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_ct.c | 49 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_els.c | 118 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_hbadisc.c | 7 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_hw.h | 6 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_init.c | 6 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_nportdisc.c | 11 |
9 files changed, 219 insertions, 7 deletions
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index b388e436c687..e2a763426a7c 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h | |||
@@ -325,6 +325,7 @@ struct lpfc_vport { | |||
325 | #define FC_VPORT_CVL_RCVD 0x400000 /* VLink failed due to CVL */ | 325 | #define FC_VPORT_CVL_RCVD 0x400000 /* VLink failed due to CVL */ |
326 | #define FC_VFI_REGISTERED 0x800000 /* VFI is registered */ | 326 | #define FC_VFI_REGISTERED 0x800000 /* VFI is registered */ |
327 | #define FC_FDISC_COMPLETED 0x1000000/* FDISC completed */ | 327 | #define FC_FDISC_COMPLETED 0x1000000/* FDISC completed */ |
328 | #define FC_DISC_DELAYED 0x2000000/* Delay NPort discovery */ | ||
328 | 329 | ||
329 | uint32_t ct_flags; | 330 | uint32_t ct_flags; |
330 | #define FC_CT_RFF_ID 0x1 /* RFF_ID accepted by switch */ | 331 | #define FC_CT_RFF_ID 0x1 /* RFF_ID accepted by switch */ |
@@ -348,6 +349,8 @@ struct lpfc_vport { | |||
348 | 349 | ||
349 | uint32_t fc_myDID; /* fibre channel S_ID */ | 350 | uint32_t fc_myDID; /* fibre channel S_ID */ |
350 | uint32_t fc_prevDID; /* previous fibre channel S_ID */ | 351 | uint32_t fc_prevDID; /* previous fibre channel S_ID */ |
352 | struct lpfc_name fabric_portname; | ||
353 | struct lpfc_name fabric_nodename; | ||
351 | 354 | ||
352 | int32_t stopped; /* HBA has not been restarted since last ERATT */ | 355 | int32_t stopped; /* HBA has not been restarted since last ERATT */ |
353 | uint8_t fc_linkspeed; /* Link speed after last READ_LA */ | 356 | uint8_t fc_linkspeed; /* Link speed after last READ_LA */ |
@@ -372,6 +375,7 @@ struct lpfc_vport { | |||
372 | #define WORKER_DISC_TMO 0x1 /* vport: Discovery timeout */ | 375 | #define WORKER_DISC_TMO 0x1 /* vport: Discovery timeout */ |
373 | #define WORKER_ELS_TMO 0x2 /* vport: ELS timeout */ | 376 | #define WORKER_ELS_TMO 0x2 /* vport: ELS timeout */ |
374 | #define WORKER_FDMI_TMO 0x4 /* vport: FDMI timeout */ | 377 | #define WORKER_FDMI_TMO 0x4 /* vport: FDMI timeout */ |
378 | #define WORKER_DELAYED_DISC_TMO 0x8 /* vport: delayed discovery */ | ||
375 | 379 | ||
376 | #define WORKER_MBOX_TMO 0x100 /* hba: MBOX timeout */ | 380 | #define WORKER_MBOX_TMO 0x100 /* hba: MBOX timeout */ |
377 | #define WORKER_HB_TMO 0x200 /* hba: Heart beat timeout */ | 381 | #define WORKER_HB_TMO 0x200 /* hba: Heart beat timeout */ |
@@ -382,6 +386,7 @@ struct lpfc_vport { | |||
382 | 386 | ||
383 | struct timer_list fc_fdmitmo; | 387 | struct timer_list fc_fdmitmo; |
384 | struct timer_list els_tmofunc; | 388 | struct timer_list els_tmofunc; |
389 | struct timer_list delayed_disc_tmo; | ||
385 | 390 | ||
386 | int unreg_vpi_cmpl; | 391 | int unreg_vpi_cmpl; |
387 | 392 | ||
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 745774c5a4be..a57f6c0cbbba 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.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 * |
@@ -3365,6 +3365,25 @@ unsigned char lpfc_prot_guard = SHOST_DIX_GUARD_IP; | |||
3365 | module_param(lpfc_prot_guard, byte, 0); | 3365 | module_param(lpfc_prot_guard, byte, 0); |
3366 | MODULE_PARM_DESC(lpfc_prot_guard, "host protection guard type"); | 3366 | MODULE_PARM_DESC(lpfc_prot_guard, "host protection guard type"); |
3367 | 3367 | ||
3368 | /* | ||
3369 | * Delay initial NPort discovery when Clean Address bit is cleared in | ||
3370 | * FLOGI/FDISC accept and FCID/Fabric name/Fabric portname is changed. | ||
3371 | * This parameter can have value 0 or 1. | ||
3372 | * When this parameter is set to 0, no delay is added to the initial | ||
3373 | * discovery. | ||
3374 | * When this parameter is set to non-zero value, initial Nport discovery is | ||
3375 | * delayed by ra_tov seconds when Clean Address bit is cleared in FLOGI/FDISC | ||
3376 | * accept and FCID/Fabric name/Fabric portname is changed. | ||
3377 | * Driver always delay Nport discovery for subsequent FLOGI/FDISC completion | ||
3378 | * when Clean Address bit is cleared in FLOGI/FDISC | ||
3379 | * accept and FCID/Fabric name/Fabric portname is changed. | ||
3380 | * Default value is 0. | ||
3381 | */ | ||
3382 | int lpfc_delay_discovery; | ||
3383 | module_param(lpfc_delay_discovery, int, 0); | ||
3384 | MODULE_PARM_DESC(lpfc_delay_discovery, | ||
3385 | "Delay NPort discovery when Clean Address bit is cleared. " | ||
3386 | "Allowed values: 0,1."); | ||
3368 | 3387 | ||
3369 | /* | 3388 | /* |
3370 | * lpfc_sg_seg_cnt - Initial Maximum DMA Segment Count | 3389 | * lpfc_sg_seg_cnt - Initial Maximum DMA Segment Count |
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 34fbc1820c40..3d40023f4804 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h | |||
@@ -167,6 +167,8 @@ int lpfc_ns_cmd(struct lpfc_vport *, int, uint8_t, uint32_t); | |||
167 | int lpfc_fdmi_cmd(struct lpfc_vport *, struct lpfc_nodelist *, int); | 167 | int lpfc_fdmi_cmd(struct lpfc_vport *, struct lpfc_nodelist *, int); |
168 | void lpfc_fdmi_tmo(unsigned long); | 168 | void lpfc_fdmi_tmo(unsigned long); |
169 | void lpfc_fdmi_timeout_handler(struct lpfc_vport *); | 169 | void lpfc_fdmi_timeout_handler(struct lpfc_vport *); |
170 | void lpfc_delayed_disc_tmo(unsigned long); | ||
171 | void lpfc_delayed_disc_timeout_handler(struct lpfc_vport *); | ||
170 | 172 | ||
171 | int lpfc_config_port_prep(struct lpfc_hba *); | 173 | int lpfc_config_port_prep(struct lpfc_hba *); |
172 | int lpfc_config_port_post(struct lpfc_hba *); | 174 | int lpfc_config_port_post(struct lpfc_hba *); |
@@ -341,6 +343,7 @@ extern struct fc_function_template lpfc_transport_functions; | |||
341 | extern struct fc_function_template lpfc_vport_transport_functions; | 343 | extern struct fc_function_template lpfc_vport_transport_functions; |
342 | extern int lpfc_sli_mode; | 344 | extern int lpfc_sli_mode; |
343 | extern int lpfc_enable_npiv; | 345 | extern int lpfc_enable_npiv; |
346 | extern int lpfc_delay_discovery; | ||
344 | 347 | ||
345 | int lpfc_vport_symbolic_node_name(struct lpfc_vport *, char *, size_t); | 348 | int lpfc_vport_symbolic_node_name(struct lpfc_vport *, char *, size_t); |
346 | int lpfc_vport_symbolic_port_name(struct lpfc_vport *, char *, size_t); | 349 | int lpfc_vport_symbolic_port_name(struct lpfc_vport *, char *, size_t); |
diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index c004fa9a681e..d9edfd90d7ff 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c | |||
@@ -1738,6 +1738,55 @@ fdmi_cmd_exit: | |||
1738 | return 1; | 1738 | return 1; |
1739 | } | 1739 | } |
1740 | 1740 | ||
1741 | /** | ||
1742 | * lpfc_delayed_disc_tmo - Timeout handler for delayed discovery timer. | ||
1743 | * @ptr - Context object of the timer. | ||
1744 | * | ||
1745 | * This function set the WORKER_DELAYED_DISC_TMO flag and wake up | ||
1746 | * the worker thread. | ||
1747 | **/ | ||
1748 | void | ||
1749 | lpfc_delayed_disc_tmo(unsigned long ptr) | ||
1750 | { | ||
1751 | struct lpfc_vport *vport = (struct lpfc_vport *)ptr; | ||
1752 | struct lpfc_hba *phba = vport->phba; | ||
1753 | uint32_t tmo_posted; | ||
1754 | unsigned long iflag; | ||
1755 | |||
1756 | spin_lock_irqsave(&vport->work_port_lock, iflag); | ||
1757 | tmo_posted = vport->work_port_events & WORKER_DELAYED_DISC_TMO; | ||
1758 | if (!tmo_posted) | ||
1759 | vport->work_port_events |= WORKER_DELAYED_DISC_TMO; | ||
1760 | spin_unlock_irqrestore(&vport->work_port_lock, iflag); | ||
1761 | |||
1762 | if (!tmo_posted) | ||
1763 | lpfc_worker_wake_up(phba); | ||
1764 | return; | ||
1765 | } | ||
1766 | |||
1767 | /** | ||
1768 | * lpfc_delayed_disc_timeout_handler - Function called by worker thread to | ||
1769 | * handle delayed discovery. | ||
1770 | * @vport: pointer to a host virtual N_Port data structure. | ||
1771 | * | ||
1772 | * This function start nport discovery of the vport. | ||
1773 | **/ | ||
1774 | void | ||
1775 | lpfc_delayed_disc_timeout_handler(struct lpfc_vport *vport) | ||
1776 | { | ||
1777 | struct Scsi_Host *shost = lpfc_shost_from_vport(vport); | ||
1778 | |||
1779 | spin_lock_irq(shost->host_lock); | ||
1780 | if (!(vport->fc_flag & FC_DISC_DELAYED)) { | ||
1781 | spin_unlock_irq(shost->host_lock); | ||
1782 | return; | ||
1783 | } | ||
1784 | vport->fc_flag &= ~FC_DISC_DELAYED; | ||
1785 | spin_unlock_irq(shost->host_lock); | ||
1786 | |||
1787 | lpfc_do_scr_ns_plogi(vport->phba, vport); | ||
1788 | } | ||
1789 | |||
1741 | void | 1790 | void |
1742 | lpfc_fdmi_tmo(unsigned long ptr) | 1791 | lpfc_fdmi_tmo(unsigned long ptr) |
1743 | { | 1792 | { |
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 |
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 63300be2e45b..154c715fb3af 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c | |||
@@ -658,6 +658,8 @@ lpfc_work_done(struct lpfc_hba *phba) | |||
658 | lpfc_ramp_down_queue_handler(phba); | 658 | lpfc_ramp_down_queue_handler(phba); |
659 | if (work_port_events & WORKER_RAMP_UP_QUEUE) | 659 | if (work_port_events & WORKER_RAMP_UP_QUEUE) |
660 | lpfc_ramp_up_queue_handler(phba); | 660 | lpfc_ramp_up_queue_handler(phba); |
661 | if (work_port_events & WORKER_DELAYED_DISC_TMO) | ||
662 | lpfc_delayed_disc_timeout_handler(vport); | ||
661 | } | 663 | } |
662 | lpfc_destroy_vport_work_array(phba, vports); | 664 | lpfc_destroy_vport_work_array(phba, vports); |
663 | 665 | ||
@@ -838,6 +840,11 @@ lpfc_linkdown_port(struct lpfc_vport *vport) | |||
838 | 840 | ||
839 | lpfc_port_link_failure(vport); | 841 | lpfc_port_link_failure(vport); |
840 | 842 | ||
843 | /* Stop delayed Nport discovery */ | ||
844 | spin_lock_irq(shost->host_lock); | ||
845 | vport->fc_flag &= ~FC_DISC_DELAYED; | ||
846 | spin_unlock_irq(shost->host_lock); | ||
847 | del_timer_sync(&vport->delayed_disc_tmo); | ||
841 | } | 848 | } |
842 | 849 | ||
843 | int | 850 | int |
diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index 96ed3ba6ba95..5a4a196baa90 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h | |||
@@ -341,6 +341,12 @@ struct csp { | |||
341 | uint8_t bbCreditMsb; | 341 | uint8_t bbCreditMsb; |
342 | uint8_t bbCreditlsb; /* FC Word 0, byte 3 */ | 342 | uint8_t bbCreditlsb; /* FC Word 0, byte 3 */ |
343 | 343 | ||
344 | /* | ||
345 | * Word 1 Bit 31 in common service parameter is overloaded. | ||
346 | * Word 1 Bit 31 in FLOGI request is multiple NPort request | ||
347 | * Word 1 Bit 31 in FLOGI response is clean address bit | ||
348 | */ | ||
349 | #define clean_address_bit request_multiple_Nport /* Word 1, bit 31 */ | ||
344 | #ifdef __BIG_ENDIAN_BITFIELD | 350 | #ifdef __BIG_ENDIAN_BITFIELD |
345 | uint16_t request_multiple_Nport:1; /* FC Word 1, bit 31 */ | 351 | uint16_t request_multiple_Nport:1; /* FC Word 1, bit 31 */ |
346 | uint16_t randomOffset:1; /* FC Word 1, bit 30 */ | 352 | uint16_t randomOffset:1; /* FC Word 1, bit 30 */ |
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 32cd138f6543..5e84d2a6ada6 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c | |||
@@ -2292,6 +2292,7 @@ lpfc_stop_vport_timers(struct lpfc_vport *vport) | |||
2292 | { | 2292 | { |
2293 | del_timer_sync(&vport->els_tmofunc); | 2293 | del_timer_sync(&vport->els_tmofunc); |
2294 | del_timer_sync(&vport->fc_fdmitmo); | 2294 | del_timer_sync(&vport->fc_fdmitmo); |
2295 | del_timer_sync(&vport->delayed_disc_tmo); | ||
2295 | lpfc_can_disctmo(vport); | 2296 | lpfc_can_disctmo(vport); |
2296 | return; | 2297 | return; |
2297 | } | 2298 | } |
@@ -2733,6 +2734,11 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev) | |||
2733 | init_timer(&vport->els_tmofunc); | 2734 | init_timer(&vport->els_tmofunc); |
2734 | vport->els_tmofunc.function = lpfc_els_timeout; | 2735 | vport->els_tmofunc.function = lpfc_els_timeout; |
2735 | vport->els_tmofunc.data = (unsigned long)vport; | 2736 | vport->els_tmofunc.data = (unsigned long)vport; |
2737 | |||
2738 | init_timer(&vport->delayed_disc_tmo); | ||
2739 | vport->delayed_disc_tmo.function = lpfc_delayed_disc_tmo; | ||
2740 | vport->delayed_disc_tmo.data = (unsigned long)vport; | ||
2741 | |||
2736 | error = scsi_add_host_with_dma(shost, dev, &phba->pcidev->dev); | 2742 | error = scsi_add_host_with_dma(shost, dev, &phba->pcidev->dev); |
2737 | if (error) | 2743 | if (error) |
2738 | goto out_put_shost; | 2744 | goto out_put_shost; |
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index d85a7423a694..52b35159fc35 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c | |||
@@ -350,7 +350,11 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
350 | ndlp->nlp_maxframe = | 350 | ndlp->nlp_maxframe = |
351 | ((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) | sp->cmn.bbRcvSizeLsb; | 351 | ((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) | sp->cmn.bbRcvSizeLsb; |
352 | 352 | ||
353 | /* no need to reg_login if we are already in one of these states */ | 353 | /* |
354 | * Need to unreg_login if we are already in one of these states and | ||
355 | * change to NPR state. This will block the port until after the ACC | ||
356 | * completes and the reg_login is issued and completed. | ||
357 | */ | ||
354 | switch (ndlp->nlp_state) { | 358 | switch (ndlp->nlp_state) { |
355 | case NLP_STE_NPR_NODE: | 359 | case NLP_STE_NPR_NODE: |
356 | if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) | 360 | if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) |
@@ -359,8 +363,9 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
359 | case NLP_STE_PRLI_ISSUE: | 363 | case NLP_STE_PRLI_ISSUE: |
360 | case NLP_STE_UNMAPPED_NODE: | 364 | case NLP_STE_UNMAPPED_NODE: |
361 | case NLP_STE_MAPPED_NODE: | 365 | case NLP_STE_MAPPED_NODE: |
362 | lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, NULL); | 366 | lpfc_unreg_rpi(vport, ndlp); |
363 | return 1; | 367 | ndlp->nlp_prev_state = ndlp->nlp_state; |
368 | lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); | ||
364 | } | 369 | } |
365 | 370 | ||
366 | if ((vport->fc_flag & FC_PT2PT) && | 371 | if ((vport->fc_flag & FC_PT2PT) && |