📄 viopath.c
字号:
/* -*- linux-c -*- * * iSeries Virtual I/O Message Path code * * Authors: Dave Boutcher <boutcher@us.ibm.com> * Ryan Arnold <ryanarn@us.ibm.com> * Colin Devilbiss <devilbis@us.ibm.com> * * (C) Copyright 2000-2005 IBM Corporation * * This code is used by the iSeries virtual disk, cd, * tape, and console to communicate with OS/400 in another * partition. * * 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 of the * License, or (at your option) anyu 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */#include <linux/module.h>#include <linux/kernel.h>#include <linux/errno.h>#include <linux/vmalloc.h>#include <linux/string.h>#include <linux/proc_fs.h>#include <linux/dma-mapping.h>#include <linux/wait.h>#include <linux/seq_file.h>#include <linux/smp_lock.h>#include <linux/interrupt.h>#include <asm/system.h>#include <asm/uaccess.h>#include <asm/iseries/hv_types.h>#include <asm/iseries/it_exp_vpd_panel.h>#include <asm/iseries/hv_lp_event.h>#include <asm/iseries/hv_lp_config.h>#include <asm/iseries/mf.h>#include <asm/iseries/vio.h>/* Status of the path to each other partition in the system. * This is overkill, since we will only ever establish connections * to our hosting partition and the primary partition on the system. * But this allows for other support in the future. */static struct viopathStatus { int isOpen; /* Did we open the path? */ int isActive; /* Do we have a mon msg outstanding */ int users[VIO_MAX_SUBTYPES]; HvLpInstanceId mSourceInst; HvLpInstanceId mTargetInst; int numberAllocated;} viopathStatus[HVMAXARCHITECTEDLPS];static DEFINE_SPINLOCK(statuslock);/* * For each kind of event we allocate a buffer that is * guaranteed not to cross a page boundary */static unsigned char event_buffer[VIO_MAX_SUBTYPES * 256] __attribute__((__aligned__(4096)));static atomic_t event_buffer_available[VIO_MAX_SUBTYPES];static int event_buffer_initialised;static void handleMonitorEvent(struct HvLpEvent *event);/* * We use this structure to handle asynchronous responses. The caller * blocks on the semaphore and the handler posts the semaphore. However, * if system_state is not SYSTEM_RUNNING, then wait_atomic is used ... */struct alloc_parms { struct semaphore sem; int number; atomic_t wait_atomic; int used_wait_atomic;};/* Put a sequence number in each mon msg. The value is not * important. Start at something other than 0 just for * readability. wrapping this is ok. */static u8 viomonseq = 22;/* Our hosting logical partition. We get this at startup * time, and different modules access this variable directly. */HvLpIndex viopath_hostLp = HvLpIndexInvalid;EXPORT_SYMBOL(viopath_hostLp);HvLpIndex viopath_ourLp = HvLpIndexInvalid;EXPORT_SYMBOL(viopath_ourLp);/* For each kind of incoming event we set a pointer to a * routine to call. */static vio_event_handler_t *vio_handler[VIO_MAX_SUBTYPES];#define VIOPATH_KERN_WARN KERN_WARNING "viopath: "#define VIOPATH_KERN_INFO KERN_INFO "viopath: "static int proc_viopath_show(struct seq_file *m, void *v){ char *buf; u16 vlanMap; dma_addr_t handle; HvLpEvent_Rc hvrc; DECLARE_MUTEX_LOCKED(Semaphore); buf = kmalloc(HW_PAGE_SIZE, GFP_KERNEL); if (!buf) return 0; memset(buf, 0, HW_PAGE_SIZE); handle = dma_map_single(iSeries_vio_dev, buf, HW_PAGE_SIZE, DMA_FROM_DEVICE); hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, HvLpEvent_Type_VirtualIo, viomajorsubtype_config | vioconfigget, HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, viopath_sourceinst(viopath_hostLp), viopath_targetinst(viopath_hostLp), (u64)(unsigned long)&Semaphore, VIOVERSION << 16, ((u64)handle) << 32, HW_PAGE_SIZE, 0, 0); if (hvrc != HvLpEvent_Rc_Good) printk(VIOPATH_KERN_WARN "hv error on op %d\n", (int)hvrc); down(&Semaphore); vlanMap = HvLpConfig_getVirtualLanIndexMap(); buf[HW_PAGE_SIZE-1] = '\0'; seq_printf(m, "%s", buf); seq_printf(m, "AVAILABLE_VETH=%x\n", vlanMap); seq_printf(m, "SRLNBR=%c%c%c%c%c%c%c\n", e2a(xItExtVpdPanel.mfgID[2]), e2a(xItExtVpdPanel.mfgID[3]), e2a(xItExtVpdPanel.systemSerial[1]), e2a(xItExtVpdPanel.systemSerial[2]), e2a(xItExtVpdPanel.systemSerial[3]), e2a(xItExtVpdPanel.systemSerial[4]), e2a(xItExtVpdPanel.systemSerial[5])); dma_unmap_single(iSeries_vio_dev, handle, HW_PAGE_SIZE, DMA_FROM_DEVICE); kfree(buf); return 0;}static int proc_viopath_open(struct inode *inode, struct file *file){ return single_open(file, proc_viopath_show, NULL);}static struct file_operations proc_viopath_operations = { .open = proc_viopath_open, .read = seq_read, .llseek = seq_lseek, .release = single_release,};static int __init vio_proc_init(void){ struct proc_dir_entry *e; e = create_proc_entry("iSeries/config", 0, NULL); if (e) e->proc_fops = &proc_viopath_operations; return 0;}__initcall(vio_proc_init);/* See if a given LP is active. Allow for invalid lps to be passed in * and just return invalid */int viopath_isactive(HvLpIndex lp){ if (lp == HvLpIndexInvalid) return 0; if (lp < HVMAXARCHITECTEDLPS) return viopathStatus[lp].isActive; else return 0;}EXPORT_SYMBOL(viopath_isactive);/* * We cache the source and target instance ids for each * partition. */HvLpInstanceId viopath_sourceinst(HvLpIndex lp){ return viopathStatus[lp].mSourceInst;}EXPORT_SYMBOL(viopath_sourceinst);HvLpInstanceId viopath_targetinst(HvLpIndex lp){ return viopathStatus[lp].mTargetInst;}EXPORT_SYMBOL(viopath_targetinst);/* * Send a monitor message. This is a message with the acknowledge * bit on that the other side will NOT explicitly acknowledge. When * the other side goes down, the hypervisor will acknowledge any * outstanding messages....so we will know when the other side dies. */static void sendMonMsg(HvLpIndex remoteLp){ HvLpEvent_Rc hvrc; viopathStatus[remoteLp].mSourceInst = HvCallEvent_getSourceLpInstanceId(remoteLp, HvLpEvent_Type_VirtualIo); viopathStatus[remoteLp].mTargetInst = HvCallEvent_getTargetLpInstanceId(remoteLp, HvLpEvent_Type_VirtualIo); /* * Deliberately ignore the return code here. if we call this * more than once, we don't care. */ vio_setHandler(viomajorsubtype_monitor, handleMonitorEvent); hvrc = HvCallEvent_signalLpEventFast(remoteLp, HvLpEvent_Type_VirtualIo, viomajorsubtype_monitor, HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_DeferredAck, viopathStatus[remoteLp].mSourceInst, viopathStatus[remoteLp].mTargetInst, viomonseq++, 0, 0, 0, 0, 0); if (hvrc == HvLpEvent_Rc_Good) viopathStatus[remoteLp].isActive = 1; else { printk(VIOPATH_KERN_WARN "could not connect to partition %d\n", remoteLp); viopathStatus[remoteLp].isActive = 0; }}static void handleMonitorEvent(struct HvLpEvent *event){ HvLpIndex remoteLp; int i; /* * This handler is _also_ called as part of the loop * at the end of this routine, so it must be able to * ignore NULL events... */ if (!event) return; /* * First see if this is just a normal monitor message from the * other partition */ if (event->xFlags.xFunction == HvLpEvent_Function_Int) { remoteLp = event->xSourceLp; if (!viopathStatus[remoteLp].isActive) sendMonMsg(remoteLp); return; } /* * This path is for an acknowledgement; the other partition * died */ remoteLp = event->xTargetLp; if ((event->xSourceInstanceId != viopathStatus[remoteLp].mSourceInst) || (event->xTargetInstanceId != viopathStatus[remoteLp].mTargetInst)) { printk(VIOPATH_KERN_WARN "ignoring ack....mismatched instances\n"); return; } printk(VIOPATH_KERN_WARN "partition %d ended\n", remoteLp); viopathStatus[remoteLp].isActive = 0; /* * For each active handler, pass them a NULL * message to indicate that the other partition * died */ for (i = 0; i < VIO_MAX_SUBTYPES; i++) { if (vio_handler[i] != NULL) (*vio_handler[i])(NULL); }}int vio_setHandler(int subtype, vio_event_handler_t *beh){ subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT; if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES)) return -EINVAL; if (vio_handler[subtype] != NULL) return -EBUSY; vio_handler[subtype] = beh; return 0;}EXPORT_SYMBOL(vio_setHandler);int vio_clearHandler(int subtype){ subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT; if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES)) return -EINVAL; if (vio_handler[subtype] == NULL) return -EAGAIN; vio_handler[subtype] = NULL; return 0;}EXPORT_SYMBOL(vio_clearHandler);static void handleConfig(struct HvLpEvent *event){ if (!event) return; if (event->xFlags.xFunction == HvLpEvent_Function_Int) { printk(VIOPATH_KERN_WARN "unexpected config request from partition %d", event->xSourceLp);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -