zfcp_fsf.c

来自「优龙2410linux2.6.8内核源代码」· C语言 代码 · 共 1,995 行 · 第 1/5 页

C
1,995
字号
/* * * 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> * * 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. *//* this drivers version (do not edit !!! generated and updated by cvs) */#define ZFCP_FSF_C_REVISION "$Revision: 1.55 $"#include "zfcp_ext.h"static int zfcp_fsf_exchange_config_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_create_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 int zfcp_fsf_req_dispatch(struct zfcp_fsf_req *);static void zfcp_fsf_req_dismiss(struct zfcp_fsf_req *);static void zfcp_fsf_req_free(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 */static 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){	int retval = 0;	struct zfcp_fsf_req *fsf_req, *tmp;	list_for_each_entry_safe(fsf_req, tmp, &adapter->fsf_req_list_head,				 list)	    zfcp_fsf_req_dismiss(fsf_req);	/* wait_event_timeout? */	while (!list_empty(&adapter->fsf_req_list_head)) {		ZFCP_LOG_DEBUG("fsf req list of adapter %s not yet empty\n",			       zfcp_get_busid_by_adapter(adapter));		/* wait for woken intiators to clean up their requests */		msleep(jiffies_to_msecs(ZFCP_FSFREQ_CLEANUP_TIMEOUT));	}	/* consistency check */	if (atomic_read(&adapter->fsf_reqs_active)) {		ZFCP_LOG_NORMAL("bug: There are still %d FSF requests pending "				"on adapter %s after cleanup.\n",				atomic_read(&adapter->fsf_reqs_active),				zfcp_get_busid_by_adapter(adapter));		atomic_set(&adapter->fsf_reqs_active, 0);	}	return retval;}/* * 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;	struct zfcp_adapter *adapter = fsf_req->adapter;	/* do some statistics */	atomic_dec(&adapter->fsf_reqs_active);	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_cleanup(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;	ZFCP_LOG_DEBUG("QTCB is at %p\n", fsf_req->qtcb);	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. */		zfcp_cmd_dbf_event_fsf("dismiss", fsf_req, NULL, 0);		goto skip_protstatus;	}	/* log additional information provided by FSF (if any) */	if (unlikely(fsf_req->qtcb->header.log_length)) {		/* do not trust them ;-) */		if (fsf_req->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",			     fsf_req->qtcb->header.log_start,			     sizeof(struct fsf_qtcb));			goto forget_log;		}		if ((size_t) (fsf_req->qtcb->header.log_start +		     fsf_req->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",					fsf_req->qtcb->header.log_start,					fsf_req->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 *) fsf_req->qtcb +			      fsf_req->qtcb->header.log_start,			      fsf_req->qtcb->header.log_length);	} forget_log:	/* evaluate FSF Protocol Status */	switch (fsf_req->qtcb->prefix.prot_status) {	case FSF_PROT_GOOD:		ZFCP_LOG_TRACE("FSF_PROT_GOOD\n");		break;	case FSF_PROT_FSF_STATUS_PRESENTED:		ZFCP_LOG_TRACE("FSF_PROT_FSF_STATUS_PRESENTED\n");		break;	case FSF_PROT_QTCB_VERSION_ERROR:		ZFCP_LOG_FLAGS(0, "FSF_PROT_QTCB_VERSION_ERROR\n");		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),				fsf_req->qtcb->prefix.prot_status_qual.				version_error.fsf_version, ZFCP_QTCB_VERSION);		/* stop operation for this adapter */		debug_text_exception(adapter->erp_dbf, 0, "prot_ver_err");		zfcp_erp_adapter_shutdown(adapter, 0);		zfcp_cmd_dbf_event_fsf("qverserr", fsf_req,				       &fsf_req->qtcb->prefix.prot_status_qual,				       sizeof (union fsf_prot_status_qual));		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;		break;	case FSF_PROT_SEQ_NUMB_ERROR:		ZFCP_LOG_FLAGS(0, "FSF_PROT_SEQ_NUMB_ERROR\n");		ZFCP_LOG_NORMAL("bug: Sequence number mismatch between "				"driver (0x%x) and adapter %s (0x%x). "				"Restarting all operations on this adapter.\n",				fsf_req->qtcb->prefix.req_seq_no,				zfcp_get_busid_by_adapter(adapter),				fsf_req->qtcb->prefix.prot_status_qual.				sequence_error.exp_req_seq_no);		debug_text_exception(adapter->erp_dbf, 0, "prot_seq_err");		/* restart operation on this adapter */		zfcp_erp_adapter_reopen(adapter, 0);		zfcp_cmd_dbf_event_fsf("seqnoerr", fsf_req,				       &fsf_req->qtcb->prefix.prot_status_qual,				       sizeof (union fsf_prot_status_qual));		fsf_req->status |= ZFCP_STATUS_FSFREQ_RETRY;		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;		break;	case FSF_PROT_UNSUPP_QTCB_TYPE:		ZFCP_LOG_FLAGS(0, "FSF_PROT_UNSUP_QTCB_TYPE\n");		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));		debug_text_exception(adapter->erp_dbf, 0, "prot_unsup_qtcb");		zfcp_erp_adapter_shutdown(adapter, 0);

⌨️ 快捷键说明

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