aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Smart <James.Smart@Emulex.Com>2008-12-04 22:39:08 -0500
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2008-12-29 12:24:25 -0500
commit109f6ed05aadb7dd1cc9671a63603658d3ba518e (patch)
tree637d09437a45ab0f21e28a30ae4e876d59b6b733
parent9bad76719ee4fa8c305bb6cba6e19b4ddbe800b2 (diff)
[SCSI] lpfc 8.3.0 : Fix system crash due to uninitialized node access
In the IOCB completion handler, always check if the node is valid before accessing the node object. Added lpfc_initialize_node() to initialize nodes. Signed-off-by: James Smart <James.Smart@emulex.com> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
-rw-r--r--drivers/scsi/lpfc/lpfc_hbadisc.c52
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c44
2 files changed, 56 insertions, 40 deletions
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index 58ed6859c921..ba120530cf80 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -1857,6 +1857,32 @@ lpfc_disable_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
1857 lpfc_nlp_state_cleanup(vport, ndlp, ndlp->nlp_state, 1857 lpfc_nlp_state_cleanup(vport, ndlp, ndlp->nlp_state,
1858 NLP_STE_UNUSED_NODE); 1858 NLP_STE_UNUSED_NODE);
1859} 1859}
1860/**
1861 * lpfc_initialize_node: Initialize all fields of node object.
1862 * @vport: Pointer to Virtual Port object.
1863 * @ndlp: Pointer to FC node object.
1864 * @did: FC_ID of the node.
1865 * This function is always called when node object need to
1866 * be initialized. It initializes all the fields of the node
1867 * object.
1868 **/
1869static inline void
1870lpfc_initialize_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
1871 uint32_t did)
1872{
1873 INIT_LIST_HEAD(&ndlp->els_retry_evt.evt_listp);
1874 INIT_LIST_HEAD(&ndlp->dev_loss_evt.evt_listp);
1875 init_timer(&ndlp->nlp_delayfunc);
1876 ndlp->nlp_delayfunc.function = lpfc_els_retry_delay;
1877 ndlp->nlp_delayfunc.data = (unsigned long)ndlp;
1878 ndlp->nlp_DID = did;
1879 ndlp->vport = vport;
1880 ndlp->nlp_sid = NLP_NO_SID;
1881 kref_init(&ndlp->kref);
1882 NLP_INT_NODE_ACT(ndlp);
1883 atomic_set(&ndlp->cmd_pending, 0);
1884 ndlp->cmd_qdepth = LPFC_MAX_TGT_QDEPTH;
1885}
1860 1886
1861struct lpfc_nodelist * 1887struct lpfc_nodelist *
1862lpfc_enable_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, 1888lpfc_enable_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
@@ -1897,17 +1923,7 @@ lpfc_enable_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
1897 /* re-initialize ndlp except of ndlp linked list pointer */ 1923 /* re-initialize ndlp except of ndlp linked list pointer */
1898 memset((((char *)ndlp) + sizeof (struct list_head)), 0, 1924 memset((((char *)ndlp) + sizeof (struct list_head)), 0,
1899 sizeof (struct lpfc_nodelist) - sizeof (struct list_head)); 1925 sizeof (struct lpfc_nodelist) - sizeof (struct list_head));
1900 INIT_LIST_HEAD(&ndlp->els_retry_evt.evt_listp); 1926 lpfc_initialize_node(vport, ndlp, did);
1901 INIT_LIST_HEAD(&ndlp->dev_loss_evt.evt_listp);
1902 init_timer(&ndlp->nlp_delayfunc);
1903 ndlp->nlp_delayfunc.function = lpfc_els_retry_delay;
1904 ndlp->nlp_delayfunc.data = (unsigned long)ndlp;
1905 ndlp->nlp_DID = did;
1906 ndlp->vport = vport;
1907 ndlp->nlp_sid = NLP_NO_SID;
1908 /* ndlp management re-initialize */
1909 kref_init(&ndlp->kref);
1910 NLP_INT_NODE_ACT(ndlp);
1911 1927
1912 spin_unlock_irqrestore(&phba->ndlp_lock, flags); 1928 spin_unlock_irqrestore(&phba->ndlp_lock, flags);
1913 1929
@@ -3121,19 +3137,9 @@ lpfc_nlp_init(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
3121 uint32_t did) 3137 uint32_t did)
3122{ 3138{
3123 memset(ndlp, 0, sizeof (struct lpfc_nodelist)); 3139 memset(ndlp, 0, sizeof (struct lpfc_nodelist));
3124 INIT_LIST_HEAD(&ndlp->els_retry_evt.evt_listp); 3140
3125 INIT_LIST_HEAD(&ndlp->dev_loss_evt.evt_listp); 3141 lpfc_initialize_node(vport, ndlp, did);
3126 init_timer(&ndlp->nlp_delayfunc);
3127 ndlp->nlp_delayfunc.function = lpfc_els_retry_delay;
3128 ndlp->nlp_delayfunc.data = (unsigned long)ndlp;
3129 ndlp->nlp_DID = did;
3130 ndlp->vport = vport;
3131 ndlp->nlp_sid = NLP_NO_SID;
3132 INIT_LIST_HEAD(&ndlp->nlp_listp); 3142 INIT_LIST_HEAD(&ndlp->nlp_listp);
3133 kref_init(&ndlp->kref);
3134 NLP_INT_NODE_ACT(ndlp);
3135 atomic_set(&ndlp->cmd_pending, 0);
3136 ndlp->cmd_qdepth = LPFC_MAX_TGT_QDEPTH;
3137 3143
3138 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_NODE, 3144 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_NODE,
3139 "node init: did:x%x", 3145 "node init: did:x%x",
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index 6293b6fc65a6..cf6b2d40a923 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -945,7 +945,8 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
945 945
946 lpfc_cmd->result = pIocbOut->iocb.un.ulpWord[4]; 946 lpfc_cmd->result = pIocbOut->iocb.un.ulpWord[4];
947 lpfc_cmd->status = pIocbOut->iocb.ulpStatus; 947 lpfc_cmd->status = pIocbOut->iocb.ulpStatus;
948 atomic_dec(&pnode->cmd_pending); 948 if (pnode && NLP_CHK_NODE_ACT(pnode))
949 atomic_dec(&pnode->cmd_pending);
949 950
950 if (lpfc_cmd->status) { 951 if (lpfc_cmd->status) {
951 if (lpfc_cmd->status == IOSTAT_LOCAL_REJECT && 952 if (lpfc_cmd->status == IOSTAT_LOCAL_REJECT &&
@@ -1035,23 +1036,31 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
1035 time_after(jiffies, lpfc_cmd->start_time + 1036 time_after(jiffies, lpfc_cmd->start_time +
1036 msecs_to_jiffies(vport->cfg_max_scsicmpl_time))) { 1037 msecs_to_jiffies(vport->cfg_max_scsicmpl_time))) {
1037 spin_lock_irqsave(sdev->host->host_lock, flags); 1038 spin_lock_irqsave(sdev->host->host_lock, flags);
1038 if ((pnode->cmd_qdepth > atomic_read(&pnode->cmd_pending) && 1039 if (pnode && NLP_CHK_NODE_ACT(pnode)) {
1039 (atomic_read(&pnode->cmd_pending) > LPFC_MIN_TGT_QDEPTH) && 1040 if (pnode->cmd_qdepth >
1040 ((cmd->cmnd[0] == READ_10) || (cmd->cmnd[0] == WRITE_10)))) 1041 atomic_read(&pnode->cmd_pending) &&
1041 pnode->cmd_qdepth = atomic_read(&pnode->cmd_pending); 1042 (atomic_read(&pnode->cmd_pending) >
1042 1043 LPFC_MIN_TGT_QDEPTH) &&
1043 pnode->last_change_time = jiffies; 1044 ((cmd->cmnd[0] == READ_10) ||
1045 (cmd->cmnd[0] == WRITE_10)))
1046 pnode->cmd_qdepth =
1047 atomic_read(&pnode->cmd_pending);
1048
1049 pnode->last_change_time = jiffies;
1050 }
1044 spin_unlock_irqrestore(sdev->host->host_lock, flags); 1051 spin_unlock_irqrestore(sdev->host->host_lock, flags);
1045 } else if ((pnode->cmd_qdepth < LPFC_MAX_TGT_QDEPTH) && 1052 } else if (pnode && NLP_CHK_NODE_ACT(pnode)) {
1053 if ((pnode->cmd_qdepth < LPFC_MAX_TGT_QDEPTH) &&
1046 time_after(jiffies, pnode->last_change_time + 1054 time_after(jiffies, pnode->last_change_time +
1047 msecs_to_jiffies(LPFC_TGTQ_INTERVAL))) { 1055 msecs_to_jiffies(LPFC_TGTQ_INTERVAL))) {
1048 spin_lock_irqsave(sdev->host->host_lock, flags); 1056 spin_lock_irqsave(sdev->host->host_lock, flags);
1049 pnode->cmd_qdepth += pnode->cmd_qdepth * 1057 pnode->cmd_qdepth += pnode->cmd_qdepth *
1050 LPFC_TGTQ_RAMPUP_PCENT / 100; 1058 LPFC_TGTQ_RAMPUP_PCENT / 100;
1051 if (pnode->cmd_qdepth > LPFC_MAX_TGT_QDEPTH) 1059 if (pnode->cmd_qdepth > LPFC_MAX_TGT_QDEPTH)
1052 pnode->cmd_qdepth = LPFC_MAX_TGT_QDEPTH; 1060 pnode->cmd_qdepth = LPFC_MAX_TGT_QDEPTH;
1053 pnode->last_change_time = jiffies; 1061 pnode->last_change_time = jiffies;
1054 spin_unlock_irqrestore(sdev->host->host_lock, flags); 1062 spin_unlock_irqrestore(sdev->host->host_lock, flags);
1063 }
1055 } 1064 }
1056 1065
1057 lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd); 1066 lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd);
@@ -1536,7 +1545,8 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
1536 cmnd->result = ScsiResult(DID_TRANSPORT_DISRUPTED, 0); 1545 cmnd->result = ScsiResult(DID_TRANSPORT_DISRUPTED, 0);
1537 goto out_fail_command; 1546 goto out_fail_command;
1538 } 1547 }
1539 if (atomic_read(&ndlp->cmd_pending) >= ndlp->cmd_qdepth) 1548 if (vport->cfg_max_scsicmpl_time &&
1549 (atomic_read(&ndlp->cmd_pending) >= ndlp->cmd_qdepth))
1540 goto out_host_busy; 1550 goto out_host_busy;
1541 1551
1542 lpfc_cmd = lpfc_get_scsi_buf(phba); 1552 lpfc_cmd = lpfc_get_scsi_buf(phba);