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

📄 zfcp_fsf.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * * linux/drivers/s390/scsi/zfcp_fsf.c * * FCP adapter driver for IBM eServer zSeries * * (C) Copyright IBM Corp. 2002, 2004 * * Author(s): Martin Peschke <mpeschke@de.ibm.com> *            Raimund Schroeder <raimund.schroeder@de.ibm.com> *            Aron Zeh *            Wolfgang Taphorn *            Stefan Bader <stefan.bader@de.ibm.com> *            Heiko Carstens <heiko.carstens@de.ibm.com> *            Andreas Herrmann <aherrman@de.ibm.com> *            Volker Sameske <sameske@de.ibm.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */#define ZFCP_FSF_C_REVISION "$Revision: 1.92 $"#include "zfcp_ext.h"static int zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *);static void zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *);static int zfcp_fsf_open_port_handler(struct zfcp_fsf_req *);static int zfcp_fsf_close_port_handler(struct zfcp_fsf_req *);static int zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *);static int zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *);static int zfcp_fsf_close_unit_handler(struct zfcp_fsf_req *);static int zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *);static int zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *);static int zfcp_fsf_send_fcp_command_task_management_handler(	struct zfcp_fsf_req *);static int zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *);static int zfcp_fsf_status_read_handler(struct zfcp_fsf_req *);static int zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *);static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *);static int zfcp_fsf_control_file_handler(struct zfcp_fsf_req *);static inline int zfcp_fsf_req_sbal_check(	unsigned long *, struct zfcp_qdio_queue *, int);static inline int zfcp_use_one_sbal(	struct scatterlist *, int, struct scatterlist *, int);static struct zfcp_fsf_req *zfcp_fsf_req_alloc(mempool_t *, int);static int zfcp_fsf_req_send(struct zfcp_fsf_req *, struct timer_list *);static int zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *);static int zfcp_fsf_fsfstatus_eval(struct zfcp_fsf_req *);static int zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *);static void zfcp_fsf_link_down_info_eval(struct zfcp_adapter *,	struct fsf_link_down_info *);static int zfcp_fsf_req_dispatch(struct zfcp_fsf_req *);static void zfcp_fsf_req_dismiss(struct zfcp_fsf_req *);/* association between FSF command and FSF QTCB type */static u32 fsf_qtcb_type[] = {	[FSF_QTCB_FCP_CMND] =             FSF_IO_COMMAND,	[FSF_QTCB_ABORT_FCP_CMND] =       FSF_SUPPORT_COMMAND,	[FSF_QTCB_OPEN_PORT_WITH_DID] =   FSF_SUPPORT_COMMAND,	[FSF_QTCB_OPEN_LUN] =             FSF_SUPPORT_COMMAND,	[FSF_QTCB_CLOSE_LUN] =            FSF_SUPPORT_COMMAND,	[FSF_QTCB_CLOSE_PORT] =           FSF_SUPPORT_COMMAND,	[FSF_QTCB_CLOSE_PHYSICAL_PORT] =  FSF_SUPPORT_COMMAND,	[FSF_QTCB_SEND_ELS] =             FSF_SUPPORT_COMMAND,	[FSF_QTCB_SEND_GENERIC] =         FSF_SUPPORT_COMMAND,	[FSF_QTCB_EXCHANGE_CONFIG_DATA] = FSF_CONFIG_COMMAND,	[FSF_QTCB_EXCHANGE_PORT_DATA] =   FSF_PORT_COMMAND,	[FSF_QTCB_DOWNLOAD_CONTROL_FILE] = FSF_SUPPORT_COMMAND,	[FSF_QTCB_UPLOAD_CONTROL_FILE] =  FSF_SUPPORT_COMMAND};static const char zfcp_act_subtable_type[5][8] = {	"unknown", "OS", "WWPN", "DID", "LUN"};/****************************************************************//*************** FSF related Functions  *************************//****************************************************************/#define ZFCP_LOG_AREA			ZFCP_LOG_AREA_FSF/* * function:	zfcp_fsf_req_alloc * * purpose:     Obtains an fsf_req and potentially a qtcb (for all but  *              unsolicited requests) via helper functions *              Does some initial fsf request set-up. *               * returns:	pointer to allocated fsf_req if successfull *              NULL otherwise * * locks:       none * */static struct zfcp_fsf_req *zfcp_fsf_req_alloc(mempool_t *pool, int req_flags){	size_t size;	void *ptr;	struct zfcp_fsf_req *fsf_req = NULL;	if (req_flags & ZFCP_REQ_NO_QTCB)		size = sizeof(struct zfcp_fsf_req);	else		size = sizeof(struct zfcp_fsf_req_pool_element);	if (likely(pool != NULL))		ptr = mempool_alloc(pool, GFP_ATOMIC);	else		ptr = kmalloc(size, GFP_ATOMIC);	if (unlikely(NULL == ptr))		goto out;	memset(ptr, 0, size);	if (req_flags & ZFCP_REQ_NO_QTCB) {		fsf_req = (struct zfcp_fsf_req *) ptr;	} else {		fsf_req = &((struct zfcp_fsf_req_pool_element *) ptr)->fsf_req;		fsf_req->qtcb =			&((struct zfcp_fsf_req_pool_element *) ptr)->qtcb;	}	fsf_req->pool = pool; out:	return fsf_req;}/* * function:	zfcp_fsf_req_free * * purpose:     Frees the memory of an fsf_req (and potentially a qtcb) or *              returns it into the pool via helper functions. * * returns:     sod all * * locks:       none */voidzfcp_fsf_req_free(struct zfcp_fsf_req *fsf_req){	if (likely(fsf_req->pool != NULL))		mempool_free(fsf_req, fsf_req->pool);	else		kfree(fsf_req);}/* * function:	 * * purpose:	 * * returns: * * note: qdio queues shall be down (no ongoing inbound processing) */intzfcp_fsf_req_dismiss_all(struct zfcp_adapter *adapter){	struct zfcp_fsf_req *fsf_req, *tmp;	unsigned long flags;	LIST_HEAD(remove_queue);	spin_lock_irqsave(&adapter->fsf_req_list_lock, flags);	list_splice_init(&adapter->fsf_req_list_head, &remove_queue);	atomic_set(&adapter->fsf_reqs_active, 0);	spin_unlock_irqrestore(&adapter->fsf_req_list_lock, flags);	list_for_each_entry_safe(fsf_req, tmp, &remove_queue, list) {		list_del(&fsf_req->list);		zfcp_fsf_req_dismiss(fsf_req);	}	return 0;}/* * function:	 * * purpose:	 * * returns: */static voidzfcp_fsf_req_dismiss(struct zfcp_fsf_req *fsf_req){	fsf_req->status |= ZFCP_STATUS_FSFREQ_DISMISSED;	zfcp_fsf_req_complete(fsf_req);}/* * function:    zfcp_fsf_req_complete * * purpose:	Updates active counts and timers for openfcp-reqs *              May cleanup request after req_eval returns * * returns:	0 - success *		!0 - failure * * context:	 */intzfcp_fsf_req_complete(struct zfcp_fsf_req *fsf_req){	int retval = 0;	int cleanup;	if (unlikely(fsf_req->fsf_command == FSF_QTCB_UNSOLICITED_STATUS)) {		ZFCP_LOG_DEBUG("Status read response received\n");		/*		 * Note: all cleanup handling is done in the callchain of		 * the function call-chain below.		 */		zfcp_fsf_status_read_handler(fsf_req);		goto out;	} else		zfcp_fsf_protstatus_eval(fsf_req);	/*	 * fsf_req may be deleted due to waking up functions, so 	 * cleanup is saved here and used later 	 */	if (likely(fsf_req->status & ZFCP_STATUS_FSFREQ_CLEANUP))		cleanup = 1;	else		cleanup = 0;	fsf_req->status |= ZFCP_STATUS_FSFREQ_COMPLETED;	/* cleanup request if requested by initiator */	if (likely(cleanup)) {		ZFCP_LOG_TRACE("removing FSF request %p\n", fsf_req);		/*		 * lock must not be held here since it will be		 * grabed by the called routine, too		 */		zfcp_fsf_req_free(fsf_req);	} else {		/* notify initiator waiting for the requests completion */		ZFCP_LOG_TRACE("waking initiator of FSF request %p\n",fsf_req);		/*		 * FIXME: Race! We must not access fsf_req here as it might have been		 * cleaned up already due to the set ZFCP_STATUS_FSFREQ_COMPLETED		 * flag. It's an improbable case. But, we have the same paranoia for		 * the cleanup flag already.		 * Might better be handled using complete()?		 * (setting the flag and doing wakeup ought to be atomic		 *  with regard to checking the flag as long as waitqueue is		 *  part of the to be released structure)		 */		wake_up(&fsf_req->completion_wq);	} out:	return retval;}/* * function:    zfcp_fsf_protstatus_eval * * purpose:	evaluates the QTCB of the finished FSF request *		and initiates appropriate actions *		(usually calling FSF command specific handlers) * * returns:	 * * context:	 * * locks: */static intzfcp_fsf_protstatus_eval(struct zfcp_fsf_req *fsf_req){	int retval = 0;	struct zfcp_adapter *adapter = fsf_req->adapter;	struct fsf_qtcb *qtcb = fsf_req->qtcb;	union fsf_prot_status_qual *prot_status_qual =		&qtcb->prefix.prot_status_qual;	zfcp_hba_dbf_event_fsf_response(fsf_req);	if (fsf_req->status & ZFCP_STATUS_FSFREQ_DISMISSED) {		ZFCP_LOG_DEBUG("fsf_req 0x%lx has been dismissed\n",			       (unsigned long) fsf_req);		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR |			ZFCP_STATUS_FSFREQ_RETRY; /* only for SCSI cmnds. */		goto skip_protstatus;	}	/* log additional information provided by FSF (if any) */	if (unlikely(qtcb->header.log_length)) {		/* do not trust them ;-) */		if (qtcb->header.log_start > sizeof(struct fsf_qtcb)) {			ZFCP_LOG_NORMAL			    ("bug: ULP (FSF logging) log data starts "			     "beyond end of packet header. Ignored. "			     "(start=%i, size=%li)\n",			     qtcb->header.log_start,			     sizeof(struct fsf_qtcb));			goto forget_log;		}		if ((size_t) (qtcb->header.log_start + qtcb->header.log_length)		    > sizeof(struct fsf_qtcb)) {			ZFCP_LOG_NORMAL("bug: ULP (FSF logging) log data ends "					"beyond end of packet header. Ignored. "					"(start=%i, length=%i, size=%li)\n",					qtcb->header.log_start,					qtcb->header.log_length,					sizeof(struct fsf_qtcb));			goto forget_log;		}		ZFCP_LOG_TRACE("ULP log data: \n");		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE,			      (char *) qtcb + qtcb->header.log_start,			      qtcb->header.log_length);	} forget_log:	/* evaluate FSF Protocol Status */	switch (qtcb->prefix.prot_status) {	case FSF_PROT_GOOD:	case FSF_PROT_FSF_STATUS_PRESENTED:		break;	case FSF_PROT_QTCB_VERSION_ERROR:		ZFCP_LOG_NORMAL("error: The adapter %s contains "				"microcode of version 0x%x, the device driver "				"only supports 0x%x. Aborting.\n",				zfcp_get_busid_by_adapter(adapter),				prot_status_qual->version_error.fsf_version,				ZFCP_QTCB_VERSION);		zfcp_erp_adapter_shutdown(adapter, 0);		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;		break;	case FSF_PROT_SEQ_NUMB_ERROR:		ZFCP_LOG_NORMAL("bug: Sequence number mismatch between "				"driver (0x%x) and adapter %s (0x%x). "				"Restarting all operations on this adapter.\n",				qtcb->prefix.req_seq_no,				zfcp_get_busid_by_adapter(adapter),				prot_status_qual->sequence_error.exp_req_seq_no);		zfcp_erp_adapter_reopen(adapter, 0);		fsf_req->status |= ZFCP_STATUS_FSFREQ_RETRY;		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;		break;	case FSF_PROT_UNSUPP_QTCB_TYPE:		ZFCP_LOG_NORMAL("error: Packet header type used by the "				"device driver is incompatible with "				"that used on adapter %s. "				"Stopping all operations on this adapter.\n",				zfcp_get_busid_by_adapter(adapter));		zfcp_erp_adapter_shutdown(adapter, 0);		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;		break;	case FSF_PROT_HOST_CONNECTION_INITIALIZING:		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;		atomic_set_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,				&(adapter->status));		break;	case FSF_PROT_DUPLICATE_REQUEST_ID:			ZFCP_LOG_NORMAL("bug: The request identifier 0x%Lx "					"to the adapter %s is ambiguous. "				"Stopping all operations on this adapter.\n",				*(unsigned long long*)				(&qtcb->bottom.support.req_handle),					zfcp_get_busid_by_adapter(adapter));		zfcp_erp_adapter_shutdown(adapter, 0);		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;		break;	case FSF_PROT_LINK_DOWN:		zfcp_fsf_link_down_info_eval(adapter,					     &prot_status_qual->link_down_info);		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;		break;	case FSF_PROT_REEST_QUEUE:		ZFCP_LOG_NORMAL("The local link to adapter with "			      "%s was re-plugged. "			      "Re-starting operations on this adapter.\n",			      zfcp_get_busid_by_adapter(adapter));		/* All ports should be marked as ready to run again */		zfcp_erp_modify_adapter_status(adapter,					       ZFCP_STATUS_COMMON_RUNNING,					       ZFCP_SET);		zfcp_erp_adapter_reopen(adapter,					ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED					| ZFCP_STATUS_COMMON_ERP_FAILED);		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;		break;

⌨️ 快捷键说明

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