From d7fd5f1e3b195a8232b3ed768ac2809ddce8ca46 Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Thu, 26 Mar 2009 15:23:42 +0100 Subject: [S390] fix dump_stack vs. %p and (null) The s390 implemenation of dump_stack uses %p to display stack content. Since d97106ab53f812910a62d18afb9dbe882819c1ba (Make %p print '(null)' for NULL pointers) this causes a strange output for dump_stack: [...] Process basename (pid: 8822, task: 00000000b2ece038, ksp: 00000000b24d7b38) 04000000b5685c00 00000000b24d7760 0000000000000002 (null) 00000000b24d7800 00000000b24d7778 00000000b24d7778 00000000001052fe (null) 00000000b24d7b38 (null) 000000000000000a 000000000000000d (null) 00000000b24d7760 00000000b24d77d8 000000000051a7e8 00000000001052fe 00000000b24d7760 00000000b24d77b0 Call Trace: [...] This patch changes our dump_stack to use the appropriate %x format. Signed-off-by: Christian Borntraeger Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/traps.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index 4584d81984c..c2e42cc65ce 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c @@ -61,9 +61,11 @@ extern pgm_check_handler_t do_asce_exception; #define stack_pointer ({ void **sp; asm("la %0,0(15)" : "=&d" (sp)); sp; }) #ifndef CONFIG_64BIT +#define LONG "%08lx " #define FOURLONG "%08lx %08lx %08lx %08lx\n" static int kstack_depth_to_print = 12; #else /* CONFIG_64BIT */ +#define LONG "%016lx " #define FOURLONG "%016lx %016lx %016lx %016lx\n" static int kstack_depth_to_print = 20; #endif /* CONFIG_64BIT */ @@ -155,7 +157,7 @@ void show_stack(struct task_struct *task, unsigned long *sp) break; if (i && ((i * sizeof (long) % 32) == 0)) printk("\n "); - printk("%p ", (void *)*stack++); + printk(LONG, *stack++); } printk("\n"); show_trace(task, sp); -- cgit v1.2.3-70-g09d2 From 099b765139929efdcf232f8870804accf8c4cdc5 Mon Sep 17 00:00:00 2001 From: Frank Munzert Date: Thu, 26 Mar 2009 15:23:43 +0100 Subject: [S390] Automatic IPL after dump Provide new shutdown action "dump_reipl" for automatic ipl after dump. Signed-off-by: Frank Munzert Signed-off-by: Martin Schwidefsky Signed-off-by: Heiko Carstens --- arch/s390/include/asm/lowcore.h | 24 +++++------ arch/s390/include/asm/system.h | 16 ++++++++ arch/s390/kernel/ipl.c | 56 ++++++++++++++++++++++++-- arch/s390/kernel/setup.c | 5 +++ arch/s390/kernel/smp.c | 9 ----- drivers/s390/char/zcore.c | 88 ++++++++++++++++++++++++++++++++++++++++- 6 files changed, 172 insertions(+), 26 deletions(-) diff --git a/arch/s390/include/asm/lowcore.h b/arch/s390/include/asm/lowcore.h index f3720defdd1..ee4b10ff938 100644 --- a/arch/s390/include/asm/lowcore.h +++ b/arch/s390/include/asm/lowcore.h @@ -111,7 +111,7 @@ #define __LC_PASTE 0xE40 -#define __LC_PANIC_MAGIC 0xE00 +#define __LC_DUMP_REIPL 0xE00 #ifndef __s390x__ #define __LC_PFAULT_INTPARM 0x080 #define __LC_CPU_TIMER_SAVE_AREA 0x0D8 @@ -286,12 +286,14 @@ struct _lowcore __u64 int_clock; /* 0xc98 */ __u8 pad11[0xe00-0xca0]; /* 0xca0 */ - /* 0xe00 is used as indicator for dump tools */ - /* whether the kernel died with panic() or not */ - __u32 panic_magic; /* 0xe00 */ + /* 0xe00 contains the address of the IPL Parameter */ + /* Information block. Dump tools need IPIB for IPL */ + /* after dump. */ + __u32 ipib; /* 0xe00 */ + __u32 ipib_checksum; /* 0xe04 */ /* Align to the top 1k of prefix area */ - __u8 pad12[0x1000-0xe04]; /* 0xe04 */ + __u8 pad12[0x1000-0xe08]; /* 0xe08 */ #else /* !__s390x__ */ /* prefix area: defined by architecture */ __u32 ccw1[2]; /* 0x000 */ @@ -379,12 +381,14 @@ struct _lowcore __u64 int_clock; /* 0xde8 */ __u8 pad12[0xe00-0xdf0]; /* 0xdf0 */ - /* 0xe00 is used as indicator for dump tools */ - /* whether the kernel died with panic() or not */ - __u32 panic_magic; /* 0xe00 */ + /* 0xe00 contains the address of the IPL Parameter */ + /* Information block. Dump tools need IPIB for IPL */ + /* after dump. */ + __u64 ipib; /* 0xe00 */ + __u32 ipib_checksum; /* 0xe08 */ /* Per cpu primary space access list */ - __u8 pad_0xe04[0xe38-0xe04]; /* 0xe04 */ + __u8 pad_0xe0c[0xe38-0xe0c]; /* 0xe0c */ __u64 vdso_per_cpu_data; /* 0xe38 */ __u32 paste[16]; /* 0xe40 */ @@ -433,8 +437,6 @@ static inline __u32 store_prefix(void) return address; } -#define __PANIC_MAGIC 0xDEADC0DE - #endif #endif diff --git a/arch/s390/include/asm/system.h b/arch/s390/include/asm/system.h index 3a8b26eb1f2..3f2ccb82b86 100644 --- a/arch/s390/include/asm/system.h +++ b/arch/s390/include/asm/system.h @@ -458,6 +458,22 @@ static inline unsigned short stap(void) return cpu_address; } +static inline u32 cksm(void *addr, unsigned long len) +{ + register unsigned long _addr asm("0") = (unsigned long) addr; + register unsigned long _len asm("1") = len; + unsigned long accu = 0; + + asm volatile( + "0:\n" + " cksm %0,%1\n" + " jnz 0b\n" + : "+d" (accu), "+d" (_addr), "+d" (_len) + : + : "cc", "memory"); + return accu; +} + extern void (*_machine_restart)(char *command); extern void (*_machine_halt)(void); extern void (*_machine_power_off)(void); diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index 2dcf590faba..5663c1f8e46 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c @@ -56,13 +56,14 @@ struct shutdown_trigger { }; /* - * Five shutdown action types are supported: + * The following shutdown action types are supported: */ #define SHUTDOWN_ACTION_IPL_STR "ipl" #define SHUTDOWN_ACTION_REIPL_STR "reipl" #define SHUTDOWN_ACTION_DUMP_STR "dump" #define SHUTDOWN_ACTION_VMCMD_STR "vmcmd" #define SHUTDOWN_ACTION_STOP_STR "stop" +#define SHUTDOWN_ACTION_DUMP_REIPL_STR "dump_reipl" struct shutdown_action { char *name; @@ -146,6 +147,7 @@ static enum ipl_method reipl_method = REIPL_METHOD_DEFAULT; static struct ipl_parameter_block *reipl_block_fcp; static struct ipl_parameter_block *reipl_block_ccw; static struct ipl_parameter_block *reipl_block_nss; +static struct ipl_parameter_block *reipl_block_actual; static int dump_capabilities = DUMP_TYPE_NONE; static enum dump_type dump_type = DUMP_TYPE_NONE; @@ -835,6 +837,7 @@ static int reipl_set_type(enum ipl_type type) reipl_method = REIPL_METHOD_CCW_VM; else reipl_method = REIPL_METHOD_CCW_CIO; + reipl_block_actual = reipl_block_ccw; break; case IPL_TYPE_FCP: if (diag308_set_works) @@ -843,6 +846,7 @@ static int reipl_set_type(enum ipl_type type) reipl_method = REIPL_METHOD_FCP_RO_VM; else reipl_method = REIPL_METHOD_FCP_RO_DIAG; + reipl_block_actual = reipl_block_fcp; break; case IPL_TYPE_FCP_DUMP: reipl_method = REIPL_METHOD_FCP_DUMP; @@ -852,6 +856,7 @@ static int reipl_set_type(enum ipl_type type) reipl_method = REIPL_METHOD_NSS_DIAG; else reipl_method = REIPL_METHOD_NSS; + reipl_block_actual = reipl_block_nss; break; case IPL_TYPE_UNKNOWN: reipl_method = REIPL_METHOD_DEFAULT; @@ -1332,6 +1337,48 @@ static struct shutdown_action __refdata dump_action = { .init = dump_init, }; +static void dump_reipl_run(struct shutdown_trigger *trigger) +{ + preempt_disable(); + /* + * Bypass dynamic address translation (DAT) when storing IPL parameter + * information block address and checksum into the prefix area + * (corresponding to absolute addresses 0-8191). + * When enhanced DAT applies and the STE format control in one, + * the absolute address is formed without prefixing. In this case a + * normal store (stg/st) into the prefix area would no more match to + * absolute addresses 0-8191. + */ +#ifdef CONFIG_64BIT + asm volatile("sturg %0,%1" + :: "a" ((unsigned long) reipl_block_actual), + "a" (&lowcore_ptr[smp_processor_id()]->ipib)); +#else + asm volatile("stura %0,%1" + :: "a" ((unsigned long) reipl_block_actual), + "a" (&lowcore_ptr[smp_processor_id()]->ipib)); +#endif + asm volatile("stura %0,%1" + :: "a" (cksm(reipl_block_actual, reipl_block_actual->hdr.len)), + "a" (&lowcore_ptr[smp_processor_id()]->ipib_checksum)); + preempt_enable(); + dump_run(trigger); +} + +static int __init dump_reipl_init(void) +{ + if (!diag308_set_works) + return -EOPNOTSUPP; + else + return 0; +} + +static struct shutdown_action __refdata dump_reipl_action = { + .name = SHUTDOWN_ACTION_DUMP_REIPL_STR, + .fn = dump_reipl_run, + .init = dump_reipl_init, +}; + /* * vmcmd shutdown action: Trigger vm command on shutdown. */ @@ -1421,7 +1468,8 @@ static struct shutdown_action stop_action = {SHUTDOWN_ACTION_STOP_STR, /* action list */ static struct shutdown_action *shutdown_actions_list[] = { - &ipl_action, &reipl_action, &dump_action, &vmcmd_action, &stop_action}; + &ipl_action, &reipl_action, &dump_reipl_action, &dump_action, + &vmcmd_action, &stop_action}; #define SHUTDOWN_ACTIONS_COUNT (sizeof(shutdown_actions_list) / sizeof(void *)) /* @@ -1434,11 +1482,11 @@ static int set_trigger(const char *buf, struct shutdown_trigger *trigger, size_t len) { int i; + for (i = 0; i < SHUTDOWN_ACTIONS_COUNT; i++) { if (!shutdown_actions_list[i]) continue; - if (strncmp(buf, shutdown_actions_list[i]->name, - strlen(shutdown_actions_list[i]->name)) == 0) { + if (sysfs_streq(buf, shutdown_actions_list[i]->name)) { trigger->action = shutdown_actions_list[i]; return len; } diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index c5cfb6185ea..8fdf08379ce 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -86,6 +86,10 @@ volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */ int __initdata memory_end_set; unsigned long __initdata memory_end; +/* An array with a pointer to the lowcore of every CPU. */ +struct _lowcore *lowcore_ptr[NR_CPUS]; +EXPORT_SYMBOL(lowcore_ptr); + /* * This is set up by the setup-routine at boot-time * for S390 need to find out, what we have to setup @@ -434,6 +438,7 @@ setup_lowcore(void) lc->vdso_per_cpu_data = (unsigned long) &lc->paste[0]; #endif set_prefix((u32)(unsigned long) lc); + lowcore_ptr[0] = lc; } static void __init diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 2d337cbb932..e279d0fbbbe 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -50,12 +50,6 @@ #include #include "entry.h" -/* - * An array with a pointer the lowcore of every CPU. - */ -struct _lowcore *lowcore_ptr[NR_CPUS]; -EXPORT_SYMBOL(lowcore_ptr); - static struct task_struct *current_set[NR_CPUS]; static u8 smp_cpu_type; @@ -82,9 +76,6 @@ void smp_send_stop(void) /* Disable all interrupts/machine checks */ __load_psw_mask(psw_kernel_bits & ~PSW_MASK_MCHECK); - /* write magic number to zero page (absolute 0) */ - lowcore_ptr[smp_processor_id()]->panic_magic = __PANIC_MAGIC; - /* stop all processors */ for_each_online_cpu(cpu) { if (cpu == smp_processor_id()) diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c index eefc6611412..cfe782ee647 100644 --- a/drivers/s390/char/zcore.c +++ b/drivers/s390/char/zcore.c @@ -5,7 +5,7 @@ * * For more information please refer to Documentation/s390/zfcpdump.txt * - * Copyright IBM Corp. 2003,2007 + * Copyright IBM Corp. 2003,2008 * Author(s): Michael Holzheu */ @@ -48,12 +48,19 @@ struct sys_info { union save_area lc_mask; }; +struct ipib_info { + unsigned long ipib; + u32 checksum; +} __attribute__((packed)); + static struct sys_info sys_info; static struct debug_info *zcore_dbf; static int hsa_available; static struct dentry *zcore_dir; static struct dentry *zcore_file; static struct dentry *zcore_memmap_file; +static struct dentry *zcore_reipl_file; +static struct ipl_parameter_block *ipl_block; /* * Copy memory from HSA to kernel or user memory (not reentrant): @@ -527,6 +534,33 @@ static const struct file_operations zcore_memmap_fops = { .release = zcore_memmap_release, }; +static ssize_t zcore_reipl_write(struct file *filp, const char __user *buf, + size_t count, loff_t *ppos) +{ + if (ipl_block) { + diag308(DIAG308_SET, ipl_block); + diag308(DIAG308_IPL, NULL); + } + return count; +} + +static int zcore_reipl_open(struct inode *inode, struct file *filp) +{ + return 0; +} + +static int zcore_reipl_release(struct inode *inode, struct file *filp) +{ + return 0; +} + +static const struct file_operations zcore_reipl_fops = { + .owner = THIS_MODULE, + .write = zcore_reipl_write, + .open = zcore_reipl_open, + .release = zcore_reipl_release, +}; + static void __init set_s390_lc_mask(union save_area *map) { @@ -645,6 +679,39 @@ static int __init zcore_header_init(int arch, struct zcore_header *hdr) return 0; } +/* + * Provide IPL parameter information block from either HSA or memory + * for future reipl + */ +static int __init zcore_reipl_init(void) +{ + struct ipib_info ipib_info; + int rc; + + rc = memcpy_hsa_kernel(&ipib_info, __LC_DUMP_REIPL, sizeof(ipib_info)); + if (rc) + return rc; + if (ipib_info.ipib == 0) + return 0; + ipl_block = (void *) __get_free_page(GFP_KERNEL); + if (!ipl_block) + return -ENOMEM; + if (ipib_info.ipib < ZFCPDUMP_HSA_SIZE) + rc = memcpy_hsa_kernel(ipl_block, ipib_info.ipib, PAGE_SIZE); + else + rc = memcpy_real(ipl_block, ipib_info.ipib, PAGE_SIZE); + if (rc) { + free_page((unsigned long) ipl_block); + return rc; + } + if (cksm(ipl_block, ipl_block->hdr.len) != ipib_info.checksum) { + TRACE("Checksum does not match\n"); + free_page((unsigned long) ipl_block); + ipl_block = NULL; + } + return 0; +} + static int __init zcore_init(void) { unsigned char arch; @@ -690,6 +757,10 @@ static int __init zcore_init(void) if (rc) goto fail; + rc = zcore_reipl_init(); + if (rc) + goto fail; + zcore_dir = debugfs_create_dir("zcore" , NULL); if (!zcore_dir) { rc = -ENOMEM; @@ -707,9 +778,17 @@ static int __init zcore_init(void) rc = -ENOMEM; goto fail_file; } + zcore_reipl_file = debugfs_create_file("reipl", S_IRUSR, zcore_dir, + NULL, &zcore_reipl_fops); + if (!zcore_reipl_file) { + rc = -ENOMEM; + goto fail_memmap_file; + } hsa_available = 1; return 0; +fail_memmap_file: + debugfs_remove(zcore_memmap_file); fail_file: debugfs_remove(zcore_file); fail_dir: @@ -723,10 +802,15 @@ static void __exit zcore_exit(void) { debug_unregister(zcore_dbf); sclp_sdias_exit(); + free_page((unsigned long) ipl_block); + debugfs_remove(zcore_reipl_file); + debugfs_remove(zcore_memmap_file); + debugfs_remove(zcore_file); + debugfs_remove(zcore_dir); diag308(DIAG308_REL_HSA, NULL); } -MODULE_AUTHOR("Copyright IBM Corp. 2003,2007"); +MODULE_AUTHOR("Copyright IBM Corp. 2003,2008"); MODULE_DESCRIPTION("zcore module for zfcpdump support"); MODULE_LICENSE("GPL"); -- cgit v1.2.3-70-g09d2 From 59fa4392dddae244a1148cbbcb090b5a5728f576 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 26 Mar 2009 15:23:44 +0100 Subject: [S390] page fault: invoke oom-killer s390 arch backend for 1c0fe6e3bda0464728c23c8d84aa47567e8b716c "mm: invoke oom-killer from page fault". Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/mm/fault.c | 28 ++-------------------------- 1 file changed, 2 insertions(+), 26 deletions(-) diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index 4d537205e83..833e8366c35 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -200,29 +200,6 @@ static void do_low_address(struct pt_regs *regs, unsigned long error_code) do_no_context(regs, error_code, 0); } -/* - * We ran out of memory, or some other thing happened to us that made - * us unable to handle the page fault gracefully. - */ -static int do_out_of_memory(struct pt_regs *regs, unsigned long error_code, - unsigned long address) -{ - struct task_struct *tsk = current; - struct mm_struct *mm = tsk->mm; - - up_read(&mm->mmap_sem); - if (is_global_init(tsk)) { - yield(); - down_read(&mm->mmap_sem); - return 1; - } - printk("VM: killing process %s\n", tsk->comm); - if (regs->psw.mask & PSW_MASK_PSTATE) - do_group_exit(SIGKILL); - do_no_context(regs, error_code, address); - return 0; -} - static void do_sigbus(struct pt_regs *regs, unsigned long error_code, unsigned long address) { @@ -367,7 +344,6 @@ good_area: goto bad_area; } -survive: if (is_vm_hugetlb_page(vma)) address &= HPAGE_MASK; /* @@ -378,8 +354,8 @@ survive: fault = handle_mm_fault(mm, vma, address, write); if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) { - if (do_out_of_memory(regs, error_code, address)) - goto survive; + up_read(&mm->mmap_sem); + pagefault_out_of_memory(); return; } else if (fault & VM_FAULT_SIGBUS) { do_sigbus(regs, error_code, address); -- cgit v1.2.3-70-g09d2 From 0000d031703c33b9ea909ad81f03762db66135e1 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 26 Mar 2009 15:23:45 +0100 Subject: [S390] dasd: enable compat ioctls All of the ioctls are compatible. Just enable them. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- drivers/s390/block/dasd.c | 3 ++- drivers/s390/block/dasd_ioctl.c | 17 ++++++++++++++--- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 08c23a92101..93972ed7f2d 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -2101,7 +2101,8 @@ dasd_device_operations = { .owner = THIS_MODULE, .open = dasd_open, .release = dasd_release, - .locked_ioctl = dasd_ioctl, + .ioctl = dasd_ioctl, + .compat_ioctl = dasd_ioctl, .getgeo = dasd_getgeo, }; diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c index b82d816d9ef..16e6ba462cb 100644 --- a/drivers/s390/block/dasd_ioctl.c +++ b/drivers/s390/block/dasd_ioctl.c @@ -365,9 +365,9 @@ static int dasd_ioctl_readall_cmb(struct dasd_block *block, unsigned int cmd, return ret; } -int -dasd_ioctl(struct block_device *bdev, fmode_t mode, - unsigned int cmd, unsigned long arg) +static int +dasd_do_ioctl(struct block_device *bdev, fmode_t mode, + unsigned int cmd, unsigned long arg) { struct dasd_block *block = bdev->bd_disk->private_data; void __user *argp = (void __user *)arg; @@ -420,3 +420,14 @@ dasd_ioctl(struct block_device *bdev, fmode_t mode, return -EINVAL; } } + +int dasd_ioctl(struct block_device *bdev, fmode_t mode, + unsigned int cmd, unsigned long arg) +{ + int rc; + + lock_kernel(); + rc = dasd_do_ioctl(bdev, mode, cmd, arg); + unlock_kernel(); + return rc; +} -- cgit v1.2.3-70-g09d2 From f9a28f7bc5225af476f8d4bb669038da8801b7c4 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Joret Date: Thu, 26 Mar 2009 15:23:46 +0100 Subject: [S390] dasd_eckd / Write format R0 is now allowed BB Permission is now granted to the subsystem to format write R0 with: * an ID = CCHHR, where CC = physical cylinder number, HH = physical head number, and R = 0 * a key length of zero * a data length of eight * a data field containing all zeros Signed-off-by: Jean-Baptiste Joret Signed-off-by: Martin Schwidefsky --- drivers/s390/block/dasd_eckd.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index bdb87998f36..0eb5e5888c4 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -1265,6 +1265,8 @@ dasd_eckd_format_device(struct dasd_device * device, int rpt, cyl, head; int cplength, datasize; int i; + int intensity = 0; + int r0_perm; private = (struct dasd_eckd_private *) device->private; rpt = recs_per_track(&private->rdc_data, 0, fdata->blksize); @@ -1296,9 +1298,17 @@ dasd_eckd_format_device(struct dasd_device * device, * Bit 1: write home address, currently not supported * Bit 2: invalidate tracks * Bit 3: use OS/390 compatible disk layout (cdl) + * Bit 4: do not allow storage subsystem to modify record zero * Only some bit combinations do make sense. */ - switch (fdata->intensity) { + if (fdata->intensity & 0x10) { + r0_perm = 0; + intensity = fdata->intensity & ~0x10; + } else { + r0_perm = 1; + intensity = fdata->intensity; + } + switch (intensity) { case 0x00: /* Normal format */ case 0x08: /* Normal format, use cdl. */ cplength = 2 + rpt; @@ -1335,11 +1345,14 @@ dasd_eckd_format_device(struct dasd_device * device, data = fcp->data; ccw = fcp->cpaddr; - switch (fdata->intensity & ~0x08) { + switch (intensity & ~0x08) { case 0x00: /* Normal format. */ define_extent(ccw++, (struct DE_eckd_data *) data, fdata->start_unit, fdata->start_unit, DASD_ECKD_CCW_WRITE_CKD, device); + /* grant subsystem permission to format R0 */ + if (r0_perm) + ((struct DE_eckd_data *)data)->ga_extended |= 0x04; data += sizeof(struct DE_eckd_data); ccw[-1].flags |= CCW_FLAG_CC; locate_record(ccw++, (struct LO_eckd_data *) data, @@ -1373,7 +1386,7 @@ dasd_eckd_format_device(struct dasd_device * device, data += sizeof(struct LO_eckd_data); break; } - if (fdata->intensity & 0x01) { /* write record zero */ + if (intensity & 0x01) { /* write record zero */ ect = (struct eckd_count *) data; data += sizeof(struct eckd_count); ect->cyl = cyl; @@ -1388,7 +1401,7 @@ dasd_eckd_format_device(struct dasd_device * device, ccw->cda = (__u32)(addr_t) ect; ccw++; } - if ((fdata->intensity & ~0x08) & 0x04) { /* erase track */ + if ((intensity & ~0x08) & 0x04) { /* erase track */ ect = (struct eckd_count *) data; data += sizeof(struct eckd_count); ect->cyl = cyl; @@ -1411,14 +1424,14 @@ dasd_eckd_format_device(struct dasd_device * device, ect->kl = 0; ect->dl = fdata->blksize; /* Check for special tracks 0-1 when formatting CDL */ - if ((fdata->intensity & 0x08) && + if ((intensity & 0x08) && fdata->start_unit == 0) { if (i < 3) { ect->kl = 4; ect->dl = sizes_trk0[i] - 4; } } - if ((fdata->intensity & 0x08) && + if ((intensity & 0x08) && fdata->start_unit == 1) { ect->kl = 44; ect->dl = LABEL_SIZE - 44; -- cgit v1.2.3-70-g09d2 From b44b0ab3bac16356f03e94b1b49ba9305710c445 Mon Sep 17 00:00:00 2001 From: Stefan Weinhuber Date: Thu, 26 Mar 2009 15:23:47 +0100 Subject: [S390] dasd: add large volume support The dasd device driver will now support ECKD devices with more then 65520 cylinders. In the traditional ECKD adressing scheme each track is addressed by a 16-bit cylinder and 16-bit head number. The new addressing scheme makes use of the fact that the actual number of heads is never larger then 15, so 12 bits of the head number can be redefined to be part of the cylinder address. Signed-off-by: Stefan Weinhuber Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/dasd.h | 10 ++-- arch/s390/include/asm/vtoc.h | 16 ++++- drivers/s390/block/dasd_eckd.c | 126 ++++++++++++++++++++++------------------ drivers/s390/block/dasd_eckd.h | 9 ++- drivers/s390/block/dasd_int.h | 2 +- drivers/s390/block/dasd_ioctl.c | 4 +- drivers/s390/block/dasd_proc.c | 2 +- fs/partitions/ibm.c | 101 ++++++++++++++++++++++---------- 8 files changed, 171 insertions(+), 99 deletions(-) diff --git a/arch/s390/include/asm/dasd.h b/arch/s390/include/asm/dasd.h index e2db6f16d9c..218bce81ec7 100644 --- a/arch/s390/include/asm/dasd.h +++ b/arch/s390/include/asm/dasd.h @@ -162,15 +162,15 @@ typedef struct dasd_profile_info_t { unsigned int dasd_io_nr_req[32]; /* histogram of # of requests in chanq */ } dasd_profile_info_t; -/* +/* * struct format_data_t * represents all data necessary to format a dasd */ typedef struct format_data_t { - int start_unit; /* from track */ - int stop_unit; /* to track */ - int blksize; /* sectorsize */ - int intensity; + unsigned int start_unit; /* from track */ + unsigned int stop_unit; /* to track */ + unsigned int blksize; /* sectorsize */ + unsigned int intensity; } format_data_t; /* diff --git a/arch/s390/include/asm/vtoc.h b/arch/s390/include/asm/vtoc.h index 3a5267d90d2..8406a2b3157 100644 --- a/arch/s390/include/asm/vtoc.h +++ b/arch/s390/include/asm/vtoc.h @@ -39,7 +39,7 @@ struct vtoc_labeldate __u16 day; } __attribute__ ((packed)); -struct vtoc_volume_label +struct vtoc_volume_label_cdl { char volkey[4]; /* volume key = volume label */ char vollbl[4]; /* volume label */ @@ -56,6 +56,14 @@ struct vtoc_volume_label char res3[29]; /* reserved */ } __attribute__ ((packed)); +struct vtoc_volume_label_ldl { + char vollbl[4]; /* volume label */ + char volid[6]; /* volume identifier */ + char res3[69]; /* reserved */ + char ldl_version; /* version number, valid for ldl format */ + __u64 formatted_blocks; /* valid when ldl_version >= f2 */ +} __attribute__ ((packed)); + struct vtoc_extent { __u8 typeind; /* extent type indicator */ @@ -140,7 +148,11 @@ struct vtoc_format4_label char res2[10]; /* reserved */ __u8 DS4EFLVL; /* extended free-space management level */ struct vtoc_cchhb DS4EFPTR; /* pointer to extended free-space info */ - char res3[9]; /* reserved */ + char res3; /* reserved */ + __u32 DS4DCYL; /* number of logical cyls */ + char res4[2]; /* reserved */ + __u8 DS4DEVF2; /* device flags */ + char res5; /* reserved */ } __attribute__ ((packed)); struct vtoc_ds5ext diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 0eb5e5888c4..69f93e626fd 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -159,6 +159,14 @@ recs_per_track(struct dasd_eckd_characteristics * rdc, return 0; } +static void set_ch_t(struct ch_t *geo, __u32 cyl, __u8 head) +{ + geo->cyl = (__u16) cyl; + geo->head = cyl >> 16; + geo->head <<= 4; + geo->head |= head; +} + static int check_XRC (struct ccw1 *de_ccw, struct DE_eckd_data *data, @@ -186,11 +194,12 @@ check_XRC (struct ccw1 *de_ccw, } static int -define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk, - int totrk, int cmd, struct dasd_device * device) +define_extent(struct ccw1 *ccw, struct DE_eckd_data *data, unsigned int trk, + unsigned int totrk, int cmd, struct dasd_device *device) { struct dasd_eckd_private *private; - struct ch_t geo, beg, end; + u32 begcyl, endcyl; + u16 heads, beghead, endhead; int rc = 0; private = (struct dasd_eckd_private *) device->private; @@ -248,27 +257,24 @@ define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk, && !(private->uses_cdl && trk < 2)) data->ga_extended |= 0x40; /* Regular Data Format Mode */ - geo.cyl = private->rdc_data.no_cyl; - geo.head = private->rdc_data.trk_per_cyl; - beg.cyl = trk / geo.head; - beg.head = trk % geo.head; - end.cyl = totrk / geo.head; - end.head = totrk % geo.head; + heads = private->rdc_data.trk_per_cyl; + begcyl = trk / heads; + beghead = trk % heads; + endcyl = totrk / heads; + endhead = totrk % heads; /* check for sequential prestage - enhance cylinder range */ if (data->attributes.operation == DASD_SEQ_PRESTAGE || data->attributes.operation == DASD_SEQ_ACCESS) { - if (end.cyl + private->attrib.nr_cyl < geo.cyl) - end.cyl += private->attrib.nr_cyl; + if (endcyl + private->attrib.nr_cyl < private->real_cyl) + endcyl += private->attrib.nr_cyl; else - end.cyl = (geo.cyl - 1); + endcyl = (private->real_cyl - 1); } - data->beg_ext.cyl = beg.cyl; - data->beg_ext.head = beg.head; - data->end_ext.cyl = end.cyl; - data->end_ext.head = end.head; + set_ch_t(&data->beg_ext, begcyl, beghead); + set_ch_t(&data->end_ext, endcyl, endhead); return rc; } @@ -294,13 +300,14 @@ static int check_XRC_on_prefix(struct PFX_eckd_data *pfxdata, return rc; } -static int prefix(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata, int trk, - int totrk, int cmd, struct dasd_device *basedev, - struct dasd_device *startdev) +static int prefix(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata, + unsigned int trk, unsigned int totrk, int cmd, + struct dasd_device *basedev, struct dasd_device *startdev) { struct dasd_eckd_private *basepriv, *startpriv; struct DE_eckd_data *data; - struct ch_t geo, beg, end; + u32 begcyl, endcyl; + u16 heads, beghead, endhead; int rc = 0; basepriv = (struct dasd_eckd_private *) basedev->private; @@ -374,33 +381,30 @@ static int prefix(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata, int trk, && !(basepriv->uses_cdl && trk < 2)) data->ga_extended |= 0x40; /* Regular Data Format Mode */ - geo.cyl = basepriv->rdc_data.no_cyl; - geo.head = basepriv->rdc_data.trk_per_cyl; - beg.cyl = trk / geo.head; - beg.head = trk % geo.head; - end.cyl = totrk / geo.head; - end.head = totrk % geo.head; + heads = basepriv->rdc_data.trk_per_cyl; + begcyl = trk / heads; + beghead = trk % heads; + endcyl = totrk / heads; + endhead = totrk % heads; /* check for sequential prestage - enhance cylinder range */ if (data->attributes.operation == DASD_SEQ_PRESTAGE || data->attributes.operation == DASD_SEQ_ACCESS) { - if (end.cyl + basepriv->attrib.nr_cyl < geo.cyl) - end.cyl += basepriv->attrib.nr_cyl; + if (endcyl + basepriv->attrib.nr_cyl < basepriv->real_cyl) + endcyl += basepriv->attrib.nr_cyl; else - end.cyl = (geo.cyl - 1); + endcyl = (basepriv->real_cyl - 1); } - data->beg_ext.cyl = beg.cyl; - data->beg_ext.head = beg.head; - data->end_ext.cyl = end.cyl; - data->end_ext.head = end.head; + set_ch_t(&data->beg_ext, begcyl, beghead); + set_ch_t(&data->end_ext, endcyl, endhead); return rc; } static void -locate_record(struct ccw1 *ccw, struct LO_eckd_data *data, int trk, - int rec_on_trk, int no_rec, int cmd, +locate_record(struct ccw1 *ccw, struct LO_eckd_data *data, unsigned int trk, + unsigned int rec_on_trk, int no_rec, int cmd, struct dasd_device * device, int reclen) { struct dasd_eckd_private *private; @@ -493,10 +497,11 @@ locate_record(struct ccw1 *ccw, struct LO_eckd_data *data, int trk, default: DEV_MESSAGE(KERN_ERR, device, "unknown opcode 0x%x", cmd); } - data->seek_addr.cyl = data->search_arg.cyl = - trk / private->rdc_data.trk_per_cyl; - data->seek_addr.head = data->search_arg.head = - trk % private->rdc_data.trk_per_cyl; + set_ch_t(&data->seek_addr, + trk / private->rdc_data.trk_per_cyl, + trk % private->rdc_data.trk_per_cyl); + data->search_arg.cyl = data->seek_addr.cyl; + data->search_arg.head = data->seek_addr.head; data->search_arg.record = rec_on_trk; } @@ -1002,13 +1007,20 @@ dasd_eckd_check_characteristics(struct dasd_device *device) "rc=%d", rc); goto out_err3; } + /* find the vaild cylinder size */ + if (private->rdc_data.no_cyl == LV_COMPAT_CYL && + private->rdc_data.long_no_cyl) + private->real_cyl = private->rdc_data.long_no_cyl; + else + private->real_cyl = private->rdc_data.no_cyl; + DEV_MESSAGE(KERN_INFO, device, "%04X/%02X(CU:%04X/%02X) Cyl:%d Head:%d Sec:%d", private->rdc_data.dev_type, private->rdc_data.dev_model, private->rdc_data.cu_type, private->rdc_data.cu_model.model, - private->rdc_data.no_cyl, + private->real_cyl, private->rdc_data.trk_per_cyl, private->rdc_data.sec_per_trk); return 0; @@ -1157,8 +1169,6 @@ dasd_eckd_end_analysis(struct dasd_block *block) } private->uses_cdl = 1; - /* Calculate number of blocks/records per track. */ - blk_per_trk = recs_per_track(&private->rdc_data, 0, block->bp_block); /* Check Track 0 for Compatible Disk Layout */ count_area = NULL; for (i = 0; i < 3; i++) { @@ -1200,14 +1210,14 @@ dasd_eckd_end_analysis(struct dasd_block *block) block->s2b_shift++; blk_per_trk = recs_per_track(&private->rdc_data, 0, block->bp_block); - block->blocks = (private->rdc_data.no_cyl * + block->blocks = (private->real_cyl * private->rdc_data.trk_per_cyl * blk_per_trk); DEV_MESSAGE(KERN_INFO, device, "(%dkB blks): %dkB at %dkB/trk %s", (block->bp_block >> 10), - ((private->rdc_data.no_cyl * + ((private->real_cyl * private->rdc_data.trk_per_cyl * blk_per_trk * (block->bp_block >> 9)) >> 1), ((blk_per_trk * block->bp_block) >> 10), @@ -1262,7 +1272,8 @@ dasd_eckd_format_device(struct dasd_device * device, struct eckd_count *ect; struct ccw1 *ccw; void *data; - int rpt, cyl, head; + int rpt; + struct ch_t address; int cplength, datasize; int i; int intensity = 0; @@ -1270,24 +1281,25 @@ dasd_eckd_format_device(struct dasd_device * device, private = (struct dasd_eckd_private *) device->private; rpt = recs_per_track(&private->rdc_data, 0, fdata->blksize); - cyl = fdata->start_unit / private->rdc_data.trk_per_cyl; - head = fdata->start_unit % private->rdc_data.trk_per_cyl; + set_ch_t(&address, + fdata->start_unit / private->rdc_data.trk_per_cyl, + fdata->start_unit % private->rdc_data.trk_per_cyl); /* Sanity checks. */ if (fdata->start_unit >= - (private->rdc_data.no_cyl * private->rdc_data.trk_per_cyl)) { - DEV_MESSAGE(KERN_INFO, device, "Track no %d too big!", + (private->real_cyl * private->rdc_data.trk_per_cyl)) { + DEV_MESSAGE(KERN_INFO, device, "Track no %u too big!", fdata->start_unit); return ERR_PTR(-EINVAL); } if (fdata->start_unit > fdata->stop_unit) { - DEV_MESSAGE(KERN_INFO, device, "Track %d reached! ending.", + DEV_MESSAGE(KERN_INFO, device, "Track %u reached! ending.", fdata->start_unit); return ERR_PTR(-EINVAL); } if (dasd_check_blocksize(fdata->blksize) != 0) { DEV_MESSAGE(KERN_WARNING, device, - "Invalid blocksize %d...terminating!", + "Invalid blocksize %u...terminating!", fdata->blksize); return ERR_PTR(-EINVAL); } @@ -1389,8 +1401,8 @@ dasd_eckd_format_device(struct dasd_device * device, if (intensity & 0x01) { /* write record zero */ ect = (struct eckd_count *) data; data += sizeof(struct eckd_count); - ect->cyl = cyl; - ect->head = head; + ect->cyl = address.cyl; + ect->head = address.head; ect->record = 0; ect->kl = 0; ect->dl = 8; @@ -1404,8 +1416,8 @@ dasd_eckd_format_device(struct dasd_device * device, if ((intensity & ~0x08) & 0x04) { /* erase track */ ect = (struct eckd_count *) data; data += sizeof(struct eckd_count); - ect->cyl = cyl; - ect->head = head; + ect->cyl = address.cyl; + ect->head = address.head; ect->record = 1; ect->kl = 0; ect->dl = 0; @@ -1418,8 +1430,8 @@ dasd_eckd_format_device(struct dasd_device * device, for (i = 0; i < rpt; i++) { ect = (struct eckd_count *) data; data += sizeof(struct eckd_count); - ect->cyl = cyl; - ect->head = head; + ect->cyl = address.cyl; + ect->head = address.head; ect->record = i + 1; ect->kl = 0; ect->dl = fdata->blksize; diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h index 2476f87d21d..eecfa776db1 100644 --- a/drivers/s390/block/dasd_eckd.h +++ b/drivers/s390/block/dasd_eckd.h @@ -48,6 +48,11 @@ #define PSF_ORDER_PRSSD 0x18 #define PSF_ORDER_SSC 0x1D +/* + * Size that is reportet for large volumes in the old 16-bit no_cyl field + */ +#define LV_COMPAT_CYL 0xFFFE + /***************************************************************************** * SECTION: Type Definitions ****************************************************************************/ @@ -228,7 +233,8 @@ struct dasd_eckd_characteristics { __u8 factor7; __u8 factor8; __u8 reserved2[3]; - __u8 reserved3[10]; + __u8 reserved3[6]; + __u32 long_no_cyl; } __attribute__ ((packed)); /* elements of the configuration data */ @@ -406,6 +412,7 @@ struct dasd_eckd_private { int uses_cdl; struct attrib_data_t attrib; /* e.g. cache operations */ struct dasd_rssd_features features; + u32 real_cyl; /* alias managemnet */ struct dasd_uid uid; diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index 4a39084d9c9..29991a9fa07 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -378,7 +378,7 @@ struct dasd_block { struct block_device *bdev; atomic_t open_count; - unsigned long blocks; /* size of volume in blocks */ + unsigned long long blocks; /* size of volume in blocks */ unsigned int bp_block; /* bytes per block */ unsigned int s2b_shift; /* log2 (bp_block/512) */ diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c index 16e6ba462cb..a3bbdb807ba 100644 --- a/drivers/s390/block/dasd_ioctl.c +++ b/drivers/s390/block/dasd_ioctl.c @@ -146,7 +146,7 @@ static int dasd_format(struct dasd_block *block, struct format_data_t *fdata) } DBF_DEV_EVENT(DBF_NOTICE, base, - "formatting units %d to %d (%d B blocks) flags %d", + "formatting units %u to %u (%u B blocks) flags %u", fdata->start_unit, fdata->stop_unit, fdata->blksize, fdata->intensity); @@ -170,7 +170,7 @@ static int dasd_format(struct dasd_block *block, struct format_data_t *fdata) if (rc) { if (rc != -ERESTARTSYS) DEV_MESSAGE(KERN_ERR, base, - " Formatting of unit %d failed " + " Formatting of unit %u failed " "with rc = %d", fdata->start_unit, rc); return rc; diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c index bf6fd348f20..0aa569419d5 100644 --- a/drivers/s390/block/dasd_proc.c +++ b/drivers/s390/block/dasd_proc.c @@ -112,7 +112,7 @@ dasd_devices_show(struct seq_file *m, void *v) seq_printf(m, "n/f "); else seq_printf(m, - "at blocksize: %d, %ld blocks, %ld MB", + "at blocksize: %d, %lld blocks, %lld MB", block->bp_block, block->blocks, ((block->bp_block >> 9) * block->blocks) >> 11); diff --git a/fs/partitions/ibm.c b/fs/partitions/ibm.c index 1e064c4a4f8..46297683cd3 100644 --- a/fs/partitions/ibm.c +++ b/fs/partitions/ibm.c @@ -21,20 +21,38 @@ * compute the block number from a * cyl-cyl-head-head structure */ -static inline int +static sector_t cchh2blk (struct vtoc_cchh *ptr, struct hd_geometry *geo) { - return ptr->cc * geo->heads * geo->sectors + - ptr->hh * geo->sectors; + + sector_t cyl; + __u16 head; + + /*decode cylinder and heads for large volumes */ + cyl = ptr->hh & 0xFFF0; + cyl <<= 12; + cyl |= ptr->cc; + head = ptr->hh & 0x000F; + return cyl * geo->heads * geo->sectors + + head * geo->sectors; } /* * compute the block number from a * cyl-cyl-head-head-block structure */ -static inline int +static sector_t cchhb2blk (struct vtoc_cchhb *ptr, struct hd_geometry *geo) { - return ptr->cc * geo->heads * geo->sectors + - ptr->hh * geo->sectors + + + sector_t cyl; + __u16 head; + + /*decode cylinder and heads for large volumes */ + cyl = ptr->hh & 0xFFF0; + cyl <<= 12; + cyl |= ptr->cc; + head = ptr->hh & 0x000F; + return cyl * geo->heads * geo->sectors + + head * geo->sectors + ptr->b; } @@ -43,14 +61,15 @@ cchhb2blk (struct vtoc_cchhb *ptr, struct hd_geometry *geo) { int ibm_partition(struct parsed_partitions *state, struct block_device *bdev) { - int blocksize, offset, size,res; - loff_t i_size; + int blocksize, res; + loff_t i_size, offset, size, fmt_size; dasd_information2_t *info; struct hd_geometry *geo; char type[5] = {0,}; char name[7] = {0,}; union label_t { - struct vtoc_volume_label vol; + struct vtoc_volume_label_cdl vol; + struct vtoc_volume_label_ldl lnx; struct vtoc_cms_label cms; } *label; unsigned char *data; @@ -85,14 +104,16 @@ ibm_partition(struct parsed_partitions *state, struct block_device *bdev) if (data == NULL) goto out_readerr; - strncpy (type, data, 4); - if ((!info->FBA_layout) && (!strcmp(info->type, "ECKD"))) - strncpy(name, data + 8, 6); - else - strncpy(name, data + 4, 6); memcpy(label, data, sizeof(union label_t)); put_dev_sector(sect); + if ((!info->FBA_layout) && (!strcmp(info->type, "ECKD"))) { + strncpy(type, label->vol.vollbl, 4); + strncpy(name, label->vol.volid, 6); + } else { + strncpy(type, label->lnx.vollbl, 4); + strncpy(name, label->lnx.volid, 6); + } EBCASC(type, 4); EBCASC(name, 6); @@ -110,36 +131,54 @@ ibm_partition(struct parsed_partitions *state, struct block_device *bdev) /* * VM style CMS1 labeled disk */ + blocksize = label->cms.block_size; if (label->cms.disk_offset != 0) { printk("CMS1/%8s(MDSK):", name); /* disk is reserved minidisk */ - blocksize = label->cms.block_size; offset = label->cms.disk_offset; size = (label->cms.block_count - 1) * (blocksize >> 9); } else { printk("CMS1/%8s:", name); offset = (info->label_block + 1); - size = i_size >> 9; + size = label->cms.block_count + * (blocksize >> 9); } + put_partition(state, 1, offset*(blocksize >> 9), + size-offset*(blocksize >> 9)); } else { - /* - * Old style LNX1 or unlabeled disk - */ - if (strncmp(type, "LNX1", 4) == 0) - printk ("LNX1/%8s:", name); - else + if (strncmp(type, "LNX1", 4) == 0) { + printk("LNX1/%8s:", name); + if (label->lnx.ldl_version == 0xf2) { + fmt_size = label->lnx.formatted_blocks + * (blocksize >> 9); + } else if (!strcmp(info->type, "ECKD")) { + /* formated w/o large volume support */ + fmt_size = geo->cylinders * geo->heads + * geo->sectors * (blocksize >> 9); + } else { + /* old label and no usable disk geometry + * (e.g. DIAG) */ + fmt_size = i_size >> 9; + } + size = i_size >> 9; + if (fmt_size < size) + size = fmt_size; + offset = (info->label_block + 1); + } else { + /* unlabeled disk */ printk("(nonl)"); - offset = (info->label_block + 1); - size = i_size >> 9; - } - put_partition(state, 1, offset*(blocksize >> 9), + size = i_size >> 9; + offset = (info->label_block + 1); + } + put_partition(state, 1, offset*(blocksize >> 9), size-offset*(blocksize >> 9)); + } } else if (info->format == DASD_FORMAT_CDL) { /* * New style CDL formatted disk */ - unsigned int blk; + sector_t blk; int counter; /* @@ -166,7 +205,8 @@ ibm_partition(struct parsed_partitions *state, struct block_device *bdev) /* skip FMT4 / FMT5 / FMT7 labels */ if (f1.DS1FMTID == _ascebc['4'] || f1.DS1FMTID == _ascebc['5'] - || f1.DS1FMTID == _ascebc['7']) { + || f1.DS1FMTID == _ascebc['7'] + || f1.DS1FMTID == _ascebc['9']) { blk++; data = read_dev_sector(bdev, blk * (blocksize/512), @@ -174,8 +214,9 @@ ibm_partition(struct parsed_partitions *state, struct block_device *bdev) continue; } - /* only FMT1 valid at this point */ - if (f1.DS1FMTID != _ascebc['1']) + /* only FMT1 and 8 labels valid at this point */ + if (f1.DS1FMTID != _ascebc['1'] && + f1.DS1FMTID != _ascebc['8']) break; /* OK, we got valid partition data */ -- cgit v1.2.3-70-g09d2 From f3eb5384cf0325c02e306b1d81e70f81a03d7432 Mon Sep 17 00:00:00 2001 From: Stefan Weinhuber Date: Thu, 26 Mar 2009 15:23:48 +0100 Subject: [S390] dasd: add High Performance FICON support To support High Performance FICON, the DASD device driver has to translate I/O requests into the new transport mode control words (TCW) instead of the traditional (command mode) CCW requests. Signed-off-by: Stefan Weinhuber Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/idals.h | 17 +- drivers/s390/block/dasd.c | 70 ++- drivers/s390/block/dasd_3990_erp.c | 141 ++++-- drivers/s390/block/dasd_alias.c | 25 +- drivers/s390/block/dasd_devmap.c | 7 + drivers/s390/block/dasd_eckd.c | 972 +++++++++++++++++++++++++++++++++---- drivers/s390/block/dasd_eckd.h | 40 +- drivers/s390/block/dasd_eer.c | 21 +- drivers/s390/block/dasd_int.h | 5 +- 9 files changed, 1123 insertions(+), 175 deletions(-) diff --git a/arch/s390/include/asm/idals.h b/arch/s390/include/asm/idals.h index e82c10efe65..aae276d0038 100644 --- a/arch/s390/include/asm/idals.h +++ b/arch/s390/include/asm/idals.h @@ -44,24 +44,18 @@ idal_is_needed(void *vaddr, unsigned int length) /* * Return the number of idal words needed for an address/length pair. */ -static inline unsigned int -idal_nr_words(void *vaddr, unsigned int length) +static inline unsigned int idal_nr_words(void *vaddr, unsigned int length) { -#ifdef __s390x__ - if (idal_is_needed(vaddr, length)) - return ((__pa(vaddr) & (IDA_BLOCK_SIZE-1)) + length + - (IDA_BLOCK_SIZE-1)) >> IDA_SIZE_LOG; -#endif - return 0; + return ((__pa(vaddr) & (IDA_BLOCK_SIZE-1)) + length + + (IDA_BLOCK_SIZE-1)) >> IDA_SIZE_LOG; } /* * Create the list of idal words for an address/length pair. */ -static inline unsigned long * -idal_create_words(unsigned long *idaws, void *vaddr, unsigned int length) +static inline unsigned long *idal_create_words(unsigned long *idaws, + void *vaddr, unsigned int length) { -#ifdef __s390x__ unsigned long paddr; unsigned int cidaw; @@ -74,7 +68,6 @@ idal_create_words(unsigned long *idaws, void *vaddr, unsigned int length) paddr += IDA_BLOCK_SIZE; *idaws++ = paddr; } -#endif return idaws; } diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 93972ed7f2d..00f7d24b337 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -22,6 +22,7 @@ #include #include #include +#include /* This is ugly... */ #define PRINTK_HEADER "dasd:" @@ -852,8 +853,13 @@ int dasd_start_IO(struct dasd_ccw_req *cqr) cqr->startclk = get_clock(); cqr->starttime = jiffies; cqr->retries--; - rc = ccw_device_start(device->cdev, cqr->cpaddr, (long) cqr, - cqr->lpm, 0); + if (cqr->cpmode == 1) { + rc = ccw_device_tm_start(device->cdev, cqr->cpaddr, + (long) cqr, cqr->lpm); + } else { + rc = ccw_device_start(device->cdev, cqr->cpaddr, + (long) cqr, cqr->lpm, 0); + } switch (rc) { case 0: cqr->status = DASD_CQR_IN_IO; @@ -881,9 +887,12 @@ int dasd_start_IO(struct dasd_ccw_req *cqr) " retry on all pathes"); break; case -ENODEV: + DBF_DEV_EVENT(DBF_DEBUG, device, "%s", + "start_IO: -ENODEV device gone, retry"); + break; case -EIO: DBF_DEV_EVENT(DBF_ERR, device, "%s", - "start_IO: device gone, retry"); + "start_IO: -EIO device gone, retry"); break; default: DEV_MESSAGE(KERN_ERR, device, @@ -1015,9 +1024,9 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, /* check for unsolicited interrupts */ cqr = (struct dasd_ccw_req *) intparm; - if (!cqr || ((irb->scsw.cmd.cc == 1) && - (irb->scsw.cmd.fctl & SCSW_FCTL_START_FUNC) && - (irb->scsw.cmd.stctl & SCSW_STCTL_STATUS_PEND))) { + if (!cqr || ((scsw_cc(&irb->scsw) == 1) && + (scsw_fctl(&irb->scsw) & SCSW_FCTL_START_FUNC) && + (scsw_stctl(&irb->scsw) & SCSW_STCTL_STATUS_PEND))) { if (cqr && cqr->status == DASD_CQR_IN_IO) cqr->status = DASD_CQR_QUEUED; device = dasd_device_from_cdev_locked(cdev); @@ -1040,7 +1049,7 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, /* Check for clear pending */ if (cqr->status == DASD_CQR_CLEAR_PENDING && - irb->scsw.cmd.fctl & SCSW_FCTL_CLEAR_FUNC) { + scsw_fctl(&irb->scsw) & SCSW_FCTL_CLEAR_FUNC) { cqr->status = DASD_CQR_CLEARED; dasd_device_clear_timer(device); wake_up(&dasd_flush_wq); @@ -1048,7 +1057,7 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, return; } - /* check status - the request might have been killed by dyn detach */ + /* check status - the request might have been killed by dyn detach */ if (cqr->status != DASD_CQR_IN_IO) { MESSAGE(KERN_DEBUG, "invalid status: bus_id %s, status %02x", @@ -1059,8 +1068,8 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, ((irb->scsw.cmd.cstat << 8) | irb->scsw.cmd.dstat), cqr); next = NULL; expires = 0; - if (irb->scsw.cmd.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END) && - irb->scsw.cmd.cstat == 0 && !irb->esw.esw0.erw.cons) { + if (scsw_dstat(&irb->scsw) == (DEV_STAT_CHN_END | DEV_STAT_DEV_END) && + scsw_cstat(&irb->scsw) == 0) { /* request was completed successfully */ cqr->status = DASD_CQR_SUCCESS; cqr->stopclk = now; @@ -1991,8 +2000,11 @@ static void dasd_setup_queue(struct dasd_block *block) blk_queue_max_sectors(block->request_queue, max); blk_queue_max_phys_segments(block->request_queue, -1L); blk_queue_max_hw_segments(block->request_queue, -1L); - blk_queue_max_segment_size(block->request_queue, -1L); - blk_queue_segment_boundary(block->request_queue, -1L); + /* with page sized segments we can translate each segement into + * one idaw/tidaw + */ + blk_queue_max_segment_size(block->request_queue, PAGE_SIZE); + blk_queue_segment_boundary(block->request_queue, PAGE_SIZE - 1); blk_queue_ordered(block->request_queue, QUEUE_ORDERED_DRAIN, NULL); } @@ -2432,6 +2444,40 @@ int dasd_generic_read_dev_chars(struct dasd_device *device, char *magic, } EXPORT_SYMBOL_GPL(dasd_generic_read_dev_chars); +/* + * In command mode and transport mode we need to look for sense + * data in different places. The sense data itself is allways + * an array of 32 bytes, so we can unify the sense data access + * for both modes. + */ +char *dasd_get_sense(struct irb *irb) +{ + struct tsb *tsb = NULL; + char *sense = NULL; + + if (scsw_is_tm(&irb->scsw) && (irb->scsw.tm.fcxs == 0x01)) { + if (irb->scsw.tm.tcw) + tsb = tcw_get_tsb((struct tcw *)(unsigned long) + irb->scsw.tm.tcw); + if (tsb && tsb->length == 64 && tsb->flags) + switch (tsb->flags & 0x07) { + case 1: /* tsa_iostat */ + sense = tsb->tsa.iostat.sense; + break; + case 2: /* tsa_ddpc */ + sense = tsb->tsa.ddpc.sense; + break; + default: + /* currently we don't use interrogate data */ + break; + } + } else if (irb->esw.esw0.erw.cons) { + sense = irb->ecw; + } + return sense; +} +EXPORT_SYMBOL_GPL(dasd_get_sense); + static int __init dasd_init(void) { int rc; diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c index d82aad5224f..4cee4591614 100644 --- a/drivers/s390/block/dasd_3990_erp.c +++ b/drivers/s390/block/dasd_3990_erp.c @@ -1561,6 +1561,13 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense) cqr = cqr->refers; } + if (scsw_is_tm(&cqr->irb.scsw)) { + DBF_DEV_EVENT(DBF_WARNING, device, "%s", + "32 bit sense, action 1B is not defined" + " in transport mode - just retry"); + return default_erp; + } + /* for imprecise ending just do default erp */ if (sense[1] & 0x01) { @@ -1599,7 +1606,7 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense) oldccw = cqr->cpaddr; if (oldccw->cmd_code == DASD_ECKD_CCW_PFX) { PFX_data = cqr->data; - memcpy(DE_data, &PFX_data->define_extend, + memcpy(DE_data, &PFX_data->define_extent, sizeof(struct DE_eckd_data)); } else memcpy(DE_data, cqr->data, sizeof(struct DE_eckd_data)); @@ -1712,6 +1719,13 @@ dasd_3990_update_1B(struct dasd_ccw_req * previous_erp, char *sense) cqr = cqr->refers; } + if (scsw_is_tm(&cqr->irb.scsw)) { + DBF_DEV_EVENT(DBF_WARNING, device, "%s", + "32 bit sense, action 1B, update," + " in transport mode - just retry"); + return previous_erp; + } + /* for imprecise ending just do default erp */ if (sense[1] & 0x01) { @@ -2171,7 +2185,7 @@ dasd_3990_erp_control_check(struct dasd_ccw_req *erp) { struct dasd_device *device = erp->startdev; - if (erp->refers->irb.scsw.cmd.cstat & (SCHN_STAT_INTF_CTRL_CHK + if (scsw_cstat(&erp->refers->irb.scsw) & (SCHN_STAT_INTF_CTRL_CHK | SCHN_STAT_CHN_CTRL_CHK)) { DEV_MESSAGE(KERN_DEBUG, device, "%s", "channel or interface control check"); @@ -2193,21 +2207,23 @@ dasd_3990_erp_control_check(struct dasd_ccw_req *erp) * erp_new contens was possibly modified */ static struct dasd_ccw_req * -dasd_3990_erp_inspect(struct dasd_ccw_req * erp) +dasd_3990_erp_inspect(struct dasd_ccw_req *erp) { struct dasd_ccw_req *erp_new = NULL; - /* sense data are located in the refers record of the */ - /* already set up new ERP ! */ - char *sense = erp->refers->irb.ecw; + char *sense; /* if this problem occured on an alias retry on base */ erp_new = dasd_3990_erp_inspect_alias(erp); if (erp_new) return erp_new; - /* check if no concurrent sens is available */ - if (!erp->refers->irb.esw.esw0.erw.cons) + /* sense data are located in the refers record of the + * already set up new ERP ! + * check if concurrent sens is available + */ + sense = dasd_get_sense(&erp->refers->irb); + if (!sense) erp_new = dasd_3990_erp_control_check(erp); /* distinguish between 24 and 32 byte sense data */ else if (sense[27] & DASD_SENSE_BIT_0) { @@ -2231,7 +2247,11 @@ dasd_3990_erp_inspect(struct dasd_ccw_req * erp) * DESCRIPTION * This funtion adds an additional request block (ERP) to the head of * the given cqr (or erp). - * This erp is initialized as an default erp (retry TIC) + * For a command mode cqr the erp is initialized as an default erp + * (retry TIC). + * For transport mode we make a copy of the original TCW (points to + * the original TCCB, TIDALs, etc.) but give it a fresh + * TSB so the original sense data will not be changed. * * PARAMETER * cqr head of the current ERP-chain (or single cqr if @@ -2239,17 +2259,27 @@ dasd_3990_erp_inspect(struct dasd_ccw_req * erp) * RETURN VALUES * erp pointer to new ERP-chain head */ -static struct dasd_ccw_req * -dasd_3990_erp_add_erp(struct dasd_ccw_req * cqr) +static struct dasd_ccw_req *dasd_3990_erp_add_erp(struct dasd_ccw_req *cqr) { struct dasd_device *device = cqr->startdev; struct ccw1 *ccw; - - /* allocate additional request block */ struct dasd_ccw_req *erp; + int cplength, datasize; + struct tcw *tcw; + struct tsb *tsb; + + if (cqr->cpmode == 1) { + cplength = 0; + datasize = sizeof(struct tcw) + sizeof(struct tsb); + } else { + cplength = 2; + datasize = 0; + } - erp = dasd_alloc_erp_request((char *) &cqr->magic, 2, 0, device); + /* allocate additional request block */ + erp = dasd_alloc_erp_request((char *) &cqr->magic, + cplength, datasize, device); if (IS_ERR(erp)) { if (cqr->retries <= 0) { DEV_MESSAGE(KERN_ERR, device, "%s", @@ -2266,13 +2296,24 @@ dasd_3990_erp_add_erp(struct dasd_ccw_req * cqr) return cqr; } - /* initialize request with default TIC to current ERP/CQR */ - ccw = erp->cpaddr; - ccw->cmd_code = CCW_CMD_NOOP; - ccw->flags = CCW_FLAG_CC; - ccw++; - ccw->cmd_code = CCW_CMD_TIC; - ccw->cda = (long)(cqr->cpaddr); + if (cqr->cpmode == 1) { + /* make a shallow copy of the original tcw but set new tsb */ + erp->cpmode = 1; + erp->cpaddr = erp->data; + tcw = erp->data; + tsb = (struct tsb *) &tcw[1]; + *tcw = *((struct tcw *)cqr->cpaddr); + tcw->tsb = (long)tsb; + } else { + /* initialize request with default TIC to current ERP/CQR */ + ccw = erp->cpaddr; + ccw->cmd_code = CCW_CMD_NOOP; + ccw->flags = CCW_FLAG_CC; + ccw++; + ccw->cmd_code = CCW_CMD_TIC; + ccw->cda = (long)(cqr->cpaddr); + } + erp->function = dasd_3990_erp_add_erp; erp->refers = cqr; erp->startdev = device; @@ -2282,7 +2323,6 @@ dasd_3990_erp_add_erp(struct dasd_ccw_req * cqr) erp->expires = 0; erp->retries = 256; erp->buildclk = get_clock(); - erp->status = DASD_CQR_FILLED; return erp; @@ -2340,28 +2380,33 @@ dasd_3990_erp_additional_erp(struct dasd_ccw_req * cqr) * match 'boolean' for match found * returns 1 if match found, otherwise 0. */ -static int -dasd_3990_erp_error_match(struct dasd_ccw_req *cqr1, struct dasd_ccw_req *cqr2) +static int dasd_3990_erp_error_match(struct dasd_ccw_req *cqr1, + struct dasd_ccw_req *cqr2) { + char *sense1, *sense2; if (cqr1->startdev != cqr2->startdev) return 0; - if (cqr1->irb.esw.esw0.erw.cons != cqr2->irb.esw.esw0.erw.cons) - return 0; + sense1 = dasd_get_sense(&cqr1->irb); + sense2 = dasd_get_sense(&cqr2->irb); - if ((cqr1->irb.esw.esw0.erw.cons == 0) && - (cqr2->irb.esw.esw0.erw.cons == 0)) { - if ((cqr1->irb.scsw.cmd.cstat & (SCHN_STAT_INTF_CTRL_CHK | - SCHN_STAT_CHN_CTRL_CHK)) == - (cqr2->irb.scsw.cmd.cstat & (SCHN_STAT_INTF_CTRL_CHK | - SCHN_STAT_CHN_CTRL_CHK))) + /* one request has sense data, the other not -> no match, return 0 */ + if (!sense1 != !sense2) + return 0; + /* no sense data in both cases -> check cstat for IFCC */ + if (!sense1 && !sense2) { + if ((scsw_cstat(&cqr1->irb.scsw) & (SCHN_STAT_INTF_CTRL_CHK | + SCHN_STAT_CHN_CTRL_CHK)) == + (scsw_cstat(&cqr2->irb.scsw) & (SCHN_STAT_INTF_CTRL_CHK | + SCHN_STAT_CHN_CTRL_CHK))) return 1; /* match with ifcc*/ } /* check sense data; byte 0-2,25,27 */ - if (!((memcmp (cqr1->irb.ecw, cqr2->irb.ecw, 3) == 0) && - (cqr1->irb.ecw[27] == cqr2->irb.ecw[27]) && - (cqr1->irb.ecw[25] == cqr2->irb.ecw[25]))) { + if (!(sense1 && sense2 && + (memcmp(sense1, sense2, 3) == 0) && + (sense1[27] == sense2[27]) && + (sense1[25] == sense2[25]))) { return 0; /* sense doesn't match */ } @@ -2434,7 +2479,7 @@ dasd_3990_erp_further_erp(struct dasd_ccw_req *erp) { struct dasd_device *device = erp->startdev; - char *sense = erp->irb.ecw; + char *sense = dasd_get_sense(&erp->irb); /* check for 24 byte sense ERP */ if ((erp->function == dasd_3990_erp_bus_out) || @@ -2449,7 +2494,7 @@ dasd_3990_erp_further_erp(struct dasd_ccw_req *erp) /* prepare erp for retry on different channel path */ erp = dasd_3990_erp_action_1(erp); - if (!(sense[2] & DASD_SENSE_BIT_0)) { + if (sense && !(sense[2] & DASD_SENSE_BIT_0)) { /* issue a Diagnostic Control command with an * Inhibit Write subcommand */ @@ -2479,10 +2524,11 @@ dasd_3990_erp_further_erp(struct dasd_ccw_req *erp) } /* check for 32 byte sense ERP */ - } else if ((erp->function == dasd_3990_erp_compound_retry) || - (erp->function == dasd_3990_erp_compound_path) || - (erp->function == dasd_3990_erp_compound_code) || - (erp->function == dasd_3990_erp_compound_config)) { + } else if (sense && + ((erp->function == dasd_3990_erp_compound_retry) || + (erp->function == dasd_3990_erp_compound_path) || + (erp->function == dasd_3990_erp_compound_code) || + (erp->function == dasd_3990_erp_compound_config))) { erp = dasd_3990_erp_compound(erp, sense); @@ -2548,18 +2594,19 @@ dasd_3990_erp_handle_match_erp(struct dasd_ccw_req *erp_head, if (erp->retries > 0) { - char *sense = erp->refers->irb.ecw; + char *sense = dasd_get_sense(&erp->refers->irb); /* check for special retries */ - if (erp->function == dasd_3990_erp_action_4) { + if (sense && erp->function == dasd_3990_erp_action_4) { erp = dasd_3990_erp_action_4(erp, sense); - } else if (erp->function == dasd_3990_erp_action_1B_32) { + } else if (sense && + erp->function == dasd_3990_erp_action_1B_32) { erp = dasd_3990_update_1B(erp, sense); - } else if (erp->function == dasd_3990_erp_int_req) { + } else if (sense && erp->function == dasd_3990_erp_int_req) { erp = dasd_3990_erp_int_req(erp); @@ -2622,8 +2669,8 @@ dasd_3990_erp_action(struct dasd_ccw_req * cqr) } /* double-check if current erp/cqr was successful */ - if ((cqr->irb.scsw.cmd.cstat == 0x00) && - (cqr->irb.scsw.cmd.dstat == + if ((scsw_cstat(&cqr->irb.scsw) == 0x00) && + (scsw_dstat(&cqr->irb.scsw) == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))) { DEV_MESSAGE(KERN_DEBUG, device, diff --git a/drivers/s390/block/dasd_alias.c b/drivers/s390/block/dasd_alias.c index 20676cdef4a..219bee7bd77 100644 --- a/drivers/s390/block/dasd_alias.c +++ b/drivers/s390/block/dasd_alias.c @@ -646,14 +646,16 @@ static int reset_summary_unit_check(struct alias_lcu *lcu, { struct dasd_ccw_req *cqr; int rc = 0; + struct ccw1 *ccw; cqr = lcu->rsu_cqr; strncpy((char *) &cqr->magic, "ECKD", 4); ASCEBC((char *) &cqr->magic, 4); - cqr->cpaddr->cmd_code = DASD_ECKD_CCW_RSCK; - cqr->cpaddr->flags = 0 ; - cqr->cpaddr->count = 16; - cqr->cpaddr->cda = (__u32)(addr_t) cqr->data; + ccw = cqr->cpaddr; + ccw->cmd_code = DASD_ECKD_CCW_RSCK; + ccw->flags = 0 ; + ccw->count = 16; + ccw->cda = (__u32)(addr_t) cqr->data; ((char *)cqr->data)[0] = reason; clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); @@ -855,12 +857,21 @@ void dasd_alias_handle_summary_unit_check(struct dasd_device *device, struct alias_lcu *lcu; char reason; struct dasd_eckd_private *private; + char *sense; private = (struct dasd_eckd_private *) device->private; - reason = irb->ecw[8]; - DEV_MESSAGE(KERN_WARNING, device, "%s %x", - "eckd handle summary unit check: reason", reason); + sense = dasd_get_sense(irb); + if (sense) { + reason = sense[8]; + DBF_DEV_EVENT(DBF_NOTICE, device, "%s %x", + "eckd handle summary unit check: reason", reason); + } else { + DBF_DEV_EVENT(DBF_WARNING, device, "%s", + "eckd handle summary unit check:" + " no reason code available"); + return; + } lcu = private->lcu; if (!lcu) { diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index 34339902efb..da231a787ce 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c @@ -67,6 +67,8 @@ int dasd_probeonly = 0; /* is true, when probeonly mode is active */ int dasd_autodetect = 0; /* is true, when autodetection is active */ int dasd_nopav = 0; /* is true, when PAV is disabled */ EXPORT_SYMBOL_GPL(dasd_nopav); +int dasd_nofcx; /* disable High Performance Ficon */ +EXPORT_SYMBOL_GPL(dasd_nofcx); /* * char *dasd[] is intended to hold the ranges supplied by the dasd= statement @@ -272,6 +274,11 @@ dasd_parse_keyword( char *parsestring ) { } return residual_str; } + if (strncmp("nofcx", parsestring, length) == 0) { + dasd_nofcx = 1; + MESSAGE(KERN_INFO, "%s", "disable High Performance Ficon"); + return residual_str; + } if (strncmp("fixedbuffers", parsestring, length) == 0) { if (dasd_page_cache) return residual_str; diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 69f93e626fd..1e4c89b8b30 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -27,9 +27,12 @@ #include #include #include +#include #include "dasd_int.h" #include "dasd_eckd.h" +#include "../cio/chsc.h" + #ifdef PRINTK_HEADER #undef PRINTK_HEADER @@ -245,7 +248,8 @@ define_extent(struct ccw1 *ccw, struct DE_eckd_data *data, unsigned int trk, rc = check_XRC (ccw, data, device); break; default: - DEV_MESSAGE(KERN_ERR, device, "unknown opcode 0x%x", cmd); + DBF_DEV_EVENT(DBF_ERR, device, + "PFX LRE unknown opcode 0x%x", cmd); break; } @@ -289,30 +293,145 @@ static int check_XRC_on_prefix(struct PFX_eckd_data *pfxdata, return 0; /* switch on System Time Stamp - needed for XRC Support */ - pfxdata->define_extend.ga_extended |= 0x08; /* 'Time Stamp Valid' */ - pfxdata->define_extend.ga_extended |= 0x02; /* 'Extended Parameter' */ + pfxdata->define_extent.ga_extended |= 0x08; /* 'Time Stamp Valid' */ + pfxdata->define_extent.ga_extended |= 0x02; /* 'Extended Parameter' */ pfxdata->validity.time_stamp = 1; /* 'Time Stamp Valid' */ - rc = get_sync_clock(&pfxdata->define_extend.ep_sys_time); + rc = get_sync_clock(&pfxdata->define_extent.ep_sys_time); /* Ignore return code if sync clock is switched off. */ if (rc == -ENOSYS || rc == -EACCES) rc = 0; return rc; } -static int prefix(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata, - unsigned int trk, unsigned int totrk, int cmd, - struct dasd_device *basedev, struct dasd_device *startdev) +static void fill_LRE_data(struct LRE_eckd_data *data, unsigned int trk, + unsigned int rec_on_trk, int count, int cmd, + struct dasd_device *device, unsigned int reclen, + unsigned int tlf) +{ + struct dasd_eckd_private *private; + int sector; + int dn, d; + + private = (struct dasd_eckd_private *) device->private; + + memset(data, 0, sizeof(*data)); + sector = 0; + if (rec_on_trk) { + switch (private->rdc_data.dev_type) { + case 0x3390: + dn = ceil_quot(reclen + 6, 232); + d = 9 + ceil_quot(reclen + 6 * (dn + 1), 34); + sector = (49 + (rec_on_trk - 1) * (10 + d)) / 8; + break; + case 0x3380: + d = 7 + ceil_quot(reclen + 12, 32); + sector = (39 + (rec_on_trk - 1) * (8 + d)) / 7; + break; + } + } + data->sector = sector; + /* note: meaning of count depends on the operation + * for record based I/O it's the number of records, but for + * track based I/O it's the number of tracks + */ + data->count = count; + switch (cmd) { + case DASD_ECKD_CCW_WRITE_HOME_ADDRESS: + data->operation.orientation = 0x3; + data->operation.operation = 0x03; + break; + case DASD_ECKD_CCW_READ_HOME_ADDRESS: + data->operation.orientation = 0x3; + data->operation.operation = 0x16; + break; + case DASD_ECKD_CCW_WRITE_RECORD_ZERO: + data->operation.orientation = 0x1; + data->operation.operation = 0x03; + data->count++; + break; + case DASD_ECKD_CCW_READ_RECORD_ZERO: + data->operation.orientation = 0x3; + data->operation.operation = 0x16; + data->count++; + break; + case DASD_ECKD_CCW_WRITE: + case DASD_ECKD_CCW_WRITE_MT: + case DASD_ECKD_CCW_WRITE_KD: + case DASD_ECKD_CCW_WRITE_KD_MT: + data->auxiliary.length_valid = 0x1; + data->length = reclen; + data->operation.operation = 0x01; + break; + case DASD_ECKD_CCW_WRITE_CKD: + case DASD_ECKD_CCW_WRITE_CKD_MT: + data->auxiliary.length_valid = 0x1; + data->length = reclen; + data->operation.operation = 0x03; + break; + case DASD_ECKD_CCW_WRITE_TRACK_DATA: + data->auxiliary.length_valid = 0x1; + data->length = reclen; /* not tlf, as one might think */ + data->operation.operation = 0x3F; + data->extended_operation = 0x23; + break; + case DASD_ECKD_CCW_READ: + case DASD_ECKD_CCW_READ_MT: + case DASD_ECKD_CCW_READ_KD: + case DASD_ECKD_CCW_READ_KD_MT: + data->auxiliary.length_valid = 0x1; + data->length = reclen; + data->operation.operation = 0x06; + break; + case DASD_ECKD_CCW_READ_CKD: + case DASD_ECKD_CCW_READ_CKD_MT: + data->auxiliary.length_valid = 0x1; + data->length = reclen; + data->operation.operation = 0x16; + break; + case DASD_ECKD_CCW_READ_COUNT: + data->operation.operation = 0x06; + break; + case DASD_ECKD_CCW_READ_TRACK_DATA: + data->auxiliary.length_valid = 0x1; + data->length = tlf; + data->operation.operation = 0x0C; + break; + case DASD_ECKD_CCW_ERASE: + data->length = reclen; + data->auxiliary.length_valid = 0x1; + data->operation.operation = 0x0b; + break; + default: + DBF_DEV_EVENT(DBF_ERR, device, + "fill LRE unknown opcode 0x%x", cmd); + BUG(); + } + set_ch_t(&data->seek_addr, + trk / private->rdc_data.trk_per_cyl, + trk % private->rdc_data.trk_per_cyl); + data->search_arg.cyl = data->seek_addr.cyl; + data->search_arg.head = data->seek_addr.head; + data->search_arg.record = rec_on_trk; +} + +static int prefix_LRE(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata, + unsigned int trk, unsigned int totrk, int cmd, + struct dasd_device *basedev, struct dasd_device *startdev, + unsigned char format, unsigned int rec_on_trk, int count, + unsigned int blksize, unsigned int tlf) { struct dasd_eckd_private *basepriv, *startpriv; - struct DE_eckd_data *data; + struct DE_eckd_data *dedata; + struct LRE_eckd_data *lredata; u32 begcyl, endcyl; u16 heads, beghead, endhead; int rc = 0; basepriv = (struct dasd_eckd_private *) basedev->private; startpriv = (struct dasd_eckd_private *) startdev->private; - data = &pfxdata->define_extend; + dedata = &pfxdata->define_extent; + lredata = &pfxdata->locate_record; ccw->cmd_code = DASD_ECKD_CCW_PFX; ccw->flags = 0; @@ -321,10 +440,16 @@ static int prefix(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata, memset(pfxdata, 0, sizeof(*pfxdata)); /* prefix data */ - pfxdata->format = 0; + if (format > 1) { + DBF_DEV_EVENT(DBF_ERR, basedev, + "PFX LRE unknown format 0x%x", format); + BUG(); + return -EINVAL; + } + pfxdata->format = format; pfxdata->base_address = basepriv->ned->unit_addr; pfxdata->base_lss = basepriv->ned->ID; - pfxdata->validity.define_extend = 1; + pfxdata->validity.define_extent = 1; /* private uid is kept up to date, conf_data may be outdated */ if (startpriv->uid.type != UA_BASE_DEVICE) { @@ -344,42 +469,55 @@ static int prefix(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata, case DASD_ECKD_CCW_READ_KD: case DASD_ECKD_CCW_READ_KD_MT: case DASD_ECKD_CCW_READ_COUNT: - data->mask.perm = 0x1; - data->attributes.operation = basepriv->attrib.operation; + dedata->mask.perm = 0x1; + dedata->attributes.operation = basepriv->attrib.operation; + break; + case DASD_ECKD_CCW_READ_TRACK_DATA: + dedata->mask.perm = 0x1; + dedata->attributes.operation = basepriv->attrib.operation; + dedata->blk_size = 0; break; case DASD_ECKD_CCW_WRITE: case DASD_ECKD_CCW_WRITE_MT: case DASD_ECKD_CCW_WRITE_KD: case DASD_ECKD_CCW_WRITE_KD_MT: - data->mask.perm = 0x02; - data->attributes.operation = basepriv->attrib.operation; + dedata->mask.perm = 0x02; + dedata->attributes.operation = basepriv->attrib.operation; rc = check_XRC_on_prefix(pfxdata, basedev); break; case DASD_ECKD_CCW_WRITE_CKD: case DASD_ECKD_CCW_WRITE_CKD_MT: - data->attributes.operation = DASD_BYPASS_CACHE; + dedata->attributes.operation = DASD_BYPASS_CACHE; rc = check_XRC_on_prefix(pfxdata, basedev); break; case DASD_ECKD_CCW_ERASE: case DASD_ECKD_CCW_WRITE_HOME_ADDRESS: case DASD_ECKD_CCW_WRITE_RECORD_ZERO: - data->mask.perm = 0x3; - data->mask.auth = 0x1; - data->attributes.operation = DASD_BYPASS_CACHE; + dedata->mask.perm = 0x3; + dedata->mask.auth = 0x1; + dedata->attributes.operation = DASD_BYPASS_CACHE; rc = check_XRC_on_prefix(pfxdata, basedev); break; - default: - DEV_MESSAGE(KERN_ERR, basedev, "unknown opcode 0x%x", cmd); + case DASD_ECKD_CCW_WRITE_TRACK_DATA: + dedata->mask.perm = 0x02; + dedata->attributes.operation = basepriv->attrib.operation; + dedata->blk_size = blksize; + rc = check_XRC_on_prefix(pfxdata, basedev); break; + default: + DBF_DEV_EVENT(DBF_ERR, basedev, + "PFX LRE unknown opcode 0x%x", cmd); + BUG(); + return -EINVAL; } - data->attributes.mode = 0x3; /* ECKD */ + dedata->attributes.mode = 0x3; /* ECKD */ if ((basepriv->rdc_data.cu_type == 0x2105 || basepriv->rdc_data.cu_type == 0x2107 || basepriv->rdc_data.cu_type == 0x1750) && !(basepriv->uses_cdl && trk < 2)) - data->ga_extended |= 0x40; /* Regular Data Format Mode */ + dedata->ga_extended |= 0x40; /* Regular Data Format Mode */ heads = basepriv->rdc_data.trk_per_cyl; begcyl = trk / heads; @@ -388,8 +526,8 @@ static int prefix(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata, endhead = totrk % heads; /* check for sequential prestage - enhance cylinder range */ - if (data->attributes.operation == DASD_SEQ_PRESTAGE || - data->attributes.operation == DASD_SEQ_ACCESS) { + if (dedata->attributes.operation == DASD_SEQ_PRESTAGE || + dedata->attributes.operation == DASD_SEQ_ACCESS) { if (endcyl + basepriv->attrib.nr_cyl < basepriv->real_cyl) endcyl += basepriv->attrib.nr_cyl; @@ -397,11 +535,25 @@ static int prefix(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata, endcyl = (basepriv->real_cyl - 1); } - set_ch_t(&data->beg_ext, begcyl, beghead); - set_ch_t(&data->end_ext, endcyl, endhead); + set_ch_t(&dedata->beg_ext, begcyl, beghead); + set_ch_t(&dedata->end_ext, endcyl, endhead); + + if (format == 1) { + fill_LRE_data(lredata, trk, rec_on_trk, count, cmd, + basedev, blksize, tlf); + } + return rc; } +static int prefix(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata, + unsigned int trk, unsigned int totrk, int cmd, + struct dasd_device *basedev, struct dasd_device *startdev) +{ + return prefix_LRE(ccw, pfxdata, trk, totrk, cmd, basedev, startdev, + 0, 0, 0, 0, 0); +} + static void locate_record(struct ccw1 *ccw, struct LO_eckd_data *data, unsigned int trk, unsigned int rec_on_trk, int no_rec, int cmd, @@ -845,7 +997,8 @@ static int dasd_eckd_read_features(struct dasd_device *device) /* * Build CP for Perform Subsystem Function - SSC. */ -static struct dasd_ccw_req *dasd_eckd_build_psf_ssc(struct dasd_device *device) +static struct dasd_ccw_req *dasd_eckd_build_psf_ssc(struct dasd_device *device, + int enable_pav) { struct dasd_ccw_req *cqr; struct dasd_psf_ssc_data *psf_ssc_data; @@ -862,9 +1015,11 @@ static struct dasd_ccw_req *dasd_eckd_build_psf_ssc(struct dasd_device *device) } psf_ssc_data = (struct dasd_psf_ssc_data *)cqr->data; psf_ssc_data->order = PSF_ORDER_SSC; - psf_ssc_data->suborder = 0x88; - psf_ssc_data->reserved[0] = 0x88; - + psf_ssc_data->suborder = 0x40; + if (enable_pav) { + psf_ssc_data->suborder |= 0x88; + psf_ssc_data->reserved[0] = 0x88; + } ccw = cqr->cpaddr; ccw->cmd_code = DASD_ECKD_CCW_PSF; ccw->cda = (__u32)(addr_t)psf_ssc_data; @@ -885,12 +1040,12 @@ static struct dasd_ccw_req *dasd_eckd_build_psf_ssc(struct dasd_device *device) * call might change behaviour of DASD devices. */ static int -dasd_eckd_psf_ssc(struct dasd_device *device) +dasd_eckd_psf_ssc(struct dasd_device *device, int enable_pav) { struct dasd_ccw_req *cqr; int rc; - cqr = dasd_eckd_build_psf_ssc(device); + cqr = dasd_eckd_build_psf_ssc(device, enable_pav); if (IS_ERR(cqr)) return PTR_ERR(cqr); @@ -909,12 +1064,13 @@ static int dasd_eckd_validate_server(struct dasd_device *device) { int rc; struct dasd_eckd_private *private; + int enable_pav; - /* Currently PAV is the only reason to 'validate' server on LPAR */ if (dasd_nopav || MACHINE_IS_VM) - return 0; - - rc = dasd_eckd_psf_ssc(device); + enable_pav = 0; + else + enable_pav = 1; + rc = dasd_eckd_psf_ssc(device, enable_pav); /* may be requested feature is not available on server, * therefore just report error and go ahead */ private = (struct dasd_eckd_private *) device->private; @@ -1504,40 +1660,41 @@ static void dasd_eckd_handle_unsolicited_interrupt(struct dasd_device *device, struct irb *irb) { char mask; + char *sense = NULL; /* first of all check for state change pending interrupt */ mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP; - if ((irb->scsw.cmd.dstat & mask) == mask) { + if ((scsw_dstat(&irb->scsw) & mask) == mask) { dasd_generic_handle_state_change(device); return; } /* summary unit check */ - if ((irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) && + if ((scsw_dstat(&irb->scsw) & DEV_STAT_UNIT_CHECK) && (irb->ecw[7] == 0x0D)) { dasd_alias_handle_summary_unit_check(device, irb); return; } - + sense = dasd_get_sense(irb); /* service information message SIM */ - if (irb->esw.esw0.erw.cons && !(irb->ecw[27] & DASD_SENSE_BIT_0) && - ((irb->ecw[6] & DASD_SIM_SENSE) == DASD_SIM_SENSE)) { - dasd_3990_erp_handle_sim(device, irb->ecw); + if (sense && !(sense[27] & DASD_SENSE_BIT_0) && + ((sense[6] & DASD_SIM_SENSE) == DASD_SIM_SENSE)) { + dasd_3990_erp_handle_sim(device, sense); dasd_schedule_device_bh(device); return; } - if ((irb->scsw.cmd.cc == 1) && - (irb->scsw.cmd.fctl & SCSW_FCTL_START_FUNC) && - (irb->scsw.cmd.actl & SCSW_ACTL_START_PEND) && - (irb->scsw.cmd.stctl & SCSW_STCTL_STATUS_PEND)) { + if ((scsw_cc(&irb->scsw) == 1) && + (scsw_fctl(&irb->scsw) & SCSW_FCTL_START_FUNC) && + (scsw_actl(&irb->scsw) & SCSW_ACTL_START_PEND) && + (scsw_stctl(&irb->scsw) & SCSW_STCTL_STATUS_PEND)) { /* fake irb do nothing, they are handled elsewhere */ dasd_schedule_device_bh(device); return; } - if (!(irb->esw.esw0.erw.cons)) { + if (!sense) { /* just report other unsolicited interrupts */ DEV_MESSAGE(KERN_ERR, device, "%s", "unsolicited interrupt received"); @@ -1552,9 +1709,19 @@ static void dasd_eckd_handle_unsolicited_interrupt(struct dasd_device *device, return; }; -static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev, + +static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single( + struct dasd_device *startdev, struct dasd_block *block, - struct request *req) + struct request *req, + sector_t first_rec, + sector_t last_rec, + sector_t first_trk, + sector_t last_trk, + unsigned int first_offs, + unsigned int last_offs, + unsigned int blk_per_trk, + unsigned int blksize) { struct dasd_eckd_private *private; unsigned long *idaws; @@ -1564,11 +1731,9 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev, struct req_iterator iter; struct bio_vec *bv; char *dst; - unsigned int blksize, blk_per_trk, off; + unsigned int off; int count, cidaw, cplength, datasize; - sector_t recid, first_rec, last_rec; - sector_t first_trk, last_trk; - unsigned int first_offs, last_offs; + sector_t recid; unsigned char cmd, rcmd; int use_prefix; struct dasd_device *basedev; @@ -1581,15 +1746,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev, cmd = DASD_ECKD_CCW_WRITE_MT; else return ERR_PTR(-EINVAL); - /* Calculate number of blocks/records per track. */ - blksize = block->bp_block; - blk_per_trk = recs_per_track(&private->rdc_data, 0, blksize); - /* Calculate record id of first and last block. */ - first_rec = first_trk = req->sector >> block->s2b_shift; - first_offs = sector_div(first_trk, blk_per_trk); - last_rec = last_trk = - (req->sector + req->nr_sectors - 1) >> block->s2b_shift; - last_offs = sector_div(last_trk, blk_per_trk); + /* Check struct bio and count the number of blocks for the request. */ count = 0; cidaw = 0; @@ -1739,6 +1896,497 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev, return cqr; } +static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_track( + struct dasd_device *startdev, + struct dasd_block *block, + struct request *req, + sector_t first_rec, + sector_t last_rec, + sector_t first_trk, + sector_t last_trk, + unsigned int first_offs, + unsigned int last_offs, + unsigned int blk_per_trk, + unsigned int blksize) +{ + struct dasd_eckd_private *private; + unsigned long *idaws; + struct dasd_ccw_req *cqr; + struct ccw1 *ccw; + struct req_iterator iter; + struct bio_vec *bv; + char *dst, *idaw_dst; + unsigned int cidaw, cplength, datasize; + unsigned int tlf; + sector_t recid; + unsigned char cmd; + struct dasd_device *basedev; + unsigned int trkcount, count, count_to_trk_end; + unsigned int idaw_len, seg_len, part_len, len_to_track_end; + unsigned char new_track, end_idaw; + sector_t trkid; + unsigned int recoffs; + + basedev = block->base; + private = (struct dasd_eckd_private *) basedev->private; + if (rq_data_dir(req) == READ) + cmd = DASD_ECKD_CCW_READ_TRACK_DATA; + else if (rq_data_dir(req) == WRITE) + cmd = DASD_ECKD_CCW_WRITE_TRACK_DATA; + else + return ERR_PTR(-EINVAL); + + /* Track based I/O needs IDAWs for each page, and not just for + * 64 bit addresses. We need additional idals for pages + * that get filled from two tracks, so we use the number + * of records as upper limit. + */ + cidaw = last_rec - first_rec + 1; + trkcount = last_trk - first_trk + 1; + + /* 1x prefix + one read/write ccw per track */ + cplength = 1 + trkcount; + + /* on 31-bit we need space for two 32 bit addresses per page + * on 64-bit one 64 bit address + */ + datasize = sizeof(struct PFX_eckd_data) + + cidaw * sizeof(unsigned long long); + + /* Allocate the ccw request. */ + cqr = dasd_smalloc_request(dasd_eckd_discipline.name, + cplength, datasize, startdev); + if (IS_ERR(cqr)) + return cqr; + ccw = cqr->cpaddr; + /* transfer length factor: how many bytes to read from the last track */ + if (first_trk == last_trk) + tlf = last_offs - first_offs + 1; + else + tlf = last_offs + 1; + tlf *= blksize; + + if (prefix_LRE(ccw++, cqr->data, first_trk, + last_trk, cmd, basedev, startdev, + 1 /* format */, first_offs + 1, + trkcount, blksize, + tlf) == -EAGAIN) { + /* Clock not in sync and XRC is enabled. + * Try again later. + */ + dasd_sfree_request(cqr, startdev); + return ERR_PTR(-EAGAIN); + } + + /* + * The translation of request into ccw programs must meet the + * following conditions: + * - all idaws but the first and the last must address full pages + * (or 2K blocks on 31-bit) + * - the scope of a ccw and it's idal ends with the track boundaries + */ + idaws = (unsigned long *) (cqr->data + sizeof(struct PFX_eckd_data)); + recid = first_rec; + new_track = 1; + end_idaw = 0; + len_to_track_end = 0; + idaw_dst = 0; + idaw_len = 0; + rq_for_each_segment(bv, req, iter) { + dst = page_address(bv->bv_page) + bv->bv_offset; + seg_len = bv->bv_len; + while (seg_len) { + if (new_track) { + trkid = recid; + recoffs = sector_div(trkid, blk_per_trk); + count_to_trk_end = blk_per_trk - recoffs; + count = min((last_rec - recid + 1), + (sector_t)count_to_trk_end); + len_to_track_end = count * blksize; + ccw[-1].flags |= CCW_FLAG_CC; + ccw->cmd_code = cmd; + ccw->count = len_to_track_end; + ccw->cda = (__u32)(addr_t)idaws; + ccw->flags = CCW_FLAG_IDA; + ccw++; + recid += count; + new_track = 0; + } + /* If we start a new idaw, everything is fine and the + * start of the new idaw is the start of this segment. + * If we continue an idaw, we must make sure that the + * current segment begins where the so far accumulated + * idaw ends + */ + if (!idaw_dst) + idaw_dst = dst; + if ((idaw_dst + idaw_len) != dst) { + dasd_sfree_request(cqr, startdev); + return ERR_PTR(-ERANGE); + } + part_len = min(seg_len, len_to_track_end); + seg_len -= part_len; + dst += part_len; + idaw_len += part_len; + len_to_track_end -= part_len; + /* collected memory area ends on an IDA_BLOCK border, + * -> create an idaw + * idal_create_words will handle cases where idaw_len + * is larger then IDA_BLOCK_SIZE + */ + if (!(__pa(idaw_dst + idaw_len) & (IDA_BLOCK_SIZE-1))) + end_idaw = 1; + /* We also need to end the idaw at track end */ + if (!len_to_track_end) { + new_track = 1; + end_idaw = 1; + } + if (end_idaw) { + idaws = idal_create_words(idaws, idaw_dst, + idaw_len); + idaw_dst = 0; + idaw_len = 0; + end_idaw = 0; + } + } + } + + if (blk_noretry_request(req) || + block->base->features & DASD_FEATURE_FAILFAST) + set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); + cqr->startdev = startdev; + cqr->memdev = startdev; + cqr->block = block; + cqr->expires = 5 * 60 * HZ; /* 5 minutes */ + cqr->lpm = private->path_data.ppm; + cqr->retries = 256; + cqr->buildclk = get_clock(); + cqr->status = DASD_CQR_FILLED; + return cqr; +} + +static int prepare_itcw(struct itcw *itcw, + unsigned int trk, unsigned int totrk, int cmd, + struct dasd_device *basedev, + struct dasd_device *startdev, + unsigned int rec_on_trk, int count, + unsigned int blksize, + unsigned int total_data_size, + unsigned int tlf, + unsigned int blk_per_trk) +{ + struct PFX_eckd_data pfxdata; + struct dasd_eckd_private *basepriv, *startpriv; + struct DE_eckd_data *dedata; + struct LRE_eckd_data *lredata; + struct dcw *dcw; + + u32 begcyl, endcyl; + u16 heads, beghead, endhead; + u8 pfx_cmd; + + int rc = 0; + int sector = 0; + int dn, d; + + + /* setup prefix data */ + basepriv = (struct dasd_eckd_private *) basedev->private; + startpriv = (struct dasd_eckd_private *) startdev->private; + dedata = &pfxdata.define_extent; + lredata = &pfxdata.locate_record; + + memset(&pfxdata, 0, sizeof(pfxdata)); + pfxdata.format = 1; /* PFX with LRE */ + pfxdata.base_address = basepriv->ned->unit_addr; + pfxdata.base_lss = basepriv->ned->ID; + pfxdata.validity.define_extent = 1; + + /* private uid is kept up to date, conf_data may be outdated */ + if (startpriv->uid.type != UA_BASE_DEVICE) { + pfxdata.validity.verify_base = 1; + if (startpriv->uid.type == UA_HYPER_PAV_ALIAS) + pfxdata.validity.hyper_pav = 1; + } + + switch (cmd) { + case DASD_ECKD_CCW_READ_TRACK_DATA: + dedata->mask.perm = 0x1; + dedata->attributes.operation = basepriv->attrib.operation; + dedata->blk_size = blksize; + dedata->ga_extended |= 0x42; + lredata->operation.orientation = 0x0; + lredata->operation.operation = 0x0C; + lredata->auxiliary.check_bytes = 0x01; + pfx_cmd = DASD_ECKD_CCW_PFX_READ; + break; + case DASD_ECKD_CCW_WRITE_TRACK_DATA: + dedata->mask.perm = 0x02; + dedata->attributes.operation = basepriv->attrib.operation; + dedata->blk_size = blksize; + rc = check_XRC_on_prefix(&pfxdata, basedev); + dedata->ga_extended |= 0x42; + lredata->operation.orientation = 0x0; + lredata->operation.operation = 0x3F; + lredata->extended_operation = 0x23; + lredata->auxiliary.check_bytes = 0x2; + pfx_cmd = DASD_ECKD_CCW_PFX; + break; + default: + DBF_DEV_EVENT(DBF_ERR, basedev, + "prepare itcw, unknown opcode 0x%x", cmd); + BUG(); + break; + } + if (rc) + return rc; + + dedata->attributes.mode = 0x3; /* ECKD */ + + heads = basepriv->rdc_data.trk_per_cyl; + begcyl = trk / heads; + beghead = trk % heads; + endcyl = totrk / heads; + endhead = totrk % heads; + + /* check for sequential prestage - enhance cylinder range */ + if (dedata->attributes.operation == DASD_SEQ_PRESTAGE || + dedata->attributes.operation == DASD_SEQ_ACCESS) { + + if (endcyl + basepriv->attrib.nr_cyl < basepriv->real_cyl) + endcyl += basepriv->attrib.nr_cyl; + else + endcyl = (basepriv->real_cyl - 1); + } + + set_ch_t(&dedata->beg_ext, begcyl, beghead); + set_ch_t(&dedata->end_ext, endcyl, endhead); + + dedata->ep_format = 0x20; /* records per track is valid */ + dedata->ep_rec_per_track = blk_per_trk; + + if (rec_on_trk) { + switch (basepriv->rdc_data.dev_type) { + case 0x3390: + dn = ceil_quot(blksize + 6, 232); + d = 9 + ceil_quot(blksize + 6 * (dn + 1), 34); + sector = (49 + (rec_on_trk - 1) * (10 + d)) / 8; + break; + case 0x3380: + d = 7 + ceil_quot(blksize + 12, 32); + sector = (39 + (rec_on_trk - 1) * (8 + d)) / 7; + break; + } + } + + lredata->auxiliary.length_valid = 1; + lredata->auxiliary.length_scope = 1; + lredata->auxiliary.imbedded_ccw_valid = 1; + lredata->length = tlf; + lredata->imbedded_ccw = cmd; + lredata->count = count; + lredata->sector = sector; + set_ch_t(&lredata->seek_addr, begcyl, beghead); + lredata->search_arg.cyl = lredata->seek_addr.cyl; + lredata->search_arg.head = lredata->seek_addr.head; + lredata->search_arg.record = rec_on_trk; + + dcw = itcw_add_dcw(itcw, pfx_cmd, 0, + &pfxdata, sizeof(pfxdata), total_data_size); + + return rc; +} + +static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track( + struct dasd_device *startdev, + struct dasd_block *block, + struct request *req, + sector_t first_rec, + sector_t last_rec, + sector_t first_trk, + sector_t last_trk, + unsigned int first_offs, + unsigned int last_offs, + unsigned int blk_per_trk, + unsigned int blksize) +{ + struct dasd_eckd_private *private; + struct dasd_ccw_req *cqr; + struct req_iterator iter; + struct bio_vec *bv; + char *dst; + unsigned int trkcount, ctidaw; + unsigned char cmd; + struct dasd_device *basedev; + unsigned int tlf; + struct itcw *itcw; + struct tidaw *last_tidaw = NULL; + int itcw_op; + size_t itcw_size; + + basedev = block->base; + private = (struct dasd_eckd_private *) basedev->private; + if (rq_data_dir(req) == READ) { + cmd = DASD_ECKD_CCW_READ_TRACK_DATA; + itcw_op = ITCW_OP_READ; + } else if (rq_data_dir(req) == WRITE) { + cmd = DASD_ECKD_CCW_WRITE_TRACK_DATA; + itcw_op = ITCW_OP_WRITE; + } else + return ERR_PTR(-EINVAL); + + /* trackbased I/O needs address all memory via TIDAWs, + * not just for 64 bit addresses. This allows us to map + * each segment directly to one tidaw. + */ + trkcount = last_trk - first_trk + 1; + ctidaw = 0; + rq_for_each_segment(bv, req, iter) { + ++ctidaw; + } + + /* Allocate the ccw request. */ + itcw_size = itcw_calc_size(0, ctidaw, 0); + cqr = dasd_smalloc_request(dasd_eckd_discipline.name, + 0, itcw_size, startdev); + if (IS_ERR(cqr)) + return cqr; + + cqr->cpmode = 1; + cqr->startdev = startdev; + cqr->memdev = startdev; + cqr->block = block; + cqr->expires = 100*HZ; + cqr->buildclk = get_clock(); + cqr->status = DASD_CQR_FILLED; + cqr->retries = 10; + + /* transfer length factor: how many bytes to read from the last track */ + if (first_trk == last_trk) + tlf = last_offs - first_offs + 1; + else + tlf = last_offs + 1; + tlf *= blksize; + + itcw = itcw_init(cqr->data, itcw_size, itcw_op, 0, ctidaw, 0); + cqr->cpaddr = itcw_get_tcw(itcw); + + if (prepare_itcw(itcw, first_trk, last_trk, + cmd, basedev, startdev, + first_offs + 1, + trkcount, blksize, + (last_rec - first_rec + 1) * blksize, + tlf, blk_per_trk) == -EAGAIN) { + /* Clock not in sync and XRC is enabled. + * Try again later. + */ + dasd_sfree_request(cqr, startdev); + return ERR_PTR(-EAGAIN); + } + + /* + * A tidaw can address 4k of memory, but must not cross page boundaries + * We can let the block layer handle this by setting + * blk_queue_segment_boundary to page boundaries and + * blk_max_segment_size to page size when setting up the request queue. + */ + rq_for_each_segment(bv, req, iter) { + dst = page_address(bv->bv_page) + bv->bv_offset; + last_tidaw = itcw_add_tidaw(itcw, 0x00, dst, bv->bv_len); + if (IS_ERR(last_tidaw)) + return (struct dasd_ccw_req *)last_tidaw; + } + + last_tidaw->flags |= 0x80; + itcw_finalize(itcw); + + if (blk_noretry_request(req) || + block->base->features & DASD_FEATURE_FAILFAST) + set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); + cqr->startdev = startdev; + cqr->memdev = startdev; + cqr->block = block; + cqr->expires = 5 * 60 * HZ; /* 5 minutes */ + cqr->lpm = private->path_data.ppm; + cqr->retries = 256; + cqr->buildclk = get_clock(); + cqr->status = DASD_CQR_FILLED; + return cqr; +} + +static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev, + struct dasd_block *block, + struct request *req) +{ + int tpm, cmdrtd, cmdwtd; + int use_prefix; + + struct dasd_eckd_private *private; + int fcx_in_css, fcx_in_gneq, fcx_in_features; + struct dasd_device *basedev; + sector_t first_rec, last_rec; + sector_t first_trk, last_trk; + unsigned int first_offs, last_offs; + unsigned int blk_per_trk, blksize; + int cdlspecial; + struct dasd_ccw_req *cqr; + + basedev = block->base; + private = (struct dasd_eckd_private *) basedev->private; + + /* Calculate number of blocks/records per track. */ + blksize = block->bp_block; + blk_per_trk = recs_per_track(&private->rdc_data, 0, blksize); + /* Calculate record id of first and last block. */ + first_rec = first_trk = req->sector >> block->s2b_shift; + first_offs = sector_div(first_trk, blk_per_trk); + last_rec = last_trk = + (req->sector + req->nr_sectors - 1) >> block->s2b_shift; + last_offs = sector_div(last_trk, blk_per_trk); + cdlspecial = (private->uses_cdl && first_rec < 2*blk_per_trk); + + /* is transport mode supported ? */ + fcx_in_css = css_general_characteristics.fcx; + fcx_in_gneq = private->gneq->reserved2[7] & 0x04; + fcx_in_features = private->features.feature[40] & 0x80; + tpm = fcx_in_css && fcx_in_gneq && fcx_in_features; + + /* is read track data and write track data in command mode supported? */ + cmdrtd = private->features.feature[9] & 0x20; + cmdwtd = private->features.feature[12] & 0x40; + use_prefix = private->features.feature[8] & 0x01; + + cqr = NULL; + if (cdlspecial || dasd_page_cache) { + /* do nothing, just fall through to the cmd mode single case */ + } else if (!dasd_nofcx && tpm && (first_trk == last_trk)) { + cqr = dasd_eckd_build_cp_tpm_track(startdev, block, req, + first_rec, last_rec, + first_trk, last_trk, + first_offs, last_offs, + blk_per_trk, blksize); + if (IS_ERR(cqr) && PTR_ERR(cqr) != -EAGAIN) + cqr = NULL; + } else if (use_prefix && + (((rq_data_dir(req) == READ) && cmdrtd) || + ((rq_data_dir(req) == WRITE) && cmdwtd))) { + cqr = dasd_eckd_build_cp_cmd_track(startdev, block, req, + first_rec, last_rec, + first_trk, last_trk, + first_offs, last_offs, + blk_per_trk, blksize); + if (IS_ERR(cqr) && PTR_ERR(cqr) != -EAGAIN) + cqr = NULL; + } + if (!cqr) + cqr = dasd_eckd_build_cp_cmd_single(startdev, block, req, + first_rec, last_rec, + first_trk, last_trk, + first_offs, last_offs, + blk_per_trk, blksize); + return cqr; +} + static int dasd_eckd_free_cp(struct dasd_ccw_req *cqr, struct request *req) { @@ -1792,7 +2440,7 @@ out: } /* - * Modify ccw chain in cqr so it can be started on a base device. + * Modify ccw/tcw in cqr so it can be started on a base device. * * Note that this is not enough to restart the cqr! * Either reset cqr->startdev as well (summary unit check handling) @@ -1802,13 +2450,24 @@ void dasd_eckd_reset_ccw_to_base_io(struct dasd_ccw_req *cqr) { struct ccw1 *ccw; struct PFX_eckd_data *pfxdata; - - ccw = cqr->cpaddr; - pfxdata = cqr->data; - - if (ccw->cmd_code == DASD_ECKD_CCW_PFX) { + struct tcw *tcw; + struct tccb *tccb; + struct dcw *dcw; + + if (cqr->cpmode == 1) { + tcw = cqr->cpaddr; + tccb = tcw_get_tccb(tcw); + dcw = (struct dcw *)&tccb->tca[0]; + pfxdata = (struct PFX_eckd_data *)&dcw->cd[0]; pfxdata->validity.verify_base = 0; pfxdata->validity.hyper_pav = 0; + } else { + ccw = cqr->cpaddr; + pfxdata = cqr->data; + if (ccw->cmd_code == DASD_ECKD_CCW_PFX) { + pfxdata->validity.verify_base = 0; + pfxdata->validity.hyper_pav = 0; + } } } @@ -1886,6 +2545,7 @@ dasd_eckd_release(struct dasd_device *device) { struct dasd_ccw_req *cqr; int rc; + struct ccw1 *ccw; if (!capable(CAP_SYS_ADMIN)) return -EACCES; @@ -1897,10 +2557,11 @@ dasd_eckd_release(struct dasd_device *device) "Could not allocate initialization request"); return PTR_ERR(cqr); } - cqr->cpaddr->cmd_code = DASD_ECKD_CCW_RELEASE; - cqr->cpaddr->flags |= CCW_FLAG_SLI; - cqr->cpaddr->count = 32; - cqr->cpaddr->cda = (__u32)(addr_t) cqr->data; + ccw = cqr->cpaddr; + ccw->cmd_code = DASD_ECKD_CCW_RELEASE; + ccw->flags |= CCW_FLAG_SLI; + ccw->count = 32; + ccw->cda = (__u32)(addr_t) cqr->data; cqr->startdev = device; cqr->memdev = device; clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); @@ -1927,6 +2588,7 @@ dasd_eckd_reserve(struct dasd_device *device) { struct dasd_ccw_req *cqr; int rc; + struct ccw1 *ccw; if (!capable(CAP_SYS_ADMIN)) return -EACCES; @@ -1938,10 +2600,11 @@ dasd_eckd_reserve(struct dasd_device *device) "Could not allocate initialization request"); return PTR_ERR(cqr); } - cqr->cpaddr->cmd_code = DASD_ECKD_CCW_RESERVE; - cqr->cpaddr->flags |= CCW_FLAG_SLI; - cqr->cpaddr->count = 32; - cqr->cpaddr->cda = (__u32)(addr_t) cqr->data; + ccw = cqr->cpaddr; + ccw->cmd_code = DASD_ECKD_CCW_RESERVE; + ccw->flags |= CCW_FLAG_SLI; + ccw->count = 32; + ccw->cda = (__u32)(addr_t) cqr->data; cqr->startdev = device; cqr->memdev = device; clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); @@ -1967,6 +2630,7 @@ dasd_eckd_steal_lock(struct dasd_device *device) { struct dasd_ccw_req *cqr; int rc; + struct ccw1 *ccw; if (!capable(CAP_SYS_ADMIN)) return -EACCES; @@ -1978,10 +2642,11 @@ dasd_eckd_steal_lock(struct dasd_device *device) "Could not allocate initialization request"); return PTR_ERR(cqr); } - cqr->cpaddr->cmd_code = DASD_ECKD_CCW_SLCK; - cqr->cpaddr->flags |= CCW_FLAG_SLI; - cqr->cpaddr->count = 32; - cqr->cpaddr->cda = (__u32)(addr_t) cqr->data; + ccw = cqr->cpaddr; + ccw->cmd_code = DASD_ECKD_CCW_SLCK; + ccw->flags |= CCW_FLAG_SLI; + ccw->count = 32; + ccw->cda = (__u32)(addr_t) cqr->data; cqr->startdev = device; cqr->memdev = device; clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); @@ -2271,7 +2936,7 @@ dasd_eckd_dump_ccw_range(struct ccw1 *from, struct ccw1 *to, char *page) * Print sense data and related channel program. * Parts are printed because printk buffer is only 1024 bytes. */ -static void dasd_eckd_dump_sense(struct dasd_device *device, +static void dasd_eckd_dump_sense_ccw(struct dasd_device *device, struct dasd_ccw_req *req, struct irb *irb) { char *page; @@ -2290,7 +2955,7 @@ static void dasd_eckd_dump_sense(struct dasd_device *device, dev_name(&device->cdev->dev)); len += sprintf(page + len, KERN_ERR PRINTK_HEADER " in req: %p CS: 0x%02X DS: 0x%02X\n", req, - irb->scsw.cmd.cstat, irb->scsw.cmd.dstat); + scsw_cstat(&irb->scsw), scsw_dstat(&irb->scsw)); len += sprintf(page + len, KERN_ERR PRINTK_HEADER " device %s: Failing CCW: %p\n", dev_name(&device->cdev->dev), @@ -2366,6 +3031,147 @@ static void dasd_eckd_dump_sense(struct dasd_device *device, free_page((unsigned long) page); } + +/* + * Print sense data from a tcw. + */ +static void dasd_eckd_dump_sense_tcw(struct dasd_device *device, + struct dasd_ccw_req *req, struct irb *irb) +{ + char *page; + int len, sl, sct, residual; + + struct tsb *tsb; + u8 *sense; + + + page = (char *) get_zeroed_page(GFP_ATOMIC); + if (page == NULL) { + DEV_MESSAGE(KERN_ERR, device, " %s", + "No memory to dump sense data"); + return; + } + /* dump the sense data */ + len = sprintf(page, KERN_ERR PRINTK_HEADER + " I/O status report for device %s:\n", + dev_name(&device->cdev->dev)); + len += sprintf(page + len, KERN_ERR PRINTK_HEADER + " in req: %p CS: 0x%02X DS: 0x%02X " + "fcxs: 0x%02X schxs: 0x%02X\n", req, + scsw_cstat(&irb->scsw), scsw_dstat(&irb->scsw), + irb->scsw.tm.fcxs, irb->scsw.tm.schxs); + len += sprintf(page + len, KERN_ERR PRINTK_HEADER + " device %s: Failing TCW: %p\n", + dev_name(&device->cdev->dev), + (void *) (addr_t) irb->scsw.tm.tcw); + + tsb = NULL; + sense = NULL; + if (irb->scsw.tm.tcw) + tsb = tcw_get_tsb( + (struct tcw *)(unsigned long)irb->scsw.tm.tcw); + + if (tsb && (irb->scsw.tm.fcxs == 0x01)) { + len += sprintf(page + len, KERN_ERR PRINTK_HEADER + " tsb->length %d\n", tsb->length); + len += sprintf(page + len, KERN_ERR PRINTK_HEADER + " tsb->flags %x\n", tsb->flags); + len += sprintf(page + len, KERN_ERR PRINTK_HEADER + " tsb->dcw_offset %d\n", tsb->dcw_offset); + len += sprintf(page + len, KERN_ERR PRINTK_HEADER + " tsb->count %d\n", tsb->count); + residual = tsb->count - 28; + len += sprintf(page + len, KERN_ERR PRINTK_HEADER + " residual %d\n", residual); + + switch (tsb->flags & 0x07) { + case 1: /* tsa_iostat */ + len += sprintf(page + len, KERN_ERR PRINTK_HEADER + " tsb->tsa.iostat.dev_time %d\n", + tsb->tsa.iostat.dev_time); + len += sprintf(page + len, KERN_ERR PRINTK_HEADER + " tsb->tsa.iostat.def_time %d\n", + tsb->tsa.iostat.def_time); + len += sprintf(page + len, KERN_ERR PRINTK_HEADER + " tsb->tsa.iostat.queue_time %d\n", + tsb->tsa.iostat.queue_time); + len += sprintf(page + len, KERN_ERR PRINTK_HEADER + " tsb->tsa.iostat.dev_busy_time %d\n", + tsb->tsa.iostat.dev_busy_time); + len += sprintf(page + len, KERN_ERR PRINTK_HEADER + " tsb->tsa.iostat.dev_act_time %d\n", + tsb->tsa.iostat.dev_act_time); + sense = tsb->tsa.iostat.sense; + break; + case 2: /* ts_ddpc */ + len += sprintf(page + len, KERN_ERR PRINTK_HEADER + " tsb->tsa.ddpc.rc %d\n", tsb->tsa.ddpc.rc); + len += sprintf(page + len, KERN_ERR PRINTK_HEADER + " tsb->tsa.ddpc.rcq: "); + for (sl = 0; sl < 16; sl++) { + for (sct = 0; sct < 8; sct++) { + len += sprintf(page + len, " %02x", + tsb->tsa.ddpc.rcq[sl]); + } + len += sprintf(page + len, "\n"); + } + sense = tsb->tsa.ddpc.sense; + break; + case 3: /* tsa_intrg */ + len += sprintf(page + len, KERN_ERR PRINTK_HEADER + " tsb->tsa.intrg.: not supportet yet \n"); + break; + } + + if (sense) { + for (sl = 0; sl < 4; sl++) { + len += sprintf(page + len, + KERN_ERR PRINTK_HEADER + " Sense(hex) %2d-%2d:", + (8 * sl), ((8 * sl) + 7)); + for (sct = 0; sct < 8; sct++) { + len += sprintf(page + len, " %02x", + sense[8 * sl + sct]); + } + len += sprintf(page + len, "\n"); + } + + if (sense[27] & DASD_SENSE_BIT_0) { + /* 24 Byte Sense Data */ + sprintf(page + len, KERN_ERR PRINTK_HEADER + " 24 Byte: %x MSG %x, " + "%s MSGb to SYSOP\n", + sense[7] >> 4, sense[7] & 0x0f, + sense[1] & 0x10 ? "" : "no"); + } else { + /* 32 Byte Sense Data */ + sprintf(page + len, KERN_ERR PRINTK_HEADER + " 32 Byte: Format: %x " + "Exception class %x\n", + sense[6] & 0x0f, sense[22] >> 4); + } + } else { + sprintf(page + len, KERN_ERR PRINTK_HEADER + " SORRY - NO VALID SENSE AVAILABLE\n"); + } + } else { + sprintf(page + len, KERN_ERR PRINTK_HEADER + " SORRY - NO TSB DATA AVAILABLE\n"); + } + printk("%s", page); + free_page((unsigned long) page); +} + +static void dasd_eckd_dump_sense(struct dasd_device *device, + struct dasd_ccw_req *req, struct irb *irb) +{ + if (req && scsw_is_tm(&req->irb.scsw)) + dasd_eckd_dump_sense_tcw(device, req, irb); + else + dasd_eckd_dump_sense_ccw(device, req, irb); +} + + /* * max_blocks is dependent on the amount of storage that is available * in the static io buffer for each device. Currently each device has diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h index eecfa776db1..ad45bcac3ce 100644 --- a/drivers/s390/block/dasd_eckd.h +++ b/drivers/s390/block/dasd_eckd.h @@ -38,8 +38,11 @@ #define DASD_ECKD_CCW_RELEASE 0x94 #define DASD_ECKD_CCW_READ_CKD_MT 0x9e #define DASD_ECKD_CCW_WRITE_CKD_MT 0x9d +#define DASD_ECKD_CCW_WRITE_TRACK_DATA 0xA5 +#define DASD_ECKD_CCW_READ_TRACK_DATA 0xA6 #define DASD_ECKD_CCW_RESERVE 0xB4 #define DASD_ECKD_CCW_PFX 0xE7 +#define DASD_ECKD_CCW_PFX_READ 0xEA #define DASD_ECKD_CCW_RSCK 0xF9 /* @@ -123,7 +126,9 @@ struct DE_eckd_data { unsigned long long ep_sys_time; /* Ext Parameter - System Time Stamp */ __u8 ep_format; /* Extended Parameter format byte */ __u8 ep_prio; /* Extended Parameter priority I/O byte */ - __u8 ep_reserved[6]; /* Extended Parameter Reserved */ + __u8 ep_reserved1; /* Extended Parameter Reserved */ + __u8 ep_rec_per_track; /* Number of records on a track */ + __u8 ep_reserved[4]; /* Extended Parameter Reserved */ } __attribute__ ((packed)); struct LO_eckd_data { @@ -144,11 +149,37 @@ struct LO_eckd_data { __u16 length; } __attribute__ ((packed)); +struct LRE_eckd_data { + struct { + unsigned char orientation:2; + unsigned char operation:6; + } __attribute__ ((packed)) operation; + struct { + unsigned char length_valid:1; + unsigned char length_scope:1; + unsigned char imbedded_ccw_valid:1; + unsigned char check_bytes:2; + unsigned char imbedded_count_valid:1; + unsigned char reserved:1; + unsigned char read_count_suffix:1; + } __attribute__ ((packed)) auxiliary; + __u8 imbedded_ccw; + __u8 count; + struct ch_t seek_addr; + struct chr_t search_arg; + __u8 sector; + __u16 length; + __u8 imbedded_count; + __u8 extended_operation; + __u16 extended_parameter_length; + __u8 extended_parameter[0]; +} __attribute__ ((packed)); + /* Prefix data for format 0x00 and 0x01 */ struct PFX_eckd_data { unsigned char format; struct { - unsigned char define_extend:1; + unsigned char define_extent:1; unsigned char time_stamp:1; unsigned char verify_base:1; unsigned char hyper_pav:1; @@ -158,9 +189,8 @@ struct PFX_eckd_data { __u8 aux; __u8 base_lss; __u8 reserved[7]; - struct DE_eckd_data define_extend; - struct LO_eckd_data locate_record; - __u8 LO_extended_data[4]; + struct DE_eckd_data define_extent; + struct LRE_eckd_data locate_record; } __attribute__ ((packed)); struct dasd_eckd_characteristics { diff --git a/drivers/s390/block/dasd_eer.c b/drivers/s390/block/dasd_eer.c index f8e05ce9862..9ce4209552a 100644 --- a/drivers/s390/block/dasd_eer.c +++ b/drivers/s390/block/dasd_eer.c @@ -297,11 +297,12 @@ static void dasd_eer_write_standard_trigger(struct dasd_device *device, struct dasd_eer_header header; unsigned long flags; struct eerbuffer *eerb; + char *sense; /* go through cqr chain and count the valid sense data sets */ data_size = 0; for (temp_cqr = cqr; temp_cqr; temp_cqr = temp_cqr->refers) - if (temp_cqr->irb.esw.esw0.erw.cons) + if (dasd_get_sense(&temp_cqr->irb)) data_size += 32; header.total_size = sizeof(header) + data_size + 4; /* "EOR" */ @@ -316,9 +317,11 @@ static void dasd_eer_write_standard_trigger(struct dasd_device *device, list_for_each_entry(eerb, &bufferlist, list) { dasd_eer_start_record(eerb, header.total_size); dasd_eer_write_buffer(eerb, (char *) &header, sizeof(header)); - for (temp_cqr = cqr; temp_cqr; temp_cqr = temp_cqr->refers) - if (temp_cqr->irb.esw.esw0.erw.cons) - dasd_eer_write_buffer(eerb, cqr->irb.ecw, 32); + for (temp_cqr = cqr; temp_cqr; temp_cqr = temp_cqr->refers) { + sense = dasd_get_sense(&temp_cqr->irb); + if (sense) + dasd_eer_write_buffer(eerb, sense, 32); + } dasd_eer_write_buffer(eerb, "EOR", 4); } spin_unlock_irqrestore(&bufferlock, flags); @@ -451,6 +454,7 @@ int dasd_eer_enable(struct dasd_device *device) { struct dasd_ccw_req *cqr; unsigned long flags; + struct ccw1 *ccw; if (device->eer_cqr) return 0; @@ -468,10 +472,11 @@ int dasd_eer_enable(struct dasd_device *device) cqr->expires = 10 * HZ; clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); - cqr->cpaddr->cmd_code = DASD_ECKD_CCW_SNSS; - cqr->cpaddr->count = SNSS_DATA_SIZE; - cqr->cpaddr->flags = 0; - cqr->cpaddr->cda = (__u32)(addr_t) cqr->data; + ccw = cqr->cpaddr; + ccw->cmd_code = DASD_ECKD_CCW_SNSS; + ccw->count = SNSS_DATA_SIZE; + ccw->flags = 0; + ccw->cda = (__u32)(addr_t) cqr->data; cqr->buildclk = get_clock(); cqr->status = DASD_CQR_FILLED; diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index 29991a9fa07..7b314c1d471 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -157,7 +157,8 @@ struct dasd_ccw_req { struct dasd_block *block; /* the originating block device */ struct dasd_device *memdev; /* the device used to allocate this */ struct dasd_device *startdev; /* device the request is started on */ - struct ccw1 *cpaddr; /* address of channel program */ + void *cpaddr; /* address of ccw or tcw */ + unsigned char cpmode; /* 0 = cmd mode, 1 = itcw */ char status; /* status of this request */ short retries; /* A retry counter */ unsigned long flags; /* flags of this request */ @@ -573,12 +574,14 @@ int dasd_generic_notify(struct ccw_device *, int); void dasd_generic_handle_state_change(struct dasd_device *); int dasd_generic_read_dev_chars(struct dasd_device *, char *, void **, int); +char *dasd_get_sense(struct irb *); /* externals in dasd_devmap.c */ extern int dasd_max_devindex; extern int dasd_probeonly; extern int dasd_autodetect; extern int dasd_nopav; +extern int dasd_nofcx; int dasd_devmap_init(void); void dasd_devmap_exit(void); -- cgit v1.2.3-70-g09d2 From fc19f381b3828aa4f8a3417dbefc3418ec6bbe10 Mon Sep 17 00:00:00 2001 From: Stefan Haberland Date: Thu, 26 Mar 2009 15:23:49 +0100 Subject: [S390] dasd: message cleanup Moved some Messages into s390 debug feature and changed remaining messages to use the dev_xxx and pr_xxx macros. Signed-off-by: Stefan Haberland Signed-off-by: Martin Schwidefsky --- drivers/s390/block/dasd.c | 176 ++++----- drivers/s390/block/dasd_3990_erp.c | 730 +++++++++++++++++++------------------ drivers/s390/block/dasd_alias.c | 10 +- drivers/s390/block/dasd_devmap.c | 38 +- drivers/s390/block/dasd_diag.c | 66 ++-- drivers/s390/block/dasd_eckd.c | 196 ++++++---- drivers/s390/block/dasd_eer.c | 6 +- drivers/s390/block/dasd_erp.c | 21 +- drivers/s390/block/dasd_fba.c | 77 ++-- drivers/s390/block/dasd_genhd.c | 7 +- drivers/s390/block/dasd_int.h | 6 + drivers/s390/block/dasd_ioctl.c | 27 +- drivers/s390/block/dasd_proc.c | 20 +- 13 files changed, 743 insertions(+), 637 deletions(-) diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 00f7d24b337..2fd64e5a9ab 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -9,6 +9,9 @@ * */ +#define KMSG_COMPONENT "dasd" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include @@ -222,7 +225,7 @@ static int dasd_state_known_to_basic(struct dasd_device *device) return rc; } /* register 'device' debug area, used for all DBF_DEV_XXX calls */ - device->debug_area = debug_register(dev_name(&device->cdev->dev), 1, 1, + device->debug_area = debug_register(dev_name(&device->cdev->dev), 4, 1, 8 * sizeof(long)); debug_register_view(device->debug_area, &debug_sprintf_view); debug_set_level(device->debug_area, DBF_WARNING); @@ -763,7 +766,7 @@ static inline int dasd_check_cqr(struct dasd_ccw_req *cqr) return -EINVAL; device = cqr->startdev; if (strncmp((char *) &cqr->magic, device->discipline->ebcname, 4)) { - DEV_MESSAGE(KERN_WARNING, device, + DBF_DEV_EVENT(DBF_WARNING, device, " dasd_ccw_req 0x%08x magic doesn't match" " discipline 0x%08x", cqr->magic, @@ -783,6 +786,7 @@ int dasd_term_IO(struct dasd_ccw_req *cqr) { struct dasd_device *device; int retries, rc; + char errorstring[ERRORLENGTH]; /* Check the cqr */ rc = dasd_check_cqr(cqr); @@ -816,10 +820,10 @@ int dasd_term_IO(struct dasd_ccw_req *cqr) "device busy, retry later"); break; default: - DEV_MESSAGE(KERN_ERR, device, - "line %d unknown RC=%d, please " - "report to linux390@de.ibm.com", - __LINE__, rc); + /* internal error 10 - unknown rc*/ + snprintf(errorstring, ERRORLENGTH, "10 %d", rc); + dev_err(&device->cdev->dev, "An error occurred in the " + "DASD device driver, reason=%s\n", errorstring); BUG(); break; } @@ -837,6 +841,7 @@ int dasd_start_IO(struct dasd_ccw_req *cqr) { struct dasd_device *device; int rc; + char errorstring[ERRORLENGTH]; /* Check the cqr */ rc = dasd_check_cqr(cqr); @@ -844,9 +849,10 @@ int dasd_start_IO(struct dasd_ccw_req *cqr) return rc; device = (struct dasd_device *) cqr->startdev; if (cqr->retries < 0) { - DEV_MESSAGE(KERN_DEBUG, device, - "start_IO: request %p (%02x/%i) - no retry left.", - cqr, cqr->status, cqr->retries); + /* internal error 14 - start_IO run out of retries */ + sprintf(errorstring, "14 %p", cqr); + dev_err(&device->cdev->dev, "An error occurred in the DASD " + "device driver, reason=%s\n", errorstring); cqr->status = DASD_CQR_ERROR; return -EIO; } @@ -868,11 +874,11 @@ int dasd_start_IO(struct dasd_ccw_req *cqr) cqr); break; case -EBUSY: - DBF_DEV_EVENT(DBF_ERR, device, "%s", + DBF_DEV_EVENT(DBF_DEBUG, device, "%s", "start_IO: device busy, retry later"); break; case -ETIMEDOUT: - DBF_DEV_EVENT(DBF_ERR, device, "%s", + DBF_DEV_EVENT(DBF_DEBUG, device, "%s", "start_IO: request timeout, retry later"); break; case -EACCES: @@ -882,7 +888,7 @@ int dasd_start_IO(struct dasd_ccw_req *cqr) * Do a retry with all available pathes. */ cqr->lpm = LPM_ANYPATH; - DBF_DEV_EVENT(DBF_ERR, device, "%s", + DBF_DEV_EVENT(DBF_DEBUG, device, "%s", "start_IO: selected pathes gone," " retry on all pathes"); break; @@ -891,13 +897,15 @@ int dasd_start_IO(struct dasd_ccw_req *cqr) "start_IO: -ENODEV device gone, retry"); break; case -EIO: - DBF_DEV_EVENT(DBF_ERR, device, "%s", + DBF_DEV_EVENT(DBF_DEBUG, device, "%s", "start_IO: -EIO device gone, retry"); break; default: - DEV_MESSAGE(KERN_ERR, device, - "line %d unknown RC=%d, please report" - " to linux390@de.ibm.com", __LINE__, rc); + /* internal error 11 - unknown rc */ + snprintf(errorstring, ERRORLENGTH, "11 %d", rc); + dev_err(&device->cdev->dev, + "An error occurred in the DASD device driver, " + "reason=%s\n", errorstring); BUG(); break; } @@ -954,7 +962,7 @@ static void dasd_handle_killed_request(struct ccw_device *cdev, return; cqr = (struct dasd_ccw_req *) intparm; if (cqr->status != DASD_CQR_IN_IO) { - MESSAGE(KERN_DEBUG, + DBF_EVENT(DBF_DEBUG, "invalid status in handle_killed_request: " "bus_id %s, status %02x", dev_name(&cdev->dev), cqr->status); @@ -965,8 +973,8 @@ static void dasd_handle_killed_request(struct ccw_device *cdev, if (device == NULL || device != dasd_device_from_cdev_locked(cdev) || strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) { - MESSAGE(KERN_DEBUG, "invalid device in request: bus_id %s", - dev_name(&cdev->dev)); + DBF_DEV_EVENT(DBF_DEBUG, device, "invalid device in request: " + "bus_id %s", dev_name(&cdev->dev)); return; } @@ -1005,11 +1013,11 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, case -EIO: break; case -ETIMEDOUT: - printk(KERN_WARNING"%s(%s): request timed out\n", + DBF_EVENT(DBF_WARNING, "%s(%s): request timed out\n", __func__, dev_name(&cdev->dev)); break; default: - printk(KERN_WARNING"%s(%s): unknown error %ld\n", + DBF_EVENT(DBF_WARNING, "%s(%s): unknown error %ld\n", __func__, dev_name(&cdev->dev), PTR_ERR(irb)); } dasd_handle_killed_request(cdev, intparm); @@ -1018,10 +1026,6 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, now = get_clock(); - DBF_EVENT(DBF_ERR, "Interrupt: bus_id %s CS/DS %04x ip %08x", - dev_name(&cdev->dev), ((irb->scsw.cmd.cstat << 8) | - irb->scsw.cmd.dstat), (unsigned int) intparm); - /* check for unsolicited interrupts */ cqr = (struct dasd_ccw_req *) intparm; if (!cqr || ((scsw_cc(&irb->scsw) == 1) && @@ -1042,8 +1046,8 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, device = (struct dasd_device *) cqr->startdev; if (!device || strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) { - MESSAGE(KERN_DEBUG, "invalid device in request: bus_id %s", - dev_name(&cdev->dev)); + DBF_DEV_EVENT(DBF_DEBUG, device, "invalid device in request: " + "bus_id %s", dev_name(&cdev->dev)); return; } @@ -1059,13 +1063,11 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, /* check status - the request might have been killed by dyn detach */ if (cqr->status != DASD_CQR_IN_IO) { - MESSAGE(KERN_DEBUG, - "invalid status: bus_id %s, status %02x", - dev_name(&cdev->dev), cqr->status); + DBF_DEV_EVENT(DBF_DEBUG, device, "invalid status: bus_id %s, " + "status %02x", dev_name(&cdev->dev), cqr->status); return; } - DBF_DEV_EVENT(DBF_DEBUG, device, "Int: CS/DS 0x%04x for cqr %p", - ((irb->scsw.cmd.cstat << 8) | irb->scsw.cmd.dstat), cqr); + next = NULL; expires = 0; if (scsw_dstat(&irb->scsw) == (DEV_STAT_CHN_END | DEV_STAT_DEV_END) && @@ -1080,18 +1082,23 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, } } else { /* error */ memcpy(&cqr->irb, irb, sizeof(struct irb)); + /* log sense for every failed I/O to s390 debugfeature */ + dasd_log_sense_dbf(cqr, irb); if (device->features & DASD_FEATURE_ERPLOG) { dasd_log_sense(cqr, irb); } + /* * If we don't want complex ERP for this request, then just * reset this and retry it in the fastpath */ if (!test_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags) && cqr->retries > 0) { - DEV_MESSAGE(KERN_DEBUG, device, - "default ERP in fastpath (%i retries left)", - cqr->retries); + if (cqr->lpm == LPM_ANYPATH) + DBF_DEV_EVENT(DBF_DEBUG, device, + "default ERP in fastpath " + "(%i retries left)", + cqr->retries); cqr->lpm = LPM_ANYPATH; cqr->status = DASD_CQR_QUEUED; next = cqr; @@ -1102,10 +1109,6 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, (!device->stopped)) { if (device->discipline->start_IO(next) == 0) expires = next->expires; - else - DEV_MESSAGE(KERN_DEBUG, device, "%s", - "Interrupt fastpath " - "failed!"); } if (expires != 0) dasd_device_set_timer(device, expires); @@ -1178,6 +1181,7 @@ static void __dasd_device_process_final_queue(struct dasd_device *device, struct dasd_block *block; void (*callback)(struct dasd_ccw_req *, void *data); void *callback_data; + char errorstring[ERRORLENGTH]; list_for_each_safe(l, n, final_queue) { cqr = list_entry(l, struct dasd_ccw_req, devlist); @@ -1198,10 +1202,11 @@ static void __dasd_device_process_final_queue(struct dasd_device *device, cqr->status = DASD_CQR_TERMINATED; break; default: - DEV_MESSAGE(KERN_ERR, device, - "wrong cqr status in __dasd_process_final_queue " - "for cqr %p, status %x", - cqr, cqr->status); + /* internal error 12 - wrong cqr status*/ + snprintf(errorstring, ERRORLENGTH, "12 %p %x02", cqr, cqr->status); + dev_err(&device->cdev->dev, + "An error occurred in the DASD device driver, " + "reason=%s\n", errorstring); BUG(); } if (cqr->callback != NULL) @@ -1226,18 +1231,17 @@ static void __dasd_device_check_expire(struct dasd_device *device) (time_after_eq(jiffies, cqr->expires + cqr->starttime))) { if (device->discipline->term_IO(cqr) != 0) { /* Hmpf, try again in 5 sec */ - DEV_MESSAGE(KERN_ERR, device, - "internal error - timeout (%is) expired " - "for cqr %p, termination failed, " - "retrying in 5s", - (cqr->expires/HZ), cqr); + dev_err(&device->cdev->dev, + "cqr %p timed out (%is) but cannot be " + "ended, retrying in 5 s\n", + cqr, (cqr->expires/HZ)); cqr->expires += 5*HZ; dasd_device_set_timer(device, 5*HZ); } else { - DEV_MESSAGE(KERN_ERR, device, - "internal error - timeout (%is) expired " - "for cqr %p (%i retries left)", - (cqr->expires/HZ), cqr, cqr->retries); + dev_err(&device->cdev->dev, + "cqr %p timed out (%is), %i retries " + "remaining\n", cqr, (cqr->expires/HZ), + cqr->retries); } } } @@ -1299,10 +1303,9 @@ int dasd_flush_device_queue(struct dasd_device *device) rc = device->discipline->term_IO(cqr); if (rc) { /* unable to terminate requeust */ - DEV_MESSAGE(KERN_ERR, device, - "dasd flush ccw_queue is unable " - " to terminate request %p", - cqr); + dev_err(&device->cdev->dev, + "Flushing the DASD request queue " + "failed for request %p\n", cqr); /* stop flush processing */ goto finished; } @@ -1546,10 +1549,9 @@ int dasd_cancel_req(struct dasd_ccw_req *cqr) /* request in IO - terminate IO and release again */ rc = device->discipline->term_IO(cqr); if (rc) { - DEV_MESSAGE(KERN_ERR, device, - "dasd_cancel_req is unable " - " to terminate request %p, rc = %d", - cqr, rc); + dev_err(&device->cdev->dev, + "Cancelling request %p failed with rc=%d\n", + cqr, rc); } else { cqr->stopclk = get_clock(); rc = 1; @@ -1626,7 +1628,7 @@ static inline void __dasd_block_process_erp(struct dasd_block *block, if (cqr->status == DASD_CQR_DONE) DBF_DEV_EVENT(DBF_NOTICE, device, "%s", "ERP successful"); else - DEV_MESSAGE(KERN_ERR, device, "%s", "ERP unsuccessful"); + dev_err(&device->cdev->dev, "ERP failed for the DASD\n"); erp_fn = device->discipline->erp_postaction(cqr); erp_fn(cqr); } @@ -2055,8 +2057,9 @@ static int dasd_open(struct block_device *bdev, fmode_t mode) } if (dasd_probeonly) { - DEV_MESSAGE(KERN_INFO, base, "%s", - "No access to device due to probeonly mode"); + dev_info(&base->cdev->dev, + "Accessing the DASD failed because it is in " + "probeonly mode\n"); rc = -EPERM; goto out; } @@ -2156,14 +2159,14 @@ int dasd_generic_probe(struct ccw_device *cdev, ret = ccw_device_set_options(cdev, CCWDEV_DO_PATHGROUP); if (ret) { - printk(KERN_WARNING + DBF_EVENT(DBF_WARNING, "dasd_generic_probe: could not set ccw-device options " "for %s\n", dev_name(&cdev->dev)); return ret; } ret = dasd_add_sysfs_files(cdev); if (ret) { - printk(KERN_WARNING + DBF_EVENT(DBF_WARNING, "dasd_generic_probe: could not add sysfs entries " "for %s\n", dev_name(&cdev->dev)); return ret; @@ -2179,9 +2182,7 @@ int dasd_generic_probe(struct ccw_device *cdev, (dasd_autodetect && dasd_busid_known(dev_name(&cdev->dev)) != 0)) ret = ccw_device_set_online(cdev); if (ret) - printk(KERN_WARNING - "dasd_generic_probe: could not initially " - "online ccw-device %s; return code: %d\n", + pr_warning("%s: Setting the DASD online failed with rc=%d\n", dev_name(&cdev->dev), ret); return 0; } @@ -2245,10 +2246,9 @@ int dasd_generic_set_online(struct ccw_device *cdev, discipline = base_discipline; if (device->features & DASD_FEATURE_USEDIAG) { if (!dasd_diag_discipline_pointer) { - printk (KERN_WARNING - "dasd_generic couldn't online device %s " - "- discipline DIAG not available\n", - dev_name(&cdev->dev)); + pr_warning("%s Setting the DASD online failed because " + "of missing DIAG discipline\n", + dev_name(&cdev->dev)); dasd_delete_device(device); return -ENODEV; } @@ -2269,10 +2269,9 @@ int dasd_generic_set_online(struct ccw_device *cdev, /* check_device will allocate block device if necessary */ rc = discipline->check_device(device); if (rc) { - printk (KERN_WARNING - "dasd_generic couldn't online device %s " - "with discipline %s rc=%i\n", - dev_name(&cdev->dev), discipline->name, rc); + pr_warning("%s Setting the DASD online with discipline %s " + "failed with rc=%i\n", + dev_name(&cdev->dev), discipline->name, rc); module_put(discipline->owner); module_put(base_discipline->owner); dasd_delete_device(device); @@ -2281,9 +2280,8 @@ int dasd_generic_set_online(struct ccw_device *cdev, dasd_set_target_state(device, DASD_STATE_ONLINE); if (device->state <= DASD_STATE_KNOWN) { - printk (KERN_WARNING - "dasd_generic discipline not found for %s\n", - dev_name(&cdev->dev)); + pr_warning("%s Setting the DASD online failed because of a " + "missing discipline\n", dev_name(&cdev->dev)); rc = -ENODEV; dasd_set_target_state(device, DASD_STATE_NEW); if (device->block) @@ -2327,13 +2325,13 @@ int dasd_generic_set_offline(struct ccw_device *cdev) open_count = atomic_read(&device->block->open_count); if (open_count > max_count) { if (open_count > 0) - printk(KERN_WARNING "Can't offline dasd " - "device with open count = %i.\n", - open_count); + pr_warning("%s: The DASD cannot be set offline " + "with open count %i\n", + dev_name(&cdev->dev), open_count); else - printk(KERN_WARNING "%s", - "Can't offline dasd device due " - "to internal use\n"); + pr_warning("%s: The DASD cannot be set offline " + "while it is in use\n", + dev_name(&cdev->dev)); clear_bit(DASD_FLAG_OFFLINE, &device->flags); dasd_put_device(device); return -EBUSY; @@ -2406,8 +2404,10 @@ static struct dasd_ccw_req *dasd_generic_build_rdc(struct dasd_device *device, cqr = dasd_smalloc_request(magic, 1 /* RDC */, rdc_buffer_size, device); if (IS_ERR(cqr)) { - DEV_MESSAGE(KERN_WARNING, device, "%s", - "Could not allocate RDC request"); + /* internal error 13 - Allocating the RDC request failed*/ + dev_err(&device->cdev->dev, + "An error occurred in the DASD device driver, " + "reason=%s\n", "13"); return cqr; } @@ -2519,7 +2519,7 @@ static int __init dasd_init(void) return 0; failed: - MESSAGE(KERN_INFO, "%s", "initialization not performed due to errors"); + pr_info("The DASD device driver could not be initialized\n"); dasd_exit(); return rc; } diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c index 4cee4591614..27991b69205 100644 --- a/drivers/s390/block/dasd_3990_erp.c +++ b/drivers/s390/block/dasd_3990_erp.c @@ -7,6 +7,8 @@ * */ +#define KMSG_COMPONENT "dasd" + #include #include #include @@ -75,7 +77,7 @@ dasd_3990_erp_block_queue(struct dasd_ccw_req * erp, int expires) struct dasd_device *device = erp->startdev; unsigned long flags; - DEV_MESSAGE(KERN_INFO, device, + DBF_DEV_EVENT(DBF_INFO, device, "blocking request queue for %is", expires/HZ); spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); @@ -114,9 +116,9 @@ dasd_3990_erp_int_req(struct dasd_ccw_req * erp) } else { /* issue a message and wait for 'device ready' interrupt */ - DEV_MESSAGE(KERN_ERR, device, "%s", + dev_err(&device->cdev->dev, "is offline or not installed - " - "INTERVENTION REQUIRED!!"); + "INTERVENTION REQUIRED!!\n"); dasd_3990_erp_block_queue(erp, 60*HZ); } @@ -158,7 +160,7 @@ dasd_3990_erp_alternate_path(struct dasd_ccw_req * erp) if ((erp->lpm & opm) != 0x00) { - DEV_MESSAGE(KERN_DEBUG, device, + DBF_DEV_EVENT(DBF_WARNING, device, "try alternate lpm=%x (lpum=%x / opm=%x)", erp->lpm, erp->irb.esw.esw0.sublog.lpum, opm); @@ -166,10 +168,9 @@ dasd_3990_erp_alternate_path(struct dasd_ccw_req * erp) erp->status = DASD_CQR_FILLED; erp->retries = 10; } else { - DEV_MESSAGE(KERN_ERR, device, - "No alternate channel path left (lpum=%x / " - "opm=%x) -> permanent error", - erp->irb.esw.esw0.sublog.lpum, opm); + dev_err(&device->cdev->dev, + "The DASD cannot be reached on any path (lpum=%x" + "/opm=%x)\n", erp->irb.esw.esw0.sublog.lpum, opm); /* post request with permanent error */ erp->status = DASD_CQR_FAILED; @@ -204,8 +205,8 @@ dasd_3990_erp_DCTL(struct dasd_ccw_req * erp, char modifier) sizeof(struct DCTL_data), device); if (IS_ERR(dctl_cqr)) { - DEV_MESSAGE(KERN_ERR, device, "%s", - "Unable to allocate DCTL-CQR"); + dev_err(&device->cdev->dev, + "Unable to allocate DCTL-CQR\n"); erp->status = DASD_CQR_FAILED; return erp; } @@ -294,7 +295,7 @@ dasd_3990_erp_action_4(struct dasd_ccw_req * erp, char *sense) /* interrupt (this enables easier enqueing of the cqr) */ if (erp->function != dasd_3990_erp_action_4) { - DEV_MESSAGE(KERN_INFO, device, "%s", + DBF_DEV_EVENT(DBF_INFO, device, "%s", "dasd_3990_erp_action_4: first time retry"); erp->retries = 256; @@ -303,7 +304,7 @@ dasd_3990_erp_action_4(struct dasd_ccw_req * erp, char *sense) } else { if (sense && (sense[25] == 0x1D)) { /* state change pending */ - DEV_MESSAGE(KERN_INFO, device, + DBF_DEV_EVENT(DBF_INFO, device, "waiting for state change pending " "interrupt, %d retries left", erp->retries); @@ -311,15 +312,14 @@ dasd_3990_erp_action_4(struct dasd_ccw_req * erp, char *sense) dasd_3990_erp_block_queue(erp, 30*HZ); } else if (sense && (sense[25] == 0x1E)) { /* busy */ - DEV_MESSAGE(KERN_INFO, device, + DBF_DEV_EVENT(DBF_INFO, device, "busy - redriving request later, " "%d retries left", erp->retries); dasd_3990_erp_block_queue(erp, HZ); } else { - /* no state change pending - retry */ - DEV_MESSAGE (KERN_INFO, device, + DBF_DEV_EVENT(DBF_INFO, device, "redriving request immediately, " "%d retries left", erp->retries); @@ -384,6 +384,7 @@ dasd_3990_handle_env_data(struct dasd_ccw_req * erp, char *sense) struct dasd_device *device = erp->startdev; char msg_format = (sense[7] & 0xF0); char msg_no = (sense[7] & 0x0F); + char errorstring[ERRORLENGTH]; switch (msg_format) { case 0x00: /* Format 0 - Program or System Checks */ @@ -394,95 +395,97 @@ dasd_3990_handle_env_data(struct dasd_ccw_req * erp, char *sense) case 0x00: /* No Message */ break; case 0x01: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT 0 - Invalid Command"); + dev_warn(&device->cdev->dev, + "FORMAT 0 - Invalid Command\n"); break; case 0x02: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT 0 - Invalid Command " - "Sequence"); + "Sequence\n"); break; case 0x03: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT 0 - CCW Count less than " - "required"); + "required\n"); break; case 0x04: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT 0 - Invalid Parameter"); + dev_warn(&device->cdev->dev, + "FORMAT 0 - Invalid Parameter\n"); break; case 0x05: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT 0 - Diagnostic of Sepecial" - " Command Violates File Mask"); + dev_warn(&device->cdev->dev, + "FORMAT 0 - Diagnostic of Special" + " Command Violates File Mask\n"); break; case 0x07: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT 0 - Channel Returned with " - "Incorrect retry CCW"); + "Incorrect retry CCW\n"); break; case 0x08: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT 0 - Reset Notification"); + dev_warn(&device->cdev->dev, + "FORMAT 0 - Reset Notification\n"); break; case 0x09: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT 0 - Storage Path Restart"); + dev_warn(&device->cdev->dev, + "FORMAT 0 - Storage Path Restart\n"); break; case 0x0A: - DEV_MESSAGE(KERN_WARNING, device, + dev_warn(&device->cdev->dev, "FORMAT 0 - Channel requested " - "... %02x", sense[8]); + "... %02x\n", sense[8]); break; case 0x0B: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT 0 - Invalid Defective/" - "Alternate Track Pointer"); + "Alternate Track Pointer\n"); break; case 0x0C: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT 0 - DPS Installation " - "Check"); + "Check\n"); break; case 0x0E: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT 0 - Command Invalid on " - "Secondary Address"); + "Secondary Address\n"); break; case 0x0F: - DEV_MESSAGE(KERN_WARNING, device, + dev_warn(&device->cdev->dev, "FORMAT 0 - Status Not As " - "Required: reason %02x", sense[8]); + "Required: reason %02x\n", + sense[8]); break; default: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT 0 - Reseved"); + dev_warn(&device->cdev->dev, + "FORMAT 0 - Reserved\n"); } } else { switch (msg_no) { case 0x00: /* No Message */ break; case 0x01: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT 0 - Device Error Source"); + dev_warn(&device->cdev->dev, + "FORMAT 0 - Device Error " + "Source\n"); break; case 0x02: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT 0 - Reserved"); + dev_warn(&device->cdev->dev, + "FORMAT 0 - Reserved\n"); break; case 0x03: - DEV_MESSAGE(KERN_WARNING, device, + dev_warn(&device->cdev->dev, "FORMAT 0 - Device Fenced - " - "device = %02x", sense[4]); + "device = %02x\n", sense[4]); break; case 0x04: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT 0 - Data Pinned for " - "Device"); + "Device\n"); break; default: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT 0 - Reserved"); + dev_warn(&device->cdev->dev, + "FORMAT 0 - Reserved\n"); } } break; @@ -492,348 +495,352 @@ dasd_3990_handle_env_data(struct dasd_ccw_req * erp, char *sense) case 0x00: /* No Message */ break; case 0x01: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT 1 - Device Status 1 not as " - "expected"); + "expected\n"); break; case 0x03: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT 1 - Index missing"); + dev_warn(&device->cdev->dev, + "FORMAT 1 - Index missing\n"); break; case 0x04: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT 1 - Interruption cannot be reset"); + dev_warn(&device->cdev->dev, + "FORMAT 1 - Interruption cannot be " + "reset\n"); break; case 0x05: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT 1 - Device did not respond to " - "selection"); + "selection\n"); break; case 0x06: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT 1 - Device check-2 error or Set " - "Sector is not complete"); + "Sector is not complete\n"); break; case 0x07: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT 1 - Head address does not " - "compare"); + "compare\n"); break; case 0x08: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT 1 - Device status 1 not valid"); + dev_warn(&device->cdev->dev, + "FORMAT 1 - Device status 1 not valid\n"); break; case 0x09: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT 1 - Device not ready"); + dev_warn(&device->cdev->dev, + "FORMAT 1 - Device not ready\n"); break; case 0x0A: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT 1 - Track physical address did " - "not compare"); + "not compare\n"); break; case 0x0B: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT 1 - Missing device address bit"); + dev_warn(&device->cdev->dev, + "FORMAT 1 - Missing device address bit\n"); break; case 0x0C: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT 1 - Drive motor switch is off"); + dev_warn(&device->cdev->dev, + "FORMAT 1 - Drive motor switch is off\n"); break; case 0x0D: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT 1 - Seek incomplete"); + dev_warn(&device->cdev->dev, + "FORMAT 1 - Seek incomplete\n"); break; case 0x0E: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT 1 - Cylinder address did not " - "compare"); + "compare\n"); break; case 0x0F: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT 1 - Offset active cannot be " - "reset"); + "reset\n"); break; default: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT 1 - Reserved"); + dev_warn(&device->cdev->dev, + "FORMAT 1 - Reserved\n"); } break; case 0x20: /* Format 2 - 3990 Equipment Checks */ switch (msg_no) { case 0x08: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT 2 - 3990 check-2 error"); + dev_warn(&device->cdev->dev, + "FORMAT 2 - 3990 check-2 error\n"); break; case 0x0E: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT 2 - Support facility errors"); + dev_warn(&device->cdev->dev, + "FORMAT 2 - Support facility errors\n"); break; case 0x0F: - DEV_MESSAGE(KERN_WARNING, device, - "FORMAT 2 - Microcode detected error %02x", - sense[8]); + dev_warn(&device->cdev->dev, + "FORMAT 2 - Microcode detected error " + "%02x\n", + sense[8]); break; default: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT 2 - Reserved"); + dev_warn(&device->cdev->dev, + "FORMAT 2 - Reserved\n"); } break; case 0x30: /* Format 3 - 3990 Control Checks */ switch (msg_no) { case 0x0F: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT 3 - Allegiance terminated"); + dev_warn(&device->cdev->dev, + "FORMAT 3 - Allegiance terminated\n"); break; default: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT 3 - Reserved"); + dev_warn(&device->cdev->dev, + "FORMAT 3 - Reserved\n"); } break; case 0x40: /* Format 4 - Data Checks */ switch (msg_no) { case 0x00: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT 4 - Home address area error"); + dev_warn(&device->cdev->dev, + "FORMAT 4 - Home address area error\n"); break; case 0x01: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT 4 - Count area error"); + dev_warn(&device->cdev->dev, + "FORMAT 4 - Count area error\n"); break; case 0x02: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT 4 - Key area error"); + dev_warn(&device->cdev->dev, + "FORMAT 4 - Key area error\n"); break; case 0x03: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT 4 - Data area error"); + dev_warn(&device->cdev->dev, + "FORMAT 4 - Data area error\n"); break; case 0x04: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT 4 - No sync byte in home address " - "area"); + "area\n"); break; case 0x05: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT 4 - No sync byte in count address " - "area"); + "area\n"); break; case 0x06: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT 4 - No sync byte in key area"); + dev_warn(&device->cdev->dev, + "FORMAT 4 - No sync byte in key area\n"); break; case 0x07: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT 4 - No sync byte in data area"); + dev_warn(&device->cdev->dev, + "FORMAT 4 - No sync byte in data area\n"); break; case 0x08: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT 4 - Home address area error; " - "offset active"); + "offset active\n"); break; case 0x09: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT 4 - Count area error; offset " - "active"); + "active\n"); break; case 0x0A: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT 4 - Key area error; offset " - "active"); + "active\n"); break; case 0x0B: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT 4 - Data area error; " - "offset active"); + "offset active\n"); break; case 0x0C: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT 4 - No sync byte in home " - "address area; offset active"); + "address area; offset active\n"); break; case 0x0D: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT 4 - No syn byte in count " - "address area; offset active"); + "address area; offset active\n"); break; case 0x0E: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT 4 - No sync byte in key area; " - "offset active"); + "offset active\n"); break; case 0x0F: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT 4 - No syn byte in data area; " - "offset active"); + "offset active\n"); break; default: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT 4 - Reserved"); + dev_warn(&device->cdev->dev, + "FORMAT 4 - Reserved\n"); } break; case 0x50: /* Format 5 - Data Check with displacement information */ switch (msg_no) { case 0x00: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT 5 - Data Check in the " - "home address area"); + "home address area\n"); break; case 0x01: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT 5 - Data Check in the count area"); + dev_warn(&device->cdev->dev, + "FORMAT 5 - Data Check in the count " + "area\n"); break; case 0x02: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT 5 - Data Check in the key area"); + dev_warn(&device->cdev->dev, + "FORMAT 5 - Data Check in the key area\n"); break; case 0x03: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT 5 - Data Check in the data area"); + dev_warn(&device->cdev->dev, + "FORMAT 5 - Data Check in the data " + "area\n"); break; case 0x08: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT 5 - Data Check in the " - "home address area; offset active"); + "home address area; offset active\n"); break; case 0x09: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT 5 - Data Check in the count area; " - "offset active"); + "offset active\n"); break; case 0x0A: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT 5 - Data Check in the key area; " - "offset active"); + "offset active\n"); break; case 0x0B: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT 5 - Data Check in the data area; " - "offset active"); + "offset active\n"); break; default: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT 5 - Reserved"); + dev_warn(&device->cdev->dev, + "FORMAT 5 - Reserved\n"); } break; case 0x60: /* Format 6 - Usage Statistics/Overrun Errors */ switch (msg_no) { case 0x00: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT 6 - Overrun on channel A"); + dev_warn(&device->cdev->dev, + "FORMAT 6 - Overrun on channel A\n"); break; case 0x01: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT 6 - Overrun on channel B"); + dev_warn(&device->cdev->dev, + "FORMAT 6 - Overrun on channel B\n"); break; case 0x02: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT 6 - Overrun on channel C"); + dev_warn(&device->cdev->dev, + "FORMAT 6 - Overrun on channel C\n"); break; case 0x03: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT 6 - Overrun on channel D"); + dev_warn(&device->cdev->dev, + "FORMAT 6 - Overrun on channel D\n"); break; case 0x04: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT 6 - Overrun on channel E"); + dev_warn(&device->cdev->dev, + "FORMAT 6 - Overrun on channel E\n"); break; case 0x05: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT 6 - Overrun on channel F"); + dev_warn(&device->cdev->dev, + "FORMAT 6 - Overrun on channel F\n"); break; case 0x06: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT 6 - Overrun on channel G"); + dev_warn(&device->cdev->dev, + "FORMAT 6 - Overrun on channel G\n"); break; case 0x07: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT 6 - Overrun on channel H"); + dev_warn(&device->cdev->dev, + "FORMAT 6 - Overrun on channel H\n"); break; default: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT 6 - Reserved"); + dev_warn(&device->cdev->dev, + "FORMAT 6 - Reserved\n"); } break; case 0x70: /* Format 7 - Device Connection Control Checks */ switch (msg_no) { case 0x00: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT 7 - RCC initiated by a connection " - "check alert"); + "check alert\n"); break; case 0x01: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT 7 - RCC 1 sequence not " - "successful"); + "successful\n"); break; case 0x02: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT 7 - RCC 1 and RCC 2 sequences not " - "successful"); + "successful\n"); break; case 0x03: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT 7 - Invalid tag-in during " - "selection sequence"); + "selection sequence\n"); break; case 0x04: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT 7 - extra RCC required"); + dev_warn(&device->cdev->dev, + "FORMAT 7 - extra RCC required\n"); break; case 0x05: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT 7 - Invalid DCC selection " - "response or timeout"); + "response or timeout\n"); break; case 0x06: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT 7 - Missing end operation; device " - "transfer complete"); + "transfer complete\n"); break; case 0x07: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT 7 - Missing end operation; device " - "transfer incomplete"); + "transfer incomplete\n"); break; case 0x08: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT 7 - Invalid tag-in for an " - "immediate command sequence"); + "immediate command sequence\n"); break; case 0x09: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT 7 - Invalid tag-in for an " - "extended command sequence"); + "extended command sequence\n"); break; case 0x0A: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT 7 - 3990 microcode time out when " - "stopping selection"); + "stopping selection\n"); break; case 0x0B: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT 7 - No response to selection " - "after a poll interruption"); + "after a poll interruption\n"); break; case 0x0C: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT 7 - Permanent path error (DASD " - "controller not available)"); + "controller not available)\n"); break; case 0x0D: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT 7 - DASD controller not available" - " on disconnected command chain"); + " on disconnected command chain\n"); break; default: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT 7 - Reserved"); + dev_warn(&device->cdev->dev, + "FORMAT 7 - Reserved\n"); } break; @@ -841,52 +848,52 @@ dasd_3990_handle_env_data(struct dasd_ccw_req * erp, char *sense) switch (msg_no) { case 0x00: /* No Message */ case 0x01: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT 8 - Error correction code " - "hardware fault"); + "hardware fault\n"); break; case 0x03: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT 8 - Unexpected end operation " - "response code"); + "response code\n"); break; case 0x04: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT 8 - End operation with transfer " - "count not zero"); + "count not zero\n"); break; case 0x05: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT 8 - End operation with transfer " - "count zero"); + "count zero\n"); break; case 0x06: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT 8 - DPS checks after a system " - "reset or selective reset"); + "reset or selective reset\n"); break; case 0x07: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT 8 - DPS cannot be filled"); + dev_warn(&device->cdev->dev, + "FORMAT 8 - DPS cannot be filled\n"); break; case 0x08: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT 8 - Short busy time-out during " - "device selection"); + "device selection\n"); break; case 0x09: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT 8 - DASD controller failed to " - "set or reset the long busy latch"); + "set or reset the long busy latch\n"); break; case 0x0A: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT 8 - No interruption from device " - "during a command chain"); + "during a command chain\n"); break; default: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT 8 - Reserved"); + dev_warn(&device->cdev->dev, + "FORMAT 8 - Reserved\n"); } break; @@ -895,97 +902,100 @@ dasd_3990_handle_env_data(struct dasd_ccw_req * erp, char *sense) case 0x00: break; /* No Message */ case 0x06: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT 9 - Device check-2 error"); + dev_warn(&device->cdev->dev, + "FORMAT 9 - Device check-2 error\n"); break; case 0x07: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT 9 - Head address did not compare"); + dev_warn(&device->cdev->dev, + "FORMAT 9 - Head address did not " + "compare\n"); break; case 0x0A: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT 9 - Track physical address did " - "not compare while oriented"); + "not compare while oriented\n"); break; case 0x0E: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT 9 - Cylinder address did not " - "compare"); + "compare\n"); break; default: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT 9 - Reserved"); + dev_warn(&device->cdev->dev, + "FORMAT 9 - Reserved\n"); } break; case 0xF0: /* Format F - Cache Storage Checks */ switch (msg_no) { case 0x00: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT F - Operation Terminated"); + dev_warn(&device->cdev->dev, + "FORMAT F - Operation Terminated\n"); break; case 0x01: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT F - Subsystem Processing Error"); + dev_warn(&device->cdev->dev, + "FORMAT F - Subsystem Processing Error\n"); break; case 0x02: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT F - Cache or nonvolatile storage " - "equipment failure"); + "equipment failure\n"); break; case 0x04: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT F - Caching terminated"); + dev_warn(&device->cdev->dev, + "FORMAT F - Caching terminated\n"); break; case 0x06: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT F - Cache fast write access not " - "authorized"); + "authorized\n"); break; case 0x07: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT F - Track format incorrect"); + dev_warn(&device->cdev->dev, + "FORMAT F - Track format incorrect\n"); break; case 0x09: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT F - Caching reinitiated"); + dev_warn(&device->cdev->dev, + "FORMAT F - Caching reinitiated\n"); break; case 0x0A: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT F - Nonvolatile storage " - "terminated"); + "terminated\n"); break; case 0x0B: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT F - Volume is suspended duplex"); + dev_warn(&device->cdev->dev, + "FORMAT F - Volume is suspended duplex\n"); /* call extended error reporting (EER) */ dasd_eer_write(device, erp->refers, DASD_EER_PPRCSUSPEND); break; case 0x0C: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT F - Subsystem status connot be " - "determined"); + dev_warn(&device->cdev->dev, + "FORMAT F - Subsystem status cannot be " + "determined\n"); break; case 0x0D: - DEV_MESSAGE(KERN_WARNING, device, "%s", + dev_warn(&device->cdev->dev, "FORMAT F - Caching status reset to " - "default"); + "default\n"); break; case 0x0E: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT F - DASD Fast Write inhibited"); + dev_warn(&device->cdev->dev, + "FORMAT F - DASD Fast Write inhibited\n"); break; default: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "FORMAT D - Reserved"); + dev_warn(&device->cdev->dev, + "FORMAT D - Reserved\n"); } break; - default: /* unknown message format - should not happen */ - DEV_MESSAGE (KERN_WARNING, device, - "unknown message format %02x", - msg_format); + default: /* unknown message format - should not happen + internal error 03 - unknown message format */ + snprintf(errorstring, ERRORLENGTH, "03 %x02", msg_format); + dev_err(&device->cdev->dev, + "An error occurred in the DASD device driver, " + "reason=%s\n", errorstring); break; } /* end switch message format */ @@ -1015,7 +1025,7 @@ dasd_3990_erp_com_rej(struct dasd_ccw_req * erp, char *sense) /* env data present (ACTION 10 - retry should work) */ if (sense[2] & SNS2_ENV_DATA_PRESENT) { - DEV_MESSAGE(KERN_DEBUG, device, "%s", + DBF_DEV_EVENT(DBF_WARNING, device, "%s", "Command Reject - environmental data present"); dasd_3990_handle_env_data(erp, sense); @@ -1023,9 +1033,10 @@ dasd_3990_erp_com_rej(struct dasd_ccw_req * erp, char *sense) erp->retries = 5; } else { - /* fatal error - set status to FAILED */ - DEV_MESSAGE(KERN_ERR, device, "%s", - "Command Reject - Fatal error"); + /* fatal error - set status to FAILED + internal error 09 - Command Reject */ + dev_err(&device->cdev->dev, "An error occurred in the DASD " + "device driver, reason=%s\n", "09"); erp = dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED); } @@ -1061,7 +1072,7 @@ dasd_3990_erp_bus_out(struct dasd_ccw_req * erp) } else { /* issue a message and wait for 'device ready' interrupt */ - DEV_MESSAGE(KERN_DEBUG, device, "%s", + DBF_DEV_EVENT(DBF_WARNING, device, "%s", "bus out parity error or BOPC requested by " "channel"); @@ -1093,21 +1104,19 @@ dasd_3990_erp_equip_check(struct dasd_ccw_req * erp, char *sense) erp->function = dasd_3990_erp_equip_check; if (sense[1] & SNS1_WRITE_INHIBITED) { + dev_info(&device->cdev->dev, + "Write inhibited path encountered\n"); - DEV_MESSAGE(KERN_DEBUG, device, "%s", - "Write inhibited path encountered"); - - /* vary path offline */ - DEV_MESSAGE(KERN_ERR, device, "%s", - "Path should be varied off-line. " - "This is not implemented yet \n - please report " - "to linux390@de.ibm.com"); + /* vary path offline + internal error 04 - Path should be varied off-line.*/ + dev_err(&device->cdev->dev, "An error occurred in the DASD " + "device driver, reason=%s\n", "04"); erp = dasd_3990_erp_action_1(erp); } else if (sense[2] & SNS2_ENV_DATA_PRESENT) { - DEV_MESSAGE(KERN_DEBUG, device, "%s", + DBF_DEV_EVENT(DBF_WARNING, device, "%s", "Equipment Check - " "environmental data present"); dasd_3990_handle_env_data(erp, sense); @@ -1116,7 +1125,7 @@ dasd_3990_erp_equip_check(struct dasd_ccw_req * erp, char *sense) } else if (sense[1] & SNS1_PERM_ERR) { - DEV_MESSAGE(KERN_DEBUG, device, "%s", + DBF_DEV_EVENT(DBF_WARNING, device, "%s", "Equipment Check - retry exhausted or " "undesirable"); @@ -1125,7 +1134,7 @@ dasd_3990_erp_equip_check(struct dasd_ccw_req * erp, char *sense) } else { /* all other equipment checks - Action 5 */ /* rest is done when retries == 0 */ - DEV_MESSAGE(KERN_DEBUG, device, "%s", + DBF_DEV_EVENT(DBF_WARNING, device, "%s", "Equipment check or processing error"); erp = dasd_3990_erp_action_5(erp); @@ -1156,9 +1165,9 @@ dasd_3990_erp_data_check(struct dasd_ccw_req * erp, char *sense) if (sense[2] & SNS2_CORRECTABLE) { /* correctable data check */ /* issue message that the data has been corrected */ - DEV_MESSAGE(KERN_EMERG, device, "%s", + dev_emerg(&device->cdev->dev, "Data recovered during retry with PCI " - "fetch mode active"); + "fetch mode active\n"); /* not possible to handle this situation in Linux */ panic("No way to inform application about the possibly " @@ -1166,7 +1175,7 @@ dasd_3990_erp_data_check(struct dasd_ccw_req * erp, char *sense) } else if (sense[2] & SNS2_ENV_DATA_PRESENT) { - DEV_MESSAGE(KERN_DEBUG, device, "%s", + DBF_DEV_EVENT(DBF_WARNING, device, "%s", "Uncorrectable data check recovered secondary " "addr of duplex pair"); @@ -1174,7 +1183,7 @@ dasd_3990_erp_data_check(struct dasd_ccw_req * erp, char *sense) } else if (sense[1] & SNS1_PERM_ERR) { - DEV_MESSAGE(KERN_DEBUG, device, "%s", + DBF_DEV_EVENT(DBF_WARNING, device, "%s", "Uncorrectable data check with internal " "retry exhausted"); @@ -1182,7 +1191,7 @@ dasd_3990_erp_data_check(struct dasd_ccw_req * erp, char *sense) } else { /* all other data checks */ - DEV_MESSAGE(KERN_DEBUG, device, "%s", + DBF_DEV_EVENT(DBF_WARNING, device, "%s", "Uncorrectable data check with retry count " "exhausted..."); @@ -1212,7 +1221,7 @@ dasd_3990_erp_overrun(struct dasd_ccw_req * erp, char *sense) erp->function = dasd_3990_erp_overrun; - DEV_MESSAGE(KERN_DEBUG, device, "%s", + DBF_DEV_EVENT(DBF_WARNING, device, "%s", "Overrun - service overrun or overrun" " error requested by channel"); @@ -1243,7 +1252,7 @@ dasd_3990_erp_inv_format(struct dasd_ccw_req * erp, char *sense) if (sense[2] & SNS2_ENV_DATA_PRESENT) { - DEV_MESSAGE(KERN_DEBUG, device, "%s", + DBF_DEV_EVENT(DBF_WARNING, device, "%s", "Track format error when destaging or " "staging data"); @@ -1252,8 +1261,10 @@ dasd_3990_erp_inv_format(struct dasd_ccw_req * erp, char *sense) erp = dasd_3990_erp_action_4(erp, sense); } else { - DEV_MESSAGE(KERN_ERR, device, "%s", - "Invalid Track Format - Fatal error"); + /* internal error 06 - The track format is not valid*/ + dev_err(&device->cdev->dev, + "An error occurred in the DASD device driver, " + "reason=%s\n", "06"); erp = dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED); } @@ -1279,8 +1290,8 @@ dasd_3990_erp_EOC(struct dasd_ccw_req * default_erp, char *sense) struct dasd_device *device = default_erp->startdev; - DEV_MESSAGE(KERN_ERR, device, "%s", - "End-of-Cylinder - must never happen"); + dev_err(&device->cdev->dev, + "The cylinder data for accessing the DASD is inconsistent\n"); /* implement action 7 - BUG */ return dasd_3990_erp_cleanup(default_erp, DASD_CQR_FAILED); @@ -1306,7 +1317,7 @@ dasd_3990_erp_env_data(struct dasd_ccw_req * erp, char *sense) erp->function = dasd_3990_erp_env_data; - DEV_MESSAGE(KERN_DEBUG, device, "%s", "Environmental data present"); + DBF_DEV_EVENT(DBF_WARNING, device, "%s", "Environmental data present"); dasd_3990_handle_env_data(erp, sense); @@ -1339,8 +1350,8 @@ dasd_3990_erp_no_rec(struct dasd_ccw_req * default_erp, char *sense) struct dasd_device *device = default_erp->startdev; - DEV_MESSAGE(KERN_ERR, device, "%s", - "No Record Found - Fatal error "); + dev_err(&device->cdev->dev, + "The specified record was not found\n"); return dasd_3990_erp_cleanup(default_erp, DASD_CQR_FAILED); @@ -1365,7 +1376,8 @@ dasd_3990_erp_file_prot(struct dasd_ccw_req * erp) struct dasd_device *device = erp->startdev; - DEV_MESSAGE(KERN_ERR, device, "%s", "File Protected"); + dev_err(&device->cdev->dev, "Accessing the DASD failed because of " + "a hardware error\n"); return dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED); @@ -1394,7 +1406,7 @@ static struct dasd_ccw_req *dasd_3990_erp_inspect_alias( if (cqr->block && (cqr->block->base != cqr->startdev)) { if (cqr->startdev->features & DASD_FEATURE_ERPLOG) { - DEV_MESSAGE(KERN_ERR, cqr->startdev, + DBF_DEV_EVENT(DBF_ERR, cqr->startdev, "ERP on alias device for request %p," " recover on base device %s", cqr, dev_name(&cqr->block->base->cdev->dev)); @@ -1511,7 +1523,7 @@ dasd_3990_erp_action_10_32(struct dasd_ccw_req * erp, char *sense) erp->retries = 256; erp->function = dasd_3990_erp_action_10_32; - DEV_MESSAGE(KERN_DEBUG, device, "%s", "Perform logging requested"); + DBF_DEV_EVENT(DBF_WARNING, device, "%s", "Perform logging requested"); return erp; @@ -1549,7 +1561,7 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense) char *LO_data; /* LO_eckd_data_t */ struct ccw1 *ccw, *oldccw; - DEV_MESSAGE(KERN_DEBUG, device, "%s", + DBF_DEV_EVENT(DBF_WARNING, device, "%s", "Write not finished because of unexpected condition"); default_erp->function = dasd_3990_erp_action_1B_32; @@ -1570,8 +1582,7 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense) /* for imprecise ending just do default erp */ if (sense[1] & 0x01) { - - DEV_MESSAGE(KERN_DEBUG, device, "%s", + DBF_DEV_EVENT(DBF_WARNING, device, "%s", "Imprecise ending is set - just retry"); return default_erp; @@ -1582,8 +1593,7 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense) cpa = default_erp->refers->irb.scsw.cmd.cpa; if (cpa == 0) { - - DEV_MESSAGE(KERN_DEBUG, device, "%s", + DBF_DEV_EVENT(DBF_WARNING, device, "%s", "Unable to determine address of the CCW " "to be restarted"); @@ -1597,7 +1607,9 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense) sizeof(struct LO_eckd_data), device); if (IS_ERR(erp)) { - DEV_MESSAGE(KERN_ERR, device, "%s", "Unable to allocate ERP"); + /* internal error 01 - Unable to allocate ERP */ + dev_err(&device->cdev->dev, "An error occurred in the DASD " + "device driver, reason=%s\n", "01"); return dasd_3990_erp_cleanup(default_erp, DASD_CQR_FAILED); } @@ -1615,10 +1627,7 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense) LO_data = erp->data + sizeof(struct DE_eckd_data); if ((sense[3] == 0x01) && (LO_data[1] & 0x01)) { - - DEV_MESSAGE(KERN_ERR, device, "%s", - "BUG - this should not happen"); - + /* should not */ return dasd_3990_erp_cleanup(default_erp, DASD_CQR_FAILED); } @@ -1708,7 +1717,7 @@ dasd_3990_update_1B(struct dasd_ccw_req * previous_erp, char *sense) char *LO_data; /* struct LO_eckd_data */ struct ccw1 *ccw; - DEV_MESSAGE(KERN_DEBUG, device, "%s", + DBF_DEV_EVENT(DBF_WARNING, device, "%s", "Write not finished because of unexpected condition" " - follow on"); @@ -1728,8 +1737,7 @@ dasd_3990_update_1B(struct dasd_ccw_req * previous_erp, char *sense) /* for imprecise ending just do default erp */ if (sense[1] & 0x01) { - - DEV_MESSAGE(KERN_DEBUG, device, "%s", + DBF_DEV_EVENT(DBF_WARNING, device, "%s", "Imprecise ending is set - just retry"); previous_erp->status = DASD_CQR_FILLED; @@ -1742,10 +1750,10 @@ dasd_3990_update_1B(struct dasd_ccw_req * previous_erp, char *sense) cpa = previous_erp->irb.scsw.cmd.cpa; if (cpa == 0) { - - DEV_MESSAGE(KERN_DEBUG, device, "%s", - "Unable to determine address of the CCW " - "to be restarted"); + /* internal error 02 - + Unable to determine address of the CCW to be restarted */ + dev_err(&device->cdev->dev, "An error occurred in the DASD " + "device driver, reason=%s\n", "02"); previous_erp->status = DASD_CQR_FAILED; @@ -1758,10 +1766,7 @@ dasd_3990_update_1B(struct dasd_ccw_req * previous_erp, char *sense) LO_data = erp->data + sizeof(struct DE_eckd_data); if ((sense[3] == 0x01) && (LO_data[1] & 0x01)) { - - DEV_MESSAGE(KERN_ERR, device, "%s", - "BUG - this should not happen"); - + /* should not happen */ previous_erp->status = DASD_CQR_FAILED; return previous_erp; @@ -1949,14 +1954,13 @@ dasd_3990_erp_compound_config(struct dasd_ccw_req * erp, char *sense) if ((sense[25] & DASD_SENSE_BIT_1) && (sense[26] & DASD_SENSE_BIT_2)) { - /* set to suspended duplex state then restart */ + /* set to suspended duplex state then restart + internal error 05 - Set device to suspended duplex state + should be done */ struct dasd_device *device = erp->startdev; - - DEV_MESSAGE(KERN_ERR, device, "%s", - "Set device to suspended duplex state should be " - "done!\n" - "This is not implemented yet (for compound ERP)" - " - please report to linux390@de.ibm.com"); + dev_err(&device->cdev->dev, + "An error occurred in the DASD device driver, " + "reason=%s\n", "05"); } @@ -2026,15 +2030,14 @@ dasd_3990_erp_handle_sim(struct dasd_device *device, char *sense) { /* print message according to log or message to operator mode */ if ((sense[24] & DASD_SIM_MSG_TO_OP) || (sense[1] & 0x10)) { - /* print SIM SRC from RefCode */ - DEV_MESSAGE(KERN_ERR, device, "SIM - SRC: " - "%02x%02x%02x%02x", sense[22], + dev_err(&device->cdev->dev, "SIM - SRC: " + "%02x%02x%02x%02x\n", sense[22], sense[23], sense[11], sense[12]); } else if (sense[24] & DASD_SIM_LOG) { /* print SIM SRC Refcode */ - DEV_MESSAGE(KERN_WARNING, device, "SIM - SRC: " - "%02x%02x%02x%02x", sense[22], + dev_warn(&device->cdev->dev, "log SIM - SRC: " + "%02x%02x%02x%02x\n", sense[22], sense[23], sense[11], sense[12]); } } @@ -2077,14 +2080,14 @@ dasd_3990_erp_inspect_32(struct dasd_ccw_req * erp, char *sense) switch (sense[25]) { case 0x00: /* success - use default ERP for retries */ - DEV_MESSAGE(KERN_DEBUG, device, "%s", + DBF_DEV_EVENT(DBF_DEBUG, device, "%s", "ERP called for successful request" " - just retry"); break; case 0x01: /* fatal error */ - DEV_MESSAGE(KERN_ERR, device, "%s", - "Retry not recommended - Fatal error"); + dev_err(&device->cdev->dev, + "ERP failed for the DASD\n"); erp = dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED); break; @@ -2094,13 +2097,10 @@ dasd_3990_erp_inspect_32(struct dasd_ccw_req * erp, char *sense) erp = dasd_3990_erp_int_req(erp); break; - case 0x0F: /* length mismatch during update write command */ - DEV_MESSAGE(KERN_ERR, device, "%s", - "update write command error - should not " - "happen;\n" - "Please send this message together with " - "the above sense data to linux390@de." - "ibm.com"); + case 0x0F: /* length mismatch during update write command + internal error 08 - update write command error*/ + dev_err(&device->cdev->dev, "An error occurred in the " + "DASD device driver, reason=%s\n", "08"); erp = dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED); break; @@ -2109,13 +2109,12 @@ dasd_3990_erp_inspect_32(struct dasd_ccw_req * erp, char *sense) erp = dasd_3990_erp_action_10_32(erp, sense); break; - case 0x15: /* next track outside defined extend */ - DEV_MESSAGE(KERN_ERR, device, "%s", - "next track outside defined extend - " - "should not happen;\n" - "Please send this message together with " - "the above sense data to linux390@de." - "ibm.com"); + case 0x15: /* next track outside defined extend + internal error 07 - The next track is not + within the defined storage extent */ + dev_err(&device->cdev->dev, + "An error occurred in the DASD device driver, " + "reason=%s\n", "07"); erp = dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED); break; @@ -2126,9 +2125,9 @@ dasd_3990_erp_inspect_32(struct dasd_ccw_req * erp, char *sense) break; case 0x1C: /* invalid data */ - DEV_MESSAGE(KERN_EMERG, device, "%s", + dev_emerg(&device->cdev->dev, "Data recovered during retry with PCI " - "fetch mode active"); + "fetch mode active\n"); /* not possible to handle this situation in Linux */ panic @@ -2137,7 +2136,7 @@ dasd_3990_erp_inspect_32(struct dasd_ccw_req * erp, char *sense) break; case 0x1D: /* state-change pending */ - DEV_MESSAGE(KERN_DEBUG, device, "%s", + DBF_DEV_EVENT(DBF_WARNING, device, "%s", "A State change pending condition exists " "for the subsystem or device"); @@ -2145,7 +2144,7 @@ dasd_3990_erp_inspect_32(struct dasd_ccw_req * erp, char *sense) break; case 0x1E: /* busy */ - DEV_MESSAGE(KERN_DEBUG, device, "%s", + DBF_DEV_EVENT(DBF_WARNING, device, "%s", "Busy condition exists " "for the subsystem or device"); erp = dasd_3990_erp_action_4(erp, sense); @@ -2187,7 +2186,7 @@ dasd_3990_erp_control_check(struct dasd_ccw_req *erp) if (scsw_cstat(&erp->refers->irb.scsw) & (SCHN_STAT_INTF_CTRL_CHK | SCHN_STAT_CHN_CTRL_CHK)) { - DEV_MESSAGE(KERN_DEBUG, device, "%s", + DBF_DEV_EVENT(DBF_WARNING, device, "%s", "channel or interface control check"); erp = dasd_3990_erp_action_4(erp, NULL); } @@ -2282,12 +2281,12 @@ static struct dasd_ccw_req *dasd_3990_erp_add_erp(struct dasd_ccw_req *cqr) cplength, datasize, device); if (IS_ERR(erp)) { if (cqr->retries <= 0) { - DEV_MESSAGE(KERN_ERR, device, "%s", + DBF_DEV_EVENT(DBF_ERR, device, "%s", "Unable to allocate ERP request"); cqr->status = DASD_CQR_FAILED; cqr->stopclk = get_clock (); } else { - DEV_MESSAGE (KERN_ERR, device, + DBF_DEV_EVENT(DBF_ERR, device, "Unable to allocate ERP request " "(%i retries left)", cqr->retries); @@ -2516,7 +2515,7 @@ dasd_3990_erp_further_erp(struct dasd_ccw_req *erp) break; } default: - DEV_MESSAGE(KERN_DEBUG, device, + DBF_DEV_EVENT(DBF_WARNING, device, "invalid subcommand modifier 0x%x " "for Diagnostic Control Command", sense[25]); @@ -2533,11 +2532,12 @@ dasd_3990_erp_further_erp(struct dasd_ccw_req *erp) erp = dasd_3990_erp_compound(erp, sense); } else { - /* No retry left and no additional special handling */ - /*necessary */ - DEV_MESSAGE(KERN_ERR, device, - "no retries left for erp %p - " - "set status to FAILED", erp); + /* + * No retry left and no additional special handling + * necessary + */ + dev_err(&device->cdev->dev, + "ERP %p has run out of retries and failed\n", erp); erp->status = DASD_CQR_FAILED; } @@ -2612,7 +2612,7 @@ dasd_3990_erp_handle_match_erp(struct dasd_ccw_req *erp_head, } else { /* simple retry */ - DEV_MESSAGE(KERN_DEBUG, device, + DBF_DEV_EVENT(DBF_DEBUG, device, "%i retries left for erp %p", erp->retries, erp); @@ -2656,13 +2656,13 @@ dasd_3990_erp_action(struct dasd_ccw_req * cqr) if (device->features & DASD_FEATURE_ERPLOG) { /* print current erp_chain */ - DEV_MESSAGE(KERN_ERR, device, "%s", - "ERP chain at BEGINNING of ERP-ACTION"); + dev_err(&device->cdev->dev, + "ERP chain at BEGINNING of ERP-ACTION\n"); for (temp_erp = cqr; temp_erp != NULL; temp_erp = temp_erp->refers) { - DEV_MESSAGE(KERN_ERR, device, - " erp %p (%02x) refers to %p", + dev_err(&device->cdev->dev, + "ERP %p (%02x) refers to %p\n", temp_erp, temp_erp->status, temp_erp->refers); } @@ -2673,7 +2673,7 @@ dasd_3990_erp_action(struct dasd_ccw_req * cqr) (scsw_dstat(&cqr->irb.scsw) == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))) { - DEV_MESSAGE(KERN_DEBUG, device, + DBF_DEV_EVENT(DBF_DEBUG, device, "ERP called for successful request %p" " - NO ERP necessary", cqr); @@ -2695,13 +2695,13 @@ dasd_3990_erp_action(struct dasd_ccw_req * cqr) if (device->features & DASD_FEATURE_ERPLOG) { /* print current erp_chain */ - DEV_MESSAGE(KERN_ERR, device, "%s", - "ERP chain at END of ERP-ACTION"); + dev_err(&device->cdev->dev, + "ERP chain at END of ERP-ACTION\n"); for (temp_erp = erp; temp_erp != NULL; temp_erp = temp_erp->refers) { - DEV_MESSAGE(KERN_ERR, device, - " erp %p (%02x) refers to %p", + dev_err(&device->cdev->dev, + "ERP %p (%02x) refers to %p\n", temp_erp, temp_erp->status, temp_erp->refers); } @@ -2714,6 +2714,8 @@ dasd_3990_erp_action(struct dasd_ccw_req * cqr) list_add_tail(&erp->blocklist, &cqr->blocklist); } + + return erp; } /* end dasd_3990_erp_action */ diff --git a/drivers/s390/block/dasd_alias.c b/drivers/s390/block/dasd_alias.c index 219bee7bd77..5b7bbc87593 100644 --- a/drivers/s390/block/dasd_alias.c +++ b/drivers/s390/block/dasd_alias.c @@ -5,6 +5,8 @@ * Author(s): Stefan Weinhuber */ +#define KMSG_COMPONENT "dasd" + #include #include #include "dasd_int.h" @@ -503,7 +505,7 @@ static void lcu_update_work(struct work_struct *work) */ spin_lock_irqsave(&lcu->lock, flags); if (rc || (lcu->flags & NEED_UAC_UPDATE)) { - DEV_MESSAGE(KERN_WARNING, device, "could not update" + DBF_DEV_EVENT(DBF_WARNING, device, "could not update" " alias data in lcu (rc = %d), retry later", rc); schedule_delayed_work(&lcu->ruac_data.dwork, 30*HZ); } else { @@ -875,7 +877,7 @@ void dasd_alias_handle_summary_unit_check(struct dasd_device *device, lcu = private->lcu; if (!lcu) { - DEV_MESSAGE(KERN_WARNING, device, "%s", + DBF_DEV_EVENT(DBF_WARNING, device, "%s", "device not ready to handle summary" " unit check (no lcu structure)"); return; @@ -888,7 +890,7 @@ void dasd_alias_handle_summary_unit_check(struct dasd_device *device, * the next interrupt on a different device */ if (list_empty(&device->alias_list)) { - DEV_MESSAGE(KERN_WARNING, device, "%s", + DBF_DEV_EVENT(DBF_WARNING, device, "%s", "device is in offline processing," " don't do summary unit check handling"); spin_unlock(&lcu->lock); @@ -896,7 +898,7 @@ void dasd_alias_handle_summary_unit_check(struct dasd_device *device, } if (lcu->suc_data.device) { /* already scheduled or running */ - DEV_MESSAGE(KERN_WARNING, device, "%s", + DBF_DEV_EVENT(DBF_WARNING, device, "%s", "previous instance of summary unit check worker" " still pending"); spin_unlock(&lcu->lock); diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index da231a787ce..e77666c8e6c 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c @@ -13,6 +13,8 @@ * */ +#define KMSG_COMPONENT "dasd" + #include #include #include @@ -127,6 +129,7 @@ __setup ("dasd=", dasd_call_setup); * Read a device busid/devno from a string. */ static int + dasd_busid(char **str, int *id0, int *id1, int *devno) { int val, old_style; @@ -134,8 +137,7 @@ dasd_busid(char **str, int *id0, int *id1, int *devno) /* Interpret ipldev busid */ if (strncmp(DASD_IPLDEV, *str, strlen(DASD_IPLDEV)) == 0) { if (ipl_info.type != IPL_TYPE_CCW) { - MESSAGE(KERN_ERR, "%s", "ipl device is not a ccw " - "device"); + pr_err("The IPL device is not a CCW device\n"); return -EINVAL; } *id0 = 0; @@ -211,9 +213,8 @@ dasd_feature_list(char *str, char **endp) else if (len == 8 && !strncmp(str, "failfast", 8)) features |= DASD_FEATURE_FAILFAST; else { - MESSAGE(KERN_WARNING, - "unsupported feature: %*s, " - "ignoring setting", len, str); + pr_warning("%*s is not a supported device option\n", + len, str); rc = -EINVAL; } str += len; @@ -222,8 +223,8 @@ dasd_feature_list(char *str, char **endp) str++; } if (*str != ')') { - MESSAGE(KERN_WARNING, "%s", - "missing ')' in dasd parameter string\n"); + pr_warning("A closing parenthesis ')' is missing in the " + "dasd= parameter\n"); rc = -EINVAL; } else str++; @@ -255,28 +256,27 @@ dasd_parse_keyword( char *parsestring ) { } if (strncmp("autodetect", parsestring, length) == 0) { dasd_autodetect = 1; - MESSAGE (KERN_INFO, "%s", - "turning to autodetection mode"); + pr_info("The autodetection mode has been activated\n"); return residual_str; } if (strncmp("probeonly", parsestring, length) == 0) { dasd_probeonly = 1; - MESSAGE(KERN_INFO, "%s", - "turning to probeonly mode"); + pr_info("The probeonly mode has been activated\n"); return residual_str; } if (strncmp("nopav", parsestring, length) == 0) { if (MACHINE_IS_VM) - MESSAGE(KERN_INFO, "%s", "'nopav' not supported on VM"); + pr_info("'nopav' is not supported on z/VM\n"); else { dasd_nopav = 1; - MESSAGE(KERN_INFO, "%s", "disable PAV mode"); + pr_info("PAV support has be deactivated\n"); } return residual_str; } if (strncmp("nofcx", parsestring, length) == 0) { dasd_nofcx = 1; - MESSAGE(KERN_INFO, "%s", "disable High Performance Ficon"); + pr_info("High Performance FICON support has been " + "deactivated\n"); return residual_str; } if (strncmp("fixedbuffers", parsestring, length) == 0) { @@ -287,10 +287,10 @@ dasd_parse_keyword( char *parsestring ) { PAGE_SIZE, SLAB_CACHE_DMA, NULL); if (!dasd_page_cache) - MESSAGE(KERN_WARNING, "%s", "Failed to create slab, " + DBF_EVENT(DBF_WARNING, "%s", "Failed to create slab, " "fixed buffer mode disabled."); else - MESSAGE (KERN_INFO, "%s", + DBF_EVENT(DBF_INFO, "%s", "turning on fixed buffer mode"); return residual_str; } @@ -328,7 +328,7 @@ dasd_parse_range( char *parsestring ) { (from_id0 != to_id0 || from_id1 != to_id1 || from > to)) rc = -EINVAL; if (rc) { - MESSAGE(KERN_ERR, "Invalid device range %s", parsestring); + pr_err("%s is not a valid device range\n", parsestring); return ERR_PTR(rc); } features = dasd_feature_list(str, &str); @@ -347,8 +347,8 @@ dasd_parse_range( char *parsestring ) { return str + 1; if (*str == '\0') return str; - MESSAGE(KERN_WARNING, - "junk at end of dasd parameter string: %s\n", str); + pr_warning("The dasd= parameter value %s has an invalid ending\n", + str); return ERR_PTR(-EINVAL); } diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index ef2a5695205..b9a7f773344 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c @@ -8,6 +8,8 @@ * */ +#define KMSG_COMPONENT "dasd" + #include #include #include @@ -144,8 +146,8 @@ dasd_diag_erp(struct dasd_device *device) mdsk_term_io(device); rc = mdsk_init_io(device, device->block->bp_block, 0, NULL); if (rc) - DEV_MESSAGE(KERN_WARNING, device, "DIAG ERP unsuccessful, " - "rc=%d", rc); + dev_warn(&device->cdev->dev, "DIAG ERP failed with " + "rc=%d\n", rc); } /* Start a given request at the device. Return zero on success, non-zero @@ -160,7 +162,7 @@ dasd_start_diag(struct dasd_ccw_req * cqr) device = cqr->startdev; if (cqr->retries < 0) { - DEV_MESSAGE(KERN_WARNING, device, "DIAG start_IO: request %p " + DBF_DEV_EVENT(DBF_ERR, device, "DIAG start_IO: request %p " "- no retry left)", cqr); cqr->status = DASD_CQR_ERROR; return -EIO; @@ -195,7 +197,7 @@ dasd_start_diag(struct dasd_ccw_req * cqr) break; default: /* Error condition */ cqr->status = DASD_CQR_QUEUED; - DEV_MESSAGE(KERN_WARNING, device, "dia250 returned rc=%d", rc); + DBF_DEV_EVENT(DBF_WARNING, device, "dia250 returned rc=%d", rc); dasd_diag_erp(device); rc = -EIO; break; @@ -243,13 +245,14 @@ dasd_ext_handler(__u16 code) return; } if (!ip) { /* no intparm: unsolicited interrupt */ - MESSAGE(KERN_DEBUG, "%s", "caught unsolicited interrupt"); + DBF_EVENT(DBF_NOTICE, "%s", "caught unsolicited " + "interrupt"); return; } cqr = (struct dasd_ccw_req *) ip; device = (struct dasd_device *) cqr->startdev; if (strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) { - DEV_MESSAGE(KERN_WARNING, device, + DBF_DEV_EVENT(DBF_WARNING, device, " magic number of dasd_ccw_req 0x%08X doesn't" " match discipline 0x%08X", cqr->magic, *(int *) (&device->discipline->name)); @@ -281,15 +284,11 @@ dasd_ext_handler(__u16 code) rc = dasd_start_diag(next); if (rc == 0) expires = next->expires; - else if (rc != -EACCES) - DEV_MESSAGE(KERN_WARNING, device, "%s", - "Interrupt fastpath " - "failed!"); } } } else { cqr->status = DASD_CQR_QUEUED; - DEV_MESSAGE(KERN_WARNING, device, "interrupt status for " + DBF_DEV_EVENT(DBF_DEBUG, device, "interrupt status for " "request %p was %d (%d retries left)", cqr, status, cqr->retries); dasd_diag_erp(device); @@ -322,8 +321,9 @@ dasd_diag_check_device(struct dasd_device *device) if (private == NULL) { private = kzalloc(sizeof(struct dasd_diag_private),GFP_KERNEL); if (private == NULL) { - DEV_MESSAGE(KERN_WARNING, device, "%s", - "memory allocation failed for private data"); + DBF_DEV_EVENT(DBF_WARNING, device, "%s", + "Allocating memory for private DASD data " + "failed\n"); return -ENOMEM; } ccw_device_get_id(device->cdev, &private->dev_id); @@ -331,7 +331,7 @@ dasd_diag_check_device(struct dasd_device *device) } block = dasd_alloc_block(); if (IS_ERR(block)) { - DEV_MESSAGE(KERN_WARNING, device, "%s", + DBF_DEV_EVENT(DBF_WARNING, device, "%s", "could not allocate dasd block structure"); device->private = NULL; kfree(private); @@ -347,7 +347,7 @@ dasd_diag_check_device(struct dasd_device *device) rc = diag210((struct diag210 *) rdc_data); if (rc) { - DEV_MESSAGE(KERN_WARNING, device, "failed to retrieve device " + DBF_DEV_EVENT(DBF_WARNING, device, "failed to retrieve device " "information (rc=%d)", rc); rc = -EOPNOTSUPP; goto out; @@ -362,8 +362,8 @@ dasd_diag_check_device(struct dasd_device *device) private->pt_block = 2; break; default: - DEV_MESSAGE(KERN_WARNING, device, "unsupported device class " - "(class=%d)", private->rdc_data.vdev_class); + dev_warn(&device->cdev->dev, "Device type %d is not supported " + "in DIAG mode\n", private->rdc_data.vdev_class); rc = -EOPNOTSUPP; goto out; } @@ -380,7 +380,7 @@ dasd_diag_check_device(struct dasd_device *device) /* figure out blocksize of device */ label = (struct vtoc_cms_label *) get_zeroed_page(GFP_KERNEL); if (label == NULL) { - DEV_MESSAGE(KERN_WARNING, device, "%s", + DBF_DEV_EVENT(DBF_WARNING, device, "%s", "No memory to allocate initialization request"); rc = -ENOMEM; goto out; @@ -404,8 +404,8 @@ dasd_diag_check_device(struct dasd_device *device) private->iob.flaga = DASD_DIAG_FLAGA_DEFAULT; rc = dia250(&private->iob, RW_BIO); if (rc == 3) { - DEV_MESSAGE(KERN_WARNING, device, "%s", - "DIAG call failed"); + dev_warn(&device->cdev->dev, + "A 64-bit DIAG call failed\n"); rc = -EOPNOTSUPP; goto out_label; } @@ -414,8 +414,8 @@ dasd_diag_check_device(struct dasd_device *device) break; } if (bsize > PAGE_SIZE) { - DEV_MESSAGE(KERN_WARNING, device, "device access failed " - "(rc=%d)", rc); + dev_warn(&device->cdev->dev, "Accessing the DASD failed because" + " of an incorrect format (rc=%d)\n", rc); rc = -EIO; goto out_label; } @@ -433,15 +433,15 @@ dasd_diag_check_device(struct dasd_device *device) block->s2b_shift++; rc = mdsk_init_io(device, block->bp_block, 0, NULL); if (rc) { - DEV_MESSAGE(KERN_WARNING, device, "DIAG initialization " - "failed (rc=%d)", rc); + dev_warn(&device->cdev->dev, "DIAG initialization " + "failed with rc=%d\n", rc); rc = -EIO; } else { - DEV_MESSAGE(KERN_INFO, device, - "(%ld B/blk): %ldkB", - (unsigned long) block->bp_block, - (unsigned long) (block->blocks << - block->s2b_shift) >> 1); + dev_info(&device->cdev->dev, + "New DASD with %ld byte/block, total size %ld KB\n", + (unsigned long) block->bp_block, + (unsigned long) (block->blocks << + block->s2b_shift) >> 1); } out_label: free_page((long) label); @@ -595,7 +595,7 @@ static void dasd_diag_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req, struct irb *stat) { - DEV_MESSAGE(KERN_ERR, device, "%s", + DBF_DEV_EVENT(DBF_WARNING, device, "%s", "dump sense not available for DIAG data"); } @@ -621,10 +621,8 @@ static int __init dasd_diag_init(void) { if (!MACHINE_IS_VM) { - MESSAGE_LOG(KERN_INFO, - "Machine is not VM: %s " - "discipline not initializing", - dasd_diag_discipline.name); + pr_info("Discipline %s cannot be used without z/VM\n", + dasd_diag_discipline.name); return -ENODEV; } ASCEBC(dasd_diag_discipline.ebcname, 4); diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 1e4c89b8b30..21254793c60 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -11,6 +11,8 @@ * */ +#define KMSG_COMPONENT "dasd" + #include #include #include @@ -87,7 +89,7 @@ dasd_eckd_probe (struct ccw_device *cdev) /* set ECKD specific ccw-device options */ ret = ccw_device_set_options(cdev, CCWDEV_ALLOW_FORCE); if (ret) { - printk(KERN_WARNING + DBF_EVENT(DBF_WARNING, "dasd_eckd_probe: could not set ccw-device options " "for %s\n", dev_name(&cdev->dev)); return ret; @@ -248,8 +250,8 @@ define_extent(struct ccw1 *ccw, struct DE_eckd_data *data, unsigned int trk, rc = check_XRC (ccw, data, device); break; default: - DBF_DEV_EVENT(DBF_ERR, device, - "PFX LRE unknown opcode 0x%x", cmd); + dev_err(&device->cdev->dev, + "0x%x is not a known command\n", cmd); break; } @@ -647,7 +649,8 @@ locate_record(struct ccw1 *ccw, struct LO_eckd_data *data, unsigned int trk, data->operation.operation = 0x0b; break; default: - DEV_MESSAGE(KERN_ERR, device, "unknown opcode 0x%x", cmd); + DBF_DEV_EVENT(DBF_ERR, device, "unknown locate record " + "opcode 0x%x", cmd); } set_ch_t(&data->seek_addr, trk / private->rdc_data.trk_per_cyl, @@ -742,8 +745,8 @@ static struct dasd_ccw_req *dasd_eckd_build_rcd_lpm(struct dasd_device *device, cqr = dasd_smalloc_request("ECKD", 1 /* RCD */, ciw->count, device); if (IS_ERR(cqr)) { - DEV_MESSAGE(KERN_WARNING, device, "%s", - "Could not allocate RCD request"); + DBF_DEV_EVENT(DBF_WARNING, device, "%s", + "Could not allocate RCD request"); return cqr; } @@ -893,14 +896,16 @@ static int dasd_eckd_read_conf(struct dasd_device *device) rc = dasd_eckd_read_conf_lpm(device, &conf_data, &conf_len, lpm); if (rc && rc != -EOPNOTSUPP) { /* -EOPNOTSUPP is ok */ - MESSAGE(KERN_WARNING, - "Read configuration data returned " - "error %d", rc); + DBF_EVENT(DBF_WARNING, + "Read configuration data returned " + "error %d for device: %s", rc, + dev_name(&device->cdev->dev)); return rc; } if (conf_data == NULL) { - MESSAGE(KERN_WARNING, "%s", "No configuration " - "data retrieved"); + DBF_EVENT(DBF_WARNING, "No configuration " + "data retrieved for device: %s", + dev_name(&device->cdev->dev)); continue; /* no error */ } /* save first valid configuration data */ @@ -947,8 +952,9 @@ static int dasd_eckd_read_features(struct dasd_device *device) sizeof(struct dasd_rssd_features)), device); if (IS_ERR(cqr)) { - DEV_MESSAGE(KERN_WARNING, device, "%s", - "Could not allocate initialization request"); + DBF_EVENT(DBF_WARNING, "Could not allocate initialization " + "request for device: %s", + dev_name(&device->cdev->dev)); return PTR_ERR(cqr); } cqr->startdev = device; @@ -1009,7 +1015,7 @@ static struct dasd_ccw_req *dasd_eckd_build_psf_ssc(struct dasd_device *device, device); if (IS_ERR(cqr)) { - DEV_MESSAGE(KERN_WARNING, device, "%s", + DBF_DEV_EVENT(DBF_WARNING, device, "%s", "Could not allocate PSF-SSC request"); return cqr; } @@ -1074,10 +1080,10 @@ static int dasd_eckd_validate_server(struct dasd_device *device) /* may be requested feature is not available on server, * therefore just report error and go ahead */ private = (struct dasd_eckd_private *) device->private; - DEV_MESSAGE(KERN_INFO, device, - "PSF-SSC on storage subsystem %s.%s.%04x returned rc=%d", - private->uid.vendor, private->uid.serial, - private->uid.ssid, rc); + DBF_EVENT(DBF_WARNING, "PSF-SSC on storage subsystem %s.%s.%04x " + "returned rc=%d for device: %s", + private->uid.vendor, private->uid.serial, + private->uid.ssid, rc, dev_name(&device->cdev->dev)); /* RE-Read Configuration Data */ return dasd_eckd_read_conf(device); } @@ -1099,9 +1105,9 @@ dasd_eckd_check_characteristics(struct dasd_device *device) private = kzalloc(sizeof(struct dasd_eckd_private), GFP_KERNEL | GFP_DMA); if (private == NULL) { - DEV_MESSAGE(KERN_WARNING, device, "%s", - "memory allocation failed for private " - "data"); + dev_warn(&device->cdev->dev, + "Allocating memory for private DASD data " + "failed\n"); return -ENOMEM; } device->private = (void *) private; @@ -1126,8 +1132,9 @@ dasd_eckd_check_characteristics(struct dasd_device *device) if (private->uid.type == UA_BASE_DEVICE) { block = dasd_alloc_block(); if (IS_ERR(block)) { - DEV_MESSAGE(KERN_WARNING, device, "%s", - "could not allocate dasd block structure"); + DBF_EVENT(DBF_WARNING, "could not allocate dasd " + "block structure for device: %s", + dev_name(&device->cdev->dev)); rc = PTR_ERR(block); goto out_err1; } @@ -1158,9 +1165,9 @@ dasd_eckd_check_characteristics(struct dasd_device *device) memset(rdc_data, 0, sizeof(rdc_data)); rc = dasd_generic_read_dev_chars(device, "ECKD", &rdc_data, 64); if (rc) { - DEV_MESSAGE(KERN_WARNING, device, - "Read device characteristics returned " - "rc=%d", rc); + DBF_EVENT(DBF_WARNING, + "Read device characteristics failed, rc=%d for " + "device: %s", rc, dev_name(&device->cdev->dev)); goto out_err3; } /* find the vaild cylinder size */ @@ -1170,15 +1177,15 @@ dasd_eckd_check_characteristics(struct dasd_device *device) else private->real_cyl = private->rdc_data.no_cyl; - DEV_MESSAGE(KERN_INFO, device, - "%04X/%02X(CU:%04X/%02X) Cyl:%d Head:%d Sec:%d", - private->rdc_data.dev_type, - private->rdc_data.dev_model, - private->rdc_data.cu_type, - private->rdc_data.cu_model.model, + dev_info(&device->cdev->dev, "New DASD %04X/%02X (CU %04X/%02X) " + "with %d cylinders, %d heads, %d sectors\n", + private->rdc_data.dev_type, + private->rdc_data.dev_model, + private->rdc_data.cu_type, + private->rdc_data.cu_model.model, private->real_cyl, - private->rdc_data.trk_per_cyl, - private->rdc_data.sec_per_trk); + private->rdc_data.trk_per_cyl, + private->rdc_data.sec_per_trk); return 0; out_err3: @@ -1319,8 +1326,8 @@ dasd_eckd_end_analysis(struct dasd_block *block) status = private->init_cqr_status; private->init_cqr_status = -1; if (status != DASD_CQR_DONE) { - DEV_MESSAGE(KERN_WARNING, device, "%s", - "volume analysis returned unformatted disk"); + dev_warn(&device->cdev->dev, + "The DASD is not formatted\n"); return -EMEDIUMTYPE; } @@ -1348,8 +1355,8 @@ dasd_eckd_end_analysis(struct dasd_block *block) count_area = &private->count_area[0]; } else { if (private->count_area[3].record == 1) - DEV_MESSAGE(KERN_WARNING, device, "%s", - "Trk 0: no records after VTOC!"); + dev_warn(&device->cdev->dev, + "Track 0 has no records following the VTOC\n"); } if (count_area != NULL && count_area->kl == 0) { /* we found notthing violating our disk layout */ @@ -1357,8 +1364,8 @@ dasd_eckd_end_analysis(struct dasd_block *block) block->bp_block = count_area->dl; } if (block->bp_block == 0) { - DEV_MESSAGE(KERN_WARNING, device, "%s", - "Volume has incompatible disk layout"); + dev_warn(&device->cdev->dev, + "The disk layout of the DASD is not supported\n"); return -EMEDIUMTYPE; } block->s2b_shift = 0; /* bits to shift 512 to get a block */ @@ -1370,15 +1377,15 @@ dasd_eckd_end_analysis(struct dasd_block *block) private->rdc_data.trk_per_cyl * blk_per_trk); - DEV_MESSAGE(KERN_INFO, device, - "(%dkB blks): %dkB at %dkB/trk %s", - (block->bp_block >> 10), - ((private->real_cyl * - private->rdc_data.trk_per_cyl * - blk_per_trk * (block->bp_block >> 9)) >> 1), - ((blk_per_trk * block->bp_block) >> 10), - private->uses_cdl ? - "compatible disk layout" : "linux disk layout"); + dev_info(&device->cdev->dev, + "DASD with %d KB/block, %d KB total size, %d KB/track, " + "%s\n", (block->bp_block >> 10), + ((private->real_cyl * + private->rdc_data.trk_per_cyl * + blk_per_trk * (block->bp_block >> 9)) >> 1), + ((blk_per_trk * block->bp_block) >> 10), + private->uses_cdl ? + "compatible disk layout" : "linux disk layout"); return 0; } @@ -1444,19 +1451,19 @@ dasd_eckd_format_device(struct dasd_device * device, /* Sanity checks. */ if (fdata->start_unit >= (private->real_cyl * private->rdc_data.trk_per_cyl)) { - DEV_MESSAGE(KERN_INFO, device, "Track no %u too big!", - fdata->start_unit); + dev_warn(&device->cdev->dev, "Start track number %d used in " + "formatting is too big\n", fdata->start_unit); return ERR_PTR(-EINVAL); } if (fdata->start_unit > fdata->stop_unit) { - DEV_MESSAGE(KERN_INFO, device, "Track %u reached! ending.", - fdata->start_unit); + dev_warn(&device->cdev->dev, "Start track %d used in " + "formatting exceeds end track\n", fdata->start_unit); return ERR_PTR(-EINVAL); } if (dasd_check_blocksize(fdata->blksize) != 0) { - DEV_MESSAGE(KERN_WARNING, device, - "Invalid blocksize %u...terminating!", - fdata->blksize); + dev_warn(&device->cdev->dev, + "The DASD cannot be formatted with block size %d\n", + fdata->blksize); return ERR_PTR(-EINVAL); } @@ -1500,8 +1507,8 @@ dasd_eckd_format_device(struct dasd_device * device, sizeof(struct eckd_count); break; default: - DEV_MESSAGE(KERN_WARNING, device, "Invalid flags 0x%x.", - fdata->intensity); + dev_warn(&device->cdev->dev, "An I/O control call used " + "incorrect flags 0x%x\n", fdata->intensity); return ERR_PTR(-EINVAL); } /* Allocate the format ccw request. */ @@ -1696,13 +1703,14 @@ static void dasd_eckd_handle_unsolicited_interrupt(struct dasd_device *device, if (!sense) { /* just report other unsolicited interrupts */ - DEV_MESSAGE(KERN_ERR, device, "%s", + DBF_DEV_EVENT(DBF_ERR, device, "%s", "unsolicited interrupt received"); } else { - DEV_MESSAGE(KERN_ERR, device, "%s", + DBF_DEV_EVENT(DBF_ERR, device, "%s", "unsolicited interrupt received " "(sense available)"); - device->discipline->dump_sense(device, NULL, irb); + device->discipline->dump_sense_dbf(device, NULL, irb, + "unsolicited"); } dasd_schedule_device_bh(device); @@ -2553,7 +2561,7 @@ dasd_eckd_release(struct dasd_device *device) cqr = dasd_smalloc_request(dasd_eckd_discipline.name, 1, 32, device); if (IS_ERR(cqr)) { - DEV_MESSAGE(KERN_WARNING, device, "%s", + DBF_DEV_EVENT(DBF_WARNING, device, "%s", "Could not allocate initialization request"); return PTR_ERR(cqr); } @@ -2596,7 +2604,7 @@ dasd_eckd_reserve(struct dasd_device *device) cqr = dasd_smalloc_request(dasd_eckd_discipline.name, 1, 32, device); if (IS_ERR(cqr)) { - DEV_MESSAGE(KERN_WARNING, device, "%s", + DBF_DEV_EVENT(DBF_WARNING, device, "%s", "Could not allocate initialization request"); return PTR_ERR(cqr); } @@ -2638,7 +2646,7 @@ dasd_eckd_steal_lock(struct dasd_device *device) cqr = dasd_smalloc_request(dasd_eckd_discipline.name, 1, 32, device); if (IS_ERR(cqr)) { - DEV_MESSAGE(KERN_WARNING, device, "%s", + DBF_DEV_EVENT(DBF_WARNING, device, "%s", "Could not allocate initialization request"); return PTR_ERR(cqr); } @@ -2680,7 +2688,7 @@ dasd_eckd_performance(struct dasd_device *device, void __user *argp) sizeof(struct dasd_rssd_perf_stats_t)), device); if (IS_ERR(cqr)) { - DEV_MESSAGE(KERN_WARNING, device, "%s", + DBF_DEV_EVENT(DBF_WARNING, device, "%s", "Could not allocate initialization request"); return PTR_ERR(cqr); } @@ -2770,9 +2778,9 @@ dasd_eckd_set_attrib(struct dasd_device *device, void __user *argp) return -EFAULT; private->attrib = attrib; - DEV_MESSAGE(KERN_INFO, device, - "cache operation mode set to %x (%i cylinder prestage)", - private->attrib.operation, private->attrib.nr_cyl); + dev_info(&device->cdev->dev, + "The DASD cache mode was set to %x (%i cylinder prestage)\n", + private->attrib.operation, private->attrib.nr_cyl); return 0; } @@ -2823,7 +2831,7 @@ static int dasd_symm_io(struct dasd_device *device, void __user *argp) /* setup CCWs for PSF + RSSD */ cqr = dasd_smalloc_request("ECKD", 2 , 0, device); if (IS_ERR(cqr)) { - DEV_MESSAGE(KERN_WARNING, device, "%s", + DBF_DEV_EVENT(DBF_WARNING, device, "%s", "Could not allocate initialization request"); rc = PTR_ERR(cqr); goto out_free; @@ -2932,6 +2940,49 @@ dasd_eckd_dump_ccw_range(struct ccw1 *from, struct ccw1 *to, char *page) return len; } +static void +dasd_eckd_dump_sense_dbf(struct dasd_device *device, struct dasd_ccw_req *req, + struct irb *irb, char *reason) +{ + u64 *sense; + int sl; + struct tsb *tsb; + + sense = NULL; + tsb = NULL; + if (req && scsw_is_tm(&req->irb.scsw)) { + if (irb->scsw.tm.tcw) + tsb = tcw_get_tsb( + (struct tcw *)(unsigned long)irb->scsw.tm.tcw); + if (tsb && (irb->scsw.tm.fcxs == 0x01)) { + switch (tsb->flags & 0x07) { + case 1: /* tsa_iostat */ + sense = (u64 *)tsb->tsa.iostat.sense; + break; + case 2: /* ts_ddpc */ + sense = (u64 *)tsb->tsa.ddpc.sense; + break; + case 3: /* tsa_intrg */ + break; + } + } + } else { + if (irb->esw.esw0.erw.cons) + sense = (u64 *)irb->ecw; + } + if (sense) { + for (sl = 0; sl < 4; sl++) { + DBF_DEV_EVENT(DBF_EMERG, device, + "%s: %016llx %016llx %016llx %016llx", + reason, sense[0], sense[1], sense[2], + sense[3]); + } + } else { + DBF_DEV_EVENT(DBF_EMERG, device, "%s", + "SORRY - NO VALID SENSE AVAILABLE\n"); + } +} + /* * Print sense data and related channel program. * Parts are printed because printk buffer is only 1024 bytes. @@ -2945,8 +2996,8 @@ static void dasd_eckd_dump_sense_ccw(struct dasd_device *device, page = (char *) get_zeroed_page(GFP_ATOMIC); if (page == NULL) { - DEV_MESSAGE(KERN_ERR, device, " %s", - "No memory to dump sense data"); + DBF_DEV_EVENT(DBF_WARNING, device, "%s", + "No memory to dump sense data\n"); return; } /* dump the sense data */ @@ -3047,7 +3098,7 @@ static void dasd_eckd_dump_sense_tcw(struct dasd_device *device, page = (char *) get_zeroed_page(GFP_ATOMIC); if (page == NULL) { - DEV_MESSAGE(KERN_ERR, device, " %s", + DBF_DEV_EVENT(DBF_WARNING, device, " %s", "No memory to dump sense data"); return; } @@ -3206,6 +3257,7 @@ static struct dasd_discipline dasd_eckd_discipline = { .build_cp = dasd_eckd_build_alias_cp, .free_cp = dasd_eckd_free_alias_cp, .dump_sense = dasd_eckd_dump_sense, + .dump_sense_dbf = dasd_eckd_dump_sense_dbf, .fill_info = dasd_eckd_fill_info, .ioctl = dasd_eckd_ioctl, }; diff --git a/drivers/s390/block/dasd_eer.c b/drivers/s390/block/dasd_eer.c index 9ce4209552a..c24c8c30380 100644 --- a/drivers/s390/block/dasd_eer.c +++ b/drivers/s390/block/dasd_eer.c @@ -6,6 +6,8 @@ * Author(s): Stefan Weinhuber */ +#define KMSG_COMPONENT "dasd" + #include #include #include @@ -539,7 +541,7 @@ static int dasd_eer_open(struct inode *inp, struct file *filp) if (eerb->buffer_page_count < 1 || eerb->buffer_page_count > INT_MAX / PAGE_SIZE) { kfree(eerb); - MESSAGE(KERN_WARNING, "can't open device since module " + DBF_EVENT(DBF_WARNING, "can't open device since module " "parameter eer_pages is smaller than 1 or" " bigger than %d", (int)(INT_MAX / PAGE_SIZE)); unlock_kernel(); @@ -692,7 +694,7 @@ int __init dasd_eer_init(void) if (rc) { kfree(dasd_eer_dev); dasd_eer_dev = NULL; - MESSAGE(KERN_ERR, "%s", "dasd_eer_init could not " + DBF_EVENT(DBF_ERR, "%s", "dasd_eer_init could not " "register misc device"); return rc; } diff --git a/drivers/s390/block/dasd_erp.c b/drivers/s390/block/dasd_erp.c index 8f10000851a..d970ce2814b 100644 --- a/drivers/s390/block/dasd_erp.c +++ b/drivers/s390/block/dasd_erp.c @@ -9,6 +9,8 @@ * */ +#define KMSG_COMPONENT "dasd" + #include #include @@ -91,14 +93,14 @@ dasd_default_erp_action(struct dasd_ccw_req *cqr) /* just retry - there is nothing to save ... I got no sense data.... */ if (cqr->retries > 0) { - DEV_MESSAGE (KERN_DEBUG, device, + DBF_DEV_EVENT(DBF_DEBUG, device, "default ERP called (%i retries left)", cqr->retries); cqr->lpm = LPM_ANYPATH; cqr->status = DASD_CQR_FILLED; } else { - DEV_MESSAGE (KERN_WARNING, device, "%s", - "default ERP called (NO retry left)"); + dev_err(&device->cdev->dev, + "default ERP has run out of retries and failed\n"); cqr->status = DASD_CQR_FAILED; cqr->stopclk = get_clock(); } @@ -162,8 +164,21 @@ dasd_log_sense(struct dasd_ccw_req *cqr, struct irb *irb) device->discipline->dump_sense(device, cqr, irb); } +void +dasd_log_sense_dbf(struct dasd_ccw_req *cqr, struct irb *irb) +{ + struct dasd_device *device; + + device = cqr->startdev; + /* dump sense data to s390 debugfeature*/ + if (device->discipline && device->discipline->dump_sense_dbf) + device->discipline->dump_sense_dbf(device, cqr, irb, "log"); +} +EXPORT_SYMBOL(dasd_log_sense_dbf); + EXPORT_SYMBOL(dasd_default_erp_action); EXPORT_SYMBOL(dasd_default_erp_postaction); EXPORT_SYMBOL(dasd_alloc_erp_request); EXPORT_SYMBOL(dasd_free_erp_request); EXPORT_SYMBOL(dasd_log_sense); + diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index f1d17602169..a3eb6fd1467 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c @@ -6,6 +6,8 @@ * */ +#define KMSG_COMPONENT "dasd" + #include #include #include @@ -128,17 +130,18 @@ dasd_fba_check_characteristics(struct dasd_device *device) private = kzalloc(sizeof(struct dasd_fba_private), GFP_KERNEL | GFP_DMA); if (private == NULL) { - DEV_MESSAGE(KERN_WARNING, device, "%s", - "memory allocation failed for private " - "data"); + dev_warn(&device->cdev->dev, + "Allocating memory for private DASD " + "data failed\n"); return -ENOMEM; } device->private = (void *) private; } block = dasd_alloc_block(); if (IS_ERR(block)) { - DEV_MESSAGE(KERN_WARNING, device, "%s", - "could not allocate dasd block structure"); + DBF_EVENT(DBF_WARNING, "could not allocate dasd block " + "structure for device: %s", + dev_name(&device->cdev->dev)); device->private = NULL; kfree(private); return PTR_ERR(block); @@ -150,9 +153,9 @@ dasd_fba_check_characteristics(struct dasd_device *device) rdc_data = (void *) &(private->rdc_data); rc = dasd_generic_read_dev_chars(device, "FBA ", &rdc_data, 32); if (rc) { - DEV_MESSAGE(KERN_WARNING, device, - "Read device characteristics returned error %d", - rc); + DBF_EVENT(DBF_WARNING, "Read device characteristics returned " + "error %d for device: %s", + rc, dev_name(&device->cdev->dev)); device->block = NULL; dasd_free_block(block); device->private = NULL; @@ -160,15 +163,16 @@ dasd_fba_check_characteristics(struct dasd_device *device) return rc; } - DEV_MESSAGE(KERN_INFO, device, - "%04X/%02X(CU:%04X/%02X) %dMB at(%d B/blk)", - cdev->id.dev_type, - cdev->id.dev_model, - cdev->id.cu_type, - cdev->id.cu_model, - ((private->rdc_data.blk_bdsa * - (private->rdc_data.blk_size >> 9)) >> 11), - private->rdc_data.blk_size); + dev_info(&device->cdev->dev, + "New FBA DASD %04X/%02X (CU %04X/%02X) with %d MB " + "and %d B/blk\n", + cdev->id.dev_type, + cdev->id.dev_model, + cdev->id.cu_type, + cdev->id.cu_model, + ((private->rdc_data.blk_bdsa * + (private->rdc_data.blk_size >> 9)) >> 11), + private->rdc_data.blk_size); return 0; } @@ -180,7 +184,7 @@ static int dasd_fba_do_analysis(struct dasd_block *block) private = (struct dasd_fba_private *) block->base->private; rc = dasd_check_blocksize(private->rdc_data.blk_size); if (rc) { - DEV_MESSAGE(KERN_INFO, block->base, "unknown blocksize %d", + DBF_DEV_EVENT(DBF_WARNING, block->base, "unknown blocksize %d", private->rdc_data.blk_size); return rc; } @@ -215,7 +219,7 @@ dasd_fba_erp_postaction(struct dasd_ccw_req * cqr) if (cqr->function == dasd_default_erp_action) return dasd_default_erp_postaction; - DEV_MESSAGE(KERN_WARNING, cqr->startdev, "unknown ERP action %p", + DBF_DEV_EVENT(DBF_WARNING, cqr->startdev, "unknown ERP action %p", cqr->function); return NULL; } @@ -233,9 +237,9 @@ static void dasd_fba_handle_unsolicited_interrupt(struct dasd_device *device, } /* check for unsolicited interrupts */ - DEV_MESSAGE(KERN_DEBUG, device, "%s", + DBF_DEV_EVENT(DBF_WARNING, device, "%s", "unsolicited interrupt received"); - device->discipline->dump_sense(device, NULL, irb); + device->discipline->dump_sense_dbf(device, NULL, irb, "unsolicited"); dasd_schedule_device_bh(device); return; }; @@ -436,6 +440,25 @@ dasd_fba_fill_info(struct dasd_device * device, return 0; } +static void +dasd_fba_dump_sense_dbf(struct dasd_device *device, struct dasd_ccw_req *req, + struct irb *irb, char *reason) +{ + int sl; + if (irb->esw.esw0.erw.cons) { + for (sl = 0; sl < 4; sl++) { + DBF_DEV_EVENT(DBF_EMERG, device, + "%s: %08x %08x %08x %08x", + reason, irb->ecw[8 * 0], irb->ecw[8 * 1], + irb->ecw[8 * 2], irb->ecw[8 * 3]); + } + } else { + DBF_DEV_EVENT(DBF_EMERG, device, "%s", + "SORRY - NO VALID SENSE AVAILABLE\n"); + } +} + + static void dasd_fba_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req, struct irb *irb) @@ -446,7 +469,7 @@ dasd_fba_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req, page = (char *) get_zeroed_page(GFP_ATOMIC); if (page == NULL) { - DEV_MESSAGE(KERN_ERR, device, " %s", + DBF_DEV_EVENT(DBF_WARNING, device, "%s", "No memory to dump sense data"); return; } @@ -476,8 +499,7 @@ dasd_fba_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req, len += sprintf(page + len, KERN_ERR PRINTK_HEADER " SORRY - NO VALID SENSE AVAILABLE\n"); } - MESSAGE_LOG(KERN_ERR, "%s", - page + sizeof(KERN_ERR PRINTK_HEADER)); + printk(KERN_ERR "%s", page); /* dump the Channel Program */ /* print first CCWs (maximum 8) */ @@ -498,8 +520,7 @@ dasd_fba_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req, len += sprintf(page + len, "\n"); act++; } - MESSAGE_LOG(KERN_ERR, "%s", - page + sizeof(KERN_ERR PRINTK_HEADER)); + printk(KERN_ERR "%s", page); /* print failing CCW area */ @@ -540,8 +561,7 @@ dasd_fba_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req, act++; } if (len > 0) - MESSAGE_LOG(KERN_ERR, "%s", - page + sizeof(KERN_ERR PRINTK_HEADER)); + printk(KERN_ERR "%s", page); free_page((unsigned long) page); } @@ -576,6 +596,7 @@ static struct dasd_discipline dasd_fba_discipline = { .build_cp = dasd_fba_build_cp, .free_cp = dasd_fba_free_cp, .dump_sense = dasd_fba_dump_sense, + .dump_sense_dbf = dasd_fba_dump_sense_dbf, .fill_info = dasd_fba_fill_info, }; diff --git a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c index e99d566b69c..d3198303b93 100644 --- a/drivers/s390/block/dasd_genhd.c +++ b/drivers/s390/block/dasd_genhd.c @@ -11,6 +11,8 @@ * */ +#define KMSG_COMPONENT "dasd" + #include #include #include @@ -163,9 +165,8 @@ int dasd_gendisk_init(void) /* Register to static dasd major 94 */ rc = register_blkdev(DASD_MAJOR, "dasd"); if (rc != 0) { - MESSAGE(KERN_WARNING, - "Couldn't register successfully to " - "major no %d", DASD_MAJOR); + pr_warning("Registering the device driver with major number " + "%d failed\n", DASD_MAJOR); return rc; } return 0; diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index 7b314c1d471..c1e487f774c 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -112,6 +112,9 @@ do { \ d_data); \ } while(0) +/* limit size for an errorstring */ +#define ERRORLENGTH 30 + /* definition of dbf debug levels */ #define DBF_EMERG 0 /* system is unusable */ #define DBF_ALERT 1 /* action must be taken immediately */ @@ -281,6 +284,8 @@ struct dasd_discipline { dasd_erp_fn_t(*erp_postaction) (struct dasd_ccw_req *); void (*dump_sense) (struct dasd_device *, struct dasd_ccw_req *, struct irb *); + void (*dump_sense_dbf) (struct dasd_device *, struct dasd_ccw_req *, + struct irb *, char *); void (*handle_unsolicited_interrupt) (struct dasd_device *, struct irb *); @@ -626,6 +631,7 @@ struct dasd_ccw_req *dasd_alloc_erp_request(char *, int, int, struct dasd_device *); void dasd_free_erp_request(struct dasd_ccw_req *, struct dasd_device *); void dasd_log_sense(struct dasd_ccw_req *, struct irb *); +void dasd_log_sense_dbf(struct dasd_ccw_req *cqr, struct irb *irb); /* externals in dasd_3990_erp.c */ struct dasd_ccw_req *dasd_3990_erp_action(struct dasd_ccw_req *); diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c index a3bbdb807ba..4ce3f72ee1c 100644 --- a/drivers/s390/block/dasd_ioctl.c +++ b/drivers/s390/block/dasd_ioctl.c @@ -9,6 +9,9 @@ * * i/o controls for the dasd driver. */ + +#define KMSG_COMPONENT "dasd" + #include #include #include @@ -94,7 +97,8 @@ static int dasd_ioctl_quiesce(struct dasd_block *block) if (!capable (CAP_SYS_ADMIN)) return -EACCES; - DEV_MESSAGE(KERN_DEBUG, base, "%s", "Quiesce IO on device"); + dev_info(&base->cdev->dev, "The DASD has been put in the quiesce " + "state\n"); spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags); base->stopped |= DASD_STOPPED_QUIESCE; spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), flags); @@ -103,7 +107,7 @@ static int dasd_ioctl_quiesce(struct dasd_block *block) /* - * Quiesce device. + * Resume device. */ static int dasd_ioctl_resume(struct dasd_block *block) { @@ -114,7 +118,8 @@ static int dasd_ioctl_resume(struct dasd_block *block) if (!capable (CAP_SYS_ADMIN)) return -EACCES; - DEV_MESSAGE(KERN_DEBUG, base, "%s", "resume IO on device"); + dev_info(&base->cdev->dev, "I/O operations have been resumed " + "on the DASD\n"); spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags); base->stopped &= ~DASD_STOPPED_QUIESCE; spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), flags); @@ -140,8 +145,8 @@ static int dasd_format(struct dasd_block *block, struct format_data_t *fdata) return -EPERM; if (base->state != DASD_STATE_BASIC) { - DEV_MESSAGE(KERN_WARNING, base, "%s", - "dasd_format: device is not disabled! "); + dev_warn(&base->cdev->dev, + "The DASD cannot be formatted while it is enabled\n"); return -EBUSY; } @@ -169,10 +174,9 @@ static int dasd_format(struct dasd_block *block, struct format_data_t *fdata) dasd_sfree_request(cqr, cqr->memdev); if (rc) { if (rc != -ERESTARTSYS) - DEV_MESSAGE(KERN_ERR, base, - " Formatting of unit %u failed " - "with rc = %d", - fdata->start_unit, rc); + dev_err(&base->cdev->dev, + "Formatting unit %d failed with " + "rc=%d\n", fdata->start_unit, rc); return rc; } fdata->start_unit++; @@ -199,8 +203,9 @@ dasd_ioctl_format(struct block_device *bdev, void __user *argp) if (copy_from_user(&fdata, argp, sizeof(struct format_data_t))) return -EFAULT; if (bdev != bdev->bd_contains) { - DEV_MESSAGE(KERN_WARNING, block->base, "%s", - "Cannot low-level format a partition"); + dev_warn(&block->base->cdev->dev, + "The specified DASD is a partition and cannot be " + "formatted\n"); return -EINVAL; } return dasd_format(block, &fdata); diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c index 0aa569419d5..2080ba6a69b 100644 --- a/drivers/s390/block/dasd_proc.c +++ b/drivers/s390/block/dasd_proc.c @@ -11,6 +11,8 @@ * */ +#define KMSG_COMPONENT "dasd" + #include #include #include @@ -267,7 +269,7 @@ dasd_statistics_write(struct file *file, const char __user *user_buf, buffer = dasd_get_user_string(user_buf, user_len); if (IS_ERR(buffer)) return PTR_ERR(buffer); - MESSAGE_LOG(KERN_INFO, "/proc/dasd/statictics: '%s'", buffer); + DBF_EVENT(DBF_DEBUG, "/proc/dasd/statictics: '%s'\n", buffer); /* check for valid verbs */ for (str = buffer; isspace(*str); str++); @@ -277,33 +279,33 @@ dasd_statistics_write(struct file *file, const char __user *user_buf, if (strcmp(str, "on") == 0) { /* switch on statistics profiling */ dasd_profile_level = DASD_PROFILE_ON; - MESSAGE(KERN_INFO, "%s", "Statistics switched on"); + pr_info("The statistics feature has been switched " + "on\n"); } else if (strcmp(str, "off") == 0) { /* switch off and reset statistics profiling */ memset(&dasd_global_profile, 0, sizeof (struct dasd_profile_info_t)); dasd_profile_level = DASD_PROFILE_OFF; - MESSAGE(KERN_INFO, "%s", "Statistics switched off"); + pr_info("The statistics feature has been switched " + "off\n"); } else goto out_error; } else if (strncmp(str, "reset", 5) == 0) { /* reset the statistics */ memset(&dasd_global_profile, 0, sizeof (struct dasd_profile_info_t)); - MESSAGE(KERN_INFO, "%s", "Statistics reset"); + pr_info("The statistics have been reset\n"); } else goto out_error; kfree(buffer); return user_len; out_error: - MESSAGE(KERN_WARNING, "%s", - "/proc/dasd/statistics: only 'set on', 'set off' " - "and 'reset' are supported verbs"); + pr_warning("%s is not a supported value for /proc/dasd/statistics\n", + str); kfree(buffer); return -EINVAL; #else - MESSAGE(KERN_WARNING, "%s", - "/proc/dasd/statistics: is not activated in this kernel"); + pr_warning("/proc/dasd/statistics: is not activated in this kernel\n"); return user_len; #endif /* CONFIG_DASD_PROFILE */ } -- cgit v1.2.3-70-g09d2 From 94f5b09d97ee1f803c76d0262e0b0d3791825d09 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 26 Mar 2009 15:23:50 +0100 Subject: [S390] move sysinfo.c from drivers/s390 to arch/s390/kernel All in sysinfo.c is core kernel code and not driver code. So move it to arch/s390/kernel. Also includes some small cleanups. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/Makefile | 4 +- arch/s390/kernel/sysinfo.c | 428 +++++++++++++++++++++++++++++++++++++++++ drivers/s390/Makefile | 4 +- drivers/s390/sysinfo.c | 469 --------------------------------------------- 4 files changed, 432 insertions(+), 473 deletions(-) create mode 100644 arch/s390/kernel/sysinfo.c delete mode 100644 drivers/s390/sysinfo.c diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index 3edc6c6f258..33e7aee7051 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile @@ -17,10 +17,12 @@ CFLAGS_smp.o := -Wno-nonnull # CFLAGS_ptrace.o += -DUTS_MACHINE='"$(UTS_MACHINE)"' +CFLAGS_sysinfo.o += -Iinclude/math-emu -Iarch/s390/math-emu -w + obj-y := bitmap.o traps.o time.o process.o base.o early.o setup.o \ processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \ s390_ext.o debug.o irq.o ipl.o dis.o diag.o mem_detect.o \ - vdso.o vtime.o + vdso.o vtime.o sysinfo.o obj-y += $(if $(CONFIG_64BIT),entry64.o,entry.o) obj-y += $(if $(CONFIG_64BIT),reipl64.o,reipl.o) diff --git a/arch/s390/kernel/sysinfo.c b/arch/s390/kernel/sysinfo.c new file mode 100644 index 00000000000..b5e75e1061c --- /dev/null +++ b/arch/s390/kernel/sysinfo.c @@ -0,0 +1,428 @@ +/* + * Copyright IBM Corp. 2001, 2009 + * Author(s): Ulrich Weigand , + * Martin Schwidefsky , + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Sigh, math-emu. Don't ask. */ +#include +#include +#include + +static inline int stsi_0(void) +{ + int rc = stsi(NULL, 0, 0, 0); + return rc == -ENOSYS ? rc : (((unsigned int) rc) >> 28); +} + +static int stsi_1_1_1(struct sysinfo_1_1_1 *info, char *page, int len) +{ + if (stsi(info, 1, 1, 1) == -ENOSYS) + return len; + + EBCASC(info->manufacturer, sizeof(info->manufacturer)); + EBCASC(info->type, sizeof(info->type)); + EBCASC(info->model, sizeof(info->model)); + EBCASC(info->sequence, sizeof(info->sequence)); + EBCASC(info->plant, sizeof(info->plant)); + EBCASC(info->model_capacity, sizeof(info->model_capacity)); + EBCASC(info->model_perm_cap, sizeof(info->model_perm_cap)); + EBCASC(info->model_temp_cap, sizeof(info->model_temp_cap)); + len += sprintf(page + len, "Manufacturer: %-16.16s\n", + info->manufacturer); + len += sprintf(page + len, "Type: %-4.4s\n", + info->type); + if (info->model[0] != '\0') + /* + * Sigh: the model field has been renamed with System z9 + * to model_capacity and a new model field has been added + * after the plant field. To avoid confusing older programs + * the "Model:" prints "model_capacity model" or just + * "model_capacity" if the model string is empty . + */ + len += sprintf(page + len, + "Model: %-16.16s %-16.16s\n", + info->model_capacity, info->model); + else + len += sprintf(page + len, "Model: %-16.16s\n", + info->model_capacity); + len += sprintf(page + len, "Sequence Code: %-16.16s\n", + info->sequence); + len += sprintf(page + len, "Plant: %-4.4s\n", + info->plant); + len += sprintf(page + len, "Model Capacity: %-16.16s %08u\n", + info->model_capacity, *(u32 *) info->model_cap_rating); + if (info->model_perm_cap[0] != '\0') + len += sprintf(page + len, + "Model Perm. Capacity: %-16.16s %08u\n", + info->model_perm_cap, + *(u32 *) info->model_perm_cap_rating); + if (info->model_temp_cap[0] != '\0') + len += sprintf(page + len, + "Model Temp. Capacity: %-16.16s %08u\n", + info->model_temp_cap, + *(u32 *) info->model_temp_cap_rating); + return len; +} + +static int stsi_1_2_2(struct sysinfo_1_2_2 *info, char *page, int len) +{ + struct sysinfo_1_2_2_extension *ext; + int i; + + if (stsi(info, 1, 2, 2) == -ENOSYS) + return len; + ext = (struct sysinfo_1_2_2_extension *) + ((unsigned long) info + info->acc_offset); + + len += sprintf(page + len, "\n"); + len += sprintf(page + len, "CPUs Total: %d\n", + info->cpus_total); + len += sprintf(page + len, "CPUs Configured: %d\n", + info->cpus_configured); + len += sprintf(page + len, "CPUs Standby: %d\n", + info->cpus_standby); + len += sprintf(page + len, "CPUs Reserved: %d\n", + info->cpus_reserved); + + if (info->format == 1) { + /* + * Sigh 2. According to the specification the alternate + * capability field is a 32 bit floating point number + * if the higher order 8 bits are not zero. Printing + * a floating point number in the kernel is a no-no, + * always print the number as 32 bit unsigned integer. + * The user-space needs to know about the strange + * encoding of the alternate cpu capability. + */ + len += sprintf(page + len, "Capability: %u %u\n", + info->capability, ext->alt_capability); + for (i = 2; i <= info->cpus_total; i++) + len += sprintf(page + len, + "Adjustment %02d-way: %u %u\n", + i, info->adjustment[i-2], + ext->alt_adjustment[i-2]); + + } else { + len += sprintf(page + len, "Capability: %u\n", + info->capability); + for (i = 2; i <= info->cpus_total; i++) + len += sprintf(page + len, + "Adjustment %02d-way: %u\n", + i, info->adjustment[i-2]); + } + + if (info->secondary_capability != 0) + len += sprintf(page + len, "Secondary Capability: %d\n", + info->secondary_capability); + return len; +} + +static int stsi_2_2_2(struct sysinfo_2_2_2 *info, char *page, int len) +{ + if (stsi(info, 2, 2, 2) == -ENOSYS) + return len; + + EBCASC(info->name, sizeof(info->name)); + + len += sprintf(page + len, "\n"); + len += sprintf(page + len, "LPAR Number: %d\n", + info->lpar_number); + + len += sprintf(page + len, "LPAR Characteristics: "); + if (info->characteristics & LPAR_CHAR_DEDICATED) + len += sprintf(page + len, "Dedicated "); + if (info->characteristics & LPAR_CHAR_SHARED) + len += sprintf(page + len, "Shared "); + if (info->characteristics & LPAR_CHAR_LIMITED) + len += sprintf(page + len, "Limited "); + len += sprintf(page + len, "\n"); + + len += sprintf(page + len, "LPAR Name: %-8.8s\n", + info->name); + + len += sprintf(page + len, "LPAR Adjustment: %d\n", + info->caf); + + len += sprintf(page + len, "LPAR CPUs Total: %d\n", + info->cpus_total); + len += sprintf(page + len, "LPAR CPUs Configured: %d\n", + info->cpus_configured); + len += sprintf(page + len, "LPAR CPUs Standby: %d\n", + info->cpus_standby); + len += sprintf(page + len, "LPAR CPUs Reserved: %d\n", + info->cpus_reserved); + len += sprintf(page + len, "LPAR CPUs Dedicated: %d\n", + info->cpus_dedicated); + len += sprintf(page + len, "LPAR CPUs Shared: %d\n", + info->cpus_shared); + return len; +} + +static int stsi_3_2_2(struct sysinfo_3_2_2 *info, char *page, int len) +{ + int i; + + if (stsi(info, 3, 2, 2) == -ENOSYS) + return len; + for (i = 0; i < info->count; i++) { + EBCASC(info->vm[i].name, sizeof(info->vm[i].name)); + EBCASC(info->vm[i].cpi, sizeof(info->vm[i].cpi)); + len += sprintf(page + len, "\n"); + len += sprintf(page + len, "VM%02d Name: %-8.8s\n", + i, info->vm[i].name); + len += sprintf(page + len, "VM%02d Control Program: %-16.16s\n", + i, info->vm[i].cpi); + + len += sprintf(page + len, "VM%02d Adjustment: %d\n", + i, info->vm[i].caf); + + len += sprintf(page + len, "VM%02d CPUs Total: %d\n", + i, info->vm[i].cpus_total); + len += sprintf(page + len, "VM%02d CPUs Configured: %d\n", + i, info->vm[i].cpus_configured); + len += sprintf(page + len, "VM%02d CPUs Standby: %d\n", + i, info->vm[i].cpus_standby); + len += sprintf(page + len, "VM%02d CPUs Reserved: %d\n", + i, info->vm[i].cpus_reserved); + } + return len; +} + +static int proc_read_sysinfo(char *page, char **start, + off_t off, int count, + int *eof, void *data) +{ + unsigned long info = get_zeroed_page(GFP_KERNEL); + int level, len; + + if (!info) + return 0; + + len = 0; + level = stsi_0(); + if (level >= 1) + len = stsi_1_1_1((struct sysinfo_1_1_1 *) info, page, len); + + if (level >= 1) + len = stsi_1_2_2((struct sysinfo_1_2_2 *) info, page, len); + + if (level >= 2) + len = stsi_2_2_2((struct sysinfo_2_2_2 *) info, page, len); + + if (level >= 3) + len = stsi_3_2_2((struct sysinfo_3_2_2 *) info, page, len); + + free_page(info); + return len; +} + +static __init int create_proc_sysinfo(void) +{ + create_proc_read_entry("sysinfo", 0444, NULL, + proc_read_sysinfo, NULL); + return 0; +} +device_initcall(create_proc_sysinfo); + +/* + * Service levels interface. + */ + +static DECLARE_RWSEM(service_level_sem); +static LIST_HEAD(service_level_list); + +int register_service_level(struct service_level *slr) +{ + struct service_level *ptr; + + down_write(&service_level_sem); + list_for_each_entry(ptr, &service_level_list, list) + if (ptr == slr) { + up_write(&service_level_sem); + return -EEXIST; + } + list_add_tail(&slr->list, &service_level_list); + up_write(&service_level_sem); + return 0; +} +EXPORT_SYMBOL(register_service_level); + +int unregister_service_level(struct service_level *slr) +{ + struct service_level *ptr, *next; + int rc = -ENOENT; + + down_write(&service_level_sem); + list_for_each_entry_safe(ptr, next, &service_level_list, list) { + if (ptr != slr) + continue; + list_del(&ptr->list); + rc = 0; + break; + } + up_write(&service_level_sem); + return rc; +} +EXPORT_SYMBOL(unregister_service_level); + +static void *service_level_start(struct seq_file *m, loff_t *pos) +{ + down_read(&service_level_sem); + return seq_list_start(&service_level_list, *pos); +} + +static void *service_level_next(struct seq_file *m, void *p, loff_t *pos) +{ + return seq_list_next(p, &service_level_list, pos); +} + +static void service_level_stop(struct seq_file *m, void *p) +{ + up_read(&service_level_sem); +} + +static int service_level_show(struct seq_file *m, void *p) +{ + struct service_level *slr; + + slr = list_entry(p, struct service_level, list); + slr->seq_print(m, slr); + return 0; +} + +static const struct seq_operations service_level_seq_ops = { + .start = service_level_start, + .next = service_level_next, + .stop = service_level_stop, + .show = service_level_show +}; + +static int service_level_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &service_level_seq_ops); +} + +static const struct file_operations service_level_ops = { + .open = service_level_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release +}; + +static void service_level_vm_print(struct seq_file *m, + struct service_level *slr) +{ + char *query_buffer, *str; + + query_buffer = kmalloc(1024, GFP_KERNEL | GFP_DMA); + if (!query_buffer) + return; + cpcmd("QUERY CPLEVEL", query_buffer, 1024, NULL); + str = strchr(query_buffer, '\n'); + if (str) + *str = 0; + seq_printf(m, "VM: %s\n", query_buffer); + kfree(query_buffer); +} + +static struct service_level service_level_vm = { + .seq_print = service_level_vm_print +}; + +static __init int create_proc_service_level(void) +{ + proc_create("service_levels", 0, NULL, &service_level_ops); + if (MACHINE_IS_VM) + register_service_level(&service_level_vm); + return 0; +} +subsys_initcall(create_proc_service_level); + +/* + * Bogomips calculation based on cpu capability. + */ +int get_cpu_capability(unsigned int *capability) +{ + struct sysinfo_1_2_2 *info; + int rc; + + info = (void *) get_zeroed_page(GFP_KERNEL); + if (!info) + return -ENOMEM; + rc = stsi(info, 1, 2, 2); + if (rc == -ENOSYS) + goto out; + rc = 0; + *capability = info->capability; +out: + free_page((unsigned long) info); + return rc; +} + +/* + * CPU capability might have changed. Therefore recalculate loops_per_jiffy. + */ +void s390_adjust_jiffies(void) +{ + struct sysinfo_1_2_2 *info; + const unsigned int fmil = 0x4b189680; /* 1e7 as 32-bit float. */ + FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR); + FP_DECL_EX; + unsigned int capability; + + info = (void *) get_zeroed_page(GFP_KERNEL); + if (!info) + return; + + if (stsi(info, 1, 2, 2) != -ENOSYS) { + /* + * Major sigh. The cpu capability encoding is "special". + * If the first 9 bits of info->capability are 0 then it + * is a 32 bit unsigned integer in the range 0 .. 2^23. + * If the first 9 bits are != 0 then it is a 32 bit float. + * In addition a lower value indicates a proportionally + * higher cpu capacity. Bogomips are the other way round. + * To get to a halfway suitable number we divide 1e7 + * by the cpu capability number. Yes, that means a floating + * point division .. math-emu here we come :-) + */ + FP_UNPACK_SP(SA, &fmil); + if ((info->capability >> 23) == 0) + FP_FROM_INT_S(SB, info->capability, 32, int); + else + FP_UNPACK_SP(SB, &info->capability); + FP_DIV_S(SR, SA, SB); + FP_TO_INT_S(capability, SR, 32, 0); + } else + /* + * Really old machine without stsi block for basic + * cpu information. Report 42.0 bogomips. + */ + capability = 42; + loops_per_jiffy = capability * (500000/HZ); + free_page((unsigned long) info); +} + +/* + * calibrate the delay loop + */ +void __cpuinit calibrate_delay(void) +{ + s390_adjust_jiffies(); + /* Print the good old Bogomips line .. */ + printk(KERN_DEBUG "Calibrating delay loop (skipped)... " + "%lu.%02lu BogoMIPS preset\n", loops_per_jiffy/(500000/HZ), + (loops_per_jiffy/(5000/HZ)) % 100); +} diff --git a/drivers/s390/Makefile b/drivers/s390/Makefile index d0eae59bc36..0828dc83935 100644 --- a/drivers/s390/Makefile +++ b/drivers/s390/Makefile @@ -2,9 +2,7 @@ # Makefile for the S/390 specific device drivers # -CFLAGS_sysinfo.o += -Iinclude/math-emu -Iarch/s390/math-emu -w - -obj-y += s390mach.o sysinfo.o +obj-y += s390mach.o obj-y += cio/ block/ char/ crypto/ net/ scsi/ kvm/ drivers-y += drivers/s390/built-in.o diff --git a/drivers/s390/sysinfo.c b/drivers/s390/sysinfo.c deleted file mode 100644 index 0eea9078138..00000000000 --- a/drivers/s390/sysinfo.c +++ /dev/null @@ -1,469 +0,0 @@ -/* - * drivers/s390/sysinfo.c - * - * Copyright IBM Corp. 2001, 2008 - * Author(s): Ulrich Weigand (Ulrich.Weigand@de.ibm.com) - * Martin Schwidefsky - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Sigh, math-emu. Don't ask. */ -#include -#include -#include - -static inline int stsi_0(void) -{ - int rc = stsi (NULL, 0, 0, 0); - return rc == -ENOSYS ? rc : (((unsigned int) rc) >> 28); -} - -static int stsi_1_1_1(struct sysinfo_1_1_1 *info, char *page, int len) -{ - if (stsi(info, 1, 1, 1) == -ENOSYS) - return len; - - EBCASC(info->manufacturer, sizeof(info->manufacturer)); - EBCASC(info->type, sizeof(info->type)); - EBCASC(info->model, sizeof(info->model)); - EBCASC(info->sequence, sizeof(info->sequence)); - EBCASC(info->plant, sizeof(info->plant)); - EBCASC(info->model_capacity, sizeof(info->model_capacity)); - EBCASC(info->model_perm_cap, sizeof(info->model_perm_cap)); - EBCASC(info->model_temp_cap, sizeof(info->model_temp_cap)); - len += sprintf(page + len, "Manufacturer: %-16.16s\n", - info->manufacturer); - len += sprintf(page + len, "Type: %-4.4s\n", - info->type); - if (info->model[0] != '\0') - /* - * Sigh: the model field has been renamed with System z9 - * to model_capacity and a new model field has been added - * after the plant field. To avoid confusing older programs - * the "Model:" prints "model_capacity model" or just - * "model_capacity" if the model string is empty . - */ - len += sprintf(page + len, - "Model: %-16.16s %-16.16s\n", - info->model_capacity, info->model); - else - len += sprintf(page + len, "Model: %-16.16s\n", - info->model_capacity); - len += sprintf(page + len, "Sequence Code: %-16.16s\n", - info->sequence); - len += sprintf(page + len, "Plant: %-4.4s\n", - info->plant); - len += sprintf(page + len, "Model Capacity: %-16.16s %08u\n", - info->model_capacity, *(u32 *) info->model_cap_rating); - if (info->model_perm_cap[0] != '\0') - len += sprintf(page + len, - "Model Perm. Capacity: %-16.16s %08u\n", - info->model_perm_cap, - *(u32 *) info->model_perm_cap_rating); - if (info->model_temp_cap[0] != '\0') - len += sprintf(page + len, - "Model Temp. Capacity: %-16.16s %08u\n", - info->model_temp_cap, - *(u32 *) info->model_temp_cap_rating); - return len; -} - -#if 0 /* Currently unused */ -static int stsi_1_2_1(struct sysinfo_1_2_1 *info, char *page, int len) -{ - if (stsi(info, 1, 2, 1) == -ENOSYS) - return len; - - len += sprintf(page + len, "\n"); - EBCASC(info->sequence, sizeof(info->sequence)); - EBCASC(info->plant, sizeof(info->plant)); - len += sprintf(page + len, "Sequence Code of CPU: %-16.16s\n", - info->sequence); - len += sprintf(page + len, "Plant of CPU: %-16.16s\n", - info->plant); - return len; -} -#endif - -static int stsi_1_2_2(struct sysinfo_1_2_2 *info, char *page, int len) -{ - struct sysinfo_1_2_2_extension *ext; - int i; - - if (stsi(info, 1, 2, 2) == -ENOSYS) - return len; - ext = (struct sysinfo_1_2_2_extension *) - ((unsigned long) info + info->acc_offset); - - len += sprintf(page + len, "\n"); - len += sprintf(page + len, "CPUs Total: %d\n", - info->cpus_total); - len += sprintf(page + len, "CPUs Configured: %d\n", - info->cpus_configured); - len += sprintf(page + len, "CPUs Standby: %d\n", - info->cpus_standby); - len += sprintf(page + len, "CPUs Reserved: %d\n", - info->cpus_reserved); - - if (info->format == 1) { - /* - * Sigh 2. According to the specification the alternate - * capability field is a 32 bit floating point number - * if the higher order 8 bits are not zero. Printing - * a floating point number in the kernel is a no-no, - * always print the number as 32 bit unsigned integer. - * The user-space needs to know about the strange - * encoding of the alternate cpu capability. - */ - len += sprintf(page + len, "Capability: %u %u\n", - info->capability, ext->alt_capability); - for (i = 2; i <= info->cpus_total; i++) - len += sprintf(page + len, - "Adjustment %02d-way: %u %u\n", - i, info->adjustment[i-2], - ext->alt_adjustment[i-2]); - - } else { - len += sprintf(page + len, "Capability: %u\n", - info->capability); - for (i = 2; i <= info->cpus_total; i++) - len += sprintf(page + len, - "Adjustment %02d-way: %u\n", - i, info->adjustment[i-2]); - } - - if (info->secondary_capability != 0) - len += sprintf(page + len, "Secondary Capability: %d\n", - info->secondary_capability); - - return len; -} - -#if 0 /* Currently unused */ -static int stsi_2_2_1(struct sysinfo_2_2_1 *info, char *page, int len) -{ - if (stsi(info, 2, 2, 1) == -ENOSYS) - return len; - - len += sprintf(page + len, "\n"); - EBCASC (info->sequence, sizeof(info->sequence)); - EBCASC (info->plant, sizeof(info->plant)); - len += sprintf(page + len, "Sequence Code of logical CPU: %-16.16s\n", - info->sequence); - len += sprintf(page + len, "Plant of logical CPU: %-16.16s\n", - info->plant); - return len; -} -#endif - -static int stsi_2_2_2(struct sysinfo_2_2_2 *info, char *page, int len) -{ - if (stsi(info, 2, 2, 2) == -ENOSYS) - return len; - - EBCASC (info->name, sizeof(info->name)); - - len += sprintf(page + len, "\n"); - len += sprintf(page + len, "LPAR Number: %d\n", - info->lpar_number); - - len += sprintf(page + len, "LPAR Characteristics: "); - if (info->characteristics & LPAR_CHAR_DEDICATED) - len += sprintf(page + len, "Dedicated "); - if (info->characteristics & LPAR_CHAR_SHARED) - len += sprintf(page + len, "Shared "); - if (info->characteristics & LPAR_CHAR_LIMITED) - len += sprintf(page + len, "Limited "); - len += sprintf(page + len, "\n"); - - len += sprintf(page + len, "LPAR Name: %-8.8s\n", - info->name); - - len += sprintf(page + len, "LPAR Adjustment: %d\n", - info->caf); - - len += sprintf(page + len, "LPAR CPUs Total: %d\n", - info->cpus_total); - len += sprintf(page + len, "LPAR CPUs Configured: %d\n", - info->cpus_configured); - len += sprintf(page + len, "LPAR CPUs Standby: %d\n", - info->cpus_standby); - len += sprintf(page + len, "LPAR CPUs Reserved: %d\n", - info->cpus_reserved); - len += sprintf(page + len, "LPAR CPUs Dedicated: %d\n", - info->cpus_dedicated); - len += sprintf(page + len, "LPAR CPUs Shared: %d\n", - info->cpus_shared); - return len; -} - -static int stsi_3_2_2(struct sysinfo_3_2_2 *info, char *page, int len) -{ - int i; - - if (stsi(info, 3, 2, 2) == -ENOSYS) - return len; - for (i = 0; i < info->count; i++) { - EBCASC (info->vm[i].name, sizeof(info->vm[i].name)); - EBCASC (info->vm[i].cpi, sizeof(info->vm[i].cpi)); - len += sprintf(page + len, "\n"); - len += sprintf(page + len, "VM%02d Name: %-8.8s\n", - i, info->vm[i].name); - len += sprintf(page + len, "VM%02d Control Program: %-16.16s\n", - i, info->vm[i].cpi); - - len += sprintf(page + len, "VM%02d Adjustment: %d\n", - i, info->vm[i].caf); - - len += sprintf(page + len, "VM%02d CPUs Total: %d\n", - i, info->vm[i].cpus_total); - len += sprintf(page + len, "VM%02d CPUs Configured: %d\n", - i, info->vm[i].cpus_configured); - len += sprintf(page + len, "VM%02d CPUs Standby: %d\n", - i, info->vm[i].cpus_standby); - len += sprintf(page + len, "VM%02d CPUs Reserved: %d\n", - i, info->vm[i].cpus_reserved); - } - return len; -} - - -static int proc_read_sysinfo(char *page, char **start, - off_t off, int count, - int *eof, void *data) -{ - unsigned long info = get_zeroed_page (GFP_KERNEL); - int level, len; - - if (!info) - return 0; - - len = 0; - level = stsi_0(); - if (level >= 1) - len = stsi_1_1_1((struct sysinfo_1_1_1 *) info, page, len); - - if (level >= 1) - len = stsi_1_2_2((struct sysinfo_1_2_2 *) info, page, len); - - if (level >= 2) - len = stsi_2_2_2((struct sysinfo_2_2_2 *) info, page, len); - - if (level >= 3) - len = stsi_3_2_2((struct sysinfo_3_2_2 *) info, page, len); - - free_page (info); - return len; -} - -static __init int create_proc_sysinfo(void) -{ - create_proc_read_entry("sysinfo", 0444, NULL, - proc_read_sysinfo, NULL); - return 0; -} - -__initcall(create_proc_sysinfo); - -/* - * Service levels interface. - */ - -static DECLARE_RWSEM(service_level_sem); -static LIST_HEAD(service_level_list); - -int register_service_level(struct service_level *slr) -{ - struct service_level *ptr; - - down_write(&service_level_sem); - list_for_each_entry(ptr, &service_level_list, list) - if (ptr == slr) { - up_write(&service_level_sem); - return -EEXIST; - } - list_add_tail(&slr->list, &service_level_list); - up_write(&service_level_sem); - return 0; -} -EXPORT_SYMBOL(register_service_level); - -int unregister_service_level(struct service_level *slr) -{ - struct service_level *ptr, *next; - int rc = -ENOENT; - - down_write(&service_level_sem); - list_for_each_entry_safe(ptr, next, &service_level_list, list) { - if (ptr != slr) - continue; - list_del(&ptr->list); - rc = 0; - break; - } - up_write(&service_level_sem); - return rc; -} -EXPORT_SYMBOL(unregister_service_level); - -static void *service_level_start(struct seq_file *m, loff_t *pos) -{ - down_read(&service_level_sem); - return seq_list_start(&service_level_list, *pos); -} - -static void *service_level_next(struct seq_file *m, void *p, loff_t *pos) -{ - return seq_list_next(p, &service_level_list, pos); -} - -static void service_level_stop(struct seq_file *m, void *p) -{ - up_read(&service_level_sem); -} - -static int service_level_show(struct seq_file *m, void *p) -{ - struct service_level *slr; - - slr = list_entry(p, struct service_level, list); - slr->seq_print(m, slr); - return 0; -} - -static const struct seq_operations service_level_seq_ops = { - .start = service_level_start, - .next = service_level_next, - .stop = service_level_stop, - .show = service_level_show -}; - -static int service_level_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &service_level_seq_ops); -} - -static const struct file_operations service_level_ops = { - .open = service_level_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release -}; - -static void service_level_vm_print(struct seq_file *m, - struct service_level *slr) -{ - char *query_buffer, *str; - - query_buffer = kmalloc(1024, GFP_KERNEL | GFP_DMA); - if (!query_buffer) - return; - cpcmd("QUERY CPLEVEL", query_buffer, 1024, NULL); - str = strchr(query_buffer, '\n'); - if (str) - *str = 0; - seq_printf(m, "VM: %s\n", query_buffer); - kfree(query_buffer); -} - -static struct service_level service_level_vm = { - .seq_print = service_level_vm_print -}; - -static __init int create_proc_service_level(void) -{ - proc_create("service_levels", 0, NULL, &service_level_ops); - if (MACHINE_IS_VM) - register_service_level(&service_level_vm); - return 0; -} - -subsys_initcall(create_proc_service_level); - -/* - * Bogomips calculation based on cpu capability. - */ - -int get_cpu_capability(unsigned int *capability) -{ - struct sysinfo_1_2_2 *info; - int rc; - - info = (void *) get_zeroed_page(GFP_KERNEL); - if (!info) - return -ENOMEM; - rc = stsi(info, 1, 2, 2); - if (rc == -ENOSYS) - goto out; - rc = 0; - *capability = info->capability; -out: - free_page((unsigned long) info); - return rc; -} - -/* - * CPU capability might have changed. Therefore recalculate loops_per_jiffy. - */ -void s390_adjust_jiffies(void) -{ - struct sysinfo_1_2_2 *info; - const unsigned int fmil = 0x4b189680; /* 1e7 as 32-bit float. */ - FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR); - FP_DECL_EX; - unsigned int capability; - - info = (void *) get_zeroed_page(GFP_KERNEL); - if (!info) - return; - - if (stsi(info, 1, 2, 2) != -ENOSYS) { - /* - * Major sigh. The cpu capability encoding is "special". - * If the first 9 bits of info->capability are 0 then it - * is a 32 bit unsigned integer in the range 0 .. 2^23. - * If the first 9 bits are != 0 then it is a 32 bit float. - * In addition a lower value indicates a proportionally - * higher cpu capacity. Bogomips are the other way round. - * To get to a halfway suitable number we divide 1e7 - * by the cpu capability number. Yes, that means a floating - * point division .. math-emu here we come :-) - */ - FP_UNPACK_SP(SA, &fmil); - if ((info->capability >> 23) == 0) - FP_FROM_INT_S(SB, info->capability, 32, int); - else - FP_UNPACK_SP(SB, &info->capability); - FP_DIV_S(SR, SA, SB); - FP_TO_INT_S(capability, SR, 32, 0); - } else - /* - * Really old machine without stsi block for basic - * cpu information. Report 42.0 bogomips. - */ - capability = 42; - loops_per_jiffy = capability * (500000/HZ); - free_page((unsigned long) info); -} - -/* - * calibrate the delay loop - */ -void __cpuinit calibrate_delay(void) -{ - s390_adjust_jiffies(); - /* Print the good old Bogomips line .. */ - printk(KERN_DEBUG "Calibrating delay loop (skipped)... " - "%lu.%02lu BogoMIPS preset\n", loops_per_jiffy/(500000/HZ), - (loops_per_jiffy/(5000/HZ)) % 100); -} -- cgit v1.2.3-70-g09d2 From 082fb301e048e84669234afb80fe27e6fa87efb4 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 26 Mar 2009 15:23:51 +0100 Subject: [S390] delete drivers/s390/ebcdic.c Dead file. Seems to be a leftover from the 2.4->2.5 conversion. The used and uptodate version of this file is in arch/s390/kernel. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- drivers/s390/ebcdic.c | 246 -------------------------------------------------- 1 file changed, 246 deletions(-) delete mode 100644 drivers/s390/ebcdic.c diff --git a/drivers/s390/ebcdic.c b/drivers/s390/ebcdic.c deleted file mode 100644 index 99c98da1547..00000000000 --- a/drivers/s390/ebcdic.c +++ /dev/null @@ -1,246 +0,0 @@ -/* - * arch/s390/kernel/ebcdic.c - * ECBDIC -> ASCII, ASCII -> ECBDIC conversion tables. - * - * S390 version - * Copyright (C) 1998 IBM Corporation - * Author(s): Martin Schwidefsky - */ - -#include - -/* - * ASCII -> EBCDIC - */ -__u8 _ascebc[256] = -{ - /*00 NL SH SX EX ET NQ AK BL */ - 0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F, - /*08 BS HT LF VT FF CR SO SI */ - 0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - /*10 DL D1 D2 D3 D4 NK SN EB */ - 0x10, 0x11, 0x12, 0x13, 0x3C, 0x15, 0x32, 0x26, - /*18 CN EM SB EC FS GS RS US */ - 0x18, 0x19, 0x3F, 0x27, 0x1C, 0x1D, 0x1E, 0x1F, - /*20 SP ! " # $ % & ' */ - 0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D, - /*28 ( ) * + , - . / */ - 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61, - /*30 0 1 2 3 4 5 6 7 */ - 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, - /*38 8 9 : ; < = > ? */ - 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F, - /*40 @ A B C D E F G */ - 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, - /*48 H I J K L M N O */ - 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, - /*50 P Q R S T U V W */ - 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, - /*58 X Y Z [ \ ] ^ _ */ - 0xE7, 0xE8, 0xE9, 0xAD, 0xE0, 0xBD, 0x5F, 0x6D, - /*60 ` a b c d e f g */ - 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, - /*68 h i j k l m n o */ - 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, - /*70 p q r s t u v w */ - 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, - /*78 x y z { | } ~ DL */ - 0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0xFF -}; - -/* - * EBCDIC -> ASCII - */ -__u8 _ebcasc[256] = -{ - /* 0x00 NUL SOH STX ETX *SEL HT *RNL DEL */ - 0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F, - /* 0x08 -GE -SPS -RPT VT FF CR SO SI */ - 0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - /* 0x10 DLE DC1 DC2 DC3 -RES -NL BS -POC - -ENP ->LF */ - 0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07, - /* 0x18 CAN EM -UBS -CU1 -IFS -IGS -IRS -ITB - -IUS */ - 0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - /* 0x20 -DS -SOS FS -WUS -BYP LF ETB ESC - -INP */ - 0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B, - /* 0x28 -SA -SFE -SM -CSP -MFA ENQ ACK BEL - -SW */ - 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07, - /* 0x30 ---- ---- SYN -IR -PP -TRN -NBS EOT */ - 0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04, - /* 0x38 -SBS -IT -RFF -CU3 DC4 NAK ---- SUB */ - 0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A, - /* 0x40 SP RSP ä ---- */ - 0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86, - /* 0x48 . < ( + | */ - 0x87, 0xA4, 0x9B, 0x2E, 0x3C, 0x28, 0x2B, 0x7C, - /* 0x50 & ---- */ - 0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07, - /* 0x58 ß ! $ * ) ; */ - 0x8D, 0xE1, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAA, - /* 0x60 - / ---- Ä ---- ---- ---- */ - 0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F, - /* 0x68 ---- , % _ > ? */ - 0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F, - /* 0x70 ---- ---- ---- ---- ---- ---- ---- */ - 0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - /* 0x78 * ` : # @ ' = " */ - 0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22, - /* 0x80 * a b c d e f g */ - 0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, - /* 0x88 h i ---- ---- ---- */ - 0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1, - /* 0x90 ° j k l m n o p */ - 0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, - /* 0x98 q r ---- ---- */ - 0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07, - /* 0xA0 ~ s t u v w x */ - 0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, - /* 0xA8 y z ---- ---- ---- ---- */ - 0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07, - /* 0xB0 ^ ---- § ---- */ - 0x5E, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC, - /* 0xB8 ---- [ ] ---- ---- ---- ---- */ - 0xAB, 0x07, 0x5B, 0x5D, 0x07, 0x07, 0x07, 0x07, - /* 0xC0 { A B C D E F G */ - 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - /* 0xC8 H I ---- ö ---- */ - 0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07, - /* 0xD0 } J K L M N O P */ - 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, - /* 0xD8 Q R ---- ü */ - 0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98, - /* 0xE0 \ S T U V W X */ - 0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, - /* 0xE8 Y Z ---- Ö ---- ---- ---- */ - 0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07, - /* 0xF0 0 1 2 3 4 5 6 7 */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, - /* 0xF8 8 9 ---- ---- Ü ---- ---- ---- */ - 0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07 -}; - -/* - * EBCDIC (capitals) -> ASCII (small case) - */ -__u8 _ebcasc_reduce_case[256] = -{ - /* 0x00 NUL SOH STX ETX *SEL HT *RNL DEL */ - 0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F, - - /* 0x08 -GE -SPS -RPT VT FF CR SO SI */ - 0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - - /* 0x10 DLE DC1 DC2 DC3 -RES -NL BS -POC - -ENP ->LF */ - 0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07, - - /* 0x18 CAN EM -UBS -CU1 -IFS -IGS -IRS -ITB - -IUS */ - 0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - - /* 0x20 -DS -SOS FS -WUS -BYP LF ETB ESC - -INP */ - 0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B, - - /* 0x28 -SA -SFE -SM -CSP -MFA ENQ ACK BEL - -SW */ - 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07, - - /* 0x30 ---- ---- SYN -IR -PP -TRN -NBS EOT */ - 0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04, - - /* 0x38 -SBS -IT -RFF -CU3 DC4 NAK ---- SUB */ - 0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A, - - /* 0x40 SP RSP ä ---- */ - 0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86, - - /* 0x48 . < ( + | */ - 0x87, 0xA4, 0x9B, 0x2E, 0x3C, 0x28, 0x2B, 0x7C, - - /* 0x50 & ---- */ - 0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07, - - /* 0x58 ß ! $ * ) ; */ - 0x8D, 0xE1, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAA, - - /* 0x60 - / ---- Ä ---- ---- ---- */ - 0x2D, 0x2F, 0x07, 0x84, 0x07, 0x07, 0x07, 0x8F, - - /* 0x68 ---- , % _ > ? */ - 0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F, - - /* 0x70 ---- ---- ---- ---- ---- ---- ---- */ - 0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - - /* 0x78 * ` : # @ ' = " */ - 0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22, - - /* 0x80 * a b c d e f g */ - 0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, - - /* 0x88 h i ---- ---- ---- */ - 0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1, - - /* 0x90 ° j k l m n o p */ - 0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, - - /* 0x98 q r ---- ---- */ - 0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07, - - /* 0xA0 ~ s t u v w x */ - 0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, - - /* 0xA8 y z ---- ---- ---- ---- */ - 0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07, - - /* 0xB0 ^ ---- § ---- */ - 0x5E, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC, - - /* 0xB8 ---- [ ] ---- ---- ---- ---- */ - 0xAB, 0x07, 0x5B, 0x5D, 0x07, 0x07, 0x07, 0x07, - - /* 0xC0 { A B C D E F G */ - 0x7B, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, - - /* 0xC8 H I ---- ö ---- */ - 0x68, 0x69, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07, - - /* 0xD0 } J K L M N O P */ - 0x7D, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, - - /* 0xD8 Q R ---- ü */ - 0x71, 0x72, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98, - - /* 0xE0 \ S T U V W X */ - 0x5C, 0xF6, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, - - /* 0xE8 Y Z ---- Ö ---- ---- ---- */ - 0x79, 0x7A, 0xFD, 0x07, 0x94, 0x07, 0x07, 0x07, - - /* 0xF0 0 1 2 3 4 5 6 7 */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, - - /* 0xF8 8 9 ---- ---- Ü ---- ---- ---- */ - 0x38, 0x39, 0x07, 0x07, 0x81, 0x07, 0x07, 0x07 -}; -- cgit v1.2.3-70-g09d2 From cbdc229245e8cf5c201e68221ebf2f33d2aaf029 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 26 Mar 2009 15:23:52 +0100 Subject: [S390] arch/s390/kernel/process.c: fix whitespace damage Fix all the whitespace damage in process.c, especially copy_thread(). Next patch will add code to copy_thread() which needs to 'fixed' first. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/process.c | 64 +++++++++++++++++++--------------------------- 1 file changed, 27 insertions(+), 37 deletions(-) diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index 5cd38a90e64..e0563baa1cf 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c @@ -1,18 +1,10 @@ /* - * arch/s390/kernel/process.c + * This file handles the architecture dependent parts of process handling. * - * S390 version - * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), - * Hartmut Penner (hp@de.ibm.com), - * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com), - * - * Derived from "arch/i386/kernel/process.c" - * Copyright (C) 1995, Linus Torvalds - */ - -/* - * This file handles the architecture-dependent parts of process handling.. + * Copyright IBM Corp. 1999,2009 + * Author(s): Martin Schwidefsky , + * Hartmut Penner , + * Denis Joseph Barrow, */ #include @@ -168,34 +160,34 @@ void release_thread(struct task_struct *dead_task) } int copy_thread(int nr, unsigned long clone_flags, unsigned long new_stackp, - unsigned long unused, - struct task_struct * p, struct pt_regs * regs) + unsigned long unused, + struct task_struct *p, struct pt_regs *regs) { - struct fake_frame - { - struct stack_frame sf; - struct pt_regs childregs; - } *frame; - - frame = container_of(task_pt_regs(p), struct fake_frame, childregs); - p->thread.ksp = (unsigned long) frame; + struct fake_frame + { + struct stack_frame sf; + struct pt_regs childregs; + } *frame; + + frame = container_of(task_pt_regs(p), struct fake_frame, childregs); + p->thread.ksp = (unsigned long) frame; /* Store access registers to kernel stack of new process. */ - frame->childregs = *regs; + frame->childregs = *regs; frame->childregs.gprs[2] = 0; /* child returns 0 on fork. */ - frame->childregs.gprs[15] = new_stackp; - frame->sf.back_chain = 0; + frame->childregs.gprs[15] = new_stackp; + frame->sf.back_chain = 0; - /* new return point is ret_from_fork */ - frame->sf.gprs[8] = (unsigned long) ret_from_fork; + /* new return point is ret_from_fork */ + frame->sf.gprs[8] = (unsigned long) ret_from_fork; - /* fake return stack for resume(), don't go back to schedule */ - frame->sf.gprs[9] = (unsigned long) frame; + /* fake return stack for resume(), don't go back to schedule */ + frame->sf.gprs[9] = (unsigned long) frame; /* Save access registers to new thread structure. */ save_access_regs(&p->thread.acrs[0]); #ifndef CONFIG_64BIT - /* + /* * save fprs to current->thread.fp_regs to merge them with * the emulated registers and then copy the result to the child. */ @@ -220,10 +212,9 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long new_stackp, #endif /* CONFIG_64BIT */ /* start new process with ar4 pointing to the correct address space */ p->thread.mm_segment = get_fs(); - /* Don't copy debug registers */ - memset(&p->thread.per_info,0,sizeof(p->thread.per_info)); - - return 0; + /* Don't copy debug registers */ + memset(&p->thread.per_info, 0, sizeof(p->thread.per_info)); + return 0; } SYSCALL_DEFINE0(fork) @@ -311,7 +302,7 @@ out: int dump_fpu (struct pt_regs * regs, s390_fp_regs *fpregs) { #ifndef CONFIG_64BIT - /* + /* * save fprs to current->thread.fp_regs to merge them with * the emulated registers and then copy the result to the dump. */ @@ -346,4 +337,3 @@ unsigned long get_wchan(struct task_struct *p) } return 0; } - -- cgit v1.2.3-70-g09d2 From 5168ce2c647f02756803bef7b74906f485491a1c Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 26 Mar 2009 15:23:53 +0100 Subject: [S390] cputime: initialize per thread timer values on fork Initialize per thread timer values instead of just copying them from the parent. That way it is easily possible to tell how much time a thread spent in user/system context. Doesn't fix a bug, this is just for debugging purposes. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/process.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index e0563baa1cf..e6b480625cb 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c @@ -163,6 +163,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long new_stackp, unsigned long unused, struct task_struct *p, struct pt_regs *regs) { + struct thread_info *ti; struct fake_frame { struct stack_frame sf; @@ -214,6 +215,10 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long new_stackp, p->thread.mm_segment = get_fs(); /* Don't copy debug registers */ memset(&p->thread.per_info, 0, sizeof(p->thread.per_info)); + /* Initialize per thread user and system timer values */ + ti = task_thread_info(p); + ti->user_timer = 0; + ti->system_timer = 0; return 0; } -- cgit v1.2.3-70-g09d2 From 82f3a79bc6b50ab82744ebc32efba31c78dbccf7 Mon Sep 17 00:00:00 2001 From: Hendrik Brueckner Date: Thu, 26 Mar 2009 15:23:54 +0100 Subject: [S390] hvc_iucv: Update and add missing kernel messages If the hvc_iucv= kernel parameter specifies a value that is not valid, display an error message. Minor changes to existing kernel messages. Signed-off-by: Hendrik Brueckner Signed-off-by: Martin Schwidefsky --- drivers/char/hvc_iucv.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/char/hvc_iucv.c b/drivers/char/hvc_iucv.c index a53496828b7..146be5a6094 100644 --- a/drivers/char/hvc_iucv.c +++ b/drivers/char/hvc_iucv.c @@ -885,7 +885,7 @@ static int __init hvc_iucv_init(void) unsigned int i; if (!MACHINE_IS_VM) { - pr_info("The z/VM IUCV HVC device driver cannot " + pr_notice("The z/VM IUCV HVC device driver cannot " "be used without z/VM\n"); return -ENODEV; } @@ -893,8 +893,11 @@ static int __init hvc_iucv_init(void) if (!hvc_iucv_devices) return -ENODEV; - if (hvc_iucv_devices > MAX_HVC_IUCV_LINES) + if (hvc_iucv_devices > MAX_HVC_IUCV_LINES) { + pr_err("%lu is not a valid value for the hvc_iucv= " + "kernel parameter\n", hvc_iucv_devices); return -EINVAL; + } hvc_iucv_buffer_cache = kmem_cache_create(KMSG_COMPONENT, sizeof(struct iucv_tty_buffer), -- cgit v1.2.3-70-g09d2 From 431429ff788598a19c1a193b9fca3961b7f55916 Mon Sep 17 00:00:00 2001 From: Hendrik Brueckner Date: Thu, 26 Mar 2009 15:23:55 +0100 Subject: [S390] hvc_iucv: Provide IUCV z/VM user ID filtering This patch introduces the kernel parameter hvc_iucv_allow= that specifies a comma-separated list of z/VM user IDs. If specified, the z/VM IUCV hypervisor console device driver accepts IUCV connections from listed z/VM user IDs only. Signed-off-by: Hendrik Brueckner Signed-off-by: Martin Schwidefsky --- Documentation/kernel-parameters.txt | 3 + drivers/char/hvc_iucv.c | 254 ++++++++++++++++++++++++++++++++++-- 2 files changed, 249 insertions(+), 8 deletions(-) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 54f21a5c262..9f932a76a94 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -829,6 +829,9 @@ and is between 256 and 4096 characters. It is defined in the file hvc_iucv= [S390] Number of z/VM IUCV hypervisor console (HVC) terminal devices. Valid values: 0..8 + hvc_iucv_allow= [S390] Comma-separated list of z/VM user IDs. + If specified, z/VM IUCV HVC accepts connections + from listed z/VM user IDs only. i8042.debug [HW] Toggle i8042 debug mode i8042.direct [HW] Put keyboard port into non-translated mode diff --git a/drivers/char/hvc_iucv.c b/drivers/char/hvc_iucv.c index 146be5a6094..54481a88776 100644 --- a/drivers/char/hvc_iucv.c +++ b/drivers/char/hvc_iucv.c @@ -13,10 +13,11 @@ #include #include +#include #include #include #include -#include +#include #include #include #include @@ -95,6 +96,12 @@ static unsigned long hvc_iucv_devices = 1; /* Array of allocated hvc iucv tty lines... */ static struct hvc_iucv_private *hvc_iucv_table[MAX_HVC_IUCV_LINES]; #define IUCV_HVC_CON_IDX (0) +/* List of z/VM user ID filter entries (struct iucv_vmid_filter) */ +#define MAX_VMID_FILTER (500) +static size_t hvc_iucv_filter_size; +static void *hvc_iucv_filter; +static const char *hvc_iucv_filter_string; +static DEFINE_RWLOCK(hvc_iucv_filter_lock); /* Kmem cache and mempool for iucv_tty_buffer elements */ static struct kmem_cache *hvc_iucv_buffer_cache; @@ -617,6 +624,27 @@ static void hvc_iucv_notifier_del(struct hvc_struct *hp, int id) } } +/** + * hvc_iucv_filter_connreq() - Filter connection request based on z/VM user ID + * @ipvmid: Originating z/VM user ID (right padded with blanks) + * + * Returns 0 if the z/VM user ID @ipvmid is allowed to connection, otherwise + * non-zero. + */ +static int hvc_iucv_filter_connreq(u8 ipvmid[8]) +{ + size_t i; + + /* Note: default policy is ACCEPT if no filter is set */ + if (!hvc_iucv_filter_size) + return 0; + + for (i = 0; i < hvc_iucv_filter_size; i++) + if (0 == memcmp(ipvmid, hvc_iucv_filter + (8 * i), 8)) + return 0; + return 1; +} + /** * hvc_iucv_path_pending() - IUCV handler to process a connection request. * @path: Pending path (struct iucv_path) @@ -641,6 +669,7 @@ static int hvc_iucv_path_pending(struct iucv_path *path, { struct hvc_iucv_private *priv; u8 nuser_data[16]; + u8 vm_user_id[9]; int i, rc; priv = NULL; @@ -653,6 +682,20 @@ static int hvc_iucv_path_pending(struct iucv_path *path, if (!priv) return -ENODEV; + /* Enforce that ipvmid is allowed to connect to us */ + read_lock(&hvc_iucv_filter_lock); + rc = hvc_iucv_filter_connreq(ipvmid); + read_unlock(&hvc_iucv_filter_lock); + if (rc) { + iucv_path_sever(path, ipuser); + iucv_path_free(path); + memcpy(vm_user_id, ipvmid, 8); + vm_user_id[8] = 0; + pr_info("A connection request from z/VM user ID %s " + "was refused\n", vm_user_id); + return 0; + } + spin_lock(&priv->lock); /* If the terminal is already connected or being severed, then sever @@ -876,6 +919,171 @@ static int __init hvc_iucv_alloc(int id, unsigned int is_console) return 0; } +/** + * hvc_iucv_parse_filter() - Parse filter for a single z/VM user ID + * @filter: String containing a comma-separated list of z/VM user IDs + */ +static const char *hvc_iucv_parse_filter(const char *filter, char *dest) +{ + const char *nextdelim, *residual; + size_t len; + + nextdelim = strchr(filter, ','); + if (nextdelim) { + len = nextdelim - filter; + residual = nextdelim + 1; + } else { + len = strlen(filter); + residual = filter + len; + } + + if (len == 0) + return ERR_PTR(-EINVAL); + + /* check for '\n' (if called from sysfs) */ + if (filter[len - 1] == '\n') + len--; + + if (len > 8) + return ERR_PTR(-EINVAL); + + /* pad with blanks and save upper case version of user ID */ + memset(dest, ' ', 8); + while (len--) + dest[len] = toupper(filter[len]); + return residual; +} + +/** + * hvc_iucv_setup_filter() - Set up z/VM user ID filter + * @filter: String consisting of a comma-separated list of z/VM user IDs + * + * The function parses the @filter string and creates an array containing + * the list of z/VM user ID filter entries. + * Return code 0 means success, -EINVAL if the filter is syntactically + * incorrect, -ENOMEM if there was not enough memory to allocate the + * filter list array, or -ENOSPC if too many z/VM user IDs have been specified. + */ +static int hvc_iucv_setup_filter(const char *val) +{ + const char *residual; + int err; + size_t size, count; + void *array, *old_filter; + + count = strlen(val); + if (count == 0 || (count == 1 && val[0] == '\n')) { + size = 0; + array = NULL; + goto out_replace_filter; /* clear filter */ + } + + /* count user IDs in order to allocate sufficient memory */ + size = 1; + residual = val; + while ((residual = strchr(residual, ',')) != NULL) { + residual++; + size++; + } + + /* check if the specified list exceeds the filter limit */ + if (size > MAX_VMID_FILTER) + return -ENOSPC; + + array = kzalloc(size * 8, GFP_KERNEL); + if (!array) + return -ENOMEM; + + count = size; + residual = val; + while (*residual && count) { + residual = hvc_iucv_parse_filter(residual, + array + ((size - count) * 8)); + if (IS_ERR(residual)) { + err = PTR_ERR(residual); + kfree(array); + goto out_err; + } + count--; + } + +out_replace_filter: + write_lock_bh(&hvc_iucv_filter_lock); + old_filter = hvc_iucv_filter; + hvc_iucv_filter_size = size; + hvc_iucv_filter = array; + write_unlock_bh(&hvc_iucv_filter_lock); + kfree(old_filter); + + err = 0; +out_err: + return err; +} + +/** + * param_set_vmidfilter() - Set z/VM user ID filter parameter + * @val: String consisting of a comma-separated list of z/VM user IDs + * @kp: Kernel parameter pointing to hvc_iucv_filter array + * + * The function sets up the z/VM user ID filter specified as comma-separated + * list of user IDs in @val. + * Note: If it is called early in the boot process, @val is stored and + * parsed later in hvc_iucv_init(). + */ +static int param_set_vmidfilter(const char *val, struct kernel_param *kp) +{ + int rc; + + if (!MACHINE_IS_VM || !hvc_iucv_devices) + return -ENODEV; + + if (!val) + return -EINVAL; + + rc = 0; + if (slab_is_available()) + rc = hvc_iucv_setup_filter(val); + else + hvc_iucv_filter_string = val; /* defer... */ + return rc; +} + +/** + * param_get_vmidfilter() - Get z/VM user ID filter + * @buffer: Buffer to store z/VM user ID filter, + * (buffer size assumption PAGE_SIZE) + * @kp: Kernel parameter pointing to the hvc_iucv_filter array + * + * The function stores the filter as a comma-separated list of z/VM user IDs + * in @buffer. Typically, sysfs routines call this function for attr show. + */ +static int param_get_vmidfilter(char *buffer, struct kernel_param *kp) +{ + int rc; + size_t index, len; + void *start, *end; + + if (!MACHINE_IS_VM || !hvc_iucv_devices) + return -ENODEV; + + rc = 0; + read_lock_bh(&hvc_iucv_filter_lock); + for (index = 0; index < hvc_iucv_filter_size; index++) { + start = hvc_iucv_filter + (8 * index); + end = memchr(start, ' ', 8); + len = (end) ? end - start : 8; + memcpy(buffer + rc, start, len); + rc += len; + buffer[rc++] = ','; + } + read_unlock_bh(&hvc_iucv_filter_lock); + if (rc) + buffer[--rc] = '\0'; /* replace last comma and update rc */ + return rc; +} + +#define param_check_vmidfilter(name, p) __param_check(name, p, void) + /** * hvc_iucv_init() - z/VM IUCV HVC device driver initialization */ @@ -884,19 +1092,44 @@ static int __init hvc_iucv_init(void) int rc; unsigned int i; + if (!hvc_iucv_devices) + return -ENODEV; + if (!MACHINE_IS_VM) { pr_notice("The z/VM IUCV HVC device driver cannot " "be used without z/VM\n"); - return -ENODEV; + rc = -ENODEV; + goto out_error; } - if (!hvc_iucv_devices) - return -ENODEV; - if (hvc_iucv_devices > MAX_HVC_IUCV_LINES) { pr_err("%lu is not a valid value for the hvc_iucv= " "kernel parameter\n", hvc_iucv_devices); - return -EINVAL; + rc = -EINVAL; + goto out_error; + } + + /* parse hvc_iucv_allow string and create z/VM user ID filter list */ + if (hvc_iucv_filter_string) { + rc = hvc_iucv_setup_filter(hvc_iucv_filter_string); + switch (rc) { + case 0: + break; + case -ENOMEM: + pr_err("Allocating memory failed with " + "reason code=%d\n", 3); + goto out_error; + case -EINVAL: + pr_err("hvc_iucv_allow= does not specify a valid " + "z/VM user ID list\n"); + goto out_error; + case -ENOSPC: + pr_err("hvc_iucv_allow= specifies too many " + "z/VM user IDs\n"); + goto out_error; + default: + goto out_error; + } } hvc_iucv_buffer_cache = kmem_cache_create(KMSG_COMPONENT, @@ -904,7 +1137,8 @@ static int __init hvc_iucv_init(void) 0, 0, NULL); if (!hvc_iucv_buffer_cache) { pr_err("Allocating memory failed with reason code=%d\n", 1); - return -ENOMEM; + rc = -ENOMEM; + goto out_error; } hvc_iucv_mempool = mempool_create_slab_pool(MEMPOOL_MIN_NR, @@ -912,7 +1146,8 @@ static int __init hvc_iucv_init(void) if (!hvc_iucv_mempool) { pr_err("Allocating memory failed with reason code=%d\n", 2); kmem_cache_destroy(hvc_iucv_buffer_cache); - return -ENOMEM; + rc = -ENOMEM; + goto out_error; } /* register the first terminal device as console @@ -956,6 +1191,8 @@ out_error_hvc: out_error_memory: mempool_destroy(hvc_iucv_mempool); kmem_cache_destroy(hvc_iucv_buffer_cache); +out_error: + hvc_iucv_devices = 0; /* ensure that we do not provide any device */ return rc; } @@ -971,3 +1208,4 @@ static int __init hvc_iucv_config(char *val) device_initcall(hvc_iucv_init); __setup("hvc_iucv=", hvc_iucv_config); +core_param(hvc_iucv_allow, hvc_iucv_filter, vmidfilter, 0640); -- cgit v1.2.3-70-g09d2 From 3324e60aafa9aeb1009878d45079b67367a5e2b6 Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Thu, 26 Mar 2009 15:23:56 +0100 Subject: [S390] lockdep: trace hardirq off in smp_send_stop With lockdep we got the following trace after a panic: Badness at /home/autobuild/BUILD/linux-2.6.28-20090204/kernel/lockdep.c:2878 [...] Call Trace: [<0000000000176334>] lock_acquire+0x54/0xbc [<000000000050b4fe>] __atomic_notifier_call_chain+0x6e/0xdc [<000000000050b59c>] atomic_notifier_call_chain+0x30/0x44 [<0000000000504274>] panic+0xd0/0x1e8 [...] INFO: lockdep is turned off. Last Breaking-Event-Address: [<0000000000170e62>] check_flags+0xae/0x15c possible reason: unannotated irqs-off. lockdep is right. We missed a trace_hardirq_off in our smp_send_stop function and smp_send_stop is called before the panic call chain. Reported-by: Mijo Signed-off-by: Christian Borntraeger Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/smp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index e279d0fbbbe..a8858634dd0 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -75,6 +76,7 @@ void smp_send_stop(void) /* Disable all interrupts/machine checks */ __load_psw_mask(psw_kernel_bits & ~PSW_MASK_MCHECK); + trace_hardirqs_off(); /* stop all processors */ for_each_online_cpu(cpu) { -- cgit v1.2.3-70-g09d2 From 702d9e584feb028ed7e2a6d2b103b8ea57622ff2 Mon Sep 17 00:00:00 2001 From: Carsten Otte Date: Thu, 26 Mar 2009 15:23:57 +0100 Subject: [S390] check addressing mode in s390_enable_sie The sie instruction requires address spaces to be switched to run proper. This patch verifies that this is the case in s390_enable_sie, otherwise the kernel would crash badly as soon as the process runs into sie. Signed-off-by: Carsten Otte Signed-off-by: Martin Schwidefsky --- arch/s390/mm/pgtable.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c index 6b6ddc4ea02..9bf86125f6f 100644 --- a/arch/s390/mm/pgtable.c +++ b/arch/s390/mm/pgtable.c @@ -258,6 +258,10 @@ int s390_enable_sie(void) struct task_struct *tsk = current; struct mm_struct *mm, *old_mm; + /* Do we have switched amode? If no, we cannot do sie */ + if (!switch_amode) + return -EINVAL; + /* Do we have pgstes? if yes, we are done */ if (tsk->mm->context.has_pgste) return 0; -- cgit v1.2.3-70-g09d2 From 92e6ecf392fac3082653ac9d84b1bdf53d0ea160 Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Thu, 26 Mar 2009 15:23:58 +0100 Subject: [S390] Fix hypervisor detection for KVM Currently we use the cpuid (via STIDP instruction) to recognize LPAR, z/VM and KVM. The architecture states, that bit 0-7 of STIDP returns all zero, and if STIDP is executed in a virtual machine, the VM operating system will replace bits 0-7 with FF. KVM should not use FE to distinguish z/VM from KVM for interested guests. The proper way to detect the hypervisor is the STSI (Store System Information) instruction, which return information about the hypervisors via function code 3, selector1=2, selector2=2. This patch changes the detection routine of Linux to use STSI instead of STIDP. This detection is earlier than bootmem, we have to use a static buffer. Since STSI expects a 4kb block (4kb aligned) this patch also changes the init.data alignment for s390. As this section will be freed during boot, this should be no problem. Patch is tested with LPAR, z/VM, KVM on LPAR, and KVM under z/VM. Signed-off-by: Christian Borntraeger Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/sysinfo.h | 1 + arch/s390/kernel/early.c | 22 +++++++++++++--------- arch/s390/kernel/vmlinux.lds.S | 2 ++ arch/s390/kvm/kvm-s390.c | 2 +- 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/arch/s390/include/asm/sysinfo.h b/arch/s390/include/asm/sysinfo.h index ad93212d9e1..9d70057d828 100644 --- a/arch/s390/include/asm/sysinfo.h +++ b/arch/s390/include/asm/sysinfo.h @@ -100,6 +100,7 @@ struct sysinfo_3_2_2 { char reserved_1[24]; } vm[8]; + char reserved_544[3552]; }; static inline int stsi(void *sysinfo, int fc, int sel1, int sel2) diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index 2a2ca268b1d..d61eb3334ed 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c @@ -6,6 +6,7 @@ * Heiko Carstens */ +#include #include #include #include @@ -20,6 +21,7 @@ #include #include #include +#include #include #include #include "entry.h" @@ -173,19 +175,21 @@ static noinline __init void init_kernel_storage_key(void) page_set_storage_key(init_pfn << PAGE_SHIFT, PAGE_DEFAULT_KEY); } +static __initdata struct sysinfo_3_2_2 vmms __aligned(PAGE_SIZE); + static noinline __init void detect_machine_type(void) { - struct cpuinfo_S390 *cpuinfo = &S390_lowcore.cpu_data; - - get_cpu_id(&S390_lowcore.cpu_data.cpu_id); - - /* Running under z/VM ? */ - if (cpuinfo->cpu_id.version == 0xff) - machine_flags |= MACHINE_FLAG_VM; + /* No VM information? Looks like LPAR */ + if (stsi(&vmms, 3, 2, 2) == -ENOSYS) + return; + if (!vmms.count) + return; - /* Running under KVM ? */ - if (cpuinfo->cpu_id.version == 0xfe) + /* Running under KVM? If not we assume z/VM */ + if (!memcmp(vmms.vm[0].cpi, "\xd2\xe5\xd4", 3)) machine_flags |= MACHINE_FLAG_KVM; + else + machine_flags |= MACHINE_FLAG_VM; } static __init void early_pgm_check_handler(void) diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S index d796d05c9c0..7a2063eb88f 100644 --- a/arch/s390/kernel/vmlinux.lds.S +++ b/arch/s390/kernel/vmlinux.lds.S @@ -108,6 +108,8 @@ SECTIONS EXIT_TEXT } + /* early.c uses stsi, which requires page aligned data. */ + . = ALIGN(PAGE_SIZE); .init.data : { INIT_DATA } diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 0d33893e1e8..c55a4b9ffd8 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -286,7 +286,7 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu) setup_timer(&vcpu->arch.ckc_timer, kvm_s390_idle_wakeup, (unsigned long) vcpu); get_cpu_id(&vcpu->arch.cpu_id); - vcpu->arch.cpu_id.version = 0xfe; + vcpu->arch.cpu_id.version = 0xff; return 0; } -- cgit v1.2.3-70-g09d2 From cc54c1e66e4b90ab657464fec30e6970636ee23d Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 26 Mar 2009 15:23:59 +0100 Subject: [S390] ftrace: dont trace machine check handler The ftrace code is currently not reentrant, so we better don't trace our machine check handler. Machine checks are handled like NMIs on s390. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- drivers/s390/s390mach.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/s390/s390mach.c b/drivers/s390/s390mach.c index 92b0417f8e1..8e437052e07 100644 --- a/drivers/s390/s390mach.c +++ b/drivers/s390/s390mach.c @@ -357,8 +357,7 @@ s390_revalidate_registers(struct mci *mci) /* * machine check handler. */ -void -s390_do_machine_check(struct pt_regs *regs) +void notrace s390_do_machine_check(struct pt_regs *regs) { static DEFINE_SPINLOCK(ipd_lock); static unsigned long long last_ipd; -- cgit v1.2.3-70-g09d2 From 70193af9188113c9b4ff3dde1aed9f9c8f7c4f93 Mon Sep 17 00:00:00 2001 From: Sachin Sant Date: Thu, 26 Mar 2009 15:24:00 +0100 Subject: [S390] Fix appldata build break with !NET With CONFIG_NET not set appldata build breaks on s390. arch/s390/appldata/built-in.o: In function appldata_get_net_sum_data: appldata_net_sum.c:(.text+0x2684): undefined reference to dev_get_stats appldata_net_sum.c:(.text+0x2688): undefined reference to init_net appldata_net_sum.c:(.text+0x268c): undefined reference to init_net appldata_net_sum.c:(.text+0x2694): undefined reference to dev_base_lock The following patch fixes the issue for me. Signed-off-by: Sachin Sant Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 6b0a3538dc6..3f470604a89 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -521,7 +521,7 @@ config APPLDATA_OS config APPLDATA_NET_SUM tristate "Monitor overall network statistics" - depends on APPLDATA_BASE + depends on APPLDATA_BASE && NET help This provides network related data to the Linux - VM Monitor Stream, currently there is only a total sum of network I/O statistics, no -- cgit v1.2.3-70-g09d2 From f5daba1d4116d964435ddd99f32b6c80448a496b Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 26 Mar 2009 15:24:01 +0100 Subject: [S390] split/move machine check handler code Split machine check handler code and move it to cio and kernel code where it belongs to. No functional change. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/crw.h | 68 ++++++ arch/s390/include/asm/nmi.h | 66 ++++++ arch/s390/kernel/Makefile | 2 +- arch/s390/kernel/nmi.c | 383 +++++++++++++++++++++++++++++++ arch/s390/kernel/process.c | 2 +- arch/s390/kvm/kvm-s390.c | 4 +- drivers/s390/Makefile | 1 - drivers/s390/cio/Makefile | 2 +- drivers/s390/cio/chp.c | 6 +- drivers/s390/cio/chsc.c | 6 +- drivers/s390/cio/cio.c | 3 +- drivers/s390/cio/crw.c | 145 ++++++++++++ drivers/s390/cio/css.c | 6 +- drivers/s390/s390mach.c | 537 -------------------------------------------- drivers/s390/s390mach.h | 122 ---------- 15 files changed, 677 insertions(+), 676 deletions(-) create mode 100644 arch/s390/include/asm/crw.h create mode 100644 arch/s390/include/asm/nmi.h create mode 100644 arch/s390/kernel/nmi.c create mode 100644 drivers/s390/cio/crw.c delete mode 100644 drivers/s390/s390mach.c delete mode 100644 drivers/s390/s390mach.h diff --git a/arch/s390/include/asm/crw.h b/arch/s390/include/asm/crw.h new file mode 100644 index 00000000000..2185a6d619d --- /dev/null +++ b/arch/s390/include/asm/crw.h @@ -0,0 +1,68 @@ +/* + * Data definitions for channel report processing + * Copyright IBM Corp. 2000,2009 + * Author(s): Ingo Adlung , + * Martin Schwidefsky , + * Cornelia Huck , + * Heiko Carstens , + */ + +#ifndef _ASM_S390_CRW_H +#define _ASM_S390_CRW_H + +#include + +/* + * Channel Report Word + */ +struct crw { + __u32 res1 : 1; /* reserved zero */ + __u32 slct : 1; /* solicited */ + __u32 oflw : 1; /* overflow */ + __u32 chn : 1; /* chained */ + __u32 rsc : 4; /* reporting source code */ + __u32 anc : 1; /* ancillary report */ + __u32 res2 : 1; /* reserved zero */ + __u32 erc : 6; /* error-recovery code */ + __u32 rsid : 16; /* reporting-source ID */ +} __attribute__ ((packed)); + +typedef void (*crw_handler_t)(struct crw *, struct crw *, int); + +extern int crw_register_handler(int rsc, crw_handler_t handler); +extern void crw_unregister_handler(int rsc); +extern void crw_handle_channel_report(void); + +#define NR_RSCS 16 + +#define CRW_RSC_MONITOR 0x2 /* monitoring facility */ +#define CRW_RSC_SCH 0x3 /* subchannel */ +#define CRW_RSC_CPATH 0x4 /* channel path */ +#define CRW_RSC_CONFIG 0x9 /* configuration-alert facility */ +#define CRW_RSC_CSS 0xB /* channel subsystem */ + +#define CRW_ERC_EVENT 0x00 /* event information pending */ +#define CRW_ERC_AVAIL 0x01 /* available */ +#define CRW_ERC_INIT 0x02 /* initialized */ +#define CRW_ERC_TERROR 0x03 /* temporary error */ +#define CRW_ERC_IPARM 0x04 /* installed parm initialized */ +#define CRW_ERC_TERM 0x05 /* terminal */ +#define CRW_ERC_PERRN 0x06 /* perm. error, fac. not init */ +#define CRW_ERC_PERRI 0x07 /* perm. error, facility init */ +#define CRW_ERC_PMOD 0x08 /* installed parameters modified */ + +static inline int stcrw(struct crw *pcrw) +{ + int ccode; + + asm volatile( + " stcrw 0(%2)\n" + " ipm %0\n" + " srl %0,28\n" + : "=d" (ccode), "=m" (*pcrw) + : "a" (pcrw) + : "cc" ); + return ccode; +} + +#endif /* _ASM_S390_CRW_H */ diff --git a/arch/s390/include/asm/nmi.h b/arch/s390/include/asm/nmi.h new file mode 100644 index 00000000000..f4b60441adc --- /dev/null +++ b/arch/s390/include/asm/nmi.h @@ -0,0 +1,66 @@ +/* + * Machine check handler definitions + * + * Copyright IBM Corp. 2000,2009 + * Author(s): Ingo Adlung , + * Martin Schwidefsky , + * Cornelia Huck , + * Heiko Carstens , + */ + +#ifndef _ASM_S390_NMI_H +#define _ASM_S390_NMI_H + +#include + +struct mci { + __u32 sd : 1; /* 00 system damage */ + __u32 pd : 1; /* 01 instruction-processing damage */ + __u32 sr : 1; /* 02 system recovery */ + __u32 : 1; /* 03 */ + __u32 cd : 1; /* 04 timing-facility damage */ + __u32 ed : 1; /* 05 external damage */ + __u32 : 1; /* 06 */ + __u32 dg : 1; /* 07 degradation */ + __u32 w : 1; /* 08 warning pending */ + __u32 cp : 1; /* 09 channel-report pending */ + __u32 sp : 1; /* 10 service-processor damage */ + __u32 ck : 1; /* 11 channel-subsystem damage */ + __u32 : 2; /* 12-13 */ + __u32 b : 1; /* 14 backed up */ + __u32 : 1; /* 15 */ + __u32 se : 1; /* 16 storage error uncorrected */ + __u32 sc : 1; /* 17 storage error corrected */ + __u32 ke : 1; /* 18 storage-key error uncorrected */ + __u32 ds : 1; /* 19 storage degradation */ + __u32 wp : 1; /* 20 psw mwp validity */ + __u32 ms : 1; /* 21 psw mask and key validity */ + __u32 pm : 1; /* 22 psw program mask and cc validity */ + __u32 ia : 1; /* 23 psw instruction address validity */ + __u32 fa : 1; /* 24 failing storage address validity */ + __u32 : 1; /* 25 */ + __u32 ec : 1; /* 26 external damage code validity */ + __u32 fp : 1; /* 27 floating point register validity */ + __u32 gr : 1; /* 28 general register validity */ + __u32 cr : 1; /* 29 control register validity */ + __u32 : 1; /* 30 */ + __u32 st : 1; /* 31 storage logical validity */ + __u32 ie : 1; /* 32 indirect storage error */ + __u32 ar : 1; /* 33 access register validity */ + __u32 da : 1; /* 34 delayed access exception */ + __u32 : 7; /* 35-41 */ + __u32 pr : 1; /* 42 tod programmable register validity */ + __u32 fc : 1; /* 43 fp control register validity */ + __u32 ap : 1; /* 44 ancillary report */ + __u32 : 1; /* 45 */ + __u32 ct : 1; /* 46 cpu timer validity */ + __u32 cc : 1; /* 47 clock comparator validity */ + __u32 : 16; /* 47-63 */ +}; + +struct pt_regs; + +extern void s390_handle_mcck(void); +extern void s390_do_machine_check(struct pt_regs *regs); + +#endif /* _ASM_S390_NMI_H */ diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index 33e7aee7051..228e3105ded 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile @@ -22,7 +22,7 @@ CFLAGS_sysinfo.o += -Iinclude/math-emu -Iarch/s390/math-emu -w obj-y := bitmap.o traps.o time.o process.o base.o early.o setup.o \ processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \ s390_ext.o debug.o irq.o ipl.o dis.o diag.o mem_detect.o \ - vdso.o vtime.o sysinfo.o + vdso.o vtime.o sysinfo.o nmi.o obj-y += $(if $(CONFIG_64BIT),entry64.o,entry.o) obj-y += $(if $(CONFIG_64BIT),reipl64.o,reipl.o) diff --git a/arch/s390/kernel/nmi.c b/arch/s390/kernel/nmi.c new file mode 100644 index 00000000000..8d50eaf76a6 --- /dev/null +++ b/arch/s390/kernel/nmi.c @@ -0,0 +1,383 @@ +/* + * Machine check handler + * + * Copyright IBM Corp. 2000,2009 + * Author(s): Ingo Adlung , + * Martin Schwidefsky , + * Cornelia Huck , + * Heiko Carstens , + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct mcck_struct { + int kill_task; + int channel_report; + int warning; + unsigned long long mcck_code; +}; + +static DEFINE_PER_CPU(struct mcck_struct, cpu_mcck); + +static NORET_TYPE void s390_handle_damage(char *msg) +{ + smp_send_stop(); + disabled_wait((unsigned long) __builtin_return_address(0)); + while (1); +} + +/* + * Main machine check handler function. Will be called with interrupts enabled + * or disabled and machine checks enabled or disabled. + */ +void s390_handle_mcck(void) +{ + unsigned long flags; + struct mcck_struct mcck; + + /* + * Disable machine checks and get the current state of accumulated + * machine checks. Afterwards delete the old state and enable machine + * checks again. + */ + local_irq_save(flags); + local_mcck_disable(); + mcck = __get_cpu_var(cpu_mcck); + memset(&__get_cpu_var(cpu_mcck), 0, sizeof(struct mcck_struct)); + clear_thread_flag(TIF_MCCK_PENDING); + local_mcck_enable(); + local_irq_restore(flags); + + if (mcck.channel_report) + crw_handle_channel_report(); + +#ifdef CONFIG_MACHCHK_WARNING +/* + * The warning may remain for a prolonged period on the bare iron. + * (actually till the machine is powered off, or until the problem is gone) + * So we just stop listening for the WARNING MCH and prevent continuously + * being interrupted. One caveat is however, that we must do this per + * processor and cannot use the smp version of ctl_clear_bit(). + * On VM we only get one interrupt per virtally presented machinecheck. + * Though one suffices, we may get one interrupt per (virtual) processor. + */ + if (mcck.warning) { /* WARNING pending ? */ + static int mchchk_wng_posted = 0; + /* + * Use single machine clear, as we cannot handle smp right now + */ + __ctl_clear_bit(14, 24); /* Disable WARNING MCH */ + if (xchg(&mchchk_wng_posted, 1) == 0) + kill_cad_pid(SIGPWR, 1); + } +#endif + + if (mcck.kill_task) { + local_irq_enable(); + printk(KERN_EMERG "mcck: Terminating task because of machine " + "malfunction (code 0x%016llx).\n", mcck.mcck_code); + printk(KERN_EMERG "mcck: task: %s, pid: %d.\n", + current->comm, current->pid); + do_exit(SIGSEGV); + } +} +EXPORT_SYMBOL_GPL(s390_handle_mcck); + +/* + * returns 0 if all registers could be validated + * returns 1 otherwise + */ +static int notrace s390_revalidate_registers(struct mci *mci) +{ + int kill_task; + u64 tmpclock; + u64 zero; + void *fpt_save_area, *fpt_creg_save_area; + + kill_task = 0; + zero = 0; + + if (!mci->gr) { + /* + * General purpose registers couldn't be restored and have + * unknown contents. Process needs to be terminated. + */ + kill_task = 1; + } + if (!mci->fp) { + /* + * Floating point registers can't be restored and + * therefore the process needs to be terminated. + */ + kill_task = 1; + } +#ifndef CONFIG_64BIT + asm volatile( + " ld 0,0(%0)\n" + " ld 2,8(%0)\n" + " ld 4,16(%0)\n" + " ld 6,24(%0)" + : : "a" (&S390_lowcore.floating_pt_save_area)); +#endif + + if (MACHINE_HAS_IEEE) { +#ifdef CONFIG_64BIT + fpt_save_area = &S390_lowcore.floating_pt_save_area; + fpt_creg_save_area = &S390_lowcore.fpt_creg_save_area; +#else + fpt_save_area = (void *) S390_lowcore.extended_save_area_addr; + fpt_creg_save_area = fpt_save_area + 128; +#endif + if (!mci->fc) { + /* + * Floating point control register can't be restored. + * Task will be terminated. + */ + asm volatile("lfpc 0(%0)" : : "a" (&zero), "m" (zero)); + kill_task = 1; + + } else + asm volatile("lfpc 0(%0)" : : "a" (fpt_creg_save_area)); + + asm volatile( + " ld 0,0(%0)\n" + " ld 1,8(%0)\n" + " ld 2,16(%0)\n" + " ld 3,24(%0)\n" + " ld 4,32(%0)\n" + " ld 5,40(%0)\n" + " ld 6,48(%0)\n" + " ld 7,56(%0)\n" + " ld 8,64(%0)\n" + " ld 9,72(%0)\n" + " ld 10,80(%0)\n" + " ld 11,88(%0)\n" + " ld 12,96(%0)\n" + " ld 13,104(%0)\n" + " ld 14,112(%0)\n" + " ld 15,120(%0)\n" + : : "a" (fpt_save_area)); + } + /* Revalidate access registers */ + asm volatile( + " lam 0,15,0(%0)" + : : "a" (&S390_lowcore.access_regs_save_area)); + if (!mci->ar) { + /* + * Access registers have unknown contents. + * Terminating task. + */ + kill_task = 1; + } + /* Revalidate control registers */ + if (!mci->cr) { + /* + * Control registers have unknown contents. + * Can't recover and therefore stopping machine. + */ + s390_handle_damage("invalid control registers."); + } else { +#ifdef CONFIG_64BIT + asm volatile( + " lctlg 0,15,0(%0)" + : : "a" (&S390_lowcore.cregs_save_area)); +#else + asm volatile( + " lctl 0,15,0(%0)" + : : "a" (&S390_lowcore.cregs_save_area)); +#endif + } + /* + * We don't even try to revalidate the TOD register, since we simply + * can't write something sensible into that register. + */ +#ifdef CONFIG_64BIT + /* + * See if we can revalidate the TOD programmable register with its + * old contents (should be zero) otherwise set it to zero. + */ + if (!mci->pr) + asm volatile( + " sr 0,0\n" + " sckpf" + : : : "0", "cc"); + else + asm volatile( + " l 0,0(%0)\n" + " sckpf" + : : "a" (&S390_lowcore.tod_progreg_save_area) + : "0", "cc"); +#endif + /* Revalidate clock comparator register */ + asm volatile( + " stck 0(%1)\n" + " sckc 0(%1)" + : "=m" (tmpclock) : "a" (&(tmpclock)) : "cc", "memory"); + + /* Check if old PSW is valid */ + if (!mci->wp) + /* + * Can't tell if we come from user or kernel mode + * -> stopping machine. + */ + s390_handle_damage("old psw invalid."); + + if (!mci->ms || !mci->pm || !mci->ia) + kill_task = 1; + + return kill_task; +} + +#define MAX_IPD_COUNT 29 +#define MAX_IPD_TIME (5 * 60 * USEC_PER_SEC) /* 5 minutes */ + +#define ED_STP_ISLAND 6 /* External damage STP island check */ +#define ED_STP_SYNC 7 /* External damage STP sync check */ +#define ED_ETR_SYNC 12 /* External damage ETR sync check */ +#define ED_ETR_SWITCH 13 /* External damage ETR switch to local */ + +/* + * machine check handler. + */ +void notrace s390_do_machine_check(struct pt_regs *regs) +{ + static int ipd_count; + static DEFINE_SPINLOCK(ipd_lock); + static unsigned long long last_ipd; + struct mcck_struct *mcck; + unsigned long long tmp; + struct mci *mci; + int umode; + + lockdep_off(); + s390_idle_check(); + + mci = (struct mci *) &S390_lowcore.mcck_interruption_code; + mcck = &__get_cpu_var(cpu_mcck); + umode = user_mode(regs); + + if (mci->sd) { + /* System damage -> stopping machine */ + s390_handle_damage("received system damage machine check."); + } + if (mci->pd) { + if (mci->b) { + /* Processing backup -> verify if we can survive this */ + u64 z_mcic, o_mcic, t_mcic; +#ifdef CONFIG_64BIT + z_mcic = (1ULL<<63 | 1ULL<<59 | 1ULL<<29); + o_mcic = (1ULL<<43 | 1ULL<<42 | 1ULL<<41 | 1ULL<<40 | + 1ULL<<36 | 1ULL<<35 | 1ULL<<34 | 1ULL<<32 | + 1ULL<<30 | 1ULL<<21 | 1ULL<<20 | 1ULL<<17 | + 1ULL<<16); +#else + z_mcic = (1ULL<<63 | 1ULL<<59 | 1ULL<<57 | 1ULL<<50 | + 1ULL<<29); + o_mcic = (1ULL<<43 | 1ULL<<42 | 1ULL<<41 | 1ULL<<40 | + 1ULL<<36 | 1ULL<<35 | 1ULL<<34 | 1ULL<<32 | + 1ULL<<30 | 1ULL<<20 | 1ULL<<17 | 1ULL<<16); +#endif + t_mcic = *(u64 *)mci; + + if (((t_mcic & z_mcic) != 0) || + ((t_mcic & o_mcic) != o_mcic)) { + s390_handle_damage("processing backup machine " + "check with damage."); + } + + /* + * Nullifying exigent condition, therefore we might + * retry this instruction. + */ + spin_lock(&ipd_lock); + tmp = get_clock(); + if (((tmp - last_ipd) >> 12) < MAX_IPD_TIME) + ipd_count++; + else + ipd_count = 1; + last_ipd = tmp; + if (ipd_count == MAX_IPD_COUNT) + s390_handle_damage("too many ipd retries."); + spin_unlock(&ipd_lock); + } else { + /* Processing damage -> stopping machine */ + s390_handle_damage("received instruction processing " + "damage machine check."); + } + } + if (s390_revalidate_registers(mci)) { + if (umode) { + /* + * Couldn't restore all register contents while in + * user mode -> mark task for termination. + */ + mcck->kill_task = 1; + mcck->mcck_code = *(unsigned long long *) mci; + set_thread_flag(TIF_MCCK_PENDING); + } else { + /* + * Couldn't restore all register contents while in + * kernel mode -> stopping machine. + */ + s390_handle_damage("unable to revalidate registers."); + } + } + if (mci->cd) { + /* Timing facility damage */ + s390_handle_damage("TOD clock damaged"); + } + if (mci->ed && mci->ec) { + /* External damage */ + if (S390_lowcore.external_damage_code & (1U << ED_ETR_SYNC)) + etr_sync_check(); + if (S390_lowcore.external_damage_code & (1U << ED_ETR_SWITCH)) + etr_switch_to_local(); + if (S390_lowcore.external_damage_code & (1U << ED_STP_SYNC)) + stp_sync_check(); + if (S390_lowcore.external_damage_code & (1U << ED_STP_ISLAND)) + stp_island_check(); + } + if (mci->se) + /* Storage error uncorrected */ + s390_handle_damage("received storage error uncorrected " + "machine check."); + if (mci->ke) + /* Storage key-error uncorrected */ + s390_handle_damage("received storage key-error uncorrected " + "machine check."); + if (mci->ds && mci->fa) + /* Storage degradation */ + s390_handle_damage("received storage degradation machine " + "check."); + if (mci->cp) { + /* Channel report word pending */ + mcck->channel_report = 1; + set_thread_flag(TIF_MCCK_PENDING); + } + if (mci->w) { + /* Warning pending */ + mcck->warning = 1; + set_thread_flag(TIF_MCCK_PENDING); + } + lockdep_on(); +} + +static int __init machine_check_init(void) +{ + ctl_set_bit(14, 25); /* enable external damage MCH */ + ctl_set_bit(14, 27); /* enable system recovery MCH */ +#ifdef CONFIG_MACHCHK_WARNING + ctl_set_bit(14, 24); /* enable warning MCH */ +#endif + return 0; +} +arch_initcall(machine_check_init); diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index e6b480625cb..bd616fb31e7 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c @@ -39,6 +39,7 @@ #include #include #include +#include #include "entry.h" asmlinkage void ret_from_fork(void) asm ("ret_from_fork"); @@ -68,7 +69,6 @@ unsigned long thread_saved_pc(struct task_struct *tsk) return sf->gprs[8]; } -extern void s390_handle_mcck(void); /* * The idle loop on a S390... */ diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index c55a4b9ffd8..caa4d287701 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -23,7 +23,7 @@ #include #include #include - +#include #include "kvm-s390.h" #include "gaccess.h" @@ -440,8 +440,6 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu, return -EINVAL; /* not implemented yet */ } -extern void s390_handle_mcck(void); - static void __vcpu_run(struct kvm_vcpu *vcpu) { memcpy(&vcpu->arch.sie_block->gg14, &vcpu->arch.guest_gprs[14], 16); diff --git a/drivers/s390/Makefile b/drivers/s390/Makefile index 0828dc83935..95bccfd3f16 100644 --- a/drivers/s390/Makefile +++ b/drivers/s390/Makefile @@ -2,7 +2,6 @@ # Makefile for the S/390 specific device drivers # -obj-y += s390mach.o obj-y += cio/ block/ char/ crypto/ net/ scsi/ kvm/ drivers-y += drivers/s390/built-in.o diff --git a/drivers/s390/cio/Makefile b/drivers/s390/cio/Makefile index bd79bd16539..adb3dd30152 100644 --- a/drivers/s390/cio/Makefile +++ b/drivers/s390/cio/Makefile @@ -3,7 +3,7 @@ # obj-y += airq.o blacklist.o chsc.o cio.o css.o chp.o idset.o isc.o scsw.o \ - fcx.o itcw.o + fcx.o itcw.o crw.o ccw_device-objs += device.o device_fsm.o device_ops.o ccw_device-objs += device_id.o device_pgid.o device_status.o obj-y += ccw_device.o cmf.o diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c index 1246f61a533..3e5f304ad88 100644 --- a/drivers/s390/cio/chp.c +++ b/drivers/s390/cio/chp.c @@ -17,8 +17,8 @@ #include #include #include +#include -#include "../s390mach.h" #include "cio.h" #include "css.h" #include "ioasm.h" @@ -706,12 +706,12 @@ static int __init chp_init(void) struct chp_id chpid; int ret; - ret = s390_register_crw_handler(CRW_RSC_CPATH, chp_process_crw); + ret = crw_register_handler(CRW_RSC_CPATH, chp_process_crw); if (ret) return ret; chp_wq = create_singlethread_workqueue("cio_chp"); if (!chp_wq) { - s390_unregister_crw_handler(CRW_RSC_CPATH); + crw_unregister_handler(CRW_RSC_CPATH); return -ENOMEM; } INIT_WORK(&cfg_work, cfg_func); diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index ebab6ea4659..7399b07a1ae 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -19,8 +19,8 @@ #include #include #include +#include -#include "../s390mach.h" #include "css.h" #include "cio.h" #include "cio_debug.h" @@ -820,7 +820,7 @@ int __init chsc_alloc_sei_area(void) "chsc machine checks!\n"); return -ENOMEM; } - ret = s390_register_crw_handler(CRW_RSC_CSS, chsc_process_crw); + ret = crw_register_handler(CRW_RSC_CSS, chsc_process_crw); if (ret) kfree(sei_page); return ret; @@ -828,7 +828,7 @@ int __init chsc_alloc_sei_area(void) void __init chsc_free_sei_area(void) { - s390_unregister_crw_handler(CRW_RSC_CSS); + crw_unregister_handler(CRW_RSC_CSS); kfree(sei_page); } diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 659f8a79165..73135c5e9df 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -30,6 +30,8 @@ #include #include #include +#include +#include #include "cio.h" #include "css.h" #include "chsc.h" @@ -38,7 +40,6 @@ #include "blacklist.h" #include "cio_debug.h" #include "chp.h" -#include "../s390mach.h" debug_info_t *cio_debug_msg_id; debug_info_t *cio_debug_trace_id; diff --git a/drivers/s390/cio/crw.c b/drivers/s390/cio/crw.c new file mode 100644 index 00000000000..508f88f6420 --- /dev/null +++ b/drivers/s390/cio/crw.c @@ -0,0 +1,145 @@ +/* + * Channel report handling code + * + * Copyright IBM Corp. 2000,2009 + * Author(s): Ingo Adlung , + * Martin Schwidefsky , + * Cornelia Huck , + * Heiko Carstens , + */ + +#include +#include +#include +#include + +static struct semaphore crw_semaphore; +static crw_handler_t crw_handlers[NR_RSCS]; + +/** + * crw_register_handler() - register a channel report word handler + * @rsc: reporting source code to handle + * @handler: handler to be registered + * + * Returns %0 on success and a negative error value otherwise. + */ +int crw_register_handler(int rsc, crw_handler_t handler) +{ + if ((rsc < 0) || (rsc >= NR_RSCS)) + return -EINVAL; + if (!cmpxchg(&crw_handlers[rsc], NULL, handler)) + return 0; + return -EBUSY; +} + +/** + * crw_unregister_handler() - unregister a channel report word handler + * @rsc: reporting source code to handle + */ +void crw_unregister_handler(int rsc) +{ + if ((rsc < 0) || (rsc >= NR_RSCS)) + return; + xchg(&crw_handlers[rsc], NULL); + synchronize_sched(); +} + +/* + * Retrieve CRWs and call function to handle event. + */ +static int crw_collect_info(void *unused) +{ + struct crw crw[2]; + int ccode; + unsigned int chain; + int ignore; + +repeat: + ignore = down_interruptible(&crw_semaphore); + chain = 0; + while (1) { + if (unlikely(chain > 1)) { + struct crw tmp_crw; + + printk(KERN_WARNING"%s: Code does not support more " + "than two chained crws; please report to " + "linux390@de.ibm.com!\n", __func__); + ccode = stcrw(&tmp_crw); + printk(KERN_WARNING"%s: crw reports slct=%d, oflw=%d, " + "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n", + __func__, tmp_crw.slct, tmp_crw.oflw, + tmp_crw.chn, tmp_crw.rsc, tmp_crw.anc, + tmp_crw.erc, tmp_crw.rsid); + printk(KERN_WARNING"%s: This was crw number %x in the " + "chain\n", __func__, chain); + if (ccode != 0) + break; + chain = tmp_crw.chn ? chain + 1 : 0; + continue; + } + ccode = stcrw(&crw[chain]); + if (ccode != 0) + break; + printk(KERN_DEBUG "crw_info : CRW reports slct=%d, oflw=%d, " + "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n", + crw[chain].slct, crw[chain].oflw, crw[chain].chn, + crw[chain].rsc, crw[chain].anc, crw[chain].erc, + crw[chain].rsid); + /* Check for overflows. */ + if (crw[chain].oflw) { + int i; + + pr_debug("%s: crw overflow detected!\n", __func__); + for (i = 0; i < NR_RSCS; i++) { + if (crw_handlers[i]) + crw_handlers[i](NULL, NULL, 1); + } + chain = 0; + continue; + } + if (crw[0].chn && !chain) { + chain++; + continue; + } + if (crw_handlers[crw[chain].rsc]) + crw_handlers[crw[chain].rsc](&crw[0], + chain ? &crw[1] : NULL, + 0); + /* chain is always 0 or 1 here. */ + chain = crw[chain].chn ? chain + 1 : 0; + } + goto repeat; + return 0; +} + +void crw_handle_channel_report(void) +{ + up(&crw_semaphore); +} + +/* + * Separate initcall needed for semaphore initialization since + * crw_handle_channel_report might be called before crw_machine_check_init. + */ +static int __init crw_init_semaphore(void) +{ + init_MUTEX_LOCKED(&crw_semaphore); + return 0; +} +pure_initcall(crw_init_semaphore); + +/* + * Machine checks for the channel subsystem must be enabled + * after the channel subsystem is initialized + */ +static int __init crw_machine_check_init(void) +{ + struct task_struct *task; + + task = kthread_run(crw_collect_info, NULL, "kmcheck"); + if (IS_ERR(task)) + return PTR_ERR(task); + ctl_set_bit(14, 28); /* enable channel report MCH */ + return 0; +} +device_initcall(crw_machine_check_init); diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 8019288bc6d..a5fc56371ba 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -18,8 +18,8 @@ #include #include #include +#include -#include "../s390mach.h" #include "css.h" #include "cio.h" #include "cio_debug.h" @@ -765,7 +765,7 @@ init_channel_subsystem (void) if (ret) goto out; - ret = s390_register_crw_handler(CRW_RSC_SCH, css_process_crw); + ret = crw_register_handler(CRW_RSC_SCH, css_process_crw); if (ret) goto out; @@ -845,7 +845,7 @@ out_unregister: out_bus: bus_unregister(&css_bus_type); out: - s390_unregister_crw_handler(CRW_RSC_CSS); + crw_unregister_handler(CRW_RSC_CSS); chsc_free_sei_area(); kfree(slow_subchannel_set); pr_alert("The CSS device driver initialization failed with " diff --git a/drivers/s390/s390mach.c b/drivers/s390/s390mach.c deleted file mode 100644 index 8e437052e07..00000000000 --- a/drivers/s390/s390mach.c +++ /dev/null @@ -1,537 +0,0 @@ -/* - * drivers/s390/s390mach.c - * S/390 machine check handler - * - * Copyright IBM Corp. 2000,2008 - * Author(s): Ingo Adlung (adlung@de.ibm.com) - * Martin Schwidefsky (schwidefsky@de.ibm.com) - * Cornelia Huck - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "s390mach.h" - -static struct semaphore m_sem; - -static NORET_TYPE void -s390_handle_damage(char *msg) -{ -#ifdef CONFIG_SMP - smp_send_stop(); -#endif - disabled_wait((unsigned long) __builtin_return_address(0)); - for(;;); -} - -static crw_handler_t crw_handlers[NR_RSCS]; - -/** - * s390_register_crw_handler() - register a channel report word handler - * @rsc: reporting source code to handle - * @handler: handler to be registered - * - * Returns %0 on success and a negative error value otherwise. - */ -int s390_register_crw_handler(int rsc, crw_handler_t handler) -{ - if ((rsc < 0) || (rsc >= NR_RSCS)) - return -EINVAL; - if (!cmpxchg(&crw_handlers[rsc], NULL, handler)) - return 0; - return -EBUSY; -} - -/** - * s390_unregister_crw_handler() - unregister a channel report word handler - * @rsc: reporting source code to handle - */ -void s390_unregister_crw_handler(int rsc) -{ - if ((rsc < 0) || (rsc >= NR_RSCS)) - return; - xchg(&crw_handlers[rsc], NULL); - synchronize_sched(); -} - -/* - * Retrieve CRWs and call function to handle event. - */ -static int s390_collect_crw_info(void *param) -{ - struct crw crw[2]; - int ccode; - struct semaphore *sem; - unsigned int chain; - int ignore; - - sem = (struct semaphore *)param; -repeat: - ignore = down_interruptible(sem); - chain = 0; - while (1) { - if (unlikely(chain > 1)) { - struct crw tmp_crw; - - printk(KERN_WARNING"%s: Code does not support more " - "than two chained crws; please report to " - "linux390@de.ibm.com!\n", __func__); - ccode = stcrw(&tmp_crw); - printk(KERN_WARNING"%s: crw reports slct=%d, oflw=%d, " - "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n", - __func__, tmp_crw.slct, tmp_crw.oflw, - tmp_crw.chn, tmp_crw.rsc, tmp_crw.anc, - tmp_crw.erc, tmp_crw.rsid); - printk(KERN_WARNING"%s: This was crw number %x in the " - "chain\n", __func__, chain); - if (ccode != 0) - break; - chain = tmp_crw.chn ? chain + 1 : 0; - continue; - } - ccode = stcrw(&crw[chain]); - if (ccode != 0) - break; - printk(KERN_DEBUG "crw_info : CRW reports slct=%d, oflw=%d, " - "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n", - crw[chain].slct, crw[chain].oflw, crw[chain].chn, - crw[chain].rsc, crw[chain].anc, crw[chain].erc, - crw[chain].rsid); - /* Check for overflows. */ - if (crw[chain].oflw) { - int i; - - pr_debug("%s: crw overflow detected!\n", __func__); - for (i = 0; i < NR_RSCS; i++) { - if (crw_handlers[i]) - crw_handlers[i](NULL, NULL, 1); - } - chain = 0; - continue; - } - if (crw[0].chn && !chain) { - chain++; - continue; - } - if (crw_handlers[crw[chain].rsc]) - crw_handlers[crw[chain].rsc](&crw[0], - chain ? &crw[1] : NULL, - 0); - /* chain is always 0 or 1 here. */ - chain = crw[chain].chn ? chain + 1 : 0; - } - goto repeat; - return 0; -} - -struct mcck_struct { - int kill_task; - int channel_report; - int warning; - unsigned long long mcck_code; -}; - -static DEFINE_PER_CPU(struct mcck_struct, cpu_mcck); - -/* - * Main machine check handler function. Will be called with interrupts enabled - * or disabled and machine checks enabled or disabled. - */ -void -s390_handle_mcck(void) -{ - unsigned long flags; - struct mcck_struct mcck; - - /* - * Disable machine checks and get the current state of accumulated - * machine checks. Afterwards delete the old state and enable machine - * checks again. - */ - local_irq_save(flags); - local_mcck_disable(); - mcck = __get_cpu_var(cpu_mcck); - memset(&__get_cpu_var(cpu_mcck), 0, sizeof(struct mcck_struct)); - clear_thread_flag(TIF_MCCK_PENDING); - local_mcck_enable(); - local_irq_restore(flags); - - if (mcck.channel_report) - up(&m_sem); - -#ifdef CONFIG_MACHCHK_WARNING -/* - * The warning may remain for a prolonged period on the bare iron. - * (actually till the machine is powered off, or until the problem is gone) - * So we just stop listening for the WARNING MCH and prevent continuously - * being interrupted. One caveat is however, that we must do this per - * processor and cannot use the smp version of ctl_clear_bit(). - * On VM we only get one interrupt per virtally presented machinecheck. - * Though one suffices, we may get one interrupt per (virtual) processor. - */ - if (mcck.warning) { /* WARNING pending ? */ - static int mchchk_wng_posted = 0; - /* - * Use single machine clear, as we cannot handle smp right now - */ - __ctl_clear_bit(14, 24); /* Disable WARNING MCH */ - if (xchg(&mchchk_wng_posted, 1) == 0) - kill_cad_pid(SIGPWR, 1); - } -#endif - - if (mcck.kill_task) { - local_irq_enable(); - printk(KERN_EMERG "mcck: Terminating task because of machine " - "malfunction (code 0x%016llx).\n", mcck.mcck_code); - printk(KERN_EMERG "mcck: task: %s, pid: %d.\n", - current->comm, current->pid); - do_exit(SIGSEGV); - } -} -EXPORT_SYMBOL_GPL(s390_handle_mcck); - -/* - * returns 0 if all registers could be validated - * returns 1 otherwise - */ -static int -s390_revalidate_registers(struct mci *mci) -{ - int kill_task; - u64 tmpclock; - u64 zero; - void *fpt_save_area, *fpt_creg_save_area; - - kill_task = 0; - zero = 0; - /* General purpose registers */ - if (!mci->gr) - /* - * General purpose registers couldn't be restored and have - * unknown contents. Process needs to be terminated. - */ - kill_task = 1; - - /* Revalidate floating point registers */ - if (!mci->fp) - /* - * Floating point registers can't be restored and - * therefore the process needs to be terminated. - */ - kill_task = 1; - -#ifndef CONFIG_64BIT - asm volatile( - " ld 0,0(%0)\n" - " ld 2,8(%0)\n" - " ld 4,16(%0)\n" - " ld 6,24(%0)" - : : "a" (&S390_lowcore.floating_pt_save_area)); -#endif - - if (MACHINE_HAS_IEEE) { -#ifdef CONFIG_64BIT - fpt_save_area = &S390_lowcore.floating_pt_save_area; - fpt_creg_save_area = &S390_lowcore.fpt_creg_save_area; -#else - fpt_save_area = (void *) S390_lowcore.extended_save_area_addr; - fpt_creg_save_area = fpt_save_area+128; -#endif - /* Floating point control register */ - if (!mci->fc) { - /* - * Floating point control register can't be restored. - * Task will be terminated. - */ - asm volatile("lfpc 0(%0)" : : "a" (&zero), "m" (zero)); - kill_task = 1; - - } else - asm volatile("lfpc 0(%0)" : : "a" (fpt_creg_save_area)); - - asm volatile( - " ld 0,0(%0)\n" - " ld 1,8(%0)\n" - " ld 2,16(%0)\n" - " ld 3,24(%0)\n" - " ld 4,32(%0)\n" - " ld 5,40(%0)\n" - " ld 6,48(%0)\n" - " ld 7,56(%0)\n" - " ld 8,64(%0)\n" - " ld 9,72(%0)\n" - " ld 10,80(%0)\n" - " ld 11,88(%0)\n" - " ld 12,96(%0)\n" - " ld 13,104(%0)\n" - " ld 14,112(%0)\n" - " ld 15,120(%0)\n" - : : "a" (fpt_save_area)); - } - - /* Revalidate access registers */ - asm volatile( - " lam 0,15,0(%0)" - : : "a" (&S390_lowcore.access_regs_save_area)); - if (!mci->ar) - /* - * Access registers have unknown contents. - * Terminating task. - */ - kill_task = 1; - - /* Revalidate control registers */ - if (!mci->cr) - /* - * Control registers have unknown contents. - * Can't recover and therefore stopping machine. - */ - s390_handle_damage("invalid control registers."); - else -#ifdef CONFIG_64BIT - asm volatile( - " lctlg 0,15,0(%0)" - : : "a" (&S390_lowcore.cregs_save_area)); -#else - asm volatile( - " lctl 0,15,0(%0)" - : : "a" (&S390_lowcore.cregs_save_area)); -#endif - - /* - * We don't even try to revalidate the TOD register, since we simply - * can't write something sensible into that register. - */ - -#ifdef CONFIG_64BIT - /* - * See if we can revalidate the TOD programmable register with its - * old contents (should be zero) otherwise set it to zero. - */ - if (!mci->pr) - asm volatile( - " sr 0,0\n" - " sckpf" - : : : "0", "cc"); - else - asm volatile( - " l 0,0(%0)\n" - " sckpf" - : : "a" (&S390_lowcore.tod_progreg_save_area) - : "0", "cc"); -#endif - - /* Revalidate clock comparator register */ - asm volatile( - " stck 0(%1)\n" - " sckc 0(%1)" - : "=m" (tmpclock) : "a" (&(tmpclock)) : "cc", "memory"); - - /* Check if old PSW is valid */ - if (!mci->wp) - /* - * Can't tell if we come from user or kernel mode - * -> stopping machine. - */ - s390_handle_damage("old psw invalid."); - - if (!mci->ms || !mci->pm || !mci->ia) - kill_task = 1; - - return kill_task; -} - -#define MAX_IPD_COUNT 29 -#define MAX_IPD_TIME (5 * 60 * USEC_PER_SEC) /* 5 minutes */ - -/* - * machine check handler. - */ -void notrace s390_do_machine_check(struct pt_regs *regs) -{ - static DEFINE_SPINLOCK(ipd_lock); - static unsigned long long last_ipd; - static int ipd_count; - unsigned long long tmp; - struct mci *mci; - struct mcck_struct *mcck; - int umode; - - lockdep_off(); - - s390_idle_check(); - - mci = (struct mci *) &S390_lowcore.mcck_interruption_code; - mcck = &__get_cpu_var(cpu_mcck); - umode = user_mode(regs); - - if (mci->sd) - /* System damage -> stopping machine */ - s390_handle_damage("received system damage machine check."); - - if (mci->pd) { - if (mci->b) { - /* Processing backup -> verify if we can survive this */ - u64 z_mcic, o_mcic, t_mcic; -#ifdef CONFIG_64BIT - z_mcic = (1ULL<<63 | 1ULL<<59 | 1ULL<<29); - o_mcic = (1ULL<<43 | 1ULL<<42 | 1ULL<<41 | 1ULL<<40 | - 1ULL<<36 | 1ULL<<35 | 1ULL<<34 | 1ULL<<32 | - 1ULL<<30 | 1ULL<<21 | 1ULL<<20 | 1ULL<<17 | - 1ULL<<16); -#else - z_mcic = (1ULL<<63 | 1ULL<<59 | 1ULL<<57 | 1ULL<<50 | - 1ULL<<29); - o_mcic = (1ULL<<43 | 1ULL<<42 | 1ULL<<41 | 1ULL<<40 | - 1ULL<<36 | 1ULL<<35 | 1ULL<<34 | 1ULL<<32 | - 1ULL<<30 | 1ULL<<20 | 1ULL<<17 | 1ULL<<16); -#endif - t_mcic = *(u64 *)mci; - - if (((t_mcic & z_mcic) != 0) || - ((t_mcic & o_mcic) != o_mcic)) { - s390_handle_damage("processing backup machine " - "check with damage."); - } - - /* - * Nullifying exigent condition, therefore we might - * retry this instruction. - */ - - spin_lock(&ipd_lock); - - tmp = get_clock(); - - if (((tmp - last_ipd) >> 12) < MAX_IPD_TIME) - ipd_count++; - else - ipd_count = 1; - - last_ipd = tmp; - - if (ipd_count == MAX_IPD_COUNT) - s390_handle_damage("too many ipd retries."); - - spin_unlock(&ipd_lock); - } - else { - /* Processing damage -> stopping machine */ - s390_handle_damage("received instruction processing " - "damage machine check."); - } - } - if (s390_revalidate_registers(mci)) { - if (umode) { - /* - * Couldn't restore all register contents while in - * user mode -> mark task for termination. - */ - mcck->kill_task = 1; - mcck->mcck_code = *(unsigned long long *) mci; - set_thread_flag(TIF_MCCK_PENDING); - } - else - /* - * Couldn't restore all register contents while in - * kernel mode -> stopping machine. - */ - s390_handle_damage("unable to revalidate registers."); - } - - if (mci->cd) { - /* Timing facility damage */ - s390_handle_damage("TOD clock damaged"); - } - - if (mci->ed && mci->ec) { - /* External damage */ - if (S390_lowcore.external_damage_code & (1U << ED_ETR_SYNC)) - etr_sync_check(); - if (S390_lowcore.external_damage_code & (1U << ED_ETR_SWITCH)) - etr_switch_to_local(); - if (S390_lowcore.external_damage_code & (1U << ED_STP_SYNC)) - stp_sync_check(); - if (S390_lowcore.external_damage_code & (1U << ED_STP_ISLAND)) - stp_island_check(); - } - - if (mci->se) - /* Storage error uncorrected */ - s390_handle_damage("received storage error uncorrected " - "machine check."); - - if (mci->ke) - /* Storage key-error uncorrected */ - s390_handle_damage("received storage key-error uncorrected " - "machine check."); - - if (mci->ds && mci->fa) - /* Storage degradation */ - s390_handle_damage("received storage degradation machine " - "check."); - - if (mci->cp) { - /* Channel report word pending */ - mcck->channel_report = 1; - set_thread_flag(TIF_MCCK_PENDING); - } - - if (mci->w) { - /* Warning pending */ - mcck->warning = 1; - set_thread_flag(TIF_MCCK_PENDING); - } - lockdep_on(); -} - -/* - * s390_init_machine_check - * - * initialize machine check handling - */ -static int -machine_check_init(void) -{ - init_MUTEX_LOCKED(&m_sem); - ctl_set_bit(14, 25); /* enable external damage MCH */ - ctl_set_bit(14, 27); /* enable system recovery MCH */ -#ifdef CONFIG_MACHCHK_WARNING - ctl_set_bit(14, 24); /* enable warning MCH */ -#endif - return 0; -} - -/* - * Initialize the machine check handler really early to be able to - * catch all machine checks that happen during boot - */ -arch_initcall(machine_check_init); - -/* - * Machine checks for the channel subsystem must be enabled - * after the channel subsystem is initialized - */ -static int __init -machine_check_crw_init (void) -{ - struct task_struct *task; - - task = kthread_run(s390_collect_crw_info, &m_sem, "kmcheck"); - if (IS_ERR(task)) - return PTR_ERR(task); - ctl_set_bit(14, 28); /* enable channel report MCH */ - return 0; -} - -device_initcall (machine_check_crw_init); diff --git a/drivers/s390/s390mach.h b/drivers/s390/s390mach.h deleted file mode 100644 index d39f8b697d2..00000000000 --- a/drivers/s390/s390mach.h +++ /dev/null @@ -1,122 +0,0 @@ -/* - * drivers/s390/s390mach.h - * S/390 data definitions for machine check processing - * - * S390 version - * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Ingo Adlung (adlung@de.ibm.com) - */ - -#ifndef __s390mach_h -#define __s390mach_h - -#include - -struct mci { - __u32 sd : 1; /* 00 system damage */ - __u32 pd : 1; /* 01 instruction-processing damage */ - __u32 sr : 1; /* 02 system recovery */ - __u32 to_be_defined_1 : 1; /* 03 */ - __u32 cd : 1; /* 04 timing-facility damage */ - __u32 ed : 1; /* 05 external damage */ - __u32 to_be_defined_2 : 1; /* 06 */ - __u32 dg : 1; /* 07 degradation */ - __u32 w : 1; /* 08 warning pending */ - __u32 cp : 1; /* 09 channel-report pending */ - __u32 sp : 1; /* 10 service-processor damage */ - __u32 ck : 1; /* 11 channel-subsystem damage */ - __u32 to_be_defined_3 : 2; /* 12-13 */ - __u32 b : 1; /* 14 backed up */ - __u32 to_be_defined_4 : 1; /* 15 */ - __u32 se : 1; /* 16 storage error uncorrected */ - __u32 sc : 1; /* 17 storage error corrected */ - __u32 ke : 1; /* 18 storage-key error uncorrected */ - __u32 ds : 1; /* 19 storage degradation */ - __u32 wp : 1; /* 20 psw mwp validity */ - __u32 ms : 1; /* 21 psw mask and key validity */ - __u32 pm : 1; /* 22 psw program mask and cc validity */ - __u32 ia : 1; /* 23 psw instruction address validity */ - __u32 fa : 1; /* 24 failing storage address validity */ - __u32 to_be_defined_5 : 1; /* 25 */ - __u32 ec : 1; /* 26 external damage code validity */ - __u32 fp : 1; /* 27 floating point register validity */ - __u32 gr : 1; /* 28 general register validity */ - __u32 cr : 1; /* 29 control register validity */ - __u32 to_be_defined_6 : 1; /* 30 */ - __u32 st : 1; /* 31 storage logical validity */ - __u32 ie : 1; /* 32 indirect storage error */ - __u32 ar : 1; /* 33 access register validity */ - __u32 da : 1; /* 34 delayed access exception */ - __u32 to_be_defined_7 : 7; /* 35-41 */ - __u32 pr : 1; /* 42 tod programmable register validity */ - __u32 fc : 1; /* 43 fp control register validity */ - __u32 ap : 1; /* 44 ancillary report */ - __u32 to_be_defined_8 : 1; /* 45 */ - __u32 ct : 1; /* 46 cpu timer validity */ - __u32 cc : 1; /* 47 clock comparator validity */ - __u32 to_be_defined_9 : 16; /* 47-63 */ -}; - -/* - * Channel Report Word - */ -struct crw { - __u32 res1 : 1; /* reserved zero */ - __u32 slct : 1; /* solicited */ - __u32 oflw : 1; /* overflow */ - __u32 chn : 1; /* chained */ - __u32 rsc : 4; /* reporting source code */ - __u32 anc : 1; /* ancillary report */ - __u32 res2 : 1; /* reserved zero */ - __u32 erc : 6; /* error-recovery code */ - __u32 rsid : 16; /* reporting-source ID */ -} __attribute__ ((packed)); - -typedef void (*crw_handler_t)(struct crw *, struct crw *, int); - -extern int s390_register_crw_handler(int rsc, crw_handler_t handler); -extern void s390_unregister_crw_handler(int rsc); - -#define NR_RSCS 16 - -#define CRW_RSC_MONITOR 0x2 /* monitoring facility */ -#define CRW_RSC_SCH 0x3 /* subchannel */ -#define CRW_RSC_CPATH 0x4 /* channel path */ -#define CRW_RSC_CONFIG 0x9 /* configuration-alert facility */ -#define CRW_RSC_CSS 0xB /* channel subsystem */ - -#define CRW_ERC_EVENT 0x00 /* event information pending */ -#define CRW_ERC_AVAIL 0x01 /* available */ -#define CRW_ERC_INIT 0x02 /* initialized */ -#define CRW_ERC_TERROR 0x03 /* temporary error */ -#define CRW_ERC_IPARM 0x04 /* installed parm initialized */ -#define CRW_ERC_TERM 0x05 /* terminal */ -#define CRW_ERC_PERRN 0x06 /* perm. error, fac. not init */ -#define CRW_ERC_PERRI 0x07 /* perm. error, facility init */ -#define CRW_ERC_PMOD 0x08 /* installed parameters modified */ - -static inline int stcrw(struct crw *pcrw ) -{ - int ccode; - - __asm__ __volatile__( - "stcrw 0(%2)\n\t" - "ipm %0\n\t" - "srl %0,28\n\t" - : "=d" (ccode), "=m" (*pcrw) - : "a" (pcrw) - : "cc" ); - return ccode; -} - -#define ED_ETR_SYNC 12 /* External damage ETR sync check */ -#define ED_ETR_SWITCH 13 /* External damage ETR switch to local */ - -#define ED_STP_SYNC 7 /* External damage STP sync check */ -#define ED_STP_ISLAND 6 /* External damage STP island check */ - -struct pt_regs; - -void s390_handle_mcck(void); -void s390_do_machine_check(struct pt_regs *regs); -#endif /* __s390mach */ -- cgit v1.2.3-70-g09d2 From 7b886416dfd76df9dd7304868556b1d82cf38890 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 26 Mar 2009 15:24:02 +0100 Subject: [S390] Remove CONFIG_MACHCHK_WARNING. Everybody enables it so there is no point for an extra config option. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/Kconfig | 7 ------- arch/s390/kernel/nmi.c | 29 +++++++++++------------------ 2 files changed, 11 insertions(+), 25 deletions(-) diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 3f470604a89..0a9463bea75 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -343,13 +343,6 @@ source "mm/Kconfig" comment "I/O subsystem configuration" -config MACHCHK_WARNING - bool "Process warning machine checks" - help - Select this option if you want the machine check handler on IBM S/390 or - zSeries to process warning machine checks (e.g. on power failures). - If unsure, say "Y". - config QDIO tristate "QDIO support" ---help--- diff --git a/arch/s390/kernel/nmi.c b/arch/s390/kernel/nmi.c index 8d50eaf76a6..4bfdc421d7e 100644 --- a/arch/s390/kernel/nmi.c +++ b/arch/s390/kernel/nmi.c @@ -59,28 +59,23 @@ void s390_handle_mcck(void) if (mcck.channel_report) crw_handle_channel_report(); - -#ifdef CONFIG_MACHCHK_WARNING -/* - * The warning may remain for a prolonged period on the bare iron. - * (actually till the machine is powered off, or until the problem is gone) - * So we just stop listening for the WARNING MCH and prevent continuously - * being interrupted. One caveat is however, that we must do this per - * processor and cannot use the smp version of ctl_clear_bit(). - * On VM we only get one interrupt per virtally presented machinecheck. - * Though one suffices, we may get one interrupt per (virtual) processor. - */ + /* + * A warning may remain for a prolonged period on the bare iron. + * (actually until the machine is powered off, or the problem is gone) + * So we just stop listening for the WARNING MCH and avoid continuously + * being interrupted. One caveat is however, that we must do this per + * processor and cannot use the smp version of ctl_clear_bit(). + * On VM we only get one interrupt per virtally presented machinecheck. + * Though one suffices, we may get one interrupt per (virtual) cpu. + */ if (mcck.warning) { /* WARNING pending ? */ static int mchchk_wng_posted = 0; - /* - * Use single machine clear, as we cannot handle smp right now - */ + + /* Use single cpu clear, as we cannot handle smp here. */ __ctl_clear_bit(14, 24); /* Disable WARNING MCH */ if (xchg(&mchchk_wng_posted, 1) == 0) kill_cad_pid(SIGPWR, 1); } -#endif - if (mcck.kill_task) { local_irq_enable(); printk(KERN_EMERG "mcck: Terminating task because of machine " @@ -375,9 +370,7 @@ static int __init machine_check_init(void) { ctl_set_bit(14, 25); /* enable external damage MCH */ ctl_set_bit(14, 27); /* enable system recovery MCH */ -#ifdef CONFIG_MACHCHK_WARNING ctl_set_bit(14, 24); /* enable warning MCH */ -#endif return 0; } arch_initcall(machine_check_init); -- cgit v1.2.3-70-g09d2 From e3dd9c2da674993edb5b52acb56a5d954415639b Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 26 Mar 2009 15:24:03 +0100 Subject: [S390] convert bitmap definitions to C Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/bitops.h | 2 +- arch/s390/kernel/bitmap.S | 56 ------------------------------------------ arch/s390/kernel/bitmap.c | 49 ++++++++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 57 deletions(-) delete mode 100644 arch/s390/kernel/bitmap.S create mode 100644 arch/s390/kernel/bitmap.c diff --git a/arch/s390/include/asm/bitops.h b/arch/s390/include/asm/bitops.h index 8e9243ae0c1..334964a0fb1 100644 --- a/arch/s390/include/asm/bitops.h +++ b/arch/s390/include/asm/bitops.h @@ -57,7 +57,7 @@ * with operation of the form "set_bit(bitnr, flags)". */ -/* bitmap tables from arch/S390/kernel/bitmap.S */ +/* bitmap tables from arch/s390/kernel/bitmap.c */ extern const char _oi_bitmap[]; extern const char _ni_bitmap[]; extern const char _zb_findmap[]; diff --git a/arch/s390/kernel/bitmap.S b/arch/s390/kernel/bitmap.S deleted file mode 100644 index dfb41f946e2..00000000000 --- a/arch/s390/kernel/bitmap.S +++ /dev/null @@ -1,56 +0,0 @@ -/* - * arch/s390/kernel/bitmap.S - * Bitmaps for set_bit, clear_bit, test_and_set_bit, ... - * See include/asm-s390/{bitops.h|posix_types.h} for details - * - * S390 version - * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), - */ - - .globl _oi_bitmap -_oi_bitmap: - .byte 0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80 - - .globl _ni_bitmap -_ni_bitmap: - .byte 0xFE,0xFD,0xFB,0xF7,0xEF,0xDF,0xBF,0x7F - - .globl _zb_findmap -_zb_findmap: - .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4 - .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5 - .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4 - .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6 - .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4 - .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5 - .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4 - .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,7 - .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4 - .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5 - .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4 - .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6 - .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4 - .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5 - .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4 - .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,8 - - .globl _sb_findmap -_sb_findmap: - .byte 8,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 - .byte 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 - .byte 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 - .byte 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 - .byte 6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 - .byte 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 - .byte 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 - .byte 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 - .byte 7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 - .byte 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 - .byte 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 - .byte 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 - .byte 6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 - .byte 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 - .byte 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 - .byte 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 - diff --git a/arch/s390/kernel/bitmap.c b/arch/s390/kernel/bitmap.c new file mode 100644 index 00000000000..54e362b4267 --- /dev/null +++ b/arch/s390/kernel/bitmap.c @@ -0,0 +1,49 @@ +/* + * Bitmaps for set_bit, clear_bit, test_and_set_bit, ... + * See include/asm/{bitops.h|posix_types.h} for details + * + * Copyright IBM Corp. 1999,2009 + * Author(s): Martin Schwidefsky , + */ + +#include + +const char _oi_bitmap[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }; + +const char _ni_bitmap[] = { 0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f }; + +const char _zb_findmap[] = { + 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4, + 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5, + 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4, + 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6, + 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4, + 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5, + 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4, + 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,7, + 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4, + 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5, + 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4, + 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6, + 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4, + 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5, + 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4, + 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,8 }; + +const char _sb_findmap[] = { + 8,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 }; -- cgit v1.2.3-70-g09d2 From 1485c5c88483d200c9c4c71ed7e8eef1a1e317a1 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 26 Mar 2009 15:24:04 +0100 Subject: [S390] move EXPORT_SYMBOLs to definitions Move all EXPORT_SYMBOLs to their corresponding definitions. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/bitmap.c | 5 +++++ arch/s390/kernel/process.c | 2 ++ arch/s390/kernel/s390_ksyms.c | 44 ------------------------------------------- arch/s390/kernel/setup.c | 8 ++++++++ arch/s390/lib/delay.c | 2 ++ arch/s390/mm/init.c | 2 ++ 6 files changed, 19 insertions(+), 44 deletions(-) diff --git a/arch/s390/kernel/bitmap.c b/arch/s390/kernel/bitmap.c index 54e362b4267..3ae4757b006 100644 --- a/arch/s390/kernel/bitmap.c +++ b/arch/s390/kernel/bitmap.c @@ -7,10 +7,13 @@ */ #include +#include const char _oi_bitmap[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }; +EXPORT_SYMBOL(_oi_bitmap); const char _ni_bitmap[] = { 0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f }; +EXPORT_SYMBOL(_ni_bitmap); const char _zb_findmap[] = { 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4, @@ -29,6 +32,7 @@ const char _zb_findmap[] = { 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5, 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4, 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,8 }; +EXPORT_SYMBOL(_zb_findmap); const char _sb_findmap[] = { 8,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, @@ -47,3 +51,4 @@ const char _sb_findmap[] = { 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 }; +EXPORT_SYMBOL(_sb_findmap); diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index bd616fb31e7..b48e961a38f 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c @@ -141,6 +141,7 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); } +EXPORT_SYMBOL(kernel_thread); /* * Free current thread data structures etc.. @@ -318,6 +319,7 @@ int dump_fpu (struct pt_regs * regs, s390_fp_regs *fpregs) #endif /* CONFIG_64BIT */ return 1; } +EXPORT_SYMBOL(dump_fpu); unsigned long get_wchan(struct task_struct *p) { diff --git a/arch/s390/kernel/s390_ksyms.c b/arch/s390/kernel/s390_ksyms.c index 46b90cb0370..656fcbb9bd8 100644 --- a/arch/s390/kernel/s390_ksyms.c +++ b/arch/s390/kernel/s390_ksyms.c @@ -1,49 +1,5 @@ -/* - * arch/s390/kernel/s390_ksyms.c - * - * S390 version - */ -#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#ifdef CONFIG_IP_MULTICAST -#include -#endif - -/* - * memory management - */ -EXPORT_SYMBOL(_oi_bitmap); -EXPORT_SYMBOL(_ni_bitmap); -EXPORT_SYMBOL(_zb_findmap); -EXPORT_SYMBOL(_sb_findmap); - -/* - * binfmt_elf loader - */ -extern int dump_fpu (struct pt_regs * regs, s390_fp_regs *fpregs); -EXPORT_SYMBOL(dump_fpu); -EXPORT_SYMBOL(empty_zero_page); - -/* - * misc. - */ -EXPORT_SYMBOL(machine_flags); -EXPORT_SYMBOL(__udelay); -EXPORT_SYMBOL(kernel_thread); -EXPORT_SYMBOL(csum_fold); -EXPORT_SYMBOL(console_mode); -EXPORT_SYMBOL(console_devno); -EXPORT_SYMBOL(console_irq); #ifdef CONFIG_FUNCTION_TRACER EXPORT_SYMBOL(_mcount); diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 8fdf08379ce..0b8ad7b4f8f 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -74,9 +74,17 @@ EXPORT_SYMBOL(uaccess); * Machine setup.. */ unsigned int console_mode = 0; +EXPORT_SYMBOL(console_mode); + unsigned int console_devno = -1; +EXPORT_SYMBOL(console_devno); + unsigned int console_irq = -1; +EXPORT_SYMBOL(console_irq); + unsigned long machine_flags; +EXPORT_SYMBOL(machine_flags); + unsigned long elf_hwcap = 0; char elf_platform[ELF_PLATFORM_SIZE]; diff --git a/arch/s390/lib/delay.c b/arch/s390/lib/delay.c index 6ccb9fab055..3f5f680726e 100644 --- a/arch/s390/lib/delay.c +++ b/arch/s390/lib/delay.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -92,6 +93,7 @@ out: local_irq_restore(flags); preempt_enable(); } +EXPORT_SYMBOL(__udelay); /* * Simple udelay variant. To be used on startup and reboot diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c index f0258ca3b17..c634dfbe92e 100644 --- a/arch/s390/mm/init.c +++ b/arch/s390/mm/init.c @@ -40,7 +40,9 @@ DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__((__aligned__(PAGE_SIZE))); + char empty_zero_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); +EXPORT_SYMBOL(empty_zero_page); /* * paging_init() sets up the page tables -- cgit v1.2.3-70-g09d2 From eb32ae8d0e052d1a287f99f93130ea2ad9af317e Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Thu, 26 Mar 2009 15:24:05 +0100 Subject: [S390] cio: Use unbind/bind instead of unregister/register. The common I/O layer may encounter a situation where the device number of a ccw device has changed or a device driver doesn't want to keep a formerly disconnected device becoming operational again. Instead of using device_del()/ device_add() as now, we can just unbind the driver from the device and rebind it to get the desired effect (rebinding) with less overhead. Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/device.c | 27 +++++++-------------------- drivers/s390/cio/device.h | 2 +- drivers/s390/cio/device_fsm.c | 4 ++-- 3 files changed, 10 insertions(+), 23 deletions(-) diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 23d5752349b..71b3b73e8eb 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -681,35 +681,22 @@ get_orphaned_ccwdev_by_dev_id(struct channel_subsystem *css, return dev ? to_ccwdev(dev) : NULL; } -static void -ccw_device_add_changed(struct work_struct *work) -{ - struct ccw_device_private *priv; - struct ccw_device *cdev; - - priv = container_of(work, struct ccw_device_private, kick_work); - cdev = priv->cdev; - if (device_add(&cdev->dev)) { - put_device(&cdev->dev); - return; - } - set_bit(1, &cdev->private->registered); -} - -void ccw_device_do_unreg_rereg(struct work_struct *work) +void ccw_device_do_unbind_bind(struct work_struct *work) { struct ccw_device_private *priv; struct ccw_device *cdev; struct subchannel *sch; + int ret; priv = container_of(work, struct ccw_device_private, kick_work); cdev = priv->cdev; sch = to_subchannel(cdev->dev.parent); - ccw_device_unregister(cdev); - PREPARE_WORK(&cdev->private->kick_work, - ccw_device_add_changed); - queue_work(ccw_device_work, &cdev->private->kick_work); + if (test_bit(1, &cdev->private->registered)) { + device_release_driver(&cdev->dev); + ret = device_attach(&cdev->dev); + WARN_ON(ret == -ENODEV); + } } static void diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h index 0f2e63ea48d..85e01846ca6 100644 --- a/drivers/s390/cio/device.h +++ b/drivers/s390/cio/device.h @@ -80,7 +80,7 @@ void io_subchannel_init_config(struct subchannel *sch); int ccw_device_cancel_halt_clear(struct ccw_device *); -void ccw_device_do_unreg_rereg(struct work_struct *); +void ccw_device_do_unbind_bind(struct work_struct *); void ccw_device_move_to_orphanage(struct work_struct *); int ccw_device_is_orphan(struct ccw_device *); diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index 8df5eaafc5a..95f2f352cb9 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -194,7 +194,7 @@ ccw_device_handle_oper(struct ccw_device *cdev) cdev->id.dev_type != cdev->private->senseid.dev_type || cdev->id.dev_model != cdev->private->senseid.dev_model) { PREPARE_WORK(&cdev->private->kick_work, - ccw_device_do_unreg_rereg); + ccw_device_do_unbind_bind); queue_work(ccw_device_work, &cdev->private->kick_work); return 0; } @@ -366,7 +366,7 @@ static void ccw_device_oper_notify(struct ccw_device *cdev) } /* Driver doesn't want device back. */ ccw_device_set_notoper(cdev); - PREPARE_WORK(&cdev->private->kick_work, ccw_device_do_unreg_rereg); + PREPARE_WORK(&cdev->private->kick_work, ccw_device_do_unbind_bind); queue_work(ccw_device_work, &cdev->private->kick_work); } -- cgit v1.2.3-70-g09d2 From ed04b892e28ae96662fbb3f4c961df5ff3385d28 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Thu, 26 Mar 2009 15:24:06 +0100 Subject: [S390] cio: Try harder to disable subchannel. Acting upon the assumption that cio_disable_subchannel() is only called when we really want to disable the subchannel (a) remove the check for activity (it is already done in ccw_device_offline(), which is the place where it matters) (b) collect pending status via tsch() and ignore it (it can't matter anymore since the subchannel will be disabled). Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/cio.c | 18 ++++++++++-------- drivers/s390/cio/device_fsm.c | 2 +- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 73135c5e9df..2aebb982304 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -472,6 +472,7 @@ EXPORT_SYMBOL_GPL(cio_enable_subchannel); int cio_disable_subchannel(struct subchannel *sch) { char dbf_txt[15]; + int retry; int ret; CIO_TRACE_EVENT (2, "dissch"); @@ -482,16 +483,17 @@ int cio_disable_subchannel(struct subchannel *sch) if (cio_update_schib(sch)) return -ENODEV; - if (scsw_actl(&sch->schib.scsw) != 0) - /* - * the disable function must not be called while there are - * requests pending for completion ! - */ - return -EBUSY; - sch->config.ena = 0; - ret = cio_commit_config(sch); + for (retry = 0; retry < 3; retry++) { + ret = cio_commit_config(sch); + if (ret == -EBUSY) { + struct irb irb; + if (tsch(sch->schid, &irb) != 0) + break; + } else + break; + } sprintf (dbf_txt, "ret:%d", ret); CIO_TRACE_EVENT (2, dbf_txt); return ret; diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index 95f2f352cb9..301d27bf944 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -1052,7 +1052,7 @@ ccw_device_offline_irq(struct ccw_device *cdev, enum dev_event dev_event) sch = to_subchannel(cdev->dev.parent); /* * An interrupt in state offline means a previous disable was not - * successful. Try again. + * successful - should not happen, but we try to disable again. */ cio_disable_subchannel(sch); } -- cgit v1.2.3-70-g09d2 From c08f294a14cb4c2abbd1a9a619c2d8d07afd41e3 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Thu, 26 Mar 2009 15:24:07 +0100 Subject: [S390] cio: Use ccw_device_set_notoper(). Use ccw_device_set_notoper() (which also deletes the device timer and disables the subchannel) instead of simply setting the state to DEV_STATE_NOT_OPER in the generic not operational handling code. This prevents unexpected interrupts popping up for devices that are deemed not operational. Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/device_fsm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index 301d27bf944..87b4bfca080 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -728,7 +728,7 @@ static void ccw_device_generic_notoper(struct ccw_device *cdev, { struct subchannel *sch; - cdev->private->state = DEV_STATE_NOT_OPER; + ccw_device_set_notoper(cdev); sch = to_subchannel(cdev->dev.parent); css_schedule_eval(sch->schid); } -- cgit v1.2.3-70-g09d2 From e74fe0cec92439115630b51195444b89b910800a Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Thu, 26 Mar 2009 15:24:08 +0100 Subject: [S390] cio: ccw device online store - report rc from ccw driver. In case the ccw driver refuses to set a device offline, we should transmit the return code to the caller. Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/device.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 71b3b73e8eb..9be6dd5a566 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -457,12 +457,13 @@ int ccw_device_set_online(struct ccw_device *cdev) return (ret == 0) ? -ENODEV : ret; } -static void online_store_handle_offline(struct ccw_device *cdev) +static int online_store_handle_offline(struct ccw_device *cdev) { if (cdev->private->state == DEV_STATE_DISCONNECTED) ccw_device_remove_disconnected(cdev); - else if (cdev->drv && cdev->drv->set_offline) - ccw_device_set_offline(cdev); + else if (cdev->online && cdev->drv && cdev->drv->set_offline) + return ccw_device_set_offline(cdev); + return 0; } static int online_store_recog_and_online(struct ccw_device *cdev) @@ -530,13 +531,10 @@ static ssize_t online_store (struct device *dev, struct device_attribute *attr, goto out; switch (i) { case 0: - online_store_handle_offline(cdev); - ret = count; + ret = online_store_handle_offline(cdev); break; case 1: ret = online_store_handle_online(cdev, force); - if (!ret) - ret = count; break; default: ret = -EINVAL; @@ -545,7 +543,7 @@ out: if (cdev->drv) module_put(cdev->drv->owner); atomic_set(&cdev->private->onoff, 0); - return ret; + return (ret < 0) ? ret : count; } static ssize_t -- cgit v1.2.3-70-g09d2 From 98c1c6825247c71e3d8a9a5439ba21fce7563014 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 26 Mar 2009 15:24:09 +0100 Subject: [S390] cio/crw: add/fix locking The crw_unregister_handler uses xchg + synchronize_sched when unregistering a crw_handler. This doesn't protect crw_collect_info to potentially jump to NULL since it has unlocked code like this: if (crw_handlers[i]) crw_handlers[i](NULL, NULL, 1); So add a mutex which protects the crw handler array for changes. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/crw.c | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/drivers/s390/cio/crw.c b/drivers/s390/cio/crw.c index 508f88f6420..d157665d0e7 100644 --- a/drivers/s390/cio/crw.c +++ b/drivers/s390/cio/crw.c @@ -9,11 +9,13 @@ */ #include +#include #include #include #include static struct semaphore crw_semaphore; +static DEFINE_MUTEX(crw_handler_mutex); static crw_handler_t crw_handlers[NR_RSCS]; /** @@ -25,11 +27,17 @@ static crw_handler_t crw_handlers[NR_RSCS]; */ int crw_register_handler(int rsc, crw_handler_t handler) { + int rc = 0; + if ((rsc < 0) || (rsc >= NR_RSCS)) return -EINVAL; - if (!cmpxchg(&crw_handlers[rsc], NULL, handler)) - return 0; - return -EBUSY; + mutex_lock(&crw_handler_mutex); + if (crw_handlers[rsc]) + rc = -EBUSY; + else + crw_handlers[rsc] = handler; + mutex_unlock(&crw_handler_mutex); + return rc; } /** @@ -40,8 +48,9 @@ void crw_unregister_handler(int rsc) { if ((rsc < 0) || (rsc >= NR_RSCS)) return; - xchg(&crw_handlers[rsc], NULL); - synchronize_sched(); + mutex_lock(&crw_handler_mutex); + crw_handlers[rsc] = NULL; + mutex_unlock(&crw_handler_mutex); } /* @@ -58,6 +67,8 @@ repeat: ignore = down_interruptible(&crw_semaphore); chain = 0; while (1) { + crw_handler_t handler; + if (unlikely(chain > 1)) { struct crw tmp_crw; @@ -90,10 +101,12 @@ repeat: int i; pr_debug("%s: crw overflow detected!\n", __func__); + mutex_lock(&crw_handler_mutex); for (i = 0; i < NR_RSCS; i++) { if (crw_handlers[i]) crw_handlers[i](NULL, NULL, 1); } + mutex_unlock(&crw_handler_mutex); chain = 0; continue; } @@ -101,10 +114,11 @@ repeat: chain++; continue; } - if (crw_handlers[crw[chain].rsc]) - crw_handlers[crw[chain].rsc](&crw[0], - chain ? &crw[1] : NULL, - 0); + mutex_lock(&crw_handler_mutex); + handler = crw_handlers[crw[chain].rsc]; + if (handler) + handler(&crw[0], chain ? &crw[1] : NULL, 0); + mutex_unlock(&crw_handler_mutex); /* chain is always 0 or 1 here. */ chain = crw[chain].chn ? chain + 1 : 0; } -- cgit v1.2.3-70-g09d2 From 87fa5af80cdd5053b27a546725948c2b74ec82b2 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 26 Mar 2009 15:24:10 +0100 Subject: [S390] cio: ensure single load of irq handler pointer Add barrier to prevent compiler from reloading pointer to irq handler. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/airq.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/s390/cio/airq.c b/drivers/s390/cio/airq.c index fe6cea15bba..d3850dc30e4 100644 --- a/drivers/s390/cio/airq.c +++ b/drivers/s390/cio/airq.c @@ -133,6 +133,8 @@ void do_adapter_IO(u8 isc) while (word) { if (word & INDICATOR_MASK) { airq = airqs[isc][i]; + /* Make sure gcc reads from airqs only once. */ + barrier(); if (likely(airq)) airq->handler(&indicators[isc].byte[i], airq->drv_data); -- cgit v1.2.3-70-g09d2 From 90ac24a5aeb8d4bef001bd3589564a52846d0eee Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Thu, 26 Mar 2009 15:24:11 +0100 Subject: [S390] cio: device scan oom fallback. Since some callers rely on for_each_subchannel_staged to not fail, fall back to brute force scanning using get_subchannel_by_schid in case of a oom situation. Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/css.c | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index a5fc56371ba..1f2e424596a 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -83,6 +83,25 @@ static int call_fn_unknown_sch(struct subchannel_id schid, void *data) return rc; } +static int call_fn_all_sch(struct subchannel_id schid, void *data) +{ + struct cb_data *cb = data; + struct subchannel *sch; + int rc = 0; + + sch = get_subchannel_by_schid(schid); + if (sch) { + if (cb->fn_known_sch) + rc = cb->fn_known_sch(sch, cb->data); + put_device(&sch->dev); + } else { + if (cb->fn_unknown_sch) + rc = cb->fn_unknown_sch(schid, cb->data); + } + + return rc; +} + int for_each_subchannel_staged(int (*fn_known)(struct subchannel *, void *), int (*fn_unknown)(struct subchannel_id, void *), void *data) @@ -90,13 +109,17 @@ int for_each_subchannel_staged(int (*fn_known)(struct subchannel *, void *), struct cb_data cb; int rc; - cb.set = idset_sch_new(); - if (!cb.set) - return -ENOMEM; - idset_fill(cb.set); cb.data = data; cb.fn_known_sch = fn_known; cb.fn_unknown_sch = fn_unknown; + + cb.set = idset_sch_new(); + if (!cb.set) + /* fall back to brute force scanning in case of oom */ + return for_each_subchannel(call_fn_all_sch, &cb); + + idset_fill(cb.set); + /* Process registered subchannels. */ rc = bus_for_each_dev(&css_bus_type, NULL, &cb, call_fn_known_sch); if (rc) -- cgit v1.2.3-70-g09d2 From a1f640734ab57d548a3fdadad6b869da534d4ecb Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Thu, 26 Mar 2009 15:24:12 +0100 Subject: [S390] cio: airq - fix array boundary MAX_ISC is a valid isc number, so arrays with an index of isc need to have a length of MAX_ISC+1 Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/airq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/s390/cio/airq.c b/drivers/s390/cio/airq.c index d3850dc30e4..65d2e769dfa 100644 --- a/drivers/s390/cio/airq.c +++ b/drivers/s390/cio/airq.c @@ -34,8 +34,8 @@ struct airq_t { void *drv_data; }; -static union indicator_t indicators[MAX_ISC]; -static struct airq_t *airqs[MAX_ISC][NR_AIRQS]; +static union indicator_t indicators[MAX_ISC+1]; +static struct airq_t *airqs[MAX_ISC+1][NR_AIRQS]; static int register_airq(struct airq_t *airq, u8 isc) { -- cgit v1.2.3-70-g09d2 From 40c9f9992bc1caa1bb890bd8163361dbf2eefa86 Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Thu, 26 Mar 2009 15:24:13 +0100 Subject: [S390] cio: ccw group online store - report rcs to the caller. In case the ccw group driver refuses to set a device [on|off]line, we should transmit the return code to the caller. Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/ccwgroup.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index 918e6fce257..ec2742813bf 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c @@ -391,27 +391,28 @@ ccwgroup_online_store (struct device *dev, struct device_attribute *attr, const unsigned long value; int ret; - gdev = to_ccwgroupdev(dev); if (!dev->driver) - return count; + return -ENODEV; + + gdev = to_ccwgroupdev(dev); + gdrv = to_ccwgroupdrv(dev->driver); - gdrv = to_ccwgroupdrv (gdev->dev.driver); if (!try_module_get(gdrv->owner)) return -EINVAL; ret = strict_strtoul(buf, 0, &value); if (ret) goto out; - ret = count; + if (value == 1) - ccwgroup_set_online(gdev); + ret = ccwgroup_set_online(gdev); else if (value == 0) - ccwgroup_set_offline(gdev); + ret = ccwgroup_set_offline(gdev); else ret = -EINVAL; out: module_put(gdrv->owner); - return ret; + return (ret == 0) ? count : ret; } static ssize_t -- cgit v1.2.3-70-g09d2 From 50f1548399b7bd00ceb38c84a84463a89c82afe8 Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Thu, 26 Mar 2009 15:24:14 +0100 Subject: [S390] cio: fix sanity checks in ccwgroup driver. Some sanity checks in the ccw group driver test the output of container_of macros to be !NULL. Test the input parameters instead. Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/ccwgroup.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index ec2742813bf..2becedbe888 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c @@ -454,13 +454,17 @@ ccwgroup_remove (struct device *dev) struct ccwgroup_device *gdev; struct ccwgroup_driver *gdrv; + device_remove_file(dev, &dev_attr_online); + + if (!dev->driver) + return 0; + gdev = to_ccwgroupdev(dev); gdrv = to_ccwgroupdrv(dev->driver); - device_remove_file(dev, &dev_attr_online); - - if (gdrv && gdrv->remove) + if (gdrv->remove) gdrv->remove(gdev); + return 0; } @@ -469,9 +473,13 @@ static void ccwgroup_shutdown(struct device *dev) struct ccwgroup_device *gdev; struct ccwgroup_driver *gdrv; + if (!dev->driver) + return; + gdev = to_ccwgroupdev(dev); gdrv = to_ccwgroupdrv(dev->driver); - if (gdrv && gdrv->shutdown) + + if (gdrv->shutdown) gdrv->shutdown(gdev); } -- cgit v1.2.3-70-g09d2 From e909074bb91773680c0b2e49ea8af9f85c6f59bd Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Thu, 26 Mar 2009 15:24:15 +0100 Subject: [S390] cio: ccw group fix unbind behaviour. For a ccw group device unbinding it from its driver should do the same as a call to ungroup, since this virtual device can not exist without a driver. Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/ccwgroup.c | 42 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index 2becedbe888..86b136cb09e 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c @@ -314,16 +314,32 @@ error: } EXPORT_SYMBOL(ccwgroup_create_from_string); -static int __init -init_ccwgroup (void) +static int ccwgroup_notifier(struct notifier_block *nb, unsigned long action, + void *data); + +static struct notifier_block ccwgroup_nb = { + .notifier_call = ccwgroup_notifier +}; + +static int __init init_ccwgroup(void) { - return bus_register (&ccwgroup_bus_type); + int ret; + + ret = bus_register(&ccwgroup_bus_type); + if (ret) + return ret; + + ret = bus_register_notifier(&ccwgroup_bus_type, &ccwgroup_nb); + if (ret) + bus_unregister(&ccwgroup_bus_type); + + return ret; } -static void __exit -cleanup_ccwgroup (void) +static void __exit cleanup_ccwgroup(void) { - bus_unregister (&ccwgroup_bus_type); + bus_unregister_notifier(&ccwgroup_bus_type, &ccwgroup_nb); + bus_unregister(&ccwgroup_bus_type); } module_init(init_ccwgroup); @@ -455,6 +471,7 @@ ccwgroup_remove (struct device *dev) struct ccwgroup_driver *gdrv; device_remove_file(dev, &dev_attr_online); + device_remove_file(dev, &dev_attr_ungroup); if (!dev->driver) return 0; @@ -492,6 +509,19 @@ static struct bus_type ccwgroup_bus_type = { .shutdown = ccwgroup_shutdown, }; + +static int ccwgroup_notifier(struct notifier_block *nb, unsigned long action, + void *data) +{ + struct device *dev = data; + + if (action == BUS_NOTIFY_UNBIND_DRIVER) + device_schedule_callback(dev, ccwgroup_ungroup_callback); + + return NOTIFY_OK; +} + + /** * ccwgroup_driver_register() - register a ccw group driver * @cdriver: driver to be registered -- cgit v1.2.3-70-g09d2 From 94cbc203bee4ea87bd49ad56f6c5381bc10d8b6b Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Thu, 26 Mar 2009 15:24:16 +0100 Subject: [S390] cio: fix wrong buffer access in cio_ignore_write Writing only spaces to /proc/cio_ignore will cause a buffer overflow since the size_t value i will not become negative and so buf[-1UL] is accessed. Change the value of i to ssize_t. Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/blacklist.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c index fe00be3675c..6565f027791 100644 --- a/drivers/s390/cio/blacklist.c +++ b/drivers/s390/cio/blacklist.c @@ -336,8 +336,7 @@ cio_ignore_write(struct file *file, const char __user *user_buf, size_t user_len, loff_t *offset) { char *buf; - size_t i; - ssize_t rc, ret; + ssize_t rc, ret, i; if (*offset) return -EINVAL; -- cgit v1.2.3-70-g09d2 From 17e7d87d9f88480a75fc9c5978ab38131a074277 Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Thu, 26 Mar 2009 15:24:17 +0100 Subject: [S390] cio: fix rc generation after chsc call In some situations a rc in __chsc_do_secm will be overwritten by another one. This shouldn't do harm since todays callers don't check for _specific_ errors but fix it for the sake of correctness. Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/chsc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 7399b07a1ae..883f16f96f2 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -589,6 +589,7 @@ __chsc_do_secm(struct channel_subsystem *css, int enable, void *page) case 0x0102: case 0x0103: ret = -EINVAL; + break; default: ret = chsc_error_from_response(secm_area->response.code); } -- cgit v1.2.3-70-g09d2 From 7a968f0565dc5d0518c784465cc8ce32408102b7 Mon Sep 17 00:00:00 2001 From: Peter Oberparleiter Date: Thu, 26 Mar 2009 15:24:18 +0100 Subject: [S390] cio: incorrect status check in interrogate function Fix incorrect check for active I/O in interrogate function. Signed-off-by: Peter Oberparleiter Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/device_ops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c index eabcc42d63d..151754d5474 100644 --- a/drivers/s390/cio/device_ops.c +++ b/drivers/s390/cio/device_ops.c @@ -680,7 +680,7 @@ int ccw_device_tm_intrg(struct ccw_device *cdev) if (cdev->private->state != DEV_STATE_ONLINE) return -EIO; if (!scsw_is_tm(&sch->schib.scsw) || - !(scsw_actl(&sch->schib.scsw) | SCSW_ACTL_START_PEND)) + !(scsw_actl(&sch->schib.scsw) & SCSW_ACTL_START_PEND)) return -EINVAL; return cio_tm_intrg(sch); } -- cgit v1.2.3-70-g09d2 From 0cc110651bed4612074eeb445a23418a5ee34cd0 Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Thu, 26 Mar 2009 15:24:19 +0100 Subject: [S390] cio: remove unused local variable Remove unused subchannel pointer in io_subchannel_recog_done. Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/device.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 9be6dd5a566..a048a5afa12 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -1019,8 +1019,6 @@ static void ccw_device_call_sch_unregister(struct work_struct *work) void io_subchannel_recog_done(struct ccw_device *cdev) { - struct subchannel *sch; - if (css_init_done == 0) { cdev->private->flags.recog_done = 1; return; @@ -1031,7 +1029,6 @@ io_subchannel_recog_done(struct ccw_device *cdev) /* Remove device found not operational. */ if (!get_device(&cdev->dev)) break; - sch = to_subchannel(cdev->dev.parent); PREPARE_WORK(&cdev->private->kick_work, ccw_device_call_sch_unregister); queue_work(slow_path_wq, &cdev->private->kick_work); -- cgit v1.2.3-70-g09d2 From 56e25e9777bf15365293e27a3256eb9214a11edf Mon Sep 17 00:00:00 2001 From: Peter Oberparleiter Date: Thu, 26 Mar 2009 15:24:20 +0100 Subject: [S390] cio: prevent workqueue deadlock Subchannel reprobing can block the kslowcrw workqueue indefinitely while waiting for device recognition to finish which is also scheduled to run on kslowcrw. Prevent this deadlock by moving the waiting portion of subchannel reprobing to the cio workqueue. Signed-off-by: Peter Oberparleiter Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/css.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 1f2e424596a..8446d15e448 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -533,6 +533,17 @@ static int reprobe_subchannel(struct subchannel_id schid, void *data) return ret; } +static void reprobe_after_idle(struct work_struct *unused) +{ + /* Make sure initial subchannel scan is done. */ + wait_event(ccw_device_init_wq, + atomic_read(&ccw_device_init_count) == 0); + if (need_reprobe) + css_schedule_reprobe(); +} + +static DECLARE_WORK(reprobe_idle_work, reprobe_after_idle); + /* Work function used to reprobe all unregistered subchannels. */ static void reprobe_all(struct work_struct *unused) { @@ -540,10 +551,12 @@ static void reprobe_all(struct work_struct *unused) CIO_MSG_EVENT(4, "reprobe start\n"); - need_reprobe = 0; /* Make sure initial subchannel scan is done. */ - wait_event(ccw_device_init_wq, - atomic_read(&ccw_device_init_count) == 0); + if (atomic_read(&ccw_device_init_count) != 0) { + queue_work(ccw_device_work, &reprobe_idle_work); + return; + } + need_reprobe = 0; ret = for_each_subchannel_staged(NULL, reprobe_subchannel, NULL); CIO_MSG_EVENT(4, "reprobe done (rc=%d, need_reprobe=%d)\n", ret, -- cgit v1.2.3-70-g09d2 From 8283cb43ab3e92a039d3486a0f6253df95a5fa55 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Thu, 26 Mar 2009 15:24:21 +0100 Subject: [S390] clock sync mode flags The clock sync mode flag CLOCK_SYNC_STP is not cleared when stp is set offline. In this case the get_sync_clock() function returns -EACCESS and the dasd driver will block all i/o until stp is enabled again. In addition get_sync_clock can return -EACCESS if the clock is not in sync instead of -EAGAIN. Rework the stp/etr online handling to fix these problems. Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/time.c | 71 ++++++++++++++++++++++++++++++------------------- 1 file changed, 44 insertions(+), 27 deletions(-) diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index fc468cae446..f72d41068dc 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c @@ -331,6 +331,7 @@ static unsigned long long adjust_time(unsigned long long old, } static DEFINE_PER_CPU(atomic_t, clock_sync_word); +static DEFINE_MUTEX(clock_sync_mutex); static unsigned long clock_sync_flags; #define CLOCK_SYNC_HAS_ETR 0 @@ -394,6 +395,20 @@ static void enable_sync_clock(void) atomic_set_mask(0x80000000, sw_ptr); } +/* + * Function to check if the clock is in sync. + */ +static inline int check_sync_clock(void) +{ + atomic_t *sw_ptr; + int rc; + + sw_ptr = &get_cpu_var(clock_sync_word); + rc = (atomic_read(sw_ptr) & 0x80000000U) != 0; + put_cpu_var(clock_sync_sync); + return rc; +} + /* Single threaded workqueue used for etr and stp sync events */ static struct workqueue_struct *time_sync_wq; @@ -485,6 +500,8 @@ static void etr_reset(void) if (etr_setr(&etr_eacr) == 0) { etr_tolec = get_clock(); set_bit(CLOCK_SYNC_HAS_ETR, &clock_sync_flags); + if (etr_port0_online && etr_port1_online) + set_bit(CLOCK_SYNC_ETR, &clock_sync_flags); } else if (etr_port0_online || etr_port1_online) { pr_warning("The real or virtual hardware system does " "not provide an ETR interface\n"); @@ -533,8 +550,7 @@ void etr_switch_to_local(void) { if (!etr_eacr.sl) return; - if (test_bit(CLOCK_SYNC_ETR, &clock_sync_flags)) - disable_sync_clock(NULL); + disable_sync_clock(NULL); set_bit(ETR_EVENT_SWITCH_LOCAL, &etr_events); queue_work(time_sync_wq, &etr_work); } @@ -549,8 +565,7 @@ void etr_sync_check(void) { if (!etr_eacr.es) return; - if (test_bit(CLOCK_SYNC_ETR, &clock_sync_flags)) - disable_sync_clock(NULL); + disable_sync_clock(NULL); set_bit(ETR_EVENT_SYNC_CHECK, &etr_events); queue_work(time_sync_wq, &etr_work); } @@ -914,7 +929,7 @@ static struct etr_eacr etr_handle_update(struct etr_aib *aib, * Do not try to get the alternate port aib if the clock * is not in sync yet. */ - if (!test_bit(CLOCK_SYNC_STP, &clock_sync_flags) && !eacr.es) + if (!check_sync_clock()) return eacr; /* @@ -997,7 +1012,6 @@ static void etr_work_fn(struct work_struct *work) on_each_cpu(disable_sync_clock, NULL, 1); del_timer_sync(&etr_timer); etr_update_eacr(eacr); - clear_bit(CLOCK_SYNC_ETR, &clock_sync_flags); goto out_unlock; } @@ -1071,18 +1085,13 @@ static void etr_work_fn(struct work_struct *work) /* Both ports not usable. */ eacr.es = eacr.sl = 0; sync_port = -1; - clear_bit(CLOCK_SYNC_ETR, &clock_sync_flags); } - if (!test_bit(CLOCK_SYNC_ETR, &clock_sync_flags)) - eacr.es = 0; - /* * If the clock is in sync just update the eacr and return. * If there is no valid sync port wait for a port update. */ - if (test_bit(CLOCK_SYNC_STP, &clock_sync_flags) || - eacr.es || sync_port < 0) { + if (check_sync_clock() || sync_port < 0) { etr_update_eacr(eacr); etr_set_tolec_timeout(now); goto out_unlock; @@ -1103,13 +1112,11 @@ static void etr_work_fn(struct work_struct *work) * and set up a timer to try again after 0.5 seconds */ etr_update_eacr(eacr); - set_bit(CLOCK_SYNC_ETR, &clock_sync_flags); if (now < etr_tolec + (1600000 << 12) || etr_sync_clock_stop(&aib, sync_port) != 0) { /* Sync failed. Try again in 1/2 second. */ eacr.es = 0; etr_update_eacr(eacr); - clear_bit(CLOCK_SYNC_ETR, &clock_sync_flags); etr_set_sync_timeout(); } else etr_set_tolec_timeout(now); @@ -1191,19 +1198,30 @@ static ssize_t etr_online_store(struct sys_device *dev, return -EINVAL; if (!test_bit(CLOCK_SYNC_HAS_ETR, &clock_sync_flags)) return -EOPNOTSUPP; + mutex_lock(&clock_sync_mutex); if (dev == &etr_port0_dev) { if (etr_port0_online == value) - return count; /* Nothing to do. */ + goto out; /* Nothing to do. */ etr_port0_online = value; + if (etr_port0_online && etr_port1_online) + set_bit(CLOCK_SYNC_ETR, &clock_sync_flags); + else + clear_bit(CLOCK_SYNC_ETR, &clock_sync_flags); set_bit(ETR_EVENT_PORT0_CHANGE, &etr_events); queue_work(time_sync_wq, &etr_work); } else { if (etr_port1_online == value) - return count; /* Nothing to do. */ + goto out; /* Nothing to do. */ etr_port1_online = value; + if (etr_port0_online && etr_port1_online) + set_bit(CLOCK_SYNC_ETR, &clock_sync_flags); + else + clear_bit(CLOCK_SYNC_ETR, &clock_sync_flags); set_bit(ETR_EVENT_PORT1_CHANGE, &etr_events); queue_work(time_sync_wq, &etr_work); } +out: + mutex_unlock(&clock_sync_mutex); return count; } @@ -1471,8 +1489,6 @@ static void stp_timing_alert(struct stp_irq_parm *intparm) */ void stp_sync_check(void) { - if (!test_bit(CLOCK_SYNC_STP, &clock_sync_flags)) - return; disable_sync_clock(NULL); queue_work(time_sync_wq, &stp_work); } @@ -1485,8 +1501,6 @@ void stp_sync_check(void) */ void stp_island_check(void) { - if (!test_bit(CLOCK_SYNC_STP, &clock_sync_flags)) - return; disable_sync_clock(NULL); queue_work(time_sync_wq, &stp_work); } @@ -1513,10 +1527,6 @@ static int stp_sync_clock(void *data) enable_sync_clock(); - set_bit(CLOCK_SYNC_STP, &clock_sync_flags); - if (test_and_clear_bit(CLOCK_SYNC_ETR, &clock_sync_flags)) - queue_work(time_sync_wq, &etr_work); - rc = 0; if (stp_info.todoff[0] || stp_info.todoff[1] || stp_info.todoff[2] || stp_info.todoff[3] || @@ -1535,9 +1545,6 @@ static int stp_sync_clock(void *data) if (rc) { disable_sync_clock(NULL); stp_sync->in_sync = -EAGAIN; - clear_bit(CLOCK_SYNC_STP, &clock_sync_flags); - if (etr_port0_online || etr_port1_online) - queue_work(time_sync_wq, &etr_work); } else stp_sync->in_sync = 1; xchg(&first, 0); @@ -1569,6 +1576,10 @@ static void stp_work_fn(struct work_struct *work) if (rc || stp_info.c == 0) goto out_unlock; + /* Skip synchronization if the clock is already in sync. */ + if (check_sync_clock()) + goto out_unlock; + memset(&stp_sync, 0, sizeof(stp_sync)); get_online_cpus(); atomic_set(&stp_sync.cpus, num_online_cpus() - 1); @@ -1684,8 +1695,14 @@ static ssize_t stp_online_store(struct sysdev_class *class, return -EINVAL; if (!test_bit(CLOCK_SYNC_HAS_STP, &clock_sync_flags)) return -EOPNOTSUPP; + mutex_lock(&clock_sync_mutex); stp_online = value; + if (stp_online) + set_bit(CLOCK_SYNC_STP, &clock_sync_flags); + else + clear_bit(CLOCK_SYNC_STP, &clock_sync_flags); queue_work(time_sync_wq, &stp_work); + mutex_unlock(&clock_sync_mutex); return count; } -- cgit v1.2.3-70-g09d2 From 4b2a8b6043979f1e6cc8aaa4116c95b31ae942ec Mon Sep 17 00:00:00 2001 From: Gerald Schaefer Date: Thu, 26 Mar 2009 15:24:22 +0100 Subject: [S390] kernel: Disable switch_amode by default Disable switch_amode by default because pagetable walk on pre z9 hardware has negative performance impact. Signed-off-by: Gerald Schaefer Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/setup.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 0b8ad7b4f8f..dd3c5173627 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -301,11 +301,7 @@ static int __init early_parse_mem(char *p) early_param("mem", early_parse_mem); #ifdef CONFIG_S390_SWITCH_AMODE -#ifdef CONFIG_PGSTE -unsigned int switch_amode = 1; -#else unsigned int switch_amode = 0; -#endif EXPORT_SYMBOL_GPL(switch_amode); static int set_amode_and_uaccess(unsigned long user_amode, -- cgit v1.2.3-70-g09d2 From feed9b62da6e2997612143ae4b857ec7f33c810d Mon Sep 17 00:00:00 2001 From: Felix Beck Date: Thu, 26 Mar 2009 15:24:23 +0100 Subject: [S390] Add zcrypt section in MAINTAINERS Add zcrypt section in S390 part of MAINTAINERS file. Signed-off-by: Felix Beck Signed-off-by: Ralph Wuerthner Signed-off-by: Martin Schwidefsky --- MAINTAINERS | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 5d460c9d1c2..fc1e8d6250e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3726,6 +3726,15 @@ L: linux-s390@vger.kernel.org W: http://www.ibm.com/developerworks/linux/linux390/ S: Supported +S390 ZCRYPT DRIVER +P: Felix Beck +M: felix.beck@de.ibm.com +P: Ralph Wuerthner +M: ralph.wuerthner@de.ibm.com +M: linux390@de.ibm.com +L: linux-s390@vger.kernel.org +S: Supported + S390 ZFCP DRIVER P: Christof Schmitt M: christof.schmitt@de.ibm.com -- cgit v1.2.3-70-g09d2 From b454740246d14b0a9c00220696f9020eaa15ca12 Mon Sep 17 00:00:00 2001 From: Jan Glauber Date: Thu, 26 Mar 2009 15:24:24 +0100 Subject: [S390] qdio: add missing tiq_list locking Add a mutex to protect the tiq_list. Although reading the list is done using RCU adding and removing elements from the list must still happen locked since multiple qdio devices may change the list in parallel otherwise. Signed-off-by: Jan Glauber Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/qdio_main.c | 1 + drivers/s390/cio/qdio_thinint.c | 10 +++++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 10cb0f8726e..5100996201d 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -1112,6 +1112,7 @@ int qdio_shutdown(struct ccw_device *cdev, int how) if (!irq_ptr) return -ENODEV; + BUG_ON(irqs_disabled()); DBF_EVENT("qshutdown:%4x", cdev->private->schid.sch_no); mutex_lock(&irq_ptr->setup_mutex); diff --git a/drivers/s390/cio/qdio_thinint.c b/drivers/s390/cio/qdio_thinint.c index 8e90e147b74..981044c8386 100644 --- a/drivers/s390/cio/qdio_thinint.c +++ b/drivers/s390/cio/qdio_thinint.c @@ -31,6 +31,7 @@ /* list of thin interrupt input queues */ static LIST_HEAD(tiq_list); +DEFINE_MUTEX(tiq_list_lock); /* adapter local summary indicator */ static unsigned char *tiqdio_alsi; @@ -95,10 +96,10 @@ void tiqdio_add_input_queues(struct qdio_irq *irq_ptr) if (!css_qdio_omit_svs && irq_ptr->siga_flag.sync) css_qdio_omit_svs = 1; - for_each_input_queue(irq_ptr, q, i) { + mutex_lock(&tiq_list_lock); + for_each_input_queue(irq_ptr, q, i) list_add_rcu(&q->entry, &tiq_list); - synchronize_rcu(); - } + mutex_unlock(&tiq_list_lock); xchg(irq_ptr->dsci, 1); tasklet_schedule(&tiqdio_tasklet); } @@ -118,7 +119,10 @@ void tiqdio_remove_input_queues(struct qdio_irq *irq_ptr) /* if establish triggered an error */ if (!q || !q->entry.prev || !q->entry.next) continue; + + mutex_lock(&tiq_list_lock); list_del_rcu(&q->entry); + mutex_unlock(&tiq_list_lock); synchronize_rcu(); } } -- cgit v1.2.3-70-g09d2 From e4c14e2085cd32f61e9ffc47d5b20d4f5f7639f3 Mon Sep 17 00:00:00 2001 From: Jan Glauber Date: Thu, 26 Mar 2009 15:24:25 +0100 Subject: [S390] qdio: Dont call qdio_shutdown in case qdio_activate fails Remove the call to qdio_shutdown from qdio_activate since the upper-layer drivers are responsible to call qdio_shutdown when qdio_activate returns with an error. Signed-off-by: Jan Glauber Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/qdio_main.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 5100996201d..fa902703996 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -1404,9 +1404,8 @@ int qdio_activate(struct ccw_device *cdev) switch (irq_ptr->state) { case QDIO_IRQ_STATE_STOPPED: case QDIO_IRQ_STATE_ERR: - mutex_unlock(&irq_ptr->setup_mutex); - qdio_shutdown(cdev, QDIO_FLAG_CLEANUP_USING_CLEAR); - return -EIO; + rc = -EIO; + break; default: qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ACTIVE); rc = 0; -- cgit v1.2.3-70-g09d2 From c38f96080955854e54df9cb392bc674e1ae330e1 Mon Sep 17 00:00:00 2001 From: Jan Glauber Date: Thu, 26 Mar 2009 15:24:26 +0100 Subject: [S390] qdio: proper kill of qdio tasklets The queue tasklets were stopped with tasklet_disable. Although tasklet_disable prevents the tasklet from beeing executed it is still possible that a tasklet is scheduled on a CPU at that point. A following qdio_establish calls tasklet_init which clears the tasklet count and the tasklet state leading to the following Oops: <2>kernel BUG at kernel/softirq.c:392! <4>illegal operation: 0001 [#1] SMP <4>Modules linked in: iptable_filter ip_tables x_tables dm_round_robin dm_multipath scsi_dh sg sd_mod crc_t10dif nfs lockd nfs _acl sunrpc fuse loop dm_mod qeth_l3 ipv6 zfcp qeth scsi_transport_fc qdio scsi_tgt scsi_mod chsc_sch ccwgroup dasd_eckd_mod dasdm od ext3 mbcache jbd <4>Supported: Yes <4>CPU: 0 Not tainted 2.6.27.13-1.1.mz13-default #1 <4>Process blast.LzS_64 (pid: 16445, task: 000000006cc02538, ksp: 000000006cb67998) <4>Krnl PSW : 0704c00180000000 00000000001399f4 (tasklet_action+0xc8/0x1d4) <4> R:0 T:1 IO:1 EX:1 Key:0 M:1 W:0 P:0 AS:3 CC:0 PM:0 EA:3 <4>Krnl GPRS: ffffffff00000030 0000000000000002 0000000000000002 fffffffffffffffe <4> 000000000013aabe 00000000003b6a18 fffffffffffffffd 0000000000000000 <4> 00000000006705a8 000000007d0914a8 000000007d0914b0 000000007fecfd30 <4> 0000000000000000 00000000003b63e8 000000007fecfd90 000000007fecfd30 <4>Krnl Code: 00000000001399e8: b9200021 cgr %r2,%r1 <4> 00000000001399ec: a7740004 brc 7,1399f4 <4> 00000000001399f0: a7f40001 brc 15,1399f2 <4> >00000000001399f4: c0100027e8ee larl %r1,636bd0 <4> 00000000001399fa: bf1f1008 icm %r1,15,8(%r1) <4> 00000000001399fe: a7840019 brc 8,139a30 <4> 0000000000139a02: c0300027e8ef larl %r3,636be0 <4> 0000000000139a08: e3c030000004 lg %r12,0(%r3) <4>Call Trace: <4>([<0000000000139c12>] tasklet_hi_action+0x112/0x1d4) <4> [<000000000013aabe>] __do_softirq+0xde/0x1c4 <4> [<000000000010fa2e>] do_softirq+0x96/0xb0 <4> [<000000000013a8d8>] irq_exit+0x70/0xcc <4> [<000000000010d1d8>] do_extint+0xf0/0x110 <4> [<0000000000113b10>] ext_no_vtime+0x16/0x1a <4> [<000003e0000a3662>] ext3_dirty_inode+0xe6/0xe8 [ext3] <4>([<00000000001f6cf2>] __mark_inode_dirty+0x52/0x1d4) <4> [<000003e0000a44f0>] ext3_ordered_write_end+0x138/0x190 [ext3] <4> [<000000000018d5ec>] generic_perform_write+0x174/0x230 <4> [<0000000000190144>] generic_file_buffered_write+0xb4/0x194 <4> [<0000000000190864>] __generic_file_aio_write_nolock+0x418/0x454 <4> [<0000000000190ee2>] generic_file_aio_write+0x76/0xe4 <4> [<000003e0000a05c2>] ext3_file_write+0x3e/0xc8 [ext3] <4> [<00000000001cc2fe>] do_sync_write+0xd6/0x120 <4> [<00000000001ccfc8>] vfs_write+0xac/0x184 <4> [<00000000001cd218>] SyS_write+0x68/0xe0 <4> [<0000000000113402>] sysc_noemu+0x10/0x16 <4> [<0000020000043188>] 0x20000043188 <4>Last Breaking-Event-Address: <4> [<00000000001399f0>] tasklet_action+0xc4/0x1d4 <6>qdio: 0.0.c61b ZFCP on SC f67 using AI:1 QEBSM:0 PCI:1 TDD:1 SIGA: W AOP <4> <0>Kernel panic - not syncing: Fatal exception in interrupt Use tasklet_kill instead of tasklet_disbale. Since tasklet_schedule must not be called after tasklet_kill use the QDIO_IRQ_STATE_STOPPED to inidicate that a queue is going down and prevent further tasklet schedules in that case. Remove superflous tasklet_schedule from input queue setup, at that time the queues are not ready so the schedule results in a NOP. Signed-off-by: Jan Glauber Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/qdio_main.c | 35 ++++++++++++++++++++++++----------- drivers/s390/cio/qdio_thinint.c | 8 ++++---- 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index fa902703996..1974ec7bf0e 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -778,21 +778,17 @@ static void __qdio_outbound_processing(struct qdio_q *q) spin_unlock_irqrestore(&q->lock, flags); - if (queue_type(q) == QDIO_ZFCP_QFMT) { + if (queue_type(q) == QDIO_ZFCP_QFMT) if (!pci_out_supported(q) && !qdio_outbound_q_done(q)) - tasklet_schedule(&q->tasklet); - return; - } + goto sched; /* bail out for HiperSockets unicast queues */ if (queue_type(q) == QDIO_IQDIO_QFMT && !multicast_outbound(q)) return; if ((queue_type(q) == QDIO_IQDIO_QFMT) && - (atomic_read(&q->nr_buf_used)) > QDIO_IQDIO_POLL_LVL) { - tasklet_schedule(&q->tasklet); - return; - } + (atomic_read(&q->nr_buf_used)) > QDIO_IQDIO_POLL_LVL) + goto sched; if (q->u.out.pci_out_enabled) return; @@ -810,6 +806,12 @@ static void __qdio_outbound_processing(struct qdio_q *q) qdio_perf_stat_inc(&perf_stats.debug_tl_out_timer); } } + return; + +sched: + if (unlikely(q->irq_ptr->state == QDIO_IRQ_STATE_STOPPED)) + return; + tasklet_schedule(&q->tasklet); } /* outbound tasklet */ @@ -822,6 +824,9 @@ void qdio_outbound_processing(unsigned long data) void qdio_outbound_timer(unsigned long data) { struct qdio_q *q = (struct qdio_q *)data; + + if (unlikely(q->irq_ptr->state == QDIO_IRQ_STATE_STOPPED)) + return; tasklet_schedule(&q->tasklet); } @@ -863,6 +868,9 @@ static void qdio_int_handler_pci(struct qdio_irq *irq_ptr) int i; struct qdio_q *q; + if (unlikely(irq_ptr->state == QDIO_IRQ_STATE_STOPPED)) + return; + qdio_perf_stat_inc(&perf_stats.pci_int); for_each_input_queue(irq_ptr, q, i) @@ -1090,11 +1098,11 @@ static void qdio_shutdown_queues(struct ccw_device *cdev) int i; for_each_input_queue(irq_ptr, q, i) - tasklet_disable(&q->tasklet); + tasklet_kill(&q->tasklet); for_each_output_queue(irq_ptr, q, i) { - tasklet_disable(&q->tasklet); del_timer(&q->u.out.timer); + tasklet_kill(&q->tasklet); } } @@ -1125,6 +1133,12 @@ int qdio_shutdown(struct ccw_device *cdev, int how) return 0; } + /* + * Indicate that the device is going down. Scheduling the queue + * tasklets is forbidden from here on. + */ + qdio_set_state(irq_ptr, QDIO_IRQ_STATE_STOPPED); + tiqdio_remove_input_queues(irq_ptr); qdio_shutdown_queues(cdev); qdio_shutdown_debug_entries(irq_ptr, cdev); @@ -1556,7 +1570,6 @@ static void handle_outbound(struct qdio_q *q, unsigned int callflags, qdio_perf_stat_inc(&perf_stats.fast_requeue); } out: - /* Fixme: could wait forever if called from process context */ tasklet_schedule(&q->tasklet); } diff --git a/drivers/s390/cio/qdio_thinint.c b/drivers/s390/cio/qdio_thinint.c index 981044c8386..c7c5512a892 100644 --- a/drivers/s390/cio/qdio_thinint.c +++ b/drivers/s390/cio/qdio_thinint.c @@ -101,7 +101,6 @@ void tiqdio_add_input_queues(struct qdio_irq *irq_ptr) list_add_rcu(&q->entry, &tiq_list); mutex_unlock(&tiq_list_lock); xchg(irq_ptr->dsci, 1); - tasklet_schedule(&tiqdio_tasklet); } /* @@ -159,7 +158,6 @@ static void __tiqdio_inbound_processing(struct qdio_q *q) */ qdio_check_outbound_after_thinint(q); -again: if (!qdio_inbound_q_moved(q)) return; @@ -167,7 +165,8 @@ again: if (!tiqdio_inbound_q_done(q)) { qdio_perf_stat_inc(&perf_stats.thinint_inbound_loop); - goto again; + if (likely(q->irq_ptr->state != QDIO_IRQ_STATE_STOPPED)) + tasklet_schedule(&q->tasklet); } qdio_stop_polling(q); @@ -177,7 +176,8 @@ again: */ if (!tiqdio_inbound_q_done(q)) { qdio_perf_stat_inc(&perf_stats.thinint_inbound_loop2); - goto again; + if (likely(q->irq_ptr->state != QDIO_IRQ_STATE_STOPPED)) + tasklet_schedule(&q->tasklet); } } -- cgit v1.2.3-70-g09d2 From 700e982f28f5e13cef8eea93ac8c6702f699d894 Mon Sep 17 00:00:00 2001 From: Jan Glauber Date: Thu, 26 Mar 2009 15:24:27 +0100 Subject: [S390] qdio: call qdio_free also if qdio_shutdown fails qdio_cleanup is a wrapper function that should call qdio_shutdown and qdio_free. qdio_free was not called if an error occured in qdio_shutdown resulting in a missing free of allocated resources. Call qdio_free regardless of the return value of qdio_shutdown. Signed-off-by: Jan Glauber Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/qdio_main.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 1974ec7bf0e..8e6bc9cddfa 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -1073,8 +1073,9 @@ EXPORT_SYMBOL_GPL(qdio_get_ssqd_desc); * @cdev: associated ccw device * @how: use halt or clear to shutdown * - * This function calls qdio_shutdown() for @cdev with method @how - * and on success qdio_free() for @cdev. + * This function calls qdio_shutdown() for @cdev with method @how. + * and qdio_free(). The qdio_free() return value is ignored since + * !irq_ptr is already checked. */ int qdio_cleanup(struct ccw_device *cdev, int how) { @@ -1085,8 +1086,8 @@ int qdio_cleanup(struct ccw_device *cdev, int how) return -ENODEV; rc = qdio_shutdown(cdev, how); - if (rc == 0) - rc = qdio_free(cdev); + + qdio_free(cdev); return rc; } EXPORT_SYMBOL_GPL(qdio_cleanup); -- cgit v1.2.3-70-g09d2 From 3fdf1e18cbc7c58f2d5604315ddae3596725bc6a Mon Sep 17 00:00:00 2001 From: Jan Glauber Date: Thu, 26 Mar 2009 15:24:28 +0100 Subject: [S390] qdio: move ACK to newest buffer for devices without QEBSM The ACKnowledgement state should be set on the newest SBAL so an adapter interrupt surpression check needs to scan fewer SBALs. Signed-off-by: Jan Glauber Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/qdio_main.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 8e6bc9cddfa..61ba765936a 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -440,12 +440,16 @@ static inline void inbound_primed(struct qdio_q *q, int count) /* reset the previous ACK but first set the new one */ set_buf_state(q, new, SLSB_P_INPUT_ACK); set_buf_state(q, q->last_move_ftc, SLSB_P_INPUT_NOT_INIT); - } - else { + } else { q->u.in.polling = 1; - set_buf_state(q, q->first_to_check, SLSB_P_INPUT_ACK); + set_buf_state(q, new, SLSB_P_INPUT_ACK); } + /* + * last_move_ftc points to the ACK'ed buffer and not to the last turns + * first_to_check like for qebsm. Since it is only used to check if + * the queue front moved in qdio_inbound_q_done this is not a problem. + */ q->last_move_ftc = new; count--; if (!count) @@ -455,7 +459,7 @@ static inline void inbound_primed(struct qdio_q *q, int count) * Need to change all PRIMED buffers to NOT_INIT, otherwise * we're loosing initiative in the thinint code. */ - set_buf_states(q, next_buf(q->first_to_check), SLSB_P_INPUT_NOT_INIT, + set_buf_states(q, q->first_to_check, SLSB_P_INPUT_NOT_INIT, count); } @@ -1480,7 +1484,6 @@ static void handle_inbound(struct qdio_q *q, unsigned int callflags, if (q->u.in.ack_count <= 0) { q->u.in.polling = 0; q->u.in.ack_count = 0; - /* TODO: must we set last_move_ftc to something meaningful? */ goto set; } q->last_move_ftc = add_buf(q->last_move_ftc, diff); -- cgit v1.2.3-70-g09d2 From e85dea0e415617b5c5627f38c71b33fbc7f94a85 Mon Sep 17 00:00:00 2001 From: Jan Glauber Date: Thu, 26 Mar 2009 15:24:29 +0100 Subject: [S390] qdio: seperate last move index and polling index The index value that indicated that the input queue moved was also used to store the index of the first acknowledged buffer. For non-qebsm only the newest buffer is acknowledged which may be different from the last move index so two seperate values are needed to track the input queue. Signed-off-by: Jan Glauber Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/qdio.h | 5 ++++- drivers/s390/cio/qdio_debug.c | 3 ++- drivers/s390/cio/qdio_main.c | 38 +++++++++++++++++--------------------- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h index 42f2b09631b..57807f5ffe8 100644 --- a/drivers/s390/cio/qdio.h +++ b/drivers/s390/cio/qdio.h @@ -186,6 +186,9 @@ struct qdio_input_q { /* input buffer acknowledgement flag */ int polling; + /* first ACK'ed buffer */ + int ack_start; + /* how much sbals are acknowledged with qebsm */ int ack_count; @@ -234,7 +237,7 @@ struct qdio_q { int first_to_check; /* first_to_check of the last time */ - int last_move_ftc; + int last_move; /* beginning position for calling the program */ int first_to_kick; diff --git a/drivers/s390/cio/qdio_debug.c b/drivers/s390/cio/qdio_debug.c index da7afb04e71..e3434b34f86 100644 --- a/drivers/s390/cio/qdio_debug.c +++ b/drivers/s390/cio/qdio_debug.c @@ -63,8 +63,9 @@ static int qstat_show(struct seq_file *m, void *v) seq_printf(m, "device state indicator: %d\n", *(u32 *)q->irq_ptr->dsci); seq_printf(m, "nr_used: %d\n", atomic_read(&q->nr_buf_used)); seq_printf(m, "ftc: %d\n", q->first_to_check); - seq_printf(m, "last_move_ftc: %d\n", q->last_move_ftc); + seq_printf(m, "last_move: %d\n", q->last_move); seq_printf(m, "polling: %d\n", q->u.in.polling); + seq_printf(m, "ack start: %d\n", q->u.in.ack_start); seq_printf(m, "ack count: %d\n", q->u.in.ack_count); seq_printf(m, "slsb buffer states:\n"); seq_printf(m, "|0 |8 |16 |24 |32 |40 |48 |56 63|\n"); diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 61ba765936a..31b9318149b 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -380,11 +380,11 @@ inline void qdio_stop_polling(struct qdio_q *q) /* show the card that we are not polling anymore */ if (is_qebsm(q)) { - set_buf_states(q, q->last_move_ftc, SLSB_P_INPUT_NOT_INIT, + set_buf_states(q, q->u.in.ack_start, SLSB_P_INPUT_NOT_INIT, q->u.in.ack_count); q->u.in.ack_count = 0; } else - set_buf_state(q, q->last_move_ftc, SLSB_P_INPUT_NOT_INIT); + set_buf_state(q, q->u.in.ack_start, SLSB_P_INPUT_NOT_INIT); } static void announce_buffer_error(struct qdio_q *q, int count) @@ -419,15 +419,15 @@ static inline void inbound_primed(struct qdio_q *q, int count) if (!q->u.in.polling) { q->u.in.polling = 1; q->u.in.ack_count = count; - q->last_move_ftc = q->first_to_check; + q->u.in.ack_start = q->first_to_check; return; } /* delete the previous ACK's */ - set_buf_states(q, q->last_move_ftc, SLSB_P_INPUT_NOT_INIT, + set_buf_states(q, q->u.in.ack_start, SLSB_P_INPUT_NOT_INIT, q->u.in.ack_count); q->u.in.ack_count = count; - q->last_move_ftc = q->first_to_check; + q->u.in.ack_start = q->first_to_check; return; } @@ -439,18 +439,13 @@ static inline void inbound_primed(struct qdio_q *q, int count) if (q->u.in.polling) { /* reset the previous ACK but first set the new one */ set_buf_state(q, new, SLSB_P_INPUT_ACK); - set_buf_state(q, q->last_move_ftc, SLSB_P_INPUT_NOT_INIT); + set_buf_state(q, q->u.in.ack_start, SLSB_P_INPUT_NOT_INIT); } else { q->u.in.polling = 1; set_buf_state(q, new, SLSB_P_INPUT_ACK); } - /* - * last_move_ftc points to the ACK'ed buffer and not to the last turns - * first_to_check like for qebsm. Since it is only used to check if - * the queue front moved in qdio_inbound_q_done this is not a problem. - */ - q->last_move_ftc = new; + q->u.in.ack_start = new; count--; if (!count) return; @@ -527,7 +522,8 @@ int qdio_inbound_q_moved(struct qdio_q *q) bufnr = get_inbound_buffer_frontier(q); - if ((bufnr != q->last_move_ftc) || q->qdio_error) { + if ((bufnr != q->last_move) || q->qdio_error) { + q->last_move = bufnr; if (!need_siga_sync(q) && !pci_out_supported(q)) q->u.in.timestamp = get_usecs(); @@ -702,8 +698,8 @@ static inline int qdio_outbound_q_moved(struct qdio_q *q) bufnr = get_outbound_buffer_frontier(q); - if ((bufnr != q->last_move_ftc) || q->qdio_error) { - q->last_move_ftc = bufnr; + if ((bufnr != q->last_move) || q->qdio_error) { + q->last_move = bufnr; DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "out moved:%1d", q->nr); return 1; } else @@ -748,7 +744,7 @@ static void qdio_kick_outbound_handler(struct qdio_q *q) int start, end, count; start = q->first_to_kick; - end = q->last_move_ftc; + end = q->last_move; if (end >= start) count = end - start; else @@ -764,7 +760,7 @@ static void qdio_kick_outbound_handler(struct qdio_q *q) q->irq_ptr->int_parm); /* for the next time: */ - q->first_to_kick = q->last_move_ftc; + q->first_to_kick = q->last_move; q->qdio_error = 0; } @@ -1475,18 +1471,18 @@ static void handle_inbound(struct qdio_q *q, unsigned int callflags, q->u.in.polling = 0; q->u.in.ack_count = 0; goto set; - } else if (buf_in_between(q->last_move_ftc, bufnr, count)) { + } else if (buf_in_between(q->u.in.ack_start, bufnr, count)) { if (is_qebsm(q)) { - /* partial overwrite, just update last_move_ftc */ + /* partial overwrite, just update ack_start */ diff = add_buf(bufnr, count); - diff = sub_buf(diff, q->last_move_ftc); + diff = sub_buf(diff, q->u.in.ack_start); q->u.in.ack_count -= diff; if (q->u.in.ack_count <= 0) { q->u.in.polling = 0; q->u.in.ack_count = 0; goto set; } - q->last_move_ftc = add_buf(q->last_move_ftc, diff); + q->u.in.ack_start = add_buf(q->u.in.ack_start, diff); } else /* the only ACK will be deleted, so stop polling */ -- cgit v1.2.3-70-g09d2 From 9e890ad880be1dd98483313b2ec0e23fbd4e3792 Mon Sep 17 00:00:00 2001 From: Jan Glauber Date: Thu, 26 Mar 2009 15:24:30 +0100 Subject: [S390] qdio: tasklet termination in case of module unload If the qdio module is unloaded the tiqdio tasklet must be terminated by tasklet_kill. Move the tasklet_kill after the unregistration of the adapter interrupt so the tiqdio tasklet will not be scheduled anymore before calling tasklet_kill. Signed-off-by: Jan Glauber Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/qdio_thinint.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/s390/cio/qdio_thinint.c b/drivers/s390/cio/qdio_thinint.c index c7c5512a892..96f0095f568 100644 --- a/drivers/s390/cio/qdio_thinint.c +++ b/drivers/s390/cio/qdio_thinint.c @@ -370,10 +370,11 @@ void qdio_shutdown_thinint(struct qdio_irq *irq_ptr) void __exit tiqdio_unregister_thinints(void) { - tasklet_disable(&tiqdio_tasklet); + WARN_ON(!list_empty(&tiq_list)); if (tiqdio_alsi) { s390_unregister_adapter_interrupt(tiqdio_alsi, QDIO_AIRQ_ISC); isc_unregister(QDIO_AIRQ_ISC); } + tasklet_kill(&tiqdio_tasklet); } -- cgit v1.2.3-70-g09d2 From d303b6fd858370c22d5c70c313669e3521a5f758 Mon Sep 17 00:00:00 2001 From: Jan Glauber Date: Thu, 26 Mar 2009 15:24:31 +0100 Subject: [S390] qdio: report SIGA errors directly Errors from SIGA instructions are stored in the per queue qdio_error and reported back when the queue handler is called. That opens a race when multiple error conditions occur simultanously. Report SIGA errors immediately in the return value of do_QDIO so the upper layer can react and SIGA errors no longer interfere with other errors. Move the SIGA error handling in qeth from the outbound handler to qeth_flush_buffers. Signed-off-by: Jan Glauber --- arch/s390/include/asm/qdio.h | 1 + drivers/s390/cio/qdio.h | 1 - drivers/s390/cio/qdio_main.c | 73 ++++++++++++++++----------------------- drivers/s390/cio/qdio_setup.c | 1 - drivers/s390/net/qeth_core_main.c | 55 +++++++++-------------------- 5 files changed, 48 insertions(+), 83 deletions(-) diff --git a/arch/s390/include/asm/qdio.h b/arch/s390/include/asm/qdio.h index 27fc1746de1..402d6dcf0d2 100644 --- a/arch/s390/include/asm/qdio.h +++ b/arch/s390/include/asm/qdio.h @@ -314,6 +314,7 @@ typedef void qdio_handler_t(struct ccw_device *, unsigned int, int, int, int, unsigned long); /* qdio errors reported to the upper-layer program */ +#define QDIO_ERROR_SIGA_TARGET 0x02 #define QDIO_ERROR_SIGA_ACCESS_EXCEPTION 0x10 #define QDIO_ERROR_SIGA_BUSY 0x20 #define QDIO_ERROR_ACTIVATE_CHECK_CONDITION 0x40 diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h index 57807f5ffe8..41171d741f3 100644 --- a/drivers/s390/cio/qdio.h +++ b/drivers/s390/cio/qdio.h @@ -247,7 +247,6 @@ struct qdio_q { struct qdio_irq *irq_ptr; struct tasklet_struct tasklet; - spinlock_t lock; /* error condition during a data transfer */ unsigned int qdio_error; diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 31b9318149b..e53ac67e1e4 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -706,13 +706,13 @@ static inline int qdio_outbound_q_moved(struct qdio_q *q) return 0; } -static void qdio_kick_outbound_q(struct qdio_q *q) +static int qdio_kick_outbound_q(struct qdio_q *q) { unsigned int busy_bit; int cc; if (!need_siga_out(q)) - return; + return 0; DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w:%1d", q->nr); qdio_perf_stat_inc(&perf_stats.siga_out); @@ -724,19 +724,16 @@ static void qdio_kick_outbound_q(struct qdio_q *q) case 2: if (busy_bit) { DBF_ERROR("%4x cc2 REP:%1d", SCH_NO(q), q->nr); - q->qdio_error = cc | QDIO_ERROR_SIGA_BUSY; - } else { - DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w cc2:%1d", - q->nr); - q->qdio_error = cc; - } + cc |= QDIO_ERROR_SIGA_BUSY; + } else + DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w cc2:%1d", q->nr); break; case 1: case 3: DBF_ERROR("%4x SIGA-W:%1d", SCH_NO(q), cc); - q->qdio_error = cc; break; } + return cc; } static void qdio_kick_outbound_handler(struct qdio_q *q) @@ -766,18 +763,12 @@ static void qdio_kick_outbound_handler(struct qdio_q *q) static void __qdio_outbound_processing(struct qdio_q *q) { - unsigned long flags; - qdio_perf_stat_inc(&perf_stats.tasklet_outbound); - spin_lock_irqsave(&q->lock, flags); - BUG_ON(atomic_read(&q->nr_buf_used) < 0); if (qdio_outbound_q_moved(q)) qdio_kick_outbound_handler(q); - spin_unlock_irqrestore(&q->lock, flags); - if (queue_type(q) == QDIO_ZFCP_QFMT) if (!pci_out_supported(q) && !qdio_outbound_q_done(q)) goto sched; @@ -1457,10 +1448,10 @@ static inline int buf_in_between(int bufnr, int start, int count) * @bufnr: first buffer to process * @count: how many buffers are emptied */ -static void handle_inbound(struct qdio_q *q, unsigned int callflags, - int bufnr, int count) +static int handle_inbound(struct qdio_q *q, unsigned int callflags, + int bufnr, int count) { - int used, cc, diff; + int used, diff; if (!q->u.in.polling) goto set; @@ -1497,13 +1488,11 @@ set: /* no need to signal as long as the adapter had free buffers */ if (used) - return; + return 0; - if (need_siga_in(q)) { - cc = qdio_siga_input(q); - if (cc) - q->qdio_error = cc; - } + if (need_siga_in(q)) + return qdio_siga_input(q); + return 0; } /** @@ -1513,11 +1502,11 @@ set: * @bufnr: first buffer to process * @count: how many buffers are filled */ -static void handle_outbound(struct qdio_q *q, unsigned int callflags, - int bufnr, int count) +static int handle_outbound(struct qdio_q *q, unsigned int callflags, + int bufnr, int count) { unsigned char state; - int used; + int used, rc = 0; qdio_perf_stat_inc(&perf_stats.outbound_handler); @@ -1532,27 +1521,26 @@ static void handle_outbound(struct qdio_q *q, unsigned int callflags, if (queue_type(q) == QDIO_IQDIO_QFMT) { if (multicast_outbound(q)) - qdio_kick_outbound_q(q); + rc = qdio_kick_outbound_q(q); else if ((q->irq_ptr->ssqd_desc.mmwc > 1) && (count > 1) && (count <= q->irq_ptr->ssqd_desc.mmwc)) { /* exploit enhanced SIGA */ q->u.out.use_enh_siga = 1; - qdio_kick_outbound_q(q); + rc = qdio_kick_outbound_q(q); } else { /* * One siga-w per buffer required for unicast * HiperSockets. */ q->u.out.use_enh_siga = 0; - while (count--) - qdio_kick_outbound_q(q); + while (count--) { + rc = qdio_kick_outbound_q(q); + if (rc) + goto out; + } } - - /* report CC=2 conditions synchronously */ - if (q->qdio_error) - __qdio_outbound_processing(q); goto out; } @@ -1564,13 +1552,14 @@ static void handle_outbound(struct qdio_q *q, unsigned int callflags, /* try to fast requeue buffers */ get_buf_state(q, prev_buf(bufnr), &state, 0); if (state != SLSB_CU_OUTPUT_PRIMED) - qdio_kick_outbound_q(q); + rc = qdio_kick_outbound_q(q); else { DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "fast-req"); qdio_perf_stat_inc(&perf_stats.fast_requeue); } out: tasklet_schedule(&q->tasklet); + return rc; } /** @@ -1609,14 +1598,12 @@ int do_QDIO(struct ccw_device *cdev, unsigned int callflags, return -EBUSY; if (callflags & QDIO_FLAG_SYNC_INPUT) - handle_inbound(irq_ptr->input_qs[q_nr], callflags, bufnr, - count); + return handle_inbound(irq_ptr->input_qs[q_nr], + callflags, bufnr, count); else if (callflags & QDIO_FLAG_SYNC_OUTPUT) - handle_outbound(irq_ptr->output_qs[q_nr], callflags, bufnr, - count); - else - return -EINVAL; - return 0; + return handle_outbound(irq_ptr->output_qs[q_nr], + callflags, bufnr, count); + return -EINVAL; } EXPORT_SYMBOL_GPL(do_QDIO); diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c index c08356b95bf..18d54fc21ce 100644 --- a/drivers/s390/cio/qdio_setup.c +++ b/drivers/s390/cio/qdio_setup.c @@ -117,7 +117,6 @@ static void setup_queues_misc(struct qdio_q *q, struct qdio_irq *irq_ptr, q->mask = 1 << (31 - i); q->nr = i; q->handler = handler; - spin_lock_init(&q->lock); } static void setup_storage_lists(struct qdio_q *q, struct qdio_irq *irq_ptr, diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index d1b5bebea7f..2489bcebf5e 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -2693,40 +2693,21 @@ static int qeth_handle_send_error(struct qeth_card *card, struct qeth_qdio_out_buffer *buffer, unsigned int qdio_err) { int sbalf15 = buffer->buffer->element[15].flags & 0xff; - int cc = qdio_err & 3; QETH_DBF_TEXT(TRACE, 6, "hdsnderr"); qeth_check_qdio_errors(buffer->buffer, qdio_err, "qouterr"); - switch (cc) { - case 0: - if (qdio_err) { - QETH_DBF_TEXT(TRACE, 1, "lnkfail"); - QETH_DBF_TEXT_(TRACE, 1, "%s", CARD_BUS_ID(card)); - QETH_DBF_TEXT_(TRACE, 1, "%04x %02x", - (u16)qdio_err, (u8)sbalf15); - return QETH_SEND_ERROR_LINK_FAILURE; - } + + if (!qdio_err) return QETH_SEND_ERROR_NONE; - case 2: - if (qdio_err & QDIO_ERROR_SIGA_BUSY) { - QETH_DBF_TEXT(TRACE, 1, "SIGAcc2B"); - QETH_DBF_TEXT_(TRACE, 1, "%s", CARD_BUS_ID(card)); - return QETH_SEND_ERROR_KICK_IT; - } - if ((sbalf15 >= 15) && (sbalf15 <= 31)) - return QETH_SEND_ERROR_RETRY; - return QETH_SEND_ERROR_LINK_FAILURE; - /* look at qdio_error and sbalf 15 */ - case 1: - QETH_DBF_TEXT(TRACE, 1, "SIGAcc1"); - QETH_DBF_TEXT_(TRACE, 1, "%s", CARD_BUS_ID(card)); - return QETH_SEND_ERROR_LINK_FAILURE; - case 3: - default: - QETH_DBF_TEXT(TRACE, 1, "SIGAcc3"); - QETH_DBF_TEXT_(TRACE, 1, "%s", CARD_BUS_ID(card)); - return QETH_SEND_ERROR_KICK_IT; - } + + if ((sbalf15 >= 15) && (sbalf15 <= 31)) + return QETH_SEND_ERROR_RETRY; + + QETH_DBF_TEXT(TRACE, 1, "lnkfail"); + QETH_DBF_TEXT_(TRACE, 1, "%s", CARD_BUS_ID(card)); + QETH_DBF_TEXT_(TRACE, 1, "%04x %02x", + (u16)qdio_err, (u8)sbalf15); + return QETH_SEND_ERROR_LINK_FAILURE; } /* @@ -2862,10 +2843,14 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index, qeth_get_micros() - queue->card->perf_stats.outbound_do_qdio_start_time; if (rc) { + queue->card->stats.tx_errors += count; + /* ignore temporary SIGA errors without busy condition */ + if (rc == QDIO_ERROR_SIGA_TARGET) + return; QETH_DBF_TEXT(TRACE, 2, "flushbuf"); QETH_DBF_TEXT_(TRACE, 2, " err%d", rc); QETH_DBF_TEXT_(TRACE, 2, "%s", CARD_DDEV_ID(queue->card)); - queue->card->stats.tx_errors += count; + /* this must not happen under normal circumstances. if it * happens something is really wrong -> recover */ qeth_schedule_recovery(queue->card); @@ -2940,13 +2925,7 @@ void qeth_qdio_output_handler(struct ccw_device *ccwdev, } for (i = first_element; i < (first_element + count); ++i) { buffer = &queue->bufs[i % QDIO_MAX_BUFFERS_PER_Q]; - /*we only handle the KICK_IT error by doing a recovery */ - if (qeth_handle_send_error(card, buffer, qdio_error) - == QETH_SEND_ERROR_KICK_IT){ - netif_stop_queue(card->dev); - qeth_schedule_recovery(card); - return; - } + qeth_handle_send_error(card, buffer, qdio_error); qeth_clear_output_buffer(queue, buffer); } atomic_sub(count, &queue->used_buffers); -- cgit v1.2.3-70-g09d2 From 9c8a08d7a74b07ab2c47e259231d9d0f0047a3c1 Mon Sep 17 00:00:00 2001 From: Jan Glauber Date: Thu, 26 Mar 2009 15:24:32 +0100 Subject: [S390] qdio: merge inbound and outbound handler functions The inbound and outbound handlers are nearly identical if the outbound handler uses first_to_check as end index instead of last_move. Since both values are identical at that point the handlers can be merged. Signed-off-by: Jan Glauber Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/qdio.h | 2 +- drivers/s390/cio/qdio_main.c | 62 +++++++++++++---------------------------- drivers/s390/cio/qdio_thinint.c | 2 +- 3 files changed, 21 insertions(+), 45 deletions(-) diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h index 41171d741f3..13bcb811438 100644 --- a/drivers/s390/cio/qdio.h +++ b/drivers/s390/cio/qdio.h @@ -356,7 +356,7 @@ int get_buf_state(struct qdio_q *q, unsigned int bufnr, unsigned char *state, int auto_ack); void qdio_check_outbound_after_thinint(struct qdio_q *q); int qdio_inbound_q_moved(struct qdio_q *q); -void qdio_kick_inbound_handler(struct qdio_q *q); +void qdio_kick_handler(struct qdio_q *q); void qdio_stop_polling(struct qdio_q *q); int qdio_siga_sync_q(struct qdio_q *q); diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index e53ac67e1e4..9e8a2914259 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -570,29 +570,30 @@ static int qdio_inbound_q_done(struct qdio_q *q) } } -void qdio_kick_inbound_handler(struct qdio_q *q) +void qdio_kick_handler(struct qdio_q *q) { - int count, start, end; - - qdio_perf_stat_inc(&perf_stats.inbound_handler); - - start = q->first_to_kick; - end = q->first_to_check; - if (end >= start) - count = end - start; - else - count = end + QDIO_MAX_BUFFERS_PER_Q - start; - - DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "kih s:%3d c:%3d", start, count); + int start = q->first_to_kick; + int end = q->first_to_check; + int count; if (unlikely(q->irq_ptr->state != QDIO_IRQ_STATE_ACTIVE)) return; - q->handler(q->irq_ptr->cdev, q->qdio_error, q->nr, - start, count, q->irq_ptr->int_parm); + count = sub_buf(end, start); + + if (q->is_input_q) { + qdio_perf_stat_inc(&perf_stats.inbound_handler); + DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "kih s:%3d c:%3d", start, count); + } else { + DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "koh: nr:%1d", q->nr); + DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "s:%3d c:%3d", start, count); + } + + q->handler(q->irq_ptr->cdev, q->qdio_error, q->nr, start, count, + q->irq_ptr->int_parm); /* for the next time */ - q->first_to_kick = q->first_to_check; + q->first_to_kick = end; q->qdio_error = 0; } @@ -603,7 +604,7 @@ again: if (!qdio_inbound_q_moved(q)) return; - qdio_kick_inbound_handler(q); + qdio_kick_handler(q); if (!qdio_inbound_q_done(q)) /* means poll time is not yet over */ @@ -736,38 +737,13 @@ static int qdio_kick_outbound_q(struct qdio_q *q) return cc; } -static void qdio_kick_outbound_handler(struct qdio_q *q) -{ - int start, end, count; - - start = q->first_to_kick; - end = q->last_move; - if (end >= start) - count = end - start; - else - count = end + QDIO_MAX_BUFFERS_PER_Q - start; - - DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "kickouth: %1d", q->nr); - DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "s:%3d c:%3d", start, count); - - if (unlikely(q->irq_ptr->state != QDIO_IRQ_STATE_ACTIVE)) - return; - - q->handler(q->irq_ptr->cdev, q->qdio_error, q->nr, start, count, - q->irq_ptr->int_parm); - - /* for the next time: */ - q->first_to_kick = q->last_move; - q->qdio_error = 0; -} - static void __qdio_outbound_processing(struct qdio_q *q) { qdio_perf_stat_inc(&perf_stats.tasklet_outbound); BUG_ON(atomic_read(&q->nr_buf_used) < 0); if (qdio_outbound_q_moved(q)) - qdio_kick_outbound_handler(q); + qdio_kick_handler(q); if (queue_type(q) == QDIO_ZFCP_QFMT) if (!pci_out_supported(q) && !qdio_outbound_q_done(q)) diff --git a/drivers/s390/cio/qdio_thinint.c b/drivers/s390/cio/qdio_thinint.c index 96f0095f568..c655d011a78 100644 --- a/drivers/s390/cio/qdio_thinint.c +++ b/drivers/s390/cio/qdio_thinint.c @@ -161,7 +161,7 @@ static void __tiqdio_inbound_processing(struct qdio_q *q) if (!qdio_inbound_q_moved(q)) return; - qdio_kick_inbound_handler(q); + qdio_kick_handler(q); if (!tiqdio_inbound_q_done(q)) { qdio_perf_stat_inc(&perf_stats.thinint_inbound_loop); -- cgit v1.2.3-70-g09d2 From 6faf250789dfd35146a71402f9be245be82bf01e Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 26 Mar 2009 15:24:33 +0100 Subject: [S390] allow usage of string functions in linux/string.h In introducing a trivial "strstarts()" function in linux/string.h, we hit the following error on s390: In file included from include/linux/bitmap.h:8, from include/linux/cpumask.h:142, from include/linux/smp.h:12, from /home/rusty/devel/kernel/patches/linux-2.6/arch/s390/include/asm/spinlock.h:14, from include/linux/spinlock.h:88, from include/linux/seqlock.h:29, from include/linux/time.h:8, from include/linux/stat.h:60, from include/linux/module.h:10, from arch/s390/lib/string.c:13: include/linux/string.h: In function 'strstarts': include/linux/string.h:124: error: implicit declaration of function 'strlen' include/linux/string.h:124: warning: incompatible implicit declaration of built-in function 'strlen' Because when including asm/string.h from arch/s390/lib/string.c we don't declare the string ops we are about to define, and linux/string.h barfs. The fix is to declare them in this IN_ARCH_STRING_C case, but in general I wonder if there's a neater fix. Reported-by: linux-next Signed-off-by: Rusty Russell Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/string.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/arch/s390/include/asm/string.h b/arch/s390/include/asm/string.h index d074673a6d9..adf079170aa 100644 --- a/arch/s390/include/asm/string.h +++ b/arch/s390/include/asm/string.h @@ -135,7 +135,13 @@ static inline size_t strnlen(const char * s, size_t n) : "+a" (end), "+a" (tmp) : "d" (r0) : "cc"); return end - s; } - +#else /* IN_ARCH_STRING_C */ +void *memchr(const void * s, int c, size_t n); +void *memscan(void *s, int c, size_t n); +char *strcat(char *dst, const char *src); +char *strcpy(char *dst, const char *src); +size_t strlen(const char *s); +size_t strnlen(const char * s, size_t n); #endif /* !IN_ARCH_STRING_C */ #endif /* __KERNEL__ */ -- cgit v1.2.3-70-g09d2 From ced2c8bcbc5082bc112d7c7410b3f5380c77e306 Mon Sep 17 00:00:00 2001 From: Hendrik Brueckner Date: Thu, 26 Mar 2009 15:24:34 +0100 Subject: [S390] remove duplicate nul-termination of string strlcpy() does already NUL-terminate the destination string. Signed-off-by: Hendrik Brueckner Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/early.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index d61eb3334ed..4d221c81c84 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c @@ -352,7 +352,6 @@ static void __init setup_boot_command_line(void) /* copy arch command line */ strlcpy(boot_command_line, COMMAND_LINE, ARCH_COMMAND_LINE_SIZE); - boot_command_line[ARCH_COMMAND_LINE_SIZE - 1] = 0; /* append IPL PARM data to the boot command line */ if (MACHINE_IS_VM) { -- cgit v1.2.3-70-g09d2 From e13ed9b2704487e98d9241282765869fbd9a2dda Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 26 Mar 2009 15:24:35 +0100 Subject: [S390] bitops: remove likely annotations likely/unlikely profiling revealed that none of the branches in bitops is taken likely or unlikely. So remove the annotations. In addition the generated code is shorter. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/bitops.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/s390/include/asm/bitops.h b/arch/s390/include/asm/bitops.h index 334964a0fb1..b30606f6d52 100644 --- a/arch/s390/include/asm/bitops.h +++ b/arch/s390/include/asm/bitops.h @@ -525,16 +525,16 @@ static inline unsigned long __ffs_word_loop(const unsigned long *addr, static inline unsigned long __ffz_word(unsigned long nr, unsigned long word) { #ifdef __s390x__ - if (likely((word & 0xffffffff) == 0xffffffff)) { + if ((word & 0xffffffff) == 0xffffffff) { word >>= 32; nr += 32; } #endif - if (likely((word & 0xffff) == 0xffff)) { + if ((word & 0xffff) == 0xffff) { word >>= 16; nr += 16; } - if (likely((word & 0xff) == 0xff)) { + if ((word & 0xff) == 0xff) { word >>= 8; nr += 8; } @@ -549,16 +549,16 @@ static inline unsigned long __ffz_word(unsigned long nr, unsigned long word) static inline unsigned long __ffs_word(unsigned long nr, unsigned long word) { #ifdef __s390x__ - if (likely((word & 0xffffffff) == 0)) { + if ((word & 0xffffffff) == 0) { word >>= 32; nr += 32; } #endif - if (likely((word & 0xffff) == 0)) { + if ((word & 0xffff) == 0) { word >>= 16; nr += 16; } - if (likely((word & 0xff) == 0)) { + if ((word & 0xff) == 0) { word >>= 8; nr += 8; } -- cgit v1.2.3-70-g09d2 From 504665a91498f43d220b7d0942281067283a35f7 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Thu, 26 Mar 2009 15:24:36 +0100 Subject: [S390] module function call optimization Avoid the detour over the PLT if the branch target of a function call in a module is in the range of the bras (16-bit) or brasl (32-bit) instruction. The PLT is still generated but it is unused. Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/module.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/arch/s390/kernel/module.c b/arch/s390/kernel/module.c index 59b4e796680..eed4a00cb67 100644 --- a/arch/s390/kernel/module.c +++ b/arch/s390/kernel/module.c @@ -310,15 +310,20 @@ apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab, info->plt_initialized = 1; } if (r_type == R_390_PLTOFF16 || - r_type == R_390_PLTOFF32 - || r_type == R_390_PLTOFF64 - ) + r_type == R_390_PLTOFF32 || + r_type == R_390_PLTOFF64) val = me->arch.plt_offset - me->arch.got_offset + info->plt_offset + rela->r_addend; - else - val = (Elf_Addr) me->module_core + - me->arch.plt_offset + info->plt_offset + - rela->r_addend - loc; + else { + if (!((r_type == R_390_PLT16DBL && + val - loc + 0xffffUL < 0x1ffffeUL) || + (r_type == R_390_PLT32DBL && + val - loc + 0xffffffffULL < 0x1fffffffeULL))) + val = (Elf_Addr) me->module_core + + me->arch.plt_offset + + info->plt_offset; + val += rela->r_addend - loc; + } if (r_type == R_390_PLT16DBL) *(unsigned short *) loc = val >> 1; else if (r_type == R_390_PLTOFF16) -- cgit v1.2.3-70-g09d2 From 1edad85b16fdda43c8ab809e2779e8bf64ab8bb2 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 26 Mar 2009 15:24:37 +0100 Subject: [S390] use compiler builtin versions of strlen/strcpy/strcat Use builtin variants if gcc 4 or newer is used to compile the kernel. Generates better code than the asm variants. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/string.h | 8 ++++++++ arch/s390/lib/string.c | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/arch/s390/include/asm/string.h b/arch/s390/include/asm/string.h index adf079170aa..cd0241db5a4 100644 --- a/arch/s390/include/asm/string.h +++ b/arch/s390/include/asm/string.h @@ -100,6 +100,7 @@ static inline char *strcat(char *dst, const char *src) static inline char *strcpy(char *dst, const char *src) { +#if __GNUC__ < 4 register int r0 asm("0") = 0; char *ret = dst; @@ -109,10 +110,14 @@ static inline char *strcpy(char *dst, const char *src) : "+&a" (dst), "+&a" (src) : "d" (r0) : "cc", "memory"); return ret; +#else + return __builtin_strcpy(dst, src); +#endif } static inline size_t strlen(const char *s) { +#if __GNUC__ < 4 register unsigned long r0 asm("0") = 0; const char *tmp = s; @@ -121,6 +126,9 @@ static inline size_t strlen(const char *s) " jo 0b" : "+d" (r0), "+a" (tmp) : : "cc"); return r0 - (unsigned long) s; +#else + return __builtin_strlen(s); +#endif } static inline size_t strnlen(const char * s, size_t n) diff --git a/arch/s390/lib/string.c b/arch/s390/lib/string.c index ae5cf5d03d4..4143b7c1909 100644 --- a/arch/s390/lib/string.c +++ b/arch/s390/lib/string.c @@ -44,7 +44,11 @@ static inline char *__strnend(const char *s, size_t n) */ size_t strlen(const char *s) { +#if __GNUC__ < 4 return __strend(s) - s; +#else + return __builtin_strlen(s); +#endif } EXPORT_SYMBOL(strlen); @@ -70,6 +74,7 @@ EXPORT_SYMBOL(strnlen); */ char *strcpy(char *dest, const char *src) { +#if __GNUC__ < 4 register int r0 asm("0") = 0; char *ret = dest; @@ -78,6 +83,9 @@ char *strcpy(char *dest, const char *src) : "+&a" (dest), "+&a" (src) : "d" (r0) : "cc", "memory" ); return ret; +#else + return __builtin_strcpy(dest, src); +#endif } EXPORT_SYMBOL(strcpy); -- cgit v1.2.3-70-g09d2 From ab640db01013192f6867785a7def7c9d9ec8903d Mon Sep 17 00:00:00 2001 From: Carsten Otte Date: Thu, 26 Mar 2009 15:24:38 +0100 Subject: [S390] tape message cleanup This is a cleanup of all the messages this driver prints. It uses the dev_message macros now. Signed-off-by: Carsten Otte Signed-off-by: Martin Schwidefsky --- drivers/s390/char/tape.h | 2 - drivers/s390/char/tape_34xx.c | 161 ++++++++---------- drivers/s390/char/tape_3590.c | 364 ++++++++++++++++++++--------------------- drivers/s390/char/tape_block.c | 18 +- drivers/s390/char/tape_char.c | 7 - drivers/s390/char/tape_core.c | 62 +------ drivers/s390/char/tape_proc.c | 3 - drivers/s390/char/tape_std.c | 21 +-- 8 files changed, 267 insertions(+), 371 deletions(-) diff --git a/drivers/s390/char/tape.h b/drivers/s390/char/tape.h index d0d565a05df..c07809c8016 100644 --- a/drivers/s390/char/tape.h +++ b/drivers/s390/char/tape.h @@ -324,8 +324,6 @@ static inline void tape_proc_cleanup (void) {;} #endif /* a function for dumping device sense info */ -extern void tape_dump_sense(struct tape_device *, struct tape_request *, - struct irb *); extern void tape_dump_sense_dbf(struct tape_device *, struct tape_request *, struct irb *); diff --git a/drivers/s390/char/tape_34xx.c b/drivers/s390/char/tape_34xx.c index 22ca34361ed..807ded5eb04 100644 --- a/drivers/s390/char/tape_34xx.c +++ b/drivers/s390/char/tape_34xx.c @@ -8,6 +8,8 @@ * Martin Schwidefsky */ +#define KMSG_COMPONENT "tape" + #include #include #include @@ -18,8 +20,6 @@ #include "tape.h" #include "tape_std.h" -#define PRINTK_HEADER "TAPE_34XX: " - /* * Pointer to debug area. */ @@ -203,8 +203,7 @@ tape_34xx_unsolicited_irq(struct tape_device *device, struct irb *irb) tape_34xx_schedule_work(device, TO_MSEN); } else { DBF_EVENT(3, "unsol.irq! dev end: %08x\n", device->cdev_id); - PRINT_WARN("Unsolicited IRQ (Device End) caught.\n"); - tape_dump_sense(device, NULL, irb); + tape_dump_sense_dbf(device, NULL, irb); } return TAPE_IO_SUCCESS; } @@ -226,9 +225,7 @@ tape_34xx_erp_read_opposite(struct tape_device *device, tape_std_read_backward(device, request); return tape_34xx_erp_retry(request); } - if (request->op != TO_RBA) - PRINT_ERR("read_opposite called with state:%s\n", - tape_op_verbose[request->op]); + /* * We tried to read forward and backward, but hat no * success -> failed. @@ -241,13 +238,9 @@ tape_34xx_erp_bug(struct tape_device *device, struct tape_request *request, struct irb *irb, int no) { if (request->op != TO_ASSIGN) { - PRINT_WARN("An unexpected condition #%d was caught in " - "tape error recovery.\n", no); - PRINT_WARN("Please report this incident.\n"); - if (request) - PRINT_WARN("Operation of tape:%s\n", - tape_op_verbose[request->op]); - tape_dump_sense(device, request, irb); + dev_err(&device->cdev->dev, "An unexpected condition %d " + "occurred in tape error recovery\n", no); + tape_dump_sense_dbf(device, request, irb); } return tape_34xx_erp_failed(request, -EIO); } @@ -261,9 +254,8 @@ tape_34xx_erp_overrun(struct tape_device *device, struct tape_request *request, struct irb *irb) { if (irb->ecw[3] == 0x40) { - PRINT_WARN ("Data overrun error between control-unit " - "and drive. Use a faster channel connection, " - "if possible! \n"); + dev_warn (&device->cdev->dev, "A data overrun occurred between" + " the control unit and tape unit\n"); return tape_34xx_erp_failed(request, -EIO); } return tape_34xx_erp_bug(device, request, irb, -1); @@ -280,7 +272,8 @@ tape_34xx_erp_sequence(struct tape_device *device, /* * cu detected incorrect block-id sequence on tape. */ - PRINT_WARN("Illegal block-id sequence found!\n"); + dev_warn (&device->cdev->dev, "The block ID sequence on the " + "tape is incorrect\n"); return tape_34xx_erp_failed(request, -EIO); } /* @@ -393,8 +386,6 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request, /* Writing at physical end of volume */ return tape_34xx_erp_failed(request, -ENOSPC); default: - PRINT_ERR("Invalid op in %s:%i\n", - __func__, __LINE__); return tape_34xx_erp_failed(request, 0); } } @@ -420,7 +411,8 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request, irb, -4); /* data check is permanent, CU recovery has failed */ - PRINT_WARN("Permanent read error\n"); + dev_warn (&device->cdev->dev, "A read error occurred " + "that cannot be recovered\n"); return tape_34xx_erp_failed(request, -EIO); case 0x25: // a write data check occurred @@ -433,22 +425,26 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request, irb, -5); // data check is permanent, cu-recovery has failed - PRINT_WARN("Permanent write error\n"); + dev_warn (&device->cdev->dev, "A write error on the " + "tape cannot be recovered\n"); return tape_34xx_erp_failed(request, -EIO); case 0x26: /* Data Check (read opposite) occurred. */ return tape_34xx_erp_read_opposite(device, request); case 0x28: /* ID-Mark at tape start couldn't be written */ - PRINT_WARN("ID-Mark could not be written.\n"); + dev_warn (&device->cdev->dev, "Writing the ID-mark " + "failed\n"); return tape_34xx_erp_failed(request, -EIO); case 0x31: /* Tape void. Tried to read beyond end of device. */ - PRINT_WARN("Read beyond end of recorded area.\n"); + dev_warn (&device->cdev->dev, "Reading the tape beyond" + " the end of the recorded area failed\n"); return tape_34xx_erp_failed(request, -ENOSPC); case 0x41: /* Record sequence error. */ - PRINT_WARN("Invalid block-id sequence found.\n"); + dev_warn (&device->cdev->dev, "The tape contains an " + "incorrect block ID sequence\n"); return tape_34xx_erp_failed(request, -EIO); default: /* all data checks for 3480 should result in one of @@ -470,16 +466,12 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request, switch (sense[3]) { case 0x00: /* Unit check with erpa code 0. Report and ignore. */ - PRINT_WARN("Non-error sense was found. " - "Unit-check will be ignored.\n"); return TAPE_IO_SUCCESS; case 0x21: /* * Data streaming not operational. CU will switch to * interlock mode. Reissue the command. */ - PRINT_WARN("Data streaming not operational. " - "Switching to interlock-mode.\n"); return tape_34xx_erp_retry(request); case 0x22: /* @@ -487,11 +479,8 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request, * error on the lower interface, internal path not usable, * or error during cartridge load. */ - PRINT_WARN("A path equipment check occurred. One of the " - "following conditions occurred:\n"); - PRINT_WARN("drive adapter error, buffer error on the lower " - "interface, internal path not usable, error " - "during cartridge load.\n"); + dev_warn (&device->cdev->dev, "A path equipment check occurred" + " for the tape device\n"); return tape_34xx_erp_failed(request, -EIO); case 0x24: /* @@ -514,7 +503,6 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request, * but the hardware isn't capable to do idrc, or a perform * subsystem func is issued and the CU is not on-line. */ - PRINT_WARN ("Function incompatible. Try to switch off idrc\n"); return tape_34xx_erp_failed(request, -EIO); case 0x2a: /* @@ -552,23 +540,26 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request, * reading the format id mark or that that format specified * is not supported by the drive. */ - PRINT_WARN("Drive not capable processing the tape format!\n"); + dev_warn (&device->cdev->dev, "The tape unit cannot process " + "the tape format\n"); return tape_34xx_erp_failed(request, -EMEDIUMTYPE); case 0x30: /* The medium is write protected. */ - PRINT_WARN("Medium is write protected!\n"); + dev_warn (&device->cdev->dev, "The tape medium is write-" + "protected\n"); return tape_34xx_erp_failed(request, -EACCES); case 0x32: // Tension loss. We cannot recover this, it's an I/O error. - PRINT_WARN("The drive lost tape tension.\n"); + dev_warn (&device->cdev->dev, "The tape does not have the " + "required tape tension\n"); return tape_34xx_erp_failed(request, -EIO); case 0x33: /* * Load Failure. The cartridge was not inserted correctly or * the tape is not threaded correctly. */ - PRINT_WARN("Cartridge load failure. Reload the cartridge " - "and try again.\n"); + dev_warn (&device->cdev->dev, "The tape unit failed to load" + " the cartridge\n"); tape_34xx_delete_sbid_from(device, 0); return tape_34xx_erp_failed(request, -EIO); case 0x34: @@ -576,8 +567,8 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request, * Unload failure. The drive cannot maintain tape tension * and control tape movement during an unload operation. */ - PRINT_WARN("Failure during cartridge unload. " - "Please try manually.\n"); + dev_warn (&device->cdev->dev, "Automatic unloading of the tape" + " cartridge failed\n"); if (request->op == TO_RUN) return tape_34xx_erp_failed(request, -EIO); return tape_34xx_erp_bug(device, request, irb, sense[3]); @@ -589,8 +580,8 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request, * - the cartridge loader does not respond correctly * - a failure occurs during an index, load, or unload cycle */ - PRINT_WARN("Equipment check! Please check the drive and " - "the cartridge loader.\n"); + dev_warn (&device->cdev->dev, "An equipment check has occurred" + " on the tape unit\n"); return tape_34xx_erp_failed(request, -EIO); case 0x36: if (device->cdev->id.driver_info == tape_3490) @@ -603,7 +594,8 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request, * Tape length error. The tape is shorter than reported in * the beginning-of-tape data. */ - PRINT_WARN("Tape length error.\n"); + dev_warn (&device->cdev->dev, "The tape information states an" + " incorrect length\n"); return tape_34xx_erp_failed(request, -EIO); case 0x38: /* @@ -620,12 +612,12 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request, return tape_34xx_erp_failed(request, -EIO); case 0x3a: /* Drive switched to not ready. */ - PRINT_WARN("Drive not ready. Turn the ready/not ready switch " - "to ready position and try again.\n"); + dev_warn (&device->cdev->dev, "The tape unit is not ready\n"); return tape_34xx_erp_failed(request, -EIO); case 0x3b: /* Manual rewind or unload. This causes an I/O error. */ - PRINT_WARN("Medium was rewound or unloaded manually.\n"); + dev_warn (&device->cdev->dev, "The tape medium has been " + "rewound or unloaded manually\n"); tape_34xx_delete_sbid_from(device, 0); return tape_34xx_erp_failed(request, -EIO); case 0x42: @@ -633,7 +625,8 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request, * Degraded mode. A condition that can cause degraded * performance is detected. */ - PRINT_WARN("Subsystem is running in degraded mode.\n"); + dev_warn (&device->cdev->dev, "The tape subsystem is running " + "in degraded mode\n"); return tape_34xx_erp_retry(request); case 0x43: /* Drive not ready. */ @@ -652,7 +645,6 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request, break; } } - PRINT_WARN("The drive is not ready.\n"); return tape_34xx_erp_failed(request, -ENOMEDIUM); case 0x44: /* Locate Block unsuccessful. */ @@ -663,7 +655,8 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request, return tape_34xx_erp_failed(request, -EIO); case 0x45: /* The drive is assigned to a different channel path. */ - PRINT_WARN("The drive is assigned elsewhere.\n"); + dev_warn (&device->cdev->dev, "The tape unit is already " + "assigned\n"); return tape_34xx_erp_failed(request, -EIO); case 0x46: /* @@ -671,11 +664,12 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request, * the power supply may be switched off or * the drive address may not be set correctly. */ - PRINT_WARN("The drive is not on-line."); + dev_warn (&device->cdev->dev, "The tape unit is not online\n"); return tape_34xx_erp_failed(request, -EIO); case 0x47: /* Volume fenced. CU reports volume integrity is lost. */ - PRINT_WARN("Volume fenced. The volume integrity is lost.\n"); + dev_warn (&device->cdev->dev, "The control unit has fenced " + "access to the tape volume\n"); tape_34xx_delete_sbid_from(device, 0); return tape_34xx_erp_failed(request, -EIO); case 0x48: @@ -683,20 +677,21 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request, return tape_34xx_erp_retry(request); case 0x49: /* Bus out check. A parity check error on the bus was found. */ - PRINT_WARN("Bus out check. A data transfer over the bus " - "has been corrupted.\n"); + dev_warn (&device->cdev->dev, "A parity error occurred on the " + "tape bus\n"); return tape_34xx_erp_failed(request, -EIO); case 0x4a: /* Control unit erp failed. */ - PRINT_WARN("The control unit I/O error recovery failed.\n"); + dev_warn (&device->cdev->dev, "I/O error recovery failed on " + "the tape control unit\n"); return tape_34xx_erp_failed(request, -EIO); case 0x4b: /* * CU and drive incompatible. The drive requests micro-program * patches, which are not available on the CU. */ - PRINT_WARN("The drive needs microprogram patches from the " - "control unit, which are not available.\n"); + dev_warn (&device->cdev->dev, "The tape unit requires a " + "firmware update\n"); return tape_34xx_erp_failed(request, -EIO); case 0x4c: /* @@ -721,8 +716,8 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request, * the block to be written is larger than allowed for * buffered mode. */ - PRINT_WARN("Maximum block size for buffered " - "mode exceeded.\n"); + dev_warn (&device->cdev->dev, "The maximum block size" + " for buffered mode is exceeded\n"); return tape_34xx_erp_failed(request, -ENOBUFS); } /* This erpa is reserved for 3480. */ @@ -759,22 +754,20 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request, return tape_34xx_erp_retry(request); case 0x55: /* Channel interface recovery (permanent). */ - PRINT_WARN("A permanent channel interface error occurred.\n"); + dev_warn (&device->cdev->dev, "A channel interface error cannot be" + " recovered\n"); return tape_34xx_erp_failed(request, -EIO); case 0x56: /* Channel protocol error. */ - PRINT_WARN("A channel protocol error occurred.\n"); + dev_warn (&device->cdev->dev, "A channel protocol error " + "occurred\n"); return tape_34xx_erp_failed(request, -EIO); case 0x57: if (device->cdev->id.driver_info == tape_3480) { /* Attention intercept. */ - PRINT_WARN("An attention intercept occurred, " - "which will be recovered.\n"); return tape_34xx_erp_retry(request); } else { /* Global status intercept. */ - PRINT_WARN("An global status intercept was received, " - "which will be recovered.\n"); return tape_34xx_erp_retry(request); } case 0x5a: @@ -782,42 +775,31 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request, * Tape length incompatible. The tape inserted is too long, * which could cause damage to the tape or the drive. */ - PRINT_WARN("Tape Length Incompatible\n"); - PRINT_WARN("Tape length exceeds IBM enhanced capacity " - "cartdridge length or a medium\n"); - PRINT_WARN("with EC-CST identification mark has been mounted " - "in a device that writes\n"); - PRINT_WARN("3480 or 3480 XF format.\n"); + dev_warn (&device->cdev->dev, "The tape unit does not support " + "the tape length\n"); return tape_34xx_erp_failed(request, -EIO); case 0x5b: /* Format 3480 XF incompatible */ if (sense[1] & SENSE_BEGINNING_OF_TAPE) /* The tape will get overwritten. */ return tape_34xx_erp_retry(request); - PRINT_WARN("Format 3480 XF Incompatible\n"); - PRINT_WARN("Medium has been created in 3480 format. " - "To change the format writes\n"); - PRINT_WARN("must be issued at BOT.\n"); + dev_warn (&device->cdev->dev, "The tape unit does not support" + " format 3480 XF\n"); return tape_34xx_erp_failed(request, -EIO); case 0x5c: /* Format 3480-2 XF incompatible */ - PRINT_WARN("Format 3480-2 XF Incompatible\n"); - PRINT_WARN("Device can only read 3480 or 3480 XF format.\n"); + dev_warn (&device->cdev->dev, "The tape unit does not support tape " + "format 3480-2 XF\n"); return tape_34xx_erp_failed(request, -EIO); case 0x5d: /* Tape length violation. */ - PRINT_WARN("Tape Length Violation\n"); - PRINT_WARN("The mounted tape exceeds IBM Enhanced Capacity " - "Cartdridge System Tape length.\n"); - PRINT_WARN("This may cause damage to the drive or tape when " - "processing to the EOV\n"); + dev_warn (&device->cdev->dev, "The tape unit does not support" + " the current tape length\n"); return tape_34xx_erp_failed(request, -EMEDIUMTYPE); case 0x5e: /* Compaction algorithm incompatible. */ - PRINT_WARN("Compaction Algorithm Incompatible\n"); - PRINT_WARN("The volume is recorded using an incompatible " - "compaction algorithm,\n"); - PRINT_WARN("which is not supported by the device.\n"); + dev_warn (&device->cdev->dev, "The tape unit does not support" + " the compaction algorithm\n"); return tape_34xx_erp_failed(request, -EMEDIUMTYPE); /* The following erpas should have been covered earlier. */ @@ -848,7 +830,6 @@ tape_34xx_irq(struct tape_device *device, struct tape_request *request, (irb->scsw.cmd.dstat & DEV_STAT_DEV_END) && (request->op == TO_WRI)) { /* Write at end of volume */ - PRINT_INFO("End of volume\n"); /* XXX */ return tape_34xx_erp_failed(request, -ENOSPC); } @@ -869,9 +850,7 @@ tape_34xx_irq(struct tape_device *device, struct tape_request *request, } DBF_EVENT(6, "xunknownirq\n"); - PRINT_ERR("Unexpected interrupt.\n"); - PRINT_ERR("Current op is: %s", tape_op_verbose[request->op]); - tape_dump_sense(device, request, irb); + tape_dump_sense_dbf(device, request, irb); return TAPE_IO_STOP; } diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c index 71605a179d6..5a5bb97a081 100644 --- a/drivers/s390/char/tape_3590.c +++ b/drivers/s390/char/tape_3590.c @@ -8,12 +8,15 @@ * Martin Schwidefsky */ +#define KMSG_COMPONENT "tape" + #include #include #include #include #define TAPE_DBF_AREA tape_3590_dbf +#define BUFSIZE 512 /* size of buffers for dynamic generated messages */ #include "tape.h" #include "tape_std.h" @@ -36,7 +39,7 @@ EXPORT_SYMBOL(TAPE_DBF_AREA); * - Read Alternate: implemented *******************************************************************/ -#define PRINTK_HEADER "TAPE_3590: " +#define KMSG_COMPONENT "tape" static const char *tape_3590_msg[TAPE_3590_MAX_MSG] = { [0x00] = "", @@ -726,7 +729,7 @@ static void tape_3590_med_state_set(struct tape_device *device, } c_info->medium_status |= TAPE390_MEDIUM_LOADED_MASK; if (sense->flags & MSENSE_CRYPT_MASK) { - PRINT_INFO("Medium is encrypted (%04x)\n", sense->flags); + DBF_EVENT(6, "Medium is encrypted (%04x)\n", sense->flags); c_info->medium_status |= TAPE390_MEDIUM_ENCRYPTED_MASK; } else { DBF_EVENT(6, "Medium is not encrypted %04x\n", sense->flags); @@ -847,8 +850,7 @@ tape_3590_unsolicited_irq(struct tape_device *device, struct irb *irb) tape_3590_schedule_work(device, TO_READ_ATTMSG); } else { DBF_EVENT(3, "unsol.irq! dev end: %08x\n", device->cdev_id); - PRINT_WARN("Unsolicited IRQ (Device End) caught.\n"); - tape_dump_sense(device, NULL, irb); + tape_dump_sense_dbf(device, NULL, irb); } /* check medium state */ tape_3590_schedule_work(device, TO_MSEN); @@ -876,8 +878,6 @@ tape_3590_erp_basic(struct tape_device *device, struct tape_request *request, case SENSE_BRA_DRE: return tape_3590_erp_failed(device, request, irb, rc); default: - PRINT_ERR("Unknown BRA %x - This should not happen!\n", - sense->bra); BUG(); return TAPE_IO_STOP; } @@ -910,7 +910,8 @@ tape_3590_erp_swap(struct tape_device *device, struct tape_request *request, * should proceed with the new tape... this * should probably be done in user space! */ - PRINT_WARN("(%s): Swap Tape Device!\n", dev_name(&device->cdev->dev)); + dev_warn (&device->cdev->dev, "The tape medium must be loaded into a " + "different tape unit\n"); return tape_3590_erp_basic(device, request, irb, -EIO); } @@ -985,8 +986,6 @@ tape_3590_erp_read_opposite(struct tape_device *device, return tape_3590_erp_failed(device, request, irb, -EIO); break; default: - PRINT_WARN("read_opposite_recovery_called_with_op: %s\n", - tape_op_verbose[request->op]); return tape_3590_erp_failed(device, request, irb, -EIO); } } @@ -998,50 +997,61 @@ static void tape_3590_print_mim_msg_f0(struct tape_device *device, struct irb *irb) { struct tape_3590_sense *sense; + char *exception, *service; + + exception = kmalloc(BUFSIZE, GFP_ATOMIC); + service = kmalloc(BUFSIZE, GFP_ATOMIC); + + if (!exception || !service) + goto out_nomem; sense = (struct tape_3590_sense *) irb->ecw; /* Exception Message */ switch (sense->fmt.f70.emc) { case 0x02: - PRINT_WARN("(%s): Data degraded\n", - dev_name(&device->cdev->dev)); + snprintf(exception, BUFSIZE, "Data degraded"); break; case 0x03: - PRINT_WARN("(%s): Data degraded in partion %i\n", - dev_name(&device->cdev->dev), sense->fmt.f70.mp); + snprintf(exception, BUFSIZE, "Data degraded in partion %i", + sense->fmt.f70.mp); break; case 0x04: - PRINT_WARN("(%s): Medium degraded\n", - dev_name(&device->cdev->dev)); + snprintf(exception, BUFSIZE, "Medium degraded"); break; case 0x05: - PRINT_WARN("(%s): Medium degraded in partition %i\n", - dev_name(&device->cdev->dev), sense->fmt.f70.mp); + snprintf(exception, BUFSIZE, "Medium degraded in partition %i", + sense->fmt.f70.mp); break; case 0x06: - PRINT_WARN("(%s): Block 0 Error\n", - dev_name(&device->cdev->dev)); + snprintf(exception, BUFSIZE, "Block 0 Error"); break; case 0x07: - PRINT_WARN("(%s): Medium Exception 0x%02x\n", - dev_name(&device->cdev->dev), sense->fmt.f70.md); + snprintf(exception, BUFSIZE, "Medium Exception 0x%02x", + sense->fmt.f70.md); break; default: - PRINT_WARN("(%s): MIM ExMsg: 0x%02x\n", - dev_name(&device->cdev->dev), sense->fmt.f70.emc); + snprintf(exception, BUFSIZE, "0x%02x", + sense->fmt.f70.emc); break; } /* Service Message */ switch (sense->fmt.f70.smc) { case 0x02: - PRINT_WARN("(%s): Reference Media maintenance procedure %i\n", - dev_name(&device->cdev->dev), sense->fmt.f70.md); + snprintf(service, BUFSIZE, "Reference Media maintenance " + "procedure %i", sense->fmt.f70.md); break; default: - PRINT_WARN("(%s): MIM ServiceMsg: 0x%02x\n", - dev_name(&device->cdev->dev), sense->fmt.f70.smc); + snprintf(service, BUFSIZE, "0x%02x", + sense->fmt.f70.smc); break; } + + dev_warn (&device->cdev->dev, "Tape media information: exception %s, " + "service %s\n", exception, service); + +out_nomem: + kfree(exception); + kfree(service); } /* @@ -1051,108 +1061,108 @@ static void tape_3590_print_io_sim_msg_f1(struct tape_device *device, struct irb *irb) { struct tape_3590_sense *sense; + char *exception, *service; + + exception = kmalloc(BUFSIZE, GFP_ATOMIC); + service = kmalloc(BUFSIZE, GFP_ATOMIC); + + if (!exception || !service) + goto out_nomem; sense = (struct tape_3590_sense *) irb->ecw; /* Exception Message */ switch (sense->fmt.f71.emc) { case 0x01: - PRINT_WARN("(%s): Effect of failure is unknown\n", - dev_name(&device->cdev->dev)); + snprintf(exception, BUFSIZE, "Effect of failure is unknown"); break; case 0x02: - PRINT_WARN("(%s): CU Exception - no performance impact\n", - dev_name(&device->cdev->dev)); + snprintf(exception, BUFSIZE, "CU Exception - no performance " + "impact"); break; case 0x03: - PRINT_WARN("(%s): CU Exception on channel interface 0x%02x\n", - dev_name(&device->cdev->dev), sense->fmt.f71.md[0]); + snprintf(exception, BUFSIZE, "CU Exception on channel " + "interface 0x%02x", sense->fmt.f71.md[0]); break; case 0x04: - PRINT_WARN("(%s): CU Exception on device path 0x%02x\n", - dev_name(&device->cdev->dev), sense->fmt.f71.md[0]); + snprintf(exception, BUFSIZE, "CU Exception on device path " + "0x%02x", sense->fmt.f71.md[0]); break; case 0x05: - PRINT_WARN("(%s): CU Exception on library path 0x%02x\n", - dev_name(&device->cdev->dev), sense->fmt.f71.md[0]); + snprintf(exception, BUFSIZE, "CU Exception on library path " + "0x%02x", sense->fmt.f71.md[0]); break; case 0x06: - PRINT_WARN("(%s): CU Exception on node 0x%02x\n", - dev_name(&device->cdev->dev), sense->fmt.f71.md[0]); + snprintf(exception, BUFSIZE, "CU Exception on node 0x%02x", + sense->fmt.f71.md[0]); break; case 0x07: - PRINT_WARN("(%s): CU Exception on partition 0x%02x\n", - dev_name(&device->cdev->dev), sense->fmt.f71.md[0]); + snprintf(exception, BUFSIZE, "CU Exception on partition " + "0x%02x", sense->fmt.f71.md[0]); break; default: - PRINT_WARN("(%s): SIM ExMsg: 0x%02x\n", - dev_name(&device->cdev->dev), sense->fmt.f71.emc); + snprintf(exception, BUFSIZE, "0x%02x", + sense->fmt.f71.emc); } /* Service Message */ switch (sense->fmt.f71.smc) { case 0x01: - PRINT_WARN("(%s): Repair impact is unknown\n", - dev_name(&device->cdev->dev)); + snprintf(service, BUFSIZE, "Repair impact is unknown"); break; case 0x02: - PRINT_WARN("(%s): Repair will not impact cu performance\n", - dev_name(&device->cdev->dev)); + snprintf(service, BUFSIZE, "Repair will not impact cu " + "performance"); break; case 0x03: if (sense->fmt.f71.mdf == 0) - PRINT_WARN("(%s): Repair will disable node " - "0x%x on CU\n", - dev_name(&device->cdev->dev), - sense->fmt.f71.md[1]); + snprintf(service, BUFSIZE, "Repair will disable node " + "0x%x on CU", sense->fmt.f71.md[1]); else - PRINT_WARN("(%s): Repair will disable nodes " - "(0x%x-0x%x) on CU\n", - dev_name(&device->cdev->dev), - sense->fmt.f71.md[1], sense->fmt.f71.md[2]); + snprintf(service, BUFSIZE, "Repair will disable " + "nodes (0x%x-0x%x) on CU", sense->fmt.f71.md[1], + sense->fmt.f71.md[2]); break; case 0x04: if (sense->fmt.f71.mdf == 0) - PRINT_WARN("(%s): Repair will disable cannel path " - "0x%x on CU\n", - dev_name(&device->cdev->dev), - sense->fmt.f71.md[1]); + snprintf(service, BUFSIZE, "Repair will disable " + "channel path 0x%x on CU", + sense->fmt.f71.md[1]); else - PRINT_WARN("(%s): Repair will disable cannel paths " - "(0x%x-0x%x) on CU\n", - dev_name(&device->cdev->dev), - sense->fmt.f71.md[1], sense->fmt.f71.md[2]); + snprintf(service, BUFSIZE, "Repair will disable cannel" + " paths (0x%x-0x%x) on CU", + sense->fmt.f71.md[1], sense->fmt.f71.md[2]); break; case 0x05: if (sense->fmt.f71.mdf == 0) - PRINT_WARN("(%s): Repair will disable device path " - "0x%x on CU\n", - dev_name(&device->cdev->dev), - sense->fmt.f71.md[1]); + snprintf(service, BUFSIZE, "Repair will disable device" + " path 0x%x on CU", sense->fmt.f71.md[1]); else - PRINT_WARN("(%s): Repair will disable device paths " - "(0x%x-0x%x) on CU\n", - dev_name(&device->cdev->dev), - sense->fmt.f71.md[1], sense->fmt.f71.md[2]); + snprintf(service, BUFSIZE, "Repair will disable device" + " paths (0x%x-0x%x) on CU", + sense->fmt.f71.md[1], sense->fmt.f71.md[2]); break; case 0x06: if (sense->fmt.f71.mdf == 0) - PRINT_WARN("(%s): Repair will disable library path " - "0x%x on CU\n", - dev_name(&device->cdev->dev), - sense->fmt.f71.md[1]); + snprintf(service, BUFSIZE, "Repair will disable " + "library path 0x%x on CU", + sense->fmt.f71.md[1]); else - PRINT_WARN("(%s): Repair will disable library paths " - "(0x%x-0x%x) on CU\n", - dev_name(&device->cdev->dev), - sense->fmt.f71.md[1], sense->fmt.f71.md[2]); + snprintf(service, BUFSIZE, "Repair will disable " + "library paths (0x%x-0x%x) on CU", + sense->fmt.f71.md[1], sense->fmt.f71.md[2]); break; case 0x07: - PRINT_WARN("(%s): Repair will disable access to CU\n", - dev_name(&device->cdev->dev)); + snprintf(service, BUFSIZE, "Repair will disable access to CU"); break; default: - PRINT_WARN("(%s): SIM ServiceMsg: 0x%02x\n", - dev_name(&device->cdev->dev), sense->fmt.f71.smc); + snprintf(service, BUFSIZE, "0x%02x", + sense->fmt.f71.smc); } + + dev_warn (&device->cdev->dev, "I/O subsystem information: exception" + " %s, service %s\n", exception, service); +out_nomem: + kfree(exception); + kfree(service); } /* @@ -1162,111 +1172,109 @@ static void tape_3590_print_dev_sim_msg_f2(struct tape_device *device, struct irb *irb) { struct tape_3590_sense *sense; + char *exception, *service; + + exception = kmalloc(BUFSIZE, GFP_ATOMIC); + service = kmalloc(BUFSIZE, GFP_ATOMIC); + + if (!exception || !service) + goto out_nomem; sense = (struct tape_3590_sense *) irb->ecw; /* Exception Message */ switch (sense->fmt.f71.emc) { case 0x01: - PRINT_WARN("(%s): Effect of failure is unknown\n", - dev_name(&device->cdev->dev)); + snprintf(exception, BUFSIZE, "Effect of failure is unknown"); break; case 0x02: - PRINT_WARN("(%s): DV Exception - no performance impact\n", - dev_name(&device->cdev->dev)); + snprintf(exception, BUFSIZE, "DV Exception - no performance" + " impact"); break; case 0x03: - PRINT_WARN("(%s): DV Exception on channel interface 0x%02x\n", - dev_name(&device->cdev->dev), sense->fmt.f71.md[0]); + snprintf(exception, BUFSIZE, "DV Exception on channel " + "interface 0x%02x", sense->fmt.f71.md[0]); break; case 0x04: - PRINT_WARN("(%s): DV Exception on loader 0x%02x\n", - dev_name(&device->cdev->dev), sense->fmt.f71.md[0]); + snprintf(exception, BUFSIZE, "DV Exception on loader 0x%02x", + sense->fmt.f71.md[0]); break; case 0x05: - PRINT_WARN("(%s): DV Exception on message display 0x%02x\n", - dev_name(&device->cdev->dev), sense->fmt.f71.md[0]); + snprintf(exception, BUFSIZE, "DV Exception on message display" + " 0x%02x", sense->fmt.f71.md[0]); break; case 0x06: - PRINT_WARN("(%s): DV Exception in tape path\n", - dev_name(&device->cdev->dev)); + snprintf(exception, BUFSIZE, "DV Exception in tape path"); break; case 0x07: - PRINT_WARN("(%s): DV Exception in drive\n", - dev_name(&device->cdev->dev)); + snprintf(exception, BUFSIZE, "DV Exception in drive"); break; default: - PRINT_WARN("(%s): DSIM ExMsg: 0x%02x\n", - dev_name(&device->cdev->dev), sense->fmt.f71.emc); + snprintf(exception, BUFSIZE, "0x%02x", + sense->fmt.f71.emc); } /* Service Message */ switch (sense->fmt.f71.smc) { case 0x01: - PRINT_WARN("(%s): Repair impact is unknown\n", - dev_name(&device->cdev->dev)); + snprintf(service, BUFSIZE, "Repair impact is unknown"); break; case 0x02: - PRINT_WARN("(%s): Repair will not impact device performance\n", - dev_name(&device->cdev->dev)); + snprintf(service, BUFSIZE, "Repair will not impact device " + "performance"); break; case 0x03: if (sense->fmt.f71.mdf == 0) - PRINT_WARN("(%s): Repair will disable channel path " - "0x%x on DV\n", - dev_name(&device->cdev->dev), - sense->fmt.f71.md[1]); + snprintf(service, BUFSIZE, "Repair will disable " + "channel path 0x%x on DV", + sense->fmt.f71.md[1]); else - PRINT_WARN("(%s): Repair will disable channel path " - "(0x%x-0x%x) on DV\n", - dev_name(&device->cdev->dev), - sense->fmt.f71.md[1], sense->fmt.f71.md[2]); + snprintf(service, BUFSIZE, "Repair will disable " + "channel path (0x%x-0x%x) on DV", + sense->fmt.f71.md[1], sense->fmt.f71.md[2]); break; case 0x04: if (sense->fmt.f71.mdf == 0) - PRINT_WARN("(%s): Repair will disable interface 0x%x " - "on DV\n", - dev_name(&device->cdev->dev), - sense->fmt.f71.md[1]); + snprintf(service, BUFSIZE, "Repair will disable " + "interface 0x%x on DV", sense->fmt.f71.md[1]); else - PRINT_WARN("(%s): Repair will disable interfaces " - "(0x%x-0x%x) on DV\n", - dev_name(&device->cdev->dev), - sense->fmt.f71.md[1], sense->fmt.f71.md[2]); + snprintf(service, BUFSIZE, "Repair will disable " + "interfaces (0x%x-0x%x) on DV", + sense->fmt.f71.md[1], sense->fmt.f71.md[2]); break; case 0x05: if (sense->fmt.f71.mdf == 0) - PRINT_WARN("(%s): Repair will disable loader 0x%x " - "on DV\n", - dev_name(&device->cdev->dev), - sense->fmt.f71.md[1]); + snprintf(service, BUFSIZE, "Repair will disable loader" + " 0x%x on DV", sense->fmt.f71.md[1]); else - PRINT_WARN("(%s): Repair will disable loader " - "(0x%x-0x%x) on DV\n", - dev_name(&device->cdev->dev), - sense->fmt.f71.md[1], sense->fmt.f71.md[2]); + snprintf(service, BUFSIZE, "Repair will disable loader" + " (0x%x-0x%x) on DV", + sense->fmt.f71.md[1], sense->fmt.f71.md[2]); break; case 0x07: - PRINT_WARN("(%s): Repair will disable access to DV\n", - dev_name(&device->cdev->dev)); + snprintf(service, BUFSIZE, "Repair will disable access to DV"); break; case 0x08: if (sense->fmt.f71.mdf == 0) - PRINT_WARN("(%s): Repair will disable message " - "display 0x%x on DV\n", - dev_name(&device->cdev->dev), - sense->fmt.f71.md[1]); + snprintf(service, BUFSIZE, "Repair will disable " + "message display 0x%x on DV", + sense->fmt.f71.md[1]); else - PRINT_WARN("(%s): Repair will disable message " - "displays (0x%x-0x%x) on DV\n", - dev_name(&device->cdev->dev), - sense->fmt.f71.md[1], sense->fmt.f71.md[2]); + snprintf(service, BUFSIZE, "Repair will disable " + "message displays (0x%x-0x%x) on DV", + sense->fmt.f71.md[1], sense->fmt.f71.md[2]); break; case 0x09: - PRINT_WARN("(%s): Clean DV\n", dev_name(&device->cdev->dev)); + snprintf(service, BUFSIZE, "Clean DV"); break; default: - PRINT_WARN("(%s): DSIM ServiceMsg: 0x%02x\n", - dev_name(&device->cdev->dev), sense->fmt.f71.smc); + snprintf(service, BUFSIZE, "0x%02x", + sense->fmt.f71.smc); } + + dev_warn (&device->cdev->dev, "Device subsystem information: exception" + " %s, service %s\n", exception, service); +out_nomem: + kfree(exception); + kfree(service); } /* @@ -1282,46 +1290,44 @@ tape_3590_print_era_msg(struct tape_device *device, struct irb *irb) return; if ((sense->mc > 0) && (sense->mc < TAPE_3590_MAX_MSG)) { if (tape_3590_msg[sense->mc] != NULL) - PRINT_WARN("(%s): %s\n", dev_name(&device->cdev->dev), - tape_3590_msg[sense->mc]); - else { - PRINT_WARN("(%s): Message Code 0x%x\n", - dev_name(&device->cdev->dev), sense->mc); - } + dev_warn (&device->cdev->dev, "The tape unit has " + "issued sense message %s\n", + tape_3590_msg[sense->mc]); + else + dev_warn (&device->cdev->dev, "The tape unit has " + "issued an unknown sense message code 0x%x\n", + sense->mc); return; } if (sense->mc == 0xf0) { /* Standard Media Information Message */ - PRINT_WARN("(%s): MIM SEV=%i, MC=%02x, ES=%x/%x, " - "RC=%02x-%04x-%02x\n", dev_name(&device->cdev->dev), - sense->fmt.f70.sev, sense->mc, - sense->fmt.f70.emc, sense->fmt.f70.smc, - sense->fmt.f70.refcode, sense->fmt.f70.mid, - sense->fmt.f70.fid); + dev_warn (&device->cdev->dev, "MIM SEV=%i, MC=%02x, ES=%x/%x, " + "RC=%02x-%04x-%02x\n", sense->fmt.f70.sev, sense->mc, + sense->fmt.f70.emc, sense->fmt.f70.smc, + sense->fmt.f70.refcode, sense->fmt.f70.mid, + sense->fmt.f70.fid); tape_3590_print_mim_msg_f0(device, irb); return; } if (sense->mc == 0xf1) { /* Standard I/O Subsystem Service Information Message */ - PRINT_WARN("(%s): IOSIM SEV=%i, DEVTYPE=3590/%02x, " - "MC=%02x, ES=%x/%x, REF=0x%04x-0x%04x-0x%04x\n", - dev_name(&device->cdev->dev), sense->fmt.f71.sev, - device->cdev->id.dev_model, - sense->mc, sense->fmt.f71.emc, - sense->fmt.f71.smc, sense->fmt.f71.refcode1, - sense->fmt.f71.refcode2, sense->fmt.f71.refcode3); + dev_warn (&device->cdev->dev, "IOSIM SEV=%i, DEVTYPE=3590/%02x," + " MC=%02x, ES=%x/%x, REF=0x%04x-0x%04x-0x%04x\n", + sense->fmt.f71.sev, device->cdev->id.dev_model, + sense->mc, sense->fmt.f71.emc, sense->fmt.f71.smc, + sense->fmt.f71.refcode1, sense->fmt.f71.refcode2, + sense->fmt.f71.refcode3); tape_3590_print_io_sim_msg_f1(device, irb); return; } if (sense->mc == 0xf2) { /* Standard Device Service Information Message */ - PRINT_WARN("(%s): DEVSIM SEV=%i, DEVTYPE=3590/%02x, " - "MC=%02x, ES=%x/%x, REF=0x%04x-0x%04x-0x%04x\n", - dev_name(&device->cdev->dev), sense->fmt.f71.sev, - device->cdev->id.dev_model, - sense->mc, sense->fmt.f71.emc, - sense->fmt.f71.smc, sense->fmt.f71.refcode1, - sense->fmt.f71.refcode2, sense->fmt.f71.refcode3); + dev_warn (&device->cdev->dev, "DEVSIM SEV=%i, DEVTYPE=3590/%02x" + ", MC=%02x, ES=%x/%x, REF=0x%04x-0x%04x-0x%04x\n", + sense->fmt.f71.sev, device->cdev->id.dev_model, + sense->mc, sense->fmt.f71.emc, sense->fmt.f71.smc, + sense->fmt.f71.refcode1, sense->fmt.f71.refcode2, + sense->fmt.f71.refcode3); tape_3590_print_dev_sim_msg_f2(device, irb); return; } @@ -1329,8 +1335,8 @@ tape_3590_print_era_msg(struct tape_device *device, struct irb *irb) /* Standard Library Service Information Message */ return; } - PRINT_WARN("(%s): Device Message(%x)\n", - dev_name(&device->cdev->dev), sense->mc); + dev_warn (&device->cdev->dev, "The tape unit has issued an unknown " + "sense message code %x\n", sense->mc); } static int tape_3590_crypt_error(struct tape_device *device, @@ -1355,9 +1361,8 @@ static int tape_3590_crypt_error(struct tape_device *device, /* No connection to EKM */ return tape_3590_erp_basic(device, request, irb, -ENOTCONN); - PRINT_ERR("(%s): Unable to get encryption key from EKM\n", bus_id); - PRINT_ERR("(%s): CU=%02X DRIVE=%06X EKM=%02X:%04X\n", bus_id, cu_rc, - drv_rc, ekm_rc1, ekm_rc2); + dev_err (&device->cdev->dev, "The tape unit failed to obtain the " + "encryption key from EKM\n"); return tape_3590_erp_basic(device, request, irb, -ENOKEY); } @@ -1443,8 +1448,6 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request, * print additional msg since default msg * "device intervention" is not very meaningfull */ - PRINT_WARN("(%s): Tape operation when medium not loaded\n", - dev_name(&device->cdev->dev)); tape_med_state_set(device, MS_UNLOADED); tape_3590_schedule_work(device, TO_CRYPT_OFF); return tape_3590_erp_basic(device, request, irb, -ENOMEDIUM); @@ -1490,19 +1493,13 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request, return tape_3590_erp_basic(device, request, irb, -ENOMEDIUM); case 0x6020: - PRINT_WARN("(%s): Cartridge of wrong type ?\n", - dev_name(&device->cdev->dev)); return tape_3590_erp_basic(device, request, irb, -EMEDIUMTYPE); case 0x8011: - PRINT_WARN("(%s): Another host has reserved the tape device\n", - dev_name(&device->cdev->dev)); return tape_3590_erp_basic(device, request, irb, -EPERM); case 0x8013: - PRINT_WARN("(%s): Another host has privileged access to the " - "tape device\n", dev_name(&device->cdev->dev)); - PRINT_WARN("(%s): To solve the problem unload the current " - "cartridge!\n", dev_name(&device->cdev->dev)); + dev_warn (&device->cdev->dev, "A different host has privileged" + " access to the tape unit\n"); return tape_3590_erp_basic(device, request, irb, -EPERM); default: return tape_3590_erp_basic(device, request, irb, -EIO); @@ -1552,9 +1549,7 @@ tape_3590_irq(struct tape_device *device, struct tape_request *request, } DBF_EVENT(6, "xunknownirq\n"); - PRINT_ERR("Unexpected interrupt.\n"); - PRINT_ERR("Current op is: %s", tape_op_verbose[request->op]); - tape_dump_sense(device, request, irb); + tape_dump_sense_dbf(device, request, irb); return TAPE_IO_STOP; } @@ -1609,7 +1604,6 @@ tape_3590_setup_device(struct tape_device *device) if (rc) goto fail_rdc_data; if (rdc_data->data[31] == 0x13) { - PRINT_INFO("Device has crypto support\n"); data->crypt_info.capability |= TAPE390_CRYPT_SUPPORTED_MASK; tape_3592_disable_crypt(device); } else { diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c index ae18baf59f0..f32e89e7c4f 100644 --- a/drivers/s390/char/tape_block.c +++ b/drivers/s390/char/tape_block.c @@ -10,6 +10,8 @@ * Stefan Bader */ +#define KMSG_COMPONENT "tape" + #include #include #include @@ -23,8 +25,6 @@ #include "tape.h" -#define PRINTK_HEADER "TAPE_BLOCK: " - #define TAPEBLOCK_MAX_SEC 100 #define TAPEBLOCK_MIN_REQUEUE 3 @@ -279,8 +279,6 @@ tapeblock_cleanup_device(struct tape_device *device) tape_put_device(device); if (!device->blk_data.disk) { - PRINT_ERR("(%s): No gendisk to clean up!\n", - dev_name(&device->cdev->dev)); goto cleanup_queue; } @@ -314,7 +312,8 @@ tapeblock_revalidate_disk(struct gendisk *disk) if (!device->blk_data.medium_changed) return 0; - PRINT_INFO("Detecting media size...\n"); + dev_info(&device->cdev->dev, "Determining the size of the recorded " + "area...\n"); rc = tape_mtop(device, MTFSFM, 1); if (rc) return rc; @@ -341,7 +340,8 @@ tapeblock_revalidate_disk(struct gendisk *disk) device->bof = rc; nr_of_blks -= rc; - PRINT_INFO("Found %i blocks on media\n", nr_of_blks); + dev_info(&device->cdev->dev, "The size of the recorded area is %i " + "blocks\n", nr_of_blks); set_capacity(device->blk_data.disk, nr_of_blks*(TAPEBLOCK_HSEC_SIZE/512)); @@ -376,8 +376,8 @@ tapeblock_open(struct block_device *bdev, fmode_t mode) if (device->required_tapemarks) { DBF_EVENT(2, "TBLOCK: missing tapemarks\n"); - PRINT_ERR("TBLOCK: Refusing to open tape with missing" - " end of file marks.\n"); + dev_warn(&device->cdev->dev, "Opening the tape failed because" + " of missing end-of-file marks\n"); rc = -EPERM; goto put_device; } @@ -452,7 +452,6 @@ tapeblock_ioctl( rc = -EINVAL; break; default: - PRINT_WARN("invalid ioctl 0x%x\n", command); rc = -EINVAL; } @@ -474,7 +473,6 @@ tapeblock_init(void) if (tapeblock_major == 0) tapeblock_major = rc; - PRINT_INFO("tape gets major %d for block device\n", tapeblock_major); return 0; } diff --git a/drivers/s390/char/tape_char.c b/drivers/s390/char/tape_char.c index be0ce2215c8..31566c55adf 100644 --- a/drivers/s390/char/tape_char.c +++ b/drivers/s390/char/tape_char.c @@ -24,8 +24,6 @@ #include "tape_std.h" #include "tape_class.h" -#define PRINTK_HEADER "TAPE_CHAR: " - #define TAPECHAR_MAJOR 0 /* get dynamic major */ /* @@ -102,8 +100,6 @@ tapechar_check_idalbuffer(struct tape_device *device, size_t block_size) if (block_size > MAX_BLOCKSIZE) { DBF_EVENT(3, "Invalid blocksize (%zd > %d)\n", block_size, MAX_BLOCKSIZE); - PRINT_ERR("Invalid blocksize (%zd> %d)\n", - block_size, MAX_BLOCKSIZE); return -EINVAL; } @@ -485,7 +481,6 @@ tapechar_init (void) return -1; tapechar_major = MAJOR(dev); - PRINT_INFO("tape gets major %d for character devices\n", MAJOR(dev)); return 0; } @@ -496,7 +491,5 @@ tapechar_init (void) void tapechar_exit(void) { - PRINT_INFO("tape releases major %d for character devices\n", - tapechar_major); unregister_chrdev_region(MKDEV(tapechar_major, 0), 256); } diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c index f9bb51fa7f5..1b6a2441246 100644 --- a/drivers/s390/char/tape_core.c +++ b/drivers/s390/char/tape_core.c @@ -11,6 +11,7 @@ * Stefan Bader */ +#define KMSG_COMPONENT "tape" #include #include // for kernel parameters #include // for requesting modules @@ -25,7 +26,6 @@ #include "tape.h" #include "tape_std.h" -#define PRINTK_HEADER "TAPE_CORE: " #define LONG_BUSY_TIMEOUT 180 /* seconds */ static void __tape_do_irq (struct ccw_device *, unsigned long, struct irb *); @@ -214,13 +214,13 @@ tape_med_state_set(struct tape_device *device, enum tape_medium_state newstate) switch(newstate){ case MS_UNLOADED: device->tape_generic_status |= GMT_DR_OPEN(~0); - PRINT_INFO("(%s): Tape is unloaded\n", - dev_name(&device->cdev->dev)); + dev_info(&device->cdev->dev, "The tape cartridge has been " + "successfully unloaded\n"); break; case MS_LOADED: device->tape_generic_status &= ~GMT_DR_OPEN(~0); - PRINT_INFO("(%s): Tape has been mounted\n", - dev_name(&device->cdev->dev)); + dev_info(&device->cdev->dev, "A tape cartridge has been " + "mounted\n"); break; default: // print nothing @@ -333,7 +333,6 @@ tape_generic_online(struct tape_device *device, /* Let the discipline have a go at the device. */ device->discipline = discipline; if (!try_module_get(discipline->owner)) { - PRINT_ERR("Cannot get module. Module gone.\n"); return -EINVAL; } @@ -391,7 +390,6 @@ int tape_generic_offline(struct tape_device *device) { if (!device) { - PRINT_ERR("tape_generic_offline: no such device\n"); return -ENODEV; } @@ -413,9 +411,6 @@ tape_generic_offline(struct tape_device *device) DBF_EVENT(3, "(%08x): Set offline failed " "- drive in use.\n", device->cdev_id); - PRINT_WARN("(%s): Set offline failed " - "- drive in use.\n", - dev_name(&device->cdev->dev)); spin_unlock_irq(get_ccwdev_lock(device->cdev)); return -EBUSY; } @@ -435,14 +430,11 @@ tape_alloc_device(void) device = kzalloc(sizeof(struct tape_device), GFP_KERNEL); if (device == NULL) { DBF_EXCEPTION(2, "ti:no mem\n"); - PRINT_INFO ("can't allocate memory for " - "tape info structure\n"); return ERR_PTR(-ENOMEM); } device->modeset_byte = kmalloc(1, GFP_KERNEL | GFP_DMA); if (device->modeset_byte == NULL) { DBF_EXCEPTION(2, "ti:no mem\n"); - PRINT_INFO("can't allocate memory for modeset byte\n"); kfree(device); return ERR_PTR(-ENOMEM); } @@ -490,7 +482,6 @@ tape_put_device(struct tape_device *device) } else { if (remain < 0) { DBF_EVENT(4, "put device without reference\n"); - PRINT_ERR("put device without reference\n"); } else { DBF_EVENT(4, "tape_free_device(%p)\n", device); kfree(device->modeset_byte); @@ -538,8 +529,6 @@ tape_generic_probe(struct ccw_device *cdev) ret = sysfs_create_group(&cdev->dev.kobj, &tape_attr_group); if (ret) { tape_put_device(device); - PRINT_ERR("probe failed for tape device %s\n", - dev_name(&cdev->dev)); return ret; } cdev->dev.driver_data = device; @@ -547,7 +536,6 @@ tape_generic_probe(struct ccw_device *cdev) device->cdev = cdev; ccw_device_get_id(cdev, &dev_id); device->cdev_id = devid_to_int(&dev_id); - PRINT_INFO("tape device %s found\n", dev_name(&cdev->dev)); return ret; } @@ -584,7 +572,6 @@ tape_generic_remove(struct ccw_device *cdev) device = cdev->dev.driver_data; if (!device) { - PRINT_ERR("No device pointer in tape_generic_remove!\n"); return; } DBF_LH(3, "(%08x): tape_generic_remove(%p)\n", device->cdev_id, cdev); @@ -615,10 +602,8 @@ tape_generic_remove(struct ccw_device *cdev) */ DBF_EVENT(3, "(%08x): Drive in use vanished!\n", device->cdev_id); - PRINT_WARN("(%s): Drive in use vanished - " - "expect trouble!\n", - dev_name(&device->cdev->dev)); - PRINT_WARN("State was %i\n", device->tape_state); + dev_warn(&device->cdev->dev, "A tape unit was detached" + " while in use\n"); tape_state_set(device, TS_NOT_OPER); __tape_discard_requests(device); spin_unlock_irq(get_ccwdev_lock(device->cdev)); @@ -829,30 +814,6 @@ __tape_end_request( __tape_start_next_request(device); } -/* - * Write sense data to console/dbf - */ -void -tape_dump_sense(struct tape_device* device, struct tape_request *request, - struct irb *irb) -{ - unsigned int *sptr; - - PRINT_INFO("-------------------------------------------------\n"); - PRINT_INFO("DSTAT : %02x CSTAT: %02x CPA: %04x\n", - irb->scsw.cmd.dstat, irb->scsw.cmd.cstat, irb->scsw.cmd.cpa); - PRINT_INFO("DEVICE: %s\n", dev_name(&device->cdev->dev)); - if (request != NULL) - PRINT_INFO("OP : %s\n", tape_op_verbose[request->op]); - - sptr = (unsigned int *) irb->ecw; - PRINT_INFO("Sense data: %08X %08X %08X %08X \n", - sptr[0], sptr[1], sptr[2], sptr[3]); - PRINT_INFO("Sense data: %08X %08X %08X %08X \n", - sptr[4], sptr[5], sptr[6], sptr[7]); - PRINT_INFO("--------------------------------------------------\n"); -} - /* * Write sense data to dbf */ @@ -1051,8 +1012,6 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb) device = (struct tape_device *) cdev->dev.driver_data; if (device == NULL) { - PRINT_ERR("could not get device structure for %s " - "in interrupt\n", dev_name(&cdev->dev)); return; } request = (struct tape_request *) intparm; @@ -1064,13 +1023,13 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb) /* FIXME: What to do with the request? */ switch (PTR_ERR(irb)) { case -ETIMEDOUT: - PRINT_WARN("(%s): Request timed out\n", + DBF_LH(1, "(%s): Request timed out\n", dev_name(&cdev->dev)); case -EIO: __tape_end_request(device, request, -EIO); break; default: - PRINT_ERR("(%s): Unexpected i/o error %li\n", + DBF_LH(1, "(%s): Unexpected i/o error %li\n", dev_name(&cdev->dev), PTR_ERR(irb)); } @@ -1182,8 +1141,6 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb) default: if (rc > 0) { DBF_EVENT(6, "xunknownrc\n"); - PRINT_ERR("Invalid return code from discipline " - "interrupt function.\n"); __tape_end_request(device, request, -EIO); } else { __tape_end_request(device, request, rc); @@ -1323,7 +1280,6 @@ EXPORT_SYMBOL(tape_state_set); EXPORT_SYMBOL(tape_med_state_set); EXPORT_SYMBOL(tape_alloc_request); EXPORT_SYMBOL(tape_free_request); -EXPORT_SYMBOL(tape_dump_sense); EXPORT_SYMBOL(tape_dump_sense_dbf); EXPORT_SYMBOL(tape_do_io); EXPORT_SYMBOL(tape_do_io_async); diff --git a/drivers/s390/char/tape_proc.c b/drivers/s390/char/tape_proc.c index 8a376af926a..202f4213293 100644 --- a/drivers/s390/char/tape_proc.c +++ b/drivers/s390/char/tape_proc.c @@ -20,8 +20,6 @@ #include "tape.h" -#define PRINTK_HEADER "TAPE_PROC: " - static const char *tape_med_st_verbose[MS_SIZE] = { [MS_UNKNOWN] = "UNKNOWN ", @@ -128,7 +126,6 @@ tape_proc_init(void) proc_create("tapedevices", S_IFREG | S_IRUGO | S_IWUSR, NULL, &tape_proc_ops); if (tape_proc_devices == NULL) { - PRINT_WARN("tape: Cannot register procfs entry tapedevices\n"); return; } } diff --git a/drivers/s390/char/tape_std.c b/drivers/s390/char/tape_std.c index 5bd573d144d..44dd0f80c84 100644 --- a/drivers/s390/char/tape_std.c +++ b/drivers/s390/char/tape_std.c @@ -26,8 +26,6 @@ #include "tape.h" #include "tape_std.h" -#define PRINTK_HEADER "TAPE_STD: " - /* * tape_std_assign */ @@ -46,9 +44,8 @@ tape_std_assign_timeout(unsigned long data) device->cdev_id); rc = tape_cancel_io(device, request); if(rc) - PRINT_ERR("(%s): Assign timeout: Cancel failed with rc = %i\n", + DBF_EVENT(3, "(%s): Assign timeout: Cancel failed with rc = %i\n", dev_name(&device->cdev->dev), rc); - } int @@ -82,8 +79,6 @@ tape_std_assign(struct tape_device *device) del_timer(&timeout); if (rc != 0) { - PRINT_WARN("%s: assign failed - device might be busy\n", - dev_name(&device->cdev->dev)); DBF_EVENT(3, "%08x: assign failed - device might be busy\n", device->cdev_id); } else { @@ -105,8 +100,6 @@ tape_std_unassign (struct tape_device *device) if (device->tape_state == TS_NOT_OPER) { DBF_EVENT(3, "(%08x): Can't unassign device\n", device->cdev_id); - PRINT_WARN("(%s): Can't unassign device - device gone\n", - dev_name(&device->cdev->dev)); return -EIO; } @@ -120,8 +113,6 @@ tape_std_unassign (struct tape_device *device) if ((rc = tape_do_io(device, request)) != 0) { DBF_EVENT(3, "%08x: Unassign failed\n", device->cdev_id); - PRINT_WARN("%s: Unassign failed\n", - dev_name(&device->cdev->dev)); } else { DBF_EVENT(3, "%08x: Tape unassigned\n", device->cdev_id); } @@ -242,8 +233,6 @@ tape_std_mtsetblk(struct tape_device *device, int count) if (count > MAX_BLOCKSIZE) { DBF_EVENT(3, "Invalid block size (%d > %d) given.\n", count, MAX_BLOCKSIZE); - PRINT_ERR("Invalid block size (%d > %d) given.\n", - count, MAX_BLOCKSIZE); return -EINVAL; } @@ -633,14 +622,6 @@ tape_std_mtcompression(struct tape_device *device, int mt_count) if (mt_count < 0 || mt_count > 1) { DBF_EXCEPTION(6, "xcom parm\n"); - if (*device->modeset_byte & 0x08) - PRINT_INFO("(%s) Compression is currently on\n", - dev_name(&device->cdev->dev)); - else - PRINT_INFO("(%s) Compression is currently off\n", - dev_name(&device->cdev->dev)); - PRINT_INFO("Use 1 to switch compression on, 0 to " - "switch it off\n"); return -EINVAL; } request = tape_alloc_request(2, 0); -- cgit v1.2.3-70-g09d2 From 1fbc9f46a024535d95c3d5f136901decd86b109e Mon Sep 17 00:00:00 2001 From: Eric Sesterhenn Date: Thu, 26 Mar 2009 15:24:39 +0100 Subject: [S390] list usage cleanup in s390 Trivial cleanup, list_del(); list_add{,_tail}() is equivalent to list_move{,_tail}(). Semantic patch for coccinelle can be found at www.cccmz.de/~snakebyte/list_move_tail.spatch Signed-off-by: Eric Sesterhenn Signed-off-by: Martin Schwidefsky --- drivers/s390/crypto/zcrypt_api.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index cb22b97944b..65b6a96afe6 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -128,8 +128,7 @@ static void __zcrypt_increase_preference(struct zcrypt_device *zdev) if (l == zdev->list.prev) return; /* Move zdev behind l */ - list_del(&zdev->list); - list_add(&zdev->list, l); + list_move(&zdev->list, l); } /** @@ -157,8 +156,7 @@ static void __zcrypt_decrease_preference(struct zcrypt_device *zdev) if (l == zdev->list.next) return; /* Move zdev before l */ - list_del(&zdev->list); - list_add_tail(&zdev->list, l); + list_move_tail(&zdev->list, l); } static void zcrypt_device_release(struct kref *kref) -- cgit v1.2.3-70-g09d2 From eaf1b6fbca8d9be87bef2eafaa3f40bffe26ce04 Mon Sep 17 00:00:00 2001 From: Dan Smith Date: Thu, 26 Mar 2009 15:24:40 +0100 Subject: [S390] Expose a constant for the number of words representing the CRs We need to use this value in the checkpoint/restart code and would like to have a constant instead of a magic '3'. Cc: linux-s390@vger.kernel.org Signed-off-by: Dan Smith Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/ptrace.h | 4 +++- arch/s390/kernel/compat_ptrace.h | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/s390/include/asm/ptrace.h b/arch/s390/include/asm/ptrace.h index 8920025c3c0..f1b051630c5 100644 --- a/arch/s390/include/asm/ptrace.h +++ b/arch/s390/include/asm/ptrace.h @@ -172,6 +172,8 @@ #define NUM_CRS 16 #define NUM_ACRS 16 +#define NUM_CR_WORDS 3 + #define FPR_SIZE 8 #define FPC_SIZE 4 #define FPC_PAD_SIZE 4 /* gcc insists on aligning the fpregs */ @@ -334,7 +336,7 @@ struct pt_regs */ typedef struct { - unsigned long cr[3]; + unsigned long cr[NUM_CR_WORDS]; } per_cr_words; #define PER_EM_MASK 0xE8000000UL diff --git a/arch/s390/kernel/compat_ptrace.h b/arch/s390/kernel/compat_ptrace.h index a2be3a978d5..123dd660d7f 100644 --- a/arch/s390/kernel/compat_ptrace.h +++ b/arch/s390/kernel/compat_ptrace.h @@ -1,10 +1,11 @@ #ifndef _PTRACE32_H #define _PTRACE32_H +#include /* needed for NUM_CR_WORDS */ #include "compat_linux.h" /* needed for psw_compat_t */ typedef struct { - __u32 cr[3]; + __u32 cr[NUM_CR_WORDS]; } per_cr_words32; typedef struct { -- cgit v1.2.3-70-g09d2 From 2938af534d47891ddbced552e5d29f7b90bec609 Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Thu, 26 Mar 2009 15:24:41 +0100 Subject: [S390] Fix comments in lowcore structure This patch fixes two addresses in the comments for the lowcore structure. Looks like an copy-paste bug. Signed-off-by: Christian Borntraeger Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/lowcore.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/s390/include/asm/lowcore.h b/arch/s390/include/asm/lowcore.h index ee4b10ff938..f94386ece0d 100644 --- a/arch/s390/include/asm/lowcore.h +++ b/arch/s390/include/asm/lowcore.h @@ -315,8 +315,8 @@ struct _lowcore __u8 op_access_id; /* 0x0a2 */ __u8 ar_access_id; /* 0x0a3 */ __u8 pad2[0xA8-0xA4]; /* 0x0a4 */ - addr_t trans_exc_code; /* 0x0A0 */ - addr_t monitor_code; /* 0x09c */ + addr_t trans_exc_code; /* 0x0a8 */ + addr_t monitor_code; /* 0x0b0 */ __u16 subchannel_id; /* 0x0b8 */ __u16 subchannel_nr; /* 0x0ba */ __u32 io_int_parm; /* 0x0bc */ -- cgit v1.2.3-70-g09d2 From 7b4684880dfc6c45bc56039ca5eada771d7643ab Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Thu, 26 Mar 2009 15:24:42 +0100 Subject: [S390] eliminate cpuinfo_S390 structure Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/lowcore.h | 15 +++++---- arch/s390/include/asm/processor.h | 16 +-------- arch/s390/include/asm/smp.h | 7 +--- arch/s390/kernel/processor.c | 69 +++++++++++++++++++-------------------- arch/s390/kernel/setup.c | 10 ++---- arch/s390/kernel/smp.c | 8 ++--- drivers/s390/cio/css.c | 2 +- 7 files changed, 52 insertions(+), 75 deletions(-) diff --git a/arch/s390/include/asm/lowcore.h b/arch/s390/include/asm/lowcore.h index f94386ece0d..ad543c11826 100644 --- a/arch/s390/include/asm/lowcore.h +++ b/arch/s390/include/asm/lowcore.h @@ -80,7 +80,6 @@ #define __LC_USER_ASCE 0xC50 #define __LC_PANIC_STACK 0xC54 #define __LC_CPUID 0xC60 -#define __LC_CPUADDR 0xC68 #define __LC_IPLDEV 0xC7C #define __LC_CURRENT 0xC90 #define __LC_INT_CLOCK 0xC98 @@ -102,7 +101,6 @@ #define __LC_USER_ASCE 0xD60 #define __LC_PANIC_STACK 0xD68 #define __LC_CPUID 0xD80 -#define __LC_CPUADDR 0xD88 #define __LC_IPLDEV 0xDB8 #define __LC_CURRENT 0xDD8 #define __LC_INT_CLOCK 0xDE8 @@ -273,8 +271,10 @@ struct _lowcore __u32 user_exec_asce; /* 0xc58 */ __u8 pad10[0xc60-0xc5c]; /* 0xc5c */ /* entry.S sensitive area start */ - struct cpuinfo_S390 cpu_data; /* 0xc60 */ - __u32 ipl_device; /* 0xc7c */ + cpuid_t cpu_id; /* 0xc60 */ + __u32 cpu_nr; /* 0xc68 */ + __u32 ipl_device; /* 0xc6c */ + __u8 pad_0xc70[0xc80-0xc70]; /* 0xc70 */ /* entry.S sensitive area end */ /* SMP info area: defined by DJB */ @@ -366,9 +366,10 @@ struct _lowcore __u64 user_exec_asce; /* 0xd70 */ __u8 pad10[0xd80-0xd78]; /* 0xd78 */ /* entry.S sensitive area start */ - struct cpuinfo_S390 cpu_data; /* 0xd80 */ - __u32 ipl_device; /* 0xdb8 */ - __u32 pad11; /* 0xdbc */ + cpuid_t cpu_id; /* 0xd80 */ + __u32 cpu_nr; /* 0xd88 */ + __u32 ipl_device; /* 0xd8c */ + __u8 pad_0xd90[0xdc0-0xd90]; /* 0xd90 */ /* entry.S sensitive area end */ /* SMP info area: defined by DJB */ diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h index db4523fe38a..61862b3ac79 100644 --- a/arch/s390/include/asm/processor.h +++ b/arch/s390/include/asm/processor.h @@ -42,22 +42,8 @@ static inline void get_cpu_id(cpuid_t *ptr) asm volatile("stidp 0(%1)" : "=m" (*ptr) : "a" (ptr)); } -struct cpuinfo_S390 -{ - cpuid_t cpu_id; - __u16 cpu_addr; - __u16 cpu_nr; - unsigned long loops_per_jiffy; - unsigned long *pgd_quick; -#ifdef __s390x__ - unsigned long *pmd_quick; -#endif /* __s390x__ */ - unsigned long *pte_quick; - unsigned long pgtable_cache_sz; -}; - extern void s390_adjust_jiffies(void); -extern void print_cpu_info(struct cpuinfo_S390 *); +extern void print_cpu_info(void); extern int get_cpu_capability(unsigned int *); /* diff --git a/arch/s390/include/asm/smp.h b/arch/s390/include/asm/smp.h index 024b91e0623..2009158a450 100644 --- a/arch/s390/include/asm/smp.h +++ b/arch/s390/include/asm/smp.h @@ -50,12 +50,7 @@ extern void machine_power_off_smp(void); #define PROC_CHANGE_PENALTY 20 /* Schedule penalty */ -#define raw_smp_processor_id() (S390_lowcore.cpu_data.cpu_nr) - -static inline __u16 hard_smp_processor_id(void) -{ - return stap(); -} +#define raw_smp_processor_id() (S390_lowcore.cpu_nr) /* * returns 1 if cpu is in stopped/check stopped state or not operational diff --git a/arch/s390/kernel/processor.c b/arch/s390/kernel/processor.c index 82c1872cfe8..423da1bd42a 100644 --- a/arch/s390/kernel/processor.c +++ b/arch/s390/kernel/processor.c @@ -18,10 +18,11 @@ #include #include -void __cpuinit print_cpu_info(struct cpuinfo_S390 *cpuinfo) +void __cpuinit print_cpu_info(void) { pr_info("Processor %d started, address %d, identification %06X\n", - cpuinfo->cpu_nr, cpuinfo->cpu_addr, cpuinfo->cpu_id.ident); + S390_lowcore.cpu_nr, S390_lowcore.cpu_addr, + S390_lowcore.cpu_id.ident); } /* @@ -34,44 +35,42 @@ static int show_cpuinfo(struct seq_file *m, void *v) "esan3", "zarch", "stfle", "msa", "ldisp", "eimm", "dfp", "edat" }; - struct cpuinfo_S390 *cpuinfo; - unsigned long n = (unsigned long) v - 1; - int i; + struct _lowcore *lc; + unsigned long n = (unsigned long) v - 1; + int i; - s390_adjust_jiffies(); - preempt_disable(); - if (!n) { - seq_printf(m, "vendor_id : IBM/S390\n" - "# processors : %i\n" - "bogomips per cpu: %lu.%02lu\n", - num_online_cpus(), loops_per_jiffy/(500000/HZ), - (loops_per_jiffy/(5000/HZ))%100); - seq_puts(m, "features\t: "); - for (i = 0; i < 8; i++) - if (hwcap_str[i] && (elf_hwcap & (1UL << i))) - seq_printf(m, "%s ", hwcap_str[i]); - seq_puts(m, "\n"); - } + s390_adjust_jiffies(); + preempt_disable(); + if (!n) { + seq_printf(m, "vendor_id : IBM/S390\n" + "# processors : %i\n" + "bogomips per cpu: %lu.%02lu\n", + num_online_cpus(), loops_per_jiffy/(500000/HZ), + (loops_per_jiffy/(5000/HZ))%100); + seq_puts(m, "features\t: "); + for (i = 0; i < 8; i++) + if (hwcap_str[i] && (elf_hwcap & (1UL << i))) + seq_printf(m, "%s ", hwcap_str[i]); + seq_puts(m, "\n"); + } - if (cpu_online(n)) { + if (cpu_online(n)) { #ifdef CONFIG_SMP - if (smp_processor_id() == n) - cpuinfo = &S390_lowcore.cpu_data; - else - cpuinfo = &lowcore_ptr[n]->cpu_data; + lc = (smp_processor_id() == n) ? + &S390_lowcore : lowcore_ptr[n]; #else - cpuinfo = &S390_lowcore.cpu_data; + lc = &S390_lowcore; #endif - seq_printf(m, "processor %li: " - "version = %02X, " - "identification = %06X, " - "machine = %04X\n", - n, cpuinfo->cpu_id.version, - cpuinfo->cpu_id.ident, - cpuinfo->cpu_id.machine); - } - preempt_enable(); - return 0; + seq_printf(m, "processor %li: " + "version = %02X, " + "identification = %06X, " + "machine = %04X\n", + n, lc->cpu_id.version, + lc->cpu_id.ident, + lc->cpu_id.machine); + } + preempt_enable(); + return 0; } static void *c_start(struct seq_file *m, loff_t *pos) diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index dd3c5173627..9c8853f21bb 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -121,13 +121,10 @@ static struct resource data_resource = { */ void __cpuinit cpu_init(void) { - int addr = hard_smp_processor_id(); - /* * Store processor id in lowcore (used e.g. in timer_interrupt) */ - get_cpu_id(&S390_lowcore.cpu_data.cpu_id); - S390_lowcore.cpu_data.cpu_addr = addr; + get_cpu_id(&S390_lowcore.cpu_id); /* * Force FPU initialization: @@ -686,7 +683,6 @@ setup_memory(void) static void __init setup_hwcaps(void) { static const int stfl_bits[6] = { 0, 2, 7, 17, 19, 21 }; - struct cpuinfo_S390 *cpuinfo = &S390_lowcore.cpu_data; unsigned long long facility_list_extended; unsigned int facility_list; int i; @@ -732,7 +728,7 @@ static void __init setup_hwcaps(void) if (MACHINE_HAS_HPAGE) elf_hwcap |= 1UL << 7; - switch (cpuinfo->cpu_id.machine) { + switch (S390_lowcore.cpu_id.machine) { case 0x9672: #if !defined(CONFIG_64BIT) default: /* Use "g5" as default for 31 bit kernels. */ @@ -825,7 +821,7 @@ setup_arch(char **cmdline_p) setup_lowcore(); cpu_init(); - __cpu_logical_map[0] = S390_lowcore.cpu_data.cpu_addr; + __cpu_logical_map[0] = stap(); s390_init_cpu_topology(); /* diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index a8858634dd0..b167f74d94c 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -372,7 +372,7 @@ static void __init smp_detect_cpus(void) c_cpus = 1; s_cpus = 0; - boot_cpu_addr = S390_lowcore.cpu_data.cpu_addr; + boot_cpu_addr = __cpu_logical_map[0]; info = kmalloc(sizeof(*info), GFP_KERNEL); if (!info) panic("smp_detect_cpus failed to allocate memory\n"); @@ -446,7 +446,7 @@ int __cpuinit start_secondary(void *cpuvoid) /* Switch on interrupts */ local_irq_enable(); /* Print info about this processor */ - print_cpu_info(&S390_lowcore.cpu_data); + print_cpu_info(); /* cpu_idle will call schedule for us */ cpu_idle(); return 0; @@ -564,7 +564,7 @@ int __cpuinit __cpu_up(unsigned int cpu) : : "a" (&cpu_lowcore->access_regs_save_area) : "memory"); cpu_lowcore->percpu_offset = __per_cpu_offset[cpu]; cpu_lowcore->current_task = (unsigned long) idle; - cpu_lowcore->cpu_data.cpu_nr = cpu; + cpu_lowcore->cpu_nr = cpu; cpu_lowcore->kernel_asce = S390_lowcore.kernel_asce; cpu_lowcore->ipl_device = S390_lowcore.ipl_device; eieio(); @@ -656,7 +656,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus) /* request the 0x1201 emergency signal external interrupt */ if (register_external_interrupt(0x1201, do_ext_call_interrupt) != 0) panic("Couldn't request external interrupt 0x1201"); - print_cpu_info(&S390_lowcore.cpu_data); + print_cpu_info(); /* Reallocate current lowcore, but keep its contents. */ lc_order = sizeof(long) == 8 ? 1 : 0; diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 8446d15e448..dcd0e48918d 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -655,7 +655,7 @@ css_generate_pgid(struct channel_subsystem *css, u32 tod_high) css->global_pgid.pgid_high.ext_cssid.cssid = css->cssid; } else { #ifdef CONFIG_SMP - css->global_pgid.pgid_high.cpu_addr = hard_smp_processor_id(); + css->global_pgid.pgid_high.cpu_addr = stap(); #else css->global_pgid.pgid_high.cpu_addr = 0; #endif -- cgit v1.2.3-70-g09d2 From da292bbe1f620221b08c4b589424f370168d642b Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Thu, 26 Mar 2009 15:24:43 +0100 Subject: [S390] eliminate ipl_device from lowcore Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/lowcore.h | 8 ++------ arch/s390/kernel/head31.S | 1 - arch/s390/kernel/head64.S | 1 - arch/s390/kernel/setup.c | 1 - arch/s390/kernel/smp.c | 1 - 5 files changed, 2 insertions(+), 10 deletions(-) diff --git a/arch/s390/include/asm/lowcore.h b/arch/s390/include/asm/lowcore.h index ad543c11826..5b18035c1dc 100644 --- a/arch/s390/include/asm/lowcore.h +++ b/arch/s390/include/asm/lowcore.h @@ -80,7 +80,6 @@ #define __LC_USER_ASCE 0xC50 #define __LC_PANIC_STACK 0xC54 #define __LC_CPUID 0xC60 -#define __LC_IPLDEV 0xC7C #define __LC_CURRENT 0xC90 #define __LC_INT_CLOCK 0xC98 #else /* __s390x__ */ @@ -101,7 +100,6 @@ #define __LC_USER_ASCE 0xD60 #define __LC_PANIC_STACK 0xD68 #define __LC_CPUID 0xD80 -#define __LC_IPLDEV 0xDB8 #define __LC_CURRENT 0xDD8 #define __LC_INT_CLOCK 0xDE8 #define __LC_VDSO_PER_CPU 0xE38 @@ -273,8 +271,7 @@ struct _lowcore /* entry.S sensitive area start */ cpuid_t cpu_id; /* 0xc60 */ __u32 cpu_nr; /* 0xc68 */ - __u32 ipl_device; /* 0xc6c */ - __u8 pad_0xc70[0xc80-0xc70]; /* 0xc70 */ + __u8 pad_0xc6c[0xc80-0xc6c]; /* 0xc6c */ /* entry.S sensitive area end */ /* SMP info area: defined by DJB */ @@ -368,8 +365,7 @@ struct _lowcore /* entry.S sensitive area start */ cpuid_t cpu_id; /* 0xd80 */ __u32 cpu_nr; /* 0xd88 */ - __u32 ipl_device; /* 0xd8c */ - __u8 pad_0xd90[0xdc0-0xd90]; /* 0xd90 */ + __u8 pad_0xd8c[0xdc0-0xd8c]; /* 0xd8c */ /* entry.S sensitive area end */ /* SMP info area: defined by DJB */ diff --git a/arch/s390/kernel/head31.S b/arch/s390/kernel/head31.S index db476d114ca..2ced846065b 100644 --- a/arch/s390/kernel/head31.S +++ b/arch/s390/kernel/head31.S @@ -20,7 +20,6 @@ startup_continue: lctl %c0,%c15,.Lctl-.LPG1(%r13) # load control registers l %r12,.Lparmaddr-.LPG1(%r13) # pointer to parameter area # move IPL device to lowcore - mvc __LC_IPLDEV(4),IPL_DEVICE-PARMAREA(%r12) # # Setup stack # diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S index f9f70aa1524..65667b2e65c 100644 --- a/arch/s390/kernel/head64.S +++ b/arch/s390/kernel/head64.S @@ -86,7 +86,6 @@ startup_continue: lctlg %c0,%c15,.Lctl-.LPG1(%r13) # load control registers lg %r12,.Lparmaddr-.LPG1(%r13) # pointer to parameter area # move IPL device to lowcore - mvc __LC_IPLDEV(4),IPL_DEVICE+4-PARMAREA(%r12) lghi %r0,__LC_PASTE stg %r0,__LC_VDSO_PER_CPU # diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 9c8853f21bb..91551ef1d67 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -419,7 +419,6 @@ setup_lowcore(void) PSW_ADDR_AMODE | (unsigned long) mcck_int_handler; lc->io_new_psw.mask = psw_kernel_bits; lc->io_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) io_int_handler; - lc->ipl_device = S390_lowcore.ipl_device; lc->clock_comparator = -1ULL; lc->kernel_stack = ((unsigned long) &init_thread_union) + THREAD_SIZE; lc->async_stack = (unsigned long) diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index b167f74d94c..775885772ff 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -566,7 +566,6 @@ int __cpuinit __cpu_up(unsigned int cpu) cpu_lowcore->current_task = (unsigned long) idle; cpu_lowcore->cpu_nr = cpu; cpu_lowcore->kernel_asce = S390_lowcore.kernel_asce; - cpu_lowcore->ipl_device = S390_lowcore.ipl_device; eieio(); while (signal_processor(cpu, sigp_restart) == sigp_busy) -- cgit v1.2.3-70-g09d2 From 866ba28418d30122d863c50182a202741f4dcf3e Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Thu, 26 Mar 2009 15:24:44 +0100 Subject: [S390] cleanup lowcore.h The lowcore.h header has quite a lot of whitespace damage and a rather wild collection of entries. Remove all that whitespace and tidy up the order of the lowcore fields. Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/lowcore.h | 652 ++++++++++++++++++++-------------------- arch/s390/kernel/head.S | 2 + 2 files changed, 331 insertions(+), 323 deletions(-) diff --git a/arch/s390/include/asm/lowcore.h b/arch/s390/include/asm/lowcore.h index 5b18035c1dc..b349f1c7fdf 100644 --- a/arch/s390/include/asm/lowcore.h +++ b/arch/s390/include/asm/lowcore.h @@ -11,125 +11,118 @@ #ifndef _ASM_S390_LOWCORE_H #define _ASM_S390_LOWCORE_H -#ifndef __s390x__ -#define __LC_EXT_OLD_PSW 0x018 -#define __LC_SVC_OLD_PSW 0x020 -#define __LC_PGM_OLD_PSW 0x028 -#define __LC_MCK_OLD_PSW 0x030 -#define __LC_IO_OLD_PSW 0x038 -#define __LC_EXT_NEW_PSW 0x058 -#define __LC_SVC_NEW_PSW 0x060 -#define __LC_PGM_NEW_PSW 0x068 -#define __LC_MCK_NEW_PSW 0x070 -#define __LC_IO_NEW_PSW 0x078 -#else /* !__s390x__ */ -#define __LC_EXT_OLD_PSW 0x0130 -#define __LC_SVC_OLD_PSW 0x0140 -#define __LC_PGM_OLD_PSW 0x0150 -#define __LC_MCK_OLD_PSW 0x0160 -#define __LC_IO_OLD_PSW 0x0170 -#define __LC_EXT_NEW_PSW 0x01b0 -#define __LC_SVC_NEW_PSW 0x01c0 -#define __LC_PGM_NEW_PSW 0x01d0 -#define __LC_MCK_NEW_PSW 0x01e0 -#define __LC_IO_NEW_PSW 0x01f0 -#endif /* !__s390x__ */ - -#define __LC_IPL_PARMBLOCK_PTR 0x014 -#define __LC_EXT_PARAMS 0x080 -#define __LC_CPU_ADDRESS 0x084 -#define __LC_EXT_INT_CODE 0x086 - -#define __LC_SVC_ILC 0x088 -#define __LC_SVC_INT_CODE 0x08A -#define __LC_PGM_ILC 0x08C -#define __LC_PGM_INT_CODE 0x08E +#define __LC_IPL_PARMBLOCK_PTR 0x0014 +#define __LC_EXT_PARAMS 0x0080 +#define __LC_CPU_ADDRESS 0x0084 +#define __LC_EXT_INT_CODE 0x0086 -#define __LC_PER_ATMID 0x096 -#define __LC_PER_ADDRESS 0x098 -#define __LC_PER_ACCESS_ID 0x0A1 -#define __LC_AR_MODE_ID 0x0A3 +#define __LC_SVC_ILC 0x0088 +#define __LC_SVC_INT_CODE 0x008a +#define __LC_PGM_ILC 0x008c +#define __LC_PGM_INT_CODE 0x008e -#define __LC_SUBCHANNEL_ID 0x0B8 -#define __LC_SUBCHANNEL_NR 0x0BA -#define __LC_IO_INT_PARM 0x0BC -#define __LC_IO_INT_WORD 0x0C0 -#define __LC_MCCK_CODE 0x0E8 +#define __LC_PER_ATMID 0x0096 +#define __LC_PER_ADDRESS 0x0098 +#define __LC_PER_ACCESS_ID 0x00a1 +#define __LC_AR_MODE_ID 0x00a3 -#define __LC_LAST_BREAK 0x110 +#define __LC_SUBCHANNEL_ID 0x00b8 +#define __LC_SUBCHANNEL_NR 0x00ba +#define __LC_IO_INT_PARM 0x00bc +#define __LC_IO_INT_WORD 0x00c0 +#define __LC_MCCK_CODE 0x00e8 -#define __LC_RETURN_PSW 0x200 - -#define __LC_SAVE_AREA 0xC00 +#define __LC_DUMP_REIPL 0x0e00 #ifndef __s390x__ -#define __LC_IRB 0x208 -#define __LC_SYNC_ENTER_TIMER 0x248 -#define __LC_ASYNC_ENTER_TIMER 0x250 -#define __LC_EXIT_TIMER 0x258 -#define __LC_USER_TIMER 0x260 -#define __LC_SYSTEM_TIMER 0x268 -#define __LC_STEAL_TIMER 0x270 -#define __LC_LAST_UPDATE_TIMER 0x278 -#define __LC_LAST_UPDATE_CLOCK 0x280 -#define __LC_RETURN_MCCK_PSW 0x288 -#define __LC_KERNEL_STACK 0xC40 -#define __LC_THREAD_INFO 0xC44 -#define __LC_ASYNC_STACK 0xC48 -#define __LC_KERNEL_ASCE 0xC4C -#define __LC_USER_ASCE 0xC50 -#define __LC_PANIC_STACK 0xC54 -#define __LC_CPUID 0xC60 -#define __LC_CURRENT 0xC90 -#define __LC_INT_CLOCK 0xC98 +#define __LC_EXT_OLD_PSW 0x0018 +#define __LC_SVC_OLD_PSW 0x0020 +#define __LC_PGM_OLD_PSW 0x0028 +#define __LC_MCK_OLD_PSW 0x0030 +#define __LC_IO_OLD_PSW 0x0038 +#define __LC_EXT_NEW_PSW 0x0058 +#define __LC_SVC_NEW_PSW 0x0060 +#define __LC_PGM_NEW_PSW 0x0068 +#define __LC_MCK_NEW_PSW 0x0070 +#define __LC_IO_NEW_PSW 0x0078 +#define __LC_SAVE_AREA 0x0200 +#define __LC_RETURN_PSW 0x0240 +#define __LC_RETURN_MCCK_PSW 0x0248 +#define __LC_SYNC_ENTER_TIMER 0x0250 +#define __LC_ASYNC_ENTER_TIMER 0x0258 +#define __LC_EXIT_TIMER 0x0260 +#define __LC_USER_TIMER 0x0268 +#define __LC_SYSTEM_TIMER 0x0270 +#define __LC_STEAL_TIMER 0x0278 +#define __LC_LAST_UPDATE_TIMER 0x0280 +#define __LC_LAST_UPDATE_CLOCK 0x0288 +#define __LC_CURRENT 0x0290 +#define __LC_THREAD_INFO 0x0294 +#define __LC_KERNEL_STACK 0x0298 +#define __LC_ASYNC_STACK 0x029c +#define __LC_PANIC_STACK 0x02a0 +#define __LC_KERNEL_ASCE 0x02a4 +#define __LC_USER_ASCE 0x02a8 +#define __LC_USER_EXEC_ASCE 0x02ac +#define __LC_CPUID 0x02b0 +#define __LC_INT_CLOCK 0x02c8 +#define __LC_IRB 0x0300 +#define __LC_PFAULT_INTPARM 0x0080 +#define __LC_CPU_TIMER_SAVE_AREA 0x00d8 +#define __LC_CLOCK_COMP_SAVE_AREA 0x00e0 +#define __LC_PSW_SAVE_AREA 0x0100 +#define __LC_PREFIX_SAVE_AREA 0x0108 +#define __LC_AREGS_SAVE_AREA 0x0120 +#define __LC_FPREGS_SAVE_AREA 0x0160 +#define __LC_GPREGS_SAVE_AREA 0x0180 +#define __LC_CREGS_SAVE_AREA 0x01c0 #else /* __s390x__ */ -#define __LC_IRB 0x210 -#define __LC_SYNC_ENTER_TIMER 0x250 -#define __LC_ASYNC_ENTER_TIMER 0x258 -#define __LC_EXIT_TIMER 0x260 -#define __LC_USER_TIMER 0x268 -#define __LC_SYSTEM_TIMER 0x270 -#define __LC_STEAL_TIMER 0x278 -#define __LC_LAST_UPDATE_TIMER 0x280 -#define __LC_LAST_UPDATE_CLOCK 0x288 -#define __LC_RETURN_MCCK_PSW 0x290 -#define __LC_KERNEL_STACK 0xD40 -#define __LC_THREAD_INFO 0xD48 -#define __LC_ASYNC_STACK 0xD50 -#define __LC_KERNEL_ASCE 0xD58 -#define __LC_USER_ASCE 0xD60 -#define __LC_PANIC_STACK 0xD68 -#define __LC_CPUID 0xD80 -#define __LC_CURRENT 0xDD8 -#define __LC_INT_CLOCK 0xDE8 -#define __LC_VDSO_PER_CPU 0xE38 -#endif /* __s390x__ */ - -#define __LC_PASTE 0xE40 - -#define __LC_DUMP_REIPL 0xE00 -#ifndef __s390x__ -#define __LC_PFAULT_INTPARM 0x080 -#define __LC_CPU_TIMER_SAVE_AREA 0x0D8 -#define __LC_CLOCK_COMP_SAVE_AREA 0x0E0 -#define __LC_PSW_SAVE_AREA 0x100 -#define __LC_PREFIX_SAVE_AREA 0x108 -#define __LC_AREGS_SAVE_AREA 0x120 -#define __LC_FPREGS_SAVE_AREA 0x160 -#define __LC_GPREGS_SAVE_AREA 0x180 -#define __LC_CREGS_SAVE_AREA 0x1C0 -#else /* __s390x__ */ -#define __LC_PFAULT_INTPARM 0x11B8 +#define __LC_LAST_BREAK 0x0110 +#define __LC_EXT_OLD_PSW 0x0130 +#define __LC_SVC_OLD_PSW 0x0140 +#define __LC_PGM_OLD_PSW 0x0150 +#define __LC_MCK_OLD_PSW 0x0160 +#define __LC_IO_OLD_PSW 0x0170 +#define __LC_EXT_NEW_PSW 0x01b0 +#define __LC_SVC_NEW_PSW 0x01c0 +#define __LC_PGM_NEW_PSW 0x01d0 +#define __LC_MCK_NEW_PSW 0x01e0 +#define __LC_IO_NEW_PSW 0x01f0 +#define __LC_SAVE_AREA 0x0200 +#define __LC_RETURN_PSW 0x0280 +#define __LC_RETURN_MCCK_PSW 0x0290 +#define __LC_SYNC_ENTER_TIMER 0x02a0 +#define __LC_ASYNC_ENTER_TIMER 0x02a8 +#define __LC_EXIT_TIMER 0x02b0 +#define __LC_USER_TIMER 0x02b8 +#define __LC_SYSTEM_TIMER 0x02c0 +#define __LC_STEAL_TIMER 0x02c8 +#define __LC_LAST_UPDATE_TIMER 0x02d0 +#define __LC_LAST_UPDATE_CLOCK 0x02d8 +#define __LC_CURRENT 0x02e0 +#define __LC_THREAD_INFO 0x02e8 +#define __LC_KERNEL_STACK 0x02f0 +#define __LC_ASYNC_STACK 0x02f8 +#define __LC_PANIC_STACK 0x0300 +#define __LC_KERNEL_ASCE 0x0308 +#define __LC_USER_ASCE 0x0310 +#define __LC_USER_EXEC_ASCE 0x0318 +#define __LC_CPUID 0x0320 +#define __LC_INT_CLOCK 0x0340 +#define __LC_VDSO_PER_CPU 0x0350 +#define __LC_IRB 0x0380 +#define __LC_PASTE 0x03c0 +#define __LC_PFAULT_INTPARM 0x11b8 #define __LC_FPREGS_SAVE_AREA 0x1200 -#define __LC_GPREGS_SAVE_AREA 0x1280 +#define __LC_GPREGS_SAVE_AREA 0x1280 #define __LC_PSW_SAVE_AREA 0x1300 #define __LC_PREFIX_SAVE_AREA 0x1318 -#define __LC_FP_CREG_SAVE_AREA 0x131C +#define __LC_FP_CREG_SAVE_AREA 0x131c #define __LC_TODREG_SAVE_AREA 0x1324 -#define __LC_CPU_TIMER_SAVE_AREA 0x1328 +#define __LC_CPU_TIMER_SAVE_AREA 0x1328 #define __LC_CLOCK_COMP_SAVE_AREA 0x1331 -#define __LC_AREGS_SAVE_AREA 0x1340 -#define __LC_CREGS_SAVE_AREA 0x1380 +#define __LC_AREGS_SAVE_AREA 0x1340 +#define __LC_CREGS_SAVE_AREA 0x1380 #endif /* __s390x__ */ #ifndef __ASSEMBLY__ @@ -194,227 +187,240 @@ union save_area { struct _lowcore { #ifndef __s390x__ - /* prefix area: defined by architecture */ - psw_t restart_psw; /* 0x000 */ - __u32 ccw2[4]; /* 0x008 */ - psw_t external_old_psw; /* 0x018 */ - psw_t svc_old_psw; /* 0x020 */ - psw_t program_old_psw; /* 0x028 */ - psw_t mcck_old_psw; /* 0x030 */ - psw_t io_old_psw; /* 0x038 */ - __u8 pad1[0x58-0x40]; /* 0x040 */ - psw_t external_new_psw; /* 0x058 */ - psw_t svc_new_psw; /* 0x060 */ - psw_t program_new_psw; /* 0x068 */ - psw_t mcck_new_psw; /* 0x070 */ - psw_t io_new_psw; /* 0x078 */ - __u32 ext_params; /* 0x080 */ - __u16 cpu_addr; /* 0x084 */ - __u16 ext_int_code; /* 0x086 */ - __u16 svc_ilc; /* 0x088 */ - __u16 svc_code; /* 0x08a */ - __u16 pgm_ilc; /* 0x08c */ - __u16 pgm_code; /* 0x08e */ - __u32 trans_exc_code; /* 0x090 */ - __u16 mon_class_num; /* 0x094 */ - __u16 per_perc_atmid; /* 0x096 */ - __u32 per_address; /* 0x098 */ - __u32 monitor_code; /* 0x09c */ - __u8 exc_access_id; /* 0x0a0 */ - __u8 per_access_id; /* 0x0a1 */ - __u8 pad2[0xB8-0xA2]; /* 0x0a2 */ - __u16 subchannel_id; /* 0x0b8 */ - __u16 subchannel_nr; /* 0x0ba */ - __u32 io_int_parm; /* 0x0bc */ - __u32 io_int_word; /* 0x0c0 */ - __u8 pad3[0xc8-0xc4]; /* 0x0c4 */ - __u32 stfl_fac_list; /* 0x0c8 */ - __u8 pad4[0xd4-0xcc]; /* 0x0cc */ - __u32 extended_save_area_addr; /* 0x0d4 */ - __u32 cpu_timer_save_area[2]; /* 0x0d8 */ - __u32 clock_comp_save_area[2]; /* 0x0e0 */ - __u32 mcck_interruption_code[2]; /* 0x0e8 */ - __u8 pad5[0xf4-0xf0]; /* 0x0f0 */ - __u32 external_damage_code; /* 0x0f4 */ - __u32 failing_storage_address; /* 0x0f8 */ - __u8 pad6[0x100-0xfc]; /* 0x0fc */ - __u32 st_status_fixed_logout[4];/* 0x100 */ - __u8 pad7[0x120-0x110]; /* 0x110 */ - __u32 access_regs_save_area[16];/* 0x120 */ - __u32 floating_pt_save_area[8]; /* 0x160 */ - __u32 gpregs_save_area[16]; /* 0x180 */ - __u32 cregs_save_area[16]; /* 0x1c0 */ - - psw_t return_psw; /* 0x200 */ - __u8 irb[64]; /* 0x208 */ - __u64 sync_enter_timer; /* 0x248 */ - __u64 async_enter_timer; /* 0x250 */ - __u64 exit_timer; /* 0x258 */ - __u64 user_timer; /* 0x260 */ - __u64 system_timer; /* 0x268 */ - __u64 steal_timer; /* 0x270 */ - __u64 last_update_timer; /* 0x278 */ - __u64 last_update_clock; /* 0x280 */ - psw_t return_mcck_psw; /* 0x288 */ - __u8 pad8[0xc00-0x290]; /* 0x290 */ - - /* System info area */ - __u32 save_area[16]; /* 0xc00 */ - __u32 kernel_stack; /* 0xc40 */ - __u32 thread_info; /* 0xc44 */ - __u32 async_stack; /* 0xc48 */ - __u32 kernel_asce; /* 0xc4c */ - __u32 user_asce; /* 0xc50 */ - __u32 panic_stack; /* 0xc54 */ - __u32 user_exec_asce; /* 0xc58 */ - __u8 pad10[0xc60-0xc5c]; /* 0xc5c */ - /* entry.S sensitive area start */ - cpuid_t cpu_id; /* 0xc60 */ - __u32 cpu_nr; /* 0xc68 */ - __u8 pad_0xc6c[0xc80-0xc6c]; /* 0xc6c */ - /* entry.S sensitive area end */ - - /* SMP info area: defined by DJB */ - __u64 clock_comparator; /* 0xc80 */ - __u32 ext_call_fast; /* 0xc88 */ - __u32 percpu_offset; /* 0xc8c */ - __u32 current_task; /* 0xc90 */ - __u32 softirq_pending; /* 0xc94 */ - __u64 int_clock; /* 0xc98 */ - __u8 pad11[0xe00-0xca0]; /* 0xca0 */ - - /* 0xe00 contains the address of the IPL Parameter */ - /* Information block. Dump tools need IPIB for IPL */ - /* after dump. */ - __u32 ipib; /* 0xe00 */ - __u32 ipib_checksum; /* 0xe04 */ - - /* Align to the top 1k of prefix area */ - __u8 pad12[0x1000-0xe08]; /* 0xe08 */ + /* 0x0000 - 0x01ff: defined by architecture */ + psw_t restart_psw; /* 0x0000 */ + __u32 ccw2[4]; /* 0x0008 */ + psw_t external_old_psw; /* 0x0018 */ + psw_t svc_old_psw; /* 0x0020 */ + psw_t program_old_psw; /* 0x0028 */ + psw_t mcck_old_psw; /* 0x0030 */ + psw_t io_old_psw; /* 0x0038 */ + __u8 pad_0x0040[0x0058-0x0040]; /* 0x0040 */ + psw_t external_new_psw; /* 0x0058 */ + psw_t svc_new_psw; /* 0x0060 */ + psw_t program_new_psw; /* 0x0068 */ + psw_t mcck_new_psw; /* 0x0070 */ + psw_t io_new_psw; /* 0x0078 */ + __u32 ext_params; /* 0x0080 */ + __u16 cpu_addr; /* 0x0084 */ + __u16 ext_int_code; /* 0x0086 */ + __u16 svc_ilc; /* 0x0088 */ + __u16 svc_code; /* 0x008a */ + __u16 pgm_ilc; /* 0x008c */ + __u16 pgm_code; /* 0x008e */ + __u32 trans_exc_code; /* 0x0090 */ + __u16 mon_class_num; /* 0x0094 */ + __u16 per_perc_atmid; /* 0x0096 */ + __u32 per_address; /* 0x0098 */ + __u32 monitor_code; /* 0x009c */ + __u8 exc_access_id; /* 0x00a0 */ + __u8 per_access_id; /* 0x00a1 */ + __u8 pad_0x00a2[0x00b8-0x00a2]; /* 0x00a2 */ + __u16 subchannel_id; /* 0x00b8 */ + __u16 subchannel_nr; /* 0x00ba */ + __u32 io_int_parm; /* 0x00bc */ + __u32 io_int_word; /* 0x00c0 */ + __u8 pad_0x00c4[0x00c8-0x00c4]; /* 0x00c4 */ + __u32 stfl_fac_list; /* 0x00c8 */ + __u8 pad_0x00cc[0x00d4-0x00cc]; /* 0x00cc */ + __u32 extended_save_area_addr; /* 0x00d4 */ + __u32 cpu_timer_save_area[2]; /* 0x00d8 */ + __u32 clock_comp_save_area[2]; /* 0x00e0 */ + __u32 mcck_interruption_code[2]; /* 0x00e8 */ + __u8 pad_0x00f0[0x00f4-0x00f0]; /* 0x00f0 */ + __u32 external_damage_code; /* 0x00f4 */ + __u32 failing_storage_address; /* 0x00f8 */ + __u8 pad_0x00fc[0x0100-0x00fc]; /* 0x00fc */ + __u32 st_status_fixed_logout[4]; /* 0x0100 */ + __u8 pad_0x0110[0x0120-0x0110]; /* 0x0110 */ + + /* CPU register save area: defined by architecture */ + __u32 access_regs_save_area[16]; /* 0x0120 */ + __u32 floating_pt_save_area[8]; /* 0x0160 */ + __u32 gpregs_save_area[16]; /* 0x0180 */ + __u32 cregs_save_area[16]; /* 0x01c0 */ + + /* Return psws. */ + __u32 save_area[16]; /* 0x0200 */ + psw_t return_psw; /* 0x0240 */ + psw_t return_mcck_psw; /* 0x0248 */ + + /* CPU time accounting values */ + __u64 sync_enter_timer; /* 0x0250 */ + __u64 async_enter_timer; /* 0x0258 */ + __u64 exit_timer; /* 0x0260 */ + __u64 user_timer; /* 0x0268 */ + __u64 system_timer; /* 0x0270 */ + __u64 steal_timer; /* 0x0278 */ + __u64 last_update_timer; /* 0x0280 */ + __u64 last_update_clock; /* 0x0288 */ + + /* Current process. */ + __u32 current_task; /* 0x0290 */ + __u32 thread_info; /* 0x0294 */ + __u32 kernel_stack; /* 0x0298 */ + + /* Interrupt and panic stack. */ + __u32 async_stack; /* 0x029c */ + __u32 panic_stack; /* 0x02a0 */ + + /* Address space pointer. */ + __u32 kernel_asce; /* 0x02a4 */ + __u32 user_asce; /* 0x02a8 */ + __u32 user_exec_asce; /* 0x02ac */ + + /* SMP info area */ + cpuid_t cpu_id; /* 0x02b0 */ + __u32 cpu_nr; /* 0x02b8 */ + __u32 softirq_pending; /* 0x02bc */ + __u32 percpu_offset; /* 0x02c0 */ + __u32 ext_call_fast; /* 0x02c4 */ + __u64 int_clock; /* 0x02c8 */ + __u64 clock_comparator; /* 0x02d0 */ + __u8 pad_0x02d8[0x0300-0x02d8]; /* 0x02d8 */ + + /* Interrupt response block */ + __u8 irb[64]; /* 0x0300 */ + + __u8 pad_0x0400[0x0e00-0x0400]; /* 0x0400 */ + + /* + * 0xe00 contains the address of the IPL Parameter Information + * block. Dump tools need IPIB for IPL after dump. + * Note: do not change the position of any fields in 0x0e00-0x0f00 + */ + __u32 ipib; /* 0x0e00 */ + __u32 ipib_checksum; /* 0x0e04 */ + + /* Align to the top 1k of prefix area */ + __u8 pad_0x0e08[0x1000-0x0e08]; /* 0x0e08 */ #else /* !__s390x__ */ - /* prefix area: defined by architecture */ - __u32 ccw1[2]; /* 0x000 */ - __u32 ccw2[4]; /* 0x008 */ - __u8 pad1[0x80-0x18]; /* 0x018 */ - __u32 ext_params; /* 0x080 */ - __u16 cpu_addr; /* 0x084 */ - __u16 ext_int_code; /* 0x086 */ - __u16 svc_ilc; /* 0x088 */ - __u16 svc_code; /* 0x08a */ - __u16 pgm_ilc; /* 0x08c */ - __u16 pgm_code; /* 0x08e */ - __u32 data_exc_code; /* 0x090 */ - __u16 mon_class_num; /* 0x094 */ - __u16 per_perc_atmid; /* 0x096 */ - addr_t per_address; /* 0x098 */ - __u8 exc_access_id; /* 0x0a0 */ - __u8 per_access_id; /* 0x0a1 */ - __u8 op_access_id; /* 0x0a2 */ - __u8 ar_access_id; /* 0x0a3 */ - __u8 pad2[0xA8-0xA4]; /* 0x0a4 */ - addr_t trans_exc_code; /* 0x0a8 */ - addr_t monitor_code; /* 0x0b0 */ - __u16 subchannel_id; /* 0x0b8 */ - __u16 subchannel_nr; /* 0x0ba */ - __u32 io_int_parm; /* 0x0bc */ - __u32 io_int_word; /* 0x0c0 */ - __u8 pad3[0xc8-0xc4]; /* 0x0c4 */ - __u32 stfl_fac_list; /* 0x0c8 */ - __u8 pad4[0xe8-0xcc]; /* 0x0cc */ - __u32 mcck_interruption_code[2]; /* 0x0e8 */ - __u8 pad5[0xf4-0xf0]; /* 0x0f0 */ - __u32 external_damage_code; /* 0x0f4 */ - addr_t failing_storage_address; /* 0x0f8 */ - __u8 pad6[0x120-0x100]; /* 0x100 */ - psw_t restart_old_psw; /* 0x120 */ - psw_t external_old_psw; /* 0x130 */ - psw_t svc_old_psw; /* 0x140 */ - psw_t program_old_psw; /* 0x150 */ - psw_t mcck_old_psw; /* 0x160 */ - psw_t io_old_psw; /* 0x170 */ - __u8 pad7[0x1a0-0x180]; /* 0x180 */ - psw_t restart_psw; /* 0x1a0 */ - psw_t external_new_psw; /* 0x1b0 */ - psw_t svc_new_psw; /* 0x1c0 */ - psw_t program_new_psw; /* 0x1d0 */ - psw_t mcck_new_psw; /* 0x1e0 */ - psw_t io_new_psw; /* 0x1f0 */ - psw_t return_psw; /* 0x200 */ - __u8 irb[64]; /* 0x210 */ - __u64 sync_enter_timer; /* 0x250 */ - __u64 async_enter_timer; /* 0x258 */ - __u64 exit_timer; /* 0x260 */ - __u64 user_timer; /* 0x268 */ - __u64 system_timer; /* 0x270 */ - __u64 steal_timer; /* 0x278 */ - __u64 last_update_timer; /* 0x280 */ - __u64 last_update_clock; /* 0x288 */ - psw_t return_mcck_psw; /* 0x290 */ - __u8 pad8[0xc00-0x2a0]; /* 0x2a0 */ - /* System info area */ - __u64 save_area[16]; /* 0xc00 */ - __u8 pad9[0xd40-0xc80]; /* 0xc80 */ - __u64 kernel_stack; /* 0xd40 */ - __u64 thread_info; /* 0xd48 */ - __u64 async_stack; /* 0xd50 */ - __u64 kernel_asce; /* 0xd58 */ - __u64 user_asce; /* 0xd60 */ - __u64 panic_stack; /* 0xd68 */ - __u64 user_exec_asce; /* 0xd70 */ - __u8 pad10[0xd80-0xd78]; /* 0xd78 */ - /* entry.S sensitive area start */ - cpuid_t cpu_id; /* 0xd80 */ - __u32 cpu_nr; /* 0xd88 */ - __u8 pad_0xd8c[0xdc0-0xd8c]; /* 0xd8c */ - /* entry.S sensitive area end */ - - /* SMP info area: defined by DJB */ - __u64 clock_comparator; /* 0xdc0 */ - __u64 ext_call_fast; /* 0xdc8 */ - __u64 percpu_offset; /* 0xdd0 */ - __u64 current_task; /* 0xdd8 */ - __u32 softirq_pending; /* 0xde0 */ - __u32 pad_0x0de4; /* 0xde4 */ - __u64 int_clock; /* 0xde8 */ - __u8 pad12[0xe00-0xdf0]; /* 0xdf0 */ - - /* 0xe00 contains the address of the IPL Parameter */ - /* Information block. Dump tools need IPIB for IPL */ - /* after dump. */ - __u64 ipib; /* 0xe00 */ - __u32 ipib_checksum; /* 0xe08 */ + /* 0x0000 - 0x01ff: defined by architecture */ + __u32 ccw1[2]; /* 0x0000 */ + __u32 ccw2[4]; /* 0x0008 */ + __u8 pad_0x0018[0x0080-0x0018]; /* 0x0018 */ + __u32 ext_params; /* 0x0080 */ + __u16 cpu_addr; /* 0x0084 */ + __u16 ext_int_code; /* 0x0086 */ + __u16 svc_ilc; /* 0x0088 */ + __u16 svc_code; /* 0x008a */ + __u16 pgm_ilc; /* 0x008c */ + __u16 pgm_code; /* 0x008e */ + __u32 data_exc_code; /* 0x0090 */ + __u16 mon_class_num; /* 0x0094 */ + __u16 per_perc_atmid; /* 0x0096 */ + addr_t per_address; /* 0x0098 */ + __u8 exc_access_id; /* 0x00a0 */ + __u8 per_access_id; /* 0x00a1 */ + __u8 op_access_id; /* 0x00a2 */ + __u8 ar_access_id; /* 0x00a3 */ + __u8 pad_0x00a4[0x00a8-0x00a4]; /* 0x00a4 */ + addr_t trans_exc_code; /* 0x00a8 */ + addr_t monitor_code; /* 0x00b0 */ + __u16 subchannel_id; /* 0x00b8 */ + __u16 subchannel_nr; /* 0x00ba */ + __u32 io_int_parm; /* 0x00bc */ + __u32 io_int_word; /* 0x00c0 */ + __u8 pad_0x00c4[0x00c8-0x00c4]; /* 0x00c4 */ + __u32 stfl_fac_list; /* 0x00c8 */ + __u8 pad_0x00cc[0x00e8-0x00cc]; /* 0x00cc */ + __u32 mcck_interruption_code[2]; /* 0x00e8 */ + __u8 pad_0x00f0[0x00f4-0x00f0]; /* 0x00f0 */ + __u32 external_damage_code; /* 0x00f4 */ + addr_t failing_storage_address; /* 0x00f8 */ + __u8 pad_0x0100[0x0120-0x0100]; /* 0x0100 */ + psw_t restart_old_psw; /* 0x0120 */ + psw_t external_old_psw; /* 0x0130 */ + psw_t svc_old_psw; /* 0x0140 */ + psw_t program_old_psw; /* 0x0150 */ + psw_t mcck_old_psw; /* 0x0160 */ + psw_t io_old_psw; /* 0x0170 */ + __u8 pad_0x0180[0x01a0-0x0180]; /* 0x0180 */ + psw_t restart_psw; /* 0x01a0 */ + psw_t external_new_psw; /* 0x01b0 */ + psw_t svc_new_psw; /* 0x01c0 */ + psw_t program_new_psw; /* 0x01d0 */ + psw_t mcck_new_psw; /* 0x01e0 */ + psw_t io_new_psw; /* 0x01f0 */ + + /* Entry/exit save area & return psws. */ + __u64 save_area[16]; /* 0x0200 */ + psw_t return_psw; /* 0x0280 */ + psw_t return_mcck_psw; /* 0x0290 */ + + /* CPU accounting and timing values. */ + __u64 sync_enter_timer; /* 0x02a0 */ + __u64 async_enter_timer; /* 0x02a8 */ + __u64 exit_timer; /* 0x02b0 */ + __u64 user_timer; /* 0x02b8 */ + __u64 system_timer; /* 0x02c0 */ + __u64 steal_timer; /* 0x02c8 */ + __u64 last_update_timer; /* 0x02d0 */ + __u64 last_update_clock; /* 0x02d8 */ + + /* Current process. */ + __u64 current_task; /* 0x02e0 */ + __u64 thread_info; /* 0x02e8 */ + __u64 kernel_stack; /* 0x02f0 */ + + /* Interrupt and panic stack. */ + __u64 async_stack; /* 0x02f8 */ + __u64 panic_stack; /* 0x0300 */ + + /* Address space pointer. */ + __u64 kernel_asce; /* 0x0308 */ + __u64 user_asce; /* 0x0310 */ + __u64 user_exec_asce; /* 0x0318 */ + + /* SMP info area */ + cpuid_t cpu_id; /* 0x0320 */ + __u32 cpu_nr; /* 0x0328 */ + __u32 softirq_pending; /* 0x032c */ + __u64 percpu_offset; /* 0x0330 */ + __u64 ext_call_fast; /* 0x0338 */ + __u64 int_clock; /* 0x0340 */ + __u64 clock_comparator; /* 0x0348 */ + __u64 vdso_per_cpu_data; /* 0x0350 */ + __u8 pad_0x0358[0x0380-0x0358]; /* 0x0358 */ + + /* Interrupt response block. */ + __u8 irb[64]; /* 0x0380 */ /* Per cpu primary space access list */ - __u8 pad_0xe0c[0xe38-0xe0c]; /* 0xe0c */ - __u64 vdso_per_cpu_data; /* 0xe38 */ - __u32 paste[16]; /* 0xe40 */ - - __u8 pad13[0x11b8-0xe80]; /* 0xe80 */ - - /* 64 bit extparam used for pfault, diag 250 etc */ - __u64 ext_params2; /* 0x11B8 */ - - __u8 pad14[0x1200-0x11C0]; /* 0x11C0 */ - - /* System info area */ - - __u64 floating_pt_save_area[16]; /* 0x1200 */ - __u64 gpregs_save_area[16]; /* 0x1280 */ - __u32 st_status_fixed_logout[4]; /* 0x1300 */ - __u8 pad15[0x1318-0x1310]; /* 0x1310 */ - __u32 prefixreg_save_area; /* 0x1318 */ - __u32 fpt_creg_save_area; /* 0x131c */ - __u8 pad16[0x1324-0x1320]; /* 0x1320 */ - __u32 tod_progreg_save_area; /* 0x1324 */ - __u32 cpu_timer_save_area[2]; /* 0x1328 */ - __u32 clock_comp_save_area[2]; /* 0x1330 */ - __u8 pad17[0x1340-0x1338]; /* 0x1338 */ - __u32 access_regs_save_area[16]; /* 0x1340 */ - __u64 cregs_save_area[16]; /* 0x1380 */ + __u32 paste[16]; /* 0x03c0 */ + + __u8 pad_0x0400[0x0e00-0x0400]; /* 0x0400 */ + + /* + * 0xe00 contains the address of the IPL Parameter Information + * block. Dump tools need IPIB for IPL after dump. + * Note: do not change the position of any fields in 0x0e00-0x0f00 + */ + __u64 ipib; /* 0x0e00 */ + __u32 ipib_checksum; /* 0x0e08 */ + __u8 pad_0x0e0c[0x11b8-0x0e0c]; /* 0x0e0c */ + + /* 64 bit extparam used for pfault/diag 250: defined by architecture */ + __u64 ext_params2; /* 0x11B8 */ + __u8 pad_0x11c0[0x1200-0x11C0]; /* 0x11C0 */ + + /* CPU register save area: defined by architecture */ + __u64 floating_pt_save_area[16]; /* 0x1200 */ + __u64 gpregs_save_area[16]; /* 0x1280 */ + __u32 st_status_fixed_logout[4]; /* 0x1300 */ + __u8 pad_0x1310[0x1318-0x1310]; /* 0x1310 */ + __u32 prefixreg_save_area; /* 0x1318 */ + __u32 fpt_creg_save_area; /* 0x131c */ + __u8 pad_0x1320[0x1324-0x1320]; /* 0x1320 */ + __u32 tod_progreg_save_area; /* 0x1324 */ + __u32 cpu_timer_save_area[2]; /* 0x1328 */ + __u32 clock_comp_save_area[2]; /* 0x1330 */ + __u8 pad_0x1338[0x1340-0x1338]; /* 0x1338 */ + __u32 access_regs_save_area[16]; /* 0x1340 */ + __u64 cregs_save_area[16]; /* 0x1380 */ /* align to the top of the prefix area */ - - __u8 pad18[0x2000-0x1400]; /* 0x1400 */ + __u8 pad_0x1400[0x2000-0x1400]; /* 0x1400 */ #endif /* !__s390x__ */ } __attribute__((packed)); /* End structure*/ diff --git a/arch/s390/kernel/head.S b/arch/s390/kernel/head.S index ec7e35f6055..1046c2c9f8d 100644 --- a/arch/s390/kernel/head.S +++ b/arch/s390/kernel/head.S @@ -469,6 +469,8 @@ start: .org 0x10000 startup:basr %r13,0 # get base .LPG0: + xc 0x200(256),0x200 # partially clear lowcore + xc 0x300(256),0x300 #ifndef CONFIG_MARCH_G5 # check processor version against MARCH_{G5,Z900,Z990,Z9_109,Z10} -- cgit v1.2.3-70-g09d2 From 159d1ff8f6c38086ed75f8e892790d0a4f3a6b71 Mon Sep 17 00:00:00 2001 From: Frank Munzert Date: Thu, 26 Mar 2009 15:24:45 +0100 Subject: [S390] Use csum_partial in checksum.h The cksm function in system.h is duplicate to csum_partial in checksum.h. Remove cksm and use csum_partial instead. Signed-off-by: Frank Munzert Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/system.h | 16 ---------------- arch/s390/kernel/ipl.c | 4 +++- drivers/s390/char/zcore.c | 4 +++- 3 files changed, 6 insertions(+), 18 deletions(-) diff --git a/arch/s390/include/asm/system.h b/arch/s390/include/asm/system.h index 3f2ccb82b86..3a8b26eb1f2 100644 --- a/arch/s390/include/asm/system.h +++ b/arch/s390/include/asm/system.h @@ -458,22 +458,6 @@ static inline unsigned short stap(void) return cpu_address; } -static inline u32 cksm(void *addr, unsigned long len) -{ - register unsigned long _addr asm("0") = (unsigned long) addr; - register unsigned long _len asm("1") = len; - unsigned long accu = 0; - - asm volatile( - "0:\n" - " cksm %0,%1\n" - " jnz 0b\n" - : "+d" (accu), "+d" (_addr), "+d" (_len) - : - : "cc", "memory"); - return accu; -} - extern void (*_machine_restart)(char *command); extern void (*_machine_halt)(void); extern void (*_machine_power_off)(void); diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index 5663c1f8e46..505fec06e63 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c @@ -24,6 +24,7 @@ #include #include #include +#include #define IPL_PARM_BLOCK_VERSION 0 @@ -1359,7 +1360,8 @@ static void dump_reipl_run(struct shutdown_trigger *trigger) "a" (&lowcore_ptr[smp_processor_id()]->ipib)); #endif asm volatile("stura %0,%1" - :: "a" (cksm(reipl_block_actual, reipl_block_actual->hdr.len)), + :: "a" (csum_partial(reipl_block_actual, + reipl_block_actual->hdr.len, 0)), "a" (&lowcore_ptr[smp_processor_id()]->ipib_checksum)); preempt_enable(); dump_run(trigger); diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c index cfe782ee647..1bbae433fbd 100644 --- a/drivers/s390/char/zcore.c +++ b/drivers/s390/char/zcore.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "sclp.h" #define TRACE(x...) debug_sprintf_event(zcore_dbf, 1, x) @@ -704,7 +705,8 @@ static int __init zcore_reipl_init(void) free_page((unsigned long) ipl_block); return rc; } - if (cksm(ipl_block, ipl_block->hdr.len) != ipib_info.checksum) { + if (csum_partial(ipl_block, ipl_block->hdr.len, 0) != + ipib_info.checksum) { TRACE("Checksum does not match\n"); free_page((unsigned long) ipl_block); ipl_block = NULL; -- cgit v1.2.3-70-g09d2 From 59f2e69d0f95bc00353628ef33fd534fbb8e3597 Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Thu, 26 Mar 2009 15:24:46 +0100 Subject: [S390] zfcpdump: Prevent zcore from beeing built as a kernel module. The zcore code switches to real addressing mode when creating a kernel dump. This is not possible, if it is built as a kernel module. With this patch zcore (zfcpdump) can't be built as a kernel module any more. Signed-off-by: Michael Holzheu Signed-off-by: Martin Schwidefsky --- arch/s390/Kconfig | 2 +- arch/s390/kernel/setup.c | 4 ++-- arch/s390/kernel/smp.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 0a9463bea75..2a8af5e1634 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -545,7 +545,7 @@ config KEXEC but is independent of hardware/microcode support. config ZFCPDUMP - tristate "zfcpdump support" + bool "zfcpdump support" select SMP default n help diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 91551ef1d67..46fc981e02b 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -226,7 +226,7 @@ static void __init conmode_default(void) } } -#if defined(CONFIG_ZFCPDUMP) || defined(CONFIG_ZFCPDUMP_MODULE) +#ifdef CONFIG_ZFCPDUMP static void __init setup_zfcpdump(unsigned int console_devno) { static char str[41]; @@ -515,7 +515,7 @@ static void __init setup_memory_end(void) unsigned long max_mem; int i; -#if defined(CONFIG_ZFCPDUMP) || defined(CONFIG_ZFCPDUMP_MODULE) +#ifdef CONFIG_ZFCPDUMP if (ipl_info.type == IPL_TYPE_FCP_DUMP) { memory_end = ZFCPDUMP_HSA_SIZE; memory_end_set = 1; diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 775885772ff..bb3d34aa7b8 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -226,7 +226,7 @@ EXPORT_SYMBOL(smp_ctl_clear_bit); */ #define CPU_INIT_NO 1 -#if defined(CONFIG_ZFCPDUMP) || defined(CONFIG_ZFCPDUMP_MODULE) +#ifdef CONFIG_ZFCPDUMP /* * zfcpdump_prefix_array holds prefix registers for the following scenario: @@ -267,7 +267,7 @@ EXPORT_SYMBOL_GPL(zfcpdump_save_areas); static inline void smp_get_save_area(unsigned int cpu, unsigned int phy_cpu) { } -#endif /* CONFIG_ZFCPDUMP || CONFIG_ZFCPDUMP_MODULE */ +#endif /* CONFIG_ZFCPDUMP */ static int cpu_stopped(int cpu) { -- cgit v1.2.3-70-g09d2 From 6aa0d3a922c4f58fc36cc1502c6ac72f999e26bb Mon Sep 17 00:00:00 2001 From: Stoyan Gaydarov Date: Thu, 26 Mar 2009 15:24:47 +0100 Subject: [S390] BUG to BUG_ON changes Signed-off-by: Stoyan Gaydarov Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/debug.c | 3 +-- arch/s390/kernel/setup.c | 3 +-- drivers/s390/char/tape_3590.c | 3 +-- drivers/s390/char/tape_core.c | 6 ++---- drivers/s390/char/tape_std.c | 4 ++-- 5 files changed, 7 insertions(+), 12 deletions(-) diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c index ba03fc0a3a5..39137b9e162 100644 --- a/arch/s390/kernel/debug.c +++ b/arch/s390/kernel/debug.c @@ -698,8 +698,7 @@ debug_info_t *debug_register_mode(const char *name, int pages_per_area, if ((uid != 0) || (gid != 0)) pr_warning("Root becomes the owner of all s390dbf files " "in sysfs\n"); - if (!initialized) - BUG(); + BUG_ON(!initialized); mutex_lock(&debug_mutex); /* create new debug_info */ diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 46fc981e02b..580abb53ce8 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -134,8 +134,7 @@ void __cpuinit cpu_init(void) atomic_inc(&init_mm.mm_count); current->active_mm = &init_mm; - if (current->mm) - BUG(); + BUG_ON(current->mm); enter_lazy_tlb(&init_mm, current); } diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c index 5a5bb97a081..fc1d9129414 100644 --- a/drivers/s390/char/tape_3590.c +++ b/drivers/s390/char/tape_3590.c @@ -664,8 +664,7 @@ tape_3590_bread(struct tape_device *device, struct request *req) ccw++; dst += TAPEBLOCK_HSEC_SIZE; } - if (off > bv->bv_len) - BUG(); + BUG_ON(off > bv->bv_len); } ccw = tape_ccw_end(ccw, NOP, 0, NULL); DBF_EVENT(6, "xBREDccwg\n"); diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c index 1b6a2441246..08c09d3503c 100644 --- a/drivers/s390/char/tape_core.c +++ b/drivers/s390/char/tape_core.c @@ -624,8 +624,7 @@ tape_alloc_request(int cplength, int datasize) { struct tape_request *request; - if (datasize > PAGE_SIZE || (cplength*sizeof(struct ccw1)) > PAGE_SIZE) - BUG(); + BUG_ON(datasize > PAGE_SIZE || (cplength*sizeof(struct ccw1)) > PAGE_SIZE); DBF_LH(6, "tape_alloc_request(%d, %d)\n", cplength, datasize); @@ -782,8 +781,7 @@ static void tape_long_busy_timeout(unsigned long data) device = (struct tape_device *) data; spin_lock_irq(get_ccwdev_lock(device->cdev)); request = list_entry(device->req_queue.next, struct tape_request, list); - if (request->status != TAPE_REQUEST_LONG_BUSY) - BUG(); + BUG_ON(request->status != TAPE_REQUEST_LONG_BUSY); DBF_LH(6, "%08x: Long busy timeout.\n", device->cdev_id); __tape_start_next_request(device); device->lb_timeout.data = (unsigned long) tape_put_device(device); diff --git a/drivers/s390/char/tape_std.c b/drivers/s390/char/tape_std.c index 44dd0f80c84..1a9420ba518 100644 --- a/drivers/s390/char/tape_std.c +++ b/drivers/s390/char/tape_std.c @@ -37,8 +37,8 @@ tape_std_assign_timeout(unsigned long data) int rc; request = (struct tape_request *) data; - if ((device = request->device) == NULL) - BUG(); + device = request->device; + BUG_ON(!device); DBF_EVENT(3, "%08x: Assignment timeout. Device busy.\n", device->cdev_id); -- cgit v1.2.3-70-g09d2 From 3e75a902196c45d26d5e28014eb2d9821aa9794f Mon Sep 17 00:00:00 2001 From: Johannes Weiner Date: Thu, 26 Mar 2009 15:24:48 +0100 Subject: [S390] use kzfree() Use kzfree() instead of memset() + kfree(). Signed-off-by: Johannes Weiner Reviewed-by: Pekka Enberg Signed-off-by: Andrew Morton Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/crypto/prng.c | 3 +-- drivers/s390/crypto/zcrypt_pcixcc.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/arch/s390/crypto/prng.c b/arch/s390/crypto/prng.c index eca724d229e..b49c00ce65e 100644 --- a/arch/s390/crypto/prng.c +++ b/arch/s390/crypto/prng.c @@ -201,8 +201,7 @@ out_free: static void __exit prng_exit(void) { /* wipe me */ - memset(p->buf, 0, prng_chunk_size); - kfree(p->buf); + kzfree(p->buf); kfree(p); misc_deregister(&prng_dev); diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c index e7a1e22e77a..c20d4790258 100644 --- a/drivers/s390/crypto/zcrypt_pcixcc.c +++ b/drivers/s390/crypto/zcrypt_pcixcc.c @@ -781,8 +781,7 @@ static long zcrypt_pcixcc_send_cprb(struct zcrypt_device *zdev, /* Signal pending. */ ap_cancel_message(zdev->ap_dev, &ap_msg); out_free: - memset(ap_msg.message, 0x0, ap_msg.length); - kfree(ap_msg.message); + kzfree(ap_msg.message); return rc; } -- cgit v1.2.3-70-g09d2 From a0fa8e3743c80643a06a770b95e73e751548ab17 Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Thu, 26 Mar 2009 15:24:49 +0100 Subject: [S390] s390dbf: Remove redundant initilizations. Signed-off-by: Michael Holzheu Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/debug.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c index 39137b9e162..369de12b873 100644 --- a/arch/s390/kernel/debug.c +++ b/arch/s390/kernel/debug.c @@ -603,7 +603,7 @@ debug_input(struct file *file, const char __user *user_buf, size_t length, static int debug_open(struct inode *inode, struct file *file) { - int i = 0, rc = 0; + int i, rc = 0; file_private_info_t *p_info; debug_info_t *debug_info, *debug_info_snapshot; @@ -1155,7 +1155,6 @@ debug_unregister_view(debug_info_t * id, struct debug_view *view) else { debugfs_remove(id->debugfs_entries[i]); id->views[i] = NULL; - rc = 0; } spin_unlock_irqrestore(&id->lock, flags); out: -- cgit v1.2.3-70-g09d2 From 58ace9f2a8f1caa0303aa64079d3929be28a937a Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Thu, 26 Mar 2009 15:24:50 +0100 Subject: [S390] s390dbf: Remove needless check for NULL pointer. The check for NULL pointer has already be done before. Therefore we can remove the second check. Signed-off-by: Michael Holzheu Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/debug.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c index 369de12b873..be8bceaf37d 100644 --- a/arch/s390/kernel/debug.c +++ b/arch/s390/kernel/debug.c @@ -642,8 +642,7 @@ found: p_info = kmalloc(sizeof(file_private_info_t), GFP_KERNEL); if(!p_info){ - if(debug_info_snapshot) - debug_info_free(debug_info_snapshot); + debug_info_free(debug_info_snapshot); rc = -ENOMEM; goto out; } -- cgit v1.2.3-70-g09d2 From 008d2d112cb8a743a87dfe41a67e11c0a4c73aa4 Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Thu, 26 Mar 2009 15:24:51 +0100 Subject: [S390] ipl: Improve checking logic and remove switch defaults. A code analysis tool reported two warnings: "The expression `ipl_info.type == IPL_TYPE_FCP' is true whenever evaluated." and "Default is not possible". This patch improves the corresponding if statement logic and removes the unnecessary switch defaults. Signed-off-by: Michael Holzheu Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/ipl.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index 505fec06e63..2b901fb8193 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c @@ -966,7 +966,6 @@ static void reipl_run(struct shutdown_trigger *trigger) diag308(DIAG308_IPL, NULL); break; case REIPL_METHOD_FCP_DUMP: - default: break; } disabled_wait((unsigned long) __builtin_return_address(0)); @@ -1075,10 +1074,12 @@ static int __init reipl_fcp_init(void) { int rc; - if ((!diag308_set_works) && (ipl_info.type != IPL_TYPE_FCP)) - return 0; - if ((!diag308_set_works) && (ipl_info.type == IPL_TYPE_FCP)) - make_attrs_ro(reipl_fcp_attrs); + if (!diag308_set_works) { + if (ipl_info.type == IPL_TYPE_FCP) + make_attrs_ro(reipl_fcp_attrs); + else + return 0; + } reipl_block_fcp = (void *) get_zeroed_page(GFP_KERNEL); if (!reipl_block_fcp) @@ -1259,7 +1260,6 @@ static void dump_run(struct shutdown_trigger *trigger) diag308(DIAG308_DUMP, NULL); break; case DUMP_METHOD_NONE: - default: return; } printk(KERN_EMERG "Dump failed!\n"); @@ -1746,7 +1746,6 @@ void __init setup_ipl(void) sizeof(ipl_info.data.nss.name)); break; case IPL_TYPE_UNKNOWN: - default: /* We have no info to copy */ break; } -- cgit v1.2.3-70-g09d2 From 6d54c5a3fb13d32d66a8383cb0b5fb422a563051 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 26 Mar 2009 15:24:52 +0100 Subject: [S390] smp: fix memory leak on __cpu_up If sigp_set_prefix fails on __cpu_up we leak the lowcore structures and async+panic stacks for the failed cpu. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/smp.c | 6 +++--- arch/s390/kernel/vdso.c | 2 -- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index bb3d34aa7b8..1f4711b60aa 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -508,7 +508,6 @@ out: return -ENOMEM; } -#ifdef CONFIG_HOTPLUG_CPU static void smp_free_lowcore(int cpu) { struct _lowcore *lowcore; @@ -527,7 +526,6 @@ static void smp_free_lowcore(int cpu) free_pages((unsigned long) lowcore, lc_order); lowcore_ptr[cpu] = NULL; } -#endif /* CONFIG_HOTPLUG_CPU */ /* Upping and downing of CPUs */ int __cpuinit __cpu_up(unsigned int cpu) @@ -544,8 +542,10 @@ int __cpuinit __cpu_up(unsigned int cpu) ccode = signal_processor_p((__u32)(unsigned long)(lowcore_ptr[cpu]), cpu, sigp_set_prefix); - if (ccode) + if (ccode) { + smp_free_lowcore(cpu); return -EIO; + } idle = current_set[cpu]; cpu_lowcore = lowcore_ptr[cpu]; diff --git a/arch/s390/kernel/vdso.c b/arch/s390/kernel/vdso.c index 690e1781968..89b2e7f1b7a 100644 --- a/arch/s390/kernel/vdso.c +++ b/arch/s390/kernel/vdso.c @@ -144,7 +144,6 @@ out: return -ENOMEM; } -#ifdef CONFIG_HOTPLUG_CPU void vdso_free_per_cpu(int cpu, struct _lowcore *lowcore) { unsigned long segment_table, page_table, page_frame; @@ -163,7 +162,6 @@ void vdso_free_per_cpu(int cpu, struct _lowcore *lowcore) free_page(page_table); free_pages(segment_table, SEGMENT_ORDER); } -#endif /* CONFIG_HOTPLUG_CPU */ static void __vdso_init_cr5(void *dummy) { -- cgit v1.2.3-70-g09d2 From d0d3cdf4c27fa4ce241616da08138954e02890f7 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 26 Mar 2009 15:24:53 +0100 Subject: [S390] smp: perform initial cpu reset before starting a cpu Performing an initial cpu reset makes sure all registers and tlbs of the targeted cpu are initialized and flushed. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/smp.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 1f4711b60aa..fe5f8dc1e6f 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -534,18 +534,23 @@ int __cpuinit __cpu_up(unsigned int cpu) struct _lowcore *cpu_lowcore; struct stack_frame *sf; sigp_ccode ccode; + u32 lowcore; if (smp_cpu_state[cpu] != CPU_STATE_CONFIGURED) return -EIO; if (smp_alloc_lowcore(cpu)) return -ENOMEM; - - ccode = signal_processor_p((__u32)(unsigned long)(lowcore_ptr[cpu]), - cpu, sigp_set_prefix); - if (ccode) { - smp_free_lowcore(cpu); - return -EIO; - } + do { + ccode = signal_processor(cpu, sigp_initial_cpu_reset); + if (ccode == sigp_busy) + udelay(10); + if (ccode == sigp_not_operational) + goto err_out; + } while (ccode == sigp_busy); + + lowcore = (u32)(unsigned long)lowcore_ptr[cpu]; + while (signal_processor_p(lowcore, cpu, sigp_set_prefix) == sigp_busy) + udelay(10); idle = current_set[cpu]; cpu_lowcore = lowcore_ptr[cpu]; @@ -574,6 +579,10 @@ int __cpuinit __cpu_up(unsigned int cpu) while (!cpu_online(cpu)) cpu_relax(); return 0; + +err_out: + smp_free_lowcore(cpu); + return -EIO; } static int __init setup_possible_cpus(char *s) -- cgit v1.2.3-70-g09d2 From 2ac3307f275c2a91af0417e16d2cfb95ae478661 Mon Sep 17 00:00:00 2001 From: Christian Ehrhardt Date: Thu, 26 Mar 2009 15:24:54 +0100 Subject: [S390] fix dfp elf hwcap/facility bit detection The old dfp detection wanted to check bit 43 (dfp high performance), but due to a wrong calculation always used to check bit 42. Additionally the "userspace expectation" is, that the dfp capability bit is set is if facility bit 42 (decimal floating point facility available) and bit 44 (perform floating point operation facility avail). The patch fixes the bit calculation and extends the check to work like: elf hw cap dfp bit = facility bits 42 (dfp) & 44 (pfpo) available Signed-off-by: Christian Ehrhardt Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/setup.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 580abb53ce8..18222ac4078 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -713,13 +713,15 @@ static void __init setup_hwcaps(void) * How many facility words are stored depends on the number of * doublewords passed to the instruction. The additional facilites * are: - * Bit 43: decimal floating point facility is installed + * Bit 42: decimal floating point facility is installed + * Bit 44: perform floating point operation facility is installed * translated to: * HWCAP_S390_DFP bit 6. */ if ((elf_hwcap & (1UL << 2)) && __stfle(&facility_list_extended, 1) > 0) { - if (facility_list_extended & (1ULL << (64 - 43))) + if ((facility_list_extended & (1ULL << (63 - 42))) + && (facility_list_extended & (1ULL << (63 - 44)))) elf_hwcap |= 1UL << 6; } -- cgit v1.2.3-70-g09d2 From 7e9b580e5f0644cd8952b6671fd5380fd430bca3 Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Thu, 26 Mar 2009 15:24:55 +0100 Subject: [S390] Ensure that ipl panic notifier is called late. The s390 ipl panic notifier will stop the system or trigger a system dump. This should be done as final action on the panic path. All other panic notifiers should be executed before. Currently we use priority 0 for the ipl notifier. In order to be called late, this patch changes the priority to INT_MIN which is the lowest possible priority. Signed-off-by: Michael Holzheu Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/ipl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index 2b901fb8193..56d876904ec 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c @@ -1722,7 +1722,7 @@ static int on_panic_notify(struct notifier_block *self, static struct notifier_block on_panic_nb = { .notifier_call = on_panic_notify, - .priority = 0, + .priority = INT_MIN, }; void __init setup_ipl(void) -- cgit v1.2.3-70-g09d2 From 488253ce49714f4e9d42413c1d60b7724059a338 Mon Sep 17 00:00:00 2001 From: Andreas Krebbel Date: Thu, 26 Mar 2009 15:24:56 +0100 Subject: [S390] Add hwcap flag for the etf3 enhancement facility The Extended Translation Facility 3 (ETF3) added instructions which allow conversions between different unicode character maps (UTF-8, UTF-32 ...). These instructions got enhanced with a later version of the ETF3 allowing malformed multibyte chars to be recognized and reported correctly. The attached patch reserves bit 8 in the elf hwcaps vector for the enhanced version of ETF3. The bit corresponds to the stfle bits 22 and 30 and will only be set if both of the stfle bits are set. Signed-off-by: Andreas Krebbel Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/processor.c | 6 +++--- arch/s390/kernel/setup.c | 13 ++++++++++--- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/arch/s390/kernel/processor.c b/arch/s390/kernel/processor.c index 423da1bd42a..802c8ab247f 100644 --- a/arch/s390/kernel/processor.c +++ b/arch/s390/kernel/processor.c @@ -31,9 +31,9 @@ void __cpuinit print_cpu_info(void) static int show_cpuinfo(struct seq_file *m, void *v) { - static const char *hwcap_str[8] = { + static const char *hwcap_str[9] = { "esan3", "zarch", "stfle", "msa", "ldisp", "eimm", "dfp", - "edat" + "edat", "etf3eh" }; struct _lowcore *lc; unsigned long n = (unsigned long) v - 1; @@ -48,7 +48,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) num_online_cpus(), loops_per_jiffy/(500000/HZ), (loops_per_jiffy/(5000/HZ))%100); seq_puts(m, "features\t: "); - for (i = 0; i < 8; i++) + for (i = 0; i < 9; i++) if (hwcap_str[i] && (elf_hwcap & (1UL << i))) seq_printf(m, "%s ", hwcap_str[i]); seq_puts(m, "\n"); diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 18222ac4078..06201b93cbb 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -696,15 +696,22 @@ static void __init setup_hwcaps(void) * Bit 17: the message-security assist is installed * Bit 19: the long-displacement facility is installed * Bit 21: the extended-immediate facility is installed + * Bit 22: extended-translation facility 3 is installed + * Bit 30: extended-translation facility 3 enhancement facility * These get translated to: * HWCAP_S390_ESAN3 bit 0, HWCAP_S390_ZARCH bit 1, * HWCAP_S390_STFLE bit 2, HWCAP_S390_MSA bit 3, - * HWCAP_S390_LDISP bit 4, and HWCAP_S390_EIMM bit 5. + * HWCAP_S390_LDISP bit 4, HWCAP_S390_EIMM bit 5 and + * HWCAP_S390_ETF3EH bit 8 (22 && 30). */ for (i = 0; i < 6; i++) if (facility_list & (1UL << (31 - stfl_bits[i]))) elf_hwcap |= 1UL << i; + if ((facility_list & (1UL << (31 - 22))) + && (facility_list & (1UL << (31 - 30)))) + elf_hwcap |= 1UL << 8; + /* * Check for additional facilities with store-facility-list-extended. * stfle stores doublewords (8 byte) with bit 1ULL<<63 as bit 0 @@ -716,12 +723,12 @@ static void __init setup_hwcaps(void) * Bit 42: decimal floating point facility is installed * Bit 44: perform floating point operation facility is installed * translated to: - * HWCAP_S390_DFP bit 6. + * HWCAP_S390_DFP bit 6 (42 && 44). */ if ((elf_hwcap & (1UL << 2)) && __stfle(&facility_list_extended, 1) > 0) { if ((facility_list_extended & (1ULL << (63 - 42))) - && (facility_list_extended & (1ULL << (63 - 44)))) + && (facility_list_extended & (1ULL << (63 - 44)))) elf_hwcap |= 1UL << 6; } -- cgit v1.2.3-70-g09d2 From c70d0fef1da286d7f96e774674aea2d20cf6222f Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 26 Mar 2009 15:24:57 +0100 Subject: [S390] fix clock comparator save area usage The lowcore clock comparator save area on 64 bit machines is defined to contain only the seven most significant bits of the register. That's also why it starts at an uneven address (0x1331). The current code however writes eight bytes to the address and therefore overwrites the first byte of the access register save area. Fix this and write only seven bytes to the save area. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/reipl64.S | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/arch/s390/kernel/reipl64.S b/arch/s390/kernel/reipl64.S index c41930499a5..774147824c3 100644 --- a/arch/s390/kernel/reipl64.S +++ b/arch/s390/kernel/reipl64.S @@ -1,10 +1,7 @@ /* - * arch/s390/kernel/reipl.S - * - * S390 version - * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Holger Smolinski (Holger.Smolinski@de.ibm.com) - Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) + * Copyright IBM Corp 2000,2009 + * Author(s): Holger Smolinski , + * Denis Joseph Barrow, */ #include @@ -30,7 +27,7 @@ do_reipl_asm: basr %r13,0 mvc __LC_PREFIX_SAVE_AREA-0x1000(4,%r1),0(%r10) stfpc __LC_FP_CREG_SAVE_AREA-0x1000(%r1) stckc .Lclkcmp-.Lpg0(%r13) - mvc __LC_CLOCK_COMP_SAVE_AREA-0x1000(8,%r1),.Lclkcmp-.Lpg0(%r13) + mvc __LC_CLOCK_COMP_SAVE_AREA-0x1000(7,%r1),.Lclkcmp-.Lpg0(%r13) stpt __LC_CPU_TIMER_SAVE_AREA-0x1000(%r1) stg %r13, __LC_PSW_SAVE_AREA-0x1000+8(%r1) -- cgit v1.2.3-70-g09d2 From 6f7a321d5feb0bc9aa7f7b14eceb1e6a63bff937 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 26 Mar 2009 15:24:58 +0100 Subject: [S390] cpumask: remove cpu_coregroup_map Impact: cleanup cpu_coregroup_mask is the New Hotness. As S/390 uses theirs internally, so we just make it static. Signed-off-by: Rusty Russell Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/topology.h | 1 - arch/s390/kernel/topology.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/s390/include/asm/topology.h b/arch/s390/include/asm/topology.h index c979c3b56ab..5e0ad618dc4 100644 --- a/arch/s390/include/asm/topology.h +++ b/arch/s390/include/asm/topology.h @@ -5,7 +5,6 @@ #define mc_capable() (1) -cpumask_t cpu_coregroup_map(unsigned int cpu); const struct cpumask *cpu_coregroup_mask(unsigned int cpu); extern cpumask_t cpu_core_map[NR_CPUS]; diff --git a/arch/s390/kernel/topology.c b/arch/s390/kernel/topology.c index cc362c9ea8f..3c72c9cf22b 100644 --- a/arch/s390/kernel/topology.c +++ b/arch/s390/kernel/topology.c @@ -74,7 +74,7 @@ static DEFINE_SPINLOCK(topology_lock); cpumask_t cpu_core_map[NR_CPUS]; -cpumask_t cpu_coregroup_map(unsigned int cpu) +static cpumask_t cpu_coregroup_map(unsigned int cpu) { struct core_info *core = &core_info; unsigned long flags; -- cgit v1.2.3-70-g09d2 From 93632d1bf7447d445c6fc274c8931152f9412b56 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 26 Mar 2009 15:24:59 +0100 Subject: [S390] cpumask: prepare for iterators to only go to nr_cpu_ids/nr_cpumask_bits. Impact: cleanup, futureproof In fact, all cpumask ops will only be valid (in general) for bit numbers < nr_cpu_ids. So use that instead of NR_CPUS in various places (I also updated the immediate sites to use the new cpumask_ operators). This is always safe: no cpu number can be >= nr_cpu_ids, and nr_cpu_ids is initialized to NR_CPUS at boot. Signed-off-by: Rusty Russell Signed-off-by: Mike Travis Acked-by: Ingo Molnar Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/smp.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index fe5f8dc1e6f..13052a4ed71 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -297,8 +297,8 @@ static int smp_rescan_cpus_sigp(cpumask_t avail) { int cpu_id, logical_cpu; - logical_cpu = first_cpu(avail); - if (logical_cpu == NR_CPUS) + logical_cpu = cpumask_first(&avail); + if (logical_cpu >= nr_cpu_ids) return 0; for (cpu_id = 0; cpu_id <= 65535; cpu_id++) { if (cpu_known(cpu_id)) @@ -309,8 +309,8 @@ static int smp_rescan_cpus_sigp(cpumask_t avail) continue; cpu_set(logical_cpu, cpu_present_map); smp_cpu_state[logical_cpu] = CPU_STATE_CONFIGURED; - logical_cpu = next_cpu(logical_cpu, avail); - if (logical_cpu == NR_CPUS) + logical_cpu = cpumask_next(logical_cpu, &avail); + if (logical_cpu >= nr_cpu_ids) break; } return 0; @@ -322,8 +322,8 @@ static int smp_rescan_cpus_sclp(cpumask_t avail) int cpu_id, logical_cpu, cpu; int rc; - logical_cpu = first_cpu(avail); - if (logical_cpu == NR_CPUS) + logical_cpu = cpumask_first(&avail); + if (logical_cpu >= nr_cpu_ids) return 0; info = kmalloc(sizeof(*info), GFP_KERNEL); if (!info) @@ -344,8 +344,8 @@ static int smp_rescan_cpus_sclp(cpumask_t avail) smp_cpu_state[logical_cpu] = CPU_STATE_STANDBY; else smp_cpu_state[logical_cpu] = CPU_STATE_CONFIGURED; - logical_cpu = next_cpu(logical_cpu, avail); - if (logical_cpu == NR_CPUS) + logical_cpu = cpumask_next(logical_cpu, &avail); + if (logical_cpu >= nr_cpu_ids) break; } out: @@ -591,7 +591,7 @@ static int __init setup_possible_cpus(char *s) pcpus = simple_strtoul(s, NULL, 0); cpu_possible_map = cpumask_of_cpu(0); - for (cpu = 1; cpu < pcpus && cpu < NR_CPUS; cpu++) + for (cpu = 1; cpu < pcpus && cpu < nr_cpu_ids; cpu++) cpu_set(cpu, cpu_possible_map); return 0; } -- cgit v1.2.3-70-g09d2 From def6cfb70bab83c0094bc0cedd27c4eda563043e Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 26 Mar 2009 15:25:00 +0100 Subject: [S390] cpumask: Use accessors code. Impact: use new API Use the accessors rather than frobbing bits directly. Most of this is in arch code I haven't even compiled, but is straightforward. Signed-off-by: Rusty Russell Signed-off-by: Mike Travis Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/smp.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 13052a4ed71..006ed5016eb 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -590,9 +590,8 @@ static int __init setup_possible_cpus(char *s) int pcpus, cpu; pcpus = simple_strtoul(s, NULL, 0); - cpu_possible_map = cpumask_of_cpu(0); - for (cpu = 1; cpu < pcpus && cpu < nr_cpu_ids; cpu++) - cpu_set(cpu, cpu_possible_map); + for (cpu = 0; cpu < pcpus && cpu < nr_cpu_ids; cpu++) + set_cpu_possible(cpu, true); return 0; } early_param("possible_cpus", setup_possible_cpus); -- cgit v1.2.3-70-g09d2 From 005f8eee6f3c8173e492d7bd4d51bda990eb468b Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 26 Mar 2009 15:25:01 +0100 Subject: [S390] cpumask: use mm_cpumask() wrapper Makes code futureproof against the impending change to mm->cpu_vm_mask. It's also a chance to use the new cpumask_ ops which take a pointer (the older ones are deprecated, but there's no hurry for arch code). Signed-off-by: Rusty Russell Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/mmu_context.h | 2 +- arch/s390/include/asm/tlbflush.h | 4 ++-- arch/s390/mm/pgtable.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/s390/include/asm/mmu_context.h b/arch/s390/include/asm/mmu_context.h index 28ec870655a..fc7edd6f41b 100644 --- a/arch/s390/include/asm/mmu_context.h +++ b/arch/s390/include/asm/mmu_context.h @@ -74,7 +74,7 @@ static inline void update_mm(struct mm_struct *mm, struct task_struct *tsk) static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk) { - cpu_set(smp_processor_id(), next->cpu_vm_mask); + cpumask_set_cpu(smp_processor_id(), mm_cpumask(next)); update_mm(next, tsk); } diff --git a/arch/s390/include/asm/tlbflush.h b/arch/s390/include/asm/tlbflush.h index d60394b9745..304cffa623e 100644 --- a/arch/s390/include/asm/tlbflush.h +++ b/arch/s390/include/asm/tlbflush.h @@ -51,7 +51,7 @@ static inline void __tlb_flush_full(struct mm_struct *mm) * If the process only ran on the local cpu, do a local flush. */ local_cpumask = cpumask_of_cpu(smp_processor_id()); - if (cpus_equal(mm->cpu_vm_mask, local_cpumask)) + if (cpumask_equal(mm_cpumask(mm), &local_cpumask)) __tlb_flush_local(); else __tlb_flush_global(); @@ -73,7 +73,7 @@ static inline void __tlb_flush_idte(unsigned long asce) static inline void __tlb_flush_mm(struct mm_struct * mm) { - if (unlikely(cpus_empty(mm->cpu_vm_mask))) + if (unlikely(cpumask_empty(mm_cpumask(mm)))) return; /* * If the machine has IDTE we prefer to do a per mm flush diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c index 9bf86125f6f..be6c1cf4ad5 100644 --- a/arch/s390/mm/pgtable.c +++ b/arch/s390/mm/pgtable.c @@ -296,7 +296,7 @@ int s390_enable_sie(void) tsk->mm = tsk->active_mm = mm; preempt_disable(); update_mm(mm, tsk); - cpu_set(smp_processor_id(), mm->cpu_vm_mask); + cpumask_set_cpu(smp_processor_id(), mm_cpumask(mm)); preempt_enable(); task_unlock(tsk); mmput(old_mm); -- cgit v1.2.3-70-g09d2 From ef3500b2b2955af4fa6b0564b51c0c604e38c571 Mon Sep 17 00:00:00 2001 From: Huang Weiyi Date: Thu, 26 Mar 2009 15:25:02 +0100 Subject: [S390] remove duplicated #includes Remove duplicated #include's in arch/s390/kernel/ipl.c. Signed-off-by: Huang Weiyi Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/ipl.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index 56d876904ec..6f3711a0eaa 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #define IPL_PARM_BLOCK_VERSION 0 -- cgit v1.2.3-70-g09d2