📄 zfcp_aux.c
字号:
/* * * 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> * Andreas Herrmann <aherrman@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_AUX_REVISION "$Revision: 1.145 $"#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 long zfcp_cfdc_dev_ioctl(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)static struct file_operations zfcp_cfdc_fops = { .unlocked_ioctl = zfcp_cfdc_dev_ioctl,#ifdef CONFIG_COMPAT .compat_ioctl = zfcp_cfdc_dev_ioctl#endif};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>, " "Andreas Herrman <aherrman@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, 0400);MODULE_PARM_DESC(device, "specify initial device");module_param(loglevel, uint, 0400);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");/****************************************************************//************** 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_OTHER/** * zfcp_device_setup - setup function * @str: pointer to parameter string * * Parse "device=..." parameter string. */static int __initzfcp_device_setup(char *devstr){ char *tmp, *str; size_t len; if (!devstr) return 0; len = strlen(devstr) + 1; str = (char *) kmalloc(len, GFP_KERNEL); if (!str) goto err_out; memcpy(str, devstr, len); 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; kfree(str); return 1; err_out: ZFCP_LOG_NORMAL("Parse error for device parameter string %s\n", str); kfree(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); zfcp_erp_wait(adapter); 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; retval = misc_register(&zfcp_cfdc_misc); if (retval != 0) { ZFCP_LOG_INFO("registration of misc device " "zfcp_cfdc failed\n"); goto out; } 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: 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 longzfcp_cfdc_dev_ioctl(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; sense_data = kmalloc(sizeof(struct zfcp_cfdc_sense_data), GFP_KERNEL); if (sense_data == NULL) { retval = -ENOMEM; goto out; } 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; goto out; } } retval = zfcp_fsf_control_file(adapter, &fsf_req, fsf_command, option, sg_list); if (retval) goto out; if ((fsf_req->qtcb->prefix.prot_status != FSF_PROT_GOOD) && (fsf_req->qtcb->prefix.prot_status != FSF_PROT_FSF_STATUS_PRESENTED)) { retval = -ENXIO; goto out; } sense_data->fsf_status = fsf_req->qtcb->header.fsf_status; memcpy(&sense_data->fsf_status_qual, &fsf_req->qtcb->header.fsf_status_qual, sizeof(union fsf_status_qual)); memcpy(&sense_data->payloads, &fsf_req->qtcb->bottom.support.els, 256); retval = copy_to_user(sense_data_user, sense_data, sizeof(struct zfcp_cfdc_sense_data)); if (retval) { retval = -EFAULT; goto out; } if (sense_data->command & ZFCP_CFDC_UPLOAD) { retval = zfcp_sg_list_copy_to_user( &sense_data_user->control_file, sg_list, ZFCP_CFDC_MAX_CONTROL_FILE_SIZE); if (retval) { retval = -EFAULT; goto out; } } out: if (fsf_req != NULL) zfcp_fsf_req_free(fsf_req); if ((adapter != NULL) && (retval != -ENXIO)) zfcp_adapter_put(adapter);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -