zfcp_aux.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,982 行 · 第 1/4 页
C
1,982 行
/* * * linux/drivers/s390/scsi/zfcp_aux.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_AUX_REVISION "$Revision: 1.129 $"#include "zfcp_ext.h"/* accumulated log level (module parameter) */static u32 loglevel = ZFCP_LOG_LEVEL_DEFAULTS;static char *device;/*********************** FUNCTION PROTOTYPES *********************************//* written against the module interface */static int __init zfcp_module_init(void);/* FCP related */static void zfcp_ns_gid_pn_handler(unsigned long);/* miscellaneous */static inline int zfcp_sg_list_alloc(struct zfcp_sg_list *, size_t);static inline void zfcp_sg_list_free(struct zfcp_sg_list *);static inline int zfcp_sg_list_copy_from_user(struct zfcp_sg_list *, void __user *, size_t);static inline int zfcp_sg_list_copy_to_user(void __user *, struct zfcp_sg_list *, size_t);static int zfcp_cfdc_dev_ioctl(struct inode *, struct file *, unsigned int, unsigned long);#define ZFCP_CFDC_IOC_MAGIC 0xDD#define ZFCP_CFDC_IOC \ _IOWR(ZFCP_CFDC_IOC_MAGIC, 0, struct zfcp_cfdc_sense_data)#ifdef CONFIG_S390_SUPPORTstatic struct ioctl_trans zfcp_ioctl_trans = {ZFCP_CFDC_IOC, (void*) sys_ioctl};#endifstatic struct file_operations zfcp_cfdc_fops = { .ioctl = zfcp_cfdc_dev_ioctl};static struct miscdevice zfcp_cfdc_misc = { .minor = ZFCP_CFDC_DEV_MINOR, .name = ZFCP_CFDC_DEV_NAME, .fops = &zfcp_cfdc_fops};/*********************** KERNEL/MODULE PARAMETERS ***************************//* declare driver module init/cleanup functions */module_init(zfcp_module_init);MODULE_AUTHOR("Heiko Carstens <heiko.carstens@de.ibm.com>, " "Martin Peschke <mpeschke@de.ibm.com>, " "Raimund Schroeder <raimund.schroeder@de.ibm.com>, " "Wolfgang Taphorn <taphorn@de.ibm.com>, " "Aron Zeh <arzeh@de.ibm.com>, " "IBM Deutschland Entwicklung GmbH");MODULE_DESCRIPTION ("FCP (SCSI over Fibre Channel) HBA driver for IBM eServer zSeries");MODULE_LICENSE("GPL");module_param(device, charp, 0);MODULE_PARM_DESC(device, "specify initial device");module_param(loglevel, uint, 0);MODULE_PARM_DESC(loglevel, "log levels, 8 nibbles: " "FC ERP QDIO CIO Config FSF SCSI Other, " "levels: 0=none 1=normal 2=devel 3=trace");#ifdef ZFCP_PRINT_FLAGSu32 flags_dump = 0;module_param(flags_dump, uint, 0);#endif/****************************************************************//************** Functions without logging ***********************//****************************************************************/void_zfcp_hex_dump(char *addr, int count){ int i; for (i = 0; i < count; i++) { printk("%02x", addr[i]); if ((i % 4) == 3) printk(" "); if ((i % 32) == 31) printk("\n"); } if (((i-1) % 32) != 31) printk("\n");}/****************************************************************//************** Uncategorised Functions *************************//****************************************************************/#define ZFCP_LOG_AREA ZFCP_LOG_AREA_OTHERstatic inline intzfcp_fsf_req_is_scsi_cmnd(struct zfcp_fsf_req *fsf_req){ return ((fsf_req->fsf_command == FSF_QTCB_FCP_CMND) && !(fsf_req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT));}voidzfcp_cmd_dbf_event_fsf(const char *text, struct zfcp_fsf_req *fsf_req, void *add_data, int add_length){ struct zfcp_adapter *adapter = fsf_req->adapter; struct scsi_cmnd *scsi_cmnd; int level = 3; int i; unsigned long flags; write_lock_irqsave(&adapter->cmd_dbf_lock, flags); if (zfcp_fsf_req_is_scsi_cmnd(fsf_req)) { scsi_cmnd = fsf_req->data.send_fcp_command_task.scsi_cmnd; debug_text_event(adapter->cmd_dbf, level, "fsferror"); debug_text_event(adapter->cmd_dbf, level, text); debug_event(adapter->cmd_dbf, level, &fsf_req, sizeof (unsigned long)); debug_event(adapter->cmd_dbf, level, &fsf_req->seq_no, sizeof (u32)); debug_event(adapter->cmd_dbf, level, &scsi_cmnd, sizeof (unsigned long)); debug_event(adapter->cmd_dbf, level, &scsi_cmnd->cmnd, min(ZFCP_CMD_DBF_LENGTH, (int)scsi_cmnd->cmd_len)); for (i = 0; i < add_length; i += ZFCP_CMD_DBF_LENGTH) debug_event(adapter->cmd_dbf, level, (char *) add_data + i, min(ZFCP_CMD_DBF_LENGTH, add_length - i)); } write_unlock_irqrestore(&adapter->cmd_dbf_lock, flags);}/* XXX additionally log unit if available *//* ---> introduce new parameter for unit, see 2.4 code */voidzfcp_cmd_dbf_event_scsi(const char *text, struct scsi_cmnd *scsi_cmnd){ struct zfcp_adapter *adapter; union zfcp_req_data *req_data; struct zfcp_fsf_req *fsf_req; int level = ((host_byte(scsi_cmnd->result) != 0) ? 1 : 5); unsigned long flags; adapter = (struct zfcp_adapter *) scsi_cmnd->device->host->hostdata[0]; req_data = (union zfcp_req_data *) scsi_cmnd->host_scribble; fsf_req = (req_data ? req_data->send_fcp_command_task.fsf_req : NULL); write_lock_irqsave(&adapter->cmd_dbf_lock, flags); debug_text_event(adapter->cmd_dbf, level, "hostbyte"); debug_text_event(adapter->cmd_dbf, level, text); debug_event(adapter->cmd_dbf, level, &scsi_cmnd->result, sizeof (u32)); debug_event(adapter->cmd_dbf, level, &scsi_cmnd, sizeof (unsigned long)); debug_event(adapter->cmd_dbf, level, &scsi_cmnd->cmnd, min(ZFCP_CMD_DBF_LENGTH, (int)scsi_cmnd->cmd_len)); if (likely(fsf_req)) { debug_event(adapter->cmd_dbf, level, &fsf_req, sizeof (unsigned long)); debug_event(adapter->cmd_dbf, level, &fsf_req->seq_no, sizeof (u32)); } else { debug_text_event(adapter->cmd_dbf, level, ""); debug_text_event(adapter->cmd_dbf, level, ""); } write_unlock_irqrestore(&adapter->cmd_dbf_lock, flags);}voidzfcp_in_els_dbf_event(struct zfcp_adapter *adapter, const char *text, struct fsf_status_read_buffer *status_buffer, int length){ int level = 1; int i; debug_text_event(adapter->in_els_dbf, level, text); debug_event(adapter->in_els_dbf, level, &status_buffer->d_id, 8); for (i = 0; i < length; i += ZFCP_IN_ELS_DBF_LENGTH) debug_event(adapter->in_els_dbf, level, (char *) status_buffer->payload + i, min(ZFCP_IN_ELS_DBF_LENGTH, length - i));}/** * zfcp_device_setup - setup function * @str: pointer to parameter string * * Parse "device=..." parameter string. */static int __initzfcp_device_setup(char *str){ char *tmp; if (!str) return 0; tmp = strchr(str, ','); if (!tmp) goto err_out; *tmp++ = '\0'; strncpy(zfcp_data.init_busid, str, BUS_ID_SIZE); zfcp_data.init_busid[BUS_ID_SIZE-1] = '\0'; zfcp_data.init_wwpn = simple_strtoull(tmp, &tmp, 0); if (*tmp++ != ',') goto err_out; if (*tmp == '\0') goto err_out; zfcp_data.init_fcp_lun = simple_strtoull(tmp, &tmp, 0); if (*tmp != '\0') goto err_out; return 1; err_out: ZFCP_LOG_NORMAL("Parse error for device parameter string %s\n", str); return 0;}static void __initzfcp_init_device_configure(void){ struct zfcp_adapter *adapter; struct zfcp_port *port; struct zfcp_unit *unit; down(&zfcp_data.config_sema); read_lock_irq(&zfcp_data.config_lock); adapter = zfcp_get_adapter_by_busid(zfcp_data.init_busid); if (adapter) zfcp_adapter_get(adapter); read_unlock_irq(&zfcp_data.config_lock); if (adapter == NULL) goto out_adapter; port = zfcp_port_enqueue(adapter, zfcp_data.init_wwpn, 0, 0); if (!port) goto out_port; unit = zfcp_unit_enqueue(port, zfcp_data.init_fcp_lun); if (!unit) goto out_unit; up(&zfcp_data.config_sema); ccw_device_set_online(adapter->ccw_device); wait_event(unit->scsi_add_wq, atomic_read(&unit->scsi_add_work) == 0); down(&zfcp_data.config_sema); zfcp_unit_put(unit); out_unit: zfcp_port_put(port); out_port: zfcp_adapter_put(adapter); out_adapter: up(&zfcp_data.config_sema); return;}static int __initzfcp_module_init(void){ int retval = 0; atomic_set(&zfcp_data.loglevel, loglevel); /* initialize adapter list */ INIT_LIST_HEAD(&zfcp_data.adapter_list_head); /* initialize adapters to be removed list head */ INIT_LIST_HEAD(&zfcp_data.adapter_remove_lh); zfcp_transport_template = fc_attach_transport(&zfcp_transport_functions); if (!zfcp_transport_template) return -ENODEV;#ifdef CONFIG_S390_SUPPORT retval = register_ioctl32_conversion(zfcp_ioctl_trans.cmd, zfcp_ioctl_trans.handler); if (retval != 0) { ZFCP_LOG_INFO("registration of ioctl32 conversion failed\n"); goto out_ioctl32; }#endif retval = misc_register(&zfcp_cfdc_misc); if (retval != 0) { ZFCP_LOG_INFO("registration of misc device " "zfcp_cfdc failed\n"); goto out_misc_register; } else { ZFCP_LOG_TRACE("major/minor for zfcp_cfdc: %d/%d\n", ZFCP_CFDC_DEV_MAJOR, zfcp_cfdc_misc.minor); } /* Initialise proc semaphores */ sema_init(&zfcp_data.config_sema, 1); /* initialise configuration rw lock */ rwlock_init(&zfcp_data.config_lock); /* save address of data structure managing the driver module */ zfcp_data.scsi_host_template.module = THIS_MODULE; /* setup dynamic I/O */ retval = zfcp_ccw_register(); if (retval) { ZFCP_LOG_NORMAL("registration with common I/O layer failed\n"); goto out_ccw_register; } if (zfcp_device_setup(device)) zfcp_init_device_configure(); goto out; out_ccw_register: misc_deregister(&zfcp_cfdc_misc); out_misc_register:#ifdef CONFIG_S390_SUPPORT unregister_ioctl32_conversion(zfcp_ioctl_trans.cmd); out_ioctl32:#endif out: return retval;}/* * function: zfcp_cfdc_dev_ioctl * * purpose: Handle control file upload/download transaction via IOCTL * interface * * returns: 0 - Operation completed successfuly * -ENOTTY - Unknown IOCTL command * -EINVAL - Invalid sense data record * -ENXIO - The FCP adapter is not available * -EOPNOTSUPP - The FCP adapter does not have CFDC support * -ENOMEM - Insufficient memory * -EFAULT - User space memory I/O operation fault * -EPERM - Cannot create or queue FSF request or create SBALs * -ERESTARTSYS- Received signal (is mapped to EAGAIN by VFS) */static intzfcp_cfdc_dev_ioctl(struct inode *inode, struct file *file, unsigned int command, unsigned long buffer){ struct zfcp_cfdc_sense_data sense_data, __user *sense_data_user; struct zfcp_adapter *adapter = NULL; struct zfcp_fsf_req *fsf_req = NULL; struct zfcp_sg_list *sg_list = NULL; u32 fsf_command, option; char *bus_id = NULL; int retval = 0; sg_list = kmalloc(sizeof(struct zfcp_sg_list), GFP_KERNEL); if (sg_list == NULL) { retval = -ENOMEM; goto out; } memset(sg_list, 0, sizeof(*sg_list)); if (command != ZFCP_CFDC_IOC) { ZFCP_LOG_INFO("IOC request code 0x%x invalid\n", command); retval = -ENOTTY; goto out; } if ((sense_data_user = (void __user *) buffer) == NULL) { ZFCP_LOG_INFO("sense data record is required\n"); retval = -EINVAL; goto out; } retval = copy_from_user(&sense_data, sense_data_user, sizeof(struct zfcp_cfdc_sense_data)); if (retval) { retval = -EFAULT; goto out; } if (sense_data.signature != ZFCP_CFDC_SIGNATURE) { ZFCP_LOG_INFO("invalid sense data request signature 0x%08x\n", ZFCP_CFDC_SIGNATURE); retval = -EINVAL; goto out; } switch (sense_data.command) { case ZFCP_CFDC_CMND_DOWNLOAD_NORMAL: fsf_command = FSF_QTCB_DOWNLOAD_CONTROL_FILE; option = FSF_CFDC_OPTION_NORMAL_MODE; break; case ZFCP_CFDC_CMND_DOWNLOAD_FORCE: fsf_command = FSF_QTCB_DOWNLOAD_CONTROL_FILE; option = FSF_CFDC_OPTION_FORCE; break; case ZFCP_CFDC_CMND_FULL_ACCESS: fsf_command = FSF_QTCB_DOWNLOAD_CONTROL_FILE; option = FSF_CFDC_OPTION_FULL_ACCESS; break; case ZFCP_CFDC_CMND_RESTRICTED_ACCESS: fsf_command = FSF_QTCB_DOWNLOAD_CONTROL_FILE; option = FSF_CFDC_OPTION_RESTRICTED_ACCESS; break; case ZFCP_CFDC_CMND_UPLOAD: fsf_command = FSF_QTCB_UPLOAD_CONTROL_FILE; option = 0; break; default: ZFCP_LOG_INFO("invalid command code 0x%08x\n", sense_data.command); retval = -EINVAL; goto out; } bus_id = kmalloc(BUS_ID_SIZE, GFP_KERNEL); if (bus_id == NULL) { retval = -ENOMEM; goto out; } snprintf(bus_id, BUS_ID_SIZE, "%d.%d.%04x", (sense_data.devno >> 24), (sense_data.devno >> 16) & 0xFF, (sense_data.devno & 0xFFFF)); read_lock_irq(&zfcp_data.config_lock); adapter = zfcp_get_adapter_by_busid(bus_id); if (adapter) zfcp_adapter_get(adapter); read_unlock_irq(&zfcp_data.config_lock); kfree(bus_id); if (adapter == NULL) { ZFCP_LOG_INFO("invalid adapter\n"); retval = -ENXIO; goto out; } if (sense_data.command & ZFCP_CFDC_WITH_CONTROL_FILE) { retval = zfcp_sg_list_alloc(sg_list, ZFCP_CFDC_MAX_CONTROL_FILE_SIZE); if (retval) { retval = -ENOMEM; goto out; } } if ((sense_data.command & ZFCP_CFDC_DOWNLOAD) && (sense_data.command & ZFCP_CFDC_WITH_CONTROL_FILE)) { retval = zfcp_sg_list_copy_from_user( sg_list, &sense_data_user->control_file, ZFCP_CFDC_MAX_CONTROL_FILE_SIZE); if (retval) { retval = -EFAULT;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?