diff options
author | James Smart <james.smart@emulex.com> | 2010-02-26 14:15:29 -0500 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2010-03-03 08:39:52 -0500 |
commit | fc2b989be9190f3311a5ae41289828e24897a20e (patch) | |
tree | 86de4a9129f003697819af1e5aa5d83eae683b4b /drivers/scsi/lpfc/lpfc_init.c | |
parent | e2aed29f29d0d289df3b0b627b122832d4dc80fe (diff) |
[SCSI] lpfc 8.3.10: Fix Discovery issues
- Prevent Vport discovery after reg_new_vport completes when physical
logged in using FDISC.
- Remove fast FCF failover fabric name matching. Allow failover to FCFs
connected to different fabrics.
- Added fast FCF failover in response to FCF DEAD event on current
FCF record.
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_init.c')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_init.c | 140 |
1 files changed, 111 insertions, 29 deletions
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 88e02a453e0e..ff45e336917a 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c | |||
@@ -2199,8 +2199,10 @@ lpfc_stop_vport_timers(struct lpfc_vport *vport) | |||
2199 | void | 2199 | void |
2200 | __lpfc_sli4_stop_fcf_redisc_wait_timer(struct lpfc_hba *phba) | 2200 | __lpfc_sli4_stop_fcf_redisc_wait_timer(struct lpfc_hba *phba) |
2201 | { | 2201 | { |
2202 | /* Clear pending FCF rediscovery wait timer */ | 2202 | /* Clear pending FCF rediscovery wait and failover in progress flags */ |
2203 | phba->fcf.fcf_flag &= ~FCF_REDISC_PEND; | 2203 | phba->fcf.fcf_flag &= ~(FCF_REDISC_PEND | |
2204 | FCF_DEAD_FOVER | | ||
2205 | FCF_CVL_FOVER); | ||
2204 | /* Now, try to stop the timer */ | 2206 | /* Now, try to stop the timer */ |
2205 | del_timer(&phba->fcf.redisc_wait); | 2207 | del_timer(&phba->fcf.redisc_wait); |
2206 | } | 2208 | } |
@@ -3212,6 +3214,68 @@ out_free_pmb: | |||
3212 | } | 3214 | } |
3213 | 3215 | ||
3214 | /** | 3216 | /** |
3217 | * lpfc_sli4_perform_vport_cvl - Perform clear virtual link on a vport | ||
3218 | * @vport: pointer to vport data structure. | ||
3219 | * | ||
3220 | * This routine is to perform Clear Virtual Link (CVL) on a vport in | ||
3221 | * response to a CVL event. | ||
3222 | * | ||
3223 | * Return the pointer to the ndlp with the vport if successful, otherwise | ||
3224 | * return NULL. | ||
3225 | **/ | ||
3226 | static struct lpfc_nodelist * | ||
3227 | lpfc_sli4_perform_vport_cvl(struct lpfc_vport *vport) | ||
3228 | { | ||
3229 | struct lpfc_nodelist *ndlp; | ||
3230 | struct Scsi_Host *shost; | ||
3231 | struct lpfc_hba *phba; | ||
3232 | |||
3233 | if (!vport) | ||
3234 | return NULL; | ||
3235 | ndlp = lpfc_findnode_did(vport, Fabric_DID); | ||
3236 | if (!ndlp) | ||
3237 | return NULL; | ||
3238 | phba = vport->phba; | ||
3239 | if (!phba) | ||
3240 | return NULL; | ||
3241 | if (phba->pport->port_state <= LPFC_FLOGI) | ||
3242 | return NULL; | ||
3243 | /* If virtual link is not yet instantiated ignore CVL */ | ||
3244 | if (vport->port_state <= LPFC_FDISC) | ||
3245 | return NULL; | ||
3246 | shost = lpfc_shost_from_vport(vport); | ||
3247 | if (!shost) | ||
3248 | return NULL; | ||
3249 | lpfc_linkdown_port(vport); | ||
3250 | lpfc_cleanup_pending_mbox(vport); | ||
3251 | spin_lock_irq(shost->host_lock); | ||
3252 | vport->fc_flag |= FC_VPORT_CVL_RCVD; | ||
3253 | spin_unlock_irq(shost->host_lock); | ||
3254 | |||
3255 | return ndlp; | ||
3256 | } | ||
3257 | |||
3258 | /** | ||
3259 | * lpfc_sli4_perform_all_vport_cvl - Perform clear virtual link on all vports | ||
3260 | * @vport: pointer to lpfc hba data structure. | ||
3261 | * | ||
3262 | * This routine is to perform Clear Virtual Link (CVL) on all vports in | ||
3263 | * response to a FCF dead event. | ||
3264 | **/ | ||
3265 | static void | ||
3266 | lpfc_sli4_perform_all_vport_cvl(struct lpfc_hba *phba) | ||
3267 | { | ||
3268 | struct lpfc_vport **vports; | ||
3269 | int i; | ||
3270 | |||
3271 | vports = lpfc_create_vport_work_array(phba); | ||
3272 | if (vports) | ||
3273 | for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) | ||
3274 | lpfc_sli4_perform_vport_cvl(vports[i]); | ||
3275 | lpfc_destroy_vport_work_array(phba, vports); | ||
3276 | } | ||
3277 | |||
3278 | /** | ||
3215 | * lpfc_sli4_async_fcoe_evt - Process the asynchronous fcoe event | 3279 | * lpfc_sli4_async_fcoe_evt - Process the asynchronous fcoe event |
3216 | * @phba: pointer to lpfc hba data structure. | 3280 | * @phba: pointer to lpfc hba data structure. |
3217 | * @acqe_link: pointer to the async fcoe completion queue entry. | 3281 | * @acqe_link: pointer to the async fcoe completion queue entry. |
@@ -3227,7 +3291,6 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba, | |||
3227 | struct lpfc_vport *vport; | 3291 | struct lpfc_vport *vport; |
3228 | struct lpfc_nodelist *ndlp; | 3292 | struct lpfc_nodelist *ndlp; |
3229 | struct Scsi_Host *shost; | 3293 | struct Scsi_Host *shost; |
3230 | uint32_t link_state; | ||
3231 | int active_vlink_present; | 3294 | int active_vlink_present; |
3232 | struct lpfc_vport **vports; | 3295 | struct lpfc_vport **vports; |
3233 | int i; | 3296 | int i; |
@@ -3284,16 +3347,35 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba, | |||
3284 | /* If the event is not for currently used fcf do nothing */ | 3347 | /* If the event is not for currently used fcf do nothing */ |
3285 | if (phba->fcf.current_rec.fcf_indx != acqe_fcoe->index) | 3348 | if (phba->fcf.current_rec.fcf_indx != acqe_fcoe->index) |
3286 | break; | 3349 | break; |
3287 | /* | 3350 | /* We request port to rediscover the entire FCF table for |
3288 | * Currently, driver support only one FCF - so treat this as | 3351 | * a fast recovery from case that the current FCF record |
3289 | * a link down, but save the link state because we don't want | 3352 | * is no longer valid if the last CVL event hasn't already |
3290 | * it to be changed to Link Down unless it is already down. | 3353 | * triggered process. |
3291 | */ | 3354 | */ |
3292 | link_state = phba->link_state; | 3355 | spin_lock_irq(&phba->hbalock); |
3293 | lpfc_linkdown(phba); | 3356 | if (phba->fcf.fcf_flag & FCF_CVL_FOVER) { |
3294 | phba->link_state = link_state; | 3357 | spin_unlock_irq(&phba->hbalock); |
3295 | /* Unregister FCF if no devices connected to it */ | 3358 | break; |
3296 | lpfc_unregister_unused_fcf(phba); | 3359 | } |
3360 | /* Mark the fast failover process in progress */ | ||
3361 | phba->fcf.fcf_flag |= FCF_DEAD_FOVER; | ||
3362 | spin_unlock_irq(&phba->hbalock); | ||
3363 | rc = lpfc_sli4_redisc_fcf_table(phba); | ||
3364 | if (rc) { | ||
3365 | spin_lock_irq(&phba->hbalock); | ||
3366 | phba->fcf.fcf_flag &= ~FCF_DEAD_FOVER; | ||
3367 | spin_unlock_irq(&phba->hbalock); | ||
3368 | /* | ||
3369 | * Last resort will fail over by treating this | ||
3370 | * as a link down to FCF registration. | ||
3371 | */ | ||
3372 | lpfc_sli4_fcf_dead_failthrough(phba); | ||
3373 | } else | ||
3374 | /* Handling fast FCF failover to a DEAD FCF event | ||
3375 | * is considered equalivant to receiving CVL to all | ||
3376 | * vports. | ||
3377 | */ | ||
3378 | lpfc_sli4_perform_all_vport_cvl(phba); | ||
3297 | break; | 3379 | break; |
3298 | case LPFC_FCOE_EVENT_TYPE_CVL: | 3380 | case LPFC_FCOE_EVENT_TYPE_CVL: |
3299 | lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, | 3381 | lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, |
@@ -3301,23 +3383,9 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba, | |||
3301 | " tag 0x%x\n", acqe_fcoe->index, acqe_fcoe->event_tag); | 3383 | " tag 0x%x\n", acqe_fcoe->index, acqe_fcoe->event_tag); |
3302 | vport = lpfc_find_vport_by_vpid(phba, | 3384 | vport = lpfc_find_vport_by_vpid(phba, |
3303 | acqe_fcoe->index - phba->vpi_base); | 3385 | acqe_fcoe->index - phba->vpi_base); |
3304 | if (!vport) | 3386 | ndlp = lpfc_sli4_perform_vport_cvl(vport); |
3305 | break; | ||
3306 | ndlp = lpfc_findnode_did(vport, Fabric_DID); | ||
3307 | if (!ndlp) | 3387 | if (!ndlp) |
3308 | break; | 3388 | break; |
3309 | shost = lpfc_shost_from_vport(vport); | ||
3310 | if (phba->pport->port_state <= LPFC_FLOGI) | ||
3311 | break; | ||
3312 | /* If virtual link is not yet instantiated ignore CVL */ | ||
3313 | if (vport->port_state <= LPFC_FDISC) | ||
3314 | break; | ||
3315 | |||
3316 | lpfc_linkdown_port(vport); | ||
3317 | lpfc_cleanup_pending_mbox(vport); | ||
3318 | spin_lock_irq(shost->host_lock); | ||
3319 | vport->fc_flag |= FC_VPORT_CVL_RCVD; | ||
3320 | spin_unlock_irq(shost->host_lock); | ||
3321 | active_vlink_present = 0; | 3389 | active_vlink_present = 0; |
3322 | 3390 | ||
3323 | vports = lpfc_create_vport_work_array(phba); | 3391 | vports = lpfc_create_vport_work_array(phba); |
@@ -3340,6 +3408,7 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba, | |||
3340 | * re-instantiate the Vlink using FDISC. | 3408 | * re-instantiate the Vlink using FDISC. |
3341 | */ | 3409 | */ |
3342 | mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ); | 3410 | mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ); |
3411 | shost = lpfc_shost_from_vport(vport); | ||
3343 | spin_lock_irq(shost->host_lock); | 3412 | spin_lock_irq(shost->host_lock); |
3344 | ndlp->nlp_flag |= NLP_DELAY_TMO; | 3413 | ndlp->nlp_flag |= NLP_DELAY_TMO; |
3345 | spin_unlock_irq(shost->host_lock); | 3414 | spin_unlock_irq(shost->host_lock); |
@@ -3350,15 +3419,28 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba, | |||
3350 | * Otherwise, we request port to rediscover | 3419 | * Otherwise, we request port to rediscover |
3351 | * the entire FCF table for a fast recovery | 3420 | * the entire FCF table for a fast recovery |
3352 | * from possible case that the current FCF | 3421 | * from possible case that the current FCF |
3353 | * is no longer valid. | 3422 | * is no longer valid if the FCF_DEAD event |
3423 | * hasn't already triggered process. | ||
3354 | */ | 3424 | */ |
3425 | spin_lock_irq(&phba->hbalock); | ||
3426 | if (phba->fcf.fcf_flag & FCF_DEAD_FOVER) { | ||
3427 | spin_unlock_irq(&phba->hbalock); | ||
3428 | break; | ||
3429 | } | ||
3430 | /* Mark the fast failover process in progress */ | ||
3431 | phba->fcf.fcf_flag |= FCF_CVL_FOVER; | ||
3432 | spin_unlock_irq(&phba->hbalock); | ||
3355 | rc = lpfc_sli4_redisc_fcf_table(phba); | 3433 | rc = lpfc_sli4_redisc_fcf_table(phba); |
3356 | if (rc) | 3434 | if (rc) { |
3435 | spin_lock_irq(&phba->hbalock); | ||
3436 | phba->fcf.fcf_flag &= ~FCF_CVL_FOVER; | ||
3437 | spin_unlock_irq(&phba->hbalock); | ||
3357 | /* | 3438 | /* |
3358 | * Last resort will be re-try on the | 3439 | * Last resort will be re-try on the |
3359 | * the current registered FCF entry. | 3440 | * the current registered FCF entry. |
3360 | */ | 3441 | */ |
3361 | lpfc_retry_pport_discovery(phba); | 3442 | lpfc_retry_pport_discovery(phba); |
3443 | } | ||
3362 | } | 3444 | } |
3363 | break; | 3445 | break; |
3364 | default: | 3446 | default: |