diff options
author | James Smart <James.Smart@Emulex.Com> | 2007-06-17 20:56:39 -0400 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.il.steeleye.com> | 2007-06-17 23:38:11 -0400 |
commit | 858c9f6c19c6f9bf86cbbc64ce0d17c61d6131b8 (patch) | |
tree | 9591b15b4424066023e375ad0aa33fdd37e1c452 /drivers/scsi/lpfc/lpfc_nportdisc.c | |
parent | 92d7f7b0cde3ad2260e7462b40867b57efd49851 (diff) |
[SCSI] lpfc: bug fixes
Following the NPIV support, the following changes have been accumulated
in the testing and qualification of the driver:
- Fix affinity of ELS ring to slow/deferred event processing
- Fix Ring attention masks
- Defer dev_loss_tmo timeout handling to worker thread
- Consolidate link down error classification for better error checking
- Remove unused/deprecated nlp_initiator_tmr timer
- Fix for async scan - move adapter init code back into pci_probe_one
context. Fix async scan interfaces.
- Expand validation of ability to create vports
- Extract VPI resource cnt from firmware
- Tuning of Login/Reject policies to better deal with overwhelmned targets
- Misc ELS and discovery fixes
- Export the npiv_enable attribute to sysfs
- Mailbox handling fix
- Add debugfs support
- A few other small misc fixes:
- wrong return values, double-frees, bad locking
- Added adapter failure heartbeat
Signed-off-by: James Smart <James.Smart@emulex.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_nportdisc.c')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_nportdisc.c | 63 |
1 files changed, 49 insertions, 14 deletions
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index 50a247602a6b..bca2f5c9b4ba 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include "lpfc_logmsg.h" | 36 | #include "lpfc_logmsg.h" |
37 | #include "lpfc_crtn.h" | 37 | #include "lpfc_crtn.h" |
38 | #include "lpfc_vport.h" | 38 | #include "lpfc_vport.h" |
39 | #include "lpfc_debugfs.h" | ||
39 | 40 | ||
40 | 41 | ||
41 | /* Called to verify a rcv'ed ADISC was intended for us. */ | 42 | /* Called to verify a rcv'ed ADISC was intended for us. */ |
@@ -204,11 +205,9 @@ lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) | |||
204 | /* First check the txq */ | 205 | /* First check the txq */ |
205 | spin_lock_irq(&phba->hbalock); | 206 | spin_lock_irq(&phba->hbalock); |
206 | list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) { | 207 | list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) { |
207 | /* Check to see if iocb matches the nport we are looking | 208 | /* Check to see if iocb matches the nport we are looking for */ |
208 | for */ | ||
209 | if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp)) { | 209 | if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp)) { |
210 | /* It matches, so deque and call compl with an | 210 | /* It matches, so deque and call compl with anp error */ |
211 | error */ | ||
212 | list_move_tail(&iocb->list, &completions); | 211 | list_move_tail(&iocb->list, &completions); |
213 | pring->txq_cnt--; | 212 | pring->txq_cnt--; |
214 | } | 213 | } |
@@ -216,8 +215,7 @@ lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) | |||
216 | 215 | ||
217 | /* Next check the txcmplq */ | 216 | /* Next check the txcmplq */ |
218 | list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) { | 217 | list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) { |
219 | /* Check to see if iocb matches the nport we are looking | 218 | /* Check to see if iocb matches the nport we are looking for */ |
220 | for */ | ||
221 | if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp)) { | 219 | if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp)) { |
222 | lpfc_sli_issue_abort_iotag(phba, pring, iocb); | 220 | lpfc_sli_issue_abort_iotag(phba, pring, iocb); |
223 | } | 221 | } |
@@ -282,7 +280,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
282 | stat.un.b.lsRjtRsnCode = LSRJT_LOGICAL_BSY; | 280 | stat.un.b.lsRjtRsnCode = LSRJT_LOGICAL_BSY; |
283 | stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE; | 281 | stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE; |
284 | lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, | 282 | lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, |
285 | ndlp); | 283 | ndlp, NULL); |
286 | return 0; | 284 | return 0; |
287 | } | 285 | } |
288 | } | 286 | } |
@@ -293,7 +291,8 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
293 | /* Reject this request because invalid parameters */ | 291 | /* Reject this request because invalid parameters */ |
294 | stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; | 292 | stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; |
295 | stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS; | 293 | stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS; |
296 | lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp); | 294 | lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, |
295 | NULL); | ||
297 | return 0; | 296 | return 0; |
298 | } | 297 | } |
299 | icmd = &cmdiocb->iocb; | 298 | icmd = &cmdiocb->iocb; |
@@ -392,13 +391,30 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
392 | lpfc_els_abort(phba, ndlp); | 391 | lpfc_els_abort(phba, ndlp); |
393 | } | 392 | } |
394 | 393 | ||
394 | if ((vport->port_type == LPFC_NPIV_PORT && | ||
395 | phba->cfg_vport_restrict_login)) { | ||
396 | |||
397 | /* In order to preserve RPIs, we want to cleanup | ||
398 | * the default RPI the firmware created to rcv | ||
399 | * this ELS request. The only way to do this is | ||
400 | * to register, then unregister the RPI. | ||
401 | */ | ||
402 | spin_lock_irq(shost->host_lock); | ||
403 | ndlp->nlp_flag |= NLP_RM_DFLT_RPI; | ||
404 | spin_unlock_irq(shost->host_lock); | ||
405 | stat.un.b.lsRjtRsnCode = LSRJT_INVALID_CMD; | ||
406 | stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE; | ||
407 | lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, | ||
408 | ndlp, mbox); | ||
409 | return 1; | ||
410 | } | ||
395 | lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, mbox, 0); | 411 | lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, mbox, 0); |
396 | return 1; | 412 | return 1; |
397 | 413 | ||
398 | out: | 414 | out: |
399 | stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; | 415 | stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; |
400 | stat.un.b.lsRjtRsnCodeExp = LSEXP_OUT_OF_RESOURCE; | 416 | stat.un.b.lsRjtRsnCodeExp = LSEXP_OUT_OF_RESOURCE; |
401 | lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp); | 417 | lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL); |
402 | return 0; | 418 | return 0; |
403 | } | 419 | } |
404 | 420 | ||
@@ -445,7 +461,7 @@ lpfc_rcv_padisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
445 | stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; | 461 | stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; |
446 | stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS; | 462 | stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS; |
447 | stat.un.b.vendorUnique = 0; | 463 | stat.un.b.vendorUnique = 0; |
448 | lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp); | 464 | lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL); |
449 | 465 | ||
450 | /* 1 sec timeout */ | 466 | /* 1 sec timeout */ |
451 | mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ); | 467 | mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ); |
@@ -535,6 +551,11 @@ lpfc_rcv_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
535 | roles |= FC_RPORT_ROLE_FCP_INITIATOR; | 551 | roles |= FC_RPORT_ROLE_FCP_INITIATOR; |
536 | if (ndlp->nlp_type & NLP_FCP_TARGET) | 552 | if (ndlp->nlp_type & NLP_FCP_TARGET) |
537 | roles |= FC_RPORT_ROLE_FCP_TARGET; | 553 | roles |= FC_RPORT_ROLE_FCP_TARGET; |
554 | |||
555 | lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT, | ||
556 | "rport rolechg: role:x%x did:x%x flg:x%x", | ||
557 | roles, ndlp->nlp_DID, ndlp->nlp_flag); | ||
558 | |||
538 | fc_remote_port_rolechg(rport, roles); | 559 | fc_remote_port_rolechg(rport, roles); |
539 | } | 560 | } |
540 | } | 561 | } |
@@ -657,7 +678,8 @@ lpfc_rcv_plogi_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
657 | ours */ | 678 | ours */ |
658 | stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; | 679 | stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; |
659 | stat.un.b.lsRjtRsnCodeExp = LSEXP_CMD_IN_PROGRESS; | 680 | stat.un.b.lsRjtRsnCodeExp = LSEXP_CMD_IN_PROGRESS; |
660 | lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp); | 681 | lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, |
682 | NULL); | ||
661 | } else { | 683 | } else { |
662 | lpfc_rcv_plogi(vport, ndlp, cmdiocb); | 684 | lpfc_rcv_plogi(vport, ndlp, cmdiocb); |
663 | } /* If our portname was less */ | 685 | } /* If our portname was less */ |
@@ -675,7 +697,7 @@ lpfc_rcv_prli_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
675 | memset(&stat, 0, sizeof (struct ls_rjt)); | 697 | memset(&stat, 0, sizeof (struct ls_rjt)); |
676 | stat.un.b.lsRjtRsnCode = LSRJT_LOGICAL_BSY; | 698 | stat.un.b.lsRjtRsnCode = LSRJT_LOGICAL_BSY; |
677 | stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE; | 699 | stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE; |
678 | lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp); | 700 | lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL); |
679 | return ndlp->nlp_state; | 701 | return ndlp->nlp_state; |
680 | } | 702 | } |
681 | 703 | ||
@@ -1335,6 +1357,10 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
1335 | 1357 | ||
1336 | irsp = &rspiocb->iocb; | 1358 | irsp = &rspiocb->iocb; |
1337 | if (irsp->ulpStatus) { | 1359 | if (irsp->ulpStatus) { |
1360 | if ((vport->port_type == LPFC_NPIV_PORT) && | ||
1361 | phba->cfg_vport_restrict_login) { | ||
1362 | goto out; | ||
1363 | } | ||
1338 | ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE; | 1364 | ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE; |
1339 | lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); | 1365 | lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); |
1340 | return ndlp->nlp_state; | 1366 | return ndlp->nlp_state; |
@@ -1355,6 +1381,7 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
1355 | if (!(ndlp->nlp_type & NLP_FCP_TARGET) && | 1381 | if (!(ndlp->nlp_type & NLP_FCP_TARGET) && |
1356 | (vport->port_type == LPFC_NPIV_PORT) && | 1382 | (vport->port_type == LPFC_NPIV_PORT) && |
1357 | phba->cfg_vport_restrict_login) { | 1383 | phba->cfg_vport_restrict_login) { |
1384 | out: | ||
1358 | spin_lock_irq(shost->host_lock); | 1385 | spin_lock_irq(shost->host_lock); |
1359 | ndlp->nlp_flag |= NLP_TARGET_REMOVE; | 1386 | ndlp->nlp_flag |= NLP_TARGET_REMOVE; |
1360 | spin_unlock_irq(shost->host_lock); | 1387 | spin_unlock_irq(shost->host_lock); |
@@ -1606,7 +1633,7 @@ lpfc_rcv_plogi_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
1606 | struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; | 1633 | struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; |
1607 | 1634 | ||
1608 | /* Ignore PLOGI if we have an outstanding LOGO */ | 1635 | /* Ignore PLOGI if we have an outstanding LOGO */ |
1609 | if (ndlp->nlp_flag & NLP_LOGO_SND) { | 1636 | if (ndlp->nlp_flag & (NLP_LOGO_SND | NLP_LOGO_ACC)) { |
1610 | return ndlp->nlp_state; | 1637 | return ndlp->nlp_state; |
1611 | } | 1638 | } |
1612 | 1639 | ||
@@ -1638,7 +1665,7 @@ lpfc_rcv_prli_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
1638 | memset(&stat, 0, sizeof (struct ls_rjt)); | 1665 | memset(&stat, 0, sizeof (struct ls_rjt)); |
1639 | stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; | 1666 | stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; |
1640 | stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE; | 1667 | stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE; |
1641 | lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp); | 1668 | lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL); |
1642 | 1669 | ||
1643 | if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) { | 1670 | if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) { |
1644 | if (ndlp->nlp_flag & NLP_NPR_ADISC) { | 1671 | if (ndlp->nlp_flag & NLP_NPR_ADISC) { |
@@ -2035,6 +2062,10 @@ lpfc_disc_state_machine(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
2035 | phba->brd_no, vport->vpi, | 2062 | phba->brd_no, vport->vpi, |
2036 | evt, ndlp->nlp_DID, cur_state, ndlp->nlp_flag); | 2063 | evt, ndlp->nlp_DID, cur_state, ndlp->nlp_flag); |
2037 | 2064 | ||
2065 | lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_DSM, | ||
2066 | "DSM in: evt:%d ste:%d did:x%x", | ||
2067 | evt, cur_state, ndlp->nlp_DID); | ||
2068 | |||
2038 | func = lpfc_disc_action[(cur_state * NLP_EVT_MAX_EVENT) + evt]; | 2069 | func = lpfc_disc_action[(cur_state * NLP_EVT_MAX_EVENT) + evt]; |
2039 | rc = (func) (vport, ndlp, arg, evt); | 2070 | rc = (func) (vport, ndlp, arg, evt); |
2040 | 2071 | ||
@@ -2045,6 +2076,10 @@ lpfc_disc_state_machine(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
2045 | phba->brd_no, vport->vpi, | 2076 | phba->brd_no, vport->vpi, |
2046 | rc, ndlp->nlp_DID, ndlp->nlp_flag); | 2077 | rc, ndlp->nlp_DID, ndlp->nlp_flag); |
2047 | 2078 | ||
2079 | lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_DSM, | ||
2080 | "DSM out: ste:%d did:x%x flg:x%x", | ||
2081 | rc, ndlp->nlp_DID, ndlp->nlp_flag); | ||
2082 | |||
2048 | lpfc_nlp_put(ndlp); | 2083 | lpfc_nlp_put(ndlp); |
2049 | 2084 | ||
2050 | return rc; | 2085 | return rc; |