aboutsummaryrefslogtreecommitdiffstats
path: root/arch/parisc
diff options
context:
space:
mode:
Diffstat (limited to 'arch/parisc')
-rw-r--r--arch/parisc/include/asm/parisc-device.h4
-rw-r--r--arch/parisc/include/asm/posix_types.h3
-rw-r--r--arch/parisc/include/asm/ptrace.h2
-rw-r--r--arch/parisc/include/asm/smp.h2
-rw-r--r--arch/parisc/include/asm/tlbflush.h5
-rw-r--r--arch/parisc/kernel/drivers.c6
-rw-r--r--arch/parisc/kernel/ptrace.c10
-rw-r--r--arch/parisc/kernel/signal.c2
-rw-r--r--arch/parisc/kernel/traps.c43
9 files changed, 38 insertions, 39 deletions
diff --git a/arch/parisc/include/asm/parisc-device.h b/arch/parisc/include/asm/parisc-device.h
index 7aa13f2add7a..9afdad6c2ffb 100644
--- a/arch/parisc/include/asm/parisc-device.h
+++ b/arch/parisc/include/asm/parisc-device.h
@@ -42,9 +42,9 @@ struct parisc_driver {
42#define to_parisc_driver(d) container_of(d, struct parisc_driver, drv) 42#define to_parisc_driver(d) container_of(d, struct parisc_driver, drv)
43#define parisc_parent(d) to_parisc_device(d->dev.parent) 43#define parisc_parent(d) to_parisc_device(d->dev.parent)
44 44
45static inline char *parisc_pathname(struct parisc_device *d) 45static inline const char *parisc_pathname(struct parisc_device *d)
46{ 46{
47 return d->dev.bus_id; 47 return dev_name(&d->dev);
48} 48}
49 49
50static inline void 50static inline void
diff --git a/arch/parisc/include/asm/posix_types.h b/arch/parisc/include/asm/posix_types.h
index bb725a6630bb..00da29a340ba 100644
--- a/arch/parisc/include/asm/posix_types.h
+++ b/arch/parisc/include/asm/posix_types.h
@@ -24,13 +24,12 @@ typedef int __kernel_daddr_t;
24typedef unsigned long __kernel_size_t; 24typedef unsigned long __kernel_size_t;
25typedef long __kernel_ssize_t; 25typedef long __kernel_ssize_t;
26typedef long __kernel_ptrdiff_t; 26typedef long __kernel_ptrdiff_t;
27typedef long __kernel_time_t;
28#else 27#else
29typedef unsigned int __kernel_size_t; 28typedef unsigned int __kernel_size_t;
30typedef int __kernel_ssize_t; 29typedef int __kernel_ssize_t;
31typedef int __kernel_ptrdiff_t; 30typedef int __kernel_ptrdiff_t;
32typedef long __kernel_time_t;
33#endif 31#endif
32typedef long __kernel_time_t;
34typedef char * __kernel_caddr_t; 33typedef char * __kernel_caddr_t;
35 34
36typedef unsigned short __kernel_uid16_t; 35typedef unsigned short __kernel_uid16_t;
diff --git a/arch/parisc/include/asm/ptrace.h b/arch/parisc/include/asm/ptrace.h
index afa5333187b4..302f68dc889c 100644
--- a/arch/parisc/include/asm/ptrace.h
+++ b/arch/parisc/include/asm/ptrace.h
@@ -47,8 +47,6 @@ struct pt_regs {
47 47
48#define task_regs(task) ((struct pt_regs *) ((char *)(task) + TASK_REGS)) 48#define task_regs(task) ((struct pt_regs *) ((char *)(task) + TASK_REGS))
49 49
50#define __ARCH_WANT_COMPAT_SYS_PTRACE
51
52struct task_struct; 50struct task_struct;
53#define arch_has_single_step() 1 51#define arch_has_single_step() 1
54void user_disable_single_step(struct task_struct *task); 52void user_disable_single_step(struct task_struct *task);
diff --git a/arch/parisc/include/asm/smp.h b/arch/parisc/include/asm/smp.h
index 398cdbaf4e54..409e698f4361 100644
--- a/arch/parisc/include/asm/smp.h
+++ b/arch/parisc/include/asm/smp.h
@@ -44,8 +44,6 @@ extern void arch_send_call_function_ipi(cpumask_t mask);
44 44
45#define PROC_CHANGE_PENALTY 15 /* Schedule penalty */ 45#define PROC_CHANGE_PENALTY 15 /* Schedule penalty */
46 46
47extern unsigned long cpu_present_mask;
48
49#define raw_smp_processor_id() (current_thread_info()->cpu) 47#define raw_smp_processor_id() (current_thread_info()->cpu)
50 48
51#else /* CONFIG_SMP */ 49#else /* CONFIG_SMP */
diff --git a/arch/parisc/include/asm/tlbflush.h b/arch/parisc/include/asm/tlbflush.h
index b72ec66db699..1f6fd4fc05b9 100644
--- a/arch/parisc/include/asm/tlbflush.h
+++ b/arch/parisc/include/asm/tlbflush.h
@@ -44,9 +44,12 @@ static inline void flush_tlb_mm(struct mm_struct *mm)
44{ 44{
45 BUG_ON(mm == &init_mm); /* Should never happen */ 45 BUG_ON(mm == &init_mm); /* Should never happen */
46 46
47#ifdef CONFIG_SMP 47#if 1 || defined(CONFIG_SMP)
48 flush_tlb_all(); 48 flush_tlb_all();
49#else 49#else
50 /* FIXME: currently broken, causing space id and protection ids
51 * to go out of sync, resulting in faults on userspace accesses.
52 */
50 if (mm) { 53 if (mm) {
51 if (mm->context != 0) 54 if (mm->context != 0)
52 free_sid(mm->context); 55 free_sid(mm->context);
diff --git a/arch/parisc/kernel/drivers.c b/arch/parisc/kernel/drivers.c
index 2ca654bd6322..884b7ce16a3b 100644
--- a/arch/parisc/kernel/drivers.c
+++ b/arch/parisc/kernel/drivers.c
@@ -43,7 +43,7 @@ struct hppa_dma_ops *hppa_dma_ops __read_mostly;
43EXPORT_SYMBOL(hppa_dma_ops); 43EXPORT_SYMBOL(hppa_dma_ops);
44 44
45static struct device root = { 45static struct device root = {
46 .bus_id = "parisc", 46 .init_name = "parisc",
47}; 47};
48 48
49static inline int check_dev(struct device *dev) 49static inline int check_dev(struct device *dev)
@@ -393,7 +393,8 @@ EXPORT_SYMBOL(print_pci_hwpath);
393static void setup_bus_id(struct parisc_device *padev) 393static void setup_bus_id(struct parisc_device *padev)
394{ 394{
395 struct hardware_path path; 395 struct hardware_path path;
396 char *output = padev->dev.bus_id; 396 char name[20];
397 char *output = name;
397 int i; 398 int i;
398 399
399 get_node_path(padev->dev.parent, &path); 400 get_node_path(padev->dev.parent, &path);
@@ -404,6 +405,7 @@ static void setup_bus_id(struct parisc_device *padev)
404 output += sprintf(output, "%u:", (unsigned char) path.bc[i]); 405 output += sprintf(output, "%u:", (unsigned char) path.bc[i]);
405 } 406 }
406 sprintf(output, "%u", (unsigned char) padev->hw_path); 407 sprintf(output, "%u", (unsigned char) padev->hw_path);
408 dev_set_name(&padev->dev, name);
407} 409}
408 410
409struct parisc_device * create_tree_node(char id, struct device *parent) 411struct parisc_device * create_tree_node(char id, struct device *parent)
diff --git a/arch/parisc/kernel/ptrace.c b/arch/parisc/kernel/ptrace.c
index 90904f9dfc50..927db3668b6f 100644
--- a/arch/parisc/kernel/ptrace.c
+++ b/arch/parisc/kernel/ptrace.c
@@ -183,10 +183,10 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
183 * being 64 bit in both cases. 183 * being 64 bit in both cases.
184 */ 184 */
185 185
186static long translate_usr_offset(long offset) 186static compat_ulong_t translate_usr_offset(compat_ulong_t offset)
187{ 187{
188 if (offset < 0) 188 if (offset < 0)
189 return -1; 189 return sizeof(struct pt_regs);
190 else if (offset <= 32*4) /* gr[0..31] */ 190 else if (offset <= 32*4) /* gr[0..31] */
191 return offset * 2 + 4; 191 return offset * 2 + 4;
192 else if (offset <= 32*4+32*8) /* gr[0..31] + fr[0..31] */ 192 else if (offset <= 32*4+32*8) /* gr[0..31] + fr[0..31] */
@@ -194,7 +194,7 @@ static long translate_usr_offset(long offset)
194 else if (offset < sizeof(struct pt_regs)/2 + 32*4) 194 else if (offset < sizeof(struct pt_regs)/2 + 32*4)
195 return offset * 2 + 4 - 32*8; 195 return offset * 2 + 4 - 32*8;
196 else 196 else
197 return -1; 197 return sizeof(struct pt_regs);
198} 198}
199 199
200long compat_arch_ptrace(struct task_struct *child, compat_long_t request, 200long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
@@ -209,7 +209,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
209 if (addr & (sizeof(compat_uint_t)-1)) 209 if (addr & (sizeof(compat_uint_t)-1))
210 break; 210 break;
211 addr = translate_usr_offset(addr); 211 addr = translate_usr_offset(addr);
212 if (addr < 0) 212 if (addr >= sizeof(struct pt_regs))
213 break; 213 break;
214 214
215 tmp = *(compat_uint_t *) ((char *) task_regs(child) + addr); 215 tmp = *(compat_uint_t *) ((char *) task_regs(child) + addr);
@@ -236,7 +236,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
236 if (addr & (sizeof(compat_uint_t)-1)) 236 if (addr & (sizeof(compat_uint_t)-1))
237 break; 237 break;
238 addr = translate_usr_offset(addr); 238 addr = translate_usr_offset(addr);
239 if (addr < 0) 239 if (addr >= sizeof(struct pt_regs))
240 break; 240 break;
241 if (addr >= PT_FR0 && addr <= PT_FR31 + 4) { 241 if (addr >= PT_FR0 && addr <= PT_FR31 + 4) {
242 /* Special case, fp regs are 64 bits anyway */ 242 /* Special case, fp regs are 64 bits anyway */
diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c
index 06213d1d6d95..f82544225e8e 100644
--- a/arch/parisc/kernel/signal.c
+++ b/arch/parisc/kernel/signal.c
@@ -182,7 +182,7 @@ give_sigsegv:
182 si.si_errno = 0; 182 si.si_errno = 0;
183 si.si_code = SI_KERNEL; 183 si.si_code = SI_KERNEL;
184 si.si_pid = task_pid_vnr(current); 184 si.si_pid = task_pid_vnr(current);
185 si.si_uid = current->uid; 185 si.si_uid = current_uid();
186 si.si_addr = &frame->uc; 186 si.si_addr = &frame->uc;
187 force_sig_info(SIGSEGV, &si, current); 187 force_sig_info(SIGSEGV, &si, current);
188 return; 188 return;
diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c
index 675f1d098f05..4c771cd580ec 100644
--- a/arch/parisc/kernel/traps.c
+++ b/arch/parisc/kernel/traps.c
@@ -24,7 +24,6 @@
24#include <linux/init.h> 24#include <linux/init.h>
25#include <linux/interrupt.h> 25#include <linux/interrupt.h>
26#include <linux/console.h> 26#include <linux/console.h>
27#include <linux/kallsyms.h>
28#include <linux/bug.h> 27#include <linux/bug.h>
29 28
30#include <asm/assembly.h> 29#include <asm/assembly.h>
@@ -51,7 +50,7 @@
51DEFINE_SPINLOCK(pa_dbit_lock); 50DEFINE_SPINLOCK(pa_dbit_lock);
52#endif 51#endif
53 52
54void parisc_show_stack(struct task_struct *t, unsigned long *sp, 53static void parisc_show_stack(struct task_struct *task, unsigned long *sp,
55 struct pt_regs *regs); 54 struct pt_regs *regs);
56 55
57static int printbinary(char *buf, unsigned long x, int nbits) 56static int printbinary(char *buf, unsigned long x, int nbits)
@@ -121,18 +120,19 @@ static void print_fr(char *level, struct pt_regs *regs)
121 120
122void show_regs(struct pt_regs *regs) 121void show_regs(struct pt_regs *regs)
123{ 122{
124 int i; 123 int i, user;
125 char *level; 124 char *level;
126 unsigned long cr30, cr31; 125 unsigned long cr30, cr31;
127 126
128 level = user_mode(regs) ? KERN_DEBUG : KERN_CRIT; 127 user = user_mode(regs);
128 level = user ? KERN_DEBUG : KERN_CRIT;
129 129
130 print_gr(level, regs); 130 print_gr(level, regs);
131 131
132 for (i = 0; i < 8; i += 4) 132 for (i = 0; i < 8; i += 4)
133 PRINTREGS(level, regs->sr, "sr", RFMT, i); 133 PRINTREGS(level, regs->sr, "sr", RFMT, i);
134 134
135 if (user_mode(regs)) 135 if (user)
136 print_fr(level, regs); 136 print_fr(level, regs);
137 137
138 cr30 = mfctl(30); 138 cr30 = mfctl(30);
@@ -145,14 +145,18 @@ void show_regs(struct pt_regs *regs)
145 printk("%s CPU: %8d CR30: " RFMT " CR31: " RFMT "\n", 145 printk("%s CPU: %8d CR30: " RFMT " CR31: " RFMT "\n",
146 level, current_thread_info()->cpu, cr30, cr31); 146 level, current_thread_info()->cpu, cr30, cr31);
147 printk("%s ORIG_R28: " RFMT "\n", level, regs->orig_r28); 147 printk("%s ORIG_R28: " RFMT "\n", level, regs->orig_r28);
148 printk(level); 148
149 print_symbol(" IAOQ[0]: %s\n", regs->iaoq[0]); 149 if (user) {
150 printk(level); 150 printk("%s IAOQ[0]: " RFMT "\n", level, regs->iaoq[0]);
151 print_symbol(" IAOQ[1]: %s\n", regs->iaoq[1]); 151 printk("%s IAOQ[1]: " RFMT "\n", level, regs->iaoq[1]);
152 printk(level); 152 printk("%s RP(r2): " RFMT "\n", level, regs->gr[2]);
153 print_symbol(" RP(r2): %s\n", regs->gr[2]); 153 } else {
154 154 printk("%s IAOQ[0]: %pS\n", level, (void *) regs->iaoq[0]);
155 parisc_show_stack(current, NULL, regs); 155 printk("%s IAOQ[1]: %pS\n", level, (void *) regs->iaoq[1]);
156 printk("%s RP(r2): %pS\n", level, (void *) regs->gr[2]);
157
158 parisc_show_stack(current, NULL, regs);
159 }
156} 160}
157 161
158 162
@@ -173,20 +177,15 @@ static void do_show_stack(struct unwind_frame_info *info)
173 break; 177 break;
174 178
175 if (__kernel_text_address(info->ip)) { 179 if (__kernel_text_address(info->ip)) {
176 printk("%s [<" RFMT ">] ", (i&0x3)==1 ? KERN_CRIT : "", info->ip); 180 printk(KERN_CRIT " [<" RFMT ">] %pS\n",
177#ifdef CONFIG_KALLSYMS 181 info->ip, (void *) info->ip);
178 print_symbol("%s\n", info->ip);
179#else
180 if ((i & 0x03) == 0)
181 printk("\n");
182#endif
183 i++; 182 i++;
184 } 183 }
185 } 184 }
186 printk("\n"); 185 printk(KERN_CRIT "\n");
187} 186}
188 187
189void parisc_show_stack(struct task_struct *task, unsigned long *sp, 188static void parisc_show_stack(struct task_struct *task, unsigned long *sp,
190 struct pt_regs *regs) 189 struct pt_regs *regs)
191{ 190{
192 struct unwind_frame_info info; 191 struct unwind_frame_info info;
truct op_struct *op = get_op_struct(); int noblock = ((flags & O_NONBLOCK) != 0); ssize_t ret; struct viot_devinfo_struct devi; if (op == NULL) return -ENOMEM; get_dev_info(file->f_dentry->d_inode, &devi); /* * We need to make sure we can send a request. We use * a semaphore to keep track of # requests in use. If * we are non-blocking, make sure we don't block on the * semaphore */ if (noblock) { if (down_trylock(&reqSem)) { ret = -EWOULDBLOCK; goto free_op; } } else down(&reqSem); chg_state(devi.devno, VIOT_READING, file); /* Allocate a DMA buffer */ op->dev = tape_device[devi.devno]; op->buffer = dma_alloc_coherent(op->dev, count, &op->dmaaddr, GFP_ATOMIC); if (op->buffer == NULL) { ret = -EFAULT; goto up_sem; } op->count = count; init_completion(&op->com); hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, HvLpEvent_Type_VirtualIo, viomajorsubtype_tape | viotaperead, HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, viopath_sourceinst(viopath_hostLp), viopath_targetinst(viopath_hostLp), (u64)(unsigned long)op, VIOVERSION << 16, ((u64)devi.devno << 48) | op->dmaaddr, count, 0, 0); if (hvrc != HvLpEvent_Rc_Good) { printk(VIOTAPE_KERN_WARN "tape hv error on op %d\n", (int)hvrc); ret = -EIO; goto free_dma; } wait_for_completion(&op->com); if (op->rc) ret = tape_rc_to_errno(op->rc, "read", devi.devno); else { ret = op->count; if (ret && copy_to_user(buf, op->buffer, ret)) { printk(VIOTAPE_KERN_WARN "error on copy_to_user\n"); ret = -EFAULT; } } free_dma: dma_free_coherent(op->dev, count, op->buffer, op->dmaaddr); up_sem: up(&reqSem); free_op: free_op_struct(op); return ret; } /* ioctl */ static int viotap_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { HvLpEvent_Rc hvrc; int ret; struct viot_devinfo_struct devi; struct mtop mtc; u32 myOp; struct op_struct *op = get_op_struct(); if (op == NULL) return -ENOMEM; get_dev_info(file->f_dentry->d_inode, &devi); down(&reqSem); ret = -EINVAL; switch (cmd) { case MTIOCTOP: ret = -EFAULT; /* * inode is null if and only if we (the kernel) * made the request */ if (inode == NULL) memcpy(&mtc, (void *) arg, sizeof(struct mtop)); else if (copy_from_user((char *)&mtc, (char *)arg, sizeof(struct mtop))) goto free_op; ret = -EIO; switch (mtc.mt_op) { case MTRESET: myOp = VIOTAPOP_RESET; break; case MTFSF: myOp = VIOTAPOP_FSF; break; case MTBSF: myOp = VIOTAPOP_BSF; break; case MTFSR: myOp = VIOTAPOP_FSR; break; case MTBSR: myOp = VIOTAPOP_BSR; break; case MTWEOF: myOp = VIOTAPOP_WEOF; break; case MTREW: myOp = VIOTAPOP_REW; break; case MTNOP: myOp = VIOTAPOP_NOP; break; case MTEOM: myOp = VIOTAPOP_EOM; break; case MTERASE: myOp = VIOTAPOP_ERASE; break; case MTSETBLK: myOp = VIOTAPOP_SETBLK; break; case MTSETDENSITY: myOp = VIOTAPOP_SETDENSITY; break; case MTTELL: myOp = VIOTAPOP_GETPOS; break; case MTSEEK: myOp = VIOTAPOP_SETPOS; break; case MTSETPART: myOp = VIOTAPOP_SETPART; break; case MTOFFL: myOp = VIOTAPOP_UNLOAD; break; default: printk(VIOTAPE_KERN_WARN "MTIOCTOP called " "with invalid op 0x%x\n", mtc.mt_op); goto free_op; } /* * if we moved the head, we are no longer * reading or writing */ switch (mtc.mt_op) { case MTFSF: case MTBSF: case MTFSR: case MTBSR: case MTTELL: case MTSEEK: case MTREW: chg_state(devi.devno, VIOT_IDLE, file); } init_completion(&op->com); hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, HvLpEvent_Type_VirtualIo, viomajorsubtype_tape | viotapeop, HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, viopath_sourceinst(viopath_hostLp), viopath_targetinst(viopath_hostLp), (u64)(unsigned long)op, VIOVERSION << 16, ((u64)devi.devno << 48), 0, (((u64)myOp) << 32) | mtc.mt_count, 0); if (hvrc != HvLpEvent_Rc_Good) { printk(VIOTAPE_KERN_WARN "hv error on op %d\n", (int)hvrc); goto free_op; } wait_for_completion(&op->com); ret = tape_rc_to_errno(op->rc, "tape operation", devi.devno); goto free_op; case MTIOCGET: ret = -EIO; init_completion(&op->com); hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, HvLpEvent_Type_VirtualIo, viomajorsubtype_tape | viotapegetstatus, HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, viopath_sourceinst(viopath_hostLp), viopath_targetinst(viopath_hostLp), (u64)(unsigned long)op, VIOVERSION << 16, ((u64)devi.devno << 48), 0, 0, 0); if (hvrc != HvLpEvent_Rc_Good) { printk(VIOTAPE_KERN_WARN "hv error on op %d\n", (int)hvrc); goto free_op; } wait_for_completion(&op->com); /* Operation is complete - grab the error code */ ret = tape_rc_to_errno(op->rc, "get status", devi.devno); free_op_struct(op); up(&reqSem); if ((ret == 0) && copy_to_user((void *)arg, &viomtget[devi.devno], sizeof(viomtget[0]))) ret = -EFAULT; return ret; case MTIOCPOS: printk(VIOTAPE_KERN_WARN "Got an (unsupported) MTIOCPOS\n"); break; default: printk(VIOTAPE_KERN_WARN "got an unsupported ioctl 0x%0x\n", cmd); break; } free_op: free_op_struct(op); up(&reqSem); return ret; } static int viotap_open(struct inode *inode, struct file *file) { HvLpEvent_Rc hvrc; struct viot_devinfo_struct devi; int ret; struct op_struct *op = get_op_struct(); if (op == NULL) return -ENOMEM; get_dev_info(file->f_dentry->d_inode, &devi); /* Note: We currently only support one mode! */ if ((devi.devno >= viotape_numdev) || (devi.mode)) { ret = -ENODEV; goto free_op; } init_completion(&op->com); hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, HvLpEvent_Type_VirtualIo, viomajorsubtype_tape | viotapeopen, HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, viopath_sourceinst(viopath_hostLp), viopath_targetinst(viopath_hostLp), (u64)(unsigned long)op, VIOVERSION << 16, ((u64)devi.devno << 48), 0, 0, 0); if (hvrc != 0) { printk(VIOTAPE_KERN_WARN "bad rc on signalLpEvent %d\n", (int) hvrc); ret = -EIO; goto free_op; } wait_for_completion(&op->com); ret = tape_rc_to_errno(op->rc, "open", devi.devno); free_op: free_op_struct(op); return ret; } static int viotap_release(struct inode *inode, struct file *file) { HvLpEvent_Rc hvrc; struct viot_devinfo_struct devi; int ret = 0; struct op_struct *op = get_op_struct(); if (op == NULL) return -ENOMEM; init_completion(&op->com); get_dev_info(file->f_dentry->d_inode, &devi); if (devi.devno >= viotape_numdev) { ret = -ENODEV; goto free_op; } chg_state(devi.devno, VIOT_IDLE, file); if (devi.rewind) { hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, HvLpEvent_Type_VirtualIo, viomajorsubtype_tape | viotapeop, HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, viopath_sourceinst(viopath_hostLp), viopath_targetinst(viopath_hostLp), (u64)(unsigned long)op, VIOVERSION << 16, ((u64)devi.devno << 48), 0, ((u64)VIOTAPOP_REW) << 32, 0); wait_for_completion(&op->com); tape_rc_to_errno(op->rc, "rewind", devi.devno); } hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, HvLpEvent_Type_VirtualIo, viomajorsubtype_tape | viotapeclose, HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, viopath_sourceinst(viopath_hostLp), viopath_targetinst(viopath_hostLp), (u64)(unsigned long)op, VIOVERSION << 16, ((u64)devi.devno << 48), 0, 0, 0); if (hvrc != 0) { printk(VIOTAPE_KERN_WARN "bad rc on signalLpEvent %d\n", (int) hvrc); ret = -EIO; goto free_op; } wait_for_completion(&op->com); if (op->rc) printk(VIOTAPE_KERN_WARN "close failed\n"); free_op: free_op_struct(op); return ret; } struct file_operations viotap_fops = { owner: THIS_MODULE, read: viotap_read, write: viotap_write, ioctl: viotap_ioctl, open: viotap_open, release: viotap_release, }; /* Handle interrupt events for tape */ static void vioHandleTapeEvent(struct HvLpEvent *event) { int tapeminor; struct op_struct *op; struct viotapelpevent *tevent = (struct viotapelpevent *)event; if (event == NULL) { /* Notification that a partition went away! */ if (!viopath_isactive(viopath_hostLp)) { /* TODO! Clean up */ } return; } tapeminor = event->xSubtype & VIOMINOR_SUBTYPE_MASK; op = (struct op_struct *)event->xCorrelationToken; switch (tapeminor) { case viotapegetinfo: case viotapeopen: case viotapeclose: op->rc = tevent->sub_type_result; complete(&op->com); break; case viotaperead: op->rc = tevent->sub_type_result; op->count = tevent->len; complete(&op->com); break; case viotapewrite: if (op->non_blocking) { dma_free_coherent(op->dev, op->count, op->buffer, op->dmaaddr); free_op_struct(op); up(&reqSem); } else { op->rc = tevent->sub_type_result; op->count = tevent->len; complete(&op->com); } break; case viotapeop: case viotapegetpos: case viotapesetpos: case viotapegetstatus: if (op) { op->count = tevent->u.op.count; op->rc = tevent->sub_type_result; if (!op->non_blocking) complete(&op->com); } break; default: printk(VIOTAPE_KERN_WARN "weird ack\n"); } } static int viotape_probe(struct vio_dev *vdev, const struct vio_device_id *id) { char tapename[32]; int i = vdev->unit_address; int j; if (i >= viotape_numdev) return -ENODEV; tape_device[i] = &vdev->dev; state[i].cur_part = 0; for (j = 0; j < MAX_PARTITIONS; ++j) state[i].part_stat_rwi[j] = VIOT_IDLE; class_device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i), NULL, "iseries!vt%d", i); class_device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i | 0x80), NULL, "iseries!nvt%d", i); sprintf(tapename, "iseries/vt%d", i); printk(VIOTAPE_KERN_INFO "tape %s is iSeries " "resource %10.10s type %4.4s, model %3.3s\n", tapename, viotape_unitinfo[i].rsrcname, viotape_unitinfo[i].type, viotape_unitinfo[i].model); return 0; } static int viotape_remove(struct vio_dev *vdev) { int i = vdev->unit_address; class_device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i | 0x80)); class_device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i)); return 0; } /** * viotape_device_table: Used by vio.c to match devices that we * support. */ static struct vio_device_id viotape_device_table[] __devinitdata = { { "byte", "IBM,iSeries-viotape" }, { "", "" } }; MODULE_DEVICE_TABLE(vio, viotape_device_table); static struct vio_driver viotape_driver = { .id_table = viotape_device_table, .probe = viotape_probe, .remove = viotape_remove, .driver = { .name = "viotape", .owner = THIS_MODULE, } }; int __init viotap_init(void) { int ret; struct proc_dir_entry *e; op_struct_list = NULL; if ((ret = add_op_structs(VIOTAPE_MAXREQ)) < 0) { printk(VIOTAPE_KERN_WARN "couldn't allocate op structs\n"); return ret; } spin_lock_init(&op_struct_list_lock); sema_init(&reqSem, VIOTAPE_MAXREQ); if (viopath_hostLp == HvLpIndexInvalid) { vio_set_hostlp(); if (viopath_hostLp == HvLpIndexInvalid) { ret = -ENODEV; goto clear_op; } } ret = viopath_open(viopath_hostLp, viomajorsubtype_tape, VIOTAPE_MAXREQ + 2); if (ret) { printk(VIOTAPE_KERN_WARN "error on viopath_open to hostlp %d\n", ret); ret = -EIO; goto clear_op; } printk(VIOTAPE_KERN_INFO "vers " VIOTAPE_VERSION ", hosting partition %d\n", viopath_hostLp); vio_setHandler(viomajorsubtype_tape, vioHandleTapeEvent); ret = register_chrdev(VIOTAPE_MAJOR, "viotape", &viotap_fops); if (ret < 0) { printk(VIOTAPE_KERN_WARN "Error registering viotape device\n"); goto clear_handler; } tape_class = class_create(THIS_MODULE, "tape"); if (IS_ERR(tape_class)) { printk(VIOTAPE_KERN_WARN "Unable to allocat class\n"); ret = PTR_ERR(tape_class); goto unreg_chrdev; } if ((ret = get_viotape_info()) < 0) { printk(VIOTAPE_KERN_WARN "Unable to obtain virtual device information"); goto unreg_class; } ret = vio_register_driver(&viotape_driver); if (ret) goto unreg_class; e = create_proc_entry("iSeries/viotape", S_IFREG|S_IRUGO, NULL); if (e) { e->owner = THIS_MODULE; e->proc_fops = &proc_viotape_operations; } return 0; unreg_class: class_destroy(tape_class); unreg_chrdev: unregister_chrdev(VIOTAPE_MAJOR, "viotape"); clear_handler: vio_clearHandler(viomajorsubtype_tape); viopath_close(viopath_hostLp, viomajorsubtype_tape, VIOTAPE_MAXREQ + 2); clear_op: clear_op_struct_pool(); return ret; } /* Give a new state to the tape object */ static int chg_state(int index, unsigned char new_state, struct file *file) { unsigned char *cur_state = &state[index].part_stat_rwi[state[index].cur_part]; int rc = 0; /* if the same state, don't bother */ if (*cur_state == new_state) return 0; /* write an EOF if changing from writing to some other state */ if (*cur_state == VIOT_WRITING) { struct mtop write_eof = { MTWEOF, 1 }; rc = viotap_ioctl(NULL, file, MTIOCTOP, (unsigned long)&write_eof); } *cur_state = new_state; return rc; } /* Cleanup */ static void __exit viotap_exit(void) { int ret; remove_proc_entry("iSeries/viotape", NULL); vio_unregister_driver(&viotape_driver); class_destroy(tape_class); ret = unregister_chrdev(VIOTAPE_MAJOR, "viotape"); if (ret < 0) printk(VIOTAPE_KERN_WARN "Error unregistering device: %d\n", ret); if (viotape_unitinfo) dma_free_coherent(iSeries_vio_dev, sizeof(viotape_unitinfo[0]) * VIOTAPE_MAX_TAPE, viotape_unitinfo, viotape_unitinfo_token); viopath_close(viopath_hostLp, viomajorsubtype_tape, VIOTAPE_MAXREQ + 2); vio_clearHandler(viomajorsubtype_tape); clear_op_struct_pool(); } MODULE_LICENSE("GPL"); module_init(viotap_init); module_exit(viotap_exit);