zfcp_fsf.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,994 行 · 第 1/5 页
C
1,994 行
/* * * 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.65 $"#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 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 + -
显示快捷键?