⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lpfc_hbadisc.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
/******************************************************************* * This file is part of the Emulex Linux Device Driver for         * * Fibre Channel Host Bus Adapters.                                * * Copyright (C) 2004-2005 Emulex.  All rights reserved.           * * EMULEX and SLI are trademarks of Emulex.                        * * www.emulex.com                                                  * * Portions Copyright (C) 2004-2005 Christoph Hellwig              * *                                                                 * * This program is free software; you can redistribute it and/or   * * modify it under the terms of version 2 of the GNU General       * * Public License as published by the Free Software Foundation.    * * This program is distributed in the hope that it will be useful. * * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          * * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  * * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      * * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * * TO BE LEGALLY INVALID.  See the GNU General Public License for  * * more details, a copy of which can be found in the file COPYING  * * included with this package.                                     * *******************************************************************/#include <linux/blkdev.h>#include <linux/pci.h>#include <linux/kthread.h>#include <linux/interrupt.h>#include <scsi/scsi.h>#include <scsi/scsi_device.h>#include <scsi/scsi_host.h>#include <scsi/scsi_transport_fc.h>#include "lpfc_hw.h"#include "lpfc_disc.h"#include "lpfc_sli.h"#include "lpfc_scsi.h"#include "lpfc.h"#include "lpfc_logmsg.h"#include "lpfc_crtn.h"/* AlpaArray for assignment of scsid for scan-down and bind_method */static uint8_t lpfcAlpaArray[] = {	0xEF, 0xE8, 0xE4, 0xE2, 0xE1, 0xE0, 0xDC, 0xDA, 0xD9, 0xD6,	0xD5, 0xD4, 0xD3, 0xD2, 0xD1, 0xCE, 0xCD, 0xCC, 0xCB, 0xCA,	0xC9, 0xC7, 0xC6, 0xC5, 0xC3, 0xBC, 0xBA, 0xB9, 0xB6, 0xB5,	0xB4, 0xB3, 0xB2, 0xB1, 0xAE, 0xAD, 0xAC, 0xAB, 0xAA, 0xA9,	0xA7, 0xA6, 0xA5, 0xA3, 0x9F, 0x9E, 0x9D, 0x9B, 0x98, 0x97,	0x90, 0x8F, 0x88, 0x84, 0x82, 0x81, 0x80, 0x7C, 0x7A, 0x79,	0x76, 0x75, 0x74, 0x73, 0x72, 0x71, 0x6E, 0x6D, 0x6C, 0x6B,	0x6A, 0x69, 0x67, 0x66, 0x65, 0x63, 0x5C, 0x5A, 0x59, 0x56,	0x55, 0x54, 0x53, 0x52, 0x51, 0x4E, 0x4D, 0x4C, 0x4B, 0x4A,	0x49, 0x47, 0x46, 0x45, 0x43, 0x3C, 0x3A, 0x39, 0x36, 0x35,	0x34, 0x33, 0x32, 0x31, 0x2E, 0x2D, 0x2C, 0x2B, 0x2A, 0x29,	0x27, 0x26, 0x25, 0x23, 0x1F, 0x1E, 0x1D, 0x1B, 0x18, 0x17,	0x10, 0x0F, 0x08, 0x04, 0x02, 0x01};static void lpfc_disc_timeout_handler(struct lpfc_hba *);static voidlpfc_process_nodev_timeout(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp){	int warn_on = 0;	spin_lock_irq(phba->host->host_lock);	if (!(ndlp->nlp_flag & NLP_NODEV_TMO)) {		spin_unlock_irq(phba->host->host_lock);		return;	}	ndlp->nlp_flag &= ~NLP_NODEV_TMO;	if (ndlp->nlp_sid != NLP_NO_SID) {		warn_on = 1;		/* flush the target */		lpfc_sli_abort_iocb(phba, &phba->sli.ring[phba->sli.fcp_ring],			ndlp->nlp_sid, 0, 0, LPFC_CTX_TGT);	}	spin_unlock_irq(phba->host->host_lock);	if (warn_on) {		lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,				"%d:0203 Nodev timeout on NPort x%x "				"Data: x%x x%x x%x\n",				phba->brd_no, ndlp->nlp_DID, ndlp->nlp_flag,				ndlp->nlp_state, ndlp->nlp_rpi);	} else {		lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,				"%d:0204 Nodev timeout on NPort x%x "				"Data: x%x x%x x%x\n",				phba->brd_no, ndlp->nlp_DID, ndlp->nlp_flag,				ndlp->nlp_state, ndlp->nlp_rpi);	}	lpfc_disc_state_machine(phba, ndlp, NULL, NLP_EVT_DEVICE_RM);	return;}static voidlpfc_work_list_done(struct lpfc_hba * phba){	struct lpfc_work_evt  *evtp = NULL;	struct lpfc_nodelist  *ndlp;	int free_evt;	spin_lock_irq(phba->host->host_lock);	while(!list_empty(&phba->work_list)) {		list_remove_head((&phba->work_list), evtp, typeof(*evtp),				 evt_listp);		spin_unlock_irq(phba->host->host_lock);		free_evt = 1;		switch(evtp->evt) {		case LPFC_EVT_NODEV_TMO:			ndlp = (struct lpfc_nodelist *)(evtp->evt_arg1);			lpfc_process_nodev_timeout(phba, ndlp);			free_evt = 0;			break;		case LPFC_EVT_ELS_RETRY:			ndlp = (struct lpfc_nodelist *)(evtp->evt_arg1);			lpfc_els_retry_delay_handler(ndlp);			free_evt = 0;			break;		case LPFC_EVT_ONLINE:			*(int *)(evtp->evt_arg1)  = lpfc_online(phba);			complete((struct completion *)(evtp->evt_arg2));			break;		case LPFC_EVT_OFFLINE:			*(int *)(evtp->evt_arg1)  = lpfc_offline(phba);			complete((struct completion *)(evtp->evt_arg2));			break;		}		if (free_evt)			kfree(evtp);		spin_lock_irq(phba->host->host_lock);	}	spin_unlock_irq(phba->host->host_lock);}static voidlpfc_work_done(struct lpfc_hba * phba){	struct lpfc_sli_ring *pring;	int i;	uint32_t ha_copy;	uint32_t control;	uint32_t work_hba_events;	spin_lock_irq(phba->host->host_lock);	ha_copy = phba->work_ha;	phba->work_ha = 0;	work_hba_events=phba->work_hba_events;	spin_unlock_irq(phba->host->host_lock);	if(ha_copy & HA_ERATT)		lpfc_handle_eratt(phba);	if(ha_copy & HA_MBATT)		lpfc_sli_handle_mb_event(phba);	if(ha_copy & HA_LATT)		lpfc_handle_latt(phba);	if (work_hba_events & WORKER_DISC_TMO)		lpfc_disc_timeout_handler(phba);	if (work_hba_events & WORKER_ELS_TMO)		lpfc_els_timeout_handler(phba);	if (work_hba_events & WORKER_MBOX_TMO)		lpfc_mbox_timeout_handler(phba);	if (work_hba_events & WORKER_FDMI_TMO)		lpfc_fdmi_tmo_handler(phba);	spin_lock_irq(phba->host->host_lock);	phba->work_hba_events &= ~work_hba_events;	spin_unlock_irq(phba->host->host_lock);	for (i = 0; i < phba->sli.num_rings; i++, ha_copy >>= 4) {		pring = &phba->sli.ring[i];		if ((ha_copy & HA_RXATT)		    || (pring->flag & LPFC_DEFERRED_RING_EVENT)) {			if (pring->flag & LPFC_STOP_IOCB_MASK) {				pring->flag |= LPFC_DEFERRED_RING_EVENT;			} else {				lpfc_sli_handle_slow_ring_event(phba, pring,								(ha_copy &								 HA_RXMASK));				pring->flag &= ~LPFC_DEFERRED_RING_EVENT;			}			/*			 * Turn on Ring interrupts			 */			spin_lock_irq(phba->host->host_lock);			control = readl(phba->HCregaddr);			control |= (HC_R0INT_ENA << i);			writel(control, phba->HCregaddr);			readl(phba->HCregaddr); /* flush */			spin_unlock_irq(phba->host->host_lock);		}	}	lpfc_work_list_done (phba);}static intcheck_work_wait_done(struct lpfc_hba *phba) {	spin_lock_irq(phba->host->host_lock);	if (phba->work_ha ||	    phba->work_hba_events ||	    (!list_empty(&phba->work_list)) ||	    kthread_should_stop()) {		spin_unlock_irq(phba->host->host_lock);		return 1;	} else {		spin_unlock_irq(phba->host->host_lock);		return 0;	}}intlpfc_do_work(void *p){	struct lpfc_hba *phba = p;	int rc;	DECLARE_WAIT_QUEUE_HEAD(work_waitq);	set_user_nice(current, -20);	phba->work_wait = &work_waitq;	while (1) {		rc = wait_event_interruptible(work_waitq,						check_work_wait_done(phba));		BUG_ON(rc);		if (kthread_should_stop())			break;		lpfc_work_done(phba);	}	phba->work_wait = NULL;	return 0;}/* * This is only called to handle FC worker events. Since this a rare * occurance, we allocate a struct lpfc_work_evt structure here instead of * embedding it in the IOCB. */intlpfc_workq_post_event(struct lpfc_hba * phba, void *arg1, void *arg2,		      uint32_t evt){	struct lpfc_work_evt  *evtp;	/*	 * All Mailbox completions and LPFC_ELS_RING rcv ring IOCB events will	 * be queued to worker thread for processing	 */	evtp = kmalloc(sizeof(struct lpfc_work_evt), GFP_KERNEL);	if (!evtp)		return 0;	evtp->evt_arg1  = arg1;	evtp->evt_arg2  = arg2;	evtp->evt       = evt;	list_add_tail(&evtp->evt_listp, &phba->work_list);	spin_lock_irq(phba->host->host_lock);	if (phba->work_wait)		wake_up(phba->work_wait);	spin_unlock_irq(phba->host->host_lock);	return 1;}intlpfc_linkdown(struct lpfc_hba * phba){	struct lpfc_sli       *psli;	struct lpfc_nodelist  *ndlp, *next_ndlp;	struct list_head *listp;	struct list_head *node_list[7];	LPFC_MBOXQ_t     *mb;	int               rc, i;	psli = &phba->sli;	spin_lock_irq(phba->host->host_lock);	phba->hba_state = LPFC_LINK_DOWN;	spin_unlock_irq(phba->host->host_lock);	/* Clean up any firmware default rpi's */	if ((mb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL))) {		lpfc_unreg_did(phba, 0xffffffff, mb);		mb->mbox_cmpl=lpfc_sli_def_mbox_cmpl;		if (lpfc_sli_issue_mbox(phba, mb, (MBX_NOWAIT | MBX_STOP_IOCB))		    == MBX_NOT_FINISHED) {			mempool_free( mb, phba->mbox_mem_pool);		}	}	/* Cleanup any outstanding RSCN activity */	lpfc_els_flush_rscn(phba);	/* Cleanup any outstanding ELS commands */	lpfc_els_flush_cmd(phba);	/* Issue a LINK DOWN event to all nodes */	node_list[0] = &phba->fc_npr_list;  /* MUST do this list first */	node_list[1] = &phba->fc_nlpmap_list;	node_list[2] = &phba->fc_nlpunmap_list;	node_list[3] = &phba->fc_prli_list;	node_list[4] = &phba->fc_reglogin_list;	node_list[5] = &phba->fc_adisc_list;	node_list[6] = &phba->fc_plogi_list;	for (i = 0; i < 7; i++) {		listp = node_list[i];		if (list_empty(listp))			continue;		list_for_each_entry_safe(ndlp, next_ndlp, listp, nlp_listp) {			/* Fabric nodes are not handled thru state machine for			   link down */			if (ndlp->nlp_type & NLP_FABRIC) {				/* Remove ALL Fabric nodes except Fabric_DID */				if (ndlp->nlp_DID != Fabric_DID) {					/* Take it off current list and free */					lpfc_nlp_list(phba, ndlp,						NLP_NO_LIST);				}			}			else {				rc = lpfc_disc_state_machine(phba, ndlp, NULL,						     NLP_EVT_DEVICE_RECOVERY);				/* Check config parameter use-adisc or FCP-2 */				if ((rc != NLP_STE_FREED_NODE) &&					(phba->cfg_use_adisc == 0) &&					!(ndlp->nlp_fcp_info &						NLP_FCP_2_DEVICE)) {					/* We know we will have to relogin, so					 * unreglogin the rpi right now to fail					 * any outstanding I/Os quickly.					 */					lpfc_unreg_rpi(phba, ndlp);				}			}		}	}	/* free any ndlp's on unused list */	list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_unused_list,				nlp_listp) {		lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);	}	/* Setup myDID for link up if we are in pt2pt mode */	if (phba->fc_flag & FC_PT2PT) {		phba->fc_myDID = 0;		if ((mb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL))) {			lpfc_config_link(phba, mb);			mb->mbox_cmpl=lpfc_sli_def_mbox_cmpl;			if (lpfc_sli_issue_mbox			    (phba, mb, (MBX_NOWAIT | MBX_STOP_IOCB))			    == MBX_NOT_FINISHED) {				mempool_free( mb, phba->mbox_mem_pool);			}		}		spin_lock_irq(phba->host->host_lock);		phba->fc_flag &= ~(FC_PT2PT | FC_PT2PT_PLOGI);		spin_unlock_irq(phba->host->host_lock);	}	spin_lock_irq(phba->host->host_lock);	phba->fc_flag &= ~FC_LBIT;	spin_unlock_irq(phba->host->host_lock);	/* Turn off discovery timer if its running */	lpfc_can_disctmo(phba);	/* Must process IOCBs on all rings to handle ABORTed I/Os */	return (0);}static intlpfc_linkup(struct lpfc_hba * phba){	struct lpfc_nodelist *ndlp, *next_ndlp;	spin_lock_irq(phba->host->host_lock);	phba->hba_state = LPFC_LINK_UP;	phba->fc_flag &= ~(FC_PT2PT | FC_PT2PT_PLOGI | FC_ABORT_DISCOVERY |			   FC_RSCN_MODE | FC_NLP_MORE | FC_RSCN_DISCOVERY);	phba->fc_flag |= FC_NDISC_ACTIVE;	phba->fc_ns_retry = 0;	spin_unlock_irq(phba->host->host_lock);	/*	 * Clean up old Fabric NLP_FABRIC logins.	 */	list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nlpunmap_list,				nlp_listp) {		if (ndlp->nlp_DID == Fabric_DID) {			/* Take it off current list and free */			lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);		}	}	/* free any ndlp's on unused list */	list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_unused_list,				nlp_listp) {		lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);	}	return 0;}/* * This routine handles processing a CLEAR_LA mailbox * command upon completion. It is setup in the LPFC_MBOXQ * as the completion routine when the command is * handed off to the SLI layer. */voidlpfc_mbx_cmpl_clear_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb){	struct lpfc_sli *psli;	MAILBOX_t *mb;	uint32_t control;	psli = &phba->sli;	mb = &pmb->mb;	/* Since we don't do discovery right now, turn these off here */	psli->ring[psli->ip_ring].flag &= ~LPFC_STOP_IOCB_EVENT;	psli->ring[psli->fcp_ring].flag &= ~LPFC_STOP_IOCB_EVENT;	psli->ring[psli->next_ring].flag &= ~LPFC_STOP_IOCB_EVENT;	/* Check for error */	if ((mb->mbxStatus) && (mb->mbxStatus != 0x1601)) {		/* CLEAR_LA mbox error <mbxStatus> state <hba_state> */		lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,				"%d:0320 CLEAR_LA mbxStatus error x%x hba "				"state x%x\n",				phba->brd_no, mb->mbxStatus, phba->hba_state);		phba->hba_state = LPFC_HBA_ERROR;		goto out;	}	if (phba->fc_flag & FC_ABORT_DISCOVERY)		goto out;	phba->num_disc_nodes = 0;	/* go thru NPR list and issue ELS PLOGIs */	if (phba->fc_npr_cnt) {		lpfc_els_disc_plogi(phba);	}	if(!phba->num_disc_nodes) {		spin_lock_irq(phba->host->host_lock);		phba->fc_flag &= ~FC_NDISC_ACTIVE;		spin_unlock_irq(phba->host->host_lock);	}	phba->hba_state = LPFC_HBA_READY;out:	/* Device Discovery completes */	lpfc_printf_log(phba,			 KERN_INFO,			 LOG_DISCOVERY,			 "%d:0225 Device Discovery completes\n",			 phba->brd_no);	mempool_free( pmb, phba->mbox_mem_pool);	spin_lock_irq(phba->host->host_lock);	phba->fc_flag &= ~FC_ABORT_DISCOVERY;	if (phba->fc_flag & FC_ESTABLISH_LINK) {		phba->fc_flag &= ~FC_ESTABLISH_LINK;	}	spin_unlock_irq(phba->host->host_lock);	del_timer_sync(&phba->fc_estabtmo);	lpfc_can_disctmo(phba);	/* turn on Link Attention interrupts */	spin_lock_irq(phba->host->host_lock);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -